diff options
Diffstat (limited to 'utils')
564 files changed, 236010 insertions, 0 deletions
diff --git a/utils/0a/a.h b/utils/0a/a.h new file mode 100644 index 00000000..664ac9b0 --- /dev/null +++ b/utils/0a/a.h @@ -0,0 +1,183 @@ +#include <lib9.h> +#include <bio.h> +#include "../vc/v.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + + +#define MAXALIGN 7 + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#define FPCHIP 1 +#define NSYMB 8192 +#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; + char* macro; + long value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym* sym; + long offset; + short type; + short reg; + short name; + double dval; + char sval[8]; +}; + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) + +enum /* keep in synch with ../cc/cc.h */ +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +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 nosched; +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; + +int assemble(char*); +void* alloc(long); +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 pinit(char*); +void cclean(void); +int isreg(Gen*); +void outcode(int, Gen*, int, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, 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 maclin(void); +void macprag(void); +void macif(int); +void macend(void); +void outhist(void); +void dodefine(char*); +void prfile(long); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); + +/* + * Posix.c/Inferno.c/Nt.c + */ +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); diff --git a/utils/0a/a.y b/utils/0a/a.y new file mode 100644 index 00000000..4f72a892 --- /dev/null +++ b/utils/0a/a.y @@ -0,0 +1,588 @@ +%{ +#include "a.h" +%} +%union +{ + Sym *sym; + long lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 +%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA +%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF +%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK +%token <lval> LCONST LSP LSB LFP LPC LHI LLO LMREG +%token <lval> LTYPEX LREG LFREG LFCREG LR LM LF +%token <lval> LFCR LSCHED +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr pointer offset sreg +%type <gen> gen vgen lgen vlgen rel reg freg mreg fcreg +%type <gen> imm ximm ireg name oreg imr nireg fgen +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| LSCHED ';' + { + nosched = $1; + } +| ';' +| inst ';' +| error ';' + +inst: +/* + * Immed-type + */ + LTYPE1 imr ',' sreg ',' reg + { + outcode($1, &$2, $4, &$6); + } +| LTYPE1 imr ',' reg + { + outcode($1, &$2, NREG, &$4); + } +/* + * NOR + */ +| LTYPE2 imr ',' sreg ',' imr + { + outcode($1, &$2, $4, &$6); + } +| LTYPE2 imr ',' imr + { + outcode($1, &$2, NREG, &$4); + } +/* + * LOAD/STORE, but not MOVW + */ +| LTYPE3 lgen ',' gen + { + if(!isreg(&$2) && !isreg(&$4)) + print("one side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +/* + * SPECIAL + */ +| LTYPE4 comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +/* + * MOVW + */ +| LTYPE5 vlgen ',' vgen + { + if(!isreg(&$2) && !isreg(&$4)) + print("one side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +/* + * MUL/DIV + */ +| LTYPE6 reg ',' sreg comma + { + outcode($1, &$2, $4, &nullgen); + } +| LTYPE6 reg ',' sreg ',' reg + { + outcode($1, &$2, $4, &$6); + } +/* + * JMP/JAL + */ +| LTYPE7 comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE7 comma nireg + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE8 comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE8 comma nireg + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE8 sreg ',' nireg + { + outcode($1, &nullgen, $2, &$4); + } +/* + * BEQ/BNE + */ +| LTYPE9 gen ',' rel + { + if(!isreg(&$2)) + print("left side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +| LTYPE9 gen ',' sreg ',' rel + { + if(!isreg(&$2)) + print("left side must be register\n"); + outcode($1, &$2, $4, &$6); + } +/* + * B-other + */ +| LTYPEA gen ',' rel + { + if(!isreg(&$2)) + print("left side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +/* + * TEXT/GLOBL + */ +| LTYPEB name ',' imm + { + outcode($1, &$2, NREG, &$4); + } +| LTYPEB name ',' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +/* + * DATA + */ +| LTYPEC name '/' con ',' ximm + { + outcode($1, &$2, $4, &$6); + } +/* + * floating-type + */ +| LTYPED freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LTYPEE freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LTYPEE freg ',' LFREG ',' freg + { + outcode($1, &$2, $4, &$6); + } +| LTYPEF freg ',' LFREG comma + { + outcode($1, &$2, $4, &nullgen); + } +/* + * coprocessor branch + */ +| LTYPEG comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * word + */ +| LTYPEH comma ximm + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * NOP + */ +| LTYPEI comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LTYPEI ',' vgen + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPEI vgen comma + { + outcode($1, &$2, NREG, &nullgen); + } +/* + * BREAK -- overloaded with CACHE opcode + */ +| LTYPEJ comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LTYPEJ vgen ',' vgen + { + outcode($1, &$2, NREG, &$4); + } + +comma: +| ',' + +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; + } + +vlgen: + lgen +| fgen +| mreg +| fcreg +| LHI + { + $$ = nullgen; + $$.type = D_HI; + } +| LLO + { + $$ = nullgen; + $$.type = D_LO; + } + +vgen: + gen +| fgen +| mreg +| fcreg +| LHI + { + $$ = nullgen; + $$.type = D_HI; + } +| LLO + { + $$ = nullgen; + $$.type = D_LO; + } + +lgen: + gen +| ximm + +fgen: + freg + +mreg: + LMREG + { + $$ = nullgen; + $$.type = D_MREG; + $$.reg = $1; + } +| LM '(' con ')' + { + $$ = nullgen; + $$.type = D_MREG; + $$.reg = $3; + } + +fcreg: + LFCREG + { + $$ = nullgen; + $$.type = D_FCREG; + $$.reg = $1; + } +| LFCR '(' con ')' + { + $$ = nullgen; + $$.type = D_FCREG; + $$.reg = $3; + } + +freg: + LFREG + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } +| LF '(' con ')' + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $3; + } + +ximm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } +| '$' oreg + { + $$ = $2; + $$.type = D_CONST; + } +| '$' '*' '$' oreg + { + $$ = $4; + $$.type = D_OCONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +nireg: + ireg +| con ireg + { + if($1 != 0) + yyerror("offset must be zero"); + $$ = $2; + } +| name + { + $$ = $1; + if($1.name != D_EXTERN && $1.name != D_STATIC) { + } + } + +ireg: + '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } + +gen: + reg +| con + { + $$ = nullgen; + $$.type = D_OREG; + $$.offset = $1; + } +| oreg + +oreg: + name +| name '(' sreg ')' + { + $$ = $1; + $$.type = D_OREG; + $$.reg = $3; + } +| '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +imr: + reg +| imm + +imm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } + +reg: + sreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +sreg: + LREG +| LR '(' expr ')' + { + if($$ < 0 || $$ >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/0a/l.s b/utils/0a/l.s new file mode 100644 index 00000000..2f8e6341 --- /dev/null +++ b/utils/0a/l.s @@ -0,0 +1,703 @@ +/* + * 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 MAXMACH 4 /* max # cpus system can run */ + +/* + * Time + */ +#define MS2HZ 50 /* millisec per clock tick */ +#define TK2SEC(t) ((t)/20) /* ticks to seconds */ +#define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */ +#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */ + +/* + * CP0 registers + */ + +#define INDEX 0 +#define RANDOM 1 +#define TLBPHYS 2 +#define CONTEXT 4 +#define BADVADDR 8 +#define TLBVIRT 10 +#define STATUS 12 +#define CAUSE 13 +#define EPC 14 +#define PRID 15 + +/* + * M(STATUS) bits + */ +#define IEC 0x00000001 +#define KUC 0x00000002 +#define IEP 0x00000004 +#define KUP 0x00000008 +#define INTMASK 0x0000ff00 +#define SW0 0x00000100 +#define SW1 0x00000200 +#define INTR0 0x00000400 +#define INTR1 0x00000800 +#define INTR2 0x00001000 +#define INTR3 0x00002000 +#define INTR4 0x00004000 +#define INTR5 0x00008000 +#define ISC 0x00010000 +#define SWC 0x00020000 +#define CU1 0x20000000 + +/* + * Traps + */ + +#define UTLBMISS (KSEG0+0x00) +#define EXCEPTION (KSEG0+0x80) + +/* + * Magic registers + */ + +#define MACH 25 /* R25 is m-> */ +#define USER 24 /* R24 is u-> */ +#define MPID 0xBF000000 /* long; low 3 bits identify mp bus slot */ +#define WBFLUSH 0xBC000000 /* D-CACHE data; used for write buffer flush */ + +/* + * Fundamental addresses + */ + +#define MACHADDR 0x80014000 +#define USERADDR 0xC0000000 +#define UREGADDR (USERADDR+BY2PG-4-0xA0) +/* + * MMU + */ + +#define KUSEG 0x00000000 +#define KSEG0 0x80000000 +#define KSEG1 0xA0000000 +#define KSEG2 0xC0000000 +#define KSEGM 0xE0000000 /* mask to check which seg */ + +#define PTEGLOBL (1<<8) +#define PTEVALID (1<<9) +#define PTEWRITE (1<<10) +#define PTEPID(n) ((n)<<6) + +#define NTLBPID 64 /* number of pids */ +#define NTLB 64 /* number of entries */ +#define TLBROFF 8 /* offset of first randomly indexed entry */ + +/* + * Address spaces + */ + +#define UZERO KUSEG /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define USTKTOP KZERO /* byte just beyond user stack */ +#define TSTKTOP (USERADDR+100*BY2PG) /* top of temporary stack */ +#define KZERO KSEG0 /* base of kernel address space */ +#define KTZERO (KSEG0+0x20000) /* first address in kernel text */ +#define USTACKSIZE (4*1024*1024) /* size of user stack */ +/* + * Exception codes + */ +#define CINT 0 /* external interrupt */ +#define CTLBM 1 /* TLB modification */ +#define CTLBL 2 /* TLB miss (load or fetch) */ +#define CTLBS 3 /* TLB miss (store) */ +#define CADREL 4 /* address error (load or fetch) */ +#define CADRES 5 /* address error (store) */ +#define CBUSI 6 /* bus error (fetch) */ +#define CBUSD 7 /* bus error (data load or store) */ +#define CSYS 8 /* system call */ +#define CBRK 9 /* breakpoint */ +#define CRES 10 /* reserved instruction */ +#define CCPU 11 /* coprocessor unusable */ +#define COVF 12 /* arithmetic overflow */ +#define CUNK13 13 /* undefined 13 */ +#define CUNK14 14 /* undefined 14 */ +#define CUNK15 15 /* undefined 15 */ + +#define NSEG 5 + +#define SP R29 + +#define PROM (KSEG1+0x1FC00000) +#define NOOP NOR R0,R0 +#define WAIT NOOP; NOOP + +/* + * Boot first processor + * - why is the processor number loaded from R0 ????? + */ +TEXT start(SB), $-4 + + MOVW $setR30(SB), R30 + MOVW $(CU1|INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 + MOVW R1, M(STATUS) + WAIT + + MOVW $(0x1C<<7), R1 + MOVW R1, FCR31 /* permit only inexact and underflow */ + NOOP + MOVD $0.5, F26 + SUBD F26, F26, F24 + ADDD F26, F26, F28 + ADDD F28, F28, F30 + + MOVD F24, F0 + MOVD F24, F2 + MOVD F24, F4 + MOVD F24, F6 + MOVD F24, F8 + MOVD F24, F10 + MOVD F24, F12 + MOVD F24, F14 + MOVD F24, F16 + MOVD F24, F18 + MOVD F24, F20 + MOVD F24, F22 + + MOVW $MACHADDR, R(MACH) + ADDU $(BY2PG-4), R(MACH), SP + MOVW $0, R(USER) + MOVW R0, 0(R(MACH)) + + MOVW $edata(SB), R1 + MOVW $end(SB), R2 + +clrbss: + MOVB $0, (R1) + ADDU $1, R1 + BNE R1, R2, clrbss + + MOVW R4, _argc(SB) + MOVW R5, _argv(SB) + MOVW R6, _env(SB) + JAL main(SB) + JMP (R0) + +/* + * Take first processor into user mode + * - argument is stack pointer to user + */ + +TEXT touser(SB), $-4 + + MOVW M(STATUS), R1 + OR $(KUP|IEP), R1 + MOVW R1, M(STATUS) + NOOP + MOVW 0(FP), SP + MOVW $(UTZERO+32), R26 /* header appears in text */ + RFE (R26) + +/* + * Bring subsequent processors on line + */ +TEXT newstart(SB), $0 + + MOVW $setR30(SB), R30 + MOVW $(INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 + MOVW R1, M(STATUS) + NOOP + MOVW $MACHADDR, R(MACH) + MOVB (MPID+3), R1 + AND $7, R1 + SLL $PGSHIFT, R1, R2 + ADDU R2, R(MACH) + ADDU $(BY2PG-4), R(MACH), SP + MOVW $0, R(USER) + MOVW R1, 0(R(MACH)) + JAL online(SB) + JMP (R0) + +TEXT firmware(SB), $0 + + MOVW $(PROM+0x18), R1 /**/ +/* MOVW $(PROM+0x00), R1 /**/ + JMP (R1) + +TEXT splhi(SB), $0 + + MOVW M(STATUS), R1 + AND $~IEC, R1, R2 + MOVW R2, M(STATUS) + NOOP + RET + +TEXT spllo(SB), $0 + + MOVW M(STATUS), R1 + OR $IEC, R1, R2 + MOVW R2, M(STATUS) + NOOP + RET + +TEXT splx(SB), $0 + + MOVW 0(FP), R1 + MOVW M(STATUS), R2 + AND $IEC, R1 + AND $~IEC, R2 + OR R2, R1 + MOVW R1, M(STATUS) + NOOP + RET + +TEXT wbflush(SB), $-4 + + MOVW $WBFLUSH, R1 + MOVW 0(R1), R1 + RET + +TEXT setlabel(SB), $0 + + MOVW 0(FP), R2 + MOVW $0, R1 + MOVW R31, 0(R2) + MOVW R29, 4(R2) + RET + +TEXT gotolabel(SB), $0 + + MOVW 0(FP), R2 + MOVW $1, R1 + MOVW 0(R2), R31 + MOVW 4(R2), R29 + RET + +TEXT gotopc(SB), $8 + + MOVW 0(FP), R7 /* save arguments for later */ + MOVW _argc(SB), R4 + MOVW _argv(SB), R5 + MOVW _env(SB), R6 + MOVW R0, 4(SP) + MOVW $(64*1024), R1 + MOVW R1, 8(SP) + JAL icflush(SB) + JMP (R7) + +TEXT puttlb(SB), $4 + + JAL splhi(SB) + MOVW 0(FP), R2 + MOVW 4(FP), R3 + MOVW R1, 4(SP) + MOVW R2, M(TLBVIRT) + MOVW R3, M(TLBPHYS) + NOOP + TLBP + NOOP + MOVW M(INDEX), R4 + BGEZ R4, index + TLBWR + NOOP + JAL splx(SB) + RET +index: + TLBWI + NOOP + JAL splx(SB) + RET + +TEXT puttlbx(SB), $0 + + MOVW 0(FP), R4 + MOVW 4(FP), R2 + MOVW 8(FP), R3 + SLL $8, R4 + MOVW R2, M(TLBVIRT) + MOVW R3, M(TLBPHYS) + MOVW R4, M(INDEX) + NOOP + TLBWI + NOOP + RET + +TEXT tlbp(SB), $0 + TLBP + NOOP + MOVW M(INDEX), R1 + RET + +TEXT tlbvirt(SB), $0 + TLBP + NOOP + MOVW M(TLBVIRT), R1 + RET + + +TEXT gettlb(SB), $0 + + MOVW 0(FP), R3 + MOVW 4(FP), R4 + SLL $8, R3 + MOVW R3, M(INDEX) + NOOP + TLBR + NOOP + MOVW M(TLBVIRT), R1 + MOVW M(TLBPHYS), R2 + NOOP + MOVW R1, 0(R4) + MOVW R2, 4(R4) + RET + +TEXT gettlbvirt(SB), $0 + + MOVW 0(FP), R3 + SLL $8, R3 + MOVW R3, M(INDEX) + NOOP + TLBR + NOOP + MOVW M(TLBVIRT), R1 + NOOP + RET + +TEXT vector80(SB), $-4 + + MOVW $exception(SB), R26 + JMP (R26) + +TEXT exception(SB), $-4 + + MOVW M(STATUS), R26 + AND $KUP, R26 + BEQ R26, waskernel + +wasuser: + MOVW SP, R26 + /* + * set kernel sp: ureg - ureg* - pc + * done in 2 steps because R30 is not set + * and the loader will make a literal + */ + MOVW $((UREGADDR-2*BY2WD) & 0xffff0000), SP + OR $((UREGADDR-2*BY2WD) & 0xffff), SP + MOVW R26, 0x10(SP) /* user SP */ + MOVW R31, 0x28(SP) + MOVW R30, 0x2C(SP) + MOVW M(CAUSE), R26 + MOVW R(MACH), 0x3C(SP) + MOVW R(USER), 0x40(SP) + AND $(0xF<<2), R26 + SUB $(CSYS<<2), R26 + + JAL saveregs(SB) + + MOVW $setR30(SB), R30 + SUBU $(UREGADDR-2*BY2WD-USERADDR), SP, R(USER) + MOVW $MPID, R1 + MOVB 3(R1), R1 + MOVW $MACHADDR, R(MACH) /* locn of mach 0 */ + AND $7, R1 + SLL $PGSHIFT, R1 + ADDU R1, R(MACH) /* add offset for mach # */ + + BNE R26, notsys + + JAL syscall(SB) + + MOVW 0x28(SP), R31 + MOVW 0x08(SP), R26 + MOVW 0x2C(SP), R30 + MOVW R26, M(STATUS) + NOOP + MOVW 0x0C(SP), R26 /* old pc */ + MOVW 0x10(SP), SP + RFE (R26) + +notsys: + JAL trap(SB) + +restore: + JAL restregs(SB) + MOVW 0x28(SP), R31 + MOVW 0x2C(SP), R30 + MOVW 0x3C(SP), R(MACH) + MOVW 0x40(SP), R(USER) + MOVW 0x10(SP), SP + RFE (R26) + +waskernel: + MOVW $1, R26 /* not sys call */ + MOVW SP, -0x90(SP) /* drop this if possible */ + SUB $0xA0, SP + MOVW R31, 0x28(SP) + JAL saveregs(SB) + JAL trap(SB) + JAL restregs(SB) + MOVW 0x28(SP), R31 + ADD $0xA0, SP + RFE (R26) + +TEXT saveregs(SB), $-4 + MOVW R1, 0x9C(SP) + MOVW R2, 0x98(SP) + ADDU $8, SP, R1 + MOVW R1, 0x04(SP) /* arg to base of regs */ + MOVW M(STATUS), R1 + MOVW M(EPC), R2 + MOVW R1, 0x08(SP) + MOVW R2, 0x0C(SP) + + BEQ R26, return /* sys call, don't save */ + + MOVW M(CAUSE), R1 + MOVW M(BADVADDR), R2 + MOVW R1, 0x14(SP) + MOVW M(TLBVIRT), R1 + MOVW R2, 0x18(SP) + MOVW R1, 0x1C(SP) + MOVW HI, R1 + MOVW LO, R2 + MOVW R1, 0x20(SP) + MOVW R2, 0x24(SP) + /* LINK,SB,SP missing */ + MOVW R28, 0x30(SP) + /* R27, R26 not saved */ + /* R25, R24 missing */ + MOVW R23, 0x44(SP) + MOVW R22, 0x48(SP) + MOVW R21, 0x4C(SP) + MOVW R20, 0x50(SP) + MOVW R19, 0x54(SP) + MOVW R18, 0x58(SP) + MOVW R17, 0x5C(SP) + MOVW R16, 0x60(SP) + MOVW R15, 0x64(SP) + MOVW R14, 0x68(SP) + MOVW R13, 0x6C(SP) + MOVW R12, 0x70(SP) + MOVW R11, 0x74(SP) + MOVW R10, 0x78(SP) + MOVW R9, 0x7C(SP) + MOVW R8, 0x80(SP) + MOVW R7, 0x84(SP) + MOVW R6, 0x88(SP) + MOVW R5, 0x8C(SP) + MOVW R4, 0x90(SP) + MOVW R3, 0x94(SP) +return: + RET + +TEXT restregs(SB), $-4 + /* LINK,SB,SP missing */ + MOVW 0x30(SP), R28 + /* R27, R26 not saved */ + /* R25, R24 missing */ + MOVW 0x44(SP), R23 + MOVW 0x48(SP), R22 + MOVW 0x4C(SP), R21 + MOVW 0x50(SP), R20 + MOVW 0x54(SP), R19 + MOVW 0x58(SP), R18 + MOVW 0x5C(SP), R17 + MOVW 0x60(SP), R16 + MOVW 0x64(SP), R15 + MOVW 0x68(SP), R14 + MOVW 0x6C(SP), R13 + MOVW 0x70(SP), R12 + MOVW 0x74(SP), R11 + MOVW 0x78(SP), R10 + MOVW 0x7C(SP), R9 + MOVW 0x80(SP), R8 + MOVW 0x84(SP), R7 + MOVW 0x88(SP), R6 + MOVW 0x8C(SP), R5 + MOVW 0x90(SP), R4 + MOVW 0x94(SP), R3 + MOVW 0x24(SP), R2 + MOVW 0x20(SP), R1 + MOVW R2, LO + MOVW R1, HI + MOVW 0x08(SP), R1 + MOVW 0x98(SP), R2 + MOVW R1, M(STATUS) + NOOP + MOVW 0x9C(SP), R1 + MOVW 0x0C(SP), R26 /* old pc */ + RET + +TEXT rfnote(SB), $0 + MOVW 0(FP), R26 /* 1st arg is &uregpointer */ + SUBU $(BY2WD), R26, SP /* pc hole */ + BNE R26, restore + + +TEXT clrfpintr(SB), $0 + MOVW FCR31, R1 + MOVW R1, R2 + AND $~(0x3F<<12), R2 + MOVW R2, FCR31 + RET + +TEXT savefpregs(SB), $0 + MOVW M(STATUS), R3 + MOVW 0(FP), R1 + MOVW FCR31, R2 + + MOVD F0, 0x00(R1) + MOVD F2, 0x08(R1) + MOVD F4, 0x10(R1) + MOVD F6, 0x18(R1) + MOVD F8, 0x20(R1) + MOVD F10, 0x28(R1) + MOVD F12, 0x30(R1) + MOVD F14, 0x38(R1) + MOVD F16, 0x40(R1) + MOVD F18, 0x48(R1) + MOVD F20, 0x50(R1) + MOVD F22, 0x58(R1) + MOVD F24, 0x60(R1) + MOVD F26, 0x68(R1) + MOVD F28, 0x70(R1) + MOVD F30, 0x78(R1) + + MOVW R2, 0x80(R1) + AND $~CU1, R3 + MOVW R3, M(STATUS) + RET + +TEXT restfpregs(SB), $0 + + MOVW M(STATUS), R3 + MOVW 0(FP), R1 + OR $CU1, R3 + MOVW R3, M(STATUS) + MOVW 0x80(R1), R2 + + MOVD 0x00(R1), F0 + MOVD 0x08(R1), F2 + MOVD 0x10(R1), F4 + MOVD 0x18(R1), F6 + MOVD 0x20(R1), F8 + MOVD 0x28(R1), F10 + MOVD 0x30(R1), F12 + MOVD 0x38(R1), F14 + MOVD 0x40(R1), F16 + MOVD 0x48(R1), F18 + MOVD 0x50(R1), F20 + MOVD 0x58(R1), F22 + MOVD 0x60(R1), F24 + MOVD 0x68(R1), F26 + MOVD 0x70(R1), F28 + MOVD 0x78(R1), F30 + + MOVW R2, FCR31 + AND $~CU1, R3 + MOVW R3, M(STATUS) + RET + +/* + * we avoid using R4, R5, R6, and R7 so gotopc can call us without saving them + */ +TEXT icflush(SB), $-4 /* icflush(physaddr, nbytes) */ + + MOVW M(STATUS), R10 + MOVW 0(FP), R8 + MOVW 4(FP), R9 + MOVW $KSEG0, R3 + OR R3, R8 + MOVW $0, M(STATUS) + MOVW $WBFLUSH, R1 /* wbflush */ + MOVW 0(R1), R1 + NOOP + MOVW $KSEG1, R3 + MOVW $icflush0(SB), R2 /* make sure PC is in uncached address space */ + MOVW $(SWC|ISC), R1 + OR R3, R2 + JMP (R2) + +TEXT icflush0(SB), $-4 + + MOVW R1, M(STATUS) /* swap and isolate cache, splhi */ + MOVW $icflush1(SB), R2 + JMP (R2) + +TEXT icflush1(SB), $-4 + +_icflush1: + MOVBU R0, 0x00(R8) + MOVBU R0, 0x04(R8) + MOVBU R0, 0x08(R8) + MOVBU R0, 0x0C(R8) + MOVBU R0, 0x10(R8) + MOVBU R0, 0x14(R8) + MOVBU R0, 0x18(R8) + MOVBU R0, 0x1C(R8) + MOVBU R0, 0x20(R8) + MOVBU R0, 0x24(R8) + MOVBU R0, 0x28(R8) + MOVBU R0, 0x2C(R8) + MOVBU R0, 0x30(R8) + MOVBU R0, 0x34(R8) + MOVBU R0, 0x38(R8) + MOVBU R0, 0x3C(R8) + SUB $0x40, R9 + ADD $0x40, R8 + BGTZ R9, _icflush1 + MOVW $icflush2(SB), R2 /* make sure PC is in uncached address space */ + OR R3, R2 + JMP (R2) + +TEXT icflush2(SB), $-4 + + MOVW $0, M(STATUS) /* swap back caches, de-isolate them, and stay splhi */ + NOOP /* +++ */ + MOVW R10, M(STATUS) + RET + +TEXT dcflush(SB), $-4 /* dcflush(physaddr, nbytes) */ + + MOVW M(STATUS), R6 + MOVW 0(FP), R4 + MOVW 4(FP), R5 + MOVW $KSEG0, R3 + OR R3, R4 + MOVW $0, M(STATUS) + MOVW $WBFLUSH, R1 + MOVW 0(R1), R1 + NOOP + MOVW $ISC, R1 + MOVW R1, M(STATUS) +_dcflush0: + MOVBU R0, 0x00(R4) + MOVBU R0, 0x04(R4) + MOVBU R0, 0x08(R4) + MOVBU R0, 0x0C(R4) + MOVBU R0, 0x10(R4) + MOVBU R0, 0x14(R4) + MOVBU R0, 0x18(R4) + MOVBU R0, 0x1C(R4) + MOVBU R0, 0x20(R4) + MOVBU R0, 0x24(R4) + MOVBU R0, 0x28(R4) + MOVBU R0, 0x2C(R4) + MOVBU R0, 0x30(R4) + MOVBU R0, 0x34(R4) + MOVBU R0, 0x38(R4) + MOVBU R0, 0x3C(R4) + SUB $0x40, R5 + ADD $0x40, R4 + BGTZ R5, _dcflush0 + MOVW $0, M(STATUS) + NOOP /* +++ */ + MOVW R6, M(STATUS) + RET diff --git a/utils/0a/lex.c b/utils/0a/lex.c new file mode 100644 index 00000000..6d736d7c --- /dev/null +++ b/utils/0a/lex.c @@ -0,0 +1,697 @@ +#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 = '0'; + thestring = "spim"; + 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, '/'); + 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, + "HI", LHI, D_HI, + "LO", LLO, D_LO, + + "R", LR, 0, + "R0", LREG, 0, + "R1", LREG, 1, + "R2", LREG, 2, + "R3", LREG, 3, + "R4", LREG, 4, + "R5", LREG, 5, + "R6", LREG, 6, + "R7", LREG, 7, + "R8", LREG, 8, + "R9", LREG, 9, + "R10", LREG, 10, + "R11", LREG, 11, + "R12", LREG, 12, + "R13", LREG, 13, + "R14", LREG, 14, + "R15", LREG, 15, + "R16", LREG, 16, + "R17", LREG, 17, + "R18", LREG, 18, + "R19", LREG, 19, + "R20", LREG, 20, + "R21", LREG, 21, + "R22", LREG, 22, + "R23", LREG, 23, + "R24", LREG, 24, + "R25", LREG, 25, + "R26", LREG, 26, + "R27", LREG, 27, + "R28", LREG, 28, + "R29", LREG, 29, + "R30", LREG, 30, + "R31", LREG, 31, + + "M", LM, 0, + "M0", LMREG, 0, + "M1", LMREG, 1, + "M2", LMREG, 2, + "M3", LMREG, 3, + "M4", LMREG, 4, + "M5", LMREG, 5, + "M6", LMREG, 6, + "M7", LMREG, 7, + "M8", LMREG, 8, + "M9", LMREG, 9, + "M10", LMREG, 10, + "M11", LMREG, 11, + "M12", LMREG, 12, + "M13", LMREG, 13, + "M14", LMREG, 14, + "M15", LMREG, 15, + "M16", LMREG, 16, + "M17", LMREG, 17, + "M18", LMREG, 18, + "M19", LMREG, 19, + "M20", LMREG, 20, + "M21", LMREG, 21, + "M22", LMREG, 22, + "M23", LMREG, 23, + "M24", LMREG, 24, + "M25", LMREG, 25, + "M26", LMREG, 26, + "M27", LMREG, 27, + "M28", LMREG, 28, + "M29", LMREG, 29, + "M30", LMREG, 30, + "M31", LMREG, 31, + + "F", LF, 0, + + "F0", LFREG, 0, + "F1", LFREG, 1, + "F2", LFREG, 2, + "F3", LFREG, 3, + "F4", LFREG, 4, + "F5", LFREG, 5, + "F6", LFREG, 6, + "F7", LFREG, 7, + "F8", LFREG, 8, + "F9", LFREG, 9, + "F10", LFREG, 10, + "F11", LFREG, 11, + "F12", LFREG, 12, + "F13", LFREG, 13, + "F14", LFREG, 14, + "F15", LFREG, 15, + "F16", LFREG, 16, + "F17", LFREG, 17, + "F18", LFREG, 18, + "F19", LFREG, 19, + "F20", LFREG, 20, + "F21", LFREG, 21, + "F22", LFREG, 22, + "F23", LFREG, 23, + "F24", LFREG, 24, + "F25", LFREG, 25, + "F26", LFREG, 26, + "F27", LFREG, 27, + "F28", LFREG, 28, + "F29", LFREG, 29, + "F30", LFREG, 30, + "F31", LFREG, 31, + + "FCR", LFCR, 0, + "FCR0", LFCREG, 0, + "FCR1", LFCREG, 1, + "FCR2", LFCREG, 2, + "FCR3", LFCREG, 3, + "FCR4", LFCREG, 4, + "FCR5", LFCREG, 5, + "FCR6", LFCREG, 6, + "FCR7", LFCREG, 7, + "FCR8", LFCREG, 8, + "FCR9", LFCREG, 9, + "FCR10", LFCREG, 10, + "FCR11", LFCREG, 11, + "FCR12", LFCREG, 12, + "FCR13", LFCREG, 13, + "FCR14", LFCREG, 14, + "FCR15", LFCREG, 15, + "FCR16", LFCREG, 16, + "FCR17", LFCREG, 17, + "FCR18", LFCREG, 18, + "FCR19", LFCREG, 19, + "FCR20", LFCREG, 20, + "FCR21", LFCREG, 21, + "FCR22", LFCREG, 22, + "FCR23", LFCREG, 23, + "FCR24", LFCREG, 24, + "FCR25", LFCREG, 25, + "FCR26", LFCREG, 26, + "FCR27", LFCREG, 27, + "FCR28", LFCREG, 28, + "FCR29", LFCREG, 29, + "FCR30", LFCREG, 30, + "FCR31", LFCREG, 31, + + "ADD", LTYPE1, AADD, + "ADDU", LTYPE1, AADDU, + "SUB", LTYPE1, ASUB, /* converted to ADD(-) in loader */ + "SUBU", LTYPE1, ASUBU, + "SGT", LTYPE1, ASGT, + "SGTU", LTYPE1, ASGTU, + "AND", LTYPE1, AAND, + "OR", LTYPE1, AOR, + "XOR", LTYPE1, AXOR, + "SLL", LTYPE1, ASLL, + "SRL", LTYPE1, ASRL, + "SRA", LTYPE1, ASRA, + + "ADDV", LTYPE1, AADDV, + "ADDVU", LTYPE1, AADDVU, + "SUBV", LTYPE1, ASUBV, /* converted to ADD(-) in loader */ + "SUBVU", LTYPE1, ASUBVU, + "SLLV", LTYPE1, ASLLV, + "SRLV", LTYPE1, ASRLV, + "SRAV", LTYPE1, ASRAV, + + "NOR", LTYPE2, ANOR, + + "MOVB", LTYPE3, AMOVB, + "MOVBU", LTYPE3, AMOVBU, + "MOVH", LTYPE3, AMOVH, + "MOVHU", LTYPE3, AMOVHU, + "MOVWL", LTYPE3, AMOVWL, + "MOVWR", LTYPE3, AMOVWR, + "MOVVL", LTYPE3, AMOVVL, + "MOVVR", LTYPE3, AMOVVR, + + "BREAK", LTYPEJ, ABREAK, /* overloaded CACHE opcode */ + "END", LTYPE4, AEND, + "REM", LTYPE6, AREM, + "REMU", LTYPE6, AREMU, + "RET", LTYPE4, ARET, + "SYSCALL", LTYPE4, ASYSCALL, + "TLBP", LTYPE4, ATLBP, + "TLBR", LTYPE4, ATLBR, + "TLBWI", LTYPE4, ATLBWI, + "TLBWR", LTYPE4, ATLBWR, + + "MOVW", LTYPE5, AMOVW, + "MOVV", LTYPE5, AMOVV, + "MOVD", LTYPE5, AMOVD, + "MOVF", LTYPE5, AMOVF, + + "DIV", LTYPE6, ADIV, + "DIVU", LTYPE6, ADIVU, + "MUL", LTYPE6, AMUL, + "MULU", LTYPE6, AMULU, + "DIVV", LTYPE6, ADIVV, + "DIVVU", LTYPE6, ADIVVU, + "MULV", LTYPE6, AMULV, + "MULVU", LTYPE6, AMULVU, + + "RFE", LTYPE7, ARFE, + "JMP", LTYPE7, AJMP, + + "JAL", LTYPE8, AJAL, + + "BEQ", LTYPE9, ABEQ, + "BNE", LTYPE9, ABNE, + + "BGEZ", LTYPEA, ABGEZ, + "BGEZAL", LTYPEA, ABGEZAL, + "BGTZ", LTYPEA, ABGTZ, + "BLEZ", LTYPEA, ABLEZ, + "BLTZ", LTYPEA, ABLTZ, + "BLTZAL", LTYPEA, ABLTZAL, + + "TEXT", LTYPEB, ATEXT, + "GLOBL", LTYPEB, AGLOBL, + + "DATA", LTYPEC, ADATA, + + "MOVDF", LTYPE5, AMOVDF, + "MOVDW", LTYPE5, AMOVDW, + "MOVFD", LTYPE5, AMOVFD, + "MOVFW", LTYPE5, AMOVFW, + "MOVWD", LTYPE5, AMOVWD, + "MOVWF", LTYPE5, AMOVWF, + + "ABSD", LTYPED, AABSD, + "ABSF", LTYPED, AABSF, + "ABSW", LTYPED, AABSW, + "NEGD", LTYPED, ANEGD, + "NEGF", LTYPED, ANEGF, + "NEGW", LTYPED, ANEGW, + + "CMPEQD", LTYPEF, ACMPEQD, + "CMPEQF", LTYPEF, ACMPEQF, + "CMPGED", LTYPEF, ACMPGED, + "CMPGEF", LTYPEF, ACMPGEF, + "CMPGTD", LTYPEF, ACMPGTD, + "CMPGTF", LTYPEF, ACMPGTF, + + "ADDD", LTYPEE, AADDD, + "ADDF", LTYPEE, AADDF, + "ADDW", LTYPEE, AADDW, + "DIVD", LTYPEE, ADIVD, + "DIVF", LTYPEE, ADIVF, + "DIVW", LTYPEE, ADIVW, + "MULD", LTYPEE, AMULD, + "MULF", LTYPEE, AMULF, + "MULW", LTYPEE, AMULW, + "SUBD", LTYPEE, ASUBD, + "SUBF", LTYPEE, ASUBF, + "SUBW", LTYPEE, ASUBW, + + "BFPT", LTYPEG, ABFPT, + "BFPF", LTYPEG, ABFPF, + + "WORD", LTYPEH, AWORD, + "NOP", LTYPEI, ANOP, + "SCHED", LSCHED, 0, + "NOSCHED", LSCHED, 0x80, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.sym = S; + nullgen.offset = 0; + nullgen.type = D_NONE; + nullgen.name = D_NONE; + nullgen.reg = NREG; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 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); + s->type = itab[i].type; + s->value = itab[i].value; + } + + pathname = alloc(100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } +} + +void +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +int +isreg(Gen *g) +{ + + USED(g); + return 1; +} + +void +cclean(void) +{ + + outcode(AEND, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + 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; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + case D_MREG: + case D_FCREG: + case D_LO: + case D_HI: + break; + + case D_OREG: + case D_CONST: + case D_OCONST: + case D_BRANCH: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(&obuf, *n); + n++; + } + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +void +outcode(int a, Gen *g1, int reg, Gen *g2) +{ + int sf, st, t; + Sym *s; + + if(pass == 1) + goto out; +jackpot: + sf = 0; + s = g1->sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g1->name; + 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->sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->name; + 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, reg|nosched); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, sf); + zaddr(g2, 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, 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, 0); + 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" diff --git a/utils/0a/mkfile b/utils/0a/mkfile new file mode 100644 index 00000000..1c1a88c7 --- /dev/null +++ b/utils/0a/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=0a + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../vc/v.out.h\ + y.tab.h\ + a.h\ + +YFILES= a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/0c/cgen.c b/utils/0c/cgen.c new file mode 100644 index 00000000..e77c2114 --- /dev/null +++ b/utils/0c/cgen.c @@ -0,0 +1,1148 @@ +#include "gc.h" + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o; + long v, curs; + + if(debug['g']) { + prtree(nn, "cgen lhs"); + prtree(n, "cgen"); + } + if(n == Z || n->type == T) + return; + if(typesu[n->type->etype]) { + sugen(n, nn, n->type->width); + return; + } + if(n->addable > INDEXED) { + if(nn != Z) + gmove(n, nn); + return; + } + curs = cursafe; + l = n->left; + r = n->right; + o = n->op; + + if(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED && l->complex < FNX) { + 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) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OADD: + case OSUB: + case OAND: + case OOR: + case OXOR: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(l, nn); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OLMUL: + case OLDIV: + case OLMOD: + case OMUL: + case ODIV: + case OMOD: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, &nod1, Z, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, n, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } else { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + + regalloc(&nod, n, nn); + gmove(&nod2, &nod); + gopcode(o, &nod1, Z, &nod); + gmove(&nod, &nod2); + if(nn != Z) + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + 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); + gopcode(o, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + 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); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type)) { + if(nocast(n->type, nn->type)) { + cgen(l, nn); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (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(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; + return; +} + +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; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, "boolgen"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + regalloc(&nod, n, nn); + cgen(n, &nod); + if(nn == Z || typefd[n->type->etype]) { + o = ONE; + if(true) + o = comrel[relindex(o)]; + if(typefd[n->type->etype]) { + nodreg(&nod1, n, NREG+FREGZERO); + gopcode(o, &nod, &nod1, Z); + } else + gopcode(o, &nod, Z, Z); + regfree(&nod); + goto com; + } + if(true) + gopcode(OCOND, &nod, nodconst(0), &nod); + else + gopcode(OCOND, nodconst(1), &nod, &nod); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + 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(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(nn != Z && !typefd[l->type->etype]) { + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + switch(o) { + case OEQ: + gopcode(OSUB, &nod1, &nod, &nod); + gopcode(OCOND, &nod, nodconst(0), &nod); + break; + case ONE: + gopcode(OSUB, &nod1, &nod, &nod); + gopcode(OCOND, nodconst(1), &nod, &nod); + break; + case OLE: + gopcode(OCOMMA, &nod1, &nod, &nod); + break; + case OGT: + gopcode(OCOMMA, &nod1, &nod, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OLT: + gopcode(OCOMMA, &nod, &nod1, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OGE: + gopcode(OCOMMA, &nod, &nod1, &nod); + break; + case OLS: + gopcode(OCOND, &nod1, &nod, &nod); + break; + case OHI: + gopcode(OCOND, &nod1, &nod, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OLO: + gopcode(OCOND, &nod, &nod1, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OHS: + gopcode(OCOND, &nod, &nod1, &nod); + break; + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + } + if(sconst(l)) { + switch(o) { + default: + if(l->vconst != 0) + break; + + case OGT: + case OHI: + case OLE: + case OLS: + regalloc(&nod, r, nn); + cgen(r, &nod); + gopcode(o, l, &nod, Z); + regfree(&nod); + goto com; + } + } + if(sconst(r)) { + switch(o) { + default: + if(r->vconst != 0) + break; + + case OGE: + case OHS: + case OLT: + case OLO: + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod, r, Z); + regfree(&nod); + goto com; + } + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + gopcode(o, &nod1, &nod, Z); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && nn->complex >= FNX) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + 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; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TVLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + + t = nn->type; + nn->type = types[TVLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TVLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + + t = n->type; + n->type = types[TVLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + } + + w /= SZ_VLONG; + if(w <= 5) { + layout(&nod1, &nod2, w, 0, Z); + goto out; + } + + /* + * minimize space for unrolling loop + * 3,4,5 times. (6 or more is never minimum) + * if small structure, try 2 also. + */ + c = 0; /* set */ + m = 100; + i = 3; + if(w <= 15) + i = 2; + for(; i<=5; i++) + if(i + w%i <= m) { + c = i; + m = c + w%c; + } + + regalloc(&nod3, ®node, Z); + layout(&nod1, &nod2, w%c, w/c, &nod3); + + pc1 = pc; + layout(&nod1, &nod2, c, 0, Z); + + gopcode(OSUB, nodconst(1), Z, &nod3); + nod1.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_VLONG), Z, &nod1); + nod2.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_VLONG), Z, &nod2); + + gopcode(OEQ, &nod3, Z, Z); + p->as = ABGTZ; + patch(p, pc1); + + regfree(&nod3); +out: + regfree(&nod1); + regfree(&nod2); +} + +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, ®node, Z); + regalloc(&t2, ®node, Z); + t1.type = types[TVLONG]; + t2.type = types[TVLONG]; + if(c > 0) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_VLONG; + } + if(cn != Z) + gopcode(OAS, nodconst(cv), Z, cn); + if(c > 1) { + gopcode(OAS, f, Z, &t2); + f->xoffset += SZ_VLONG; + } + if(c > 0) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_VLONG; + } + if(c > 2) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_VLONG; + } + if(c > 1) { + gopcode(OAS, &t2, Z, t); + t->xoffset += SZ_VLONG; + } + if(c > 2) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_VLONG; + } + regfree(&t1); + regfree(&t2); +} diff --git a/utils/0c/enam.c b/utils/0c/enam.c new file mode 100644 index 00000000..f9c94f7f --- /dev/null +++ b/utils/0c/enam.c @@ -0,0 +1,118 @@ +char* anames[] = +{ + "XXX", + "ABSD", + "ABSF", + "ABSW", + "ADD", + "ADDD", + "ADDF", + "ADDU", + "ADDW", + "AND", + "BEQ", + "BFPF", + "BFPT", + "BGEZ", + "BGEZAL", + "BGTZ", + "BLEZ", + "BLTZ", + "BLTZAL", + "BNE", + "BREAK", + "CMPEQD", + "CMPEQF", + "CMPGED", + "CMPGEF", + "CMPGTD", + "CMPGTF", + "DATA", + "DIV", + "DIVD", + "DIVF", + "DIVU", + "DIVW", + "GLOBL", + "GOK", + "HISTORY", + "JAL", + "JMP", + "MOVB", + "MOVBU", + "MOVD", + "MOVDF", + "MOVDW", + "MOVF", + "MOVFD", + "MOVFW", + "MOVH", + "MOVHU", + "MOVW", + "MOVWD", + "MOVWF", + "MOVWL", + "MOVWR", + "MUL", + "MULD", + "MULF", + "MULU", + "MULW", + "NAME", + "NEGD", + "NEGF", + "NEGW", + "NOP", + "NOR", + "OR", + "REM", + "REMU", + "RET", + "RFE", + "SGT", + "SGTU", + "SLL", + "SRA", + "SRL", + "SUB", + "SUBD", + "SUBF", + "SUBU", + "SUBW", + "SYSCALL", + "TEXT", + "TLBP", + "TLBR", + "TLBWI", + "TLBWR", + "WORD", + "XOR", + "END", + "MOVV", + "MOVVL", + "MOVVR", + "SLLV", + "SRAV", + "SRLV", + "DIVV", + "DIVVU", + "REMV", + "REMVU", + "MULV", + "MULVU", + "ADDV", + "ADDVU", + "SUBV", + "SUBVU", + "DYNT", + "INIT", + "BCASE", + "CASE", + "TRUNCFV", + "TRUNCDV", + "TRUNCFW", + "TRUNCDW", + "MOVWU", + "SIGNAME", + "LAST", +}; diff --git a/utils/0c/gc.h b/utils/0c/gc.h new file mode 100644 index 00000000..88196aec --- /dev/null +++ b/utils/0c/gc.h @@ -0,0 +1,332 @@ +#include "../cc/cc.h" +#include "../vc/v.out.h" + +/* + * 0c/spim + * Mips 4000 little endian + */ +#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 Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + +struct Adr +{ + long offset; + double dval; + vlong vval; + char sval[NSNAME]; + Ieee ieee; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + char as; + char reg; +}; +#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 Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +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) + +#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 Multab multab[20]; +EXTERN int retok; +EXTERN int hintabsize; +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 char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[NREG+NREG]; +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 4 +#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 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[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void xcom(Node*); +void bcomplex(Node*); +void usedset(Node*, int); + +/* + * cgen.c + */ +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nodfconst(double); +void nodreg(Node*, 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 raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int llconst(Node*); +int sval(long); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(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 Nconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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 regzer(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 copyau1(Prog*, 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); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/0c/list.c b/utils/0c/list.c new file mode 100644 index 00000000..f89b17ca --- /dev/null +++ b/utils/0c/list.c @@ -0,0 +1,244 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('B', Bconv); + fmtinstall('D', Dconv); +} + +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; + int a; + + p = va_arg(fp->args, Prog*); + a = p->as; + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FCREG: + sprint(str, "FCR%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_LO: + sprint(str, "LO"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(LO)(REG)", a); + break; + + case D_HI: + sprint(str, "HI"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(HI)(REG)", a); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<NSNAME; i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/0c/mkenam b/utils/0c/mkenam new file mode 100644 index 00000000..f09ef75d --- /dev/null +++ b/utils/0c/mkenam @@ -0,0 +1,15 @@ +ed - ../vc/v.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/utils/0c/mkfile b/utils/0c/mkfile new file mode 100644 index 00000000..6b722243 --- /dev/null +++ b/utils/0c/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=0c + +OFILES= cgen.$O\ + enam.$O\ + list.$O\ + peep.$O\ + reg.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + mul.$O\ + +HFILES= gc.h\ + v.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/0c/mul.c b/utils/0c/mul.c new file mode 100644 index 00000000..3ef56cd5 --- /dev/null +++ b/utils/0c/mul.c @@ -0,0 +1,608 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ +}; + +Multab* +mulcon0(long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; g<nelem(multab); g++) { + if(m->val == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=6; g++) { + if(g >= 6 && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<<c, r1)) + goto out; + break; + case 1: + if(docode(hp, cp, r1<<c, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r0, r0<<c)) + goto out; + break; + case 3: + if(docode(hp, cp, r0, r1<<c)) + goto out; + break; + } + } + break; + + case '+': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0+r1, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0+r1)) + goto out; + break; + } + } + break; + + case '-': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0-r1, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r1-r0, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0-r1)) + goto out; + break; + case 6: + if(docode(hp, cp, r0, r1-r0)) + goto out; + break; + } + } + break; + + case 0: + if(r0 == mulval) + return 1; + } + return 0; + +out: + cp[-1] = i+'0'; + return 1; +} + +static int +gen1(int len) +{ + int i; + + for(shmax=1; shmax<30; shmax++) { + valmax = 1<<shmax; + if(valmax >= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<<i)) { + *--mulcp = 'a'+i; + return 1; + } + return 0; +} + +static int +gen2(int len, long r1) +{ + int i; + + if(len <= 0) { + if(r1 == mulval) + return 1; + return 0; + } + + len--; + if(len == 0) + goto calcr0; + + if(gen3(len, r1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, r1-1, r1, UR0)) { + i = '-'; + goto out; + } + if(gen3(len, 1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, 1, r1-1, UR1)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + if(mulval == r1+1) { + i = '+'; + goto out; + } + if(mulval == r1-1) { + i = '-'; + goto out; + } + return 0; + +out: + *--mulcp = i; + return 1; +} + +static int +gen3(int len, long r0, long r1, int flag) +{ + int i, f1, f2; + long x; + + if(r0 <= 0 || + r0 >= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x >= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/0c/peep.c b/utils/0c/peep.c new file mode 100644 index 00000000..a9a43da4 --- /dev/null +++ b/utils/0c/peep.c @@ -0,0 +1,694 @@ +#include "gc.h" + +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; + } + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) + if(regtyp(&p->to)) { + if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + if(regzer(&p->from)) + if(p->to.type == D_REG) { + p->from.type = D_REG; + p->from.reg = 0; + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +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 +regzer(Adr *a) +{ + + if(a->type == D_CONST) + if(a->sym == S) + if(a->offset == 0) + return 1; + if(a->type == D_REG) + if(a->reg == 0) + return 1; + return 0; +} + +int +regtyp(Adr *a) +{ + + if(a->type == D_REG) { + if(a->reg != 0) + return 1; + return 0; + } + if(a->type == D_FREG) + 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 AJAL: + return 0; + + case ASGT: + case ASGTU: + + case AADD: + case AADDU: + case ASUB: + case ASUBU: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case AMULU: + case ADIV: + case ADIVU: + + case AADDD: + case AADDF: + case ASUBD: + case ASUBF: + case AMULD: + case AMULF: + case ADIVD: + case ADIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AMOVF: + case AMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +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("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * 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) + */ +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print(" (???)"); + return 2; + + + case ANOP: /* read, write */ + case AMOVW: + case AMOVF: + case AMOVD: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + case AMOVDW: + case AMOVWD: + case AMOVFD: + case AMOVDF: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ASGT: /* read, read, write */ + case ASGTU: + + case AADD: + case AADDU: + case ASUB: + case ASUBU: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case ANOR: + case AAND: + case AXOR: + case AMUL: + case AMULU: + case ADIV: + case ADIVU: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: /* read, read */ + case ABNE: + case ABGTZ: + case ABGEZ: + case ABLTZ: + case ABLEZ: + + case ACMPEQD: + case ACMPEQF: + case ACMPGED: + case ACMPGEF: + case ACMPGTD: + case ACMPGTF: + case ABFPF: + case ABFPT: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub1(p, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + return 0; + + case 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 == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case AJAL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(REGARG && v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) + if(v->reg <= FREGEXT && v->reg > exfregoffset) + 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; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } + return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + case ABEQ: + case ABNE: + case ABGTZ: + case ABGEZ: + case ABLTZ: + case ABLEZ: + + case ASGT: + case ASGTU: + + case AADD: + case AADDU: + case ASUB: + case ASUBU: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case AMULU: + case ADIV: + case ADIVU: + return D_REG; + + case ACMPEQD: + case ACMPEQF: + case ACMPGED: + case ACMPGEF: + case ACMPGTD: + case ACMPGTF: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) + if(a->type == D_OREG) + if(v->reg == a->reg) + return 1; + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) + if(p->from.type == v->type || p->to.type == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) + a->reg = s->reg; + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} diff --git a/utils/0c/reg.c b/utils/0c/reg.c new file mode 100644 index 00000000..0ed8d696 --- /dev/null +++ b/utils/0c/reg.c @@ -0,0 +1,1151 @@ +#include "gc.h" + +void addsplits(void); + +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 = 0; + 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 ARFE: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW); + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + case AMOVW: + case AMOVV: + case AMOVF: + case AMOVD: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case AJAL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + 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); + + /* + * 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; + + addsplits(); + + if(debug['R'] && debug['v']) { + print("\nprop 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->set.b[z] | + r->refahead.b[z] | r->calahead.b[z] | + r->refbehind.b[z] | r->calbehind.b[z] | + r->use1.b[z] | r->use2.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); + if(bany(&r->refahead)) + print(" ra=%B", r->refahead); + if(bany(&r->calahead)) + print(" ca=%B", r->calahead); + if(bany(&r->refbehind)) + print(" rb=%B", r->refbehind); + if(bany(&r->calbehind)) + print(" cb=%B", r->calbehind); + } + print("\n"); + } + } + + /* + * 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); + } + } + + for(r = firstr; r != R; r = r->link) + r->act = zbits; + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + 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']) { + if(rgp->regno >= NREG) + print("%L $%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L $%d R%d: %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; + } +} + +void +addsplits(void) +{ + Reg *r, *r1; + int z, i; + Bits bit; + + for(r = firstr; r != R; r = r->link) { + if(r->loop > 1) + continue; + if(r->prog->as == AJAL) + continue; + for(r1 = r->p2; r1 != R; r1 = r1->p2link) { + if(r1->loop <= 1) + continue; + for(z=0; z<BITS; z++) + bit.b[z] = r1->calbehind.b[z] & + (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & + ~(r->calahead.b[z] & addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + } + } + } +} + +/* + * 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->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TVLONG || v->etype == TUVLONG) + p1->as = AMOVV; + if(v->etype == TFLOAT) + p1->as = AMOVF; + if(v->etype == TDOUBLE) + p1->as = AMOVD; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBU; + if(v->etype == TUSHORT) + p1->as = AMOVHU; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + + n = a->name; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = et; + v->name = n; + 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]/* || typev[et]*/)) /* funny punning */ + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + if(t == D_CONST) { + if(s == S) { + for(z=0; z<BITS; z++) + consts.b[z] |= bit.b[z]; + return bit; + } + if(et != TARRAY) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + return bit; + } + if(t == D_OREG) + 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 AJAL: + 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 TVLONG: + case TUVLONG: + case TIND: + case TARRAY: + i = BtoR(~b); + if(i && r->cost >= 0) { + r->regno = i; + return RtoB(i); + } + break; + + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i && r->cost >= 0) { + r->regno = i+NREG; + return FtoB(i); + } + 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(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(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(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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + 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->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * bit reg + * 0 R3 + * 1 R4 + * ... ... + * 19 R22 + * 20 R23 + */ +long +RtoB(int r) +{ + + if(r < 3 || r > 23) + return 0; + return 1L << (r-3); +} + +BtoR(long b) +{ + + b &= 0x001fffffL; + if(b == 0) + return 0; + return bitno(b) + 3; +} + +/* + * bit reg + * 22 F4 + * 23 F6 + * ... ... + * 31 F22 + */ +long +FtoB(int f) +{ + + if(f < 4 || f > 22 || (f&1)) + return 0; + return 1L << (f/2 + 20); +} + +int +BtoF(long b) +{ + + b &= 0xffc00000L; + if(b == 0) + return 0; + return bitno(b)*2 - 40; +} diff --git a/utils/0c/sgen.c b/utils/0c/sgen.c new file mode 100644 index 00000000..eb562e8f --- /dev/null +++ b/utils/0c/sgen.c @@ -0,0 +1,569 @@ +#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)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typesu[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gopcode(OAS, &nod, Z, &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); + gopcode(OAS, &nod, Z, &nod1); + } + } + + 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); + gbranch(ORETURN); + + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); + + sp->to.offset += maxargsafe; +} + +void +gen(Node *n) +{ + Node *l, nod; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int 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); + gbranch(ORETURN); + break; + } + if(typesu[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->pc = 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; + } + gbranch(OGOTO); + if(n->pc) { + patch(p, n->pc); + 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); /* 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); + 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; + bcomplex(l); + 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 = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int t; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + + case OASLMUL: + case OASMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASASHL; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASHL; + r->vconst = t; + r->type = types[TINT]; + } + t = vlog(l); + if(t >= 0) { + n->op = OASHL; + n->left = r; + n->right = l; + r = l; + l = n->left; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + switch(n->op) { + case OFUNC: + n->complex = FNX; + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + case OEQ: + case ONE: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + } +} + +void +bcomplex(Node *n) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type != T) + boolgen(n, 1, Z); + else + gbranch(OGOTO); +} diff --git a/utils/0c/swt.c b/utils/0c/swt.c new file mode 100644 index 00000000..38cd3d43 --- /dev/null +++ b/utils/0c/swt.c @@ -0,0 +1,727 @@ +#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; + Node tn; + + 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); + regalloc(&tn, ®node, Z); + swit1(iq, nc, def, n, &tn); + regfree(&tn); +} + +void +swit1(C1 *q, int nc, long def, Node *n, Node *tn) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; i<nc; i++) { + if(debug['W']) + print("case = %.8lux\n", q->val); + gmove(nodconst(q->val), tn); + gopcode(OEQ, n, tn, Z); + 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); + gmove(nodconst(r->val), tn); + gopcode(OLT, tn, n, Z); + sp = p; + gopcode(OEQ, n, tn, Z); + patch(p, r->label); + swit1(q, i, def, n, tn); + + if(debug['W']) + print("case < %.8lux\n", r->val); + patch(sp, pc); + swit1(r+1, nc-i-1, def, n, tn); +} + +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); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, nodconst(0L)); + p->from.offset += nstring - NSNAME; + p->reg = NSNAME; + p->to.type = D_SCONST; + memmove(p->to.sval, string, NSNAME); + mnstring = 0; + } + n--; + } + return r; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + 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; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + if(debug['M'] && debug['v']) + print("%L multiply: %ld\n", n->lineno, v); + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + if(v < 0) + gopcode(OSUB, &nod1, nodconst(0), &nod1); + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +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(0)); + p->from.offset += o+e; + p->reg = 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, nodconst(a->vconst)); + p->from.offset += o; + p->reg = 4; + gpseudo(ADATA, s, nodconst(a->vconst>>32)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + + bf[0] = p->as; + bf[1] = p->reg; + bf[2] = p->lineno; + bf[3] = p->lineno>>8; + bf[4] = p->lineno>>16; + bf[5] = p->lineno>>24; + bp = zaddr(bf+6, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + 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++; + } + } + outhist(&outbuf); + 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.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, 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.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + 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, 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; + + zwrite(b, &pg, 0, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n, bf[7]; + ulong sig; + + n = s->name; + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); + s->sig = SIGDONE; + } + else{ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); + } + Bwrite(b, n, strlen(n)+1); +} + +char* +zaddr(char *bp, Adr *a, int s) +{ + vlong v; + long l; + Ieee e; + + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_MREG: + case D_FCREG: + case D_LO: + case D_HI: + break; + + case D_CONST: + case D_OREG: + case D_BRANCH: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + case D_VCONST: + v = a->vval; + bp[0] = v; + bp[1] = v>>8; + bp[2] = v>>16; + bp[3] = v>>24; + bp[4] = v>>32; + bp[5] = v>>40; + bp[6] = v>>48; + bp[7] = v>>56; + bp += 8; + break; + } + return bp; +} + +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_VLONG; + 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_VLONG) + w = SZ_VLONG; + 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(typesu[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_VLONG) { + w = SZ_VLONG; + 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_VLONG-1; + if(v > max) + max = round(v, SZ_VLONG); + return max; +} diff --git a/utils/0c/txt.c b/utils/0c/txt.c new file mode 100644 index 00000000..964db985 --- /dev/null +++ b/utils/0c/txt.c @@ -0,0 +1,1483 @@ +#include "gc.h" + +void +ginit(void) +{ + int i; + Type *t; + + thechar = '0'; + thestring = "spim"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + 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.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMP; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + 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); + + for(i=0; i<nelem(reg); i++) { + reg[i] = 0; + if(i == REGZERO || + (i >= NREG && ((i-NREG)&1))) + reg[i] = 1; + } +} + +void +gclean(void) +{ + int i; + Sym *s; + + for(i=0; i<NREG; i++) + if(i != REGZERO) + if(reg[i]) + diag(Z, "reg %d left allocated", i); + for(i=NREG; i<NREG+NREG; i+=2) + if(reg[i]) + diag(Z, "freg %d left allocated", i-NREG); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + 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; +} + +void +garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) +{ + Node nod; + + if(n == Z) + return; + if(n->op == OLIST) { + garg1(n->left, tn1, tn2, f, fnxp); + garg1(n->right, tn1, tn2, f, fnxp); + return; + } + if(f == 0) { + if(n->complex >= FNX) { + regsalloc(*fnxp, n); + nod = znode; + nod.op = OAS; + nod.left = *fnxp; + nod.right = n; + nod.type = n->type; + cgen(&nod, Z); + (*fnxp)++; + } + return; + } + if(typesu[n->type->etype]) { + regaalloc(tn2, n); + if(n->complex >= FNX) { + sugen(*fnxp, tn2, n->type->width); + (*fnxp)++; + } else + sugen(n, tn2, n->type->width); + return; + } + if(REGARG && curarg == 0 && typechlp[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + if(vconst(n) == 0) { + regaalloc(tn2, n); + gopcode(OAS, n, Z, tn2); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +int +tmpreg(void) +{ + int i; + + for(i=REGRET+1; i<NREG; i++) + if(reg[i] == 0) + return i; + diag(Z, "out of fixed registers"); + return 0; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i, j; + static int lasti; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TUVLONG: + case TVLONG: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i > 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<NREG; i++) { + if(j >= NREG) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NREG) + goto out; + } + j = 0*2 + NREG; + for(i=NREG; i<NREG+NREG; i+=2) { + if(j >= NREG+NREG) + j = NREG; + if(reg[j] == 0) { + i = j; + goto out; + } + j += 2; + } + diag(tn, "out of float registers"); + goto err; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + i = 0; +out: + if(i) + reg[i]++; + lasti++; + if(lasti >= 5) + lasti = 0; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + 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 + SZ_VLONG; + 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 +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: <null>"); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else + if(llconst(n)) { + a->type = D_VCONST; + a->vval = n->vconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +fop(int as, int f1, int f2, Node *t) +{ + Node nod1, nod2, nod3; + + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod; + Prog *p1; + double d; + + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + d = f->fconst; + if(d == 0.0) { + a = FREGZERO; + goto ffreg; + } + if(d == 0.5) { + a = FREGHALF; + goto ffreg; + } + if(d == 1.0) { + a = FREGONE; + goto ffreg; + } + if(d == 2.0) { + a = FREGTWO; + goto ffreg; + } + if(d == -.5) { + fop(OSUB, FREGHALF, FREGZERO, t); + return; + } + if(d == -1.0) { + fop(OSUB, FREGONE, FREGZERO, t); + return; + } + if(d == -2.0) { + fop(OSUB, FREGTWO, FREGZERO, t); + return; + } + if(d == 1.5) { + fop(OADD, FREGONE, FREGHALF, t); + return; + } + if(d == 2.5) { + fop(OADD, FREGTWO, FREGHALF, t); + return; + } + if(d == 3.0) { + fop(OADD, FREGTWO, FREGONE, t); + return; + } + } + if(ft == TFLOAT && f->op == OCONST) { + d = f->fconst; + if(d == 0) { + a = FREGZERO; + ffreg: + nodreg(&nod, f, NREG+a); + gmove(&nod, t); + return; + } + } + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + if(typefd[tt]) { + /* special case can load mem to Freg */ + regalloc(&nod, t, t); + gins(AMOVW, f, &nod); + a = AMOVWD; + if(tt == TFLOAT) + a = AMOVWF; + gins(a, &nod, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + a = AMOVW; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TUVLONG: + case TVLONG: + a = AMOVV; + break; + } + if(typechlp[ft] && typeilp[tt]) + regalloc(&nod, t, t); + else + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + a = AMOVBU; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHU; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TUVLONG: + case TVLONG: + a = AMOVV; + break; + } + if(!typefd[ft] && vconst(f) == 0) { + gins(a, f, t); + return; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TUVLONG: + case TVLONG: + switch(tt) { + case TUVLONG: + case TVLONG: + a = AMOVV; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + case TDOUBLE: + gins(AMOVW, f, t); + gins(AMOVWD, t, t); + if(ft == TULONG || ft == TUINT) { + regalloc(&nod, t, Z); + gins(ACMPGED, t, Z); + p->reg = FREGZERO; + gins(ABFPT, Z, Z); + p1 = p; + gins(AMOVD, nodfconst(4294967296.), &nod); + gins(AADDD, &nod, t); + patch(p1, pc); + regfree(&nod); + } + return; + case TFLOAT: + gins(AMOVW, f, t); + gins(AMOVWF, t, t); + if(ft == TULONG || ft == TUINT) { + regalloc(&nod, t, Z); + gins(ACMPGEF, t, Z); + p->reg = FREGZERO; + gins(ABFPT, Z, Z); + p1 = p; + gins(AMOVF, nodfconst(4294967296.), &nod); + gins(AADDF, &nod, t); + patch(p1, pc); + regfree(&nod); + } + return; + } + break; + case TDOUBLE: + case TFLOAT: + switch(tt) { + case TDOUBLE: + a = AMOVD; + if(ft == TFLOAT) + a = AMOVFD; + break; + case TFLOAT: + a = AMOVDF; + if(ft == TFLOAT) + a = AMOVF; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + regalloc(&nod, f, Z); + gins(ATRUNCDW, f, &nod); + if(ft == TFLOAT) + p->as = ATRUNCFW; + gins(AMOVW, &nod, t); + regfree(&nod); + return; + case TUVLONG: + case TVLONG: + regalloc(&nod, f, Z); + gins(ATRUNCDV, f, &nod); + if(ft == TFLOAT) + p->as = ATRUNCFV; + gins(AMOVV, &nod, t); + regfree(&nod); + return; + } + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + switch(tt) { + case TDOUBLE: + gins(AMOVW, f, t); + gins(AMOVWD, t, t); + if(ft == TULONG || ft == TUINT) { + regalloc(&nod, t, Z); + gins(ACMPGED, t, Z); + p->reg = FREGZERO; + gins(ABFPT, Z, Z); + p1 = p; + gins(AMOVD, nodfconst(4294967296.), &nod); + gins(AADDD, &nod, t); + patch(p1, pc); + regfree(&nod); + } + return; + case TFLOAT: + gins(AMOVW, f, t); + gins(AMOVWF, t, t); + if(ft == TULONG || ft == TUINT) { + regalloc(&nod, t, Z); + gins(ACMPGEF, t, Z); + p->reg = FREGZERO; + gins(ABFPT, Z, Z); + p1 = p; + gins(AMOVF, nodfconst(4294967296.), &nod); + gins(AADDF, &nod, t); + patch(p1, pc); + regfree(&nod); + } + return; + case TUVLONG: + case TVLONG: + if(ft == TULONG || ft == TUINT) { + a = AMOVWU; + break; + } + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TSHORT: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AMOVF || a == AMOVD || a == AMOVV) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, et, ett; + Adr ta; + Node nod; + + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + ett = TLONG; + if(t != Z && t->type != T) + ett = t->type->etype; + if(llconst(f1) && o != OAS) { + regalloc(&nod, f1, Z); + gmove(f1, &nod); + gopcode(o, &nod, f2, t); + regfree(&nod); + return; + } + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = AADDU; + if(et == TVLONG || et == TUVLONG) + a = AADDVU; + else + if(et == TFLOAT) + a = AADDF; + else + if(et == TDOUBLE) + a = AADDD; + break; + + case OASSUB: + case OSUB: + a = ASUBU; + if(et == TVLONG || et == TUVLONG) + a = ASUBVU; + else + if(et == TFLOAT) + a = ASUBF; + else + if(et == TDOUBLE) + a = ASUBD; + break; + + case OASOR: + case OOR: + a = AOR; + break; + + case OASAND: + case OAND: + a = AAND; + break; + + case OASXOR: + case OXOR: + a = AXOR; + break; + + case OASLSHR: + case OLSHR: + a = ASRL; + if(ett == TVLONG || ett == TUVLONG) + a = ASRLV; + break; + + case OASASHR: + case OASHR: + a = ASRA; + if(ett == TVLONG || ett == TUVLONG) + a = ASRAV; + break; + + case OASASHL: + case OASHL: + a = ASLL; + if(ett == TVLONG || ett == TUVLONG) + a = ASLLV; + break; + + case OFUNC: + a = AJAL; + break; + + case OCOND: + a = ASGTU; + break; + + case OCOMMA: + a = ASGT; + break; + + case OASMUL: + case OMUL: + if(et == TFLOAT) { + a = AMULF; + break; + } else + if(et == TDOUBLE) { + a = AMULD; + break; + } + a = AMUL; + if(et == TVLONG || et == TUVLONG) + a = AMULV; + goto muldiv; + + case OASDIV: + case ODIV: + if(et == TFLOAT) { + a = ADIVF; + break; + } else + if(et == TDOUBLE) { + a = ADIVD; + break; + } + a = ADIV; + if(et == TVLONG || et == TUVLONG) + a = ADIVV; + goto muldiv; + + case OASMOD: + case OMOD: + a = ADIV; + o = OMOD; + if(et == TVLONG || et == TUVLONG) + a = ADIVV; + goto muldiv; + + case OASLMUL: + case OLMUL: + a = AMULU; + if(et == TVLONG || et == TUVLONG) + a = AMULVU; + goto muldiv; + + case OASLMOD: + case OLMOD: + o = OMOD; + + case OASLDIV: + case OLDIV: + a = ADIVU; + if(et == TVLONG || et == TUVLONG) + a = ADIVVU; + goto muldiv; + + muldiv: + nextpc(); + naddr(f1, &p->from); + if(f2 == Z) + raddr(t, p); + else + raddr(f2, p); + p->as = a; + if(debug['g']) + print("%P\n", p); + nextpc(); + p->as = AMOVW; + if(et == TVLONG || et == TUVLONG) + p->as = AMOVV; + a = D_LO; + if(o == OMOD) + a = D_HI; + p->from.type = a; + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); + return; + + case OEQ: + if(!typefd[et]) { + a = ABEQ; + break; + } + + case ONE: + if(!typefd[et]) { + a = ABNE; + break; + } + + case OLT: + case OLE: + case OGE: + case OGT: + if(typefd[et]) { + nextpc(); + if(et == TFLOAT) { + a = ACMPGTF; + if(o == OEQ || o == ONE) + a = ACMPEQF; + else + if(o == OLT || o == OGE) + a = ACMPGEF; + } else { + a = ACMPGTD; + if(o == OEQ || o == ONE) + a = ACMPEQD; + else + if(o == OLT || o == OGE) + a = ACMPGED; + } + p->as = a; + naddr(f1, &p->from); + raddr(f2, p); + if(debug['g']) + print("%P\n", p); + nextpc(); + a = ABFPF; + if(o == OEQ || o == OGE || o == OGT) + a = ABFPT; + p->as = a; + if(debug['g']) + print("%P\n", p); + return; + } + if(vconst(f1) == 0 || vconst(f2) == 0) { + if(vconst(f1) == 0) { + o = invrel[relindex(o)]; + f1 = f2; + } + switch(o) { + case OLT: + a = ABLTZ; + break; + case OLE: + a = ABLEZ; + break; + case OGE: + a = ABGEZ; + break; + case OGT: + a = ABGTZ; + break; + } + f2 = Z; + break; + } + + case OLO: + case OLS: + case OHS: + case OHI: + nextpc(); + if(o == OLE || o == OGT || o == OLS || o == OHI) { + naddr(f1, &p->from); + raddr(f2, p); + } else { + naddr(f2, &p->from); + raddr(f1, p); + } + naddr(®node, &p->to); + p->to.reg = tmpreg(); + a = ASGT; + if(o == OLO || o == OLS || o == OHS || o == OHI) + a = ASGTU; + p->as = a; + if(debug['g']) + print("%P\n", p); + + nextpc(); + naddr(®node, &p->from); + p->from.reg = tmpreg(); + a = ABEQ; + if(o == OLT || o == OGT || o == OLO || o == OHI) + a = ABNE; + p->as = a; + if(debug['g']) + print("%P\n", p); + return; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + if(ta.type == D_CONST && ta.offset == 0) + p->reg = REGZERO; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +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_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= (vlong)-32766 && vv < (vlong)32766) + return 1; + } + } + return 0; +} + +int +llconst(Node *n) +{ + vlong vv; + + if(n != Z && n->op == OCONST) { + if(typev[n->type->etype]) { + vv = n->vconst >> 32; + if(vv != 0 && vv != -1) + return 1; + } + } + return 0; +} + +int +sval(long v) +{ + if(v >= -32766L && v < 32766L) + return 1; + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= 16) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 16) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /*[TXXX]*/ + SZ_CHAR, /*[TCHAR]*/ + SZ_CHAR, /*[TUCHAR]*/ + SZ_SHORT, /*[TSHORT]*/ + SZ_SHORT, /*[TUSHORT]*/ + SZ_INT, /*[TINT]*/ + SZ_INT, /*[TUINT]*/ + SZ_LONG, /*[TLONG]*/ + SZ_LONG, /*[TULONG]*/ + SZ_VLONG, /*[TVLONG]*/ + SZ_VLONG, /*[TUVLONG]*/ + SZ_FLOAT, /*[TFLOAT]*/ + SZ_DOUBLE, /*[TDOUBLE]*/ + SZ_IND, /*[TIND]*/ + 0, /*[TFUNC]*/ + -1, /*[TARRAY]*/ + 0, /*[TVOID]*/ + -1, /*[TSTRUCT]*/ + -1, /*[TUNION]*/ + SZ_INT, /*[TENUM]*/ +}; +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]*/ +}; diff --git a/utils/0c/v.out.h b/utils/0c/v.out.h new file mode 100644 index 00000000..2fec2893 --- /dev/null +++ b/utils/0c/v.out.h @@ -0,0 +1,201 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 32 + +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +#define REGZERO 0 +#define REGRET 1 +#define REGARG 1 +/* compiler allocates R1 up as temps */ +/* compiler allocates register variables R3-R23 */ +#define REGEXT 25 +/* compiler allocates external registers R25 down */ +/* dont use R26 R27 */ +#define REGTMP 28 +#define REGSP 29 +#define REGSB 30 +#define REGLINK 31 + +#define FREGRET 0 +/* compiler allocates register variables F4-F22 */ +/* compiler allocates external registers F22 down */ +#define FREGEXT 22 +#define FREGZERO 24 /* both float and double */ +#define FREGHALF 26 /* double */ +#define FREGONE 28 /* double */ +#define FREGTWO 30 /* double */ + +enum as +{ + AXXX, + + AABSD, + AABSF, + AABSW, + AADD, + AADDD, + AADDF, + AADDU, + AADDW, + AAND, + ABEQ, + ABFPF, + ABFPT, + ABGEZ, + ABGEZAL, + ABGTZ, + ABLEZ, + ABLTZ, + ABLTZAL, + ABNE, + ABREAK, + ACMPEQD, + ACMPEQF, + ACMPGED, + ACMPGEF, + ACMPGTD, + ACMPGTF, + ADATA, + ADIV, + ADIVD, + ADIVF, + ADIVU, + ADIVW, + AGLOBL, + AGOK, + AHISTORY, + AJAL, + AJMP, + AMOVB, + AMOVBU, + AMOVD, + AMOVDF, + AMOVDW, + AMOVF, + AMOVFD, + AMOVFW, + AMOVH, + AMOVHU, + AMOVW, + AMOVWD, + AMOVWF, + AMOVWL, + AMOVWR, + AMUL, + AMULD, + AMULF, + AMULU, + AMULW, + ANAME, + ANEGD, + ANEGF, + ANEGW, + ANOP, + ANOR, + AOR, + AREM, + AREMU, + ARET, + ARFE, + ASGT, + ASGTU, + ASLL, + ASRA, + ASRL, + ASUB, + ASUBD, + ASUBF, + ASUBU, + ASUBW, + ASYSCALL, + ATEXT, + ATLBP, + ATLBR, + ATLBWI, + ATLBWR, + AWORD, + AXOR, + + AEND, + + AMOVV, + AMOVVL, + AMOVVR, + ASLLV, + ASRAV, + ASRLV, + ADIVV, + ADIVVU, + AREMV, + AREMVU, + AMULV, + AMULVU, + AADDV, + AADDVU, + ASUBV, + ASUBVU, + + ADYNT, + AINIT, + + ABCASE, + ACASE, + + ATRUNCFV, + ATRUNCDV, + ATRUNCFW, + ATRUNCDW, + AMOVWU, + AMOVFV, + AMOVDV, + AMOVVF, + AMOVVD, + + ASIGNAME, + + ALAST, +}; + +/* type/name */ +#define D_GOK 0 +#define D_NONE 1 + +/* type */ +#define D_BRANCH (D_NONE+1) +#define D_OREG (D_NONE+2) +#define D_EXTERN (D_NONE+3) /* name */ +#define D_STATIC (D_NONE+4) /* name */ +#define D_AUTO (D_NONE+5) /* name */ +#define D_PARAM (D_NONE+6) /* name */ +#define D_CONST (D_NONE+7) +#define D_FCONST (D_NONE+8) +#define D_SCONST (D_NONE+9) +#define D_HI (D_NONE+10) +#define D_LO (D_NONE+11) +#define D_REG (D_NONE+12) +#define D_FREG (D_NONE+13) +#define D_FCREG (D_NONE+14) +#define D_MREG (D_NONE+15) +#define D_FILE (D_NONE+16) +#define D_OCONST (D_NONE+17) +#define D_FILE1 (D_NONE+18) +#define D_VCONST (D_NONE+19) + +/* + * 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 */ +}; diff --git a/utils/0l/Nt.c b/utils/0l/Nt.c new file mode 100644 index 00000000..2efff499 --- /dev/null +++ b/utils/0l/Nt.c @@ -0,0 +1,77 @@ +#include <windows.h> +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/0l/Plan9.c b/utils/0l/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/0l/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/0l/Posix.c b/utils/0l/Posix.c new file mode 100644 index 00000000..aa5d9551 --- /dev/null +++ b/utils/0l/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fials if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} diff --git a/utils/0l/asm.c b/utils/0l/asm.c new file mode 100644 index 00000000..f0ee58bf --- /dev/null +++ b/utils/0l/asm.c @@ -0,0 +1,1433 @@ +#include "l.h" + +long OFFSET; +/* +long BADOFFSET = -1; + + if(OFFSET <= BADOFFSET && OFFSET+4 > BADOFFSET)\ + abort();\ + OFFSET += 4;\ + + if(OFFSET == BADOFFSET)\ + abort();\ + OFFSET++;\ +*/ + +void +cput(int c) +{ + cbp[0] = c; + cbp++; + cbc--; + if(cbc <= 0) + cflush(); +} + +void +bput(long l) +{ + cbp[0] = l>>24; + cbp[1] = l>>16; + cbp[2] = l>>8; + cbp[3] = l; + cbp += 4; + cbc -= 4; + if(cbc <= 0) + cflush(); +} + +void +lput(long l) +{ + + cbp[0] = l; + cbp[1] = l>>8; + cbp[2] = l>>16; + cbp[3] = l>>24; + cbp += 4; + cbc -= 4; + if(cbc <= 0) + cflush(); +} + +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; + if(s->type != STEXT && s->type != SLEAF) + diag("entry not text: %s", s->name); + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long t; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f asm\n", cputime()); + Bflush(&bso); + OFFSET = HEADR; + seek(cout, OFFSET, 0); + pc = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 8; + } + if(p->pc != pc) { + diag("phase error %lux sb %lux\n", + p->pc, pc); + if(!debug['a']) + prasm(curp); + pc = p->pc; + } + curp = p; + o = oplook(p); /* could probably avoid this call */ + if(asmout(p, o, 0)) { + p = p->link; + pc += 4; + } + pc += o->size; + } + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + + curtext = P; + switch(HEADTYPE) { + case 0: + case 4: + OFFSET = rnd(HEADR+textsize, 4096); + seek(cout, OFFSET, 0); + break; + case 1: + case 2: + case 3: + case 5: + case 6: + OFFSET = HEADR+textsize; + seek(cout, OFFSET, 0); + break; + } + for(t = 0; t < datsize; t += sizeof(buf)-100) { + if(datsize-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100); + else + datblk(t, datsize-t); + } + + symsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + case 0: + case 4: + OFFSET = rnd(HEADR+textsize, 4096)+datsize; + seek(cout, OFFSET, 0); + break; + case 3: + case 2: + case 1: + case 5: + case 6: + OFFSET = HEADR+textsize+datsize; + seek(cout, OFFSET, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + cflush(); + } + + if(debug['v']) + Bprint(&bso, "%5.2f header\n", cputime()); + Bflush(&bso); + OFFSET = 0; + seek(cout, OFFSET, 0); + switch(HEADTYPE) { + case 0: + bput(0x160L<<16); /* magic and sections */ + bput(0L); /* time and date */ + bput(rnd(HEADR+textsize, 4096)+datsize); + bput(symsize); /* nsyms */ + bput((0x38L<<16)|7L); /* size of optional hdr and flags */ + bput((0413<<16)|0437L); /* magic and version */ + bput(rnd(HEADR+textsize, 4096)); /* sizes */ + bput(datsize); + bput(bsssize); + bput(entryvalue()); /* va of entry */ + bput(INITTEXT-HEADR); /* va of base of text */ + bput(INITDAT); /* va of base of data */ + bput(INITDAT+datsize); /* va of base of bss */ + bput(~0L); /* gp reg mask */ + bput(0L); + bput(0L); + bput(0L); + bput(0L); + bput(~0L); /* gp value ?? */ + break; + case 1: + bput(0x160L<<16); /* magic and sections */ + bput(0L); /* time and date */ + bput(HEADR+textsize+datsize); + bput(symsize); /* nsyms */ + bput((0x38L<<16)|7L); /* size of optional hdr and flags */ + + bput((0407<<16)|0437L); /* magic and version */ + bput(textsize); /* sizes */ + bput(datsize); + bput(bsssize); + bput(entryvalue()); /* va of entry */ + bput(INITTEXT); /* va of base of text */ + bput(INITDAT); /* va of base of data */ + bput(INITDAT+datsize); /* va of base of bss */ + bput(~0L); /* gp reg mask */ + bput(lcsize); + bput(0L); + bput(0L); + bput(0L); + bput(~0L); /* gp value ?? */ + bput(0L); /* complete mystery */ + break; + case 2: + t = 22; + bput(((((4*t)+0)*t)+7)); /* magic */ + bput(textsize); /* sizes */ + bput(datsize); + bput(bsssize); + bput(symsize); /* nsyms */ + bput(entryvalue()); /* va of entry */ + bput(0L); + bput(lcsize); + break; + case 3: + bput((0x160L<<16)|3L); /* magic and sections */ + bput(time(0)); /* time and date */ + bput(HEADR+textsize+datsize); + bput(symsize); /* nsyms */ + bput((0x38L<<16)|7L); /* size of optional hdr and flags */ + + bput((0407<<16)|0437L); /* magic and version */ + bput(textsize); /* sizes */ + bput(datsize); + bput(bsssize); + bput(entryvalue()); /* va of entry */ + bput(INITTEXT); /* va of base of text */ + bput(INITDAT); /* va of base of data */ + bput(INITDAT+datsize); /* va of base of bss */ + bput(~0L); /* gp reg mask */ + bput(lcsize); + bput(0L); + bput(0L); + bput(0L); + bput(~0L); /* gp value ?? */ + + strnput(".text", 8); /* text segment */ + bput(INITTEXT); /* address */ + bput(INITTEXT); + bput(textsize); + bput(HEADR); + bput(0L); + bput(HEADR+textsize+datsize+symsize); + bput(lcsize); /* line number size */ + bput(0x20L); /* flags */ + + strnput(".data", 8); /* data segment */ + bput(INITDAT); /* address */ + bput(INITDAT); + bput(datsize); + bput(HEADR+textsize); + bput(0L); + bput(0L); + bput(0L); + bput(0x40L); /* flags */ + + strnput(".bss", 8); /* bss segment */ + bput(INITDAT+datsize); /* address */ + bput(INITDAT+datsize); + bput(bsssize); + bput(0L); + bput(0L); + bput(0L); + bput(0L); + bput(0x80L); /* flags */ + break; + case 4: + + bput((0x160L<<16)|3L); /* magic and sections */ + bput(time(0)); /* time and date */ + bput(rnd(HEADR+textsize, 4096)+datsize); + bput(symsize); /* nsyms */ + bput((0x38L<<16)|7L); /* size of optional hdr and flags */ + + bput((0413<<16)|01012L); /* magic and version */ + bput(textsize); /* sizes */ + bput(datsize); + bput(bsssize); + bput(entryvalue()); /* va of entry */ + bput(INITTEXT); /* va of base of text */ + bput(INITDAT); /* va of base of data */ + bput(INITDAT+datsize); /* va of base of bss */ + bput(~0L); /* gp reg mask */ + bput(lcsize); + bput(0L); + bput(0L); + bput(0L); + bput(~0L); /* gp value ?? */ + + strnput(".text", 8); /* text segment */ + bput(INITTEXT); /* address */ + bput(INITTEXT); + bput(textsize); + bput(HEADR); + bput(0L); + bput(HEADR+textsize+datsize+symsize); + bput(lcsize); /* line number size */ + bput(0x20L); /* flags */ + + strnput(".data", 8); /* data segment */ + bput(INITDAT); /* address */ + bput(INITDAT); + bput(datsize); + bput(rnd(HEADR+textsize, 4096)); /* sizes */ + bput(0L); + bput(0L); + bput(0L); + bput(0x40L); /* flags */ + + strnput(".bss", 8); /* bss segment */ + bput(INITDAT+datsize); /* address */ + bput(INITDAT+datsize); + bput(bsssize); + bput(0L); + bput(0L); + bput(0L); + bput(0L); + bput(0x80L); /* flags */ + break; + case 5: + strnput("\177ELF", 4); /* e_ident */ + cput(1); /* class = 32 bit */ + cput(2); /* data = MSB */ + cput(1); /* version = CURRENT */ + strnput("", 9); + bput((2L<<16)|8L); /* type = EXEC; machine = MIPS */ + bput(1L); /* version = CURRENT */ + bput(entryvalue()); /* entry vaddr */ + bput(52L); /* offset to first phdr */ + bput(0L); /* offset to first shdr */ + bput(0L); /* flags = MIPS */ + bput((52L<<16)|32L); /* Ehdr & Phdr sizes*/ + bput((3L<<16)|0L); /* # Phdrs & Shdr size */ + bput((0L<<16)|0L); /* # Shdrs & shdr string size */ + + bput(1L); /* text - type = PT_LOAD */ + bput(0L); /* file offset */ + bput(INITTEXT-HEADR); /* vaddr */ + bput(INITTEXT-HEADR); /* paddr */ + bput(HEADR+textsize); /* file size */ + bput(HEADR+textsize); /* memory size */ + bput(0x05L); /* protections = RX */ + bput(0x10000L); /* alignment code?? */ + + bput(1L); /* data - type = PT_LOAD */ + bput(HEADR+textsize); /* file offset */ + bput(INITDAT); /* vaddr */ + bput(INITDAT); /* paddr */ + bput(datsize); /* file size */ + bput(datsize+bsssize); /* memory size */ + bput(0x06L); /* protections = RW */ + bput(0x10000L); /* alignment code?? */ + + bput(0L); /* data - type = PT_NULL */ + bput(HEADR+textsize+datsize); /* file offset */ + bput(0L); + bput(0L); + bput(symsize); /* symbol table size */ + bput(lcsize); /* line number size */ + bput(0x04L); /* protections = R */ + bput(0x04L); /* alignment code?? */ + break; + case 6: + t = 22; + bput(((((4*t)+0)*t)+7)); /* magic */ + bput(textsize); /* sizes */ + bput(datsize); + bput(bsssize); + bput(symsize); /* nsyms */ + bput(entryvalue()); /* va of entry */ + bput(0L); + bput(lcsize); + break; + } + cflush(); +} + +void +strnput(char *s, int n) +{ + for(; *s; s++){ + cput(*s); + n--; + } + for(; n > 0; n--) + cput(0); +} + +void +cflush(void) +{ + int n; + + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = (uchar*)buf.cbuf; + cbc = sizeof(buf.cbuf); +} + +void +nopstat(char *f, Count *c) +{ + if(c->outof) + Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, + c->outof - c->count, c->outof, + (double)(c->outof - c->count)/c->outof); +} + +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->cond) { + s = p->from.sym; + if(s->type != STEXT && s->type != SLEAF) + 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); + + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + else + putsymb(s->name, 'L', s->value, s->version); + + /* frame, auto and param after */ + putsymb(".frame", 'm', p->to.offset+8, 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 +putsymb(char *s, int t, long v, int ver) +{ + int i, f; + + if(t == 'f') + s++; + bput(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); + } +} + +#define MINLC 4 +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); +} + +void +datblk(long s, long n) +{ + Prog *p; + char *cast; + long l, fl, j, d; + int i, c; + + memset(buf.dbuf, 0, n+100); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->reg; + 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\n"); + break; + } + } + switch(p->to.type) { + default: + diag("unknown mode in initialization\n%P\n", p); + break; + + case D_VCONST: + cast = (char*)p->to.ieee; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(p->to.ieee); + cast = (char*)&fl; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi4[i]]; + l++; + } + break; + case 8: + cast = (char*)p->to.ieee; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + for(; i<c; i++) { + buf.dbuf[l] = p->to.sval[i]; + l++; + } + break; + + case D_CONST: + d = p->to.offset; + if(p->to.sym) { + if(p->to.sym->type == STEXT || + p->to.sym->type == SLEAF) + d += p->to.sym->value; + if(p->to.sym->type == SDATA) + d += p->to.sym->value + INITDAT; + if(p->to.sym->type == SBSS) + d += p->to.sym->value + INITDAT; + } + cast = (char*)&d; + switch(c) { + default: + diag("bad nuxi %d %d\n%P\n", c, i, curp); + break; + case 1: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +#define OP_RRR(op,r1,r2,r3)\ + (op|(((r1)&31L)<<16)|(((r2)&31L)<<21)|(((r3)&31L)<<11)) +#define OP_IRR(op,i,r2,r3)\ + (op|((i)&0xffffL)|(((r2)&31L)<<21)|(((r3)&31L)<<16)) +#define OP_SRR(op,s,r2,r3)\ + (op|(((s)&31L)<<6)|(((r2)&31L)<<16)|(((r3)&31L)<<11)) +#define OP_FRRR(op,r1,r2,r3)\ + (op|(((r1)&31L)<<16)|(((r2)&31L)<<11)|(((r3)&31L)<<6)) +#define OP_JMP(op,i)\ + ((op)|((i)&0x3ffffffL)) + +#define OP(x,y)\ + (((x)<<3)|((y)<<0)) +#define SP(x,y)\ + (((x)<<29)|((y)<<26)) +#define BCOND(x,y)\ + (((x)<<19)|((y)<<16)) +#define MMU(x,y)\ + (SP(2,0)|(16<<21)|((x)<<3)|((y)<<0)) +#define FPF(x,y)\ + (SP(2,1)|(16<<21)|((x)<<3)|((y)<<0)) +#define FPD(x,y)\ + (SP(2,1)|(17<<21)|((x)<<3)|((y)<<0)) +#define FPW(x,y)\ + (SP(2,1)|(20<<21)|((x)<<3)|((y)<<0)) +#define FPV(x,y)\ + (SP(2,1)|(21<<21)|((x)<<3)|((y)<<0)) + +int +asmout(Prog *p, Optab *o, int aflag) +{ + long o1, o2, o3, o4, o5, o6, o7, v; + Prog *ct; + int r, a; + + o1 = 0; + o2 = 0; + o3 = 0; + o4 = 0; + o5 = 0; + o6 = 0; + o7 = 0; + switch(o->type) { + default: + diag("unknown type %d\n", o->type); + if(!debug['a']) + prasm(p); + break; + + case 0: /* pseudo ops */ + if(aflag) { + if(p->link) { + if(p->as == ATEXT) { + ct = curtext; + o2 = autosize; + curtext = p; + autosize = p->to.offset + 8; + o1 = asmout(p->link, oplook(p->link), aflag); + curtext = ct; + autosize = o2; + } else + o1 = asmout(p->link, oplook(p->link), aflag); + } + return o1; + } + break; + + case 1: /* mov[v] r1,r2 ==> OR r1,r0,r2 */ + o1 = OP_RRR(oprrr(AOR), p->from.reg, REGZERO, p->to.reg); + break; + + case 2: /* add/sub r1,[r2],r3 */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg); + break; + + case 3: /* mov $soreg, r ==> or/add $i,o,r */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + a = AADDU; + if(o->a1 == C_ANDCON) + a = AOR; + o1 = OP_IRR(opirr(a), v, r, p->to.reg); + break; + + case 4: /* add $scon,[r1],r2 */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(opirr(p->as), v, r, p->to.reg); + break; + + case 5: /* syscall */ + if(aflag) + return 0; + o1 = oprrr(p->as); + break; + + case 6: /* beq r1,[r2],sbra */ + if(aflag) + return 0; + if(!debug['Y'] && p->link && p->cond && isnop(p->link)) { + nop.branch.count--; + nop.branch.outof--; + nop.jump.outof++; + o2 = asmout(p->cond, oplook(p->cond), 1); + if(o2) { + if(p->cond == P) + v = -4 >> 2; + else + v = (p->cond->pc+4 - pc-4) >> 2; + if(((v << 16) >> 16) != v) + diag("short branch too far: %d\n%P\n", v, p); + o1 = OP_IRR(opirr(p->as+ALAST), v, p->from.reg, p->reg); + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", + p->pc, o1, o2, p); + lput(o1); + lput(o2); + return 1; + } + } + if(p->cond == P) + v = -4 >> 2; + else + v = (p->cond->pc - pc-4) >> 2; + if(((v << 16) >> 16) != v) + diag("short branch too far: %d\n%P\n", v, p); + o1 = OP_IRR(opirr(p->as), v, p->from.reg, p->reg); + break; + + case 7: /* mov r, soreg ==> sw o(r) */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + o1 = OP_IRR(opirr(p->as), v, r, p->from.reg); + break; + + case 8: /* mov soreg, r ==> lw o(r) */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = OP_IRR(opirr(p->as+ALAST), v, r, p->to.reg); + break; + + case 9: /* asl r1,[r2],r3 */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg); + break; + + case 10: /* add $con,[r1],r2 ==> mov $con,t; add t,[r1],r2 */ + v = regoff(&p->from); + r = AOR; + if(v < 0) + r = AADDU; + o1 = OP_IRR(opirr(r), v, 0, REGTMP); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); + break; + + case 11: /* jmp lbra */ + if(aflag) + return 0; + if(p->cond == P) + v = p->pc >> 2; + else + v = p->cond->pc >> 2; + o1 = OP_JMP(opirr(p->as), v); + if(!debug['Y'] && p->link && p->cond && isnop(p->link)) { + nop.branch.count--; + nop.branch.outof--; + nop.jump.outof++; + o2 = asmout(p->cond, oplook(p->cond), 1); + if(o2) { + o1 += 1; + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", + p->pc, o1, o2, p); + lput(o1); + lput(o2); + return 1; + } + } + break; + + case 12: /* movbs r,r */ + v = 16; + if(p->as == AMOVB) + v = 24; + o1 = OP_SRR(opirr(ASLL), v, p->from.reg, p->to.reg); + o2 = OP_SRR(opirr(ASRA), v, p->to.reg, p->to.reg); + break; + + case 13: /* movbu r,r */ + if(p->as == AMOVBU) + o1 = OP_IRR(opirr(AAND), 0xffL, p->from.reg, p->to.reg); + else + o1 = OP_IRR(opirr(AAND), 0xffffL, p->from.reg, p->to.reg); + break; + + case 14: /* movwu r,r */ + v = 32-32; + o1 = OP_SRR(opirr(ASLLV+ALAST), v, p->from.reg, p->to.reg); + o2 = OP_SRR(opirr(ASRLV+ALAST), v, p->to.reg, p->to.reg); + break; + + case 16: /* sll $c,[r1],r2 */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + if(v >= 32) + o1 = OP_SRR(opirr(p->as+ALAST), v-32, r, p->to.reg); + else + o1 = OP_SRR(opirr(p->as), v, r, p->to.reg); + break; + + case 18: /* jmp [r1],0(r2) */ + if(aflag) + return 0; + r = p->reg; + if(r == NREG) + r = o->param; + o1 = OP_RRR(oprrr(p->as), 0, p->to.reg, r); + break; + + case 19: /* mov $lcon,r ==> lu+or */ + v = regoff(&p->from); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg); + o2 = OP_IRR(opirr(AOR), v, p->to.reg, p->to.reg); + break; + + case 20: /* mov lohi,r */ + r = OP(2,0); /* mfhi */ + if(p->from.type == D_LO) + r = OP(2,2); /* mflo */ + o1 = OP_RRR(r, REGZERO, REGZERO, p->to.reg); + break; + + case 21: /* mov r,lohi */ + r = OP(2,1); /* mthi */ + if(p->to.type == D_LO) + r = OP(2,3); /* mtlo */ + o1 = OP_RRR(r, REGZERO, p->from.reg, REGZERO); + break; + + case 22: /* mul r1,r2 */ + o1 = OP_RRR(oprrr(p->as), p->from.reg, p->reg, REGZERO); + break; + + case 23: /* add $lcon,r1,r2 ==> lu+or+add */ + v = regoff(&p->from); + if(p->to.reg == REGTMP || p->reg == REGTMP) + diag("cant synthesize large constant\n%P\n", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o3 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); + break; + + case 24: /* mov $ucon,,r ==> lu r */ + v = regoff(&p->from); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg); + break; + + case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */ + v = regoff(&p->from); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); + break; + + case 26: /* mov $lsext/auto/oreg,,r2 ==> lu+or+add */ + v = regoff(&p->from); + if(p->to.reg == REGTMP) + diag("cant synthesize large constant\n%P\n", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + r = p->from.reg; + if(r == NREG) + r = o->param; + o3 = OP_RRR(oprrr(AADDU), REGTMP, r, p->to.reg); + break; + + case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + if(p->as == AMOVD) + o4 = opirr(AMOVD+ALAST); + else + o4 = opirr(AMOVF+ALAST); + switch(o->size) { + case 16: + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(o4, 0, REGTMP, p->to.reg); + break; + case 4: + o1 = OP_IRR(o4, v, r, p->to.reg); + break; + } + break; + + case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + if(p->as == AMOVD) + o4 = opirr(AMOVD); + else + o4 = opirr(AMOVF); + switch(o->size) { + case 16: + if(r == REGTMP) + diag("cant synthesize large constant\n%P\n", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(o4, 0, REGTMP, p->from.reg); + break; + case 4: + o1 = OP_IRR(o4, v, r, p->from.reg); + break; + } + break; + + case 30: /* movw r,fr */ + r = SP(2,1)|(4<<21); /* mtc1 */ + o1 = OP_RRR(r, p->from.reg, 0, p->to.reg); + break; + + case 31: /* movw fr,r */ + r = SP(2,1)|(0<<21); /* mfc1 */ + o1 = OP_RRR(r, p->to.reg, 0, p->from.reg); + break; + + case 32: /* fadd fr1,[fr2],fr3 */ + r = p->reg; + if(r == NREG) + o1 = OP_FRRR(oprrr(p->as), p->from.reg, p->to.reg, p->to.reg); + else + o1 = OP_FRRR(oprrr(p->as), p->from.reg, r, p->to.reg); + break; + + case 33: /* fabs fr1,fr3 */ + o1 = OP_FRRR(oprrr(p->as), 0, p->from.reg, p->to.reg); + break; + + case 34: /* mov $con,fr ==> or/add $i,r,r2 */ + v = regoff(&p->from); + r = AADDU; + if(o->a1 == C_ANDCON) + r = AOR; + o1 = OP_IRR(opirr(r), v, 0, REGTMP); + o2 = OP_RRR(SP(2,1)|(4<<21), REGTMP, 0, p->to.reg); /* mtc1 */ + break; + + case 35: /* mov r,lext/luto/oreg ==> sw o(r) */ + /* + * the lowbits of the constant cannot + * be moved into the offset of the load + * because the mips 4000 in 64-bit mode + * does a 64-bit add and it will screw up. + */ + v = regoff(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + if(r == REGTMP) + diag("cant synthesize large constant\n%P\n", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(p->as), 0, REGTMP, p->from.reg); + break; + + case 36: /* mov lext/lauto/lreg,r ==> lw o(r30) */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + if(r == REGTMP) + diag("cant synthesize large constant\n%P\n", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(p->as+ALAST), 0, REGTMP, p->to.reg); + break; + + case 37: /* movw r,mr */ + r = SP(2,0)|(4<<21); /* mtc0 */ + if(p->as == AMOVV) + r = SP(2,0)|(5<<21); /* dmtc0 */ + o1 = OP_RRR(r, p->from.reg, 0, p->to.reg); + break; + + case 38: /* movw mr,r */ + r = SP(2,0)|(0<<21); /* mfc0 */ + if(p->as == AMOVV) + r = SP(2,0)|(1<<21); /* dmfc0 */ + o1 = OP_RRR(r, p->to.reg, 0, p->from.reg); + break; + + case 39: /* rfe ==> jmp+rfe */ + if(aflag) + return 0; + o1 = OP_RRR(oprrr(AJMP), 0, p->to.reg, REGZERO); + o2 = oprrr(p->as); + break; + + case 40: /* word */ + if(aflag) + return 0; + o1 = regoff(&p->to); + break; + + case 41: /* movw r,fcr */ + o1 = OP_RRR(SP(2,1)|(2<<21), REGZERO, 0, p->to.reg); /* mfcc1 */ + o2 = OP_RRR(SP(2,1)|(6<<21), p->from.reg, 0, p->to.reg);/* mtcc1 */ + break; + + case 42: /* movw fcr,r */ + o1 = OP_RRR(SP(2,1)|(2<<21), p->to.reg, 0, p->from.reg);/* mfcc1 */ + break; + + case 47: /* movv r,fr */ + r = SP(2,1)|(5<<21); /* dmtc1 */ + o1 = OP_RRR(r, p->from.reg, 0, p->to.reg); + break; + + case 48: /* movv fr,r */ + r = SP(2,1)|(1<<21); /* dmfc1 */ + o1 = OP_RRR(r, p->to.reg, 0, p->from.reg); + break; + } + if(aflag) + return o1; + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + lput(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + lput(o1); + lput(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + lput(o1); + lput(o2); + lput(o3); + break; + case 16: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, p); + lput(o1); + lput(o2); + lput(o3); + lput(o4); + break; + case 20: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, p); + lput(o1); + lput(o2); + lput(o3); + lput(o4); + lput(o5); + break; + + case 28: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, o6, o7, p); + lput(o1); + lput(o2); + lput(o3); + lput(o4); + lput(o5); + lput(o6); + lput(o7); + break; + } + return 0; +} + +int +isnop(Prog *p) +{ + if(p->as != ANOR) + return 0; + if(p->reg != REGZERO && p->reg != NREG) + return 0; + if(p->from.type != D_REG || p->from.reg != REGZERO) + return 0; + if(p->to.type != D_REG || p->to.reg != REGZERO) + return 0; + return 1; +} + +long +oprrr(int a) +{ + switch(a) { + case AADD: return OP(4,0); + case AADDU: return OP(4,1); + case ASGT: return OP(5,2); + case ASGTU: return OP(5,3); + case AAND: return OP(4,4); + case AOR: return OP(4,5); + case AXOR: return OP(4,6); + case ASUB: return OP(4,2); + case ASUBU: return OP(4,3); + case ANOR: return OP(4,7); + case ASLL: return OP(0,4); + case ASRL: return OP(0,6); + case ASRA: return OP(0,7); + + case ASLLV: return OP(2,4); + case ASRLV: return OP(2,6); + case ASRAV: return OP(2,7); + + case AADDV: return OP(5,4); + case AADDVU: return OP(5,5); + case ASUBV: return OP(5,6); + case ASUBVU: return OP(5,7); + case AREM: + case ADIV: return OP(3,2); + case AREMU: + case ADIVU: return OP(3,3); + case AMUL: return OP(3,0); + case AMULU: return OP(3,1); + + case AREMV: + case ADIVV: return OP(3,6); + case AREMVU: + case ADIVVU: return OP(3,7); + case AMULV: return OP(3,4); + case AMULVU: return OP(3,5); + + case AJMP: return OP(1,0); + case AJAL: return OP(1,1); + + case ABREAK: return OP(1,5); + case ASYSCALL: return OP(1,4); + case ATLBP: return MMU(1,0); + case ATLBR: return MMU(0,1); + case ATLBWI: return MMU(0,2); + case ATLBWR: return MMU(0,6); + case ARFE: return MMU(2,0); + + case ADIVF: return FPF(0,3); + case ADIVD: return FPD(0,3); + case AMULF: return FPF(0,2); + case AMULD: return FPD(0,2); + case ASUBF: return FPF(0,1); + case ASUBD: return FPD(0,1); + case AADDF: return FPF(0,0); + case AADDD: return FPD(0,0); + + case ATRUNCFV: return FPF(1,1); + case ATRUNCDV: return FPD(1,1); + case ATRUNCFW: return FPF(1,5); + case ATRUNCDW: return FPD(1,5); + case AMOVFV: return FPF(4,5); + case AMOVDV: return FPD(4,5); + case AMOVVF: return FPV(4,0); + case AMOVVD: return FPV(4,1); + + case AMOVFW: return FPF(4,4); + case AMOVDW: return FPD(4,4); + case AMOVWF: return FPW(4,0); + case AMOVDF: return FPD(4,0); + case AMOVWD: return FPW(4,1); + case AMOVFD: return FPF(4,1); + case AABSF: return FPF(0,5); + case AABSD: return FPD(0,5); + case AMOVF: return FPF(0,6); + case AMOVD: return FPD(0,6); + case ANEGF: return FPF(0,7); + case ANEGD: return FPD(0,7); + + case ACMPEQF: return FPF(6,2); + case ACMPEQD: return FPD(6,2); + case ACMPGTF: return FPF(7,4); + case ACMPGTD: return FPD(7,4); + case ACMPGEF: return FPF(7,6); + case ACMPGED: return FPD(7,6); + } + if(a >= ALAST) + diag("bad rrr %A+ALAST", a-ALAST); + else + diag("bad rrr %A", a); + return 0; +} + +long +opirr(int a) +{ + switch(a) { + case AADD: return SP(1,0); + case AADDU: return SP(1,1); + case ASGT: return SP(1,2); + case ASGTU: return SP(1,3); + case AAND: return SP(1,4); + case AOR: return SP(1,5); + case AXOR: return SP(1,6); + case ALAST: return SP(1,7); /* lui */ + case ASLL: return OP(0,0); + case ASRL: return OP(0,2); + case ASRA: return OP(0,3); + + case AADDV: return SP(3,0); + case AADDVU: return SP(3,1); + + case AJMP: return SP(0,2); + case AJAL: return SP(0,3); + case ABEQ: return SP(0,4); + case ABEQ+ALAST: return SP(2,4); /* likely */ + case ABNE: return SP(0,5); + case ABNE+ALAST: return SP(2,5); /* likely */ + + case ABGEZ: return SP(0,1)|BCOND(0,1); + case ABGEZ+ALAST: return SP(0,1)|BCOND(0,3); /* likely */ + case ABGEZAL: return SP(0,1)|BCOND(2,1); + case ABGEZAL+ALAST: return SP(0,1)|BCOND(2,3); /* likely */ + case ABGTZ: return SP(0,7); + case ABGTZ+ALAST: return SP(2,7); /* likely */ + case ABLEZ: return SP(0,6); + case ABLEZ+ALAST: return SP(2,6); /* likely */ + case ABLTZ: return SP(0,1)|BCOND(0,0); + case ABLTZ+ALAST: return SP(0,1)|BCOND(0,2); /* likely */ + case ABLTZAL: return SP(0,1)|BCOND(2,0); + case ABLTZAL+ALAST: return SP(0,1)|BCOND(2,2); /* likely */ + + case ABFPT: return SP(2,1)|(257<<16); + case ABFPT+ALAST: return SP(2,1)|(259<<16); /* likely */ + case ABFPF: return SP(2,1)|(256<<16); + case ABFPF+ALAST: return SP(2,1)|(258<<16); /* likely */ + + case AMOVB: + case AMOVBU: return SP(5,0); + case AMOVH: + case AMOVHU: return SP(5,1); + case AMOVW: return SP(5,3); + case AMOVV: return SP(7,7); + case AMOVF: return SP(7,1); + case AMOVD: return SP(7,5); + case AMOVWL: return SP(5,2); + case AMOVWR: return SP(5,6); + case AMOVVL: return SP(5,4); + case AMOVVR: return SP(5,5); + + case ABREAK: return SP(5,7); + + case AMOVWL+ALAST: return SP(4,2); + case AMOVWR+ALAST: return SP(4,6); + case AMOVVL+ALAST: return SP(3,2); + case AMOVVR+ALAST: return SP(3,3); + case AMOVB+ALAST: return SP(4,0); + case AMOVBU+ALAST: return SP(4,4); + case AMOVH+ALAST: return SP(4,1); + case AMOVHU+ALAST: return SP(4,5); + case AMOVW+ALAST: return SP(4,3); + case AMOVV+ALAST: return SP(6,7); + case AMOVF+ALAST: return SP(6,1); + case AMOVD+ALAST: return SP(6,5); + + case ASLLV: return OP(7,0); + case ASRLV: return OP(7,2); + case ASRAV: return OP(7,3); + case ASLLV+ALAST: return OP(7,4); + case ASRLV+ALAST: return OP(7,6); + case ASRAV+ALAST: return OP(7,7); + } + if(a >= ALAST) + diag("bad irr %A+ALAST", a-ALAST); + else + diag("bad irr %A", a); + return 0; +} diff --git a/utils/0l/enam.c b/utils/0l/enam.c new file mode 100644 index 00000000..5fd1a351 --- /dev/null +++ b/utils/0l/enam.c @@ -0,0 +1,122 @@ +char* anames[] = +{ + "XXX", + "ABSD", + "ABSF", + "ABSW", + "ADD", + "ADDD", + "ADDF", + "ADDU", + "ADDW", + "AND", + "BEQ", + "BFPF", + "BFPT", + "BGEZ", + "BGEZAL", + "BGTZ", + "BLEZ", + "BLTZ", + "BLTZAL", + "BNE", + "BREAK", + "CMPEQD", + "CMPEQF", + "CMPGED", + "CMPGEF", + "CMPGTD", + "CMPGTF", + "DATA", + "DIV", + "DIVD", + "DIVF", + "DIVU", + "DIVW", + "GLOBL", + "GOK", + "HISTORY", + "JAL", + "JMP", + "MOVB", + "MOVBU", + "MOVD", + "MOVDF", + "MOVDW", + "MOVF", + "MOVFD", + "MOVFW", + "MOVH", + "MOVHU", + "MOVW", + "MOVWD", + "MOVWF", + "MOVWL", + "MOVWR", + "MUL", + "MULD", + "MULF", + "MULU", + "MULW", + "NAME", + "NEGD", + "NEGF", + "NEGW", + "NOP", + "NOR", + "OR", + "REM", + "REMU", + "RET", + "RFE", + "SGT", + "SGTU", + "SLL", + "SRA", + "SRL", + "SUB", + "SUBD", + "SUBF", + "SUBU", + "SUBW", + "SYSCALL", + "TEXT", + "TLBP", + "TLBR", + "TLBWI", + "TLBWR", + "WORD", + "XOR", + "END", + "MOVV", + "MOVVL", + "MOVVR", + "SLLV", + "SRAV", + "SRLV", + "DIVV", + "DIVVU", + "REMV", + "REMVU", + "MULV", + "MULVU", + "ADDV", + "ADDVU", + "SUBV", + "SUBVU", + "DYNT", + "INIT", + "BCASE", + "CASE", + "TRUNCFV", + "TRUNCDV", + "TRUNCFW", + "TRUNCDW", + "MOVWU", + "MOVFV", + "MOVDV", + "MOVVF", + "MOVVD", + "SIGNAME", + "LAST", +}; diff --git a/utils/0l/l.h b/utils/0l/l.h new file mode 100644 index 00000000..6b027814 --- /dev/null +++ b/utils/0l/l.h @@ -0,0 +1,329 @@ +#include <lib9.h> +#include <bio.h> +#include "../vc/v.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Adr Adr; +typedef struct Sym Sym; +typedef struct Autom Auto; +typedef struct Prog Prog; +typedef struct Optab Optab; +typedef struct Oprang Oprang; +typedef uchar Opcross[32][2][32]; +typedef struct Count Count; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Adr +{ + union + { + long u0offset; + char* u0sval; + Ieee* u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + char type; + char reg; + char name; + char class; +}; + +#define offset u0.u0offset +#define sval u0.u0sval +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + union + { + long u0regused; + Prog* u0forwd; + } u0; + Prog* cond; + Prog* link; + long pc; + long line; + uchar mark; + uchar optab; + char as; + char reg; +}; + +#define regused u0.u0regused +#define forwd u0.u0forwd + +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + long value; + Sym* link; +}; +struct Autom +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Optab +{ + char as; + char a1; + char a2; + char a3; + char type; + char size; + char param; +}; +struct Oprang +{ + Optab* start; + Optab* stop; +}; +struct Count +{ + long count; + long outof; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SLEAF, + SFILE, + SCONST, + + C_NONE = 0, + C_REG, + C_FREG, + C_FCREG, + C_MREG, + C_HI, + C_LO, + C_ZCON, + C_SCON, + C_ADD0CON, + C_AND0CON, + C_ADDCON, + C_ANDCON, + C_UCON, + C_LCON, + C_SACON, + C_SECON, + C_LACON, + C_LECON, + C_SBRA, + C_LBRA, + C_SAUTO, + C_SEXT, + C_LAUTO, + C_LEXT, + C_ZOREG, + C_SOREG, + C_LOREG, + C_GOK, + + NSCHED = 20, + +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + SYNC = 1<<3, + BRANCH = 1<<4, + LOAD = 1<<5, + FCMP = 1<<6, + NOSCHED = 1<<7, + + BIG = 32766, + STRINGSZ = 200, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ +}; + +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 + +EXTERN long HEADR; /* length of header */ +EXTERN int HEADTYPE; /* type of header */ +EXTERN long INITDAT; /* data location */ +EXTERN long INITRND; /* data round above text location */ +EXTERN long INITTEXT; /* text location */ +EXTERN char* INITENTRY; /* entry point */ +EXTERN long autosize; +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN char fnuxi4[4]; +EXTERN char fnuxi8[8]; +EXTERN char* noname; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN char literal[32]; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long instoffset; +EXTERN Opcross opcross[10]; +EXTERN Oprang oprange[ALAST]; +EXTERN char* outfile; +EXTERN long pc; +EXTERN uchar repop[ALAST]; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN char xcmp[32][32]; +EXTERN Prog zprg; +EXTERN int dtype; + +EXTERN struct +{ + Count branch; + Count fcmp; + Count load; + Count mfrom; + Count page; + Count jump; +} nop; + +extern char* anames[]; +extern Optab optab[]; + +#pragma varargck type "A" int +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* + + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Nconv(Fmt*); +int Pconv(Fmt*); +int Sconv(Fmt*); +int aclass(Adr*); +void addhist(long, int); +void addnop(Prog*); +void append(Prog*, Prog*); +void asmb(void); +void asmlc(void); +int asmout(Prog*, Optab*, int); +void asmsym(void); +long atolwhex(char*); +Prog* brloop(Prog*); +void buildop(void); +void buildrep(int, int); +void cflush(void); +int cmp(int, int); +int compound(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +long entryvalue(void); +void errorexit(void); +void exchange(Prog*); +int find1(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +vlong ieeedtov(Ieee*); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +int isnop(Prog*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void mkfwd(void); +void* mysbrk(ulong); +void names(void); +void nocache(Prog*); +void noops(void); +void nuxiinit(void); +void objfile(char*); +int ocmp(const void*, const void*); +long opirr(int); +Optab* oplook(Prog*); +long oprrr(int); +void patch(void); +void prasm(Prog*); +void prepend(Prog*, Prog*); +Prog* prg(void); +int pseudo(Prog*); +void putsymb(char*, int, long, int); +long regoff(Adr*); +int relinv(int); +long rnd(long, long); +void sched(Prog*, Prog*); +void span(void); +void strnput(char*, int); +void undef(void); +void xdefine(char*, int, long); +void xfol(Prog*); +void xfol(Prog*); +void nopstat(char*, Count*); diff --git a/utils/0l/list.c b/utils/0l/list.c new file mode 100644 index 00000000..9261bc8e --- /dev/null +++ b/utils/0l/list.c @@ -0,0 +1,277 @@ +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], *s; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + curp = p; + a = p->as; + if(a == ADATA || a == ADYNT || a == AINIT) + sprint(str, "(%ld) %A %D/%d,%D", + p->line, a, &p->from, p->reg, &p->to); + else{ + s = str; + s += sprint(s, "(%ld)", p->line); + if(p->mark & NOSCHED) + s += sprint(s, "*"); + if(p->reg == NREG) + sprint(s, " %A %D,%D", + a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(s, " %A %D,R%d,%D", + a, &p->from, p->reg, &p->to); + else + sprint(s, " %A %D,F%d,%D", + a, &p->from, p->reg, &p->to); + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + long v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + sprint(str, "$%N", a); + if(a->reg != NREG) + sprint(str, "%N(R%d)(CONST)", a, a->reg); + break; + + case D_OCONST: + sprint(str, "$*$%N", a); + if(a->reg != NREG) + sprint(str, "%N(R%d)(CONST)", a, a->reg); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_MREG: + sprint(str, "M%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FCREG: + sprint(str, "FC%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_LO: + sprint(str, "LO"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(LO)(REG)", a); + break; + + case D_HI: + sprint(str, "HI"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(HI)(REG)", a); + break; + + case D_BRANCH: /* botch */ + if(curp->cond != P) { + v = curp->cond->pc; + if(v >= INITTEXT) + v -= INITTEXT-HEADR; + if(a->sym != S) + sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + else + sprint(str, "%.5lux(BRANCH)", v); + } else + if(a->sym != S) + sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + else + sprint(str, "%ld(APC)", a->offset); + break; + + case D_FCONST: + sprint(str, "$%e", ieeedtod(a->ieee)); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + if(s == S) + sprint(str, "%ld(SB)", a->offset); + else + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + if(s == S) + sprint(str, "<>+%ld(SB)", a->offset); + else + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + if(s == S) + sprint(str, "%ld(SP)", a->offset); + else + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + if(s == S) + sprint(str, "%ld(FP)", a->offset); + else + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(long); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/0l/mkfile b/utils/0l/mkfile new file mode 100644 index 00000000..3001002b --- /dev/null +++ b/utils/0l/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=0l +OFILES=\ + asm.$O\ + list.$O\ + noop.$O\ + sched.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + enam.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../vc/v.out.h\ + ../include/ar.h\ + +LIBS=bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I ../include + +enam.$O: ../0c/enam.c + $CC $CFLAGS ../0c/enam.c diff --git a/utils/0l/noop.c b/utils/0l/noop.c new file mode 100644 index 00000000..21998947 --- /dev/null +++ b/utils/0l/noop.c @@ -0,0 +1,420 @@ +#include "l.h" + +void +noops(void) +{ + Prog *p, *p1, *q, *q1; + int o, curframe, curbecome, maxbecome; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + + q = P; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + 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; + + p->mark |= LABEL|LEAF|SYNC; + if(p->link) + p->link->mark |= LABEL; + curtext = p; + break; + + /* too hard, just leave alone */ + case AMOVW: + case AMOVV: + if(p->to.type == D_FCREG || + p->to.type == D_MREG) { + p->mark |= LABEL|SYNC; + break; + } + if(p->from.type == D_FCREG || + p->from.type == D_MREG) { + p->mark |= LABEL|SYNC; + addnop(p); + addnop(p); + nop.mfrom.count += 2; + nop.mfrom.outof += 2; + break; + } + break; + + /* too hard, just leave alone */ + case ACASE: + case ASYSCALL: + case AWORD: + case ATLBWR: + case ATLBWI: + case ATLBP: + case ATLBR: + p->mark |= LABEL|SYNC; + break; + + case ANOR: + if(p->to.type == D_REG && p->to.reg == REGZERO) + p->mark |= LABEL|SYNC; + break; + + case ARET: + /* special form of RET is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + + if(p->link != P) + p->link->mark |= LABEL; + break; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + case ABCASE: + p->mark |= LABEL|SYNC; + goto dstlab; + + case ABGEZAL: + case ABLTZAL: + case AJAL: + if(curtext != P) + curtext->mark &= ~LEAF; + + case AJMP: + case ABEQ: + case ABGEZ: + case ABGTZ: + case ABLEZ: + case ABLTZ: + case ABNE: + case ABFPT: + case ABFPF: + p->mark |= BRANCH; + + dstlab: + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + if(!(q1->mark & LEAF)) + q1->mark |= LABEL; + } else + p->mark |= LABEL; + q1 = p->link; + if(q1 != P) + q1->mark |= LABEL; + break; + } + q = p; + } + + 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 AJAL: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + for(p = firstp; p != P; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + curtext = p; + autosize = p->to.offset + 8; + if(autosize <= 8) + if(curtext->mark & LEAF) { + p->to.offset = -8; + autosize = 0; + } + + q = p; + if(autosize) { + if(autosize & 7) + Bprint(&bso, "odd stack in: %s\n", + curtext->from.sym->name); + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = -autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } else + if(!(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + Bflush(&bso); + curtext->mark |= LEAF; + } + + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; + break; + } + + q1 = prg(); + q1->as = AMOVW; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->from.offset = 0; + q1->to.reg = REGSP; + + q1->link = q->link; + q->link = q1; + break; + + case ARET: + nocache(p); + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + p->as = AJMP; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + p->mark |= BRANCH; + break; + } + + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_OREG; + q->to.offset = 0; + q->to.reg = REGLINK; + q->mark |= BRANCH; + + q->link = p->link; + p->link = q; + break; + } + p->as = AMOVW; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = 2; + + q = p; + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + + q1 = prg(); + q1->as = AJMP; + q1->line = p->line; + q1->to.type = D_OREG; + q1->to.offset = 0; + q1->to.reg = 2; + q1->mark |= BRANCH; + + q1->link = q->link; + q->link = q1; + break; + + become: + if(curtext->mark & LEAF) { + + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; + } + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + q = prg(); + q->line = p->line; + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + + p->as = AMOVW; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGLINK; + + break; + } + } + + curtext = P; + q = P; /* p - 1 */ + q1 = firstp; /* top of block */ + o = 0; /* count of instructions */ + for(p = firstp; p != P; p = p1) { + p1 = p->link; + o++; + if(p->mark & NOSCHED){ + if(q1 != p){ + sched(q1, q); + } + for(; p != P; p = p->link){ + if(!(p->mark & NOSCHED)) + break; + q = p; + } + p1 = p; + q1 = p; + o = 0; + continue; + } + if(p->mark & (LABEL|SYNC)) { + if(q1 != p) + sched(q1, q); + q1 = p; + o = 1; + } + if(p->mark & (BRANCH|SYNC)) { + sched(q1, p); + q1 = p1; + o = 0; + } + if(o >= NSCHED) { + sched(q1, p); + q1 = p1; + o = 0; + } + q = p; + } +} + +void +addnop(Prog *p) +{ + Prog *q; + + q = prg(); + q->as = ANOR; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGZERO; + q->to.type = D_REG; + q->to.reg = REGZERO; + + q->link = p->link; + p->link = q; +} + +void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} diff --git a/utils/0l/obj.c b/utils/0l/obj.c new file mode 100644 index 00000000..644925ac --- /dev/null +++ b/utils/0l/obj.c @@ -0,0 +1,1384 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = '0'; +char *thestring = "spim"; + +/* + * -H0 -T0x40004C -D0x10000000 is abbrev unix + * -H1 -T0x80020000 -R4 is bootp() format for 3k + * -H2 -T4128 -R4096 is plan9 spim format + * -H3 -T0x80020000 -R8 is bootp() format for 4k + * -H4 -T0x400000 -R4 is sgi unix coff executable + * -H5 -T0x4000A0 -R4 is sgi unix elf executable + * -H6 -T0x4000A0 -R4 is plan9 spim format + */ + +void +main(int argc, char *argv[]) +{ + int c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + outfile = 0; + nerrors = 0; + curtext = P; + 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': + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = 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 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + /* do something about setting INITTEXT */ + break; + } ARGEND + + USED(argc); + + if(*argv == 0) { + diag("usage: vl [-options] objects\n"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 0; + if(debug['B']) + HEADTYPE = 1; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + + case 0: /* unix simple */ + HEADR = 20L+56L; + if(INITTEXT == -1) + INITTEXT = 0x40004CL; + if(INITDAT == -1) + INITDAT = 0x10000000L; + if(INITRND == -1) + INITRND = 0; + break; + case 1: /* boot for 3k */ + HEADR = 20L+60L; + if(INITTEXT == -1) + INITTEXT = 0x80020000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 2: /* plan 9 spim */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* boot for 4k */ + HEADR = 20L+56L+3*40L; + if(INITTEXT == -1) + INITTEXT = 0x80020000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 8; + break; + case 4: /* sgi unix coff executable */ + HEADR = 20L+56L+3*40L; + if(INITTEXT == -1) + INITTEXT = 0x00400000L+HEADR; + if(INITDAT == -1) + INITDAT = 0x10000000; + if(INITRND == -1) + INITRND = 0; + break; + case 5: /* sgi unix elf executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0x00400000L+HEADR; + if(INITDAT == -1) + INITDAT = 0x10000000; + if(INITRND == -1) + INITRND = 0; + break; + case 6: /* plan 9 spim */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + 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); + zprg.as = AGOK; + zprg.reg = NREG; + zprg.from.name = D_NONE; + zprg.from.type = D_NONE; + zprg.from.reg = NREG; + zprg.to = zprg.from; + buildop(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + dtype = 4; + if(outfile == 0) + outfile = "0.out"; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("%s: cannot create\n", outfile); + errorexit(); + } + nuxiinit(); + + version = 0; + cbp = (uchar*)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) + goto out; + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + dodata(); + follow(); + if(firstp == P) + goto out; + noops(); + span(); + asmb(); + undef(); + +out: + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + 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) +{ + + Bflush(&bso); + 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\n", 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; + } + + if(debug['v']) + Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file); + l = read(f, &arhdr, SAR_HDR); + if(l != SAR_HDR) { + diag("%s: short read on archive file symbol header\n", file); + goto out; + } + if(strncmp(arhdr.name, symname, strlen(symname))) { + diag("%s: first entry not symbol header\n", 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\n", file, s->name); + errorexit(); + } + work = 1; + xrefresolv = 1; + } + } + return; + +bad: + diag("%s: bad or out of date archive\n", file); +out: + close(f); +} + +int +zaddr(uchar *p, Adr *a, Sym *h[]) +{ + int i, c; + long l; + Sym *s; + Auto *u; + + c = p[2]; + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + p[0] = ALAST+1; + return 0; + } + a->type = p[0]; + a->reg = p[1]; + a->sym = h[c]; + a->name = p[3]; + c = 4; + + if(a->reg < 0 || a->reg > NREG) { + print("register out of range %d\n", a->reg); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + case D_MREG: + case D_FCREG: + case D_LO: + case D_HI: + break; + + case D_BRANCH: + case D_OREG: + case D_CONST: + case D_OCONST: + a->offset = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + c += 4; + break; + + case D_SCONST: + a->sval = malloc(NSNAME); + memmove(a->sval, p+4, NSNAME); + c += NSNAME; + break; + + case D_VCONST: + case D_FCONST: + a->ieee = malloc(sizeof(Ieee)); + a->ieee->l = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + a->ieee->h = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + } + s = a->sym; + if(s == S) + return c; + i = a->name; + if(i != D_AUTO && i != D_PARAM) + return c; + + l = a->offset; + for(u=curauto; u; u=u->link) + if(u->asym == s) + if(u->type == i) { + 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 = i; + 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; + Sym *h[NSYM], *s, *di; + int v, o, r, skip; + + 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]; /* as */ + if(o <= AXXX || o >= ALAST) { + diag("%s: line %ld: opcode out of range %d\n", pn, pc-ipc, o); + print(" probably not a .v file\n"); + errorexit(); + } + if(o == ANAME || o == ASIGNAME) { + if(o == ASIGNAME) { + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[1]; /* type */ + o = bloc[2]; /* sym */ + bloc += 3; + c -= 3; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 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; + } + + if(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->reg = bloc[1] & 0x7f; + if(bloc[1] & 0x80) + p->mark = NOSCHED; + p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(p->reg < 0 || p->reg > NREG) + diag("register out of range %d\n", p->reg); + + p->link = P; + p->cond = P; + + if(debug['W']) + print("%P\n", p); + + switch(o) { + 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 == S) { + diag("GLOBL must have a name\n%P\n", p); + errorexit(); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("redefinition: %s\n%P\n", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset && s->value && p->to.offset != s->value) + print("warning: resize of a global: %s\n%P\n", s->name, p); + if(p->to.offset > s->value) + s->value = p->to.offset; + break; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P\n", p); + break; + } + di = p->to.sym; + p->reg = 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\n", p); + break; + } + p->to.sym = curtext->from.sym; + p->to.type = D_CONST; + p->link = datap; + datap = p; + break; + + case AINIT: + if(p->from.sym == S) { + diag("INIT without a sym\n%P\n", p); + break; + } + if(di == S) { + diag("INIT without previous DYNT\n%P\n", p); + break; + } + p->from.offset = di->value; + p->from.sym->type = SDATA; + p->link = datap; + datap = p; + break; + + case ADATA: + if(p->from.sym == S) { + diag("DATA without a sym\n%P\n", p); + break; + } + p->link = datap; + datap = p; + break; + + case AGOK: + diag("unknown opcode\n%P\n", p); + p->pc = pc; + pc++; + break; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + s = p->from.sym; + if(s == S) { + diag("TEXT must have a name\n%P\n", p); + errorexit(); + } + autosize = p->to.offset; + if(autosize & 7) { + diag("stack frame not 8 multiple: %s\n%P\n", s->name, p); + autosize = autosize + 7 & ~7; + p->to.offset = autosize; + } + autosize += 8; + if(s->type != 0 && s->type != SXREF) { + if(p->reg & DUPOK) { + skip = 1; + goto casedef; + } + diag("redefinition: %s\n%P\n", 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->cond = p; + etextp = p; + break; + + case ASUB: + case ASUBU: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) { + p->from.offset = -p->from.offset; + if(p->as == ASUB) + p->as = AADD; + else + p->as = AADDU; + } + goto casedef; + + case AMOVF: + if(skip) + goto casedef; + + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 4; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AMOVD: + if(skip) + goto casedef; + + if(p->from.type == D_FCONST) { + /* size sb 18 max */ + sprint(literal, "$%lux.%lux", + p->from.ieee->h, p->from.ieee->l); + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AMOVV: + if(skip) + goto casedef; + + if(p->from.type == D_VCONST) { + /* size sb 18 max */ + sprint(literal, "$%lux.%lux", + p->from.ieee->h, p->from.ieee->l); + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + default: + casedef: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + } + goto loop; + +eof: + diag("truncated object file: %s\n", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + 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); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + hash[h] = s; + 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; +} + +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\n"); + 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_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 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 = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDU; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_OREG; + p->to.name = 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_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 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\n"); + return; + } + + ps2 = P; + ps4 = P; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->from.sym == s2) { + ps2 = p; + p->reg = 1; + } + if(p->from.sym == s4) { + ps4 = p; + p->reg = 1; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->reg & NOPROF) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * JAL profin, R2 + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AJAL; + p->to.type = D_BRANCH; + p->cond = 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 = AJAL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = 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; +} + +vlong +ieeedtov(Ieee *ieeep) +{ + vlong v; + + v = (vlong)ieeep->l & (vlong)0xffffffff; + v |= (vlong)ieeep->h << 32; + return v; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->l >> 28) & 1) { + v++; + if(v & 0x800000L) { + v = (v & 0x7fffffL) >> 1; + exp++; + } + } + if(exp <= -126 || exp >= 130) + diag("double fp to single fp overflow\n"); + v |= ((exp + 126) & 0xffL) << 23; + v |= ieeep->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); +} diff --git a/utils/0l/optab.c b/utils/0l/optab.c new file mode 100644 index 00000000..d788c013 --- /dev/null +++ b/utils/0l/optab.c @@ -0,0 +1,221 @@ +#include "l.h" + +#define X 99 + +Optab optab[] = +{ + { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, + + { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0 }, + { AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0 }, + { AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0 }, + + { ASUB, C_REG, C_REG, C_REG, 2, 4, 0 }, + { AADD, C_REG, C_REG, C_REG, 2, 4, 0 }, + { AAND, C_REG, C_REG, C_REG, 2, 4, 0 }, + { ASUB, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AADD, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AAND, C_REG, C_NONE, C_REG, 2, 4, 0 }, + + { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, + { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, + + { AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0 }, + { AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0 }, + { ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0 }, + { AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0 }, + { AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0 }, + { AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + + { AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVW, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVV, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVB, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVBU, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVWL, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVV, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVB, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVBU, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVWL, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + + { AMOVW, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVV, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVB, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVBU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVW, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVV, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVB, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVW, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + { AMOVV, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + { AMOVB, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + { AMOVBU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + + { AMOVW, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVV, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVB, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVBU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVW, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVV, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVB, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVBU, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVW, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + { AMOVV, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + { AMOVB, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + { AMOVBU, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + + { AMOVW, C_SECON,C_NONE, C_REG, 3, 4, REGSB }, + { AMOVW, C_SACON,C_NONE, C_REG, 3, 4, REGSP }, + { AMOVW, C_LECON,C_NONE, C_REG, 26, 12, REGSB }, + { AMOVW, C_LACON,C_NONE, C_REG, 26, 12, REGSP }, + { AMOVW, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO }, + { AMOVV, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO }, + { AMOVW, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO }, + { AMOVV, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO }, + + { AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0 }, + { AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0 }, + { AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0 }, + { AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0 }, + + { AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0 }, + { AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0 }, + { AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0 }, + { AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0 }, + + { AMUL, C_REG, C_REG, C_NONE, 22, 4, 0 }, + + { AADD, C_ADD0CON,C_REG,C_REG, 4, 4, 0 }, + { AADD, C_ADD0CON,C_NONE,C_REG, 4, 4, 0 }, + { AADD, C_ANDCON,C_REG, C_REG, 10, 8, 0 }, + { AADD, C_ANDCON,C_NONE,C_REG, 10, 8, 0 }, + + { AAND, C_AND0CON,C_REG,C_REG, 4, 4, 0 }, + { AAND, C_AND0CON,C_NONE,C_REG, 4, 4, 0 }, + { AAND, C_ADDCON,C_REG, C_REG, 10, 8, 0 }, + { AAND, C_ADDCON,C_NONE,C_REG, 10, 8, 0 }, + + { AADD, C_UCON, C_REG, C_REG, 25, 8, 0 }, + { AADD, C_UCON, C_NONE, C_REG, 25, 8, 0 }, + { AAND, C_UCON, C_REG, C_REG, 25, 8, 0 }, + { AAND, C_UCON, C_NONE, C_REG, 25, 8, 0 }, + + { AADD, C_LCON, C_NONE, C_REG, 23, 12, 0 }, + { AAND, C_LCON, C_NONE, C_REG, 23, 12, 0 }, + { AADD, C_LCON, C_REG, C_REG, 23, 12, 0 }, + { AAND, C_LCON, C_REG, C_REG, 23, 12, 0 }, + + { ASLL, C_SCON, C_REG, C_REG, 16, 4, 0 }, + { ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0 }, + + { ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0 }, + + { ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0 }, + { ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0 }, + { ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0 }, + { ABFPT, C_NONE, C_NONE, C_SBRA, 6, 4, 0 }, + + { AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, + { AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, + + { AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO }, + { AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK }, + + { AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB }, + { AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB }, + { AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB }, + { AMOVW, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP }, + { AMOVF, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP }, + { AMOVD, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO }, + { AMOVF, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO }, + { AMOVD, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO }, + + { AMOVW, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB }, + { AMOVF, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB }, + { AMOVD, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB }, + { AMOVW, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP }, + { AMOVF, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP }, + { AMOVD, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP }, + { AMOVW, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO }, + { AMOVF, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO }, + { AMOVD, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO }, + + { AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB }, + { AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB }, + { AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB }, + { AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP }, + { AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP }, + { AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP }, + { AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO }, + { AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO }, + { AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO }, + + { AMOVW, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB }, + { AMOVF, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB }, + { AMOVD, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB }, + { AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP }, + { AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP }, + { AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP }, + { AMOVW, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO }, + { AMOVF, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO }, + { AMOVD, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO }, + + { AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0 }, + { AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0 }, + { AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0 }, + + { AMOVW, C_ADDCON,C_NONE,C_FREG, 34, 8, 0 }, + { AMOVW, C_ANDCON,C_NONE,C_FREG, 34, 8, 0 }, + { AMOVW, C_UCON, C_NONE, C_FREG, 35, 8, 0 }, + { AMOVW, C_LCON, C_NONE, C_FREG, 36, 12, 0 }, + + { AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0 }, + { AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0 }, + { AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0 }, + + { ARFE, C_NONE, C_NONE, C_ZOREG, 39, 8, 0 }, + { AWORD, C_NONE, C_NONE, C_LCON, 40, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0 }, + { AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0 }, + { AMOVW, C_FCREG,C_NONE, C_REG, 42, 4, 0 }, + { AMOVV, C_FCREG,C_NONE, C_REG, 42, 4, 0 }, + + { ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, /* really CACHE instruction */ + { ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0 }, + + { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, +}; diff --git a/utils/0l/pass.c b/utils/0l/pass.c new file mode 100644 index 00000000..95c4a754 --- /dev/null +++ b/utils/0l/pass.c @@ -0,0 +1,498 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p, *p1; + long orig, orig1, v; + + 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\n", + s->type, s->name, p); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%ld): %s\n%P\n", + s->value, s->name, p); + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rational is that data segment is more easily + * addressed through offset on R30) + */ + orig = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size\n", s->name); + v = 1; + } + while(v & 7) + v++; + s->value = v; + if(v > MINSIZ) + continue; + s->value = orig; + orig += v; + s->type = SDATA1; + } + orig1 = orig; + + /* + * pass 2 + * assign 'data' variables to data segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + while(v & 7) + v++; + s->value = orig; + orig += v; + s->type = SDATA1; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + v = s->value; + while(v & 7) + v++; + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + /* + * pass 4 + * add literals to all large values. + * at this time: + * small data is allocated DATA + * large data is allocated DATA1 + * large bss is allocated BSS + * the new literals are loaded between + * small data and large data. + */ + orig = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as != AMOVW) + continue; + if(p->from.type != D_CONST) + continue; + if(s = p->from.sym) { + t = s->type; + if(t != SDATA && t != SDATA1 && t != SBSS) + continue; + t = p->from.name; + if(t != D_EXTERN && t != D_STATIC) + continue; + v = s->value + p->from.offset; + if(v >= 0 && v <= 0xffff) + continue; + if(!strcmp(s->name, "setR30")) + continue; + /* size should be 19 max */ + if(strlen(s->name) >= 10) /* has loader address */ + sprint(literal, "$%lux.%lux", (long)s, p->from.offset); + else + sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset); + } else { + if(p->from.name != D_NONE) + continue; + if(p->from.reg != NREG) + continue; + v = p->from.offset; + if(v >= -0x7fff && v <= 0xffff) + continue; + if(!(v & 0xffff)) + continue; + /* size should be 9 max */ + sprint(literal, "$%lux", v); + } + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + s->value = orig1+orig; + orig += 8; + p1 = prg(); + p1->line = p->line; + p1->as = ADATA; + p1->from.type = D_OREG; + p1->from.sym = s; + p1->from.name = D_EXTERN; + p1->reg = 4; + p1->to = p->from; + p1->link = datap; + datap = p1; + } + if(s->type != SDATA) + diag("literal not data: %s", s->name); + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + nocache(p); + continue; + } + while(orig & 7) + orig++; + /* + * pass 5 + * re-adjust offsets + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t == SBSS) { + s->value += orig; + continue; + } + if(t == SDATA1) { + s->type = SDATA; + s->value += orig; + continue; + } + } + datsize += orig; + xdefine("setR30", SDATA, 0L+BIG); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +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\n", s->name); +} + +void +follow(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(a == AJMP) { + q = p->cond; + if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){ + p->mark |= FOLL; + lastp->link = p; + lastp = p; + p = p->link; + xfol(p); + p = q; + if(p && !(p->mark & FOLL)) + goto loop; + return; + } + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp || (q->mark&NOSCHED)) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == AJMP || a == ARET || a == ARFE) + goto copy; + if(!q->cond || (q->cond->mark&FOLL)) + continue; + if(a != ABEQ && a != ABNE) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(a == AJMP || a == ARET || a == ARFE) + return; + r->as = ABNE; + if(a == ABNE) + r->as = ABEQ; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + a = AJMP; + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(a == AJMP || a == ARET || a == ARFE){ + if(p->mark & NOSCHED){ + p = p->link; + goto loop; + } + return; + } + if(p->cond != P) + if(a != AJAL && p->link != P) { + xfol(p->link); + p = p->cond; + if(p == P || (p->mark&FOLL)) + return; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((a == AJAL || a == AJMP || a == ARET) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT) { + diag("undefined: %s\n%P\n", s->name, p); + s->type = STEXT; + s->value = vexit; + } + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH) + 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 %ld\n%P\n", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->cond != P) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + 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) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(p->as != AJMP || (p->mark&NOSCHED)) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +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; +} + +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; +} diff --git a/utils/0l/sched.c b/utils/0l/sched.c new file mode 100644 index 00000000..28e78f28 --- /dev/null +++ b/utils/0l/sched.c @@ -0,0 +1,709 @@ +#include "l.h" + +enum +{ + E_HILO = 1<<0, + E_FCR = 1<<1, + E_MCR = 1<<2, + E_MEM = 1<<3, + E_MEMSP = 1<<4, /* uses offset and size */ + E_MEMSB = 1<<5, /* uses offset and size */ + ANYMEM = E_MEM|E_MEMSP|E_MEMSB, + DELAY = BRANCH|LOAD|FCMP, +}; + +typedef struct Sch Sch; +typedef struct Dep Dep; + +struct Dep +{ + ulong ireg; + ulong freg; + ulong cc; +}; +struct Sch +{ + Prog p; + Dep set; + Dep used; + long soffset; + char size; + char nop; + char comp; +}; + +void markregused(Sch*, Prog*); +int depend(Sch*, Sch*); +int conflict(Sch*, Sch*); +int offoverlap(Sch*, Sch*); +void dumpbits(Sch*, Dep*); + +void +sched(Prog *p0, Prog *pe) +{ + Prog *p, *q; + Sch sch[NSCHED], *s, *t, *u, *se, stmp; + + /* + * build side structure + */ + s = sch; + for(p=p0;; p=p->link) { + memset(s, 0, sizeof(*s)); + s->p = *p; + markregused(s, p); + if(debug['X']) { + Bprint(&bso, "%P%|set", &s->p, 40); + dumpbits(s, &s->set); + Bprint(&bso, "; used"); + dumpbits(s, &s->used); + if(s->comp) + Bprint(&bso, "; compound"); + if(s->p.mark & LOAD) + Bprint(&bso, "; load"); + if(s->p.mark & BRANCH) + Bprint(&bso, "; branch"); + if(s->p.mark & FCMP) + Bprint(&bso, "; fcmp"); + Bprint(&bso, "\n"); + } + if(p == pe) + break; + s++; + } + se = s; + + /* + * prepass to move things around + * does nothing, but tries to make + * the actual scheduler work better + */ + for(s=sch; s<=se; s++) { + if(!(s->p.mark & LOAD)) + continue; + /* always good to put nonconflict loads together */ + for(t=s+1; t<=se; t++) { + if(!(t->p.mark & LOAD)) + continue; + if(t->p.mark & BRANCH) + break; + if(conflict(s, t)) + break; + for(u=t-1; u>s; u--) + if(depend(u, t)) + goto no11; + u = s+1; + stmp = *t; + memmove(s+2, u, (uchar*)t - (uchar*)u); + *u = stmp; + break; + } + no11: + + /* put schedule fodder above load */ + for(t=s+1; t<=se; t++) { + if(t->p.mark & BRANCH) + break; + if(s > sch && conflict(s-1, t)) + continue; + for(u=t-1; u>=s; u--) + if(depend(t, u)) + goto no1; + stmp = *t; + memmove(s+1, s, (uchar*)t - (uchar*)s); + *s = stmp; + if(!(s->p.mark & LOAD)) + break; + no1:; + } + } + + for(s=se; s>=sch; s--) { + if(!(s->p.mark & DELAY)) + continue; + if(s < se) + if(!conflict(s, s+1)) + goto out3; + /* + * s is load, s+1 is immediate use of result or end of block + * t is the trial instruction to insert between s and s+1 + */ + if(!debug['Y']) + for(t=s-1; t>=sch; t--) { + if(t->comp) + if(s->p.mark & BRANCH) + goto no2; + if(t->p.mark & DELAY) + if(s >= se || conflict(t, s+1)) + goto no2; + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no2; + goto out2; + no2:; + } + if(debug['X']) + Bprint(&bso, "?l%P\n", &s->p); + if(s->p.mark & BRANCH) + s->nop = 1; + if(debug['v']) { + if(s->p.mark & LOAD) { + nop.load.count++; + nop.load.outof++; + } + if(s->p.mark & BRANCH) { + nop.branch.count++; + nop.branch.outof++; + } + if(s->p.mark & FCMP) { + nop.fcmp.count++; + nop.fcmp.outof++; + } + } + continue; + + out2: + if(debug['X']) { + Bprint(&bso, "!l%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + + out3: + if(debug['v']) { + if(s->p.mark & LOAD) + nop.load.outof++; + if(s->p.mark & BRANCH) + nop.branch.outof++; + if(s->p.mark & FCMP) + nop.fcmp.outof++; + } + } + + /* Avoid HI/LO use->set */ + t = sch+1; + for(s=sch; s<se-1; s++, t++) { + if((s->used.cc & E_HILO) == 0) + continue; + if(t->set.cc & E_HILO) + s->nop = 2; + } + + /* + * put it all back + */ + for(s=sch, p=p0; s<=se; s++, p=q) { + q = p->link; + if(q != s->p.link) { + *p = s->p; + p->link = q; + } + while(s->nop--) + addnop(p); + } + if(debug['X']) { + Bprint(&bso, "\n"); + Bflush(&bso); + } +} + +void +markregused(Sch *s, Prog *realp) +{ + int c, ar, ad, ld, sz; + ulong m; + Prog *p; + + p = &s->p; + s->comp = compound(p); + s->nop = 0; + if(s->comp) { + s->set.ireg |= 1<<REGTMP; + s->used.ireg |= 1<<REGTMP; + } + + ar = 0; /* dest is really reference */ + ad = 0; /* source/dest is really address */ + ld = 0; /* opcode is load instruction */ + sz = 20; /* size of load/store for overlap computation */ + +/* + * flags based on opcode + */ + switch(p->as) { + case ATEXT: + curtext = realp; + autosize = p->to.offset + 8; + ad = 1; + break; + case AJAL: + c = p->reg; + if(c == NREG) + c = REGLINK; + s->set.ireg |= 1<<c; + ar = 1; + ad = 1; + break; + case ABGEZAL: + case ABLTZAL: + s->set.ireg |= 1<<REGLINK; + case ABEQ: + case ABGEZ: + case ABGTZ: + case ABLEZ: + case ABLTZ: + case ABNE: + ar = 1; + ad = 1; + break; + case ABFPT: + case ABFPF: + ad = 1; + s->used.cc |= E_FCR; + break; + case ACMPEQD: + case ACMPEQF: + case ACMPGED: + case ACMPGEF: + case ACMPGTD: + case ACMPGTF: + ar = 1; + s->set.cc |= E_FCR; + p->mark |= FCMP; + break; + case AJMP: + ar = 1; + ad = 1; + break; + case AMOVB: + case AMOVBU: + sz = 1; + ld = 1; + break; + case AMOVH: + case AMOVHU: + sz = 2; + ld = 1; + break; + case AMOVF: + case AMOVW: + case AMOVWL: + case AMOVWR: + sz = 4; + ld = 1; + break; + case AMOVD: + case AMOVV: + case AMOVVL: + case AMOVVR: + sz = 8; + ld = 1; + break; + case ADIV: + case ADIVU: + case AMUL: + case AMULU: + case AREM: + case AREMU: + case ADIVV: + case ADIVVU: + case AMULV: + case AMULVU: + case AREMV: + case AREMVU: + s->set.cc = E_HILO; + case AADD: + case AADDU: + case AADDV: + case AADDVU: + case AAND: + case ANOR: + case AOR: + case ASGT: + case ASGTU: + case ASLL: + case ASRA: + case ASRL: + case ASLLV: + case ASRAV: + case ASRLV: + case ASUB: + case ASUBU: + case ASUBV: + case ASUBVU: + case AXOR: + + case AADDD: + case AADDF: + case AADDW: + case ASUBD: + case ASUBF: + case ASUBW: + case AMULF: + case AMULD: + case AMULW: + case ADIVF: + case ADIVD: + case ADIVW: + if(p->reg == NREG) { + if(p->to.type == D_REG || p->to.type == D_FREG) + p->reg = p->to.reg; + if(p->reg == NREG) + print("botch %P\n", p); + } + break; + } + +/* + * flags based on 'to' field + */ + c = p->to.class; + if(c == 0) { + c = aclass(&p->to) + 1; + p->to.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->to); + + case C_ZCON: + case C_SCON: + case C_ADD0CON: + case C_AND0CON: + case C_ADDCON: + case C_ANDCON: + case C_UCON: + case C_LCON: + case C_NONE: + case C_SBRA: + case C_LBRA: + break; + + case C_HI: + case C_LO: + s->set.cc |= E_HILO; + break; + case C_FCREG: + s->set.cc |= E_FCR; + break; + case C_MREG: + s->set.cc |= E_MCR; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + c = p->to.reg; + s->used.ireg |= 1<<c; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + if(ar) + s->used.cc |= m; + else + s->set.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + if(ar) + s->used.ireg |= 1<<p->to.reg; + else + s->set.ireg |= 1<<p->to.reg; + break; + case C_FREG: + /* do better -- determine double prec */ + if(ar) { + s->used.freg |= 1<<p->to.reg; + s->used.freg |= 1<<(p->to.reg|1); + } else { + s->set.freg |= 1<<p->to.reg; + s->set.freg |= 1<<(p->to.reg|1); + } + if(ld && p->from.type == D_REG) + p->mark |= LOAD; + break; + case C_SAUTO: + case C_LAUTO: + s->used.ireg |= 1<<REGSP; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSP; + else + s->set.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + s->used.ireg |= 1<<REGSB; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSB; + else + s->set.cc |= E_MEMSB; + break; + } + +/* + * flags based on 'from' field + */ + c = p->from.class; + if(c == 0) { + c = aclass(&p->from) + 1; + p->from.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->from); + + case C_ZCON: + case C_SCON: + case C_ADD0CON: + case C_AND0CON: + case C_ADDCON: + case C_ANDCON: + case C_UCON: + case C_LCON: + case C_NONE: + case C_SBRA: + case C_LBRA: + break; + case C_HI: + case C_LO: + s->used.cc |= E_HILO; + break; + case C_FCREG: + s->used.cc |= E_FCR; + break; + case C_MREG: + s->used.cc |= E_MCR; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + c = p->from.reg; + s->used.ireg |= 1<<c; + if(ld) + p->mark |= LOAD; + s->size = sz; + s->soffset = regoff(&p->from); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + s->used.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + s->used.ireg |= 1<<p->from.reg; + break; + case C_FREG: + /* do better -- determine double prec */ + s->used.freg |= 1<<p->from.reg; + s->used.freg |= 1<<(p->from.reg|1); + if(ld && p->to.type == D_REG) + p->mark |= LOAD; + break; + case C_SAUTO: + case C_LAUTO: + s->used.ireg |= 1<<REGSP; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + s->used.ireg |= 1<<REGSB; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSB; + break; + } + + c = p->reg; + if(c != NREG) { + if(p->from.type == D_FREG || p->to.type == D_FREG) { + s->used.freg |= 1<<c; + s->used.freg |= 1<<(c|1); + } else + s->used.ireg |= 1<<c; + } + s->set.ireg &= ~(1<<REGZERO); /* R0 cant be set */ +} + +/* + * test to see if 2 instrictions can be + * interchanged without changing semantics + */ +int +depend(Sch *sa, Sch *sb) +{ + ulong x; + + if(sa->set.ireg & (sb->set.ireg|sb->used.ireg)) + return 1; + if(sb->set.ireg & sa->used.ireg) + return 1; + + if(sa->set.freg & (sb->set.freg|sb->used.freg)) + return 1; + if(sb->set.freg & sa->used.freg) + return 1; + + /* + * special case. + * loads from same address cannot pass. + * this is for hardware fifo's and the like + */ + if(sa->used.cc & sb->used.cc & E_MEM) + if(sa->p.reg == sb->p.reg) + if(regoff(&sa->p.from) == regoff(&sb->p.from)) + return 1; + + x = (sa->set.cc & (sb->set.cc|sb->used.cc)) | + (sb->set.cc & sa->used.cc); + if(x) { + /* + * allow SB and SP to pass each other. + * allow SB to pass SB iff doffsets are ok + * anything else conflicts + */ + if(x != E_MEMSP && x != E_MEMSB) + return 1; + x = sa->set.cc | sb->set.cc | + sa->used.cc | sb->used.cc; + if(x & E_MEM) + return 1; + if(offoverlap(sa, sb)) + return 1; + } + + return 0; +} + +int +offoverlap(Sch *sa, Sch *sb) +{ + + if(sa->soffset < sb->soffset) { + if(sa->soffset+sa->size > sb->soffset) + return 1; + return 0; + } + if(sb->soffset+sb->size > sa->soffset) + return 1; + return 0; +} + +/* + * test 2 adjacent instructions + * and find out if inserted instructions + * are desired to prevent stalls. + */ +int +conflict(Sch *sa, Sch *sb) +{ + + if(sa->set.ireg & sb->used.ireg) + return 1; + if(sa->set.freg & sb->used.freg) + return 1; + if(sa->set.cc & sb->used.cc) + return 1; + + return 0; +} + +int +compound(Prog *p) +{ + Optab *o; + + o = oplook(p); + if(o->size != 4) + return 1; + if(p->to.type == D_REG && p->to.reg == REGSB) + return 1; + return 0; +} + +void +dumpbits(Sch *s, Dep *d) +{ + int i; + + for(i=0; i<32; i++) + if(d->ireg & (1<<i)) + Bprint(&bso, " R%d", i); + for(i=0; i<32; i++) + if(d->freg & (1<<i)) + Bprint(&bso, " F%d", i); + for(i=0; i<32; i++) + switch(d->cc & (1<<i)) { + default: + break; + case E_HILO: + Bprint(&bso, " HILO"); + break; + case E_FCR: + Bprint(&bso, " FCR"); + break; + case E_MCR: + Bprint(&bso, " MCR"); + break; + case E_MEM: + Bprint(&bso, " MEM%d", s->size); + break; + case E_MEMSB: + Bprint(&bso, " SB%d", s->size); + break; + case E_MEMSP: + Bprint(&bso, " SP%d", s->size); + break; + } +} diff --git a/utils/0l/span.c b/utils/0l/span.c new file mode 100644 index 00000000..3c9d2d50 --- /dev/null +++ b/utils/0l/span.c @@ -0,0 +1,628 @@ +#include "l.h" + +void +span(void) +{ + Prog *p, *q; + Sym *setext; + Optab *o; + int m, bflag; + long c, otxt; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + + bflag = 0; + c = INITTEXT; + otxt = c; + for(p = firstp; p != P; p = p->link) { + p->pc = c; + o = oplook(p); + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 8; + if(p->from.sym != S) + p->from.sym->value = c; + /* need passes to resolve branches */ + if(c-otxt >= 1L<<17) + bflag = 1; + otxt = c; + continue; + } + diag("zero-width instruction\n%P\n", p); + continue; + } + c += m; + } + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + while(bflag) { + if(debug['v']) + Bprint(&bso, "%5.2f span1\n", cputime()); + bflag = 0; + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + p->pc = c; + o = oplook(p); + if(o->type == 6 && p->cond) { + otxt = p->cond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = prg(); + q->link = p->link; + p->link = q; + q->as = AJMP; + q->to.type = D_BRANCH; + q->cond = p->cond; + p->cond = q; + q = prg(); + q->link = p->link; + p->link = q; + q->as = AJMP; + q->to.type = D_BRANCH; + q->cond = q->link->link; + addnop(p->link); + addnop(p); + bflag = 1; + } + } + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 8; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + diag("zero-width instruction\n%P\n", p); + continue; + } + c += m; + } + } + c = rnd(c, 8); + + setext = lookup("etext", 0); + if(setext != S) { + setext->value = c; + textsize = c - INITTEXT; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(debug['v']) + Bprint(&bso, "tsize = %lux\n", textsize); + Bflush(&bso); +} + +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; + } +} + +long +regoff(Adr *a) +{ + + instoffset = 0; + aclass(a); + return instoffset; +} + +int +aclass(Adr *a) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_FREG: + return C_FREG; + + case D_FCREG: + return C_FCREG; + + case D_MREG: + return C_MREG; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == 0 || a->sym->name == 0) { + print("null sym external\n"); + print("%D\n", a); + return C_GOK; + } + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s\n", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + instoffset = a->sym->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SEXT; + return C_LEXT; + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + + case D_PARAM: + instoffset = autosize + a->offset + 8L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + case D_NONE: + instoffset = a->offset; + if(instoffset == 0) + return C_ZOREG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SOREG; + return C_LOREG; + } + return C_GOK; + + case D_HI: + return C_LO; + case D_LO: + return C_HI; + + case D_OCONST: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + s = a->sym; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s\n", + s->name, TNAME); + s->type = SDATA; + } + instoffset = s->value + a->offset + INITDAT; + if(s->type == STEXT || s->type == SLEAF) + instoffset = s->value + a->offset; + return C_LCON; + } + return C_GOK; + + case D_CONST: + switch(a->name) { + + case D_NONE: + instoffset = a->offset; + consize: + if(instoffset > 0) { + if(instoffset <= 0x7fff) + return C_SCON; + if(instoffset <= 0xffff) + return C_ANDCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + } + if(instoffset == 0) + return C_ZCON; + if(instoffset >= -0x8000) + return C_ADDCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == S) + break; + t = s->type; + switch(t) { + case 0: + case SXREF: + diag("undefined external: %s in %s\n", + s->name, TNAME); + s->type = SDATA; + break; + case SCONST: + instoffset = s->value + a->offset; + goto consize; + case STEXT: + case SLEAF: + instoffset = s->value + a->offset; + return C_LCON; + } + instoffset = s->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L) + return C_SECON; + instoffset = s->value + a->offset + INITDAT; + return C_LCON; + + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + + case D_PARAM: + instoffset = autosize + a->offset + 8L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +Optab* +oplook(Prog *p) +{ + int a1, a2, a3, r, t; + char *c1, *c3; + Optab *o, *e; + + a1 = p->optab; + if(a1) + return optab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + a1 = aclass(&p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->to.class; + if(a3 == 0) { + a3 = aclass(&p->to) + 1; + p->to.class = a3; + } + a3--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = oprange[r].start; + if(o == 0) { + t = opcross[repop[r]][a1][a2][a3]; + if(t) { + p->optab = t+1; + return optab+t; + } + o = oprange[r].stop; /* just generate an error */ + } + e = oprange[r].stop; + c1 = xcmp[a1]; + c3 = xcmp[a3]; + for(; o<e; o++) + if(o->a2 == a2) + if(c1[o->a1]) + if(c3[o->a3]) { + p->optab = (o-optab)+1; + return o; + } + diag("illegal combination %A %d %d %d", + p->as, a1, a2, a3); + if(!debug['a']) + prasm(p); + o = optab; + p->optab = (o-optab)+1; + return o; +} + +int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_ZCON || b == C_SCON || b == C_UCON || + b == C_ADDCON || b == C_ANDCON) + return 1; + break; + case C_ADD0CON: + if(b == C_ADDCON) + return 1; + case C_ADDCON: + if(b == C_ZCON || b == C_SCON) + return 1; + break; + case C_AND0CON: + if(b == C_ANDCON) + return 1; + case C_ANDCON: + if(b == C_ZCON || b == C_SCON) + return 1; + break; + case C_UCON: + if(b == C_ZCON) + return 1; + break; + case C_SCON: + if(b == C_ZCON) + return 1; + break; + case C_LACON: + if(b == C_SACON) + return 1; + break; + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + case C_LEXT: + if(b == C_SEXT) + return 1; + break; + case C_LAUTO: + if(b == C_SAUTO) + return 1; + break; + case C_REG: + if(b == C_ZCON) + return 1; + break; + case C_LOREG: + if(b == C_ZOREG || b == C_SOREG) + return 1; + break; + case C_SOREG: + if(b == C_ZOREG) + return 1; + break; + } + return 0; +} + +int +ocmp(const void *a1, const void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = (Optab*)a1; + p2 = (Optab*)a2; + n = p1->as - p2->as; + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a2 - p2->a2; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + return 0; +} + +void +buildop(void) +{ + int i, n, r; + + for(i=0; i<32; i++) + for(n=0; n<32; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) + ; + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + diag("unknown op in build: %A\n", r); + errorexit(); + case AABSF: + oprange[AMOVFD] = oprange[r]; + oprange[AMOVDF] = oprange[r]; + oprange[AMOVWF] = oprange[r]; + oprange[AMOVFW] = oprange[r]; + oprange[AMOVWD] = oprange[r]; + oprange[AMOVDW] = oprange[r]; + oprange[ANEGF] = oprange[r]; + oprange[ANEGD] = oprange[r]; + oprange[AABSD] = oprange[r]; + oprange[ATRUNCDW] = oprange[r]; + oprange[ATRUNCFW] = oprange[r]; + oprange[ATRUNCDV] = oprange[r]; + oprange[ATRUNCFV] = oprange[r]; + oprange[AMOVDV] = oprange[r]; + oprange[AMOVFV] = oprange[r]; + oprange[AMOVVD] = oprange[r]; + oprange[AMOVVF] = oprange[r]; + break; + case AADD: + buildrep(1, AADD); + oprange[ASGT] = oprange[r]; + repop[ASGT] = 1; + oprange[ASGTU] = oprange[r]; + repop[ASGTU] = 1; + oprange[AADDU] = oprange[r]; + repop[AADDU] = 1; + oprange[AADDVU] = oprange[r]; + repop[AADDVU] = 1; + oprange[AADDV] = oprange[r]; + repop[AADDV] = 1; + break; + case AADDF: + oprange[ADIVF] = oprange[r]; + oprange[ADIVD] = oprange[r]; + oprange[AMULF] = oprange[r]; + oprange[AMULD] = oprange[r]; + oprange[ASUBF] = oprange[r]; + oprange[ASUBD] = oprange[r]; + oprange[AADDD] = oprange[r]; + break; + case AAND: + buildrep(2, AAND); + oprange[AXOR] = oprange[r]; + repop[AXOR] = 2; + oprange[AOR] = oprange[r]; + repop[AOR] = 2; + break; + case ABEQ: + oprange[ABNE] = oprange[r]; + break; + case ABLEZ: + oprange[ABGEZ] = oprange[r]; + oprange[ABGEZAL] = oprange[r]; + oprange[ABLTZ] = oprange[r]; + oprange[ABLTZAL] = oprange[r]; + oprange[ABGTZ] = oprange[r]; + break; + case AMOVB: + buildrep(3, AMOVB); + oprange[AMOVH] = oprange[r]; + repop[AMOVH] = 3; + break; + case AMOVBU: + buildrep(4, AMOVBU); + oprange[AMOVHU] = oprange[r]; + repop[AMOVHU] = 4; + break; + case AMUL: + oprange[AREM] = oprange[r]; + oprange[AREMU] = oprange[r]; + oprange[ADIVU] = oprange[r]; + oprange[AMULU] = oprange[r]; + oprange[ADIV] = oprange[r]; + oprange[ADIVV] = oprange[r]; + oprange[ADIVVU] = oprange[r]; + oprange[AMULV] = oprange[r]; + oprange[AMULVU] = oprange[r]; + oprange[AREMV] = oprange[r]; + oprange[AREMVU] = oprange[r]; + break; + case ASLL: + oprange[ASRL] = oprange[r]; + oprange[ASRA] = oprange[r]; + oprange[ASLLV] = oprange[r]; + oprange[ASRAV] = oprange[r]; + oprange[ASRLV] = oprange[r]; + break; + case ASUB: + oprange[ASUBU] = oprange[r]; + oprange[ASUBV] = oprange[r]; + oprange[ASUBVU] = oprange[r]; + oprange[ANOR] = oprange[r]; + break; + case ASYSCALL: + oprange[ATLBP] = oprange[r]; + oprange[ATLBR] = oprange[r]; + oprange[ATLBWI] = oprange[r]; + oprange[ATLBWR] = oprange[r]; + break; + case ACMPEQF: + oprange[ACMPGTF] = oprange[r]; + oprange[ACMPGTD] = oprange[r]; + oprange[ACMPGEF] = oprange[r]; + oprange[ACMPGED] = oprange[r]; + oprange[ACMPEQD] = oprange[r]; + break; + case ABFPT: + oprange[ABFPF] = oprange[r]; + break; + case AMOVWL: + oprange[AMOVWR] = oprange[r]; + oprange[AMOVVR] = oprange[r]; + oprange[AMOVVL] = oprange[r]; + break; + case AMOVW: + buildrep(5, AMOVW); + break; + case AMOVD: + buildrep(6, AMOVD); + break; + case AMOVF: + buildrep(7, AMOVF); + break; + case AMOVV: + buildrep(8, AMOVV); + break; + case ABREAK: + case AWORD: + case ARFE: + case AJAL: + case AJMP: + case ATEXT: + case ACASE: + case ABCASE: + case AMOVWU: + break; + } + } +} + +void +buildrep(int x, int as) +{ + Opcross *p; + Optab *e, *s, *o; + int a1, a2, a3, n; + + if(C_NONE != 0 || + C_REG != 1 || + C_GOK >= 32 || + x >= nelem(opcross)) { + diag("assumptions fail in buildrep"); + errorexit(); + } + repop[as] = x; + p = (opcross + x); + s = oprange[as].start; + e = oprange[as].stop; + for(o=e-1; o>=s; o--) { + n = o-optab; + for(a2=0; a2<2; a2++) { + if(a2) { + if(o->a2 == C_NONE) + continue; + } else + if(o->a2 != C_NONE) + continue; + for(a1=0; a1<32; a1++) { + if(!xcmp[a1][o->a1]) + continue; + for(a3=0; a3<32; a3++) + if(xcmp[a3][o->a3]) + (*p)[a1][a2][a3] = n; + } + } + } + oprange[as].start = 0; +} diff --git a/utils/1a/a.h b/utils/1a/a.h new file mode 100644 index 00000000..7c064db1 --- /dev/null +++ b/utils/1a/a.h @@ -0,0 +1,198 @@ +#include <lib9.h> +#include <bio.h> +#include "../2c/2.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 Addr Addr; +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 Addr +{ + Sym* sym; + long offset; + short type; +}; +struct Gen +{ + Addr s0; + double dval; + char sval[8]; + long displace; + short type; + short field; +}; +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; + +int assemble(char*); +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 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*); + +/* + * compat + */ +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); diff --git a/utils/1a/a.y b/utils/1a/a.y new file mode 100644 index 00000000..626154d5 --- /dev/null +++ b/utils/1a/a.y @@ -0,0 +1,402 @@ +%{ +#include "a.h" +%} +%union { + Sym *sym; + long lval; + double dval; + char sval[8]; + Addr addr; + Gen gen; + Gen2 gen2; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 +%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA LTYPEB +%token <lval> LCONST LSP LSB LFP LPC LTOS LAREG LDREG LFREG +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr type pointer reg offset +%type <addr> name areg +%type <gen> gen rel +%type <gen2> noaddr gengen dstgen spec1 spec2 spec3 srcgen dstrel genrel +%% +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; + } +| LTYPE1 gengen { outcode($1, &$2); } +| LTYPE2 noaddr { outcode($1, &$2); } +| LTYPE3 dstgen { outcode($1, &$2); } +| LTYPE4 spec1 { outcode($1, &$2); } +| LTYPE5 srcgen { outcode($1, &$2); } +| LTYPE6 dstrel { outcode($1, &$2); } +| LTYPE7 genrel { outcode($1, &$2); } +| LTYPE8 dstgen { outcode($1, &$2); } +| LTYPE8 gengen { outcode($1, &$2); } +| LTYPE9 noaddr { outcode($1, &$2); } +| LTYPE9 dstgen { outcode($1, &$2); } +| LTYPEA spec2 { outcode($1, &$2); } +| LTYPEB spec3 { outcode($1, &$2); } + +noaddr: + { + $$.from = nullgen; + $$.to = nullgen; + } +| ',' + { + $$.from = nullgen; + $$.to = nullgen; + } + +srcgen: + gen + { + $$.from = $1; + $$.to = nullgen; + } +| gen ',' + { + $$.from = $1; + $$.to = nullgen; + } + +dstgen: + gen + { + $$.from = nullgen; + $$.to = $1; + } +| ',' gen + { + $$.from = nullgen; + $$.to = $2; + } + +gengen: + gen ',' gen + { + $$.from = $1; + $$.to = $3; + } + +dstrel: + rel + { + $$.from = nullgen; + $$.to = $1; + } +| ',' rel + { + $$.from = nullgen; + $$.to = $2; + } + +genrel: + gen ',' rel + { + $$.from = $1; + $$.to = $3; + } + +spec1: /* DATA opcode */ + gen '/' con ',' gen + { + $1.displace = $3; + $$.from = $1; + $$.to = $5; + } + +spec2: /* bit field opcodes */ + gen ',' gen ',' con ',' con + { + $1.field = $7; + $3.field = $5; + $$.from = $1; + $$.to = $3; + } + +spec3: /* TEXT opcode */ + gengen +| gen ',' con ',' gen + { + $1.displace = $3; + $$.from = $1; + $$.to = $5; + } + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.s0.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.s0.sym = $1; + $$.s0.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.s0.sym = $1; + $$.s0.offset = $1->value + $2; + } + +gen: + type + { + $$ = nullgen; + $$.type = $1; + } +| '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.s0.offset = $2; + } +| '$' name + { + $$ = nullgen; + { + Addr *a; + a = &$$.s0; + *a = $2; + } + if($2.type == D_AUTO || $2.type == D_PARAM) + yyerror("constant cannot be automatic: %s", + $2.sym->name); + $$.type = $2.type | I_ADDR; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } +| LTOS '+' con + { + $$ = nullgen; + $$.type = D_STACK; + $$.s0.offset = $3; + } +| LTOS '-' con + { + $$ = nullgen; + $$.type = D_STACK; + $$.s0.offset = -$3; + } +| con + { + $$ = nullgen; + $$.type = D_CONST | I_INDIR; + $$.s0.offset = $1; + } +| '-' '(' LAREG ')' + { + $$ = nullgen; + $$.type = $3 | I_INDDEC; + } +| '(' LAREG ')' '+' + { + $$ = nullgen; + $$.type = $2 | I_INDINC; + } +| areg + { + $$ = nullgen; + $$.type = $1.type; + { + Addr *a; + a = &$$.s0; + *a = $1; + } + } + +type: + reg +| LFREG + +reg: + LAREG +| LDREG +| LTOS + +areg: + '(' LAREG ')' + { + $$.type = $2 | I_INDIR; + $$.sym = S; + $$.offset = 0; + } +| con '(' LAREG ')' + { + $$.type = $3 | I_INDIR; + $$.sym = S; + $$.offset = $1; + } +| '(' ')' + { + $$.type = D_NONE | I_INDIR; + $$.sym = S; + $$.offset = 0; + } +| con '(' ')' + { + $$.type = D_NONE | I_INDIR; + $$.sym = S; + $$.offset = $1; + } +| name + +name: + LNAME offset '(' pointer ')' + { + $$.type = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$.type = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/1a/l.s b/utils/1a/l.s new file mode 100644 index 00000000..6f3cca3a --- /dev/null +++ b/utils/1a/l.s @@ -0,0 +1,479 @@ + +/* + * 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 8192 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 13 /* log(BY2PG) */ +#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) +#define ICACHESIZE 0 +#define MB4 (4*1024*1024) /* Lots of things are 4Mb in size */ + +#define MAXMACH 1 /* max # cpus system can run */ + +/* + * Time + */ +#define HZ (60) /* 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 */ + +/* + * SR bits + */ +#define SUPER 0x2000 +#define SPL(n) (n<<8) + +/* + * CACR + */ +#define CCLEAR 0x08 +#define CENABLE 0x01 + +/* + * Magic registers (unused in current system) + */ + +#define MACH A5 /* A5 is m-> */ +#define USER A4 /* A4 is u-> */ + +/* + * Fundamental addresses + */ + +#define USERADDR 0x80000000 +/* assuming we're in a syscall, this is the address of the Ureg structure */ +#define UREGVARSZ (23*BY2WD) /* size of variable part of Ureg */ +#define UREGADDR (USERADDR+BY2PG-(UREGVARSZ+2+4+2+(8+8+1+1)*BY2WD)) + +/* + * Devices poked during bootstrap + */ +#define TACADDR 0x40600000 +#define MOUSE 0x40200000 + +/* + * MMU + */ + +#define VAMASK 0xCFFFFFFF /* clear balu bits in address */ +#define KUSEG 0x00000000 +#define KSEG 0x80000000 + +/* + * MMU entries + */ +#define PTEVALID (1<<13) +#define PTEWRITE 0 +#define PTERONLY (1<<14) +#define PTEKERNEL (1<<15) +#define PTEUNCACHED 0 +#define INVALIDPTE 0 +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 16 + +#define PPN(pa) ((pa>>13)&0x1FFF) + +#define KMAP ((unsigned long *)0xD0000000) +#define UMAP ((unsigned long *)0x50000000) + +/* + * Virtual addresses + */ +#define VTAG(va) ((va>>22)&0x03F) +#define VPN(va) ((va>>13)&0x1FF) + +#define PARAM ((char*)0x40500000) +#define TLBFLUSH_ 0x01 + +/* + * Address spaces + */ + +#define UZERO KUSEG /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define TSTKTOP 0x10000000 /* end of new stack in sysexec */ +#define TSTKSIZ 100 +#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */ +#define KZERO KSEG /* base of kernel address space */ +#define KTZERO (KZERO+BY2PG) /* first address in kernel text */ +#define USTKSIZE (4*1024*1024) /* size of user stack */ + +#define MACHSIZE 4096 + + +#define isphys(p) ((((ulong)(p))&0xF0000000) == KSEG) +#define DBMAGIC 0xBADC0C0A + +/* + * Boot first processor + */ +TEXT start(SB), $-4 + + MOVW $(SUPER|SPL(7)), SR + MOVL $a6base(SB), A6 + MOVL $0, R0 + MOVL R0, CACR + MOVL R0, TACADDR /* zero tac counter (cause an intr?) */ + + MOVL $mach0(SB), A0 + MOVL A0, m(SB) + MOVL $0, 0(A0) + MOVL A0, A7 + ADDL $(MACHSIZE-4), A7 /* start stack under machine struct */ + MOVL $0, u(SB) + + MOVL $vectors(SB), A0 + MOVL A0, VBR + + BSR main(SB) + /* never returns */ +dead: + BRA dead + +/* + * Take first processor into user mode. Leave enough room on the stack + * for a full-sized Ureg (including long bus error format) to fit + */ + +TEXT touser(SB), $-4 + + MOVL $(USERADDR+BY2PG-UREGVARSZ), A7 + MOVW $0, -(A7) + MOVL $(UTZERO+32), -(A7) /* header is in text */ + MOVW $0, -(A7) + MOVL $(USTKTOP-6*BY2WD), A0 /* MAXSYSARG=6 */ + MOVL A0, USP + MOVW $(SUPER|SPL(0)), SR + MOVL $8, R0 + MOVL R0, CACR + RTE + +TEXT firmware(SB), $0 + + MOVL $0x40000090, A0 + JMP (A0) + +TEXT splhi(SB), $0 + + MOVL m(SB), A0 + MOVL (A7), 4(A0) + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(7)), SR + RTS + +TEXT splduart(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(5)), SR + RTS + +TEXT spllo(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(0)), SR + RTS + +TEXT splx(SB), $0 + + MOVL sr+0(FP), R0 + MOVW R0, SR + RTS + +TEXT spldone(SB), $0 + + RTS + +TEXT spl1(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(1)), SR + RTS + +TEXT flushcpucache(SB), $0 + + MOVL $(CCLEAR|CENABLE), R0 + MOVL R0, CACR + RTS + +TEXT cacrtrap(SB), $0 /* user entry point to control cache, e.g. flush */ + + MOVL R0, CACR + RTE + +TEXT setlabel(SB), $0 + + MOVL sr+0(FP), A0 + MOVL A7, (A0)+ /* stack pointer */ + MOVL (A7), (A0)+ /* pc of caller */ + MOVW SR, (A0)+ /* status register */ + CLRL R0 /* ret 0 => not returning */ + RTS + +TEXT gotolabel(SB), $0 + + MOVL p+0(FP), A0 + MOVW $(SUPER|SPL(7)), SR + MOVL (A0)+, A7 /* stack pointer */ + MOVL (A0)+, (A7) /* pc; stuff into stack frame */ + MOVW (A0)+, R0 /* status register */ + MOVW R0, SR + MOVL $1, R0 /* ret 1 => returning */ + RTS + +/* + * Test and set, as a subroutine + */ + +TEXT tas(SB), $0 + + MOVL $0, R0 + MOVL a+0(FP), A0 + TAS (A0) + BEQ tas_1 + MOVL $1, R0 +tas_1: + RTS + +/* + * Floating point + */ + +TEXT fpsave(SB), $0 + + FSAVE (fp+0(FP)) + RTS + +TEXT fprestore(SB), $0 + + FRESTORE (fp+0(FP)) + RTS + +TEXT fpregsave(SB), $0 + + FMOVEM $0xFF, (3*4)(fr+0(FP)) + FMOVEMC $0x7, (fr+0(FP)) + RTS + +TEXT fpregrestore(SB), $0 + + FMOVEMC (fr+0(FP)), $0x7 + FMOVEM (3*4)(fr+0(FP)), $0xFF + RTS + +TEXT fpcr(SB), $0 + + MOVL new+0(FP), R1 + MOVL FPCR, R0 + MOVL R1, FPCR + RTS + + +TEXT rfnote(SB), $0 + + MOVL uregp+0(FP), A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1+1)*BY2WD), A7 + RTE + +TEXT illegal(SB), $0 + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR trap(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1)*BY2WD+BY2WD), A7 + RTE + +TEXT systrap(SB), $0 + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVL A6, ((8+6)*BY2WD)(A7) + MOVL R0, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR syscall(SB) + MOVL ((1+8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVL ((1+8+6)*BY2WD)(A7), A6 + ADDL $((1+8+8+1)*BY2WD+BY2WD), A7 + RTE + +TEXT buserror(SB), $0 + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + PEA ((8+8+1+3)*BY2WD)(A7) + PEA 4(A7) + BSR fault68020(SB) + ADDL $8, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1)*BY2WD+BY2WD), A7 + RTE + +TEXT tacintr(SB), $0 /* level 1 */ + + MOVL R0, -(A7) + MOVL TACADDR, R0 + MOVL (A7)+, R0 + RTE + +TEXT portintr(SB), $0 /* level 2 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR devportintr(SB) + BRA retintr + +TEXT dkintr(SB), $0 /* level 3 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR inconintr(SB) + BRA retintr + +TEXT mouseintr(SB), $0 /* level 4 */ + + MOVEM $0x80C2, -(A7) /* D0, A0, A1, A6 */ + MOVL $a6base(SB), A6 + MOVL $15, R0 /* mask off hex switch */ + ANDB MOUSE,R0 /* clears quadrature interrupt */ + LEA mousetab(SB)(R0.W*8), A0 + LEA mouse(SB), A1 + MOVL (A0)+, R0 + ADDL R0, (A1)+ /* dx */ + MOVL (A0), R0 + ADDL R0, (A1)+ /* dy */ + ADDL $1, (A1) /* track */ + MOVEM (A7)+, $0x4301 + RTE + +TEXT uartintr(SB), $0 /* level 5 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR duartintr(SB) + BRA retintr + +TEXT syncintr(SB), $0 /* level 6 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR clock(SB) + /* fall through */ +retintr: + BSR mousetry(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1)*BY2WD+BY2WD), A7 + RTE + +GLOBL duarttimer+0(SB),$4 + +TEXT duartreadtimer+0(SB), $0 + MOVW SR, R1 /* spl7() */ + MOVW $0x2700, SR + MOVL $0x40100000, A0 + CLRL R0 + TSTB 15(A0) /* stop timer */ + MOVW 6(A0), R0 /* read hi,lo */ + TSTB 14(A0) /* restart timer */ + NOTW R0 /* timer counts down from 0xffff */ + ADDL duarttimer(SB), R0 + MOVL R0, duarttimer(SB) + MOVW R1, SR + RTS + +GLOBL mousetab(SB), $128 +DATA mousetab+ 0(SB)/4, -1 /* x down, */ +DATA mousetab+ 4(SB)/4, 1 /* y up */ +DATA mousetab+ 8(SB)/4, 0 /* x - */ +DATA mousetab+ 12(SB)/4, 1 /* y up */ +DATA mousetab+ 16(SB)/4, 1 /* x up */ +DATA mousetab+ 20(SB)/4, 1 /* y up */ +DATA mousetab+ 24(SB)/4, 0 /* x - */ +DATA mousetab+ 28(SB)/4, 1 /* y up */ +DATA mousetab+ 32(SB)/4, -1 /* x down */ +DATA mousetab+ 36(SB)/4, 0 /* y - */ +DATA mousetab+ 40(SB)/4, 0 /* x - */ +DATA mousetab+ 44(SB)/4, 0 /* y - */ +DATA mousetab+ 48(SB)/4, 1 /* x up, */ +DATA mousetab+ 52(SB)/4, 0 /* y - */ +DATA mousetab+ 56(SB)/4, 0 /* x - */ +DATA mousetab+ 60(SB)/4, 0 /* y - */ +DATA mousetab+ 64(SB)/4, -1 /* x down */ +DATA mousetab+ 68(SB)/4, -1 /* y down */ +DATA mousetab+ 72(SB)/4, 0 /* x - */ +DATA mousetab+ 76(SB)/4, -1 /* y down */ +DATA mousetab+ 80(SB)/4, 1 /* x up */ +DATA mousetab+ 84(SB)/4, -1 /* y down */ +DATA mousetab+ 88(SB)/4, 0 /* x - */ +DATA mousetab+ 92(SB)/4, -1 /* y down */ +DATA mousetab+ 96(SB)/4, -1 /* x down */ +DATA mousetab+100(SB)/4, 0 /* y - */ +DATA mousetab+104(SB)/4, 0 /* x - */ +DATA mousetab+108(SB)/4, 0 /* y - */ +DATA mousetab+112(SB)/4, 1 /* x up */ +DATA mousetab+116(SB)/4, 0 /* y - */ +DATA mousetab+120(SB)/4, 0 /* x - */ +DATA mousetab+124(SB)/4, 0 /* y - */ + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL u(SB), $4 +GLOBL m(SB), $4 diff --git a/utils/1a/lex.c b/utils/1a/lex.c new file mode 100644 index 00000000..a3936d26 --- /dev/null +++ b/utils/1a/lex.c @@ -0,0 +1,925 @@ +#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 = '1'; + thestring = "68000"; + 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, + "TOS", LTOS, D_TOS, + "CCR", LTOS, D_CCR, + "SR", LTOS, D_SR, + "SFC", LTOS, D_SFC, + "DFC", LTOS, D_DFC, + "CACR", LTOS, D_CACR, + "USP", LTOS, D_USP, + "VBR", LTOS, D_VBR, + "CAAR", LTOS, D_CAAR, + "MSP", LTOS, D_MSP, + "ISP", LTOS, D_ISP, + "FPCR", LTOS, D_FPCR, + "FPSR", LTOS, D_FPSR, + "FPIAR", LTOS, D_FPIAR, + "TC", LTOS, D_TC, + "ITT0", LTOS, D_ITT0, + "ITT1", LTOS, D_ITT1, + "DTT0", LTOS, D_DTT0, + "DTT1", LTOS, D_DTT1, + "MMUSR", LTOS, D_MMUSR, + "URP", LTOS, D_URP, + "SRP", LTOS, D_SRP, + + "R0", LDREG, D_R0+0, + "R1", LDREG, D_R0+1, + "R2", LDREG, D_R0+2, + "R3", LDREG, D_R0+3, + "R4", LDREG, D_R0+4, + "R5", LDREG, D_R0+5, + "R6", LDREG, D_R0+6, + "R7", LDREG, D_R0+7, + + "A0", LAREG, D_A0+0, + "A1", LAREG, D_A0+1, + "A2", LAREG, D_A0+2, + "A3", LAREG, D_A0+3, + "A4", LAREG, D_A0+4, + "A5", LAREG, D_A0+5, + "A6", LAREG, D_A0+6, + "A7", LAREG, D_A0+7, + + "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, + + "ABCD", LTYPE1, AABCD, + "ADDB", LTYPE1, AADDB, + "ADDL", LTYPE1, AADDL, + "ADDW", LTYPE1, AADDW, + "ADDXB", LTYPE1, AADDXB, + "ADDXL", LTYPE1, AADDXL, + "ADDXW", LTYPE1, AADDXW, + "ADJSP", LTYPE5, AADJSP, + "ANDB", LTYPE1, AANDB, + "ANDL", LTYPE1, AANDL, + "ANDW", LTYPE1, AANDW, + "ASLB", LTYPE1, AASLB, + "ASLL", LTYPE1, AASLL, + "ASLW", LTYPE1, AASLW, + "ASRB", LTYPE1, AASRB, + "ASRL", LTYPE1, AASRL, + "ASRW", LTYPE1, AASRW, + "BCASE", LTYPE7, ABCASE, + "BCC", LTYPE6, ABCC, + "BCHG", LTYPE1, ABCHG, + "BCLR", LTYPE1, ABCLR, + "BCS", LTYPE6, ABCS, + "BEQ", LTYPE6, ABEQ, + "BFCHG", LTYPEA, ABFCHG, + "BFCLR", LTYPEA, ABFCLR, + "BFEXTS", LTYPEA, ABFEXTS, + "BFEXTU", LTYPEA, ABFEXTU, + "BFFFO", LTYPEA, ABFFFO, + "BFINS", LTYPEA, ABFINS, + "BFSET", LTYPEA, ABFSET, + "BFTST", LTYPEA, ABFTST, + "BGE", LTYPE6, ABGE, + "BGT", LTYPE6, ABGT, + "BHI", LTYPE6, ABHI, + "BKPT", LTYPE1, ABKPT, + "BLE", LTYPE6, ABLE, + "BLS", LTYPE6, ABLS, + "BLT", LTYPE6, ABLT, + "BMI", LTYPE6, ABMI, + "BNE", LTYPE6, ABNE, + "BPL", LTYPE6, ABPL, + "BRA", LTYPE6, ABRA, + "BSET", LTYPE1, ABSET, + "BSR", LTYPE3, ABSR, + "BTST", LTYPE1, ABTST, + "BVC", LTYPE6, ABVC, + "BVS", LTYPE6, ABVS, + "CALLM", LTYPE1, ACALLM, + "CAS2B", LTYPE1, ACAS2B, + "CAS2L", LTYPE1, ACAS2L, + "CAS2W", LTYPE1, ACAS2W, + "CASB", LTYPE1, ACASB, + "CASEW", LTYPE2, ACASEW, + "CASL", LTYPE1, ACASL, + "CASW", LTYPE1, ACASW, + "CHK2B", LTYPE1, ACHK2B, + "CHK2L", LTYPE1, ACHK2L, + "CHK2W", LTYPE1, ACHK2W, + "CHKL", LTYPE1, ACHKL, + "CHKW", LTYPE1, ACHKW, + "CLRB", LTYPE3, ACLRB, + "CLRL", LTYPE3, ACLRL, + "CLRW", LTYPE3, ACLRW, + "CMP2B", LTYPE1, ACMP2B, + "CMP2L", LTYPE1, ACMP2L, + "CMP2W", LTYPE1, ACMP2W, + "CMPB", LTYPE1, ACMPB, + "CMPL", LTYPE1, ACMPL, + "CMPW", LTYPE1, ACMPW, + "DATA", LTYPE4, ADATA, + "DBCC", LTYPE7, ADBCC, + "DBCS", LTYPE7, ADBCS, + "DBEQ", LTYPE7, ADBEQ, + "DBF", LTYPE7, ADBF, + "DBGE", LTYPE7, ADBGE, + "DBGT", LTYPE7, ADBGT, + "DBHI", LTYPE7, ADBHI, + "DBLE", LTYPE7, ADBLE, + "DBLS", LTYPE7, ADBLS, + "DBLT", LTYPE7, ADBLT, + "DBMI", LTYPE7, ADBMI, + "DBNE", LTYPE7, ADBNE, + "DBPL", LTYPE7, ADBPL, + "DBT", LTYPE7, ADBT, + "DBVC", LTYPE7, ADBVC, + "DBVS", LTYPE7, ADBVS, + "DIVSL", LTYPE1, ADIVSL, + "DIVSW", LTYPE1, ADIVSW, + "DIVUL", LTYPE1, ADIVUL, + "DIVUW", LTYPE1, ADIVUW, + "END", LTYPE2, AEND, + "EORB", LTYPE1, AEORB, + "EORL", LTYPE1, AEORL, + "EORW", LTYPE1, AEORW, + "EXG", LTYPE1, AEXG, + "EXTBL", LTYPE3, AEXTBL, + "EXTBW", LTYPE3, AEXTBW, + "EXTWL", LTYPE3, AEXTWL, + "FABSB", LTYPE1, AFABSB, + "FABSD", LTYPE1, AFABSD, + "FABSF", LTYPE1, AFABSF, + "FABSL", LTYPE1, AFABSL, + "FABSW", LTYPE1, AFABSW, + "FACOSB", LTYPE1, AFACOSB, + "FACOSD", LTYPE1, AFACOSD, + "FACOSF", LTYPE1, AFACOSF, + "FACOSL", LTYPE1, AFACOSL, + "FACOSW", LTYPE1, AFACOSW, + "FADDB", LTYPE1, AFADDB, + "FADDD", LTYPE1, AFADDD, + "FADDF", LTYPE1, AFADDF, + "FADDL", LTYPE1, AFADDL, + "FADDW", LTYPE1, AFADDW, + "FASINB", LTYPE1, AFASINB, + "FASIND", LTYPE1, AFASIND, + "FASINF", LTYPE1, AFASINF, + "FASINL", LTYPE1, AFASINL, + "FASINW", LTYPE1, AFASINW, + "FATANB", LTYPE1, AFATANB, + "FATAND", LTYPE1, AFATAND, + "FATANF", LTYPE1, AFATANF, + "FATANHB", LTYPE1, AFATANHB, + "FATANHD", LTYPE1, AFATANHD, + "FATANHF", LTYPE1, AFATANHF, + "FATANHL", LTYPE1, AFATANHL, + "FATANHW", LTYPE1, AFATANHW, + "FATANL", LTYPE1, AFATANL, + "FATANW", LTYPE1, AFATANW, + "FBEQ", LTYPE6, AFBEQ, + "FBF", LTYPE6, AFBF, + "FBGE", LTYPE6, AFBGE, + "FBGT", LTYPE6, AFBGT, + "FBLE", LTYPE6, AFBLE, + "FBLT", LTYPE6, AFBLT, + "FBNE", LTYPE6, AFBNE, + "FBT", LTYPE6, AFBT, + "FCMPB", LTYPE1, AFCMPB, + "FCMPD", LTYPE1, AFCMPD, + "FCMPF", LTYPE1, AFCMPF, + "FCMPL", LTYPE1, AFCMPL, + "FCMPW", LTYPE1, AFCMPW, + "FCOSB", LTYPE1, AFCOSB, + "FCOSD", LTYPE1, AFCOSD, + "FCOSF", LTYPE1, AFCOSF, + "FCOSHB", LTYPE1, AFCOSHB, + "FCOSHD", LTYPE1, AFCOSHD, + "FCOSHF", LTYPE1, AFCOSHF, + "FCOSHL", LTYPE1, AFCOSHL, + "FCOSHW", LTYPE1, AFCOSHW, + "FCOSL", LTYPE1, AFCOSL, + "FCOSW", LTYPE1, AFCOSW, + "FDBEQ", LTYPE7, AFDBEQ, + "FDBF", LTYPE7, AFDBF, + "FDBGE", LTYPE7, AFDBGE, + "FDBGT", LTYPE7, AFDBGT, + "FDBLE", LTYPE7, AFDBLE, + "FDBLT", LTYPE7, AFDBLT, + "FDBNE", LTYPE7, AFDBNE, + "FDBT", LTYPE7, AFDBT, + "FDIVB", LTYPE1, AFDIVB, + "FDIVD", LTYPE1, AFDIVD, + "FDIVF", LTYPE1, AFDIVF, + "FDIVL", LTYPE1, AFDIVL, + "FDIVW", LTYPE1, AFDIVW, + "FETOXB", LTYPE1, AFETOXB, + "FETOXD", LTYPE1, AFETOXD, + "FETOXF", LTYPE1, AFETOXF, + "FETOXL", LTYPE1, AFETOXL, + "FETOXM1B", LTYPE1, AFETOXM1B, + "FETOXM1D", LTYPE1, AFETOXM1D, + "FETOXM1F", LTYPE1, AFETOXM1F, + "FETOXM1L", LTYPE1, AFETOXM1L, + "FETOXM1W", LTYPE1, AFETOXM1W, + "FETOXW", LTYPE1, AFETOXW, + "FGETEXPB", LTYPE1, AFGETEXPB, + "FGETEXPD", LTYPE1, AFGETEXPD, + "FGETEXPF", LTYPE1, AFGETEXPF, + "FGETEXPL", LTYPE1, AFGETEXPL, + "FGETEXPW", LTYPE1, AFGETEXPW, + "FGETMANB", LTYPE1, AFGETMANB, + "FGETMAND", LTYPE1, AFGETMAND, + "FGETMANF", LTYPE1, AFGETMANF, + "FGETMANL", LTYPE1, AFGETMANL, + "FGETMANW", LTYPE1, AFGETMANW, + "FINTB", LTYPE1, AFINTB, + "FINTD", LTYPE1, AFINTD, + "FINTF", LTYPE1, AFINTF, + "FINTL", LTYPE1, AFINTL, + "FINTRZB", LTYPE1, AFINTRZB, + "FINTRZD", LTYPE1, AFINTRZD, + "FINTRZF", LTYPE1, AFINTRZF, + "FINTRZL", LTYPE1, AFINTRZL, + "FINTRZW", LTYPE1, AFINTRZW, + "FINTW", LTYPE1, AFINTW, + "FLOG10B", LTYPE1, AFLOG10B, + "FLOG10D", LTYPE1, AFLOG10D, + "FLOG10F", LTYPE1, AFLOG10F, + "FLOG10L", LTYPE1, AFLOG10L, + "FLOG10W", LTYPE1, AFLOG10W, + "FLOG2B", LTYPE1, AFLOG2B, + "FLOG2D", LTYPE1, AFLOG2D, + "FLOG2F", LTYPE1, AFLOG2F, + "FLOG2L", LTYPE1, AFLOG2L, + "FLOG2W", LTYPE1, AFLOG2W, + "FLOGNB", LTYPE1, AFLOGNB, + "FLOGND", LTYPE1, AFLOGND, + "FLOGNF", LTYPE1, AFLOGNF, + "FLOGNL", LTYPE1, AFLOGNL, + "FLOGNP1B", LTYPE1, AFLOGNP1B, + "FLOGNP1D", LTYPE1, AFLOGNP1D, + "FLOGNP1F", LTYPE1, AFLOGNP1F, + "FLOGNP1L", LTYPE1, AFLOGNP1L, + "FLOGNP1W", LTYPE1, AFLOGNP1W, + "FLOGNW", LTYPE1, AFLOGNW, + "FMODB", LTYPE1, AFMODB, + "FMODD", LTYPE1, AFMODD, + "FMODF", LTYPE1, AFMODF, + "FMODL", LTYPE1, AFMODL, + "FMODW", LTYPE1, AFMODW, + "FMOVEB", LTYPE1, AFMOVEB, + "FMOVED", LTYPE1, AFMOVED, + "FMOVEF", LTYPE1, AFMOVEF, + "FMOVEL", LTYPE1, AFMOVEL, + "FMOVEW", LTYPE1, AFMOVEW, + "FMULB", LTYPE1, AFMULB, + "FMULD", LTYPE1, AFMULD, + "FMULF", LTYPE1, AFMULF, + "FMULL", LTYPE1, AFMULL, + "FMULW", LTYPE1, AFMULW, + "FNEGB", LTYPE8, AFNEGB, + "FNEGD", LTYPE8, AFNEGD, + "FNEGF", LTYPE8, AFNEGF, + "FNEGL", LTYPE8, AFNEGL, + "FNEGW", LTYPE8, AFNEGW, + "FREMB", LTYPE1, AFREMB, + "FREMD", LTYPE1, AFREMD, + "FREMF", LTYPE1, AFREMF, + "FREML", LTYPE1, AFREML, + "FREMW", LTYPE1, AFREMW, + "FSCALEB", LTYPE1, AFSCALEB, + "FSCALED", LTYPE1, AFSCALED, + "FSCALEF", LTYPE1, AFSCALEF, + "FSCALEL", LTYPE1, AFSCALEL, + "FSCALEW", LTYPE1, AFSCALEW, + "FSEQ", LTYPE1, AFSEQ, + "FSF", LTYPE1, AFSF, + "FSGE", LTYPE1, AFSGE, + "FSGT", LTYPE1, AFSGT, + "FSINB", LTYPE1, AFSINB, + "FSIND", LTYPE1, AFSIND, + "FSINF", LTYPE1, AFSINF, + "FSINHB", LTYPE1, AFSINHB, + "FSINHD", LTYPE1, AFSINHD, + "FSINHF", LTYPE1, AFSINHF, + "FSINHL", LTYPE1, AFSINHL, + "FSINHW", LTYPE1, AFSINHW, + "FSINL", LTYPE1, AFSINL, + "FSINW", LTYPE1, AFSINW, + "FSLE", LTYPE1, AFSLE, + "FSLT", LTYPE1, AFSLT, + "FSNE", LTYPE1, AFSNE, + "FSQRTB", LTYPE1, AFSQRTB, + "FSQRTD", LTYPE1, AFSQRTD, + "FSQRTF", LTYPE1, AFSQRTF, + "FSQRTL", LTYPE1, AFSQRTL, + "FSQRTW", LTYPE1, AFSQRTW, + "FST", LTYPE1, AFST, + "FSUBB", LTYPE1, AFSUBB, + "FSUBD", LTYPE1, AFSUBD, + "FSUBF", LTYPE1, AFSUBF, + "FSUBL", LTYPE1, AFSUBL, + "FSUBW", LTYPE1, AFSUBW, + "FTANB", LTYPE1, AFTANB, + "FTAND", LTYPE1, AFTAND, + "FTANF", LTYPE1, AFTANF, + "FTANHB", LTYPE1, AFTANHB, + "FTANHD", LTYPE1, AFTANHD, + "FTANHF", LTYPE1, AFTANHF, + "FTANHL", LTYPE1, AFTANHL, + "FTANHW", LTYPE1, AFTANHW, + "FTANL", LTYPE1, AFTANL, + "FTANW", LTYPE1, AFTANW, + "FTENTOXB", LTYPE1, AFTENTOXB, + "FTENTOXD", LTYPE1, AFTENTOXD, + "FTENTOXF", LTYPE1, AFTENTOXF, + "FTENTOXL", LTYPE1, AFTENTOXL, + "FTENTOXW", LTYPE1, AFTENTOXW, + "FTSTB", LTYPE1, AFTSTB, + "FTSTD", LTYPE1, AFTSTD, + "FTSTF", LTYPE1, AFTSTF, + "FTSTL", LTYPE1, AFTSTL, + "FTSTW", LTYPE1, AFTSTW, + "FTWOTOXB", LTYPE1, AFTWOTOXB, + "FTWOTOXD", LTYPE1, AFTWOTOXD, + "FTWOTOXF", LTYPE1, AFTWOTOXF, + "FTWOTOXL", LTYPE1, AFTWOTOXL, + "FTWOTOXW", LTYPE1, AFTWOTOXW, + "FMOVEM", LTYPE1, AFMOVEM, + "FMOVEMC", LTYPE1, AFMOVEMC, + "FRESTORE", LTYPE3, AFRESTORE, + "FSAVE", LTYPE3, AFSAVE, + "GLOBL", LTYPE1, AGLOBL, + "GOK", LTYPE2, AGOK, + "HISTORY", LTYPE2, AHISTORY, + "ILLEG", LTYPE2, AILLEG, + "INSTR", LTYPE3, AINSTR, + "JMP", LTYPE3, AJMP, + "JSR", LTYPE3, AJSR, + "LEA", LTYPE1, ALEA, + "LINKL", LTYPE1, ALINKL, + "LINKW", LTYPE1, ALINKW, + "LOCATE", LTYPE1, ALOCATE, + "LONG", LTYPE3, ALONG, + "LSLB", LTYPE1, ALSLB, + "LSLL", LTYPE1, ALSLL, + "LSLW", LTYPE1, ALSLW, + "LSRB", LTYPE1, ALSRB, + "LSRL", LTYPE1, ALSRL, + "LSRW", LTYPE1, ALSRW, + "MOVB", LTYPE1, AMOVB, + "MOVEM", LTYPE1, AMOVEM, + "MOVEPL", LTYPE1, AMOVEPL, + "MOVEPW", LTYPE1, AMOVEPW, + "MOVESB", LTYPE1, AMOVESB, + "MOVESL", LTYPE1, AMOVESL, + "MOVESW", LTYPE1, AMOVESW, + "MOVL", LTYPE1, AMOVL, + "MOVW", LTYPE1, AMOVW, + "MULSL", LTYPE1, AMULSL, + "MULSW", LTYPE1, AMULSW, + "MULUL", LTYPE1, AMULUL, + "MULUW", LTYPE1, AMULUW, + "NAME", LTYPE1, ANAME, + "NBCD", LTYPE3, ANBCD, + "NEGB", LTYPE3, ANEGB, + "NEGL", LTYPE3, ANEGL, + "NEGW", LTYPE3, ANEGW, + "NEGXB", LTYPE3, ANEGXB, + "NEGXL", LTYPE3, ANEGXL, + "NEGXW", LTYPE3, ANEGXW, + "NOP", LTYPE9, ANOP, + "NOTB", LTYPE3, ANOTB, + "NOTL", LTYPE3, ANOTL, + "NOTW", LTYPE3, ANOTW, + "ORB", LTYPE1, AORB, + "ORL", LTYPE1, AORL, + "ORW", LTYPE1, AORW, + "PACK", LTYPE1, APACK, + "PEA", LTYPE3, APEA, + "RESET", LTYPE2, ARESET, + "ROTLB", LTYPE1, AROTLB, + "ROTLL", LTYPE1, AROTLL, + "ROTLW", LTYPE1, AROTLW, + "ROTRB", LTYPE1, AROTRB, + "ROTRL", LTYPE1, AROTRL, + "ROTRW", LTYPE1, AROTRW, + "ROXLB", LTYPE1, AROXLB, + "ROXLL", LTYPE1, AROXLL, + "ROXLW", LTYPE1, AROXLW, + "ROXRB", LTYPE1, AROXRB, + "ROXRL", LTYPE1, AROXRL, + "ROXRW", LTYPE1, AROXRW, + "RTD", LTYPE3, ARTD, + "RTE", LTYPE2, ARTE, + "RTM", LTYPE3, ARTM, + "RTR", LTYPE2, ARTR, + "RTS", LTYPE2, ARTS, + "SBCD", LTYPE1, ASBCD, + "SCC", LTYPE3, ASCC, + "SCS", LTYPE3, ASCS, + "SEQ", LTYPE3, ASEQ, + "SF", LTYPE3, ASF, + "SGE", LTYPE3, ASGE, + "SGT", LTYPE3, ASGT, + "SHI", LTYPE3, ASHI, + "SLE", LTYPE3, ASLE, + "SLS", LTYPE3, ASLS, + "SLT", LTYPE3, ASLT, + "SMI", LTYPE3, ASMI, + "SNE", LTYPE3, ASNE, + "SPL", LTYPE3, ASPL, + "ST", LTYPE3, AST, + "STOP", LTYPE3, ASTOP, + "SUBB", LTYPE1, ASUBB, + "SUBL", LTYPE1, ASUBL, + "SUBW", LTYPE1, ASUBW, + "SUBXB", LTYPE1, ASUBXB, + "SUBXL", LTYPE1, ASUBXL, + "SUBXW", LTYPE1, ASUBXW, + "SVC", LTYPE2, ASVC, + "SVS", LTYPE2, ASVS, + "SWAP", LTYPE3, ASWAP, + "SYS", LTYPE2, ASYS, + "TAS", LTYPE3, ATAS, + "TEXT", LTYPEB, ATEXT, + "TRAP", LTYPE3, ATRAP, + "TRAPCC", LTYPE2, ATRAPCC, + "TRAPCS", LTYPE2, ATRAPCS, + "TRAPEQ", LTYPE2, ATRAPEQ, + "TRAPF", LTYPE2, ATRAPF, + "TRAPGE", LTYPE2, ATRAPGE, + "TRAPGT", LTYPE2, ATRAPGT, + "TRAPHI", LTYPE2, ATRAPHI, + "TRAPLE", LTYPE2, ATRAPLE, + "TRAPLS", LTYPE2, ATRAPLS, + "TRAPLT", LTYPE2, ATRAPLT, + "TRAPMI", LTYPE2, ATRAPMI, + "TRAPNE", LTYPE2, ATRAPNE, + "TRAPPL", LTYPE2, ATRAPPL, + "TRAPT", LTYPE2, ATRAPT, + "TRAPV", LTYPE2, ATRAPV, + "TRAPVC", LTYPE2, ATRAPVC, + "TRAPVS", LTYPE2, ATRAPVS, + "TSTB", LTYPE3, ATSTB, + "TSTL", LTYPE3, ATSTL, + "TSTW", LTYPE3, ATSTW, + "UNLK", LTYPE3, AUNLK, + "UNPK", LTYPE1, AUNPK, + "WORD", LTYPE3, AWORD, + + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.s0.sym = S; + nullgen.s0.offset = 0; + nullgen.type = D_NONE; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 0; + nullgen.displace = 0; + nullgen.type = D_NONE; + nullgen.field = 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); + 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 +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 */ + 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->field) + t |= T_FIELD; + if(a->displace != 0) + t |= T_INDEX; + if(a->s0.offset != 0) + t |= T_OFFSET; + if(s != 0) + t |= T_SYM; + + if(a->type == D_FCONST) + t |= T_FCONST; + else + if(a->type == D_SCONST) + t |= T_SCONST; + else + if(a->type & ~0xff) + t |= T_TYPE; + Bputc(&obuf, t); + + if(t & T_FIELD) { /* implies field */ + i = a->field; + Bputc(&obuf, i); + Bputc(&obuf, i>>8); + } + if(t & T_INDEX) { /* implies index, scale, displace */ + i = D_NONE; + Bputc(&obuf, i); + Bputc(&obuf, i>>8); + Bputc(&obuf, 0); + l = a->displace; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->s0.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; + } + i = a->type; + Bputc(&obuf, i); + if(t & T_TYPE) + Bputc(&obuf, i>>8); +} + +void +outcode(int a, Gen2 *g2) +{ + int sf, st, t; + Sym *s; + + if(pass == 1) + goto out; + +jackpot: + sf = 0; + s = g2->from.s0.sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g2->from.type & D_MASK; + 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.s0.sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->to.type & D_MASK; + 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; + 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.s0.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" diff --git a/utils/1a/mkfile b/utils/1a/mkfile new file mode 100644 index 00000000..da0bd1f5 --- /dev/null +++ b/utils/1a/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=1a + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../2c/2.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/1c/cgen.c b/utils/1c/cgen.c new file mode 100644 index 00000000..2f121e51 --- /dev/null +++ b/utils/1c/cgen.c @@ -0,0 +1,1396 @@ +#include "gc.h" + +void +cgen(Node *n, int result, Node *nn) +{ + Node *l, *r, nod; + int lg, rg, xg, yg, g, o; + long v; + Prog *p1; + + if(n == Z || n->type == T) + return; + if(typesuv[n->type->etype]) { + sugen(n, result, nn, n->type->width); + return; + } + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R\n", result); + prtree(n, "cgen"); + } + l = n->left; + r = n->right; + o = n->op; + if(n->addable >= INDEXED) { + if(result == D_NONE) { + if(nn == Z) + switch(o) { + default: + nullwarn(Z, Z); + break; + case OINDEX: + nullwarn(l, r); + break; + } + return; + } + gmove(n->type, nn->type, D_TREE, n, result, nn); + return; + } + + v = 0; /* set */ + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + /* + * recursive use of result + */ + if(result == D_NONE) + if(l->addable > INDEXED) + if(l->complex < FNX) { + cgen(r, D_TREE, l); + break; + } + + /* + * function calls on both sides + */ + if(l->complex >= FNX && r->complex >= FNX) { + cgen(r, D_TOS, r); + v = argoff; + lg = regaddr(result); + lcgen(l, lg, Z); + lg |= I_INDIR; + adjsp(v - argoff); + gmove(r->type, l->type, D_TOS, r, lg, l); + if(result != D_NONE) + gmove(l->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + } + + rg = D_TREE; + lg = D_TREE; + if(r->complex >= l->complex) { + /* + * right side before left + */ + if(result != D_NONE) { + rg = regalloc(n->type, result); + cgen(r, rg, n); + } else + if(r->complex >= FNX || r->addable < INDEXED) { + rg = regalloc(r->type, result); + cgen(r, rg, r); + } + if(l->addable < INDEXED) { + lg = regaddr(lg); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + } else { + /* + * left before right + */ + if(l->complex >= FNX || l->addable < INDEXED) { + lg = regaddr(lg); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + if(result != D_NONE) { + rg = regalloc(n->type, result); + cgen(r, rg, n); + } else + if(r->addable < INDEXED) { + rg = regalloc(r->type, result); + cgen(r, rg, r); + } + } + if(result != D_NONE) { + gmove(n->type, l->type, rg, r, lg, l); + gmove(n->type, nn->type, rg, r, result, nn); + } else + gmove(r->type, l->type, rg, r, lg, l); + regfree(lg); + regfree(rg); + break; + + bitas: + n = l->left; + rg = regalloc(tfield, result); + if(l->complex >= r->complex) { + lg = regaddr(D_NONE); + lcgen(n, lg, Z); + lg |= I_INDIR; + cgen(r, rg, r); + } else { + cgen(r, rg, r); + lg = regaddr(D_NONE); + lcgen(n, lg, Z); + lg |= I_INDIR; + } + g = regalloc(n->type, D_NONE); + gmove(l->type, l->type, lg, l, g, l); + bitstore(l, rg, lg, g, result, nn); + break; + + case OBIT: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + g = bitload(n, D_NONE, D_NONE, result, nn); + gopcode(OAS, nn->type, g, n, result, nn); + regfree(g); + break; + + case ODOT: + sugen(l, D_TREE, nodrat, l->type->width); + if(result != D_NONE) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += r->vconst; + nod.type = n->type; + cgen(&nod, result, nn); + } + break; + + case OASLDIV: + case OASLMOD: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]) + goto asbinop; + rg = D_TREE; + if(l->complex >= FNX || r->complex >= FNX) { + rg = D_TOS; + cgen(r, rg, r); + v = argoff; + } else + if(r->addable < INDEXED) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + lg = D_TREE; + if(!simplv(l)) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); /* destroys register optimization */ + lg |= I_INDIR; + } + g = regpair(result); + gmove(l->type, n->type, lg, l, g, n); + if(rg == D_TOS) + adjsp(v - argoff); + gopcode(o, n->type, rg, r, g, n); + if(o == OASLMOD || o == OASMOD) + gmove(n->type, l->type, g+1, n, lg, l); + else + gmove(n->type, l->type, g, n, lg, l); + if(result != D_NONE) + if(o == OASLMOD || o == OASMOD) + gmove(n->type, nn->type, g+1, n, result, nn); + else + gmove(n->type, nn->type, g, n, result, nn); + regfree(g); + regfree(g+1); + regfree(lg); + regfree(rg); + break; + + case OASXOR: + case OASAND: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= FNX || + l->addable < INDEXED || + result != D_NONE || + typefd[n->type->etype]) + goto asbinop; + rg = D_TREE; + if(r->op != OCONST) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + gopcode(o, l->type, rg, r, D_TREE, l); + regfree(rg); + break; + + case OASADD: + case OASSUB: + if(l->op == OBIT || + l->complex >= FNX || + l->addable < INDEXED || + result != D_NONE || + typefd[n->type->etype]) + goto asbinop; + v = vconst(r); + if(v > 0 && v <= 8) { + gopcode(o, n->type, D_TREE, r, D_TREE, l); + break; + } + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + gopcode(o, n->type, rg, r, D_TREE, l); + regfree(rg); + break; + + case OASLSHR: + case OASASHR: + case OASASHL: + if(l->op == OBIT || + l->complex >= FNX || + l->addable < INDEXED || + result != D_NONE || + typefd[n->type->etype]) + goto asbinop; + rg = D_TREE; + v = vconst(r); + if(v <= 0 || v > 8) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + lg = regalloc(n->type, D_NONE); + cgen(l, lg, l); + gopcode(o, n->type, rg, r, lg, l); + gmove(n->type, n->type, lg, l, D_TREE, l); + regfree(lg); + regfree(rg); + break; + + case OASLMUL: + case OASMUL: + asbinop: + if(l->op == OBIT) + goto asbitop; + rg = D_TREE; + if(l->complex >= FNX || r->complex >= FNX) { + rg = D_TOS; + cgen(r, rg, r); + v = argoff; + } else + if(r->addable < INDEXED) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } else { + if(o == OASLSHR || o == OASASHR || o == OASASHL) { + v = vconst(r); + if(v <= 0 || v > 8) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + } + } + lg = D_TREE; + if(!simplv(l)) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); /* destroys register optimization */ + lg |= I_INDIR; + } + g = regalloc(n->type, result); + gmove(l->type, n->type, lg, l, g, n); + if(rg == D_TOS) + adjsp(v - argoff); + if(o == OASXOR) + if(rg == D_TREE) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL) + if(rg == D_TOS) { + rg = regalloc(n->type, D_NONE); + gmove(n->type, n->type, D_TOS, n, rg, n); + } + gopcode(o, n->type, rg, r, g, n); + gmove(n->type, l->type, g, n, lg, l); + if(result != D_NONE) + gmove(n->type, nn->type, g, n, result, nn); + regfree(g); + regfree(lg); + regfree(rg); + break; + + asbitop: + rg = regaddr(D_NONE); + lg = regalloc(tfield, D_NONE); + if(l->complex >= r->complex) { + g = bitload(l, lg, rg, result, nn); + xg = regalloc(r->type, D_NONE); + cgen(r, xg, nn); + } else { + xg = regalloc(r->type, D_NONE); + cgen(r, xg, nn); + g = bitload(l, lg, rg, result, nn); + } + + if(!typefd[n->type->etype]) { + if(o == OASLDIV || o == OASDIV) { + yg = regpair(result); + gmove(tfield, n->type, g, l, yg, n); + gopcode(o, n->type, xg, r, yg, n); + gmove(n->type, tfield, yg, n, g, l); + regfree(yg); + regfree(yg+1); + + regfree(xg); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } + if(o == OASLMOD || o == OASMOD) { + yg = regpair(result); + gmove(tfield, n->type, g, l, yg, n); + gopcode(o, n->type, xg, r, yg, n); + gmove(n->type, tfield, yg+1, n, g, l); + regfree(yg); + regfree(yg+1); + + regfree(xg); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } + } + + yg = regalloc(n->type, result); + gmove(tfield, n->type, g, l, yg, n); + gopcode(o, n->type, xg, r, yg, n); + gmove(n->type, tfield, yg, n, g, l); + regfree(yg); + + regfree(xg); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + + case OCAST: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lg = result; + if(l->complex >= FNX) + lg = regret(l->type); + lg = eval(l, lg); + if(nocast(l->type, n->type)) { + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + } + if(nocast(n->type, nn->type)) { + gmove(l->type, n->type, lg, l, result, nn); + regfree(lg); + break; + } + rg = regalloc(n->type, result); + gmove(l->type, n->type, lg, l, rg, n); + gmove(n->type, nn->type, rg, n, result, nn); + regfree(rg); + regfree(lg); + break; + + case OCOND: + doinc(l, PRE); + boolgen(l, 1, D_NONE, Z, l); + p1 = p; + + inargs++; + doinc(r->left, PRE); + cgen(r->left, result, nn); + doinc(r->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(r->right, PRE); + cgen(r->right, result, nn); + doinc(r->right, POST); + patch(p1, pc); + inargs--; + break; + + case OIND: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lg = nodalloc(types[TIND], result, &nod); + nod.lineno = n->lineno; + if(l->op == OADD) { + if(l->left->op == OCONST) { + nod.xoffset += l->left->vconst; + l = l->right; + } else + if(l->right->op == OCONST) { + nod.xoffset += l->right->vconst; + l = l->left; + } + } + cgen(l, lg, l); + gmove(n->type, nn->type, D_TREE, &nod, result, nn); + regfree(lg); + break; + + case OFUNC: + v = argoff; + inargs++; + gargs(r); + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(result); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + inargs--; + doinc(r, POST); + doinc(l, POST); + gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l); + regfree(lg); + if(inargs) + adjsp(v - argoff); + if(result != D_NONE) { + lg = regret(n->type); + gmove(n->type, nn->type, lg, n, result, nn); + } + break; + + case OLDIV: + case OLMOD: + case ODIV: + case OMOD: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto binop; + if(r->addable >= INDEXED && r->complex < FNX) { + lg = regpair(result); + cgen(l, lg, l); + rg = D_TREE; + } else { + cgen(r, D_TOS, r); + v = argoff; + lg = regpair(result); + cgen(l, lg, l); + adjsp(v - argoff); + rg = D_TOS; + } + gopcode(o, n->type, rg, r, lg, l); + if(o == OMOD || o == OLMOD) + gmove(l->type, nn->type, lg+1, l, result, nn); + else + gmove(l->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(lg+1); + break; + + case OMUL: + case OLMUL: + if(l->op == OCONST) + if(mulcon(r, l, result, nn)) + break; + if(r->op == OCONST) + if(mulcon(l, r, result, nn)) + break; + if(debug['M']) + print("%L multiply\n", n->lineno); + goto binop; + + case OAND: + if(r->op == OCONST) + if(typeil[n->type->etype]) + if(l->op == OCAST) { + if(typec[l->left->type->etype]) + if(!(r->vconst & ~0xff)) { + l = l->left; + goto binop; + } + if(typeh[l->left->type->etype]) + if(!(r->vconst & ~0xffff)) { + l = l->left; + goto binop; + } + } + goto binop; + + case OADD: + if(result == D_TOS) + if(r->addable >= INDEXED) + if(l->op == OCONST) + if(typeil[l->type->etype]) { + v = l->vconst; + if(v > -32768 && v < 32768) { + rg = regaddr(D_NONE); + gmove(r->type, r->type, D_TREE, r, rg, r); + gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r); + p->to.offset = v; + p->to.type |= I_INDIR; + regfree(rg); + break; + } + } + + case OSUB: + if(result == D_TOS) + if(l->addable >= INDEXED) + if(r->op == OCONST) + if(typeil[r->type->etype]) { + v = r->vconst; + if(v > -32768 && v < 32768) { + if(n->op == OSUB) + v = -v; + lg = regaddr(D_NONE); + gmove(l->type, l->type, D_TREE, l, lg, l); + gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l); + p->to.offset = v; + p->to.type |= I_INDIR; + regfree(lg); + break; + } + } + goto binop; + + case OOR: + case OXOR: + binop: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + if(l->complex >= FNX && r->complex >= FNX) { + cgen(r, D_TOS, r); + v = argoff; + lg = regalloc(l->type, result); + cgen(l, lg, l); + adjsp(v - argoff); + if(o == OXOR) { + rg = regalloc(r->type, D_NONE); + gmove(r->type, r->type, D_TOS, r, rg, r); + gopcode(o, n->type, rg, r, lg, l); + regfree(rg); + } else + gopcode(o, n->type, D_TOS, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + } + if(l->complex >= r->complex) { + if(l->op == OADDR && (o == OADD || o == OSUB)) + lg = regaddr(result); + else + lg = regalloc(l->type, result); + cgen(l, lg, l); + rg = eval(r, D_NONE); + } else { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + lg = regalloc(l->type, result); + cgen(l, lg, l); + } + if(o == OXOR) { + if(rg == D_TREE) { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + } + if(rg == D_TOS) { + rg = regalloc(r->type, D_NONE); + gmove(r->type, r->type, D_TOS, r, rg, r); + } + } + gopcode(o, n->type, rg, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(rg); + break; + + case OASHL: + if(r->op == OCONST) + if(shlcon(l, r, result, nn)) + break; + case OLSHR: + case OASHR: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + + if(l->complex >= FNX && r->complex >= FNX) { + cgen(r, D_TOS, r); + v = argoff; + lg = regalloc(l->type, result); + cgen(l, lg, l); + adjsp(v - argoff); + rg = regalloc(r->type, D_NONE); + gopcode(OAS, r->type, D_TOS, r, rg, r); + gopcode(n->op, n->type, rg, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(rg); + break; + } + if(l->complex >= r->complex) { + lg = regalloc(l->type, result); + cgen(l, lg, l); + v = vconst(r); + if(v <= 0 || v > 8) { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + } else + rg = eval(r, D_NONE); + } else { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + lg = regalloc(l->type, result); + cgen(l, lg, l); + } + gopcode(o, n->type, rg, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(rg); + break; + + case ONEG: + case OCOM: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lg = regalloc(l->type, result); + cgen(l, lg, l); + gopcode(o, l->type, D_NONE, Z, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + + case OADDR: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lcgen(l, result, nn); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + boolgen(n, 1, result, nn, Z); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, result, nn, Z); + if(result == D_NONE) + patch(p, pc); + break; + + case OCOMMA: + cgen(l, D_NONE, l); + doinc(l, POST); + doinc(r, PRE); + cgen(r, result, nn); + break; + + case ONOT: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, result, nn, Z); + 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; + + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + if(result != D_NONE) + gmove(l->type, nn->type, lg, l, result, nn); + if(typefd[n->type->etype]) { + rg = regalloc(n->type, D_NONE); + gmove(l->type, l->type, lg, l, rg, l); + gopcode(o, n->type, D_CONST, nodconst(1), rg, l); + gmove(l->type, l->type, rg, l, lg, l); + regfree(rg); + } else { + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), lg, l); + else + gopcode(o, n->type, D_CONST, nodconst(v), lg, l); + } + regfree(lg); + 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: + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + if(typefd[n->type->etype]) { + rg = regalloc(n->type, D_NONE); + gmove(l->type, l->type, lg, l, rg, l); + gopcode(o, n->type, D_CONST, nodconst(1), rg, l); + gmove(l->type, l->type, rg, l, lg, l); + regfree(rg); + } else { + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), lg, l); + else + gopcode(o, n->type, D_CONST, nodconst(v), lg, l); + } + if(result != D_NONE) + gmove(l->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + + bitinc: + rg = regaddr(D_NONE); + lg = regalloc(tfield, D_NONE); + if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) { + g = bitload(l, lg, rg, D_NONE, nn); + if(nn != Z) + gmove(l->type, nn->type, g, l, result, nn); + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), g, n); + else + gopcode(o, n->type, D_CONST, nodconst(v), g, n); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } + g = bitload(l, lg, rg, result, nn); + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), g, n); + else + gopcode(o, n->type, D_CONST, nodconst(v), g, n); + if(result != D_NONE) + gmove(l->type, nn->type, g, l, result, nn); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } +} + +void +lcgen(Node *n, int result, Node *nn) +{ + Node rn; + Prog *p1; + int lg; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R\n", result); + prtree(n, "lcgen"); + } + if(nn == Z) { + nn = &rn; + nn->type = types[TIND]; + } + switch(n->op) { + case OCOMMA: + cgen(n->left, D_NONE, n->left); + doinc(n->left, POST); + doinc(n->right, PRE); + lcgen(n->right, result, nn); + break; + + case OCOND: + doinc(n->left, PRE); + boolgen(n->left, 1, D_NONE, Z, n->left); + p1 = p; + + inargs++; + doinc(n->right->left, PRE); + lcgen(n->right->left, result, nn); + doinc(n->right->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(n->right->right, PRE); + lcgen(n->right->right, result, nn); + doinc(n->right->right, POST); + patch(p1, pc); + inargs--; + break; + + case OIND: + if(n->addable >= INDEXED) { + if(result >= D_A0 && result < D_A0+NREG) { + gopcode(OADDR, types[TLONG], D_TREE, n, result, nn); + break; + } + if(result == D_TOS) { + gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n); + break; + } + } + cgen(n->left, result, nn); + break; + + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + if(result >= D_A0 && result < D_A0+NREG) { + gopcode(OADDR, types[TLONG], D_TREE, n, result, nn); + break; + } + if(result == D_TOS) { + gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n); + break; + } + lg = regaddr(result); + gopcode(OADDR, types[TLONG], D_TREE, n, lg, nn); + gopcode(OAS, nn->type, lg, nn, result, nn); + regfree(lg); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + boolgen(n, true, D_NONE, Z, Z); +} + +void +boolgen(Node *n, int true, int result, Node *nn, Node *post) +{ + Prog *p1, *p2; + Node *l, *r; + int lg, rg, fp, o; + long v; + + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R\n", result); + prtree(n, "boolgen"); + } + l = n->left; + r = n->right; + switch(n->op) { + + default: + lg = eval(n, result); + if(lg >= D_A0 && lg < D_A0+NREG) { + rg = regalloc(types[TLONG], D_NONE); + gopcode(OAS, types[TLONG], lg, n, rg, Z); + regfree(rg); + } else + gopcode(OTST, n->type, D_NONE, Z, lg, n); + regfree(lg); + o = ONE; + fp = typefd[n->type->etype]; + goto genbool; + + case OCONST: + fp = vconst(n); + if(!true) + fp = !fp; + gbranch(OGOTO); + if(fp) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + + case ONOT: + boolgen(l, !true, result, nn, post); + break; + + case OCOND: + doinc(l, PRE); + boolgen(l, 1, D_NONE, Z, l); + p1 = p; + + inargs++; + doinc(r->left, PRE); + boolgen(r->left, true, result, nn, r->left); + if(result != D_NONE) { + doinc(r->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(r->right, PRE); + boolgen(r->right, !true, result, nn, r->right); + doinc(r->right, POST); + patch(p1, pc); + inargs--; + break; + } + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(r->right, PRE); + boolgen(r->right, !true, result, nn, r->right); + patch(p2, pc); + p2 = p; + if(doinc(post, POST|TEST)) { + lg = regalloc(types[TSHORT], D_NONE); + gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z); + doinc(post, POST); + gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z); + regfree(lg); + } + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + inargs--; + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + doinc(l, PRE); + boolgen(l, true, D_NONE, Z, l); + p1 = p; + inargs++; + doinc(r, PRE); + boolgen(r, !true, D_NONE, Z, r); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + inargs--; + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + doinc(l, PRE); + boolgen(l, !true, D_NONE, Z, l); + p1 = p; + inargs++; + doinc(r, PRE); + boolgen(r, !true, D_NONE, Z, r); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + inargs--; + goto com; + + case OEQ: + case ONE: + if(vconst(l) == 0) { + if(n->op == ONE) { + boolgen(r, true, result, nn, post); + break; + } + boolgen(r, !true, result, nn, post); + break; + } + + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + fp = typefd[r->type->etype]; + if(l->op == OCONST) { + v = vconst(l); + if(v == 0) { /* tst instruction */ + o = invrel[relindex(n->op)]; + rg = eval(r, result); + gopcode(OTST, r->type, D_NONE, Z, rg, r); + regfree(rg); + goto genbool; + } + if(!fp) { /* cmpi and movq, saves about .5% both time and space */ + if(v < 128 && v >= -128 && + ewidth[r->type->etype] == SZ_LONG) { + rg = eval(r, result); + lg = regalloc(l->type, D_NONE); + cgen(l, lg, l); + o = n->op; + gopcode(o, l->type, lg, l, rg, r); + regfree(lg); + regfree(rg); + goto genbool; + } + o = invrel[relindex(n->op)]; + rg = eval(r, result); + gopcode(o, r->type, rg, r, D_TREE, l); + regfree(rg); + goto genbool; + } + } + lg = D_TOS; + if(r->complex < FNX) + lg = regalloc(l->type, lg); + cgen(l, lg, l); + v = argoff; + rg = eval(r, result); + if(lg == D_TOS) { + adjsp(v - argoff); + lg = regalloc(l->type, lg); + gopcode(OAS, l->type, D_TOS, l, lg, l); + } + o = n->op; + gopcode(o, l->type, lg, l, rg, r); + regfree(lg); + regfree(rg); + + genbool: + if(true) + o = comrel[relindex(o)]; + if(doinc(post, POST|TEST)) { + lg = regalloc(types[TSHORT], D_NONE); + gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z); + doinc(post, POST); + gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z); + regfree(lg); + } + gbranch(o); + if(fp) + fpbranch(); + + com: + if(result == D_NONE) + break; + p1 = p; + gopcode(OAS, nn->type, D_CONST, nodconst(1), result, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nn->type, D_CONST, nodconst(0), result, nn); + patch(p2, pc); + break; + } +} + +void +sugen(Node *n, int result, Node *nn, long w) +{ + long s, v, o; + int lg, rg, ng; + Prog *p1; + Node *l, *r, nod; + Type *t; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R width = %ld\n", result, w); + prtree(n, "sugen"); + } + s = argoff; + if(result == D_TREE) { + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + } + + if(n->addable >= INDEXED && n->op != OCONST) + goto copy; + switch(n->op) { + default: + diag(n, "unknown op in sugen: %O", n->op); + break; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(result == D_NONE) { + nullwarn(n->left, Z); + break; + } + + lg = regaddr(D_NONE); + if(result == D_TOS) { + adjsp(s - argoff + w); + gopcode(OADDR, types[TIND], result, nn, lg, n); + } else + if(result == D_TREE) { + lcgen(nn, lg, Z); + } else + diag(n, "unknown su result: %R", result); + + gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst>>32)), + lg|I_INDINC, n); + gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst)), + lg|I_INDINC, n); + regfree(lg); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, D_TREE, nodrat, l->type->width); + if(result != D_NONE) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += r->vconst; + nod.type = n->type; + sugen(&nod, result, nn, w); + } + break; + + case OIND: + if(result == D_NONE) { + nullwarn(n->left, Z); + break; + } + goto copy; + + case OSTRUCT: + lg = nodalloc(types[TIND], result, &nod); + nod.lineno = n->lineno; + if(result == D_TREE) + lcgen(nn, lg, Z); + else + if(result == D_TOS) { + adjsp(s - argoff + w); + gopcode(OADDR, types[TIND], result, nn, lg, n); + } else + diag(n, "unknown su result: %R", result); + o = 0; + 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; + } + nod.type = t; + if(l->complex < FNX) { + nod.xoffset = 0; + if(o != t->offset) { + gopcode(OADD, types[TIND], D_CONST, + nodconst(t->offset-o), lg, Z); + o = t->offset; + } + cgen(l, D_TREE, &nod); + continue; + } + nod.xoffset = t->offset - o; + gopcode(OAS, types[TIND], lg, Z, D_TOS, Z); + s = argoff; + if(typesuv[t->etype]) { + sugen(l, D_TREE, nodrat, t->width); + adjsp(s - argoff); + gopcode(OAS, types[TIND], D_TOS, Z, lg, Z); + warn(n, "non-interruptable temporary"); + sugen(nodrat, D_TREE, &nod, t->width); + continue; + } + rg = regalloc(t, D_NONE); + cgen(l, rg, l); + adjsp(s - argoff); + gopcode(OAS, types[TIND], D_TOS, Z, lg, Z); + gopcode(OAS, t, rg, Z, D_TREE, &nod); + regfree(rg); + } + regfree(lg); + break; + + case OAS: + if(result == D_NONE) { + sugen(n->right, D_TREE, n->left, w); + break; + } + sugen(n->right, D_TREE, nodrat, w); /* could do better */ + warn(n, "non-interruptable temporary"); + sugen(nodrat, D_TREE, n->left, w); + sugen(nodrat, result, nn, w); + break; + + case OFUNC: + if(result == D_NONE) { + sugen(n, D_TREE, nodrat, w); + break; + } + inargs++; + /* prepare zero-th arg: address of result */ + if(result == D_TOS) { + adjsp(s - argoff + w); + v = argoff; + gargs(n->right); + gopcode(OADDR, types[TSHORT], D_NONE, nn, result, nn); + p->to.type = D_STACK; + p->to.offset = argoff - v; + } else + if(result == D_TREE) { + v = argoff; + gargs(n->right); + if(nn->complex >= FNX) { + rg = regalloc(types[TIND], regret(types[TIND])); + lcgen(nn, rg, Z); + gopcode(OAS, types[TIND], rg, Z, D_TOS, Z); + regfree(rg); + } else + lcgen(nn, D_TOS, Z); + } else { + diag(n, "unknown result in FUNC sugen"); + break; + } + argoff += types[TIND]->width; + l = n->left; + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(result); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + inargs--; + doinc(n->right, POST); + doinc(n->left, POST); + gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l); + regfree(lg); + if(inargs) + adjsp(v - argoff); + break; + + case OCOND: + doinc(n->left, PRE); + boolgen(n->left, 1, D_NONE, Z, n->left); + p1 = p; + + inargs++; + doinc(n->right->left, PRE); + sugen(n->right->left, result, nn, w); + doinc(n->right->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(n->right->right, PRE); + sugen(n->right->right, result, nn, w); + doinc(n->right->right, POST); + patch(p1, pc); + inargs--; + break; + + case OCOMMA: + cgen(n->left, D_NONE, n->left); + doinc(n->left, POST); + doinc(n->right, PRE); + sugen(n->right, result, nn, w); + break; + } + return; + +copy: + if(result == D_NONE) + return; + rg = regaddr(D_NONE); + lcgen(n, rg, Z); + + lg = regaddr(D_NONE); + if(result == D_TOS) { + adjsp(s - argoff + w); + gopcode(OADDR, types[TIND], result, nn, lg, n); + } else + if(result == D_TREE) { + if(nn->complex >= FNX) { + gopcode(OAS, types[TIND], rg, n, D_TOS, n); + s = argoff; + lcgen(nn, lg, Z); + adjsp(s - argoff); + gopcode(OAS, types[TIND], D_TOS, n, rg, n); + } else + lcgen(nn, lg, Z); + } else + diag(n, "unknown su result: %R", result); + + if(w % SZ_LONG) + diag(Z, "sucopy width not 0%%%d", SZ_LONG); + v = w / SZ_LONG; + if(v & 1) { + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + v--; + } + if(v > 6) { + ng = regalloc(types[TLONG], D_NONE); + gopcode(OAS, types[TLONG], D_CONST, nodconst(v/2-1), ng, n); + v = pc; + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + gbranch(OGT); + patch(p, v); + p->from.type = ng; + p->as = ADBF; + regfree(ng); + } else + while(v > 0) { + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + v--; + } + + regfree(lg); + regfree(rg); +} diff --git a/utils/1c/enam.c b/utils/1c/enam.c new file mode 100644 index 00000000..be6917af --- /dev/null +++ b/utils/1c/enam.c @@ -0,0 +1,425 @@ +char *anames[] = +{ + "XXX", + "ABCD", + "ADDB", + "ADDL", + "ADDW", + "ADDXB", + "ADDXL", + "ADDXW", + "ADJSP", + "ANDB", + "ANDL", + "ANDW", + "ASLB", + "ASLL", + "ASLW", + "ASRB", + "ASRL", + "ASRW", + "BCASE", + "BCC", + "BCHG", + "BCLR", + "BCS", + "BEQ", + "BFCHG", + "BFCLR", + "BFEXTS", + "BFEXTU", + "BFFFO", + "BFINS", + "BFSET", + "BFTST", + "BGE", + "BGT", + "BHI", + "BKPT", + "BLE", + "BLS", + "BLT", + "BMI", + "BNE", + "BPL", + "BRA", + "BSET", + "BSR", + "BTST", + "BVC", + "BVS", + "CALLM", + "CAS2B", + "CAS2L", + "CAS2W", + "CASB", + "CASEW", + "CASL", + "CASW", + "CHK2B", + "CHK2L", + "CHK2W", + "CHKL", + "CHKW", + "CLRB", + "CLRL", + "CLRW", + "CMP2B", + "CMP2L", + "CMP2W", + "CMPB", + "CMPL", + "CMPW", + "DATA", + "DBCC", + "DBCS", + "DBEQ", + "DBF", + "DBGE", + "DBGT", + "DBHI", + "DBLE", + "DBLS", + "DBLT", + "DBMI", + "DBNE", + "DBPL", + "DBT", + "DBVC", + "DBVS", + "DIVSL", + "DIVSW", + "DIVUL", + "DIVUW", + "END", + "EORB", + "EORL", + "EORW", + "EXG", + "EXTBL", + "EXTBW", + "EXTWL", + "FABSB", + "FABSD", + "FABSF", + "FABSL", + "FABSW", + "FACOSB", + "FACOSD", + "FACOSF", + "FACOSL", + "FACOSW", + "FADDB", + "FADDD", + "FADDF", + "FADDL", + "FADDW", + "FASINB", + "FASIND", + "FASINF", + "FASINL", + "FASINW", + "FATANB", + "FATAND", + "FATANF", + "FATANHB", + "FATANHD", + "FATANHF", + "FATANHL", + "FATANHW", + "FATANL", + "FATANW", + "FBEQ", + "FBF", + "FBGE", + "FBGT", + "FBLE", + "FBLT", + "FBNE", + "FBT", + "FCMPB", + "FCMPD", + "FCMPF", + "FCMPL", + "FCMPW", + "FCOSB", + "FCOSD", + "FCOSF", + "FCOSHB", + "FCOSHD", + "FCOSHF", + "FCOSHL", + "FCOSHW", + "FCOSL", + "FCOSW", + "FDBEQ", + "FDBF", + "FDBGE", + "FDBGT", + "FDBLE", + "FDBLT", + "FDBNE", + "FDBT", + "FDIVB", + "FDIVD", + "FDIVF", + "FDIVL", + "FDIVW", + "FETOXB", + "FETOXD", + "FETOXF", + "FETOXL", + "FETOXM1B", + "FETOXM1D", + "FETOXM1F", + "FETOXM1L", + "FETOXM1W", + "FETOXW", + "FGETEXPB", + "FGETEXPD", + "FGETEXPF", + "FGETEXPL", + "FGETEXPW", + "FGETMANB", + "FGETMAND", + "FGETMANF", + "FGETMANL", + "FGETMANW", + "FINTB", + "FINTD", + "FINTF", + "FINTL", + "FINTRZB", + "FINTRZD", + "FINTRZF", + "FINTRZL", + "FINTRZW", + "FINTW", + "FLOG10B", + "FLOG10D", + "FLOG10F", + "FLOG10L", + "FLOG10W", + "FLOG2B", + "FLOG2D", + "FLOG2F", + "FLOG2L", + "FLOG2W", + "FLOGNB", + "FLOGND", + "FLOGNF", + "FLOGNL", + "FLOGNP1B", + "FLOGNP1D", + "FLOGNP1F", + "FLOGNP1L", + "FLOGNP1W", + "FLOGNW", + "FMODB", + "FMODD", + "FMODF", + "FMODL", + "FMODW", + "FMOVEB", + "FMOVED", + "FMOVEF", + "FMOVEL", + "FMOVEM", + "FMOVEMC", + "FMOVEW", + "FMULB", + "FMULD", + "FMULF", + "FMULL", + "FMULW", + "FNEGB", + "FNEGD", + "FNEGF", + "FNEGL", + "FNEGW", + "FREMB", + "FREMD", + "FREMF", + "FREML", + "FREMW", + "FRESTORE", + "FSAVE", + "FSCALEB", + "FSCALED", + "FSCALEF", + "FSCALEL", + "FSCALEW", + "FSEQ", + "FSF", + "FSGE", + "FSGT", + "FSINB", + "FSIND", + "FSINF", + "FSINHB", + "FSINHD", + "FSINHF", + "FSINHL", + "FSINHW", + "FSINL", + "FSINW", + "FSLE", + "FSLT", + "FSNE", + "FSQRTB", + "FSQRTD", + "FSQRTF", + "FSQRTL", + "FSQRTW", + "FST", + "FSUBB", + "FSUBD", + "FSUBF", + "FSUBL", + "FSUBW", + "FTANB", + "FTAND", + "FTANF", + "FTANHB", + "FTANHD", + "FTANHF", + "FTANHL", + "FTANHW", + "FTANL", + "FTANW", + "FTENTOXB", + "FTENTOXD", + "FTENTOXF", + "FTENTOXL", + "FTENTOXW", + "FTSTB", + "FTSTD", + "FTSTF", + "FTSTL", + "FTSTW", + "FTWOTOXB", + "FTWOTOXD", + "FTWOTOXF", + "FTWOTOXL", + "FTWOTOXW", + "GLOBL", + "GOK", + "HISTORY", + "ILLEG", + "INSTR", + "JMP", + "JSR", + "LEA", + "LINKL", + "LINKW", + "LOCATE", + "LONG", + "LSLB", + "LSLL", + "LSLW", + "LSRB", + "LSRL", + "LSRW", + "MOVB", + "MOVEM", + "MOVEPL", + "MOVEPW", + "MOVESB", + "MOVESL", + "MOVESW", + "MOVL", + "MOVW", + "MULSL", + "MULSW", + "MULUL", + "MULUW", + "NAME", + "NBCD", + "NEGB", + "NEGL", + "NEGW", + "NEGXB", + "NEGXL", + "NEGXW", + "NOP", + "NOTB", + "NOTL", + "NOTW", + "ORB", + "ORL", + "ORW", + "PACK", + "PEA", + "RESET", + "ROTLB", + "ROTLL", + "ROTLW", + "ROTRB", + "ROTRL", + "ROTRW", + "ROXLB", + "ROXLL", + "ROXLW", + "ROXRB", + "ROXRL", + "ROXRW", + "RTD", + "RTE", + "RTM", + "RTR", + "RTS", + "SBCD", + "SCC", + "SCS", + "SEQ", + "SF", + "SGE", + "SGT", + "SHI", + "SLE", + "SLS", + "SLT", + "SMI", + "SNE", + "SPL", + "ST", + "STOP", + "SUBB", + "SUBL", + "SUBW", + "SUBXB", + "SUBXL", + "SUBXW", + "SVC", + "SVS", + "SWAP", + "SYS", + "TAS", + "TEXT", + "TRAP", + "TRAPCC", + "TRAPCS", + "TRAPEQ", + "TRAPF", + "TRAPGE", + "TRAPGT", + "TRAPHI", + "TRAPLE", + "TRAPLS", + "TRAPLT", + "TRAPMI", + "TRAPNE", + "TRAPPL", + "TRAPT", + "TRAPV", + "TRAPVC", + "TRAPVS", + "TSTB", + "TSTL", + "TSTW", + "UNLK", + "UNPK", + "WORD", + "SIGNAME", + "LAST", +}; diff --git a/utils/1c/gc.h b/utils/1c/gc.h new file mode 100644 index 00000000..288971f3 --- /dev/null +++ b/utils/1c/gc.h @@ -0,0 +1,339 @@ +#include "../cc/cc.h" +#include "../2c/2.out.h" +/* + * 1c/68000 + * Motorola 68000 + */ + +#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 ALLOP OEND +#define NRGN 300 +#define FNX 100 +#define INDEXED 9 + +#define PRE 1 +#define POST 2 +#define TEST 4 + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Txt Txt; +typedef struct Cases Case; +typedef struct Reg Reg; +typedef struct Rgn Rgn; +typedef struct Var Var; +typedef struct Multab Multab; +typedef struct C1 C1; + +struct Adr +{ + long displace; + long offset; + + char sval[NSNAME]; + double dval; + + Sym* sym; + short type; + short field; + short etype; +}; +#define A ((Adr*)0) + +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + short as; +}; +#define P ((Prog*)0) + +struct Txt +{ + short movas; + short postext; + char preclr; +}; + +struct Cases +{ + long val; + long label; + uchar def; + Case* link; +}; +#define C ((Case*)0) + +struct Var +{ + long offset; + Sym* sym; + char type; + 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; + + ulong 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 Rgn +{ + Reg* enter; + short costr; + short costa; + short varno; + short regno; +}; + +struct Multab +{ + short val; + char code[6]; +}; + +struct C1 +{ + long val; + long label; +}; + +#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 8 +#define CREF 5 +#define CTEST 2 +#define CXREF 3 +#define CINF 1000 +#define LOOP 3 + +EXTERN Bits externs; +EXTERN Bits params; +EXTERN Bits addrs; +EXTERN ulong regbits; + +#define B_INDIR (1<<0) +#define B_ADDR (1<<1) +EXTERN int mvbits; +EXTERN int changer; +EXTERN int changea; + +EXTERN Txt txt[NTYPE][NTYPE]; +EXTERN short opxt[ALLOP][NTYPE]; +EXTERN Txt* txtp; +EXTERN int multabsize; + +EXTERN Reg* firstr; +EXTERN Reg* lastr; +EXTERN Reg zreg; +EXTERN Reg* freer; + +EXTERN long argoff; +EXTERN long breakpc; +EXTERN Case* cases; +EXTERN long continpc; +EXTERN Prog* firstp; +EXTERN Reg* firstr; +EXTERN int inargs; +EXTERN Prog* lastp; +EXTERN int retok; +EXTERN long mnstring; +EXTERN Node* nodrat; +EXTERN Node* nodret; +EXTERN long nrathole; +EXTERN long nstatic; +EXTERN int nregion; +EXTERN long nstring; +EXTERN int nvar; +EXTERN Prog* p; +EXTERN long pc; +EXTERN Rgn region[NRGN]; +EXTERN Rgn* rgp; +EXTERN char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Sym* symstatic; +EXTERN Var var[NVAR]; +EXTERN long* idom; +EXTERN Reg** rpo2r; +EXTERN long maxnr; +EXTERN Prog zprog; + +EXTERN uchar regused[NREG]; +EXTERN uchar aregused[NREG]; +EXTERN uchar fregused[NREG]; +EXTERN uchar regbase[I_MASK]; +EXTERN long exregoffset; +EXTERN long exaregoffset; +EXTERN long exfregoffset; +extern char* anames[]; +extern Multab multab[]; + +void cgen(Node*, int, Node*); +void lcgen(Node*, int, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, int, Node*, Node*); +void sugen(Node*, int, Node*, long); + + +void listinit(void); +int Bconv(Fmt*); +int Pconv(Fmt*); +int Aconv(Fmt*); +int Xconv(Fmt*); +int Dconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); + +void peep(void); +void excise(Reg*); +Reg* uniqp(Reg*); +Reg* uniqs(Reg*); +int findtst(Reg*, Prog*, int); +int setcc(Prog*, Prog*); +int compat(Adr*, Adr*); +int aregind(Adr*); +int asize(int); +int usedin(int, Adr*); +Reg* findccr(Reg*); +int setccr(Prog*); +Reg* findop(Reg*, int, int, int); +int regtyp(int); +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 tasas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copysub(Adr*, Adr*, Adr*, Prog*, int); + +ulong RtoB(int); +ulong AtoB(int); +ulong FtoB(int); +int BtoR(ulong); +int BtoA(ulong); +int BtoF(ulong); + +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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, ulong, int); +void addreg(Adr*, int); + +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void usedset(Node*, int); +Node* nodconst(long); + +int swcmp(const void*, const void*); +void doswit(int, Node*); +void swit1(C1*, int, long, int, Node*); +void cas(void); +int bitload(Node*, int, int, int, Node*); +void bitstore(Node*, int, int, int, int, Node*); +long outstring(char*, long); +int doinc(Node*, int); +void setsp(void); +void adjsp(long); +int simplv(Node*); +int eval(Node*, int); +void outcode(void); +void ieeedtod(Ieee*, double); +int nodalloc(Type*, int, Node*); +int mulcon(Node*, Node*, int, Node*); +int shlcon(Node*, Node*, int, Node*); +int mulcon1(Node*, long, int, Node*); +void nullwarn(Node*, Node*); + +void tindex(Type*, Type*); +void ginit(void); +void gclean(void); +void oinit(int, int, int, int, int, int); +Prog* prg(void); +void nextpc(void); +void gargs(Node*); +void naddr(Node*, Adr*, int); +int regalloc(Type*, int); +int regaddr(int); +int regpair(int); +int regret(Type*); +void regfree(int); +void gmove(Type*, Type*, int, Node*, int, Node*); +void gopcode(int, Type*, int, Node*, int, Node*); +void asopt(void); +int relindex(int); +void gbranch(int); +void fpbranch(void); +void patch(Prog*, long); +void gpseudo(int, Sym*, int, long); +void gpseudotree(int, Sym*, Node*); + +void indx(Node*); +void bcomplex(Node*); + +/* + * com64 + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* +#pragma varargck type "R" int diff --git a/utils/1c/list.c b/utils/1c/list.c new file mode 100644 index 00000000..f6bc2e62 --- /dev/null +++ b/utils/1c/list.c @@ -0,0 +1,319 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('R', Rconv); + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('B', Bconv); +} + +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], s[20]; + Prog *p; + + p = va_arg(fp->args, Prog*); + sprint(str, " %A %D,%D", p->as, &p->from, &p->to); + if(p->from.field) { + sprint(s, ",%d,%d", p->to.field, p->from.field); + strcat(str, s); + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int r; + + r = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[r]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i, j; + long d; + + a = va_arg(fp->args, Adr*); + i = a->type; + j = i & I_MASK; + if(j) { + a->type = i & D_MASK; + d = a->offset; + a->offset = 0; + switch(j) { + case I_INDINC: + sprint(str, "(%D)+", a); + break; + + case I_INDDEC: + sprint(str, "-(%D)", a); + break; + + case I_INDIR: + if(a->type == D_CONST) + sprint(str, "%ld", d); + else + if(d) + sprint(str, "%ld(%D)", d, a); + else + sprint(str, "(%D)", a); + break; + + case I_ADDR: + a->offset = d; + sprint(str, "$%D", a); + break; + } + a->type = i; + a->offset = d; + goto out; + } + switch(i) { + + default: + 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: + sprint(str, "%s+%ld(FP)", a->sym->name, a->offset); + break; + + case D_CONST: + sprint(str, "$%ld", a->offset); + break; + + case D_STACK: + sprint(str, "TOS+%ld", a->offset); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + goto out; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + goto out; + } + if(a->displace) { + sprint(s, "/%ld", a->displace); + strcat(str, s); + } +out: + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_R0 && r < D_R0+NREG) + sprint(str, "R%d", r-D_R0); + else + if(r >= D_A0 && r < D_A0+NREG) + sprint(str, "A%d", r-D_A0); + else + if(r >= D_F0 && r < D_F0+NREG) + sprint(str, "F%d", r-D_F0); + else + switch(r) { + + default: + sprint(str, "gok(%d)", r); + break; + + case D_NONE: + sprint(str, "NONE"); + break; + + case D_TOS: + sprint(str, "TOS"); + break; + + case D_CCR: + sprint(str, "CCR"); + break; + + case D_SR: + sprint(str, "SR"); + break; + + case D_SFC: + sprint(str, "SFC"); + break; + + case D_DFC: + sprint(str, "DFC"); + break; + + case D_CACR: + sprint(str, "CACR"); + break; + + case D_USP: + sprint(str, "USP"); + break; + + case D_VBR: + sprint(str, "VBR"); + break; + + case D_CAAR: + sprint(str, "CAAR"); + break; + + case D_MSP: + sprint(str, "MSP"); + break; + + case D_ISP: + sprint(str, "ISP"); + break; + + case D_TREE: + sprint(str, "TREE"); + break; + + case D_FPCR: + sprint(str, "FPCR"); + break; + + case D_FPSR: + sprint(str, "FPSR"); + break; + + case D_FPIAR: + sprint(str, "FPIAR"); + break; + + case D_TC: + sprint(str, "TC"); + break; + + case D_ITT0: + sprint(str, "ITT0"); + break; + + case D_ITT1: + sprint(str, "ITT1"); + break; + + case D_DTT0: + sprint(str, "DTT0"); + break; + + case D_DTT1: + sprint(str, "DTT1"); + break; + + case D_MMUSR: + sprint(str, "MMUSR"); + break; + case D_URP: + sprint(str, "URP"); + break; + + case D_SRP: + sprint(str, "SRP"); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *s; + + s = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(double); i++) { + c = s[i] & 0xff; + if(c != '\\' && c != '"' && isprint(c)) { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = '0'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = ((c>>6) & 7) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = ((c>>0) & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} diff --git a/utils/1c/mkfile b/utils/1c/mkfile new file mode 100644 index 00000000..e5486b5c --- /dev/null +++ b/utils/1c/mkfile @@ -0,0 +1,29 @@ +<../../mkconfig + +TARG=1c + +OFILES=\ + cgen.$O\ + reg.$O\ + txt.$O\ + peep.$O\ + swt.$O\ + sgen.$O\ + list.$O\ + enam.$O\ + mul.$O\ + +HFILES= gc.h\ + ../2c/2.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/1c/mul.c b/utils/1c/mul.c new file mode 100644 index 00000000..65ddda2f --- /dev/null +++ b/utils/1c/mul.c @@ -0,0 +1,174 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant + * all sequences start with leading '0'. + * if sequence starts with 'i', then the + * leading '0' is suppressed. + * '0' mov r0,r1 + * '1' sub r0,r1 + * '2' sub r1,r0 + * '3' add r0,r1 + * '4' add r1,r0 + * '5' add r0,r0 + * '6' add r1,r1 + * 'b' lsh $2,r0 + * 'c' lsh $3,r0 + * 'd'-'h' ... + * 'j' lsh $2,r1 + * 'k'-'p' ... + */ +Multab multab[] = +{ + 2, "i5", + 3, "64", + 4, "i55", + 5, "664", + 6, "645", + 7, "c2", + 9, "k4", + 10, "6645", + 11, "66364", + 12, "6455", + 13, "66464", + 14, "6d2", + 15, "d2", + 17, "l4", + 18, "6d4", + 19, "64k4", + 20, "66455", + 21, "664664", + 22, "64c2", + 23, "44c2", + 24, "64c", + 25, "63k4", + 26, "64c4", + 27, "663e2", + 28, "66e2", + 29, "63e2", + 30, "6e2", + 31, "e2", + 33, "m4", + 34, "6e4", + 35, "64l4", + 36, "66e4", + 37, "664k4", + 38, "64k45", + 39, "454c2", + 40, "664c", + 41, "663k4", + 42, "644c4", + 43, "643k4", + 44, "664c4", + 45, "640d2", + 46, "64d2", + 47, "44d2", + 48, "64d", + 49, "63l4", + 50, "64d4", + 51, "640l4", + 52, "646d4", + 53, "643d4", + 54, "6636f2", + 55, "k3f2", + 56, "kf2", + 57, "k2k4", + 58, "636f2", + 59, "663f2", + 60, "66f2", + 61, "63f2", + 62, "6f2", + 63, "f2", + 65, "n4", + 66, "6f4", + 67, "64m4", + 68, "66f4", + 69, "664l4", + 70, "64l45", + 71, "k1f4", + 72, "k4c", + 73, "k4k4", + 74, "664k45", + 75, "6640d2", + 76, "664d2", + 77, "434d2", + 78, "644d2", + 79, "454d2", + 80, "664d", + 81, "663l4", + 82, "644d4", + 83, "643l4", + 84, "664d4", + 85, "6640l4", + 86, "6634l4", + 87, "6443d4", + 88, "6646d4", + 89, "6643d4", + 90, "6406e2", + 91, "643e2", + 92, "646e2", + 93, "640e2", + 94, "64e2", + 95, "44e2", + 96, "64e", + 97, "63m4", + 98, "64e4", + 99, "640m4", + 100, "646e4", + 200, "66f364", + 300, "j40jf2", + 400, "64kg4", + 500, "66h212", + 600, "64m4c4", + 700, "j4c4d2", + 800, "64lh4", + 900, "6464g4", + 1000, "63g2c", + 1100, "j4d2p4", + 1200, "64k4f2", + 1300, "j4n4b4", + 1400, "64j4g2", + 1600, "64d4e", + 1800, "p4c2", + 2000, "63g2d", + 2100, "l4b2o4", + 2200, "k4d4p4", + 2300, "6644h2", + 2400, "j4k4f4", + 2500, "j4e2d4", + 2600, "j40n4c", + 3100, "jd12p2", + 3200, "64d4f", + 3600, "6d1p2", + 3800, "e3k3g2", + 3900, "jf20n4", + 4000, "o4e2", + 4100, "66p455", + 4200, "l4c3e2", + 4300, "l4b1f4", + 4400, "64o4d4", + 4600, "k45h2", + 4700, "k3j4g2", + 4800, "j40d2f", + 5000, "l4c3m4", + 5100, "j40h2b", + 5200, "j40n4d", + 6000, "d1o3h2", + 6100, "o1l4b2", + 6200, "ke12p2", + 6400, "64d4g", + 7200, "66e1p2", + 7400, "m3m4c2", + 7600, "l4f3c2", + 7800, "kg20n4", + 8000, "63g2f", + 8100, "m2b4p4", + 8200, "66p4c", + 8700, "66f4g2", + 8900, "l3j4g4", + 9200, "k45h25", + 9600, "j40d2g", + 9800, "k4f3d4", +}; + +int multabsize = sizeof(multab) / sizeof(multab[0]); diff --git a/utils/1c/peep.c b/utils/1c/peep.c new file mode 100644 index 00000000..e0a535c2 --- /dev/null +++ b/utils/1c/peep.c @@ -0,0 +1,1060 @@ +#include "gc.h" + +void +peep(void) +{ + Reg *r, *r1, *r2; + Prog *p, *p1; + int t, s; +/* + * 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; + } + } + +loop1: + /* + * propigate move's by renaming + */ + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVL || p->as == AFMOVEF || p->as == AFMOVED) + if(regtyp(p->from.type)) + if(anyvar(&p->to)) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + if(t) + goto loop1; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + /* + * convert (A) ... A++ into (A)++ + * and A-- ... (A) into --(A) + */ + t = aregind(&p->from); + if(t == D_NONE) + goto out1; + s = asize(p->as); + if(s == 0) + goto out1; + r1 = findop(r, t, AADDL, s); + if(r1 != R) { + if(usedin(t, &p->to)) + goto out1; + p->from.type += I_INDINC - I_INDIR; + excise(r1); + goto out1; + } + r1 = findop(r, t, ASUBL, s); + if(r1 != R) { + p->from.type += I_INDDEC - I_INDIR; + excise(r1); + } + out1: + t = aregind(&p->to); + if(t == D_NONE) + goto out2; + s = asize(p->as); + if(s == 0) + goto out2; + r1 = findop(r, t, AADDL, s); + if(r1 != R) { + p->to.type += I_INDINC - I_INDIR; + excise(r1); + goto out2; + } + r1 = findop(r, t, ASUBL, s); + if(r1 != R) { + if(usedin(t, &p->from)) + goto out2; + p->to.type += I_INDDEC - I_INDIR; + excise(r1); + } + out2: + /* + * get rid of unneeded save/restore CCR + */ + if(p->from.type == D_CCR) { + r1 = findccr(r); + if(r1 != R) { + excise(r); + excise(r1); + } + } + switch(p->as) { + case ATSTB: + case ATSTW: + case ATSTL: + if(findtst(r, r->prog, 0)) + excise(r); + } + /* + * turn TSTB (A); BLT; ORB $128,(A) into TAS (A); BLT; NOP + */ + if(p->as == ATSTB && (r1 = r->s1)) { + if((r1->prog->as == ABLT && (r2 = r1->s1)) || + (r1->prog->as == ABGE && (r2 = r1->s2))) { + p1 = r2->prog; + if(p1->as == AORB) + if(p1->from.type == D_CONST) + if(p1->from.offset == 128) + if(r1 == uniqp(r2)) + if(tasas(&p->to, &p1->to)) { + p->as = ATAS; + excise(r2); + } + } + } + } +} + +void +excise(Reg *r) +{ + + 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; +} + +/* + * chase backward all cc setting. + * returns 1 if all set same. + */ +int +findtst(Reg *r0, Prog *rp, int n) +{ + Reg *r; + int c; + +loop: + n++; + if(n >= 10) + return 0; + for(r=r0->p2; r!=R; r=r->p2link) { + c = setcc(r->prog, rp); + if(c > 0) + continue; + if(c == 0) + return 0; + if(findtst(r, rp, n) == 0) + return 0; + } + r = r0->p1; + if(r == R) + return 1; + c = setcc(r->prog, rp); + if(c > 0) + return 1; + if(c == 0) + return 0; + r0 = r; + goto loop; +} + +/* + * tests cc + * returns -1 if no change + * returns 1 if set the same + * returns 0 if set different + */ +int +setcc(Prog *p, Prog *rp) +{ + int s; + + s = asize(rp->as); + switch(p->as) { + default: + if(debug['P']) + print("unknown setcc %A\n", p->as); + break; + + case ACMPB: + case ACMPW: + case ACMPL: + case ABSR: + return 0; + + case ABRA: + case ABGE: + case ABNE: + case ABLE: + case ABEQ: + case ABHI: + case ABLS: + case ABMI: + case ABPL: + case ABGT: + case ABLT: + case ABCC: + case ABCS: + case APEA: + case ALEA: + case ANOP: + + case AFADDD: + case AFMULD: + case AFDIVD: + case AFSUBD: + case AFADDF: + case AFMULF: + case AFDIVF: + case AFSUBF: + case AADJSP: + return -1; + + case AADDW: + case AADDL: + case ASUBW: + case ASUBL: + case ACLRL: + case ACLRW: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + goto areg; + + case AADDB: + case ASUBB: + case AANDB: + case AANDW: + case AANDL: + case AORB: + case AORW: + case AORL: + case AEORB: + case AEORW: + case AEORL: + case ALSLB: + case ALSLW: + case ALSLL: + case ALSRB: + case ALSRW: + case ALSRL: + case AASLB: + case AASLW: + case AASLL: + case AASRB: + case AASRW: + case AASRL: + case ATSTB: + case ATSTW: + case ATSTL: + case ANEGB: + case ANEGW: + case ANEGL: + case ACLRB: + if(asize(p->as) != s) + break; + if(compat(&rp->to, &p->to)) + return 1; + break; + + case AMOVW: + case AMOVL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + goto areg; + case AMOVB: + if(asize(p->as) != s) + break; + if(compat(&rp->to, &p->to)) + return 1; + if(compat(&rp->to, &p->from)) + return 1; + } + return 0; + +areg: + if((rp->to.type&D_MASK) == p->to.type) + return 0; + return -1; +} + +int +compat(Adr *a, Adr *b) +{ + int o; + + o = a->type; + if((o >= D_R0 && o < D_R0+NREG) || + (o >= D_A0 && o < D_A0+NREG)) + return o == b->type; + o &= D_MASK; + if(o >= D_A0 && o < D_A0+NREG) { + if(o != (b->type&D_MASK)) + return 0; + if(a->offset != b->offset) + return 0; + o = a->type & I_MASK; + if(o == I_INDIR) { + o = b->type & I_MASK; + if(o == I_INDIR || o == I_INDDEC) + return 1; + return 0; + } + if(o == I_INDINC) { + o = b->type & I_MASK; + if(o == I_INDIR) { + b->type += I_INDINC-I_INDIR; + return 1; + } + if(o == I_INDDEC) { + b->type += I_INDIR-I_INDDEC; + return 1; + } + return 0; + } + } + return 0; +} + +int +aregind(Adr *a) +{ + int t; + + t = a->type; + if(t >= (D_A0|I_INDIR) && t < ((D_A0+NREG)|I_INDIR)) + while(a->offset == 0) + return t & D_MASK; + return D_NONE; +} + +int +asize(int a) +{ + + switch(a) { + case AFTSTD: + case AFMOVED: + case AFADDD: + case AFSUBD: + case AFMULD: + case AFDIVD: + case AFCMPD: + case AFNEGD: + return 8; + + case AFTSTF: + case AFMOVEF: + case AFADDF: + case AFSUBF: + case AFMULF: + case AFDIVF: + case AFCMPF: + case AFNEGF: + + case ACLRL: + case ATSTL: + case AMOVL: + case AADDL: + case ASUBL: + case ACMPL: + case AANDL: + case AORL: + case AEORL: + case ALSLL: + case ALSRL: + case AASLL: + case AASRL: + case ANEGL: + return 4; + + case ACLRW: + case ATSTW: + case AMOVW: + case AADDW: + case ASUBW: + case ACMPW: + case AANDW: + case AORW: + case AEORW: + case ALSLW: + case ALSRW: + case AASLW: + case AASRW: + case ANEGW: + return 2; + + case ACLRB: + case ATSTB: + case AMOVB: + case AADDB: + case ASUBB: + case ACMPB: + case AANDB: + case AORB: + case AEORB: + case ALSLB: + case ALSRB: + case AASLB: + case AASRB: + case ANEGB: + return 1; + } + if(debug['P']) + print("unknown asize %A\n", p->as); + return 0; +} + +int +usedin(int t, Adr *a) +{ + + if((a->type&D_MASK) == t) + return 1; + return 0; +} + +Reg* +findccr(Reg *r) +{ + Prog *p; + + for(;;) { + r = uniqs(r); + if(r == R) + break; + p = r->prog; + if(p->to.type == D_CCR) + return r; + if(setccr(p)) + break; + } + return R; +} + +int +setccr(Prog *p) +{ + + switch(p->as) { + case ANOP: + return 0; + + case AADDL: + case AMOVL: + case ACLRL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + return 0; + } + return 1; +} + +Reg* +findop(Reg *r, int t, int o, int s) +{ + Prog *p; + Reg *r1; + + for(;;) { + if(o == AADDL) { + r1 = uniqs(r); + if(r1 == R) + break; + if(uniqp(r1) != r) + break; + } else { + r1 = uniqp(r); + if(r1 == R) + break; + if(uniqs(r1) != r) + break; + } + r = r1; + p = r->prog; + if(usedin(t, &p->from)) + break; + if(usedin(t, &p->to)) { + if(p->as == o) + if(p->to.type == t) + if(p->from.type == D_CONST) + if(p->from.offset == s) + return r; + break; + } + } + return R; +} + +int +regtyp(int t) +{ + + if(t >= D_R0 && t < D_R0+8) + return 1; + if(t >= D_A0 && t < D_A0+8) + return 1; + if(t >= D_F0 && t < D_F0+8) + return 1; + return 0; +} + +int +anyvar(Adr *a) +{ + + if(regtyp(a->type)) + return 1; + return 0; + if(a->type == D_AUTO || a->type == D_PARAM) + 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 MOVL + * 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->type)) + return 0; + v2 = &p->to; + if(!regtyp(v2->type)) + return 0; + for(r=uniqp(r0); r!=R; r=uniqp(r)) { + if(uniqs(r) == R) + break; + p = r->prog; + switch(p->as) { + case ADIVUW: /* these set Rn and Rn+1 */ + case ADIVUL: + case ADIVSW: + case ADIVSL: + case ABSR: + return 0; + + case AFMOVED: + case AFMOVEF: + case AMOVL: + if(p->to.type == v1->type) + goto gotit; + } + if(copyau(&p->from, v2) || copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, p, 0) || copysub(&p->to, v1, v2, p, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, p, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + if(p->from.type == v2->type) + excise(r); + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, p, 1); + copysub(&p->to, v1, v2, p, 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; + + if(r->active) { + if(debug['P']) + print("copyret 1\n"); + return 1; + } + r->active = 1; + if(debug['P']) + print("copy %D->%D\n", v1, v2); + for(; r != R; r = r->s1) { + if(debug['P']) + print("%P", r->prog); + if(!f && uniqp(r) == R) { + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(r->prog, v2, A); + switch(t) { + case 2: /* rar, cant split */ + if(debug['P']) + print("; rar return 0\n"); + return 0; + case 3: /* set */ + if(debug['P']) + print("; set; return 1\n"); + return 1; + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(debug['P']) + print("; used and f; return 0\n"); + return 0; + } + if(copyu(r->prog, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; substitute"); + if(t == 4) { + if(debug['P']) + print("; used and set; return 1\n"); + return 1; + } + break; + } + if(!f) { + t = copyu(r->prog, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + if(debug['P']) + print("; f set used"); + f = 1; + } + } + 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) +{ + int t; + + switch(p->as) { + + default: + if(debug['P']) + print("unknown op %A\n", p->as); + return 2; + + case APEA: /* rhs addr */ + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ALEA: /* lhs addr, rhs store */ + if(copyas(&p->from, v)) + return 2; + + case AMOVL: /* rhs store */ + case ACLRL: + case AFMOVEF: + case AFMOVED: + case AFMOVEB: + case AFMOVEW: + case AFMOVEL: + case ANOP: + if(copyas(&p->to, v)) { + if(s != A) + return copysub(&p->from, v, s, p, 1); + if(copyau(&p->from, v)) + return 4; + return 3; + } + goto caseread; + + case AADDL: /* rhs rar */ + case AADDW: + case AADDB: + case ASUBL: + case ASUBW: + case ASUBB: + case AANDL: + case AANDW: + case AANDB: + case AORL: + case AORW: + case AORB: + case AEORL: + case AEORW: + case AEORB: + case AASRL: + case AASRW: + case AASRB: + case AASLL: + case AASLW: + case AASLB: + case ALSRL: + case ALSRW: + case ALSRB: + case ANOTL: + case ANOTW: + case ANOTB: + case ANEGL: + case ANEGW: + case ANEGB: + case AEXTBL: + case AEXTWL: + case AEXTBW: + + case AMULSL: + case AMULUL: + + case AMOVW: /* only sets part of register */ + case AMOVB: + case ACLRW: + case ACLRB: + + case AFADDD: + case AFMULD: + case AFDIVD: + case AFSUBD: + case AFNEGD: + case AFADDF: + case AFMULF: + case AFDIVF: + case AFSUBF: + case AFNEGF: + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ADBF: /* lhs rar */ + if(copyas(&p->from, v)) + return 2; + goto caseread; + + case ACMPL: /* read only */ + case ACMPW: + case ACMPB: + case AFCMPF: + case AFCMPD: + case ATSTL: + case ATSTW: + case ATSTB: + case AFTSTF: + case AFTSTD: + caseread: + if(s != A) { + if(copysub(&p->from, v, s, p, 1)) + return 1; + return copysub(&p->to, v, s, p, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + break; + + case ABRA: /* no reference */ + case ABGE: + case ABNE: + case ABLE: + case ABEQ: + case ABHI: + case ABLS: + case ABMI: + case ABPL: + case ABGT: + case ABLT: + case ABCC: + case ABCS: + + case AFBEQ: + case AFBNE: + case AFBGT: + case AFBGE: + case AFBLE: + case AFBLT: + + case AADJSP: + case ACASEW: + break; + + case ADIVUW: /* these set Rn and Rn+1 */ + case ADIVUL: + case ADIVSW: + case ADIVSL: + t = v->type; + if(t == p->to.type || t == p->to.type+1) + return 2; + goto caseread; + + case ARTS: /* funny */ + t = v->type; + if(t == D_R0 || t == D_F0) + return 2; + if(t >= D_R0 && t < D_R0+NREG) + if(t-D_R0 > exregoffset) + return 2; + if(t >= D_A0 && t < D_A0+NREG) + if(t-D_A0 > exaregoffset) + return 2; + if(t >= D_F0 && t < D_F0+NREG) + if(t-D_F0 > exfregoffset) + return 2; + return 3; + + case ABSR: /* funny */ + t = v->type; + if(t >= D_R0 && t < D_R0+NREG) + if(t-D_R0 > exregoffset) + return 2; + if(t >= D_A0 && t < D_A0+NREG) + if(t-D_A0 > exaregoffset) + return 2; + if(t >= D_F0 && t < D_F0+NREG) + if(t-D_F0 > exfregoffset) + return 2; + if(copyau(&p->to, v)) + return 2; + 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->type)) + return 1; + if(v->type == D_AUTO || v->type == D_PARAM) { + if(v->offset == a->offset) + return 1; + return 0; + } + return 0; +} + +/* + * indirect + */ +int +tasas(Adr *a, Adr *v) +{ + int t; + + t = a->type; + if(t < I_INDIR+D_A0 && t >= I_INDIR+D_A0+8) + return 0; + if(v->type != t) + return 0; + if(a->displace != v->displace) + return 0; + return 1; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + int t; + + if(copyas(a, v)) + return 1; + t = v->type; + if(regtyp(t)) { + if((a->type & D_MASK) == t) + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, Prog *p, int f) +{ + int t; + + if(copyas(a, v)) { + t = s->type; + if(t >= D_F0 && t < D_F0+8) { + if(f) + a->type = t; + return 0; + } + if(t >= D_R0 && t < D_R0+8) { + if(f) + a->type = t; + return 0; + } + if(!(t >= D_A0 && t < D_A0+8)) + return 1; + switch(p->as) { + default: + return 1; + + case AMOVL: + case AMOVW: + case ACMPL: + case ACMPW: + break; + + case AADDL: + case AADDW: + case ASUBL: + case ASUBW: + if(a == &p->from && !regtyp(p->to.type)) + return 1; + break; + } + if(f) + a->type = t; + return 0; + } + t = v->type; + if(regtyp(t)) { + if((a->type & D_MASK) == t) { + if((s->type ^ t) & ~(NREG-1)) + return 1; + if(f) + a->type = (a->type & ~D_MASK) | s->type; + return 0; + } + return 0; + } + return 0; +} diff --git a/utils/1c/reg.c b/utils/1c/reg.c new file mode 100644 index 00000000..ad4231c0 --- /dev/null +++ b/utils/1c/reg.c @@ -0,0 +1,1221 @@ +#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->costr; + if(p2->costa > c1) + c1 = p2->costa; + c2 = p1->costr; + if(p1->costa > c2) + c2 = p1->costa; + if(c1 -= c2) + return c1; + return p2->varno - p1->varno; +} + +void +regopt(Prog *p) +{ + Reg *r, *r1, *r2; + Prog *p1; + int i, z; + long val, initpc, npc; + ulong vreg; + Bits bit; + Var *v; + struct { + long m; + long c; + Reg* p; + } log5[6], *lp; + + firstr = R; + lastr = R; + nvar = 0; + for(z=0; z<BITS; z++) { + externs.b[z] = 0; + params.b[z] = 0; + addrs.b[z] = 0; + } + regbits = RtoB(0) | /* return reg */ + AtoB(6) | AtoB(7) | /* sp and sb */ + FtoB(0) | FtoB(1); /* floating return reg */ + for(i=0; i<NREG; i++) { + if(regused[i]) + regbits |= RtoB(i); + if(fregused[i]) + regbits |= FtoB(i); + if(aregused[i]) + regbits |= AtoB(i); + } + + /* + * 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 ABRA: + case ARTS: + case ARTE: + r->p1 = R; + r1->s1 = R; + } + + bit = mkvar(&p->from, AGOK); + if(bany(&bit)) + switch(p->as) { + case ALEA: + if(!(mvbits & B_INDIR)) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + + default: + if(mvbits & B_ADDR) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + } + + bit = mkvar(&p->to, p->as); + if(bany(&bit)) + switch(p->as) { + case ABSR: /* funny */ + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + goto def; + + case APEA: + if(!(mvbits & B_INDIR)) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + + def: + case ACMPB: case ACMPW: case ACMPL: + case AFCMPF: case AFCMPD: + case ATSTB: case ATSTW: case ATSTL: + case AFTSTF: case AFTSTD: + case ABFEXTU: case ABFEXTS: + if(mvbits & B_ADDR) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + break; + + default: + diag(Z, "reg: unknown asop: %A", p->as); + + case AADDB: case AADDW: case AADDL: + case ASUBB: case ASUBW: case ASUBL: + case AANDB: case AANDW: case AANDL: + case AORB: case AORW: case AORL: + case AEORB: case AEORW: case AEORL: + case ABFINS: + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + + case ANOP: + case AMOVB: case AMOVW: case AMOVL: + case AFMOVEB: case AFMOVEW: case AFMOVEL: + case ACLRB: case ACLRW: case ACLRL: + case AFMOVEF: case AFMOVED: + if(mvbits & B_INDIR) + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + else + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + 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) { + diag(Z, "ref not found\n%L:%P", p->lineno, p); + continue; + } + if(r1 == r) { + diag(Z, "ref to self"); + continue; + } + r->s2 = r1; + r->p2link = r1->p2; + r1->p2 = r; + } + } + if(debug['R']) + print("\n%L %D\n", firstr->prog->lineno, &firstr->prog->from); + + /* + * pass 2.5 + * find looping structure + */ + for(r = firstr; r != R; r = r->link) + r->active = 0; + changer = 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: + changer = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + for(r = firstr; r != R; r = r->link) + if(r->prog->as == ARTS) + 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(changer) + goto loop1; + + /* + * pass 4 + * iterate propagating register/variable synchrony + * forward until graph is complete + */ +loop2: + changer = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + synch(firstr, zbits); + if(changer) + 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]); + 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); + + /* + * 68040 'feature': + * load of a denormalized fp will trap + */ + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + v = var + i; + if(v->type == D_AUTO) { + r->set.b[i/32] |= (1L << (i%32)); + if(typefd[v->etype]) + addmove(r, i, NREG+NREG, 1); + } + } + } + } + if(debug['R'] && debug['v']) + print("\nprop structure:\n"); + for(r = firstr; r != R; r = r->link) { + if(debug['R'] && debug['v']) + print("%P\n set = %B; rah = %B; cal = %B\n", + r->prog, r->set, r->refahead, r->calahead); + r->act = zbits; + } + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + 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 an 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; + changer = 0; + changea = 0; + if(debug['R'] && debug['v']) + print("\n"); + paint1(r, i); + bit.b[i/32] &= ~(1L<<(i%32)); + if(changer <= 0 && changea <= 0) { + if(debug['R']) + print("%L$%d.%d: %B\n", + r->prog->lineno, + changer, changea, blsh(i)); + continue; + } + rgp->costr = changer; + rgp->costa = changea; + 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.%d %R: %B\n", + rgp->enter->prog->lineno, + rgp->costr, rgp->costa, + rgp->regno, + bit); + if(rgp->regno != D_NONE) + 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; + Var *v; + int badccr; + + badccr = 0; + p = r->prog; + p1 = p->link; + if(p1) + switch(p1->as) { + case AMOVW: + if(p1->from.type == D_CCR) + p = p1; + break; + + case ABEQ: + case ABNE: + case ABLE: + case ABLS: + case ABLT: + case ABMI: + case ABGE: + case ABPL: + case ABGT: + case ABHI: + case ABCC: + case ABCS: + p1 = prg(); + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + p1->from.type = D_CCR; + p1->to.type = D_TOS; + p1->as = AMOVW; + p = p1; + badccr = 1; + } + p1 = prg(); + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + v = var + bn; + p1->from.sym = v->sym; + p1->from.type = v->type; + p1->from.offset = v->offset; + p1->from.etype = v->etype; + p1->to.type = rn; + if(f) { + p1->to = p1->from; + p1->from = zprog.from; + p1->from.type = rn; + } + p1->as = opxt[OAS][v->etype]; + if(badccr) { + p = p1; + p1 = prg(); + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + p1->from.type = D_TOS; + p1->to.type = D_CCR; + p1->as = AMOVW; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int as) +{ + Var *v; + int i, t, z; + long o; + Bits bit; + Sym *s; + + mvbits = 0; + t = a->type & D_MASK; + switch(t) { + + default: + if(t >= D_R0 && t < D_R0+NREG) { + regbits |= RtoB(t-D_R0); + if(as == ADIVUL || as == ADIVSL) + regbits |= RtoB(t-D_R0+1); + } + if(t >= D_A0 && t < D_A0+NREG) + regbits |= AtoB(t-D_A0); + if(t >= D_F0 && t < D_F0+NREG) + regbits |= FtoB(t-D_F0); + goto none; + + case D_EXTERN: + case D_STATIC: + case D_AUTO: + case D_PARAM: + break; + } + s = a->sym; + if(s == S) + goto none; + + if((a->type & I_MASK) == I_ADDR) + mvbits |= B_ADDR; + + o = a->offset; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(t == v->type) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = a->etype; + v->type = t; + if(debug['R']) + print("bit=%2d et=%2d %s (%p,%d,%ld)\n", + i, a->etype, s->name, + v->sym, v->type, v->offset); + +out: + bit = blsh(i); + if(t == D_EXTERN || t == D_STATIC) + for(z=0; z<BITS; z++) + externs.b[z] |= bit.b[z]; + if(t == D_PARAM) + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + if(a->etype != v->etype || !typechlpfd[a->etype]) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; /* funny punning */ + 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]; + changer++; + } + cal.b[z] |= r1->calahead.b[z]; + if(cal.b[z] != r1->calahead.b[z]) { + r1->calahead.b[z] = cal.b[z]; + changer++; + } + } + switch(r1->prog->as) { + case ABSR: + 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 ARTS: + 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]; + changer++; + } + } + 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, j; + + v = var + r->varno; + r->regno = D_NONE; + switch(v->etype) { + + default: + diag(Z, "unknown etype"); + break; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + i = BtoR(~b); + j = BtoA(~b); + if(r->costa == r->costr) + if(i > j) + i = NREG; + if(j < NREG && r->costa > 0) + if(r->costa > r->costr || i >= NREG) { + r->regno = D_A0 + j; + return AtoB(j); + } + if(i < NREG && r->costr > 0) { + r->regno = D_R0 + i; + return RtoB(i); + } + break; + + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i < NREG) { + r->regno = D_F0 + i; + return FtoB(i); + } + break; + } + return 0; +} + +void +paint1(Reg *r, int bn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + int x; + + 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) { + changer -= CLOAD * r->loop; + changea -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tld %B $%d.%d\n", r->loop, + r->prog, blsh(bn), changer, changea); + } + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + changer += CREF * r->loop; + changea += CREF * r->loop; + switch(p->as) { + default: + changea = -CINF; + case AADDL: + case ASUBL: + case AMOVL: + case ACMPL: + break; + } + if(p->as == AMOVL) { + x = p->to.type; + if(x >= D_R0 && x < D_R0+NREG) + changer += r->loop; + if(x >= D_A0 && x < D_A0+NREG) + changea += r->loop; + } + if(debug['R'] && debug['v']) + print("%ld%P\tu1 %B $%d.%d\n", r->loop, + p, blsh(bn), changer, changea); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + changer += CREF * r->loop; + changea += CREF * r->loop; + switch(p->as) { + default: + changea = -CINF; + break; + case AMOVL: + case AADDL: + case ACMPL: + case ASUBL: + case ACLRL: /* can be faked */ + case ATSTL: /* can be faked */ + break; + } + if(p->as == AMOVL) { + x = p->from.type; + if(x >= D_R0 && x < D_R0+NREG) + changer += r->loop; + if(x >= D_A0 && x < D_A0+NREG) + changea += r->loop; + } + if(debug['R'] && debug['v']) + print("%ld%P\tu2 %B $%d.%d\n", r->loop, + p, blsh(bn), changer, changea); + } + if(STORE(r) & r->regdiff.b[z] & bb) { + changer -= CLOAD * r->loop; + changea -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tst %B $%d.%d\n", r->loop, + p, blsh(bn), changer, changea); + } + + 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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + return vreg; +} + +void +paint3(Reg *r, int bn, ulong 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; + if(rn >= D_R0 && rn < D_R0+NREG) + goto addr; + a->type = rn | (a->type & I_INDIR); + return; + +addr: + a->type = rn | (a->type & I_INDIR); +} + +/* + * bit reg + * 0-7 R0-R7 + * 8-15 A0-A7 + * 16-23 F0-F7 + */ +ulong +RtoB(int r) +{ + + if(r < 0 || r >= NREG) + return 0; + return 1L << (r + 0); +} + +int +BtoR(ulong b) +{ + + b &= 0x0000ffL; + if(b == 0) + return NREG; + return bitno(b) - 0; +} + +ulong +AtoB(int a) +{ + + if(a < 0 || a >= NREG) + return 0; + return 1L << (a + NREG); +} + +int +BtoA(ulong b) +{ + + b &= 0x00ff00L; + if(b == 0) + return NREG; + return bitno(b) - NREG; +} + +ulong +FtoB(int f) +{ + + if(f < 0 || f >= NREG) + return 0; + return 1L << (f + NREG+NREG); +} + +int +BtoF(ulong b) +{ + + b &= 0xff0000L; + if(b == 0) + return NREG; + return bitno(b) - NREG-NREG; +} diff --git a/utils/1c/sgen.c b/utils/1c/sgen.c new file mode 100644 index 00000000..b7da4762 --- /dev/null +++ b/utils/1c/sgen.c @@ -0,0 +1,694 @@ +#include "gc.h" + +void +codgen(Node *n, Node *nn) +{ + Prog *sp; + + argoff = 0; + inargs = 0; + for(;; nn = nn->left) { + if(nn == Z) { + diag(Z, "cant find function name"); + return; + } + if(nn->op == ONAME) + break; + } + nearln = nn->lineno; + gpseudo(ATEXT, nn->sym, D_CONST, stkoff); + sp = p; + + retok = 0; + gen(n); + if(!retok) + if(thisfn->link->etype != TVOID) + warn(Z, "no return at end of function: %s", nn->sym->name); + + noretval(3); + gbranch(ORETURN); + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); +} + +void +gen(Node *n) +{ + Node *l; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int g, 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); + doinc(n, PRE); + cgen(n, D_NONE, n); + doinc(n, POST); + 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); + gbranch(ORETURN); + break; + } + doinc(l, PRE); + if(typesuv[n->type->etype]) { + sugen(l, D_TREE, nodret, n->type->width); + doinc(l, POST); + noretval(3); + gbranch(ORETURN); + break; + } + g = regalloc(n->type, regret(n->type)); + cgen(l, g, n); + doinc(l, POST); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + regfree(g); + 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; + } + 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; + setsp();; + 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; + setsp(); + goto rloop; + } + diag(n, "case expression must be integer constant"); + goto rloop; + + case OSWITCH: + l = n->left; + complex(l); + doinc(l, PRE); + if(l->type == T) + break; + if(!typechl[l->type->etype]) { + diag(n, "switch expression must be integer"); + break; + } + g = regalloc(types[TLONG], D_NONE); + n->type = types[TLONG]; + cgen(l, g, n); + regfree(g); + doinc(l, POST); + setsp(); + 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); + doswit(g, l); + + patch(spb, pc); + cases = cn; + breakpc = sbc; + setsp(); + 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); /* 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); + 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; + bcomplex(l); + 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 */ + gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z); + p->as = ANOP; + break; + case ONAME: + if(o == OSET) + gopcode(OTST, types[TINT], D_NONE, Z, D_TREE, n); + else + gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z); + p->as = ANOP; + break; + } +} + +void +noretval(int n) +{ + + if(n & 1) { + gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TLONG]), Z); + p->as = ANOP; + } + if(n & 2) { + gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TDOUBLE]), Z); + p->as = ANOP; + } +} + +/* + * calculate addressability as follows + * REGISTER ==> 12 register + * NAME ==> 11 name+value(SB/SP) + * note that 10 is no longer generated + * CONST ==> 20 $value + * *(20) ==> 21 value + * &(10) ==> 12 $name+value(SB) + * &(11) ==> 1 $name+value(SP) + * (12) + (20) ==> 12 fold constants + * (1) + (20) ==> 1 fold constants + * *(12) ==> 10 back to name + * *(1) ==> 11 back to name + * + * (2,10,11) + (20) ==> 2 indirect w offset + * (2) ==> &13 + * *(10,11) ==> 13 indirect, no index + * + * (20) * (X) ==> 7 multiplier in indexing + * (X,7) + (12,1) ==> 8 adder in indexing (addresses) + * (X,7) + (10,11,2) ==> 8 adder in indexing (names) + * (8) ==> &9 index, almost addressable + * + * (X)++ ==> X fake addressability + * + * 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 = 11; /* difference to make relocatable */ + break; + + case OREGISTER: + n->addable = 12; + break; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 12; + else + if(l->addable == 11) + n->addable = 1; + break; + + case OADD: + xcom(l); + xcom(r); + if(n->type->etype != TIND) + break; + + if(l->addable == 20) + switch(r->addable) { + case 12: + case 1: + n->addable = r->addable; + goto brk; + } + if(r->addable == 20) + switch(l->addable) { + case 12: + case 1: + n->addable = l->addable; + goto brk; + } + 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 12: + n->addable = 10; + break; + } + break; + + case OASHL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vconst(r); + if(g >= 0 && g < 4) + n->addable = 7; + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + n->op = OASHL; + r->vconst = g; + if(g < 4) + n->addable = 7; + break; + } + g = vlog(l); + if(g >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + n->op = OASHL; + r->vconst = g; + if(g < 4) + n->addable = 7; + break; + } + break; + + case ODIV: + case OLDIV: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + if(n->op == ODIV) + n->op = OASHR; + else + n->op = OLSHR; + r->vconst = g; + } + break; + + case OSUB: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + if(vconst(l) == 0) { + n->op = ONEG; + n->left = r; + n->right = Z; + } + break; + + case OXOR: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + if(vconst(l) == -1) { + n->op = OCOM; + n->left = r; + n->right = Z; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + n->op = OASASHL; + r->vconst = g; + } + goto aseae; + + case OASDIV: + case OASLDIV: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + if(n->op == OASDIV) + n->op = OASASHR; + else + n->op = OASLSHR; + r->vconst = g; + } + goto aseae; + + case OASLMOD: + case OASMOD: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + + aseae: /* hack that there are no byte/short mul/div operators */ + if(n->type->etype == TCHAR || n->type->etype == TSHORT) { + n->right = new1(OCAST, n->right, Z); + n->right->type = types[TLONG]; + n->type = types[TLONG]; + } + if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) { + n->right = new1(OCAST, n->right, Z); + n->right->type = types[TULONG]; + n->type = types[TULONG]; + } + goto asop; + + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + case OAS: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + + asop: + if(l->addable > INDEXED && + l->complex < FNX && + r && r->complex < FNX) + n->addable = l->addable; + break; + + case OPOSTINC: + case OPREINC: + case OPOSTDEC: + case OPREDEC: + xcom(l); + if(typev[n->type->etype]) + break; + if(l->addable > INDEXED && + l->complex < FNX) + n->addable = l->addable; + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + +brk: + n->complex = 0; + 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 OADD: + case OMUL: + case OLMUL: + case OXOR: + case OAND: + case OOR: + /* + * symmetric operators, make right side simple + * if same, put constant on left to get movq + */ + if(r->complex > l->complex || + (r->complex == l->complex && r->addable == 20)) { + n->left = r; + n->right = l; + } + break; + + case OLE: + case OLT: + case OGE: + case OGT: + case OEQ: + case ONE: + /* + * relational operators, make right side simple + * if same, put constant on left to get movq + */ + if(r->complex > l->complex || r->addable == 20) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + } +} + +void +bcomplex(Node *n) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type != T) { + bool64(n); + doinc(n, PRE); + boolgen(n, 1, D_NONE, Z, n); + } else + gbranch(OGOTO); +} + +Node* +nodconst(long v) +{ + + return (Node*)v; +} diff --git a/utils/1c/swt.c b/utils/1c/swt.c new file mode 100644 index 00000000..dc735a29 --- /dev/null +++ b/utils/1c/swt.c @@ -0,0 +1,964 @@ +#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(int g, 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(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, g, n); +} + +#define N1 4 /* ncase: always linear */ + /* else binary */ +void +swit1(C1 *q, int nc, long def, int g, Node *n) +{ + C1 *r; + int i; + long v; + Prog *sp1, *sp2; + + /* note that g and g+1 are not allocated */ + if(nc <= N1) + goto linear; + + /* + * divide and conquer + */ + i = nc / 2; + r = q+i; + v = r->val; + /* compare median */ + if(v >= -128 && v < 128) { + gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); + gopcode(OEQ, n->type, g, n, g+1, n); + } else + gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); + gbranch(OLT); + sp1 = p; + gbranch(OGT); + sp2 = p; + gbranch(OGOTO); + patch(p, r->label); + + patch(sp1, pc); + swit1(q, i, def, g, n); + + patch(sp2, pc); + swit1(r+1, nc-i-1, def, g, n); + return; + +linear: + for(i=0; i<nc; i++) { + v = q->val; + if(v >= -128 && v < 128) { + gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); + gopcode(OEQ, n->type, g+1, n, g, n); + } else + gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); + gbranch(OEQ); + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); +} + +void +cas(void) +{ + Case *c; + + c = alloc(sizeof(*c)); + c->link = cases; + cases = c; +} + + +int +bitload(Node *b, int n1, int n2, int n3, Node *nn) +{ + int sh, g, gs; + long v; + Node *l; + Type *t; + + /* + * n1 gets adjusted/masked value + * n2 gets address of cell + * n3 gets contents of cell + */ + gs = 0; + t = tfield; + + l = b->left; + g = regalloc(t, n3); + if(n2 != D_NONE) { + lcgen(l, n2, Z); + n2 |= I_INDIR; + gmove(t, t, n2, l, g, l); + gmove(t, t, g, l, n1, l); + } else + cgen(l, g, nn); + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, t, D_CONST, nodconst(v), g, l); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + if(sh >= 8) { + gs = regalloc(t, D_NONE); + gmove(t, t, D_CONST, nodconst(sh), gs, l); + gopcode(OASHL, t, gs, l, g, l); + if(b->type->shift) + regfree(gs); + } else + gopcode(OASHL, t, D_CONST, nodconst(sh), g, l); + sh += b->type->shift; + if(sh > 0) { + if(sh >= 8) { + if(b->type->shift) { + gs = regalloc(t, D_NONE); + gmove(t, t, D_CONST, nodconst(sh), gs, l); + } + if(typeu[b->type->etype]) + gopcode(OLSHR, t, gs, l, g, l); + else + gopcode(OASHR, t, gs, l, g, l); + regfree(gs); + } else { + if(typeu[b->type->etype]) + gopcode(OLSHR, t, D_CONST, nodconst(sh), g, l); + else + gopcode(OASHR, t, D_CONST, nodconst(sh), g, l); + } + } + } + return g; +} + +void +bitstore(Node *b, int n1, int n2, int n3, int result, Node *nn) +{ + long v; + Node *l; + Type *t; + int sh, g, gs; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + t = tfield; + + l = b->left; + g = regalloc(t, D_NONE); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, t, D_CONST, nodconst(v), n1, l); + gmove(t, t, n1, l, g, l); + if(result != D_NONE) + gmove(t, nn->type, n1, l, result, nn); + sh = b->type->shift; + if(sh > 0) { + if(sh >= 8) { + gs = regalloc(t, D_NONE); + gmove(t, t, D_CONST, nodconst(sh), gs, l); + gopcode(OASHL, t, gs, l, g, l); + regfree(gs); + } else + gopcode(OASHL, t, D_CONST, nodconst(sh), g, l); + } + v <<= sh; + gopcode(OAND, t, D_CONST, nodconst(~v), n3, l); + gopcode(OOR, t, n3, l, g, l); + gmove(t, t, g, l, n2|I_INDIR, l); + + regfree(g); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, D_SCONST, 0L); + memmove(p->to.sval, string, NSNAME); + p->from.offset = nstring - NSNAME; + p->from.displace = NSNAME; + mnstring = 0; + } + n--; + } + return r; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + 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; +} + +int +doinc(Node *n, int f) +{ + Node *l; + int a; + +loop: + if(n == Z) + return 0; + l = n->left; + switch(n->op) { + + case OPOSTINC: + case OPOSTDEC: + if(f & POST) { + a = n->addable; + if(a >= INDEXED) { + if(f & TEST) + return 1; + n->addable = 0; + cgen(n, D_NONE, n); + n->addable = a; + } + } + break; + + case OAS: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + + case OPREINC: + case OPREDEC: + if(f & PRE) { + a = n->addable; + if(a >= INDEXED) { + if(f & TEST) + return 1; + n->addable = 0; + doinc(n, PRE); + cgen(n, D_NONE, n); + n->addable = a; + return 0; + } + } + break; + + case OFUNC: + if(f & PRE) + break; + return 0; + + case ONAME: + case OREGISTER: + case OSTRING: + case OCONST: + + case OANDAND: + case OOROR: + return 0; + + case OCOND: + return 0; + + case OCOMMA: + n = n->right; + if(f & PRE) + n = l; + goto loop; + } + if(l != Z) + if(doinc(l, f)) + return 1; + n = n->right; + goto loop; +} + +void +setsp(void) +{ + + nextpc(); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = 0; +} + +void +adjsp(long o) +{ + + if(o != 0) { + nextpc(); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = o; + argoff += o; + } +} + +int +simplv(Node *n) +{ + + if(n->addable <= INDEXED) + return 0; + while(n->op == OIND) + n = n->left; + if(n->op == ONAME) + return 1; + return 0; +} + +int +eval(Node *n, int g) +{ + + if(n->addable >= INDEXED) + return D_TREE; + g = regalloc(n->type, g); + cgen(n, g, n); + return g; +} + +void outhist(Biobuf*); +void zname(Biobuf*, Sym*, int); +void zaddr(Biobuf*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); + +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, "cant open %s", outfile); + errorexit(); + } + 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 & D_MASK; + 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 & D_MASK; + 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; + } + zwrite(&b, p, sf, st); + } + Bflush(&b); + close(f); + firstp = P; + lastp = P; +} + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + long l; + + l = p->as; + Bputc(b, l); + Bputc(b, l>>8); + l = p->lineno; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + zaddr(b, &p->from, sf); + zaddr(b, &p->to, st); +} + +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->field) + t |= T_FIELD; + if(s) + t |= T_SYM; + + switch(a->type) { + default: + if(a->offset) + t |= T_OFFSET; + if(a->displace) + t |= T_INDEX; + if(a->type & ~0xff) + t |= T_TYPE; + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + Bputc(b, t); + + if(t & T_FIELD) { /* implies field */ + i = a->field; + Bputc(b, i); + Bputc(b, i>>8); + } + if(t & T_INDEX) { /* implies index, scale, displace */ + i = D_NONE; + Bputc(b, i); + Bputc(b, i>>8); + Bputc(b, 0); + l = a->displace; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + } + 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; + } + i = a->type; + Bputc(b, i); + if(t & T_TYPE) + Bputc(b, i>>8); +} + + + +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; + + zwrite(b, &pg, 0, 0); + } +} + +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); +} + +int +nodalloc(Type *t, int g, Node *n) +{ + + n->type = t; + n->op = OREGISTER; + n->addable = 12; + n->complex = 0; + g = regaddr(g); + n->reg = g | I_INDIR; + n->xoffset = 0; + return g; +} + +int +mulcon(Node *n, Node *c, int result, Node *nn) +{ + long v; + + if(typefd[n->type->etype]) + return 0; + v = c->vconst; + if(mulcon1(n, v, result, nn)) + return 1; + return 0; +} + +int +shlcon(Node *n, Node *c, int result, Node *nn) +{ + long v; + + v = 1L << c->vconst; + return mulcon1(n, v, result, nn); +} + +int +mulcon1(Node *n, long v, int result, Node *nn) +{ + int g, g1, a1, a2, neg; + int o; + char code[10], *p; + + if(result == D_NONE) + return 0; + neg = 0; + if(v < 0) { + v = -v; + neg++; + } + a1 = 0; + a2 = multabsize; + for(;;) { + if(a1 >= a2) + return 0; + g1 = (a2 + a1)/2; + if(v < multab[g1].val) { + a2 = g1; + continue; + } + if(v > multab[g1].val) { + a1 = g1+1; + continue; + } + break; + } + strcpy(code, "0"); + strncat(code, multab[g1].code, sizeof(multab[0].code)); + p = code; + if(p[1] == 'i') + p += 2; + g = regalloc(n->type, result); + cgen(n, g, n); + if(neg) + gopcode(ONEG, n->type, D_NONE, n, g, n); + g1 = regalloc(n->type, D_NONE); +loop: + switch(*p) { + case 0: + regfree(g1); + gmove(n->type, nn->type, g, n, result, nn); + regfree(g); + return 1; + case '0': + o = OAS; + *p -= '0'; + goto com; + case '1': + case '2': + o = OSUB; + *p -= '1'; + goto com; + case '3': + case '4': + case '5': + case '6': + o = OADD; + *p -= '3'; + com: + a1 = g; + if(*p == 1 || *p == 3) + a1 = g1; + a2 = g; + if(*p == 0 || *p == 3) + a2 = g1; + gopcode(o, n->type, a1, n, a2, n); + p++; + break; + default: + a1 = *p++ - 'a' + 1; + a2 = g; + if(a1 > 8) { + a2 = g1; + a1 -= 8; + } + gopcode(OASHL, n->type, D_CONST, nodconst(a1), a2, n); + break; + } + goto loop; +} + +void +nullwarn(Node *l, Node *r) +{ + warn(Z, "result of operation not used"); + if(l != Z) + cgen(l, D_NONE, Z); + if(r != Z) + cgen(r, D_NONE, 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, D_SCONST, 0L); + p->from.offset += o+e; + p->from.displace = lw; + 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, D_CONST, (long)(a->vconst>>32)); + p->from.offset += o; + p->from.displace = 4; + gpseudo(ADATA, s, D_CONST, (long)(a->vconst)); + p->from.offset += o + 4; + p->from.displace = 4; + return; + } + gpseudotree(ADATA, s, a); + p->from.offset += o; + p->from.displace = w; +} + +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_SHORT) + w = SZ_SHORT; + 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; + } + o += SZ_LONG - w; /* big endian adjustment */ + w = 1; + 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; +} diff --git a/utils/1c/txt.c b/utils/1c/txt.c new file mode 100644 index 00000000..e439c40c --- /dev/null +++ b/utils/1c/txt.c @@ -0,0 +1,903 @@ +#include "gc.h" + +void +tindex(Type *tf, Type *tt) +{ + int i, j; + + j = 0; + if(tt != T) { + j = tt->etype; + if(j >= NTYPE) + j = 0; + } + i = 0; + if(tf != T) { + i = tf->etype; + if(i >= NTYPE) + if(typesu[i]) + i = j; + else + i = 0; + } + txtp = &txt[i][j]; +} + +void +ginit(void) +{ + int i, j, si, sj; + + thestring = "68000"; + thechar = '1'; + exregoffset = 7; + exaregoffset = 5; + exfregoffset = 7; + listinit(); + for(i=0; i<NREG; i++) { + regused[i] = 0; + fregused[i] = 0; + aregused[i] = 0; + } + regaddr(D_A0+6); + regaddr(D_A0+7); + for(i=0; i<sizeof(regbase); i++) + regbase[i] = D_NONE; + for(i=0; i<NREG; i++) { + regbase[D_R0+i] = D_R0+i; + regbase[D_A0+i] = D_A0+i; + regbase[D_F0+i] = D_F0+i; + } + regbase[D_TOS] = D_TOS; + + for(i=0; i<NTYPE; i++) + for(j=0; j<NTYPE; j++) { + txtp = &txt[i][j]; + txtp->movas = AGOK; + txtp->preclr = 0; + txtp->postext = AGOK; + if(!(typechlp[i] && typechlp[j])) + continue; + si = types[i]->width; + sj = types[j]->width; + if(sj < si) + txtp->preclr = -1; + if(sj > si) { + if(typeu[i]) { + txtp->preclr = 1; + } else { + if(sj == 2) + txtp->postext = AEXTBW; + else + if(sj == 4) + if(si == 1) + txtp->postext = AEXTBL; + else + txtp->postext = AEXTWL; + } + sj = si; + } + if(sj == 1) + txtp->movas = AMOVB; + if(sj == 2) + txtp->movas = AMOVW; + if(sj == 4) + txtp->movas = AMOVL; + } + + for(i=0; i<ALLOP; i++) + for(j=0; j<NTYPE; j++) + opxt[i][j] = AGOK; + oinit(OFUNC, ABSR, ATRAP, AGOK, AGOK, AGOK); + + oinit(OAS, AMOVB, AMOVW, AMOVL, AFMOVEF, AFMOVED); + oinit(OFAS, AFMOVEB, AFMOVEW, AFMOVEL, AFMOVEF, AFMOVED); + oinit(OADDR, AGOK, APEA, ALEA, AGOK, AGOK); + oinit(OPREINC, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OPOSTINC, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OPREDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OPOSTDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OADD, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OASADD, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OASSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(OLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(OASMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(OASLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(ODIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD); + oinit(OLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD); + oinit(OASDIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD); + oinit(OASLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD); + oinit(OMOD, AGOK, ADIVSW, ADIVSL, AFMODF, AFMODD); + oinit(OASMOD, AGOK, ADIVSW, ADIVSL, AGOK, AGOK); + oinit(OLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK); + oinit(OASLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK); + oinit(OAND, AANDB, AANDW, AANDL, AGOK, AGOK); + oinit(OASAND, AANDB, AANDW, AANDL, AGOK, AGOK); + oinit(OOR, AORB, AORW, AORL, AGOK, AGOK); + oinit(OASOR, AORB, AORW, AORL, AGOK, AGOK); + oinit(OXOR, AEORB, AEORW, AEORL, AGOK, AGOK); + oinit(OASXOR, AEORB, AEORW, AEORL, AGOK, AGOK); + oinit(ONEG, ANEGB, ANEGW, ANEGL, AFNEGF, AFNEGD); + oinit(OCOM, ANOTB, ANOTW, ANOTL, AGOK, AGOK); + oinit(OTST, ATSTB, ATSTW, ATSTL, AFTSTF, AFTSTD); + oinit(OEQ, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(ONE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OGE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OGT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLO, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OHS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OHI, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OASHR, AASRB, AASRW, AASRL, AGOK, AGOK); + oinit(OASASHR, AASRB, AASRW, AASRL, AGOK, AGOK); + oinit(OLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK); + oinit(OASLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK); + oinit(OASHL, AASLB, AASLW, AASLL, AGOK, AGOK); + oinit(OASASHL, AASLB, AASLW, AASLL, AGOK, AGOK); + oinit(OBIT, ABFEXTU, AGOK, AGOK, AGOK, AGOK); + + nstring = 0; + mnstring = 0; + nrathole = 0; + nstatic = 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.to = zprog.from; + + nodret = new(ONAME, Z, Z); + nodret->sym = slookup(".ret"); + nodret->type = types[TIND]; + nodret->etype = types[TIND]->etype; + nodret->class = CPARAM; + nodret = new(OIND, nodret, Z); + complex(nodret); + + symrathole = slookup(".rathole"); + symrathole->class = CGLOBL; + symrathole->type = typ(TARRAY, types[TCHAR]); + nodrat = new(ONAME, Z, Z); + nodrat->sym = symrathole; + nodrat->type = types[TIND]; + nodrat->etype = TVOID; + nodrat->class = CGLOBL; + complex(nodrat); + nodrat->type = symrathole->type; + + com64init(); + + symstatic = slookup(".static"); + symstatic->class = CSTATIC; + symstatic->type = typ(TARRAY, types[TLONG]); +} + +void +gclean(void) +{ + int i; + Sym *s; + + regfree(D_A0+6); + regfree(D_A0+7); + for(i=0; i<NREG; i++) { + if(regused[i]) + diag(Z, "missing R%d", i); + if(aregused[i]) + diag(Z, "missing A%d", i); + if(fregused[i]) + diag(Z, "missing F%d", i); + } + + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symstatic->type->width = nstatic; + 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, D_CONST, s->type->width); + pc--; + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +oinit(int o, int ab, int aw, int al, int af, int ad) +{ + int i; + + i = o; + if(i >= ALLOP) { + diag(Z, "op(%d) >= ALLOP(%d)", i, ALLOP); + errorexit(); + } + opxt[i][TCHAR] = ab; + opxt[i][TUCHAR] = ab; + opxt[i][TSHORT] = aw; + opxt[i][TUSHORT] = aw; + opxt[i][TINT] = al; + opxt[i][TUINT] = al; + opxt[i][TLONG] = al; + opxt[i][TULONG] = al; + opxt[i][TIND] = al; + opxt[i][TFLOAT] = af; + opxt[i][TDOUBLE] = ad; +} + +Prog* +prg(void) +{ + Prog *p; + + p = alloc(sizeof(*p)); + *p = zprog; + return p; +} + +void +nextpc(void) +{ + + p = prg(); + pc++; + p->lineno = nearln; + if(firstp == P) { + firstp = p; + lastp = p; + return; + } + lastp->link = p; + lastp = p; +} + +void +gargs(Node *n) +{ + long s; + +loop: + if(n == Z) + return; + if(n->op == OLIST) { + gargs(n->right); + n = n->left; + goto loop; + } + s = argoff; + cgen(n, D_TOS, n); + argoff = s + n->type->width; +} + +void +naddr(Node *n, Adr *a, int x) +{ + Node *l; + long v; + + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OADDR: + case OIND: + naddr(n->left, a, x); + goto noadd; + + case OREGISTER: + a->sym = S; + a->type = n->reg; + a->offset = n->xoffset; + a->displace = 0; + break; + + case ONAME: + a->etype = n->etype; + a->displace = 0; + a->sym = n->sym; + a->offset = n->xoffset; + a->type = D_STATIC; + 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: + a->displace = 0; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + break; + } + a->type = D_CONST; + a->offset = n->vconst; + break; + + case OADD: + l = n->left; + if(l->addable == 20) { + v = l->vconst; + naddr(n->right, a, x); + goto add; + } + l = n->right; + if(l->addable == 20) { + v = l->vconst; + naddr(n->left, a, x); + goto add; + } + goto bad; + + noadd: + v = 0; + add: + switch(n->addable) { + default: + goto bad; + case 2: + a->displace += v; + break; + case 21: + a->type &= D_MASK; + a->type |= I_INDIR; + break; + case 1: + case 12: + a->offset += v; + a->type &= D_MASK; + a->type |= I_ADDR; + break; + case 10: + case 11: + case 20: + a->type &= D_MASK; + a->type |= I_DIR; + break; + } + break; + + case OPREINC: + case OPREDEC: + case OPOSTINC: + case OPOSTDEC: + + case OAS: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + naddr(n->left, a, x); + break; + } +} + +int +regalloc(Type *t, int g) +{ + + if(t == T) + return D_NONE; + g &= D_MASK; + if(typefd[t->etype]) { + if(g >= D_F0 && g < D_F0+NREG) { + fregused[g-D_F0]++; + return g; + } + for(g=0; g<NREG; g++) + if(fregused[g] == 0) { + fregused[g]++; + return g + D_F0; + } + } else { + if(g >= D_R0 && g < D_R0+NREG) { + regused[g-D_R0]++; + return g; + } + for(g=0; g<NREG; g++) + if(regused[g] == 0) { + regused[g]++; + return g + D_R0; + } + } + diag(Z, "out of registers"); + return D_TOS; +} + +int +regaddr(int g) +{ + + if(g >= D_A0 && g < D_A0+NREG) { + aregused[g-D_A0]++; + return g; + } + for(g=0; g<NREG; g++) + if(aregused[g] == 0) { + aregused[g]++; + return g + D_A0; + } + diag(Z, "out of addr registers"); + return D_TOS; +} + +int +regpair(int g) +{ + + if(g >= D_R0+1 && g < D_R0+NREG) + if(!regused[g-D_R0-1]) { + regused[g-D_R0-1]++; + regused[g-D_R0]++; + return g-1; + } + if(g >= D_R0 && g < D_R0+NREG-1) + if(!regused[g-D_R0+1]) { + regused[g-D_R0+1]++; + regused[g-D_R0]++; + return g; + } + for(g = 0; g < NREG-1; g++) + if(!regused[g]) + if(!regused[g+1]) { + regused[g]++; + regused[g+1]++; + return g + D_R0; + } + diag(Z, "out of register pairs"); + return D_TOS; +} + +int +regret(Type *t) +{ + + if(t == T) + return D_NONE; + if(typefd[t->etype]) + return D_F0; + return D_R0; +} + +void +regfree(int g) +{ + + g &= D_MASK; + if(g == D_TOS || g == D_TREE || g == D_NONE) + return; + if(g >= D_R0 && g < D_R0+NREG) { + regused[g-D_R0]--; + return; + } + if(g >= D_A0 && g < D_A0+NREG) { + aregused[g-D_A0]--; + return; + } + if(g >= D_F0 && g < D_F0+NREG) { + fregused[g-D_F0]--; + return; + } + diag(Z, "bad in regfree: %d", g); +} + +void +gmove(Type *tf, Type *tt, int gf, Node *f, int gt, Node *t) +{ + int g, a, b; + Prog *p1; + + tindex(tf, tt); + if(txtp->preclr) { + if(gf >= D_R0 && gf < D_R0+NREG) + if(txtp->preclr < 0) { + gmove(tt, tt, gf, f, gt, t); + return; + } + g = regalloc(types[TLONG], gt); + if(g == gf) { + g = regalloc(types[TLONG], D_NONE); + regfree(gf); + } + if(txtp->preclr > 0) + gopcode(OAS, types[TLONG], D_CONST, nodconst(0), g, Z); + gopcode(OAS, tf, gf, f, g, Z); + if(g != gt) + gopcode(OAS, tt, g, Z, gt, t); + regfree(g); + return; + } + a = txtp->postext; + if(a != AGOK) { + if(gf >= D_R0 && gf < D_R0+NREG) + g = regalloc(types[TLONG], gf); + else + g = regalloc(types[TLONG], gt); + if(g != gf) + gopcode(OAS, tf, gf, f, g, Z); + nextpc(); + p->as = a; + p->to.type = g; + if(debug['g']) + print("%P\n", p); + if(g != gt) + gopcode(OAS, tt, g, Z, gt, t); + regfree(g); + return; + } + if((regbase[gf] != D_NONE && regbase[gf] == regbase[gt]) || + (gf == D_TREE && gt == D_TREE && f == t)) + return; + if(typefd[tf->etype] || typefd[tt->etype]) { + if(typeu[tf->etype] && typefd[tt->etype]) { /* unsign->float */ + a = regalloc(types[TLONG], D_NONE); + gmove(tf, types[TLONG], gf, f, a, t); + if(tf->etype == TULONG) { + b = regalloc(types[TDOUBLE], D_NONE); + gmove(types[TLONG], tt, a, t, b, t); + gopcode(OTST, types[TLONG], D_NONE, Z, a, t); + gbranch(OGE); + p1 = p; + gopcode(OASADD, types[TDOUBLE], + D_CONST, nodconst(100), b, t); + p->from.dval = 4294967296.; + patch(p1, pc); + gmove(types[TDOUBLE], tt, b, t, gt, t); + regfree(b); + } else + gmove(types[TLONG], tt, a, t, gt, t); + regfree(a); + return; + } + if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */ + a = regalloc(types[TLONG], D_NONE); + gopcode(OAS, types[TLONG], D_FPCR, t, a, t); + gopcode(OAS, types[TLONG], D_CONST, nodconst(16), D_FPCR, t); + } + if(gf < D_F0 || gf >= D_F0+NREG) { + g = regalloc(types[TDOUBLE], gt); + gopcode(OFAS, tf, gf, f, g, t); + if(g != gt) + gopcode(OFAS, tt, g, t, gt, t); + regfree(g); + } else + gopcode(OFAS, tt, gf, f, gt, t); + if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */ + gopcode(OAS, types[TLONG], a, t, D_FPCR, t); + regfree(a); + } + return; + } + gopcode(OAS, tt, gf, f, gt, t); +} + +void +gopcode(int o, Type *ty, int gf, Node *f, int gt, Node *t) +{ + int i, fidx, tidx; + + if(o == OAS) + if(gf == gt) + if(gf != D_TREE || f == t) + return; + + fidx = D_NONE; + tidx = D_NONE; + i = 0; + if(ty != T) { + i = ty->etype; + if(i >= NTYPE) + i = 0; + } + nextpc(); + if(gf == D_TREE) { + naddr(f, &p->from, fidx); + } else { + p->from.type = gf; + if(gf == D_CONST) { + p->from.offset = (long)(uintptr)f; + if(typefd[i]) { + p->from.type = D_FCONST; + p->from.dval = (long)(uintptr)f; + } + } + } + p->as = opxt[o][i]; + if(gt == D_TREE) { + naddr(t, &p->to, tidx); + } else { + p->to.type = gt; + if(gt == D_CONST) + p->to.offset = (long)(uintptr)t; + } + if(o == OBIT) { + p->from.field = f->type->nbits; + p->to.field = f->type->shift; + if(p->from.field == 0) + diag(Z, "BIT zero width bit field"); + } + if(p->as == AMOVL || p->as == AMOVW || p->as == AMOVB) + asopt(); + if(debug['g']) + print("%P\n", p); + if(p->as == AGOK) + diag(Z, "GOK in gopcode: %s", onames[o]); + if(fidx != D_NONE) + regfree(fidx); + if(tidx != D_NONE) + regfree(tidx); +} + +void +asopt(void) +{ + long v; + int g; + Prog *q; + + /* + * mov $0, ... + * ==> + * clr , ... + */ + v = 0; + if(p->from.type == D_CONST) { + v = p->from.offset; + if(v == 0) { + p->from.type = D_NONE; + if(p->as == AMOVL) + p->as = ACLRL; + if(p->as == AMOVW) + p->as = ACLRW; + if(p->as == AMOVB) + p->as = ACLRB; + return; + } + } + /* + * mov ..., TOS + * ==> + * pea (...) + */ + if(p->as == AMOVL && p->to.type == D_TOS) + switch(p->from.type) { + case D_CONST: + p->from.type |= I_INDIR; + p->to = p->from; + p->from = zprog.from; + p->as = APEA; + return; + + case I_ADDR|D_EXTERN: + case I_ADDR|D_STATIC: + p->from.type &= ~I_ADDR; + p->to = p->from; + p->from = zprog.from; + p->as = APEA; + return; + } + /* + * movL $Qx, ... + * ==> + * movL $Qx,R + * movL R, ... + */ + if(p->as == AMOVL && p->from.type == D_CONST) + if(v >= -128 && v < 128) + if(p->to.type < D_R0 || p->to.type >= D_R0+NREG) { + g = regalloc(types[TLONG], D_NONE); + q = p; + nextpc(); + p->as = AMOVL; + p->from.type = g; + p->to = q->to; + q->to = p->from; + regfree(g); + if(debug['g']) + print("%P\n", q); + return; + } +} + +void +gbranch(int o) +{ + int a; + + a = ABNE; + switch(o) { + case ORETURN: a = ARTS; break; + case OGOTO: a = ABRA; break; + case OEQ: a = ABEQ; break; + case ONE: a = ABNE; break; + case OLE: a = ABLE; break; + case OLS: a = ABLS; break; + case OLT: a = ABLT; break; + case OLO: a = ABCS; break; + case OGE: a = ABGE; break; + case OHS: a = ABCC; break; + case OGT: a = ABGT; break; + case OHI: a = ABHI; break; + case OBIT: a = ABCS; break; + case OCASE: a = ABCASE; break; + } + nextpc(); + p->from.type = D_NONE; + p->to.type = D_NONE; + p->as = a; +} + +void +fpbranch(void) +{ + int a; + + a = p->as; + switch(a) { + case ABEQ: a = AFBEQ; break; + case ABNE: a = AFBNE; break; + case ABLE: a = AFBLE; break; + case ABLT: a = AFBLT; break; + case ABGE: a = AFBGE; break; + case ABGT: a = AFBGT; break; + } + p->as = a; +} + +void +patch(Prog *op, long pc) +{ + + op->to.offset = pc; + op->to.type = D_BRANCH; +} + +void +gpseudo(int a, Sym *s, int g, long v) +{ + + nextpc(); + if(a == ADATA) + pc--; + p->as = a; + p->to.type = g; + p->to.offset = v; + p->from.sym = s; + p->from.type = D_EXTERN; + if(s->class == CSTATIC) + p->from.type = D_STATIC; +} + +void +gpseudotree(int a, Sym *s, Node *n) +{ + + nextpc(); + if(a == ADATA) + pc--; + p->as = a; + naddr(n, &p->to, D_NONE); + p->from.sym = s; + p->from.type = D_EXTERN; + if(s->class == CSTATIC) + p->from.type = D_STATIC; +} + +long +exreg(Type *t) +{ + long o; + + if(typechl[t->etype]) { + if(exregoffset <= 5) + return 0; + o = exregoffset + D_R0; + exregoffset--; + return o; + } + if(t->etype == TIND) { + if(exaregoffset <= 3) + return 0; + o = exaregoffset + D_A0; + exaregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 5) + return 0; + o = exfregoffset + D_F0; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; +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] */ +}; diff --git a/utils/1l/Nt.c b/utils/1l/Nt.c new file mode 100644 index 00000000..2efff499 --- /dev/null +++ b/utils/1l/Nt.c @@ -0,0 +1,77 @@ +#include <windows.h> +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/1l/Plan9.c b/utils/1l/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/1l/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/1l/Posix.c b/utils/1l/Posix.c new file mode 100644 index 00000000..aa5d9551 --- /dev/null +++ b/utils/1l/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fials if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} diff --git a/utils/1l/asm.c b/utils/1l/asm.c new file mode 100644 index 00000000..f8dba670 --- /dev/null +++ b/utils/1l/asm.c @@ -0,0 +1,1534 @@ +#include "l.h" + +short opa[20]; +short *op; + +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; + if(s->type != STEXT) + diag("entry not text: %s", s->name); + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long v; + int a; + short *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 %.4lux sb %.4lux in %s", p->pc, pc, TNAME); + pc = p->pc; + } + curp = p; + if(debug['a']) + Bprint(&bso, "%lux:%P\n", pc, curp); + asmins(p); + if(cbc < sizeof(opa)) + cflush(); + for(op1 = opa; op1 < op; op1++) { + a = *op1; + *cbp++ = a >> 8; + *cbp++ = a; + } + a = 2*(op - opa); + pc += a; + cbc -= a; + if(debug['a']) { + for(op1 = opa; op1 < op; op1++) + if(op1 == opa) + Bprint(&bso, "\t\t%4ux", *op1 & 0xffff); + else + Bprint(&bso, " %4ux", *op1 & 0xffff); + if(op != opa) + Bprint(&bso, "\n"); + } + } + cflush(); + switch(HEADTYPE) { + case 0: /* this is garbage */ + seek(cout, rnd(HEADR+textsize, 8192), 0); + break; + case 1: /* plan9 boot data goes into text */ + seek(cout, rnd(HEADR+textsize, INITRND), 0); + break; + case 2: /* plan 9 */ + seek(cout, HEADR+textsize, 0); + break; + case 3: /* next boot */ + seek(cout, HEADR+rnd(textsize, INITRND), 0); + break; + case 4: /* preprocess pilot */ + seek(cout, HEADR+textsize, 0); + break; + } + + if(debug['v']) + Bprint(&bso, "%5.2f datblk\n", cputime()); + Bflush(&bso); + + for(v = 0; v < datsize; v += sizeof(buf)-100) { + if(datsize-v > sizeof(buf)-100) + datblk(v, sizeof(buf)-100); + else + datblk(v, datsize-v); + } + + symsize = 0; + spsize = 0; + lcsize = 0; + relocsize = 0; + + Bflush(&bso); + + switch(HEADTYPE) { + default: + seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0); + break; + case 1: /* plan9 boot data goes into text */ + seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); + break; + case 2: /* plan 9 */ + seek(cout, HEADR+textsize+datsize, 0); + break; + case 3: /* next boot */ + seek(cout, HEADR+rnd(textsize, INITRND)+datsize, 0); + break; + case 4: /* preprocess pilot */ + seek(cout, HEADR+textsize+datsize, 0); + break; + } + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + asmsym(); + } + Bflush(&bso); + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + asmsp(); + } + Bflush(&bso); + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + asmlc(); + } + Bflush(&bso); + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f reloc\n", cputime()); + asmreloc(); + } + cflush(); + + if(debug['v']) + Bprint(&bso, "%5.2f headr\n", cputime()); + Bflush(&bso); + seek(cout, 0L, 0); + switch(HEADTYPE) { + default: + 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; + case 1: /* plan9 boot data goes into text */ + lput(0407); /* magic */ + lput(rnd(HEADR+textsize, INITRND)-HEADR+datsize); /* sizes */ + lput(0); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + case 2: /* plan 9 */ + lput(0407); /* 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: /* next boot */ + /* header */ + lput(0xfeedfaceL); /* magic */ + lput(6); /* 68040 */ + lput(1); /* more 68040 */ + lput(5); /* file type 'boot' */ + lput(HEADTYPE); /* number commands */ + lput(HEADR-7*4); /* sizeof commands */ + lput(1); /* no undefineds */ + /* command 1 text */ + lput(1); /* command = 'segment' */ + lput(124); /* command size */ + s16put("__TEXT"); + /* botch?? entryvalue() */ + lput(INITTEXT); /* va of start */ + lput(rnd(textsize, 8192)); /* va size */ + lput(HEADR); /* file offset */ + lput(rnd(textsize, 8192)); /* file size */ + lput(7); /* max prot */ + lput(7); /* init prot */ + lput(1); /* number of sections */ + lput(0); /* flags */ + /* text section */ + s16put("__text"); + s16put("__TEXT"); + /* botch?? entryvalue() */ + lput(INITTEXT); /* va of start */ + lput(textsize); /* va size */ + lput(HEADR); /* file offset */ + lput(2); /* align */ + lput(0); /* reloff */ + lput(0); /* nreloc */ + lput(0); /* flags */ + lput(0); /* reserved1 */ + lput(0); /* reserved2 */ + /* command 1 data */ + lput(1); /* command = 'segment' */ + lput(192); /* command size */ + s16put("__DATA"); + lput(INITDAT); /* va of start */ + lput(rnd(datsize, 8192)); /* va size */ + lput(HEADR+rnd(textsize, 8192)); /* file offset */ + lput(rnd(datsize, 8192)); /* file size */ + lput(7); /* max prot */ + lput(7); /* init prot */ + lput(2); /* number of sections */ + lput(0); /* flags */ + /* data section */ + s16put("__data"); + s16put("__DATA"); + lput(INITDAT); /* va of start */ + lput(datsize); /* va size */ + lput(HEADR+rnd(textsize, 8192)); /* file offset */ + lput(2); /* align */ + lput(0); /* reloff */ + lput(0); /* nreloc */ + lput(0); /* flags */ + lput(0); /* reserved1 */ + lput(0); /* reserved2 */ + /* bss section */ + s16put("__bss"); + s16put("__DATA"); + lput(INITDAT+datsize); /* va of start */ + lput(bsssize); /* va size */ + lput(0); /* file offset */ + lput(2); /* align */ + lput(0); /* reloff */ + lput(0); /* nreloc */ + lput(1); /* flags = zero fill */ + lput(0); /* reserved1 */ + lput(0); /* reserved2 */ + /* command 2 symbol */ + lput(2); /* command = 'symbol' */ + lput(24); /* command size */ + lput(HEADR+rnd(textsize, INITRND) + +datsize); /* symoff */ + lput(symsize); /* nsyms */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + case 4: /* preprocess pilot */ + lput(0407); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + lput(relocsize); /* relocation */ + break; + } + cflush(); +} + +void +asmins(Prog *p) +{ + Optab *o; + int t, a, b; + long v; + + op = opa + 1; + if(special[p->from.type]) + switch(p->from.type) { + + case D_CCR: + if(p->as != AMOVW) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x42c0 | a; /* mov from ccr */ + return; + + case D_SR: + if(p->as != AMOVW) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x40c0 | a; /* mov from sr */ + return; + + case D_USP: + if(p->as != AMOVL) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 010) { + opa[0] = 0x4e68|(a&7); /* mov usp An */ + return; + } + t = 0x800; + goto movec1; + + case D_SFC: + t = 0x000; + goto movec1; + + case D_DFC: + t = 0x001; + goto movec1; + + case D_CACR: + t = 0x002; + goto movec1; + + case D_TC: + t = 0x003; + goto movec1; + + case D_ITT0: + t = 0x004; + goto movec1; + + case D_ITT1: + t = 0x005; + goto movec1; + + case D_DTT0: + t = 0x006; + goto movec1; + + case D_DTT1: + t = 0x007; + goto movec1; + + case D_VBR: + t = 0x801; + goto movec1; + + case D_CAAR: + t = 0x802; + goto movec1; + + case D_MSP: + t = 0x803; + goto movec1; + + case D_ISP: + t = 0x804; + goto movec1; + + case D_MMUSR: + t = 0x805; + goto movec1; + + case D_URP: + t = 0x806; + goto movec1; + + case D_SRP: + t = 0x807; + goto movec1; + + movec1: + if(p->as != AMOVL) + goto bad; + opa[0] = 0x4e7a; /* mov spc Dn */ + a = asmea(p, &p->to); + b = a & 0170; + if(b == 0 || b == 010) { + *op++ = (a<<12) | t; + return; + } + goto bad; + + case D_FPCR: + t = 0xb000; + goto movec3; + + case D_FPSR: + t = 0xa800; + goto movec3; + + case D_FPIAR: + t = 0xa400; + + movec3: + if(p->as != AMOVL) + goto bad; + op++; + a = asmea(p, &p->to); + opa[0] = optab[AFMOVEL].opcode0 | a; + opa[1] = t; + return; + } + if(special[p->to.type]) + switch(p->to.type) { + + case D_CCR: + if(p->as != AMOVW) /* botch, needs and, eor etc. */ + goto bad; + a = asmea(p, &p->from); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x44c0 | a; /* mov to ccr */ + return; + + case D_SR: + if(p->as != AMOVW) /* botch, needs and, eor etc. */ + goto bad; + a = asmea(p, &p->from); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x46c0 | a; /* mov to sr */ + return; + + case D_USP: + if(p->as != AMOVL) + goto bad; + a = asmea(p, &p->from); + if((a & 0170) == 010) { + opa[0] = 0x4e60|(a&7); /* mov An usp */ + return; + } + t = 0x800; + goto movec2; + + case D_SFC: + t = 0x000; + goto movec2; + + case D_DFC: + t = 0x001; + goto movec2; + + case D_CACR: + t = 0x002; + goto movec2; + + case D_TC: + t = 0x003; + goto movec2; + + case D_ITT0: + t = 0x004; + goto movec2; + + case D_ITT1: + t = 0x005; + goto movec2; + + case D_DTT0: + t = 0x006; + goto movec2; + + case D_DTT1: + t = 0x007; + goto movec2; + + case D_VBR: + t = 0x801; + goto movec2; + + case D_CAAR: + t = 0x802; + goto movec2; + + case D_MSP: + t = 0x803; + goto movec2; + + case D_ISP: + t = 0x804; + goto movec2; + + case D_MMUSR: + t = 0x805; + goto movec2; + + case D_URP: + t = 0x806; + goto movec2; + + case D_SRP: + t = 0x807; + goto movec2; + + movec2: + if(p->as != AMOVL) + goto bad; + opa[0] = 0x4e7b; /* mov Dn spc */ + a = asmea(p, &p->from); + b = a & 0170; + if(b == 0 || b == 010) { + *op++ = (a<<12) | t; + return; + } + goto bad; + + case D_FPCR: + t = 0x9000; + goto movec4; + + case D_FPSR: + t = 0x8800; + goto movec4; + + case D_FPIAR: + t = 0x8400; + + movec4: + if(p->as != AMOVL) + goto bad; + op++; + a = asmea(p, &p->from); + opa[0] = optab[AFMOVEL].opcode0 | a; + opa[1] = t; + return; + } + + o = &optab[p->as]; + t = o->opcode0; + switch(o->optype) { + case 0: /* pseudo ops */ + if(p->as != ATEXT && p->as != ANOP) { + if(!debug['a']) + print("%P\n", p); + diag("unimplemented instruction in %s", TNAME); + return; + } + op = opa; + return; + + case 1: /* branches */ + if(p->to.type != D_BRANCH) + goto bad; + a = asmea(p, &p->to); + if(a == 071) + t = o->opcode1; + t |= a; + break; + + case 2: /* move */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 0110) { /* src quick */ + t = o->opcode1; + if((b & 0170) != 0) + goto bad; + t |= a >> 7; + t |= b << 9; + break; + } + t |= a; + t |= (b&7) << 9; + t |= (b&070) << 3; + break; + + case 3: /* add */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 0110) { /* src quick */ + t = o->opcode1; + t |= (a&01600) << 2; + t |= b; + break; + } + if((b & 0170) == 0) { /* dst Dn */ + t |= a; + t |= (b & 7) << 9; + break; + } + if((b & 0170) == 010) { /* dst An */ + if((t & 0xc0) == 0) + goto bad; + t = o->opcode2; + t |= a; + t |= (b & 7) << 9; + break; + } + if((a & 0170) == 0) { /* src Dn */ + t |= 0x100; + t |= (a & 7) << 9; + t |= b; + break; + } + if((a & 0177) == 074) { /* src immed */ + t = o->opcode3; + t |= b; + break; + } + goto bad; + + case 4: /* no operands */ + break; + + case 5: /* tst */ + t |= asmea(p, &p->to); + if((t&0170) == 010) + goto bad; + break; + + case 6: /* lea */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) != 010) + goto bad; + t |= a; + t |= (b & 7) << 9; + break; + + case 7: /* cmp */ + b = asmea(p, &p->to); + a = asmea(p, &p->from); + if((a & 0170) == 010) { /* dst An */ + t = o->opcode1; + if(t == 0) /* cmpb illegal */ + goto bad; + t |= 0xc0; + t |= b; + t |= (a & 7) << 9; + break; + } + if((b & 0177) == 074) { /* src immed */ + t = o->opcode2; + t |= a; + break; + } + if((a & 0170) == 0) { /* dst Dn */ + t |= b; + t |= (a&7) << 9; + break; + } + if((b&0170) == 030 && (a&0170) == 030) { /* (A)+,(A)+ */ + t = o->opcode3; + t |= b & 7; + t |= (a & 7) << 9; + break; + } + goto bad; + + case 8: /* svc */ + *op++ = optab[ARTS].opcode0; + break; + + case 9: /* and */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + if((b & 0170) == 0) { /* dst Dn */ + t |= a; + t |= (b&7) << 9; + break; + } + if((a & 0170) == 0) { /* src Dn */ + t = o->opcode1; + t |= b; + t |= (a&7) << 9; + break; + } + if((a & 0177) == 074) { /* src immed */ + t = o->opcode2; + t |= b; + break; + } + goto bad; + + case 10: /* eor */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + if((a & 0170) == 0) { /* src Dn */ + t |= b; + t |= (a&7) << 9; + break; + } + if((a & 0177) == 074) { /* src immed */ + t = o->opcode1; + t |= b; + break; + } + goto bad; + + case 11: /* ext */ + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + t |= b; + break; + } + goto bad; + + case 12: /* shift */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + if((a & 0177) == 0110) { /* src quick */ + t |= (a & 01600) << 2; + t |= b; + break; + } + if((a & 0170) == 0) { /* src Dn */ + t |= 0x20; + t |= a << 9; + t |= b; + break; + } + goto bad; + } + goto bad; + + case 13: /* mul, div short */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + if((a & 0170) == 010) + goto bad; + t |= a; + t |= b << 9; + break; + } + goto bad; + + case 14: /* mul, div long */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + if((a & 0170) == 010) + goto bad; + t |= a; + opa[1] |= b << 12; + opa[1] |= b+1; + break; + } + goto bad; + + case 15: /* dec and branch */ + if(p->to.type != D_BRANCH) + goto bad; + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) + goto bad; + *op++ = v; + a = asmea(p, &p->from); + if((a & 0170) != 0) + goto bad; + t |= a; + break; + + case 16: /* fmove */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 0100) { /* src Fn */ + if((b & 0170) == 0100) { /* both Fn */ + opa[1] |= (a&7) << 10; + opa[1] |= (b&7) << 7; + break; + } + t |= b; + opa[1] = o->opcode2; + opa[1] |= (a&7) << 7; + break; + } + if((b & 0170) != 0100) /* dst Fn */ + goto bad; + t |= a; + opa[1] = o->opcode3; + opa[1] |= (b&7) << 7; + break; + + case 17: /* floating ea,Fn */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) != 0100) /* dst Fn */ + goto bad; + if((a & 0170) == 0100) { /* both Fn */ + opa[1] |= (a&7) << 10; + opa[1] |= (b&7) << 7; + break; + } + t |= a; + opa[1] = o->opcode2; + opa[1] |= (b&7) << 7; + break; + + case 18: /* floating branchs */ + if(p->to.type != D_BRANCH) + goto bad; + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) + goto bad; + *op++ = v; + break; + + case 19: /* floating dec and branch */ + if(p->to.type != D_BRANCH) + goto bad; + *op++ = o->opcode1; + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) + goto bad; + *op++ = v; + a = asmea(p, &p->from); + if((a & 0170) != 0) + goto bad; + t |= a; + break; + + case 20: /* ftst ea */ + *op++ = o->opcode1; + if(p->from.type != D_NONE) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 0100) { /* Fn */ + opa[1] |= (a&7) << 10; + break; + } + t |= a; + opa[1] = o->opcode2; + break; + + case 21: /* fneg */ + *op++ = o->opcode1; + if(p->from.type == D_NONE) { + b = asmea(p, &p->to); + a = b; + } else { + a = asmea(p, &p->from); + b = asmea(p, &p->to); + } + if((b & 0170) != 0100) /* dst Fn */ + goto bad; + if((a & 0170) == 0100) { /* both Fn */ + opa[1] |= (a&7) << 10; + opa[1] |= (b&7) << 7; + break; + } + t |= a; + opa[1] = o->opcode2; + opa[1] |= (b&7) << 7; + break; + + case 22: /* floating cmp Fn,ea */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) != 0100) /* dst Fn */ + goto bad; + if((b & 0170) == 0100) { /* both Fn */ + opa[1] |= (b&7) << 10; + opa[1] |= (a&7) << 7; + break; + } + t |= b; + opa[1] = o->opcode2; + opa[1] |= (a&7) << 7; + break; + + case 23: /* word, long */ + op = opa; + a = asmea(p, &p->to); + if(a == ((7<<3)|4)) + return; + if(a == ((7<<3)|1)) { + if(p->as == AWORD) { + op = opa; + *op++ = opa[1]; + } + return; + } + if(a == ((7<<3)|0)) { + if(p->as == ALONG) { + *op++ = opa[0]; + opa[0] = 0; + } + return; + } + goto bad; + + case 24: /* bit field */ + a = ((p->to.field&31)<<6) | (p->from.field&31); + if(p->as == ABFINS) { + b = asmea(p, &p->from); + if((b&0170) != 0) + goto bad; + a |= b<<12; + *op++ = a; + a = asmea(p, &p->to); + } else { + if(p->to.type != D_NONE) { + b = asmea(p, &p->to); + if((b&0170) != 0) + goto bad; + a |= b<<12; + } + *op++ = a; + a = asmea(p, &p->from); + } + t |= a; + a &= 0170; + if(a == 010 || a == 030 || a == 040 || a == 074) + goto bad; + break; + + case 25: /* movem */ + if(p->from.type == D_CONST) { /* registers -> memory */ + asmea(p, &p->from); + a = asmea(p, &p->to); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 030) + goto bad; + t |= a; + break; + } + if(p->to.type == D_CONST) { /* memory -> registers */ + t |= 0x400; + asmea(p, &p->to); + a = asmea(p, &p->from); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 040) + goto bad; + t |= a; + break; + } + goto bad; + + case 26: /* chk */ + a = asmea(p, &p->from); + if((a&0170) == 010) + goto bad; + b = asmea(p, &p->to); + if((b&0170) != 0) + goto bad; + t |= a; + t |= b<<9; + break; + + case 27: /* btst */ + a = asmea(p, &p->from); + if(a == 074) { + t = o->opcode1; + } else + if((a&0170) != 0) + goto bad; + b = asmea(p, &p->to); + if(b == 074 || (b&0170) == 010) + goto bad; + t |= b; + break; + + case 28: /* fmovem */ + if(p->from.type == D_CONST) { /* registers -> memory */ + b = p->from.offset & 0xff; + b |= 0xf000; /* control or postinc */ + *op++ = b; + a = asmea(p, &p->to); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 030) + goto bad; + if(b == 040) + op[-1] &= ~0x1000; /* predec */ + t |= a; + break; + } + if(p->to.type == D_CONST) { /* memory -> registers */ + b = p->to.offset & 0xff; + b |= 0xd000; /* control or postinc */ + *op++ = b; + a = asmea(p, &p->from); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 040) + goto bad; + t |= a; + break; + } + goto bad; + + case 29: /* fmovemc */ + if(p->from.type == D_CONST) { /* registers -> memory */ + b = (p->from.offset & 0x7) << 10; + b |= 0xa000; + *op++ = b; + a = asmea(p, &p->to); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 030) + goto bad; + t |= a; + break; + } + if(p->to.type == D_CONST) { /* memory -> registers */ + b = (p->to.offset & 0x7) << 10; + b |= 0x8000; + *op++ = b; + a = asmea(p, &p->from); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 040) + goto bad; + t |= a; + break; + } + goto bad; + + case 30: /* trap */ + if(p->to.type == D_CONST) { + t |= p->to.offset & 0xf; + break; + } + goto bad; + + case 31: /* chk2, cmp2 */ + b = asmea(p, &p->to); + a = b & 0170; + if(a == 000 || a == 010) { + *op++ = o->opcode1 | (b << 12); + t |= asmea(p, &p->from); + break; + } + goto bad; + + case 32: /* casew */ + /* jmp (0,pc,r0.w*1) */ + casepc = p->pc; + *op++ = o->opcode1; + break; + + case 34: /* moves */ + op++; + a = asmea(p, &p->from); + b = a & 0170; + if(b == 0 || b == 010) { + opa[1] = (a << 12) | 0x800; + b = asmea(p, &p->to); + a = b & 0170; + if(a == 0 || a == 010) + goto bad; + t |= b; + break; + } + t |= a; + b = asmea(p, &p->to); + a = b & 0170; + if(a != 0 && a != 010) + goto bad; + opa[1] = (b << 12); + break; + + case 35: /* swap */ + a = asmea(p, &p->to); + if((a & 0170) == 0) { + t |= a; + break; + } + goto bad; + } + opa[0] = t; + return; + +bad: + if(!debug['a']) + print("%P\n", p); + diag("bad combination of addressing in %s", TNAME); + opa[0] = 0; +} + +int +asmea(Prog *p, Adr *a) +{ + Optab *o; + int f, t, r, i; + long v; + + t = a->type; + r = simple[t]; + v = a->offset; + if(r != 0177) { + if(v == 0) + return r; + if((r & 070) != 020) + return r; + if(v >= -32768L && v < 32768L) { + *op++ = v; + return t-D_A0-I_INDIR+050; /* d(Ax) */ + } + goto toobig; + } + f = 0; + if(a == &p->from) + f++; + o = &optab[p->as]; + switch(t) { + case D_TOS: + if(f) { + if(o->srcsp) + return (3<<3) | 7; /* (A7)+ */ + } else + if(o->dstsp) + return (4<<3) | 7; /* -(A7) */ + return (2<<3) | 7; /* (A7) */ + + case D_BRANCH: + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) { + if(p->as == ABSR || p->as == ABRA) { + v = p->pcond->pc; + *op++ = v>>16; + *op++ = v; + return (7<<3) | 1; + } + goto toobig; + } + if(v < -128 || v >= 128 || p->mark == 4) { + *op++ = v; + return 0; + } + return v & 0xff; + + case I_ADDR|D_STATIC: + case I_ADDR|D_EXTERN: + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + v = a->sym->value + a->offset; + if(t != STEXT) + v += INITDAT; + if(strcmp(a->sym->name, "a6base")) + break; + + case D_CONST: + switch(f? o->srcsp: o->dstsp) { + case 4: + *op++ = v>>16; + + case 2: + *op++ = v; + break; + + default: + diag("unknown srcsp asmea in %s", TNAME); + } + return (7<<3) | 4; + + case D_FCONST: + r = f? o->srcsp: o->dstsp; + for(i=0; i<r; i++) + ((char*)op)[i] = gnuxi(&a->ieee, i, r); + op += r/2; + return (7<<3) | 4; + + case D_QUICK: + v = a->offset & 0xff; + return 0110 | (v<<7); + + case D_STACK: + case D_AUTO: + case D_PARAM: + if(v == 0) + return (2<<3) | 7; /* (A7) */ + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (5<<3) | 7; /* d(A7) */ + } + goto toobig; + + case I_INDIR|D_CONST: + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (7<<3) | 0; + } + *op++ = v>>16; + *op++ = v; + return (7<<3) | 1; + + case D_STATIC: + case D_EXTERN: + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + if(t == STEXT) { + if(HEADTYPE == 4) { + v = a->sym->value + a->offset - p->pc - 2; + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (7<<3) | 2; + } + goto toobig; + } + v = a->sym->value + a->offset; + *op++ = v>>16; + *op++ = v; + return (7<<3) | 1; + } + v = a->sym->value + a->offset - A6OFFSET; + if(v < -32768L || v >= 32768L) { + v += INITDAT + A6OFFSET; + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (7<<3) | 0; + } + *op++ = v>>16; + *op++ = v; + return (7<<3) | 1; + } + if(v == 0) + return (2<<3) | 6; + *op++ = v; + return (5<<3) | 6; + } + if(!debug['a']) + print("%P\n", p); + diag("unknown addressing mode: %d in %s", t, TNAME); + return 0; + + if(!debug['a']) + print("%P\n", p); + diag("bad operand in %s", TNAME); + return 0; + +toobig: + if(!debug['a']) + print("%P\n", p); + diag("addressing mode >> 2^16: %d in %s", t, TNAME); + return 0; +} + +void +lput(long l) +{ + + CPUT(l>>24) + CPUT(l>>16) + CPUT(l>>8) + CPUT(l) +} + +void +s16put(char *n) +{ + char name[16]; + 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+100); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->from.displace; + i = 0; + if(l < 0) { + if(l+c <= 0) + continue; + while(l < 0) { + l++; + i++; + } + } + if(l >= n) + continue; + 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, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[fnuxi8[j+4]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i+4]]; + l++; + } + break; + case 8: + cast = (char*)&p->to.ieee; + if(debug['a'] && i == 0) { + Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + if(debug['a'] && i == 0) { + Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = p->to.scon[i]; + l++; + } + break; + default: + fl = p->to.offset; + if(p->to.sym) { + if(p->to.sym->type == STEXT) + fl += p->to.sym->value; + if(p->to.sym->type == SDATA) + fl += p->to.sym->value + INITDAT; + if(p->to.sym->type == SBSS) + fl += p->to.sym->value + INITDAT; + } + + 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, "%.4lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux",cast[inuxi1[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + if(debug['a'] && i == 0) { + Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux",cast[inuxi2[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + if(debug['a'] && i == 0) { + Bprint(&bso, "%.4lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux",cast[inuxi4[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +void +asmreloc(void) +{ + Prog *p; + Sym *s1, *s2; + int c1, c2, c3; + long v; + + if(HEADTYPE != 4) + return; + for(p = datap; p != P; p = p->link) { + curp = p; + s1 = p->to.sym; + if(s1 == S) + continue; + c1 = 'D'; + c3 = p->from.displace; + s2 = p->from.sym; + v = s2->value + INITDAT; + switch(s1->type) { + default: + diag("unknown reloc %d", s1->type); + continue; + case STEXT: + c2 = 'T'; + break; + + case SDATA: + c2 = 'D'; + break; + + case SBSS: + c2 = 'B'; + break; + } + CPUT(c1); + CPUT(c2); + CPUT(c3); + lput(v); + if(debug['a']) + Bprint(&bso, "r %c%c%d %.8lux %s $%s\n", + c1, c2, c3, v, s2->name, s1->name); + relocsize += 7; + } +} + +int +gnuxi(Ieee *d, int i, int c) +{ + char *p; + long l; + + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + return 0; + + /* + * 2301 vax + * 0123 68k + */ + case 4: + l = ieeedtof(d); + p = (char*)&l; + i = gnuxi8[i+4]; + break; + + /* + * 67452301 vax + * 45670123 68k + */ + case 8: + p = (char*)d; + i = gnuxi8[i]; + break; + } + return p[i]; +} + +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; +} diff --git a/utils/1l/l.h b/utils/1l/l.h new file mode 100644 index 00000000..de8d48ff --- /dev/null +++ b/utils/1l/l.h @@ -0,0 +1,268 @@ +#include <lib9.h> +#include <bio.h> +#include "../2c/2.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 +{ + short type; + uchar field; + union + { + struct + { + long u0displace; + long u0offset; + } s0; + char u0scon[8]; + Prog *u0cond; /* not used, but should be D_BRANCH */ + Ieee u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; +}; + +#define displace u0.s0.u0displace +#define offset u0.s0.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; + union + { + long u0stkoff; + Prog *u0forwd; + } u0; + Prog* link; + Prog* pcond; /* work on this */ + long pc; + long line; + short as; + uchar mark; /* work on these */ + uchar back; +}; + +#define stkoff u0.u0stkoff +#define forwd u0.u0forwd + +struct Auto +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + long value; + Sym* link; +}; +struct Optab +{ + short as; + short fas; + short srcsp; + short dstsp; + ushort optype; + ushort opcode0; + ushort opcode1; + ushort opcode2; + ushort opcode3; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SAUTO, + SPARAM, + SFILE, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 4, + STRINGSZ = 200, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + A6OFFSET = 32766, +}; + +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" int +#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 int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN Prog* prog_divsl; +EXTERN Prog* prog_divul; +EXTERN Prog* prog_mull; +EXTERN Prog* prog_ccr; +EXTERN char fnuxi8[8]; +EXTERN char gnuxi8[8]; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN long relocsize; +EXTERN long ndata; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long nsymbol; +EXTERN char* noname; +EXTERN short* op; +EXTERN char* outfile; +EXTERN long pc; +EXTERN char simple[I_MASK]; +EXTERN char special[I_MASK]; +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 Optab optab[]; +extern char mmsize[]; +extern char* anames[]; + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); +int Xconv(Fmt*); +void addhist(long, int); +int andsize(Prog*, Adr*); +void asmb(void); +int asmea(Prog*, Adr*); +void asmins(Prog*); +void asmlc(void); +void asmsp(void); +void asmsym(void); +void asmreloc(void); +long atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void cflush(void); +Prog* copyp(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +void dostkoff(void); +long entryvalue(void); +void errorexit(void); +int find1(long, int); +int find2(long, int); +void follow(void); +void gethunk(void); +int gnuxi(Ieee*, int, int); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void initmuldiv1(void); +void initmuldiv2(void); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void main(int, char*[]); +void mkfwd(void); +void* mysbrk(ulong); +void nuxiinit(void); +void objfile(char*); +void patch(void); +Prog* prg(void); +Prog* nprg(Prog*); +int relinv(int); +long reuse(Prog*, Sym*); +long rnd(long, long); +void s16put(char*); +void span(void); +void undef(void); +void xdefine(char*, int, long); +void xfol(Prog*); +int zaddr(uchar*, Adr*, Sym*[]); diff --git a/utils/1l/list.c b/utils/1l/list.c new file mode 100644 index 00000000..f02c3efa --- /dev/null +++ b/utils/1l/list.c @@ -0,0 +1,334 @@ +#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], s[20]; + Prog *p; + + p = va_arg(fp->args, Prog*); + bigP = p; + sprint(str, "(%ld) %A %D,%D", + p->line, p->as, &p->from, &p->to); + if(p->from.field) { + sprint(s, ",%d,%d", p->to.field, p->from.field); + strcat(str, s); + } + bigP = P; + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + + return fmtstrcpy(fp, anames[va_arg(fp->args, int)]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i, j; + long d; + + a = va_arg(fp->args, Adr*); + i = a->type; + j = i & I_MASK; + if(j) { + a->type = i & D_MASK; + d = a->offset; + a->offset = 0; + switch(j) { + case I_INDINC: + sprint(str, "(%D)+", a); + break; + + case I_INDDEC: + sprint(str, "-(%D)", a); + break; + + case I_INDIR: + if(d) + sprint(str, "%ld(%D)", d, a); + else + sprint(str, "(%D)", a); + break; + + case I_ADDR: + a->offset = d; + sprint(str, "$%D", a); + break; + } + a->type = i; + a->offset = d; + goto out; + } + 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_STACK: + sprint(str, "TOS+%ld", a->offset); + break; + + case D_QUICK: + sprint(str, "$Q%ld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + goto out; + + case D_SCONST: + sprint(str, "$\"%S\"", a->scon); + goto out; + } + if(a->displace) { + sprint(s, "/%ld", a->displace); + strcat(str, s); + } +out: + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_R0 && r < D_R0+NREG) + sprint(str, "R%d", r-D_R0); + else + if(r >= D_A0 && r < D_A0+NREG) + sprint(str, "A%d", r-D_A0); + else + if(r >= D_F0 && r < D_F0+NREG) + sprint(str, "F%d", r-D_F0); + else + switch(r) { + + default: + sprint(str, "gok(%d)", r); + break; + + case D_NONE: + sprint(str, "NONE"); + break; + + case D_TOS: + sprint(str, "TOS"); + break; + + case D_CCR: + sprint(str, "CCR"); + break; + + case D_SR: + sprint(str, "SR"); + break; + + case D_SFC: + sprint(str, "SFC"); + break; + + case D_DFC: + sprint(str, "DFC"); + break; + + case D_CACR: + sprint(str, "CACR"); + break; + + case D_USP: + sprint(str, "USP"); + break; + + case D_VBR: + sprint(str, "VBR"); + break; + + case D_CAAR: + sprint(str, "CAAR"); + break; + + case D_MSP: + sprint(str, "MSP"); + break; + + case D_ISP: + sprint(str, "ISP"); + break; + + case D_FPCR: + sprint(str, "FPCR"); + break; + + case D_FPSR: + sprint(str, "FPSR"); + break; + + case D_FPIAR: + sprint(str, "FPIAR"); + break; + + case D_TREE: + sprint(str, "TREE"); + break; + + case D_TC: + sprint(str, "TC"); + break; + + case D_ITT0: + sprint(str, "ITT0"); + break; + + case D_ITT1: + sprint(str, "ITT1"); + break; + + case D_DTT0: + sprint(str, "DTT0"); + break; + + case D_DTT1: + sprint(str, "DTT1"); + break; + + case D_MMUSR: + sprint(str, "MMUSR"); + break; + case D_URP: + sprint(str, "URP"); + break; + + case D_SRP: + sprint(str, "SRP"); + break; + } + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/1l/mkfile b/utils/1l/mkfile new file mode 100644 index 00000000..aafa5a70 --- /dev/null +++ b/utils/1l/mkfile @@ -0,0 +1,32 @@ +<../../mkconfig + +TARG=1l +OFILES=\ + asm.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + list.$O\ + enam.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../2c/2.out.h\ + ../include/ar.h\ + +LIBS=bio 9 +BIN=$ROOT/$OBJDIR/bin +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I ../include + +enam.$O: ../2c/enam.c + $CC $CFLAGS ../2c/enam.c + +%.1: %.s + 1a $stem.s + +%.1: %.c + 1c -w $stem.c diff --git a/utils/1l/obj.c b/utils/1l/obj.c new file mode 100644 index 00000000..379a9ffb --- /dev/null +++ b/utils/1l/obj.c @@ -0,0 +1,1380 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char symname[] = SYMDEF; +char thechar = '1'; +char *thestring = "68000"; + +/* + * -H0 -T0x40004C -D0x10000000 is garbage unix + * -H1 -T0x80020000 -R4 is garbage format + * -H2 -T8224 -R8192 is plan9 format + * -H3 -Tx -Rx is next boot + * -H4 -T0 -D0 is pilot relocatable + */ + +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 = "1.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; + } ARGEND + + USED(argc); + + if(*argv == 0) { + diag("usage: 1l [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 2; + if(debug['B']) + HEADTYPE = 2; + if(debug['9']) + HEADTYPE = 2; + } + if(INITDAT != -1 && INITRND == -1) + INITRND = 0; + switch(HEADTYPE) { + default: + diag("unknown -H option %d", HEADTYPE); + errorexit(); + + case 0: /* this is garbage */ + HEADR = 20L+56L; + if(INITTEXT == -1) + INITTEXT = 0x40004CL; + if(INITDAT == -1) + INITDAT = 0x10000000L; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 0; + break; + case 1: /* plan9 boot data goes into text */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 8224; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 8192; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 8224; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 8192; + break; + case 3: /* next boot */ + HEADR = 28+124+192+24; + if(INITTEXT == -1) + INITTEXT = 0x04002000; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 8192L; + break; + case 4: /* preprocess pilot */ + HEADR = 36L; + if(INITTEXT == -1) + INITTEXT = 0; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 0; + 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(); + } + + zprg.link = P; + zprg.pcond = P; + zprg.back = 2; + zprg.as = AGOK; + zprg.from.type = D_NONE; + zprg.to = zprg.from; + + memset(special, 0, sizeof(special)); + special[D_CCR] = 1; + special[D_SR] = 1; + special[D_SFC] = 1; + special[D_CACR] = 1; + special[D_USP] = 1; + special[D_VBR] = 1; + special[D_CAAR] = 1; + special[D_MSP] = 1; + special[D_ISP] = 1; + special[D_DFC] = 1; + special[D_FPCR] = 1; + special[D_FPSR] = 1; + special[D_FPIAR] = 1; + special[D_TC] = 1; + special[D_ITT0] = 1; + special[D_ITT1] = 1; + special[D_DTT0] = 1; + special[D_DTT1] = 1; + special[D_MMUSR] = 1; + special[D_URP] = 1; + special[D_SRP] = 1; + memset(simple, 0177, sizeof(simple)); + for(i=0; i<8; i++) { + simple[D_R0+i] = i; + simple[D_F0+i] = i+0100; + simple[D_A0+i] = i+010; + simple[D_A0+I_INDIR+i] = i+020; + simple[D_A0+I_INDINC+i] = i+030; + simple[D_A0+I_INDDEC+i] = i+040; + } + nuxiinit(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + 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; + + initmuldiv1(); + while(*argv) + objfile(*argv++); + if(!debug['l']) + loadlib(); + firstp = firstp->link; + if(firstp == P) + errorexit(); + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + initmuldiv2(); + follow(); + dodata(); + dostkoff(); + span(); + asmb(); + undef(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld data statements\n", ndata); + 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') { + sprint(name, "/%s/lib/lib", thestring); + 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]; + + /* + * first try the high-time formats + */ + if(t == 0) { + a->type = p[1]; + return 2; + } + if(t == T_OFFSET) { + a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24); + a->type = p[5]; + return 6; + } + if(t == (T_OFFSET|T_SYM)) { + a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24); + s = h[p[5]]; + a->sym = s; + a->type = p[6]; + c = 7; + goto dosym; + } + if(t == T_SYM) { + s = h[p[1]]; + a->sym = s; + a->type = p[2]; + c = 3; + goto dosym; + } + if(t == (T_INDEX|T_OFFSET|T_SYM)) { + a->displace = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24); + a->offset = p[8] | (p[9]<<8) | (p[10]<<16) | (p[11]<<24); + s = h[p[12]]; + a->sym = s; + a->type = p[13]; + c = 14; + goto dosym; + } + + /* + * now do it the hard way + */ + c = 1; + if(t & T_FIELD) { + a->field = p[c] | (p[c+1]<<8); + c += 2; + } + if(t & T_INDEX) { + a->displace = p[c+3] | (p[c+4]<<8) | (p[c+5]<<16) | (p[c+6]<<24); + c += 7; + } + if(t & T_OFFSET) { + a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + c += 4; + } + if(t & T_SYM) { + a->sym = h[p[c]]; + c += 1; + } + 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; + } else + if(t & T_TYPE) { + a->type = p[c] | (p[c+1]<<8); + c += 2; + } else { + a->type = p[c]; + c++; + } + s = a->sym; + if(s == S) + return c; + +dosym: + t = a->type & D_MASK; + 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; +} + +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) +{ + Prog *p; + Sym *h[NSYM], *s; + int v, o, r; + long ipc, lv; + double dv; + uchar *bloc, *bsize, *stop; + + bsize = buf.xbuf; + bloc = buf.xbuf; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + +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 .%c file\n", thechar); + errorexit(); + } + + if(o == ANAME || o == ASIGNAME) { + if(o == ASIGNAME) { + 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['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 ADATA: + p->link = datap; + datap = p; + ndata++; + goto loop; + + case AGOK: + diag("%s: unknown opcode in %s", pn, TNAME); + pc++; + goto loop; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + curtext = p; + lastp->link = p; + lastp = p; + p->pc = pc; + s = p->from.sym; + if(s->type != 0 && s->type != SXREF) + diag("%s: redefinition: %s", pn, s->name); + s->type = STEXT; + s->value = p->pc; + pc++; + p->pcond = P; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->pcond = p; + etextp = p; + goto loop; + + case AJSR: + p->as = ABSR; + + case ABSR: + if(p->to.type != D_EXTERN && p->to.type != D_STATIC) + p->as = AJSR; + goto casdef; + + case AMOVL: + case AMOVB: + case AMOVW: + if(p->from.type != D_CONST) + goto casdef; + lv = p->from.offset; + if(lv >= -128 && lv < 128) + if(p->to.type >= D_R0 && p->to.type < D_R0+8) { + p->from.type = D_QUICK; + goto casdef; + } + + if(lv >= -0x7fff && lv <= 0x7fff) + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + if(p->as == AMOVL) + p->as = AMOVW; + goto casdef; + + case AADDB: + case AADDL: + case AADDW: + if(p->from.type != D_CONST) + goto casdef; + lv = p->from.offset; + if(lv < 0) { + lv = -lv; + p->from.offset = lv; + if(p->as == AADDB) + p->as = ASUBB; + else + if(p->as == AADDW) + p->as = ASUBW; + else + if(p->as == AADDL) + p->as = ASUBL; + } + if(lv > 0) + if(lv <= 8) + p->from.type = D_QUICK; + goto casdef; + + case ASUBB: + case ASUBL: + case ASUBW: + if(p->from.type != D_CONST) + goto casdef; + lv = p->from.offset; + if(lv < 0) { + lv = -lv; + p->from.offset = lv; + if(p->as == ASUBB) + p->as = AADDB; + else + if(p->as == ASUBW) + p->as = AADDW; + else + if(p->as == ASUBL) + p->as = AADDL; + } + if(lv > 0) + if(lv <= 8) + p->from.type = D_QUICK; + goto casdef; + + case AROTRB: + case AROTRL: + case AROTRW: + case AROTLB: + case AROTLL: + case AROTLW: + + case AASLB: + case AASLL: + case AASLW: + case AASRB: + case AASRL: + case AASRW: + case ALSLB: + case ALSLL: + case ALSLW: + case ALSRB: + case ALSRL: + case ALSRW: + if(p->from.type == D_CONST) + if(p->from.offset > 0) + if(p->from.offset <= 8) + p->from.type = D_QUICK; + goto casdef; + + case ATSTL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) { + p->as = ACMPW; + p->from = p->to; + p->to.type = D_CONST; + p->to.offset = 0; + } + goto casdef; + + case ACMPL: + if(p->to.type != D_CONST) + goto casdef; + lv = p->to.offset; + if(lv >= -0x7fff && lv <= 0x7fff) + if(p->from.type >= D_A0 && p->from.type < D_A0+8) + p->as = ACMPW; + goto casdef; + + case ACLRL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) { + p->as = AMOVW; + p->from.type = D_CONST; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(p->from.type == D_FCONST) + if(optab[p->as].fas != AXXX) { + dv = ieeedtod(&p->from.ieee); + if(dv >= -(1L<<30) && dv <= (1L<<30)) { + lv = dv; + if(lv == dv) { + p->as = optab[p->as].fas; + p->from.type = D_CONST; + p->from.offset = lv; + p->from.displace = 0; + } + } + } + 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("%s: truncated object file in %s", pn, TNAME); +} + +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; + 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* +nprg(Prog *p) +{ + Prog *q; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->stkoff = p->stkoff; + q->link = p->link; + p->link = q; + return q; +} + +Prog* +copyp(Prog *q) +{ + Prog *p; + + p = prg(); + *p = *q; + 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->as = AADDL; + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + q->from.type = D_CONST; + q->from.offset = 1; + q->to.type = D_EXTERN; + q->to.sym = s; + q->to.offset = n*4 + 4; + + q = prg(); + q->as = ADATA; + q->line = p->line; + q->link = datap; + datap = q; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.offset = n*4; + q->from.displace = 4; + q->to.type = D_EXTERN; + q->to.sym = p->from.sym; + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->as = ADATA; + q->link = datap; + datap = q; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.displace = 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) { + ps2 = p; + p->from.displace = 1; + } + if(p->from.sym == s4) { + ps4 = p; + p->from.displace = 1; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->from.displace != 0) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ABSR; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARTS) { + /* + * RTS + */ + q = prg(); + q->as = ARTS; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * BSR profout + */ + p->as = ABSR; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +long +reuse(Prog *r, Sym *s) +{ + Prog *p; + + + if(r == P) + return 0; + for(p = datap; p != r; p = p->link) + if(p->to.sym == s) + return p->from.offset; + return 0; +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x01020304L, i+1); + if(i >= 2) + inuxi2[i-2] = c; + if(i >= 3) + inuxi1[i-3] = c; + inuxi4[i] = c; + fnuxi8[i] = c+4; + fnuxi8[i+4] = c; + c = find2(0x01020304L, i+1); + gnuxi8[i] = c+4; + gnuxi8[i+4] = c; + } + 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, "\n[fg]nuxi = "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", gnuxi8[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); +} diff --git a/utils/1l/optab.c b/utils/1l/optab.c new file mode 100644 index 00000000..2109b478 --- /dev/null +++ b/utils/1l/optab.c @@ -0,0 +1,444 @@ +#include "l.h" + +#define X1 0 +#define X2 0 +#define X3 0 +#define C 0xf200 + +Optab optab[] = +/* as, fas, srcsp, dstsp, optype, opcode */ +{ + { AXXX }, + { AABCD, AXXX, X1, X2, X3, 0x4e71 }, + { AADDB, AXXX, 2, 0, 3, 0xd000, 0x5000, 0, 0x0600 }, + { AADDL, AXXX, 4, 0, 3, 0xd080, 0x5080, 0xd1c0, 0x0680 }, + { AADDW, AXXX, 2, 0, 3, 0xd040, 0x5040, 0xd0c0, 0x0640 }, + { AADDXB }, + { AADDXL }, + { AADDXW }, + { AADJSP }, + { AANDB, AXXX, 2, 0, 9, 0xc000, 0xc100, 0x0200 }, + { AANDL, AXXX, 4, 0, 9, 0xc080, 0xc180, 0x0280 }, + { AANDW, AXXX, 2, 0, 9, 0xc040, 0xc140, 0x0240 }, + { AASLB, AXXX, 0, 2, 12, 0xe100 }, + { AASLL, AXXX, 0, 4, 12, 0xe180 }, + { AASLW, AXXX, 0, 2, 12, 0xe140 }, + { AASRB, AXXX, 0, 2, 12, 0xe000 }, + { AASRL, AXXX, 0, 4, 12, 0xe080 }, + { AASRW, AXXX, 0, 2, 12, 0xe040 }, + { ABCASE }, + { ABCC, AXXX, 0, 0, 1, 0x6400 }, + { ABCHG, AXXX, 2, 2, 27, 0x0140, 0x0840 }, + { ABCLR, AXXX, 2, 2, 27, 0x0180, 0x0880 }, + { ABCS, AXXX, 0, 0, 1, 0x6500 }, + { ABEQ, AXXX, 0, 0, 1, 0x6700 }, + { ABFCHG }, + { ABFCLR }, + { ABFEXTS }, + { ABFEXTU }, + { ABFFFO }, + { ABFINS }, + { ABFSET }, + { ABFTST }, + { ABGE, AXXX, 0, 0, 1, 0x6c00 }, + { ABGT, AXXX, 0, 0, 1, 0x6e00 }, + { ABHI, AXXX, 0, 0, 1, 0x6200 }, + { ABKPT }, + { ABLE, AXXX, 0, 0, 1, 0x6f00 }, + { ABLS, AXXX, 0, 0, 1, 0x6300 }, + { ABLT, AXXX, 0, 0, 1, 0x6d00 }, + { ABMI, AXXX, 0, 0, 1, 0x6b00 }, + { ABNE, AXXX, 0, 0, 1, 0x6600 }, + { ABPL, AXXX, 0, 0, 1, 0x6a00 }, + { ABRA, AXXX, 0, 0, 1, 0x6000, 0x4ec0 }, + { ABSET, AXXX, 2, 2, 27, 0x01c0, 0x08c0 }, + { ABSR, AXXX, 0, 0, 1, 0x6100, 0x4e80 }, + { ABTST, AXXX, 2, 2, 27, 0x0100, 0x0800 }, + { ABVC, AXXX, 0, 0, 1, 0x6800 }, + { ABVS, AXXX, 0, 0, 1, 0x6900 }, + { ACALLM }, + { ACAS2B }, + { ACAS2L }, + { ACAS2W }, + { ACASB }, + { ACASEW }, + { ACASL }, + { ACASW }, + { ACHK2B }, + { ACHK2L }, + { ACHK2W }, + { ACHKL, AXXX, 4, 4, 26, 0x4100 }, + { ACHKW, AXXX, 2, 2, 26, 0x4180 }, + { ACLRB, AXXX, 0, -2, 5, 0x4200 }, + { ACLRL, AXXX, 0, -4, 5, 0x4280 }, + { ACLRW, AXXX, 0, -2, 5, 0x4240 }, + { ACMP2B }, + { ACMP2L }, + { ACMP2W }, + { ACMPB, AXXX, 2, 2, 7, 0xb000, 0, 0x0c00, 0xb108 }, + { ACMPL, AXXX, 4, 4, 7, 0xb080, 0xb100, 0x0c80, 0xb188 }, + { ACMPW, AXXX, 2, 2, 7, 0xb040, 0xb080, 0x0c40, 0xb148 }, + { ADATA }, + { ADBCC, AXXX, 0, 0, 15, 0x54c8 }, + { ADBCS, AXXX, 0, 0, 15, 0x55c8 }, + { ADBEQ, AXXX, 0, 0, 15, 0x57c8 }, + { ADBF, AXXX, 0, 0, 15, 0x51c8 }, + { ADBGE, AXXX, 0, 0, 15, 0x5cc8 }, + { ADBGT, AXXX, 0, 0, 15, 0x5ec8 }, + { ADBHI, AXXX, 0, 0, 15, 0x52c8 }, + { ADBLE, AXXX, 0, 0, 15, 0x5fc8 }, + { ADBLS, AXXX, 0, 0, 15, 0x53c8 }, + { ADBLT, AXXX, 0, 0, 15, 0x5dc8 }, + { ADBMI, AXXX, 0, 0, 15, 0x5bc8 }, + { ADBNE, AXXX, 0, 0, 15, 0x56c8 }, + { ADBPL, AXXX, 0, 0, 15, 0x5ac8 }, + { ADBT, AXXX, 0, 0, 15, 0x50c8 }, + { ADBVC, AXXX, 0, 0, 15, 0x58c8 }, + { ADBVS, AXXX, 0, 0, 15, 0x59c8 }, + { ADIVSL, AXXX, 4, 0, 14, 0x4c40, 0x0800 }, + { ADIVSW, AXXX, 2, 0, 13, 0x81c0 }, + { ADIVUL, AXXX, 4, 0, 14, 0x4c40, 0x0000 }, + { ADIVUW, AXXX, 2, 0, 13, 0x80c0 }, + { AEND }, + { AEORB, AXXX, 2, 0, 10, 0xb100, 0x0a00 }, + { AEORL, AXXX, 4, 0, 10, 0xb180, 0x0a80 }, + { AEORW, AXXX, 2, 0, 10, 0xb140, 0x0a40 }, + { AEXG }, + { AEXTBL }, + { AEXTBW, AXXX, 0, 0, 11, 0x4880 }, + { AEXTWL, AXXX, 0, 0, 11, 0x48c0 }, + { AFABSB, AXXX, 2, 0, 17, C, 0x0018, 0x5818 }, + { AFABSD, AFABSL, 8, 0, 17, C, 0x0018, 0x5418 }, + { AFABSF, AFABSL, 4, 0, 17, C, 0x0018, 0x4418 }, + { AFABSL, AXXX, 4, 0, 17, C, 0x0018, 0x4018 }, + { AFABSW, AXXX, 2, 0, 17, C, 0x0018, 0x5018 }, + { AFACOSB, AXXX, 2, 0, 17, C, 0x001c, 0x581c }, + { AFACOSD, AFACOSL, 8, 0, 17, C, 0x001c, 0x541c }, + { AFACOSF, AFACOSL, 4, 0, 17, C, 0x001c, 0x441c }, + { AFACOSL, AXXX, 4, 0, 17, C, 0x001c, 0x401c }, + { AFACOSW, AXXX, 2, 0, 17, C, 0x001c, 0x501c }, + { AFADDB, AXXX, 2, 0, 17, C, 0x0022, 0x5822 }, + { AFADDD, AFADDL, 8, 0, 17, C, 0x0022, 0x5422 }, + { AFADDF, AFADDL, 4, 0, 17, C, 0x0022, 0x4422 }, + { AFADDL, AXXX, 4, 0, 17, C, 0x0022, 0x4022 }, + { AFADDW, AXXX, 2, 0, 17, C, 0x0022, 0x5022 }, + { AFASINB, AXXX, 2, 0, 17, C, 0x000c, 0x580c }, + { AFASIND, AFASINL, 8, 0, 17, C, 0x000c, 0x540c }, + { AFASINF, AFASINL, 4, 0, 17, C, 0x000c, 0x440c }, + { AFASINL, AXXX, 4, 0, 17, C, 0x000c, 0x400c }, + { AFASINW, AXXX, 2, 0, 17, C, 0x000c, 0x500c }, + { AFATANB, AXXX, 2, 0, 17, C, 0x000a, 0x580a }, + { AFATAND, AFATANL, 8, 0, 17, C, 0x000a, 0x540a }, + { AFATANF, AFATANL, 4, 0, 17, C, 0x000a, 0x440a }, + { AFATANHB, AXXX, 2, 0, 17, C, 0x000d, 0x580d }, + { AFATANHD, AFATANHL, 8, 0, 17, C, 0x000d, 0x540d }, + { AFATANHF, AFATANHL, 4, 0, 17, C, 0x000d, 0x440d }, + { AFATANHL, AXXX, 4, 0, 17, C, 0x000d, 0x400d }, + { AFATANHW, AXXX, 2, 0, 17, C, 0x000d, 0x500d }, + { AFATANL, AXXX, 4, 0, 17, C, 0x000a, 0x400a }, + { AFATANW, AXXX, 2, 0, 17, C, 0x000a, 0x500a }, + { AFBEQ, AXXX, 0, 0, 18, C+0x81 }, + { AFBF, AXXX, 0, 0, 18, C+0x8f }, + { AFBGE, AXXX, 0, 0, 18, C+0x93 }, + { AFBGT, AXXX, 0, 0, 18, C+0x92 }, + { AFBLE, AXXX, 0, 0, 18, C+0x95 }, + { AFBLT, AXXX, 0, 0, 18, C+0x94 }, + { AFBNE, AXXX, 0, 0, 18, C+0x8e }, + { AFBT, AXXX, 0, 0, 18, C+0x80 }, + { AFCMPB, AXXX, 0, 2, 22, C, 0x0038, 0x5838 }, + { AFCMPD, AFCMPL, 0, 8, 22, C, 0x0038, 0x5438 }, + { AFCMPF, AFCMPL, 0, 4, 22, C, 0x0038, 0x4438 }, + { AFCMPL, AXXX, 0, 4, 22, C, 0x0038, 0x4038 }, + { AFCMPW, AXXX, 0, 2, 22, C, 0x0038, 0x5038 }, + { AFCOSB, AXXX, 2, 0, 17, C, 0x001d, 0x581d }, + { AFCOSD, AFCOSL, 8, 0, 17, C, 0x001d, 0x541d }, + { AFCOSF, AFCOSL, 4, 0, 17, C, 0x001d, 0x441d }, + { AFCOSHB, AXXX, 2, 0, 17, C, 0x0019, 0x5819 }, + { AFCOSHD, AFCOSHL, 8, 0, 17, C, 0x0019, 0x5419 }, + { AFCOSHF, AFCOSHL, 4, 0, 17, C, 0x0019, 0x4419 }, + { AFCOSHL, AXXX, 4, 0, 17, C, 0x0019, 0x4019 }, + { AFCOSHW, AXXX, 2, 0, 17, C, 0x0019, 0x5019 }, + { AFCOSL, AXXX, 4, 0, 17, C, 0x001d, 0x401d }, + { AFCOSW, AXXX, 2, 0, 17, C, 0x001d, 0x501d }, + { AFDBEQ, AXXX, 0, 0, 19, C+0x48, 0x01 }, + { AFDBF, AXXX, 0, 0, 19, C+0x48, 0x0f }, + { AFDBGE, AXXX, 0, 0, 19, C+0x48, 0x13 }, + { AFDBGT, AXXX, 0, 0, 19, C+0x48, 0x12 }, + { AFDBLE, AXXX, 0, 0, 19, C+0x48, 0x15 }, + { AFDBLT, AXXX, 0, 0, 19, C+0x48, 0x14 }, + { AFDBNE, AXXX, 0, 0, 19, C+0x48, 0x0e }, + { AFDBT, AXXX, 0, 0, 19, C+0x48, 0x00 }, + { AFDIVB, AXXX, 2, 0, 17, C, 0x0020, 0x5820 }, + { AFDIVD, AFDIVL, 8, 0, 17, C, 0x0020, 0x5420 }, + { AFDIVF, AFDIVL, 4, 0, 17, C, 0x0020, 0x4420 }, + { AFDIVL, AXXX, 4, 0, 17, C, 0x0020, 0x4020 }, + { AFDIVW, AXXX, 2, 0, 17, C, 0x0020, 0x5020 }, + { AFETOXB, AXXX, 2, 0, 17, C, 0x0010, 0x5810 }, + { AFETOXD, AFETOXL, 8, 0, 17, C, 0x0010, 0x5410 }, + { AFETOXF, AFETOXL, 4, 0, 17, C, 0x0010, 0x4410 }, + { AFETOXL, AXXX, 4, 0, 17, C, 0x0010, 0x4010 }, + { AFETOXM1B, AXXX, 2, 0, 17, C, 0x0008, 0x5808 }, + { AFETOXM1D, AFETOXM1L, 8, 0, 17, C, 0x0008, 0x5408 }, + { AFETOXM1F, AFETOXM1L, 4, 0, 17, C, 0x0008, 0x4408 }, + { AFETOXM1L, AXXX, 4, 0, 17, C, 0x0008, 0x4008 }, + { AFETOXM1W, AXXX, 2, 0, 17, C, 0x0008, 0x5008 }, + { AFETOXW, AXXX, 2, 0, 17, C, 0x0010, 0x5010 }, + { AFGETEXPB, AXXX, 2, 0, 17, C, 0x001e, 0x581e }, + { AFGETEXPD, AFGETEXPL, 8, 0, 17, C, 0x001e, 0x541e }, + { AFGETEXPF, AFGETEXPL, 4, 0, 17, C, 0x001e, 0x441e }, + { AFGETEXPL, AXXX, 4, 0, 17, C, 0x001e, 0x401e }, + { AFGETEXPW, AXXX, 2, 0, 17, C, 0x001e, 0x501e }, + { AFGETMANB, AXXX, 2, 0, 17, C, 0x001f, 0x581f }, + { AFGETMAND, AFGETMANL, 8, 0, 17, C, 0x001f, 0x541f }, + { AFGETMANF, AFGETMANL, 4, 0, 17, C, 0x001f, 0x441f }, + { AFGETMANL, AXXX, 4, 0, 17, C, 0x001f, 0x401f }, + { AFGETMANW, AXXX, 2, 0, 17, C, 0x001f, 0x501f }, + { AFINTB, AXXX, 2, 0, 17, C, 0x0001, 0x5801 }, + { AFINTD, AFINTL, 8, 0, 17, C, 0x0001, 0x5401 }, + { AFINTF, AFINTL, 4, 0, 17, C, 0x0001, 0x4401 }, + { AFINTL, AXXX, 4, 0, 17, C, 0x0001, 0x4001 }, + { AFINTRZB, AXXX, 2, 0, 17, C, 0x0003, 0x5803 }, + { AFINTRZD, AFINTRZL, 8, 0, 17, C, 0x0003, 0x5403 }, + { AFINTRZF, AFINTRZL, 4, 0, 17, C, 0x0003, 0x4403 }, + { AFINTRZL, AXXX, 4, 0, 17, C, 0x0003, 0x4003 }, + { AFINTRZW, AXXX, 2, 0, 17, C, 0x0003, 0x5003 }, + { AFINTW, AXXX, 2, 0, 17, C, 0x0001, 0x5001 }, + { AFLOG10B, AXXX, 2, 0, 17, C, 0x0015, 0x5815 }, + { AFLOG10D, AFLOG10L, 8, 0, 17, C, 0x0015, 0x5415 }, + { AFLOG10F, AFLOG10L, 4, 0, 17, C, 0x0015, 0x4415 }, + { AFLOG10L, AXXX, 4, 0, 17, C, 0x0015, 0x4015 }, + { AFLOG10W, AXXX, 2, 0, 17, C, 0x0015, 0x5015 }, + { AFLOG2B, AXXX, 2, 0, 17, C, 0x0016, 0x5816 }, + { AFLOG2D, AFLOG2L, 8, 0, 17, C, 0x0016, 0x5416 }, + { AFLOG2F, AFLOG2L, 4, 0, 17, C, 0x0016, 0x4416 }, + { AFLOG2L, AXXX, 4, 0, 17, C, 0x0016, 0x4016 }, + { AFLOG2W, AXXX, 2, 0, 17, C, 0x0016, 0x5016 }, + { AFLOGNB, AXXX, 2, 0, 17, C, 0x0014, 0x5814 }, + { AFLOGND, AFLOGNL, 8, 0, 17, C, 0x0014, 0x5414 }, + { AFLOGNF, AFLOGNL, 4, 0, 17, C, 0x0014, 0x4414 }, + { AFLOGNL, AXXX, 4, 0, 17, C, 0x0014, 0x4014 }, + { AFLOGNP1B, AXXX, 2, 0, 17, C, 0x0006, 0x5806 }, + { AFLOGNP1D, AFLOGNP1L, 8, 0, 17, C, 0x0006, 0x5406 }, + { AFLOGNP1F, AFLOGNP1L, 4, 0, 17, C, 0x0006, 0x4406 }, + { AFLOGNP1L, AXXX, 4, 0, 17, C, 0x0006, 0x4006 }, + { AFLOGNP1W, AXXX, 2, 0, 17, C, 0x0006, 0x5006 }, + { AFLOGNW, AXXX, 2, 0, 17, C, 0x0014, 0x5014 }, + { AFMODB, AXXX, 2, 0, 17, C, 0x0021, 0x5821 }, + { AFMODD, AFMODL, 8, 0, 17, C, 0x0021, 0x5421 }, + { AFMODF, AFMODL, 4, 0, 17, C, 0x0021, 0x4421 }, + { AFMODL, AXXX, 4, 0, 17, C, 0x0021, 0x4021 }, + { AFMODW, AXXX, 2, 0, 17, C, 0x0021, 0x5021 }, + { AFMOVEB, AXXX, 2, -2, 16, C, 0x0000, 0x7800, 0x5800 }, + { AFMOVED, AFMOVEL, 8, -8, 16, C, 0x0000, 0x7400, 0x5400 }, + { AFMOVEF, AFMOVEL, 4, -4, 16, C, 0x0000, 0x6400, 0x4400 }, + { AFMOVEL, AXXX, 4, -4, 16, C, 0x0000, 0x6000, 0x4000 }, + { AFMOVEM, AXXX, 2, 2, 28, C }, + { AFMOVEMC, AXXX, 2, 2, 29, C }, + { AFMOVEW, AXXX, 2, -2, 16, C, 0x0000, 0x7000, 0x5000 }, + { AFMULB, AXXX, 2, 0, 17, C, 0x0023, 0x5823 }, + { AFMULD, AFMULL, 8, 0, 17, C, 0x0023, 0x5423 }, + { AFMULF, AFMULL, 4, 0, 17, C, 0x0023, 0x4423 }, + { AFMULL, AXXX, 4, 0, 17, C, 0x0023, 0x4023 }, + { AFMULW, AXXX, 2, 0, 17, C, 0x0023, 0x5023 }, + { AFNEGB, AXXX, 2, 0, 21, C, 0x001a, 0x581a }, + { AFNEGD, AFNEGL, 8, 0, 21, C, 0x001a, 0x541a }, + { AFNEGF, AFNEGL, 4, 0, 21, C, 0x001a, 0x441a }, + { AFNEGL, AXXX, 4, 0, 21, C, 0x001a, 0x401a }, + { AFNEGW, AXXX, 2, 0, 21, C, 0x001a, 0x501a }, + { AFREMB, AXXX, 2, 0, 17, C, 0x0025, 0x5825 }, + { AFREMD, AFREML, 8, 0, 17, C, 0x0025, 0x5425 }, + { AFREMF, AFREML, 4, 0, 17, C, 0x0025, 0x4425 }, + { AFREML, AXXX, 4, 0, 17, C, 0x0025, 0x4025 }, + { AFREMW, AXXX, 2, 0, 17, C, 0x0025, 0x5025 }, + { AFRESTORE, AXXX, 0, 2, 5, C+0x0140 }, + { AFSAVE, AXXX, 0, 2, 5, C+0x0100 }, + { AFSCALEB, AXXX, 2, 0, 17, C, 0x0026, 0x5826 }, + { AFSCALED, AFSCALEL, 8, 0, 17, C, 0x0026, 0x5426 }, + { AFSCALEF, AFSCALEL, 4, 0, 17, C, 0x0026, 0x4426 }, + { AFSCALEL, AXXX, 4, 0, 17, C, 0x0026, 0x4026 }, + { AFSCALEW, AXXX, 2, 0, 17, C, 0x0026, 0x5026 }, + { AFSEQ, AXXX, X1, X2, X3, 0xffff }, + { AFSF, AXXX, 4, X2, X3, 0xffff }, + { AFSGE, AXXX, X1, X2, X3, 0xffff }, + { AFSGT, AXXX, X1, X2, X3, 0xffff }, + { AFSINB, AXXX, 2, 0, 17, C, 0x000e, 0x580e }, + { AFSIND, AFSINL, 8, 0, 17, C, 0x000e, 0x540e }, + { AFSINF, AFSINL, 4, 0, 17, C, 0x000e, 0x440e }, + { AFSINHB, AXXX, 2, 0, 17, C, 0x0002, 0x5802 }, + { AFSINHD, AFSINHL, 8, 0, 17, C, 0x0002, 0x5402 }, + { AFSINHF, AFSINHL, 4, 0, 17, C, 0x0002, 0x4402 }, + { AFSINHL, AXXX, 4, 0, 17, C, 0x0002, 0x4002 }, + { AFSINHW, AXXX, 2, 0, 17, C, 0x0002, 0x5002 }, + { AFSINL, AXXX, 4, 0, 17, C, 0x000e, 0x400e }, + { AFSINW, AXXX, 2, 0, 17, C, 0x000e, 0x500e }, + { AFSLE, AXXX, X1, X2, X3, 0xffff }, + { AFSLT, AXXX, X1, X2, X3, 0xffff }, + { AFSNE, AXXX, X1, X2, X3, 0xffff }, + { AFSQRTB, AXXX, 2, 0, 17, C, 0x0004, 0x5804 }, + { AFSQRTD, AFSQRTL, 8, 0, 17, C, 0x0004, 0x5404 }, + { AFSQRTF, AFSQRTL, 4, 0, 17, C, 0x0004, 0x4404 }, + { AFSQRTL, AXXX, 4, 0, 17, C, 0x0004, 0x4004 }, + { AFSQRTW, AXXX, 2, 0, 17, C, 0x0004, 0x5004 }, + { AFST, AXXX, X1, X2, X3, 0xffff }, + { AFSUBB, AXXX, 2, 0, 17, C, 0x0028, 0x5828 }, + { AFSUBD, AFSUBL, 8, 0, 17, C, 0x0028, 0x5428 }, + { AFSUBF, AFSUBL, 4, 0, 17, C, 0x0028, 0x4428 }, + { AFSUBL, AXXX, 4, 0, 17, C, 0x0028, 0x4028 }, + { AFSUBW, AXXX, 2, 0, 17, C, 0x0028, 0x5028 }, + { AFTANB, AXXX, 2, 0, 17, C, 0x000f, 0x580f }, + { AFTAND, AFTANL, 8, 0, 17, C, 0x000f, 0x540f }, + { AFTANF, AFTANL, 4, 0, 17, C, 0x000f, 0x440f }, + { AFTANHB, AXXX, 2, 0, 17, C, 0x0009, 0x5809 }, + { AFTANHD, AFTANHL, 8, 0, 17, C, 0x0009, 0x5409 }, + { AFTANHF, AFTANHL, 4, 0, 17, C, 0x0009, 0x4409 }, + { AFTANHL, AXXX, 4, 0, 17, C, 0x0009, 0x4009 }, + { AFTANHW, AXXX, 2, 0, 17, C, 0x0009, 0x5009 }, + { AFTANL, AXXX, 4, 0, 17, C, 0x000f, 0x400f }, + { AFTANW, AXXX, 2, 0, 17, C, 0x000f, 0x500f }, + { AFTENTOXB, AXXX, 2, 0, 17, C, 0x0012, 0x5812 }, + { AFTENTOXD, AFTENTOXL, 8, 0, 17, C, 0x0012, 0x5412 }, + { AFTENTOXF, AFTENTOXL, 4, 0, 17, C, 0x0012, 0x4412 }, + { AFTENTOXL, AXXX, 4, 0, 17, C, 0x0012, 0x4012 }, + { AFTENTOXW, AXXX, 2, 0, 17, C, 0x0012, 0x5012 }, + { AFTSTB, AXXX, 0, 2, 20, C, 0x003a, 0x583a }, + { AFTSTD, AFTSTL, 0, 8, 20, C, 0x003a, 0x543a }, + { AFTSTF, AFTSTL, 0, 4, 20, C, 0x003a, 0x443a }, + { AFTSTL, AXXX, 0, 4, 20, C, 0x003a, 0x403a }, + { AFTSTW, AXXX, 0, 2, 20, C, 0x003a, 0x503a }, + { AFTWOTOXB, AXXX, 2, 0, 17, C, 0x0011, 0x5811 }, + { AFTWOTOXD, AFTWOTOXL, 8, 0, 17, C, 0x0011, 0x5411 }, + { AFTWOTOXF, AFTWOTOXL, 4, 0, 17, C, 0x0011, 0x4411 }, + { AFTWOTOXL, AXXX, 4, 0, 17, C, 0x0011, 0x4011 }, + { AFTWOTOXW, AXXX, 2, 0, 17, C, 0x0011, 0x5011 }, + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AILLEG, AXXX, 0, 0, 4, 0x4efc }, + { AINSTR }, + { AJMP, AXXX, 0, 0, 5, 0x4ec0 }, + { AJSR, AXXX, 0, 0, 5, 0x4e80 }, + { ALEA, AXXX, 0, 0, 6, 0x41c0 }, + { ALINKL }, + { ALINKW }, + { ALOCATE }, + { ALONG, AXXX, 0, 4, 23 }, + { ALSLB, AXXX, 0, 2, 12, 0xe108 }, + { ALSLL, AXXX, 0, 4, 12, 0xe188 }, + { ALSLW, AXXX, 0, 2, 12, 0xe148 }, + { ALSRB, AXXX, 0, 2, 12, 0xe008 }, + { ALSRL, AXXX, 0, 4, 12, 0xe088 }, + { ALSRW, AXXX, 0, 2, 12, 0xe048 }, + { AMOVB, AXXX, 2, -2, 2, 0x1000, 0x7000 }, + { AMOVEM, AXXX, 2, 2, 25, 0x48c0 }, + { AMOVEPL }, + { AMOVEPW }, + { AMOVESB }, + { AMOVESL }, + { AMOVESW, }, + { AMOVL, AXXX, 4, -4, 2, 0x2000, 0x7000 }, + { AMOVW, AXXX, 2, -2, 2, 0x3000, 0x7000 }, + { AMULSL, AXXX, 4, 0, 14, 0x4c00, 0x0800 }, + { AMULSW, AXXX, 2, 0, 13, 0xc1c0 }, + { AMULUL, AXXX, 4, 0, 14, 0x4c00, 0x0000 }, + { AMULUW, AXXX, 2, 0, 13, 0xc0c0 }, + { ANAME }, + { ANBCD }, + { ANEGB, AXXX, 0, 0, 5, 0x4400 }, + { ANEGL, AXXX, 0, 0, 5, 0x4480 }, + { ANEGW, AXXX, 0, 0, 5, 0x4440 }, + { ANEGXB }, + { ANEGXL }, + { ANEGXW }, + { ANOP }, + { ANOTB, AXXX, 0, 0, 5, 0x4600 }, + { ANOTL, AXXX, 0, 0, 5, 0x4680 }, + { ANOTW, AXXX, 0, 0, 5, 0x4640 }, + { AORB, AXXX, 2, 0, 9, 0x8000, 0x8100, 0x0000 }, + { AORL, AXXX, 4, 0, 9, 0x8080, 0x8180, 0x0080 }, + { AORW, AXXX, 2, 0, 9, 0x8040, 0x8140, 0x0040 }, + { APACK }, + { APEA, AXXX, 0, 0, 5, 0x4840 }, + { ARESET }, + { AROTLB, AXXX, 0, 2, 12, 0xe118 }, + { AROTLL, AXXX, 0, 4, 12, 0xe198 }, + { AROTLW, AXXX, 0, 2, 12, 0xe158 }, + { AROTRB, AXXX, 0, 2, 12, 0xe018 }, + { AROTRL, AXXX, 0, 4, 12, 0xe098 }, + { AROTRW, AXXX, 0, 2, 12, 0xe058 }, + { AROXLB }, + { AROXLL }, + { AROXLW }, + { AROXRB }, + { AROXRL }, + { AROXRW }, + { ARTD }, + { ARTE, AXXX, 0, 0, 4, 0x4e73 }, + { ARTM }, + { ARTR }, + { ARTS, AXXX, 0, 0, 4, 0x4e75 }, + { ASBCD }, + { ASCC }, + { ASCS }, + { ASEQ }, + { ASF }, + { ASGE }, + { ASGT }, + { ASHI }, + { ASLE }, + { ASLS }, + { ASLT }, + { ASMI }, + { ASNE }, + { ASPL }, + { AST }, + { ASTOP }, + { ASUBB, AXXX, 2, 0, 3, 0x9000, 0x5100, 0, 0x0400 }, + { ASUBL, AXXX, 4, 0, 3, 0x9080, 0x5180, 0x91c0, 0x0480 }, + { ASUBW, AXXX, 2, 0, 3, 0x9040, 0x5140, 0x90c0, 0x0440 }, + { ASUBXB }, + { ASUBXL }, + { ASUBXW }, + { ASVC }, + { ASVS }, + { ASWAP, AXXX, 0, 0, 35, 0x4840 }, + { ASYS, AXXX, 0, 2, 8, 0x4e40 }, + { ATAS, AXXX, 0, 2, 5, 0x4ac0 }, + { ATEXT }, + { ATRAP, AXXX, 0, 0, 30, 0x4e40 }, + { ATRAPCC }, + { ATRAPCS }, + { ATRAPEQ }, + { ATRAPF }, + { ATRAPGE }, + { ATRAPGT }, + { ATRAPHI }, + { ATRAPLE }, + { ATRAPLS }, + { ATRAPLT }, + { ATRAPMI }, + { ATRAPNE }, + { ATRAPPL }, + { ATRAPT }, + { ATRAPV }, + { ATRAPVC }, + { ATRAPVS }, + { ATSTB, AXXX, 0, 2, 5, 0x4a00 }, + { ATSTL, AXXX, 0, 4, 5, 0x4a80 }, + { ATSTW, AXXX, 0, 2, 5, 0x4a40 }, + { AUNLK }, + { AUNPK }, + { AWORD, AXXX, 0, 2, 23 }, + { AXXX } +}; + +char mmsize[] = +{ + /* 0 */ 0, 2, 2, 2, 2, + /* 5 */ 2, 2, 2, 4, 2, + /* 10 */ 2, 2, 2, 2, 4, + /* 15 */ 4, 4, 4, 4, 6, + /* 20 */ 4, 4, 4, 0, 4, + /* 25 */ 2, 2, 2, 2, 2, + /* 30 */ 2, 4, 4, 0, 4, + /* 35 */ 2, 0, 0, 0, 0, +}; diff --git a/utils/1l/pass.c b/utils/1l/pass.c new file mode 100644 index 00000000..9ab22626 --- /dev/null +++ b/utils/1l/pass.c @@ -0,0 +1,673 @@ +#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(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->from.displace; + 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("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || p->as != ABRA) + return p; + p = p->pcond; + } + return P; +} + +void +follow(void) +{ + Prog *p; + long o; + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + firstp = prg(); + lastp = firstp; + xfol(textp); + lastp->link = P; + firstp = firstp->link; + o = 0; /* set */ + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + + p->stkoff = -1; /* initialization for stkoff */ + if(p->as == ATEXT) { + p->stkoff = 0; + o = p->to.offset; + continue; + } + if(p->as == AADJSP && p->from.offset == 0) { + p->stkoff = o; + continue; + } + } +} + +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 == ABRA) + 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; + } + if(a == ABRA || a == ARTS || a == ARTE) + break; + if(q->pcond == P || q->pcond->mark) + continue; + if(a == ABSR || a == ADBF) + 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; + } + } /* */ + q = prg(); + q->as = ABRA; + 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 == ARTS || a == ABRA || a == ARTE) + return; + if(p->pcond != P) + if(a != ABSR) { + q = brchain(p->link); + if(q != P && q->mark) + if(a != ADBF) { + 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 ABEQ: return ABNE; + case ABNE: return ABEQ; + case ABLE: return ABGT; + case ABLS: return ABHI; + case ABLT: return ABGE; + case ABMI: return ABPL; + case ABGE: return ABLT; + case ABPL: return ABMI; + case ABGT: return ABLE; + case ABHI: return ABLS; + case ABCS: return ABCC; + case ABCC: return ABCS; + case AFBEQ: return AFBNE; + case AFBF: return AFBT; + case AFBGE: return AFBLT; + case AFBGT: return AFBLE; + case AFBLE: return AFBGT; + case AFBLT: return AFBGE; + case AFBNE: return AFBEQ; + case AFBT: return AFBF; + } + diag("unknown relation: %s in %s", anames[a], TNAME); + return a; +} + +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 == ABSR || p->as == ARTS) && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT) { + diag("undefined: %s in %s", s->name, TNAME); + s->type = STEXT; + s->value = vexit; + } + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH) + 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 = 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 != ABRA) + break; + c++; + if(c >= 5000) + return P; + } + return q; +} + +void +dostkoff(void) +{ + Prog *p, *q, *qq; + long s, t; + int a; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f stkoff\n", cputime()); + Bflush(&bso); + s = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + s = p->to.offset; + if(s == 0) + continue; + p = nprg(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = s; + p->stkoff = 0; + continue; + } + t = 0; + for(q = p; q != P; q = q->pcond) { + if(q->as == ATEXT) + break; + if(q->stkoff >= 0) + if(q->stkoff != s) + diag("stack offset %ld is %ld sb %ld in %s\n%P", + q->pc, q->stkoff, s, q, TNAME, p); + q->stkoff = s; + if(t++ > 100) { + diag("loop in stack offset 1: %P", p); + break; + } + } + o = &optab[p->as]; + if(p->to.type == D_TOS) + s -= o->dstsp; + if(p->from.type == D_TOS) + s -= o->srcsp; + if(p->as == AADJSP) + s += p->from.offset; + if(p->as == APEA) + s += 4; + t = 0; + for(q = p->link; q != P; q = q->pcond) { + if(q->as == ATEXT) { + q = P; + break; + } + if(q->stkoff >= 0) + break; + if(t++ > 100) { + diag("loop in stack offset 2: %P", p); + break; + } + } + if(q == P || q->stkoff == s) + continue; + if(p->as == ABRA || p->as == ARTS || p->as == ARTE) { + s = q->stkoff; + continue; + } + t = q->stkoff - s; + s = q->stkoff; + p = nprg(p); + p->as = AADJSP; + p->stkoff = s - t; + p->from.type = D_CONST; + p->from.offset = t; + } + + if(debug['v']) + Bprint(&bso, "%5.2f rewrite\n", cputime()); + Bflush(&bso); + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + a = p->from.type & D_MASK; + if(a == D_AUTO) + p->from.offset += p->stkoff; + if(a == D_PARAM) + p->from.offset += p->stkoff + 4; + a = p->to.type & D_MASK; + if(a == D_AUTO) + p->to.offset += p->stkoff; + if(a == D_PARAM) + p->to.offset += p->stkoff + 4; + switch(p->as) { + default: + continue; + + case AMOVW: + if(p->from.type != D_CCR) + continue; + a = p->to.type; + if((a < D_R0 || a > D_R0+7) && a != D_TOS) + diag("bad dest for MOVCC %P", p); + p->as = ALEA; + p->from.type = I_INDIR|(D_A0+7); + p->from.offset = -2; + p->to.type = D_A0+7; + + p = nprg(p); + p->as = ABSR; + p->to.type = D_BRANCH; + p->pcond = prog_ccr; + p->to.sym = prog_ccr->from.sym; + + if(a != D_TOS) { + p = nprg(p); + p->as = AMOVW; + p->from.type = D_TOS; + p->to.type = a; + } + continue; + + case AEXTBL: + a = p->to.type; + if(a < D_R0 || a > D_R0+7) + diag("bad dest for EXTB"); + p->as = AEXTBW; + + p = nprg(p); + p->as = AEXTWL; + p->to.type = a; + continue; + + case AMULSL: + case AMULUL: + qq = prog_mull; + goto mdcom; + case ADIVSL: + qq = prog_divsl; + goto mdcom; + case ADIVUL: + qq = prog_divul; + mdcom: + if(debug['m']) + continue; + a = p->to.type; + if(a < D_R0 || a > D_R0+7) + diag("bad dest for mul/div"); + p->as = AMOVL; + p->to.type = D_TOS; + + p = nprg(p); + p->as = AMOVL; + p->from.type = a; + p->to.type = D_TOS; + + p = nprg(p); + p->as = ABSR; + p->to.type = D_BRANCH; + p->pcond = qq; + p->to.sym = qq->from.sym; + + p = nprg(p); + p->as = AMOVL; + p->from.type = D_TOS; + p->to.type = a; + + p = nprg(p); + p->as = AMOVL; + p->from.type = D_TOS; + p->to.type = a+1; + if(qq == prog_mull) + p->to.type = a; + continue; + + case ARTS: + break; + } + if(p->stkoff == 0) + continue; + + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = -p->stkoff; + + p = nprg(p); + p->as = ARTS; + p->stkoff = 0; + } +} + +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 +initmuldiv1(void) +{ + lookup("_mull", 0)->type = SXREF; + lookup("_divsl", 0)->type = SXREF; + lookup("_divul", 0)->type = SXREF; + lookup("_ccr", 0)->type = SXREF; +} + +void +initmuldiv2(void) +{ + Sym *s1, *s2, *s3, *s4; + Prog *p; + + if(prog_mull != P) + return; + s1 = lookup("_mull", 0); + s2 = lookup("_divsl", 0); + s3 = lookup("_divul", 0); + s4 = lookup("_ccr", 0); + for(p = firstp; p != P; p = p->link) + if(p->as == ATEXT) { + if(p->from.sym == s1) + prog_mull = p; + if(p->from.sym == s2) + prog_divsl = p; + if(p->from.sym == s3) + prog_divul = p; + if(p->from.sym == s4) + prog_ccr = p; + } + if(prog_mull == P) { + diag("undefined: %s", s1->name); + prog_mull = curtext; + } + if(prog_divsl == P) { + diag("undefined: %s", s2->name); + prog_divsl = curtext; + } + if(prog_divul == P) { + diag("undefined: %s", s3->name); + prog_divul = curtext; + } + if(prog_ccr == P) { + diag("undefined: %s", s4->name); + prog_ccr = curtext; + } +} diff --git a/utils/1l/span.c b/utils/1l/span.c new file mode 100644 index 00000000..d8baa362 --- /dev/null +++ b/utils/1l/span.c @@ -0,0 +1,515 @@ +#include "l.h" + +void +span(void) +{ + Prog *p, *q; + long v, c, idat; + Optab *o; + int m, n; + + xdefine("etext", STEXT, 0L); + xdefine("a6base", STEXT, 0L); + idat = INITDAT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + n = 0; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_A0+7; + v = -p->from.offset; + p->from.offset = v; + if((v < -8 && v >= -32768L) || (v > 8 && v < 32768L)) { + p->as = ALEA; + p->from.type = I_INDIR | (D_A0+7); + continue; + } + p->as = AADDL; + if(v < 0) { + p->as = ASUBL; + v = -v; + p->from.offset = v; + } + if(v >= 0 && v <= 8) + p->from.type = D_QUICK; + 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; + o = &optab[p->as]; + p->pc = c; + m = mmsize[o->optype]; + if(m == 0) { + if(p->as == AWORD) + m = 2; + if(p->as == ALONG) + m = 4; + p->mark = m; + c += m; + continue; + } + if(p->from.type != D_NONE) + m += andsize(p, &p->from); + if(p->to.type == D_BRANCH) { + if(p->pcond == P) + p->pcond = p; + c += m; + if(m == 2) + m |= 0100; + p->mark = m; + continue; + } + if(p->to.type != D_NONE) + m += andsize(p, &p->to); + p->mark = m; + c += m; + } + +loop: + n++; + if(debug['v']) + Bprint(&bso, "%5.2f span %d\n", cputime(), n); + Bflush(&bso); + if(n > 60) { + diag("span must be looping"); + errorexit(); + } + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if((m = p->mark) & 0100) { + q = p->pcond; + v = q->pc - 2; + if(p->back) + v -= c; + else + v -= p->pc; + p->pc = c; + if(v < -32768L || v >= 32768L) { + c += 6; /* only jsr and jmp can do this */ + } else + if(v < -128 || v >= 128) + c += 4; + else + if(v == 0) { + c += 4; + p->mark = 4; + } else + c += 2; + continue; + } + p->pc = c; + c += m; + } + if(c != textsize) { + textsize = c; + goto loop; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(INITDAT != idat) { + idat = INITDAT; + goto start; + } + xdefine("etext", STEXT, c); + xdefine("a6base", STEXT, INITDAT+A6OFFSET); + 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; +} + +int +andsize(Prog *p, Adr *ap) +{ + int t, n; + long v; + Optab *o; + + t = ap->type; + n = simple[t]; + if(n != 0177) { + v = ap->offset; + if(v == 0) + return 0; + if((n&070) != 020) /* D_INDIR */ + return 0; + if(v == 0) + return 0; + return 2; + } + if((t&I_MASK) == I_ADDR) + t = D_CONST; + switch(t) { + + default: + return 0; + + case D_STACK: + case D_AUTO: + case D_PARAM: + v = ap->offset; + if(v == 0) + return 0; + return 2; + + case I_INDIR|D_CONST: + v = ap->offset; + if(v < -32768L || v >= 32768L) + return 4; + return 2; + + case D_STATIC: + case D_EXTERN: + if(ap->sym->type == STEXT) { + if(HEADTYPE == 4) + return 2; + return 4; + } + v = ap->sym->value + ap->offset - A6OFFSET; + if(v == 0) + return 0; + if(v < -32768L || v >= 32768L) + return 4; + return 2; + + case D_CONST: + case D_FCONST: + o = &optab[p->as]; + if(ap == &(p->from)) + return o->srcsp; + return o->dstsp; + + case D_CCR: + case D_SR: + if(p->as == AMOVW) + return 0; + return 2; + + case D_USP: + t = p->from.type; + if(t >= D_A0 && t <= D_A0+8) + return 0; + t = p->to.type; + if(t >= D_A0 && t <= D_A0+8) + return 0; + + case D_SFC: + case D_DFC: + case D_CACR: + case D_VBR: + case D_CAAR: + case D_MSP: + case D_ISP: + case D_FPCR: + case D_FPSR: + case D_FPIAR: + case D_TC: + case D_ITT0: + case D_ITT1: + case D_DTT0: + case D_DTT1: + case D_MMUSR: + case D_URP: + case D_SRP: + return 2; + } +} + +void +putsymb(Sym *s, int t, long v) +{ + int i, f; + char *n; + + n = s->name; + if(t == 'f') + n++; + lput(v); + if(s->version) + t += 'a' - 'A'; + CPUT(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + CPUT(n[0]); + for(i=1; n[i] != 0 || n[i+1] != 0; i += 2) { + CPUT(n[i]); + CPUT(n[i+1]); + } + CPUT(0); + CPUT(0); + i++; + } + else { + for(i=0; n[i]; i++) + CPUT(n[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; n[i] != 0 || n[i+1] != 0; i+=2) { + f = ((n[i]&0xff) << 8) | (n[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(s->version) + Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, n, s->version); + else + Bprint(&bso, "%c %.8lux %s\n", t, v, n); + } +} + +void +asmsym(void) +{ + Prog *p; + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + putsymb(s, 'T', s->value); + s = lookup("a6base", 0); + if(s->type == STEXT) + putsymb(s, 'D', s->value); + + for(h=0; h<NHASH; h++) + for(s=hash[h]; s!=S; s=s->link) + switch(s->type) { + case SDATA: + putsymb(s, 'D', s->value+INITDAT); + continue; + + case SBSS: + putsymb(s, 'B', s->value+INITDAT); + continue; + + case SFILE: + putsymb(s, 'f', s->value); + 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, 'z', a->aoffset); + else + if(a->type == D_FILE1) + putsymb(a->asym, 'Z', a->aoffset); + + putsymb(s, 'T', s->value); + + /* auto and param after */ + for(a=p->to.autom; a; a=a->link) + if(a->type == D_AUTO) + putsymb(a->asym, 'a', -a->aoffset); + else + if(a->type == D_PARAM) + putsymb(a->asym, 'p', a->aoffset); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %lud\n", symsize); + Bflush(&bso); +} + +#define MINLC 2 +void +asmsp(void) +{ + long oldpc, oldsp; + Prog *p; + int s; + long v; + + oldpc = INITTEXT; + oldsp = 0; + for(p = firstp; p != P; p = p->link) { + if(p->stkoff == oldsp || p->as == ATEXT || p->as == ANOP) { + if(p->as == ATEXT) + curtext = p; + if(debug['G']) + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + continue; + } + if(debug['G']) + Bprint(&bso, "\t\t%6ld", spsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + CPUT(s+128); /* 129-255 +pc */ + if(debug['G']) + Bprint(&bso, " pc+%d*2(%d)", s, s+128); + v -= s; + spsize++; + } + v = p->stkoff - oldsp; + oldsp = p->stkoff; + oldpc = p->pc + MINLC; + if(v & 3 || v > 64L*4L || v < -64L*4L) { + CPUT(0); /* 0 vvvv +sp */ + lput(v); + if(debug['G']) { + if(v > 0) + Bprint(&bso, " sp+%ld*1(%d,%ld)\n", + v, 0, v); + else + Bprint(&bso, " sp%ld*1(%d,%ld)\n", + v, 0, v); + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + } + spsize += 5; + continue; + } + s = v/4; + if(s > 0) { + CPUT(0+s); /* 1-64 +sp */ + if(debug['G']) { + Bprint(&bso, " sp+%d*4(%d)\n", s, 0+s); + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + } + } else { + CPUT(64-s); /* 65-128 -sp */ + if(debug['G']) { + Bprint(&bso, " sp%d*4(%d)\n", s, 64-s); + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + } + } + spsize++; + } + while(spsize & 1) { + s = 129; + CPUT(s); + spsize++; + } + if(debug['v'] || debug['G']) + Bprint(&bso, "stsize = %ld\n", spsize); + 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); +} diff --git a/utils/2a/a.h b/utils/2a/a.h new file mode 100644 index 00000000..7f9987b0 --- /dev/null +++ b/utils/2a/a.h @@ -0,0 +1,200 @@ +#include <lib9.h> +#include <bio.h> +#include "../2c/2.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 Addr Addr; +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 Addr +{ + Sym* sym; + long offset; + short type; +}; +struct Gen +{ + Addr s0; + double dval; + char sval[8]; + long displace; + short type; + short index; + short scale; + short field; +}; +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 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*); + +enum /* keep in synch with ../cc/cc.h */ +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2 +}; + +/* + * system-dependent stuff from ../cc/compat.c + */ +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); diff --git a/utils/2a/a.y b/utils/2a/a.y new file mode 100644 index 00000000..2a5d5c96 --- /dev/null +++ b/utils/2a/a.y @@ -0,0 +1,540 @@ +%{ +#include "a.h" +%} +%union { + Sym *sym; + long lval; + double dval; + char sval[8]; + Addr addr; + Gen gen; + Gen2 gen2; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 +%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA LTYPEB +%token <lval> LCONST LSP LSB LFP LPC LTOS LAREG LDREG LFREG LWID +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr scale type pointer reg offset +%type <addr> name areg xreg +%type <gen> gen rel +%type <gen2> noaddr gengen dstgen spec1 spec2 spec3 srcgen dstrel genrel +%% +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; + } +| LTYPE1 gengen { outcode($1, &$2); } +| LTYPE2 noaddr { outcode($1, &$2); } +| LTYPE3 dstgen { outcode($1, &$2); } +| LTYPE4 spec1 { outcode($1, &$2); } +| LTYPE5 srcgen { outcode($1, &$2); } +| LTYPE6 dstrel { outcode($1, &$2); } +| LTYPE7 genrel { outcode($1, &$2); } +| LTYPE8 dstgen { outcode($1, &$2); } +| LTYPE8 gengen { outcode($1, &$2); } +| LTYPE9 noaddr { outcode($1, &$2); } +| LTYPE9 dstgen { outcode($1, &$2); } +| LTYPEA spec2 { outcode($1, &$2); } +| LTYPEB spec3 { outcode($1, &$2); } + +noaddr: + { + $$.from = nullgen; + $$.to = nullgen; + } +| ',' + { + $$.from = nullgen; + $$.to = nullgen; + } + +srcgen: + gen + { + $$.from = $1; + $$.to = nullgen; + } +| gen ',' + { + $$.from = $1; + $$.to = nullgen; + } + +dstgen: + gen + { + $$.from = nullgen; + $$.to = $1; + } +| ',' gen + { + $$.from = nullgen; + $$.to = $2; + } + +gengen: + gen ',' gen + { + $$.from = $1; + $$.to = $3; + } + +dstrel: + rel + { + $$.from = nullgen; + $$.to = $1; + } +| ',' rel + { + $$.from = nullgen; + $$.to = $2; + } + +genrel: + gen ',' rel + { + $$.from = $1; + $$.to = $3; + } + +spec1: /* DATA opcode */ + gen '/' con ',' gen + { + $1.displace = $3; + $$.from = $1; + $$.to = $5; + } + +spec2: /* bit field opcodes */ + gen ',' gen ',' con ',' con + { + $1.field = $7; + $3.field = $5; + $$.from = $1; + $$.to = $3; + } + +spec3: /* TEXT opcode */ + gengen +| gen ',' con ',' gen + { + $1.displace = $3; + $$.from = $1; + $$.to = $5; + } + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.s0.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.s0.sym = $1; + $$.s0.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.s0.sym = $1; + $$.s0.offset = $1->value + $2; + } + +gen: + type + { + $$ = nullgen; + $$.type = $1; + } +| '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.s0.offset = $2; + } +| '$' name + { + $$ = nullgen; + { + Addr *a; + a = &$$.s0; + *a = $2; + } + if($2.type == D_AUTO || $2.type == D_PARAM) + yyerror("constant cannot be automatic: %s", + $2.sym->name); + $$.type = $2.type | I_ADDR; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } +| LTOS '+' con + { + $$ = nullgen; + $$.type = D_STACK; + $$.s0.offset = $3; + } +| LTOS '-' con + { + $$ = nullgen; + $$.type = D_STACK; + $$.s0.offset = -$3; + } +| con + { + $$ = nullgen; + $$.type = D_CONST | I_INDIR; + $$.s0.offset = $1; + } +| '-' '(' LAREG ')' + { + $$ = nullgen; + $$.type = $3 | I_INDDEC; + } +| '(' LAREG ')' '+' + { + $$ = nullgen; + $$.type = $2 | I_INDINC; + } +| areg + { + $$ = nullgen; + $$.type = $1.type; + { + Addr *a; + a = &$$.s0; + *a = $1; + } + if(($$.type & D_MASK) == D_NONE) { + $$.index = D_NONE | I_INDEX1; + $$.scale = 0; + $$.displace = 0; + } + } +| areg xreg + { + $$ = nullgen; + $$.type = $1.type; + { + Addr *a; + a = &$$.s0; + *a = $1; + } + $$.index = $2.type | I_INDEX1; + $$.scale = $2.offset; + } +| '(' areg ')' xreg + { + $$ = nullgen; + $$.type = $2.type; + { + Addr *a; + a = &$$.s0; + *a = $2; + } + $$.index = $4.type | I_INDEX2; + $$.scale = $4.offset; + $$.displace = 0; + } +| con '(' areg ')' xreg + { + $$ = nullgen; + $$.type = $3.type; + { + Addr *a; + a = &$$.s0; + *a = $3; + } + $$.index = $5.type | I_INDEX2; + $$.scale = $5.offset; + $$.displace = $1; + } +| '(' areg ')' + { + $$ = nullgen; + $$.type = $2.type; + { + Addr *a; + a = &$$.s0; + *a = $2; + } + $$.index = D_NONE | I_INDEX3; + $$.scale = 0; + $$.displace = 0; + } +| con '(' areg ')' + { + $$ = nullgen; + $$.type = $3.type; + { + Addr *a; + a = &$$.s0; + *a = $3; + } + $$.index = D_NONE | I_INDEX3; + $$.scale = 0; + $$.displace = $1; + } +| '(' areg xreg ')' + { + $$ = nullgen; + $$.type = $2.type; + { + Addr *a; + a = &$$.s0; + *a = $2; + } + $$.index = $3.type | I_INDEX3; + $$.scale = $3.offset; + $$.displace = 0; + } +| con '(' areg xreg ')' + { + $$ = nullgen; + $$.type = $3.type; + { + Addr *a; + a = &$$.s0; + *a = $3; + } + $$.index = $4.type | I_INDEX3; + $$.scale = $4.offset; + $$.displace = $1; + } + +type: + reg +| LFREG + +xreg: + /* + * .W*1 0 + * .W*2 1 + * .W*4 2 + * .W*8 3 + * .L*1 4 + * .L*2 5 + * .L*4 6 + * .L*8 7 + */ + '(' reg LWID scale ')' + { + $$.type = $2; + $$.offset = $3+$4; + $$.sym = S; + } + +reg: + LAREG +| LDREG +| LTOS + +scale: + '*' con + { + switch($2) { + case 1: + $$ = 0; + break; + + case 2: + $$ = 1; + break; + + default: + yyerror("bad scale: %ld", $2); + + case 4: + $$ = 2; + break; + + case 8: + $$ = 3; + break; + } + } + +areg: + '(' LAREG ')' + { + $$.type = $2 | I_INDIR; + $$.sym = S; + $$.offset = 0; + } +| con '(' LAREG ')' + { + $$.type = $3 | I_INDIR; + $$.sym = S; + $$.offset = $1; + } +| '(' ')' + { + $$.type = D_NONE | I_INDIR; + $$.sym = S; + $$.offset = 0; + } +| con '(' ')' + { + $$.type = D_NONE | I_INDIR; + $$.sym = S; + $$.offset = $1; + } +| name + +name: + LNAME offset '(' pointer ')' + { + $$.type = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$.type = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/2a/l.s b/utils/2a/l.s new file mode 100644 index 00000000..6f3cca3a --- /dev/null +++ b/utils/2a/l.s @@ -0,0 +1,479 @@ + +/* + * 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 8192 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 13 /* log(BY2PG) */ +#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) +#define ICACHESIZE 0 +#define MB4 (4*1024*1024) /* Lots of things are 4Mb in size */ + +#define MAXMACH 1 /* max # cpus system can run */ + +/* + * Time + */ +#define HZ (60) /* 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 */ + +/* + * SR bits + */ +#define SUPER 0x2000 +#define SPL(n) (n<<8) + +/* + * CACR + */ +#define CCLEAR 0x08 +#define CENABLE 0x01 + +/* + * Magic registers (unused in current system) + */ + +#define MACH A5 /* A5 is m-> */ +#define USER A4 /* A4 is u-> */ + +/* + * Fundamental addresses + */ + +#define USERADDR 0x80000000 +/* assuming we're in a syscall, this is the address of the Ureg structure */ +#define UREGVARSZ (23*BY2WD) /* size of variable part of Ureg */ +#define UREGADDR (USERADDR+BY2PG-(UREGVARSZ+2+4+2+(8+8+1+1)*BY2WD)) + +/* + * Devices poked during bootstrap + */ +#define TACADDR 0x40600000 +#define MOUSE 0x40200000 + +/* + * MMU + */ + +#define VAMASK 0xCFFFFFFF /* clear balu bits in address */ +#define KUSEG 0x00000000 +#define KSEG 0x80000000 + +/* + * MMU entries + */ +#define PTEVALID (1<<13) +#define PTEWRITE 0 +#define PTERONLY (1<<14) +#define PTEKERNEL (1<<15) +#define PTEUNCACHED 0 +#define INVALIDPTE 0 +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 16 + +#define PPN(pa) ((pa>>13)&0x1FFF) + +#define KMAP ((unsigned long *)0xD0000000) +#define UMAP ((unsigned long *)0x50000000) + +/* + * Virtual addresses + */ +#define VTAG(va) ((va>>22)&0x03F) +#define VPN(va) ((va>>13)&0x1FF) + +#define PARAM ((char*)0x40500000) +#define TLBFLUSH_ 0x01 + +/* + * Address spaces + */ + +#define UZERO KUSEG /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define TSTKTOP 0x10000000 /* end of new stack in sysexec */ +#define TSTKSIZ 100 +#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */ +#define KZERO KSEG /* base of kernel address space */ +#define KTZERO (KZERO+BY2PG) /* first address in kernel text */ +#define USTKSIZE (4*1024*1024) /* size of user stack */ + +#define MACHSIZE 4096 + + +#define isphys(p) ((((ulong)(p))&0xF0000000) == KSEG) +#define DBMAGIC 0xBADC0C0A + +/* + * Boot first processor + */ +TEXT start(SB), $-4 + + MOVW $(SUPER|SPL(7)), SR + MOVL $a6base(SB), A6 + MOVL $0, R0 + MOVL R0, CACR + MOVL R0, TACADDR /* zero tac counter (cause an intr?) */ + + MOVL $mach0(SB), A0 + MOVL A0, m(SB) + MOVL $0, 0(A0) + MOVL A0, A7 + ADDL $(MACHSIZE-4), A7 /* start stack under machine struct */ + MOVL $0, u(SB) + + MOVL $vectors(SB), A0 + MOVL A0, VBR + + BSR main(SB) + /* never returns */ +dead: + BRA dead + +/* + * Take first processor into user mode. Leave enough room on the stack + * for a full-sized Ureg (including long bus error format) to fit + */ + +TEXT touser(SB), $-4 + + MOVL $(USERADDR+BY2PG-UREGVARSZ), A7 + MOVW $0, -(A7) + MOVL $(UTZERO+32), -(A7) /* header is in text */ + MOVW $0, -(A7) + MOVL $(USTKTOP-6*BY2WD), A0 /* MAXSYSARG=6 */ + MOVL A0, USP + MOVW $(SUPER|SPL(0)), SR + MOVL $8, R0 + MOVL R0, CACR + RTE + +TEXT firmware(SB), $0 + + MOVL $0x40000090, A0 + JMP (A0) + +TEXT splhi(SB), $0 + + MOVL m(SB), A0 + MOVL (A7), 4(A0) + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(7)), SR + RTS + +TEXT splduart(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(5)), SR + RTS + +TEXT spllo(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(0)), SR + RTS + +TEXT splx(SB), $0 + + MOVL sr+0(FP), R0 + MOVW R0, SR + RTS + +TEXT spldone(SB), $0 + + RTS + +TEXT spl1(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(1)), SR + RTS + +TEXT flushcpucache(SB), $0 + + MOVL $(CCLEAR|CENABLE), R0 + MOVL R0, CACR + RTS + +TEXT cacrtrap(SB), $0 /* user entry point to control cache, e.g. flush */ + + MOVL R0, CACR + RTE + +TEXT setlabel(SB), $0 + + MOVL sr+0(FP), A0 + MOVL A7, (A0)+ /* stack pointer */ + MOVL (A7), (A0)+ /* pc of caller */ + MOVW SR, (A0)+ /* status register */ + CLRL R0 /* ret 0 => not returning */ + RTS + +TEXT gotolabel(SB), $0 + + MOVL p+0(FP), A0 + MOVW $(SUPER|SPL(7)), SR + MOVL (A0)+, A7 /* stack pointer */ + MOVL (A0)+, (A7) /* pc; stuff into stack frame */ + MOVW (A0)+, R0 /* status register */ + MOVW R0, SR + MOVL $1, R0 /* ret 1 => returning */ + RTS + +/* + * Test and set, as a subroutine + */ + +TEXT tas(SB), $0 + + MOVL $0, R0 + MOVL a+0(FP), A0 + TAS (A0) + BEQ tas_1 + MOVL $1, R0 +tas_1: + RTS + +/* + * Floating point + */ + +TEXT fpsave(SB), $0 + + FSAVE (fp+0(FP)) + RTS + +TEXT fprestore(SB), $0 + + FRESTORE (fp+0(FP)) + RTS + +TEXT fpregsave(SB), $0 + + FMOVEM $0xFF, (3*4)(fr+0(FP)) + FMOVEMC $0x7, (fr+0(FP)) + RTS + +TEXT fpregrestore(SB), $0 + + FMOVEMC (fr+0(FP)), $0x7 + FMOVEM (3*4)(fr+0(FP)), $0xFF + RTS + +TEXT fpcr(SB), $0 + + MOVL new+0(FP), R1 + MOVL FPCR, R0 + MOVL R1, FPCR + RTS + + +TEXT rfnote(SB), $0 + + MOVL uregp+0(FP), A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1+1)*BY2WD), A7 + RTE + +TEXT illegal(SB), $0 + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR trap(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1)*BY2WD+BY2WD), A7 + RTE + +TEXT systrap(SB), $0 + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVL A6, ((8+6)*BY2WD)(A7) + MOVL R0, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR syscall(SB) + MOVL ((1+8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVL ((1+8+6)*BY2WD)(A7), A6 + ADDL $((1+8+8+1)*BY2WD+BY2WD), A7 + RTE + +TEXT buserror(SB), $0 + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + PEA ((8+8+1+3)*BY2WD)(A7) + PEA 4(A7) + BSR fault68020(SB) + ADDL $8, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1)*BY2WD+BY2WD), A7 + RTE + +TEXT tacintr(SB), $0 /* level 1 */ + + MOVL R0, -(A7) + MOVL TACADDR, R0 + MOVL (A7)+, R0 + RTE + +TEXT portintr(SB), $0 /* level 2 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR devportintr(SB) + BRA retintr + +TEXT dkintr(SB), $0 /* level 3 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR inconintr(SB) + BRA retintr + +TEXT mouseintr(SB), $0 /* level 4 */ + + MOVEM $0x80C2, -(A7) /* D0, A0, A1, A6 */ + MOVL $a6base(SB), A6 + MOVL $15, R0 /* mask off hex switch */ + ANDB MOUSE,R0 /* clears quadrature interrupt */ + LEA mousetab(SB)(R0.W*8), A0 + LEA mouse(SB), A1 + MOVL (A0)+, R0 + ADDL R0, (A1)+ /* dx */ + MOVL (A0), R0 + ADDL R0, (A1)+ /* dy */ + ADDL $1, (A1) /* track */ + MOVEM (A7)+, $0x4301 + RTE + +TEXT uartintr(SB), $0 /* level 5 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR duartintr(SB) + BRA retintr + +TEXT syncintr(SB), $0 /* level 6 */ + + MOVL $DBMAGIC, -(A7) + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0x7FFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR clock(SB) + /* fall through */ +retintr: + BSR mousetry(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0x7FFF + ADDL $((8+8+1)*BY2WD+BY2WD), A7 + RTE + +GLOBL duarttimer+0(SB),$4 + +TEXT duartreadtimer+0(SB), $0 + MOVW SR, R1 /* spl7() */ + MOVW $0x2700, SR + MOVL $0x40100000, A0 + CLRL R0 + TSTB 15(A0) /* stop timer */ + MOVW 6(A0), R0 /* read hi,lo */ + TSTB 14(A0) /* restart timer */ + NOTW R0 /* timer counts down from 0xffff */ + ADDL duarttimer(SB), R0 + MOVL R0, duarttimer(SB) + MOVW R1, SR + RTS + +GLOBL mousetab(SB), $128 +DATA mousetab+ 0(SB)/4, -1 /* x down, */ +DATA mousetab+ 4(SB)/4, 1 /* y up */ +DATA mousetab+ 8(SB)/4, 0 /* x - */ +DATA mousetab+ 12(SB)/4, 1 /* y up */ +DATA mousetab+ 16(SB)/4, 1 /* x up */ +DATA mousetab+ 20(SB)/4, 1 /* y up */ +DATA mousetab+ 24(SB)/4, 0 /* x - */ +DATA mousetab+ 28(SB)/4, 1 /* y up */ +DATA mousetab+ 32(SB)/4, -1 /* x down */ +DATA mousetab+ 36(SB)/4, 0 /* y - */ +DATA mousetab+ 40(SB)/4, 0 /* x - */ +DATA mousetab+ 44(SB)/4, 0 /* y - */ +DATA mousetab+ 48(SB)/4, 1 /* x up, */ +DATA mousetab+ 52(SB)/4, 0 /* y - */ +DATA mousetab+ 56(SB)/4, 0 /* x - */ +DATA mousetab+ 60(SB)/4, 0 /* y - */ +DATA mousetab+ 64(SB)/4, -1 /* x down */ +DATA mousetab+ 68(SB)/4, -1 /* y down */ +DATA mousetab+ 72(SB)/4, 0 /* x - */ +DATA mousetab+ 76(SB)/4, -1 /* y down */ +DATA mousetab+ 80(SB)/4, 1 /* x up */ +DATA mousetab+ 84(SB)/4, -1 /* y down */ +DATA mousetab+ 88(SB)/4, 0 /* x - */ +DATA mousetab+ 92(SB)/4, -1 /* y down */ +DATA mousetab+ 96(SB)/4, -1 /* x down */ +DATA mousetab+100(SB)/4, 0 /* y - */ +DATA mousetab+104(SB)/4, 0 /* x - */ +DATA mousetab+108(SB)/4, 0 /* y - */ +DATA mousetab+112(SB)/4, 1 /* x up */ +DATA mousetab+116(SB)/4, 0 /* y - */ +DATA mousetab+120(SB)/4, 0 /* x - */ +DATA mousetab+124(SB)/4, 0 /* y - */ + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL u(SB), $4 +GLOBL m(SB), $4 diff --git a/utils/2a/lex.c b/utils/2a/lex.c new file mode 100644 index 00000000..93ba0e2a --- /dev/null +++ b/utils/2a/lex.c @@ -0,0 +1,935 @@ +#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 = '2'; + thestring = "68020"; + 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, + "TOS", LTOS, D_TOS, + "CCR", LTOS, D_CCR, + "SR", LTOS, D_SR, + "SFC", LTOS, D_SFC, + "DFC", LTOS, D_DFC, + "CACR", LTOS, D_CACR, + "USP", LTOS, D_USP, + "VBR", LTOS, D_VBR, + "CAAR", LTOS, D_CAAR, + "MSP", LTOS, D_MSP, + "ISP", LTOS, D_ISP, + "FPCR", LTOS, D_FPCR, + "FPSR", LTOS, D_FPSR, + "FPIAR", LTOS, D_FPIAR, + "TC", LTOS, D_TC, + "ITT0", LTOS, D_ITT0, + "ITT1", LTOS, D_ITT1, + "DTT0", LTOS, D_DTT0, + "DTT1", LTOS, D_DTT1, + "MMUSR", LTOS, D_MMUSR, + "URP", LTOS, D_URP, + "SRP", LTOS, D_SRP, + + "R0", LDREG, D_R0+0, + "R1", LDREG, D_R0+1, + "R2", LDREG, D_R0+2, + "R3", LDREG, D_R0+3, + "R4", LDREG, D_R0+4, + "R5", LDREG, D_R0+5, + "R6", LDREG, D_R0+6, + "R7", LDREG, D_R0+7, + + ".W", LWID, 0, + ".L", LWID, 4, + + "A0", LAREG, D_A0+0, + "A1", LAREG, D_A0+1, + "A2", LAREG, D_A0+2, + "A3", LAREG, D_A0+3, + "A4", LAREG, D_A0+4, + "A5", LAREG, D_A0+5, + "A6", LAREG, D_A0+6, + "A7", LAREG, D_A0+7, + + "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, + + "ABCD", LTYPE1, AABCD, + "ADDB", LTYPE1, AADDB, + "ADDL", LTYPE1, AADDL, + "ADDW", LTYPE1, AADDW, + "ADDXB", LTYPE1, AADDXB, + "ADDXL", LTYPE1, AADDXL, + "ADDXW", LTYPE1, AADDXW, + "ADJSP", LTYPE5, AADJSP, + "ANDB", LTYPE1, AANDB, + "ANDL", LTYPE1, AANDL, + "ANDW", LTYPE1, AANDW, + "ASLB", LTYPE1, AASLB, + "ASLL", LTYPE1, AASLL, + "ASLW", LTYPE1, AASLW, + "ASRB", LTYPE1, AASRB, + "ASRL", LTYPE1, AASRL, + "ASRW", LTYPE1, AASRW, + "BCASE", LTYPE7, ABCASE, + "BCC", LTYPE6, ABCC, + "BCHG", LTYPE1, ABCHG, + "BCLR", LTYPE1, ABCLR, + "BCS", LTYPE6, ABCS, + "BEQ", LTYPE6, ABEQ, + "BFCHG", LTYPEA, ABFCHG, + "BFCLR", LTYPEA, ABFCLR, + "BFEXTS", LTYPEA, ABFEXTS, + "BFEXTU", LTYPEA, ABFEXTU, + "BFFFO", LTYPEA, ABFFFO, + "BFINS", LTYPEA, ABFINS, + "BFSET", LTYPEA, ABFSET, + "BFTST", LTYPEA, ABFTST, + "BGE", LTYPE6, ABGE, + "BGT", LTYPE6, ABGT, + "BHI", LTYPE6, ABHI, + "BKPT", LTYPE1, ABKPT, + "BLE", LTYPE6, ABLE, + "BLS", LTYPE6, ABLS, + "BLT", LTYPE6, ABLT, + "BMI", LTYPE6, ABMI, + "BNE", LTYPE6, ABNE, + "BPL", LTYPE6, ABPL, + "BRA", LTYPE6, ABRA, + "BSET", LTYPE1, ABSET, + "BSR", LTYPE3, ABSR, + "BTST", LTYPE1, ABTST, + "BVC", LTYPE6, ABVC, + "BVS", LTYPE6, ABVS, + "CALLM", LTYPE1, ACALLM, + "CAS2B", LTYPE1, ACAS2B, + "CAS2L", LTYPE1, ACAS2L, + "CAS2W", LTYPE1, ACAS2W, + "CASB", LTYPE1, ACASB, + "CASEW", LTYPE2, ACASEW, + "CASL", LTYPE1, ACASL, + "CASW", LTYPE1, ACASW, + "CHK2B", LTYPE1, ACHK2B, + "CHK2L", LTYPE1, ACHK2L, + "CHK2W", LTYPE1, ACHK2W, + "CHKL", LTYPE1, ACHKL, + "CHKW", LTYPE1, ACHKW, + "CLRB", LTYPE3, ACLRB, + "CLRL", LTYPE3, ACLRL, + "CLRW", LTYPE3, ACLRW, + "CMP2B", LTYPE1, ACMP2B, + "CMP2L", LTYPE1, ACMP2L, + "CMP2W", LTYPE1, ACMP2W, + "CMPB", LTYPE1, ACMPB, + "CMPL", LTYPE1, ACMPL, + "CMPW", LTYPE1, ACMPW, + "DATA", LTYPE4, ADATA, + "DBCC", LTYPE7, ADBCC, + "DBCS", LTYPE7, ADBCS, + "DBEQ", LTYPE7, ADBEQ, + "DBF", LTYPE7, ADBF, + "DBGE", LTYPE7, ADBGE, + "DBGT", LTYPE7, ADBGT, + "DBHI", LTYPE7, ADBHI, + "DBLE", LTYPE7, ADBLE, + "DBLS", LTYPE7, ADBLS, + "DBLT", LTYPE7, ADBLT, + "DBMI", LTYPE7, ADBMI, + "DBNE", LTYPE7, ADBNE, + "DBPL", LTYPE7, ADBPL, + "DBT", LTYPE7, ADBT, + "DBVC", LTYPE7, ADBVC, + "DBVS", LTYPE7, ADBVS, + "DIVSL", LTYPE1, ADIVSL, + "DIVSW", LTYPE1, ADIVSW, + "DIVUL", LTYPE1, ADIVUL, + "DIVUW", LTYPE1, ADIVUW, + "END", LTYPE2, AEND, + "EORB", LTYPE1, AEORB, + "EORL", LTYPE1, AEORL, + "EORW", LTYPE1, AEORW, + "EXG", LTYPE1, AEXG, + "EXTBL", LTYPE3, AEXTBL, + "EXTBW", LTYPE3, AEXTBW, + "EXTWL", LTYPE3, AEXTWL, + "FABSB", LTYPE1, AFABSB, + "FABSD", LTYPE1, AFABSD, + "FABSF", LTYPE1, AFABSF, + "FABSL", LTYPE1, AFABSL, + "FABSW", LTYPE1, AFABSW, + "FACOSB", LTYPE1, AFACOSB, + "FACOSD", LTYPE1, AFACOSD, + "FACOSF", LTYPE1, AFACOSF, + "FACOSL", LTYPE1, AFACOSL, + "FACOSW", LTYPE1, AFACOSW, + "FADDB", LTYPE1, AFADDB, + "FADDD", LTYPE1, AFADDD, + "FADDF", LTYPE1, AFADDF, + "FADDL", LTYPE1, AFADDL, + "FADDW", LTYPE1, AFADDW, + "FASINB", LTYPE1, AFASINB, + "FASIND", LTYPE1, AFASIND, + "FASINF", LTYPE1, AFASINF, + "FASINL", LTYPE1, AFASINL, + "FASINW", LTYPE1, AFASINW, + "FATANB", LTYPE1, AFATANB, + "FATAND", LTYPE1, AFATAND, + "FATANF", LTYPE1, AFATANF, + "FATANHB", LTYPE1, AFATANHB, + "FATANHD", LTYPE1, AFATANHD, + "FATANHF", LTYPE1, AFATANHF, + "FATANHL", LTYPE1, AFATANHL, + "FATANHW", LTYPE1, AFATANHW, + "FATANL", LTYPE1, AFATANL, + "FATANW", LTYPE1, AFATANW, + "FBEQ", LTYPE6, AFBEQ, + "FBF", LTYPE6, AFBF, + "FBGE", LTYPE6, AFBGE, + "FBGT", LTYPE6, AFBGT, + "FBLE", LTYPE6, AFBLE, + "FBLT", LTYPE6, AFBLT, + "FBNE", LTYPE6, AFBNE, + "FBT", LTYPE6, AFBT, + "FCMPB", LTYPE1, AFCMPB, + "FCMPD", LTYPE1, AFCMPD, + "FCMPF", LTYPE1, AFCMPF, + "FCMPL", LTYPE1, AFCMPL, + "FCMPW", LTYPE1, AFCMPW, + "FCOSB", LTYPE1, AFCOSB, + "FCOSD", LTYPE1, AFCOSD, + "FCOSF", LTYPE1, AFCOSF, + "FCOSHB", LTYPE1, AFCOSHB, + "FCOSHD", LTYPE1, AFCOSHD, + "FCOSHF", LTYPE1, AFCOSHF, + "FCOSHL", LTYPE1, AFCOSHL, + "FCOSHW", LTYPE1, AFCOSHW, + "FCOSL", LTYPE1, AFCOSL, + "FCOSW", LTYPE1, AFCOSW, + "FDBEQ", LTYPE7, AFDBEQ, + "FDBF", LTYPE7, AFDBF, + "FDBGE", LTYPE7, AFDBGE, + "FDBGT", LTYPE7, AFDBGT, + "FDBLE", LTYPE7, AFDBLE, + "FDBLT", LTYPE7, AFDBLT, + "FDBNE", LTYPE7, AFDBNE, + "FDBT", LTYPE7, AFDBT, + "FDIVB", LTYPE1, AFDIVB, + "FDIVD", LTYPE1, AFDIVD, + "FDIVF", LTYPE1, AFDIVF, + "FDIVL", LTYPE1, AFDIVL, + "FDIVW", LTYPE1, AFDIVW, + "FETOXB", LTYPE1, AFETOXB, + "FETOXD", LTYPE1, AFETOXD, + "FETOXF", LTYPE1, AFETOXF, + "FETOXL", LTYPE1, AFETOXL, + "FETOXM1B", LTYPE1, AFETOXM1B, + "FETOXM1D", LTYPE1, AFETOXM1D, + "FETOXM1F", LTYPE1, AFETOXM1F, + "FETOXM1L", LTYPE1, AFETOXM1L, + "FETOXM1W", LTYPE1, AFETOXM1W, + "FETOXW", LTYPE1, AFETOXW, + "FGETEXPB", LTYPE1, AFGETEXPB, + "FGETEXPD", LTYPE1, AFGETEXPD, + "FGETEXPF", LTYPE1, AFGETEXPF, + "FGETEXPL", LTYPE1, AFGETEXPL, + "FGETEXPW", LTYPE1, AFGETEXPW, + "FGETMANB", LTYPE1, AFGETMANB, + "FGETMAND", LTYPE1, AFGETMAND, + "FGETMANF", LTYPE1, AFGETMANF, + "FGETMANL", LTYPE1, AFGETMANL, + "FGETMANW", LTYPE1, AFGETMANW, + "FINTB", LTYPE1, AFINTB, + "FINTD", LTYPE1, AFINTD, + "FINTF", LTYPE1, AFINTF, + "FINTL", LTYPE1, AFINTL, + "FINTRZB", LTYPE1, AFINTRZB, + "FINTRZD", LTYPE1, AFINTRZD, + "FINTRZF", LTYPE1, AFINTRZF, + "FINTRZL", LTYPE1, AFINTRZL, + "FINTRZW", LTYPE1, AFINTRZW, + "FINTW", LTYPE1, AFINTW, + "FLOG10B", LTYPE1, AFLOG10B, + "FLOG10D", LTYPE1, AFLOG10D, + "FLOG10F", LTYPE1, AFLOG10F, + "FLOG10L", LTYPE1, AFLOG10L, + "FLOG10W", LTYPE1, AFLOG10W, + "FLOG2B", LTYPE1, AFLOG2B, + "FLOG2D", LTYPE1, AFLOG2D, + "FLOG2F", LTYPE1, AFLOG2F, + "FLOG2L", LTYPE1, AFLOG2L, + "FLOG2W", LTYPE1, AFLOG2W, + "FLOGNB", LTYPE1, AFLOGNB, + "FLOGND", LTYPE1, AFLOGND, + "FLOGNF", LTYPE1, AFLOGNF, + "FLOGNL", LTYPE1, AFLOGNL, + "FLOGNP1B", LTYPE1, AFLOGNP1B, + "FLOGNP1D", LTYPE1, AFLOGNP1D, + "FLOGNP1F", LTYPE1, AFLOGNP1F, + "FLOGNP1L", LTYPE1, AFLOGNP1L, + "FLOGNP1W", LTYPE1, AFLOGNP1W, + "FLOGNW", LTYPE1, AFLOGNW, + "FMODB", LTYPE1, AFMODB, + "FMODD", LTYPE1, AFMODD, + "FMODF", LTYPE1, AFMODF, + "FMODL", LTYPE1, AFMODL, + "FMODW", LTYPE1, AFMODW, + "FMOVEB", LTYPE1, AFMOVEB, + "FMOVED", LTYPE1, AFMOVED, + "FMOVEF", LTYPE1, AFMOVEF, + "FMOVEL", LTYPE1, AFMOVEL, + "FMOVEW", LTYPE1, AFMOVEW, + "FMULB", LTYPE1, AFMULB, + "FMULD", LTYPE1, AFMULD, + "FMULF", LTYPE1, AFMULF, + "FMULL", LTYPE1, AFMULL, + "FMULW", LTYPE1, AFMULW, + "FNEGB", LTYPE8, AFNEGB, + "FNEGD", LTYPE8, AFNEGD, + "FNEGF", LTYPE8, AFNEGF, + "FNEGL", LTYPE8, AFNEGL, + "FNEGW", LTYPE8, AFNEGW, + "FREMB", LTYPE1, AFREMB, + "FREMD", LTYPE1, AFREMD, + "FREMF", LTYPE1, AFREMF, + "FREML", LTYPE1, AFREML, + "FREMW", LTYPE1, AFREMW, + "FSCALEB", LTYPE1, AFSCALEB, + "FSCALED", LTYPE1, AFSCALED, + "FSCALEF", LTYPE1, AFSCALEF, + "FSCALEL", LTYPE1, AFSCALEL, + "FSCALEW", LTYPE1, AFSCALEW, + "FSEQ", LTYPE1, AFSEQ, + "FSF", LTYPE1, AFSF, + "FSGE", LTYPE1, AFSGE, + "FSGT", LTYPE1, AFSGT, + "FSINB", LTYPE1, AFSINB, + "FSIND", LTYPE1, AFSIND, + "FSINF", LTYPE1, AFSINF, + "FSINHB", LTYPE1, AFSINHB, + "FSINHD", LTYPE1, AFSINHD, + "FSINHF", LTYPE1, AFSINHF, + "FSINHL", LTYPE1, AFSINHL, + "FSINHW", LTYPE1, AFSINHW, + "FSINL", LTYPE1, AFSINL, + "FSINW", LTYPE1, AFSINW, + "FSLE", LTYPE1, AFSLE, + "FSLT", LTYPE1, AFSLT, + "FSNE", LTYPE1, AFSNE, + "FSQRTB", LTYPE1, AFSQRTB, + "FSQRTD", LTYPE1, AFSQRTD, + "FSQRTF", LTYPE1, AFSQRTF, + "FSQRTL", LTYPE1, AFSQRTL, + "FSQRTW", LTYPE1, AFSQRTW, + "FST", LTYPE1, AFST, + "FSUBB", LTYPE1, AFSUBB, + "FSUBD", LTYPE1, AFSUBD, + "FSUBF", LTYPE1, AFSUBF, + "FSUBL", LTYPE1, AFSUBL, + "FSUBW", LTYPE1, AFSUBW, + "FTANB", LTYPE1, AFTANB, + "FTAND", LTYPE1, AFTAND, + "FTANF", LTYPE1, AFTANF, + "FTANHB", LTYPE1, AFTANHB, + "FTANHD", LTYPE1, AFTANHD, + "FTANHF", LTYPE1, AFTANHF, + "FTANHL", LTYPE1, AFTANHL, + "FTANHW", LTYPE1, AFTANHW, + "FTANL", LTYPE1, AFTANL, + "FTANW", LTYPE1, AFTANW, + "FTENTOXB", LTYPE1, AFTENTOXB, + "FTENTOXD", LTYPE1, AFTENTOXD, + "FTENTOXF", LTYPE1, AFTENTOXF, + "FTENTOXL", LTYPE1, AFTENTOXL, + "FTENTOXW", LTYPE1, AFTENTOXW, + "FTSTB", LTYPE1, AFTSTB, + "FTSTD", LTYPE1, AFTSTD, + "FTSTF", LTYPE1, AFTSTF, + "FTSTL", LTYPE1, AFTSTL, + "FTSTW", LTYPE1, AFTSTW, + "FTWOTOXB", LTYPE1, AFTWOTOXB, + "FTWOTOXD", LTYPE1, AFTWOTOXD, + "FTWOTOXF", LTYPE1, AFTWOTOXF, + "FTWOTOXL", LTYPE1, AFTWOTOXL, + "FTWOTOXW", LTYPE1, AFTWOTOXW, + "FMOVEM", LTYPE1, AFMOVEM, + "FMOVEMC", LTYPE1, AFMOVEMC, + "FRESTORE", LTYPE3, AFRESTORE, + "FSAVE", LTYPE3, AFSAVE, + "GLOBL", LTYPE1, AGLOBL, + "GOK", LTYPE2, AGOK, + "HISTORY", LTYPE2, AHISTORY, + "ILLEG", LTYPE2, AILLEG, + "INSTR", LTYPE3, AINSTR, + "JMP", LTYPE3, AJMP, + "JSR", LTYPE3, AJSR, + "LEA", LTYPE1, ALEA, + "LINKL", LTYPE1, ALINKL, + "LINKW", LTYPE1, ALINKW, + "LOCATE", LTYPE1, ALOCATE, + "LONG", LTYPE3, ALONG, + "LSLB", LTYPE1, ALSLB, + "LSLL", LTYPE1, ALSLL, + "LSLW", LTYPE1, ALSLW, + "LSRB", LTYPE1, ALSRB, + "LSRL", LTYPE1, ALSRL, + "LSRW", LTYPE1, ALSRW, + "MOVB", LTYPE1, AMOVB, + "MOVEM", LTYPE1, AMOVEM, + "MOVEPL", LTYPE1, AMOVEPL, + "MOVEPW", LTYPE1, AMOVEPW, + "MOVESB", LTYPE1, AMOVESB, + "MOVESL", LTYPE1, AMOVESL, + "MOVESW", LTYPE1, AMOVESW, + "MOVL", LTYPE1, AMOVL, + "MOVW", LTYPE1, AMOVW, + "MULSL", LTYPE1, AMULSL, + "MULSW", LTYPE1, AMULSW, + "MULUL", LTYPE1, AMULUL, + "MULUW", LTYPE1, AMULUW, + "NAME", LTYPE1, ANAME, + "NBCD", LTYPE3, ANBCD, + "NEGB", LTYPE3, ANEGB, + "NEGL", LTYPE3, ANEGL, + "NEGW", LTYPE3, ANEGW, + "NEGXB", LTYPE3, ANEGXB, + "NEGXL", LTYPE3, ANEGXL, + "NEGXW", LTYPE3, ANEGXW, + "NOP", LTYPE9, ANOP, + "NOTB", LTYPE3, ANOTB, + "NOTL", LTYPE3, ANOTL, + "NOTW", LTYPE3, ANOTW, + "ORB", LTYPE1, AORB, + "ORL", LTYPE1, AORL, + "ORW", LTYPE1, AORW, + "PACK", LTYPE1, APACK, + "PEA", LTYPE3, APEA, + "RESET", LTYPE2, ARESET, + "ROTLB", LTYPE1, AROTLB, + "ROTLL", LTYPE1, AROTLL, + "ROTLW", LTYPE1, AROTLW, + "ROTRB", LTYPE1, AROTRB, + "ROTRL", LTYPE1, AROTRL, + "ROTRW", LTYPE1, AROTRW, + "ROXLB", LTYPE1, AROXLB, + "ROXLL", LTYPE1, AROXLL, + "ROXLW", LTYPE1, AROXLW, + "ROXRB", LTYPE1, AROXRB, + "ROXRL", LTYPE1, AROXRL, + "ROXRW", LTYPE1, AROXRW, + "RTD", LTYPE3, ARTD, + "RTE", LTYPE2, ARTE, + "RTM", LTYPE3, ARTM, + "RTR", LTYPE2, ARTR, + "RTS", LTYPE2, ARTS, + "SBCD", LTYPE1, ASBCD, + "SCC", LTYPE3, ASCC, + "SCS", LTYPE3, ASCS, + "SEQ", LTYPE3, ASEQ, + "SF", LTYPE3, ASF, + "SGE", LTYPE3, ASGE, + "SGT", LTYPE3, ASGT, + "SHI", LTYPE3, ASHI, + "SLE", LTYPE3, ASLE, + "SLS", LTYPE3, ASLS, + "SLT", LTYPE3, ASLT, + "SMI", LTYPE3, ASMI, + "SNE", LTYPE3, ASNE, + "SPL", LTYPE3, ASPL, + "ST", LTYPE3, AST, + "STOP", LTYPE3, ASTOP, + "SUBB", LTYPE1, ASUBB, + "SUBL", LTYPE1, ASUBL, + "SUBW", LTYPE1, ASUBW, + "SUBXB", LTYPE1, ASUBXB, + "SUBXL", LTYPE1, ASUBXL, + "SUBXW", LTYPE1, ASUBXW, + "SVC", LTYPE2, ASVC, + "SVS", LTYPE2, ASVS, + "SWAP", LTYPE3, ASWAP, + "SYS", LTYPE2, ASYS, + "TAS", LTYPE3, ATAS, + "TEXT", LTYPEB, ATEXT, + "TRAP", LTYPE3, ATRAP, + "TRAPCC", LTYPE2, ATRAPCC, + "TRAPCS", LTYPE2, ATRAPCS, + "TRAPEQ", LTYPE2, ATRAPEQ, + "TRAPF", LTYPE2, ATRAPF, + "TRAPGE", LTYPE2, ATRAPGE, + "TRAPGT", LTYPE2, ATRAPGT, + "TRAPHI", LTYPE2, ATRAPHI, + "TRAPLE", LTYPE2, ATRAPLE, + "TRAPLS", LTYPE2, ATRAPLS, + "TRAPLT", LTYPE2, ATRAPLT, + "TRAPMI", LTYPE2, ATRAPMI, + "TRAPNE", LTYPE2, ATRAPNE, + "TRAPPL", LTYPE2, ATRAPPL, + "TRAPT", LTYPE2, ATRAPT, + "TRAPV", LTYPE2, ATRAPV, + "TRAPVC", LTYPE2, ATRAPVC, + "TRAPVS", LTYPE2, ATRAPVS, + "TSTB", LTYPE3, ATSTB, + "TSTL", LTYPE3, ATSTL, + "TSTW", LTYPE3, ATSTW, + "UNLK", LTYPE3, AUNLK, + "UNPK", LTYPE1, AUNPK, + "WORD", LTYPE3, AWORD, + + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.s0.sym = S; + nullgen.s0.offset = 0; + nullgen.type = D_NONE; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 0; + nullgen.displace = 0; + nullgen.type = D_NONE; + nullgen.index = D_NONE; + nullgen.scale = 0; + nullgen.field = 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); + 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 +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 */ + 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->field) + t |= T_FIELD; + if(a->index != D_NONE || a->displace != 0) + t |= T_INDEX; + if(a->s0.offset != 0) + t |= T_OFFSET; + if(s != 0) + t |= T_SYM; + + if(a->type == D_FCONST) + t |= T_FCONST; + else + if(a->type == D_SCONST) + t |= T_SCONST; + else + if(a->type & ~0xff) + t |= T_TYPE; + Bputc(&obuf, t); + + if(t & T_FIELD) { /* implies field */ + i = a->field; + Bputc(&obuf, i); + Bputc(&obuf, i>>8); + } + if(t & T_INDEX) { /* implies index, scale, displace */ + i = a->index; + Bputc(&obuf, i); + Bputc(&obuf, i>>8); + Bputc(&obuf, a->scale); + l = a->displace; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->s0.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; + } + i = a->type; + Bputc(&obuf, i); + if(t & T_TYPE) + Bputc(&obuf, i>>8); +} + +void +outcode(int a, Gen2 *g2) +{ + int sf, st, t; + Sym *s; + + if(pass == 1) + goto out; + +jackpot: + sf = 0; + s = g2->from.s0.sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g2->from.type & D_MASK; + 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.s0.sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->to.type & D_MASK; + 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.s0.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" diff --git a/utils/2a/mkfile b/utils/2a/mkfile new file mode 100644 index 00000000..2cf27e17 --- /dev/null +++ b/utils/2a/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=2a + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../2c/2.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/2c/2.out.h b/utils/2c/2.out.h new file mode 100644 index 00000000..0cf36f82 --- /dev/null +++ b/utils/2c/2.out.h @@ -0,0 +1,523 @@ +#define NSYM 50 +#define NSNAME 8 + +/* R0 is return */ +#define REGEXT 7 +/* A7 is sp A6 is sb */ +#define AREGEXT 5 +/* F0 is ret */ +#define FREGEXT 7 + +enum as +{ + AXXX = 0, + AABCD, + AADDB, + AADDL, + AADDW, + AADDXB, + AADDXL, + AADDXW, + AADJSP, + AANDB, + AANDL, + AANDW, + AASLB, + AASLL, + AASLW, + AASRB, + AASRL, + AASRW, + ABCASE, + ABCC, + ABCHG, + ABCLR, + ABCS, + ABEQ, + ABFCHG, + ABFCLR, + ABFEXTS, + ABFEXTU, + ABFFFO, + ABFINS, + ABFSET, + ABFTST, + ABGE, + ABGT, + ABHI, + ABKPT, + ABLE, + ABLS, + ABLT, + ABMI, + ABNE, + ABPL, + ABRA, + ABSET, + ABSR, + ABTST, + ABVC, + ABVS, + ACALLM, + ACAS2B, + ACAS2L, + ACAS2W, + ACASB, + ACASEW, + ACASL, + ACASW, + ACHK2B, + ACHK2L, + ACHK2W, + ACHKL, + ACHKW, + ACLRB, + ACLRL, + ACLRW, + ACMP2B, + ACMP2L, + ACMP2W, + ACMPB, + ACMPL, + ACMPW, + ADATA, + ADBCC, + ADBCS, + ADBEQ, + ADBF, + ADBGE, + ADBGT, + ADBHI, + ADBLE, + ADBLS, + ADBLT, + ADBMI, + ADBNE, + ADBPL, + ADBT, + ADBVC, + ADBVS, + ADIVSL, + ADIVSW, + ADIVUL, + ADIVUW, + AEND, + AEORB, + AEORL, + AEORW, + AEXG, + AEXTBL, + AEXTBW, + AEXTWL, + AFABSB, + AFABSD, + AFABSF, + AFABSL, + AFABSW, + AFACOSB, + AFACOSD, + AFACOSF, + AFACOSL, + AFACOSW, + AFADDB, + AFADDD, + AFADDF, + AFADDL, + AFADDW, + AFASINB, + AFASIND, + AFASINF, + AFASINL, + AFASINW, + AFATANB, + AFATAND, + AFATANF, + AFATANHB, + AFATANHD, + AFATANHF, + AFATANHL, + AFATANHW, + AFATANL, + AFATANW, + AFBEQ, + AFBF, + AFBGE, + AFBGT, + AFBLE, + AFBLT, + AFBNE, + AFBT, + AFCMPB, + AFCMPD, + AFCMPF, + AFCMPL, + AFCMPW, + AFCOSB, + AFCOSD, + AFCOSF, + AFCOSHB, + AFCOSHD, + AFCOSHF, + AFCOSHL, + AFCOSHW, + AFCOSL, + AFCOSW, + AFDBEQ, + AFDBF, + AFDBGE, + AFDBGT, + AFDBLE, + AFDBLT, + AFDBNE, + AFDBT, + AFDIVB, + AFDIVD, + AFDIVF, + AFDIVL, + AFDIVW, + AFETOXB, + AFETOXD, + AFETOXF, + AFETOXL, + AFETOXM1B, + AFETOXM1D, + AFETOXM1F, + AFETOXM1L, + AFETOXM1W, + AFETOXW, + AFGETEXPB, + AFGETEXPD, + AFGETEXPF, + AFGETEXPL, + AFGETEXPW, + AFGETMANB, + AFGETMAND, + AFGETMANF, + AFGETMANL, + AFGETMANW, + AFINTB, + AFINTD, + AFINTF, + AFINTL, + AFINTRZB, + AFINTRZD, + AFINTRZF, + AFINTRZL, + AFINTRZW, + AFINTW, + AFLOG10B, + AFLOG10D, + AFLOG10F, + AFLOG10L, + AFLOG10W, + AFLOG2B, + AFLOG2D, + AFLOG2F, + AFLOG2L, + AFLOG2W, + AFLOGNB, + AFLOGND, + AFLOGNF, + AFLOGNL, + AFLOGNP1B, + AFLOGNP1D, + AFLOGNP1F, + AFLOGNP1L, + AFLOGNP1W, + AFLOGNW, + AFMODB, + AFMODD, + AFMODF, + AFMODL, + AFMODW, + AFMOVEB, + AFMOVED, + AFMOVEF, + AFMOVEL, + AFMOVEM, + AFMOVEMC, + AFMOVEW, + AFMULB, + AFMULD, + AFMULF, + AFMULL, + AFMULW, + AFNEGB, + AFNEGD, + AFNEGF, + AFNEGL, + AFNEGW, + AFREMB, + AFREMD, + AFREMF, + AFREML, + AFREMW, + AFRESTORE, + AFSAVE, + AFSCALEB, + AFSCALED, + AFSCALEF, + AFSCALEL, + AFSCALEW, + AFSEQ, + AFSF, + AFSGE, + AFSGT, + AFSINB, + AFSIND, + AFSINF, + AFSINHB, + AFSINHD, + AFSINHF, + AFSINHL, + AFSINHW, + AFSINL, + AFSINW, + AFSLE, + AFSLT, + AFSNE, + AFSQRTB, + AFSQRTD, + AFSQRTF, + AFSQRTL, + AFSQRTW, + AFST, + AFSUBB, + AFSUBD, + AFSUBF, + AFSUBL, + AFSUBW, + AFTANB, + AFTAND, + AFTANF, + AFTANHB, + AFTANHD, + AFTANHF, + AFTANHL, + AFTANHW, + AFTANL, + AFTANW, + AFTENTOXB, + AFTENTOXD, + AFTENTOXF, + AFTENTOXL, + AFTENTOXW, + AFTSTB, + AFTSTD, + AFTSTF, + AFTSTL, + AFTSTW, + AFTWOTOXB, + AFTWOTOXD, + AFTWOTOXF, + AFTWOTOXL, + AFTWOTOXW, + AGLOBL, + AGOK, + AHISTORY, + AILLEG, + AINSTR, + AJMP, + AJSR, + ALEA, + ALINKL, + ALINKW, + ALOCATE, + ALONG, + ALSLB, + ALSLL, + ALSLW, + ALSRB, + ALSRL, + ALSRW, + AMOVB, + AMOVEM, + AMOVEPL, + AMOVEPW, + AMOVESB, + AMOVESL, + AMOVESW, + AMOVL, + AMOVW, + AMULSL, + AMULSW, + AMULUL, + AMULUW, + ANAME, + ANBCD, + ANEGB, + ANEGL, + ANEGW, + ANEGXB, + ANEGXL, + ANEGXW, + ANOP, + ANOTB, + ANOTL, + ANOTW, + AORB, + AORL, + AORW, + APACK, + APEA, + ARESET, + AROTLB, + AROTLL, + AROTLW, + AROTRB, + AROTRL, + AROTRW, + AROXLB, + AROXLL, + AROXLW, + AROXRB, + AROXRL, + AROXRW, + ARTD, + ARTE, + ARTM, + ARTR, + ARTS, + ASBCD, + ASCC, + ASCS, + ASEQ, + ASF, + ASGE, + ASGT, + ASHI, + ASLE, + ASLS, + ASLT, + ASMI, + ASNE, + ASPL, + AST, + ASTOP, + ASUBB, + ASUBL, + ASUBW, + ASUBXB, + ASUBXL, + ASUBXW, + ASVC, + ASVS, + ASWAP, + ASYS, + ATAS, + ATEXT, + ATRAP, + ATRAPCC, + ATRAPCS, + ATRAPEQ, + ATRAPF, + ATRAPGE, + ATRAPGT, + ATRAPHI, + ATRAPLE, + ATRAPLS, + ATRAPLT, + ATRAPMI, + ATRAPNE, + ATRAPPL, + ATRAPT, + ATRAPV, + ATRAPVC, + ATRAPVS, + ATSTB, + ATSTL, + ATSTW, + AUNLK, + AUNPK, + AWORD, + ASIGNAME, + + ALAST +}; + +enum +{ + NREG = 8, + + D_R0 = 0, + D_A0 = NREG, + D_F0 = D_A0+NREG, + D_NONE = D_F0+NREG, + D_TOS, + D_BRANCH, + D_STACK, + D_TREE, + D_EXTERN, + D_STATIC, + D_AUTO, + D_PARAM, + D_CONST, + D_FCONST, + D_QUICK, + + D_CCR, + D_SR, + D_SFC, + D_CACR, + D_USP, + D_VBR, + D_CAAR, + D_MSP, + D_ISP, + D_DFC, + D_FPCR, + D_FPSR, + D_FPIAR, + D_SCONST, + D_FILE, + + D_TC, /* new for 68040 */ + D_ITT0, + D_ITT1, + D_DTT0, + D_DTT1, + D_MMUSR, + D_URP, + D_SRP, + + D_FILE1, + + D_MASK = 63/(D_SRP>=63?0:1), + + I_DIR = (D_MASK+1)*0, + I_INDINC = (D_MASK+1)*1, + I_INDDEC = (D_MASK+1)*2, + I_INDIR = (D_MASK+1)*3, + I_ADDR = (D_MASK+1)*4, + + I_INDEX1 = (D_MASK+1)*1, + I_INDEX2 = (D_MASK+1)*2, + I_INDEX3 = (D_MASK+1)*3, + + I_MASK = (D_MASK+1)*7, + + T_FIELD = 1<<0, + T_INDEX = 1<<1, + T_TYPE = 1<<2, + T_OFFSET = 1<<3, + T_FCONST = 1<<4, + T_SYM = 1<<5, + T_SCONST = 1<<6 +}; + +/* + * 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 */ +}; diff --git a/utils/2c/Update b/utils/2c/Update new file mode 100644 index 00000000..65024dfe --- /dev/null +++ b/utils/2c/Update @@ -0,0 +1,7 @@ + if(n->op == ONAME) { +< if(o == OSET) +< gopcode(OTST, tint, D_NONE, Z, D_TREE, n); +< else +< gopcode(OTST, tint, D_TREE, n, D_NONE, Z); +< p->as = ANOP; +< } diff --git a/utils/2c/cgen.c b/utils/2c/cgen.c new file mode 100644 index 00000000..3c1d4b3d --- /dev/null +++ b/utils/2c/cgen.c @@ -0,0 +1,1404 @@ +#include "gc.h" + +void +cgen(Node *n, int result, Node *nn) +{ + Node *l, *r, nod; + int lg, rg, xg, yg, g, o; + long v; + Prog *p1; + + if(n == Z || n->type == T) + return; + if(typesuv[n->type->etype]) { + sugen(n, result, nn, n->type->width); + return; + } + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R\n", result); + prtree(n, "cgen"); + } + l = n->left; + r = n->right; + o = n->op; + if(n->addable >= INDEXED) { + if(result == D_NONE) { + if(nn == Z) + switch(o) { + default: + nullwarn(Z, Z); + break; + case OINDEX: + nullwarn(l, r); + break; + } + return; + } + gmove(n->type, nn->type, D_TREE, n, result, nn); + return; + } + + v = 0; /* set */ + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + /* + * recursive use of result + */ + if(result == D_NONE) + if(l->addable > INDEXED) + if(l->complex < FNX) { + cgen(r, D_TREE, l); + break; + } + + /* + * function calls on both sides + */ + if(l->complex >= FNX && r->complex >= FNX) { + cgen(r, D_TOS, r); + v = argoff; + lg = regaddr(result); + lcgen(l, lg, Z); + lg |= I_INDIR; + adjsp(v - argoff); + gmove(r->type, l->type, D_TOS, r, lg, l); + if(result != D_NONE) + gmove(l->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + } + + rg = D_TREE; + lg = D_TREE; + if(r->complex >= l->complex) { + /* + * right side before left + */ + if(result != D_NONE) { + rg = regalloc(n->type, result); + cgen(r, rg, n); + } else + if(r->complex >= FNX || r->addable < INDEXED) { + rg = regalloc(r->type, result); + cgen(r, rg, r); + } + if(l->addable < INDEXED) { + lg = regaddr(lg); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + } else { + /* + * left before right + */ + if(l->complex >= FNX || l->addable < INDEXED) { + lg = regaddr(lg); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + if(result != D_NONE) { + rg = regalloc(n->type, result); + cgen(r, rg, n); + } else + if(r->addable < INDEXED) { + rg = regalloc(r->type, result); + cgen(r, rg, r); + } + } + if(result != D_NONE) { + gmove(n->type, l->type, rg, r, lg, l); + gmove(n->type, nn->type, rg, r, result, nn); + } else + gmove(r->type, l->type, rg, r, lg, l); + regfree(lg); + regfree(rg); + break; + + bitas: + n = l->left; + rg = regalloc(tfield, result); + if(l->complex >= r->complex) { + lg = regaddr(D_NONE); + lcgen(n, lg, Z); + lg |= I_INDIR; + cgen(r, rg, r); + } else { + cgen(r, rg, r); + lg = regaddr(D_NONE); + lcgen(n, lg, Z); + lg |= I_INDIR; + } + g = regalloc(n->type, D_NONE); + gmove(l->type, l->type, lg, l, g, l); + bitstore(l, rg, lg, g, result, nn); + break; + + case OBIT: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + g = bitload(n, D_NONE, D_NONE, result, nn); + gopcode(OAS, nn->type, g, n, result, nn); + regfree(g); + break; + + case ODOT: + sugen(l, D_TREE, nodrat, l->type->width); + if(result != D_NONE) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += r->vconst; + nod.type = n->type; + cgen(&nod, result, nn); + } + break; + + case OASLDIV: + case OASLMOD: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]) + goto asbinop; + rg = D_TREE; + if(l->complex >= FNX || r->complex >= FNX) { + rg = D_TOS; + cgen(r, rg, r); + v = argoff; + } else + if(r->addable < INDEXED) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + lg = D_TREE; + if(!simplv(l)) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); /* destroys register optimization */ + lg |= I_INDIR; + } + g = regpair(result); + gmove(l->type, n->type, lg, l, g, n); + if(rg == D_TOS) + adjsp(v - argoff); + gopcode(o, n->type, rg, r, g, n); + if(o == OASLMOD || o == OASMOD) + gmove(n->type, l->type, g+1, n, lg, l); + else + gmove(n->type, l->type, g, n, lg, l); + if(result != D_NONE) + if(o == OASLMOD || o == OASMOD) + gmove(n->type, nn->type, g+1, n, result, nn); + else + gmove(n->type, nn->type, g, n, result, nn); + regfree(g); + regfree(g+1); + regfree(lg); + regfree(rg); + break; + + case OASXOR: + case OASAND: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= FNX || + l->addable < INDEXED || + result != D_NONE || + typefd[n->type->etype]) + goto asbinop; + rg = D_TREE; + if(r->op != OCONST) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + gopcode(o, l->type, rg, r, D_TREE, l); + regfree(rg); + break; + + case OASADD: + case OASSUB: + if(l->op == OBIT || + l->complex >= FNX || + l->addable < INDEXED || + result != D_NONE || + typefd[n->type->etype]) + goto asbinop; + v = vconst(r); + if(v > 0 && v <= 8) { + gopcode(o, n->type, D_TREE, r, D_TREE, l); + break; + } + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + gopcode(o, n->type, rg, r, D_TREE, l); + regfree(rg); + break; + + case OASLSHR: + case OASASHR: + case OASASHL: + if(l->op == OBIT || + l->complex >= FNX || + l->addable < INDEXED || + result != D_NONE || + typefd[n->type->etype]) + goto asbinop; + rg = D_TREE; + v = vconst(r); + if(v <= 0 || v > 8) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + lg = regalloc(n->type, D_NONE); + cgen(l, lg, l); + gopcode(o, n->type, rg, r, lg, l); + gmove(n->type, n->type, lg, l, D_TREE, l); + regfree(lg); + regfree(rg); + break; + + case OASLMUL: + case OASMUL: + asbinop: + if(l->op == OBIT) + goto asbitop; + rg = D_TREE; + if(l->complex >= FNX || r->complex >= FNX) { + rg = D_TOS; + cgen(r, rg, r); + v = argoff; + } else + if(r->addable < INDEXED) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } else { + if(o == OASLSHR || o == OASASHR || o == OASASHL) { + v = vconst(r); + if(v <= 0 || v > 8) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + } + } + lg = D_TREE; + if(!simplv(l)) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); /* destroys register optimization */ + lg |= I_INDIR; + } + g = regalloc(n->type, result); + gmove(l->type, n->type, lg, l, g, n); + if(rg == D_TOS) + adjsp(v - argoff); + if(o == OASXOR) + if(rg == D_TREE) { + rg = regalloc(n->type, D_NONE); + cgen(r, rg, r); + } + if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL) + if(rg == D_TOS) { + rg = regalloc(n->type, D_NONE); + gmove(n->type, n->type, D_TOS, n, rg, n); + } + gopcode(o, n->type, rg, r, g, n); + gmove(n->type, l->type, g, n, lg, l); + if(result != D_NONE) + gmove(n->type, nn->type, g, n, result, nn); + regfree(g); + regfree(lg); + regfree(rg); + break; + + asbitop: + rg = regaddr(D_NONE); + lg = regalloc(tfield, D_NONE); + if(l->complex >= r->complex) { + g = bitload(l, lg, rg, result, nn); + xg = regalloc(r->type, D_NONE); + cgen(r, xg, nn); + } else { + xg = regalloc(r->type, D_NONE); + cgen(r, xg, nn); + g = bitload(l, lg, rg, result, nn); + } + + if(!typefd[n->type->etype]) { + if(o == OASLDIV || o == OASDIV) { + yg = regpair(result); + gmove(tfield, n->type, g, l, yg, n); + gopcode(o, n->type, xg, r, yg, n); + gmove(n->type, tfield, yg, n, g, l); + regfree(yg); + regfree(yg+1); + + regfree(xg); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } + if(o == OASLMOD || o == OASMOD) { + yg = regpair(result); + gmove(tfield, n->type, g, l, yg, n); + gopcode(o, n->type, xg, r, yg, n); + gmove(n->type, tfield, yg+1, n, g, l); + regfree(yg); + regfree(yg+1); + + regfree(xg); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } + } + + yg = regalloc(n->type, result); + gmove(tfield, n->type, g, l, yg, n); + gopcode(o, n->type, xg, r, yg, n); + gmove(n->type, tfield, yg, n, g, l); + regfree(yg); + + regfree(xg); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + + case OCAST: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lg = result; + if(l->complex >= FNX) + lg = regret(l->type); + lg = eval(l, lg); + if(nocast(l->type, n->type)) { + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + } + if(nocast(n->type, nn->type)) { + gmove(l->type, n->type, lg, l, result, nn); + regfree(lg); + break; + } + rg = regalloc(n->type, result); + gmove(l->type, n->type, lg, l, rg, n); + gmove(n->type, nn->type, rg, n, result, nn); + regfree(rg); + regfree(lg); + break; + + case OCOND: + doinc(l, PRE); + boolgen(l, 1, D_NONE, Z, l); + p1 = p; + + inargs++; + doinc(r->left, PRE); + cgen(r->left, result, nn); + doinc(r->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(r->right, PRE); + cgen(r->right, result, nn); + doinc(r->right, POST); + patch(p1, pc); + inargs--; + break; + + case OIND: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lg = nodalloc(types[TIND], result, &nod); + nod.lineno = n->lineno; + if(l->op == OADD) { + if(l->left->op == OCONST) { + nod.xoffset += l->left->vconst; + l = l->right; + } else + if(l->right->op == OCONST) { + nod.xoffset += l->right->vconst; + l = l->left; + } + } + cgen(l, lg, l); + gmove(n->type, nn->type, D_TREE, &nod, result, nn); + regfree(lg); + break; + + case OFUNC: + v = argoff; + inargs++; + gargs(r); + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(result); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + inargs--; + doinc(r, POST); + doinc(l, POST); + gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l); + regfree(lg); + if(inargs) + adjsp(v - argoff); + if(result != D_NONE) { + lg = regret(n->type); + gmove(n->type, nn->type, lg, n, result, nn); + } + break; + + case OLDIV: + case OLMOD: + case ODIV: + case OMOD: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto binop; + if(r->addable >= INDEXED && r->complex < FNX) { + lg = regpair(result); + cgen(l, lg, l); + rg = D_TREE; + } else { + cgen(r, D_TOS, r); + v = argoff; + lg = regpair(result); + cgen(l, lg, l); + adjsp(v - argoff); + rg = D_TOS; + } + gopcode(o, n->type, rg, r, lg, l); + if(o == OMOD || o == OLMOD) + gmove(l->type, nn->type, lg+1, l, result, nn); + else + gmove(l->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(lg+1); + break; + + case OMUL: + case OLMUL: + if(l->op == OCONST) + if(mulcon(r, l, result, nn)) + break; + if(r->op == OCONST) + if(mulcon(l, r, result, nn)) + break; + if(debug['M']) + print("%L multiply\n", n->lineno); + goto binop; + + case OAND: + if(r->op == OCONST) + if(typeil[n->type->etype]) + if(l->op == OCAST) { + if(typec[l->left->type->etype]) + if(!(r->vconst & ~0xff)) { + l = l->left; + goto binop; + } + if(typeh[l->left->type->etype]) + if(!(r->vconst & ~0xffff)) { + l = l->left; + goto binop; + } + } + goto binop; + + case OADD: + if(result == D_TOS) + if(r->addable >= INDEXED) + if(l->op == OCONST) + if(typeil[l->type->etype]) { + v = l->vconst; + if(v > -32768 && v < 32768) { + rg = regaddr(D_NONE); + gmove(r->type, r->type, D_TREE, r, rg, r); + gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r); + p->to.offset = v; + p->to.type |= I_INDIR; + regfree(rg); + break; + } + } + + case OSUB: + if(result == D_TOS) + if(l->addable >= INDEXED) + if(r->op == OCONST) + if(typeil[r->type->etype]) { + v = r->vconst; + if(v > -32768 && v < 32768) { + if(n->op == OSUB) + v = -v; + lg = regaddr(D_NONE); + gmove(l->type, l->type, D_TREE, l, lg, l); + gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l); + p->to.offset = v; + p->to.type |= I_INDIR; + regfree(lg); + break; + } + } + goto binop; + + case OOR: + case OXOR: + binop: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + if(l->complex >= FNX && r->complex >= FNX) { + cgen(r, D_TOS, r); + v = argoff; + lg = regalloc(l->type, result); + cgen(l, lg, l); + adjsp(v - argoff); + if(o == OXOR) { + rg = regalloc(r->type, D_NONE); + gmove(r->type, r->type, D_TOS, r, rg, r); + gopcode(o, n->type, rg, r, lg, l); + regfree(rg); + } else + gopcode(o, n->type, D_TOS, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + } + if(l->complex >= r->complex) { + if(l->op == OADDR && (o == OADD || o == OSUB)) + lg = regaddr(result); + else + lg = regalloc(l->type, result); + cgen(l, lg, l); + rg = eval(r, D_NONE); + } else { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + lg = regalloc(l->type, result); + cgen(l, lg, l); + } + if(o == OXOR) { + if(rg == D_TREE) { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + } + if(rg == D_TOS) { + rg = regalloc(r->type, D_NONE); + gmove(r->type, r->type, D_TOS, r, rg, r); + } + } + gopcode(o, n->type, rg, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(rg); + break; + + case OASHL: + if(r->op == OCONST) + if(shlcon(l, r, result, nn)) + break; + case OLSHR: + case OASHR: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + + if(l->complex >= FNX && r->complex >= FNX) { + cgen(r, D_TOS, r); + v = argoff; + lg = regalloc(l->type, result); + cgen(l, lg, l); + adjsp(v - argoff); + rg = regalloc(r->type, D_NONE); + gopcode(OAS, r->type, D_TOS, r, rg, r); + gopcode(n->op, n->type, rg, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(rg); + break; + } + if(l->complex >= r->complex) { + lg = regalloc(l->type, result); + cgen(l, lg, l); + v = vconst(r); + if(v <= 0 || v > 8) { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + } else + rg = eval(r, D_NONE); + } else { + rg = regalloc(r->type, D_NONE); + cgen(r, rg, r); + lg = regalloc(l->type, result); + cgen(l, lg, l); + } + gopcode(o, n->type, rg, r, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + regfree(rg); + break; + + case ONEG: + case OCOM: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + lg = regalloc(l->type, result); + cgen(l, lg, l); + gopcode(o, l->type, D_NONE, Z, lg, l); + gmove(n->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + + case OADDR: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + if(l->op == OINDEX && l->scale == 4 && result != D_TOS) { + /* index scaled by 1, add is better */ + nod = *l; + nod.op = OADD; + nod.addable = 0; + cgen(&nod, result, nn); + break; + } + lcgen(l, result, nn); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(result == D_NONE) { + nullwarn(l, r); + break; + } + boolgen(n, 1, result, nn, Z); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, result, nn, Z); + if(result == D_NONE) + patch(p, pc); + break; + + case OCOMMA: + cgen(l, D_NONE, l); + doinc(l, POST); + doinc(r, PRE); + cgen(r, result, nn); + break; + + case ONOT: + if(result == D_NONE) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, result, nn, Z); + 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; + + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + if(result != D_NONE) + gmove(l->type, nn->type, lg, l, result, nn); + if(typefd[n->type->etype]) { + rg = regalloc(n->type, D_NONE); + gmove(l->type, l->type, lg, l, rg, l); + gopcode(o, n->type, D_CONST, nodconst(1), rg, l); + gmove(l->type, l->type, rg, l, lg, l); + regfree(rg); + } else { + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), lg, l); + else + gopcode(o, n->type, D_CONST, nodconst(v), lg, l); + } + regfree(lg); + 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: + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(D_NONE); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + if(typefd[n->type->etype]) { + rg = regalloc(n->type, D_NONE); + gmove(l->type, l->type, lg, l, rg, l); + gopcode(o, n->type, D_CONST, nodconst(1), rg, l); + gmove(l->type, l->type, rg, l, lg, l); + regfree(rg); + } else { + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), lg, l); + else + gopcode(o, n->type, D_CONST, nodconst(v), lg, l); + } + if(result != D_NONE) + gmove(l->type, nn->type, lg, l, result, nn); + regfree(lg); + break; + + bitinc: + rg = regaddr(D_NONE); + lg = regalloc(tfield, D_NONE); + if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) { + g = bitload(l, lg, rg, D_NONE, nn); + if(nn != Z) + gmove(l->type, nn->type, g, l, result, nn); + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), g, n); + else + gopcode(o, n->type, D_CONST, nodconst(v), g, n); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } + g = bitload(l, lg, rg, result, nn); + if(v < 0) + gopcode(o, n->type, D_CONST, nodconst(-v), g, n); + else + gopcode(o, n->type, D_CONST, nodconst(v), g, n); + if(result != D_NONE) + gmove(l->type, nn->type, g, l, result, nn); + bitstore(l, g, rg, lg, D_NONE, nn); + break; + } +} + +void +lcgen(Node *n, int result, Node *nn) +{ + Node rn; + Prog *p1; + int lg; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R\n", result); + prtree(n, "lcgen"); + } + if(nn == Z) { + nn = &rn; + nn->type = types[TIND]; + } + switch(n->op) { + case OCOMMA: + cgen(n->left, D_NONE, n->left); + doinc(n->left, POST); + doinc(n->right, PRE); + lcgen(n->right, result, nn); + break; + + case OCOND: + doinc(n->left, PRE); + boolgen(n->left, 1, D_NONE, Z, n->left); + p1 = p; + + inargs++; + doinc(n->right->left, PRE); + lcgen(n->right->left, result, nn); + doinc(n->right->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(n->right->right, PRE); + lcgen(n->right->right, result, nn); + doinc(n->right->right, POST); + patch(p1, pc); + inargs--; + break; + + case OIND: + if(n->addable >= INDEXED) { + if(result >= D_A0 && result < D_A0+NREG) { + gopcode(OADDR, types[TLONG], D_TREE, n, result, nn); + break; + } + if(result == D_TOS) { + gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n); + break; + } + } + cgen(n->left, result, nn); + break; + + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + if(result >= D_A0 && result < D_A0+NREG) { + gopcode(OADDR, types[TLONG], D_TREE, n, result, nn); + break; + } + if(result == D_TOS) { + gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n); + break; + } + lg = regaddr(result); + gopcode(OADDR, types[TLONG], D_TREE, n, lg, nn); + gopcode(OAS, nn->type, lg, nn, result, nn); + regfree(lg); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + boolgen(n, true, D_NONE, Z, Z); +} + +void +boolgen(Node *n, int true, int result, Node *nn, Node *post) +{ + Prog *p1, *p2; + Node *l, *r; + int lg, rg, fp, o; + long v; + + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R\n", result); + prtree(n, "boolgen"); + } + l = n->left; + r = n->right; + switch(n->op) { + + default: + lg = eval(n, result); + if(lg >= D_A0 && lg < D_A0+NREG) { + rg = regalloc(types[TLONG], D_NONE); + gopcode(OAS, types[TLONG], lg, n, rg, Z); + regfree(rg); + } else + gopcode(OTST, n->type, D_NONE, Z, lg, n); + regfree(lg); + o = ONE; + fp = typefd[n->type->etype]; + goto genbool; + + case OCONST: + fp = vconst(n); + if(!true) + fp = !fp; + gbranch(OGOTO); + if(fp) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + + case ONOT: + boolgen(l, !true, result, nn, post); + break; + + case OCOND: + doinc(l, PRE); + boolgen(l, 1, D_NONE, Z, l); + p1 = p; + + inargs++; + doinc(r->left, PRE); + boolgen(r->left, true, result, nn, r->left); + if(result != D_NONE) { + doinc(r->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(r->right, PRE); + boolgen(r->right, !true, result, nn, r->right); + doinc(r->right, POST); + patch(p1, pc); + inargs--; + break; + } + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(r->right, PRE); + boolgen(r->right, !true, result, nn, r->right); + patch(p2, pc); + p2 = p; + if(doinc(post, POST|TEST)) { + lg = regalloc(types[TSHORT], D_NONE); + gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z); + doinc(post, POST); + gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z); + regfree(lg); + } + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + inargs--; + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + doinc(l, PRE); + boolgen(l, true, D_NONE, Z, l); + p1 = p; + inargs++; + doinc(r, PRE); + boolgen(r, !true, D_NONE, Z, r); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + inargs--; + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + doinc(l, PRE); + boolgen(l, !true, D_NONE, Z, l); + p1 = p; + inargs++; + doinc(r, PRE); + boolgen(r, !true, D_NONE, Z, r); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + inargs--; + goto com; + + case OEQ: + case ONE: + if(vconst(l) == 0) { + if(n->op == ONE) { + boolgen(r, true, result, nn, post); + break; + } + boolgen(r, !true, result, nn, post); + break; + } + + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + fp = typefd[r->type->etype]; + if(l->op == OCONST) { + v = vconst(l); + if(v == 0) { /* tst instruction */ + o = invrel[relindex(n->op)]; + rg = eval(r, result); + gopcode(OTST, r->type, D_NONE, Z, rg, r); + regfree(rg); + goto genbool; + } + if(!fp) { /* cmpi and movq, saves about .5% both time and space */ + if(v < 128 && v >= -128 && + ewidth[r->type->etype] == SZ_LONG) { + rg = eval(r, result); + lg = regalloc(l->type, D_NONE); + cgen(l, lg, l); + o = n->op; + gopcode(o, l->type, lg, l, rg, r); + regfree(lg); + regfree(rg); + goto genbool; + } + o = invrel[relindex(n->op)]; + rg = eval(r, result); + gopcode(o, r->type, rg, r, D_TREE, l); + regfree(rg); + goto genbool; + } + } + lg = D_TOS; + if(r->complex < FNX) + lg = regalloc(l->type, lg); + cgen(l, lg, l); + v = argoff; + rg = eval(r, result); + if(lg == D_TOS) { + adjsp(v - argoff); + lg = regalloc(l->type, lg); + gopcode(OAS, l->type, D_TOS, l, lg, l); + } + o = n->op; + gopcode(o, l->type, lg, l, rg, r); + regfree(lg); + regfree(rg); + + genbool: + if(true) + o = comrel[relindex(o)]; + if(doinc(post, POST|TEST)) { + lg = regalloc(types[TSHORT], D_NONE); + gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z); + doinc(post, POST); + gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z); + regfree(lg); + } + gbranch(o); + if(fp) + fpbranch(); + + com: + if(result == D_NONE) + break; + p1 = p; + gopcode(OAS, nn->type, D_CONST, nodconst(1), result, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nn->type, D_CONST, nodconst(0), result, nn); + patch(p2, pc); + break; + } +} + +void +sugen(Node *n, int result, Node *nn, long w) +{ + long s, v, o; + int lg, rg, ng; + Prog *p1; + Node *l, *r, nod; + Type *t; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + if(result == D_TREE) + prtree(nn, "result"); + else + print("result = %R width = %ld\n", result, w); + prtree(n, "sugen"); + } + s = argoff; + if(result == D_TREE) { + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + } + + if(n->addable >= INDEXED && n->op != OCONST) + goto copy; + switch(n->op) { + default: + diag(n, "unknown op in sugen: %O", n->op); + break; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(result == D_NONE) { + nullwarn(n->left, Z); + break; + } + + lg = regaddr(D_NONE); + if(result == D_TOS) { + adjsp(s - argoff + w); + gopcode(OADDR, types[TIND], result, nn, lg, n); + } else + if(result == D_TREE) { + lcgen(nn, lg, Z); + } else + diag(n, "unknown su result: %R", result); + + gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst>>32)), + lg|I_INDINC, n); + gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst)), + lg|I_INDINC, n); + regfree(lg); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, D_TREE, nodrat, l->type->width); + if(result != D_NONE) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += r->vconst; + nod.type = n->type; + sugen(&nod, result, nn, w); + } + break; + + case OIND: + if(result == D_NONE) { + nullwarn(n->left, Z); + break; + } + goto copy; + + case OSTRUCT: + lg = nodalloc(types[TIND], result, &nod); + nod.lineno = n->lineno; + if(result == D_TREE) + lcgen(nn, lg, Z); + else + if(result == D_TOS) { + adjsp(s - argoff + w); + gopcode(OADDR, types[TIND], result, nn, lg, n); + } else + diag(n, "unknown su result: %R", result); + o = 0; + 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; + } + nod.type = t; + if(l->complex < FNX) { + nod.xoffset = 0; + if(o != t->offset) { + gopcode(OADD, types[TIND], D_CONST, + nodconst(t->offset-o), lg, Z); + o = t->offset; + } + cgen(l, D_TREE, &nod); + continue; + } + nod.xoffset = t->offset - o; + gopcode(OAS, types[TIND], lg, Z, D_TOS, Z); + s = argoff; + if(typesuv[t->etype]) { + sugen(l, D_TREE, nodrat, t->width); + adjsp(s - argoff); + gopcode(OAS, types[TIND], D_TOS, Z, lg, Z); + warn(n, "non-interruptable temporary"); + sugen(nodrat, D_TREE, &nod, t->width); + continue; + } + rg = regalloc(t, D_NONE); + cgen(l, rg, l); + adjsp(s - argoff); + gopcode(OAS, types[TIND], D_TOS, Z, lg, Z); + gopcode(OAS, t, rg, Z, D_TREE, &nod); + regfree(rg); + } + regfree(lg); + break; + + case OAS: + if(result == D_NONE) { + sugen(n->right, D_TREE, n->left, w); + break; + } + sugen(n->right, D_TREE, nodrat, w); /* could do better */ + warn(n, "non-interruptable temporary"); + sugen(nodrat, D_TREE, n->left, w); + sugen(nodrat, result, nn, w); + break; + + case OFUNC: + if(result == D_NONE) { + sugen(n, D_TREE, nodrat, w); + break; + } + inargs++; + /* prepare zero-th arg: address of result */ + if(result == D_TOS) { + adjsp(s - argoff + w); + v = argoff; + gargs(n->right); + gopcode(OADDR, types[TSHORT], D_NONE, nn, result, nn); + p->to.type = D_STACK; + p->to.offset = argoff - v; + } else + if(result == D_TREE) { + v = argoff; + gargs(n->right); + if(nn->complex >= FNX) { + rg = regalloc(types[TIND], regret(types[TIND])); + lcgen(nn, rg, Z); + gopcode(OAS, types[TIND], rg, Z, D_TOS, Z); + regfree(rg); + } else + lcgen(nn, D_TOS, Z); + } else { + diag(n, "unknown result in FUNC sugen"); + break; + } + argoff += types[TIND]->width; + l = n->left; + lg = D_TREE; + if(l->addable < INDEXED) { + lg = regaddr(result); + lcgen(l, lg, Z); + lg |= I_INDIR; + } + inargs--; + doinc(n->right, POST); + doinc(n->left, POST); + gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l); + regfree(lg); + if(inargs) + adjsp(v - argoff); + break; + + case OCOND: + doinc(n->left, PRE); + boolgen(n->left, 1, D_NONE, Z, n->left); + p1 = p; + + inargs++; + doinc(n->right->left, PRE); + sugen(n->right->left, result, nn, w); + doinc(n->right->left, POST); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + + doinc(n->right->right, PRE); + sugen(n->right->right, result, nn, w); + doinc(n->right->right, POST); + patch(p1, pc); + inargs--; + break; + + case OCOMMA: + cgen(n->left, D_NONE, n->left); + doinc(n->left, POST); + doinc(n->right, PRE); + sugen(n->right, result, nn, w); + break; + } + return; + +copy: + if(result == D_NONE) + return; + rg = regaddr(D_NONE); + lcgen(n, rg, Z); + + lg = regaddr(D_NONE); + if(result == D_TOS) { + adjsp(s - argoff + w); + gopcode(OADDR, types[TIND], result, nn, lg, n); + } else + if(result == D_TREE) { + if(nn->complex >= FNX) { + gopcode(OAS, types[TIND], rg, n, D_TOS, n); + s = argoff; + lcgen(nn, lg, Z); + adjsp(s - argoff); + gopcode(OAS, types[TIND], D_TOS, n, rg, n); + } else + lcgen(nn, lg, Z); + } else + diag(n, "unknown su result: %R", result); + + if(w % SZ_LONG) + diag(Z, "sucopy width not 0%%%d", SZ_LONG); + v = w / SZ_LONG; + if(v & 1) { + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + v--; + } + if(v > 6) { + ng = regalloc(types[TLONG], D_NONE); + gopcode(OAS, types[TLONG], D_CONST, nodconst(v/2-1), ng, n); + v = pc; + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + gbranch(OGT); + patch(p, v); + p->from.type = ng; + p->as = ADBF; + regfree(ng); + } else + while(v > 0) { + gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n); + v--; + } + + regfree(lg); + regfree(rg); +} diff --git a/utils/2c/enam.c b/utils/2c/enam.c new file mode 100644 index 00000000..be6917af --- /dev/null +++ b/utils/2c/enam.c @@ -0,0 +1,425 @@ +char *anames[] = +{ + "XXX", + "ABCD", + "ADDB", + "ADDL", + "ADDW", + "ADDXB", + "ADDXL", + "ADDXW", + "ADJSP", + "ANDB", + "ANDL", + "ANDW", + "ASLB", + "ASLL", + "ASLW", + "ASRB", + "ASRL", + "ASRW", + "BCASE", + "BCC", + "BCHG", + "BCLR", + "BCS", + "BEQ", + "BFCHG", + "BFCLR", + "BFEXTS", + "BFEXTU", + "BFFFO", + "BFINS", + "BFSET", + "BFTST", + "BGE", + "BGT", + "BHI", + "BKPT", + "BLE", + "BLS", + "BLT", + "BMI", + "BNE", + "BPL", + "BRA", + "BSET", + "BSR", + "BTST", + "BVC", + "BVS", + "CALLM", + "CAS2B", + "CAS2L", + "CAS2W", + "CASB", + "CASEW", + "CASL", + "CASW", + "CHK2B", + "CHK2L", + "CHK2W", + "CHKL", + "CHKW", + "CLRB", + "CLRL", + "CLRW", + "CMP2B", + "CMP2L", + "CMP2W", + "CMPB", + "CMPL", + "CMPW", + "DATA", + "DBCC", + "DBCS", + "DBEQ", + "DBF", + "DBGE", + "DBGT", + "DBHI", + "DBLE", + "DBLS", + "DBLT", + "DBMI", + "DBNE", + "DBPL", + "DBT", + "DBVC", + "DBVS", + "DIVSL", + "DIVSW", + "DIVUL", + "DIVUW", + "END", + "EORB", + "EORL", + "EORW", + "EXG", + "EXTBL", + "EXTBW", + "EXTWL", + "FABSB", + "FABSD", + "FABSF", + "FABSL", + "FABSW", + "FACOSB", + "FACOSD", + "FACOSF", + "FACOSL", + "FACOSW", + "FADDB", + "FADDD", + "FADDF", + "FADDL", + "FADDW", + "FASINB", + "FASIND", + "FASINF", + "FASINL", + "FASINW", + "FATANB", + "FATAND", + "FATANF", + "FATANHB", + "FATANHD", + "FATANHF", + "FATANHL", + "FATANHW", + "FATANL", + "FATANW", + "FBEQ", + "FBF", + "FBGE", + "FBGT", + "FBLE", + "FBLT", + "FBNE", + "FBT", + "FCMPB", + "FCMPD", + "FCMPF", + "FCMPL", + "FCMPW", + "FCOSB", + "FCOSD", + "FCOSF", + "FCOSHB", + "FCOSHD", + "FCOSHF", + "FCOSHL", + "FCOSHW", + "FCOSL", + "FCOSW", + "FDBEQ", + "FDBF", + "FDBGE", + "FDBGT", + "FDBLE", + "FDBLT", + "FDBNE", + "FDBT", + "FDIVB", + "FDIVD", + "FDIVF", + "FDIVL", + "FDIVW", + "FETOXB", + "FETOXD", + "FETOXF", + "FETOXL", + "FETOXM1B", + "FETOXM1D", + "FETOXM1F", + "FETOXM1L", + "FETOXM1W", + "FETOXW", + "FGETEXPB", + "FGETEXPD", + "FGETEXPF", + "FGETEXPL", + "FGETEXPW", + "FGETMANB", + "FGETMAND", + "FGETMANF", + "FGETMANL", + "FGETMANW", + "FINTB", + "FINTD", + "FINTF", + "FINTL", + "FINTRZB", + "FINTRZD", + "FINTRZF", + "FINTRZL", + "FINTRZW", + "FINTW", + "FLOG10B", + "FLOG10D", + "FLOG10F", + "FLOG10L", + "FLOG10W", + "FLOG2B", + "FLOG2D", + "FLOG2F", + "FLOG2L", + "FLOG2W", + "FLOGNB", + "FLOGND", + "FLOGNF", + "FLOGNL", + "FLOGNP1B", + "FLOGNP1D", + "FLOGNP1F", + "FLOGNP1L", + "FLOGNP1W", + "FLOGNW", + "FMODB", + "FMODD", + "FMODF", + "FMODL", + "FMODW", + "FMOVEB", + "FMOVED", + "FMOVEF", + "FMOVEL", + "FMOVEM", + "FMOVEMC", + "FMOVEW", + "FMULB", + "FMULD", + "FMULF", + "FMULL", + "FMULW", + "FNEGB", + "FNEGD", + "FNEGF", + "FNEGL", + "FNEGW", + "FREMB", + "FREMD", + "FREMF", + "FREML", + "FREMW", + "FRESTORE", + "FSAVE", + "FSCALEB", + "FSCALED", + "FSCALEF", + "FSCALEL", + "FSCALEW", + "FSEQ", + "FSF", + "FSGE", + "FSGT", + "FSINB", + "FSIND", + "FSINF", + "FSINHB", + "FSINHD", + "FSINHF", + "FSINHL", + "FSINHW", + "FSINL", + "FSINW", + "FSLE", + "FSLT", + "FSNE", + "FSQRTB", + "FSQRTD", + "FSQRTF", + "FSQRTL", + "FSQRTW", + "FST", + "FSUBB", + "FSUBD", + "FSUBF", + "FSUBL", + "FSUBW", + "FTANB", + "FTAND", + "FTANF", + "FTANHB", + "FTANHD", + "FTANHF", + "FTANHL", + "FTANHW", + "FTANL", + "FTANW", + "FTENTOXB", + "FTENTOXD", + "FTENTOXF", + "FTENTOXL", + "FTENTOXW", + "FTSTB", + "FTSTD", + "FTSTF", + "FTSTL", + "FTSTW", + "FTWOTOXB", + "FTWOTOXD", + "FTWOTOXF", + "FTWOTOXL", + "FTWOTOXW", + "GLOBL", + "GOK", + "HISTORY", + "ILLEG", + "INSTR", + "JMP", + "JSR", + "LEA", + "LINKL", + "LINKW", + "LOCATE", + "LONG", + "LSLB", + "LSLL", + "LSLW", + "LSRB", + "LSRL", + "LSRW", + "MOVB", + "MOVEM", + "MOVEPL", + "MOVEPW", + "MOVESB", + "MOVESL", + "MOVESW", + "MOVL", + "MOVW", + "MULSL", + "MULSW", + "MULUL", + "MULUW", + "NAME", + "NBCD", + "NEGB", + "NEGL", + "NEGW", + "NEGXB", + "NEGXL", + "NEGXW", + "NOP", + "NOTB", + "NOTL", + "NOTW", + "ORB", + "ORL", + "ORW", + "PACK", + "PEA", + "RESET", + "ROTLB", + "ROTLL", + "ROTLW", + "ROTRB", + "ROTRL", + "ROTRW", + "ROXLB", + "ROXLL", + "ROXLW", + "ROXRB", + "ROXRL", + "ROXRW", + "RTD", + "RTE", + "RTM", + "RTR", + "RTS", + "SBCD", + "SCC", + "SCS", + "SEQ", + "SF", + "SGE", + "SGT", + "SHI", + "SLE", + "SLS", + "SLT", + "SMI", + "SNE", + "SPL", + "ST", + "STOP", + "SUBB", + "SUBL", + "SUBW", + "SUBXB", + "SUBXL", + "SUBXW", + "SVC", + "SVS", + "SWAP", + "SYS", + "TAS", + "TEXT", + "TRAP", + "TRAPCC", + "TRAPCS", + "TRAPEQ", + "TRAPF", + "TRAPGE", + "TRAPGT", + "TRAPHI", + "TRAPLE", + "TRAPLS", + "TRAPLT", + "TRAPMI", + "TRAPNE", + "TRAPPL", + "TRAPT", + "TRAPV", + "TRAPVC", + "TRAPVS", + "TSTB", + "TSTL", + "TSTW", + "UNLK", + "UNPK", + "WORD", + "SIGNAME", + "LAST", +}; diff --git a/utils/2c/gc.h b/utils/2c/gc.h new file mode 100644 index 00000000..ab30649e --- /dev/null +++ b/utils/2c/gc.h @@ -0,0 +1,357 @@ +#include "../cc/cc.h" +#include "../2c/2.out.h" +/* + * 2c/68020 + * Motorola 68020 + */ + +#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 ALLOP OEND +#define NRGN 300 +#define FNX 100 +#define INDEXED 9 + +#define PRE 1 +#define POST 2 +#define TEST 4 + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Txt Txt; +typedef struct Cases Case; +typedef struct Reg Reg; +typedef struct Rgn Rgn; +typedef struct Var Var; +typedef struct Multab Multab; +typedef struct C1 C1; +typedef struct Index Index; + +struct Index +{ + int o0; + int o1; +}; + +EXTERN struct +{ + Node* regtree; + Node* basetree; + short scale; +} idx; + +struct Adr +{ + long displace; + long offset; + + char sval[NSNAME]; + double dval; + + Sym* sym; + short type; + short index; + short scale; + short field; + short etype; +}; +#define A ((Adr*)0) + +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + short as; +}; +#define P ((Prog*)0) + +struct Txt +{ + short movas; + short postext; + char preclr; +}; + +struct Cases +{ + long val; + long label; + uchar def; + Case* link; +}; +#define C ((Case*)0) + +struct Var +{ + long offset; + Sym* sym; + char type; + 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; + + ulong 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 Rgn +{ + Reg* enter; + short costr; + short costa; + short varno; + short regno; +}; + +struct Multab +{ + short val; + char code[6]; +}; + +struct C1 +{ + long val; + long label; +}; + +#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 8 +#define CREF 5 +#define CTEST 2 +#define CXREF 3 +#define CINF 1000 +#define LOOP 3 + +EXTERN Bits externs; +EXTERN Bits params; +EXTERN Bits addrs; +EXTERN ulong regbits; + +#define B_INDIR (1<<0) +#define B_ADDR (1<<1) +EXTERN int mvbits; +EXTERN int changer; +EXTERN int changea; + +EXTERN Txt txt[NTYPE][NTYPE]; +EXTERN short opxt[ALLOP][NTYPE]; +EXTERN Txt* txtp; +EXTERN int multabsize; + +EXTERN Reg* firstr; +EXTERN Reg* lastr; +EXTERN Reg zreg; +EXTERN Reg* freer; + +EXTERN long argoff; +EXTERN long breakpc; +EXTERN Case* cases; +EXTERN long continpc; +EXTERN Prog* firstp; +EXTERN Reg* firstr; +EXTERN int inargs; +EXTERN Prog* lastp; +EXTERN int retok; +EXTERN long mnstring; +EXTERN Node* nodrat; +EXTERN Node* nodret; +EXTERN long nrathole; +EXTERN long nstatic; +EXTERN int nregion; +EXTERN long nstring; +EXTERN int nvar; +EXTERN Prog* p; +EXTERN long pc; +EXTERN Rgn region[NRGN]; +EXTERN Rgn* rgp; +EXTERN char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Sym* symstatic; +EXTERN Var var[NVAR]; +EXTERN long* idom; +EXTERN Reg** rpo2r; +EXTERN long maxnr; +EXTERN Prog zprog; + +EXTERN uchar regused[NREG]; +EXTERN uchar aregused[NREG]; +EXTERN uchar fregused[NREG]; +EXTERN uchar regbase[I_MASK]; +EXTERN long exregoffset; +EXTERN long exaregoffset; +EXTERN long exfregoffset; + +extern char* anames[]; +extern Multab multab[]; + +void cgen(Node*, int, Node*); +void lcgen(Node*, int, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, int, Node*, Node*); +void sugen(Node*, int, Node*, long); + + +void listinit(void); +int Bconv(Fmt*); +int Pconv(Fmt*); +int Aconv(Fmt*); +int Xconv(Fmt*); +int Dconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); + +void peep(void); +void excise(Reg*); +Reg* uniqp(Reg*); +Reg* uniqs(Reg*); +int findtst(Reg*, Prog*, int); +int setcc(Prog*, Prog*); +int compat(Adr*, Adr*); +int aregind(Adr*); +int asize(int); +int usedin(int, Adr*); +Reg* findccr(Reg*); +int setccr(Prog*); +Reg* findop(Reg*, int, int, int); +int regtyp(int); +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 tasas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copysub(Adr*, Adr*, Adr*, Prog*, int); + +ulong RtoB(int); +ulong AtoB(int); +ulong FtoB(int); +int BtoR(ulong); +int BtoA(ulong); +int BtoF(ulong); + +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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, ulong, int); +void addreg(Adr*, int); + +void codgen(Node*, Node*); +void gen(Node*); +void usedset(Node*, int); +void noretval(int); +Node* nodconst(long); + +int swcmp(const void*, const void*); +void doswit(int, Node*); +void swit1(C1*, int, long, int, Node*); +void cas(void); +int bitload(Node*, int, int, int, Node*); +void bitstore(Node*, int, int, int, int, Node*); +long outstring(char*, long); +int doinc(Node*, int); +void setsp(void); +void adjsp(long); +int simplv(Node*); +int eval(Node*, int); +void outcode(void); +void ieeedtod(Ieee*, double); +int nodalloc(Type*, int, Node*); +int mulcon(Node*, Node*, int, Node*); +int shlcon(Node*, Node*, int, Node*); +int mulcon1(Node*, long, int, Node*); +void nullwarn(Node*, Node*); + +void tindex(Type*, Type*); +void ginit(void); +void gclean(void); +void oinit(int, int, int, int, int, int); +Prog* prg(void); +void nextpc(void); +void gargs(Node*); +void naddr(Node*, Adr*, int); +int regalloc(Type*, int); +int regaddr(int); +int regpair(int); +int regret(Type*); +void regfree(int); +void gmove(Type*, Type*, int, Node*, int, Node*); +void gopcode(int, Type*, int, Node*, int, Node*); +void asopt(void); +int relindex(int); +void gbranch(int); +void fpbranch(void); +void patch(Prog*, long); +void gpseudo(int, Sym*, int, long); +void gpseudotree(int, Sym*, Node*); + +void indx(Node*); +void bcomplex(Node*); + +/* + * com64 + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* +#pragma varargck type "R" int +#pragma varargck type "X" Index diff --git a/utils/2c/list.c b/utils/2c/list.c new file mode 100644 index 00000000..2b3cb4da --- /dev/null +++ b/utils/2c/list.c @@ -0,0 +1,384 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('R', Rconv); + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('X', Xconv); + fmtinstall('B', Bconv); +} + +static Index +indexv(int i, int j) +{ + Index x; + + x.o0 = i; + x.o1 = j; + return x; +} + +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], s[20]; + Prog *p; + + p = va_arg(fp->args, Prog*); + sprint(str, " %A %D,%D", p->as, &p->from, &p->to); + if(p->from.field) { + sprint(s, ",%d,%d", p->to.field, p->from.field); + strcat(str, s); + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int r; + + r = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[r]); +} + +int +Xconv(Fmt *fp) +{ + char str[20], s[10]; + Index x; + int i; + + x = va_arg(fp->args, Index); + str[0] = 0; + i = x.o0 & D_MASK; + if(i != D_NONE) { + sprint(str, "(%R.", i); + i = x.o1; + sprint(s, "%c*%c)", + "WWWWLLLL"[i], + "12481248"[i]); + strcat(str, s); + } + return fmtstrcpy(fp, str); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i, j; + long d; + + a = va_arg(fp->args, Adr*); + i = a->index; + if(i != D_NONE) { + a->index = D_NONE; + d = a->displace; + j = a->scale; + a->displace = 0; + switch(i & I_MASK) { + default: + sprint(str, "???%ld(%D%X)", d, a, indexv(i, j)); + break; + + case I_INDEX1: + sprint(str, "%D%X", a, indexv(i, a->scale)); + break; + + case I_INDEX2: + if(d) + sprint(str, "%ld(%D)%X", d, a, indexv(i, j)); + else + sprint(str, "(%D)%X", a, indexv(i, j)); + break; + + case I_INDEX3: + if(d) + sprint(str, "%ld(%D%X)", d, a, indexv(i, j)); + else + sprint(str, "(%D%X)", a, indexv(i, j)); + break; + } + a->displace = d; + a->index = i; + goto out; + } + i = a->type; + j = i & I_MASK; + if(j) { + a->type = i & D_MASK; + d = a->offset; + a->offset = 0; + switch(j) { + case I_INDINC: + sprint(str, "(%D)+", a); + break; + + case I_INDDEC: + sprint(str, "-(%D)", a); + break; + + case I_INDIR: + if(a->type == D_CONST) + sprint(str, "%ld", d); + else + if(d) + sprint(str, "%ld(%D)", d, a); + else + sprint(str, "(%D)", a); + break; + + case I_ADDR: + a->offset = d; + sprint(str, "$%D", a); + break; + } + a->type = i; + a->offset = d; + goto out; + } + switch(i) { + + default: + 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: + sprint(str, "%s+%ld(FP)", a->sym->name, a->offset); + break; + + case D_CONST: + sprint(str, "$%ld", a->offset); + break; + + case D_STACK: + sprint(str, "TOS+%ld", a->offset); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + goto out; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + goto out; + } + if(a->displace) { + sprint(s, "/%ld", a->displace); + strcat(str, s); + } +out: + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_R0 && r < D_R0+NREG) + sprint(str, "R%d", r-D_R0); + else + if(r >= D_A0 && r < D_A0+NREG) + sprint(str, "A%d", r-D_A0); + else + if(r >= D_F0 && r < D_F0+NREG) + sprint(str, "F%d", r-D_F0); + else + switch(r) { + + default: + sprint(str, "gok(%d)", r); + break; + + case D_NONE: + sprint(str, "NONE"); + break; + + case D_TOS: + sprint(str, "TOS"); + break; + + case D_CCR: + sprint(str, "CCR"); + break; + + case D_SR: + sprint(str, "SR"); + break; + + case D_SFC: + sprint(str, "SFC"); + break; + + case D_DFC: + sprint(str, "DFC"); + break; + + case D_CACR: + sprint(str, "CACR"); + break; + + case D_USP: + sprint(str, "USP"); + break; + + case D_VBR: + sprint(str, "VBR"); + break; + + case D_CAAR: + sprint(str, "CAAR"); + break; + + case D_MSP: + sprint(str, "MSP"); + break; + + case D_ISP: + sprint(str, "ISP"); + break; + + case D_TREE: + sprint(str, "TREE"); + break; + + case D_FPCR: + sprint(str, "FPCR"); + break; + + case D_FPSR: + sprint(str, "FPSR"); + break; + + case D_FPIAR: + sprint(str, "FPIAR"); + break; + + case D_TC: + sprint(str, "TC"); + break; + + case D_ITT0: + sprint(str, "ITT0"); + break; + + case D_ITT1: + sprint(str, "ITT1"); + break; + + case D_DTT0: + sprint(str, "DTT0"); + break; + + case D_DTT1: + sprint(str, "DTT1"); + break; + + case D_MMUSR: + sprint(str, "MMUSR"); + break; + case D_URP: + sprint(str, "URP"); + break; + + case D_SRP: + sprint(str, "SRP"); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *s; + + s = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(double); i++) { + c = s[i] & 0xff; + if(c != '\\' && c != '"' && isprint(c)) { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = '0'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = ((c>>6) & 7) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = ((c>>0) & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} diff --git a/utils/2c/mkfile b/utils/2c/mkfile new file mode 100644 index 00000000..7efbd5cc --- /dev/null +++ b/utils/2c/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=2c + +OFILES=\ + cgen.$O\ + reg.$O\ + txt.$O\ + peep.$O\ + swt.$O\ + sgen.$O\ + list.$O\ + enam.$O\ + mul.$O\ + +HFILES=\ + gc.h\ + 2.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/2c/mul.c b/utils/2c/mul.c new file mode 100644 index 00000000..65ddda2f --- /dev/null +++ b/utils/2c/mul.c @@ -0,0 +1,174 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant + * all sequences start with leading '0'. + * if sequence starts with 'i', then the + * leading '0' is suppressed. + * '0' mov r0,r1 + * '1' sub r0,r1 + * '2' sub r1,r0 + * '3' add r0,r1 + * '4' add r1,r0 + * '5' add r0,r0 + * '6' add r1,r1 + * 'b' lsh $2,r0 + * 'c' lsh $3,r0 + * 'd'-'h' ... + * 'j' lsh $2,r1 + * 'k'-'p' ... + */ +Multab multab[] = +{ + 2, "i5", + 3, "64", + 4, "i55", + 5, "664", + 6, "645", + 7, "c2", + 9, "k4", + 10, "6645", + 11, "66364", + 12, "6455", + 13, "66464", + 14, "6d2", + 15, "d2", + 17, "l4", + 18, "6d4", + 19, "64k4", + 20, "66455", + 21, "664664", + 22, "64c2", + 23, "44c2", + 24, "64c", + 25, "63k4", + 26, "64c4", + 27, "663e2", + 28, "66e2", + 29, "63e2", + 30, "6e2", + 31, "e2", + 33, "m4", + 34, "6e4", + 35, "64l4", + 36, "66e4", + 37, "664k4", + 38, "64k45", + 39, "454c2", + 40, "664c", + 41, "663k4", + 42, "644c4", + 43, "643k4", + 44, "664c4", + 45, "640d2", + 46, "64d2", + 47, "44d2", + 48, "64d", + 49, "63l4", + 50, "64d4", + 51, "640l4", + 52, "646d4", + 53, "643d4", + 54, "6636f2", + 55, "k3f2", + 56, "kf2", + 57, "k2k4", + 58, "636f2", + 59, "663f2", + 60, "66f2", + 61, "63f2", + 62, "6f2", + 63, "f2", + 65, "n4", + 66, "6f4", + 67, "64m4", + 68, "66f4", + 69, "664l4", + 70, "64l45", + 71, "k1f4", + 72, "k4c", + 73, "k4k4", + 74, "664k45", + 75, "6640d2", + 76, "664d2", + 77, "434d2", + 78, "644d2", + 79, "454d2", + 80, "664d", + 81, "663l4", + 82, "644d4", + 83, "643l4", + 84, "664d4", + 85, "6640l4", + 86, "6634l4", + 87, "6443d4", + 88, "6646d4", + 89, "6643d4", + 90, "6406e2", + 91, "643e2", + 92, "646e2", + 93, "640e2", + 94, "64e2", + 95, "44e2", + 96, "64e", + 97, "63m4", + 98, "64e4", + 99, "640m4", + 100, "646e4", + 200, "66f364", + 300, "j40jf2", + 400, "64kg4", + 500, "66h212", + 600, "64m4c4", + 700, "j4c4d2", + 800, "64lh4", + 900, "6464g4", + 1000, "63g2c", + 1100, "j4d2p4", + 1200, "64k4f2", + 1300, "j4n4b4", + 1400, "64j4g2", + 1600, "64d4e", + 1800, "p4c2", + 2000, "63g2d", + 2100, "l4b2o4", + 2200, "k4d4p4", + 2300, "6644h2", + 2400, "j4k4f4", + 2500, "j4e2d4", + 2600, "j40n4c", + 3100, "jd12p2", + 3200, "64d4f", + 3600, "6d1p2", + 3800, "e3k3g2", + 3900, "jf20n4", + 4000, "o4e2", + 4100, "66p455", + 4200, "l4c3e2", + 4300, "l4b1f4", + 4400, "64o4d4", + 4600, "k45h2", + 4700, "k3j4g2", + 4800, "j40d2f", + 5000, "l4c3m4", + 5100, "j40h2b", + 5200, "j40n4d", + 6000, "d1o3h2", + 6100, "o1l4b2", + 6200, "ke12p2", + 6400, "64d4g", + 7200, "66e1p2", + 7400, "m3m4c2", + 7600, "l4f3c2", + 7800, "kg20n4", + 8000, "63g2f", + 8100, "m2b4p4", + 8200, "66p4c", + 8700, "66f4g2", + 8900, "l3j4g4", + 9200, "k45h25", + 9600, "j40d2g", + 9800, "k4f3d4", +}; + +int multabsize = sizeof(multab) / sizeof(multab[0]); diff --git a/utils/2c/peep.c b/utils/2c/peep.c new file mode 100644 index 00000000..4bde0d40 --- /dev/null +++ b/utils/2c/peep.c @@ -0,0 +1,1076 @@ +#include "gc.h" + +void +peep(void) +{ + Reg *r, *r1, *r2; + Prog *p, *p1; + int t, s; +/* + * 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; + } + } + +loop1: + /* + * propigate move's by renaming + */ + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVL || p->as == AFMOVEF || p->as == AFMOVED) + if(regtyp(p->from.type)) + if(anyvar(&p->to)) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + if(t) + goto loop1; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + /* + * convert (A) ... A++ into (A)++ + * and A-- ... (A) into --(A) + */ + t = aregind(&p->from); + if(t == D_NONE) + goto out1; + s = asize(p->as); + if(s == 0) + goto out1; + r1 = findop(r, t, AADDL, s); + if(r1 != R) { + if(usedin(t, &p->to)) + goto out1; + p->from.type += I_INDINC - I_INDIR; + excise(r1); + goto out1; + } + r1 = findop(r, t, ASUBL, s); + if(r1 != R) { + p->from.type += I_INDDEC - I_INDIR; + excise(r1); + } + out1: + t = aregind(&p->to); + if(t == D_NONE) + goto out2; + s = asize(p->as); + if(s == 0) + goto out2; + r1 = findop(r, t, AADDL, s); + if(r1 != R) { + p->to.type += I_INDINC - I_INDIR; + excise(r1); + goto out2; + } + r1 = findop(r, t, ASUBL, s); + if(r1 != R) { + if(usedin(t, &p->from)) + goto out2; + p->to.type += I_INDDEC - I_INDIR; + excise(r1); + } + out2: + /* + * get rid of unneeded save/restore CCR + */ + if(p->from.type == D_CCR) { + r1 = findccr(r); + if(r1 != R) { + excise(r); + excise(r1); + } + } + switch(p->as) { + case ATSTB: + case ATSTW: + case ATSTL: + if(findtst(r, r->prog, 0)) + excise(r); + } + /* + * turn TSTB (A); BLT; ORB $128,(A) into TAS (A); BLT; NOP + */ + if(p->as == ATSTB && (r1 = r->s1)) { + if((r1->prog->as == ABLT && (r2 = r1->s1)) || + (r1->prog->as == ABGE && (r2 = r1->s2))) { + p1 = r2->prog; + if(p1->as == AORB) + if(p1->from.type == D_CONST) + if(p1->from.offset == 128) + if(r1 == uniqp(r2)) + if(tasas(&p->to, &p1->to)) { + p->as = ATAS; + excise(r2); + } + } + } + } +} + +void +excise(Reg *r) +{ + + 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; +} + +/* + * chase backward all cc setting. + * returns 1 if all set same. + */ +int +findtst(Reg *r0, Prog *rp, int n) +{ + Reg *r; + int c; + +loop: + n++; + if(n >= 10) + return 0; + for(r=r0->p2; r!=R; r=r->p2link) { + c = setcc(r->prog, rp); + if(c > 0) + continue; + if(c == 0) + return 0; + if(findtst(r, rp, n) == 0) + return 0; + } + r = r0->p1; + if(r == R) + return 1; + c = setcc(r->prog, rp); + if(c > 0) + return 1; + if(c == 0) + return 0; + r0 = r; + goto loop; +} + +/* + * tests cc + * returns -1 if no change + * returns 1 if set the same + * returns 0 if set different + */ +int +setcc(Prog *p, Prog *rp) +{ + int s; + + s = asize(rp->as); + switch(p->as) { + default: + if(debug['P']) + print("unknown setcc %A\n", p->as); + break; + + case ACMPB: + case ACMPW: + case ACMPL: + case ABSR: + return 0; + + case ABRA: + case ABGE: + case ABNE: + case ABLE: + case ABEQ: + case ABHI: + case ABLS: + case ABMI: + case ABPL: + case ABGT: + case ABLT: + case ABCC: + case ABCS: + case APEA: + case ALEA: + case ANOP: + + case AFADDD: + case AFMULD: + case AFDIVD: + case AFSUBD: + case AFADDF: + case AFMULF: + case AFDIVF: + case AFSUBF: + case AADJSP: + return -1; + + case AADDW: + case AADDL: + case ASUBW: + case ASUBL: + case ACLRL: + case ACLRW: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + goto areg; + + case AADDB: + case ASUBB: + case AANDB: + case AANDW: + case AANDL: + case AORB: + case AORW: + case AORL: + case AEORB: + case AEORW: + case AEORL: + case ALSLB: + case ALSLW: + case ALSLL: + case ALSRB: + case ALSRW: + case ALSRL: + case AASLB: + case AASLW: + case AASLL: + case AASRB: + case AASRW: + case AASRL: + case ATSTB: + case ATSTW: + case ATSTL: + case ANEGB: + case ANEGW: + case ANEGL: + case ACLRB: + if(asize(p->as) != s) + break; + if(compat(&rp->to, &p->to)) + return 1; + break; + + case AMOVW: + case AMOVL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + goto areg; + case AMOVB: + if(asize(p->as) != s) + break; + if(compat(&rp->to, &p->to)) + return 1; + if(compat(&rp->to, &p->from)) + return 1; + } + return 0; + +areg: + if((rp->to.type&D_MASK) == p->to.type) + return 0; + return -1; +} + +int +compat(Adr *a, Adr *b) +{ + int o; + + if(a->index != D_NONE) + return 0; + if(b->index != D_NONE) + return 0; + o = a->type; + if((o >= D_R0 && o < D_R0+NREG) || + (o >= D_A0 && o < D_A0+NREG)) + return o == b->type; + o &= D_MASK; + if(o >= D_A0 && o < D_A0+NREG) { + if(o != (b->type&D_MASK)) + return 0; + if(a->offset != b->offset) + return 0; + o = a->type & I_MASK; + if(o == I_INDIR) { + o = b->type & I_MASK; + if(o == I_INDIR || o == I_INDDEC) + return 1; + return 0; + } + if(o == I_INDINC) { + o = b->type & I_MASK; + if(o == I_INDIR) { + b->type += I_INDINC-I_INDIR; + return 1; + } + if(o == I_INDDEC) { + b->type += I_INDIR-I_INDDEC; + return 1; + } + return 0; + } + } + return 0; +} + +int +aregind(Adr *a) +{ + int t; + + t = a->type; + if(t >= (D_A0|I_INDIR) && t < ((D_A0+NREG)|I_INDIR)) + while(a->offset == 0 && a->index == D_NONE) + return t & D_MASK; + return D_NONE; +} + +int +asize(int a) +{ + + switch(a) { + case AFTSTD: + case AFMOVED: + case AFADDD: + case AFSUBD: + case AFMULD: + case AFDIVD: + case AFCMPD: + case AFNEGD: + return 8; + + case AFTSTF: + case AFMOVEF: + case AFADDF: + case AFSUBF: + case AFMULF: + case AFDIVF: + case AFCMPF: + case AFNEGF: + + case ACLRL: + case ATSTL: + case AMOVL: + case AADDL: + case ASUBL: + case ACMPL: + case AANDL: + case AORL: + case AEORL: + case ALSLL: + case ALSRL: + case AASLL: + case AASRL: + case ANEGL: + return 4; + + case ACLRW: + case ATSTW: + case AMOVW: + case AADDW: + case ASUBW: + case ACMPW: + case AANDW: + case AORW: + case AEORW: + case ALSLW: + case ALSRW: + case AASLW: + case AASRW: + case ANEGW: + return 2; + + case ACLRB: + case ATSTB: + case AMOVB: + case AADDB: + case ASUBB: + case ACMPB: + case AANDB: + case AORB: + case AEORB: + case ALSLB: + case ALSRB: + case AASLB: + case AASRB: + case ANEGB: + return 1; + } + if(debug['P']) + print("unknown asize %A\n", p->as); + return 0; +} + +int +usedin(int t, Adr *a) +{ + + if((a->type&D_MASK) == t) + return 1; + if((a->index&D_MASK) == t) + return 1; + return 0; +} + +Reg* +findccr(Reg *r) +{ + Prog *p; + + for(;;) { + r = uniqs(r); + if(r == R) + break; + p = r->prog; + if(p->to.type == D_CCR) + return r; + if(setccr(p)) + break; + } + return R; +} + +int +setccr(Prog *p) +{ + + switch(p->as) { + case ANOP: + return 0; + + case AADDL: + case AMOVL: + case ACLRL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + return 0; + } + return 1; +} + +Reg* +findop(Reg *r, int t, int o, int s) +{ + Prog *p; + Reg *r1; + + for(;;) { + if(o == AADDL) { + r1 = uniqs(r); + if(r1 == R) + break; + if(uniqp(r1) != r) + break; + } else { + r1 = uniqp(r); + if(r1 == R) + break; + if(uniqs(r1) != r) + break; + } + r = r1; + p = r->prog; + if(usedin(t, &p->from)) + break; + if(usedin(t, &p->to)) { + if(p->as == o) + if(p->to.type == t) + if(p->to.index == D_NONE) + if(p->from.type == D_CONST) + if(p->from.offset == s) + return r; + break; + } + } + return R; +} + +int +regtyp(int t) +{ + + if(t >= D_R0 && t < D_R0+8) + return 1; + if(t >= D_A0 && t < D_A0+8) + return 1; + if(t >= D_F0 && t < D_F0+8) + return 1; + return 0; +} + +int +anyvar(Adr *a) +{ + + if(regtyp(a->type)) + return 1; + return 0; + if(a->type == D_AUTO || a->type == D_PARAM) + 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 MOVL + * 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->type)) + return 0; + v2 = &p->to; + if(!regtyp(v2->type)) + return 0; + for(r=uniqp(r0); r!=R; r=uniqp(r)) { + if(uniqs(r) == R) + break; + p = r->prog; + switch(p->as) { + case ADIVUW: /* these set Rn and Rn+1 */ + case ADIVUL: + case ADIVSW: + case ADIVSL: + case ABSR: + return 0; + + case AFMOVED: + case AFMOVEF: + case AMOVL: + if(p->to.type == v1->type) + goto gotit; + } + if(copyau(&p->from, v2) || copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, p, 0) || copysub(&p->to, v1, v2, p, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, p, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + if(p->from.type == v2->type) + excise(r); + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, p, 1); + copysub(&p->to, v1, v2, p, 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; + + if(r->active) { + if(debug['P']) + print("copyret 1\n"); + return 1; + } + r->active = 1; + if(debug['P']) + print("copy %D->%D\n", v1, v2); + for(; r != R; r = r->s1) { + if(debug['P']) + print("%P", r->prog); + if(!f && uniqp(r) == R) { + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(r->prog, v2, A); + switch(t) { + case 2: /* rar, cant split */ + if(debug['P']) + print("; rar return 0\n"); + return 0; + case 3: /* set */ + if(debug['P']) + print("; set; return 1\n"); + return 1; + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(debug['P']) + print("; used and f; return 0\n"); + return 0; + } + if(copyu(r->prog, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; substitute"); + if(t == 4) { + if(debug['P']) + print("; used and set; return 1\n"); + return 1; + } + break; + } + if(!f) { + t = copyu(r->prog, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + if(debug['P']) + print("; f set used"); + f = 1; + } + } + 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) +{ + int t; + + switch(p->as) { + + default: + if(debug['P']) + print("unknown op %A\n", p->as); + return 2; + + case APEA: /* rhs addr */ + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ALEA: /* lhs addr, rhs store */ + if(copyas(&p->from, v)) + return 2; + + case AMOVL: /* rhs store */ + case ACLRL: + case AFMOVEF: + case AFMOVED: + case AFMOVEB: + case AFMOVEW: + case AFMOVEL: + case ANOP: + if(copyas(&p->to, v)) { + if(s != A) + return copysub(&p->from, v, s, p, 1); + if(copyau(&p->from, v)) + return 4; + return 3; + } + goto caseread; + + case AADDL: /* rhs rar */ + case AADDW: + case AADDB: + case ASUBL: + case ASUBW: + case ASUBB: + case AANDL: + case AANDW: + case AANDB: + case AORL: + case AORW: + case AORB: + case AEORL: + case AEORW: + case AEORB: + case AASRL: + case AASRW: + case AASRB: + case AASLL: + case AASLW: + case AASLB: + case ALSRL: + case ALSRW: + case ALSRB: + case ANOTL: + case ANOTW: + case ANOTB: + case ANEGL: + case ANEGW: + case ANEGB: + case AEXTBL: + case AEXTWL: + case AEXTBW: + + case AMULSL: + case AMULUL: + + case AMOVW: /* only sets part of register */ + case AMOVB: + case ACLRW: + case ACLRB: + + case AFADDD: + case AFMULD: + case AFDIVD: + case AFSUBD: + case AFNEGD: + case AFADDF: + case AFMULF: + case AFDIVF: + case AFSUBF: + case AFNEGF: + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ADBF: /* lhs rar */ + if(copyas(&p->from, v)) + return 2; + goto caseread; + + case ACMPL: /* read only */ + case ACMPW: + case ACMPB: + case AFCMPF: + case AFCMPD: + case ATSTL: + case ATSTW: + case ATSTB: + case AFTSTF: + case AFTSTD: + caseread: + if(s != A) { + if(copysub(&p->from, v, s, p, 1)) + return 1; + return copysub(&p->to, v, s, p, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + break; + + case ABRA: /* no reference */ + case ABGE: + case ABNE: + case ABLE: + case ABEQ: + case ABHI: + case ABLS: + case ABMI: + case ABPL: + case ABGT: + case ABLT: + case ABCC: + case ABCS: + + case AFBEQ: + case AFBNE: + case AFBGT: + case AFBGE: + case AFBLE: + case AFBLT: + + case AADJSP: + case ACASEW: + break; + + case ADIVUW: /* these set Rn and Rn+1 */ + case ADIVUL: + case ADIVSW: + case ADIVSL: + t = v->type; + if(t == p->to.type || t == p->to.type+1) + return 2; + goto caseread; + + case ARTS: /* funny */ + t = v->type; + if(t == D_R0 || t == D_F0) + return 2; + if(t >= D_R0 && t < D_R0+NREG) + if(t-D_R0 > exregoffset) + return 2; + if(t >= D_A0 && t < D_A0+NREG) + if(t-D_A0 > exaregoffset) + return 2; + if(t >= D_F0 && t < D_F0+NREG) + if(t-D_F0 > exfregoffset) + return 2; + return 3; + + case ABSR: /* funny */ + t = v->type; + if(t >= D_R0 && t < D_R0+NREG) + if(t-D_R0 > exregoffset) + return 2; + if(t >= D_A0 && t < D_A0+NREG) + if(t-D_A0 > exaregoffset) + return 2; + if(t >= D_F0 && t < D_F0+NREG) + if(t-D_F0 > exfregoffset) + return 2; + 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->type)) + return 1; + if(v->type == D_AUTO || v->type == D_PARAM) { + if(v->offset == a->offset) + return 1; + return 0; + } + return 0; +} + +/* + * indirect + */ +int +tasas(Adr *a, Adr *v) +{ + int t; + + if(a->index != D_NONE) + return 0; + if(v->index != D_NONE) + return 0; + t = a->type; + if(t < I_INDIR+D_A0 && t >= I_INDIR+D_A0+8) + return 0; + if(v->type != t) + return 0; + if(a->displace != v->displace) + return 0; + return 1; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + int t; + + if(copyas(a, v)) + return 1; + t = v->type; + if(regtyp(t)) { + if((a->type & D_MASK) == t) + return 1; + if((a->index & D_MASK) == t) + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, Prog *p, int f) +{ + int t; + + if(copyas(a, v)) { + t = s->type; + if(t >= D_F0 && t < D_F0+8) { + if(f) + a->type = t; + return 0; + } + if(t >= D_R0 && t < D_R0+8) { + if(f) + a->type = t; + return 0; + } + if(!(t >= D_A0 && t < D_A0+8)) + return 1; + switch(p->as) { + default: + return 1; + + case AMOVL: + case AMOVW: + case ACMPL: + case ACMPW: + break; + + case AADDL: + case AADDW: + case ASUBL: + case ASUBW: + if(a == &p->from && !regtyp(p->to.type)) + return 1; + break; + } + if(f) + a->type = t; + return 0; + } + t = v->type; + if(regtyp(t)) { + if((a->type & D_MASK) == t) { + if((s->type ^ t) & ~(NREG-1)) + return 1; + if(f) + a->type = (a->type & ~D_MASK) | s->type; + return 0; + } + if((a->index & D_MASK) == t) { + if(f) + a->index = (a->index & ~D_MASK) | s->type; + return 0; + } + return 0; + } + return 0; +} diff --git a/utils/2c/reg.c b/utils/2c/reg.c new file mode 100644 index 00000000..d314096d --- /dev/null +++ b/utils/2c/reg.c @@ -0,0 +1,1275 @@ +#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->costr; + if(p2->costa > c1) + c1 = p2->costa; + c2 = p1->costr; + if(p1->costa > c2) + c2 = p1->costa; + if(c1 -= c2) + return c1; + return p2->varno - p1->varno; +} + +void +regopt(Prog *p) +{ + Reg *r, *r1, *r2; + Prog *p1; + int i, z; + long val, initpc, npc; + ulong vreg; + Bits bit; + Var *v; + struct { + long m; + long c; + Reg* p; + } log5[6], *lp; + + firstr = R; + lastr = R; + nvar = 0; + for(z=0; z<BITS; z++) { + externs.b[z] = 0; + params.b[z] = 0; + addrs.b[z] = 0; + } + regbits = RtoB(0) | /* return reg */ + AtoB(6) | AtoB(7) | /* sp and sb */ + FtoB(0) | FtoB(1); /* floating return reg */ + for(i=0; i<NREG; i++) { + if(regused[i]) + regbits |= RtoB(i); + if(fregused[i]) + regbits |= FtoB(i); + if(aregused[i]) + regbits |= AtoB(i); + } + + /* + * 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 ABRA: + case ARTS: + case ARTE: + r->p1 = R; + r1->s1 = R; + } + + bit = mkvar(&p->from, AGOK); + if(bany(&bit)) + switch(p->as) { + case ALEA: + if(!(mvbits & B_INDIR)) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + + default: + if(mvbits & B_ADDR) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + } + + bit = mkvar(&p->to, p->as); + if(bany(&bit)) + switch(p->as) { + case ABSR: /* funny */ + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + goto def; + + case APEA: + if(!(mvbits & B_INDIR)) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + + def: + case ACMPB: case ACMPW: case ACMPL: + case AFCMPF: case AFCMPD: + case ATSTB: case ATSTW: case ATSTL: + case AFTSTF: case AFTSTD: + case ABFEXTU: case ABFEXTS: + if(mvbits & B_ADDR) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + break; + + default: + diag(Z, "reg: unknown asop: %A", p->as); + + case AADDB: case AADDW: case AADDL: + case ASUBB: case ASUBW: case ASUBL: + case AANDB: case AANDW: case AANDL: + case AORB: case AORW: case AORL: + case AEORB: case AEORW: case AEORL: + case ABFINS: + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + + case ANOP: + case AMOVB: case AMOVW: case AMOVL: + case AFMOVEB: case AFMOVEW: case AFMOVEL: + case ACLRB: case ACLRW: case ACLRL: + case AFMOVEF: case AFMOVED: + if(mvbits & B_INDIR) + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + else + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + 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) { + diag(Z, "ref not found\n%L:%P", p->lineno, p); + continue; + } + if(r1 == r) { + diag(Z, "ref to self"); + continue; + } + r->s2 = r1; + r->p2link = r1->p2; + r1->p2 = r; + } + } + if(debug['R']) + print("\n%L %D\n", firstr->prog->lineno, &firstr->prog->from); + + /* + * pass 2.5 + * find looping structure + */ + for(r = firstr; r != R; r = r->link) + r->active = 0; + changer = 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: + changer = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + for(r = firstr; r != R; r = r->link) + if(r->prog->as == ARTS) + 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(changer) + goto loop1; + + /* + * pass 4 + * iterate propagating register/variable synchrony + * forward until graph is complete + */ +loop2: + changer = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + synch(firstr, zbits); + if(changer) + 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]); + 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); + + /* + * 68040 'feature': + * load of a denormalized fp will trap + */ + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + v = var + i; + if(v->type == D_AUTO) { + r->set.b[i/32] |= (1L << (i%32)); + if(typefd[v->etype]) + addmove(r, i, NREG+NREG, 1); + } + } + } + } + if(debug['R'] && debug['v']) + print("\nprop structure:\n"); + for(r = firstr; r != R; r = r->link) { + if(debug['R'] && debug['v']) + print("%P\n set = %B; rah = %B; cal = %B\n", + r->prog, r->set, r->refahead, r->calahead); + r->act = zbits; + } + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + 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 an 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; + changer = 0; + changea = 0; + if(debug['R'] && debug['v']) + print("\n"); + paint1(r, i); + bit.b[i/32] &= ~(1L<<(i%32)); + if(changer <= 0 && changea <= 0) { + if(debug['R']) + print("%L$%d.%d: %B\n", + r->prog->lineno, + changer, changea, blsh(i)); + continue; + } + rgp->costr = changer; + rgp->costa = changea; + 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.%d %R: %B\n", + rgp->enter->prog->lineno, + rgp->costr, rgp->costa, + rgp->regno, + bit); + if(rgp->regno != D_NONE) + 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; + Var *v; + int badccr; + + badccr = 0; + p = r->prog; + p1 = p->link; + if(p1) + switch(p1->as) { + case AMOVW: + if(p1->from.type == D_CCR) + p = p1; + break; + + case ABEQ: + case ABNE: + case ABLE: + case ABLS: + case ABLT: + case ABMI: + case ABGE: + case ABPL: + case ABGT: + case ABHI: + case ABCC: + case ABCS: + p1 = prg(); + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + p1->from.type = D_CCR; + p1->to.type = D_TOS; + p1->as = AMOVW; + p = p1; + badccr = 1; + } + p1 = prg(); + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + v = var + bn; + p1->from.sym = v->sym; + p1->from.type = v->type; + p1->from.offset = v->offset; + p1->from.etype = v->etype; + p1->to.type = rn; + if(f) { + p1->to = p1->from; + p1->from = zprog.from; + p1->from.type = rn; + } + p1->as = opxt[OAS][v->etype]; + if(badccr) { + p = p1; + p1 = prg(); + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + p1->from.type = D_TOS; + p1->to.type = D_CCR; + p1->as = AMOVW; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int as) +{ + Var *v; + int i, t, z; + long o; + Bits bit; + Sym *s; + + mvbits = 0; + t = a->type & D_MASK; + switch(t) { + + default: + if(t >= D_R0 && t < D_R0+NREG) { + regbits |= RtoB(t-D_R0); + if(as == ADIVUL || as == ADIVSL) + regbits |= RtoB(t-D_R0+1); + } + if(t >= D_A0 && t < D_A0+NREG) + regbits |= AtoB(t-D_A0); + if(t >= D_F0 && t < D_F0+NREG) + regbits |= FtoB(t-D_F0); + goto none; + + case D_EXTERN: + case D_STATIC: + case D_AUTO: + case D_PARAM: + break; + } + s = a->sym; + if(s == S) + goto none; + + if((a->type & I_MASK) == I_ADDR) + mvbits |= B_ADDR; + + switch(a->index & I_MASK) { + case I_INDEX1: + mvbits |= B_ADDR; + break; + + case I_INDEX2: + case I_INDEX3: + mvbits |= B_INDIR; + break; + } + + o = a->offset; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(t == v->type) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = a->etype; + v->type = t; + if(debug['R']) + print("bit=%2d et=%2d %s (%p,%d,%ld)\n", + i, a->etype, s->name, + v->sym, v->type, v->offset); + +out: + bit = blsh(i); + if(t == D_EXTERN || t == D_STATIC) + for(z=0; z<BITS; z++) + externs.b[z] |= bit.b[z]; + if(t == D_PARAM) + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + if(a->etype != v->etype || !typechlpfd[a->etype]) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; /* funny punning */ + 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]; + changer++; + } + cal.b[z] |= r1->calahead.b[z]; + if(cal.b[z] != r1->calahead.b[z]) { + r1->calahead.b[z] = cal.b[z]; + changer++; + } + } + switch(r1->prog->as) { + case ABSR: + 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 ARTS: + 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]; + changer++; + } + } + 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, j; + + v = var + r->varno; + r->regno = D_NONE; + switch(v->etype) { + + default: + diag(Z, "unknown etype"); + break; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + i = BtoR(~b); + j = BtoA(~b); + if(r->costa == r->costr) + if(i > j) + i = NREG; + if(j < NREG && r->costa > 0) + if(r->costa > r->costr || i >= NREG) { + r->regno = D_A0 + j; + return AtoB(j); + } + if(i < NREG && r->costr > 0) { + r->regno = D_R0 + i; + return RtoB(i); + } + break; + + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i < NREG) { + r->regno = D_F0 + i; + return FtoB(i); + } + break; + } + return 0; +} + +void +paint1(Reg *r, int bn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + int x; + + 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) { + changer -= CLOAD * r->loop; + changea -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tld %B $%d.%d\n", r->loop, + r->prog, blsh(bn), changer, changea); + } + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + changer += CREF * r->loop; + changea += CREF * r->loop; + x = p->from.index; + if(x == D_NONE) { + switch(p->as) { + default: + changea = -CINF; + case AADDL: + case ASUBL: + case AMOVL: + case ACMPL: + break; + } + } else { + changer += (CXREF-CREF) * r->loop; + if(x != (I_INDEX3|D_NONE)) + changer = -CINF; + if((x&I_MASK) == I_INDEX1) + changea = -CINF; + } + if(p->as == AMOVL) { + x = p->to.type; + if(x >= D_R0 && x < D_R0+NREG) + changer += r->loop; + if(x >= D_A0 && x < D_A0+NREG) + changea += r->loop; + } + if(debug['R'] && debug['v']) + print("%ld%P\tu1 %B $%d.%d\n", r->loop, + p, blsh(bn), changer, changea); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + changer += CREF * r->loop; + changea += CREF * r->loop; + x = p->to.index; + if(x == D_NONE) + switch(p->as) { + default: + changea = -CINF; + break; + case AMOVL: + case AADDL: + case ACMPL: + case ASUBL: + case ACLRL: /* can be faked */ + case ATSTL: /* can be faked */ + break; + } + else { + changer += (CXREF-CREF) * r->loop; + if(x != (I_INDEX3|D_NONE)) + changer = -CINF; + if((x&I_MASK) == I_INDEX1) + changea = -CINF; + } + if(p->as == AMOVL) { + x = p->from.type; + if(x >= D_R0 && x < D_R0+NREG) + changer += r->loop; + if(x >= D_A0 && x < D_A0+NREG) + changea += r->loop; + } + if(debug['R'] && debug['v']) + print("%ld%P\tu2 %B $%d.%d\n", r->loop, + p, blsh(bn), changer, changea); + } + if(STORE(r) & r->regdiff.b[z] & bb) { + changer -= CLOAD * r->loop; + changea -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tst %B $%d.%d\n", r->loop, + p, blsh(bn), changer, changea); + } + + 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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + return vreg; +} + +void +paint3(Reg *r, int bn, ulong 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) +{ + int x; + + a->sym = 0; + x = a->index; + if(rn >= D_R0 && rn < D_R0+NREG) + goto addr; + if(x == (I_INDEX3|D_NONE)) { + a->type = rn | I_INDIR; + a->index = D_NONE; + a->offset = a->displace; + a->displace = 0; + return; + } + if(x != D_NONE) { + a->type = rn | I_INDIR; + a->index += I_INDEX1 - I_INDEX2; + a->offset = a->displace; + a->displace = 0; + return; + } + a->type = rn | (a->type & I_INDIR); + return; + +addr: + if(x == (I_INDEX3|D_NONE)) { + a->type = D_NONE|I_INDIR; + a->index += I_INDEX1 + rn - D_NONE - I_INDEX3; + a->scale = 4; /* .L*1 */ + a->offset = a->displace; + a->displace = 0; + return; + } + a->type = rn | (a->type & I_INDIR); +} + +/* + * bit reg + * 0-7 R0-R7 + * 8-15 A0-A7 + * 16-23 F0-F7 + */ +ulong +RtoB(int r) +{ + + if(r < 0 || r >= NREG) + return 0; + return 1L << (r + 0); +} + +int +BtoR(ulong b) +{ + + b &= 0x0000ffL; + if(b == 0) + return NREG; + return bitno(b) - 0; +} + +ulong +AtoB(int a) +{ + + if(a < 0 || a >= NREG) + return 0; + return 1L << (a + NREG); +} + +int +BtoA(ulong b) +{ + + b &= 0x00ff00L; + if(b == 0) + return NREG; + return bitno(b) - NREG; +} + +ulong +FtoB(int f) +{ + + if(f < 0 || f >= NREG) + return 0; + return 1L << (f + NREG+NREG); +} + +int +BtoF(ulong b) +{ + + b &= 0xff0000L; + if(b == 0) + return NREG; + return bitno(b) - NREG-NREG; +} diff --git a/utils/2c/sgen.c b/utils/2c/sgen.c new file mode 100644 index 00000000..85925f72 --- /dev/null +++ b/utils/2c/sgen.c @@ -0,0 +1,819 @@ +#include "gc.h" + +void +codgen(Node *n, Node *nn) +{ + Prog *sp; + + argoff = 0; + inargs = 0; + for(;; nn = nn->left) { + if(nn == Z) { + diag(Z, "cant find function name"); + return; + } + if(nn->op == ONAME) + break; + } + nearln = nn->lineno; + gpseudo(ATEXT, nn->sym, D_CONST, stkoff); + sp = p; + + retok = 0; + gen(n); + if(!retok) + if(thisfn->link->etype != TVOID) + warn(Z, "no return at end of function: %s", nn->sym->name); + + noretval(3); + gbranch(ORETURN); + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); +} + +void +gen(Node *n) +{ + Node *l; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int g, 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); + doinc(n, PRE); + cgen(n, D_NONE, n); + doinc(n, POST); + 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); + gbranch(ORETURN); + break; + } + doinc(l, PRE); + if(typesuv[n->type->etype]) { + sugen(l, D_TREE, nodret, n->type->width); + doinc(l, POST); + noretval(3); + gbranch(ORETURN); + break; + } + g = regalloc(n->type, regret(n->type)); + cgen(l, g, n); + doinc(l, POST); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + regfree(g); + 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; + } + 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; + setsp();; + 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; + setsp(); + goto rloop; + } + diag(n, "case expression must be integer constant"); + goto rloop; + + case OSWITCH: + l = n->left; + complex(l); + doinc(l, PRE); + if(l->type == T) + break; + if(!typechl[l->type->etype]) { + diag(n, "switch expression must be integer"); + break; + } + g = regalloc(types[TLONG], D_NONE); + n->type = types[TLONG]; + cgen(l, g, n); + regfree(g); + doinc(l, POST); + setsp(); + 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); + doswit(g, l); + + patch(spb, pc); + cases = cn; + breakpc = sbc; + setsp(); + 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); /* 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); + 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; + bcomplex(l); + 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 */ + gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z); + p->as = ANOP; + break; + case ONAME: + if(o == OSET) + gopcode(OTST, types[TINT], D_NONE, Z, D_TREE, n); + else + gopcode(OTST, types[TINT], D_TREE, n, D_NONE, Z); + p->as = ANOP; + break; + } +} + +void +noretval(int n) +{ + + if(n & 1) { + gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TLONG]), Z); + p->as = ANOP; + } + if(n & 2) { + gopcode(OTST, types[TINT], D_NONE, Z, regret(types[TDOUBLE]), Z); + p->as = ANOP; + } +} + +/* + * calculate addressability as follows + * REGISTER ==> 12 register + * NAME ==> 10/11 name+value(SB/SP) + * CONST ==> 20 $value + * *(20) ==> 21 value + * &(10) ==> 12 $name+value(SB) + * &(11) ==> 1 $name+value(SP) + * (12) + (20) ==> 12 fold constants + * (1) + (20) ==> 1 fold constants + * *(12) ==> 10 back to name + * *(1) ==> 11 back to name + * + * (2,10,11) + (20) ==> 2 indirect w offset + * (2) ==> &13 + * *(10,11) ==> 13 indirect, no index + * + * (20) * (X) ==> 7 multiplier in indexing + * (X,7) + (12,1) ==> 8 adder in indexing (addresses) + * (X,7) + (10,11,2) ==> 8 adder in indexing (names) + * (8) ==> &9 index, almost addressable + * + * (X)++ ==> X fake addressability + * + * 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 OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 12; + else + if(l->addable == 11) + n->addable = 1; + break; + + case OADD: + xcom(l); + xcom(r); + if(n->type->etype != TIND) + break; + + if(l->addable == 20) + switch(r->addable) { + case 12: + case 1: + n->addable = r->addable; + goto brk; + case 10: + case 11: + case 2: + goto addr13; + } + if(r->addable == 20) + switch(l->addable) { + case 12: + case 1: + n->addable = l->addable; + goto brk; + case 10: + case 11: + case 2: + addr13: + n->addable = 2; + l = new1(OXXX, Z, Z); + *l = *n; + n->op = OIND; + n->left = l; + n->right = Z; + n->addable = 13; + l = new1(OXXX, Z, Z); + *l = *n; + n->op = OADDR; + n->left = l; + n->right = Z; + n->addable = 2; + goto brk; + } + + switch(r->addable) { + case 10: + case 11: + case 12: + case 1: + n->addable = 8; + } + switch(l->addable) { + case 10: + case 11: + case 12: + case 1: + n->addable = 8; + } + if(n->addable == 8) { + 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 = 0; + break; + } + 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 12: + n->addable = 10; + break; + case 10: + case 11: + case 2: + n->addable = 13; + break; + } + break; + + case OASHL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vconst(r); + if(g >= 0 && g < 4) + n->addable = 7; + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + n->op = OASHL; + r->vconst = g; + if(g < 4) + n->addable = 7; + break; + } + g = vlog(l); + if(g >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + n->op = OASHL; + r->vconst = g; + if(g < 4) + n->addable = 7; + break; + } + break; + + case ODIV: + case OLDIV: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + if(n->op == ODIV) + n->op = OASHR; + else + n->op = OLSHR; + r->vconst = g; + } + break; + + case OSUB: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + if(vconst(l) == 0) { + n->op = ONEG; + n->left = r; + n->right = Z; + } + break; + + case OXOR: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + if(vconst(l) == -1) { + n->op = OCOM; + n->left = r; + n->right = Z; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + n->op = OASASHL; + r->vconst = g; + } + goto aseae; + + case OASDIV: + case OASLDIV: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + g = vlog(r); + if(g >= 0) { + if(n->op == OASDIV) + n->op = OASASHR; + else + n->op = OASLSHR; + r->vconst = g; + } + goto aseae; + + case OASLMOD: + case OASMOD: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + + aseae: /* hack that there are no byte/short mul/div operators */ + if(n->type->etype == TCHAR || n->type->etype == TSHORT) { + n->right = new1(OCAST, n->right, Z); + n->right->type = types[TLONG]; + n->type = types[TLONG]; + } + if(n->type->etype == TUCHAR || n->type->etype == TUSHORT) { + n->right = new1(OCAST, n->right, Z); + n->right->type = types[TULONG]; + n->type = types[TULONG]; + } + goto asop; + + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + case OAS: + xcom(l); + xcom(r); + if(typev[n->type->etype]) + break; + + asop: + if(l->addable > INDEXED && + l->complex < FNX && + r && r->complex < FNX) + n->addable = l->addable; + break; + + case OPOSTINC: + case OPREINC: + case OPOSTDEC: + case OPREDEC: + xcom(l); + if(typev[n->type->etype]) + break; + if(l->addable > INDEXED && + l->complex < FNX) + n->addable = l->addable; + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + +brk: + n->complex = 0; + 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 OADD: + case OMUL: + case OLMUL: + case OXOR: + case OAND: + case OOR: + /* + * symmetric operators, make right side simple + * if same, put constant on left to get movq + */ + if(r->complex > l->complex || + (r->complex == l->complex && r->addable == 20)) { + n->left = r; + n->right = l; + } + break; + + case OLE: + case OLT: + case OGE: + case OGT: + case OEQ: + case ONE: + /* + * relational operators, make right side simple + * if same, put constant on left to get movq + */ + if(r->complex > l->complex || r->addable == 20) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + } +} + +void +indx(Node *n) +{ + Node *l, *r; + int t; + + if(debug['x']) + prtree(n, "indx"); + t = 0; + +loop: + l = n->left; + r = n->right; + switch(r->addable) { + default: + if(t) { + diag(n, "bad indx"); + break; + } + n->right = l; + n->left = r; + t++; + goto loop; + + case 10: + case 11: + if(l->op == ONAME && r->op == ONAME) + if(l->etype == TIND) + if(r->etype != TIND) { + n->right = l; + n->left = r; + goto loop; + } + if(l->addable == 1 || l->addable == 12) { + n->right = l; + n->left = r; + goto loop; + } + + case 1: + case 12: + break; + } + if(l->addable != 7) { + idx.regtree = l; + idx.scale = 0; + } else + if(l->right->addable == 20) { + idx.regtree = l->left; + idx.scale = l->right->vconst; + } else { + idx.regtree = l->right; + idx.scale = l->left->vconst; + } + t = ewidth[idx.regtree->type->etype]; + if(t == SZ_LONG) + idx.scale += 4; + else + if(t != SZ_SHORT) + diag(n, "index not W or L"); + + idx.basetree = r; + if(debug['x']) { + print("scale = %d\n", idx.scale); + prtree(idx.regtree, "index"); + prtree(idx.basetree, "base"); + } +} + +void +bcomplex(Node *n) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type != T) { + bool64(n); + doinc(n, PRE); + boolgen(n, 1, D_NONE, Z, n); + } else + gbranch(OGOTO); +} + +Node* +nodconst(long v) +{ + + return (Node*)v; +} diff --git a/utils/2c/swt.c b/utils/2c/swt.c new file mode 100644 index 00000000..442d1fea --- /dev/null +++ b/utils/2c/swt.c @@ -0,0 +1,1046 @@ +#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(int g, 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(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, g, n); +} + +#define N1 4 /* ncase: always linear */ +#define N2 5 /* min ncase: direct */ +#define N3 4 /* range/ncase: direct */ + /* else binary */ +void +swit1(C1 *q, int nc, long def, int g, Node *n) +{ + C1 *r, *s; + int i, l, m, y; + long v, range; + Prog *sp1, *sp2; + + /* note that g and g+1 are not allocated */ + if(nc <= N1) + goto linear; + y = 23*nc/100 + 5; /* number of cases needed to make */ + if(y < N2) /* direct switch worthwile */ + y = N2; /* try to do better than n**2 here */ + for(m=nc; m>=y; m--) { /* m is number of cases */ + s = q+nc; + r = s-m; + for(l=nc-m; l>=0; l--) { /* l is base of contig cases */ + s--; + range = s->val - r->val; + if(range > 0 && range <= N3*m) + goto direct; + r--; + } + } + + /* + * divide and conquer + */ + i = nc / 2; + r = q+i; + v = r->val; + /* compare median */ + if(v >= -128 && v < 128) { + gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); + gopcode(OEQ, n->type, g, n, g+1, n); + } else + gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); + gbranch(OLT); + sp1 = p; + gbranch(OGT); + sp2 = p; + gbranch(OGOTO); + patch(p, r->label); + + patch(sp1, pc); + swit1(q, i, def, g, n); + + patch(sp2, pc); + swit1(r+1, nc-i-1, def, g, n); + return; + +direct: + /* compare low bound */ + v = r->val; + if(v >= -128 && v < 128) { + gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); + gopcode(OEQ, n->type, g, n, g+1, n); + } else + gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); + gbranch(OLT); + sp1 = p; + + /* compare high bound */ + v = s->val; + if(v >= -128 && v < 128) { + gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); + gopcode(OEQ, n->type, g, n, g+1, n); + } else + gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); + gbranch(OGT); + sp2 = p; + + /* switch */ + v = r->val; + gpseudo(AMOVW, symstatic, D_R0, 0L); + p->from.offset = nstatic - v*2; + p->from.index = g|I_INDEX1; + p->from.scale = 5; + nextpc(); + p->as = ACASEW; + + /* table */ + for(i=0; i<=range; i++) { + gbranch(OCASE); + if(v == r->val) { + patch(p, r->label); + r++; + } else + patch(p, def); + p->from.type = D_STATIC; + p->from.sym = symstatic; + p->from.offset = nstatic; + nstatic += types[TSHORT]->width; + v++; + } + gbranch(OGOTO); + patch(p, def); + if(r != s+1) + print("smelly direct switch\n"); + + if(l > 0) { + patch(sp1, pc); + swit1(q, l, def, g, n); + } else + patch(sp1, def); + + m += l; + if(m < nc) { + patch(sp2, pc); + swit1(q+m, nc-m, def, g, n); + } else + patch(sp2, def); + return; + + +linear: + for(i=0; i<nc; i++) { + v = q->val; + if(v >= -128 && v < 128) { + gopcode(OAS, n->type, D_CONST, nodconst(v), g+1, n); + gopcode(OEQ, n->type, g+1, n, g, n); + } else + gopcode(OEQ, n->type, g, n, D_CONST, nodconst(v)); + gbranch(OEQ); + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); +} + +void +cas(void) +{ + Case *c; + + c = alloc(sizeof(*c)); + c->link = cases; + cases = c; +} + + +int +bitload(Node *b, int n1, int n2, int n3, Node *nn) +{ + int sh, g, gs; + long v; + Node *l; + Type *t; + + /* + * n1 gets adjusted/masked value + * n2 gets address of cell + * n3 gets contents of cell + */ + gs = 0; + t = tfield; + + l = b->left; + g = regalloc(t, n3); + if(n2 != D_NONE) { + lcgen(l, n2, Z); + n2 |= I_INDIR; + gmove(t, t, n2, l, g, l); + gmove(t, t, g, l, n1, l); + } else + cgen(l, g, nn); + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, t, D_CONST, nodconst(v), g, l); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + if(sh >= 8) { + gs = regalloc(t, D_NONE); + gmove(t, t, D_CONST, nodconst(sh), gs, l); + gopcode(OASHL, t, gs, l, g, l); + if(b->type->shift) + regfree(gs); + } else + gopcode(OASHL, t, D_CONST, nodconst(sh), g, l); + sh += b->type->shift; + if(sh > 0) { + if(sh >= 8) { + if(b->type->shift) { + gs = regalloc(t, D_NONE); + gmove(t, t, D_CONST, nodconst(sh), gs, l); + } + if(typeu[b->type->etype]) + gopcode(OLSHR, t, gs, l, g, l); + else + gopcode(OASHR, t, gs, l, g, l); + regfree(gs); + } else { + if(typeu[b->type->etype]) + gopcode(OLSHR, t, D_CONST, nodconst(sh), g, l); + else + gopcode(OASHR, t, D_CONST, nodconst(sh), g, l); + } + } + } + return g; +} + +void +bitstore(Node *b, int n1, int n2, int n3, int result, Node *nn) +{ + long v; + Node *l; + Type *t; + int sh, g, gs; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + t = tfield; + + l = b->left; + g = regalloc(t, D_NONE); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, t, D_CONST, nodconst(v), n1, l); + gmove(t, t, n1, l, g, l); + if(result != D_NONE) + gmove(t, nn->type, n1, l, result, nn); + sh = b->type->shift; + if(sh > 0) { + if(sh >= 8) { + gs = regalloc(t, D_NONE); + gmove(t, t, D_CONST, nodconst(sh), gs, l); + gopcode(OASHL, t, gs, l, g, l); + regfree(gs); + } else + gopcode(OASHL, t, D_CONST, nodconst(sh), g, l); + } + v <<= sh; + gopcode(OAND, t, D_CONST, nodconst(~v), n3, l); + gopcode(OOR, t, n3, l, g, l); + gmove(t, t, g, l, n2|I_INDIR, l); + + regfree(g); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, D_SCONST, 0L); + memmove(p->to.sval, string, NSNAME); + p->from.offset = nstring - NSNAME; + p->from.displace = NSNAME; + mnstring = 0; + } + n--; + } + return r; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + 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; +} + +int +doinc(Node *n, int f) +{ + Node *l; + int a; + +loop: + if(n == Z) + return 0; + l = n->left; + switch(n->op) { + + case OPOSTINC: + case OPOSTDEC: + if(f & POST) { + a = n->addable; + if(a >= INDEXED) { + if(f & TEST) + return 1; + n->addable = 0; + cgen(n, D_NONE, n); + n->addable = a; + } + } + break; + + case OAS: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + + case OPREINC: + case OPREDEC: + if(f & PRE) { + a = n->addable; + if(a >= INDEXED) { + if(f & TEST) + return 1; + n->addable = 0; + doinc(n, PRE); + cgen(n, D_NONE, n); + n->addable = a; + return 0; + } + } + break; + + case OFUNC: + if(f & PRE) + break; + return 0; + + case ONAME: + case OREGISTER: + case OSTRING: + case OCONST: + + case OANDAND: + case OOROR: + return 0; + + case OCOND: + return 0; + + case OCOMMA: + n = n->right; + if(f & PRE) + n = l; + goto loop; + } + if(l != Z) + if(doinc(l, f)) + return 1; + n = n->right; + goto loop; +} + +void +setsp(void) +{ + + nextpc(); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = 0; +} + +void +adjsp(long o) +{ + + if(o != 0) { + nextpc(); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = o; + argoff += o; + } +} + +int +simplv(Node *n) +{ + + if(n->addable <= INDEXED) + return 0; + while(n->op == OIND) + n = n->left; + if(n->op == ONAME) + return 1; + return 0; +} + +int +eval(Node *n, int g) +{ + + if(n->addable >= INDEXED) + return D_TREE; + g = regalloc(n->type, g); + cgen(n, g, n); + return g; +} + +void outhist(Biobuf*); +void zname(Biobuf*, Sym*, int); +void zaddr(Biobuf*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); + +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, "cant open %s", outfile); + errorexit(); + } + 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 & D_MASK; + 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 & D_MASK; + 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; + } + zwrite(&b, p, sf, st); + } + Bflush(&b); + close(f); + firstp = P; + lastp = P; +} + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + long l; + + l = p->as; + Bputc(b, l); + Bputc(b, l>>8); + l = p->lineno; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + zaddr(b, &p->from, sf); + zaddr(b, &p->to, st); +} + +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->field) + t |= T_FIELD; + if(a->index != D_NONE) + t |= T_INDEX; + if(s) + t |= T_SYM; + + switch(a->type) { + default: + if(a->offset) + t |= T_OFFSET; + if(a->displace) + t |= T_INDEX; + if(a->type & ~0xff) + t |= T_TYPE; + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + Bputc(b, t); + + if(t & T_FIELD) { /* implies field */ + i = a->field; + Bputc(b, i); + Bputc(b, i>>8); + } + if(t & T_INDEX) { /* implies index, scale, displace */ + i = a->index; + Bputc(b, i); + Bputc(b, i>>8); + Bputc(b, a->scale); + l = a->displace; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + } + 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; + } + i = a->type; + Bputc(b, i); + if(t & T_TYPE) + Bputc(b, i>>8); +} + + + +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; + + zwrite(b, &pg, 0, 0); + } +} + +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); +} + +int +nodalloc(Type *t, int g, Node *n) +{ + + n->type = t; + n->op = OREGISTER; + n->addable = 12; + n->complex = 0; + g = regaddr(g); + n->reg = g | I_INDIR; + n->xoffset = 0; + return g; +} + +int +mulcon(Node *n, Node *c, int result, Node *nn) +{ + long v; + + if(typefd[n->type->etype]) + return 0; + v = c->vconst; + if(mulcon1(n, v, result, nn)) + return 1; + return 0; +} + +int +shlcon(Node *n, Node *c, int result, Node *nn) +{ + long v; + + v = 1L << c->vconst; + return mulcon1(n, v, result, nn); +} + +int +mulcon1(Node *n, long v, int result, Node *nn) +{ + int g, g1, a1, a2, neg; + int o; + char code[10], *p; + + if(result == D_NONE) + return 0; + neg = 0; + if(v < 0) { + v = -v; + neg++; + } + a1 = 0; + a2 = multabsize; + for(;;) { + if(a1 >= a2) + return 0; + g1 = (a2 + a1)/2; + if(v < multab[g1].val) { + a2 = g1; + continue; + } + if(v > multab[g1].val) { + a1 = g1+1; + continue; + } + break; + } + strcpy(code, "0"); + strncat(code, multab[g1].code, sizeof(multab[0].code)); + p = code; + if(p[1] == 'i') + p += 2; + g = regalloc(n->type, result); + cgen(n, g, n); + if(neg) + gopcode(ONEG, n->type, D_NONE, n, g, n); + g1 = regalloc(n->type, D_NONE); +loop: + switch(*p) { + case 0: + regfree(g1); + gmove(n->type, nn->type, g, n, result, nn); + regfree(g); + return 1; + case '0': + o = OAS; + *p -= '0'; + goto com; + case '1': + case '2': + o = OSUB; + *p -= '1'; + goto com; + case '3': + case '4': + case '5': + case '6': + o = OADD; + *p -= '3'; + com: + a1 = g; + if(*p == 1 || *p == 3) + a1 = g1; + a2 = g; + if(*p == 0 || *p == 3) + a2 = g1; + gopcode(o, n->type, a1, n, a2, n); + p++; + break; + default: + a1 = *p++ - 'a' + 1; + a2 = g; + if(a1 > 8) { + a2 = g1; + a1 -= 8; + } + gopcode(OASHL, n->type, D_CONST, nodconst(a1), a2, n); + break; + } + goto loop; +} + +void +nullwarn(Node *l, Node *r) +{ + warn(Z, "result of operation not used"); + if(l != Z) + cgen(l, D_NONE, Z); + if(r != Z) + cgen(r, D_NONE, 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, D_SCONST, 0L); + p->from.offset += o+e; + p->from.displace = lw; + 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, D_CONST, (long)(a->vconst>>32)); + p->from.offset += o; + p->from.displace = 4; + gpseudo(ADATA, s, D_CONST, (long)(a->vconst)); + p->from.offset += o + 4; + p->from.displace = 4; + return; + } + gpseudotree(ADATA, s, a); + p->from.offset += o; + p->from.displace = w; +} + +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_SHORT) + w = SZ_SHORT; + 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; + } + o += SZ_LONG - w; /* big endian adjustment */ + w = 1; + 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; +} diff --git a/utils/2c/txt.c b/utils/2c/txt.c new file mode 100644 index 00000000..2723c6d6 --- /dev/null +++ b/utils/2c/txt.c @@ -0,0 +1,940 @@ +#include "gc.h" + +void +tindex(Type *tf, Type *tt) +{ + int i, j; + + j = 0; + if(tt != T) { + j = tt->etype; + if(j >= NTYPE) + j = 0; + } + i = 0; + if(tf != T) { + i = tf->etype; + if(i >= NTYPE) + if(typesu[i]) + i = j; + else + i = 0; + } + txtp = &txt[i][j]; +} + +void +ginit(void) +{ + int i, j, si, sj; + + thestring = "68020"; + thechar = '2'; + exregoffset = 7; + exaregoffset = 5; + exfregoffset = 7; + listinit(); + for(i=0; i<NREG; i++) { + regused[i] = 0; + fregused[i] = 0; + aregused[i] = 0; + } + regaddr(D_A0+6); + regaddr(D_A0+7); + for(i=0; i<sizeof(regbase); i++) + regbase[i] = D_NONE; + for(i=0; i<NREG; i++) { + regbase[D_R0+i] = D_R0+i; + regbase[D_A0+i] = D_A0+i; + regbase[D_F0+i] = D_F0+i; + } + regbase[D_TOS] = D_TOS; + + for(i=0; i<NTYPE; i++) + for(j=0; j<NTYPE; j++) { + txtp = &txt[i][j]; + txtp->movas = AGOK; + txtp->preclr = 0; + txtp->postext = AGOK; + if(!(typechlp[i] && typechlp[j])) + continue; + si = types[i]->width; + sj = types[j]->width; + if(sj < si) + txtp->preclr = -1; + if(sj > si) { + if(typeu[i]) { + txtp->preclr = 1; + } else { + if(sj == 2) + txtp->postext = AEXTBW; + if(sj == 4) + if(si == 1) + txtp->postext = AEXTBL; + else + txtp->postext = AEXTWL; + } + sj = si; + } + if(sj == 1) + txtp->movas = AMOVB; + if(sj == 2) + txtp->movas = AMOVW; + if(sj == 4) + txtp->movas = AMOVL; + } + + for(i=0; i<ALLOP; i++) + for(j=0; j<NTYPE; j++) + opxt[i][j] = AGOK; + oinit(OFUNC, ABSR, ATRAP, AGOK, AGOK, AGOK); + + oinit(OAS, AMOVB, AMOVW, AMOVL, AFMOVEF, AFMOVED); + oinit(OFAS, AFMOVEB, AFMOVEW, AFMOVEL, AFMOVEF, AFMOVED); + oinit(OADDR, AGOK, APEA, ALEA, AGOK, AGOK); + oinit(OPREINC, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OPOSTINC, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OPREDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OPOSTDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OADD, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OASADD, AADDB, AADDW, AADDL, AFADDF, AFADDD); + oinit(OSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OASSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD); + oinit(OMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(OLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(OASMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(OASLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD); + oinit(ODIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD); + oinit(OLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD); + oinit(OASDIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD); + oinit(OASLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD); + oinit(OMOD, AGOK, ADIVSW, ADIVSL, AFMODF, AFMODD); + oinit(OASMOD, AGOK, ADIVSW, ADIVSL, AGOK, AGOK); + oinit(OLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK); + oinit(OASLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK); + oinit(OAND, AANDB, AANDW, AANDL, AGOK, AGOK); + oinit(OASAND, AANDB, AANDW, AANDL, AGOK, AGOK); + oinit(OOR, AORB, AORW, AORL, AGOK, AGOK); + oinit(OASOR, AORB, AORW, AORL, AGOK, AGOK); + oinit(OXOR, AEORB, AEORW, AEORL, AGOK, AGOK); + oinit(OASXOR, AEORB, AEORW, AEORL, AGOK, AGOK); + oinit(ONEG, ANEGB, ANEGW, ANEGL, AFNEGF, AFNEGD); + oinit(OCOM, ANOTB, ANOTW, ANOTL, AGOK, AGOK); + oinit(OTST, ATSTB, ATSTW, ATSTL, AFTSTF, AFTSTD); + oinit(OEQ, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(ONE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OGE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OGT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OLO, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OHS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OHI, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD); + oinit(OASHR, AASRB, AASRW, AASRL, AGOK, AGOK); + oinit(OASASHR, AASRB, AASRW, AASRL, AGOK, AGOK); + oinit(OLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK); + oinit(OASLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK); + oinit(OASHL, AASLB, AASLW, AASLL, AGOK, AGOK); + oinit(OASASHL, AASLB, AASLW, AASLL, AGOK, AGOK); + oinit(OBIT, ABFEXTU, AGOK, AGOK, AGOK, AGOK); + + nstring = 0; + mnstring = 0; + nrathole = 0; + nstatic = 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.to = zprog.from; + + nodret = new(ONAME, Z, Z); + nodret->sym = slookup(".ret"); + nodret->type = types[TIND]; + nodret->etype = types[TIND]->etype; + nodret->class = CPARAM; + nodret = new(OIND, nodret, Z); + complex(nodret); + + symrathole = slookup(".rathole"); + symrathole->class = CGLOBL; + symrathole->type = typ(TARRAY, types[TCHAR]); + nodrat = new(ONAME, Z, Z); + nodrat->sym = symrathole; + nodrat->type = types[TIND]; + nodrat->etype = TVOID; + nodrat->class = CGLOBL; + complex(nodrat); + nodrat->type = symrathole->type; + + com64init(); + + symstatic = slookup(".static"); + symstatic->class = CSTATIC; + symstatic->type = typ(TARRAY, types[TLONG]); +} + +void +gclean(void) +{ + int i; + Sym *s; + + regfree(D_A0+6); + regfree(D_A0+7); + for(i=0; i<NREG; i++) { + if(regused[i]) + diag(Z, "missing R%d", i); + if(aregused[i]) + diag(Z, "missing A%d", i); + if(fregused[i]) + diag(Z, "missing F%d", i); + } + + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symstatic->type->width = nstatic; + 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, D_CONST, s->type->width); + pc--; + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +oinit(int o, int ab, int aw, int al, int af, int ad) +{ + int i; + + i = o; + if(i >= ALLOP) { + diag(Z, "op(%d) >= ALLOP(%d)", i, ALLOP); + errorexit(); + } + opxt[i][TCHAR] = ab; + opxt[i][TUCHAR] = ab; + opxt[i][TSHORT] = aw; + opxt[i][TUSHORT] = aw; + opxt[i][TINT] = al; + opxt[i][TUINT] = al; + opxt[i][TLONG] = al; + opxt[i][TULONG] = al; + opxt[i][TIND] = al; + opxt[i][TFLOAT] = af; + opxt[i][TDOUBLE] = ad; +} + +Prog* +prg(void) +{ + Prog *p; + + p = alloc(sizeof(*p)); + *p = zprog; + return p; +} + +void +nextpc(void) +{ + + p = prg(); + pc++; + p->lineno = nearln; + if(firstp == P) { + firstp = p; + lastp = p; + return; + } + lastp->link = p; + lastp = p; +} + +void +gargs(Node *n) +{ + long s; + +loop: + if(n == Z) + return; + if(n->op == OLIST) { + gargs(n->right); + n = n->left; + goto loop; + } + s = argoff; + cgen(n, D_TOS, n); + argoff = s + n->type->width; +} + +void +naddr(Node *n, Adr *a, int x) +{ + Node *l; + long v; + + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OADDR: + case OIND: + naddr(n->left, a, x); + goto noadd; + + case OREGISTER: + a->sym = S; + a->type = n->reg; + a->offset = n->xoffset; + a->displace = 0; + break; + + case ONAME: + a->etype = n->etype; + a->displace = 0; + a->sym = n->sym; + a->offset = n->xoffset; + a->type = D_STATIC; + 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 OINDEX: + naddr(n->left, a, x); + switch(n->left->addable) { + default: + goto bad; + case 1: + case 12: + a->index = x | I_INDEX1; + a->type &= D_MASK; + break; + case 2: + case 10: + case 11: + a->index = x | I_INDEX2; + break; + } + a->scale = n->scale; + break; + + case OCONST: + a->displace = 0; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + break; + } + a->type = D_CONST; + a->offset = n->vconst; + break; + + case OADD: + l = n->left; + if(l->addable == 20) { + v = l->vconst; + naddr(n->right, a, x); + goto add; + } + l = n->right; + if(l->addable == 20) { + v = l->vconst; + naddr(n->left, a, x); + goto add; + } + goto bad; + noadd: + v = 0; + add: + switch(n->addable) { + default: + goto bad; + case 2: + a->displace += v; + break; + case 21: + a->type &= D_MASK; + a->type |= I_INDIR; + break; + case 1: + case 12: + a->offset += v; + a->type &= D_MASK; + a->type |= I_ADDR; + break; + case 13: + a->index = D_NONE|I_INDEX3; + case 10: + case 11: + case 20: + a->type &= D_MASK; + a->type |= I_DIR; + break; + } + break; + + case OPREINC: + case OPREDEC: + case OPOSTINC: + case OPOSTDEC: + + case OAS: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + case OASXOR: + case OASOR: + case OASADD: + case OASSUB: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASAND: + naddr(n->left, a, x); + break; + } +} + +int +regalloc(Type *t, int g) +{ + + if(t == T) + return D_NONE; + g &= D_MASK; + if(typefd[t->etype]) { + if(g >= D_F0 && g < D_F0+NREG) { + fregused[g-D_F0]++; + return g; + } + for(g=0; g<NREG; g++) + if(fregused[g] == 0) { + fregused[g]++; + return g + D_F0; + } + } else { + if(g >= D_R0 && g < D_R0+NREG) { + regused[g-D_R0]++; + return g; + } + for(g=0; g<NREG; g++) + if(regused[g] == 0) { + regused[g]++; + return g + D_R0; + } + } + diag(Z, "out of registers"); + return D_TOS; +} + +int +regaddr(int g) +{ + + if(g >= D_A0 && g < D_A0+NREG) { + aregused[g-D_A0]++; + return g; + } + for(g=0; g<NREG; g++) + if(aregused[g] == 0) { + aregused[g]++; + return g + D_A0; + } + diag(Z, "out of addr registers"); + return D_TOS; +} + +int +regpair(int g) +{ + + if(g >= D_R0+1 && g < D_R0+NREG) + if(!regused[g-D_R0-1]) { + regused[g-D_R0-1]++; + regused[g-D_R0]++; + return g-1; + } + if(g >= D_R0 && g < D_R0+NREG-1) + if(!regused[g-D_R0+1]) { + regused[g-D_R0+1]++; + regused[g-D_R0]++; + return g; + } + for(g = 0; g < NREG-1; g++) + if(!regused[g]) + if(!regused[g+1]) { + regused[g]++; + regused[g+1]++; + return g + D_R0; + } + diag(Z, "out of register pairs"); + return D_TOS; +} + +int +regret(Type *t) +{ + + if(t == T) + return D_NONE; + if(typefd[t->etype]) + return D_F0; + return D_R0; +} + +void +regfree(int g) +{ + + g &= D_MASK; + if(g == D_TOS || g == D_TREE || g == D_NONE) + return; + if(g >= D_R0 && g < D_R0+NREG) { + regused[g-D_R0]--; + return; + } + if(g >= D_A0 && g < D_A0+NREG) { + aregused[g-D_A0]--; + return; + } + if(g >= D_F0 && g < D_F0+NREG) { + fregused[g-D_F0]--; + return; + } + diag(Z, "bad in regfree: %d", g); +} + +void +gmove(Type *tf, Type *tt, int gf, Node *f, int gt, Node *t) +{ + int g, a, b; + Prog *p1; + + tindex(tf, tt); + if(txtp->preclr) { + if(gf >= D_R0 && gf < D_R0+NREG) + if(txtp->preclr < 0) { + gmove(tt, tt, gf, f, gt, t); + return; + } + g = regalloc(types[TLONG], gt); + if(g == gf) { + g = regalloc(types[TLONG], D_NONE); + regfree(gf); + } + if(txtp->preclr > 0) + gopcode(OAS, types[TLONG], D_CONST, nodconst(0), g, Z); + gopcode(OAS, tf, gf, f, g, Z); + if(g != gt) + gopcode(OAS, tt, g, Z, gt, t); + regfree(g); + return; + } + a = txtp->postext; + if(a != AGOK) { + if(gf >= D_R0 && gf < D_R0+NREG) + g = regalloc(types[TLONG], gf); + else + g = regalloc(types[TLONG], gt); + if(g != gf) + gopcode(OAS, tf, gf, f, g, Z); + nextpc(); + p->as = a; + p->to.type = g; + if(debug['g']) + print("%P\n", p); + if(g != gt) + gopcode(OAS, tt, g, Z, gt, t); + regfree(g); + return; + } + if((regbase[gf] != D_NONE && regbase[gf] == regbase[gt]) || + (gf == D_TREE && gt == D_TREE && f == t)) + return; + if(typefd[tf->etype] || typefd[tt->etype]) { + if(typeu[tf->etype] && typefd[tt->etype]) { /* unsign->float */ + a = regalloc(types[TLONG], D_NONE); + gmove(tf, types[TLONG], gf, f, a, t); + if(tf->etype == TULONG) { + b = regalloc(types[TDOUBLE], D_NONE); + gmove(types[TLONG], tt, a, t, b, t); + gopcode(OTST, types[TLONG], D_NONE, Z, a, t); + gbranch(OGE); + p1 = p; + gopcode(OASADD, types[TDOUBLE], + D_CONST, nodconst(100), b, t); + p->from.dval = 4294967296.; + patch(p1, pc); + gmove(types[TDOUBLE], tt, b, t, gt, t); + regfree(b); + } else + gmove(types[TLONG], tt, a, t, gt, t); + regfree(a); + return; + } + if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */ + a = regalloc(types[TLONG], D_NONE); + gopcode(OAS, types[TLONG], D_FPCR, t, a, t); + gopcode(OAS, types[TLONG], D_CONST, nodconst(16), D_FPCR, t); + } + if(gf < D_F0 || gf >= D_F0+NREG) { + g = regalloc(types[TDOUBLE], gt); + gopcode(OFAS, tf, gf, f, g, t); + if(g != gt) + gopcode(OFAS, tt, g, t, gt, t); + regfree(g); + } else + gopcode(OFAS, tt, gf, f, gt, t); + if(typefd[tf->etype] && !typefd[tt->etype]) { /* float->fix */ + gopcode(OAS, types[TLONG], a, t, D_FPCR, t); + regfree(a); + } + return; + } + gopcode(OAS, tt, gf, f, gt, t); +} + +void +gopcode(int o, Type *ty, int gf, Node *f, int gt, Node *t) +{ + int i, fidx, tidx; + long v; + + if(o == OAS) + if(gf == gt) + if(gf != D_TREE || f == t) + return; + + fidx = D_NONE; + if(gf == D_TREE) { + if(f->op == OINDEX) { + fidx = regalloc(types[TIND], fidx); + cgen(f->right, fidx, f->right); + } + } + tidx = D_NONE; + if(gt == D_TREE) { + if(t->op == OINDEX) { + v = argoff; + tidx = regalloc(types[TIND], tidx); + cgen(t->right, tidx, t->right); + if(gf == D_TOS) + adjsp(v - argoff); + } + } + i = 0; + if(ty != T) { + i = ty->etype; + if(i >= NTYPE) + i = 0; + } + nextpc(); + if(gf == D_TREE) { + naddr(f, &p->from, fidx); + } else { + p->from.type = gf; + if(gf == D_CONST) { + p->from.offset = (long)(uintptr)f; + if(typefd[i]) { + p->from.type = D_FCONST; + p->from.dval = (long)(uintptr)f; + } + } + } + p->as = opxt[o][i]; + if(gt == D_TREE) { + naddr(t, &p->to, tidx); + } else { + p->to.type = gt; + if(gt == D_CONST) + p->to.offset = (long)(uintptr)t; + } + if(o == OBIT) { + p->from.field = f->type->nbits; + p->to.field = f->type->shift; + if(p->from.field == 0) + diag(Z, "BIT zero width bit field"); + } + if(p->as == AMOVL || p->as == AMOVW || p->as == AMOVB) + asopt(); + if(debug['g']) + print("%P\n", p); + if(p->as == AGOK) + diag(Z, "GOK in gopcode: %s", onames[o]); + if(fidx != D_NONE) + regfree(fidx); + if(tidx != D_NONE) + regfree(tidx); +} + +void +asopt(void) +{ + long v; + int g; + Prog *q; + + /* + * mov $0, ... + * ==> + * clr , ... + */ + v = 0; + if(p->from.type == D_CONST) { + v = p->from.offset; + if(v == 0) { + p->from.type = D_NONE; + if(p->as == AMOVL) + p->as = ACLRL; + if(p->as == AMOVW) + p->as = ACLRW; + if(p->as == AMOVB) + p->as = ACLRB; + return; + } + } + /* + * mov ..., TOS + * ==> + * pea (...) + */ + if(p->as == AMOVL && p->to.type == D_TOS && p->from.index == D_NONE) + switch(p->from.type) { + case D_CONST: + p->from.type |= I_INDIR; + p->to = p->from; + p->from = zprog.from; + p->as = APEA; + return; + + case I_ADDR|D_EXTERN: + case I_ADDR|D_STATIC: + p->from.type &= ~I_ADDR; + p->to = p->from; + p->from = zprog.from; + p->as = APEA; + return; + } + /* + * movL $Qx, ... + * ==> + * movL $Qx,R + * movL R, ... + */ + if(p->as == AMOVL && p->from.type == D_CONST) + if(v >= -128 && v < 128) + if(p->to.type < D_R0 || p->to.type >= D_R0+NREG) { + g = regalloc(types[TLONG], D_NONE); + q = p; + nextpc(); + p->as = AMOVL; + p->from.type = g; + p->to = q->to; + q->to = p->from; + regfree(g); + if(debug['g']) + print("%P\n", q); + return; + } +} + +void +gbranch(int o) +{ + int a; + + a = ABNE; + switch(o) { + case ORETURN: a = ARTS; break; + case OGOTO: a = ABRA; break; + case OEQ: a = ABEQ; break; + case ONE: a = ABNE; break; + case OLE: a = ABLE; break; + case OLS: a = ABLS; break; + case OLT: a = ABLT; break; + case OLO: a = ABCS; break; + case OGE: a = ABGE; break; + case OHS: a = ABCC; break; + case OGT: a = ABGT; break; + case OHI: a = ABHI; break; + case OBIT: a = ABCS; break; + case OCASE: a = ABCASE; break; + } + nextpc(); + p->from.type = D_NONE; + p->to.type = D_NONE; + p->as = a; +} + +void +fpbranch(void) +{ + int a; + + a = p->as; + switch(a) { + case ABEQ: a = AFBEQ; break; + case ABNE: a = AFBNE; break; + case ABLE: a = AFBLE; break; + case ABLT: a = AFBLT; break; + case ABGE: a = AFBGE; break; + case ABGT: a = AFBGT; break; + } + p->as = a; +} + +void +patch(Prog *op, long pc) +{ + + op->to.offset = pc; + op->to.type = D_BRANCH; +} + +void +gpseudo(int a, Sym *s, int g, long v) +{ + + nextpc(); + if(a == ADATA) + pc--; + p->as = a; + if(g == D_TREE) + abort(); /* obsolete */ + p->to.type = g; + p->to.offset = v; + p->from.sym = s; + p->from.type = D_EXTERN; + if(s->class == CSTATIC) + p->from.type = D_STATIC; +} + +void +gpseudotree(int a, Sym *s, Node *n) +{ + nextpc(); + if(a == ADATA) + pc--; + p->as = a; + naddr(n, &p->to, D_NONE); + p->from.sym = s; + p->from.type = D_EXTERN; + if(s->class == CSTATIC) + p->from.type = D_STATIC; +} + +long +exreg(Type *t) +{ + long o; + + if(typechl[t->etype]) { + if(exregoffset <= 5) + return 0; + o = exregoffset + D_R0; + exregoffset--; + return o; + } + if(t->etype == TIND) { + if(exaregoffset <= 3) + return 0; + o = exaregoffset + D_A0; + exaregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 5) + return 0; + o = exfregoffset + D_F0; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; +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] */ +}; diff --git a/utils/2l/Nt.c b/utils/2l/Nt.c new file mode 100644 index 00000000..2efff499 --- /dev/null +++ b/utils/2l/Nt.c @@ -0,0 +1,77 @@ +#include <windows.h> +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/2l/Plan9.c b/utils/2l/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/2l/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/2l/Posix.c b/utils/2l/Posix.c new file mode 100644 index 00000000..aa5d9551 --- /dev/null +++ b/utils/2l/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fials if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} diff --git a/utils/2l/asm.c b/utils/2l/asm.c new file mode 100644 index 00000000..10129e98 --- /dev/null +++ b/utils/2l/asm.c @@ -0,0 +1,1569 @@ +#include "l.h" + +short opa[20]; +short *op; + +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; + if(s->type != STEXT) + diag("entry not text: %s", s->name); + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long v; + int a; + short *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; + if(debug['a']) + Bprint(&bso, "%lux:%P\n", pc, curp); + asmins(p); + if(cbc < sizeof(opa)) + cflush(); + for(op1 = opa; op1 < op; op1++) { + a = *op1; + *cbp++ = a >> 8; + *cbp++ = a; + } + a = 2*(op - opa); + pc += a; + cbc -= a; + if(debug['a']) { + for(op1 = opa; op1 < op; op1++) + if(op1 == opa) + Bprint(&bso, "\t\t%4ux", *op1 & 0xffff); + else + Bprint(&bso, " %4ux", *op1 & 0xffff); + if(op != opa) + Bprint(&bso, "\n"); + } + } + cflush(); + switch(HEADTYPE) { + case 0: /* this is garbage */ + seek(cout, rnd(HEADR+textsize, 8192), 0); + break; + case 1: /* plan9 boot data goes into text */ + seek(cout, rnd(HEADR+textsize, INITRND), 0); + break; + case 2: /* plan 9 */ + seek(cout, HEADR+textsize, 0); + break; + case 3: /* next boot */ + seek(cout, HEADR+rnd(textsize, INITRND), 0); + break; + case 4: /* preprocess pilot */ + seek(cout, HEADR+textsize, 0); + break; + } + + if(debug['v']) + Bprint(&bso, "%5.2f datblk\n", cputime()); + Bflush(&bso); + + for(v = 0; v < datsize; v += sizeof(buf)-100) { + if(datsize-v > sizeof(buf)-100) + datblk(v, sizeof(buf)-100); + else + datblk(v, datsize-v); + } + + symsize = 0; + spsize = 0; + lcsize = 0; + + Bflush(&bso); + + switch(HEADTYPE) { + default: + seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0); + break; + case 1: /* plan9 boot data goes into text */ + seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); + break; + case 2: /* plan 9 */ + seek(cout, HEADR+textsize+datsize, 0); + break; + case 3: /* next boot */ + seek(cout, HEADR+rnd(textsize, INITRND)+datsize, 0); + break; + } + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + asmsym(); + } + Bflush(&bso); + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + asmsp(); + } + Bflush(&bso); + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + asmlc(); + } + cflush(); + + if(debug['v']) + Bprint(&bso, "%5.2f headr\n", cputime()); + Bflush(&bso); + seek(cout, 0L, 0); + switch(HEADTYPE) { + default: + 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; + case 1: /* plan9 boot data goes into text */ + lput(0407); /* magic */ + lput(rnd(HEADR+textsize, INITRND)-HEADR+datsize); /* sizes */ + lput(0); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + case 2: /* plan 9 */ + lput(0407); /* 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: /* next boot */ + /* header */ + lput(0xfeedfaceL); /* magic */ + lput(6); /* 68040 */ + lput(1); /* more 68040 */ + lput(5); /* file type 'boot' */ + lput(HEADTYPE); /* number commands */ + lput(HEADR-7*4); /* sizeof commands */ + lput(1); /* no undefineds */ + /* command 1 text */ + lput(1); /* command = 'segment' */ + lput(124); /* command size */ + s16put("__TEXT"); + /* botch?? entryvalue() */ + lput(INITTEXT); /* va of start */ + lput(rnd(textsize, 8192)); /* va size */ + lput(HEADR); /* file offset */ + lput(rnd(textsize, 8192)); /* file size */ + lput(7); /* max prot */ + lput(7); /* init prot */ + lput(1); /* number of sections */ + lput(0); /* flags */ + /* text section */ + s16put("__text"); + s16put("__TEXT"); + /* botch?? entryvalue() */ + lput(INITTEXT); /* va of start */ + lput(textsize); /* va size */ + lput(HEADR); /* file offset */ + lput(2); /* align */ + lput(0); /* reloff */ + lput(0); /* nreloc */ + lput(0); /* flags */ + lput(0); /* reserved1 */ + lput(0); /* reserved2 */ + /* command 1 data */ + lput(1); /* command = 'segment' */ + lput(192); /* command size */ + s16put("__DATA"); + lput(INITDAT); /* va of start */ + lput(rnd(datsize, 8192)); /* va size */ + lput(HEADR+rnd(textsize, 8192)); /* file offset */ + lput(rnd(datsize, 8192)); /* file size */ + lput(7); /* max prot */ + lput(7); /* init prot */ + lput(2); /* number of sections */ + lput(0); /* flags */ + /* data section */ + s16put("__data"); + s16put("__DATA"); + lput(INITDAT); /* va of start */ + lput(datsize); /* va size */ + lput(HEADR+rnd(textsize, 8192)); /* file offset */ + lput(2); /* align */ + lput(0); /* reloff */ + lput(0); /* nreloc */ + lput(0); /* flags */ + lput(0); /* reserved1 */ + lput(0); /* reserved2 */ + /* bss section */ + s16put("__bss"); + s16put("__DATA"); + lput(INITDAT+datsize); /* va of start */ + lput(bsssize); /* va size */ + lput(0); /* file offset */ + lput(2); /* align */ + lput(0); /* reloff */ + lput(0); /* nreloc */ + lput(1); /* flags = zero fill */ + lput(0); /* reserved1 */ + lput(0); /* reserved2 */ + /* command 2 symbol */ + lput(2); /* command = 'symbol' */ + lput(24); /* command size */ + lput(HEADR+rnd(textsize, INITRND) + +datsize); /* symoff */ + lput(symsize); /* nsyms */ + lput(spsize); /* sp offsets */ + lput(lcsize); /* line offsets */ + break; + } + cflush(); +} + +void +asmins(Prog *p) +{ + Optab *o; + int t, a, b; + long v; + Prog *q; + + op = opa + 1; + if(special[p->from.type]) + switch(p->from.type) { + + case D_CCR: + if(p->as != AMOVW) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x42c0 | a; /* mov from ccr */ + return; + + case D_SR: + if(p->as != AMOVW) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x40c0 | a; /* mov from sr */ + return; + + case D_USP: + if(p->as != AMOVL) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 010) { + opa[0] = 0x4e68|(a&7); /* mov usp An */ + return; + } + t = 0x800; + goto movec1; + + case D_SFC: + t = 0x000; + goto movec1; + + case D_DFC: + t = 0x001; + goto movec1; + + case D_CACR: + t = 0x002; + goto movec1; + + case D_TC: + t = 0x003; + goto movec1; + + case D_ITT0: + t = 0x004; + goto movec1; + + case D_ITT1: + t = 0x005; + goto movec1; + + case D_DTT0: + t = 0x006; + goto movec1; + + case D_DTT1: + t = 0x007; + goto movec1; + + case D_VBR: + t = 0x801; + goto movec1; + + case D_CAAR: + t = 0x802; + goto movec1; + + case D_MSP: + t = 0x803; + goto movec1; + + case D_ISP: + t = 0x804; + goto movec1; + + case D_MMUSR: + t = 0x805; + goto movec1; + + case D_URP: + t = 0x806; + goto movec1; + + case D_SRP: + t = 0x807; + goto movec1; + + movec1: + if(p->as != AMOVL) + goto bad; + opa[0] = 0x4e7a; /* mov spc Dn */ + a = asmea(p, &p->to); + b = a & 0170; + if(b == 0 || b == 010) { + *op++ = (a<<12) | t; + return; + } + goto bad; + + case D_FPCR: + t = 0xb000; + goto movec3; + + case D_FPSR: + t = 0xa800; + goto movec3; + + case D_FPIAR: + t = 0xa400; + + movec3: + if(p->as != AMOVL) + goto bad; + op++; + a = asmea(p, &p->to); + opa[0] = optab[AFMOVEL].opcode0 | a; + opa[1] = t; + return; + } + if(special[p->to.type]) + switch(p->to.type) { + + case D_CCR: + if(p->as != AMOVW) /* botch, needs and, eor etc. */ + goto bad; + a = asmea(p, &p->from); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x44c0 | a; /* mov to ccr */ + return; + + case D_SR: + if(p->as != AMOVW) /* botch, needs and, eor etc. */ + goto bad; + a = asmea(p, &p->from); + if((a & 0170) == 010) + goto bad; + opa[0] = 0x46c0 | a; /* mov to sr */ + return; + + case D_USP: + if(p->as != AMOVL) + goto bad; + a = asmea(p, &p->from); + if((a & 0170) == 010) { + opa[0] = 0x4e60|(a&7); /* mov An usp */ + return; + } + t = 0x800; + goto movec2; + + case D_SFC: + t = 0x000; + goto movec2; + + case D_DFC: + t = 0x001; + goto movec2; + + case D_CACR: + t = 0x002; + goto movec2; + + case D_TC: + t = 0x003; + goto movec2; + + case D_ITT0: + t = 0x004; + goto movec2; + + case D_ITT1: + t = 0x005; + goto movec2; + + case D_DTT0: + t = 0x006; + goto movec2; + + case D_DTT1: + t = 0x007; + goto movec2; + + case D_VBR: + t = 0x801; + goto movec2; + + case D_CAAR: + t = 0x802; + goto movec2; + + case D_MSP: + t = 0x803; + goto movec2; + + case D_ISP: + t = 0x804; + goto movec2; + + case D_MMUSR: + t = 0x805; + goto movec2; + + case D_URP: + t = 0x806; + goto movec2; + + case D_SRP: + t = 0x807; + goto movec2; + + movec2: + if(p->as != AMOVL) + goto bad; + opa[0] = 0x4e7b; /* mov Dn spc */ + a = asmea(p, &p->from); + b = a & 0170; + if(b == 0 || b == 010) { + *op++ = (a<<12) | t; + return; + } + goto bad; + + case D_FPCR: + t = 0x9000; + goto movec4; + + case D_FPSR: + t = 0x8800; + goto movec4; + + case D_FPIAR: + t = 0x8400; + + movec4: + if(p->as != AMOVL) + goto bad; + op++; + a = asmea(p, &p->from); + opa[0] = optab[AFMOVEL].opcode0 | a; + opa[1] = t; + return; + } + + o = &optab[p->as]; + t = o->opcode0; + switch(o->optype) { + case 0: /* pseudo ops */ + if(p->as != ATEXT && p->as != ANOP) { + if(!debug['a']) + print("%P\n", p); + diag("unimplemented instruction in %s", TNAME); + return; + } + op = opa; + return; + + case 1: /* branches */ + if(p->to.type != D_BRANCH) + goto bad; + a = asmea(p, &p->to); + /* hack to turn 3-word bsr into 2-word jsr */ + if(a == 0xff && p->as == ABSR && + p->pcond->pc < 32768L && p->pcond->pc >= 0) { + op = opa + 1; + t = o->opcode1; + *op++ = p->pcond->pc; + break; + } + t |= a; + break; + + case 2: /* move */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 0110) { /* src quick */ + t = o->opcode1; + if((b & 0170) != 0) + goto bad; + t |= a >> 7; + t |= b << 9; + break; + } + t |= a; + t |= (b&7) << 9; + t |= (b&070) << 3; + break; + + case 3: /* add */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 0110) { /* src quick */ + t = o->opcode1; + t |= (a&01600) << 2; + t |= b; + break; + } + if((b & 0170) == 0) { /* dst Dn */ + t |= a; + t |= (b & 7) << 9; + break; + } + if((b & 0170) == 010) { /* dst An */ + if((t & 0xc0) == 0) + goto bad; + t = o->opcode2; + t |= a; + t |= (b & 7) << 9; + break; + } + if((a & 0170) == 0) { /* src Dn */ + t |= 0x100; + t |= (a & 7) << 9; + t |= b; + break; + } + if((a & 0177) == 074) { /* src immed */ + t = o->opcode3; + t |= b; + break; + } + goto bad; + + case 4: /* no operands */ + break; + + case 5: /* tst */ + t |= asmea(p, &p->to); + if((t&0170) == 010) + goto bad; + break; + + case 6: /* lea */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) != 010) + goto bad; + t |= a; + t |= (b & 7) << 9; + break; + + case 7: /* cmp */ + b = asmea(p, &p->to); + a = asmea(p, &p->from); + if((a & 0170) == 010) { /* dst An */ + t = o->opcode1; + if(t == 0) /* cmpb illegal */ + goto bad; + t |= 0xc0; + t |= b; + t |= (a & 7) << 9; + break; + } + if((b & 0177) == 074) { /* src immed */ + t = o->opcode2; + t |= a; + break; + } + if((a & 0170) == 0) { /* dst Dn */ + t |= b; + t |= (a&7) << 9; + break; + } + if((b&0170) == 030 && (a&0170) == 030) { /* (A)+,(A)+ */ + t = o->opcode3; + t |= b & 7; + t |= (a & 7) << 9; + break; + } + goto bad; + + case 8: /* svc */ + *op++ = optab[ARTS].opcode0; + break; + + case 9: /* and */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + if((b & 0170) == 0) { /* dst Dn */ + t |= a; + t |= (b&7) << 9; + break; + } + if((a & 0170) == 0) { /* src Dn */ + t = o->opcode1; + t |= b; + t |= (a&7) << 9; + break; + } + if((a & 0177) == 074) { /* src immed */ + t = o->opcode2; + t |= b; + break; + } + goto bad; + + case 10: /* eor */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 010) + goto bad; + if((a & 0170) == 0) { /* src Dn */ + t |= b; + t |= (a&7) << 9; + break; + } + if((a & 0177) == 074) { /* src immed */ + t = o->opcode1; + t |= b; + break; + } + goto bad; + + case 11: /* ext */ + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + t |= b; + break; + } + goto bad; + + case 12: /* shift */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + if((a & 0177) == 0110) { /* src quick */ + t |= (a & 01600) << 2; + t |= b; + break; + } + if((a & 0170) == 0) { /* src Dn */ + t |= 0x20; + t |= a << 9; + t |= b; + break; + } + goto bad; + } + goto bad; + + case 13: /* mul, div short */ + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + if((a & 0170) == 010) + goto bad; + t |= a; + t |= b << 9; + break; + } + goto bad; + + case 14: /* mul, div long */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) == 0) { /* dst Dn */ + if((a & 0170) == 010) + goto bad; + t |= a; + opa[1] |= b << 12; + opa[1] |= b+1; + break; + } + goto bad; + + case 15: /* dec and branch */ + if(p->to.type != D_BRANCH) + goto bad; + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) + goto bad; + *op++ = v; + a = asmea(p, &p->from); + if((a & 0170) != 0) + goto bad; + t |= a; + break; + + case 16: /* fmove */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) == 0100) { /* src Fn */ + if((b & 0170) == 0100) { /* both Fn */ + opa[1] |= (a&7) << 10; + opa[1] |= (b&7) << 7; + break; + } + t |= b; + opa[1] = o->opcode2; + opa[1] |= (a&7) << 7; + break; + } + if((b & 0170) != 0100) /* dst Fn */ + goto bad; + t |= a; + opa[1] = o->opcode3; + opa[1] |= (b&7) << 7; + break; + + case 17: /* floating ea,Fn */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((b & 0170) != 0100) /* dst Fn */ + goto bad; + if((a & 0170) == 0100) { /* both Fn */ + opa[1] |= (a&7) << 10; + opa[1] |= (b&7) << 7; + break; + } + t |= a; + opa[1] = o->opcode2; + opa[1] |= (b&7) << 7; + break; + + case 18: /* floating branchs */ + if(p->to.type != D_BRANCH) + goto bad; + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) + goto bad; + *op++ = v; + break; + + case 19: /* floating dec and branch */ + if(p->to.type != D_BRANCH) + goto bad; + *op++ = o->opcode1; + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) + goto bad; + *op++ = v; + a = asmea(p, &p->from); + if((a & 0170) != 0) + goto bad; + t |= a; + break; + + case 20: /* ftst ea */ + *op++ = o->opcode1; + if(p->from.type != D_NONE) + goto bad; + a = asmea(p, &p->to); + if((a & 0170) == 0100) { /* Fn */ + opa[1] |= (a&7) << 10; + break; + } + t |= a; + opa[1] = o->opcode2; + break; + + case 21: /* fneg */ + *op++ = o->opcode1; + if(p->from.type == D_NONE) { + b = asmea(p, &p->to); + a = b; + } else { + a = asmea(p, &p->from); + b = asmea(p, &p->to); + } + if((b & 0170) != 0100) /* dst Fn */ + goto bad; + if((a & 0170) == 0100) { /* both Fn */ + opa[1] |= (a&7) << 10; + opa[1] |= (b&7) << 7; + break; + } + t |= a; + opa[1] = o->opcode2; + opa[1] |= (b&7) << 7; + break; + + case 22: /* floating cmp Fn,ea */ + *op++ = o->opcode1; + a = asmea(p, &p->from); + b = asmea(p, &p->to); + if((a & 0170) != 0100) /* dst Fn */ + goto bad; + if((b & 0170) == 0100) { /* both Fn */ + opa[1] |= (b&7) << 10; + opa[1] |= (a&7) << 7; + break; + } + t |= b; + opa[1] = o->opcode2; + opa[1] |= (a&7) << 7; + break; + + case 23: /* word, long */ + op = opa; + a = asmea(p, &p->to); + if(a == ((7<<3)|4)) + return; + if(a == ((7<<3)|1)) { + if(p->as == AWORD) { + op = opa; + *op++ = opa[1]; + } + return; + } + if(a == ((7<<3)|0)) { + if(p->as == ALONG) { + *op++ = opa[0]; + opa[0] = 0; + } + return; + } + goto bad; + + case 24: /* bit field */ + a = ((p->to.field&31)<<6) | (p->from.field&31); + if(p->as == ABFINS) { + b = asmea(p, &p->from); + if((b&0170) != 0) + goto bad; + a |= b<<12; + *op++ = a; + a = asmea(p, &p->to); + } else { + if(p->to.type != D_NONE) { + b = asmea(p, &p->to); + if((b&0170) != 0) + goto bad; + a |= b<<12; + } + *op++ = a; + a = asmea(p, &p->from); + } + t |= a; + a &= 0170; + if(a == 010 || a == 030 || a == 040 || a == 074) + goto bad; + break; + + case 25: /* movem */ + if(p->from.type == D_CONST) { /* registers -> memory */ + asmea(p, &p->from); + a = asmea(p, &p->to); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 030) + goto bad; + t |= a; + break; + } + if(p->to.type == D_CONST) { /* memory -> registers */ + t |= 0x400; + asmea(p, &p->to); + a = asmea(p, &p->from); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 040) + goto bad; + t |= a; + break; + } + goto bad; + + case 26: /* chk */ + a = asmea(p, &p->from); + if((a&0170) == 010) + goto bad; + b = asmea(p, &p->to); + if((b&0170) != 0) + goto bad; + t |= a; + t |= b<<9; + break; + + case 27: /* btst */ + a = asmea(p, &p->from); + if(a == 074) { + t = o->opcode1; + } else + if((a&0170) != 0) + goto bad; + b = asmea(p, &p->to); + if(b == 074 || (b&0170) == 010) + goto bad; + t |= b; + break; + + case 28: /* fmovem */ + if(p->from.type == D_CONST) { /* registers -> memory */ + b = p->from.offset & 0xff; + b |= 0xf000; /* control or postinc */ + *op++ = b; + a = asmea(p, &p->to); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 030) + goto bad; + if(b == 040) + op[-1] &= ~0x1000; /* predec */ + t |= a; + break; + } + if(p->to.type == D_CONST) { /* memory -> registers */ + b = p->to.offset & 0xff; + b |= 0xd000; /* control or postinc */ + *op++ = b; + a = asmea(p, &p->from); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 040) + goto bad; + t |= a; + break; + } + goto bad; + + case 29: /* fmovemc */ + if(p->from.type == D_CONST) { /* registers -> memory */ + b = (p->from.offset & 0x7) << 10; + b |= 0xa000; + *op++ = b; + a = asmea(p, &p->to); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 030) + goto bad; + t |= a; + break; + } + if(p->to.type == D_CONST) { /* memory -> registers */ + b = (p->to.offset & 0x7) << 10; + b |= 0x8000; + *op++ = b; + a = asmea(p, &p->from); + if(a == 074) + goto bad; + b = a & 0170; + if(b == 000 || b == 010 || b == 040) + goto bad; + t |= a; + break; + } + goto bad; + + case 30: /* trap */ + if(p->to.type == D_CONST) { + t |= p->to.offset & 0xf; + break; + } + goto bad; + + case 31: /* chk2, cmp2 */ + b = asmea(p, &p->to); + a = b & 0170; + if(a == 000 || a == 010) { + *op++ = o->opcode1 | (b << 12); + t |= asmea(p, &p->from); + break; + } + goto bad; + + case 32: /* casew */ + /* jmp (0,pc,r0.w*1) */ + casepc = p->pc; + *op++ = o->opcode1; + break; + + case 33: /* bcase */ + q = copyp(p); + q->as = ADATA; + q->to.type = D_CONST; + q->to.offset = p->pcond->pc - casepc - 2; + q->from.displace = 2; + q->link = datap; + datap = q; + if(debug['a']) + Bprint(&bso, "%P\n", q); + op = opa; + return; + + case 34: /* moves */ + op++; + a = asmea(p, &p->from); + b = a & 0170; + if(b == 0 || b == 010) { + opa[1] = (a << 12) | 0x800; + b = asmea(p, &p->to); + a = b & 0170; + if(a == 0 || a == 010) + goto bad; + t |= b; + break; + } + t |= a; + b = asmea(p, &p->to); + a = b & 0170; + if(a != 0 && a != 010) + goto bad; + opa[1] = (b << 12); + break; + + case 35: /* swap */ + a = asmea(p, &p->to); + if((a & 0170) == 0) { + t |= a; + break; + } + goto bad; + } + opa[0] = t; + return; + +bad: + if(!debug['a']) + print("%P\n", p); + diag("bad combination of addressing in %s", TNAME); + opa[0] = 0; +} + +int +asmea(Prog *p, Adr *a) +{ + Optab *o; + int f, t, r, i; + short *top; + long v; + + if(a->index != D_NONE) + goto index; + t = a->type; + r = simple[t]; + v = a->offset; + if(r != 0177) { + if(v == 0) + return r; + if((r & 070) != 020) + return r; + if(v >= -32768L && v < 32768L) { + *op++ = v; + return t-D_A0-I_INDIR+050; /* d(Ax) */ + } + *op++ = 0x170; /* is, no indirect */ + *op++ = v>>16; + *op++ = v; + return t-D_A0-I_INDIR+060; /* (d,Ax) */ + } + f = 0; + if(a == &p->from) + f++; + o = &optab[p->as]; + switch(t) { + case D_TOS: + if(f) { + if(o->srcsp) + return (3<<3) | 7; /* (A7)+ */ + } else + if(o->dstsp) + return (4<<3) | 7; /* -(A7) */ + return (2<<3) | 7; /* (A7) */ + + case D_BRANCH: + v = p->pcond->pc - p->pc - 2; + if(v < -32768L || v >= 32768L) { + *op++ = v>>16; + *op++ = v; + return 0xff; + } + if(v < -128 || v >= 128 || p->mark == 4) { + *op++ = v; + return 0; + } + return v & 0xff; + + case I_ADDR|D_STATIC: + case I_ADDR|D_EXTERN: + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + v = a->sym->value + a->offset; + if(t != STEXT) + v += INITDAT; + + case D_CONST: + switch(f? o->srcsp: o->dstsp) { + case 4: + *op++ = v>>16; + + case 2: + *op++ = v; + break; + + default: + diag("unknown srcsp asmea in %s", TNAME); + } + return (7<<3) | 4; + + case D_FCONST: + r = f? o->srcsp: o->dstsp; + for(i=0; i<r; i++) + ((char*)op)[i] = gnuxi(&a->ieee, i, r); + op += r/2; + return (7<<3) | 4; + + case D_QUICK: + v = a->offset & 0xff; + return 0110 | (v<<7); + + case D_STACK: + case D_AUTO: + case D_PARAM: + if(v == 0) + return (2<<3) | 7; /* (A7) */ + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (5<<3) | 7; /* d(A7) */ + } + *op++ = 0x170; /* is, no indirect */ + *op++ = v>>16; + *op++ = v; + return (6<<3) | 7; /* (d,A7) */ + + case I_INDIR|D_CONST: + goto adr; + + case D_STATIC: + case D_EXTERN: + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + if(t == STEXT) { + v = a->sym->value + a->offset; + *op++ = v>>16; + *op++ = v; + return (7<<3) | 1; + } + v = a->sym->value + a->offset - A6OFFSET; + if(debug['6']) { + v += INITDAT + A6OFFSET; + goto adr; + } + if(v == 0) + return (2<<3) | 6; + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (5<<3) | 6; + } + v += INITDAT + A6OFFSET; + + adr: + if(v >= -32768L && v < 32768L) { + *op++ = v; + return (7<<3) | 0; + } + *op++ = v>>16; + *op++ = v; + return (7<<3) | 1; + } + if(!debug['a']) + print("%P\n", p); + diag("unknown addressing mode: %d in %s", t, TNAME); + return 0; + +index: + top = op++; + t = a->index & D_MASK; + f = (a->scale & 7) << 9; /* w/l scale */ + f |= (t & 7) << 12; /* register */ + if(t < D_R0 || t >= D_R0+8) { + if(t >= D_A0 && t < D_A0+8) { + f |= 0x8000; /* d/a */ + } else + if(t == D_NONE) + f = 0x40; /* is */ + else + goto bad; + } + + t = a->type; + r = t & 7; + v = a->offset; + if(t < (I_INDIR|D_A0) || t >= (I_INDIR|(D_A0+8))) + switch(t) { + default: + goto bad; + + case I_INDIR|D_NONE: + f |= 0x80; /* bs */ + r = 0; + break; + + case D_AUTO: + case D_PARAM: + case D_STACK: + r = 7; + break; + + case D_STATIC: + case D_EXTERN: + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + r = 6; + v += a->sym->value - A6OFFSET; + if(t == STEXT) { + f |= 0x80; /* bs */ + r = 0; + v += A6OFFSET; + goto bdlong; + } + if(debug['6']) { + f |= 0x80; /* bs */ + r = 0; + v += INITDAT + A6OFFSET; + } + } + if(v == 0) + f |= 0x10; /* bd size = null */ + else + if(v >= -32768L && v < 32768L) { + f |= 0x20; /* bd size = word */ + *op++ = v; + } else { + bdlong: + f |= 0x30; /* bd size = long */ + *op++ = v>>16; + *op++ = v; + } + v = a->displace; + t = a->index & I_MASK; + if(t != I_INDEX1) { /* non-memory index */ + if(t == I_INDEX2) + f |= 5; /* post indexing */ + else + if(t == I_INDEX3) + f |= 1; /* pre indexing */ + else + goto bad; + } + if(v != 0) { + if(v >= -32768L && v < 32768L) { + f++; /* is size = word */ + *op++ = v; + } else { + f += 2; /* is size = long */ + *op++ = v>>16; + *op++ = v; + } + } + *top = f | 0x100; + return (6<<3) | r; + +bad: + if(!debug['a']) + print("%P\n", p); + diag("bad operand in %s", TNAME); + return 0; +} + +void +lput(long l) +{ + + CPUT(l>>24) + CPUT(l>>16) + CPUT(l>>8) + CPUT(l) +} + +void +s16put(char *n) +{ + char name[16]; + 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+100); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->from.displace; + i = 0; + if(l < 0) { + if(l+c <= 0) + continue; + while(l < 0) { + l++; + i++; + } + } + if(l >= n) + continue; + 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, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[fnuxi8[j+4]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i+4]]; + l++; + } + break; + case 8: + cast = (char*)&p->to.ieee; + if(debug['a'] && i == 0) { + Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + if(debug['a'] && i == 0) { + Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = p->to.scon[i]; + l++; + } + break; + default: + fl = p->to.offset; + if(p->to.sym) { + if(p->to.sym->type == STEXT) + fl += p->to.sym->value; + if(p->to.sym->type == SDATA) + fl += p->to.sym->value + INITDAT; + if(p->to.sym->type == SBSS) + fl += p->to.sym->value + INITDAT; + } + + 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, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux",cast[inuxi1[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + if(debug['a'] && i == 0) { + Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux",cast[inuxi2[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + if(debug['a'] && i == 0) { + Bprint(&bso, "%lux:%P\n\t\t", l+s+INITDAT, curp); + for(j=0; j<c; j++) + Bprint(&bso, "%.2ux",cast[inuxi4[j]] & 0xff); + Bprint(&bso, "\n"); + } + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +int +gnuxi(Ieee *d, int i, int c) +{ + char *p; + long l; + + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + return 0; + + /* + * 2301 vax + * 0123 68k + */ + case 4: + l = ieeedtof(d); + p = (char*)&l; + i = gnuxi8[i+4]; + break; + + /* + * 67452301 vax + * 45670123 68k + */ + case 8: + p = (char*)d; + i = gnuxi8[i]; + break; + } + return p[i]; +} + +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; +} diff --git a/utils/2l/l.h b/utils/2l/l.h new file mode 100644 index 00000000..8b03604c --- /dev/null +++ b/utils/2l/l.h @@ -0,0 +1,263 @@ +#include <lib9.h> +#include <bio.h> +#include "../2c/2.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 +{ + short type; + short index; + union + { + struct + { + long u0displace; + long u0offset; + } s0; + char u0scon[8]; + Prog *u0cond; /* not used, but should be D_BRANCH */ + Ieee u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + uchar field; + uchar scale; +}; + +#define displace u0.s0.u0displace +#define offset u0.s0.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; + union + { + long u0stkoff; + Prog *u0forwd; + } u0; + Prog* link; + Prog* pcond; /* work on this */ + long pc; + long line; + short as; + uchar mark; /* work on these */ + uchar back; +}; + +#define stkoff u0.u0stkoff +#define forwd u0.u0forwd + +struct Auto +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + long value; + Sym* link; +}; +struct Optab +{ + short as; + short fas; + short srcsp; + short dstsp; + ushort optype; + ushort opcode0; + ushort opcode1; + ushort opcode2; + ushort opcode3; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SAUTO, + SPARAM, + SFILE, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 4, + STRINGSZ = 200, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + A6OFFSET = 32766 +}; + +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 + +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 int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN char fnuxi8[8]; +EXTERN char gnuxi8[8]; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN long ncase; +EXTERN long ndata; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long nsymbol; +EXTERN char* noname; +EXTERN short* op; +EXTERN char* outfile; +EXTERN long pc; +EXTERN char simple[I_MASK]; +EXTERN char special[I_MASK]; +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 Optab optab[]; +extern char mmsize[]; +extern char* anames[]; + +#pragma varargck type "A" int +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Pconv(Fmt*); +int Rconv(Fmt*); +int Sconv(Fmt*); +int Xconv(Fmt*); +void addhist(long, int); +int andsize(Prog*, Adr*); +Prog* appendp(Prog*); +void asmb(void); +int asmea(Prog*, Adr*); +void asmins(Prog*); +void asmlc(void); +void asmsp(void); +void asmsym(void); +long atolwhex(char*); +Prog* brchain(Prog*); +Prog* brloop(Prog*); +void cflush(void); +Prog* copyp(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +void dostkoff(void); +long entryvalue(void); +void errorexit(void); +int find1(long, int); +int find2(long, int); +void follow(void); +void gethunk(void); +int gnuxi(Ieee*, int, int); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void main(int, char*[]); +void mkfwd(void); +void* mysbrk(ulong); +void nuxiinit(void); +void objfile(char*); +void patch(void); +Prog* prg(void); +int relinv(int); +long reuse(Prog*, Sym*); +long rnd(long, long); +void s16put(char*); +void span(void); +void undef(void); +void xdefine(char*, int, long); +void xfol(Prog*); +int zaddr(uchar*, Adr*, Sym*[]); diff --git a/utils/2l/list.c b/utils/2l/list.c new file mode 100644 index 00000000..1ebf488e --- /dev/null +++ b/utils/2l/list.c @@ -0,0 +1,395 @@ +#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], s[20]; + Prog *p; + + p = va_arg(fp->args, Prog*); + bigP = p; + sprint(str, "(%ld) %A %D,%D", + p->line, p->as, &p->from, &p->to); + if(p->from.field) { + sprint(s, ",%d,%d", p->to.field, p->from.field); + strcat(str, s); + } + bigP = P; + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + + return fmtstrcpy(fp, anames[va_arg(fp->args, int)]); +} + +int +Xconv(Fmt *fp) +{ + char str[20], s[10]; + int i0, i1; + + str[0] = 0; + i0 = va_arg(fp->args, int) & D_MASK; + i1 = va_arg(fp->args, int); + if(i0 != D_NONE) { + sprint(str, "(%R.", i0); + sprint(s, "%c*%c)", + "WWWWLLLL"[i1], + "12481248"[i1]); + strcat(str, s); + } + return fmtstrcpy(fp, str); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i, j; + long d; + + a = va_arg(fp->args, Adr*); + i = a->index; + if(i != D_NONE) { + a->index = D_NONE; + d = a->displace; + a->displace = 0; + switch(i & I_MASK) { + default: + sprint(str, "???%ld(%D)", d, a); + break; + + case I_INDEX1: + sprint(str, "%D", a); + break; + + case I_INDEX2: + if(d) + sprint(str, "%ld(%D)", d, a); + else + sprint(str, "(%D)", a); + break; + + case I_INDEX3: + if(d) + sprint(str, "%ld(%D", d, a); + else + sprint(str, "(%D", a); + break; + } + + if(i != D_NONE) { + j = a->scale & 7; + sprint(strchr(str,0), "(%R.", i); + sprint(strchr(str,0), "%c*%c)", + "WWWWLLLL"[j], + "12481248"[j]); + } + if((i & I_MASK) == I_INDEX3) + strcat(str, ")"); + a->displace = d; + a->index = i; + goto out; + } + i = a->type; + j = i & I_MASK; + if(j) { + a->type = i & D_MASK; + d = a->offset; + a->offset = 0; + switch(j) { + case I_INDINC: + sprint(str, "(%D)+", a); + break; + + case I_INDDEC: + sprint(str, "-(%D)", a); + break; + + case I_INDIR: + if(d) + sprint(str, "%ld(%D)", d, a); + else + sprint(str, "(%D)", a); + break; + + case I_ADDR: + a->offset = d; + sprint(str, "$%D", a); + break; + } + a->type = i; + a->offset = d; + goto out; + } + 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_STACK: + sprint(str, "TOS+%ld", a->offset); + break; + + case D_QUICK: + sprint(str, "$Q%ld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l); + goto out; + + case D_SCONST: + sprint(str, "$\"%S\"", a->scon); + goto out; + } + if(a->displace) { + sprint(s, "/%ld", a->displace); + strcat(str, s); + } +out: + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_R0 && r < D_R0+NREG) + sprint(str, "R%d", r-D_R0); + else + if(r >= D_A0 && r < D_A0+NREG) + sprint(str, "A%d", r-D_A0); + else + if(r >= D_F0 && r < D_F0+NREG) + sprint(str, "F%d", r-D_F0); + else + switch(r) { + + default: + sprint(str, "gok(%d)", r); + break; + + case D_NONE: + sprint(str, "NONE"); + break; + + case D_TOS: + sprint(str, "TOS"); + break; + + case D_CCR: + sprint(str, "CCR"); + break; + + case D_SR: + sprint(str, "SR"); + break; + + case D_SFC: + sprint(str, "SFC"); + break; + + case D_DFC: + sprint(str, "DFC"); + break; + + case D_CACR: + sprint(str, "CACR"); + break; + + case D_USP: + sprint(str, "USP"); + break; + + case D_VBR: + sprint(str, "VBR"); + break; + + case D_CAAR: + sprint(str, "CAAR"); + break; + + case D_MSP: + sprint(str, "MSP"); + break; + + case D_ISP: + sprint(str, "ISP"); + break; + + case D_FPCR: + sprint(str, "FPCR"); + break; + + case D_FPSR: + sprint(str, "FPSR"); + break; + + case D_FPIAR: + sprint(str, "FPIAR"); + break; + + case D_TREE: + sprint(str, "TREE"); + break; + + case D_TC: + sprint(str, "TC"); + break; + + case D_ITT0: + sprint(str, "ITT0"); + break; + + case D_ITT1: + sprint(str, "ITT1"); + break; + + case D_DTT0: + sprint(str, "DTT0"); + break; + + case D_DTT1: + sprint(str, "DTT1"); + break; + + case D_MMUSR: + sprint(str, "MMUSR"); + break; + case D_URP: + sprint(str, "URP"); + break; + + case D_SRP: + sprint(str, "SRP"); + break; + } + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/2l/mkfile b/utils/2l/mkfile new file mode 100644 index 00000000..c52b5ce7 --- /dev/null +++ b/utils/2l/mkfile @@ -0,0 +1,26 @@ +<../../mkconfig + +TARG=2l +OFILES=\ + asm.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + list.$O\ + enam.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../2c/2.out.h\ + ../include/ar.h\ + +LIBS=bio 9 +BIN=$ROOT/$OBJDIR/bin +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I ../include + +enam.$O: ../2c/enam.c + $CC $CFLAGS ../2c/enam.c diff --git a/utils/2l/obj.c b/utils/2l/obj.c new file mode 100644 index 00000000..f51d028b --- /dev/null +++ b/utils/2l/obj.c @@ -0,0 +1,1402 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = '2'; +char *thestring = "68020"; + +/* + * -H0 -T0x40004C -D0x10000000 is garbage unix + * -H1 -T0x80020000 -R4 is garbage format + * -H2 -T8224 -R8192 is plan9 format + * -H3 -Tx -Rx is next boot + */ + +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 = "2.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; + } ARGEND + + USED(argc); + + if(*argv == 0) { + diag("usage: 2l [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 2; + if(debug['B']) + HEADTYPE = 2; + if(debug['9']) + HEADTYPE = 2; + } + if(INITDAT != -1 && INITRND == -1) + INITRND = 0; + switch(HEADTYPE) { + default: + diag("unknown -H option %d", HEADTYPE); + errorexit(); + + case 0: /* this is garbage */ + HEADR = 20L+56L; + if(INITTEXT == -1) + INITTEXT = 0x40004CL; + if(INITDAT == -1) + INITDAT = 0x10000000L; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 0; + break; + case 1: /* plan9 boot data goes into text */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 8224; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 8192; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 8224; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 8192; + break; + case 3: /* next boot */ + HEADR = 28+124+192+24; + if(INITTEXT == -1) + INITTEXT = 0x04002000; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 8192L; + break; + case 4: /* preprocess pilot */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 0; + if(INITDAT == -1) + INITDAT = 0; + if(INITDAT != 0 && INITRND == -1) + INITRND = 0; + if(INITRND == -1) + INITRND = 32; + 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(); + } + + zprg.link = P; + zprg.pcond = P; + zprg.back = 2; + zprg.as = AGOK; + zprg.from.type = D_NONE; + zprg.from.index = D_NONE; + zprg.to = zprg.from; + + memset(special, 0, sizeof(special)); + special[D_CCR] = 1; + special[D_SR] = 1; + special[D_SFC] = 1; + special[D_CACR] = 1; + special[D_USP] = 1; + special[D_VBR] = 1; + special[D_CAAR] = 1; + special[D_MSP] = 1; + special[D_ISP] = 1; + special[D_DFC] = 1; + special[D_FPCR] = 1; + special[D_FPSR] = 1; + special[D_FPIAR] = 1; + special[D_TC] = 1; + special[D_ITT0] = 1; + special[D_ITT1] = 1; + special[D_DTT0] = 1; + special[D_DTT1] = 1; + special[D_MMUSR] = 1; + special[D_URP] = 1; + special[D_SRP] = 1; + memset(simple, 0177, sizeof(simple)); + for(i=0; i<8; i++) { + simple[D_R0+i] = i; + simple[D_F0+i] = i+0100; + simple[D_A0+i] = i+010; + simple[D_A0+I_INDIR+i] = i+020; + simple[D_A0+I_INDINC+i] = i+030; + simple[D_A0+I_INDDEC+i] = i+040; + } + nuxiinit(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + 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(); + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + follow(); + dodata(); + dostkoff(); + span(); + asmb(); + undef(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld+%ld = %ld data statements\n", + ndata, ncase, ndata+ncase); + 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) +{ + + Bflush(&bso); + 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]; + + /* + * first try the high-time formats + */ + if(t == 0) { + a->index = D_NONE; + a->type = p[1]; + return 2; + } + if(t == T_OFFSET) { + a->index = D_NONE; + a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24); + a->type = p[5]; + return 6; + } + if(t == (T_OFFSET|T_SYM)) { + a->index = D_NONE; + a->offset = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24); + s = h[p[5]]; + a->sym = s; + a->type = p[6]; + c = 7; + goto dosym; + } + if(t == T_SYM) { + a->index = D_NONE; + s = h[p[1]]; + a->sym = s; + a->type = p[2]; + c = 3; + goto dosym; + } + if(t == (T_INDEX|T_OFFSET|T_SYM)) { + a->index = p[1] | (p[2]<<8); + a->scale = p[3]; + a->displace = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24); + a->offset = p[8] | (p[9]<<8) | (p[10]<<16) | (p[11]<<24); + s = h[p[12]]; + a->sym = s; + a->type = p[13]; + c = 14; + goto dosym; + } + + /* + * now do it the hard way + */ + c = 1; + a->index = D_NONE; + if(t & T_FIELD) { + a->field = p[c] | (p[c+1]<<8); + c += 2; + } + if(t & T_INDEX) { + a->index = p[c] | (p[c+1]<<8); + a->scale = p[c+2]; + a->displace = p[c+3] | (p[c+4]<<8) | (p[c+5]<<16) | (p[c+6]<<24); + c += 7; + } + if(t & T_OFFSET) { + a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24); + c += 4; + } + if(t & T_SYM) { + a->sym = h[p[c]]; + c += 1; + } + 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; + } else + if(t & T_TYPE) { + a->type = p[c] | (p[c+1]<<8); + c += 2; + } else { + a->type = p[c]; + c++; + } + s = a->sym; + if(s == S) + return c; + +dosym: + t = a->type & D_MASK; + 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; +} + +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) +{ + Prog *p; + Sym *h[NSYM], *s; + int v, o, r; + long ipc, lv; + double dv; + uchar *bloc, *bsize, *stop; + + bsize = buf.xbuf; + bloc = buf.xbuf; + +newloop: + memset(h, 0, sizeof(h)); + version++; + histfrogp = 0; + ipc = pc; + +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 .2 file\n"); + errorexit(); + } + + if(o == ANAME || o == ASIGNAME) { + if(o == ASIGNAME) { + 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['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 ABCASE: + ncase++; + goto casdef; + + case ADATA: + p->link = datap; + datap = p; + ndata++; + goto loop; + + case AGOK: + diag("%s: unknown opcode in %s", pn, TNAME); + pc++; + goto loop; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + curtext = p; + lastp->link = p; + lastp = p; + p->pc = pc; + s = p->from.sym; + if(s->type != 0 && s->type != SXREF) + diag("%s: redefinition: %s", pn, s->name); + s->type = STEXT; + s->value = p->pc; + pc++; + p->pcond = P; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->pcond = p; + etextp = p; + goto loop; + + case AJSR: + p->as = ABSR; + + case ABSR: + if(p->to.index != D_NONE) + p->as = AJSR; + if(p->to.type != D_EXTERN && p->to.type != D_STATIC) + p->as = AJSR; + goto casdef; + + case AMOVL: + case AMOVB: + case AMOVW: + if(p->from.type != D_CONST) + goto casdef; + lv = p->from.offset; + if(lv >= -128 && lv < 128) + if(p->to.type >= D_R0 && p->to.type < D_R0+8) + if(p->to.index == D_NONE) { + p->from.type = D_QUICK; + goto casdef; + } + + if(lv >= -0x7fff && lv <= 0x7fff) + if(p->to.type >= D_A0 && p->to.type < D_A0+8) + if(p->to.index == D_NONE) + if(p->as == AMOVL) + p->as = AMOVW; + goto casdef; + + case AADDB: + case AADDL: + case AADDW: + if(p->from.type != D_CONST) + goto casdef; + lv = p->from.offset; + if(lv < 0) { + lv = -lv; + p->from.offset = lv; + if(p->as == AADDB) + p->as = ASUBB; + else + if(p->as == AADDW) + p->as = ASUBW; + else + if(p->as == AADDL) + p->as = ASUBL; + } + if(lv > 0) + if(lv <= 8) + p->from.type = D_QUICK; + goto casdef; + + case ASUBB: + case ASUBL: + case ASUBW: + if(p->from.type != D_CONST) + goto casdef; + lv = p->from.offset; + if(lv < 0) { + lv = -lv; + p->from.offset = lv; + if(p->as == ASUBB) + p->as = AADDB; + else + if(p->as == ASUBW) + p->as = AADDW; + else + if(p->as == ASUBL) + p->as = AADDL; + } + if(lv > 0) + if(lv <= 8) + p->from.type = D_QUICK; + goto casdef; + + case AROTRB: + case AROTRL: + case AROTRW: + case AROTLB: + case AROTLL: + case AROTLW: + + case AASLB: + case AASLL: + case AASLW: + case AASRB: + case AASRL: + case AASRW: + case ALSLB: + case ALSLL: + case ALSLW: + case ALSRB: + case ALSRL: + case ALSRW: + if(p->from.type == D_CONST) + if(p->from.offset > 0) + if(p->from.offset <= 8) + p->from.type = D_QUICK; + goto casdef; + + case ATSTL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) { + p->as = ACMPW; + p->from = p->to; + p->to.type = D_CONST; + p->to.offset = 0; + } + goto casdef; + + case ACMPL: + if(p->to.type != D_CONST) + goto casdef; + lv = p->to.offset; + if(lv >= -0x7fff && lv <= 0x7fff) + if(p->from.type >= D_A0 && p->from.type < D_A0+8) + if(p->from.index == D_NONE) + p->as = ACMPW; + goto casdef; + + case ACLRL: + if(p->to.type >= D_A0 && p->to.type < D_A0+8) { + p->as = AMOVW; + p->from.type = D_CONST; + p->from.offset = 0; + } + goto casdef; + + casdef: + default: + if(p->from.type == D_FCONST) + if(optab[p->as].fas != AXXX) { + dv = ieeedtod(&p->from.ieee); + if(dv >= -(1L<<30) && dv <= (1L<<30)) { + lv = dv; + if(lv == dv) { + p->as = optab[p->as].fas; + p->from.type = D_CONST; + p->from.offset = lv; + p->from.displace = 0; + } + } + } + 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("%s: truncated object file in %s", pn, TNAME); +} + +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; + 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->as = AADDL; + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + q->from.type = D_CONST; + q->from.offset = 1; + q->to.type = D_EXTERN; + q->to.sym = s; + q->to.offset = n*4 + 4; + + q = prg(); + q->as = ADATA; + q->line = p->line; + q->link = datap; + datap = q; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.offset = n*4; + q->from.displace = 4; + q->to.type = D_EXTERN; + q->to.sym = p->from.sym; + n += 2; + continue; + } + } + q = prg(); + q->line = 0; + q->as = ADATA; + q->link = datap; + datap = q; + q->from.type = D_EXTERN; + q->from.sym = s; + q->from.displace = 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) { + ps2 = p; + p->from.displace = 1; + } + if(p->from.sym == s4) { + ps4 = p; + p->from.displace = 1; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->from.displace != 0) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ABSR; + p->to.type = D_BRANCH; + p->pcond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARTS) { + /* + * RTS + */ + q = prg(); + q->as = ARTS; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * BSR profout + */ + p->as = ABSR; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->pcond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +long +reuse(Prog *r, Sym *s) +{ + Prog *p; + + + if(r == P) + return 0; + for(p = datap; p != r; p = p->link) + if(p->to.sym == s) + return p->from.offset; + return 0; +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x01020304L, i+1); + if(i >= 2) + inuxi2[i-2] = c; + if(i >= 3) + inuxi1[i-3] = c; + inuxi4[i] = c; + fnuxi8[i] = c+4; + fnuxi8[i+4] = c; + c = find2(0x01020304L, i+1); + gnuxi8[i] = c+4; + gnuxi8[i+4] = c; + } + 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, "\n[fg]nuxi = "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, " "); + for(i=0; i<8; i++) + Bprint(&bso, "%d", gnuxi8[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); +} diff --git a/utils/2l/optab.c b/utils/2l/optab.c new file mode 100644 index 00000000..9f4527b7 --- /dev/null +++ b/utils/2l/optab.c @@ -0,0 +1,444 @@ +#include "l.h" + +#define X1 0 +#define X2 0 +#define X3 0 +#define C 0xf200 + +Optab optab[] = +/* as, fas, srcsp, dstsp, optype, opcode */ +{ + { AXXX }, + { AABCD, AXXX, X1, X2, X3, 0x4e71 }, + { AADDB, AXXX, 2, 0, 3, 0xd000, 0x5000, 0, 0x0600 }, + { AADDL, AXXX, 4, 0, 3, 0xd080, 0x5080, 0xd1c0, 0x0680 }, + { AADDW, AXXX, 2, 0, 3, 0xd040, 0x5040, 0xd0c0, 0x0640 }, + { AADDXB }, + { AADDXL }, + { AADDXW }, + { AADJSP }, + { AANDB, AXXX, 2, 0, 9, 0xc000, 0xc100, 0x0200 }, + { AANDL, AXXX, 4, 0, 9, 0xc080, 0xc180, 0x0280 }, + { AANDW, AXXX, 2, 0, 9, 0xc040, 0xc140, 0x0240 }, + { AASLB, AXXX, 0, 2, 12, 0xe100 }, + { AASLL, AXXX, 0, 4, 12, 0xe180 }, + { AASLW, AXXX, 0, 2, 12, 0xe140 }, + { AASRB, AXXX, 0, 2, 12, 0xe000 }, + { AASRL, AXXX, 0, 4, 12, 0xe080 }, + { AASRW, AXXX, 0, 2, 12, 0xe040 }, + { ABCASE, AXXX, 0, 0, 33 }, + { ABCC, AXXX, 0, 0, 1, 0x6400 }, + { ABCHG, AXXX, 2, 2, 27, 0x0140, 0x0840 }, + { ABCLR, AXXX, 2, 2, 27, 0x0180, 0x0880 }, + { ABCS, AXXX, 0, 0, 1, 0x6500 }, + { ABEQ, AXXX, 0, 0, 1, 0x6700 }, + { ABFCHG, AXXX, 0, 0, 24, 0xeac0 }, + { ABFCLR, AXXX, 0, 0, 24, 0xecc0 }, + { ABFEXTS, AXXX, 0, 0, 24, 0xebc0 }, + { ABFEXTU, AXXX, 0, 0, 24, 0xe9c0 }, + { ABFFFO, AXXX, 0, 0, 24, 0xedc0 }, + { ABFINS, AXXX, 0, 0, 24, 0xefc0 }, + { ABFSET, AXXX, 0, 0, 24, 0xeec0 }, + { ABFTST, AXXX, 0, 0, 24, 0xe8c0 }, + { ABGE, AXXX, 0, 0, 1, 0x6c00 }, + { ABGT, AXXX, 0, 0, 1, 0x6e00 }, + { ABHI, AXXX, 0, 0, 1, 0x6200 }, + { ABKPT }, + { ABLE, AXXX, 0, 0, 1, 0x6f00 }, + { ABLS, AXXX, 0, 0, 1, 0x6300 }, + { ABLT, AXXX, 0, 0, 1, 0x6d00 }, + { ABMI, AXXX, 0, 0, 1, 0x6b00 }, + { ABNE, AXXX, 0, 0, 1, 0x6600 }, + { ABPL, AXXX, 0, 0, 1, 0x6a00 }, + { ABRA, AXXX, 0, 0, 1, 0x6000 }, + { ABSET, AXXX, 2, 2, 27, 0x01c0, 0x08c0 }, + { ABSR, AXXX, 0, 0, 1, 0x6100, 0x4eb8 }, + { ABTST, AXXX, 2, 2, 27, 0x0100, 0x0800 }, + { ABVC, AXXX, 0, 0, 1, 0x6800 }, + { ABVS, AXXX, 0, 0, 1, 0x6900 }, + { ACALLM }, + { ACAS2B }, + { ACAS2L }, + { ACAS2W }, + { ACASB }, + { ACASEW, AXXX, 0, 0, 32, 0x4efb, 0 }, + { ACASL }, + { ACASW }, + { ACHK2B, AXXX, 2, 0, 31, 0x00c0, 0x0800 }, + { ACHK2L, AXXX, 4, 0, 31, 0x04c0, 0x0800 }, + { ACHK2W, AXXX, 2, 0, 31, 0x02c0, 0x0800 }, + { ACHKL, AXXX, 4, 4, 26, 0x4100 }, + { ACHKW, AXXX, 2, 2, 26, 0x4180 }, + { ACLRB, AXXX, 0, -2, 5, 0x4200 }, + { ACLRL, AXXX, 0, -4, 5, 0x4280 }, + { ACLRW, AXXX, 0, -2, 5, 0x4240 }, + { ACMP2B, AXXX, 2, 0, 31, 0x00c0, 0x0000 }, + { ACMP2L, AXXX, 4, 0, 31, 0x04c0, 0x0000 }, + { ACMP2W, AXXX, 2, 0, 31, 0x02c0, 0x0000 }, + { ACMPB, AXXX, 2, 2, 7, 0xb000, 0, 0x0c00, 0xb108 }, + { ACMPL, AXXX, 4, 4, 7, 0xb080, 0xb100, 0x0c80, 0xb188 }, + { ACMPW, AXXX, 2, 2, 7, 0xb040, 0xb080, 0x0c40, 0xb148 }, + { ADATA }, + { ADBCC, AXXX, 0, 0, 15, 0x54c8 }, + { ADBCS, AXXX, 0, 0, 15, 0x55c8 }, + { ADBEQ, AXXX, 0, 0, 15, 0x57c8 }, + { ADBF, AXXX, 0, 0, 15, 0x51c8 }, + { ADBGE, AXXX, 0, 0, 15, 0x5cc8 }, + { ADBGT, AXXX, 0, 0, 15, 0x5ec8 }, + { ADBHI, AXXX, 0, 0, 15, 0x52c8 }, + { ADBLE, AXXX, 0, 0, 15, 0x5fc8 }, + { ADBLS, AXXX, 0, 0, 15, 0x53c8 }, + { ADBLT, AXXX, 0, 0, 15, 0x5dc8 }, + { ADBMI, AXXX, 0, 0, 15, 0x5bc8 }, + { ADBNE, AXXX, 0, 0, 15, 0x56c8 }, + { ADBPL, AXXX, 0, 0, 15, 0x5ac8 }, + { ADBT, AXXX, 0, 0, 15, 0x50c8 }, + { ADBVC, AXXX, 0, 0, 15, 0x58c8 }, + { ADBVS, AXXX, 0, 0, 15, 0x59c8 }, + { ADIVSL, AXXX, 4, 0, 14, 0x4c40, 0x0800 }, + { ADIVSW, AXXX, 2, 0, 13, 0x81c0 }, + { ADIVUL, AXXX, 4, 0, 14, 0x4c40, 0x0000 }, + { ADIVUW, AXXX, 2, 0, 13, 0x80c0 }, + { AEND }, + { AEORB, AXXX, 2, 0, 10, 0xb100, 0x0a00 }, + { AEORL, AXXX, 4, 0, 10, 0xb180, 0x0a80 }, + { AEORW, AXXX, 2, 0, 10, 0xb140, 0x0a40 }, + { AEXG }, + { AEXTBL, AXXX, 0, 0, 11, 0x49c0 }, + { AEXTBW, AXXX, 0, 0, 11, 0x4880 }, + { AEXTWL, AXXX, 0, 0, 11, 0x48c0 }, + { AFABSB, AXXX, 2, 0, 17, C, 0x0018, 0x5818 }, + { AFABSD, AFABSL, 8, 0, 17, C, 0x0018, 0x5418 }, + { AFABSF, AFABSL, 4, 0, 17, C, 0x0018, 0x4418 }, + { AFABSL, AXXX, 4, 0, 17, C, 0x0018, 0x4018 }, + { AFABSW, AXXX, 2, 0, 17, C, 0x0018, 0x5018 }, + { AFACOSB, AXXX, 2, 0, 17, C, 0x001c, 0x581c }, + { AFACOSD, AFACOSL, 8, 0, 17, C, 0x001c, 0x541c }, + { AFACOSF, AFACOSL, 4, 0, 17, C, 0x001c, 0x441c }, + { AFACOSL, AXXX, 4, 0, 17, C, 0x001c, 0x401c }, + { AFACOSW, AXXX, 2, 0, 17, C, 0x001c, 0x501c }, + { AFADDB, AXXX, 2, 0, 17, C, 0x0022, 0x5822 }, + { AFADDD, AFADDL, 8, 0, 17, C, 0x0022, 0x5422 }, + { AFADDF, AFADDL, 4, 0, 17, C, 0x0022, 0x4422 }, + { AFADDL, AXXX, 4, 0, 17, C, 0x0022, 0x4022 }, + { AFADDW, AXXX, 2, 0, 17, C, 0x0022, 0x5022 }, + { AFASINB, AXXX, 2, 0, 17, C, 0x000c, 0x580c }, + { AFASIND, AFASINL, 8, 0, 17, C, 0x000c, 0x540c }, + { AFASINF, AFASINL, 4, 0, 17, C, 0x000c, 0x440c }, + { AFASINL, AXXX, 4, 0, 17, C, 0x000c, 0x400c }, + { AFASINW, AXXX, 2, 0, 17, C, 0x000c, 0x500c }, + { AFATANB, AXXX, 2, 0, 17, C, 0x000a, 0x580a }, + { AFATAND, AFATANL, 8, 0, 17, C, 0x000a, 0x540a }, + { AFATANF, AFATANL, 4, 0, 17, C, 0x000a, 0x440a }, + { AFATANHB, AXXX, 2, 0, 17, C, 0x000d, 0x580d }, + { AFATANHD, AFATANHL, 8, 0, 17, C, 0x000d, 0x540d }, + { AFATANHF, AFATANHL, 4, 0, 17, C, 0x000d, 0x440d }, + { AFATANHL, AXXX, 4, 0, 17, C, 0x000d, 0x400d }, + { AFATANHW, AXXX, 2, 0, 17, C, 0x000d, 0x500d }, + { AFATANL, AXXX, 4, 0, 17, C, 0x000a, 0x400a }, + { AFATANW, AXXX, 2, 0, 17, C, 0x000a, 0x500a }, + { AFBEQ, AXXX, 0, 0, 18, C+0x81 }, + { AFBF, AXXX, 0, 0, 18, C+0x8f }, + { AFBGE, AXXX, 0, 0, 18, C+0x93 }, + { AFBGT, AXXX, 0, 0, 18, C+0x92 }, + { AFBLE, AXXX, 0, 0, 18, C+0x95 }, + { AFBLT, AXXX, 0, 0, 18, C+0x94 }, + { AFBNE, AXXX, 0, 0, 18, C+0x8e }, + { AFBT, AXXX, 0, 0, 18, C+0x80 }, + { AFCMPB, AXXX, 0, 2, 22, C, 0x0038, 0x5838 }, + { AFCMPD, AFCMPL, 0, 8, 22, C, 0x0038, 0x5438 }, + { AFCMPF, AFCMPL, 0, 4, 22, C, 0x0038, 0x4438 }, + { AFCMPL, AXXX, 0, 4, 22, C, 0x0038, 0x4038 }, + { AFCMPW, AXXX, 0, 2, 22, C, 0x0038, 0x5038 }, + { AFCOSB, AXXX, 2, 0, 17, C, 0x001d, 0x581d }, + { AFCOSD, AFCOSL, 8, 0, 17, C, 0x001d, 0x541d }, + { AFCOSF, AFCOSL, 4, 0, 17, C, 0x001d, 0x441d }, + { AFCOSHB, AXXX, 2, 0, 17, C, 0x0019, 0x5819 }, + { AFCOSHD, AFCOSHL, 8, 0, 17, C, 0x0019, 0x5419 }, + { AFCOSHF, AFCOSHL, 4, 0, 17, C, 0x0019, 0x4419 }, + { AFCOSHL, AXXX, 4, 0, 17, C, 0x0019, 0x4019 }, + { AFCOSHW, AXXX, 2, 0, 17, C, 0x0019, 0x5019 }, + { AFCOSL, AXXX, 4, 0, 17, C, 0x001d, 0x401d }, + { AFCOSW, AXXX, 2, 0, 17, C, 0x001d, 0x501d }, + { AFDBEQ, AXXX, 0, 0, 19, C+0x48, 0x01 }, + { AFDBF, AXXX, 0, 0, 19, C+0x48, 0x0f }, + { AFDBGE, AXXX, 0, 0, 19, C+0x48, 0x13 }, + { AFDBGT, AXXX, 0, 0, 19, C+0x48, 0x12 }, + { AFDBLE, AXXX, 0, 0, 19, C+0x48, 0x15 }, + { AFDBLT, AXXX, 0, 0, 19, C+0x48, 0x14 }, + { AFDBNE, AXXX, 0, 0, 19, C+0x48, 0x0e }, + { AFDBT, AXXX, 0, 0, 19, C+0x48, 0x00 }, + { AFDIVB, AXXX, 2, 0, 17, C, 0x0020, 0x5820 }, + { AFDIVD, AFDIVL, 8, 0, 17, C, 0x0020, 0x5420 }, + { AFDIVF, AFDIVL, 4, 0, 17, C, 0x0020, 0x4420 }, + { AFDIVL, AXXX, 4, 0, 17, C, 0x0020, 0x4020 }, + { AFDIVW, AXXX, 2, 0, 17, C, 0x0020, 0x5020 }, + { AFETOXB, AXXX, 2, 0, 17, C, 0x0010, 0x5810 }, + { AFETOXD, AFETOXL, 8, 0, 17, C, 0x0010, 0x5410 }, + { AFETOXF, AFETOXL, 4, 0, 17, C, 0x0010, 0x4410 }, + { AFETOXL, AXXX, 4, 0, 17, C, 0x0010, 0x4010 }, + { AFETOXM1B, AXXX, 2, 0, 17, C, 0x0008, 0x5808 }, + { AFETOXM1D, AFETOXM1L, 8, 0, 17, C, 0x0008, 0x5408 }, + { AFETOXM1F, AFETOXM1L, 4, 0, 17, C, 0x0008, 0x4408 }, + { AFETOXM1L, AXXX, 4, 0, 17, C, 0x0008, 0x4008 }, + { AFETOXM1W, AXXX, 2, 0, 17, C, 0x0008, 0x5008 }, + { AFETOXW, AXXX, 2, 0, 17, C, 0x0010, 0x5010 }, + { AFGETEXPB, AXXX, 2, 0, 17, C, 0x001e, 0x581e }, + { AFGETEXPD, AFGETEXPL, 8, 0, 17, C, 0x001e, 0x541e }, + { AFGETEXPF, AFGETEXPL, 4, 0, 17, C, 0x001e, 0x441e }, + { AFGETEXPL, AXXX, 4, 0, 17, C, 0x001e, 0x401e }, + { AFGETEXPW, AXXX, 2, 0, 17, C, 0x001e, 0x501e }, + { AFGETMANB, AXXX, 2, 0, 17, C, 0x001f, 0x581f }, + { AFGETMAND, AFGETMANL, 8, 0, 17, C, 0x001f, 0x541f }, + { AFGETMANF, AFGETMANL, 4, 0, 17, C, 0x001f, 0x441f }, + { AFGETMANL, AXXX, 4, 0, 17, C, 0x001f, 0x401f }, + { AFGETMANW, AXXX, 2, 0, 17, C, 0x001f, 0x501f }, + { AFINTB, AXXX, 2, 0, 17, C, 0x0001, 0x5801 }, + { AFINTD, AFINTL, 8, 0, 17, C, 0x0001, 0x5401 }, + { AFINTF, AFINTL, 4, 0, 17, C, 0x0001, 0x4401 }, + { AFINTL, AXXX, 4, 0, 17, C, 0x0001, 0x4001 }, + { AFINTRZB, AXXX, 2, 0, 17, C, 0x0003, 0x5803 }, + { AFINTRZD, AFINTRZL, 8, 0, 17, C, 0x0003, 0x5403 }, + { AFINTRZF, AFINTRZL, 4, 0, 17, C, 0x0003, 0x4403 }, + { AFINTRZL, AXXX, 4, 0, 17, C, 0x0003, 0x4003 }, + { AFINTRZW, AXXX, 2, 0, 17, C, 0x0003, 0x5003 }, + { AFINTW, AXXX, 2, 0, 17, C, 0x0001, 0x5001 }, + { AFLOG10B, AXXX, 2, 0, 17, C, 0x0015, 0x5815 }, + { AFLOG10D, AFLOG10L, 8, 0, 17, C, 0x0015, 0x5415 }, + { AFLOG10F, AFLOG10L, 4, 0, 17, C, 0x0015, 0x4415 }, + { AFLOG10L, AXXX, 4, 0, 17, C, 0x0015, 0x4015 }, + { AFLOG10W, AXXX, 2, 0, 17, C, 0x0015, 0x5015 }, + { AFLOG2B, AXXX, 2, 0, 17, C, 0x0016, 0x5816 }, + { AFLOG2D, AFLOG2L, 8, 0, 17, C, 0x0016, 0x5416 }, + { AFLOG2F, AFLOG2L, 4, 0, 17, C, 0x0016, 0x4416 }, + { AFLOG2L, AXXX, 4, 0, 17, C, 0x0016, 0x4016 }, + { AFLOG2W, AXXX, 2, 0, 17, C, 0x0016, 0x5016 }, + { AFLOGNB, AXXX, 2, 0, 17, C, 0x0014, 0x5814 }, + { AFLOGND, AFLOGNL, 8, 0, 17, C, 0x0014, 0x5414 }, + { AFLOGNF, AFLOGNL, 4, 0, 17, C, 0x0014, 0x4414 }, + { AFLOGNL, AXXX, 4, 0, 17, C, 0x0014, 0x4014 }, + { AFLOGNP1B, AXXX, 2, 0, 17, C, 0x0006, 0x5806 }, + { AFLOGNP1D, AFLOGNP1L, 8, 0, 17, C, 0x0006, 0x5406 }, + { AFLOGNP1F, AFLOGNP1L, 4, 0, 17, C, 0x0006, 0x4406 }, + { AFLOGNP1L, AXXX, 4, 0, 17, C, 0x0006, 0x4006 }, + { AFLOGNP1W, AXXX, 2, 0, 17, C, 0x0006, 0x5006 }, + { AFLOGNW, AXXX, 2, 0, 17, C, 0x0014, 0x5014 }, + { AFMODB, AXXX, 2, 0, 17, C, 0x0021, 0x5821 }, + { AFMODD, AFMODL, 8, 0, 17, C, 0x0021, 0x5421 }, + { AFMODF, AFMODL, 4, 0, 17, C, 0x0021, 0x4421 }, + { AFMODL, AXXX, 4, 0, 17, C, 0x0021, 0x4021 }, + { AFMODW, AXXX, 2, 0, 17, C, 0x0021, 0x5021 }, + { AFMOVEB, AXXX, 2, -2, 16, C, 0x0000, 0x7800, 0x5800 }, + { AFMOVED, AFMOVEL, 8, -8, 16, C, 0x0000, 0x7400, 0x5400 }, + { AFMOVEF, AFMOVEL, 4, -4, 16, C, 0x0000, 0x6400, 0x4400 }, + { AFMOVEL, AXXX, 4, -4, 16, C, 0x0000, 0x6000, 0x4000 }, + { AFMOVEM, AXXX, 2, 2, 28, C }, + { AFMOVEMC, AXXX, 2, 2, 29, C }, + { AFMOVEW, AXXX, 2, -2, 16, C, 0x0000, 0x7000, 0x5000 }, + { AFMULB, AXXX, 2, 0, 17, C, 0x0023, 0x5823 }, + { AFMULD, AFMULL, 8, 0, 17, C, 0x0023, 0x5423 }, + { AFMULF, AFMULL, 4, 0, 17, C, 0x0023, 0x4423 }, + { AFMULL, AXXX, 4, 0, 17, C, 0x0023, 0x4023 }, + { AFMULW, AXXX, 2, 0, 17, C, 0x0023, 0x5023 }, + { AFNEGB, AXXX, 2, 0, 21, C, 0x001a, 0x581a }, + { AFNEGD, AFNEGL, 8, 0, 21, C, 0x001a, 0x541a }, + { AFNEGF, AFNEGL, 4, 0, 21, C, 0x001a, 0x441a }, + { AFNEGL, AXXX, 4, 0, 21, C, 0x001a, 0x401a }, + { AFNEGW, AXXX, 2, 0, 21, C, 0x001a, 0x501a }, + { AFREMB, AXXX, 2, 0, 17, C, 0x0025, 0x5825 }, + { AFREMD, AFREML, 8, 0, 17, C, 0x0025, 0x5425 }, + { AFREMF, AFREML, 4, 0, 17, C, 0x0025, 0x4425 }, + { AFREML, AXXX, 4, 0, 17, C, 0x0025, 0x4025 }, + { AFREMW, AXXX, 2, 0, 17, C, 0x0025, 0x5025 }, + { AFRESTORE, AXXX, 0, 2, 5, C+0x0140 }, + { AFSAVE, AXXX, 0, 2, 5, C+0x0100 }, + { AFSCALEB, AXXX, 2, 0, 17, C, 0x0026, 0x5826 }, + { AFSCALED, AFSCALEL, 8, 0, 17, C, 0x0026, 0x5426 }, + { AFSCALEF, AFSCALEL, 4, 0, 17, C, 0x0026, 0x4426 }, + { AFSCALEL, AXXX, 4, 0, 17, C, 0x0026, 0x4026 }, + { AFSCALEW, AXXX, 2, 0, 17, C, 0x0026, 0x5026 }, + { AFSEQ, AXXX, X1, X2, X3, 0xffff }, + { AFSF, AXXX, 4, X2, X3, 0xffff }, + { AFSGE, AXXX, X1, X2, X3, 0xffff }, + { AFSGT, AXXX, X1, X2, X3, 0xffff }, + { AFSINB, AXXX, 2, 0, 17, C, 0x000e, 0x580e }, + { AFSIND, AFSINL, 8, 0, 17, C, 0x000e, 0x540e }, + { AFSINF, AFSINL, 4, 0, 17, C, 0x000e, 0x440e }, + { AFSINHB, AXXX, 2, 0, 17, C, 0x0002, 0x5802 }, + { AFSINHD, AFSINHL, 8, 0, 17, C, 0x0002, 0x5402 }, + { AFSINHF, AFSINHL, 4, 0, 17, C, 0x0002, 0x4402 }, + { AFSINHL, AXXX, 4, 0, 17, C, 0x0002, 0x4002 }, + { AFSINHW, AXXX, 2, 0, 17, C, 0x0002, 0x5002 }, + { AFSINL, AXXX, 4, 0, 17, C, 0x000e, 0x400e }, + { AFSINW, AXXX, 2, 0, 17, C, 0x000e, 0x500e }, + { AFSLE, AXXX, X1, X2, X3, 0xffff }, + { AFSLT, AXXX, X1, X2, X3, 0xffff }, + { AFSNE, AXXX, X1, X2, X3, 0xffff }, + { AFSQRTB, AXXX, 2, 0, 17, C, 0x0004, 0x5804 }, + { AFSQRTD, AFSQRTL, 8, 0, 17, C, 0x0004, 0x5404 }, + { AFSQRTF, AFSQRTL, 4, 0, 17, C, 0x0004, 0x4404 }, + { AFSQRTL, AXXX, 4, 0, 17, C, 0x0004, 0x4004 }, + { AFSQRTW, AXXX, 2, 0, 17, C, 0x0004, 0x5004 }, + { AFST, AXXX, X1, X2, X3, 0xffff }, + { AFSUBB, AXXX, 2, 0, 17, C, 0x0028, 0x5828 }, + { AFSUBD, AFSUBL, 8, 0, 17, C, 0x0028, 0x5428 }, + { AFSUBF, AFSUBL, 4, 0, 17, C, 0x0028, 0x4428 }, + { AFSUBL, AXXX, 4, 0, 17, C, 0x0028, 0x4028 }, + { AFSUBW, AXXX, 2, 0, 17, C, 0x0028, 0x5028 }, + { AFTANB, AXXX, 2, 0, 17, C, 0x000f, 0x580f }, + { AFTAND, AFTANL, 8, 0, 17, C, 0x000f, 0x540f }, + { AFTANF, AFTANL, 4, 0, 17, C, 0x000f, 0x440f }, + { AFTANHB, AXXX, 2, 0, 17, C, 0x0009, 0x5809 }, + { AFTANHD, AFTANHL, 8, 0, 17, C, 0x0009, 0x5409 }, + { AFTANHF, AFTANHL, 4, 0, 17, C, 0x0009, 0x4409 }, + { AFTANHL, AXXX, 4, 0, 17, C, 0x0009, 0x4009 }, + { AFTANHW, AXXX, 2, 0, 17, C, 0x0009, 0x5009 }, + { AFTANL, AXXX, 4, 0, 17, C, 0x000f, 0x400f }, + { AFTANW, AXXX, 2, 0, 17, C, 0x000f, 0x500f }, + { AFTENTOXB, AXXX, 2, 0, 17, C, 0x0012, 0x5812 }, + { AFTENTOXD, AFTENTOXL, 8, 0, 17, C, 0x0012, 0x5412 }, + { AFTENTOXF, AFTENTOXL, 4, 0, 17, C, 0x0012, 0x4412 }, + { AFTENTOXL, AXXX, 4, 0, 17, C, 0x0012, 0x4012 }, + { AFTENTOXW, AXXX, 2, 0, 17, C, 0x0012, 0x5012 }, + { AFTSTB, AXXX, 0, 2, 20, C, 0x003a, 0x583a }, + { AFTSTD, AFTSTL, 0, 8, 20, C, 0x003a, 0x543a }, + { AFTSTF, AFTSTL, 0, 4, 20, C, 0x003a, 0x443a }, + { AFTSTL, AXXX, 0, 4, 20, C, 0x003a, 0x403a }, + { AFTSTW, AXXX, 0, 2, 20, C, 0x003a, 0x503a }, + { AFTWOTOXB, AXXX, 2, 0, 17, C, 0x0011, 0x5811 }, + { AFTWOTOXD, AFTWOTOXL, 8, 0, 17, C, 0x0011, 0x5411 }, + { AFTWOTOXF, AFTWOTOXL, 4, 0, 17, C, 0x0011, 0x4411 }, + { AFTWOTOXL, AXXX, 4, 0, 17, C, 0x0011, 0x4011 }, + { AFTWOTOXW, AXXX, 2, 0, 17, C, 0x0011, 0x5011 }, + { AGLOBL }, + { AGOK }, + { AHISTORY }, + { AILLEG, AXXX, 0, 0, 4, 0x4efc }, + { AINSTR }, + { AJMP, AXXX, 0, 0, 5, 0x4ec0 }, + { AJSR, AXXX, 0, 0, 5, 0x4e80 }, + { ALEA, AXXX, 0, 0, 6, 0x41c0 }, + { ALINKL }, + { ALINKW }, + { ALOCATE }, + { ALONG, AXXX, 0, 4, 23 }, + { ALSLB, AXXX, 0, 2, 12, 0xe108 }, + { ALSLL, AXXX, 0, 4, 12, 0xe188 }, + { ALSLW, AXXX, 0, 2, 12, 0xe148 }, + { ALSRB, AXXX, 0, 2, 12, 0xe008 }, + { ALSRL, AXXX, 0, 4, 12, 0xe088 }, + { ALSRW, AXXX, 0, 2, 12, 0xe048 }, + { AMOVB, AXXX, 2, -2, 2, 0x1000, 0x7000 }, + { AMOVEM, AXXX, 2, 2, 25, 0x48c0 }, + { AMOVEPL }, + { AMOVEPW }, + { AMOVESB, AXXX, 2, -2, 34, 0xe00 }, + { AMOVESL, AXXX, 4, -4, 34, 0xe80 }, + { AMOVESW, AXXX, 2, -2, 34, 0xe40 }, + { AMOVL, AXXX, 4, -4, 2, 0x2000, 0x7000 }, + { AMOVW, AXXX, 2, -2, 2, 0x3000, 0x7000 }, + { AMULSL, AXXX, 4, 0, 14, 0x4c00, 0x0800 }, + { AMULSW, AXXX, 2, 0, 13, 0xc1c0 }, + { AMULUL, AXXX, 4, 0, 14, 0x4c00, 0x0000 }, + { AMULUW, AXXX, 2, 0, 13, 0xc0c0 }, + { ANAME }, + { ANBCD }, + { ANEGB, AXXX, 0, 0, 5, 0x4400 }, + { ANEGL, AXXX, 0, 0, 5, 0x4480 }, + { ANEGW, AXXX, 0, 0, 5, 0x4440 }, + { ANEGXB }, + { ANEGXL }, + { ANEGXW }, + { ANOP }, + { ANOTB, AXXX, 0, 0, 5, 0x4600 }, + { ANOTL, AXXX, 0, 0, 5, 0x4680 }, + { ANOTW, AXXX, 0, 0, 5, 0x4640 }, + { AORB, AXXX, 2, 0, 9, 0x8000, 0x8100, 0x0000 }, + { AORL, AXXX, 4, 0, 9, 0x8080, 0x8180, 0x0080 }, + { AORW, AXXX, 2, 0, 9, 0x8040, 0x8140, 0x0040 }, + { APACK }, + { APEA, AXXX, 0, 0, 5, 0x4840 }, + { ARESET }, + { AROTLB, AXXX, 0, 2, 12, 0xe118 }, + { AROTLL, AXXX, 0, 4, 12, 0xe198 }, + { AROTLW, AXXX, 0, 2, 12, 0xe158 }, + { AROTRB, AXXX, 0, 2, 12, 0xe018 }, + { AROTRL, AXXX, 0, 4, 12, 0xe098 }, + { AROTRW, AXXX, 0, 2, 12, 0xe058 }, + { AROXLB }, + { AROXLL }, + { AROXLW }, + { AROXRB }, + { AROXRL }, + { AROXRW }, + { ARTD }, + { ARTE, AXXX, 0, 0, 4, 0x4e73 }, + { ARTM }, + { ARTR }, + { ARTS, AXXX, 0, 0, 4, 0x4e75 }, + { ASBCD }, + { ASCC }, + { ASCS }, + { ASEQ }, + { ASF }, + { ASGE }, + { ASGT }, + { ASHI }, + { ASLE }, + { ASLS }, + { ASLT }, + { ASMI }, + { ASNE }, + { ASPL }, + { AST }, + { ASTOP }, + { ASUBB, AXXX, 2, 0, 3, 0x9000, 0x5100, 0, 0x0400 }, + { ASUBL, AXXX, 4, 0, 3, 0x9080, 0x5180, 0x91c0, 0x0480 }, + { ASUBW, AXXX, 2, 0, 3, 0x9040, 0x5140, 0x90c0, 0x0440 }, + { ASUBXB }, + { ASUBXL }, + { ASUBXW }, + { ASVC }, + { ASVS }, + { ASWAP, AXXX, 0, 0, 35, 0x4840 }, + { ASYS, AXXX, 0, 2, 8, 0x4e40 }, + { ATAS, AXXX, 0, 2, 5, 0x4ac0 }, + { ATEXT }, + { ATRAP, AXXX, 0, 0, 30, 0x4e40 }, + { ATRAPCC, AXXX, 0, 0, 4, 0x54fc }, + { ATRAPCS, AXXX, 0, 0, 4, 0x55fc }, + { ATRAPEQ, AXXX, 0, 0, 4, 0x57fc }, + { ATRAPF, AXXX, 0, 0, 4, 0x51fc }, + { ATRAPGE, AXXX, 0, 0, 4, 0x5cfc }, + { ATRAPGT, AXXX, 0, 0, 4, 0x5efc }, + { ATRAPHI, AXXX, 0, 0, 4, 0x52fc }, + { ATRAPLE, AXXX, 0, 0, 4, 0x5ffc }, + { ATRAPLS, AXXX, 0, 0, 4, 0x53fc }, + { ATRAPLT, AXXX, 0, 0, 4, 0x5dfc }, + { ATRAPMI, AXXX, 0, 0, 4, 0x5bfc }, + { ATRAPNE, AXXX, 0, 0, 4, 0x56fc }, + { ATRAPPL, AXXX, 0, 0, 4, 0x5afc }, + { ATRAPT, AXXX, 0, 0, 4, 0x50fc }, + { ATRAPV, AXXX, 0, 0, 4, 0x4e76 }, + { ATRAPVC, AXXX, 0, 0, 4, 0x58fc }, + { ATRAPVS, AXXX, 0, 0, 4, 0x59fc }, + { ATSTB, AXXX, 0, 2, 5, 0x4a00 }, + { ATSTL, AXXX, 0, 4, 5, 0x4a80 }, + { ATSTW, AXXX, 0, 2, 5, 0x4a40 }, + { AUNLK }, + { AUNPK }, + { AWORD, AXXX, 0, 2, 23 }, + { AXXX } +}; + +char mmsize[] = +{ + /* 0 */ 0, 2, 2, 2, 2, + /* 5 */ 2, 2, 2, 4, 2, + /* 10 */ 2, 2, 2, 2, 4, + /* 15 */ 4, 4, 4, 4, 6, + /* 20 */ 4, 4, 4, 0, 4, + /* 25 */ 2, 2, 2, 2, 2, + /* 30 */ 2, 4, 4, 0, 4, + /* 35 */ 2, 0, 0, 0, 0, +}; diff --git a/utils/2l/pass.c b/utils/2l/pass.c new file mode 100644 index 00000000..d429494e --- /dev/null +++ b/utils/2l/pass.c @@ -0,0 +1,538 @@ +#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(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->from.displace; + 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("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || p->as != ABRA) + return p; + p = p->pcond; + } + return P; +} + +void +follow(void) +{ + Prog *p; + long o; + Sym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + firstp = prg(); + lastp = firstp; + xfol(textp); + lastp->link = P; + firstp = firstp->link; + o = 0; /* set */ + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->as == ABCASE) { /* initialization for dodata */ + s = p->from.sym; + if(s->type == SBSS) + s->type = SDATA; + if(s->type != SDATA) + diag("BCASE of non-data: %s in %s\n%P", + s->name, TNAME, p); + } + + p->stkoff = -1; /* initialization for stkoff */ + if(p->as == ATEXT) { + p->stkoff = 0; + o = p->to.offset; + continue; + } + if(p->as == AADJSP && p->from.offset == 0) { + p->stkoff = o; + continue; + } + } +} + +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 == ABRA) + 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; + } + if(a == ABRA || a == ARTS || a == ARTE) + break; + if(q->pcond == P || q->pcond->mark) + continue; + if(a == ABSR || a == ABCASE || a == ADBF) + 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; + } + } /* */ + q = prg(); + q->as = ABRA; + 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 == ARTS || a == ABRA || a == ARTE) + return; + if(p->pcond != P) + if(a != ABSR) { + q = brchain(p->link); + if(q != P && q->mark) + if(a != ABCASE && a != ADBF) { + 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 ABEQ: return ABNE; + case ABNE: return ABEQ; + case ABLE: return ABGT; + case ABLS: return ABHI; + case ABLT: return ABGE; + case ABMI: return ABPL; + case ABGE: return ABLT; + case ABPL: return ABMI; + case ABGT: return ABLE; + case ABHI: return ABLS; + case ABCS: return ABCC; + case ABCC: return ABCS; + case AFBEQ: return AFBNE; + case AFBF: return AFBT; + case AFBGE: return AFBLT; + case AFBGT: return AFBLE; + case AFBLE: return AFBGT; + case AFBLT: return AFBGE; + case AFBNE: return AFBEQ; + case AFBT: return AFBF; + } + diag("unknown relation: %s in %s", anames[a], TNAME); + return a; +} + +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 == ABSR || p->as == ARTS) && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT) { + diag("undefined: %s in %s", s->name, TNAME); + s->type = STEXT; + s->value = vexit; + } + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH) + 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 = 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 != ABRA) + break; + c++; + if(c >= 5000) + return P; + } + return q; +} + +void +dostkoff(void) +{ + Prog *p, *q; + long s, t; + int a; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f stkoff\n", cputime()); + Bflush(&bso); + s = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + s = p->to.offset; + if(s == 0) + continue; + p = appendp(p); + p->as = AADJSP; + p->from.type = D_CONST; + p->from.offset = s; + p->stkoff = 0; + continue; + } + for(q = p; q != P; q = q->pcond) { + if(q->as == ATEXT) + break; + if(q->stkoff >= 0) + if(q->stkoff != s) + diag("stack offset %ld is %ld sb %ld in %s\n%P", + q->pc, q->stkoff, s, q, TNAME, p); + q->stkoff = s; + } + o = &optab[p->as]; + if(p->to.type == D_TOS) + s -= o->dstsp; + if(p->from.type == D_TOS) + s -= o->srcsp; + if(p->as == AADJSP) + s += p->from.offset; + if(p->as == APEA) + s += 4; + for(q = p->link; q != P; q = q->pcond) { + if(q->as == ATEXT) { + q = P; + break; + } + if(q->stkoff >= 0) + break; + } + if(q == P || q->stkoff == s) + continue; + if(p->as == ABRA || p->as == ARTS || p->as == ARTE) { + s = q->stkoff; + continue; + } + if(p->link->as == ABCASE) + diag("BCASE with stack offset in %s", TNAME); + t = q->stkoff - s; + s = q->stkoff; + p = appendp(p); + p->as = AADJSP; + p->stkoff = s - t; + p->from.type = D_CONST; + p->from.offset = t; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + a = p->from.type & D_MASK; + if(a == D_AUTO) + p->from.offset += p->stkoff; + if(a == D_PARAM) + p->from.offset += p->stkoff + 4; + a = p->to.type & D_MASK; + if(a == D_AUTO) + p->to.offset += p->stkoff; + if(a == D_PARAM) + p->to.offset += p->stkoff + 4; + if(p->as != ARTS) + continue; + if(p->stkoff == 0) + continue; + q = p; + p = appendp(p); + p->as = ARTS; + p->stkoff = 0; + + q->as = AADJSP; + q->from.type = D_CONST; + q->from.offset = -q->stkoff; + } +} + +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); +} diff --git a/utils/2l/span.c b/utils/2l/span.c new file mode 100644 index 00000000..45fc23ad --- /dev/null +++ b/utils/2l/span.c @@ -0,0 +1,551 @@ +#include "l.h" + +void +span(void) +{ + Prog *p, *q; + long v, c, idat; + Optab *o; + int m, n; + + xdefine("etext", STEXT, 0L); + xdefine("a6base", STEXT, 0L); + idat = INITDAT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + n = 0; + if((q = p->pcond) != P) + if(q->back != 2) + n = 1; + p->back = n; + if(p->as == AADJSP) { + p->to.type = D_A0+7; + v = -p->from.offset; + p->from.offset = v; + if((v < -8 && v >= -32768L) || (v > 8 && v < 32768L)) { + p->as = ALEA; + p->from.type = I_INDIR | (D_A0+7); + continue; + } + p->as = AADDL; + if(v < 0) { + p->as = ASUBL; + v = -v; + p->from.offset = v; + } + if(v >= 0 && v <= 8) + p->from.type = D_QUICK; + 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; + o = &optab[p->as]; + p->pc = c; + m = mmsize[o->optype]; + if(m == 0) { + if(p->as == AWORD) + m = 2; + if(p->as == ALONG) + m = 4; + p->mark = m; + c += m; + continue; + } + if(p->from.type != D_NONE) + m += andsize(p, &p->from); + if(p->to.type == D_BRANCH) { + if(p->pcond == P) + p->pcond = p; + c += m; + if(m == 2) + m |= 0100; + p->mark = m; + continue; + } + if(p->to.type != D_NONE) + m += andsize(p, &p->to); + p->mark = m; + c += m; + } + +loop: + n++; + if(debug['v']) + Bprint(&bso, "%5.2f span %d\n", cputime(), n); + Bflush(&bso); + if(n > 60) { + diag("span must be looping"); + errorexit(); + } + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if((m = p->mark) & 0100) { + q = p->pcond; + v = q->pc - 2; + if(p->back) + v -= c; + else + v -= p->pc; + p->pc = c; + if(v < -32768L || v >= 32768L) { + if(p->as == ABSR && q->pc < 32768L && q->pc >= 0) + c += 4; + else + c += 6; + } else + if(v < -128 || v >= 128) + c += 4; + else + if(v == 0) { + c += 4; + p->mark = 4; + } else + c += 2; + continue; + } + p->pc = c; + c += m; + } + if(c != textsize) { + textsize = c; + goto loop; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(INITDAT != idat) { + idat = INITDAT; + goto start; + } + xdefine("etext", STEXT, c); + xdefine("a6base", STEXT, INITDAT+A6OFFSET); + 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; +} + +int +andsize(Prog *p, Adr *ap) +{ + int t, n; + long v; + Optab *o; + + t = ap->type; + if(ap->index != D_NONE) { + n = 2; + v = ap->displace; + if(v != 0) { + n += 2; + if(v < -32768L || v >= 32768L) + n += 2; + } + switch(t) { + default: + v = ap->offset; + break; + + case D_STATIC: + case D_EXTERN: + if(ap->sym->type == STEXT) + return n+4; /* see below */ + v = ap->sym->value + ap->offset - A6OFFSET; + if(debug['6']) + v += INITDAT + A6OFFSET; + } + if(v != 0) { + n += 2; + if(v < -32768L || v >= 32768L) + n += 2; + } + return n; + } + n = simple[t]; + if(n != 0177) { + v = ap->offset; + if(v == 0) + return 0; + if((n&070) != 020) /* D_INDIR */ + return 0; + if(v == 0) + return 0; + if(v < -32768L || v >= 32768L) + return 6; /* switch to index1 mode */ + return 2; + } + if((t&I_MASK) == I_ADDR) + t = D_CONST; + switch(t) { + + default: + return 0; + + case D_STACK: + case D_AUTO: + case D_PARAM: + v = ap->offset; + if(v == 0) + return 0; + if(v < -32768L || v >= 32768L) + return 6; /* switch to index1 mode */ + return 2; + + case I_INDIR|D_CONST: + v = ap->offset; + goto adr; + + case D_STATIC: + case D_EXTERN: + if(ap->sym->type == STEXT) + return 4; /* too slow to get back into namelist */ + v = ap->sym->value + ap->offset - A6OFFSET; + if(debug['6']) { + v += INITDAT + A6OFFSET; + goto adr; + } + if(v == 0) + return 0; + + adr: + if(v < -32768L || v >= 32768L) + return 4; + return 2; + + case D_CONST: + case D_FCONST: + o = &optab[p->as]; + if(ap == &(p->from)) + return o->srcsp; + return o->dstsp; + + case D_CCR: + case D_SR: + if(p->as == AMOVW) + return 0; + return 2; + + case D_USP: + t = p->from.type; + if(t >= D_A0 && t <= D_A0+8) + return 0; + t = p->to.type; + if(t >= D_A0 && t <= D_A0+8) + return 0; + + case D_SFC: + case D_DFC: + case D_CACR: + case D_VBR: + case D_CAAR: + case D_MSP: + case D_ISP: + case D_FPCR: + case D_FPSR: + case D_FPIAR: + case D_TC: + case D_ITT0: + case D_ITT1: + case D_DTT0: + case D_DTT1: + case D_MMUSR: + case D_URP: + case D_SRP: + return 2; + } +} + +void +putsymb(Sym *s, int t, long v) +{ + int i, f; + char *n; + + n = s->name; + if(t == 'f') + n++; + lput(v); + if(s->version) + t += 'a' - 'A'; + CPUT(t+0x80); /* 0x80 is variable length */ + + if(t == 'Z' || t == 'z') { + CPUT(n[0]); + for(i=1; n[i] != 0 || n[i+1] != 0; i += 2) { + CPUT(n[i]); + CPUT(n[i+1]); + } + CPUT(0); + CPUT(0); + i++; + } + else { + for(i=0; n[i]; i++) + CPUT(n[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; n[i] != 0 || n[i+1] != 0; i+=2) { + f = ((n[i]&0xff) << 8) | (n[i+1]&0xff); + Bprint(&bso, "/%x", f); + } + Bprint(&bso, "\n"); + return; + } + if(s->version) + Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, n, s->version); + else + Bprint(&bso, "%c %.8lux %s\n", t, v, n); + } +} + +void +asmsym(void) +{ + Prog *p; + Auto *a; + Sym *s; + int h; + + s = lookup("etext", 0); + if(s->type == STEXT) + putsymb(s, 'T', s->value); + s = lookup("a6base", 0); + if(s->type == STEXT) + putsymb(s, 'D', s->value); + + for(h=0; h<NHASH; h++) + for(s=hash[h]; s!=S; s=s->link) + switch(s->type) { + case SDATA: + putsymb(s, 'D', s->value+INITDAT); + continue; + + case SBSS: + putsymb(s, 'B', s->value+INITDAT); + continue; + + case SFILE: + putsymb(s, 'f', s->value); + 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, 'z', a->aoffset); + else + if(a->type == D_FILE1) + putsymb(a->asym, 'Z', a->aoffset); + + putsymb(s, 'T', s->value); + + /* auto and param after */ + for(a=p->to.autom; a; a=a->link) + if(a->type == D_AUTO) + putsymb(a->asym, 'a', -a->aoffset); + else + if(a->type == D_PARAM) + putsymb(a->asym, 'p', a->aoffset); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %lud\n", symsize); + Bflush(&bso); +} + +#define MINLC 2 +void +asmsp(void) +{ + long oldpc, oldsp; + Prog *p; + int s; + long v; + + oldpc = INITTEXT; + oldsp = 0; + for(p = firstp; p != P; p = p->link) { + if(p->stkoff == oldsp || p->as == ATEXT || p->as == ANOP) { + if(p->as == ATEXT) + curtext = p; + if(debug['G']) + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + continue; + } + if(debug['G']) + Bprint(&bso, "\t\t%6ld", spsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + CPUT(s+128); /* 129-255 +pc */ + if(debug['G']) + Bprint(&bso, " pc+%d*2(%d)", s, s+128); + v -= s; + spsize++; + } + v = p->stkoff - oldsp; + oldsp = p->stkoff; + oldpc = p->pc + MINLC; + if(v & 3 || v > 64L*4L || v < -64L*4L) { + CPUT(0); /* 0 vvvv +sp */ + lput(v); + if(debug['G']) { + if(v > 0) + Bprint(&bso, " sp+%ld*1(%d,%ld)\n", + v, 0, v); + else + Bprint(&bso, " sp%ld*1(%d,%ld)\n", + v, 0, v); + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + } + spsize += 5; + continue; + } + s = v/4; + if(s > 0) { + CPUT(0+s); /* 1-64 +sp */ + if(debug['G']) { + Bprint(&bso, " sp+%d*4(%d)\n", s, 0+s); + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + } + } else { + CPUT(64-s); /* 65-128 -sp */ + if(debug['G']) { + Bprint(&bso, " sp%d*4(%d)\n", s, 64-s); + Bprint(&bso, "%6lux %4ld%P\n", + p->pc, p->stkoff, p); + } + } + spsize++; + } + while(spsize & 1) { + s = 129; + CPUT(s); + spsize++; + } + if(debug['v'] || debug['G']) + Bprint(&bso, "stsize = %ld\n", spsize); + 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); +} diff --git a/utils/5a/a.h b/utils/5a/a.h new file mode 100644 index 00000000..23d19347 --- /dev/null +++ b/utils/5a/a.h @@ -0,0 +1,182 @@ +#include <lib9.h> +#include <bio.h> +#include "../5c/5.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#define MAXALIGN 7 +#define FPCHIP 1 +#define NSYMB 8192 +#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; + char* macro; + long value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym* sym; + long offset; + short type; + short reg; + short name; + double dval; + char sval[8]; +}; + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) + +enum +{ + CLAST, + CMACARG, + CMACRO, + CPREPROC, + + Always = 14, +}; + +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* alloc(long); +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 pinit(char*); +void cclean(void); +int isreg(Gen*); +void outcode(int, int, Gen*, int, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, 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 maclin(void); +void macprag(void); +void macif(int); +void macend(void); +void outhist(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*); + +/* + * system-dependent stuff from ../cc/compat.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); diff --git a/utils/5a/a.y b/utils/5a/a.y new file mode 100644 index 00000000..7ef969ca --- /dev/null +++ b/utils/5a/a.y @@ -0,0 +1,673 @@ +%{ +#include "a.h" +%} +%union +{ + Sym *sym; + long lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 +%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA +%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF +%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK +%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX +%token <lval> LCONST LSP LSB LFP LPC +%token <lval> LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR +%token <lval> LCOND LS LAT +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr oexpr pointer offset sreg spreg creg +%type <lval> rcon cond reglist +%type <gen> gen rel reg regreg freg shift fcon frcon +%type <gen> imm ximm name oreg ireg nireg ioreg imsr +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| ';' +| inst ';' +| error ';' + +inst: +/* + * ADD + */ + LTYPE1 cond imsr ',' spreg ',' reg + { + outcode($1, $2, &$3, $5, &$7); + } +| LTYPE1 cond imsr ',' spreg ',' + { + outcode($1, $2, &$3, $5, &nullgen); + } +| LTYPE1 cond imsr ',' reg + { + outcode($1, $2, &$3, NREG, &$5); + } +/* + * MVN + */ +| LTYPE2 cond imsr ',' reg + { + outcode($1, $2, &$3, NREG, &$5); + } +/* + * MOVW + */ +| LTYPE3 cond gen ',' gen + { + outcode($1, $2, &$3, NREG, &$5); + } +/* + * B/BL + */ +| LTYPE4 cond comma rel + { + outcode($1, $2, &nullgen, NREG, &$4); + } +| LTYPE4 cond comma nireg + { + outcode($1, $2, &nullgen, NREG, &$4); + } +/* + * BX + */ +| LTYPEBX comma ireg + { + outcode($1, Always, &nullgen, NREG, &$3); + } +/* + * BEQ + */ +| LTYPE5 comma rel + { + outcode($1, Always, &nullgen, NREG, &$3); + } +/* + * SWI + */ +| LTYPE6 cond comma gen + { + outcode($1, $2, &nullgen, NREG, &$4); + } +/* + * CMP + */ +| LTYPE7 cond imsr ',' spreg comma + { + outcode($1, $2, &$3, $5, &nullgen); + } +/* + * MOVM + */ +| LTYPE8 cond ioreg ',' '[' reglist ']' + { + Gen g; + + g = nullgen; + g.type = D_CONST; + g.offset = $6; + outcode($1, $2, &$3, NREG, &g); + } +| LTYPE8 cond '[' reglist ']' ',' ioreg + { + Gen g; + + g = nullgen; + g.type = D_CONST; + g.offset = $4; + outcode($1, $2, &g, NREG, &$7); + } +/* + * SWAP + */ +| LTYPE9 cond reg ',' ireg ',' reg + { + outcode($1, $2, &$5, $3.reg, &$7); + } +| LTYPE9 cond reg ',' ireg comma + { + outcode($1, $2, &$5, $3.reg, &$3); + } +| LTYPE9 cond comma ireg ',' reg + { + outcode($1, $2, &$4, $6.reg, &$6); + } +/* + * RET + */ +| LTYPEA cond comma + { + outcode($1, $2, &nullgen, NREG, &nullgen); + } +/* + * TEXT/GLOBL + */ +| LTYPEB name ',' imm + { + outcode($1, Always, &$2, NREG, &$4); + } +| LTYPEB name ',' con ',' imm + { + outcode($1, Always, &$2, $4, &$6); + } +/* + * DATA + */ +| LTYPEC name '/' con ',' ximm + { + outcode($1, Always, &$2, $4, &$6); + } +/* + * CASE + */ +| LTYPED cond reg comma + { + outcode($1, $2, &$3, NREG, &nullgen); + } +/* + * word + */ +| LTYPEH comma ximm + { + outcode($1, Always, &nullgen, NREG, &$3); + } +/* + * floating-point coprocessor + */ +| LTYPEI cond freg ',' freg + { + outcode($1, $2, &$3, NREG, &$5); + } +| LTYPEK cond frcon ',' freg + { + outcode($1, $2, &$3, NREG, &$5); + } +| LTYPEK cond frcon ',' LFREG ',' freg + { + outcode($1, $2, &$3, $5, &$7); + } +| LTYPEL cond freg ',' freg comma + { + outcode($1, $2, &$3, $5.reg, &nullgen); + } +/* + * MCR MRC + */ +| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr + { + Gen g; + + g = nullgen; + g.type = D_CONST; + g.offset = + (0xe << 24) | /* opcode */ + ($1 << 20) | /* MCR/MRC */ + ($2 << 28) | /* scond */ + (($3 & 15) << 8) | /* coprocessor number */ + (($5 & 7) << 21) | /* coprocessor operation */ + (($7 & 15) << 12) | /* arm register */ + (($9 & 15) << 16) | /* Crn */ + (($11 & 15) << 0) | /* Crm */ + (($12 & 7) << 5) | /* coprocessor information */ + (1<<4); /* must be set */ + outcode(AWORD, Always, &nullgen, NREG, &g); + } +/* + * MULL hi,lo,r1,r2 + */ +| LTYPEM cond reg ',' reg ',' regreg + { + outcode($1, $2, &$3, $5.reg, &$7); + } +/* + * MULA hi,lo,r1,r2 + */ +| LTYPEN cond reg ',' reg ',' reg ',' spreg + { + $7.type = D_REGREG; + $7.offset = $9; + outcode($1, $2, &$3, $5.reg, &$7); + } +/* + * END + */ +| LTYPEE comma + { + outcode($1, Always, &nullgen, NREG, &nullgen); + } + +cond: + { + $$ = Always; + } +| cond LCOND + { + $$ = ($1 & ~C_SCOND) | $2; + } +| cond LS + { + $$ = $1 | $2; + } + +comma: +| ',' comma + +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; + } + +ximm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } +| '$' oreg + { + $$ = $2; + $$.type = D_CONST; + } +| '$' '*' '$' oreg + { + $$ = $4; + $$.type = D_OCONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| fcon + +fcon: + '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +reglist: + spreg + { + $$ = 1 << $1; + } +| spreg '-' spreg + { + int i; + $$=0; + for(i=$1; i<=$3; i++) + $$ |= 1<<i; + for(i=$3; i<=$1; i++) + $$ |= 1<<i; + } +| spreg comma reglist + { + $$ = (1<<$1) | $3; + } + +gen: + reg +| ximm +| shift +| shift '(' spreg ')' + { + $$ = $1; + $$.reg = $3; + } +| LPSR + { + $$ = nullgen; + $$.type = D_PSR; + $$.reg = $1; + } +| LFCR + { + $$ = nullgen; + $$.type = D_FPCR; + $$.reg = $1; + } +| con + { + $$ = nullgen; + $$.type = D_OREG; + $$.offset = $1; + } +| oreg +| freg + +nireg: + ireg +| name + { + $$ = $1; + if($1.name != D_EXTERN && $1.name != D_STATIC) { + } + } + +ireg: + '(' spreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } + +ioreg: + ireg +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +oreg: + name +| name '(' sreg ')' + { + $$ = $1; + $$.type = D_OREG; + $$.reg = $3; + } +| ioreg + +imsr: + reg +| imm +| shift + +imm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } + +reg: + spreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +regreg: + '(' spreg ',' spreg ')' + { + $$ = nullgen; + $$.type = D_REGREG; + $$.reg = $2; + $$.offset = $4; + } + +shift: + spreg '<' '<' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (0 << 5); + } +| spreg '>' '>' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (1 << 5); + } +| spreg '-' '>' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (2 << 5); + } +| spreg LAT '>' rcon + { + $$ = nullgen; + $$.type = D_SHIFT; + $$.offset = $1 | $4 | (3 << 5); + } + +rcon: + spreg + { + if($$ < 0 || $$ >= 16) + print("register value out of range\n"); + $$ = (($1&15) << 8) | (1 << 4); + } +| con + { + if($$ < 0 || $$ >= 32) + print("shift value out of range\n"); + $$ = ($1&31) << 7; + } + +sreg: + LREG +| LPC + { + $$ = REGPC; + } +| LR '(' expr ')' + { + if($3 < 0 || $3 >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +spreg: + sreg +| LSP + { + $$ = REGSP; + } + +creg: + LCREG +| LC '(' expr ')' + { + if($3 < 0 || $3 >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +frcon: + freg +| fcon + +freg: + LFREG + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } +| LF '(' con ')' + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $3; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +oexpr: + { + $$ = 0; + } +| ',' expr + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/5a/lex.c b/utils/5a/lex.c new file mode 100644 index 00000000..2802f4f8 --- /dev/null +++ b/utils/5a/lex.c @@ -0,0 +1,689 @@ +#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 = '5'; + thestring = "arm"; + 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; + case 't': + thechar = 't'; + thestring = "thumb"; + 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, + + "R", LR, 0, + "R0", LREG, 0, + "R1", LREG, 1, + "R2", LREG, 2, + "R3", LREG, 3, + "R4", LREG, 4, + "R5", LREG, 5, + "R6", LREG, 6, + "R7", LREG, 7, + "R8", LREG, 8, + "R9", LREG, 9, + "R10", LREG, 10, + "R11", LREG, 11, + "R12", LREG, 12, + "R13", LREG, 13, + "R14", LREG, 14, + "R15", LREG, 15, + + "F", LF, 0, + + "F0", LFREG, 0, + "F1", LFREG, 1, + "F2", LFREG, 2, + "F3", LFREG, 3, + "F4", LFREG, 4, + "F5", LFREG, 5, + "F6", LFREG, 6, + "F7", LFREG, 7, + "F8", LFREG, 8, + "F9", LFREG, 9, + "F10", LFREG, 10, + "F11", LFREG, 11, + "F12", LFREG, 12, + "F13", LFREG, 13, + "F14", LFREG, 14, + "F15", LFREG, 15, + + "C", LC, 0, + + "C0", LCREG, 0, + "C1", LCREG, 1, + "C2", LCREG, 2, + "C3", LCREG, 3, + "C4", LCREG, 4, + "C5", LCREG, 5, + "C6", LCREG, 6, + "C7", LCREG, 7, + "C8", LCREG, 8, + "C9", LCREG, 9, + "C10", LCREG, 10, + "C11", LCREG, 11, + "C12", LCREG, 12, + "C13", LCREG, 13, + "C14", LCREG, 14, + "C15", LCREG, 15, + + "CPSR", LPSR, 0, + "SPSR", LPSR, 1, + + "FPSR", LFCR, 0, + "FPCR", LFCR, 1, + + ".EQ", LCOND, 0, + ".NE", LCOND, 1, + ".CS", LCOND, 2, + ".HS", LCOND, 2, + ".CC", LCOND, 3, + ".LO", LCOND, 3, + ".MI", LCOND, 4, + ".PL", LCOND, 5, + ".VS", LCOND, 6, + ".VC", LCOND, 7, + ".HI", LCOND, 8, + ".LS", LCOND, 9, + ".GE", LCOND, 10, + ".LT", LCOND, 11, + ".GT", LCOND, 12, + ".LE", LCOND, 13, + ".AL", LCOND, Always, + + ".U", LS, C_UBIT, + ".S", LS, C_SBIT, + ".W", LS, C_WBIT, + ".P", LS, C_PBIT, + ".PW", LS, C_WBIT|C_PBIT, + ".WP", LS, C_WBIT|C_PBIT, + + ".F", LS, C_FBIT, + + ".IBW", LS, C_WBIT|C_PBIT|C_UBIT, + ".IAW", LS, C_WBIT|C_UBIT, + ".DBW", LS, C_WBIT|C_PBIT, + ".DAW", LS, C_WBIT, + ".IB", LS, C_PBIT|C_UBIT, + ".IA", LS, C_UBIT, + ".DB", LS, C_PBIT, + ".DA", LS, 0, + + "@", LAT, 0, + + "AND", LTYPE1, AAND, + "EOR", LTYPE1, AEOR, + "SUB", LTYPE1, ASUB, + "RSB", LTYPE1, ARSB, + "ADD", LTYPE1, AADD, + "ADC", LTYPE1, AADC, + "SBC", LTYPE1, ASBC, + "RSC", LTYPE1, ARSC, + "ORR", LTYPE1, AORR, + "BIC", LTYPE1, ABIC, + + "SLL", LTYPE1, ASLL, + "SRL", LTYPE1, ASRL, + "SRA", LTYPE1, ASRA, + + "MUL", LTYPE1, AMUL, + "MULA", LTYPEN, AMULA, + "DIV", LTYPE1, ADIV, + "MOD", LTYPE1, AMOD, + + "MULL", LTYPEM, AMULL, + "MULAL", LTYPEM, AMULAL, + "MULLU", LTYPEM, AMULLU, + "MULALU", LTYPEM, AMULALU, + + "MVN", LTYPE2, AMVN, /* op2 ignored */ + + "MOVB", LTYPE3, AMOVB, + "MOVBU", LTYPE3, AMOVBU, + "MOVH", LTYPE3, AMOVH, + "MOVHU", LTYPE3, AMOVHU, + "MOVW", LTYPE3, AMOVW, + + "MOVD", LTYPE3, AMOVD, + "MOVDF", LTYPE3, AMOVDF, + "MOVDW", LTYPE3, AMOVDW, + "MOVF", LTYPE3, AMOVF, + "MOVFD", LTYPE3, AMOVFD, + "MOVFW", LTYPE3, AMOVFW, + "MOVWD", LTYPE3, AMOVWD, + "MOVWF", LTYPE3, AMOVWF, + +/* + "ABSF", LTYPEI, AABSF, + "ABSD", LTYPEI, AABSD, + "NEGF", LTYPEI, ANEGF, + "NEGD", LTYPEI, ANEGD, + "SQTF", LTYPEI, ASQTF, + "SQTD", LTYPEI, ASQTD, + "RNDF", LTYPEI, ARNDF, + "RNDD", LTYPEI, ARNDD, + "URDF", LTYPEI, AURDF, + "URDD", LTYPEI, AURDD, + "NRMF", LTYPEI, ANRMF, + "NRMD", LTYPEI, ANRMD, +*/ + + "CMPF", LTYPEL, ACMPF, + "CMPD", LTYPEL, ACMPD, + "ADDF", LTYPEK, AADDF, + "ADDD", LTYPEK, AADDD, + "SUBF", LTYPEK, ASUBF, + "SUBD", LTYPEK, ASUBD, + "MULF", LTYPEK, AMULF, + "MULD", LTYPEK, AMULD, + "DIVF", LTYPEK, ADIVF, + "DIVD", LTYPEK, ADIVD, + + "B", LTYPE4, AB, + "BL", LTYPE4, ABL, + "BX", LTYPEBX, ABX, + + "BEQ", LTYPE5, ABEQ, + "BNE", LTYPE5, ABNE, + "BCS", LTYPE5, ABCS, + "BHS", LTYPE5, ABHS, + "BCC", LTYPE5, ABCC, + "BLO", LTYPE5, ABLO, + "BMI", LTYPE5, ABMI, + "BPL", LTYPE5, ABPL, + "BVS", LTYPE5, ABVS, + "BVC", LTYPE5, ABVC, + "BHI", LTYPE5, ABHI, + "BLS", LTYPE5, ABLS, + "BGE", LTYPE5, ABGE, + "BLT", LTYPE5, ABLT, + "BGT", LTYPE5, ABGT, + "BLE", LTYPE5, ABLE, + "BCASE", LTYPE5, ABCASE, + + "SWI", LTYPE6, ASWI, + + "CMP", LTYPE7, ACMP, + "TST", LTYPE7, ATST, + "TEQ", LTYPE7, ATEQ, + "CMN", LTYPE7, ACMN, + + "MOVM", LTYPE8, AMOVM, + + "SWPBU", LTYPE9, ASWPBU, + "SWPW", LTYPE9, ASWPW, + + "RET", LTYPEA, ARET, + "RFE", LTYPEA, ARFE, + + "TEXT", LTYPEB, ATEXT, + "GLOBL", LTYPEB, AGLOBL, + "DATA", LTYPEC, ADATA, + "CASE", LTYPED, ACASE, + "END", LTYPEE, AEND, + "WORD", LTYPEH, AWORD, + "NOP", LTYPEI, ANOP, + + "MCR", LTYPEJ, 0, + "MRC", LTYPEJ, 1, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.sym = S; + nullgen.offset = 0; + nullgen.type = D_NONE; + nullgen.name = D_NONE; + nullgen.reg = NREG; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 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); + 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 +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +int +isreg(Gen *g) +{ + + USED(g); + return 1; +} + +void +cclean(void) +{ + + outcode(AEND, Always, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + 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; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + case D_FPCR: + break; + + case D_REGREG: + Bputc(&obuf, a->offset); + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(&obuf, *n); + n++; + } + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +static int bcode[] = +{ + ABEQ, + ABNE, + ABCS, + ABCC, + ABMI, + ABPL, + ABVS, + ABVC, + ABHI, + ABLS, + ABGE, + ABLT, + ABGT, + ABLE, + AB, + ANOP, +}; + +void +outcode(int a, int scond, Gen *g1, int reg, Gen *g2) +{ + int sf, st, t; + Sym *s; + + /* hack to make B.NE etc. work: turn it into the corresponding conditional */ + if(a == AB){ + a = bcode[scond&0xf]; + scond = (scond & ~0xf) | Always; + } + + if(pass == 1) + goto out; +jackpot: + sf = 0; + s = g1->sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g1->name; + 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->sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->name; + 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, scond); + Bputc(&obuf, reg); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, sf); + zaddr(g2, 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, 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, Always); + Bputc(&obuf, 0); + 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" diff --git a/utils/5a/mkfile b/utils/5a/mkfile new file mode 100644 index 00000000..211d6387 --- /dev/null +++ b/utils/5a/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=5a + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../5c/5.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/5c/5.out.h b/utils/5c/5.out.h new file mode 100644 index 00000000..ae856e28 --- /dev/null +++ b/utils/5c/5.out.h @@ -0,0 +1,197 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 16 + +#define NOPROF (1<<0) +#define DUPOK (1<<1) +#define ALLTHUMBS (1<<2) + +#define REGRET 0 +#define REGARG 0 +/* compiler allocates R1 up as temps */ +/* compiler allocates register variables R3 up */ +#define REGEXT 10 +/* compiler allocates external registers R10 down */ +#define REGTMP 11 +#define REGSB 12 +#define REGSP 13 +#define REGLINK 14 +#define REGPC 15 + +#define REGTMPT 7 /* used by the loader for thumb code */ + +#define NFREG 8 +#define FREGRET 0 +#define FREGEXT 7 +/* compiler allocates register variables F0 up */ +/* compiler allocates external registers F7 down */ + +enum as +{ + AXXX, + + AAND, + AEOR, + ASUB, + ARSB, + AADD, + AADC, + ASBC, + ARSC, + ATST, + ATEQ, + ACMP, + ACMN, + AORR, + ABIC, + + AMVN, + + AB, + ABL, + +/* + * Do not reorder or fragment the conditional branch + * opcodes, or the predication code will break + */ + ABEQ, + ABNE, + ABCS, + ABHS, + ABCC, + ABLO, + ABMI, + ABPL, + ABVS, + ABVC, + ABHI, + ABLS, + ABGE, + ABLT, + ABGT, + ABLE, + + AMOVWD, + AMOVWF, + AMOVDW, + AMOVFW, + AMOVFD, + AMOVDF, + AMOVF, + AMOVD, + + ACMPF, + ACMPD, + AADDF, + AADDD, + ASUBF, + ASUBD, + AMULF, + AMULD, + ADIVF, + ADIVD, + + ASRL, + ASRA, + ASLL, + AMULU, + ADIVU, + AMUL, + ADIV, + AMOD, + AMODU, + + AMOVB, + AMOVBU, + AMOVH, + AMOVHU, + AMOVW, + AMOVM, + ASWPBU, + ASWPW, + + ANOP, + ARFE, + ASWI, + AMULA, + + ADATA, + AGLOBL, + AGOK, + AHISTORY, + ANAME, + ARET, + ATEXT, + AWORD, + ADYNT, + AINIT, + ABCASE, + ACASE, + + AEND, + + AMULL, + AMULAL, + AMULLU, + AMULALU, + + ABX, + ABXRET, + ADWORD, + + ASIGNAME, + + ALAST, +}; + +/* scond byte */ +#define C_SCOND ((1<<4)-1) +#define C_SBIT (1<<4) +#define C_PBIT (1<<5) +#define C_WBIT (1<<6) +#define C_FBIT (1<<7) /* psr flags-only */ +#define C_UBIT (1<<7) /* up bit */ + +/* type/name */ +#define D_GOK 0 +#define D_NONE 1 + +/* type */ +#define D_BRANCH (D_NONE+1) +#define D_OREG (D_NONE+2) +#define D_CONST (D_NONE+7) +#define D_FCONST (D_NONE+8) +#define D_SCONST (D_NONE+9) +#define D_PSR (D_NONE+10) +#define D_REG (D_NONE+12) +#define D_FREG (D_NONE+13) +#define D_FILE (D_NONE+16) +#define D_OCONST (D_NONE+17) +#define D_FILE1 (D_NONE+18) + +#define D_SHIFT (D_NONE+19) +#define D_FPCR (D_NONE+20) +#define D_REGREG (D_NONE+21) + +/* name */ +#define D_EXTERN (D_NONE+3) +#define D_STATIC (D_NONE+4) +#define D_AUTO (D_NONE+5) +#define D_PARAM (D_NONE+6) + +/* + * 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 */ +}; diff --git a/utils/5c/cgen.c b/utils/5c/cgen.c new file mode 100644 index 00000000..65db14c4 --- /dev/null +++ b/utils/5c/cgen.c @@ -0,0 +1,1156 @@ +#include "gc.h" + +void +cgen(Node *n, Node *nn, int inrel) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o, t; + long v, curs; + + 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(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod, 0); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn, 0); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED && l->complex < FNX) { + if(nn != Z || r->addable < INDEXED) { + if(r->complex >= FNX && nn == Z) + regret(&nod, r); + else + regalloc(&nod, r, nn); + cgen(r, &nod, 0); + gmove(&nod, l); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + } else + gmove(r, l); + break; + } + if(l->complex >= r->complex) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod, 0); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod, 0); + 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, 0); + } else { + cgen(r, &nod, 0); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case ODIV: + case OMOD: + if(nn != Z) + if((t = vlog(r)) >= 0) { + /* signed div/mod by constant power of 2 */ + cgen(l, nn, 0); + gopcode(OGE, nodconst(0), nn, Z); + p1 = p; + if(o == ODIV) { + gopcode(OADD, nodconst((1<<t)-1), Z, nn); + patch(p1, pc); + gopcode(OASHR, nodconst(t), Z, nn); + } else { + gopcode(OSUB, nn, nodconst(0), nn); + gopcode(OAND, nodconst((1<<t)-1), Z, nn); + gopcode(OSUB, nn, nodconst(0), nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + gopcode(OAND, nodconst((1<<t)-1), Z, nn); + patch(p1, pc); + } + break; + } + goto muldiv; + + case OSUB: + if(nn != Z) + if(l->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(r, nn, 0); + gopcode(o, Z, l, nn); + break; + } + case OADD: + case OAND: + case OOR: + case OXOR: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(l, nn, 0); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OLMUL: + case OLDIV: + case OLMOD: + case OMUL: + muldiv: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod, 0); + regalloc(&nod1, r, Z); + cgen(r, &nod1, 0); + gopcode(o, &nod1, Z, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod, 0); + regalloc(&nod1, l, Z); + cgen(l, &nod1, 0); + gopcode(o, &nod, &nod1, &nod); + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(r->op == OCONST) + if(!typefd[r->type->etype]) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, r, Z); + cgen(r, &nod1, 0); + } else { + regalloc(&nod1, r, Z); + cgen(r, &nod1, 0); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + + regalloc(&nod, n, nn); + gmove(&nod2, &nod); + gopcode(o, &nod1, Z, &nod); + gmove(&nod, &nod2); + if(nn != Z) + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + asbitop: + regalloc(&nod4, n, nn); + if(l->complex >= r->complex) { + bitload(l, &nod, &nod1, &nod2, &nod4); + regalloc(&nod3, r, Z); + cgen(r, &nod3, 0); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3, 0); + bitload(l, &nod, &nod1, &nod2, &nod4); + } + gmove(&nod, &nod4); + gopcode(o, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod, 0); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn, 0); + + return; + } + if(REGARG >= 0) + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG >= 0) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + 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+nod.xoffset) > -4096 && v < 4096) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod, 0); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod, 0); + regind(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z, 0); + cgen(r, nn, 0); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type)) { + if(nocast(n->type, nn->type)) { + cgen(l, nn, 0); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod, 0); + regalloc(&nod1, n, &nod); + if(inrel) + gmover(&nod, &nod1); + else + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (long)r->vconst; + nod.type = n->type; + cgen(&nod, nn, 0); + } + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + cgen(r->left, nn, 0); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + cgen(r->right, nn, 0); + patch(p1, pc); + break; + + case OPOSTINC: + case OPOSTDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPOSTDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + if(nn == Z) + goto pre; + + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; + return; +} + +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+t->xoffset) > -4096 && v < 4096) { + v = r->vconst; + r->vconst = 0; + lcgen(n, t); + t->xoffset += v; + r->vconst = v; + regind(t, n); + return; + } + } else if(n->op == OINDREG) { + if((v = n->xoffset) > -4096 && v < 4096) { + n->op = OREGISTER; + cgen(n, t, 0); + t->xoffset += v; + n->op = OINDREG; + regind(t, n); + return; + } + } + lcgen(n, t); + regind(t, n); +} + +void +reglpcgen(Node *n, Node *nn, int f) +{ + Type *t; + + t = nn->type; + nn->type = types[TLONG]; + if(f) + reglcgen(n, nn, Z); + else { + regialloc(n, nn, Z); + lcgen(nn, n); + regind(n, nn); + } + nn->type = t; +} + +void +lcgen(Node *n, Node *nn) +{ + Prog *p1; + Node nod; + + if(debug['g']) { + prtree(nn, "lcgen lhs"); + prtree(n, "lcgen"); + } + if(n == Z || n->type == T) + return; + if(nn == Z) { + nn = &nod; + regalloc(&nod, n, Z); + } + switch(n->op) { + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left, 0); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn, 0); + 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: + regalloc(&nod, n, nn); + cgen(n, &nod, 0); + o = ONE; + if(true) + o = comrel[relindex(o)]; + if(typefd[n->type->etype]) { + gopcode(o, nodfconst(0), &nod, Z); + } else + gopcode(o, nodconst(0), &nod, Z); + 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, 0); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod, 1); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(sconst(l)) { + regalloc(&nod, r, nn); + cgen(r, &nod, 1); + o = invrel[relindex(o)]; + gopcode(o, l, &nod, Z); + regfree(&nod); + goto com; + } + if(sconst(r)) { + regalloc(&nod, l, nn); + cgen(l, &nod, 1); + gopcode(o, r, &nod, Z); + regfree(&nod); + goto com; + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1, 1); + regalloc(&nod, r, Z); + cgen(r, &nod, 1); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod, 1); + regalloc(&nod1, l, Z); + cgen(l, &nod1, 1); + } + gopcode(o, &nod, &nod1, Z); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + nod1.xoffset += SZ_LONG; + if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + + regfree(&nod1); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && nn->complex >= FNX) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn, 0); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + cgen(&nod0, Z, 0); + } + 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; + } + 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, 0); + 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, 0); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + w /= SZ_LONG; + if(w <= 2) { + if(n->complex > nn->complex) { + reglpcgen(&nod1, n, 1); + reglpcgen(&nod2, nn, 1); + } else { + reglpcgen(&nod2, nn, 1); + reglpcgen(&nod1, n, 1); + } + regalloc(&nod3, ®node, Z); + regalloc(&nod4, ®node, Z); + nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg)); + if(w == 2 && nod1.xoffset == 0) + gmovm(&nod1, &nod0, 0); + else { + gmove(&nod1, &nod3); + if(w == 2) { + nod1.xoffset += SZ_LONG; + gmove(&nod1, &nod4); + } + } + if(w == 2 && nod2.xoffset == 0) + gmovm(&nod0, &nod2, 0); + else { + gmove(&nod3, &nod2); + if(w == 2) { + nod2.xoffset += SZ_LONG; + gmove(&nod4, &nod2); + } + } + regfree(&nod1); + regfree(&nod2); + regfree(&nod3); + regfree(&nod4); + return; + } + + if(n->complex > nn->complex) { + reglpcgen(&nod1, n, 0); + reglpcgen(&nod2, nn, 0); + } else { + reglpcgen(&nod2, nn, 0); + reglpcgen(&nod1, n, 0); + } + + m = 0; + for(c = 0; c < w && c < 4; c++) { + i = tmpreg(); + if (i == 0) + break; + reg[i]++; + m |= 1<<i; + } + nod4 = *(nodconst(m)); + if(w < 3*c) { + for (; w>c; w-=c) { + gmovm(&nod1, &nod4, 1); + gmovm(&nod4, &nod2, 1); + } + goto out; + } + + regalloc(&nod3, ®node, Z); + gopcode(OAS, nodconst(w/c), Z, &nod3); + w %= c; + + pc1 = pc; + gmovm(&nod1, &nod4, 1); + gmovm(&nod4, &nod2, 1); + + gopcode(OSUB, nodconst(1), Z, &nod3); + gopcode(OEQ, nodconst(0), &nod3, Z); + p->as = ABGT; + patch(p, pc1); + regfree(&nod3); + +out: + if (w) { + i = 0; + while (c>w) { + while ((m&(1<<i)) == 0) + i++; + m &= ~(1<<i); + reg[i] = 0; + c--; + i++; + } + nod4.vconst = m; + gmovm(&nod1, &nod4, 0); + gmovm(&nod4, &nod2, 0); + } + i = 0; + do { + while ((m&(1<<i)) == 0) + i++; + reg[i] = 0; + c--; + i++; + } while (c>0); + regfree(&nod1); + regfree(&nod2); +} diff --git a/utils/5c/enam.c b/utils/5c/enam.c new file mode 100644 index 00000000..989b2760 --- /dev/null +++ b/utils/5c/enam.c @@ -0,0 +1,98 @@ +char* anames[] = +{ + "XXX", + "AND", + "EOR", + "SUB", + "RSB", + "ADD", + "ADC", + "SBC", + "RSC", + "TST", + "TEQ", + "CMP", + "CMN", + "ORR", + "BIC", + "MVN", + "B", + "BL", + "BEQ", + "BNE", + "BCS", + "BHS", + "BCC", + "BLO", + "BMI", + "BPL", + "BVS", + "BVC", + "BHI", + "BLS", + "BGE", + "BLT", + "BGT", + "BLE", + "MOVWD", + "MOVWF", + "MOVDW", + "MOVFW", + "MOVFD", + "MOVDF", + "MOVF", + "MOVD", + "CMPF", + "CMPD", + "ADDF", + "ADDD", + "SUBF", + "SUBD", + "MULF", + "MULD", + "DIVF", + "DIVD", + "SRL", + "SRA", + "SLL", + "MULU", + "DIVU", + "MUL", + "DIV", + "MOD", + "MODU", + "MOVB", + "MOVBU", + "MOVH", + "MOVHU", + "MOVW", + "MOVM", + "SWPBU", + "SWPW", + "NOP", + "RFE", + "SWI", + "MULA", + "DATA", + "GLOBL", + "GOK", + "HISTORY", + "NAME", + "RET", + "TEXT", + "WORD", + "DYNT", + "INIT", + "BCASE", + "CASE", + "END", + "MULL", + "MULAL", + "MULLU", + "MULALU", + "BX", + "BXRET", + "DWORD", + "SIGNAME", + "LAST", +}; diff --git a/utils/5c/gc.h b/utils/5c/gc.h new file mode 100644 index 00000000..1231ac31 --- /dev/null +++ b/utils/5c/gc.h @@ -0,0 +1,349 @@ +#include "../cc/cc.h" +#include "../5c/5.out.h" + +/* + * 5c/arm + * Arm 7500 + */ +#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 Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + + +#define R0ISZERO 0 + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + Ieee ieee; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + char as; + char reg; + uchar scond; +}; +#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 Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +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) + +#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 Multab multab[20]; +EXTERN int retok; +EXTERN int hintabsize; +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 char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN char reg[NREG+NFREG]; +EXTERN long exregoffset; +EXTERN long exfregoffset; +EXTERN int suppress; + +#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 4 +#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 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[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void usedset(Node*, int); +void xcom(Node*); +int bcomplex(Node*, Node*); + +/* + * cgen.c + */ +void cgen(Node*, Node*, int); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nod32const(vlong); +Node* nodfconst(double); +void nodreg(Node*, Node*, int); +void regret(Node*, Node*); +int tmpreg(void); +void regalloc(Node*, Node*, Node*); +void regfree(Node*); +void regialloc(Node*, Node*, Node*); +void regsalloc(Node*, Node*); +void regaalloc1(Node*, Node*); +void regaalloc(Node*, Node*); +void regind(Node*, Node*); +void gprep(Node*, Node*); +void raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmovm(Node*, Node*, int); +void gmove(Node*, Node*); +void gmover(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int sval(long); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(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 Nconv(Fmt*); +int Bconv(Fmt*); +int Rconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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 regzer(Adr*); +int anyvar(Adr*); +int subprop(Reg*); +int copyprop(Reg*); +int shiftprop(Reg*); +void constprop(Adr*, Adr*, Reg*); +int copy1(Adr*, Adr*, Reg*, int); +int copyu(Prog*, Adr*, Adr*); + +int copyas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copyau1(Prog*, 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); + +void predicate(void); +int isbranch(Prog *); +int predicable(Prog *p); +int modifiescpsr(Prog *p); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "R" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/5c/list.c b/utils/5c/list.c new file mode 100644 index 00000000..d50f07db --- /dev/null +++ b/utils/5c/list.c @@ -0,0 +1,304 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('B', Bconv); + 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); +} + +char *extra [] = { + ".EQ", ".NE", ".CS", ".CC", + ".MI", ".PL", ".VS", ".VC", + ".HI", ".LS", ".GE", ".LT", + ".GT", ".LE", "", ".NV", +}; + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], sc[20]; + Prog *p; + int a, s; + + p = va_arg(fp->args, Prog*); + a = p->as; + s = p->scond; + strcpy(sc, extra[s & C_SCOND]); + if(s & C_SBIT) + strcat(sc, ".S"); + if(s & C_PBIT) + strcat(sc, ".P"); + if(s & C_WBIT) + strcat(sc, ".W"); + if(s & C_UBIT) /* ambiguous with FBIT */ + strcat(sc, ".U"); + if(a == AMOVM) { + if(p->from.type == D_CONST) + sprint(str, " %A%s %R,%D", a, sc, &p->from, &p->to); + else + if(p->to.type == D_CONST) + sprint(str, " %A%s %D,%R", a, sc, &p->from, &p->to); + else + sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); + } else + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A%s %D,%D", a, sc, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A%s %D,R%d,%D", a, sc, &p->from, p->reg, &p->to); + else + sprint(str, " %A%s %D,F%d,%D", a, sc, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + char *op; + int v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_SHIFT: + v = a->offset; + op = "<<>>->@>" + (((v>>5) & 3) << 1); + if(v & (1<<4)) + sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); + else + sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); + if(a->reg != NREG) + sprint(str+strlen(str), "(R%d)", a->reg); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_PSR: + sprint(str, "PSR"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(PSR)(REG)", a); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + int i, v; + + a = va_arg(fp->args, Adr*); + sprint(str, "GOK-reglist"); + switch(a->type) { + case D_CONST: + if(a->reg != NREG) + break; + if(a->sym != S) + break; + v = a->offset; + strcpy(str, ""); + for(i=0; i<NREG; i++) { + if(v & (1<<i)) { + if(str[0] == 0) + strcat(str, "[R"); + else + strcat(str, ",R"); + sprint(strchr(str, 0), "%d", i); + } + } + strcat(str, "]"); + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<NSNAME; i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/5c/mkenam b/utils/5c/mkenam new file mode 100644 index 00000000..e1cbf710 --- /dev/null +++ b/utils/5c/mkenam @@ -0,0 +1,15 @@ +ed - ../5c/5.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/utils/5c/mkfile b/utils/5c/mkfile new file mode 100644 index 00000000..a0f53c45 --- /dev/null +++ b/utils/5c/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=5c + +OFILES=\ + cgen.$O\ + enam.$O\ + list.$O\ + mul.$O\ + peep.$O\ + reg.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + +HFILES=\ + gc.h\ + 5.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/5c/mul.c b/utils/5c/mul.c new file mode 100644 index 00000000..67370a62 --- /dev/null +++ b/utils/5c/mul.c @@ -0,0 +1,609 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int maxmulops = 3; /* max # of ops to replace mul with */ +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ +}; + +Multab* +mulcon0(long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; g<nelem(multab); g++) { + if(m->val == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=maxmulops; g++) { + if(g >= maxmulops && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<<c, r1)) + goto out; + break; + case 1: + if(docode(hp, cp, r1<<c, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r0, r0<<c)) + goto out; + break; + case 3: + if(docode(hp, cp, r0, r1<<c)) + goto out; + break; + } + } + break; + + case '+': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0+r1, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0+r1)) + goto out; + break; + } + } + break; + + case '-': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0-r1, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r1-r0, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0-r1)) + goto out; + break; + case 6: + if(docode(hp, cp, r0, r1-r0)) + goto out; + break; + } + } + break; + + case 0: + if(r0 == mulval) + return 1; + } + return 0; + +out: + cp[-1] = i+'0'; + return 1; +} + +static int +gen1(int len) +{ + int i; + + for(shmax=1; shmax<30; shmax++) { + valmax = 1<<shmax; + if(valmax >= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<<i)) { + *--mulcp = 'a'+i; + return 1; + } + return 0; +} + +static int +gen2(int len, long r1) +{ + int i; + + if(len <= 0) { + if(r1 == mulval) + return 1; + return 0; + } + + len--; + if(len == 0) + goto calcr0; + + if(gen3(len, r1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, r1-1, r1, UR0)) { + i = '-'; + goto out; + } + if(gen3(len, 1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, 1, r1-1, UR1)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + if(mulval == r1+1) { + i = '+'; + goto out; + } + if(mulval == r1-1) { + i = '-'; + goto out; + } + return 0; + +out: + *--mulcp = i; + return 1; +} + +static int +gen3(int len, long r0, long r1, int flag) +{ + int i, f1, f2; + long x; + + if(r0 <= 0 || + r0 >= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x >= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/5c/peep.c b/utils/5c/peep.c new file mode 100644 index 00000000..4eded1dc --- /dev/null +++ b/utils/5c/peep.c @@ -0,0 +1,1440 @@ +#include "gc.h" + +int xtramodes(Reg*, Adr*); + +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; + } + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == ASLL || p->as == ASRL || p->as == ASRA) { + /* + * elide shift into D_SHIFT operand of subsequent instruction + */ + if(shiftprop(r)) { + excise(r); + t++; + } + } + if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) + if(regtyp(&p->to)) { + if(p->from.type == D_CONST) + constprop(&p->from, &p->to, r->s1); + else if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AEOR: + /* + * EOR -1,x,y => MVN x,y + */ + if(p->from.type == D_CONST && p->from.offset == -1) { + p->as = AMVN; + p->from.type = D_REG; + if(p->reg != NREG) + p->from.reg = p->reg; + else + p->from.reg = p->to.reg; + p->reg = NREG; + } + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } + + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case AMOVW: + case AMOVB: + case AMOVBU: + if(p->from.type == D_OREG && p->from.offset == 0) + xtramodes(r, &p->from); + else if(p->to.type == D_OREG && p->to.offset == 0) + xtramodes(r, &p->to); + else + continue; + break; + case ACMP: + /* + * elide CMP $0,x if calculation of x can set condition codes + */ + if(p->from.type != D_CONST || p->from.offset != 0) + continue; + r2 = r->s1; + if(r2 == R) + continue; + t = r2->prog->as; + switch(t) { + default: + continue; + case ABEQ: + case ABNE: + case ABMI: + case ABPL: + break; + case ABGE: + t = ABPL; + break; + case ABLT: + t = ABMI; + break; + case ABHI: + t = ABNE; + break; + case ABLS: + t = ABEQ; + break; + } + r1 = r; + do + r1 = uniqp(r1); + while (r1 != R && r1->prog->as == ANOP); + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->to.type != D_REG) + continue; + if(p1->to.reg != p->reg) + if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) + continue; + switch(p1->as) { + default: + continue; + case AMOVW: + if(p1->from.type != D_REG) + continue; + case AAND: + case AEOR: + case AORR: + case ABIC: + case AMVN: + case ASUB: + case ARSB: + case AADD: + case AADC: + case ASBC: + case ARSC: + break; + } + p1->scond |= C_SBIT; + r2->prog->as = t; + excise(r); + continue; + } + } + + predicate(); +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->scond = zprog.scond; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +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) +{ + + if(a->type == D_REG) + return 1; + if(a->type == D_FREG) + 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 ABL: + return 0; + + case ACMP: + case ACMN: + case AADD: + case ASUB: + case ARSB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + + case ACMPF: + case ACMPD: + case AADDD: + case AADDF: + case ASUBD: + case ASUBF: + case AMULD: + case AMULF: + case ADIVD: + case ADIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AMOVF: + case AMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + + case AMOVM: + t = 1<<v2->reg; + if((p->from.type == D_CONST && (p->from.offset&t)) || + (p->to.type == D_CONST && (p->to.offset&t))) + return 0; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +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("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * The idea is to remove redundant constants. + * $c1->v1 + * ($c1->v2 s/$c1/v1)* + * set v1 return + * The v1->v2 should be eliminated by copy propagation. + */ +void +constprop(Adr *c1, Adr *v1, Reg *r) +{ + Prog *p; + + if(debug['C']) + print("constprop %D->%D\n", c1, v1); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['C']) + print("%P", p); + if(uniqp(r) == R) { + if(debug['C']) + print("; merge; return\n"); + return; + } + if(p->as == AMOVW && copyas(&p->from, c1)) { + if(debug['C']) + print("; sub%D/%D", &p->from, v1); + p->from = *v1; + } else if(copyu(p, v1, A) > 1) { + if(debug['C']) + print("; %Dset; return\n", v1); + return; + } + if(debug['C']) + print("\n"); + if(r->s2) + constprop(c1, v1, r->s2); + } +} + +/* + * ASLL x,y,w + * .. (not use w, not set x y w) + * AXXX w,a,b (a != w) + * .. (not use w) + * (set w) + * ----------- changed to + * .. + * AXXX (x<<y),a,b + * .. + */ +#define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; } +int +shiftprop(Reg *r) +{ + Reg *r1; + Prog *p, *p1, *p2; + int n, o; + Adr a; + + p = r->prog; + if(p->to.type != D_REG) + FAIL("BOTCH: result not reg"); + n = p->to.reg; + a = zprog.from; + if(p->reg != NREG && p->reg != p->to.reg) { + a.type = D_REG; + a.reg = p->reg; + } + if(debug['H']) + print("shiftprop\n%P", p); + r1 = r; + for(;;) { + /* find first use of shift result; abort if shift operands or result are changed */ + r1 = uniqs(r1); + if(r1 == R) + FAIL("branch"); + if(uniqp(r1) == R) + FAIL("merge"); + p1 = r1->prog; + if(debug['H']) + print("\n%P", p1); + switch(copyu(p1, &p->to, A)) { + case 0: /* not used or set */ + if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) || + (a.type == D_REG && copyu(p1, &a, A) > 1)) + FAIL("args modified"); + continue; + case 3: /* set, not used */ + FAIL("BOTCH: noref"); + } + break; + } + /* check whether substitution can be done */ + switch(p1->as) { + default: + FAIL("non-dpi"); + case AAND: + case AEOR: + case AADD: + case AADC: + case AORR: + case ASUB: + case ARSB: + case ASBC: + case ARSC: + if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) { + if(p1->from.type != D_REG) + FAIL("can't swap"); + p1->reg = p1->from.reg; + p1->from.reg = n; + switch(p1->as) { + case ASUB: + p1->as = ARSB; + break; + case ARSB: + p1->as = ASUB; + break; + case ASBC: + p1->as = ARSC; + break; + case ARSC: + p1->as = ASBC; + break; + } + if(debug['H']) + print("\t=>%P", p1); + } + case ABIC: + case ACMP: + case ACMN: + if(p1->reg == n) + FAIL("can't swap"); + if(p1->reg == NREG && p1->to.reg == n) + FAIL("shift result used twice"); + case AMVN: + if(p1->from.type == D_SHIFT) + FAIL("shift result used in shift"); + if(p1->from.type != D_REG || p1->from.reg != n) + FAIL("BOTCH: where is it used?"); + break; + } + /* check whether shift result is used subsequently */ + p2 = p1; + if(p1->to.reg != n) + for (;;) { + r1 = uniqs(r1); + if(r1 == R) + FAIL("inconclusive"); + p1 = r1->prog; + if(debug['H']) + print("\n%P", p1); + switch(copyu(p1, &p->to, A)) { + case 0: /* not used or set */ + continue; + case 3: /* set, not used */ + break; + default:/* used */ + FAIL("reused"); + } + break; + } + /* make the substitution */ + p2->from.type = D_SHIFT; + p2->from.reg = NREG; + o = p->reg; + if(o == NREG) + o = p->to.reg; + switch(p->from.type){ + case D_CONST: + o |= (p->from.offset&0x1f)<<7; + break; + case D_REG: + o |= (1<<4) | (p->from.reg<<8); + break; + } + switch(p->as){ + case ASLL: + o |= 0<<5; + break; + case ASRL: + o |= 1<<5; + break; + case ASRA: + o |= 2<<5; + break; + } + p2->from.offset = o; + if(debug['H']) + print("\t=>%P\tSUCCEED\n", p2); + return 1; +} + +Reg* +findpre(Reg *r, Adr *v) +{ + Reg *r1; + + for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) { + if(uniqs(r1) != r) + return R; + switch(copyu(r1->prog, v, A)) { + case 1: /* used */ + case 2: /* read-alter-rewrite */ + return R; + case 3: /* set */ + case 4: /* set and used */ + return r1; + } + } + return R; +} + +Reg* +findinc(Reg *r, Reg *r2, Adr *v) +{ + Reg *r1; + Prog *p; + + + for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) { + if(uniqp(r1) != r) + return R; + switch(copyu(r1->prog, v, A)) { + case 0: /* not touched */ + continue; + case 4: /* set and used */ + p = r1->prog; + if(p->as == AADD) + if(p->from.type == D_CONST) + if(p->from.offset > -4096 && p->from.offset < 4096) + return r1; + default: + return R; + } + } + return R; +} + +int +nochange(Reg *r, Reg *r2, Prog *p) +{ + Adr a[3]; + int i, n; + + if(r == r2) + return 1; + n = 0; + if(p->reg != NREG && p->reg != p->to.reg) { + a[n].type = D_REG; + a[n++].reg = p->reg; + } + switch(p->from.type) { + case D_SHIFT: + a[n].type = D_REG; + a[n++].reg = p->from.offset&0xf; + case D_REG: + a[n].type = D_REG; + a[n++].reg = p->from.reg; + } + if(n == 0) + return 1; + for(; r!=R && r!=r2; r=uniqs(r)) { + p = r->prog; + for(i=0; i<n; i++) + if(copyu(p, &a[i], A) > 1) + return 0; + } + return 1; +} + +int +findu1(Reg *r, Adr *v) +{ + for(; r != R; r = r->s1) { + if(r->active) + return 0; + r->active = 1; + switch(copyu(r->prog, v, A)) { + case 1: /* used */ + case 2: /* read-alter-rewrite */ + case 4: /* set and used */ + return 1; + case 3: /* set */ + return 0; + } + if(r->s2) + if (findu1(r->s2, v)) + return 1; + } + return 0; +} + +int +finduse(Reg *r, Adr *v) +{ + Reg *r1; + + for(r1=firstr; r1!=R; r1=r1->link) + r1->active = 0; + return findu1(r, v); +} + +int +xtramodes(Reg *r, Adr *a) +{ + Reg *r1, *r2, *r3; + Prog *p, *p1; + Adr v; + + p = r->prog; + if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */ + return 0; + v = *a; + v.type = D_REG; + r1 = findpre(r, &v); + if(r1 != R) { + p1 = r1->prog; + if(p1->to.type == D_REG && p1->to.reg == v.reg) + switch(p1->as) { + case AADD: + if(p1->from.type == D_REG || + (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && + (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) || + (p1->from.type == D_CONST && + p1->from.offset > -4096 && p1->from.offset < 4096)) + if(nochange(uniqs(r1), r, p1)) { + if(a != &p->from || v.reg != p->to.reg) + if (finduse(r->s1, &v)) { + if(p1->reg == NREG || p1->reg == v.reg) + /* pre-indexing */ + p->scond |= C_WBIT; + else return 0; + } + switch (p1->from.type) { + case D_REG: + /* register offset */ + a->type = D_SHIFT; + a->offset = p1->from.reg; + break; + case D_SHIFT: + /* scaled register offset */ + a->type = D_SHIFT; + case D_CONST: + /* immediate offset */ + a->offset = p1->from.offset; + break; + } + if(p1->reg != NREG) + a->reg = p1->reg; + excise(r1); + return 1; + } + break; + case AMOVW: + if(p1->from.type == D_REG) + if((r2 = findinc(r1, r, &p1->from)) != R) { + for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) + ; + if(r3 == r) { + /* post-indexing */ + p1 = r2->prog; + a->reg = p1->to.reg; + a->offset = p1->from.offset; + p->scond |= C_PBIT; + if(!finduse(r, &r1->prog->to)) + excise(r1); + excise(r2); + return 1; + } + } + break; + } + } + if(a != &p->from || a->reg != p->to.reg) + if((r1 = findinc(r, R, &v)) != R) { + /* post-indexing */ + p1 = r1->prog; + a->offset = p1->from.offset; + p->scond |= C_PBIT; + excise(r1); + return 1; + } + return 0; +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +int +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print(" (???)"); + return 2; + + case AMOVM: + if(v->type != D_REG) + return 0; + if(p->from.type == D_CONST) { /* read reglist, read/rar */ + if(s != A) { + if(p->from.offset&(1<<v->reg)) + return 1; + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) { + if(p->scond&C_WBIT) + return 2; + return 1; + } + if(p->from.offset&(1<<v->reg)) + return 1; + } else { /* read/rar, write reglist */ + if(s != A) { + if(p->to.offset&(1<<v->reg)) + return 1; + if(copysub(&p->from, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->from, v)) { + if(p->scond&C_WBIT) + return 2; + if(p->to.offset&(1<<v->reg)) + return 4; + return 1; + } + if(p->to.offset&(1<<v->reg)) + return 3; + } + return 0; + + case ANOP: /* read, write */ + case AMOVW: + case AMOVF: + case AMOVD: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + case AMOVDW: + case AMOVWD: + case AMOVFD: + case AMOVDF: + if(p->scond&(C_WBIT|C_PBIT)) + if(v->type == D_REG) { + if(p->from.type == D_OREG || p->from.type == D_SHIFT) { + if(p->from.reg == v->reg) + return 2; + } else { + if(p->to.reg == v->reg) + return 2; + } + } + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + + case AADD: /* read, read, write */ + case ASUB: + case ARSB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + + case ACMPF: + case ACMPD: + case ACMP: + case ACMN: + case ACASE: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: /* read, read */ + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub1(p, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + return 0; + + case AB: /* funny */ + if(s != 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 == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case ABL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) + if(v->reg <= FREGEXT && v->reg > exfregoffset) + 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; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } + return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + + case ACMP: + case ACMN: + + case AADD: + case ASUB: + case ARSB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + return D_REG; + + case ACMPF: + case ACMPD: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) { + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + } else if(v->type == D_CONST) { /* for constprop */ + if(a->type == v->type) + if(a->name == v->name) + if(a->sym == v->sym) + if(a->reg == v->reg) + if(a->offset == v->offset) + return 1; + } + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) { + if(a->type == D_OREG) { + if(v->reg == a->reg) + return 1; + } else if(a->type == D_SHIFT) { + if((a->offset&0xf) == v->reg) + return 1; + if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) + return 1; + } + } + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) { + if(a2type(p) == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) { + if(a->type == D_SHIFT) { + if((a->offset&0xf) == v->reg) + a->offset = (a->offset&~0xf)|s->reg; + if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) + a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); + } else + a->reg = s->reg; + } + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} + +struct { + int opcode; + int notopcode; + int scond; + int notscond; +} predinfo[] = { + { ABEQ, ABNE, 0x0, 0x1, }, + { ABNE, ABEQ, 0x1, 0x0, }, + { ABCS, ABCC, 0x2, 0x3, }, + { ABHS, ABLO, 0x2, 0x3, }, + { ABCC, ABCS, 0x3, 0x2, }, + { ABLO, ABHS, 0x3, 0x2, }, + { ABMI, ABPL, 0x4, 0x5, }, + { ABPL, ABMI, 0x5, 0x4, }, + { ABVS, ABVC, 0x6, 0x7, }, + { ABVC, ABVS, 0x7, 0x6, }, + { ABHI, ABLS, 0x8, 0x9, }, + { ABLS, ABHI, 0x9, 0x8, }, + { ABGE, ABLT, 0xA, 0xB, }, + { ABLT, ABGE, 0xB, 0xA, }, + { ABGT, ABLE, 0xC, 0xD, }, + { ABLE, ABGT, 0xD, 0xC, }, +}; + +typedef struct { + Reg *start; + Reg *last; + Reg *end; + int len; +} Joininfo; + +enum { + Join, + Split, + End, + Branch, + Setcond, + Toolong +}; + +enum { + Falsecond, + Truecond, + Delbranch, + Keepbranch +}; + +int +isbranch(Prog *p) +{ + return (ABEQ <= p->as) && (p->as <= ABLE); +} + +int +predicable(Prog *p) +{ + if (isbranch(p) + || p->as == ANOP + || p->as == AXXX + || p->as == ADATA + || p->as == AGLOBL + || p->as == AGOK + || p->as == AHISTORY + || p->as == ANAME + || p->as == ASIGNAME + || p->as == ATEXT + || p->as == AWORD + || p->as == ADYNT + || p->as == AINIT + || p->as == ABCASE + || p->as == ACASE) + return 0; + return 1; +} + +/* + * Depends on an analysis of the encodings performed by 5l. + * These seem to be all of the opcodes that lead to the "S" bit + * being set in the instruction encodings. + * + * C_SBIT may also have been set explicitly in p->scond. + */ +int +modifiescpsr(Prog *p) +{ + return (p->scond&C_SBIT) + || p->as == ATST + || p->as == ATEQ + || p->as == ACMN + || p->as == ACMP + || p->as == AMULU + || p->as == ADIVU + || p->as == AMUL + || p->as == ADIV + || p->as == AMOD + || p->as == AMODU + || p->as == ABL; +} + +/* + * Find the maximal chain of instructions starting with r which could + * be executed conditionally + */ +int +joinsplit(Reg *r, Joininfo *j) +{ + j->start = r; + j->last = r; + j->len = 0; + do { + if (r->p2 && (r->p1 || r->p2->p2link)) { + j->end = r; + return Join; + } + if (r->s1 && r->s2) { + j->end = r; + return Split; + } + j->last = r; + if (r->prog->as != ANOP) + j->len++; + if (!r->s1 && !r->s2) { + j->end = r->link; + return End; + } + if (r->s2) { + j->end = r->s2; + return Branch; + } + if (modifiescpsr(r->prog)) { + j->end = r->s1; + return Setcond; + } + r = r->s1; + } while (j->len < 4); + j->end = r; + return Toolong; +} + +Reg * +successor(Reg *r) +{ + if (r->s1) + return r->s1; + else + return r->s2; +} + +void +applypred(Reg *rstart, Joininfo *j, int cond, int branch) +{ + int pred; + Reg *r; + + if(j->len == 0) + return; + if (cond == Truecond) + pred = predinfo[rstart->prog->as - ABEQ].scond; + else + pred = predinfo[rstart->prog->as - ABEQ].notscond; + + for (r = j->start; ; r = successor(r)) { + if (r->prog->as == AB) { + if (r != j->last || branch == Delbranch) + excise(r); + else { + if (cond == Truecond) + r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; + else + r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; + } + } + else if (predicable(r->prog)) + r->prog->scond = (r->prog->scond&~C_SCOND)|pred; + if (r->s1 != r->link) { + r->s1 = r->link; + r->link->p1 = r; + } + if (r == j->last) + break; + } +} + +void +predicate(void) +{ + Reg *r; + int t1, t2; + Joininfo j1, j2; + + for(r=firstr; r!=R; r=r->link) { + if (isbranch(r->prog)) { + t1 = joinsplit(r->s1, &j1); + t2 = joinsplit(r->s2, &j2); + if(j1.last->link != j2.start) + continue; + if(j1.end == j2.end) + if((t1 == Branch && (t2 == Join || t2 == Setcond)) || + (t2 == Join && (t1 == Join || t1 == Setcond))) { + applypred(r, &j1, Falsecond, Delbranch); + applypred(r, &j2, Truecond, Delbranch); + excise(r); + continue; + } + if(t1 == End || t1 == Branch) { + applypred(r, &j1, Falsecond, Keepbranch); + excise(r); + continue; + } + } + } +} diff --git a/utils/5c/reg.c b/utils/5c/reg.c new file mode 100644 index 00000000..19c8a7b6 --- /dev/null +++ b/utils/5c/reg.c @@ -0,0 +1,1157 @@ +#include "gc.h" + +void addsplits(void); + +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 = 0; + 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 AB: + case ARFE: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW); + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + case AMOVW: + case AMOVF: + case AMOVD: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case ABL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + break; + } + + if(p->as == AMOVM) { + if(p->from.type == D_CONST) + z = p->from.offset; + else + z = p->to.offset; + for(i=0; z; i++) { + if(z&1) + regbits |= RtoB(i); + z >>= 1; + } + } + } + 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); + + /* + * 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; + + addsplits(); + + if(debug['R'] && debug['v']) { + print("\nprop 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->set.b[z] | + r->refahead.b[z] | r->calahead.b[z] | + r->refbehind.b[z] | r->calbehind.b[z] | + r->use1.b[z] | r->use2.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); + if(bany(&r->refahead)) + print(" ra=%B", r->refahead); + if(bany(&r->calahead)) + print(" ca=%B", r->calahead); + if(bany(&r->refbehind)) + print(" rb=%B", r->refbehind); + if(bany(&r->calbehind)) + print(" cb=%B", r->calbehind); + } + print("\n"); + } + } + + /* + * 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); + } + } + + for(r = firstr; r != R; r = r->link) + r->act = zbits; + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + 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']) { + if(rgp->regno >= NREG) + print("%L $%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L $%d R%d: %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; + } +} + +void +addsplits(void) +{ + Reg *r, *r1; + int z, i; + Bits bit; + + for(r = firstr; r != R; r = r->link) { + if(r->loop > 1) + continue; + if(r->prog->as == ABL) + continue; + for(r1 = r->p2; r1 != R; r1 = r1->p2link) { + if(r1->loop <= 1) + continue; + for(z=0; z<BITS; z++) + bit.b[z] = r1->calbehind.b[z] & + (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & + ~(r->calahead.b[z] & addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + } + } + } +} + +/* + * 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->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TFLOAT) + p1->as = AMOVF; + if(v->etype == TDOUBLE) + p1->as = AMOVD; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBU; + if(v->etype == TUSHORT) + p1->as = AMOVHU; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + + n = a->name; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = et; + v->name = n; + 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]; + if(t == D_CONST) { + if(s == S) { + for(z=0; z<BITS; z++) + consts.b[z] |= bit.b[z]; + return bit; + } + if(et != TARRAY) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + return bit; + } + if(t == D_OREG) + 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 ABL: + 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 TVLONG: + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i && r->cost >= 0) { + r->regno = i+NREG; + return FtoB(i); + } + 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(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(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(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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + 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->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * bit reg + * 0 R0 + * 1 R1 + * ... ... + * 10 R10 + */ +long +RtoB(int r) +{ + + if(r < 2 || r >= REGTMP) + return 0; + return 1L << r; +} + +int +BtoR(long b) +{ + b &= 0x07fcL; + if(b == 0) + return 0; + return bitno(b); +} + +/* + * bit reg + * 18 F2 + * 19 F3 + * ... ... + * 23 F7 + */ +long +FtoB(int f) +{ + + if(f < 2 || f > NFREG-1) + return 0; + return 1L << (f + 16); +} + +int +BtoF(long b) +{ + + b &= 0xfc0000L; + if(b == 0) + return 0; + return bitno(b) - 16; +} diff --git a/utils/5c/sgen.c b/utils/5c/sgen.c new file mode 100644 index 00000000..b20865d9 --- /dev/null +++ b/utils/5c/sgen.c @@ -0,0 +1,613 @@ +#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)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG >= 0) { + if(typesuv[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gopcode(OAS, &nod, Z, &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); + gopcode(OAS, &nod, Z, &nod1); + } + } + + 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); + 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 o, f; + +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, 0); + 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); + 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, 0); + regfree(&nod); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + break; + + case OLABEL: + l = n->left; + if(l) { + l->pc = 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->pc) { + patch(p, n->pc); + 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, 0); + 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 = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int t; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + + case OASLMUL: + case OASMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASASHL; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASHL; + r->vconst = t; + r->type = types[TINT]; + } + t = vlog(l); + if(t >= 0) { + n->op = OASHL; + n->left = r; + n->right = l; + r = l; + l = n->left; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + case OFUNC: + n->complex = FNX; + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + case OEQ: + case ONE: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + } +} + +int +bcomplex(Node *n, Node *c) +{ + + 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; + bool64(n); + boolgen(n, 1, Z); + } else + gbranch(OGOTO); + return 0; +} diff --git a/utils/5c/swt.c b/utils/5c/swt.c new file mode 100644 index 00000000..4c2b33ec --- /dev/null +++ b/utils/5c/swt.c @@ -0,0 +1,757 @@ +#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; + Node tn; + + 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); + regalloc(&tn, ®node, Z); + swit1(iq, nc, def, n, &tn); + regfree(&tn); +} + +void +swit1(C1 *q, int nc, long def, Node *n, Node *tn) +{ + C1 *r; + int i; + long v; + Prog *sp; + + if(nc >= 3) { + i = (q+nc-1)->val - (q+0)->val; + if(i > 0 && i < nc*2) + goto direct; + } + if(nc < 5) { + for(i=0; i<nc; i++) { + if(debug['W']) + print("case = %.8lux\n", q->val); + gopcode(OEQ, nodconst(q->val), n, Z); + 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, nodconst(r->val), n, Z); + sp = p; + gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ + patch(p, r->label); + swit1(q, i, def, n, tn); + + if(debug['W']) + print("case < %.8lux\n", r->val); + patch(sp, pc); + swit1(r+1, nc-i-1, def, n, tn); + return; + +direct: + v = q->val; + if(v != 0) + gopcode(OSUB, nodconst(v), Z, n); + gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z); + patch(p, def); + for(i=0; i<nc; i++) { + if(debug['W']) + print("case = %.8lux\n", q->val); + while(q->val != v) { + nextpc(); + p->as = ABCASE; + patch(p, def); + v++; + } + nextpc(); + p->as = ABCASE; + patch(p, q->label); + q++; + v++; + } + gbranch(OGOTO); /* so that regopt() won't be confused */ + patch(p, def); +} + +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); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1, 0); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +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->reg = 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; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v, vs; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + if(debug['M'] && debug['v']) + print("%L multiply: %ld\n", n->lineno, v); + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1, 0); + vs = v; + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + if(vs < 0) { + gopcode(OAS, &nod1, Z, &nod1); + gopcode(OSUB, &nod1, nodconst(0), nn); + } else + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +nullwarn(Node *l, Node *r) +{ + warn(Z, "result of operation not used"); + if(l != Z) + cgen(l, Z, 0); + if(r != Z) + cgen(r, Z, 0); +} + +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(0)); + p->from.offset += o+e; + p->reg = 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]) { + if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + else + gpseudo(ADATA, s, nod32const(a->vconst)); + p->from.offset += o; + p->reg = 4; + if(1 || align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst)); + else + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + + bf[0] = p->as; + bf[1] = p->scond; + bf[2] = p->reg; + bf[3] = p->lineno; + bf[4] = p->lineno>>8; + bf[5] = p->lineno>>16; + bf[6] = p->lineno>>24; + bp = zaddr(bf+7, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + 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++; + } + } + outhist(&outbuf); + 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.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, 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.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + 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, 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; + + zwrite(b, &pg, 0, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n, bf[7]; + ulong sig; + + n = s->name; + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); + s->sig = SIGDONE; + } + else{ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); + } + Bwrite(b, n, strlen(n)+1); +} + +char* +zaddr(char *bp, Adr *a, int s) +{ + long l; + Ieee e; + + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + } + return bp; +} + +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, Ael2); + o = align(o, t, Ael1); + w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ + 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 = round(v, SZ_LONG); + if(v > max) + return v; + return max; +} diff --git a/utils/5c/txt.c b/utils/5c/txt.c new file mode 100644 index 00000000..d1025e7f --- /dev/null +++ b/utils/5c/txt.c @@ -0,0 +1,1249 @@ +#include "gc.h" + +void +ginit(void) +{ + Type *t; + + thechar = '5'; + thestring = "arm"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + 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.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + zprog.scond = 0xE; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMP; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + 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(); + + memset(reg, 0, sizeof(reg)); +} + +void +gclean(void) +{ + int i; + Sym *s; + + for(i=0; i<NREG; i++) + if(reg[i]) + diag(Z, "reg %d left allocated", i); + for(i=NREG; i<NREG+NFREG; i++) + if(reg[i]) + diag(Z, "freg %d left allocated", i-NREG); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + 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; +} + +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, 0); + (*fnxp)++; + } + return; + } + if(typesuv[n->type->etype]) { + regaalloc(tn2, n); + if(n->complex >= FNX) { + sugen(*fnxp, tn2, n->type->width); + (*fnxp)++; + } else + sugen(n, tn2, n->type->width); + return; + } + if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1, 0); + (*fnxp)++; + } else + cgen(n, tn1, 0); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1, 0); + (*fnxp)++; + } else + cgen(n, tn1, 0); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nod32const(vlong v) +{ + constnode.vconst = v & MASK(32); + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +int +tmpreg(void) +{ + int i; + + for(i=REGRET+1; i<NREG; i++) + if(reg[i] == 0) + return i; + diag(Z, "out of fixed registers"); + return 0; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i, j; + static int lasti; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<NREG; i++) { + if(j >= NREG) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + case TVLONG: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NFREG) + goto out; + } + j = 0*2 + NREG; + for(i=NREG; i<NREG+NFREG; i++) { + if(j >= NREG+NFREG) + j = NREG; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of float registers"); + goto err; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + nodreg(n, tn, 0); + return; +out: + reg[i]++; +/* lasti++; *** StrongARM does register forwarding */ + if(lasti >= 5) + lasti = 0; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + 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 + SZ_LONG; + 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 +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(R0ISZERO && a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: <null>"); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +fop(int as, int f1, int f2, Node *t) +{ + Node nod1, nod2, nod3; + + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); +} + +void +gmovm(Node *f, Node *t, int w) +{ + gins(AMOVM, f, t); + p->scond |= C_UBIT; + if(w) + p->scond |= C_WBIT; +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod; + + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + } + if(ft == TFLOAT && f->op == OCONST) { + } + + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + a = AMOVW; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + } + if(typechlp[ft] && typeilp[tt]) + regalloc(&nod, t, t); + else + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + a = AMOVBU; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHU; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AMOVF; + break; + case TVLONG: + case TDOUBLE: + a = AMOVD; + break; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + switch(tt) { + case TDOUBLE: + case TVLONG: + a = AMOVD; + if(ft == TFLOAT) + a = AMOVFD; + break; + case TFLOAT: + a = AMOVDF; + if(ft == TFLOAT) + a = AMOVF; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVDW; + if(ft == TFLOAT) + a = AMOVFW; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVDW; + if(ft == TFLOAT) + a = AMOVFW; + break; + } + break; + case TUINT: + case TINT: + case TULONG: + case TLONG: + case TIND: + switch(tt) { + case TDOUBLE: + case TVLONG: + gins(AMOVWD, f, t); + if(ft == TULONG) { + } + return; + case TFLOAT: + gins(AMOVWF, f, t); + if(ft == TULONG) { + } + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TUINT: + case TINT: + case TULONG: + case TLONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AMOVF || a == AMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gmover(Node *f, Node *t) +{ + int ft, tt, a; + + ft = f->type->etype; + tt = t->type->etype; + a = AGOK; + if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){ + switch(tt){ + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + } + } + if(a == AGOK) + gmove(f, t); + else + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, et; + Adr ta; + + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = AADD; + if(et == TFLOAT) + a = AADDF; + else + if(et == TDOUBLE || et == TVLONG) + a = AADDD; + break; + + case OASSUB: + case OSUB: + if(f2 && f2->op == OCONST) { + Node *t = f1; + f1 = f2; + f2 = t; + a = ARSB; + } else + a = ASUB; + if(et == TFLOAT) + a = ASUBF; + else + if(et == TDOUBLE || et == TVLONG) + a = ASUBD; + break; + + case OASOR: + case OOR: + a = AORR; + break; + + case OASAND: + case OAND: + a = AAND; + break; + + case OASXOR: + case OXOR: + a = AEOR; + break; + + case OASLSHR: + case OLSHR: + a = ASRL; + break; + + case OASASHR: + case OASHR: + a = ASRA; + break; + + case OASASHL: + case OASHL: + a = ASLL; + break; + + case OFUNC: + a = ABL; + break; + + case OASMUL: + case OMUL: + a = AMUL; + if(et == TFLOAT) + a = AMULF; + else + if(et == TDOUBLE || et == TVLONG) + a = AMULD; + break; + + case OASDIV: + case ODIV: + a = ADIV; + if(et == TFLOAT) + a = ADIVF; + else + if(et == TDOUBLE || et == TVLONG) + a = ADIVD; + break; + + case OASMOD: + case OMOD: + a = AMOD; + break; + + case OASLMUL: + case OLMUL: + a = AMULU; + break; + + case OASLMOD: + case OLMOD: + a = AMODU; + break; + + case OASLDIV: + case OLDIV: + a = ADIVU; + break; + + case OCASE: + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case OLO: + case OLS: + case OHS: + case OHI: + a = ACMP; + if(et == TFLOAT) + a = ACMPF; + else + if(et == TDOUBLE || et == TVLONG) + a = ACMPD; + nextpc(); + p->as = a; + naddr(f1, &p->from); + if(a == ACMP && f1->op == OCONST && p->from.offset < 0) { + p->as = ACMN; + p->from.offset = -p->from.offset; + } + raddr(f2, p); + switch(o) { + case OEQ: + a = ABEQ; + break; + case ONE: + a = ABNE; + break; + case OLT: + a = ABLT; + break; + case OLE: + a = ABLE; + break; + case OGE: + a = ABGE; + break; + case OGT: + a = ABGT; + break; + case OLO: + a = ABLO; + break; + case OLS: + a = ABLS; + break; + case OHS: + a = ABHS; + break; + case OHI: + a = ABHI; + break; + case OCASE: + nextpc(); + p->as = ACASE; + p->scond = 0x9; + naddr(f2, &p->from); + a = ABHI; + break; + } + f1 = Z; + f2 = Z; + break; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +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 = AB; + 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_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + if(a == ATEXT) + p->reg = (profileflg ? 0 : NOPROF); + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= (vlong)(-32766) && vv < (vlong)32766) + return 1; + /* + * should be specialised for constant values which will + * fit in different instructionsl; for now, let 5l + * sort it out + */ + return 1; + } + } + return 0; +} + +int +sval(long v) +{ + int i; + + for(i=0; i<16; i++) { + if((v & ~0xff) == 0) + return 1; + if((~v & ~0xff) == 0) + return 1; + v = (v<<2) | ((ulong)v>>30); + } + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= REGEXT-4) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= NFREG-1) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; + +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] */ +}; diff --git a/utils/5coff/5coff.c b/utils/5coff/5coff.c new file mode 100644 index 00000000..cae73108 --- /dev/null +++ b/utils/5coff/5coff.c @@ -0,0 +1,316 @@ +#include "auxi.h" + +#define RND(x, y) ((((x)+(y)-1)/(y))*(y)) + +char *cmd; +int sflag, dflag; + +int ifd, ofd; +Fhdr ihdr; + +long HEADR, INITTEXT, INITDAT, INITRND, INITENTRY; +long textsize, datsize, bsssize; + +int cout; +int thumb; + +static void get_file(char *); +static void put_file(char *); +static void usage(char *); +static long strxtol(char *); +static void readsyms(void); + +char *fail = "error"; + +void +main(int argc, char *argv[]) +{ + char *a, *ifile, *ofile; + + cmd = argv[0]; + + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = -1; + + ARGBEGIN { + /* + * Options without args + */ + case 's': + sflag = 1; + break; + /* + * Options with args + */ + case 'T': + a = ARGF(); + if(a) + INITTEXT = strxtol(a); + break; + case 'D': + a = ARGF(); + if(a) + INITDAT = strxtol(a); + break; + case 'R': + a = ARGF(); + if(a) + INITRND = strxtol(a); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = strxtol(a); + break; + case 'd': + dflag |= strxtol(ARGF()); + break; + default: + usage("Invalid option"); + } ARGEND + + if (argc != 2) + usage("Wrong number of arguments"); + + ifile = argv[0]; + ofile = argv[1]; + + get_file(ifile); + put_file(ofile); + exits(0); +} + +char usagemsg[] = +"usage: %s options infile outfile\n\t options (for outfile): -H[1234] -s -T<text> -D<data> -R<rnd> -E<entry>\n"; + +static void +usage(char *msg) +{ + fprint(2, "***Error: %s\n", msg); + fprint(2, usagemsg, cmd); + exits("usage"); +} + +static long +strxtol(char *s) +{ + char *es; + int base = 0; + long r; + + if (*s == '0') + if (*++s == 'x'){ + base = 16; + s++; + } + else + base = 8; + r = strtol(s, &es, base); + if (*es) + usage("bad number"); + return(r); +} + +static void +get_file(char *ifile) +{ + int h; + + ifd = open(ifile, OREAD); + if (ifd < 0) { + fprint(2, "5coff: open %s: %r\n", ifile); + exits("open"); + } + h = crackhdr(ifd, &ihdr); + if (!h || dflag){ + fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, ihdr.type, ihdr.name); + fprint(2, "txt %lux, ent %lux, txtsz %lux, dataddr %lux\n", + ihdr.txtaddr, ihdr.entry, ihdr.txtsz, ihdr.dataddr); + } + if (!h) + usage("File type not recognized"); + machbytype(ihdr.type); + if (dflag) + fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize); + + HEADR = 22+28+3*48; + if(INITTEXT == -1) + INITTEXT = ihdr.txtaddr; + else + ihdr.txtaddr = INITTEXT; + if(INITDAT == -1) + INITDAT = ihdr.dataddr; + else + ihdr.dataddr = INITDAT; + if(INITENTRY == -1) + INITENTRY = ihdr.entry; + else + ihdr.entry = INITENTRY; + textsize = ihdr.txtsz; + datsize = ihdr.datsz; + bsssize = ihdr.bsssz; + if(INITRND > 0) + ihdr.dataddr = INITDAT = RND(INITTEXT+textsize, INITRND); + if(0){ + INITTEXT = INITENTRY; + INITDAT = RND(INITTEXT+textsize, 4); + } + if(0){ + print("H=%lux T=%lux D=%lux t=%lux d=%lux b=%lux e=%lux\n", HEADR, INITTEXT, INITDAT, textsize, datsize, bsssize, INITENTRY); + print("%lux %lux %lux %lux %lux %lux\n", ihdr.txtaddr, ihdr.dataddr, ihdr.entry, ihdr.txtsz, ihdr.datsz, ihdr.bsssz); + } + + readsyms(); +} + +#define WB 128 +#define WSAFE (WB-4) +char Wbuf[WB]; +char *wp = Wbuf; + +void +cflush(void) +{ + if(wp > Wbuf) + write(ofd, Wbuf, wp-Wbuf); + wp = Wbuf; +} + +void +lput(long l) +{ + wp[0] = l>>24; + wp[1] = l>>16; + wp[2] = l>>8; + wp[3] = l; + wp += 4; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +void +cput(int l) +{ + wp[0] = l; + wp += 1; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +void +hputl(int l) +{ + wp[1] = l>>8; + wp[0] = l; + wp += 2; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +void +lputl(long l) +{ + wp[3] = l>>24; + wp[2] = l>>16; + wp[1] = l>>8; + wp[0] = l; + wp += 4; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +static void +copyseg(long sz) +{ + char buf[1024]; + + cflush(); + while (sz > 0){ + long n; + long r; + + n = sz; + if (n > sizeof buf) + n = sizeof buf; + sz -= n; + + if ((r = read(ifd, buf, n)) != n){ + fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(ifd, 0, 1)); + perror("Premature eof"); + exits(fail); + } + if ((r = write(ofd, buf, n)) != n){ + fprint(2, "%ld = write(...%ld)\n", r, n); + perror("Write error!"); + exits(fail); + } + } + cflush(); +} + +static void +put_file(char *ofile) +{ + ofd = create(ofile, OWRITE, 0666); + if (ofd < 0) { + fprint(2, "5coff: create %s: %r\n", ofile); + exits("create"); + } + cout = ofd; + + /* TBS lput for Plan9 header before ? */ + + seek(ifd, ihdr.txtoff, 0); + seek(ofd, HEADR, 0); + copyseg(ihdr.txtsz); + + seek(ifd, ihdr.datoff, 0); + seek(ofd, HEADR+textsize, 0); + copyseg(ihdr.datsz); + + seek(ofd, HEADR+textsize+datsize, 0); + coffsym(); + cflush(); + cofflc(); + cflush(); + + seek(ofd, 0, 0); + coffhdr(); + cflush(); + + close(ifd); + close(ofd); +} + +long +entryvalue(void) +{ + return INITENTRY; +} + +void +diag(char *s, ...) +{ + fprint(2, "%s\n", s); + exits("error"); +} + +static void +readsyms(void) +{ + int i; + long n; + Sym *s; + + if(sflag) + return; + n = syminit(ifd, &ihdr); + beginsym(); + for(i = 0; i < n; i++){ + s = getsym(i); + newsym(i, s->name, s->value, s->type); + } + endsym(); +} diff --git a/utils/5coff/NOTICE b/utils/5coff/NOTICE new file mode 100644 index 00000000..3b08f95f --- /dev/null +++ b/utils/5coff/NOTICE @@ -0,0 +1,27 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 2001-2003 Vita Nuova Holdings Limited. + +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. diff --git a/utils/5coff/auxi.c b/utils/5coff/auxi.c new file mode 100644 index 00000000..93e56c29 --- /dev/null +++ b/utils/5coff/auxi.c @@ -0,0 +1,251 @@ +#include "auxi.h" + +Prog *firstp, *textp, *curtext, *lastp, *etextp; +Symx *hash[NHASH]; +Auto *lasta; +long autosize; +int version = 0; + +static int +private(char *s) +{ + return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0; +} + +static int +zlen(char *s) +{ + int i; + + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) + ; + i++; + return i+1; +} + +static Symx* +allocsym(char *symb, int l, int v) +{ + Symx *s; + + s = malloc(sizeof(Symx)); + s->name = malloc(l); + memmove(s->name, symb, l); + s->name[l-1] = '\0'; + s->type = 0; + s->version = v; + s->value = 0; + s->link = nil; + return s; +} + +Symx* +lookupsym(char *symb, int v) +{ + Symx *s, **as; + char *p; + long h; + int c, l; + + 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 != nil; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + s = allocsym(symb, l, v); + for(as = &hash[h]; *as != nil; as = &((*as)->link)) + ; + *as = s; + // s->link = hash[h]; + // hash[h] = s; + return s; +} + +static void +addauto(Auto **aut, Symx *s, int t, long v) +{ + Auto *a, **aa; + + a = (Auto*)malloc(sizeof(Auto)); + a->asym = s; + a->link = nil; + a->aoffset = v; + a->type = t; + for(aa = aut; *aa != nil; aa = &((*aa)->link)) + ; + *aa = a; +} + +static Prog* +newprog(int as, long pc, long ln) +{ + Prog *p; + + p = (Prog *)malloc(sizeof(Prog)); + p->as = as; + p->pc = pc; + p->line = ln; + p->link = p->cond = P; + if(firstp == P) + firstp = p; + else + lastp->link = p; + lastp = p; + if(as == ATEXT){ + if(textp == P) + textp = p; + else + etextp->cond = p; + etextp = p; + } + return p; +} + +static int +line(long pc) +{ + char buf[1024], *s; + + // return pc2line(pc); + if(fileline(buf, sizeof(buf), pc)){ + for(s = buf; *s != ':' && *s != '\0'; s++) + ; + if(*s != ':') + return -1; + return atoi(s+1); + } + return -1; +} + +static void +lines(long v) +{ + long ll, nl, pc; + if(etextp != P){ + ll = 0; + for(pc = etextp->pc; pc < v; pc += 4){ + nl = line(pc); + if(nl != -1 && nl != ll){ + newprog(ATEXT-1, pc, nl); + ll = nl; + } + } + pc -= 4; + if(lastp->pc != pc){ + nl = line(pc); + if(nl != -1) + newprog(ATEXT-1, pc, nl); + } + } +} + +void +beginsym(void) +{ +} + +/* create the same structures as in 5l so we can use same coff.c source file */ +void +newsym(int i, char *nm, long v, int t) +{ + long l, ver; + char *os; + Symx *s; + Prog *p; + + if(i == 0 && (t == 't' || t == 'T') && strcmp(nm, "etext") == 0) + return; + if(nm[0] == '.' && private(nm+1)) + return; +// print("%s %ld %c\n", nm, v, t); + ver = 0; + if(t == 't' || t == 'l' || t == 'd' || t == 'b'){ + ver = ++version; + if(ver == 0) + diag("0 version for static"); + } + if(t == 'a' || t == 'p') + s = allocsym(nm, strlen(nm)+1, 0); + else if(t == 'z' || t == 'Z') + s = allocsym(nm, zlen(nm), 0); + else if(t != 'm'){ + s = lookupsym(nm, ver); + if(s->type != 0) + diag("seen sym before in newsym"); + s->value = v; + } + else + s = nil; + switch(t){ + case 'T': + case 'L': + case 't': + case 'l': + lines(v); + if(t == 'l' || t == 'L') + s->type = SLEAF; + else + s->type = STEXT; + p = newprog(ATEXT, v, line(v)); + p->from.sym = s; + p->to.autom = lasta; + lasta = nil; + break; + case 'D': + case 'd': + s->type = SDATA; + s->value -= INITDAT; + break; + case 'B': + case 'b': + s->type = SBSS; + s->value -= INITDAT; + break; + case 'f': + // version++; + s->type = SFILE; + os = s->name; + l = strlen(os)+1; + s->name = malloc(l+1); + s->name[0] = '>'; + memmove(s->name+1, os, l); + free(os); + break; +/* + case 'f'+'a'-'A': + s->type = SFILE; + break; +*/ + case 'z': + addauto(&lasta, s, D_FILE, v); + break; + case 'Z': + addauto(&lasta, s, D_FILE1, v); + break; + case 'a': + addauto(&(etextp->to.autom), s, D_AUTO, -v); + break; + case 'p': + addauto(&(etextp->to.autom), s, D_PARAM, v); + break; + case 'm': + etextp->to.offset = v-4; + autosize = v; + break; + default: + diag("bad case in newsym"); + break; + } +} + +void +endsym(void) +{ + lines(INITTEXT+textsize); +} diff --git a/utils/5coff/auxi.h b/utils/5coff/auxi.h new file mode 100644 index 00000000..e9907523 --- /dev/null +++ b/utils/5coff/auxi.h @@ -0,0 +1,46 @@ +#define COFFCVT +#define Sym Symx +#include "../5l/l.h" +#undef Sym +#include <mach.h> + +/* + * auxi.c + */ +extern Symx *hash[NHASH]; +Symx *lookupsym(char*, int); +void beginsym(void); +void endsym(void); +void newsym(int, char*, long, int); + +extern long autosize; +extern Prog *firstp, *textp, *curtext, *lastp, *etextp; + +/* + * coff.c + */ +void coffhdr(void); +void coffsym(void); +void cofflc(void); +void endsym(void); + +/* + * 5coff.c + */ +void cflush(void); +void lput(long); +void cput(int); +void hputl(int); +void lputl(long); +long entryvalue(void); +void diag(char*, ...); +extern long HEADR; /* length of header */ +extern long INITDAT; /* data location */ +extern long INITRND; /* data round above text location */ +extern long INITTEXT; /* text location */ +extern long INITENTRY; /* entry point */ +extern long textsize; +extern long datsize; +extern long bsssize; +extern int cout; +extern int thumb; diff --git a/utils/5coff/coff.c b/utils/5coff/coff.c new file mode 100644 index 00000000..7a057ea5 --- /dev/null +++ b/utils/5coff/coff.c @@ -0,0 +1,642 @@ +#include "auxi.h" + +/* + * in some embedded coff files, edata and end have type 0 not 4, + * and file value is pointer to next file sym (as here), but the last one + * points to an external symbol, not 0 as here. + */ + +#define C_NULL 0 +#define C_AUTO 1 +#define C_EXT 2 +#define C_STAT 3 +#define C_ARG 9 +#define C_FCN 101 +#define C_FILE 103 + +#define T_VOID 0 +#define T_CHAR 2 +#define T_SHORT 3 +#define T_INT 4 +#define T_LONG 5 + +#define DT_NON 0 +#define DT_PTR 1 +#define DT_FCN 2 +#define DT_ARY 3 + +#define T(a, b) (((a)<<4)|b) + +#define DOTTEXT ".text" +#define DOTDATA ".data" +#define DOTBSS ".bss" +#define DOTBF ".bf" +#define DOTEF ".ef" + +#define SINDEX(s) (*((long*)(&s->become))) +#define LINDEX(s) (*((long*)(&s->used))) + +typedef struct Hist Hist; + +struct Hist{ + Auto *a; + Hist *n; +}; + +static int nsym, nlc, lines; + +static void cofflcsz(void); + +static Hist *freeh, *curh; + +static void +dohist(Auto *a) +{ + Hist *h, **ha; + + if(a->aoffset == 1){ /* new file */ + for(ha = &curh; *ha != nil; ha = &((*ha)->n)) + ; + *ha = freeh; + freeh = curh; + curh = nil; + } + if(freeh != nil){ + h = freeh; + freeh = freeh->n; + } + else + h = malloc(sizeof(Hist)); + h->a = a; + h->n = nil; + for(ha = &curh; *ha != nil; ha = &((*ha)->n)) + ; + *ha = h; +} + +static long +lineno(long n) +{ + long o, d; + Hist *h; + + if(1) + return n; /* now using fileline() not pc2line() */ + + if(curh == nil) + return 0; + o = curh->a->aoffset-1; + d = 1; + for(h = curh->n; d && h != nil; h = h->n){ + if(h->a->asym->name[1] || h->a->asym->name[2]){ + if(h->a->type == D_FILE1) { + ; + } + else if(d == 1 && n < h->a->aoffset) + break; + else if(d++ == 1) + o -= h->a->aoffset; + } + else if(--d == 1) + o += h->a->aoffset; + } + return n-o; +} + +static char * +filelookup(int k) +{ + int i; + Symx *s; + + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->type == SFILE && k == s->value) + return s->name+1; + } + } + return ""; +} + +static char* +filename(char *s) +{ + int j, k, l; + static char buf[256]; + + buf[0] = '\0'; + if(s[0] != 0) + diag("bad filename"); + for(j = 1; ; j += 2){ + k = (s[j]<<8)|s[j+1]; + if(k == 0) + break; + l = strlen(buf); + if(l != 0 && buf[l-1] != '/') + strcat(buf, "/"); + strcat(buf, filelookup(k)); + } + return buf; +} + +static void +sput(char *s, int n) +{ + int i; + + for(i = 0; i < n && s != nil && *s != '\0'; i++, s++) + cput(*s); + for( ; i < n; i++) + cput(0); +} + +static void +coffsect(char *s, long a, long sz, long o, long lp, long nl, long f) +{ + if(0) + print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz); + sput(s, 8); /* name <= 8 chars in len */ + lputl(a); /* pa */ + lputl(a); /* va */ + lputl(sz); /* size */ + lputl(o); /* file offset */ + lputl(0); /* reloc */ + lputl(lp); /* line nos */ + lputl(0); /* no reloc entries */ + lputl(nl); /* no line no entries */ + lputl(f); /* flags */ + hputl(0); /* reserved */ + hputl(0); /* mem page no */ +} + +void +coffhdr(void) +{ + if(0){ + print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize); + print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT); + } + + /* + * file header + */ + hputl(0xc2); /* version ID */ + hputl(3); /* no section hdrs */ + lputl(0); /* date stamp */ + lputl(HEADR+textsize+datsize+6*nlc); /* sym table */ + lputl(nsym); /* no sym table entries */ + hputl(28); /* size optional hdr */ + hputl(0x0103); /* flags */ + hputl(0x97); /* target ID */ + /* + * optional file header + */ + hputl(0x108); /* magic */ + hputl(0); /* version stamp */ + lputl(textsize); /* text size */ + lputl(datsize); /* data size */ + lputl(bsssize); /* bss size */ + lputl(entryvalue()); /* entry pt */ + lputl(INITTEXT); /* text start */ + lputl(INITDAT); /* data start */ + /* + * sections + */ + coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20); + coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40); + coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80); +} + +static int +private(char *s) +{ + return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0; +} + +static long stoff = 4; + +static long +stput(char *s) +{ + long r; + + r = stoff; + stoff += strlen(s)+1; + return r; +} + +static long +strput(char *s) +{ + int l; + + if((l = strlen(s)) > 8){ + if(*s == '.' && private(s+1)) + return 0; + while(*s) + cput(*s++); + cput(*s); + return l+1; + } + return 0; +} + +static void +stflush(void) +{ + int i; + long o; + Prog *p; + Auto *a, *f; + Symx *s; + char *fn, file[256]; + + lputl(stoff); + o = 4; + for(p = firstp; p != P; p = p->link){ + if(p->as == ATEXT){ + f = nil; + fn = nil; + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_FILE){ + f = a; + break; + } + } + if(f != nil) + fn = filename(f->asym->name); + if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){ + strcpy(file, fn); + o += strput(file); + } + o += strput(p->from.sym->name); + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_AUTO || a->type == D_PARAM) + o += strput(a->asym->name); + } + } + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version > 0 && (s->type == SDATA || s->type == SBSS)) + o += strput(s->name); + } + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version == 0 && (s->type == SDATA || s->type == SBSS)) + o += strput(s->name); + } + } + if(o != stoff) + diag("bad stflush offset"); +} + +static int +putsect(Symx *s) +{ + int sz, ln; + + sz = ln = 0; + // isn't this repetition ? + if(strcmp(s->name, DOTTEXT) == 0){ + sz = textsize; + ln = nlc; + } + else if(strcmp(s->name, DOTDATA) == 0) + sz = datsize; + else if(strcmp(s->name, DOTBSS) == 0) + sz = bsssize; + else + diag("bad putsect sym"); + lputl(sz); + hputl(0); + hputl(ln); + sput(nil, 10); + return 1; +} + +static int +putfun(Symx *s) +{ + /* lputl(SINDEX(s)+2); */ + lputl(0); + lputl(0); /* patched later */ + lputl(HEADR+textsize+datsize+LINDEX(s)); + lputl(0); /* patched later */ + sput(nil, 2); + return 1; +} + +static int +putbf(int lno) +{ + lputl(0); + hputl(lno); + hputl(lines); + lputl(autosize); + lputl(0); /* patched later */ + sput(nil, 2); + return 1; +} + +static int +putef(int lno) +{ + sput(nil, 4); + hputl(lno); + sput(nil, 12); + return 1; +} + +static int +putsym(Symx *s, int sc, int t, int lno) +{ + long v; + + if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1))) + return 0; + if(0) + print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t); + if(strlen(s->name) <= 8) + sput(s->name, 8); + else{ + lputl(0); + lputl(stput(s->name)); + } + /* value */ + v = s->value; + if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS) + lputl(INITDAT+v); + else if(sc == C_AUTO) + lputl(autosize+v); + else if(sc == C_ARG) + lputl(autosize+v+4); + else + lputl(v); + switch(s->type){ /* section number */ + case STEXT: + case SLEAF: + hputl(1); + break; + case SDATA: + case SDATA1: + hputl(2); + break; + case SBSS: + hputl(3); + break; + case SFILE: + hputl(-2); + break; + default: + diag("type %d in putsym", s->type); + break; + } + hputl(t); /* type */ + cput(sc); /* storage class */ + /* aux entries */ + if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){ /* section */ + cput(1); + return 1+putsect(s); + } + else if((t>>4) == DT_FCN){ /* function */ + cput(1); + return 1+putfun(s); + } + else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){ /* bf */ + cput(1); + return 1+putbf(lno); + } + else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){ /* ef */ + cput(1); + return 1+putef(lno); + } + cput(0); /* 0 aux entry */ + return 1; +} + +static Symx* +defsym(char *p, int t, long v) +{ + Symx *s; + + s = lookupsym(p, 0); + if(s->type == SDATA || s->type == SBSS) + return nil; /* already output */ + if(s->type == 0 || s->type == SXREF){ + s->type = t; + s->value = v; + } + return s; +} + +static int +specsym(char *p, int t, long v, int c) +{ + return putsym(defsym(p, t, v), c, T_VOID, 0); +} + +static int +cclass(Symx *s) +{ +/* + if(s->version > 0 && dclass == D_EXTERN) + diag("%s: version %d dclass EXTERN", s->name, s->version); + if(s->version == 0 && dclass == D_STATIC) + diag("%s: version %d dclass STATIC", s->name, s->version); +*/ + return s->version > 0 ? C_STAT : C_EXT; +} + +static void +patchsym(long i, long o, long v) +{ + long oo; + + cflush(); + oo = seek(cout, 0, 1); + seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0); + lputl(v); + cflush(); + seek(cout, oo, 0); +} + +void +coffsym(void) +{ + int i; + long ns, lno, lpc, v, vs, lastf; + Prog *p; + Auto *a, *f; + Symx *s, *bf, *ef, ts; + char *fn, file[256]; + + file[0] = '\0'; + cofflcsz(); + seek(cout, 6*nlc, 1); /* advance over line table */ + ns = 0; + lpc = -1; + lno = -1; + lastf = -1; + bf = defsym(DOTBF, STEXT, 0); + ef = defsym(DOTEF, STEXT, 0); + for(p = firstp; p != P; p = p->link){ + setarch(p); + if(p->as != ATEXT){ + if(p->line != 0) + lno = lineno(p->line); + } + if(p->as == ATEXT){ + curtext = p; + autosize = p->to.offset+4; + if(lpc >= 0){ + ef->value = lpc; + ns += putsym(ef, C_FCN, T_VOID, lno); + } + f = nil; + fn = nil; + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_FILE || a->type == D_FILE1) + dohist(a); + if(f == nil && a->type == D_FILE) + f = a; /* main filename */ + } + if(f != nil) + fn = filename(f->asym->name); + if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){ + strcpy(file, fn); + ts.name = file; + ts.type = SFILE; + ts.value = 0; + if(lastf >= 0) + patchsym(lastf, 8, ns); + lastf = ns; + ns += putsym(&ts, C_FILE, T_VOID, 0); + } + if(p->link != P && p->link->line != 0) + lno = lineno(p->link->line); + else if(p->line != 0) + lno = lineno(p->line); + s = p->from.sym; + SINDEX(s) = ns; + ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0); + if(p->cond != P) + lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1; + else + lines = 0; + bf->value = p->pc; + ns += putsym(bf, C_FCN, T_VOID, lno); + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_AUTO || a->type == D_PARAM){ + ts.name = a->asym->name; + ts.type = STEXT; + ts.value = a->aoffset; + ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0); + } + } + } + lpc = p->pc; + } + if(lpc >= 0){ + ef->value = lpc; + ns += putsym(ef, C_FCN, T_VOID, lno); + } + /* patch up */ + for(p = textp; p != P; p = p->cond){ + s = p->from.sym; + if(p->cond != P){ + v = SINDEX(p->cond->from.sym); + vs = p->cond->pc - p->pc; + } + else{ + v = 0; + vs = INITTEXT+textsize-p->pc; + } + patchsym(SINDEX(s)+1, 4, 8*vs); + patchsym(SINDEX(s)+1, 12, v); + patchsym(SINDEX(s)+3, 12, v); + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version > 0 && (s->type == SDATA || s->type == SBSS)) + ns += putsym(s, cclass(s), T_INT, 0); + } + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version == 0 && (s->type == SDATA || s->type == SBSS)) + ns += putsym(s, cclass(s), T_INT, 0); + } + } + ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT); + ns += specsym(DOTDATA, SDATA, 0, C_STAT); + ns += specsym(DOTBSS, SBSS, datsize, C_STAT); + ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT); + ns += specsym("edata", SDATA, datsize, C_EXT); + ns += specsym("end", SBSS, datsize+bsssize, C_EXT); + nsym = ns; + stflush(); +} + +void +cofflc(void) +{ + long olc, nl; + Symx *s; + Prog *p; + Auto *a; + + cflush(); + seek(cout, HEADR+textsize+datsize, 0); + nl = 0; + /* opc = INITTEXT; */ + olc = 0; + for(p = firstp; p != P; p = p->link){ + setarch(p); + if(p->as == ATEXT){ + curtext = p; + s = p->from.sym; + /* opc = p->pc; */ + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_FILE || a->type == D_FILE1) + dohist(a); + } + lputl(SINDEX(s)); + hputl(0); + nl++; + continue; + } + if(p->line == 0 || p->line == olc || p->as == ANOP) + continue; + lputl(p->pc); + hputl(lineno(p->line)); + nl++; + olc = p->line; + } + if(nl != nlc) + diag("bad line count in cofflc()"); + nlc = nl; +} + +static void +cofflcsz(void) +{ + long olc, nl; + Prog *p; + + nl = 0; + olc = 0; + for(p = firstp; p != P; p = p->link){ + if(p->as == ATEXT){ + LINDEX(p->from.sym) = nl; + nl++; + continue; + } + if(p->line == 0 || p->line == olc || p->as == ANOP) + continue; + nl++; + olc = p->line; + } + nlc = nl; +} diff --git a/utils/5coff/mkfile b/utils/5coff/mkfile new file mode 100644 index 00000000..22d389ba --- /dev/null +++ b/utils/5coff/mkfile @@ -0,0 +1,23 @@ +<../../mkconfig + +TARG=5coff + +OFILES= 5coff.$O\ + coff.$O\ + auxi.$O\ + +HFILES=\ + a.out.h\ + bio.h\ + mach.h\ + +LIBS=mach bio 9 # order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$O.readcoff: readcoff.$O + $LD $LDFLAGS -o $target readcoff.$O $libs $SYSLIBS diff --git a/utils/5coff/readcoff.c b/utils/5coff/readcoff.c new file mode 100644 index 00000000..aa74ecc1 --- /dev/null +++ b/utils/5coff/readcoff.c @@ -0,0 +1,298 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +int fd; +static void readf(void); + +static void +usage(char *msg) +{ + fprint(2, "***Error: %s\n", msg); + exits("usage"); +} + +static int +cget(void) +{ + uchar b[1]; + + if(read(fd, b, 1) != 1){ + fprint(2, "bad cget\n"); + exits("cget"); + } + return b[0]; +} + +static int +hget(void) +{ + uchar b[2]; + + if(read(fd, b, 2) != 2){ + fprint(2, "bad hget\n"); + exits("hget"); + } + return b[1]<<8 | b[0]; +} + +static int +lget(void) +{ + uchar b[4]; + + if(read(fd, b, 4) != 4){ + fprint(2, "bad lget\n"); + exits("lget"); + } + return b[3]<<24 | b[2]<<16 | b[1]<<8 | b[0]; +} + +static char * +sget(char *st) +{ + int i; + static uchar buf[8+1]; + + for(i = 0; i < 8+1; i++) + buf[i] = 0; + if(read(fd, buf, 8) != 8){ + fprint(2, "bad sget\n"); + exits("sget"); + } + if(buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) + return st+(buf[7]<<24|buf[6]<<16|buf[5]<<8|buf[4]); + return (char*)buf; +} + +void +main(int argc, char *argv[]) +{ + if (argc != 2) + usage("Wrong number of arguments"); + + fd = open(argv[1], OREAD); + if (fd < 0) { + fprint(2, "5coff: open %s: %r\n", argv[1]); + exits("open"); + } + readf(); + exits(0); +} + +static void +section(int i, char *st, int *linoff, int *linn) +{ + int pa, va, sz, off, rel, lin, nrel, nlin, f, res, pno; + char *nm; + + nm = sget(st); + pa = lget(); + va = lget(); + sz = lget(); + off = lget(); + rel = lget(); + lin = lget(); + nrel = lget(); + nlin = lget(); + f = lget(); + res = hget(); + pno = hget(); + print("sect %d %s: pa=0x%x va=0x%x sz=%d off=%d rel=%d lin=%d nrel=%d nlin=%d f=0x%x res=%d pno=%d\n", i, nm, pa, va, sz, off, rel, lin, nrel, nlin, f, res, pno); + *linoff = lin; + *linn = nlin; +} + +static void +opthdr(void) +{ + int mag, ver, textsz, datasz, bsssz, entry, text, data; + + mag = hget(); + ver = hget(); + textsz = lget(); + datasz = lget(); + bsssz = lget(); + entry = lget(); + text = lget(); + data = lget(); + print("opt: mag=0x%x ver=%d txtsz=%d datsz=%d bsssz=%d ent=0x%x txt=0x%x dat=0x%x\n", mag, ver, textsz, datasz, bsssz, entry, text, data); +} + +static void +readhdr(int *o, int *ns, int *sy, int *nsy) +{ + int vid, nsec, date, sym, nsym, opt, f, tid; + + vid = hget(); + nsec = hget(); + date = lget(); + sym = lget(); + nsym = lget(); + opt = hget(); + f = hget(); + tid = hget(); + print("hdr: vid=0x%x nsect=%d date=%d sym=%d nsym=%d opt=%d f=0x%x tid=0x%x\n", vid, nsec, date, sym, nsym, opt, f, tid); + *o = opt; + *ns = nsec; + *sy = sym; + *nsy = nsym; +} + +static void +readauxsect(int i) +{ + int sz, nrel, ln; + + sz = lget(); + nrel = hget(); + ln = hget(); + lget(); + hget(); + lget(); + print("sym auxsect %d: sz=%d nrel=%d ln=%d\n", i, sz, nrel, ln); +} + +static void +readauxfun(int i) +{ + int ind, sz, fpln, nind; + + ind = lget(); + sz = lget(); + fpln = lget(); + nind = lget(); + hget(); + print("sym auxfun %d: ind=%d sz=%d fpln=%d nind=%d\n", i, ind, sz, fpln, nind); +} + +static void +readauxbf(int i) +{ + int rsav, lno, lns, fsz, nind; + + rsav = lget(); + lno = hget(); + lns = hget(); + fsz = lget(); + nind = lget(); + hget(); + print("sym auxbf %d: rsav=%x lno=%d lns=%d fsz=%d nind=%d\n", i, rsav, lno, lns, fsz, nind); +} + +static void +readauxef(int i) +{ + int lno; + + lget(); + lno = hget(); + lget(); + lget(); + lget(); + print("sym auxef %d: lno=%d\n", i, lno); +} + +static void +readauxother(int i) +{ + lget(); + lget(); + hget(); + lget(); + lget(); + print("sym auxother %d\n", i); +} + +static int +readsym(int i, char *st) +{ + int v, s, t, c, aux; + char *nm; + + nm = sget(st); + v = lget(); + s = hget(); + t = hget(); + c = cget(); + aux = cget(); + print("sym %d %s: val=%d sec=%d type=%d class=%d aux=%d\n", i, nm, v, s, t, c, aux); + if(aux){ + i++; + if(strcmp(nm, ".text") == 0 || strcmp(nm, ".data") == 0 || strcmp(nm, ".bss") == 0) + readauxsect(i); + else if(strcmp(nm, ".bf") == 0) + readauxbf(i); + else if(strcmp(nm, ".ef") == 0) + readauxef(i); + else if((t&0x30) == 0x20) // will do + readauxfun(i); + else + readauxother(i); + return 1; + } + return 0; +} + +static char * +readstr(int n) +{ + char *s = malloc(n); + + if(read(fd, s+4, n-4) != n-4){ + fprint(2, "bad readstr\n"); + exits("sget"); + } + return s; +} + +static void +readln(int i) +{ + int a, l; + + a = lget(); + l = hget(); + if(l == 0) + print("line %d: sym=%d\n", i, a); + else + print("line %d: addr=0x%x line=%d\n", i, a, l); +} + +static void +readf() +{ + int i, opt, nsec, sym, nsym, stoff, strsz, linoff, nlin, lino, linn; + char *st; + + seek(fd, 0, 0); + readhdr(&opt, &nsec, &sym, &nsym); + if(opt) + opthdr(); + stoff = sym+18*nsym; + seek(fd, stoff, 0); + strsz = lget(); + st = readstr(strsz); + linoff = nlin = 0; + seek(fd, 22+28, 0); + for(i = 0; i < nsec; i++){ + section(i, st, &lino, &linn); + if(linn != 0){ + if(nlin == 0){ + nlin = linn; + linoff = lino; + } + else + print("multiple line no. tables\n"); + } + } + seek(fd, sym, 0); + for(i = 0; i < nsym; i++) + i += readsym(i, st); + print("strsz = %d\n", strsz); + if(nlin != 0){ + seek(fd, linoff, 0); + for(i = 0; i < nlin; i++) + readln(i); + } +} diff --git a/utils/5cv/5cv.c b/utils/5cv/5cv.c new file mode 100644 index 00000000..1edbf6c6 --- /dev/null +++ b/utils/5cv/5cv.c @@ -0,0 +1,353 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +char *Cmd; +int Hdrtype; +int Strip; +long Txtaddr = -1; + +int Ofd; +int Ifd; +Fhdr Ihdr; + +int Debug; + +static void get_file(char *); +static void put_file(char *); +static void Usage(char *); +static long strxtol(char *); + +char *fail = "error"; + +void +main(int argc, char *argv[]) +{ + char *ifile, *ofile; + + Cmd = argv[0]; + Hdrtype = 2; + + ARGBEGIN { + /* + * Options without args + */ + case 's': + Strip = 1; + break; + /* + * Options with args + */ + case 'T': + Txtaddr = strxtol(ARGF()); + break; + case 'H': + Hdrtype = strxtol(ARGF()); + break; + case 'D': + Debug |= strxtol(ARGF()); + break; + default: + Usage("Invalid option"); + } ARGEND + + if (argc != 2) + Usage("Wrong number of arguments"); + + ifile = argv[0]; + ofile = argv[1]; + + get_file(ifile); + put_file(ofile); + exits(0); +} + +char usagemsg[] = +"Usage: %s options infile outfile\n\t options (for outfile): -H[123456] -s -T<text> \n"; + +static void +Usage(char *msg) +{ + fprint(2, "***Error: %s\n", msg); + fprint(2, usagemsg, Cmd); + exits("usage"); +} + +static long +strxtol(char *s) +{ + char *es; + int base = 0; + long r; + + if (*s == '0') + if (*++s == 'x'){ + base = 16; + s++; + } + else + base = 8; + r = strtol(s, &es, base); + if (*es) + Usage("bad number"); + return(r); +} + +static void +get_file(char *ifile) +{ + int h; + int d; + + Ifd = open(ifile, OREAD); + if (Ifd < 0) { + fprint(2, "5cv: open %s: %r\n", ifile); + exits("open"); + } + h = crackhdr(Ifd, &Ihdr); + if (!h || Debug){ + fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, Ihdr.type, Ihdr.name); + fprint(2, "txt %lux, ent %lux, txtsz %lux, dataddr %lux\n", + Ihdr.txtaddr, Ihdr.entry, Ihdr.txtsz, Ihdr.dataddr); + } + if (!h) + Usage("File type not recognized"); + machbytype(Ihdr.type); + if (Debug) + fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize); + + if (Txtaddr != -1){ + d = Txtaddr - Ihdr.txtaddr; + Ihdr.txtaddr += d; + Ihdr.dataddr = Ihdr.txtaddr + Ihdr.txtsz; + } +} + +char Wbuf[128]; +char *wp = Wbuf; + +void +lput(long l) +{ + wp[0] = l>>24; + wp[1] = l>>16; + wp[2] = l>>8; + wp[3] = l; + wp += 4; +} + +void +lputl(long l) +{ + wp[3] = l>>24; + wp[2] = l>>16; + wp[1] = l>>8; + wp[0] = l; + wp += 4; +} + +static void +copyseg(long sz) +{ + char buf[1024]; + + while (sz > 0){ + long n; + long r; + + n = sz; + if (n > sizeof buf) + n = sizeof buf; + sz -= n; + + if ((r = read(Ifd, buf, n)) != n){ + fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(Ifd, 0, 1)); + perror("Premature eof"); + exits(fail); + } + if ((r = write(Ofd, buf, n)) != n){ + fprint(2, "%ld = write(...%ld)\n", r, n); + perror("Write error!"); + exits(fail); + } + } +} + +static void +zero(long sz) +{ + char buf[1024]; + + memset(buf, 0, sizeof buf); + while (sz > 0){ + long n; + long r; + + n = sz; + if (n > sizeof buf) + n = sizeof buf; + sz -= n; + + if ((r = write(Ofd, buf, n)) != n){ + fprint(2, "%ld = write(...%ld)\n", r, n); + perror("Write error!"); + exits(fail); + } + } +} + +static 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; +} + +static void +put_file(char *ofile) +{ + int ii; + long doff; + long dsize; + long hlen; + long pad; + + Ofd = create(ofile, OWRITE, 0666); + if (Ofd < 0) { + fprint(2, "5cv: create %s: %r\n", ofile); + exits("create"); + } + + pad = 0; + + switch(Hdrtype) { + case 1: /* aif for risc os */ + Strip = 1; + hlen = 128; + lputl(0xe1a00000); /* NOP - decompress code */ + lputl(0xe1a00000); /* NOP - relocation code */ + lputl(0xeb000000 + 12); /* BL - zero init code */ + lputl(0xeb000000 + + (Ihdr.entry + - Ihdr.txtaddr + + hlen + - 12 + - 8) / 4); /* BL - entry code */ + + lputl(0xef000011); /* SWI - exit code */ + doff = Ihdr.txtsz+hlen; + lputl(doff); /* text size */ + dsize = Ihdr.datsz; + lputl(dsize); /* data size */ + lputl(0); /* sym size */ + + lputl(Ihdr.bsssz); /* bss size */ + lputl(0); /* sym type */ + lputl(Ihdr.txtaddr-hlen); /* text addr */ + lputl(0); /* workspace - ignored */ + + lputl(32); /* addr mode / data addr flag */ + lputl(0); /* data addr */ + for(ii=0; ii<2; ii++) + lputl(0); /* reserved */ + + for(ii=0; ii<15; ii++) + lputl(0xe1a00000); /* NOP - zero init code */ + lputl(0xe1a0f00e); /* B (R14) - zero init return */ + break; + + case 2: /* plan 9 */ + hlen = 32; + doff = hlen + Ihdr.txtsz; + dsize = Ihdr.datsz; + lput(0x647); /* magic */ + lput(Ihdr.txtsz); /* sizes */ + lput(Ihdr.datsz); + lput(Ihdr.bsssz); + if (Strip) /* nsyms */ + lput(0); + else + lput(Ihdr.symsz); + lput(Ihdr.entry); /* va of entry */ + lput(0L); + lput(Ihdr.lnpcsz); + break; + + case 3: /* boot for NetBSD */ + hlen = 32; + doff = rnd(hlen+Ihdr.txtsz, 4096); + dsize = rnd(Ihdr.datsz, 4096); + lput((143<<16)|0413); /* magic */ + lputl(doff); + lputl(dsize); + lputl(Ihdr.bsssz); + if (Strip) /* nsyms */ + lputl(0); + else + lputl(Ihdr.symsz); + lputl(Ihdr.entry); /* va of entry */ + lputl(0L); + lputl(0L); + break; + case 4: /* no header, stripped, padded to 2K, for serial bootstrap */ + hlen = 0; + Strip = 1; + doff = hlen + Ihdr.txtsz; + dsize = Ihdr.datsz; + pad = 2048; + break; + case 5: /* no header, stripped, for all sorts */ + hlen = 0; + Strip = 1; + doff = hlen + Ihdr.txtsz; + dsize = Ihdr.datsz; + break; + case 6: /* fake EPOC IMG format header */ + hlen = 256; + *wp++ = 'E'; + *wp++ = 'P'; + Strip = 1; + doff = hlen + Ihdr.txtsz; + dsize = Ihdr.datsz; + break; + default: + Usage("Bad -Htype"); + return; + } + write(Ofd, Wbuf, hlen); + + seek(Ifd, Ihdr.txtoff, 0); + copyseg(Ihdr.txtsz); + + seek(Ifd, Ihdr.datoff, 0); + seek(Ofd, doff, 0); + copyseg(Ihdr.datsz); + + if (!Strip) { + /* Write symbols */ + seek(Ofd, doff + dsize, 0); + if (Ihdr.symsz){ + seek(Ifd, Ihdr.symoff, 0); + copyseg(Ihdr.symsz); + } + if (Hdrtype == 2) + copyseg(Ihdr.lnpcsz); + } + + if (pad) { + if (doff + Ihdr.datsz > pad) { + perror("Too big!"); + exits(fail); + } + else if (doff + Ihdr.datsz < pad) + zero(pad - (doff + Ihdr.datsz)); + } +} diff --git a/utils/5cv/mkfile b/utils/5cv/mkfile new file mode 100644 index 00000000..3b544bc6 --- /dev/null +++ b/utils/5cv/mkfile @@ -0,0 +1,18 @@ +<../../mkconfig + +TARG=5cv + +OFILES= 5cv.$O\ + +HFILES=\ + a.out.h\ + bio.h\ + mach.h\ + +LIBS=mach bio 9 # order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/5l/Nt.c b/utils/5l/Nt.c new file mode 100644 index 00000000..73c6f795 --- /dev/null +++ b/utils/5l/Nt.c @@ -0,0 +1,77 @@ +#include <windows.h> +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/5l/Plan9.c b/utils/5l/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/5l/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/5l/Posix.c b/utils/5l/Posix.c new file mode 100644 index 00000000..0da0ee0c --- /dev/null +++ b/utils/5l/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fails if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} diff --git a/utils/5l/asm.c b/utils/5l/asm.c new file mode 100644 index 00000000..fbb1397b --- /dev/null +++ b/utils/5l/asm.c @@ -0,0 +1,1793 @@ +#include "l.h" + +long OFFSET; + +static Prog *PP; + +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: + case SLEAF: + break; + case SDATA: + if(dlm) + return s->value+INITDAT; + default: + diag("entry not text: %s", s->name); + } + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long t, etext; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f asm\n", cputime()); + Bflush(&bso); + OFFSET = HEADR; + seek(cout, OFFSET, 0); + pc = INITTEXT; + for(p = firstp; p != P; p = p->link) { + setarch(p); + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + } + if(p->pc != pc) { + diag("phase error %lux sb %lux", + p->pc, pc); + if(!debug['a']) + prasm(curp); + pc = p->pc; + } + curp = p; + o = oplook(p); /* could probably avoid this call */ + if(thumb) + thumbasmout(p, o); + else + asmout(p, o); + pc += o->size; + } + while(pc-INITTEXT < textsize) { + cput(0); + pc++; + } + + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + + /* output strings in text segment */ + etext = INITTEXT + textsize; + for(t = pc; t < etext; t += sizeof(buf)-100) { + if(etext-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100, 1); + else + datblk(t, etext-t, 1); + } + + curtext = P; + switch(HEADTYPE) { + case 0: + case 1: + case 2: + case 5: + OFFSET = HEADR+textsize; + seek(cout, OFFSET, 0); + break; + case 3: + OFFSET = rnd(HEADR+textsize, 4096); + seek(cout, OFFSET, 0); + break; + } + if(dlm){ + char buf[8]; + + write(cout, buf, INITDAT-textsize); + textsize = INITDAT; + } + for(t = 0; t < datsize; t += sizeof(buf)-100) { + if(datsize-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100, 0); + else + datblk(t, datsize-t, 0); + } + cflush(); + + symsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + case 0: + case 1: + case 4: + case 5: + debug['s'] = 1; + break; + case 2: + OFFSET = HEADR+textsize+datsize; + seek(cout, OFFSET, 0); + break; + case 3: + OFFSET += rnd(datsize, 4096); + seek(cout, OFFSET, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + if(!debug['s']) + asmthumbmap(); + if(dlm) + asmdyn(); + cflush(); + } + else if(dlm){ + seek(cout, HEADR+textsize+datsize, 0); + asmdyn(); + cflush(); + } + + curtext = P; + if(debug['v']) + Bprint(&bso, "%5.2f header\n", cputime()); + Bflush(&bso); + OFFSET = 0; + seek(cout, OFFSET, 0); + switch(HEADTYPE) { + case 0: /* no header */ + break; + case 1: /* aif for risc os */ + lputl(0xe1a00000); /* NOP - decompress code */ + lputl(0xe1a00000); /* NOP - relocation code */ + lputl(0xeb000000 + 12); /* BL - zero init code */ + lputl(0xeb000000 + + (entryvalue() + - INITTEXT + + HEADR + - 12 + - 8) / 4); /* BL - entry code */ + + lputl(0xef000011); /* SWI - exit code */ + lputl(textsize+HEADR); /* text size */ + lputl(datsize); /* data size */ + lputl(0); /* sym size */ + + lputl(bsssize); /* bss size */ + lputl(0); /* sym type */ + lputl(INITTEXT-HEADR); /* text addr */ + lputl(0); /* workspace - ignored */ + + lputl(32); /* addr mode / data addr flag */ + lputl(0); /* data addr */ + for(t=0; t<2; t++) + lputl(0); /* reserved */ + + for(t=0; t<15; t++) + lputl(0xe1a00000); /* NOP - zero init code */ + lputl(0xe1a0f00e); /* B (R14) - zero init return */ + break; + case 2: /* plan 9 */ + if(dlm) + lput(0x80000000|0x647); /* magic */ + else + lput(0x647); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 3: /* boot for NetBSD */ + lput((143<<16)|0413); /* magic */ + lputl(rnd(HEADR+textsize, 4096)); + lputl(rnd(datsize, 4096)); + lputl(bsssize); + lputl(symsize); /* nsyms */ + lputl(entryvalue()); /* va of entry */ + lputl(0L); + lputl(0L); + break; + case 4: /* boot for IXP1200 */ + break; + case 5: /* boot for ipaq */ + lputl(0xe3300000); /* nop */ + lputl(0xe3300000); /* nop */ + lputl(0xe3300000); /* nop */ + lputl(0xe3300000); /* nop */ + break; + } + cflush(); + if(debug['c']){ + print("textsize=%ld\n", textsize); + print("datsize=%ld\n", datsize); + print("bsssize=%ld\n", bsssize); + print("symsize=%ld\n", symsize); + print("lcsize=%ld\n", lcsize); + print("total=%ld\n", textsize+datsize+bsssize+symsize+lcsize); + } +} + +void +strnput(char *s, int n) +{ + for(; *s; s++){ + cput(*s); + n--; + } + for(; n > 0; n--) + cput(0); +} + +void +cput(int c) +{ + cbp[0] = c; + cbp++; + cbc--; + if(cbc <= 0) + cflush(); +} + +/* +void +cput(long c) +{ + *cbp++ = c; + if(--cbc <= 0) + cflush(); +} +*/ + +void +wput(long l) +{ + + cbp[0] = l>>8; + cbp[1] = l; + cbp += 2; + cbc -= 2; + if(cbc <= 0) + cflush(); +} + +void +hput(long l) +{ + + cbp[0] = l>>8; + cbp[1] = l; + cbp += 2; + cbc -= 2; + if(cbc <= 0) + cflush(); +} + +void +lput(long l) +{ + + cbp[0] = l>>24; + cbp[1] = l>>16; + cbp[2] = l>>8; + cbp[3] = l; + cbp += 4; + cbc -= 4; + if(cbc <= 0) + cflush(); +} + +void +lputl(long l) +{ + + cbp[3] = l>>24; + cbp[2] = l>>16; + cbp[1] = l>>8; + cbp[0] = l; + cbp += 4; + cbc -= 4; + if(cbc <= 0) + cflush(); +} + +void +cflush(void) +{ + int n; + + /* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */ + n = sizeof(buf.cbuf) - cbc; + if(n) + write(cout, buf.cbuf, n); + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); +} + +void +nopstat(char *f, Count *c) +{ + if(c->outof) + Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, + c->outof - c->count, c->outof, + (double)(c->outof - c->count)/c->outof); +} + +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 SSTRING: + putsymb(s->name, 'T', s->value, s->version); + continue; + + case SFILE: + putsymb(s->name, 'f', s->value, s->version); + continue; + } + + for(p=textp; p!=P; p=p->cond) { + s = p->from.sym; + if(s->type != STEXT && s->type != SLEAF) + 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); + + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + else + putsymb(s->name, 'L', 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 +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); + } +} + +#define MINLC 4 +void +asmlc(void) +{ + long oldpc, oldlc; + Prog *p; + long v, s; + + oldpc = INITTEXT; + oldlc = 0; + for(p = firstp; p != P; p = p->link) { + setarch(p); + 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); +} + +static void +outt(long f, long l) +{ + if(debug['L']) + Bprint(&bso, "tmap: %lux-%lux\n", f, l); + lput(f); + lput(l); +} + +void +asmthumbmap(void) +{ + long pc, lastt; + Prog *p; + + if(!seenthumb) + return; + pc = 0; + lastt = -1; + for(p = firstp; p != P; p = p->link){ + pc = p->pc - INITTEXT; + if(p->as == ATEXT){ + setarch(p); + if(thumb){ + if(p->from.sym->foreign){ // 8 bytes of ARM first + if(lastt >= 0){ + outt(lastt, pc-1); + lastt = -1; + } + pc += 8; + } + if(lastt < 0) + lastt = pc; + } + else{ + if(p->from.sym->foreign){ // 4 bytes of THUMB first + if(lastt < 0) + lastt = pc; + pc += 4; + } + if(lastt >= 0){ + outt(lastt, pc-1); + lastt = -1; + } + } + } + } + if(lastt >= 0) + outt(lastt, pc+1); +} + +void +datblk(long s, long n, int str) +{ + Sym *v; + Prog *p; + char *cast; + long a, l, fl, j, d; + int i, c; + + memset(buf.dbuf, 0, n+100); + for(p = datap; p != P; p = p->link) { + if(str != (p->from.sym->type == SSTRING)) + continue; + curp = p; + a = p->from.sym->value + p->from.offset; + l = a - s; + c = p->reg; + 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) { + default: + diag("unknown mode in initialization%P", p); + break; + + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(p->to.ieee); + cast = (char*)&fl; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi4[i]]; + l++; + } + break; + case 8: + cast = (char*)p->to.ieee; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + for(; i<c; i++) { + buf.dbuf[l] = p->to.sval[i]; + l++; + } + break; + + case D_CONST: + d = p->to.offset; + v = p->to.sym; + if(v) { + switch(v->type) { + case SUNDEF: + ckoff(v, d); + d += v->value; + break; + case STEXT: + case SLEAF: + d += v->value; +#ifdef CALLEEBX + d += fnpinc(v); +#else + if(v->thumb) + d++; // T bit +#endif + break; + case SSTRING: + d += v->value; + break; + case SDATA: + case SBSS: + d += v->value + INITDAT; + break; + } + if(dlm) + dynreloc(v, a+INITDAT, 1); + } + cast = (char*)&d; + switch(c) { + default: + diag("bad nuxi %d %d%P", c, i, curp); + break; + case 1: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +void +asmout(Prog *p, Optab *o) +{ + long o1, o2, o3, o4, o5, o6, v; + int r, rf, rt, rt2; + Sym *s; + +PP = p; + o1 = 0; + o2 = 0; + o3 = 0; + o4 = 0; + o5 = 0; + o6 = 0; + armsize += o->size; +if(debug['P']) print("%ulx: %P type %d\n", (ulong)(p->pc), p, o->type); + switch(o->type) { + default: + diag("unknown asm %d", o->type); + prasm(p); + break; + + case 0: /* pseudo ops */ +if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr, p->from.sym->used); + break; + + case 1: /* op R,[R],R */ + o1 = oprrr(p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; + if(r == NREG) + r = rt; + o1 |= rf | (r<<16) | (rt<<12); + break; + + case 2: /* movbu $I,[R],R */ + aclass(&p->from); + o1 = oprrr(p->as, p->scond); + o1 |= immrot(instoffset); + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; + if(r == NREG) + r = rt; + o1 |= (r<<16) | (rt<<12); + break; + + case 3: /* add R<<[IR],[R],R */ + mov: + aclass(&p->from); + o1 = oprrr(p->as, p->scond); + o1 |= p->from.offset; + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; + if(r == NREG) + r = rt; + o1 |= (r<<16) | (rt<<12); + break; + + case 4: /* add $I,[R],R */ + aclass(&p->from); + o1 = oprrr(AADD, p->scond); + o1 |= immrot(instoffset); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 |= r << 16; + o1 |= p->to.reg << 12; + break; + + case 5: /* bra s */ + v = -8; + if(p->cond == UP) { + s = p->to.sym; + if(s->type != SUNDEF) + diag("bad branch sym type"); + v = (ulong)s->value >> (Roffset-2); + dynreloc(s, p->pc, 0); + } + else if(p->cond != P) + v = (p->cond->pc - pc) - 8; +#ifdef CALLEEBX + if(p->as == ABL) + v += fninc(p->to.sym); +#endif + o1 = opbra(p->as, p->scond); + o1 |= (v >> 2) & 0xffffff; + break; + + case 6: /* b ,O(R) -> add $O,R,PC */ + aclass(&p->to); + o1 = oprrr(AADD, p->scond); + o1 |= immrot(instoffset); + o1 |= p->to.reg << 16; + o1 |= REGPC << 12; + break; + + case 7: /* bl ,O(R) -> mov PC,link; add $O,R,PC */ + aclass(&p->to); + o1 = oprrr(AADD, p->scond); + o1 |= immrot(0); + o1 |= REGPC << 16; + o1 |= REGLINK << 12; + + o2 = oprrr(AADD, p->scond); + o2 |= immrot(instoffset); + o2 |= p->to.reg << 16; + o2 |= REGPC << 12; + break; + + case 8: /* sll $c,[R],R -> mov (R<<$c),R */ + aclass(&p->from); + o1 = oprrr(p->as, p->scond); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 |= r; + o1 |= (instoffset&31) << 7; + o1 |= p->to.reg << 12; + break; + + case 9: /* sll R,[R],R -> mov (R<<R),R */ + o1 = oprrr(p->as, p->scond); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 |= r; + o1 |= (p->from.reg << 8) | (1<<4); + o1 |= p->to.reg << 12; + break; + + case 10: /* swi [$con] */ + o1 = oprrr(p->as, p->scond); + if(p->to.type != D_NONE) { + aclass(&p->to); + o1 |= instoffset & 0xffffff; + } + break; + + case 11: /* word */ + switch(aclass(&p->to)) { + case C_LCON: + if(!dlm) + break; + if(p->to.name != D_EXTERN && p->to.name != D_STATIC) + break; + case C_ADDR: + if(p->to.sym->type == SUNDEF) + ckoff(p->to.sym, p->to.offset); + dynreloc(p->to.sym, p->pc, 1); + } + o1 = instoffset; + break; + + case 12: /* movw $lcon, reg */ + o1 = omvl(p, &p->from, p->to.reg); + break; + + case 13: /* op $lcon, [R], R */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + o2 = oprrr(p->as, p->scond); + o2 |= REGTMP; + r = p->reg; + if(r == NREG) + r = p->to.reg; + o2 |= r << 16; + if(p->to.type != D_NONE) + o2 |= p->to.reg << 12; + break; + + case 14: /* movb/movbu/movh/movhu R,R */ + o1 = oprrr(ASLL, p->scond); + + if(p->as == AMOVBU || p->as == AMOVHU) + o2 = oprrr(ASRL, p->scond); + else + o2 = oprrr(ASRA, p->scond); + + r = p->to.reg; + o1 |= (p->from.reg)|(r<<12); + o2 |= (r)|(r<<12); + if(p->as == AMOVB || p->as == AMOVBU) { + o1 |= (24<<7); + o2 |= (24<<7); + } else { + o1 |= (16<<7); + o2 |= (16<<7); + } + break; + + case 15: /* mul r,[r,]r */ + o1 = oprrr(p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + if(r == NREG) + r = rt; + if(rt == r) { + r = rf; + rf = rt; + } + if(0) + if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { + diag("bad registers in MUL"); + prasm(p); + } + o1 |= (rf<<8) | r | (rt<<16); + break; + + + case 16: /* div r,[r,]r */ + o1 = 0xf << 28; + o2 = 0; + break; + + case 17: + o1 = oprrr(p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + rt2 = p->to.offset; + r = p->reg; + o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); + break; + + case 20: /* mov/movb/movbu R,O(R) */ + aclass(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = osr(p->as, p->from.reg, instoffset, r, p->scond); + break; + + case 21: /* mov/movbu O(R),R -> lr */ + aclass(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = olr(instoffset, r, p->to.reg, p->scond); + if(p->as != AMOVW) + o1 |= 1<<22; + break; + + case 22: /* movb/movh/movhu O(R),R -> lr,shl,shr */ + aclass(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = olr(instoffset, r, p->to.reg, p->scond); + + o2 = oprrr(ASLL, p->scond); + o3 = oprrr(ASRA, p->scond); + r = p->to.reg; + if(p->as == AMOVB) { + o2 |= (24<<7)|(r)|(r<<12); + o3 |= (24<<7)|(r)|(r<<12); + } else { + o2 |= (16<<7)|(r)|(r<<12); + if(p->as == AMOVHU) + o3 = oprrr(ASRL, p->scond); + o3 |= (16<<7)|(r)|(r<<12); + } + break; + + case 23: /* movh/movhu R,O(R) -> sb,sb */ + aclass(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond); + + o2 = oprrr(ASRL, p->scond); + o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12); + + o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond); + break; + + case 30: /* mov/movb/movbu R,L(R) */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = osrr(p->from.reg, REGTMP,r, p->scond); + if(p->as != AMOVW) + o2 |= 1<<22; + break; + + case 31: /* mov/movbu L(R),R -> lr[b] */ + case 32: /* movh/movb L(R),R -> lr[b] */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 = olrr(REGTMP,r, p->to.reg, p->scond); + if(p->as == AMOVBU || p->as == AMOVB) + o2 |= 1<<22; + if(o->type == 31) + break; + + o3 = oprrr(ASLL, p->scond); + + if(p->as == AMOVBU || p->as == AMOVHU) + o4 = oprrr(ASRL, p->scond); + else + o4 = oprrr(ASRA, p->scond); + + r = p->to.reg; + o3 |= (r)|(r<<12); + o4 |= (r)|(r<<12); + if(p->as == AMOVB || p->as == AMOVBU) { + o3 |= (24<<7); + o4 |= (24<<7); + } else { + o3 |= (16<<7); + o4 |= (16<<7); + } + break; + + case 33: /* movh/movhu R,L(R) -> sb, sb */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = osrr(p->from.reg, REGTMP, r, p->scond); + o2 |= (1<<22) ; + + o3 = oprrr(ASRL, p->scond); + o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12); + o3 |= (1<<6); /* ROR 8 */ + + o4 = oprrr(AADD, p->scond); + o4 |= (REGTMP << 12) | (REGTMP << 16); + o4 |= immrot(1); + + o5 = osrr(p->from.reg, REGTMP,r,p->scond); + o5 |= (1<<22); + + o6 = oprrr(ASRL, p->scond); + o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12); + o6 |= (1<<6); /* ROL 8 */ + + break; + + case 34: /* mov $lacon,R */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + + o2 = oprrr(AADD, p->scond); + o2 |= REGTMP; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 |= r << 16; + if(p->to.type != D_NONE) + o2 |= p->to.reg << 12; + break; + + case 35: /* mov PSR,R */ + o1 = (2<<23) | (0xf<<16) | (0<<0); + o1 |= (p->scond & C_SCOND) << 28; + o1 |= (p->from.reg & 1) << 22; + o1 |= p->to.reg << 12; + break; + + case 36: /* mov R,PSR */ + o1 = (2<<23) | (0x29f<<12) | (0<<4); + if(p->scond & C_FBIT) + o1 ^= 0x010 << 12; + o1 |= (p->scond & C_SCOND) << 28; + o1 |= (p->to.reg & 1) << 22; + o1 |= p->from.reg << 0; + break; + + case 37: /* mov $con,PSR */ + aclass(&p->from); + o1 = (2<<23) | (0x29f<<12) | (0<<4); + if(p->scond & C_FBIT) + o1 ^= 0x010 << 12; + o1 |= (p->scond & C_SCOND) << 28; + o1 |= immrot(instoffset); + o1 |= (p->to.reg & 1) << 22; + o1 |= p->from.reg << 0; + break; + + case 38: /* movm $con,oreg -> stm */ + o1 = (0x4 << 25); + o1 |= p->from.offset & 0xffff; + o1 |= p->to.reg << 16; + aclass(&p->to); + goto movm; + + case 39: /* movm oreg,$con -> ldm */ + o1 = (0x4 << 25) | (1 << 20); + o1 |= p->to.offset & 0xffff; + o1 |= p->from.reg << 16; + aclass(&p->from); + movm: + if(instoffset != 0) + diag("offset must be zero in MOVM"); + o1 |= (p->scond & C_SCOND) << 28; + if(p->scond & C_PBIT) + o1 |= 1 << 24; + if(p->scond & C_UBIT) + o1 |= 1 << 23; + if(p->scond & C_SBIT) + o1 |= 1 << 22; + if(p->scond & C_WBIT) + o1 |= 1 << 21; + break; + + case 40: /* swp oreg,reg,reg */ + aclass(&p->from); + if(instoffset != 0) + diag("offset must be zero in SWP"); + o1 = (0x2<<23) | (0x9<<4); + if(p->as != ASWPW) + o1 |= 1 << 22; + o1 |= p->from.reg << 16; + o1 |= p->reg << 0; + o1 |= p->to.reg << 12; + o1 |= (p->scond & C_SCOND) << 28; + break; + + case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ + o1 = 0xe8fd8000; + break; + + case 50: /* floating point store */ + v = regoff(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p); + break; + + case 51: /* floating point load */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); + break; + + case 52: /* floating point store, long offset UGLY */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; + o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); + break; + + case 53: /* floating point load, long offset UGLY */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; + o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); + break; + + case 54: /* floating point arith */ + o1 = oprrr(p->as, p->scond); + if(p->from.type == D_FCONST) { + rf = chipfloat(p->from.ieee); + if(rf < 0){ + diag("invalid floating-point immediate\n%P", p); + rf = 0; + } + rf |= (1<<3); + } else + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + if(p->to.type == D_NONE) + rt = 0; /* CMP[FD] */ + else if(o1 & (1<<15)) + r = 0; /* monadic */ + else if(r == NREG) + r = rt; + o1 |= rf | (r<<16) | (rt<<12); + break; + + case 55: /* floating point fix and float */ + o1 = oprrr(p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + if(p->to.type == D_NONE){ + rt = 0; + diag("to.type==D_NONE (asm/fp)"); + } + if(p->from.type == D_REG) + o1 |= (rf<<12) | (rt<<16); + else + o1 |= rf | (rt<<12); + break; + + case 56: /* move to FP[CS]R */ + o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); + o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); + break; + + case 57: /* move from FP[CS]R */ + o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); + o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); + break; + case 58: /* movbu R,R */ + o1 = oprrr(AAND, p->scond); + o1 |= immrot(0xff); + rt = p->to.reg; + r = p->from.reg; + if(p->to.type == D_NONE) + rt = 0; + if(r == NREG) + r = rt; + o1 |= (r<<16) | (rt<<12); + break; + + case 59: /* movw/bu R<<I(R),R -> ldr indexed */ + if(p->from.reg == NREG) { + if(p->as != AMOVW) + diag("byte MOV from shifter operand"); + goto mov; + } + if(p->from.offset&(1<<4)) + diag("bad shift in LDR"); + o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond); + if(p->as == AMOVBU) + o1 |= 1<<22; + break; + + case 60: /* movb R(R),R -> ldrsb indexed */ + if(p->from.reg == NREG) { + diag("byte MOV from shifter operand"); + goto mov; + } + if(p->from.offset&(~0xf)) + diag("bad shift in LDRSB"); + o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); + o1 ^= (1<<5)|(1<<6); + break; + + case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ + if(p->to.reg == NREG) + diag("MOV to shifter operand"); + o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond); + if(p->as == AMOVB || p->as == AMOVBU) + o1 |= 1<<22; + break; + + case 62: /* case R -> movw R<<2(PC),PC */ + o1 = olrr(p->from.reg, REGPC, REGPC, p->scond); + o1 |= 2<<7; + break; + + case 63: /* bcase */ + if(p->cond != P) { + o1 = p->cond->pc; + if(dlm) + dynreloc(S, p->pc, 1); + } + break; + + /* reloc ops */ + case 64: /* mov/movb/movbu R,addr */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); + break; + + case 65: /* mov/movbu addr,R */ + case 66: /* movh/movhu/movb addr,R */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + o2 = olr(0, REGTMP, p->to.reg, p->scond); + if(p->as == AMOVBU || p->as == AMOVB) + o2 |= 1<<22; + if(o->type == 65) + break; + + o3 = oprrr(ASLL, p->scond); + + if(p->as == AMOVBU || p->as == AMOVHU) + o4 = oprrr(ASRL, p->scond); + else + o4 = oprrr(ASRA, p->scond); + + r = p->to.reg; + o3 |= (r)|(r<<12); + o4 |= (r)|(r<<12); + if(p->as == AMOVB || p->as == AMOVBU) { + o3 |= (24<<7); + o4 |= (24<<7); + } else { + o3 |= (16<<7); + o4 |= (16<<7); + } + break; + + case 67: /* movh/movhu R,addr -> sb, sb */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); + + o3 = oprrr(ASRL, p->scond); + o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12); + o3 |= (1<<6); /* ROR 8 */ + + o4 = oprrr(AADD, p->scond); + o4 |= (REGTMP << 12) | (REGTMP << 16); + o4 |= immrot(1); + + o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); + + o6 = oprrr(ASRL, p->scond); + o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12); + o6 |= (1<<6); /* ROL 8 */ + break; + + case 68: /* floating point store -> ADDR */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); + break; + + case 69: /* floating point load <- ADDR */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); + break; + + /* ArmV4 ops: */ + case 70: /* movh/movhu R,O(R) -> strh */ + aclass(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = oshr(p->from.reg, instoffset, r, p->scond); + break; + case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ + aclass(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = olhr(instoffset, r, p->to.reg, p->scond); + if(p->as == AMOVB) + o1 ^= (1<<5)|(1<<6); + else if(p->as == AMOVH) + o1 ^= (1<<6); + break; + case 72: /* movh/movhu R,L(R) -> strh */ + o1 = omvl(p, &p->to, REGTMP); + if(!o1) + break; + r = p->to.reg; + if(r == NREG) + r = o->param; + o2 = oshrr(p->from.reg, REGTMP,r, p->scond); + break; + case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ + o1 = omvl(p, &p->from, REGTMP); + if(!o1) + break; + r = p->from.reg; + if(r == NREG) + r = o->param; + o2 = olhrr(REGTMP, r, p->to.reg, p->scond); + if(p->as == AMOVB) + o2 ^= (1<<5)|(1<<6); + else if(p->as == AMOVH) + o2 ^= (1<<6); + break; + case 74: /* bx $I */ +#ifdef CALLEEBX + diag("bx $i case (arm)"); +#endif + if(!seenthumb) + diag("ABX $I and seenthumb==0"); + v = p->cond->pc; + if(p->to.sym->thumb) + v |= 1; // T bit + o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp + o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR + o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp + o4 = opbra(AB, 14); // B over o6 + o5 = v; + break; + case 75: /* bx O(R) */ + aclass(&p->to); + if(instoffset != 0) + diag("non-zero offset in ABX"); +/* + o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR + o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R +*/ + // p->to.reg may be REGLINK + o1 = oprrr(AADD, p->scond); + o1 |= immrot(instoffset); + o1 |= p->to.reg << 16; + o1 |= REGTMP << 12; + o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR + o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp + break; + case 76: /* bx O(R) when returning from fn*/ + if(!seenthumb) + diag("ABXRET and seenthumb==0"); + aclass(&p->to); +// print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg); + if(instoffset != 0) + diag("non-zero offset in ABXRET"); + // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp + o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R + break; + } + + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + lputl(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + lputl(o1); + lputl(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + lputl(o1); + lputl(o2); + lputl(o3); + break; + case 16: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, p); + lputl(o1); + lputl(o2); + lputl(o3); + lputl(o4); + break; + case 20: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, p); + lputl(o1); + lputl(o2); + lputl(o3); + lputl(o4); + lputl(o5); + break; + case 24: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, o6, p); + lputl(o1); + lputl(o2); + lputl(o3); + lputl(o4); + lputl(o5); + lputl(o6); + break; + } +} + +long +oprrr(int a, int sc) +{ + long o; + + o = (sc & C_SCOND) << 28; + if(sc & C_SBIT) + o |= 1 << 20; + if(sc & (C_PBIT|C_WBIT)) + diag(".P/.W on dp instruction"); + switch(a) { + case AMULU: + case AMUL: return o | (0x0<<21) | (0x9<<4); + case AMULA: return o | (0x1<<21) | (0x9<<4); + case AMULLU: return o | (0x4<<21) | (0x9<<4); + case AMULL: return o | (0x6<<21) | (0x9<<4); + case AMULALU: return o | (0x5<<21) | (0x9<<4); + case AMULAL: return o | (0x7<<21) | (0x9<<4); + case AAND: return o | (0x0<<21); + case AEOR: return o | (0x1<<21); + case ASUB: return o | (0x2<<21); + case ARSB: return o | (0x3<<21); + case AADD: return o | (0x4<<21); + case AADC: return o | (0x5<<21); + case ASBC: return o | (0x6<<21); + case ARSC: return o | (0x7<<21); + case ATST: return o | (0x8<<21) | (1<<20); + case ATEQ: return o | (0x9<<21) | (1<<20); + case ACMP: return o | (0xa<<21) | (1<<20); + case ACMN: return o | (0xb<<21) | (1<<20); + case AORR: return o | (0xc<<21); + case AMOVW: return o | (0xd<<21); + case ABIC: return o | (0xe<<21); + case AMVN: return o | (0xf<<21); + case ASLL: return o | (0xd<<21) | (0<<5); + case ASRL: return o | (0xd<<21) | (1<<5); + case ASRA: return o | (0xd<<21) | (2<<5); + case ASWI: return o | (0xf<<24); + + case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7); + case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8); + case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7); + case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8); + case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7); + case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8); + case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7); + case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8); + case ACMPD: + case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */ + + case AMOVF: + case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8); + case AMOVD: + case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7); + + case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4); + case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7); + case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4); + case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7); + } + diag("bad rrr %d", a); + prasm(curp); + return 0; +} + +long +opbra(int a, int sc) +{ + + if(sc & (C_SBIT|C_PBIT|C_WBIT)) + diag(".S/.P/.W on bra instruction"); + sc &= C_SCOND; + if(a == ABL) + return (sc<<28)|(0x5<<25)|(0x1<<24); + if(sc != 0xe) + diag(".COND on bcond instruction"); + switch(a) { + case ABEQ: return (0x0<<28)|(0x5<<25); + case ABNE: return (0x1<<28)|(0x5<<25); + case ABCS: return (0x2<<28)|(0x5<<25); + case ABHS: return (0x2<<28)|(0x5<<25); + case ABCC: return (0x3<<28)|(0x5<<25); + case ABLO: return (0x3<<28)|(0x5<<25); + case ABMI: return (0x4<<28)|(0x5<<25); + case ABPL: return (0x5<<28)|(0x5<<25); + case ABVS: return (0x6<<28)|(0x5<<25); + case ABVC: return (0x7<<28)|(0x5<<25); + case ABHI: return (0x8<<28)|(0x5<<25); + case ABLS: return (0x9<<28)|(0x5<<25); + case ABGE: return (0xa<<28)|(0x5<<25); + case ABLT: return (0xb<<28)|(0x5<<25); + case ABGT: return (0xc<<28)|(0x5<<25); + case ABLE: return (0xd<<28)|(0x5<<25); + case AB: return (0xe<<28)|(0x5<<25); + } + diag("bad bra %A", a); + prasm(curp); + return 0; +} + +long +olr(long v, int b, int r, int sc) +{ + long o; + + if(sc & C_SBIT) + diag(".S on LDR/STR instruction"); + o = (sc & C_SCOND) << 28; + if(!(sc & C_PBIT)) + o |= 1 << 24; + if(!(sc & C_UBIT)) + o |= 1 << 23; + if(sc & C_WBIT) + o |= 1 << 21; + o |= (0x1<<26) | (1<<20); + if(v < 0) { + v = -v; + o ^= 1 << 23; + } + if(v >= (1<<12)) + diag("literal span too large: %d (R%d)\n%P", v, b, PP); + o |= v; + o |= b << 16; + o |= r << 12; + return o; +} + +long +olhr(long v, int b, int r, int sc) +{ + long o; + + if(sc & C_SBIT) + diag(".S on LDRH/STRH instruction"); + o = (sc & C_SCOND) << 28; + if(!(sc & C_PBIT)) + o |= 1 << 24; + if(sc & C_WBIT) + o |= 1 << 21; + o |= (1<<23) | (1<<20)|(0xb<<4); + if(v < 0) { + v = -v; + o ^= 1 << 23; + } + if(v >= (1<<8)) + diag("literal span too large: %d (R%d)\n%P", v, b, PP); + o |= (v&0xf)|((v>>4)<<8)|(1<<22); + o |= b << 16; + o |= r << 12; + return o; +} + +long +osr(int a, int r, long v, int b, int sc) +{ + long o; + + o = olr(v, b, r, sc) ^ (1<<20); + if(a != AMOVW) + o |= 1<<22; + return o; +} + +long +oshr(int r, long v, int b, int sc) +{ + long o; + + o = olhr(v, b, r, sc) ^ (1<<20); + return o; +} + + +long +osrr(int r, int i, int b, int sc) +{ + + return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); +} + +long +oshrr(int r, int i, int b, int sc) +{ + return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); +} + +long +olrr(int i, int b, int r, int sc) +{ + + return olr(i, b, r, sc) ^ (1<<25); +} + +long +olhrr(int i, int b, int r, int sc) +{ + return olhr(i, b, r, sc) ^ (1<<22); +} + +long +ofsr(int a, int r, long v, int b, int sc, Prog *p) +{ + long o; + + if(sc & C_SBIT) + diag(".S on FLDR/FSTR instruction"); + o = (sc & C_SCOND) << 28; + if(!(sc & C_PBIT)) + o |= 1 << 24; + if(sc & C_WBIT) + o |= 1 << 21; + o |= (6<<25) | (1<<24) | (1<<23); + if(v < 0) { + v = -v; + o ^= 1 << 23; + } + if(v & 3) + diag("odd offset for floating point op: %d\n%P", v, p); + else if(v >= (1<<10)) + diag("literal span too large: %d\n%P", v, p); + o |= (v>>2) & 0xFF; + o |= b << 16; + o |= r << 12; + o |= 1 << 8; + + switch(a) { + default: + diag("bad fst %A", a); + case AMOVD: + o |= 1<<15; + case AMOVF: + break; + } + return o; +} + +long +omvl(Prog *p, Adr *a, int dr) +{ + long v, o1; + if(!p->cond) { + aclass(a); + v = immrot(~instoffset); + if(v == 0) { + diag("missing literal"); + prasm(p); + return 0; + } + o1 = oprrr(AMVN, p->scond&C_SCOND); + o1 |= v; + o1 |= dr << 12; + } else { + v = p->cond->pc - p->pc - 8; + o1 = olr(v, REGPC, dr, p->scond&C_SCOND); + } + return o1; +} + +static Ieee chipfloats[] = { + {0x00000000, 0x00000000}, /* 0 */ + {0x00000000, 0x3ff00000}, /* 1 */ + {0x00000000, 0x40000000}, /* 2 */ + {0x00000000, 0x40080000}, /* 3 */ + {0x00000000, 0x40100000}, /* 4 */ + {0x00000000, 0x40140000}, /* 5 */ + {0x00000000, 0x3fe00000}, /* .5 */ + {0x00000000, 0x40240000}, /* 10 */ +}; + +int +chipfloat(Ieee *e) +{ + Ieee *p; + int n; + + for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){ + p = &chipfloats[n]; + if(p->l == e->l && p->h == e->h) + return n; + } + return -1; +} diff --git a/utils/5l/l.h b/utils/5l/l.h new file mode 100644 index 00000000..a7c322be --- /dev/null +++ b/utils/5l/l.h @@ -0,0 +1,444 @@ +#include <lib9.h> +#include <bio.h> +#include "../5c/5.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +/* do not undefine this - code will be removed eventually */ +#define CALLEEBX + +typedef struct Adr Adr; +typedef struct Sym Sym; +typedef struct Autom Auto; +typedef struct Prog Prog; +typedef struct Optab Optab; +typedef struct Oprang Oprang; +typedef uchar Opcross[32][2][32]; +typedef struct Count Count; +typedef struct Use Use; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define U ((Use*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Adr +{ + union + { + long u0offset; + char* u0sval; + Ieee* u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + char type; + char reg; + char name; + char class; +}; + +#define offset u0.u0offset +#define sval u0.u0sval +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + union + { + long u0regused; + Prog* u0forwd; + } u0; + Prog* cond; + Prog* link; + long pc; + long line; + uchar mark; + uchar optab; + uchar as; + uchar scond; + uchar reg; + uchar align; +}; +#define regused u0.u0regused +#define forwd u0.u0forwd + +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + uchar subtype; + ushort file; + long value; + long sig; + uchar used; + uchar thumb; // thumb code + uchar foreign; // called by arm if thumb, by thumb if arm + uchar fnptr; // used as fn ptr + Use* use; + Sym* link; +}; + +#define SIGNINTERN (1729*325*1729) + +struct Autom +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Optab +{ + char as; + char a1; + char a2; + char a3; + char type; + char size; + char param; + char flag; +}; +struct Oprang +{ + Optab* start; + Optab* stop; +}; +struct Count +{ + long count; + long outof; +}; +struct Use +{ + Prog* p; /* use */ + Prog* ct; /* curtext */ + Use* link; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SLEAF, + SFILE, + SCONST, + SSTRING, + SUNDEF, + SREMOVED, + + SIMPORT, + SEXPORT, + + LFROM = 1<<0, + LTO = 1<<1, + LPOOL = 1<<2, + V4 = 1<<3, /* arm v4 arch */ + + C_NONE = 0, + C_REG, + C_REGREG, + C_SHIFT, + C_FREG, + C_PSR, + C_FCR, + + C_RCON, /* 0xff rotated */ + C_NCON, /* ~RCON */ + C_SCON, /* 0xffff */ + C_BCON, /* thumb */ + C_LCON, + C_FCON, + C_GCON, /* thumb */ + + C_RACON, + C_SACON, /* thumb */ + C_LACON, + C_GACON, /* thumb */ + + C_RECON, + C_LECON, + + C_SBRA, + C_LBRA, + C_GBRA, /* thumb */ + + C_HAUTO, /* halfword insn offset (-0xff to 0xff) */ + C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */ + C_HFAUTO, /* both H and F */ + C_SAUTO, /* -0xfff to 0xfff */ + C_LAUTO, + + C_HEXT, + C_FEXT, + C_HFEXT, + C_SEXT, + C_LEXT, + + C_HOREG, + C_FOREG, + C_HFOREG, + C_SOREG, + C_ROREG, + C_SROREG, /* both S and R */ + C_LOREG, + C_GOREG, /* thumb */ + + C_PC, + C_SP, + C_HREG, + C_OFFPC, /* thumb */ + + C_ADDR, /* relocatable address */ + + C_GOK, + +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + + BIG = (1<<12)-4, + STRINGSZ = 200, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + + Roffset = 22, /* no. bits for offset in relocation address */ + Rindex = 10, /* no. bits for index in relocation address */ +}; + +EXTERN union +{ + struct + { + uchar obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +#define setarch(p) if((p)->as==ATEXT) thumb=(p)->reg&ALLTHUMBS +#define setthumb(p) if((p)->as==ATEXT) seenthumb|=(p)->reg&ALLTHUMBS + +#ifndef COFFCVT + +EXTERN long HEADR; /* length of header */ +EXTERN int HEADTYPE; /* type of header */ +EXTERN long INITDAT; /* data location */ +EXTERN long INITRND; /* data round above text location */ +EXTERN long INITTEXT; /* text location */ +EXTERN char* INITENTRY; /* entry point */ +EXTERN long autosize; +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN char fnuxi4[4]; +EXTERN char fnuxi8[8]; +EXTERN char* noname; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN char literal[32]; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long instoffset; +EXTERN Opcross opcross[8]; +EXTERN Oprang oprange[ALAST]; +EXTERN Oprang thumboprange[ALAST]; +EXTERN char* outfile; +EXTERN long pc; +EXTERN uchar repop[ALAST]; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN char xcmp[C_GOK+1][C_GOK+1]; +EXTERN Prog zprg; +EXTERN int dtype; +EXTERN int armv4; +EXTERN int thumb; +EXTERN int seenthumb; +EXTERN int armsize; + +EXTERN int doexp, dlm; +EXTERN int imports, nimports; +EXTERN int exports, nexports; +EXTERN char* EXPTAB; +EXTERN Prog undefp; + +#define UP (&undefp) + +extern char* anames[]; +extern Optab optab[]; +extern Optab thumboptab[]; + +void addpool(Prog*, Adr*); +EXTERN Prog* blitrl; +EXTERN Prog* elitrl; + +void initdiv(void); +EXTERN Prog* prog_div; +EXTERN Prog* prog_divu; +EXTERN Prog* prog_mod; +EXTERN Prog* prog_modu; + +#pragma varargck type "A" int +#pragma varargck type "C" int +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* + +int Aconv(Fmt*); +int Cconv(Fmt*); +int Dconv(Fmt*); +int Nconv(Fmt*); +int Pconv(Fmt*); +int Sconv(Fmt*); +int aclass(Adr*); +int thumbaclass(Adr*, Prog*); +void addhist(long, int); +void append(Prog*, Prog*); +void asmb(void); +void asmdyn(void); +void asmlc(void); +void asmthumbmap(void); +void asmout(Prog*, Optab*); +void thumbasmout(Prog*, Optab*); +void asmsym(void); +long atolwhex(char*); +Prog* brloop(Prog*); +void buildop(void); +void thumbbuildop(void); +void buildrep(int, int); +void cflush(void); +void ckoff(Sym*, long); +int chipfloat(Ieee*); +int cmp(int, int); +int compound(Prog*); +double cputime(void); +void datblk(long, long, int); +void diag(char*, ...); +void divsig(void); +void dodata(void); +void doprof1(void); +void doprof2(void); +void dynreloc(Sym*, long, int); +long entryvalue(void); +void errorexit(void); +void exchange(Prog*); +void export(void); +int find1(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +void hputl(int); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void import(void); +int isnop(Prog*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void cput(int); +void hput(long); +void lput(long); +void lputl(long); +void mkfwd(void); +void* mysbrk(ulong); +void names(void); +void nocache(Prog*); +void nuxiinit(void); +void objfile(char*); +int ocmp(const void*, const void*); +long opirr(int); +Optab* oplook(Prog*); +long oprrr(int, int); +long olr(long, int, int, int); +long olhr(long, int, int, int); +long olrr(int, int, int, int); +long olhrr(int, int, int, int); +long osr(int, int, long, int, int); +long oshr(int, long, int, int); +long ofsr(int, int, long, int, int, Prog*); +long osrr(int, int, int, int); +long oshrr(int, int, int, int); +long omvl(Prog*, Adr*, int); +void patch(void); +void prasm(Prog*); +void prepend(Prog*, Prog*); +Prog* prg(void); +int pseudo(Prog*); +void putsymb(char*, int, long, int); +void readundefs(char*, int); +long regoff(Adr*); +int relinv(int); +long rnd(long, long); +void span(void); +void strnput(char*, int); +void undef(void); +void undefsym(Sym*); +void wput(long); +void xdefine(char*, int, long); +void xfol(Prog*); +void zerosig(char*); +void noops(void); +long immrot(ulong); +long immaddr(long); +long opbra(int, int); +int brextra(Prog*); +int isbranch(Prog*); +int fnpinc(Sym *); +int fninc(Sym *); +void thumbcount(void); +void reachable(void); +void fnptrs(void); + +#endif diff --git a/utils/5l/list.c b/utils/5l/list.c new file mode 100644 index 00000000..5d2e7b49 --- /dev/null +++ b/utils/5l/list.c @@ -0,0 +1,360 @@ +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('C', Cconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], *s; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + curp = p; + a = p->as; + switch(a) { + default: + s = str; + s += sprint(s, "(%ld)", p->line); + if(p->reg == NREG) + sprint(s, " %A%C %D,%D", + a, p->scond, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(s, " %A%C %D,R%d,%D", + a, p->scond, &p->from, p->reg, &p->to); + else + sprint(s, " %A%C %D,F%d,%D", + a, p->scond, &p->from, p->reg, &p->to); + break; + + case ASWPW: + case ASWPBU: + sprint(str, "(%ld) %A%C R%d,%D,%D", + p->line, a, p->scond, p->reg, &p->from, &p->to); + break; + + case ADATA: + case AINIT: + case ADYNT: + sprint(str, "(%ld) %A%C %D/%d,%D", + p->line, a, p->scond, &p->from, p->reg, &p->to); + break; + + case AWORD: + sprint(str, "WORD %ld", p->to.offset); + break; + + case ADWORD: + sprint(str, "DWORD %ld %ld", p->from.offset, p->to.offset); + break; + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +char* strcond[16] = +{ + ".EQ", + ".NE", + ".HS", + ".LO", + ".MI", + ".PL", + ".VS", + ".VC", + ".HI", + ".LS", + ".GE", + ".LT", + ".GT", + ".LE", + "", + ".NV" +}; + +int +Cconv(Fmt *fp) +{ + char s[20]; + int c; + + c = va_arg(fp->args, int); + strcpy(s, strcond[c & C_SCOND]); + if(c & C_SBIT) + strcat(s, ".S"); + if(c & C_PBIT) + strcat(s, ".P"); + if(c & C_WBIT) + strcat(s, ".W"); + if(c & C_UBIT) /* ambiguous with FBIT */ + strcat(s, ".U"); + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + char *op; + Adr *a; + long v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg == NREG) + sprint(str, "$%N", a); + else + sprint(str, "$%N(R%d)", a, a->reg); + break; + + case D_SHIFT: + v = a->offset; + op = "<<>>->@>" + (((v>>5) & 3) << 1); + if(v & (1<<4)) + sprint(str, "R%ld%c%cR%ld", v&15, op[0], op[1], (v>>8)&15); + else + sprint(str, "R%ld%c%c%ld", v&15, op[0], op[1], (v>>7)&31); + if(a->reg != NREG) + sprint(str+strlen(str), "(R%d)", a->reg); + break; + + case D_OCONST: + sprint(str, "$*$%N", a); + if(a->reg != NREG) + sprint(str, "%N(R%d)(CONST)", a, a->reg); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_REGREG: + sprint(str, "(R%d,R%d)", a->reg, (int)a->offset); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_PSR: + switch(a->reg) { + case 0: + sprint(str, "CPSR"); + break; + case 1: + sprint(str, "SPSR"); + break; + default: + sprint(str, "PSR%d", a->reg); + break; + } + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(PSR%d)(REG)", a, a->reg); + break; + + case D_FPCR: + switch(a->reg){ + case 0: + sprint(str, "FPSR"); + break; + case 1: + sprint(str, "FPCR"); + break; + default: + sprint(str, "FCR%d", a->reg); + break; + } + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(FCR%d)(REG)", a, a->reg); + + break; + + case D_BRANCH: /* botch */ + if(curp->cond != P) { + v = curp->cond->pc; + if(a->sym != S) + sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + else + sprint(str, "%.5lux(BRANCH)", v); + } else + if(a->sym != S) + sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + else + sprint(str, "%ld(APC)", a->offset); + break; + + case D_FCONST: + sprint(str, "$%e", ieeedtod(a->ieee)); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + if(s == S) + sprint(str, "%ld(SB)", a->offset); + else + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + if(s == S) + sprint(str, "<>+%ld(SB)", a->offset); + else + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + if(s == S) + sprint(str, "%ld(SP)", a->offset); + else + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + if(s == S) + sprint(str, "%ld(FP)", a->offset); + else + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(long); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/5l/mkfile b/utils/5l/mkfile new file mode 100644 index 00000000..4be81d08 --- /dev/null +++ b/utils/5l/mkfile @@ -0,0 +1,32 @@ +<../../mkconfig + +TARG=5l + +OFILES=\ + asm.$O\ + list.$O\ + noop.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + enam.$O\ + $TARGMODEL.$O\ + thumb.$O\ + +HFILES=\ + l.h\ + ../5c/5.out.h\ + ../include/ar.h\ + +LIBS=bio 9 # order is important + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +enam.$O: ../5c/enam.c + $CC $CFLAGS ../5c/enam.c + diff --git a/utils/5l/noop.c b/utils/5l/noop.c new file mode 100644 index 00000000..08ef6dbe --- /dev/null +++ b/utils/5l/noop.c @@ -0,0 +1,894 @@ +#include "l.h" + +static Sym* sym_div; +static Sym* sym_divu; +static Sym* sym_mod; +static Sym* sym_modu; + +static void setdiv(int); + +static Prog * +movrr(Prog *q, int rs, int rd, Prog *p) +{ + if(q == nil) + q = prg(); + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = rs; + q->to.type = D_REG; + q->to.reg = rd; + q->link = p->link; + return q; +} + +static Prog * +fnret(Prog *q, int rs, int foreign, Prog *p) +{ + q = movrr(q, rs, REGPC, p); + if(foreign){ // BX rs + q->as = ABXRET; + q->from.type = D_NONE; + q->from.reg = NREG; + q->to.reg = rs; + } + return q; +} + +static Prog * +aword(long w, Prog *p) +{ + Prog *q; + + q = prg(); + q->as = AWORD; + q->line = p->line; + q->from.type = D_NONE; + q->reg = NREG; + q->to.type = D_CONST; + q->to.offset = w; + q->link = p->link; + p->link = q; + return q; +} + +static Prog * +adword(long w1, long w2, Prog *p) +{ + Prog *q; + + q = prg(); + q->as = ADWORD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = w1; + q->reg = NREG; + q->to.type = D_CONST; + q->to.offset = w2; + q->link = p->link; + p->link = q; + return q; +} + +void +noops(void) +{ + Prog *p, *q, *q1, *q2; + int o, curframe, curbecome, maxbecome, foreign; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + + q = P; + for(p = firstp; p != P; p = p->link) { + setarch(p); + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + 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; + + p->mark |= LEAF; + 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; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + q = p; + if(prog_div == P) + initdiv(); + if(curtext != P) + curtext->mark &= ~LEAF; + setdiv(p->as); + continue; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + case ABL: + case ABX: + if(curtext != P) + curtext->mark &= ~LEAF; + + case ABCASE: + case AB: + + case ABEQ: + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + } + break; + } + q = p; + } + + 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) { + setarch(p); + switch(p->as) { + case ATEXT: + curtext = p; + break; + case ABL: + // case ABX: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + for(p = firstp; p != P; p = p->link) { + setarch(p); + o = p->as; + switch(o) { + case ATEXT: + curtext = p; + autosize = p->to.offset + 4; + if(autosize <= 4) + if(curtext->mark & LEAF) { + p->to.offset = -4; + autosize = 0; + } + + if(!autosize && !(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + Bflush(&bso); + curtext->mark |= LEAF; + } +#ifdef CALLEEBX + if(p->from.sym->foreign){ + if(thumb) + // don't allow literal pool to seperate these + p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7 + // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7 + else + p = aword(0x4778, p); // thumb bx pc and 2 bytes padding + } +#endif + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; +#ifdef optimise_time + if(autosize) { + q = prg(); + q->as = ASUB; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + break; +#else + if(!autosize) + break; +#endif + } + + if(thumb){ + if(!(curtext->mark & LEAF)){ + q = movrr(nil, REGLINK, REGTMPT-1, p); + p->link = q; + q1 = prg(); + q1->as = AMOVW; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGTMPT-1; + q1->to.type = D_OREG; + q1->to.name = D_NONE; + q1->to.reg = REGSP; + q1->to.offset = 0; + q1->link = q->link; + q->link = q1; + } + if(autosize){ + q2 = prg(); + q2->as = ASUB; + q2->line = p->line; + q2->from.type = D_CONST; + q2->from.offset = autosize; + q2->to.type = D_REG; + q2->to.reg = REGSP; + q2->link = p->link; + p->link = q2; + } + break; + } + + q1 = prg(); + q1->as = AMOVW; + q1->scond |= C_WBIT; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->to.offset = -autosize; + q1->to.reg = REGSP; + q1->link = p->link; + p->link = q1; + break; + + case ARET: + nocache(p); + foreign = seenthumb && curtext->from.sym != S && (curtext->from.sym->foreign || curtext->from.sym->fnptr); +// print("%s %d %d\n", curtext->from.sym->name, curtext->from.sym->foreign, curtext->from.sym->fnptr); + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + if(thumb){ + p = fnret(p, REGLINK, foreign, p); + break; + } +// if(foreign) print("ABXRET 1 %s\n", curtext->from.sym->name); + p->as = foreign ? ABXRET : AB; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + break; + } + +#ifdef optimise_time + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + if(thumb){ + p->link = fnret(nil, REGLINK, foreign, p); + break; + } + q = prg(); +// if(foreign) print("ABXRET 2 %s\n", curtext->from.sym->name); + q->as = foreign ? ABXRET : AB; + q->scond = p->scond; + q->line = p->line; + q->to.type = D_OREG; + q->to.offset = 0; + q->to.reg = REGLINK; + + q->link = p->link; + p->link = q; + + break; +#endif + } + if(thumb){ + if(curtext->mark & LEAF){ + if(autosize){ + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + q = nil; + } + else + q = p; + q = fnret(q, REGLINK, foreign, p); + if(q != p) + p->link = q; + } + else{ + p->as = AMOVW; + p->from.type = D_OREG; + p->from.name = D_NONE; + p->from.reg = REGSP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + if(autosize){ + q = prg(); + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + } + else + q = p; + q1 = fnret(nil, REGTMPT-1, foreign, p); + q1->link = q->link; + q->link = q1; + } + break; + } + if(foreign) { +// if(foreign) print("ABXRET 3 %s\n", curtext->from.sym->name); +#define R 1 + p->as = AMOVW; + p->from.type = D_OREG; + p->from.name = D_NONE; + p->from.reg = REGSP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = R; + q = prg(); + q->as = AADD; + q->scond = p->scond; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + q1 = prg(); + q1->as = ABXRET; + q1->scond = p->scond; + q1->line = p->line; + q1->to.type = D_OREG; + q1->to.offset = 0; + q1->to.reg = R; + q1->link = q->link; + q->link = q1; +#undef R + } + else { + p->as = AMOVW; + p->scond |= C_PBIT; + p->from.type = D_OREG; + p->from.offset = autosize; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGPC; + } + break; + + become: + if(foreign){ + diag("foreign become - help"); + break; + } + if(thumb){ + diag("thumb become - help"); + break; + } + print("arm become\n"); + if(curtext->mark & LEAF) { + + if(!autosize) { + p->as = AB; + p->from = zprg.from; + break; + } + +#ifdef optimise_time + q = prg(); + q->scond = p->scond; + q->line = p->line; + q->as = AB; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; +#endif + } + q = prg(); + q->scond = p->scond; + q->line = p->line; + q->as = AB; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + p->link = q; + if(thumb){ + q1 = prg(); + q1->line = p->line; + q1->as = AADD; + q1->from.type = D_CONST; + q1->from.offset = autosize; + q1->to.type = D_REG; + q1->to.reg = REGSP; + p->as = AMOVW; + p->line = p->line; + p->from.type = D_OREG; + p->from.name = D_NONE; + p->from.reg = REGSP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + q1->link = q; + p->link = q1; + q2 = movrr(nil, REGTMPT-1, REGLINK, p); + q2->link = q; + q1->link = q2; + break; + } + p->as = AMOVW; + p->scond |= C_PBIT; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = autosize; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGLINK; + + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + if(debug['M']) + break; + if(p->from.type != D_REG) + break; + if(p->to.type != D_REG) + break; + q1 = p; + + /* MOV a,4(SP) */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->from.reg; + p->to.type = D_OREG; + p->to.reg = REGSP; + p->to.offset = 4; + + /* MOV b,REGTMP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->reg; + if(q1->reg == NREG) + p->from.reg = q1->to.reg; + p->to.type = D_REG; + p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP; + p->to.offset = 0; + + /* CALL appropriate */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + +#ifdef CALLEEBX + p->as = ABL; +#else + if(prog_div != UP && prog_div->from.sym->thumb) + p->as = thumb ? ABL : ABX; + else + p->as = thumb ? ABX : ABL; +#endif + p->line = q1->line; + p->to.type = D_BRANCH; + p->cond = p; + switch(o) { + case ADIV: + p->cond = prog_div; + p->to.sym = sym_div; + break; + case ADIVU: + p->cond = prog_divu; + p->to.sym = sym_divu; + break; + case AMOD: + p->cond = prog_mod; + p->to.sym = sym_mod; + break; + case AMODU: + p->cond = prog_modu; + p->to.sym = sym_modu; + break; + } + + /* MOV REGTMP, b */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = q1->to.reg; + + /* ADD $8,SP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AADD; + p->from.type = D_CONST; + p->from.reg = NREG; + p->from.offset = 8; + p->reg = NREG; + p->to.type = D_REG; + p->to.reg = REGSP; + + /* SUB $8,SP */ + q1->as = ASUB; + q1->from.type = D_CONST; + q1->from.offset = 8; + q1->from.reg = NREG; + q1->reg = NREG; + q1->to.type = D_REG; + q1->to.reg = REGSP; + + break; + case AMOVW: + if(thumb){ + Adr *a = &p->from; + + if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3)) + diag("SP offset not multiple of 4"); + } + break; + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + if(thumb){ + if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){ + q = prg(); + *q = *p; + if(p->from.name == D_AUTO) + q->from.offset += autosize; + else if(p->from.name == D_PARAM) + q->from.offset += autosize+4; + q->from.name = D_NONE; + q->from.reg = REGTMPT; + p = movrr(p, REGSP, REGTMPT, p); + q->link = p->link; + p->link = q; + } + if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){ + q = prg(); + *q = *p; + if(p->to.name == D_AUTO) + q->to.offset += autosize; + else if(p->to.name == D_PARAM) + q->to.offset += autosize+4; + q->to.name = D_NONE; + q->to.reg = REGTMPT; + p = movrr(p, REGSP, REGTMPT, p); + q->link = p->link; + p->link = q; + if(q->to.offset < 0 || q->to.offset > 255){ // complicated + p->to.reg = REGTMPT+1; // mov sp, r8 + q1 = prg(); + q1->line = p->line; + q1->as = AMOVW; + q1->from.type = D_CONST; + q1->from.offset = q->to.offset; + q1->to.type = D_REG; + q1->to.reg = REGTMPT; // mov $o, r7 + p->link = q1; + q1->link = q; + q1 = prg(); + q1->line = p->line; + q1->as = AADD; + q1->from.type = D_REG; + q1->from.reg = REGTMPT+1; + q1->to.type = D_REG; + q1->to.reg = REGTMPT; // add r8, r7 + p->link->link = q1; + q1->link = q; + q->to.offset = 0; // mov* r, 0(r7) + /* phew */ + } + } + } + break; + case AMOVM: + if(thumb){ + if(p->from.type == D_OREG){ + if(p->from.offset == 0) + p->from.type = D_REG; + else + diag("non-zero AMOVM offset"); + } + else if(p->to.type == D_OREG){ + if(p->to.offset == 0) + p->to.type = D_REG; + else + diag("non-zero AMOVM offset"); + } + } + break; + case AB: + if(thumb && p->to.type == D_OREG){ + if(p->to.offset == 0){ + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = p->to.reg; + p->to.type = D_REG; + p->to.reg = REGPC; + } + else{ + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = p->to.offset; + p->reg = p->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + q = prg(); + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGTMPT-1; + q->to.type = D_REG; + q->to.reg = REGPC; + q->link = p->link; + p->link = q; + } + } + if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){ + // print("warn %s: b (R%d) assuming a return\n", curtext->from.sym->name, p->to.reg); + p->as = ABXRET; + } + break; + case ABL: + case ABX: + if(thumb && p->to.type == D_OREG){ + if(p->to.offset == 0){ + p->as = o; + p->from.type = D_NONE; + p->to.type = D_REG; + } + else{ + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = p->to.offset; + p->reg = p->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + q = prg(); + q->as = o; + q->line = p->line; + q->from.type = D_NONE; + q->to.type = D_REG; + q->to.reg = REGTMPT-1; + q->link = p->link; + p->link = q; + } + } + break; + } + } +} + +static void +sigdiv(char *n) +{ + Sym *s; + + s = lookup(n, 0); + if(s->type == STEXT){ + if(s->sig == 0) + s->sig = SIGNINTERN; + } + else if(s->type == 0 || s->type == SXREF) + s->type = SUNDEF; +} + +void +divsig(void) +{ + sigdiv("_div"); + sigdiv("_divu"); + sigdiv("_mod"); + sigdiv("_modu"); +} + +static void +sdiv(Sym *s) +{ + if(s->type == 0 || s->type == SXREF){ + /* undefsym(s); */ + s->type = SXREF; + if(s->sig == 0) + s->sig = SIGNINTERN; + s->subtype = SIMPORT; + } + else if(s->type != STEXT) + diag("undefined: %s", s->name); +} + +void +initdiv(void) +{ + Sym *s2, *s3, *s4, *s5; + Prog *p; + + if(prog_div != P) + return; + sym_div = s2 = lookup("_div", 0); + sym_divu = s3 = lookup("_divu", 0); + sym_mod = s4 = lookup("_mod", 0); + sym_modu = s5 = lookup("_modu", 0); + if(dlm) { + sdiv(s2); if(s2->type == SXREF) prog_div = UP; + sdiv(s3); if(s3->type == SXREF) prog_divu = UP; + sdiv(s4); if(s4->type == SXREF) prog_mod = UP; + sdiv(s5); if(s5->type == SXREF) prog_modu = UP; + } + for(p = firstp; p != P; p = p->link) + if(p->as == ATEXT) { + if(p->from.sym == s2) + prog_div = p; + if(p->from.sym == s3) + prog_divu = p; + if(p->from.sym == s4) + prog_mod = p; + if(p->from.sym == s5) + prog_modu = p; + } + if(prog_div == P) { + diag("undefined: %s", s2->name); + prog_div = curtext; + } + if(prog_divu == P) { + diag("undefined: %s", s3->name); + prog_divu = curtext; + } + if(prog_mod == P) { + diag("undefined: %s", s4->name); + prog_mod = curtext; + } + if(prog_modu == P) { + diag("undefined: %s", s5->name); + prog_modu = curtext; + } +} + +static void +setdiv(int as) +{ + Prog *p = nil; + + switch(as){ + case ADIV: p = prog_div; break; + case ADIVU: p = prog_divu; break; + case AMOD: p = prog_mod; break; + case AMODU: p = prog_modu; break; + } + if(p != UP && thumb != p->from.sym->thumb) + p->from.sym->foreign = 1; +} + +void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} diff --git a/utils/5l/obj.c b/utils/5l/obj.c new file mode 100644 index 00000000..f70f7356 --- /dev/null +++ b/utils/5l/obj.c @@ -0,0 +1,1557 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = '5'; +char *thestring = "arm"; + +/* + * -H1 -T0x10005000 -R4 is aif for risc os + * -H2 -T4128 -R4096 is plan9 format + * -H3 -T0xF0000020 -R4 is NetBSD format + * -H4 is IXP1200 (raw) + * -H5 -T0xC0008010 -R1024 is ipaq + */ + +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 c; + char *a; + + Binit(&bso, 1, OWRITE); + srand(time(0)); + cout = -1; + listinit(); + outfile = 0; + nerrors = 0; + curtext = P; + 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': + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = 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 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + /* do something about setting INITTEXT */ + 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: 5l [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 0; + if(debug['B']) + HEADTYPE = 1; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + case 0: /* no header */ + HEADR = 0L; + if(INITTEXT == -1) + INITTEXT = 0; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 1: /* aif for risc os */ + HEADR = 128L; + if(INITTEXT == -1) + INITTEXT = 0x10005000 + HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* boot for NetBSD */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 0xF0000020L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 4: /* boot for IXP1200 */ + HEADR = 0L; + if(INITTEXT == -1) + INITTEXT = 0x0; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 5: /* boot for ipaq */ + HEADR = 16L; + if(INITTEXT == -1) + INITTEXT = 0xC0008010; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 1024; + 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%d -T0x%lux -D0x%lux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + zprg.as = AGOK; + zprg.scond = 14; + zprg.reg = NREG; + zprg.from.name = D_NONE; + zprg.from.type = D_NONE; + zprg.from.reg = NREG; + zprg.to = zprg.from; + buildop(); + thumbbuildop(); // could build on demand + histgen = 0; + textp = P; + datap = P; + pc = 0; + dtype = 4; + if(outfile == 0) + outfile = "5.out"; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("%s: cannot create", outfile); + errorexit(); + } + nuxiinit(); + + 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) + goto out; + if(doexp || dlm){ + EXPTAB = "_exporttab"; + zerosig(EXPTAB); + zerosig("etext"); + zerosig("edata"); + zerosig("end"); + if(dlm){ + initdiv(); + import(); + HEADTYPE = 2; + INITTEXT = INITDAT = 0; + INITRND = 8; + INITENTRY = EXPTAB; + } + else + divsig(); + export(); + } + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + if(debug['u']) + reachable(); + dodata(); + if(seenthumb && debug['f']) + fnptrs(); + follow(); + if(firstp == P) + goto out; + noops(); + span(); + asmb(); + undef(); + +out: + if(debug['c']){ + thumbcount(); + print("ARM size = %d\n", armsize); + } + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + 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) +{ + + Bflush(&bso); + 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; + } + + if(debug['v']) + Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file); + 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 i, c; + long l; + Sym *s; + Auto *u; + + c = p[2]; + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + p[0] = ALAST+1; + return 0; + } + a->type = p[0]; + a->reg = p[1]; + a->sym = h[c]; + a->name = p[3]; + c = 4; + + if(a->reg < 0 || a->reg > NREG) { + print("register out of range %d\n", a->reg); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + } + + if(a->type == D_CONST || a->type == D_OCONST) { + if(a->name == D_EXTERN || a->name == D_STATIC) { + s = a->sym; + if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) { + if(0 && !s->fnptr && s->name[0] != '.') + print("%s used as function pointer\n", s->name); + s->fnptr = 1; // over the top cos of SXREF + } + } + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + case D_FPCR: + break; + + case D_REGREG: + a->offset = p[4]; + c++; + break; + + case D_BRANCH: + case D_OREG: + case D_CONST: + case D_OCONST: + case D_SHIFT: + a->offset = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + c += 4; + break; + + case D_SCONST: + while(nhunk < NSNAME) + gethunk(); + a->sval = (char*)hunk; + nhunk -= NSNAME; + hunk += NSNAME; + + memmove(a->sval, p+4, NSNAME); + c += NSNAME; + break; + + case D_FCONST: + while(nhunk < sizeof(Ieee)) + gethunk(); + a->ieee = (Ieee*)hunk; + nhunk -= NSNAME; + hunk += NSNAME; + + a->ieee->l = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + a->ieee->h = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + } + s = a->sym; + if(s == S) + return c; + i = a->name; + if(i != D_AUTO && i != D_PARAM) + return c; + + l = a->offset; + for(u=curauto; u; u=u->link) + if(u->asym == s) + if(u->type == i) { + 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 = i; + 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; +} + +static void puntfp(Prog *); + +void +ldobj(int f, long c, char *pn) +{ + long ipc; + Prog *p, *t; + uchar *bloc, *bsize, *stop; + Sym *h[NSYM], *s, *di; + int v, o, r, skip; + 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]; /* as */ + if(o <= AXXX || o >= ALAST) { + diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o); + print(" probably not a .5 file\n"); + errorexit(); + } + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME){ + sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24); + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[1]; /* type */ + o = bloc[2]; /* sym */ + bloc += 3; + c -= 3; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 1; + + 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; + } + + if(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->scond = bloc[1]; + p->reg = bloc[2]; + p->line = bloc[3] | (bloc[4]<<8) | (bloc[5]<<16) | (bloc[6]<<24); + + r = zaddr(bloc+7, &p->from, h) + 7; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(p->reg < 0 || p->reg > NREG) + diag("register out of range %d", p->reg); + + p->link = P; + p->cond = P; + + if(debug['W']) + print("%P\n", p); + + switch(o) { + 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 == S) { + diag("GLOBL must have a name\n%P", p); + errorexit(); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("redefinition: %s\n%P", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + break; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->reg = 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_CONST; + p->link = datap; + datap = p; + break; + + 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; + p->link = datap; + datap = p; + break; + + case ADATA: + if(p->from.sym == S) { + diag("DATA without a sym\n%P", p); + break; + } + p->link = datap; + datap = p; + break; + + case AGOK: + diag("unknown opcode\n%P", p); + p->pc = pc; + pc++; + break; + + case ATEXT: + setarch(p); + setthumb(p); + p->align = 4; + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + autosize = (p->to.offset+3L) & ~3L; + p->to.offset = autosize; + autosize += 4; + s = p->from.sym; + if(s == S) { + diag("TEXT must have a name\n%P", p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->reg & DUPOK) { + skip = 1; + goto casedef; + } + diag("redefinition: %s\n%P", s->name, p); + } + s->type = STEXT; + s->value = pc; + s->thumb = thumb; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + if(textp == P) { + textp = p; + etextp = p; + goto loop; + } + etextp->cond = p; + etextp = p; + break; + + case ASUB: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) + if(p->from.offset < 0) { + p->from.offset = -p->from.offset; + p->as = AADD; + } + goto casedef; + + case AADD: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) + if(p->from.offset < 0) { + p->from.offset = -p->from.offset; + p->as = ASUB; + } + goto casedef; + + case AMOVWD: + case AMOVWF: + case AMOVDW: + case AMOVFW: + case AMOVFD: + case AMOVDF: + // case AMOVF: + // case AMOVD: + case ACMPF: + case ACMPD: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + if(thumb) + puntfp(p); + goto casedef; + + case AMOVF: + if(thumb) + puntfp(p); + if(skip) + goto casedef; + + if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) { + /* 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 4; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AMOVD: + if(thumb) + puntfp(p); + if(skip) + goto casedef; + + if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) { + /* 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + default: + casedef: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + 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); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + s->sig = 0; + s->used = s->thumb = s->foreign = s->fnptr = 0; + s->use = nil; + hash[h] = s; + 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; +} + +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) { + setarch(p); + if(p->as == ATEXT) { + q = prg(); + q->line = p->line; + q->link = datap; + datap = q; + q->as = ADATA; + q->from.type = D_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 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 = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = thumb ? REGTMPT : REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = thumb ? REGTMPT : REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = thumb ? REGTMPT : REGTMP; + p->to.type = D_OREG; + p->to.name = 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_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 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) { + setarch(p); + if(p->as == ATEXT) { + if(p->from.sym == s2) { + ps2 = p; + p->reg = 1; + } + if(p->from.sym == s4) { + ps4 = p; + p->reg = 1; + } + } + } + for(p = firstp; p != P; p = p->link) { + setarch(p); + if(p->as == ATEXT) { + if(p->reg & NOPROF) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * BL profin, R2 + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ABL; + p->to.type = D_BRANCH; + p->cond = 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; + + /* + * BL profout + */ + p->as = ABL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = 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; + if(debug['d']){ + fnuxi8[i] = c; + fnuxi8[i+4] = c+4; + } + else{ + fnuxi8[i] = c+4; /* ms word first, then ls, even in little endian mode */ + fnuxi8[i+4] = c; + } + } + 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); +} + +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; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->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 |= ieeep->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); +} + +static void +puntfp(Prog *p) +{ + USED(p); + /* floating point - punt for now */ + curtext->reg = NREG; /* ARM */ + curtext->from.sym->thumb = 0; + thumb = 0; + // print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line); +} + +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); +} diff --git a/utils/5l/optab.c b/utils/5l/optab.c new file mode 100644 index 00000000..65ad3447 --- /dev/null +++ b/utils/5l/optab.c @@ -0,0 +1,253 @@ +#include "l.h" + +Optab optab[] = +{ + { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, + + { AADD, C_REG, C_REG, C_REG, 1, 4, 0 }, + { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 }, + + { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 }, + { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 }, + { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 }, + { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 }, + { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 }, + + { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 }, + { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, + { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, + { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, + + { AMOVW, C_RECON,C_NONE, C_REG, 4, 4, REGSB }, + { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, + + { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, + { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, + { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, + { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, + + { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, + { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 }, + { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, + { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, + + { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, + { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, + + { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, + { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, + + { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, + { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, + + { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_LEXT, 11, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, + + { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, + { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM }, + + { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 }, + { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 }, + { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 }, + { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 }, + { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM }, + { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, + { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, + { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM }, + + { AMOVB, C_REG, C_NONE, C_REG, 14, 8, 0 }, + { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 }, + { AMOVH, C_REG, C_NONE, C_REG, 14, 8, 0 }, + { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 }, + + { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 }, + { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 }, + + { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 }, + { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 }, + + { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_SEXT, 20, 4, REGSB }, + { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_SEXT, 20, 4, REGSB }, + { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_SEXT, 20, 4, REGSB }, + { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, + { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, + + { AMOVW, C_SEXT, C_NONE, C_REG, 21, 4, REGSB }, + { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, + { AMOVBU, C_SEXT, C_NONE, C_REG, 21, 4, REGSB }, + { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, + { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, + + { AMOVB, C_SEXT, C_NONE, C_REG, 22, 12, REGSB }, + { AMOVB, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP }, + { AMOVB, C_SOREG,C_NONE, C_REG, 22, 12, 0 }, + { AMOVH, C_SEXT, C_NONE, C_REG, 22, 12, REGSB }, + { AMOVH, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP }, + { AMOVH, C_SOREG,C_NONE, C_REG, 22, 12, 0 }, + { AMOVHU, C_SEXT, C_NONE, C_REG, 22, 12, REGSB }, + { AMOVHU, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP }, + { AMOVHU, C_SOREG,C_NONE, C_REG, 22, 12, 0 }, + + { AMOVH, C_REG, C_NONE, C_SEXT, 23, 12, REGSB }, + { AMOVH, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP }, + { AMOVH, C_REG, C_NONE, C_SOREG, 23, 12, 0 }, + { AMOVHU, C_REG, C_NONE, C_SEXT, 23, 12, REGSB }, + { AMOVHU, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP }, + { AMOVHU, C_REG, C_NONE, C_SOREG, 23, 12, 0 }, + + { AMOVW, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO }, + { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO }, + { AMOVB, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO }, + { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO }, + { AMOVBU, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO }, + { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, + { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, + { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO }, + + { AMOVW, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM }, + { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, + { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, + { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM }, + { AMOVBU, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM }, + { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, + { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, + { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM }, + + { AMOVB, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM }, + { AMOVB, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM }, + { AMOVB, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM }, + { AMOVB, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM }, + { AMOVH, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM }, + { AMOVH, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM }, + { AMOVH, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM }, + { AMOVH, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM }, + { AMOVHU, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM }, + { AMOVHU, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM }, + { AMOVHU, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM }, + { AMOVHU, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM }, + + { AMOVH, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO }, + { AMOVH, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO }, + { AMOVH, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO }, + { AMOVH, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO }, + { AMOVHU, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO }, + { AMOVHU, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO }, + + { AMOVW, C_LECON,C_NONE, C_REG, 34, 8, REGSB, LFROM }, + { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, + + { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 }, + { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 }, + + { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 }, + { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 }, + + { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 }, + + { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, + + { AMOVF, C_FREG, C_NONE, C_FEXT, 50, 4, REGSB }, + { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, + { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, + + { AMOVF, C_FEXT, C_NONE, C_FREG, 51, 4, REGSB }, + { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP }, + { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 }, + + { AMOVF, C_FREG, C_NONE, C_LEXT, 52, 12, REGSB, LTO }, + { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO }, + { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, + + { AMOVF, C_LEXT, C_NONE, C_FREG, 53, 12, REGSB, LFROM }, + { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, + { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, + + { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO }, + { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM }, + + { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, + { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, + { AADDF, C_FCON, C_NONE, C_FREG, 54, 4, 0 }, + { AADDF, C_FCON, C_REG, C_FREG, 54, 4, 0 }, + { AMOVF, C_FCON, C_NONE, C_FREG, 54, 4, 0 }, + { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, + + { ACMPF, C_FREG, C_REG, C_NONE, 54, 4, 0 }, + { ACMPF, C_FCON, C_REG, C_NONE, 54, 4, 0 }, + + { AMOVFW, C_FREG, C_NONE, C_REG, 55, 4, 0 }, + { AMOVFW, C_REG, C_NONE, C_FREG, 55, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, + { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, + + { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, + { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, + + { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, + + { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 }, + { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 }, + + { AMOVH, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 }, + { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 }, + { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 }, + { AMOVHU, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 }, + { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 }, + { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 }, + + { AMOVB, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 }, + { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 }, + { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 }, + { AMOVH, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 }, + { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 }, + { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 }, + { AMOVHU, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 }, + { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 }, + { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 }, + + { AMOVH, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 }, + { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 }, + { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 }, + { AMOVHU, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 }, + { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 }, + { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 }, + + { AMOVB, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 }, + { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 }, + { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 }, + { AMOVH, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 }, + { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 }, + { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 }, + { AMOVHU, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 }, + { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 }, + { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 }, + + { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, +}; diff --git a/utils/5l/pass.c b/utils/5l/pass.c new file mode 100644 index 00000000..e4322df5 --- /dev/null +++ b/utils/5l/pass.c @@ -0,0 +1,942 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p; + long orig, v; + + 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); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%ld): %s\n%P", + s->value, s->name, p); + if((s->type == SBSS || s->type == SDATA) && (p->to.type == D_CONST || p->to.type == D_OCONST) && (p->to.name == D_EXTERN || p->to.name == D_STATIC)){ + s = p->to.sym; + if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) + s->fnptr = 1; + } + } + + if(debug['t']) { + /* + * pull out string constants + */ + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->to.type == D_SCONST) + s->type = SSTRING; + } + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rational is that data segment is more easily + * addressed through offset on R12) + */ + orig = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + while(v & 3) + v++; + s->value = v; + if(v > MINSIZ) + continue; + s->value = orig; + orig += v; + s->type = SDATA1; + } + + /* + * pass 2 + * assign large 'data' variables to data segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + s->value = orig; + orig += v; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + v = s->value; + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + xdefine("setR12", SDATA, 0L+BIG); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +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); +} + +Prog* +brchain(Prog *p) +{ + int i; + + for(i=0; i<20; i++) { + if(p == P || p->as != AB) + return p; + p = p->cond; + } + return P; +} + +int +relinv(int a) +{ + switch(a) { + case ABEQ: return ABNE; + case ABNE: return ABEQ; + case ABCS: return ABCC; + case ABHS: return ABLO; + case ABCC: return ABCS; + case ABLO: return ABHS; + case ABMI: return ABPL; + case ABPL: return ABMI; + case ABVS: return ABVC; + case ABVC: return ABVS; + case ABHI: return ABLS; + case ABLS: return ABHI; + case ABGE: return ABLT; + case ABLT: return ABGE; + case ABGT: return ABLE; + case ABLE: return ABGT; + } + diag("unknown relation: %s", anames[a]); + return a; +} + +void +follow(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, i; + +loop: + if(p == P) + return; + setarch(p); + a = p->as; + if(a == ATEXT) + curtext = p; + if(a == AB) { + q = p->cond; + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == AB || (a == ARET && q->scond == 14) || a == ARFE) + goto copy; + if(!q->cond || (q->cond->mark&FOLL)) + continue; + if(a != ABEQ && a != ABNE) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(a == AB || (a == ARET && q->scond == 14) || a == ARFE) + return; + r->as = ABNE; + if(a == ABNE) + r->as = ABEQ; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + a = AB; + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){ + return; + } + if(p->cond != P) + if(a != ABL && a != ABX && p->link != P) { + q = brchain(p->link); + if(a != ATEXT && a != ABCASE) + if(q != P && (q->mark&FOLL)) { + p->as = relinv(a); + p->link = p->cond; + p->cond = q; + } + xfol(p->link); + q = brchain(p->cond); + if(q == P) + q = p->cond; + if(q->mark&FOLL) { + p->cond = q; + return; + } + p = q; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s, *s1; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + setarch(p); + a = p->as; + if(a == ATEXT) + curtext = p; + if(seenthumb && a == ABL){ + // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S) + // print("%s calls %s\n", s1->name, s->name); + if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S && s->thumb != s1->thumb) + s->foreign = 1; + } + if((a == ABL || a == ABX || a == AB || a == ARET) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + switch(s->type) { + default: + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + break; + case STEXT: + p->to.offset = s->value; + p->to.type = D_BRANCH; + break; + case SUNDEF: + if(p->as != ABL) + diag("help: SUNDEF in AB || ARET"); + p->to.offset = 0; + p->to.type = D_BRANCH; + p->cond = UP; + break; + } + } + if(p->to.type != D_BRANCH || p->cond == 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 %ld\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + setarch(p); + a = p->as; + if(p->as == ATEXT) + curtext = p; + if(seenthumb && a == ABL) { +#ifdef CALLEEBX + if(0) + {} +#else + if((s = p->to.sym) != S && (s->foreign || s->fnptr)) + p->as = ABX; +#endif + else if(p->to.type == D_OREG) + p->as = ABX; + } + if(p->cond != P && p->cond != UP) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + 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) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(p->as != AB) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +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; +} + +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; +} + +#define Reachable(n) if((s = lookup(n, 0)) != nil) s->used++ + +static void +rused(Adr *a) +{ + Sym *s = a->sym; + + if(s == S) + return; + if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){ + if(a->name == D_EXTERN || a->name == D_STATIC){ + if(s->used == 0) + s->used = 1; + } + } + else if(a->type == D_BRANCH){ + if(s->used == 0) + s->used = 1; + } +} + +void +reachable() +{ + Prog *p, *prev, *prevt, *nextt, *q; + Sym *s, *s0; + int i, todo; + char *a; + + Reachable("_div"); + Reachable("_divu"); + Reachable("_mod"); + Reachable("_modu"); + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return; + s = lookup(a, 0); + if(s == nil) + return; + if(s->type == 0){ + s->used = 1; // to stop asm complaining + for(p = firstp; p != P && p->as != ATEXT; p = p->link) + ; + if(p == nil) + return; + s = p->from.sym; + } + s->used = 1; + do{ + todo = 0; + for(p = firstp; p != P; p = p->link){ + if(p->as == ATEXT && (s0 = p->from.sym)->used == 1){ + todo = 1; + for(q = p->link; q != P && q->as != ATEXT; q = q->link){ + rused(&q->from); + rused(&q->to); + } + s0->used = 2; + } + } + for(p = datap; p != P; p = p->link){ + if((s0 = p->from.sym)->used == 1){ + todo = 1; + for(q = p; q != P; q = q->link){ // data can be scattered + if(q->from.sym == s0) + rused(&q->to); + } + s0->used = 2; + } + } + }while(todo); + prev = nil; + prevt = nextt = nil; + for(p = firstp; p != P; ){ + if(p->as == ATEXT){ + prevt = nextt; + nextt = p; + } + if(p->as == ATEXT && (s0 = p->from.sym)->used == 0){ + s0->type = SREMOVED; + for(q = p->link; q != P && q->as != ATEXT; q = q->link) + ; + if(q != p->cond) + diag("bad ptr in reachable()"); + if(prev == nil) + firstp = q; + else + prev->link = q; + if(q == nil) + lastp = prev; + if(prevt == nil) + textp = q; + else + prevt->cond = q; + if(q == nil) + etextp = prevt; + nextt = prevt; + if(debug['V']) + print("%s unused\n", s0->name); + p = q; + } + else{ + prev = p; + p = p->link; + } + } + prevt = nil; + for(p = datap; p != nil; ){ + if((s0 = p->from.sym)->used == 0){ + s0->type = SREMOVED; + prev = prevt; + for(q = p; q != nil; q = q->link){ + if(q->from.sym == s0){ + if(prev == nil) + datap = q->link; + else + prev->link = q->link; + } + else + prev = q; + } + if(debug['V']) + print("%s unused (data)\n", s0->name); + p = prevt->link; + } + else{ + prevt = p; + p = p->link; + } + } + for(i=0; i<NHASH; i++){ + for(s = hash[i]; s != S; s = s->link){ + if(s->used == 0) + s->type = SREMOVED; + } + } +} + +static void +fused(Adr *a, Prog *p, Prog *ct) +{ + Sym *s = a->sym; + Use *u; + + if(s == S) + return; + if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){ + if(a->name == D_EXTERN || a->name == D_STATIC){ + u = malloc(sizeof(Use)); + u->p = p; + u->ct = ct; + u->link = s->use; + s->use = u; + } + } + else if(a->type == D_BRANCH){ + u = malloc(sizeof(Use)); + u->p = p; + u->ct = ct; + u->link = s->use; + s->use = u; + } +} + +static int +ckfpuse(Prog *p, Prog *ct, Sym *fp, Sym *r) +{ + int reg; + + USED(fp); + USED(ct); + if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){ + reg = p->to.reg; + for(p = p->link; p != P && p->as != ATEXT; p = p->link){ + if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg) + return 1; + if(!debug['F'] && (isbranch(p) || p->as == ARET)){ + // print("%s: branch %P in %s\n", fp->name, p, ct->from.sym->name); + return 0; + } + if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){ + if(!debug['F'] && p->to.type != D_REG){ + // print("%s: store %P in %s\n", fp->name, p, ct->from.sym->name); + return 0; + } + reg = p->to.reg; + } + } + } + // print("%s: no MOVW O(R), R\n", fp->name); + return debug['F']; +} + +static void +setfpuse(Prog *p, Sym *fp, Sym *r) +{ + int reg; + + if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){ + reg = p->to.reg; + for(p = p->link; p != P && p->as != ATEXT; p = p->link){ + if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg){ + fp->fnptr = 0; + p->as = ABL; // safe to do so +// print("simplified %s call\n", fp->name); + break; + } + if(!debug['F'] && (isbranch(p) || p->as == ARET)) + diag("bad setfpuse call"); + if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){ + if(!debug['F'] && p->to.type != D_REG) + diag("bad setfpuse call"); + reg = p->to.reg; + } + } + } +} + +static int +cksymuse(Sym *s, int t) +{ + Prog *p; + + for(p = datap; p != P; p = p->link){ + if(p->from.sym == s && p->to.sym != nil && strcmp(p->to.sym->name, ".string") != 0 && p->to.sym->thumb != t){ + // print("%s %s %d %d ", p->from.sym->name, p->to.sym->name, p->to.sym->thumb, t); + return 0; + } + } + return 1; +} + +/* check the use of s at the given point */ +static int +ckuse(Sym *s, Sym *s0, Use *u) +{ + Sym *s1; + + s1 = u->p->from.sym; +// print("ckuse %s %s %s\n", s->name, s0->name, s1 ? s1->name : "nil"); + if(u->ct == nil){ /* in data area */ + if(s0 == s && !cksymuse(s1, s0->thumb)){ + // print("%s: cksymuse fails\n", s0->name); + return 0; + } + for(u = s1->use; u != U; u = u->link) + if(!ckuse(s1, s0, u)) + return 0; + } + else{ /* in text area */ + if(u->ct->from.sym->thumb != s0->thumb){ + // print("%s(%d): foreign call %s(%d)\n", s0->name, s0->thumb, u->ct->from.sym->name, u->ct->from.sym->thumb); + return 0; + } + return ckfpuse(u->p, u->ct, s0, s); + } + return 1; +} + +static void +setuse(Sym *s, Sym *s0, Use *u) +{ + Sym *s1; + + s1 = u->p->from.sym; + if(u->ct == nil){ /* in data area */ + for(u = s1->use; u != U; u = u->link) + setuse(s1, s0, u); + } + else{ /* in text area */ + setfpuse(u->p, s0, s); + } +} + +/* detect BX O(R) which can be done as BL O(R) */ +void +fnptrs() +{ + int i; + Sym *s; + Prog *p; + Use *u; + + for(i=0; i<NHASH; i++){ + for(s = hash[i]; s != S; s = s->link){ + if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){ + // print("%s : fnptr %d %d\n", s->name, s->thumb, s->foreign); + } + } + } + /* record use of syms */ + for(p = firstp; p != P; p = p->link){ + if(p->as == ATEXT) + curtext = p; + else{ + fused(&p->from, p, curtext); + fused(&p->to, p, curtext); + } + } + for(p = datap; p != P; p = p->link) + fused(&p->to, p, nil); + + /* now look for fn ptrs */ + for(i=0; i<NHASH; i++){ + for(s = hash[i]; s != S; s = s->link){ + if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){ + for(u = s->use; u != U; u = u->link){ + if(!ckuse(s, s, u)) + break; + } + if(u == U){ // can simplify + for(u = s->use; u != U; u = u->link) + setuse(s, s, u); + } + } + } + } + + /* now free Use structures */ +} + +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)){ + undefsym(s); + Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value); + } +} + +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(); + p->link = datap; + datap = p; + p->as = ADATA; + p->reg = w; + p->from.type = D_OREG; + p->from.name = t; + p->from.sym = s; + p->from.offset = o; + p->to.type = D_CONST; + p->to.name = D_NONE; + 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]; + 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.name = 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; + p->to.sval = malloc(NSNAME); + memmove(p->to.sval, buf, NSNAME); + nb = 0; + } + if(*t++ == 0) + break; + } + + /* name */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.name = 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; + p->to.sval = malloc(NSNAME); + memmove(p->to.sval, 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); +} diff --git a/utils/5l/span.c b/utils/5l/span.c new file mode 100644 index 00000000..f91c776e --- /dev/null +++ b/utils/5l/span.c @@ -0,0 +1,1262 @@ +#include "l.h" + +static struct { + ulong start; + ulong size; + ulong extra; +} pool; + +int checkpool(Prog*, int); +int flushpool(Prog*, int, int); + +int +isbranch(Prog *p) +{ + int as = p->as; + return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX; +} + +static int +ispad(Prog *p) +{ + if(p->as != AMOVW) + return 0; + if(p->from.type != D_REG || p->from.reg != REGSB) + return 0; + if(p->to.type != D_REG || p->to.reg != REGSB) + return 0; + return 1; +} + +int +fninc(Sym *s) +{ + if(thumb){ + if(s->thumb){ + if(s->foreign) + return 8; + else + return 0; + } + else{ + if(s->foreign) + return 0; + else + diag("T A !foreign in fninc"); + } + } + else{ + if(s->thumb){ + if(s->foreign) + return 0; + else + diag("A T !foreign in fninc"); + } + else{ + if(s->foreign) + return 4; + else + return 0; + } + } + return 0; +} + +int +fnpinc(Sym *s) +{ + if(!s->fnptr){ // a simplified case BX O(R) -> BL O(R) + if(!debug['f']) + diag("fnptr == 0 in fnpinc"); + if(s->foreign) + diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb); + return 0; + } + /* 0, 1, 2, 3 squared */ + if(s->thumb) + return s->foreign ? 9 : 1; + else + return s->foreign ? 4 : 0; +} + +static Prog * +pad(Prog *p, int pc) +{ + Prog *q; + + q = prg(); + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGSB; + q->to.type = D_REG; + q->to.reg = REGSB; + q->pc = pc; + q->link = p->link; + return q; +} + +static int +scan(Prog *op, Prog *p, int c) +{ + Prog *q; + + for(q = op->link; q != p; q = q->link){ + q->pc = c; + c += oplook(q)->size; + nocache(q); + } + return c; +} + +/* size of a case statement including jump table */ +static long +casesz(Prog *p) +{ + int jt = 0; + long n = 0; + Optab *o; + + for( ; p != P; p = p->link){ + if(p->as == ABCASE) + jt = 1; + else if(jt) + break; + o = oplook(p); + n += o->size; + } + return n; +} + +void +span(void) +{ + Prog *p, *op; + Sym *setext, *s; + Optab *o; + int m, bflag, i; + long c, otxt, v; + int lastthumb = -1; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + + bflag = 0; + c = INITTEXT; + op = nil; + otxt = c; + for(p = firstp; p != P; op = p, p = p->link) { + setarch(p); + p->pc = c; + o = oplook(p); + m = o->size; + // must check literal pool here in case p generates many instructions + if(blitrl){ + if(thumb && isbranch(p)) + pool.extra += brextra(p); + if(checkpool(op, p->as == ACASE ? casesz(p) : m)) + c = p->pc = scan(op, p, c); + } + if(m == 0) { + if(p->as == ATEXT) { + if(blitrl && lastthumb != -1 && lastthumb != thumb){ // flush literal pool + if(flushpool(op, 0, 1)) + c = p->pc = scan(op, p, c); + } + lastthumb = thumb; + curtext = p; + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + /* need passes to resolve branches */ + if(c-otxt >= 1L<<17) + bflag = 1; + otxt = c; + if(thumb && blitrl) + pool.extra += brextra(p); + continue; + } + diag("zero-width instruction\n%P", p); + continue; + } + switch(o->flag & (LFROM|LTO|LPOOL)) { + case LFROM: + addpool(p, &p->from); + break; + case LTO: + addpool(p, &p->to); + break; + case LPOOL: + if ((p->scond&C_SCOND) == 14) + flushpool(p, 0, 0); + break; + } + if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) + flushpool(p, 0, 0); + c += m; + if(blitrl && p->link == P){ + if(thumb && isbranch(p)) + pool.extra += brextra(p); + checkpool(p, 0); + } + } + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + while(bflag) { + if(debug['v']) + Bprint(&bso, "%5.2f span1\n", cputime()); + bflag = 0; + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + setarch(p); + p->pc = c; + if(thumb && isbranch(p)) + nocache(p); + o = oplook(p); +/* very larg branches + if(o->type == 6 && p->cond) { + otxt = p->cond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = D_BRANCH; + q->cond = p->cond; + p->cond = q; + q = prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = D_BRANCH; + q->cond = q->link->link; + bflag = 1; + } + } + */ + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + } + + if(seenthumb){ // branch resolution + int passes = 0; + int lastc = 0; + int again; + Prog *oop; + + loop: + passes++; + if(passes > 100){ + diag("span looping !"); + errorexit(); + } + c = INITTEXT; + oop = op = nil; + again = 0; + for(p = firstp; p != P; oop = op, op = p, p = p->link){ + setarch(p); + if(p->pc != c) + again = 1; + p->pc = c; + if(thumb && isbranch(p)) + nocache(p); + o = oplook(p); + m = o->size; + if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added + if(p->as == ABL) + m = 4; + else + m = 2; + p->align = 0; + } + if(p->align){ + if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){ + if(ispad(op)){ + oop->link = p; + op = oop; + c -= 2; + p->pc = c; + } + else{ + op->link = pad(op, c); + op = op->link; + c += 2; + p->pc = c; + } + again = 1; + } + } + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + } + c += m; + } + if(c != lastc || again){ + lastc = c; + goto loop; + } + } + + if(0 && seenthumb){ // rm redundant padding - obsolete + int d; + + op = nil; + d = 0; + for(p = firstp; p != P; op = p, p = p->link){ + p->pc -= d; + if(p->as == ATEXT){ + if(p->from.sym != S) + p->from.sym->value -= d; +// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr); + } + if(ispad(p) && p->link != P && ispad(p->link)){ + op->link = p->link->link; + d += 4; + p = op; + } + } + // print("%d bytes removed (padding)\n", d); + c -= d; + } + + if(debug['t']) { + /* + * add strings to text segment + */ + c = rnd(c, 8); + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SSTRING) + continue; + v = s->value; + while(v & 3) + v++; + s->value = c; + c += v; + } + } + + c = rnd(c, 8); + + setext = lookup("etext", 0); + if(setext != S) { + setext->value = c; + textsize = c - INITTEXT; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(debug['v']) + Bprint(&bso, "tsize = %lux\n", textsize); + Bflush(&bso); +} + +/* + * when the first reference to the literal pool threatens + * to go out of range of a 12-bit PC-relative offset, + * drop the pool now, and branch round it. + * this happens only in extended basic blocks that exceed 4k. + */ +int +checkpool(Prog *p, int sz) +{ + if(thumb){ + if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc) + return flushpool(p, 1, 0); + else if(p->link == P) + return flushpool(p, 2, 0); + return 0; + } + if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) + return flushpool(p, 1, 0); + else if(p->link == P) + return flushpool(p, 2, 0); + return 0; +} + +int +flushpool(Prog *p, int skip, int force) +{ + Prog *q; + + if(blitrl) { + if(skip){ + if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start); + q = prg(); + q->as = AB; + q->to.type = D_BRANCH; + q->cond = p->link; + q->link = blitrl; + blitrl = q; + } + else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048))) + return 0; + elitrl->link = p->link; + p->link = blitrl; + blitrl = 0; /* BUG: should refer back to values until out-of-range */ + elitrl = 0; + pool.size = 0; + pool.start = 0; + pool.extra = 0; + return 1; + } + return 0; +} + +void +addpool(Prog *p, Adr *a) +{ + Prog *q, t; + int c; + + if(thumb) + c = thumbaclass(a, p); + else + c = aclass(a); + + t = zprg; + t.as = AWORD; + + switch(c) { + default: + t.to = *a; + break; + + case C_SROREG: + case C_LOREG: + case C_ROREG: + case C_FOREG: + case C_SOREG: + case C_HOREG: + case C_GOREG: + case C_FAUTO: + case C_SAUTO: + case C_LAUTO: + case C_LACON: + case C_GACON: + t.to.type = D_CONST; + t.to.offset = instoffset; + break; + } + + for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */ + if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { + p->cond = q; + return; + } + + q = prg(); + *q = t; + q->pc = pool.size; + + if(blitrl == P) { + blitrl = q; + pool.start = p->pc; + q->align = 4; + } else + elitrl->link = q; + elitrl = q; + pool.size += 4; + + p->cond = q; +} + +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; + } +} + +long +regoff(Adr *a) +{ + + instoffset = 0; + aclass(a); + return instoffset; +} + +long +immrot(ulong v) +{ + int i; + + for(i=0; i<16; i++) { + if((v & ~0xff) == 0) + return (i<<8) | v | (1<<25); + v = (v<<2) | (v>>30); + } + return 0; +} + +long +immaddr(long v) +{ + if(v >= 0 && v <= 0xfff) + return (v & 0xfff) | + (1<<24) | /* pre indexing */ + (1<<23); /* pre indexing, up */ + if(v >= -0xfff && v < 0) + return (-v & 0xfff) | + (1<<24); /* pre indexing */ + return 0; +} + +int +immfloat(long v) +{ + return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ +} + +int +immhalf(long v) +{ + if(v >= 0 && v <= 0xff) + return v| + (1<<24)| /* pre indexing */ + (1<<23); /* pre indexing, up */ + if(v >= -0xff && v < 0) + return (-v & 0xff)| + (1<<24); /* pre indexing */ + return 0; +} + +int +aclass(Adr *a) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_REGREG: + return C_REGREG; + + case D_SHIFT: + return C_SHIFT; + + case D_FREG: + return C_FREG; + + case D_FPCR: + return C_FCR; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == 0 || a->sym->name == 0) { + print("null sym external\n"); + print("%D\n", a); + return C_GOK; + } + s = a->sym; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + } + if(dlm) { + switch(t) { + default: + instoffset = s->value + a->offset + INITDAT; + break; + case SUNDEF: + case STEXT: + case SCONST: + case SLEAF: + case SSTRING: + instoffset = s->value + a->offset; + break; + } + return C_ADDR; + } + instoffset = s->value + a->offset - BIG; + t = immaddr(instoffset); + if(t) { + if(immhalf(instoffset)) + return immfloat(t) ? C_HFEXT : C_HEXT; + if(immfloat(t)) + return C_FEXT; + return C_SEXT; + } + return C_LEXT; + case D_AUTO: + instoffset = autosize + a->offset; + t = immaddr(instoffset); + if(t){ + if(immhalf(instoffset)) + return immfloat(t) ? C_HFAUTO : C_HAUTO; + if(immfloat(t)) + return C_FAUTO; + return C_SAUTO; + } + return C_LAUTO; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + t = immaddr(instoffset); + if(t){ + if(immhalf(instoffset)) + return immfloat(t) ? C_HFAUTO : C_HAUTO; + if(immfloat(t)) + return C_FAUTO; + return C_SAUTO; + } + return C_LAUTO; + case D_NONE: + instoffset = a->offset; + t = immaddr(instoffset); + if(t) { + if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */ + return immfloat(t) ? C_HFOREG : C_HOREG; + if(immfloat(t)) + return C_FOREG; /* n.b. that it will also satisfy immrot */ + t = immrot(instoffset); + if(t) + return C_SROREG; + if(immhalf(instoffset)) + return C_HOREG; + return C_SOREG; + } + t = immrot(instoffset); + if(t) + return C_ROREG; + return C_LOREG; + } + return C_GOK; + + case D_PSR: + return C_PSR; + + case D_OCONST: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + s = a->sym; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + } + instoffset = s->value + a->offset + INITDAT; + if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) { + instoffset = s->value + a->offset; +#ifdef CALLEEBX + instoffset += fnpinc(s); +#else + if(s->thumb) + instoffset++; // T bit +#endif + return C_LCON; + } + return C_LCON; + } + return C_GOK; + + case D_FCONST: + return C_FCON; + + case D_CONST: + switch(a->name) { + + case D_NONE: + instoffset = a->offset; + if(a->reg != NREG) + goto aconsize; + + t = immrot(instoffset); + if(t) + return C_RCON; + t = immrot(~instoffset); + if(t) + return C_NCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == S) + break; + t = s->type; + switch(t) { + case 0: + case SXREF: + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + break; + case SUNDEF: + case STEXT: + case SSTRING: + case SCONST: + case SLEAF: + instoffset = s->value + a->offset; +#ifdef CALLEEBX + instoffset += fnpinc(s); +#else + if(s->thumb) + instoffset++; // T bit +#endif + return C_LCON; + } + if(!dlm) { + instoffset = s->value + a->offset - BIG; + t = immrot(instoffset); + if(t && instoffset != 0) + return C_RECON; + } + instoffset = s->value + a->offset + INITDAT; + return C_LCON; + + case D_AUTO: + instoffset = autosize + a->offset; + goto aconsize; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + aconsize: + t = immrot(instoffset); + if(t) + return C_RACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +Optab* +oplook(Prog *p) +{ + int a1, a2, a3, r; + char *c1, *c3; + Optab *o, *e; + Optab *otab; + Oprang *orange; + + if(thumb){ + otab = thumboptab; + orange = thumboprange; + } + else{ + otab = optab; + orange = oprange; + } + a1 = p->optab; + if(a1) + return otab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + if(thumb) + a1 = thumbaclass(&p->from, p) + 1; + else + a1 = aclass(&p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->to.class; + if(a3 == 0) { + if(thumb) + a3 = thumbaclass(&p->to, p) + 1; + else + a3 = aclass(&p->to) + 1; + p->to.class = a3; + } + a3--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = orange[r].start; + if(o == 0) { + a1 = opcross[repop[r]][a1][a2][a3]; + if(a1) { + p->optab = a1+1; + return otab+a1; + } + o = orange[r].stop; /* just generate an error */ + } + if(0) { + print("oplook %A %d %d %d\n", + (int)p->as, a1, a2, a3); + print(" %d %d\n", p->from.type, p->to.type); + } + e = orange[r].stop; + c1 = xcmp[a1]; + c3 = xcmp[a3]; + for(; o<e; o++) + if(o->a2 == a2) + if(c1[o->a1]) + if(c3[o->a3]) { + p->optab = (o-otab)+1; + return o; + } + diag("illegal combination %A %d %d %d", + p->as, a1, a2, a3); + prasm(p); + if(o == 0) + o = otab; + return o; +} + +int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_RCON || b == C_NCON) + return 1; + break; + case C_LACON: + if(b == C_RACON) + return 1; + break; + case C_LECON: + if(b == C_RECON) + return 1; + break; + + case C_HFEXT: + return b == C_HEXT || b == C_FEXT; + case C_FEXT: + case C_HEXT: + return b == C_HFEXT; + case C_SEXT: + return cmp(C_HFEXT, b); + case C_LEXT: + return cmp(C_SEXT, b); + + case C_HFAUTO: + return b == C_HAUTO || b == C_FAUTO; + case C_FAUTO: + case C_HAUTO: + return b == C_HFAUTO; + case C_SAUTO: + return cmp(C_HFAUTO, b); + case C_LAUTO: + return cmp(C_SAUTO, b); + + case C_HFOREG: + return b == C_HOREG || b == C_FOREG; + case C_FOREG: + case C_HOREG: + return b == C_HFOREG; + case C_SROREG: + return cmp(C_SOREG, b) || cmp(C_ROREG, b); + case C_SOREG: + case C_ROREG: + return b == C_SROREG || cmp(C_HFOREG, b); + case C_LOREG: + return cmp(C_SROREG, b); + + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + case C_GBRA: + if(b == C_SBRA || b == C_LBRA) + return 1; + + case C_HREG: + return cmp(C_SP, b) || cmp(C_PC, b); + + } + return 0; +} + +int +ocmp(const void *a1, const void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = (Optab*)a1; + p2 = (Optab*)a2; + n = p1->as - p2->as; + if(n) + return n; + n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */ + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a2 - p2->a2; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + return 0; +} + +void +buildop(void) +{ + int i, n, r; + + armv4 = !debug['h']; + for(i=0; i<C_GOK; i++) + for(n=0; n<C_GOK; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) + if((optab[n].flag & V4) && !armv4) { + optab[n].as = AXXX; + break; + } + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + diag("unknown op in build: %A", r); + errorexit(); + case AADD: + oprange[AAND] = oprange[r]; + oprange[AEOR] = oprange[r]; + oprange[ASUB] = oprange[r]; + oprange[ARSB] = oprange[r]; + oprange[AADC] = oprange[r]; + oprange[ASBC] = oprange[r]; + oprange[ARSC] = oprange[r]; + oprange[AORR] = oprange[r]; + oprange[ABIC] = oprange[r]; + break; + case ACMP: + oprange[ATST] = oprange[r]; + oprange[ATEQ] = oprange[r]; + oprange[ACMN] = oprange[r]; + break; + case AMVN: + break; + case ABEQ: + oprange[ABNE] = oprange[r]; + oprange[ABCS] = oprange[r]; + oprange[ABHS] = oprange[r]; + oprange[ABCC] = oprange[r]; + oprange[ABLO] = oprange[r]; + oprange[ABMI] = oprange[r]; + oprange[ABPL] = oprange[r]; + oprange[ABVS] = oprange[r]; + oprange[ABVC] = oprange[r]; + oprange[ABHI] = oprange[r]; + oprange[ABLS] = oprange[r]; + oprange[ABGE] = oprange[r]; + oprange[ABLT] = oprange[r]; + oprange[ABGT] = oprange[r]; + oprange[ABLE] = oprange[r]; + break; + case ASLL: + oprange[ASRL] = oprange[r]; + oprange[ASRA] = oprange[r]; + break; + case AMUL: + oprange[AMULU] = oprange[r]; + break; + case ADIV: + oprange[AMOD] = oprange[r]; + oprange[AMODU] = oprange[r]; + oprange[ADIVU] = oprange[r]; + break; + case AMOVW: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + break; + case ASWPW: + oprange[ASWPBU] = oprange[r]; + break; + case AB: + case ABL: + case ABX: + case ABXRET: + case ASWI: + case AWORD: + case AMOVM: + case ARFE: + case ATEXT: + case ACASE: + case ABCASE: + break; + case AADDF: + oprange[AADDD] = oprange[r]; + oprange[ASUBF] = oprange[r]; + oprange[ASUBD] = oprange[r]; + oprange[AMULF] = oprange[r]; + oprange[AMULD] = oprange[r]; + oprange[ADIVF] = oprange[r]; + oprange[ADIVD] = oprange[r]; + oprange[AMOVFD] = oprange[r]; + oprange[AMOVDF] = oprange[r]; + break; + + case ACMPF: + oprange[ACMPD] = oprange[r]; + break; + + case AMOVF: + oprange[AMOVD] = oprange[r]; + break; + + case AMOVFW: + oprange[AMOVWF] = oprange[r]; + oprange[AMOVWD] = oprange[r]; + oprange[AMOVDW] = oprange[r]; + break; + + case AMULL: + oprange[AMULA] = oprange[r]; + oprange[AMULAL] = oprange[r]; + oprange[AMULLU] = oprange[r]; + oprange[AMULALU] = oprange[r]; + break; + } + } +} + +/* +void +buildrep(int x, int as) +{ + Opcross *p; + Optab *e, *s, *o; + int a1, a2, a3, n; + + if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) { + diag("assumptions fail in buildrep"); + errorexit(); + } + repop[as] = x; + p = (opcross + x); + s = oprange[as].start; + e = oprange[as].stop; + for(o=e-1; o>=s; o--) { + n = o-optab; + for(a2=0; a2<2; a2++) { + if(a2) { + if(o->a2 == C_NONE) + continue; + } else + if(o->a2 != C_NONE) + continue; + for(a1=0; a1<32; a1++) { + if(!xcmp[a1][o->a1]) + continue; + for(a3=0; a3<32; a3++) + if(xcmp[a3][o->a3]) + (*p)[a1][a2][a3] = n; + } + } + } + oprange[as].start = 0; +} +*/ + +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, long v, int abs) +{ + int i, k, n; + uchar *m; + ulong *a; + Reloc *r; + + if(v&3) + diag("bad relocation address"); + v >>= 2; + if(s != S && s->type == SUNDEF) + k = abs ? ABSU : RELU; + else + k = abs ? ABSD : RELD; + /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, 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){ + wput(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); + } +} diff --git a/utils/5l/thumb.c b/utils/5l/thumb.c new file mode 100644 index 00000000..9ec8ce5b --- /dev/null +++ b/utils/5l/thumb.c @@ -0,0 +1,1637 @@ +#include "l.h" + +static long thumboprr(int); +static long thumboprrr(int, int); +static long thumbopirr(int , int); +static long thumbopri(int); +static long thumbophh(int); +static long thumbopbra(int); +static long thumbopmv(int, int); +static void lowreg(Prog *, int); +static void mult(Prog *, int, int); +static void numr(Prog *, int, int, int); +static void regis(Prog *, int, int, int); +static void dis(int, int); + +// build a constant using neg, add and shift - only worth it if < 6 bytes */ +static int +immbuildcon(int c, Prog *p) +{ + int n = 0; + + USED(p); + if(c >= 0 && c <= 255) + return 0; // mv + if(c >= -255 && c < 0) // mv, neg + return 1; + if(c >= 256 && c <= 510) // mv, add + return 1; + if(c < 0) + return 0; + while(!(c & 1)){ + n++; + c >>= 1; + } + if(c >= 0 && c <= 255) // mv, lsl + return 1; + return 0; +} + +// positive 5 bit offset from register - O(R) +// positive 8 bit offset from register - mov O, R then [R, R] +// otherwise O goes in literal pool - mov O1(PC), R then [R, R] +static int +immoreg(int off, Prog *p) +{ + int v = 1; + int as = p->as; + + if(off < 0) + return C_GOREG; + if(as == AMOVW) + v = 4; + else if(as == AMOVH || as == AMOVHU) + v = 2; + else if(as == AMOVB || as == AMOVBU) + v = 1; + else + diag("bad op in immoreg"); + if(off/v <= 31) + return C_SOREG; + if(off <= 255) + return C_LOREG; + return C_GOREG; +} + +// positive 8 bit - mov O, R then 0(R) +// otherwise O goes in literal pool - mov O1(PC), R then 0(R) +static int +immacon(int off, Prog *p, int t1, int t2) +{ + USED(p); + if(off < 0) + return t2; + if(off <= 255) + return t1; + return t2; +} + +// unsigned 8 bit in words +static int +immauto(int off, Prog *p) +{ + if(p->as != AMOVW) + diag("bad op in immauto"); + mult(p, off, 4); + if(off >= 0 && off <= 1020) + return C_SAUTO; + return C_LAUTO; +} + +static int +immsmall(int off, Prog *p, int t1, int t2, int t3) +{ + USED(p); + if(off >= 0 && off <= 7) + return t1; + if(off >= 0 && off <= 255) + return t2; + return t3; +} + +static int +immcon(int off, Prog *p) +{ + int as = p->as; + + if(as == ASLL || as == ASRL || as == ASRA) + return C_SCON; + if(p->to.type == D_REG && p->to.reg == REGSP){ + if(as == AADD || as == ASUB){ + if(off >= 0 && off <= 508) + return C_SCON; + if(as == ASUB){ + p->as = AADD; + p->from.offset = -p->from.offset; + } + return C_LCON; + } + diag("unknown type in immcon"); + } + if(as == AADD || as == ASUB){ + if(p->reg != NREG) + return immsmall(off, p, C_SCON, C_LCON, C_GCON); + return immacon(off, p, C_SCON, C_LCON); + } + if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p)) + return C_BCON; + if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p)) + return C_BCON; + if(as == ACMP || as == AMOVW) + return immacon(off, p, C_SCON, C_LCON); + return C_LCON; +} + +int +thumbaclass(Adr *a, Prog *p) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + case D_REG: + if(a->reg == REGSP) + return C_SP; + if(a->reg == REGPC) + return C_PC; + if(a->reg >= 8) + return C_HREG; + return C_REG; + case D_SHIFT: + diag("D_SHIFT in thumbaclass"); + return C_SHIFT; + case D_FREG: + diag("D_FREG in thumbaclass"); + return C_FREG; + case D_FPCR: + diag("D_FPCR in thumbaclass"); + return C_FCR; + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == 0 || a->sym->name == 0) { + print("null sym external\n"); + print("%D\n", a); + return C_GOK; + } + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s\n", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + instoffset = a->sym->value + a->offset + INITDAT; + return C_LEXT; /* INITDAT unknown at this stage */ + // return immacon(instoffset, p, C_SEXT, C_LEXT); + case D_AUTO: + instoffset = autosize + a->offset; + return immauto(instoffset, p); + case D_PARAM: + instoffset = autosize + a->offset + 4L; +// print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4); + return immauto(instoffset, p); + case D_NONE: + instoffset = a->offset; + if(a->reg == REGSP) + return immauto(instoffset, p); + else + return immoreg(instoffset, p); + } + return C_GOK; + case D_PSR: + diag("D_PSR in thumbaclass"); + return C_PSR; + case D_OCONST: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + s = a->sym; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s\n", + s->name, TNAME); + s->type = SDATA; + } + instoffset = s->value + a->offset + INITDAT; + if(s->type == STEXT || s->type == SLEAF){ + instoffset = s->value + a->offset; +#ifdef CALLEEBX + instoffset += fnpinc(s); +#else + if(s->thumb) + instoffset++; // T bit +#endif + return C_LCON; + } + return C_LCON; /* INITDAT unknown at this stage */ + // return immcon(instoffset, p); + } + return C_GOK; + case D_FCONST: + diag("D_FCONST in thumaclass"); + return C_FCON; + case D_CONST: + switch(a->name) { + case D_NONE: + instoffset = a->offset; + if(a->reg != NREG) + goto aconsize; + return immcon(instoffset, p); + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == S) + break; + t = s->type; + switch(t) { + case 0: + case SXREF: + diag("undefined external: %s in %s\n", + s->name, TNAME); + s->type = SDATA; + break; + case SCONST: + case STEXT: + case SLEAF: + instoffset = s->value + a->offset; +#ifdef CALLEEBX + instoffset += fnpinc(s); +#else + if(s->thumb) + instoffset++; // T bit +#endif + return C_LCON; + } + instoffset = s->value + a->offset + INITDAT; + return C_LCON; /* INITDAT unknown at this stage */ + // return immcon(instoffset, p); + case D_AUTO: + instoffset = autosize + a->offset; + goto aconsize; + case D_PARAM: + instoffset = autosize + a->offset + 4L; + aconsize: + if(p->from.reg == REGSP || p->from.reg == NREG) + return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON; + else if(p->from.reg == p->to.reg) + return immacon(instoffset, p, C_SACON, C_GACON); + return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON); + } + return C_GOK; + case D_BRANCH: { + int v, va; + + p->align = 0; + v = -4; + va = 0; + if(p->cond != P){ + v = (p->cond->pc - p->pc) - 4; + va = p->cond->pc; + } + instoffset = v; + if(p->as == AB){ + if(v >= -2048 && v <= 2046) + return C_SBRA; + p->align = 4; + instoffset = va; + return C_LBRA; + } + if(p->as == ABL){ +#ifdef CALLEEBX + int e; + + if((e = fninc(p->to.sym))) { + v += e; + va += e; + instoffset += e; + } +#endif + if(v >= -4194304 && v <= 4194302) + return C_SBRA; + p->align = 2; + instoffset = va; + return C_LBRA; + } + if(p->as == ABX){ + v = va; + if(v >= 0 && v <= 255) + return C_SBRA; + p->align = 2; + instoffset = va; + return C_LBRA; + } + if(v >= -256 && v <= 254) + return C_SBRA; + if(v >= -(2048-2) && v <= (2046+2)) + return C_LBRA; + p->align = 2; + instoffset = va; + return C_GBRA; + } + } + return C_GOK; +} + +// as a1 a2 a3 type size param lit vers +Optab thumboptab[] = +{ + { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, + { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 }, + { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 }, + { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 }, + { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 }, + { AADD, C_REG, C_REG, C_REG, 2, 2, 0 }, + { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 }, + { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 }, + { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 }, + { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM }, + // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM }, + { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 }, + { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 }, + { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 }, + { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM }, + { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 }, + { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 }, + { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM }, + { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 }, + { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 }, + { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM }, + // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM }, + // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM }, + { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 }, + { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM }, + { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 }, + { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 }, + { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, + { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 }, + { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 }, + { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, + { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 }, + { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 }, + { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 }, + { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL }, + { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 }, + { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 }, + { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 }, + { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL }, + { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 }, + { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 }, + { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 }, + { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 }, + // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 }, + // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 }, + { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 }, + { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 }, + { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 }, + { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 }, + { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 }, + { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 }, + { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 }, + { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 }, + { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 }, + { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP }, + { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM }, + // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM }, + { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, + { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, + { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, + { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, + { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, + { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, + { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 }, + { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO }, + { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, + { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, + { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, + { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, + { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, + { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, + { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, + { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 }, + { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 }, + { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 }, + { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 }, + { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, + { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, + { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, + { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, + { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 }, + { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 }, + { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM }, + { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 }, + { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 }, + { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, + { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, + { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, + { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, + { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, + { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, + { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, + { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, + { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, + { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, + { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, + { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, + { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, + { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, + { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, + { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, + { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, + { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, + { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, + { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, + { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, + { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, + { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, + { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, + { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, + { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, + { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, + + { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 }, +}; + +#define OPCNTSZ 52 +int opcount[OPCNTSZ]; + +// is this too pessimistic ? +int +brextra(Prog *p) +{ + int c; + + // +2 is for padding + if(p->as == ATEXT) + return 0-0+2; + if(!isbranch(p)) + diag("bad op in brextra()"); + c = thumbaclass(&p->to, p); + switch(p->as){ + case AB: + if(c != C_SBRA) + return 0; + return 8-2+2; + case ABL: + if(c != C_SBRA) + return 0; + return 14-4+2; + case ABX: + if(c == C_REG || c == C_HREG) + return 0; +#ifdef CALLEEBX + diag("ABX $I in brextra"); +#endif + if(c != C_SBRA) + return 0; + return 14-10+2; + default: + if(c == C_GBRA) + return 0; + if(c == C_LBRA) + return 10-4+2; + return 10-2+2; + } + return 0; +} + +#define high(r) ((r)>=8) + +static long +mv(Prog *p, int r, int off) +{ + int v, o; + if(p != nil && p->cond != nil){ // in literal pool + v = p->cond->pc - p->pc - 4; + if(p->cond->pc & 3) + diag("mv: bad literal pool alignment"); + if(v & 3) + v += 2; // ensure M(4) offset + mult(p, v, 4); + off = v/4; + numr(p, off, 0, 255); + o = 0x9<<11; + } + else{ + numr(p, off, 0, 255); + o = 0x4<<11; + } + o |= (r<<8) | off; + return o; +} + +static void +mvcon(Prog *p, int r, int c, long *o1, long *o2) +{ + int op = 0, n = 0; + + if(c >= 0 && c <= 255) + diag("bad c in mvcon"); + if(c >= -255 && c < 0) // mv, neg + c = -c; + else if(c >= 256 && c <= 510){ // mv, add + n = rand()%(511-c) + (c-255); + c -= n; + // n = c-255; + // c = 255; + op = AADD; + } + else{ + if(c < 0) + diag("-ve in mvcon"); + while(!(c & 1)){ + n++; + c >>= 1; + } + if(c >= 0 && c <= 255) // mv, lsl + op = ASLL; + else + diag("bad shift in mvcon"); + } + *o1 = mv(p, r, c); + switch(op){ + case 0: + *o2 = (1<<14) | (9<<6) | (r<<3) | r; + break; + case AADD: + *o2 = (6<<11) | (r<<8) | n; + break; + case ASLL: + *o2 = (n<<6) | (r<<3) | r; + break; + } +} + +static long +mvlh(int rs, int rd) +{ + int o = 0x46<<8; + + if(high(rs)){ + rs -= 8; + o |= 1<<6; + } + if(high(rd)){ + rd -= 8; + o |= 1<<7; + } + o |= (rs<<3) | rd; + return o; +} + +void +thumbbuildop() +{ + int i, n, r; + Optab *optab = thumboptab; + Oprang *oprange = thumboprange; + + for(n=0; optab[n].as != AXXX; n++) + ; + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + break; + case ABEQ: + oprange[ABNE] = oprange[r]; + oprange[ABCS] = oprange[r]; + oprange[ABHS] = oprange[r]; + oprange[ABCC] = oprange[r]; + oprange[ABLO] = oprange[r]; + oprange[ABMI] = oprange[r]; + oprange[ABPL] = oprange[r]; + oprange[ABVS] = oprange[r]; + oprange[ABVC] = oprange[r]; + oprange[ABHI] = oprange[r]; + oprange[ABLS] = oprange[r]; + oprange[ABGE] = oprange[r]; + oprange[ABLT] = oprange[r]; + oprange[ABGT] = oprange[r]; + oprange[ABLE] = oprange[r]; + break; + case AMVN: + oprange[AADC] = oprange[r]; + oprange[ASBC] = oprange[r]; + oprange[AMUL] = oprange[r]; + oprange[AAND] = oprange[r]; + oprange[AEOR] = oprange[r]; + oprange[AORR] = oprange[r]; + oprange[ABIC] = oprange[r]; + oprange[AMULU] = oprange[r]; + break; + case ACMN: + oprange[ATST] = oprange[r]; + break; + case ASRL: + oprange[ASRA] = oprange[r]; + oprange[ASLL] = oprange[r]; + break; + case AADD: + oprange[ASUB] = oprange[r]; + break; + } + } +} + +void +thumbasmout(Prog *p, Optab *o) +{ + long o1, o2, o3, o4, o5, o6, o7, v; + int r, rf, rt; + + rf = p->from.reg; + rt = p->to.reg; + r = p->reg; + o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0; +if(debug['P']) print("%ulx: %P type %d %d\n", (ulong)(p->pc), p, o->type, p->align); + opcount[o->type] += o->size; + switch(o->type) { + default: + diag("unknown asm %d", o->type); + prasm(p); + break; + case 0: /* pseudo ops */ +if(debug['G']) print("%ulx: %s: thumb\n", (ulong)(p->pc), p->from.sym->name); + break; + case 1: /* op R, -, R or op R, R, - */ + o1 = thumboprr(p->as); + if(rt == NREG) + rt = r; + lowreg(p, rf); + lowreg(p, rt); + o1 |= (0x10<<10) | (rf<<3) | rt; + break; + case 2: /* add/sub R, R, R or add/sub R, -, R */ + o1 = p->as == AADD ? 0x0<<9 : 0x1<<9; + if(r == NREG) + r = rt; + lowreg(p, rf); + lowreg(p, r); + lowreg(p, rt); + o1 |= (0x6<<10) | (rf<<6) | (r<<3) | rt; + break; + case 3: /* add/sub $I, R, R or add/sub $I, -, R */ + thumbaclass(&p->from, p); + o1 = p->as == AADD ? 0x0<<9 : 0x1<<9; + if(r == NREG) + r = rt; + numr(p, instoffset, 0, 7); + lowreg(p, r); + lowreg(p, rt); + o1 |= (0x7<<10) | (instoffset<<6) | (r<<3) | rt; + break; + case 4: /* shift $I, R, R or shift $I, -, R */ + thumbaclass(&p->from, p); + if(instoffset < 0) + diag("negative shift in thumbasmout"); + instoffset %= 32; + o1 = thumbopri(p->as); + if(r == NREG) + r = rt; + numr(p, instoffset, 0, 31); + lowreg(p, r); + lowreg(p, rt); + o1 |= (0x0<<13) | (instoffset<<6) | (r<<3) | rt; + break; + case 5: /* add/sub/mov $I, -, R or cmp $I, R, - */ + thumbaclass(&p->from, p); + o1 = thumbopri(p->as); + if(rt == NREG) + rt = r; + numr(p, instoffset, 0, 255); + lowreg(p, rt); + o1 |= (0x1<<13) | (rt<<8) | instoffset; + break; + case 6: /* add $I, PC/SP, R */ + if(p->as == ASUB) + diag("subtract in add $I, PC/SP, R"); + thumbaclass(&p->from, p); + o1 = r == REGSP ? 0x1<<11 : 0x0<<11; + numr(p, instoffset, 0, 255); + regis(p, r, REGSP, REGPC); + lowreg(p, rt); + o1 |= (0xa<<12) | (rt<<8) | instoffset; + break; + case 7: /* add, sub $I, SP */ + thumbaclass(&p->from, p); + o1 = p->as == AADD ? 0x0<<7 : 0x1<<7; + numr(p, instoffset, 0, 508); + mult(p, instoffset, 4); + regis(p, rt, REGSP, REGSP); + o1 |= (0xb0<<8) | (instoffset>>2); + break; + case 8: /* add/mov/cmp R, R where at least 1 reg is high */ + o1 = 0; + if(rt == NREG) + rt = r; + if(high(rf)){ + o1 |= 1<<6; + rf -= 8; + } + if(high(rt)){ + o1 |= 2<<6; + rt -= 8; + } + if(o1 == 0) + diag("no high register(%P)", p); + o1 |= thumbophh(p->as); + o1 |= (0x11<<10) | (rf<<3) | rt; + break; + case 9: /* B $I */ + thumbaclass(&p->to, p); + numr(p, instoffset, -2048, 2046); + o1 = (0x1c<<11) | ((instoffset>>1)&0x7ff); + break; + case 10: /* Bcc $I */ + thumbaclass(&p->to, p); + numr(p, instoffset, -256, 254); + o1 = thumbopbra(p->as); + o1 |= (0xd<<12) | ((instoffset>>1)&0xff); + break; + case 11: /* BL $I */ + thumbaclass(&p->to, p); + numr(p, instoffset, -4194304, 4194302); + o1 = (0x1e<<11) | ((instoffset>>12)&0x7ff); + o2 = (0x1f<<11) | ((instoffset>>1)&0x7ff); + break; + case 12: /* BX $I */ +#ifdef CALLEEBX + diag("BX $I case"); +#endif + thumbaclass(&p->to, p); + if(p->to.sym->thumb) + instoffset |= 1; // T bit + o1 = mvlh(REGPC, REGTMPT); + o2 = (0x6<<11) | (REGTMPT<<8) | 7; // add 7, RTMP (T bit + PC offset) + o3 = mvlh(REGTMPT, REGLINK); + o4 = mv(nil, REGTMPT, instoffset); + o5 = (0x11c<<6) | (REGTMPT<<3); + // o1 = mv(nil, REGTMPT, v); + // o2 = (0x11b<<6) | (REGPC<<3) | REGLINK; + // o3 = (0x11c<<6) | (REGTMPT<<3); + break; + case 13: /* B O(R) */ + diag("B O(R)"); + break; + case 14: /* BL O(R) */ + diag("BL O(R)"); + break; + case 15: /* BX R */ + o1 = mvlh(REGPC, REGTMPT); + o2 = (0x6<<11) | (REGTMPT<<8) | 5; // add 5, RTMP (T bit + PC offset) + o3 = mvlh(REGTMPT, REGLINK); + o4 = 0; + if(high(rt)){ + rt -= 8; + o4 |= 1<<6; + } + o4 |= (0x8e<<7) | (rt<<3); + // o1 = (0x11c<<6) | (rt<<3); + break; + case 16: /* SWI $I */ + thumbaclass(&p->to, p); + numr(p, instoffset, 0, 255); + o1 = (0xdf<<8) | instoffset; + break; + case 17: /* AWORD */ + thumbaclass(&p->to, p); + o1 = instoffset&0xffff; + o2 = (instoffset>>16)&0xffff; + break; + case 18: /* AMOVW O(SP), R and AMOVW O(PC), R */ + thumbaclass(&p->from, p); + rf = o->param; + o1 = rf == REGSP ? 0x13<<11 : 0x9<<11; + regis(p, rf, REGSP, REGPC); + lowreg(p, rt); + mult(p, instoffset, 4); + numr(p, instoffset/4, 0, 255); + o1 |= (rt<<8) | (instoffset/4); + break; + case 19: /* AMOVW... O(R), R */ + thumbaclass(&p->from, p); + o1 = thumbopmv(p->as, 1); + v = 4; + if(p->as == AMOVHU) + v = 2; + else if(p->as == AMOVBU) + v = 1; + mult(p, instoffset, v); + lowreg(p, rf); + lowreg(p, rt); + numr(p, instoffset/v, 0, 31); + o1 |= ((instoffset/v)<<6) | (rf<<3) | rt; + break; + case 20: /* AMOVW R, O(SP) */ + thumbaclass(&p->to, p); + o1 = 0x12<<11; + if(rt != NREG) regis(p, rt, REGSP, REGSP); + lowreg(p, rf); + mult(p, instoffset, 4); + numr(p, instoffset/4, 0, 255); + o1 |= (rf<<8) | (instoffset/4); + break; + case 21: /* AMOVW... R, O(R) */ + thumbaclass(&p->to, p); + o1 = thumbopmv(p->as, 0); + v = 4; + if(p->as == AMOVHU || p->as == AMOVH) + v = 2; + else if(p->as == AMOVBU || p->as == AMOVB) + v = 1; + lowreg(p, rf); + lowreg(p, rt); + mult(p, instoffset, v); + numr(p, instoffset/v, 0, 31); + o1 |= ((instoffset/v)<<6) | (rt<<3) | rf; + break; + case 22: /* AMOVW R, R -> ASLL $0, R, R */ + o1 = thumbopri(ASLL); + lowreg(p, rf); + lowreg(p, rt); + o1 |= (0x0<<13) | (rf<<3) | rt; + break; + case 23: /* AMOVB/AMOVH/AMOVBU/AMOVHU R, R */ + o1 = thumbopri(ASLL); + o2 = p->as == AMOVB || p->as == AMOVH ? thumbopri(ASRA) : thumbopri(ASRL); + v = p->as == AMOVB || p->as == AMOVBU ? 24 : 16; + lowreg(p, rf); + lowreg(p, rt); + o1 |= (0x0<<13) | (v<<6) | (rf<<3) | rt; + o2 |= (0x0<<13) | (v<<6) | (rt<<3) | rt; + break; + case 24: /* AMOVH/AMOVB O(R), R -> AMOVH/AMOVB [R, R], R */ + thumbaclass(&p->from, p); + lowreg(p, rf); + lowreg(p, rt); + if(rf == rt) + r = REGTMPT; + else + r = rt; + if(p->as == AMOVB) + numr(p, instoffset, 0, 31); + else{ + mult(p, instoffset, 2); + numr(p, instoffset, 0, 62); + } + o1 = mv(p, r, instoffset); + o2 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9; + o2 |= (r<<6) | (rf<<3) | rt; + break; + case 25: /* MOVW $sacon, R */ + thumbaclass(&p->from, p); +// print("25: %d %d %d %d\n", instoffset, rf, r, rt); + if(rf == NREG) + rf = REGSP; + lowreg(p, rt); + if(rf == REGSP){ + mult(p, instoffset, 4); + numr(p, instoffset>>2, 0, 255); + o1 = (0x15<<11) | (rt<<8) | (instoffset>>2); // add $O, SP, R + } + else if(rf == rt){ + numr(p, instoffset, 0, 255); + o1 = (0x6<<11) | (rt<<8) | instoffset; // add $O, R + } + else{ + lowreg(p, rf); + numr(p, instoffset, 0, 7); + o1 = (0xe<<9) | (instoffset<<6) | (rf<<3) | rt; // add $O, Rs, Rd + } + break; + case 26: /* AMOVM $c, oreg -> stmia */ + lowreg(p, rt); + numr(p, p->from.offset, -256, 255); + o1 = (0x18<<11) | (rt<<8) | (p->from.offset&0xff); + break; + case 27: /* AMOVM oreg, $c ->ldmia */ + lowreg(p, rf); + numr(p, p->to.offset, -256, 256); + o1 = (0x19<<11) | (rf<<8) | (p->to.offset&0xff); + break; + case 28: /* AMOV* O(R), R -> AMOV* [R, R], R (offset large) */ + thumbaclass(&p->from, p); + lowreg(p, rf); + lowreg(p, rt); + if(rf == rt) + r = REGTMPT; + else + r = rt; + o1 = mv(p, r, instoffset); + o2 = thumboprrr(p->as, 1); + o2 |= (r<<6) | (rf<<3) | rt; + break; + case 29: /* AMOV* R, O(R) -> AMOV* R, [R, R] (offset large) */ + thumbaclass(&p->to, p); + lowreg(p, rf); + lowreg(p, rt); + if(rt == REGTMPT){ // used as tmp reg + if(instoffset >= 0 && instoffset <= 255){ + o1 = (1<<13) | (2<<11) | (rt<<8) | instoffset; // add $O, R7 + o2 = thumbopirr(p->as, 0); + o2 |= (0<<6) | (rt<<3) | rf; // mov* R, 0(R) + } + else + diag("big offset - case 29"); + } + else{ + o1 = mv(p, REGTMPT, instoffset); + o2 = thumboprrr(p->as, 0); + o2 |= (REGTMPT<<6) | (rt<<3) | rf; + } + break; + case 30: /* AMOVW... *addr, R */ + thumbaclass(&p->from, p); + o1 = mv(p, rt, instoffset); // MOV addr, rtmp + o2 = thumbopmv(p->as, 1); + lowreg(p, rt); + o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R + break; + case 31: /* AMOVW... R, *addr */ + thumbaclass(&p->to, p); + o1 = mv(p, REGTMPT, instoffset); + o2 = thumbopmv(p->as, 0); + lowreg(p, rf); + o2 |= (REGTMPT<<3) | rf; + break; + case 32: /* AMOVH/AMOVB *addr, R -> AMOVH/AMOVB [R, R], R */ + thumbaclass(&p->from, p); + o1 = mv(p, rt, instoffset); + lowreg(p, rt); + o2 = mv(nil, REGTMPT, 0); + o3 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9; + o3 |= (REGTMPT<<6) | (rt<<3) | rt; + break; + case 33: /* AMOVW O(SP), R (O large) */ + thumbaclass(&p->from, p); + lowreg(p, rt); + o1 = mv(p, rt, instoffset); + o2 = (0x111<<6) | (REGSP-8)<<3 | rt; // add SP, rt + o3 = thumbopmv(p->as, 1); + o3 |= (rt<<3) | rt; + break; + case 34: /* AMOVW R, O(SP) (O large) */ + thumbaclass(&p->to, p); + lowreg(p, rf); + o1 = mv(p, REGTMPT, instoffset); + o2 = (0x111<<6) | (REGSP-8)<<3 | REGTMPT; // add SP, REGTMP + o3 = thumbopmv(p->as, 0); + o3 |= (REGTMPT<<3) | rf; + break; + case 35: /* AMOVW $lacon, R */ + thumbaclass(&p->from, p); + lowreg(p, rt); + if(rf == NREG) + rf = REGSP; + if(rf == rt) + rf = r = REGTMPT; + else + r = rt; +// print("35: io=%d rf=%d rt=%d\n", instoffset, rf, rt); + o1 = mv(p, r, instoffset); // mov O, Rd + if(high(rf)) + o2 = (0x44<<8) | (0x1<<6) | ((rf-8)<<3) | rt; // add Rs, Rd + else + o2 = (0x6<<10) | (rf<<6) | (rt<<3) | rt; // add Rs, Rd + break; + case 36: /* AADD/ASUB $i, r, r when $i too big */ + thumbaclass(&p->from, p); + lowreg(p, r); + lowreg(p, rt); + o1 = mv(p, REGTMPT, instoffset); + o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; + o2 |= (REGTMPT<<6) | (r<<3) | rt; + break; + case 37: /* AADD/ASUB $i, r when $i too big */ + thumbaclass(&p->from, p); + lowreg(p, rt); + o1 = mv(p, REGTMPT, instoffset); + o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; + o2 |= (REGTMPT<<6) | (rt<<3) | rt; + break; + case 38: /* AMOVW $i, r when $i too big */ + thumbaclass(&p->from, p); + lowreg(p, rt); + o1 = mv(p, rt, instoffset); + break; + case 39: /* ACMP $i, r when $i too big */ + thumbaclass(&p->from, p); + lowreg(p, r); + o1 = mv(p, REGTMPT, instoffset); + o2 = (0x10a<<6) | (REGTMPT<<3) | r; + break; + case 40: /* add, sub $I, SP when $I large*/ + thumbaclass(&p->from, p); + if(p->as == ASUB) + instoffset = -instoffset; + o1 = mv(p, REGTMPT, instoffset); + o2 = (0x112<<6) | (REGTMPT<<3) | (REGSP-8); + regis(p, rt, REGSP, REGSP); + break; + case 41: /* BL LBRA */ + thumbaclass(&p->to, p); + o1 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7 + o2 = mvlh(REGTMPT, REGPC); // mov r7, pc + o3 = instoffset&0xffff; // $lab + o4 = (instoffset>>16)&0xffff; + break; + case 42: /* Bcc GBRA */ + thumbaclass(&p->to, p); + o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (6>>1); // bccnot + // ab lbra + o2 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7 + o3 = mvlh(REGTMPT, REGPC); // mov r7, pc + o4 = instoffset&0xffff; // $lab + o5 = (instoffset>>16)&0xffff; + break; + case 43: /* BL LBRA */ + thumbaclass(&p->to, p); + o1 = mvlh(REGPC, REGTMPT); // mov pc, r7 + o2 = (0x6<<11) | (REGTMPT<<8) | 10; // add 10, r7 + o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr + o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7 + o5 = mvlh(REGTMPT, REGPC); // mov r7, pc + o6 = instoffset&0xffff; // $lab + o7 = (instoffset>>16)&0xffff; + break; + case 44: /* BX LBRA */ +#ifdef CALLEEBX + diag("BX LBRA case"); +#endif + thumbaclass(&p->to, p); + if(p->to.sym->thumb) + instoffset |= 1; // T bit + o1 = mvlh(REGPC, REGTMPT); // mov pc, r7 + o2 = (0x6<<11) | (REGTMPT<<8) | 11; // add 11, r7 + o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr + o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7 + o5 = (0x11c<<6) | (REGTMPT<<3); // bx r7 + o6 = instoffset&0xffff; // $lab + o7 = (instoffset>>16)&0xffff; + break; + case 45: /* BX R when returning from fn */ + o1 = 0; + if(high(rt)){ + rt -= 8; + o1 |= 1<<6; + } + o1 |= (0x8e<<7) | (rt<<3); + break; + case 46: /* Bcc LBRA */ + thumbaclass(&p->to, p); + o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (0>>1); // bccnot + // ab lbra + instoffset -= 2; + numr(p, instoffset, -2048, 2046); + o2 = (0x1c<<11) | ((instoffset>>1)&0x7ff); + break; + case 47: /* mov $i, R where $i can be built */ + thumbaclass(&p->from, p); + mvcon(p, rt, instoffset, &o1, &o2); + break; + case 48: /* ACMP $i, r when $i built up */ + thumbaclass(&p->from, p); + lowreg(p, r); + mvcon(p, REGTMPT, instoffset, &o1, &o2); + o3 = (0x10a<<6) | (REGTMPT<<3) | r; + break; + case 49: /* AADD $i, r, r when $i is between 0 and 255 - could merge with case 36 */ + thumbaclass(&p->from, p); + lowreg(p, r); + lowreg(p, rt); + numr(p, instoffset, 0, 255); + o1 = mv(p, REGTMPT, instoffset); + o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; + o2 |= (REGTMPT<<6) | (r<<3) | rt; + break; + case 50: /* ADWORD */ + thumbaclass(&p->from, p); + o1 = instoffset&0xffff; + o2 = (instoffset>>16)&0xffff; + thumbaclass(&p->to, p); + o3 = instoffset&0xffff; + o4 = (instoffset>>16)&0xffff; + break; + case 51: /* BL r */ + o1 = mvlh(REGPC, REGLINK); // mov pc, lr + o2 = mvlh(rt, REGPC); // mov r, pc + break; + } + + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 2: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + hputl(o1); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux\t%P\n", v, o1, o2, p); + hputl(o1); + hputl(o2); + break; + case 6: + if(debug['a']) + Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p); + hputl(o1); + hputl(o2); + hputl(o3); + break; + case 8: + if(debug['a']) + Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, p); + hputl(o1); + hputl(o2); + hputl(o3); + hputl(o4); + break; + case 10: + if(debug['a']) + Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, p); + hputl(o1); + hputl(o2); + hputl(o3); + hputl(o4); + hputl(o5); + break; + case 12: + if(debug['a']) + Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, p); + hputl(o1); + hputl(o2); + hputl(o3); + hputl(o4); + hputl(o5); + hputl(o6); + break; + case 14: + if(debug['a']) + Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p); + hputl(o1); + hputl(o2); + hputl(o3); + hputl(o4); + hputl(o5); + hputl(o6); + hputl(o7); + break; + } + if(debug['G']){ + if(o->type == 17){ + print("%lx: word %ld\n", p->pc, (o2<<16)+o1); + return; + } + if(o->type == 50){ + print("%lx: word %ld\n", p->pc, (o2<<16)+o1); + print("%lx: word %ld\n", p->pc, (o4<<16)+o3); + return; + } + if(o->size > 0) dis(o1, p->pc); + if(o->size > 2) dis(o2, p->pc+2); + if(o->size > 4) dis(o3, p->pc+4); + if(o->size > 6) dis(o4, p->pc+6); + if(o->size > 8) dis(o5, p->pc+8); + if(o->size > 10) dis(o6, p->pc+10); + if(o->size > 12) dis(o7, p->pc+12); + // if(o->size > 14) dis(o8, p->pc+14); + } +} + +static long +thumboprr(int a) +{ + switch(a) { + case AMVN: return 0xf<<6; + case ACMP: return 0xa<<6; + case ACMN: return 0xb<<6; + case ATST: return 0x8<<6; + case AADC: return 0x5<<6; + case ASBC: return 0x6<<6; + case AMUL: + case AMULU: return 0xd<<6; + case AAND: return 0x0<<6; + case AEOR: return 0x1<<6; + case AORR: return 0xc<<6; + case ABIC: return 0xe<<6; + case ASRL: return 0x3<<6; + case ASRA: return 0x4<<6; + case ASLL: return 0x2<<6; + } + diag("bad thumbop oprr %d", a); + prasm(curp); + return 0; +} + +static long +thumbopirr(int a, int ld) +{ + if(ld) + diag("load in thumbopirr"); + switch(a){ + case AMOVW: return 0xc<<11; + case AMOVH: + case AMOVHU: return 0x10<<11; + case AMOVB: + case AMOVBU: return 0xe<<11; + } + return 0; +} + +static long +thumboprrr(int a, int ld) +{ + if(ld){ + switch(a){ + case AMOVW: return 0x2c<<9; + case AMOVH: return 0x2f<<9; + case AMOVB: return 0x2b<<9; + case AMOVHU: return 0x2d<<9; + case AMOVBU: return 0x2e<<9; + } + } + else{ + switch(a){ + case AMOVW: return 0x28<<9; + case AMOVHU: + case AMOVH: return 0x29<<9; + case AMOVBU: + case AMOVB: return 0x2a<<9; + } + } + diag("bad thumbop oprrr %d", a); + prasm(curp); + return 0; +} + +static long +thumbopri(int a) +{ + switch(a) { + case ASRL: return 0x1<<11; + case ASRA: return 0x2<<11; + case ASLL: return 0x0<<11; + case AADD: return 0x2<<11; + case ASUB: return 0x3<<11; + case AMOVW: return 0x0<<11; + case ACMP: return 0x1<<11; + } + diag("bad thumbop opri %d", a); + prasm(curp); + return 0; +} + +static long +thumbophh(int a) +{ + switch(a) { + case AADD: return 0x0<<8; + case AMOVW: return 0x2<<8; + case ACMP: return 0x1<<8; + } + diag("bad thumbop ophh %d", a); + prasm(curp); + return 0; +} + +static long +thumbopbra(int a) +{ + switch(a) { + case ABEQ: return 0x0<<8; + case ABNE: return 0x1<<8; + case ABCS: return 0x2<<8; + case ABHS: return 0x2<<8; + case ABCC: return 0x3<<8; + case ABLO: return 0x3<<8; + case ABMI: return 0x4<<8; + case ABPL: return 0x5<<8; + case ABVS: return 0x6<<8; + case ABVC: return 0x7<<8; + case ABHI: return 0x8<<8; + case ABLS: return 0x9<<8; + case ABGE: return 0xa<<8; + case ABLT: return 0xb<<8; + case ABGT: return 0xc<<8; + case ABLE: return 0xd<<8; + } + diag("bad thumbop opbra %d", a); + prasm(curp); + return 0; +} + +static long +thumbopmv(int a, int ld) +{ + switch(a) { + case AMOVW: return (ld ? 0xd : 0xc)<<11; + case AMOVH: + case AMOVHU: return (ld ? 0x11: 0x10)<<11; + case AMOVB: + case AMOVBU: return (ld ? 0xf : 0xe)<<11; + } + diag("bad thumbop opmv %d", a); + prasm(curp); + return 0; +} + +static void +lowreg(Prog *p, int r) +{ + if(high(r)) + diag("high reg [%P]", p); +} + +static void +mult(Prog *p, int n, int m) +{ + if(m*(n/m) != n) + diag("%d not M(%d) [%P]", n, m, p); +} + +static void +numr(Prog *p, int n, int min, int max) +{ + if(n < min || n > max) + diag("%d not in %d-%d [%P]", n, min, max, p); +} + +static void +regis(Prog *p, int r, int r1, int r2) +{ + if(r != r1 && r != r2) + diag("reg %d not %d or %d [%P]", r, r1, r2, p); +} + +void +hputl(int n) +{ + cbp[1] = n>>8; + cbp[0] = n; + cbp += 2; + cbc -= 2; + if(cbc <= 0) + cflush(); +} + +void +thumbcount() +{ + int i, c = 0, t = 0; + + for (i = 0; i < OPCNTSZ; i++) + t += opcount[i]; + if(t == 0) + return; + for (i = 0; i < OPCNTSZ; i++){ + c += opcount[i]; + print("%d: %d %d %d%%\n", i, opcount[i], c, (opcount[i]*100+t/2)/t); + } +} + +char *op1[] = { "lsl", "lsr", "asr" }; +char *op2[] = { "add", "sub" }; +char *op3[] = { "movw", "cmp", "add", "sub" }; +char *op4[] = { "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", + "tst", "neg", "cmp", "cmpn", "or", "mul", "bitc", "movn" }; +char *op5[] = { "add", "cmp", "movw", "bx" }; +char *op6[] = { "smovw", "smovh", "smovb", "lmovb", "lmovw", "lmovhu", "lmovbu", "lmovh" }; +char *op7[] = { "smovw", "lmovw", "smovb", "lmovbu" }; +char *op8[] = { "smovh", "lmovhu" }; +char *op9[] = { "smovw", "lmovw" }; +char *op10[] = { "push", "pop" }; +char *op11[] = { "stmia", "ldmia" }; + +char *cond[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" }; + +#define B(h, l) bits(i, h, l) +#define IMM(h, l) B(h, l) +#define REG(h, l) reg(B(h, l)) +#define LHREG(h, l, lh) lhreg(B(h, l), B(lh, lh)) +#define COND(h, l) cond[B(h, l)] +#define OP1(h, l) op1[B(h, l)] +#define OP2(h, l) op2[B(h, l)] +#define OP3(h, l) op3[B(h, l)] +#define OP4(h, l) op4[B(h, l)] +#define OP5(h, l) op5[B(h, l)] +#define OP6(h, l) op6[B(h, l)] +#define OP7(h, l) op7[B(h, l)] +#define OP8(h, l) op8[B(h, l)] +#define OP9(h, l) op9[B(h, l)] +#define OP10(h, l) op10[B(h, l)] +#define OP11(h, l) op11[B(h, l)] +#define SBZ(h, l) if(IMM(h, l) != 0) diag("%x: %x bits %d,%d not zero", pc, i, h, l) +#define SNBZ(h, l) if(IMM(h, l) == 0) diag("%x: %x bits %d,%d zero", pc, i, h, l) +#define SBO(h, l) if(IMM(h, l) != 1) diag("%x: %x bits %d,%d not one", pc, i, h, l) + +static int +bits(int i, int h, int l) +{ + if(h < l) + diag("h < l in bits"); + return (i&(((1<<(h-l+1))-1)<<l))>>l; +} + +static char * +reg(int r) +{ + static char s[4][4]; + static int i = 0; + + if(r < 0 || r > 7) + diag("register %d out of range", r); + i++; + if(i == 4) + i = 0; + sprint(s[i], "r%d", r); + return s[i]; +} + +static char *regnames[] = { "sp", "lr", "pc" }; + +static char * +lhreg(int r, int lh) +{ + static char s[4][4]; + static int i = 0; + + if(lh == 0) + return reg(r); + if(r < 0 || r > 7) + diag("high register %d out of range", r); + i++; + if(i == 4) + i = 0; + if(r >= 5) + sprint(s[i], "%s", regnames[r-5]); + else + sprint(s[i], "r%d", r+8); + return s[i]; +} + +static void +illegal(int i, int pc) +{ + diag("%x: %x illegal instruction", pc, i); +} + +static void +dis(int i, int pc) +{ + static int lasto; + int o, l; + char *op; + + print("%x: %x: ", pc, i); + if(i&0xffff0000) + illegal(i, pc); + o = B(15, 13); + switch(o){ + case 0: + o = B(12, 11); + switch(o){ + case 0: + case 1: + case 2: + print("%s %d, %s, %s\n", OP1(12, 11), IMM(10, 6), REG(5, 3), REG(2, 0)); + return; + case 3: + if(B(10, 10) == 0) + print("%s %s, %s, %s\n", OP2(9, 9), REG(8, 6), REG(5, 3), REG(2, 0)); + else + print("%s %d, %s, %s\n", OP2(9, 9), IMM(8, 6), REG(5, 3), REG(2, 0)); + return; + } + case 1: + print("%s %d, %s\n", OP3(12, 11), IMM(7, 0), REG(10, 8)); + return; + case 2: + o = B(12, 10); + if(o == 0){ + print("%s %s, %s\n", OP4(9, 6), REG(5, 3), REG(2, 0)); + return; + } + if(o == 1){ + o = B(9, 8); + if(o == 3){ + SBZ(7, 7); + SBZ(2, 0); + print("%s %s\n", OP5(9, 8), LHREG(5, 3, 6)); + return; + } + SNBZ(7, 6); + print("%s %s, %s\n", OP5(9, 8), LHREG(5, 3, 6), LHREG(2, 0, 7)); + return; + } + if(o == 2 || o == 3){ + print("movw %d(pc)[%x], %s\n", 4*IMM(7, 0), 4*IMM(7, 0)+pc+4, REG(10, 8)); + return; + } + op = OP6(11, 9); + if(*op == 'l') + print("%s [%s, %s], %s\n", op+1, REG(8, 6), REG(5, 3), REG(2, 0)); + else + print("%s %s, [%s, %s]\n", op+1, REG(2, 0), REG(8, 6), REG(5, 3)); + return; + case 3: + op = OP7(12, 11); + if(B(12, 11) == 0 || B(12,11) == 1) + l = 4; + else + l = 1; + if(*op == 'l') + print("%s %d(%s), %s\n", op+1, l*IMM(10, 6), REG(5, 3), REG(2, 0)); + else + print("%s %s, %d(%s)\n", op+1, REG(2, 0), l*IMM(10, 6), REG(5, 3)); + return; + case 4: + if(B(12, 12) == 0){ + op = OP8(11, 11); + if(*op == 'l') + print("%s %d(%s), %s\n", op+1, 2*IMM(10, 6), REG(5, 3), REG(2, 0)); + else + print("%s %s, %d(%s)\n", op+1, REG(2, 0), 2*IMM(10, 6), REG(5, 3)); + return; + } + op = OP9(11, 11); + if(*op == 'l') + print("%s %d(sp), %s\n", op+1, 4*IMM(7, 0), REG(10, 8)); + else + print("%s %s, %d(sp)\n", op+1, REG(10, 8), 4*IMM(7, 0)); + return; + case 5: + if(B(12, 12) == 0){ + if(B(11, 11) == 0) + print("add %d, pc, %s\n", 4*IMM(7, 0), REG(10, 8)); + else + print("add %d, sp, %s\n", 4*IMM(7, 0), REG(10, 8)); + return; + } + if(B(11, 8) == 0){ + print("%s %d, sp\n", OP2(7, 7), 4*IMM(6, 0)); + return; + } + SBO(10, 10); + SBZ(9, 9); + if(B(8, 8) == 0) + print("%s sp, %d\n", OP10(11, 11), IMM(7, 0)); + else + print("%s sp, %d|15\n", OP10(11, 11), IMM(7, 0)); + return; + case 6: + if(B(12, 12) == 0){ + print("%s %s, %d\n", OP11(11, 11), REG(10, 8), IMM(7, 0)); + return; + } + if(B(11, 8) == 0xf){ + print("swi %d\n", IMM(7, 0)); + return; + } + o = IMM(7, 0); + if(o&0x80) + o |= 0xffffff00; + o = pc+4+(o<<1); + print("b%s %x\n", COND(11, 8), o); + return; + case 7: + o = B(12, 11); + switch(o){ + case 0: + o = IMM(10, 0); + if(o&0x400) + o |= 0xfffff800; + o = pc+4+(o<<1); + print("b %x\n", o); + return; + case 1: + illegal(i, pc); + return; + case 2: + lasto = IMM(10, 0); + print("bl\n"); + return; + case 3: + if(lasto&0x400) + lasto |= 0xfffff800; + o = IMM(10, 0); + o = (pc-2)+4+(o<<1)+(lasto<<12); + print("bl %x\n", o); + return; + } + } +} diff --git a/utils/6c/6.out.h b/utils/6c/6.out.h new file mode 100644 index 00000000..0766ea3d --- /dev/null +++ b/utils/6c/6.out.h @@ -0,0 +1,820 @@ +#define NSYM 50 +#define NSNAME 8 +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +/* + * amd64 + */ + +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, + ADECQ, + ADECW, + ADIVB, + ADIVL, + ADIVW, + AENTER, + AGLOBL, + AGOK, + AHISTORY, + AHLT, + AIDIVB, + AIDIVL, + AIDIVW, + AIMULB, + AIMULL, + AIMULW, + AINB, + AINL, + AINW, + AINCB, + AINCL, + AINCQ, + 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, + AMOVBQSX, + AMOVBQZX, + AMOVBWSX, + AMOVBWZX, + AMOVWLSX, + AMOVWLZX, + AMOVWQSX, + AMOVWQZX, + 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, + + /* extra 32-bit operations */ + ACMPXCHGB, + ACMPXCHGL, + ACMPXCHGW, + ACMPXCHG8B, + ACPUID, + AINVD, + AINVLPG, + ALFENCE, + AMFENCE, + AMOVNTIL, + ARDMSR, + ARDPMC, + ARDTSC, + ARSM, + ASFENCE, + ASYSRET, + AWBINVD, + AWRMSR, + AXADDB, + AXADDL, + AXADDW, + + /* conditional move */ + ACMOVLCC, + ACMOVLCS, + ACMOVLEQ, + ACMOVLGE, + ACMOVLGT, + ACMOVLHI, + ACMOVLLE, + ACMOVLLS, + ACMOVLLT, + ACMOVLMI, + ACMOVLNE, + ACMOVLOC, + ACMOVLOS, + ACMOVLPC, + ACMOVLPL, + ACMOVLPS, + ACMOVQCC, + ACMOVQCS, + ACMOVQEQ, + ACMOVQGE, + ACMOVQGT, + ACMOVQHI, + ACMOVQLE, + ACMOVQLS, + ACMOVQLT, + ACMOVQMI, + ACMOVQNE, + ACMOVQOC, + ACMOVQOS, + ACMOVQPC, + ACMOVQPL, + ACMOVQPS, + ACMOVWCC, + ACMOVWCS, + ACMOVWEQ, + ACMOVWGE, + ACMOVWGT, + ACMOVWHI, + ACMOVWLE, + ACMOVWLS, + ACMOVWLT, + ACMOVWMI, + ACMOVWNE, + ACMOVWOC, + ACMOVWOS, + ACMOVWPC, + ACMOVWPL, + ACMOVWPS, + + /* 64-bit */ + AADCQ, + AADDQ, + AANDQ, + ABSFQ, + ABSRQ, + ABTCQ, + ABTQ, + ABTRQ, + ABTSQ, + ACMPQ, + ACMPSQ, + ACMPXCHGQ, + ACQO, + ADIVQ, + AIDIVQ, + AIMULQ, + AIRETQ, + ALEAQ, + ALEAVEQ, + ALODSQ, + AMOVQ, + AMOVLQSX, + AMOVLQZX, + AMOVNTIQ, + AMOVSQ, + AMULQ, + ANEGQ, + ANOTQ, + AORQ, + APOPFQ, + APOPQ, + APUSHFQ, + APUSHQ, + ARCLQ, + ARCRQ, + AROLQ, + ARORQ, + AQUAD, + ASALQ, + ASARQ, + ASBBQ, + ASCASQ, + ASHLQ, + ASHRQ, + ASTOSQ, + ASUBQ, + ATESTQ, + AXADDQ, + AXCHGQ, + AXORQ, + + /* media */ + AADDPD, + AADDPS, + AADDSD, + AADDSS, + AANDNPD, + AANDNPS, + AANDPD, + AANDPS, + ACMPPD, + ACMPPS, + ACMPSD, + ACMPSS, + ACOMISD, + ACOMISS, + ACVTPD2PL, + ACVTPD2PS, + ACVTPL2PD, + ACVTPL2PS, + ACVTPS2PD, + ACVTPS2PL, + ACVTSD2SL, + ACVTSD2SQ, + ACVTSD2SS, + ACVTSL2SD, + ACVTSL2SS, + ACVTSQ2SD, + ACVTSQ2SS, + ACVTSS2SD, + ACVTSS2SL, + ACVTSS2SQ, + ACVTTPD2PL, + ACVTTPS2PL, + ACVTTSD2SL, + ACVTTSD2SQ, + ACVTTSS2SL, + ACVTTSS2SQ, + ADIVPD, + ADIVPS, + ADIVSD, + ADIVSS, + AEMMS, + AFXRSTOR, + AFXRSTOR64, + AFXSAVE, + AFXSAVE64, + ALDMXCSR, + AMASKMOVOU, + AMASKMOVQ, + AMAXPD, + AMAXPS, + AMAXSD, + AMAXSS, + AMINPD, + AMINPS, + AMINSD, + AMINSS, + AMOVAPD, + AMOVAPS, + AMOVOU, + AMOVHLPS, + AMOVHPD, + AMOVHPS, + AMOVLHPS, + AMOVLPD, + AMOVLPS, + AMOVMSKPD, + AMOVMSKPS, + AMOVNTO, + AMOVNTPD, + AMOVNTPS, + AMOVNTQ, + AMOVO, + AMOVQOZX, + AMOVSD, + AMOVSS, + AMOVUPD, + AMOVUPS, + AMULPD, + AMULPS, + AMULSD, + AMULSS, + AORPD, + AORPS, + APACKSSLW, + APACKSSWB, + APACKUSWB, + APADDB, + APADDL, + APADDQ, + APADDSB, + APADDSW, + APADDUSB, + APADDUSW, + APADDW, + APANDB, + APANDL, + APANDSB, + APANDSW, + APANDUSB, + APANDUSW, + APANDW, + APAND, + APANDN, + APAVGB, + APAVGW, + APCMPEQB, + APCMPEQL, + APCMPEQW, + APCMPGTB, + APCMPGTL, + APCMPGTW, + APEXTRW, + APFACC, + APFADD, + APFCMPEQ, + APFCMPGE, + APFCMPGT, + APFMAX, + APFMIN, + APFMUL, + APFNACC, + APFPNACC, + APFRCP, + APFRCPIT1, + APFRCPI2T, + APFRSQIT1, + APFRSQRT, + APFSUB, + APFSUBR, + APINSRW, + APMADDWL, + APMAXSW, + APMAXUB, + APMINSW, + APMINUB, + APMOVMSKB, + APMULHRW, + APMULHUW, + APMULHW, + APMULLW, + APMULULQ, + APOR, + APSADBW, + APSHUFHW, + APSHUFL, + APSHUFLW, + APSHUFW, + APSLLO, + APSLLL, + APSLLQ, + APSLLW, + APSRAL, + APSRAW, + APSRLO, + APSRLL, + APSRLQ, + APSRLW, + APSUBB, + APSUBL, + APSUBQ, + APSUBSB, + APSUBSW, + APSUBUSB, + APSUBUSW, + APSUBW, + APSWAPL, + APUNPCKHBW, + APUNPCKHLQ, + APUNPCKHQDQ, + APUNPCKHWL, + APUNPCKLBW, + APUNPCKLLQ, + APUNPCKLQDQ, + APUNPCKLWL, + APXOR, + ARCPPS, + ARCPSS, + ARSQRTPS, + ARSQRTSS, + ASHUFPD, + ASHUFPS, + ASQRTPD, + ASQRTPS, + ASQRTSD, + ASQRTSS, + ASTMXCSR, + ASUBPD, + ASUBPS, + ASUBSD, + ASUBSS, + AUCOMISD, + AUCOMISS, + AUNPCKHPD, + AUNPCKHPS, + AUNPCKLPD, + AUNPCKLPS, + AXORPD, + AXORPS, + + APF2IW, + APF2IL, + API2FW, + API2FL, + ARETFW, + ARETFL, + ARETFQ, + ASWAPGS, + + AMODE, + + ALAST +}; + +enum +{ + + D_AL = 0, + D_CL, + D_DL, + D_BL, + D_SPB, + D_BPB, + D_SIB, + D_DIB, + D_R8B, + D_R9B, + D_R10B, + D_R11B, + D_R12B, + D_R13B, + D_R14B, + D_R15B, + + D_AX = 16, + D_CX, + D_DX, + D_BX, + D_SP, + D_BP, + D_SI, + D_DI, + D_R8, + D_R9, + D_R10, + D_R11, + D_R12, + D_R13, + D_R14, + D_R15, + + D_AH = 32, + D_CH, + D_DH, + D_BH, + + D_F0 = 36, + + D_M0 = 44, + + D_X0 = 52, + + D_CS = 68, + 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 = 79, + D_DR = 95, + D_TR = 103, + + D_NONE = 111, + + D_BRANCH = 112, + D_EXTERN = 113, + D_STATIC = 114, + D_AUTO = 115, + D_PARAM = 116, + D_CONST = 117, + D_FCONST = 118, + D_SCONST = 119, + D_ADDR = 120, + + 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, + T_64 = 1<<6, + + REGARG = D_BP, /* MIGHT CHANGE */ + REGRET = D_AX, + FREGRET = D_X0, + REGSP = D_SP, + REGTMP = D_DI, + REGEXT = D_R15, /* compiler allocates external registers R15 down */ + FREGMIN = D_X0+5, /* first register variable */ + FREGEXT = D_X0+7 /* first external register */ +}; + +/* + * 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 */ +}; diff --git a/utils/8a/a.h b/utils/8a/a.h new file mode 100644 index 00000000..82afc593 --- /dev/null +++ b/utils/8a/a.h @@ -0,0 +1,194 @@ +#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); diff --git a/utils/8a/a.y b/utils/8a/a.y new file mode 100644 index 00000000..167234b4 --- /dev/null +++ b/utils/8a/a.y @@ -0,0 +1,520 @@ +%{ +#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; + } diff --git a/utils/8a/l.s b/utils/8a/l.s new file mode 100644 index 00000000..09980d48 --- /dev/null +++ b/utils/8a/l.s @@ -0,0 +1,704 @@ +/* + * 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 diff --git a/utils/8a/lex.c b/utils/8a/lex.c new file mode 100644 index 00000000..0ec4dc17 --- /dev/null +++ b/utils/8a/lex.c @@ -0,0 +1,895 @@ +#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" diff --git a/utils/8a/mkfile b/utils/8a/mkfile new file mode 100644 index 00000000..b021d34f --- /dev/null +++ b/utils/8a/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=8a + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../8c/8.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/8c/8.out.h b/utils/8c/8.out.h new file mode 100644 index 00000000..fdfd0ca7 --- /dev/null +++ b/utils/8c/8.out.h @@ -0,0 +1,445 @@ +#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 */ +}; diff --git a/utils/8c/cgen.c b/utils/8c/cgen.c new file mode 100644 index 00000000..81521666 --- /dev/null +++ b/utils/8c/cgen.c @@ -0,0 +1,1821 @@ +#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]--; + } +} diff --git a/utils/8c/cgen64.c b/utils/8c/cgen64.c new file mode 100644 index 00000000..6a1e835e --- /dev/null +++ b/utils/8c/cgen64.c @@ -0,0 +1,2711 @@ +#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); + } + } +} diff --git a/utils/8c/div.c b/utils/8c/div.c new file mode 100644 index 00000000..cb588678 --- /dev/null +++ b/utils/8c/div.c @@ -0,0 +1,206 @@ +#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); +} diff --git a/utils/8c/enam.c b/utils/8c/enam.c new file mode 100644 index 00000000..3e293a28 --- /dev/null +++ b/utils/8c/enam.c @@ -0,0 +1,337 @@ +char* anames[] = +{ + "XXX", + "AAA", + "AAD", + "AAM", + "AAS", + "ADCB", + "ADCL", + "ADCW", + "ADDB", + "ADDL", + "ADDW", + "ADJSP", + "ANDB", + "ANDL", + "ANDW", + "ARPL", + "BOUNDL", + "BOUNDW", + "BSFL", + "BSFW", + "BSRL", + "BSRW", + "BTL", + "BTW", + "BTCL", + "BTCW", + "BTRL", + "BTRW", + "BTSL", + "BTSW", + "BYTE", + "CALL", + "CLC", + "CLD", + "CLI", + "CLTS", + "CMC", + "CMPB", + "CMPL", + "CMPW", + "CMPSB", + "CMPSL", + "CMPSW", + "DAA", + "DAS", + "DATA", + "DECB", + "DECL", + "DECW", + "DIVB", + "DIVL", + "DIVW", + "ENTER", + "GLOBL", + "GOK", + "HISTORY", + "HLT", + "IDIVB", + "IDIVL", + "IDIVW", + "IMULB", + "IMULL", + "IMULW", + "INB", + "INL", + "INW", + "INCB", + "INCL", + "INCW", + "INSB", + "INSL", + "INSW", + "INT", + "INTO", + "IRETL", + "IRETW", + "JCC", + "JCS", + "JCXZ", + "JEQ", + "JGE", + "JGT", + "JHI", + "JLE", + "JLS", + "JLT", + "JMI", + "JMP", + "JNE", + "JOC", + "JOS", + "JPC", + "JPL", + "JPS", + "LAHF", + "LARL", + "LARW", + "LEAL", + "LEAW", + "LEAVEL", + "LEAVEW", + "LOCK", + "LODSB", + "LODSL", + "LODSW", + "LONG", + "LOOP", + "LOOPEQ", + "LOOPNE", + "LSLL", + "LSLW", + "MOVB", + "MOVL", + "MOVW", + "MOVBLSX", + "MOVBLZX", + "MOVBWSX", + "MOVBWZX", + "MOVWLSX", + "MOVWLZX", + "MOVSB", + "MOVSL", + "MOVSW", + "MULB", + "MULL", + "MULW", + "NAME", + "NEGB", + "NEGL", + "NEGW", + "NOP", + "NOTB", + "NOTL", + "NOTW", + "ORB", + "ORL", + "ORW", + "OUTB", + "OUTL", + "OUTW", + "OUTSB", + "OUTSL", + "OUTSW", + "POPAL", + "POPAW", + "POPFL", + "POPFW", + "POPL", + "POPW", + "PUSHAL", + "PUSHAW", + "PUSHFL", + "PUSHFW", + "PUSHL", + "PUSHW", + "RCLB", + "RCLL", + "RCLW", + "RCRB", + "RCRL", + "RCRW", + "REP", + "REPN", + "RET", + "ROLB", + "ROLL", + "ROLW", + "RORB", + "RORL", + "RORW", + "SAHF", + "SALB", + "SALL", + "SALW", + "SARB", + "SARL", + "SARW", + "SBBB", + "SBBL", + "SBBW", + "SCASB", + "SCASL", + "SCASW", + "SETCC", + "SETCS", + "SETEQ", + "SETGE", + "SETGT", + "SETHI", + "SETLE", + "SETLS", + "SETLT", + "SETMI", + "SETNE", + "SETOC", + "SETOS", + "SETPC", + "SETPL", + "SETPS", + "CDQ", + "CWD", + "SHLB", + "SHLL", + "SHLW", + "SHRB", + "SHRL", + "SHRW", + "STC", + "STD", + "STI", + "STOSB", + "STOSL", + "STOSW", + "SUBB", + "SUBL", + "SUBW", + "SYSCALL", + "TESTB", + "TESTL", + "TESTW", + "TEXT", + "VERR", + "VERW", + "WAIT", + "WORD", + "XCHGB", + "XCHGL", + "XCHGW", + "XLAT", + "XORB", + "XORL", + "XORW", + "FMOVB", + "FMOVBP", + "FMOVD", + "FMOVDP", + "FMOVF", + "FMOVFP", + "FMOVL", + "FMOVLP", + "FMOVV", + "FMOVVP", + "FMOVW", + "FMOVWP", + "FMOVX", + "FMOVXP", + "FCOMB", + "FCOMBP", + "FCOMD", + "FCOMDP", + "FCOMDPP", + "FCOMF", + "FCOMFP", + "FCOML", + "FCOMLP", + "FCOMW", + "FCOMWP", + "FUCOM", + "FUCOMP", + "FUCOMPP", + "FADDDP", + "FADDW", + "FADDL", + "FADDF", + "FADDD", + "FMULDP", + "FMULW", + "FMULL", + "FMULF", + "FMULD", + "FSUBDP", + "FSUBW", + "FSUBL", + "FSUBF", + "FSUBD", + "FSUBRDP", + "FSUBRW", + "FSUBRL", + "FSUBRF", + "FSUBRD", + "FDIVDP", + "FDIVW", + "FDIVL", + "FDIVF", + "FDIVD", + "FDIVRDP", + "FDIVRW", + "FDIVRL", + "FDIVRF", + "FDIVRD", + "FXCHD", + "FFREE", + "FLDCW", + "FLDENV", + "FRSTOR", + "FSAVE", + "FSTCW", + "FSTENV", + "FSTSW", + "F2XM1", + "FABS", + "FCHS", + "FCLEX", + "FCOS", + "FDECSTP", + "FINCSTP", + "FINIT", + "FLD1", + "FLDL2E", + "FLDL2T", + "FLDLG2", + "FLDLN2", + "FLDPI", + "FLDZ", + "FNOP", + "FPATAN", + "FPREM", + "FPREM1", + "FPTAN", + "FRNDINT", + "FSCALE", + "FSIN", + "FSINCOS", + "FSQRT", + "FTST", + "FXAM", + "FXTRACT", + "FYL2X", + "FYL2XP1", + "END", + "DYNT", + "INIT", + "SIGNAME", + "LAST", +}; diff --git a/utils/8c/gc.h b/utils/8c/gc.h new file mode 100644 index 00000000..4aeb11c0 --- /dev/null +++ b/utils/8c/gc.h @@ -0,0 +1,374 @@ +#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 diff --git a/utils/8c/list.c b/utils/8c/list.c new file mode 100644 index 00000000..8ee83383 --- /dev/null +++ b/utils/8c/list.c @@ -0,0 +1,282 @@ +#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); +} diff --git a/utils/8c/machcap.c b/utils/8c/machcap.c new file mode 100644 index 00000000..3a8831a7 --- /dev/null +++ b/utils/8c/machcap.c @@ -0,0 +1,86 @@ +#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; +} diff --git a/utils/8c/mkenam b/utils/8c/mkenam new file mode 100644 index 00000000..f6364a34 --- /dev/null +++ b/utils/8c/mkenam @@ -0,0 +1,15 @@ +ed - ../8c/8.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/utils/8c/mkfile b/utils/8c/mkfile new file mode 100644 index 00000000..729cff24 --- /dev/null +++ b/utils/8c/mkfile @@ -0,0 +1,35 @@ +<../../mkconfig + +TARG=8c + +OFILES=\ + cgen.$O\ + enam.$O\ + list.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + reg.$O\ + peep.$O\ + machcap.$O\ + cgen64.$O\ + div.$O\ + mul.$O\ + +HFILES=\ + gc.h\ + 8.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/8c/mul.c b/utils/8c/mul.c new file mode 100644 index 00000000..a60908c6 --- /dev/null +++ b/utils/8c/mul.c @@ -0,0 +1,428 @@ +#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); +} diff --git a/utils/8c/peep.c b/utils/8c/peep.c new file mode 100644 index 00000000..8a2d79b7 --- /dev/null +++ b/utils/8c/peep.c @@ -0,0 +1,757 @@ +#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; +} diff --git a/utils/8c/reg.c b/utils/8c/reg.c new file mode 100644 index 00000000..12ad50ab --- /dev/null +++ b/utils/8c/reg.c @@ -0,0 +1,1255 @@ +#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; +} diff --git a/utils/8c/sgen.c b/utils/8c/sgen.c new file mode 100644 index 00000000..f5fb2090 --- /dev/null +++ b/utils/8c/sgen.c @@ -0,0 +1,842 @@ +#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; +} diff --git a/utils/8c/swt.c b/utils/8c/swt.c new file mode 100644 index 00000000..02f3a1de --- /dev/null +++ b/utils/8c/swt.c @@ -0,0 +1,647 @@ +#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; +} diff --git a/utils/8c/txt.c b/utils/8c/txt.c new file mode 100644 index 00000000..841116ab --- /dev/null +++ b/utils/8c/txt.c @@ -0,0 +1,1410 @@ +#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, ®node); + gins(AFMOVLP, f, &nod); + gmove(&nod, t); + return; + } + regsalloc(&nod, ®node); + regsalloc(&nod1, ®node); + 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, ®node); + 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, ®node); + 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, ®node, 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, ®node, 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, ®node, 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]*/ +}; diff --git a/utils/8l/Nt.c b/utils/8l/Nt.c new file mode 100644 index 00000000..73c6f795 --- /dev/null +++ b/utils/8l/Nt.c @@ -0,0 +1,77 @@ +#include <windows.h> +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/8l/Plan9.c b/utils/8l/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/8l/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/8l/Posix.c b/utils/8l/Posix.c new file mode 100644 index 00000000..0da0ee0c --- /dev/null +++ b/utils/8l/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fails if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} diff --git a/utils/8l/asm.c b/utils/8l/asm.c new file mode 100644 index 00000000..56eee141 --- /dev/null +++ b/utils/8l/asm.c @@ -0,0 +1,502 @@ +#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; +} diff --git a/utils/8l/l.h b/utils/8l/l.h new file mode 100644 index 00000000..5c274418 --- /dev/null +++ b/utils/8l/l.h @@ -0,0 +1,349 @@ +#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 diff --git a/utils/8l/list.c b/utils/8l/list.c new file mode 100644 index 00000000..7fea4cb9 --- /dev/null +++ b/utils/8l/list.c @@ -0,0 +1,292 @@ +#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(); + } +} diff --git a/utils/8l/mkfile b/utils/8l/mkfile new file mode 100644 index 00000000..aa383d07 --- /dev/null +++ b/utils/8l/mkfile @@ -0,0 +1,29 @@ +<../../mkconfig + +TARG=8l + +OFILES=\ + asm.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + list.$O\ + enam.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../8c/8.out.h\ + ../include/ar.h\ + +LIBS=bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +enam.$O: ../8c/enam.c + $CC $CFLAGS ../8c/enam.c diff --git a/utils/8l/obj.c b/utils/8l/obj.c new file mode 100644 index 00000000..07e5c53f --- /dev/null +++ b/utils/8l/obj.c @@ -0,0 +1,1492 @@ +#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); +} diff --git a/utils/8l/optab.c b/utils/8l/optab.c new file mode 100644 index 00000000..361125f7 --- /dev/null +++ b/utils/8l/optab.c @@ -0,0 +1,654 @@ +#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 +}; diff --git a/utils/8l/pass.c b/utils/8l/pass.c new file mode 100644 index 00000000..9f54d614 --- /dev/null +++ b/utils/8l/pass.c @@ -0,0 +1,763 @@ +#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); +} diff --git a/utils/8l/span.c b/utils/8l/span.c new file mode 100644 index 00000000..ef135474 --- /dev/null +++ b/utils/8l/span.c @@ -0,0 +1,1387 @@ +#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); + } +} diff --git a/utils/NOTICE b/utils/NOTICE new file mode 100644 index 00000000..23704de9 --- /dev/null +++ b/utils/NOTICE @@ -0,0 +1,34 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + 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-2006 Vita Nuova Holdings Limited (www.vitanuova.com) + Portions Copyright © 2004,2006 Bruce Ellis + Portions Copyright © 2006,2006 C H Forsyth (forsyth@terzarima.net) + Revisions Copyright © 2000-2006 Lucent Technologies Inc. and others + +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. + diff --git a/utils/acid/386 b/utils/acid/386 new file mode 100644 index 00000000..53f4ce22 --- /dev/null +++ b/utils/acid/386 @@ -0,0 +1,146 @@ +// 386 support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'b'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/386/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files + Labspoff = 4; // adjustment to Label's sp + Labpcoff = 0; // adjustment to Label's pc +} + +defn linkreg(addr) +{ + return 0; +} + +defn stk() // trace +{ + _stk(*PC, *SP, 0, 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *SP, 0, 1); +} + +defn kstk() // kernel stack +{ + _stk(*PC-Labpcoff, *SP-Labspoff, 0, 0); +} + +defn lkstk() // kernel stack and locals +{ + _stk(*PC-Labpcoff, *SP-Labspoff, 0, 1); +} +defn gpr() // print general(hah hah!) purpose registers +{ + print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n"); + print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n"); +} + +defn spr() // print special processor registers +{ + local pc; + local cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n"); + print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n"); + print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n"); + + cause = *TRAP; + print("TRAP\t", cause, " ", reason(cause), "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l; + local pc; + + pc = *PC; + + print(pid,": ", reason(*TRAP), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +aggr Ureg +{ + 'U' 0 di; + 'U' 4 si; + 'U' 8 bp; + 'U' 12 nsp; + 'U' 16 bx; + 'U' 20 dx; + 'U' 24 cx; + 'U' 28 ax; + 'U' 32 gs; + 'U' 36 fs; + 'U' 40 es; + 'U' 44 ds; + 'U' 48 trap; + 'U' 52 ecode; + 'U' 56 pc; + 'U' 60 cs; + 'U' 64 flags; + { + 'U' 68 usp; + 'U' 68 sp; + }; + 'U' 72 ss; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" di ", addr.di, "\n"); + print(" si ", addr.si, "\n"); + print(" bp ", addr.bp, "\n"); + print(" nsp ", addr.nsp, "\n"); + print(" bx ", addr.bx, "\n"); + print(" dx ", addr.dx, "\n"); + print(" cx ", addr.cx, "\n"); + print(" ax ", addr.ax, "\n"); + print(" gs ", addr.gs, "\n"); + print(" fs ", addr.fs, "\n"); + print(" es ", addr.es, "\n"); + print(" ds ", addr.ds, "\n"); + print(" trap ", addr.trap, "\n"); + print(" ecode ", addr.ecode, "\n"); + print(" pc ", addr.pc, "\n"); + print(" cs ", addr.cs, "\n"); + print(" flags ", addr.flags, "\n"); + print(" sp ", addr.sp, "\n"); + print("}\n"); + print(" ss ", addr.ss, "\n"); +}; + +print("/sys/lib/acid/386"); diff --git a/utils/acid/B.sh b/utils/acid/B.sh new file mode 100644 index 00000000..15570c7d --- /dev/null +++ b/utils/acid/B.sh @@ -0,0 +1,7 @@ +#!/bin/sh +line=`/bin/echo $1 | /bin/sed 's/-//'` +if [ "x$EDITOR" = "x" ] ; then + vi +$line $2 +else + $EDITOR +$line $2 +fi diff --git a/utils/acid/acid.h b/utils/acid/acid.h new file mode 100644 index 00000000..68c8913d --- /dev/null +++ b/utils/acid/acid.h @@ -0,0 +1,317 @@ +/* acid.h */ +enum +{ + Eof = -1, + Strsize = 4096, + Hashsize = 128, + Maxarg = 512, + NFD = 100, + Maxproc = 50, + Maxval = 10, + Mempergc = 1024*1024, +}; + +#pragma varargck type "L" void + +typedef struct Node Node; +typedef struct String String; +typedef struct Lsym Lsym; +typedef struct List List; +typedef struct Store Store; +typedef struct Gc Gc; +typedef struct Strc Strc; +typedef struct Rplace Rplace; +typedef struct Ptab Ptab; +typedef struct Value Value; +typedef struct Type Type; +typedef struct Frtype Frtype; + +Extern int kernel; +Extern int remote; +Extern int rdebug; +Extern int remfd; +Extern int protodebug; +Extern int text; +Extern int silent; +Extern Fhdr fhdr; +Extern int line; +Extern Biobuf* bout; +Extern Biobuf* io[32]; +Extern int iop; +Extern char symbol[Strsize]; +Extern int interactive; +Extern Node* code; +Extern int na; +Extern int wtflag; +Extern Map* cormap; +Extern Map* symmap; +Extern Lsym* hash[Hashsize]; +Extern long dogc; +Extern Rplace* ret; +Extern char* filename; +Extern char* aout; +Extern int gotint; +Extern long flen; +Extern Gc* gcl; +Extern int stacked; +Extern jmp_buf err; +Extern Node* prnt; +Extern Node* fomt; +Extern List* tracelist; +Extern int initialising; +Extern int quiet; +extern void (*expop[])(Node*, Node*); +#define expr(n, r) (r)->nstore.comt=0; (*expop[(n)->op])(n, r); + +enum +{ + TINT, + TFLOAT, + TSTRING, + TLIST, + TCODE, +}; + +struct Type +{ + Type* next; + int offset; + char fmt; + char depth; + Lsym* type; + Lsym* tag; + Lsym* base; +}; + +struct Frtype +{ + Lsym* var; + Type* type; + Frtype* next; +}; + +struct Ptab +{ + int pid; + int ctl; +}; +Extern Ptab ptab[Maxproc]; + +struct Rplace +{ + jmp_buf rlab; + Node* stak; + Node* val; + Lsym* local; + Lsym** tail; +}; + +struct Gc +{ + char gcmark; + Gc* gclink; +}; + +struct Store +{ + char fmt; + Type* comt; + union { + vlong sival; + double sfval; + String* sstring; + List* sl; + Node* scc; + } u0; +}; + +struct List +{ + Gc lgc; + List* next; + char type; + Store lstore; +}; + +struct Value +{ + char set; + char type; + Store vstore; + Value* pop; + Lsym* scope; + Rplace* ret; +}; + +struct Lsym +{ + char* name; + int lexval; + Lsym* hash; + Value* v; + Type* lt; + Node* proc; + Frtype* local; + void (*builtin)(Node*, Node*); +}; + +struct Node +{ + Gc ngc; + char op; + char type; + Node* left; + Node* right; + Lsym* sym; + Store nstore; +}; +#define ZN (Node*)0 + +struct String +{ + Gc sgc; + char *string; + int len; +}; + +List* addlist(List*, List*); +List* al(int); +Node* an(int, Node*, Node*); +void append(Node*, Node*, Node*); +int bool(Node*); +void build(Node*); +void call(char*, Node*, Node*, Node*, Node*); +void checkqid(int, int); +void cmd(void); +Node* con(int); +List* construct(Node*); +void ctrace(int); +void decl(Node*); +void defcomplex(Node*, Node*); +void deinstall(int); +void delete(List*, int n, Node*); +void detach(void); +void dostop(int); +Lsym* enter(char*, int); +void error(char*, ...); +void execute(Node*); +void fatal(char*, ...); +ulong findframe(ulong); +void flatten(Node**, Node*); +void gc(void); +char* getstatus(int); +void* gmalloc(long); +void indir(Map*, ulong, char, Node*); +void install(int); +void installbuiltin(void); +void kinit(void); +int Lfmt(Fmt*); +int listcmp(List*, List*); +int listlen(List*); +List* listvar(char*, long); +void loadmodule(char*); +void loadvars(void); +Lsym* look(char*); +void ltag(char*); +void setup_os_notify(void); +void marklist(List*); +Lsym* mkvar(char*); +void msg(int, char*); +void notes(int); +int nproc(char**); +void nthelem(List*, int, Node*); +int numsym(char); +void odot(Node*, Node*); +int opentty(char*, int); +void closetty(int); +void pcode(Node*, int); +void pexpr(Node*); +int popio(void); +void pstr(String*); +void pushfile(char*); +void pushstr(Node*); +ulong raddr(char*); +void readtext(char*); +int remcondset(char, ulong); +int remcondstartstop(int); +int remget(struct segment*, ulong, long, char*, int); +int remoteio(int, char*, char*, int); +int remote_read(int, char*, int); +int remote_write(int, char*, int); +int remput(struct segment*, ulong, long, char*, int); +void restartio(void); +vlong rget(Map*, char*); +String *runenode(Rune*); +char* runcmd(char*); +int scmp(String*, String*); +void setdbg_opt(char, int); +int sendremote(int, char*); +void sproc(int); +String* stradd(String*, String*); +String* strnode(char*); +String* strnodlen(char*, int); +char* mysystem(void); +void trlist(Map*, ulong, ulong, Symbol*); +void unwind(void); +void userinit(void); +void varreg(void); +void varsym(void); +char* waitfor(int); +void whatis(Lsym*); +void windir(Map*, Node*, Node*, Node*); +void yyerror(char*, ...); +int yylex(void); +int yyparse(void); + +enum +{ + ONAME, + OCONST, + OMUL, + ODIV, + OMOD, + OADD, + OSUB, + ORSH, + OLSH, + OLT, + OGT, + OLEQ, + OGEQ, + OEQ, + ONEQ, + OLAND, + OXOR, + OLOR, + OCAND, + OCOR, + OASGN, + OINDM, + OEDEC, + OEINC, + OPINC, + OPDEC, + ONOT, + OIF, + ODO, + OLIST, + OCALL, + OCTRUCT, + OWHILE, + OELSE, + OHEAD, + OTAIL, + OAPPEND, + ORET, + OINDEX, + OINDC, + ODOT, + OLOCAL, + OFRAME, + OCOMPLEX, + ODELETE, + OCAST, + OFMT, + OEVAL, + OWHAT, +}; diff --git a/utils/acid/arm b/utils/acid/arm new file mode 100644 index 00000000..79f6eb14 --- /dev/null +++ b/utils/acid/arm @@ -0,0 +1 @@ +please remove this file diff --git a/utils/acid/builtin.c b/utils/acid/builtin.c new file mode 100644 index 00000000..2afc447b --- /dev/null +++ b/utils/acid/builtin.c @@ -0,0 +1,1285 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#include "regexp.h" +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +void cvtatof(Node*, Node*); +void cvtatoi(Node*, Node*); +void cvtitoa(Node*, Node*); +void bprint(Node*, Node*); +void funcbound(Node*, Node*); +void printto(Node*, Node*); +void getfile(Node*, Node*); +void fmt(Node*, Node*); +void pcfile(Node*, Node*); +void pcline(Node*, Node*); +void setproc(Node*, Node*); +void strace(Node*, Node*); +void follow(Node*, Node*); +void reason(Node*, Node*); +void newproc(Node*, Node*); +void startstop(Node*, Node*); +void match(Node*, Node*); +void status(Node*, Node*); +void dokill(Node*,Node*); +void waitstop(Node*, Node*); +void stop(Node*, Node*); +void start(Node*, Node*); +void filepc(Node*, Node*); +void doerror(Node*, Node*); +void rc(Node*, Node*); +void doaccess(Node*, Node*); +void map(Node*, Node*); +void readfile(Node*, Node*); +void interpret(Node*, Node*); +void include(Node*, Node*); +void regexp(Node*, Node*); +void _bpcondset(Node*, Node*); +void _bpconddel(Node*, Node*); +void setdebug(Node*, Node*); + +typedef struct Btab Btab; +struct Btab +{ + char *name; + void (*fn)(Node*, Node*); +} tab[] = +{ + "atof", cvtatof, + "atoi", cvtatoi, + "error", doerror, + "file", getfile, + "readfile", readfile, + "access", doaccess, + "filepc", filepc, + "fnbound", funcbound, + "fmt", fmt, + "follow", follow, + "itoa", cvtitoa, + "kill", dokill, + "match", match, + "newproc", newproc, + "pcfile", pcfile, + "pcline", pcline, + "print", bprint, + "printto", printto, + "rc", rc, + "reason", reason, + "setproc", setproc, + "sh", rc, + "start", start, + "startstop", startstop, + "status", status, + "stop", stop, + "strace", strace, + "waitstop", waitstop, + "map", map, + "interpret", interpret, + "include", include, + "regexp", regexp, + "debug", setdebug, + "_bpcondset", _bpcondset, + "_bpconddel", _bpconddel, + 0 +}; + +void +mkprint(Lsym *s) +{ + prnt = gmalloc(sizeof(Node)); + prnt->op = OCALL; + prnt->left = gmalloc(sizeof(Node)); + prnt->left->sym = s; +} + +void +installbuiltin(void) +{ + Btab *b; + Lsym *s; + + b = tab; + while(b->name) { + s = look(b->name); + if(s == 0) + s = enter(b->name, Tid); + + s->builtin = b->fn; + if(b->fn == bprint) + mkprint(s); + b++; + } +} + +void +match(Node *r, Node *args) +{ + int i; + List *f; + Node *av[Maxarg]; + Node resi, resl; + + na = 0; + flatten(av, args); + if(na != 2) + error("match(obj, list): arg count"); + + expr(av[1], &resl); + if(resl.type != TLIST) + error("match(obj, list): need list"); + expr(av[0], &resi); + + r->op = OCONST; + r->type = TINT; + r->nstore.fmt = 'D'; + r->nstore.u0.sival = -1; + + i = 0; + for(f = resl.nstore.u0.sl; f; f = f->next) { + if(resi.type == f->type) { + switch(resi.type) { + case TINT: + if(resi.nstore.u0.sival == f->lstore.u0.sival) { + r->nstore.u0.sival = i; + return; + } + break; + case TFLOAT: + if(resi.nstore.u0.sfval == f->lstore.u0.sfval) { + r->nstore.u0.sival = i; + return; + } + break; + case TSTRING: + if(scmp(resi.nstore.u0.sstring, f->lstore.u0.sstring)) { + r->nstore.u0.sival = i; + return; + } + break; + case TLIST: + error("match(obj, list): not defined for list"); + } + } + i++; + } +} + +void +newproc(Node *r, Node *args) +{ + int i; + Node res; + char *p, *e; + char *argv[Maxarg], buf[Strsize]; + + i = 1; + argv[0] = aout; + + if(args) { + expr(args, &res); + if(res.type != TSTRING) + error("newproc(): arg not string"); + if(res.nstore.u0.sstring->len >= sizeof(buf)) + error("newproc(): too many arguments"); + memmove(buf, res.nstore.u0.sstring->string, res.nstore.u0.sstring->len); + buf[res.nstore.u0.sstring->len] = '\0'; + p = buf; + e = buf+res.nstore.u0.sstring->len; + for(;;) { + while(p < e && (*p == '\t' || *p == ' ')) + *p++ = '\0'; + if(p >= e) + break; + argv[i++] = p; + if(i >= Maxarg) + error("newproc: too many arguments"); + while(p < e && *p != '\t' && *p != ' ') + p++; + } + } + argv[i] = 0; + r->op = OCONST; + r->type = TINT; + r->nstore.fmt = 'D'; + r->nstore.u0.sival = nproc(argv); +} +void +startstop(Node *r, Node *args) +{ + Node res; + + if(args == 0) + error("startstop(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("startstop(pid): arg type"); + if(rdebug) { + Lsym *s; + r->op = OCONST; + r->type = TINT; + r->nstore.u0.sival = remcondstartstop(res.nstore.u0.sival); + r->nstore.fmt = 'D'; + + s = look("_breakid"); + if(s) + s->v->vstore.u0.sival = (int)r->nstore.u0.sival; + } else + msg(res.nstore.u0.sival, "startstop"); + notes(res.nstore.u0.sival); + dostop(res.nstore.u0.sival); +} + +void +waitstop(Node *r, Node *args) +{ + Node res; + + USED(r); + if(args == 0) + error("waitstop(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("waitstop(pid): arg type"); + + Bflush(bout); + msg(res.nstore.u0.sival, "waitstop"); + notes(res.nstore.u0.sival); + dostop(res.nstore.u0.sival); +} + +void +start(Node *r, Node *args) +{ + Node res; + + USED(r); + if(args == 0) + error("start(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("start(pid): arg type"); + + msg(res.nstore.u0.sival, "start"); +} + +void +stop(Node *r, Node *args) +{ + Node res; + + USED(r); + if(args == 0) + error("stop(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("stop(pid): arg type"); + + Bflush(bout); + msg(res.nstore.u0.sival, "stop"); + notes(res.nstore.u0.sival); + dostop(res.nstore.u0.sival); +} + +void +dokill(Node *r, Node *args) +{ + Node res; + + USED(r); + if(args == 0) + error("kill(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("kill(pid): arg type"); + + msg(res.nstore.u0.sival, "kill"); + deinstall(res.nstore.u0.sival); +} + +void +status(Node *r, Node *args) +{ + Node res; + char *p; + + USED(r); + if(args == 0) + error("status(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("status(pid): arg type"); + + p = getstatus(res.nstore.u0.sival); + r->nstore.u0.sstring = strnode(p); + r->op = OCONST; + r->nstore.fmt = 's'; + r->type = TSTRING; +} + +void +reason(Node *r, Node *args) +{ + Node res; + + if(args == 0) + error("reason(cause): no cause"); + expr(args, &res); + if(res.type != TINT) + error("reason(cause): arg type"); + + r->op = OCONST; + r->type = TSTRING; + r->nstore.fmt = 's'; + r->nstore.u0.sstring = strnode((*machdata->excep)(cormap, rget)); +} + +void +follow(Node *r, Node *args) +{ + int n, i; + Node res; + ulong f[10]; + List **tail, *l; + + if(args == 0) + error("follow(addr): no addr"); + expr(args, &res); + if(res.type != TINT) + error("follow(addr): arg type"); + + n = (*machdata->foll)(cormap, res.nstore.u0.sival, rget, f); + if (n < 0) + error("follow(addr): %r"); + tail = &r->nstore.u0.sl; + for(i = 0; i < n; i++) { + l = al(TINT); + l->lstore.u0.sival = f[i]; + l->lstore.fmt = 'X'; + *tail = l; + tail = &l->next; + } +} + +void +funcbound(Node *r, Node *args) +{ + int n; + Node res; + ulong bounds[2]; + List *l; + + if(args == 0) + error("fnbound(addr): no addr"); + expr(args, &res); + if(res.type != TINT) + error("fnbound(addr): arg type"); + + n = fnbound(res.nstore.u0.sival, bounds); + if (n != 0) { + r->nstore.u0.sl = al(TINT); + l = r->nstore.u0.sl; + l->lstore.u0.sival = bounds[0]; + l->lstore.fmt = 'X'; + l->next = al(TINT); + l = l->next; + l->lstore.u0.sival = bounds[1]; + l->lstore.fmt = 'X'; + } +} + +void +setproc(Node *r, Node *args) +{ + Node res; + + USED(r); + if(args == 0) + error("setproc(pid): no pid"); + expr(args, &res); + if(res.type != TINT) + error("setproc(pid): arg type"); + + sproc(res.nstore.u0.sival); +} + +void +filepc(Node *r, Node *args) +{ + Node res; + char *p, c; + + if(args == 0) + error("filepc(filename:line): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("filepc(filename:line): arg type"); + + p = strchr(res.nstore.u0.sstring->string, ':'); + if(p == 0) + error("filepc(filename:line): bad arg format"); + + c = *p; + *p++ = '\0'; + r->nstore.u0.sival = file2pc(res.nstore.u0.sstring->string, atoi(p)); + p[-1] = c; + if(r->nstore.u0.sival == -1) + error("filepc(filename:line): can't find address"); + + r->op = OCONST; + r->type = TINT; + r->nstore.fmt = 'D'; +} + +void +interpret(Node *r, Node *args) +{ + Node res; + int isave; + + if(args == 0) + error("interpret(string): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("interpret(string): arg type"); + + pushstr(&res); + + isave = interactive; + interactive = 0; + r->nstore.u0.sival = yyparse(); + interactive = isave; + popio(); + r->op = OCONST; + r->type = TINT; + r->nstore.fmt = 'D'; +} + +void +include(Node *r, Node *args) +{ + Node res; + int isave; + + if(args == 0) + error("include(string): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("include(string): arg type"); + + pushfile(res.nstore.u0.sstring->string); + + isave = interactive; + interactive = 0; + r->nstore.u0.sival = yyparse(); + interactive = isave; + popio(); + r->op = OCONST; + r->type = TINT; + r->nstore.fmt = 'D'; +} + +void +rc(Node *r, Node *args) +{ + Node res; + + char *p, *q; + + USED(r); + if(args == 0) + error("error(string): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("error(string): arg type"); + + p = runcmd(res.nstore.u0.sstring->string); + q = strrchr(p, ':'); + if (q) + p = q+1; + + r->op = OCONST; + r->type = TSTRING; + r->nstore.u0.sstring = strnode(p); + r->nstore.fmt = 's'; +} + +void +doerror(Node *r, Node *args) +{ + Node res; + + USED(r); + if(args == 0) + error("error(string): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("error(string): arg type"); + + error(res.nstore.u0.sstring->string); +} + +void +doaccess(Node *r, Node *args) +{ + Node res; + + if(args == 0) + error("access(filename): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("access(filename): arg type"); + + r->op = OCONST; + r->type = TINT; + r->nstore.u0.sival = 0; + if(access(res.nstore.u0.sstring->string, OREAD) == 0) + r->nstore.u0.sival = 1; +} + +void +readfile(Node *r, Node *args) +{ + Node res; + int n, fd; + char *buf; + Dir *db; + + if(args == 0) + error("readfile(filename): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("readfile(filename): arg type"); + + fd = open(res.nstore.u0.sstring->string, OREAD); + if(fd < 0) + return; + + db = dirfstat(fd); + if(db == nil || db->length == 0) + n = 8192; + else + n = db->length; + free(db); + + buf = gmalloc(n); + n = read(fd, buf, n); + + if(n > 0) { + r->op = OCONST; + r->type = TSTRING; + r->nstore.u0.sstring = strnodlen(buf, n); + r->nstore.fmt = 's'; + } + free(buf); + close(fd); +} + +void +getfile(Node *r, Node *args) +{ + int n; + char *p; + Node res; + String *s; + Biobuf *bp; + List **l, *new; + + if(args == 0) + error("file(filename): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("file(filename): arg type"); + + r->op = OCONST; + r->type = TLIST; + r->nstore.u0.sl = 0; + + p = res.nstore.u0.sstring->string; + bp = Bopen(p, OREAD); + if(bp == 0) + return; + + l = &r->nstore.u0.sl; + for(;;) { + p = Brdline(bp, '\n'); + n = BLINELEN(bp); + if(p == 0) { + if(n == 0) + break; + s = strnodlen(0, n); + Bread(bp, s->string, n); + } + else + s = strnodlen(p, n-1); + + new = al(TSTRING); + new->lstore.u0.sstring = s; + new->lstore.fmt = 's'; + *l = new; + l = &new->next; + } + Bterm(bp); +} + +void +cvtatof(Node *r, Node *args) +{ + Node res; + + if(args == 0) + error("atof(string): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("atof(string): arg type"); + + r->op = OCONST; + r->type = TFLOAT; + r->nstore.u0.sfval = atof(res.nstore.u0.sstring->string); + r->nstore.fmt = 'f'; +} + +void +cvtatoi(Node *r, Node *args) +{ + Node res; + + if(args == 0) + error("atoi(string): arg count"); + expr(args, &res); + if(res.type != TSTRING) + error("atoi(string): arg type"); + + r->op = OCONST; + r->type = TINT; + r->nstore.u0.sival = strtoul(res.nstore.u0.sstring->string, 0, 0); + r->nstore.fmt = 'D'; +} + +void +cvtitoa(Node *r, Node *args) +{ + Node res; + char buf[128]; + + if(args == 0) + error("itoa(integer): arg count"); + expr(args, &res); + if(res.type != TINT) + error("itoa(integer): arg type"); + + sprint(buf, "%d", (int)res.nstore.u0.sival); + r->op = OCONST; + r->type = TSTRING; + r->nstore.u0.sstring = strnode(buf); + r->nstore.fmt = 's'; +} + +List* +mapent(Map *m) +{ + int i; + List *l, *n, **t, *h; + + h = 0; + t = &h; + for(i = 0; i < m->nsegs; i++) { + if(m->seg[i].inuse == 0) + continue; + l = al(TSTRING); + n = al(TLIST); + n->lstore.u0.sl = l; + *t = n; + t = &n->next; + l->lstore.u0.sstring = strnode(m->seg[i].name); + l->lstore.fmt = 's'; + l->next = al(TINT); + l = l->next; + l->lstore.u0.sival = m->seg[i].b; + l->lstore.fmt = 'X'; + l->next = al(TINT); + l = l->next; + l->lstore.u0.sival = m->seg[i].e; + l->lstore.fmt = 'X'; + l->next = al(TINT); + l = l->next; + l->lstore.u0.sival = m->seg[i].f; + l->lstore.fmt = 'X'; + } + return h; +} + +void +map(Node *r, Node *args) +{ + int i; + Map *m; + List *l; + char *ent; + Node *av[Maxarg], res; + + na = 0; + flatten(av, args); + + if(na != 0) { + expr(av[0], &res); + if(res.type != TLIST) + error("map(list): map needs a list"); + if(listlen(res.nstore.u0.sl) != 4) + error("map(list): list must have 4 entries"); + + l = res.nstore.u0.sl; + if(l->type != TSTRING) + error("map name must be a string"); + ent = l->lstore.u0.sstring->string; + m = symmap; + i = findseg(m, ent); + if(i < 0) { + m = cormap; + i = findseg(m, ent); + } + if(i < 0) + error("%s is not a map entry", ent); + l = l->next; + if(l->type != TINT) + error("map entry not int"); + m->seg[i].b = l->lstore.u0.sival; + if (strcmp(ent, "text") == 0) + textseg(l->lstore.u0.sival, &fhdr); + l = l->next; + if(l->type != TINT) + error("map entry not int"); + m->seg[i].e = l->lstore.u0.sival; + l = l->next; + if(l->type != TINT) + error("map entry not int"); + m->seg[i].f = l->lstore.u0.sival; + } + + r->type = TLIST; + r->nstore.u0.sl = 0; + if(symmap) + r->nstore.u0.sl = mapent(symmap); + if(cormap) { + if(r->nstore.u0.sl == 0) + r->nstore.u0.sl = mapent(cormap); + else { + for(l = r->nstore.u0.sl; l->next; l = l->next) + ; + l->next = mapent(cormap); + } + } +} + +void +flatten(Node **av, Node *n) +{ + if(n == 0) + return; + + switch(n->op) { + case OLIST: + flatten(av, n->left); + flatten(av, n->right); + break; + default: + av[na++] = n; + if(na >= Maxarg) + error("too many function arguments"); + break; + } +} + +void +strace(Node *r, Node *args) +{ + Node *av[Maxarg], *n, res; + ulong pc, sp; + + na = 0; + flatten(av, args); + if(na != 3) + error("strace(pc, sp, link): arg count"); + + n = av[0]; + expr(n, &res); + if(res.type != TINT) + error("strace(pc, sp, link): pc bad type"); + pc = res.nstore.u0.sival; + + n = av[1]; + expr(n, &res); + if(res.type != TINT) + error("strace(pc, sp, link): sp bad type"); + sp = res.nstore.u0.sival; + + n = av[2]; + expr(n, &res); + if(res.type != TINT) + error("strace(pc, sp, link): link bad type"); + + tracelist = 0; + if ((*machdata->ctrace)(cormap, pc, sp, res.nstore.u0.sival, trlist) <= 0) + error("no stack frame"); + r->type = TLIST; + r->nstore.u0.sl = tracelist; +} + +void +regerror(char *msg) +{ + error(msg); +} + +void +regexp(Node *r, Node *args) +{ + Node res; + Reprog *rp; + Node *av[Maxarg]; + + na = 0; + flatten(av, args); + if(na != 2) + error("regexp(pattern, string): arg count"); + expr(av[0], &res); + if(res.type != TSTRING) + error("regexp(pattern, string): pattern must be string"); + rp = regcomp(res.nstore.u0.sstring->string); + if(rp == 0) + return; + + expr(av[1], &res); + if(res.type != TSTRING) + error("regexp(pattern, string): bad string"); + + r->nstore.fmt = 'D'; + r->type = TINT; + r->nstore.u0.sival = regexec(rp, res.nstore.u0.sstring->string, 0, 0); + free(rp); +} + +char vfmt[] = "aBbcCdDfFgGiIoOqQrRsuUVxXYZ"; + +void +fmt(Node *r, Node *args) +{ + Node res; + Node *av[Maxarg]; + + na = 0; + flatten(av, args); + if(na != 2) + error("fmt(obj, fmt): arg count"); + expr(av[1], &res); + if(res.type != TINT || strchr(vfmt, res.nstore.u0.sival) == 0) + error("fmt(obj, fmt): bad format '%c'", (char)res.nstore.u0.sival); + expr(av[0], r); + r->nstore.fmt = res.nstore.u0.sival; +} + +void +patom(char type, Store *res) +{ + int i; + char buf[512]; + extern char *typenames[]; + + switch(res->fmt) { + case 'c': + Bprint(bout, "%c", (int)res->u0.sival); + break; + case 'C': + if(res->u0.sival < ' ' || res->u0.sival >= 0x7f) + Bprint(bout, "%3d", (int)res->u0.sival&0xff); + else + Bprint(bout, "%3c", (int)res->u0.sival); + break; + case 'r': + Bprint(bout, "%C", (int)res->u0.sival); + break; + case 'B': + memset(buf, '0', 34); + buf[1] = 'b'; + for(i = 0; i < 32; i++) { + if(res->u0.sival & (1<<i)) + buf[33-i] = '1'; + } + buf[35] = '\0'; + Bprint(bout, "%s", buf); + break; + case 'b': + Bprint(bout, "%3d", (int)res->u0.sival&0xff); + break; + case 'X': + Bprint(bout, "%.8lux", (int)res->u0.sival); + break; + case 'x': + Bprint(bout, "%.4lux", (int)res->u0.sival&0xffff); + break; + case 'Y': + Bprint(bout, "%.16llux", res->u0.sival); + break; + case 'D': + Bprint(bout, "%d", (int)res->u0.sival); + break; + case 'd': + Bprint(bout, "%d", (ushort)res->u0.sival); + break; + case 'u': + Bprint(bout, "%ud", (int)res->u0.sival&0xffff); + break; + case 'U': + Bprint(bout, "%ud", (ulong)res->u0.sival); + break; + case 'Z': + Bprint(bout, "%llud", res->u0.sival); + break; + case 'V': + Bprint(bout, "%lld", res->u0.sival); + break; + case 'o': + Bprint(bout, "0%.11uo", (int)res->u0.sival&0xffff); + break; + case 'O': + Bprint(bout, "0%.6uo", (int)res->u0.sival); + break; + case 'q': + Bprint(bout, "0%.11o", (short)(res->u0.sival&0xffff)); + break; + case 'Q': + Bprint(bout, "0%.6o", (int)res->u0.sival); + break; + case 'f': + case 'F': + if(type != TFLOAT) + Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]); + else + Bprint(bout, "%g", res->u0.sfval); + break; + case 's': + case 'g': + case 'G': + if(type != TSTRING) + Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]); + else + Bwrite(bout, res->u0.sstring->string, res->u0.sstring->len); + break; + case 'R': + if(type != TSTRING) + Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]); + else + Bprint(bout, "%S", res->u0.sstring->string); + break; + case 'a': + case 'A': + symoff(buf, sizeof(buf), res->u0.sival, CANY); + Bprint(bout, "%s", buf); + break; + case 'I': + case 'i': + if(type != TINT) + Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]); + else { + if ((*machdata->das)(symmap, res->u0.sival, res->fmt, buf, sizeof(buf)) < 0) + Bprint(bout, "no instruction: %r"); + else + Bprint(bout, "%s", buf); + } + break; + } +} + +void +blprint(List *l) +{ + Bprint(bout, "{"); + while(l) { + switch(l->type) { + default: + patom(l->type, &l->lstore); + break; + case TSTRING: + Bputc(bout, '"'); + patom(l->type, &l->lstore); + Bputc(bout, '"'); + break; + case TLIST: + blprint(l->lstore.u0.sl); + break; + case TCODE: + pcode(l->lstore.u0.scc, 0); + break; + } + l = l->next; + if(l) + Bprint(bout, ", "); + } + Bprint(bout, "}"); +} + +int +comx(Node res) +{ + Lsym *sl; + Node *n, xx; + + if(res.nstore.fmt != 'a' && res.nstore.fmt != 'A') + return 0; + + if(res.nstore.comt == 0 || res.nstore.comt->base == 0) + return 0; + + sl = res.nstore.comt->base; + if(sl->proc) { + res.left = ZN; + res.right = ZN; + n = an(ONAME, ZN, ZN); + n->sym = sl; + n = an(OCALL, n, &res); + n->left->sym = sl; + expr(n, &xx); + return 1; + } + print("(%s)", sl->name); + return 0; +} + +void +bprint(Node *r, Node *args) +{ + int i, nas; + Node res, *av[Maxarg]; + + USED(r); + na = 0; + flatten(av, args); + nas = na; + for(i = 0; i < nas; i++) { + expr(av[i], &res); + switch(res.type) { + default: + if(comx(res)) + break; + patom(res.type, &res.nstore); + break; + case TCODE: + pcode(res.nstore.u0.scc, 0); + break; + case TLIST: + blprint(res.nstore.u0.sl); + break; + } + } + if(ret == 0) + Bputc(bout, '\n'); +} + +void +printto(Node *r, Node *args) +{ + int fd; + Biobuf *b; + int i, nas; + Node res, *av[Maxarg]; + + USED(r); + na = 0; + flatten(av, args); + nas = na; + + expr(av[0], &res); + if(res.type != TSTRING) + error("printto(string, ...): need string"); + + fd = create(res.nstore.u0.sstring->string, OWRITE, 0666); + if(fd < 0) + fd = open(res.nstore.u0.sstring->string, OWRITE); + if(fd < 0) + error("printto: open %s: %r", res.nstore.u0.sstring->string); + + b = gmalloc(sizeof(Biobuf)); + Binit(b, fd, OWRITE); + + Bflush(bout); + io[iop++] = bout; + bout = b; + + for(i = 1; i < nas; i++) { + expr(av[i], &res); + switch(res.type) { + default: + if(comx(res)) + break; + patom(res.type, &res.nstore); + break; + case TLIST: + blprint(res.nstore.u0.sl); + break; + } + } + if(ret == 0) + Bputc(bout, '\n'); + + Bterm(b); + close(fd); + free(b); + bout = io[--iop]; +} + +void +pcfile(Node *r, Node *args) +{ + Node res; + char *p, buf[128]; + + if(args == 0) + error("pcfile(addr): arg count"); + expr(args, &res); + if(res.type != TINT) + error("pcfile(addr): arg type"); + + r->type = TSTRING; + r->nstore.fmt = 's'; + if(fileline(buf, sizeof(buf), res.nstore.u0.sival) == 0) { + r->nstore.u0.sstring = strnode("?file?"); + return; + } + p = strrchr(buf, ':'); + if(p == 0) + error("pcfile(addr): funny file %s", buf); + *p = '\0'; + r->nstore.u0.sstring = strnode(buf); +} + +void +pcline(Node *r, Node *args) +{ + Node res; + char *p, buf[128]; + + if(args == 0) + error("pcline(addr): arg count"); + expr(args, &res); + if(res.type != TINT) + error("pcline(addr): arg type"); + + r->type = TINT; + r->nstore.fmt = 'D'; + if(fileline(buf, sizeof(buf), res.nstore.u0.sival) == 0) { + r->nstore.u0.sival = 0; + return; + } + + p = strrchr(buf, ':'); + if(p == 0) + error("pcline(addr): funny file %s", buf); + r->nstore.u0.sival = atoi(p+1); +} + +void +_bpcondset(Node *r, Node *args) +{ + Node id, p, addr, conds; + Node *av[Maxarg]; + List *l; + char *op; + List *val; + ulong pid; + + USED(r); + + if(!rdebug) + error("_bpcondset(id, pid, addr, conds): only available with remote debugger\n"); + + if(args == 0) + error("_bpcondset(id, pid, addr, conds): not enough args"); + na = 0; + flatten(av, args); + if(na != 4) + error("_bpcondset(id, pid, addr, conds): %s args", + na > 4 ? "too many" : "too few"); + expr(av[0], &id); + expr(av[1], &p); + expr(av[2], &addr); + expr(av[3], &conds); + if(id.type != TINT) + error("_bpcondset(id, pid, addr, conds): id: integer expected"); + if(p.type != TINT) + error("_bpcondset(pid, addr, conds): pid: integer expected"); + if(addr.type != TINT) + error("_bpcondset(pid, addr, conds): addr: integer expected"); + if(conds.type != TLIST) + error("_bpcondset(pid, addr, conds): conds: list expected"); + l = conds.nstore.u0.sl; + remcondset('n', (ulong)id.nstore.u0.sival); + pid = (ulong)p.nstore.u0.sival; + if (pid != 0) + remcondset('k', pid); + while(l != nil) { + if(l->type != TLIST || listlen(l->lstore.u0.sl) != 2) + error("_bpcondset(addr, list): list elements are {\"op\", val} pairs"); + if(l->lstore.u0.sl->type != TSTRING) + error("_bpcondset(addr, list): list elements are {string, val} pairs"); + op = l->lstore.u0.sl->lstore.u0.sstring->string; + val = l->lstore.u0.sl->next; + if(val->type != TINT) + error("_bpcondset(addr, list): list elements are {string, int} pairs"); + remcondset(op[0], (ulong)val->lstore.u0.sival); + l = l->next; + } + remcondset('b', (ulong)addr.nstore.u0.sival); +} + +void +_bpconddel(Node *r, Node *args) +{ + Node res; + + USED(r); + if(!rdebug) + error("_bpconddel(id): only available with remote debugger\n"); + + expr(args, &res); + if(res.type != TINT) + error("_bpconddel(id): arg type"); + + remcondset('d', (ulong)res.nstore.u0.sival); +} + +void +setdebug(Node *r, Node *args) +{ + Node res; + + USED(r); + expr(args, &res); + if (res.type != TINT) + error("debug(type): bad type"); + setdbg_opt((char)res.nstore.u0.sival, 1); +} + + +void +setdbg_opt(char c, int prflag) +{ + switch(c) { + case 'p': + if (protodebug) { + protodebug = 0; + if (prflag) + print("Serial protocol debug is OFF\n"); + } else { + protodebug = 1; + if (prflag) + print("Serial protocol debug is ON\n"); + } + break; + default: + print("Invalid debug flag(%c), supported values: p\n", c); + break; + } +} diff --git a/utils/acid/dbg.y b/utils/acid/dbg.y new file mode 100644 index 00000000..66c1b11d --- /dev/null +++ b/utils/acid/dbg.y @@ -0,0 +1,402 @@ +%{ +#include <lib9.h> +#include <bio.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +%} + +%union +{ + Node *node; + Lsym *sym; + ulong ival; + float fval; + String *string; +} + +%type <node> expr monexpr term stmnt name args zexpr slist +%type <node> member members mname castexpr idlist +%type <sym> zname + +%left ';' +%right '=' +%left Tfmt +%left Toror +%left Tandand +%left '|' +%left '^' +%left '&' +%left Teq Tneq +%left '<' '>' Tleq Tgeq +%left Tlsh Trsh +%left '+' '-' +%left '*' '/' '%' +%right Tdec Tinc Tindir '.' '[' '(' + +%token <sym> Tid +%token <ival> Tconst Tfmt +%token <fval> Tfconst +%token <string> Tstring +%token Tif Tdo Tthen Telse Twhile Tloop Thead Ttail Tappend Tfn Tret Tlocal +%token Tcomplex Twhat Tdelete Teval + +%% + +prog : + | prog bigstmnt + ; + +bigstmnt : stmnt + { + execute($1); + gc(); + if(interactive) + Bprint(bout, "acid: "); + } + | Tfn Tid '(' args ')' zsemi '{' slist '}' + { + if($2->builtin) + print("warning: %s() is a builtin; definition ignored\n", $2->name); + else + $2->proc = an(OLIST, $4, $8); + } + | Tcomplex name '{' members '}' ';' + { + defcomplex($2, $4); + } + ; + +zsemi : + | ';' zsemi + +members : member + | members member + { + $$ = an(OLIST, $1, $2); + } + ; + +mname : Tid + { + $$ = an(ONAME, ZN, ZN); + $$->sym = $1; + } + ; + +member : Tconst Tconst mname ';' + { + $3->nstore.u0.sival = $2; + $3->nstore.fmt = $1; + $$ = $3; + } + | Tconst mname Tconst mname ';' + { + $4->nstore.u0.sival = $3; + $4->nstore.fmt = $1; + $4->right = $2; + $$ = $4; + } + | mname Tconst mname ';' + { + $3->nstore.u0.sival = $2; + $3->left = $1; + $$ = $3; + } + | '{' members '}' ';' + { + $$ = an(OCTRUCT, $2, ZN); + } + ; + +zname : + { $$ = 0; } + | Tid + ; + +slist : stmnt + | slist stmnt + { + $$ = an(OLIST, $1, $2); + } + ; + +stmnt : zexpr ';' + | '{' slist '}' + { + $$ = $2; + } + | Tif expr Tthen stmnt + { + $$ = an(OIF, $2, $4); + } + | Tif expr Tthen stmnt Telse stmnt + { + $$ = an(OIF, $2, an(OELSE, $4, $6)); + } + | Tloop expr ',' expr Tdo stmnt + { + $$ = an(ODO, an(OLIST, $2, $4), $6); + } + | Twhile expr Tdo stmnt + { + $$ = an(OWHILE, $2, $4); + } + | Tret expr ';' + { + $$ = an(ORET, $2, ZN); + } + | Tlocal idlist + { + $$ = an(OLOCAL, $2, ZN); + } + | Tcomplex Tid name ';' + { + $$ = an(OCOMPLEX, $3, ZN); + $$->sym = $2; + } + ; + +idlist : Tid + { + $$ = an(ONAME, ZN, ZN); + $$->sym = $1; + } + | idlist ',' Tid + { + $$ = an(ONAME, $1, ZN); + $$->sym = $3; + } + ; + +zexpr : + { $$ = 0; } + | expr + ; + +expr : castexpr + | expr '*' expr + { + $$ = an(OMUL, $1, $3); + } + | expr '/' expr + { + $$ = an(ODIV, $1, $3); + } + | expr '%' expr + { + $$ = an(OMOD, $1, $3); + } + | expr '+' expr + { + $$ = an(OADD, $1, $3); + } + | expr '-' expr + { + $$ = an(OSUB, $1, $3); + } + | expr Trsh expr + { + $$ = an(ORSH, $1, $3); + } + | expr Tlsh expr + { + $$ = an(OLSH, $1, $3); + } + | expr '<' expr + { + $$ = an(OLT, $1, $3); + } + | expr '>' expr + { + $$ = an(OGT, $1, $3); + } + | expr Tleq expr + { + $$ = an(OLEQ, $1, $3); + } + | expr Tgeq expr + { + $$ = an(OGEQ, $1, $3); + } + | expr Teq expr + { + $$ = an(OEQ, $1, $3); + } + | expr Tneq expr + { + $$ = an(ONEQ, $1, $3); + } + | expr '&' expr + { + $$ = an(OLAND, $1, $3); + } + | expr '^' expr + { + $$ = an(OXOR, $1, $3); + } + | expr '|' expr + { + $$ = an(OLOR, $1, $3); + } + | expr Tandand expr + { + $$ = an(OCAND, $1, $3); + } + | expr Toror expr + { + $$ = an(OCOR, $1, $3); + } + | expr '=' expr + { + $$ = an(OASGN, $1, $3); + } + | expr Tfmt + { + $$ = an(OFMT, $1, con($2)); + } + ; + +castexpr : monexpr + | '(' Tid ')' monexpr + { + $$ = an(OCAST, $4, ZN); + $$->sym = $2; + } + ; + +monexpr : term + | '*' monexpr + { + $$ = an(OINDM, $2, ZN); + } + | '@' monexpr + { + $$ = an(OINDC, $2, ZN); + } + | '+' monexpr + { + $$ = con(0); + $$ = an(OADD, $2, $$); + } + | '-' monexpr + { + $$ = con(0); + $$ = an(OSUB, $$, $2); + } + | Tdec monexpr + { + $$ = an(OEDEC, $2, ZN); + } + | Tinc monexpr + { + $$ = an(OEINC, $2, ZN); + } + | Thead monexpr + { + $$ = an(OHEAD, $2, ZN); + } + | Ttail monexpr + { + $$ = an(OTAIL, $2, ZN); + } + | Tappend monexpr ',' monexpr + { + $$ = an(OAPPEND, $2, $4); + } + | Tdelete monexpr ',' monexpr + { + $$ = an(ODELETE, $2, $4); + } + | '!' monexpr + { + $$ = an(ONOT, $2, ZN); + } + | '~' monexpr + { + $$ = an(OXOR, $2, con(-1)); + } + | Teval monexpr + { + $$ = an(OEVAL, $2, ZN); + } + ; + +term : '(' expr ')' + { + $$ = $2; + } + | '{' args '}' + { + $$ = an(OCTRUCT, $2, ZN); + } + | term '[' expr ']' + { + $$ = an(OINDEX, $1, $3); + } + | term Tdec + { + $$ = an(OPDEC, $1, ZN); + } + | term '.' Tid + { + $$ = an(ODOT, $1, ZN); + $$->sym = $3; + } + | term Tindir Tid + { + $$ = an(ODOT, an(OINDM, $1, ZN), ZN); + $$->sym = $3; + } + | term Tinc + { + $$ = an(OPINC, $1, ZN); + } + | name '(' args ')' + { + $$ = an(OCALL, $1, $3); + } + | name + | Tconst + { + $$ = con($1); + } + | Tfconst + { + $$ = an(OCONST, ZN, ZN); + $$->type = TFLOAT; + $$->nstore.fmt = 'f'; + $$->nstore.u0.sfval = $1; + } + | Tstring + { + $$ = an(OCONST, ZN, ZN); + $$->type = TSTRING; + $$->nstore.u0.sstring = $1; + $$->nstore.fmt = 's'; + } + | Twhat zname + { + $$ = an(OWHAT, ZN, ZN); + $$->sym = $2; + } + ; + +name : Tid + { + $$ = an(ONAME, ZN, ZN); + $$->sym = $1; + } + | Tid ':' name + { + $$ = an(OFRAME, $3, ZN); + $$->sym = $1; + } + ; + +args : zexpr + | args ',' zexpr + { + $$ = an(OLIST, $1, $3); + } + ; diff --git a/utils/acid/dot.c b/utils/acid/dot.c new file mode 100644 index 00000000..89bcb2c8 --- /dev/null +++ b/utils/acid/dot.c @@ -0,0 +1,152 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" + +Type* +srch(Type *t, char *s) +{ + Type *f; + + f = 0; + while(t) { + if(strcmp(t->tag->name, s) == 0) { + if(f == 0 || t->depth < f->depth) + f = t; + } + t = t->next; + } + return f; +} + +void +odot(Node *n, Node *r) +{ + char *s; + Type *t; + Node res; + ulong addr; + + s = n->sym->name; + if(s == 0) + fatal("dodot: no tag"); + + expr(n->left, &res); + if(res.nstore.comt == 0) + error("no type specified for (expr).%s", s); + + if(res.type != TINT) + error("pointer must be integer for (expr).%s", s); + + t = srch(res.nstore.comt, s); + if(t == 0) + error("no tag for (expr).%s", s); + + /* Propagate types */ + if(t->type) + r->nstore.comt = t->type->lt; + + addr = res.nstore.u0.sival+t->offset; + if(t->fmt == 'a') { + r->op = OCONST; + r->nstore.fmt = 'a'; + r->type = TINT; + r->nstore.u0.sival = addr; + } + else + indir(cormap, addr, t->fmt, r); + +} + +static Type **tail; +static Lsym *base; + +void +buildtype(Node *m, int d) +{ + Type *t; + + if(m == ZN) + return; + + switch(m->op) { + case OLIST: + buildtype(m->left, d); + buildtype(m->right, d); + break; + + case OCTRUCT: + buildtype(m->left, d+1); + break; + default: + t = gmalloc(sizeof(Type)); + t->next = 0; + t->depth = d; + t->tag = m->sym; + t->base = base; + t->offset = m->nstore.u0.sival; + if(m->left) { + t->type = m->left->sym; + t->fmt = 'a'; + } + else { + t->type = 0; + if(m->right) + t->type = m->right->sym; + t->fmt = m->nstore.fmt; + } + + *tail = t; + tail = &t->next; + } +} + +void +defcomplex(Node *tn, Node *m) +{ + tail = &tn->sym->lt; + base = tn->sym; + buildtype(m, 0); +} + +void +decl(Node *n) +{ + Node *l; + Value *v; + Frtype *f; + Lsym *type; + + type = n->sym; + if(type->lt == 0) + error("%s is not a complex type", type->name); + + l = n->left; + if(l->op == ONAME) { + v = l->sym->v; + v->vstore.comt = type->lt; + v->vstore.fmt = 'a'; + return; + } + + /* + * Frame declaration + */ + for(f = l->sym->local; f; f = f->next) { + if(f->var == l->left->sym) { + f->type = n->sym->lt; + return; + } + } + f = gmalloc(sizeof(Frtype)); + if(f == 0) + fatal("out of memory"); + + f->type = type->lt; + + f->var = l->left->sym; + f->next = l->sym->local; + l->sym->local = f; +} diff --git a/utils/acid/exec.c b/utils/acid/exec.c new file mode 100644 index 00000000..d110673b --- /dev/null +++ b/utils/acid/exec.c @@ -0,0 +1,490 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" + +void +error(char *fmt, ...) +{ + int i; + char buf[2048]; + va_list arg; + + /* Unstack io channels */ + if(iop != 0) { + for(i = 1; i < iop; i++) + Bterm(io[i]); + bout = io[0]; + iop = 0; + } + + ret = 0; + gotint = 0; + Bflush(bout); + if(silent) + silent = 0; + else { + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%L: (error) %s\n", buf); + } + while(popio()) + ; + interactive = 1; + longjmp(err, 1); +} + +void +unwind(void) +{ + int i; + Lsym *s; + Value *v; + + for(i = 0; i < Hashsize; i++) { + for(s = hash[i]; s; s = s->hash) { + while(s->v->pop) { + v = s->v->pop; + free(s->v); + s->v = v; + } + } + } +} + +void +execute(Node *n) +{ + Value *v; + Lsym *sl; + Node *l, *r; + int i, s, e; + Node res, xx; + static int stmnt; + + if(gotint) + error("interrupted"); + + if(n == 0) + return; + + if(stmnt++ > 5000) { + Bflush(bout); + stmnt = 0; + } + + l = n->left; + r = n->right; + res.right = 0; + res.left = 0; + res.sym = 0; + + switch(n->op) { + default: + expr(n, &res); + if(ret || (res.type == TLIST && res.nstore.u0.sl == 0)) + break; + prnt->right = &res; + xx.right = 0; + xx.left = 0; + xx.sym = 0; + expr(prnt, &xx); + break; + case OASGN: + case OCALL: + expr(n, &res); + break; + case OCOMPLEX: + decl(n); + break; + case OLOCAL: + for(n = n->left; n; n = n->left) { + if(ret == 0) + error("local not in function"); + sl = n->sym; + if(sl->v->ret == ret) + error("%s declared twice", sl->name); + v = gmalloc(sizeof(Value)); + v->ret = ret; + v->pop = sl->v; + sl->v = v; + v->scope = 0; + *(ret->tail) = sl; + ret->tail = &v->scope; + v->set = 0; + } + break; + case ORET: + if(ret == 0) + error("return not in function"); + expr(n->left, ret->val); + longjmp(ret->rlab, 1); + case OLIST: + execute(n->left); + execute(n->right); + break; + case OIF: + expr(l, &res); + if(r && r->op == OELSE) { + if(bool(&res)) + execute(r->left); + else + execute(r->right); + } + else if(bool(&res)) + execute(r); + break; + case OWHILE: + for(;;) { + expr(l, &res); + if(!bool(&res)) + break; + execute(r); + } + break; + case ODO: + expr(l->left, &res); + if(res.type != TINT) + error("loop must have integer start"); + s = res.nstore.u0.sival; + expr(l->right, &res); + if(res.type != TINT) + error("loop must have integer end"); + e = res.nstore.u0.sival; + for(i = s; i <= e; i++) + execute(r); + break; + } +} + +int +bool(Node *n) +{ + int true = 0; + + if(n->op != OCONST) + fatal("bool: not const"); + + switch(n->type) { + case TINT: + if(n->nstore.u0.sival != 0) + true = 1; + break; + case TFLOAT: + if(n->nstore.u0.sfval != 0.0) + true = 1; + break; + case TSTRING: + if(n->nstore.u0.sstring->len) + true = 1; + break; + case TLIST: + if(n->nstore.u0.sl) + true = 1; + break; + } + return true; +} + +void +convflt(Node *r, char *flt) +{ + char c; + + c = flt[0]; + if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { + r->type = TSTRING; + r->nstore.fmt = 's'; + r->nstore.u0.sstring = strnode(flt); + } + else { + r->type = TFLOAT; + r->nstore.u0.sfval = atof(flt); + } +} + +void +indir(Map *m, ulong addr, char fmt, Node *r) +{ + int i; + long ival; + vlong vval; + int ret; + uchar cval; + ushort sval; + char buf[512], reg[12]; + + r->op = OCONST; + r->nstore.fmt = fmt; + switch(fmt) { + default: + error("bad pointer format '%c' for *", fmt); + case 'c': + case 'C': + case 'b': + r->type = TINT; + ret = get1(m, addr, &cval, 1); + if (ret < 0) + error("indir: %r"); + r->nstore.u0.sival = cval; + break; + case 'x': + case 'd': + case 'u': + case 'o': + case 'q': + case 'r': + r->type = TINT; + ret = get2(m, addr, &sval); + if (ret < 0) + error("indir: %r"); + r->nstore.u0.sival = sval; + break; + case 'a': + case 'A': + case 'B': + case 'X': + case 'D': + case 'U': + case 'O': + case 'Q': + r->type = TINT; + ret = get4(m, addr, &ival); + if (ret < 0) + error("indir: %r"); + r->nstore.u0.sival = ival; + break; + case 'V': + case 'Y': + case 'Z': + r->type = TINT; + ret = get8(m, addr, &vval); + if (ret < 0) + error("indir: %r"); + r->nstore.u0.sival = vval; + break; + case 's': + r->type = TSTRING; + for(i = 0; i < sizeof(buf)-1; i++) { + ret = get1(m, addr, (uchar*)&buf[i], 1); + if (ret < 0) + error("indir: %r"); + addr++; + if(buf[i] == '\0') + break; + } + buf[i] = 0; + if(i == 0) + strcpy(buf, "(null)"); + r->nstore.u0.sstring = strnode(buf); + break; + case 'R': + r->type = TSTRING; + for(i = 0; i < sizeof(buf)-2; i += 2) { + ret = get1(m, addr, (uchar*)&buf[i], 2); + if (ret < 0) + error("indir: %r"); + addr += 2; + if(buf[i] == 0 && buf[i+1] == 0) + break; + } + buf[i++] = 0; + buf[i] = 0; + r->nstore.u0.sstring = runenode((Rune*)buf); + break; + case 'i': + case 'I': + if ((*machdata->das)(m, addr, fmt, buf, sizeof(buf)) < 0) + error("indir: %r"); + r->type = TSTRING; + r->nstore.fmt = 's'; + r->nstore.u0.sstring = strnode(buf); + break; + case 'f': + ret = get1(m, addr, (uchar*)buf, mach->szfloat); + if (ret < 0) + error("indir: %r"); + machdata->sftos(buf, sizeof(buf), (void*) buf); + convflt(r, buf); + break; + case 'g': + ret = get1(m, addr, (uchar*)buf, mach->szfloat); + if (ret < 0) + error("indir: %r"); + machdata->sftos(buf, sizeof(buf), (void*) buf); + r->type = TSTRING; + r->nstore.u0.sstring = strnode(buf); + break; + case 'F': + ret = get1(m, addr, (uchar*)buf, mach->szdouble); + if (ret < 0) + error("indir: %r"); + machdata->dftos(buf, sizeof(buf), (void*) buf); + convflt(r, buf); + break; + case '3': /* little endian ieee 80 with hole in bytes 8&9 */ + ret = get1(m, addr, (uchar*)reg, 10); + if (ret < 0) + error("indir: %r"); + memmove(reg+10, reg+8, 2); /* open hole */ + memset(reg+8, 0, 2); /* fill it */ + leieee80ftos(buf, sizeof(buf), reg); + convflt(r, buf); + break; + case '8': /* big-endian ieee 80 */ + ret = get1(m, addr, (uchar*)reg, 10); + if (ret < 0) + error("indir: %r"); + beieee80ftos(buf, sizeof(buf), reg); + convflt(r, buf); + break; + case 'G': + ret = get1(m, addr, (uchar*)buf, mach->szdouble); + if (ret < 0) + error("indir: %r"); + machdata->dftos(buf, sizeof(buf), (void*) buf); + r->type = TSTRING; + r->nstore.u0.sstring = strnode(buf); + break; + } +} + +void +windir(Map *m, Node *addr, Node *rval, Node *r) +{ + uchar cval; + ushort sval; + Node res, aes; + int ret; + + if(m == 0) + error("no map for */@="); + + expr(rval, &res); + expr(addr, &aes); + + if(aes.type != TINT) + error("bad type lhs of @/*"); + + if(m != cormap && wtflag == 0) + error("not in write mode"); + + r->type = res.type; + r->nstore.fmt = res.nstore.fmt; + r->nstore = res.nstore; + + switch(res.nstore.fmt) { + default: + error("bad pointer format '%c' for */@=", res.nstore.fmt); + case 'c': + case 'C': + case 'b': + cval = res.nstore.u0.sival; + ret = put1(m, aes.nstore.u0.sival, &cval, 1); + break; + case 'r': + case 'x': + case 'd': + case 'u': + case 'o': + sval = res.nstore.u0.sival; + ret = put2(m, aes.nstore.u0.sival, sval); + r->nstore.u0.sival = sval; + break; + case 'a': + case 'A': + case 'B': + case 'X': + case 'D': + case 'U': + case 'O': + ret = put4(m, aes.nstore.u0.sival, res.nstore.u0.sival); + break; + case 'V': + case 'Y': + case 'Z': + ret = put8(m, aes.nstore.u0.sival, res.nstore.u0.sival); + break; + case 's': + case 'R': + ret = put1(m, aes.nstore.u0.sival, (uchar*)res.nstore.u0.sstring->string, res.nstore.u0.sstring->len); + break; + } + if (ret < 0) + error("windir: %r"); +} + +void +call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp) +{ + int np, i; + Rplace rlab; + Node *n, res; + Value *v, *f; + Lsym *s, *next; + Node *avp[Maxarg], *ava[Maxarg]; + + rlab.local = 0; + + na = 0; + flatten(avp, parameters); + np = na; + na = 0; + flatten(ava, local); + if(np != na) { + if(np < na) + error("%s: too few arguments", fn); + error("%s: too many arguments", fn); + } + + rlab.tail = &rlab.local; + + ret = &rlab; + for(i = 0; i < np; i++) { + n = ava[i]; + switch(n->op) { + default: + error("%s: %d formal not a name", fn, i); + case ONAME: + expr(avp[i], &res); + s = n->sym; + break; + case OINDM: + res.nstore.u0.scc = avp[i]; + res.type = TCODE; + res.nstore.comt = 0; + if(n->left->op != ONAME) + error("%s: %d formal not a name", fn, i); + s = n->left->sym; + break; + } + if(s->v->ret == ret) + error("%s already declared at this scope", s->name); + + v = gmalloc(sizeof(Value)); + v->ret = ret; + v->pop = s->v; + s->v = v; + v->scope = 0; + *(rlab.tail) = s; + rlab.tail = &v->scope; + + v->vstore = res.nstore; + v->type = res.type; + v->set = 1; + } + + ret->val = retexp; + if(setjmp(rlab.rlab) == 0) + execute(body); + + for(s = rlab.local; s; s = next) { + f = s->v; + next = f->scope; + s->v = f->pop; + free(f); + } +} diff --git a/utils/acid/expr.c b/utils/acid/expr.c new file mode 100644 index 00000000..da413742 --- /dev/null +++ b/utils/acid/expr.c @@ -0,0 +1,1032 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" + +static int fsize[] = +{ + 0,0,0,0,0,0,0,0, /* 0-7 */ + 0,0,0,0,0,0,0,0, /* 8-15 */ + 0,0,0,0,0,0,0,0, /* 16-23 */ + 0,0,0,0,0,0,0,0, /* 24-31 */ + 0,0,0,0,0,0,0,0, /* 32-39 */ + 0,0,0,0,0,0,0,0, /* 40-47 */ + 0,0,0,0,0,0,0,0, /* 48-55 */ + 0,0,0,0,0,0,0,0, /* 56-63 */ + 0, /* 64 */ + 4, /* 65 ['A'] 4, */ + 4, /* 66 ['B'] 4, */ + 1, /* 67 ['C'] 1, */ + 4, /* 68 ['D'] 4, */ + 0, /* 69 */ + 8, /* 70 ['F'] 8, */ + 8, /* 71 ['G'] 8, */ + 0,0,0,0,0,0,0, /* 72-78 */ + 4, /* 79 ['O'] 4, */ + 0, /* 80 */ + 4, /* 81 ['Q'] 4, */ + 4, /* 82 ['R'] 4, */ + 4, /* 83 ['S'] 4, */ + 0, /* 84 */ + 4, /* 85 ['U'] 4, */ + 8, /* 86 ['V'] 8, */ + 0, /* 87 */ + 4, /* 88 ['X'] 4, */ + 8, /* 89 ['Y'] 8, */ + 8, /* 90 ['Z'] 8, */ + 0,0,0,0,0,0, /* 91-96 */ + 4, /* 97 ['a'] 4, */ + 1, /* 98 ['b'] 1, */ + 1, /* 99 ['c'] 1, */ + 2, /* 100 ['d'] 2, */ + 0, /* 101 */ + 4, /* 102 ['f'] 4, */ + 4, /* 103 ['g'] 4, */ + 0,0,0,0,0,0,0, /* 104-110 */ + 2, /* 111 ['o'] 2, */ + 0, /* 112 */ + 2, /* 113 ['q'] 2, */ + 2, /* 114 ['r'] 2, */ + 4, /* 115 ['s'] 4, */ + 0, /* 116 */ + 2, /* 117 ['u'] 2, */ + 0,0, /* 118-119 */ + 2, /* 120 ['x'] 2, */ +}; + +int +fmtsize(Value *v) +{ + int ret; + + switch(v->vstore.fmt) { + default: + return fsize[v->vstore.fmt]; + case 'i': + case 'I': + if(v->type != TINT || machdata == 0) + error("no size for i fmt pointer ++/--"); + ret = (*machdata->instsize)(cormap, v->vstore.u0.sival); + if(ret < 0) { + ret = (*machdata->instsize)(symmap, v->vstore.u0.sival); + if(ret < 0) + error("%r"); + } + return ret; + } +} + +void +chklval(Node *lp) +{ + if(lp->op != ONAME) + error("need l-value"); +} + +void +olist(Node *n, Node *res) +{ + expr(n->left, res); + expr(n->right, res); +} + +void +oeval(Node *n, Node *res) +{ + expr(n->left, res); + if(res->type != TCODE) + error("bad type for eval"); + expr(res->nstore.u0.scc, res); +} + +void +ocast(Node *n, Node *res) +{ + if(n->sym->lt == 0) + error("%s is not a complex type", n->sym->name); + + expr(n->left, res); + res->nstore.comt = n->sym->lt; + res->nstore.fmt = 'a'; +} + +void +oindm(Node *n, Node *res) +{ + Map *m; + Node l; + + m = cormap; + if(m == 0) + m = symmap; + expr(n->left, &l); + if(l.type != TINT) + error("bad type for *"); + if(m == 0) + error("no map for *"); + indir(m, l.nstore.u0.sival, l.nstore.fmt, res); + res->nstore.comt = l.nstore.comt; +} + +void +oindc(Node *n, Node *res) +{ + Map *m; + Node l; + + m = symmap; + if(m == 0) + m = cormap; + expr(n->left, &l); + if(l.type != TINT) + error("bad type for @"); + if(m == 0) + error("no map for @"); + indir(m, l.nstore.u0.sival, l.nstore.fmt, res); + res->nstore.comt = l.nstore.comt; +} + +void +oframe(Node *n, Node *res) +{ + char *p; + Node *lp; + long ival; + Frtype *f; + + p = n->sym->name; + while(*p && *p == '$') + p++; + lp = n->left; + if(localaddr(cormap, p, lp->sym->name, &ival, rget) < 0) + error("colon: %r"); + + res->nstore.u0.sival = ival; + res->op = OCONST; + res->nstore.fmt = 'X'; + res->type = TINT; + + /* Try and set comt */ + for(f = n->sym->local; f; f = f->next) { + if(f->var == lp->sym) { + res->nstore.comt = f->type; + res->nstore.fmt = 'a'; + break; + } + } +} + +void +oindex(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + + if(r.type != TINT) + error("bad type for []"); + + switch(l.type) { + default: + error("lhs[] has bad type"); + case TINT: + indir(cormap, l.nstore.u0.sival+(r.nstore.u0.sival*fsize[l.nstore.fmt]), l.nstore.fmt, res); + res->nstore.comt = l.nstore.comt; + res->nstore.fmt = l.nstore.fmt; + break; + case TLIST: + nthelem(l.nstore.u0.sl, r.nstore.u0.sival, res); + break; + case TSTRING: + res->nstore.u0.sival = 0; + if(r.nstore.u0.sival >= 0 && r.nstore.u0.sival < l.nstore.u0.sstring->len) { + int xx8; /* to get around bug in vc */ + xx8 = r.nstore.u0.sival; + res->nstore.u0.sival = l.nstore.u0.sstring->string[xx8]; + } + res->op = OCONST; + res->type = TINT; + res->nstore.fmt = 'c'; + break; + } +} + +void +oappend(Node *n, Node *res) +{ + Node r, l; + + expr(n->left, &l); + expr(n->right, &r); + if(l.type != TLIST) + error("must append to list"); + append(res, &l, &r); +} + +void +odelete(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + if(l.type != TLIST) + error("must delete from list"); + if(r.type != TINT) + error("delete index must be integer"); + + delete(l.nstore.u0.sl, r.nstore.u0.sival, res); +} + +void +ohead(Node *n, Node *res) +{ + Node l; + + expr(n->left, &l); + if(l.type != TLIST) + error("head needs list"); + res->op = OCONST; + if(l.nstore.u0.sl) { + res->type = l.nstore.u0.sl->type; + res->nstore = l.nstore.u0.sl->lstore; + } + else { + res->type = TLIST; + res->nstore.u0.sl = 0; + } +} + +void +otail(Node *n, Node *res) +{ + Node l; + + expr(n->left, &l); + if(l.type != TLIST) + error("tail needs list"); + res->op = OCONST; + res->type = TLIST; + if(l.nstore.u0.sl) + res->nstore.u0.sl = l.nstore.u0.sl->next; + else + res->nstore.u0.sl = 0; +} + +void +oconst(Node *n, Node *res) +{ + res->op = OCONST; + res->type = n->type; + res->nstore = n->nstore; + res->nstore.comt = n->nstore.comt; +} + +void +oname(Node *n, Node *res) +{ + Value *v; + + v = n->sym->v; + if(v->set == 0) + error("%s used but not set", n->sym->name); + res->op = OCONST; + res->type = v->type; + res->nstore = v->vstore; + res->nstore.comt = v->vstore.comt; +} + +void +octruct(Node *n, Node *res) +{ + res->op = OCONST; + res->type = TLIST; + res->nstore.u0.sl = construct(n->left); +} + +void +oasgn(Node *n, Node *res) +{ + Node *lp, r; + Value *v; + + lp = n->left; + switch(lp->op) { + case OINDM: + windir(cormap, lp->left, n->right, res); + break; + case OINDC: + windir(symmap, lp->left, n->right, res); + break; + default: + chklval(lp); + v = lp->sym->v; + expr(n->right, &r); + v->set = 1; + v->type = r.type; + v->vstore = r.nstore; + res->op = OCONST; + res->type = v->type; + res->nstore = v->vstore; + res->nstore.comt = v->vstore.comt; + } +} + +void +oadd(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type +"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->nstore.u0.sival = l.nstore.u0.sival+r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sival+r.nstore.u0.sfval; + break; + default: + error("bad rhs type +"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sfval = l.nstore.u0.sfval+r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sfval+r.nstore.u0.sfval; + break; + default: + error("bad rhs type +"); + } + break; + case TSTRING: + if(r.type == TSTRING) { + res->type = TSTRING; + res->nstore.fmt = 's'; + res->nstore.u0.sstring = stradd(l.nstore.u0.sstring, r.nstore.u0.sstring); + break; + } + error("bad rhs for +"); + case TLIST: + res->type = TLIST; + switch(r.type) { + case TLIST: + res->nstore.u0.sl = addlist(l.nstore.u0.sl, r.nstore.u0.sl); + break; + default: + r.left = 0; + r.right = 0; + res->nstore.u0.sl = addlist(l.nstore.u0.sl, construct(&r)); + break; + } + } +} + +void +osub(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type -"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->nstore.u0.sival = l.nstore.u0.sival-r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sival-r.nstore.u0.sfval; + break; + default: + error("bad rhs type -"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sfval = l.nstore.u0.sfval-r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sfval-r.nstore.u0.sfval; + break; + default: + error("bad rhs type -"); + } + break; + } +} + +void +omul(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type *"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->nstore.u0.sival = l.nstore.u0.sival*r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sival*r.nstore.u0.sfval; + break; + default: + error("bad rhs type *"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sfval = l.nstore.u0.sfval*r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sfval*r.nstore.u0.sfval; + break; + default: + error("bad rhs type *"); + } + break; + } +} + +void +odiv(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type /"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + if(r.nstore.u0.sival == 0) + error("zero divide"); + res->nstore.u0.sival = l.nstore.u0.sival/r.nstore.u0.sival; + break; + case TFLOAT: + if(r.nstore.u0.sfval == 0) + error("zero divide"); + res->nstore.u0.sfval = l.nstore.u0.sival/r.nstore.u0.sfval; + break; + default: + error("bad rhs type /"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sfval = l.nstore.u0.sfval/r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sfval = l.nstore.u0.sfval/r.nstore.u0.sfval; + break; + default: + error("bad rhs type /"); + } + break; + } +} + +void +omod(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type %"); + res->nstore.u0.sival = l.nstore.u0.sival%r.nstore.u0.sival; +} + +void +olsh(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type <<"); + res->nstore.u0.sival = l.nstore.u0.sival<<r.nstore.u0.sival; +} + +void +orsh(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type >>"); + res->nstore.u0.sival = l.nstore.u0.sival>>r.nstore.u0.sival; +} + +void +olt(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type <"); + case TINT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sival < r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sival < r.nstore.u0.sfval; + break; + default: + error("bad rhs type <"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sfval < r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sfval < r.nstore.u0.sfval; + break; + default: + error("bad rhs type <"); + } + break; + } +} + +void +ogt(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type >"); + case TINT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sival > r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sival > r.nstore.u0.sfval; + break; + default: + error("bad rhs type >"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sfval > r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sfval > r.nstore.u0.sfval; + break; + default: + error("bad rhs type >"); + } + break; + } +} + +void +oleq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad expr type <="); + case TINT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sival <= r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sival <= r.nstore.u0.sfval; + break; + default: + error("bad expr type <="); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sfval <= r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sfval <= r.nstore.u0.sfval; + break; + default: + error("bad expr type <="); + } + break; + } +} + +void +ogeq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type >="); + case TINT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sival >= r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sival >= r.nstore.u0.sfval; + break; + default: + error("bad rhs type >="); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sfval >= r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sfval >= r.nstore.u0.sfval; + break; + default: + error("bad rhs type >="); + } + break; + } +} + +void +oeq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + res->nstore.u0.sival = 0; + switch(l.type) { + default: + break; + case TINT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sival == r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sival == r.nstore.u0.sfval; + break; + default: + break; + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->nstore.u0.sival = l.nstore.u0.sfval == r.nstore.u0.sival; + break; + case TFLOAT: + res->nstore.u0.sival = l.nstore.u0.sfval == r.nstore.u0.sfval; + break; + default: + break; + } + break; + case TSTRING: + if(r.type == TSTRING) { + res->nstore.u0.sival = scmp(r.nstore.u0.sstring, l.nstore.u0.sstring); + break; + } + break; + case TLIST: + if(r.type == TLIST) { + res->nstore.u0.sival = listcmp(l.nstore.u0.sl, r.nstore.u0.sl); + break; + } + break; + } + if(n->op == ONEQ) + res->nstore.u0.sival = !res->nstore.u0.sival; +} + + +void +oland(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type &"); + res->nstore.u0.sival = l.nstore.u0.sival&r.nstore.u0.sival; +} + +void +oxor(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type ^"); + res->nstore.u0.sival = l.nstore.u0.sival^r.nstore.u0.sival; +} + +void +olor(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type |"); + res->nstore.u0.sival = l.nstore.u0.sival|r.nstore.u0.sival; +} + +void +ocand(Node *n, Node *res) +{ + Node l, r; + + res->nstore.fmt = l.nstore.fmt; + res->op = OCONST; + res->type = TINT; + res->nstore.u0.sival = 0; + expr(n->left, &l); + if(bool(&l) == 0) + return; + expr(n->right, &r); + if(bool(&r) == 0) + return; + res->nstore.u0.sival = 1; +} + +void +onot(Node *n, Node *res) +{ + Node l; + + res->op = OCONST; + res->type = TINT; + res->nstore.u0.sival = 0; + expr(n->left, &l); + if(bool(&l) == 0) + res->nstore.u0.sival = 1; +} + +void +ocor(Node *n, Node *res) +{ + Node l, r; + + res->op = OCONST; + res->type = TINT; + res->nstore.u0.sival = 0; + expr(n->left, &l); + if(bool(&l)) { + res->nstore.u0.sival = 1; + return; + } + expr(n->right, &r); + if(bool(&r)) { + res->nstore.u0.sival = 1; + return; + } +} + +void +oeinc(Node *n, Node *res) +{ + Value *v; + + chklval(n->left); + v = n->left->sym->v; + res->op = OCONST; + res->type = v->type; + switch(v->type) { + case TINT: + if(n->op == OEDEC) + v->vstore.u0.sival -= fmtsize(v); + else + v->vstore.u0.sival += fmtsize(v); + break; + case TFLOAT: + if(n->op == OEDEC) + v->vstore.u0.sfval--; + else + v->vstore.u0.sfval++; + break; + default: + error("bad type for pre --/++"); + } + res->nstore = v->vstore; +} + +void +opinc(Node *n, Node *res) +{ + Value *v; + + chklval(n->left); + v = n->left->sym->v; + res->op = OCONST; + res->type = v->type; + res->nstore = v->vstore; + switch(v->type) { + case TINT: + if(n->op == OPDEC) + v->vstore.u0.sival -= fmtsize(v); + else + v->vstore.u0.sival += fmtsize(v); + break; + case TFLOAT: + if(n->op == OPDEC) + v->vstore.u0.sfval--; + else + v->vstore.u0.sfval++; + break; + default: + error("bad type for post --/++"); + } +} + +void +ocall(Node *n, Node *res) +{ + Lsym *s; + Rplace *rsav; + + res->op = OCONST; /* Default return value */ + res->type = TLIST; + res->nstore.u0.sl = 0; + + chklval(n->left); + s = n->left->sym; + + if(s->builtin) { + (*s->builtin)(res, n->right); + return; + } + if(s->proc == 0) + error("no function %s", s->name); + + rsav = ret; + call(s->name, n->right, s->proc->left, s->proc->right, res); + ret = rsav; +} + +void +ofmt(Node *n, Node *res) +{ + expr(n->left, res); + res->nstore.fmt = n->right->nstore.u0.sival; +} + +void +owhat(Node *n, Node *res) +{ + res->op = OCONST; /* Default return value */ + res->type = TLIST; + res->nstore.u0.sl = 0; + whatis(n->sym); +} + +void (*expop[])(Node*, Node*) = +{ + oname, /* [ONAME] oname, */ + oconst, /* [OCONST] oconst, */ + omul, /* [OMUL] omul, */ + odiv, /* [ODIV] odiv, */ + omod, /* [OMOD] omod, */ + oadd, /* [OADD] oadd, */ + osub, /* [OSUB] osub, */ + orsh, /* [ORSH] orsh, */ + olsh, /* [OLSH] olsh, */ + olt, /* [OLT] olt, */ + ogt, /* [OGT] ogt, */ + oleq, /* [OLEQ] oleq, */ + ogeq, /* [OGEQ] ogeq, */ + oeq, /* [OEQ] oeq, */ + oeq, /* [ONEQ] oeq, */ + oland, /* [OLAND] oland, */ + oxor, /* [OXOR] oxor, */ + olor, /* [OLOR] olor, */ + ocand, /* [OCAND] ocand, */ + ocor, /* [OCOR] ocor, */ + oasgn, /* [OASGN] oasgn, */ + oindm, /* [OINDM] oindm, */ + oeinc, /* [OEDEC] oeinc, */ + oeinc, /* [OEINC] oeinc, */ + opinc, /* [OPINC] opinc, */ + opinc, /* [OPDEC] opinc, */ + onot, /* [ONOT] onot, */ + 0, /* [OIF] 0, */ + 0, /* [ODO] 0, */ + olist, /* [OLIST] olist, */ + ocall, /* [OCALL] ocall, */ + octruct, /* [OCTRUCT] octruct, */ + 0, /* [OWHILE] 0, */ + 0, /* [OELSE] 0, */ + ohead, /* [OHEAD] ohead, */ + otail, /* [OTAIL] otail, */ + oappend, /* [OAPPEND] oappend, */ + 0, /* [ORET] 0, */ + oindex, /* [OINDEX] oindex, */ + oindc, /* [OINDC] oindc, */ + odot, /* [ODOT] odot, */ + 0, /* [OLOCAL] 0, */ + oframe, /* [OFRAME] oframe, */ + 0, /* [OCOMPLEX] 0, */ + odelete, /* [ODELETE] odelete, */ + ocast, /* [OCAST] ocast, */ + ofmt, /* [OFMT] ofmt, */ + oeval, /* [OEVAL] oeval, */ + owhat, /* [OWHAT] owhat, */ +}; diff --git a/utils/acid/lex.c b/utils/acid/lex.c new file mode 100644 index 00000000..364bcae9 --- /dev/null +++ b/utils/acid/lex.c @@ -0,0 +1,636 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +struct keywd +{ + char *name; + int terminal; +} +keywds[] = +{ + "do", Tdo, + "if", Tif, + "then", Tthen, + "else", Telse, + "while", Twhile, + "loop", Tloop, + "head", Thead, + "tail", Ttail, + "append", Tappend, + "defn", Tfn, + "return", Tret, + "local", Tlocal, + "aggr", Tcomplex, + "union", Tcomplex, + "adt", Tcomplex, + "complex", Tcomplex, + "delete", Tdelete, + "whatis", Twhat, + "eval", Teval, + 0, 0 +}; + +char cmap[256] = +{ + 0,0,0,0,0,0,0,0, /* 0-7 */ + 0,0,0,0,0,0,0,0, /* 8-15 */ + 0,0,0,0,0,0,0,0, /* 16-23 */ + 0,0,0,0,0,0,0,0, /* 24-31 */ + 0,0, /* 32-33 */ + '"'+1, /* 34 ['"'] '"'+1, */ + 0,0,0,0,0, /* 35-39 */ + 0,0,0,0,0,0,0,0, /* 40-47 */ + '\0'+1, /* 48 ['0'] '\0'+1, */ + 0,0,0,0,0,0,0, /* 49-55 */ + 0,0,0,0,0,0,0,0, /* 56-63 */ + 0,0,0,0,0,0,0,0, /* 64-71 */ + 0,0,0,0,0,0,0,0, /* 72-79 */ + 0,0,0,0,0,0,0,0, /* 80-87 */ + 0,0,0,0, /* 88-91 */ + '\\'+1, /* 92 ['\\'] '\\'+1, */ + 0,0,0,0, /* 93-96 */ + '\a'+1, /* 97 ['a'] '\a'+1, */ + '\b'+1, /* 98 ['b'] '\b'+1, */ + 0,0,0, /* 99-101 */ + '\f'+1, /* 102 ['f'] '\f'+1, */ + 0,0,0,0,0,0,0, /* 103-109 */ + '\n'+1, /* 110 ['n'] '\n'+1, */ + 0,0,0, /* 111-113 */ + '\r'+1, /* 114 ['r'] '\r'+1, */ + 0, /* 115 */ + '\t'+1, /* 116 ['t'] '\t'+1, */ + 0, /* 117 */ + '\v'+1, /* 118 ['v'] '\v'+1, */ +}; + +void +kinit(void) +{ + int i; + + for(i = 0; keywds[i].name; i++) + enter(keywds[i].name, keywds[i].terminal); +} + +typedef struct IOstack IOstack; +struct IOstack +{ + char *name; + int line; + char *text; + char *ip; + Biobuf *fin; + IOstack *prev; +}; +IOstack *lexio; + +void +pushfile(char *file) +{ + Biobuf *b; + IOstack *io; + char buf[512]; + extern char *acidlib; + + if(file){ + b = Bopen(file, OREAD); + if(b == nil && strchr(file, '/') == 0){ + snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, file); + b = Bopen(buf, OREAD); + } + } + else{ + b = gmalloc(sizeof(Biobuf)); + if (Binit(b, 0, OREAD) == Beof) { + free(b); + b = 0; + } + file = "<stdin>"; + } + + if(b == 0) + error("pushfile: %s: %r", file); + + io = gmalloc(sizeof(IOstack)); + if(io == 0) + fatal("no memory"); + io->name = strdup(file); + if(io->name == 0) + fatal("no memory"); + io->line = line; + line = 1; + io->text = 0; + io->fin = b; + io->prev = lexio; + lexio = io; +} + +void +pushstr(Node *s) +{ + IOstack *io; + + io = gmalloc(sizeof(IOstack)); + if(io == 0) + fatal("no memory"); + io->line = line; + line = 1; + io->name = strdup("<string>"); + if(io->name == 0) + fatal("no memory"); + io->line = line; + line = 1; + io->text = strdup(s->nstore.u0.sstring->string); + if(io->text == 0) + fatal("no memory"); + io->ip = io->text; + io->fin = 0; + io->prev = lexio; + lexio = io; +} + +void +restartio(void) +{ + Bflush(lexio->fin); + Binit(lexio->fin, 0, OREAD); +} + +int +popio(void) +{ + IOstack *s; + + if(lexio == 0) + return 0; + + if(lexio->prev == 0){ + if(lexio->fin) + restartio(); + return 0; + } + + if(lexio->fin) + Bterm(lexio->fin); + else + free(lexio->text); + free(lexio->name); + line = lexio->line; + s = lexio; + lexio = s->prev; + free(s); + return 1; +} + +int +Lfmt(Fmt *f) +{ + int i; + char buf[1024]; + IOstack *e; + + e = lexio; + if(e) { + i = sprint(buf, "%s:%d", e->name, line); + while(e->prev) { + e = e->prev; + if(initialising && e->prev == 0) + break; + i += sprint(buf+i, " [%s:%d]", e->name, e->line); + } + } else + sprint(buf, "no file:0"); + return fmtstrcpy(f, buf); +} + +void +unlexc(int s) +{ + if(s == '\n') + line--; + + if(lexio->fin) + Bungetc(lexio->fin); + else + lexio->ip--; +} + +int +lexc(void) +{ + int c; + + if(lexio->fin) { + c = Bgetc(lexio->fin); + if(gotint) + error("interrupt"); + return c; + } + + c = *lexio->ip++; + if(c == 0) + return -1; + return c; +} + +int +escchar(char c) +{ + int n; + char buf[Strsize]; + + if(c >= '0' && c <= '9') { + n = 1; + buf[0] = c; + for(;;) { + c = lexc(); + if(c == Eof) + error("%d: <eof> in escape sequence", line); + if(strchr("0123456789xX", c) == 0) { + unlexc(c); + break; + } + buf[n++] = c; + } + buf[n] = '\0'; + return strtol(buf, 0, 0); + } + + n = cmap[c]; + if(n == 0) + return c; + return n-1; +} + +void +eatstring(void) +{ + int esc, c, cnt; + char buf[Strsize]; + + esc = 0; + for(cnt = 0;;) { + c = lexc(); + switch(c) { + case Eof: + error("%d: <eof> in string constant", line); + + case '\r': + case '\n': + error("newline in string constant"); + goto done; + + case '\\': + if(esc) + goto Default; + esc = 1; + break; + + case '"': + if(esc == 0) + goto done; + + /* Fall through */ + default: + Default: + if(esc) { + c = escchar(c); + esc = 0; + } + buf[cnt++] = c; + break; + } + if(cnt >= Strsize) + error("string token too long"); + } +done: + buf[cnt] = '\0'; + yylval.string = strnode(buf); +} + +void +eatnl(void) +{ + int c; + + line++; + for(;;) { + c = lexc(); + if(c == Eof) + error("eof in comment"); + if(c == '\n') + return; + } +} + +int +yylex(void) +{ + int c; + extern char vfmt[]; + +loop: + Bflush(bout); + c = lexc(); + switch(c) { + case Eof: + if(gotint) { + gotint = 0; + stacked = 0; + Bprint(bout, "\nacid: "); + goto loop; + } + return Eof; + + case '"': + eatstring(); + return Tstring; + + case ' ': + case '\r': + case '\t': + goto loop; + + case '\n': + line++; + if(interactive == 0) + goto loop; + if(stacked) { + print("\t"); + goto loop; + } + return ';'; + + case '.': + c = lexc(); + unlexc(c); + if(isdigit(c)) + return numsym('.'); + + return '.'; + + case '(': + case ')': + case '[': + case ']': + case ';': + case ':': + case ',': + case '~': + case '?': + case '*': + case '@': + case '^': + case '%': + return c; + case '{': + stacked++; + return c; + case '}': + stacked--; + return c; + + case '\\': + c = lexc(); + if(strchr(vfmt, c) == 0) { + unlexc(c); + return '\\'; + } + yylval.ival = c; + return Tfmt; + + case '!': + c = lexc(); + if(c == '=') + return Tneq; + unlexc(c); + return '!'; + + case '+': + c = lexc(); + if(c == '+') + return Tinc; + unlexc(c); + return '+'; + + case '/': + c = lexc(); + if(c == '/') { + eatnl(); + goto loop; + } + unlexc(c); + return '/'; + + case '\'': + c = lexc(); + if(c == '\\') + yylval.ival = escchar(lexc()); + else + yylval.ival = c; + c = lexc(); + if(c != '\'') { + error("missing '"); + unlexc(c); + } + return Tconst; + + case '&': + c = lexc(); + if(c == '&') + return Tandand; + unlexc(c); + return '&'; + + case '=': + c = lexc(); + if(c == '=') + return Teq; + unlexc(c); + return '='; + + case '|': + c = lexc(); + if(c == '|') + return Toror; + unlexc(c); + return '|'; + + case '<': + c = lexc(); + if(c == '=') + return Tleq; + if(c == '<') + return Tlsh; + unlexc(c); + return '<'; + + case '>': + c = lexc(); + if(c == '=') + return Tgeq; + if(c == '>') + return Trsh; + unlexc(c); + return '>'; + + case '-': + c = lexc(); + + if(c == '>') + return Tindir; + + if(c == '-') + return Tdec; + unlexc(c); + return '-'; + + default: + return numsym(c); + } +} + +int +numsym(char first) +{ + int c, isbin, isfloat, ishex; + char *sel, *p; + Lsym *s; + + symbol[0] = first; + p = symbol; + + ishex = 0; + isbin = 0; + isfloat = 0; + if(first == '.') + isfloat = 1; + + if(isdigit(*p++) || isfloat) { + for(;;) { + c = lexc(); + if(c < 0) + error("%d: <eof> eating symbols", line); + + if(c == '\r') + continue; + if(c == '\n') + line++; + sel = "01234567890.xb"; + if(ishex) + sel = "01234567890abcdefABCDEF"; + else if(isbin) + sel = "01"; + else if(isfloat) + sel = "01234567890eE-+"; + + if(strchr(sel, c) == 0) { + unlexc(c); + break; + } + if(c == '.') + isfloat = 1; + if(!isbin && c == 'x') + ishex = 1; + if(!ishex && c == 'b') + isbin = 1; + *p++ = c; + } + *p = '\0'; + if(isfloat) { + yylval.fval = atof(symbol); + return Tfconst; + } + + if(isbin) + yylval.ival = strtoul(symbol+2, 0, 2); + else + yylval.ival = strtoul(symbol, 0, 0); + return Tconst; + } + + for(;;) { + c = lexc(); + if(c < 0) + error("%d <eof> eating symbols", line); + if(c == '\n') + line++; + if(c != '_' && c != '$' && c <= '~' && !isalnum(c)) { /* checking against ~ lets UTF names through */ + unlexc(c); + break; + } + *p++ = c; + } + + *p = '\0'; + + s = look(symbol); + if(s == 0) + s = enter(symbol, Tid); + + yylval.sym = s; + return s->lexval; +} + +Lsym* +enter(char *name, int t) +{ + Lsym *s; + ulong h; + char *p; + Value *v; + + h = 0; + for(p = name; *p; p++) + h = h*3 + *p; + h %= Hashsize; + + s = gmalloc(sizeof(Lsym)); + s->name = strdup(name); + + s->hash = hash[h]; + hash[h] = s; + s->lexval = t; + + v = gmalloc(sizeof(Value)); + s->v = v; + + v->vstore.fmt = 'X'; + v->type = TINT; + + return s; +} + +Lsym* +look(char *name) +{ + Lsym *s; + ulong h; + char *p; + + h = 0; + for(p = name; *p; p++) + h = h*3 + *p; + h %= Hashsize; + + for(s = hash[h]; s; s = s->hash) + if(strcmp(name, s->name) == 0) + return s; + return 0; +} + +Lsym* +mkvar(char *s) +{ + Lsym *l; + + l = look(s); + if(l == 0) + l = enter(s, Tid); + return l; +} diff --git a/utils/acid/list.c b/utils/acid/list.c new file mode 100644 index 00000000..ced2f4d8 --- /dev/null +++ b/utils/acid/list.c @@ -0,0 +1,276 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" + +static List **tail; + +List* +construct(Node *l) +{ + List *lh, **save; + + save = tail; + lh = 0; + tail = &lh; + build(l); + tail = save; + + return lh; +} + +int +listlen(List *l) +{ + int len; + + len = 0; + while(l) { + len++; + l = l->next; + } + return len; +} + +void +build(Node *n) +{ + List *l; + Node res; + + if(n == 0) + return; + + switch(n->op) { + case OLIST: + build(n->left); + build(n->right); + return; + default: + expr(n, &res); + l = al(res.type); + l->lstore = res.nstore; + *tail = l; + tail = &l->next; + } +} + +List* +addlist(List *l, List *r) +{ + List *f; + + if(l == 0) + return r; + + for(f = l; f->next; f = f->next) + ; + f->next = r; + + return l; +} + +void +append(Node *r, Node *list, Node *val) +{ + List *l, *f; + + l = al(val->type); + l->lstore = val->nstore; + l->next = 0; + + r->op = OCONST; + r->type = TLIST; + + if(list->nstore.u0.sl == 0) { + list->nstore.u0.sl = l; + r->nstore.u0.sl = l; + return; + } + for(f = list->nstore.u0.sl; f->next; f = f->next) + ; + f->next = l; + r->nstore.u0.sl = list->nstore.u0.sl; +} + +int +listcmp(List *l, List *r) +{ + if(l == r) + return 1; + + while(l) { + if(r == 0) + return 0; + if(l->type != r->type) + return 0; + switch(l->type) { + case TINT: + if(l->lstore.u0.sival != r->lstore.u0.sival) + return 0; + break; + case TFLOAT: + if(l->lstore.u0.sfval != r->lstore.u0.sfval) + return 0; + break; + case TSTRING: + if(scmp(l->lstore.u0.sstring, r->lstore.u0.sstring) == 0) + return 0; + break; + case TLIST: + if(listcmp(l->lstore.u0.sl, r->lstore.u0.sl) == 0) + return 0; + break; + } + l = l->next; + r = r->next; + } + if(l != r) + return 0; + return 1; +} + +void +nthelem(List *l, int n, Node *res) +{ + if(n < 0) + error("negative index in []"); + + while(l && n--) + l = l->next; + + res->op = OCONST; + if(l == 0) { + res->type = TLIST; + res->nstore.u0.sl = 0; + return; + } + res->type = l->type; + res->nstore = l->lstore; +} + +void +delete(List *l, int n, Node *res) +{ + List **tl; + + if(n < 0) + error("negative index in delete"); + + res->op = OCONST; + res->type = TLIST; + res->nstore.u0.sl = l; + + for(tl = &res->nstore.u0.sl; l && n--; l = l->next) + tl = &l->next; + + if(l == 0) + error("element beyond end of list"); + *tl = l->next; +} + +List* +listvar(char *s, long v) +{ + List *l, *tl; + + tl = al(TLIST); + + l = al(TSTRING); + tl->lstore.u0.sl = l; + l->lstore.fmt = 's'; + l->lstore.u0.sstring = strnode(s); + l->next = al(TINT); + l = l->next; + l->lstore.fmt = 'X'; + l->lstore.u0.sival = v; + + return tl; +} + +static List* +listlocals(Map *map, Symbol *fn, ulong fp) +{ + int i; + long val; + Symbol s; + List **tail, *l2; + + l2 = 0; + tail = &l2; + s = *fn; + + for(i = 0; localsym(&s, i); i++) { + if(s.class != CAUTO) + continue; + if(s.name[0] == '.') + continue; + + if(get4(map, fp-s.value, &val) > 0) { + *tail = listvar(s.name, val); + tail = &(*tail)->next; + } + } + return l2; +} + +static List* +listparams(Map *map, Symbol *fn, ulong fp) +{ + int i; + Symbol s; + long v; + List **tail, *l2; + + l2 = 0; + tail = &l2; + fp += mach->szaddr; /* skip saved pc */ + s = *fn; + for(i = 0; localsym(&s, i); i++) { + if (s.class != CPARAM) + continue; + + if(get4(map, fp+s.value, &v) > 0) { + *tail = listvar(s.name, v); + tail = &(*tail)->next; + } + } + return l2; +} + +void +trlist(Map *map, ulong pc, ulong sp, Symbol *sym) +{ + List *q, *l; + + static List **tail; + + if (tracelist == 0) { /* first time */ + tracelist = al(TLIST); + tail = &tracelist; + } + + q = al(TLIST); + *tail = q; + tail = &q->next; + + l = al(TINT); /* Function address */ + q->lstore.u0.sl = l; + l->lstore.u0.sival = sym->value; + l->lstore.fmt = 'X'; + + l->next = al(TINT); /* called from address */ + l = l->next; + l->lstore.u0.sival = pc; + l->lstore.fmt = 'X'; + + l->next = al(TLIST); /* make list of params */ + l = l->next; + l->lstore.u0.sl = listparams(map, sym, sp); + + l->next = al(TLIST); /* make list of locals */ + l = l->next; + l->lstore.u0.sl = listlocals(map, sym, sp); +} diff --git a/utils/acid/main.c b/utils/acid/main.c new file mode 100644 index 00000000..5bd85f13 --- /dev/null +++ b/utils/acid/main.c @@ -0,0 +1,616 @@ +/*#include <u.h>*/ +#include <lib9.h> +#include <bio.h> +#include "mach.h" +#define Extern +#include "acid.h" +#include "y.tab.h" + +char *argv0; +char *acidlib; +static Biobuf bioout; +static char prog[128]; +static char* lm[16]; +static int nlm; +static char* mtype; + +static int attachfiles(char*, int); +int xfmt(Fmt*); +extern int gfltconv(Fmt*), _ifmt(Fmt*); +int isnumeric(char*); +void die(void); + +void +usage(void) +{ + fprint(2, "usage: acid [-l module] [-m machine] [-qrw] [-k] [-d flag] [-R tty] [pid] [file]\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + Dir *db; + Lsym *l; + Node *n; + char buf[128], *s; + int pid, i; + char *p; + char afile[512]; + + argv0 = argv[0]; + pid = 0; + aout = "v.out"; + quiet = 1; + /* turn off all debugging */ + protodebug = 0; + + mtype = 0; + ARGBEGIN{ + case 'm': + mtype = ARGF(); + break; + case 'w': + wtflag = 1; + break; + case 'l': + s = ARGF(); + if(s == 0) + usage(); + lm[nlm++] = s; + break; + case 'd': + p = ARGF(); + if (p == 0) + usage(); + while (*p) { + setdbg_opt(*p, 0); /* don't print set message */ + p++; + } + break; + case 'k': + kernel++; + break; + case 'q': + quiet = 0; + break; + case 'r': + pid = 1; + remote++; + kernel++; + break; + case 'R': + pid = 1; + rdebug++; + s = ARGF(); + if(s == 0) + usage(); + remfd = opentty(s, 0); + if(remfd < 0){ + fprint(2, "acid: can't open %s: %r\n", s); + exits("open"); + } + break; + default: + usage(); + }ARGEND + + if(argc > 0) { + if(remote || rdebug) + aout = argv[0]; + else + if(isnumeric(argv[0])) { + pid = atoi(argv[0]); + sprint(prog, "/proc/%d/text", pid); + aout = prog; + if(argc > 1) + aout = argv[1]; + else if(kernel) + aout = mysystem(); + } + else { + if(kernel) { + print("-k requires a pid"); + kernel = 0; + } + aout = argv[0]; + } + } else if(rdebug) + aout = "/386/bpc"; + else if(remote) + aout = "/mips/bcarrera"; + + fmtinstall('x', xfmt); + fmtinstall('L', Lfmt); + fmtinstall('f', gfltconv); + fmtinstall('F', gfltconv); + fmtinstall('g', gfltconv); + fmtinstall('G', gfltconv); + fmtinstall('e', gfltconv); + fmtinstall('E', gfltconv); + Binit(&bioout, 1, OWRITE); + bout = &bioout; + + kinit(); + initialising = 1; + pushfile(0); + loadvars(); + installbuiltin(); + + if(mtype && machbyname(mtype) == 0) + print("unknown machine %s", mtype); + + if (attachfiles(aout, pid) < 0) + varreg(); /* use default register set on error */ + + acidlib = getenv("ACIDLIB"); + if(acidlib == nil){ + p = getenv("ROOT"); + if(p == nil) + p = "/usr/inferno"; + snprint(afile, sizeof(afile)-1, "%s/lib/acid", p); + acidlib = strdup(afile); + } + + snprint(afile, sizeof(afile)-1, "%s/port", acidlib); + loadmodule(afile); + for(i = 0; i < nlm; i++) { + if((db = dirstat(lm[i])) != nil) { + free(db); + loadmodule(lm[i]); + } else { + sprint(buf, "%s/%s", acidlib, lm[i]); + loadmodule(buf); + } + } + + userinit(); + varsym(); + + l = look("acidmap"); + if(l && l->proc) { + n = an(ONAME, ZN, ZN); + n->sym = l; + n = an(OCALL, n, ZN); + execute(n); + } + + interactive = 1; + initialising = 0; + line = 1; + + setup_os_notify(); + + for(;;) { + if(setjmp(err)) { + Binit(&bioout, 1, OWRITE); + unwind(); + } + stacked = 0; + + Bprint(bout, "acid: "); + + if(yyparse() != 1) + die(); + restartio(); + + unwind(); + } + Bputc(bout, '\n'); + exits(0); +} + +static int +attachfiles(char *aout, int pid) +{ + interactive = 0; + if(setjmp(err)) + return -1; + + if(aout) { /* executable given */ + if(wtflag) + text = open(aout, ORDWR); + else + text = open(aout, OREAD); + + if(text < 0) + error("%s: can't open %s: %r\n", argv0, aout); + readtext(aout); + } + if(pid) /* pid given */ + sproc(pid); + return 0; +} + +void +die(void) +{ + Lsym *s; + List *f; + + Bprint(bout, "\n"); + + s = look("proclist"); + if(!rdebug && s && s->v->type == TLIST) { + for(f = s->v->vstore.u0.sl; f; f = f->next) + Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->lstore.u0.sival); + } + exits(0); +} + +void +userinit(void) +{ + Lsym *l; + Node *n; + char buf[512], *p; + + + p = getenv("home"); + if(p == 0) + p = getenv("HOME"); + if(p != 0) { + snprint(buf, sizeof(buf)-1, "%s/lib/acid", p); + silent = 1; + loadmodule(buf); + } + + if(rdebug){ + snprint(buf, sizeof(buf)-1, "%s/rdebug", acidlib); + loadmodule(buf); + } + + snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, mach->name); + loadmodule(buf); + + interactive = 0; + if(setjmp(err)) { + unwind(); + return; + } + l = look("acidinit"); + if(l && l->proc) { + n = an(ONAME, ZN, ZN); + n->sym = l; + n = an(OCALL, n, ZN); + execute(n); + } +} + +void +loadmodule(char *s) +{ + interactive = 0; + if(setjmp(err)) { + unwind(); + return; + } + pushfile(s); + silent = 0; + yyparse(); + popio(); + return; +} + +void +readtext(char *s) +{ + Dir *d; + Lsym *l; + Value *v; + Symbol sym; + ulong length; + extern Machdata mipsmach; + + if(mtype != 0){ + symmap = newmap(0, 1); + if(symmap == 0) + print("%s: (error) loadmap: cannot make symbol map\n", argv0); + length = 1<<24; + d = dirfstat(text); + if(d != nil) { + length = d->length; + free(d); + } + setmap(symmap, text, 0, length, 0, "binary"); + free(d); + return; + } + + machdata = &mipsmach; + + if(!crackhdr(text, &fhdr)) { + print("can't decode file header\n"); + return; + } + + symmap = loadmap(0, text, &fhdr); + if(symmap == 0) + print("%s: (error) loadmap: cannot make symbol map\n", argv0); + + if(syminit(text, &fhdr) < 0) { + print("%s: (error) syminit: %r\n", argv0); + return; + } + print("%s:%s\n\n", s, fhdr.name); + + if(mach->sbreg && lookup(0, mach->sbreg, &sym)) { + mach->sb = sym.value; + l = enter("SB", Tid); + l->v->vstore.fmt = 'X'; + l->v->vstore.u0.sival = mach->sb; + l->v->type = TINT; + l->v->set = 1; + } + + l = mkvar("objtype"); + v = l->v; + v->vstore.fmt = 's'; + v->set = 1; + v->vstore.u0.sstring = strnode(mach->name); + v->type = TSTRING; + + l = mkvar("textfile"); + v = l->v; + v->vstore.fmt = 's'; + v->set = 1; + v->vstore.u0.sstring = strnode(s); + v->type = TSTRING; + + machbytype(fhdr.type); + varreg(); +} + +Node* +an(int op, Node *l, Node *r) +{ + Node *n; + + n = gmalloc(sizeof(Node)); + n->ngc.gclink = gcl; + gcl = &n->ngc; + n->op = op; + n->left = l; + n->right = r; + return n; +} + +List* +al(int t) +{ + List *l; + + l = gmalloc(sizeof(List)); + l->type = t; + l->lgc.gclink = gcl; + gcl = &l->lgc; + return l; +} + +Node* +con(int v) +{ + Node *n; + + n = an(OCONST, ZN, ZN); + n->nstore.u0.sival = v; + n->nstore.fmt = 'X'; + n->type = TINT; + return n; +} + +void +fatal(char *fmt, ...) +{ + char buf[128]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s: %L (fatal problem) %s\n", argv0, buf); + exits(buf); +} + +void +yyerror(char *fmt, ...) +{ + char buf[128]; + va_list arg; + + if(strcmp(fmt, "syntax error") == 0) { + yyerror("syntax error, near symbol '%s'", symbol); + return; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%L: %s\n", buf); +} + +void +marktree(Node *n) +{ + + if(n == 0) + return; + + marktree(n->left); + marktree(n->right); + + n->ngc.gcmark = 1; + if(n->op != OCONST) + return; + + switch(n->type) { + case TSTRING: + n->nstore.u0.sstring->sgc.gcmark = 1; + break; + case TLIST: + marklist(n->nstore.u0.sl); + break; + case TCODE: + marktree(n->nstore.u0.scc); + break; + } +} + +void +marklist(List *l) +{ + while(l) { + l->lgc.gcmark = 1; + switch(l->type) { + case TSTRING: + l->lstore.u0.sstring->sgc.gcmark = 1; + break; + case TLIST: + marklist(l->lstore.u0.sl); + break; + case TCODE: + marktree(l->lstore.u0.scc); + break; + } + l = l->next; + } +} + +void +gc(void) +{ + int i; + Lsym *f; + Value *v; + Gc *m, **p, *next; + + if(dogc < Mempergc) + return; + dogc = 0; + + /* Mark */ + for(m = gcl; m; m = m->gclink) + m->gcmark = 0; + + /* Scan */ + for(i = 0; i < Hashsize; i++) { + for(f = hash[i]; f; f = f->hash) { + marktree(f->proc); + if(f->lexval != Tid) + continue; + for(v = f->v; v; v = v->pop) { + switch(v->type) { + case TSTRING: + v->vstore.u0.sstring->sgc.gcmark = 1; + break; + case TLIST: + marklist(v->vstore.u0.sl); + break; + case TCODE: + marktree(v->vstore.u0.scc); + break; + } + } + } + } + + /* Free */ + p = &gcl; + for(m = gcl; m; m = next) { + next = m->gclink; + if(m->gcmark == 0) { + *p = next; + free(m); /* Sleazy reliance on my malloc */ + } + else + p = &m->gclink; + } +} + +void* +gmalloc(long l) +{ + void *p; + + dogc += l; + p = malloc(l); + if(p == 0) + fatal("out of memory"); + memset(p, 0, l); + return p; +} + +void +checkqid(int f1, int pid) +{ + int fd; + Dir *d1, *d2; + char buf[128]; + + if(kernel || rdebug) + return; + + d1 = dirfstat(f1); + if(d1 == nil) + fatal("checkqid: (qid not checked) dirfstat: %r"); + + sprint(buf, "/proc/%d/text", pid); + fd = open(buf, OREAD); + if(fd < 0 || (d2 = dirfstat(fd)) == nil){ + fatal("checkqid: (qid not checked) dirstat %s: %r", buf); + return; /* not reached */ + } + + close(fd); + + if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){ + print("path %llux %llux vers %lud %lud type %d %d\n", + d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type); + print("warning: image does not match text for pid %d\n", pid); + } + free(d1); + free(d2); +} + +char* +mysystem(void) +{ + char *cpu, *p, *q; + static char kernel[128]; + + cpu = getenv("cputype"); + if(cpu == 0) { + cpu = "mips"; + print("$cputype not set; assuming %s\n", cpu); + } + p = getenv("terminal"); + if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) { + p = "9power"; + print("missing or bad $terminal; assuming %s\n", p); + } + else{ + p++; + q = strchr(p, ' '); + if(q) + *q = 0; + sprint(kernel, "/%s/b%s", cpu, p); + } + return kernel; +} + +int +isnumeric(char *s) +{ + while(*s) { + if(*s < '0' || *s > '9') + return 0; + s++; + } + return 1; +} + +int +xfmt(Fmt *f) +{ + f->flags ^= FmtSharp; + return _ifmt(f); +} diff --git a/utils/acid/mips b/utils/acid/mips new file mode 100644 index 00000000..5c267d1f --- /dev/null +++ b/utils/acid/mips @@ -0,0 +1,217 @@ +// Mips support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'X'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/mips/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn stk() // trace +{ + _stk(*PC, *SP, linkreg(0), 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *SP, linkreg(0), 1); +} + +defn gpr() // print general purpose registers +{ + print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n"); + print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n"); + print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n"); + print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n"); + print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n"); + print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n"); + print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n"); + print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n"); + print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n"); + print("R28\t", *R28, " R29\t", *SP, " R30\t", *R30, "\n"); + print("R31\t", *R31, "\n"); +} + +defn Fpr() +{ + print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n"); + print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n"); + print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n"); + print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n"); + print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n"); + print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n"); + print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n"); + print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n"); +} + +defn fpr() +{ + print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n"); + print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n"); + print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n"); + print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n"); + print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n"); + print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n"); + print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n"); + print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n"); + print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n"); + print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n"); + print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n"); + print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n"); + print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n"); + print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n"); + print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n"); + print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n"); +} + +defn spr() // print special processor registers +{ + local pc, link, cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + + link = *R31; + print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " "); + pfl(link); + + cause = *CAUSE; + print("STATUS\t", *STATUS, "\tCAUSE\t", cause, " ", reason(cause), "\n"); + print("TLBVIR\t", *TLBVIRT, "\tBADVADR\t", *BADVADDR, "\n"); + + print("HI\t", *HI, "\tLO\t", *LO, "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l, pc; + + pc = *PC; + + print(pid,": ", reason(*CAUSE), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +sizeofUreg = 152; +aggr Ureg +{ + 'X' 0 status; + 'X' 4 pc; + { + 'X' 8 sp; + 'X' 8 usp; + }; + 'X' 12 cause; + 'X' 16 badvaddr; + 'X' 20 tlbvirt; + 'X' 24 hi; + 'X' 28 lo; + 'X' 32 r31; + 'X' 36 r30; + 'X' 40 r28; + 'X' 44 r27; + 'X' 48 r26; + 'X' 52 r25; + 'X' 56 r24; + 'X' 60 r23; + 'X' 64 r22; + 'X' 68 r21; + 'X' 72 r20; + 'X' 76 r19; + 'X' 80 r18; + 'X' 84 r17; + 'X' 88 r16; + 'X' 92 r15; + 'X' 96 r14; + 'X' 100 r13; + 'X' 104 r12; + 'X' 108 r11; + 'X' 112 r10; + 'X' 116 r9; + 'X' 120 r8; + 'X' 124 r7; + 'X' 128 r6; + 'X' 132 r5; + 'X' 136 r4; + 'X' 140 r3; + 'X' 144 r2; + 'X' 148 r1; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" status ", addr.status, "\n"); + print(" pc ", addr.pc, "\n"); + print(" sp ", addr.sp, "\n"); + print(" cause ", addr.cause, "\n"); + print(" badvaddr ", addr.badvaddr, "\n"); + print(" tlbvirt ", addr.tlbvirt, "\n"); + print(" hi ", addr.hi, "\n"); + print(" lo ", addr.lo, "\n"); + print(" r31 ", addr.r31, "\n"); + print(" r30 ", addr.r30, "\n"); + print(" r28 ", addr.r28, "\n"); + print(" r27 ", addr.r27, "\n"); + print(" r26 ", addr.r26, "\n"); + print(" r25 ", addr.r25, "\n"); + print(" r24 ", addr.r24, "\n"); + print(" r23 ", addr.r23, "\n"); + print(" r22 ", addr.r22, "\n"); + print(" r21 ", addr.r21, "\n"); + print(" r20 ", addr.r20, "\n"); + print(" r19 ", addr.r19, "\n"); + print(" r18 ", addr.r18, "\n"); + print(" r17 ", addr.r17, "\n"); + print(" r16 ", addr.r16, "\n"); + print(" r15 ", addr.r15, "\n"); + print(" r14 ", addr.r14, "\n"); + print(" r13 ", addr.r13, "\n"); + print(" r12 ", addr.r12, "\n"); + print(" r11 ", addr.r11, "\n"); + print(" r10 ", addr.r10, "\n"); + print(" r9 ", addr.r9, "\n"); + print(" r8 ", addr.r8, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r1 ", addr.r1, "\n"); +}; + +defn linkreg(addr) +{ + complex Ureg addr; + return addr.r31\X; +} + +print("/sys/lib/acid/mips"); diff --git a/utils/acid/mkfile b/utils/acid/mkfile new file mode 100644 index 00000000..697f7fc7 --- /dev/null +++ b/utils/acid/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=acid + +OFILES= main.$O\ + y.tab.$O\ + lex.$O\ + util.$O\ + exec.$O\ + expr.$O\ + list.$O\ + builtin.$O\ + proc.$O\ + dot.$O\ + print.$O\ + os-$TARGMODEL.$O\ + rdebug.$O\ + +YFILES=dbg.y +HFILES=acid.h y.tab.h + +LIBS=mach math bio regexp 9 + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/acid/os-Nt.c b/utils/acid/os-Nt.c new file mode 100644 index 00000000..5966d718 --- /dev/null +++ b/utils/acid/os-Nt.c @@ -0,0 +1,198 @@ +/* + * Windows Nt + */ + +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +#include <signal.h> + +#include <windows.h> + +#define MAXBUFSIZ 16640 /* 2 STYX messages plus headers */ +#define NT_DEBUG +int nt_debug = 0; + +int +opentty(char *tty, int baud) +{ + HANDLE comport; + DCB dcb; + COMMTIMEOUTS timeouts; + + comport = CreateFile(tty, GENERIC_READ|GENERIC_WRITE, + 0, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + if (comport == INVALID_HANDLE_VALUE) { + werrstr("could not create port %s", tty); + return -1; + } + + if (SetupComm(comport, MAXBUFSIZ, MAXBUFSIZ) != TRUE) { + werrstr("could not set up %s Comm port", tty); + CloseHandle(comport); + return -1; + } + + if (GetCommState(comport, &dcb) != TRUE) { + werrstr("could not get %s comstate", tty); + CloseHandle(comport); + return -1; + } + + if (baud == 0) { + dcb.BaudRate = 19200; + } else { + dcb.BaudRate = baud; + } + dcb.ByteSize = 8; + dcb.fParity = 0; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; + dcb.fInX = 0; + dcb.fOutX = 0; + dcb.fAbortOnError = 1; + + if (SetCommState(comport, &dcb) != TRUE) { + werrstr("could not set %s comstate", tty); + CloseHandle(comport); + return -1; + } + + timeouts.ReadIntervalTimeout = 2; + /* char time in milliseconds, at 19.2K char time is .4 ms */ + timeouts.ReadTotalTimeoutMultiplier = 0; /* was 100; */ + timeouts.ReadTotalTimeoutConstant = 200; /* was 500; */ + timeouts.WriteTotalTimeoutMultiplier = 0; /* was 10; */ + timeouts.WriteTotalTimeoutConstant = 400; /* was 20; */ + + SetCommTimeouts(comport, &timeouts); + + EscapeCommFunction(comport, SETDTR); + + return (int) comport; +} + +int +remote_read(int fd, char *buf, int bytes) +{ + DWORD numread = 0; + BOOL rtn; + +#ifdef NT_DEBUG + if (nt_debug) { + print("NT:rread fd %x bytes: %d", fd, bytes); + } +#endif + rtn = ReadFile((HANDLE) fd, buf, bytes, &numread, 0); +#ifdef NT_DEBUG + if (nt_debug) { + print(" numread: %d rtn: %x\n", numread, rtn); + if (numread) { + char *cp; + int i; + + cp = (char *) buf; + for (i=0; i < numread; i++) { + print(" %2.2x", *cp++); + } + print("\n"); + } + } +#endif + if (!rtn) + return -1; + else + return numread; +} + +int +remote_write(int fd, char *buf, int bytes) +{ + DWORD numwrt = 0; + BOOL rtn; + char *cp; + int i; + +#ifdef NT_DEBUG + if (nt_debug) { + print("NT:rwrite fd %x bytes: %d", fd, bytes); + print("\n"); + cp = (char *) buf; + for (i=0; i < bytes; i++) { + print(" %2.2x", *cp++); + } + print("\n"); + } +#endif + while (bytes > 0) { + rtn = WriteFile((HANDLE) fd, buf, bytes, &numwrt, 0); + if (!rtn) { + break; + } + buf += numwrt; + bytes -= numwrt; + } + return numwrt; +} + +void +detach(void) +{ + /* ??? */ +} + +char * +waitfor(int pid) +{ + fprint(2, "wait unimplemented"); + return 0; +} + +int +fork(void) +{ + fprint(2, "fork unimplemented"); + return -1; +} + +char * +runcmd(char *cmd) +{ + fprint(2, "runcmd unimplemented"); + return 0; +} + +void (*notefunc)(int); + +os_notify(void (*func)(int)) +{ + notefunc = func; + signal(SIGINT, func); + return 0; +} + +void +catcher(int sig) +{ + if (sig == SIGINT) { + gotint = 1; + signal(SIGINT, notefunc); + } +} + +void +setup_os_notify(void) +{ + os_notify(catcher); +} + +int +nproc(char **argv) +{ + fprint(2, "nproc not implemented\n"); + return -1; +} diff --git a/utils/acid/os-Plan9.c b/utils/acid/os-Plan9.c new file mode 100644 index 00000000..1ac60404 --- /dev/null +++ b/utils/acid/os-Plan9.c @@ -0,0 +1,157 @@ +/* + * Plan9 + */ + +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" + +int +opentty(char *tty, int baud) +{ + int fd, cfd; + char ctty[100]; + + if(tty == 0) + tty = "/dev/eia0"; + sprint(ctty, "%sctl", tty); + fd = open(tty, 2); + if(fd < 0) + return -1; + if(baud){ + cfd = open(ctty, 1); + if(cfd < 0) + return fd; + fprint(cfd, "b%d", baud); + close(cfd); + } + return fd; +} + +void +detach(void) +{ + rfork(RFNAMEG|RFNOTEG|RFREND); +} + +char * +waitfor(int pid) +{ + Waitmsg *w; + static char buf[ERRMAX]; + + for(;;) { + w = wait(); + if(w == nil) + error("wait %r"); + if(w->pid == pid){ + strecpy(buf, buf+ERRMAX, w->msg); + free(w); + return buf; + } + free(w); + } + return nil; +} + +char * +runcmd(char *cmd) +{ + char *argv[4]; + int pid; + + argv[0] = "/bin/rc"; + argv[1] = "-c"; + argv[2] = cmd; + argv[3] = 0; + + pid = fork(); + switch(pid) { + case -1: + error("fork %r"); + case 0: + exec("/bin/rc", argv); + exits(0); + default: + return waitfor(pid); + } + return 0; +} + +void +catcher(void *junk, char *s) +{ + USED(junk); + + if(strstr(s, "interrupt")) { + gotint = 1; + noted(NCONT); + } + noted(NDFLT); +} + +void (*notefunc)(void *, char *); + +void +setup_os_notify(void) +{ + notify(catcher); +} + +int +nproc(char **argv) +{ + char buf[128]; + int pid, i, fd; + + pid = fork(); + switch(pid) { + case -1: + error("new: fork %r"); + case 0: + rfork(RFNAMEG|RFNOTEG); + + sprint(buf, "/proc/%d/ctl", getpid()); + fd = open(buf, ORDWR); + if(fd < 0) + fatal("new: open %s: %r", buf); + write(fd, "hang", 4); + close(fd); + + close(0); + close(1); + close(2); + for(i = 3; i < NFD; i++) + close(i); + + open("/dev/cons", OREAD); + open("/dev/cons", OWRITE); + open("/dev/cons", OWRITE); + exec(argv[0], argv); + fatal("new: exec %s: %r"); + default: + install(pid); + msg(pid, "waitstop"); + notes(pid); + sproc(pid); + dostop(pid); + break; + } + + return pid; +} + +int +remote_read(int fd, char *buf, int bytes) +{ + return read(fd, buf, bytes); +} + +int +remote_write(int fd, char *buf, int bytes) +{ + return write(fd, buf, bytes); +} diff --git a/utils/acid/os-Posix.c b/utils/acid/os-Posix.c new file mode 100644 index 00000000..58b4b255 --- /dev/null +++ b/utils/acid/os-Posix.c @@ -0,0 +1,183 @@ +#include <lib9.h> +#include <bio.h> +#include <sys/types.h> +#include <termios.h> +#undef getwd +#undef getwd +#include <unistd.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +#include <signal.h> + +static void +setraw(int fd, int baud) +{ + struct termios sg; + + switch(baud){ + case 1200: baud = B1200; break; + case 2400: baud = B2400; break; + case 4800: baud = B4800; break; + case 9600: baud = B9600; break; + case 19200: baud = B19200; break; + case 38400: baud = B38400; break; + default: + werrstr("unknown speed %d", baud); + return; + } + if(tcgetattr(fd, &sg) >= 0) { + sg.c_iflag = sg.c_oflag = sg.c_lflag = 0; + sg.c_cflag &= ~CSIZE; + sg.c_cflag |= CS8 | CREAD; + sg.c_cflag &= ~(PARENB|PARODD); + sg.c_cc[VMIN] = 1; + sg.c_cc[VTIME] = 0; + if(baud) { + cfsetispeed(&sg, baud); + cfsetospeed(&sg, baud); + } + tcsetattr(fd, TCSANOW, &sg); + } +} + +int +opentty(char *tty, int baud) +{ + int fd; + + if(baud == 0) + baud = 19200; + fd = open(tty, 2); + if(fd < 0) + return -1; + setraw(fd, baud); + return fd; +} + +void +detach(void) +{ + setpgid(0, 0); +} + +char * +waitfor(int pid) +{ + int n, status; + static char buf[32]; + + for(;;) { + n = wait(&status); + if(n < 0) + error("wait %r"); + if(n == pid) { + sprint(buf, "%d", status); + return buf; + } + } +} + +char * +runcmd(char *cmd) +{ + char *argv[4]; + int pid; + + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = cmd; + argv[3] = 0; + + pid = fork(); + switch(pid) { + case -1: + error("fork %r"); + case 0: + execv("/bin/sh", argv); + exits(0); + default: + return waitfor(pid); + } + return 0; +} + +void (*notefunc)(int); + +os_notify(void (*func)(int)) +{ + notefunc = func; + signal(SIGINT, func); +} + +void +catcher(int sig) +{ + if(sig==SIGINT) { + gotint = 1; + signal(SIGINT, notefunc); + } +} + +void +setup_os_notify(void) +{ + os_notify(catcher); +} + +int +nproc(char **argv) +{ + char buf[128]; + int pid, i, fd; + + if(rdebug) + error("can't newproc in remote mode"); + + pid = fork(); + switch(pid) { + case -1: + error("new: fork %r"); + case 0: + detach(); + + sprint(buf, "/proc/%d/ctl", getpid()); + fd = open(buf, ORDWR); + if(fd < 0) + fatal("new: open %s: %r", buf); + write(fd, "hang", 4); + close(fd); + + close(0); + close(1); + close(2); + for(i = 3; i < NFD; i++) + close(i); + + open("/dev/cons", OREAD); + open("/dev/cons", OWRITE); + open("/dev/cons", OWRITE); + execvp(argv[0], argv); + fatal("new: execvp %s: %r"); + default: + install(pid); + msg(pid, "waitstop"); + notes(pid); + sproc(pid); + dostop(pid); + break; + } + + return pid; +} + +int +remote_read(int fd, char *buf, int bytes) +{ + return read(fd, buf, bytes); +} + +int remote_write(int fd, char *buf, int bytes) +{ + return write(fd, buf, bytes); +} diff --git a/utils/acid/port b/utils/acid/port new file mode 100644 index 00000000..a348eb9c --- /dev/null +++ b/utils/acid/port @@ -0,0 +1,547 @@ +// portable acid for all architectures + +defn pfl(addr) +{ + print(pcfile(addr), ":", pcline(addr), "\n"); +} + +defn +notestk(addr) +{ + local pc, sp; + complex Ureg addr; + + pc = addr.pc\X; + sp = addr.sp\X; + + print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); + pfl(pc); + _stk(pc, sp, linkreg(addr), 1); +} + +defn labstk(l) // trace from a label +{ + _stk(*(l+4)+Labpcoff, *l+Labspoff, linkreg(0), 0); +} + +defn params(param) +{ + while param do { + sym = head param; + print(sym[0], "=", sym[1]); + param = tail param; + if param then + print (","); + } +} + +defn locals(l) +{ + local sym; + + while l do { + sym = head l; + print("\t", sym[0], "=", sym[1], "\n"); + l = tail l; + } +} + +defn _stk(pc, sp, link, dolocals) +{ + local stk; + + print("At pc:", pc, ":", fmt(pc, 'a'), " "); + pfl(pc); + + stk = strace(pc, sp, link); + + while stk do { + frame = head stk; + print(fmt(frame[0], 'a'), "("); + params(frame[2]); + print(") ", pcfile(frame[0]), ":", pcline(frame[0])); + print("\n\tcalled from ", fmt(frame[1], 'a'), " "); + pfl(frame[1]); + stk = tail stk; + if dolocals then + locals(frame[3]); + } +} + +defn findsrc(file) +{ + local lst, src; + + if file[0] == '/' then { + src = file(file); + if src != {} then { + srcfiles = append srcfiles, file; + srctext = append srctext, src; + return src; + } + return {}; + } + + lst = srcpath; + while head lst do { + src = file(head lst+file); + if src != {} then { + srcfiles = append srcfiles, file; + srctext = append srctext, src; + return src; + } + lst = tail lst; + } +} + +defn line(addr) +{ + local src, file; + + file = pcfile(addr); + src = match(file, srcfiles); + + if src >= 0 then + src = srctext[src]; + else + src = findsrc(file); + + if src == {} then { + print("no source for ", file, "\n"); + return {}; + } + line = pcline(addr)-1; + print(file, ":", src[line], "\n"); +} + +defn addsrcdir(dir) +{ + dir = dir+"/"; + + if match(dir, srcpath) >= 0 then { + print("already in srcpath\n"); + return {}; + } + + srcpath = {dir}+srcpath; +} + +defn source() +{ + local l; + + l = srcpath; + while l do { + print(head l, "\n"); + l = tail l; + } + l = srcfiles; + + while l do { + print("\t", head l, "\n"); + l = tail l; + } +} + +defn Bsrc(addr) +{ + local lst; + + lst = srcpath; + file = pcfile(addr); + if file[0] == '/' && access(file) then { + rc("B "+itoa(-pcline(addr))+" "+file); + return {}; + } + while head lst do { + name = head lst+file; + if access(name) then { + rc("B "+itoa(-pcline(addr))+" "+name); + return {}; + } + lst = tail lst; + } + print("no source for ", file, "\n"); +} + +defn src(addr) +{ + local src, file, line, cline, text; + + file = pcfile(addr); + src = match(file, srcfiles); + + if src >= 0 then + src = srctext[src]; + else + src = findsrc(file); + + if src == {} then { + print("no source for ", file, "\n"); + return {}; + } + + cline = pcline(addr)-1; + print(file, ":", cline, "\n"); + line = cline-5; + loop 0,10 do { + if line >= 0 then { + if line == cline then + print(">"); + else + print(" "); + text = src[line]; + if text == {} then + return {}; + print(line, "\t", text, "\n"); + } + line = line+1; + } +} + +defn stopped(pid) // called from acid when a process changes state +{ + pstop(pid); // stub so this is easy to replace +} + +defn procs() // print status of processes +{ + local c, lst, cpid; + + cpid = pid; + lst = proclist; + while lst do { + np = head lst; + setproc(np); + if np == cpid then + c = '>'; + else + c = ' '; + print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n"); + lst = tail lst; + } + pid = cpid; + if pid != 0 then + setproc(pid); +} + +defn asm(addr) +{ + local bound; + + bound = fnbound(addr); + + addr = fmt(addr, 'i'); + loop 1,30 do { + print(fmt(addr, 'a'), " ", fmt(addr, 'X')); + print("\t", @addr++, "\n"); + if bound != {} && addr > bound[1] then { + lasmaddr = addr; + return {}; + } + } + lasmaddr = addr; +} + +defn casm() +{ + asm(lasmaddr); +} + +defn new() +{ + bplist = {}; + newproc(progargs); + // Dont miss the delay slot calls + bpset(follow(main)[0]); + cont(); + bpdel(*PC); +} + +defn stmnt() // step one statement +{ + local line; + + line = pcline(*PC); + while 1 do { + step(); + if line != pcline(*PC) then { + src(*PC); + return {}; + } + } +} + +defn func() // step until we leave the current function +{ + local bound, end, start, pc; + + bound = fnbound(*PC); + if bound == {} then { + print("cannot locate text symbol\n"); + return {}; + } + + pc = *PC; + start = bound[0]; + end = bound[1]; + while pc >= start && pc < end do { + step(); + pc = *PC; + } +} + +defn next() +{ + local sp, bound; + + sp = *SP; + bound = fnbound(*PC); + stmnt(); + pc = *PC; + if pc >= bound[0] && pc < bound[1] then + return {}; + + while (pc < bound[0] || pc > bound[1]) && sp >= *SP do { + step(); + pc = *PC; + } + src(*PC); +} + +defn dump(addr, n, fmt) +{ + loop 0, n do { + print(fmt(addr, 'X'), ": "); + addr = mem(addr, fmt); + } +} + +defn mem(addr, fmt) +{ + + local i, c, n; + + i = 0; + while fmt[i] != 0 do { + c = fmt[i]; + n = 0; + while '0' <= fmt[i] && fmt[i] <= '9' do { + n = 10*n + fmt[i]-'0'; + i = i+1; + } + if n <= 0 then n = 1; + addr = fmt(addr, fmt[i]); + while n > 0 do { + print(*addr++, " "); + n = n-1; + } + i = i+1; + } + print("\n"); + return addr; +} + +defn symbols(pattern) +{ + local l, s; + + l = symbols; + while l do { + s = head l; + if regexp(pattern, s[0]) then + print(s[0], "\t", s[1], "\t", s[2], "\n"); + l = tail l; + } +} + +defn spsrch(len) +{ + local addr, a, s, e; + + addr = *SP; + s = origin & 0x7fffffff; + e = etext & 0x7fffffff; + loop 1, len do { + a = *addr++; + c = a & 0x7fffffff; + if c > s && c < e then { + print("src(", a, ")\n"); + pfl(a); + } + } +} + +defn bppush(val) +{ + return {"p", val}; +} + +defn bpderef() +{ + return {"*", 0}; +} + +defn bpmask() +{ + return {"&", 0}; +} + +defn bpeq() +{ + return {"=", 0}; +} + +defn bpneq() +{ + return {"!", 0}; +} + +defn bpand() +{ + return {"a", 0}; +} + +defn bpor() +{ + return {"o", 0}; +} + +defn bpcondset(pid, addr, conds) +{ + local l; + local id; + local found; + + if status(pid) != "Stopped" then { + print("Waiting...\n"); + stop(pid); + } + + id = 0; + found = 0; + + while !found && id <= 255 do { + l = bpl; + while l && head head l != id do { + l = tail l; + } + + if !l then + found = 1; + else + id = id + 1; + } + + if !found then { + print("error: no breakpoints available\n"); + return -1; + } + + bpl = append bpl, {id\d, pid\d, addr\X, conds}; + + _bpcondset(id, pid, addr, conds); + + return id; +} + +defn bpconddel(id) +{ + local i; + local l; + + l = bpl; + i = 0; + while l do { + if id == head head l then { + bpl = delete bpl, i; + _bpconddel(id); + if id == bpid then + bpid = -1; + return {}; + } + i = i + 1; + l = tail l; + } + print("no breakpoint with id ", id\d, ".\n"); +} + +defn bpprint(b) +{ + local l; + + print(b[0], "\t", b[1], "\t", fmt(b[2], 'a'), " ", b[2]); + print("\t{"); + l = b[3]; + while l do { + print("\n\t\t\t\t\t", head l); + l = tail l; + } + print(" }\n"); +} + +defn bptab() +{ + local l; + + l = bpl; + print("ID PID ADDR CONDITIONS\n"); + while l do { + bpprint(head l); + l = tail l; + } +} + +defn cont() +{ + local b, c, l, found; + + l = bpl; + found = 0; + c = curpc(); + while !found && l do { + b = head l; + if b[2] == c then { + nopstop = 1; + step(); + nopstop = 0; + found = 1; + } else { + l = tail l; + } + } + + return startstop(pid); +} + +defn bpset(addr) // set a breakpoint +{ + return bpcondset(pid, addr, {}); +} + +defn bpdel(id) +{ + bpconddel(id); +} + +defn bpaddr(id) +{ + local i; + local l; + local b; + + l = bpl; + i = 0; + while l do { + b = head l; + if id == b[0] then + return b[2]; + i = i + 1; + l = tail l; + } + print("bpaddr(", id\d, "): no match\n"); + return {}; +} + +progargs=""; +print("/sys/lib/acid/port"); diff --git a/utils/acid/print.c b/utils/acid/print.c new file mode 100644 index 00000000..8043fcd7 --- /dev/null +++ b/utils/acid/print.c @@ -0,0 +1,444 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" + +static char *binop[] = +{ + 0, + 0, + "*", /* [OMUL] "*", */ + "/", /* [ODIV] "/", */ + "%", /* [OMOD] "%", */ + "+", /* [OADD] "+", */ + "-", /* [OSUB] "-", */ + ">>", /* [ORSH] ">>", */ + "<<", /* [OLSH] "<<", */ + "<", /* [OLT] "<", */ + ">", /* [OGT] ">", */ + "<=", /* [OLEQ] "<=", */ + ">=", /* [OGEQ] ">=", */ + "==", /* [OEQ] "==", */ + "!=", /* [ONEQ] "!=", */ + "&", /* [OLAND] "&", */ + "^", /* [OXOR] "^", */ + "|", /* [OLOR] "|", */ + "&&", /* [OCAND] "&&", */ + "||", /* [OCOR] "||", */ + " = ", /* [OASGN] " = ", */ +}; + +static char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; +char *typenames[] = +{ + "integer", /* [TINT] "integer", */ + "float", /* [TFLOAT] "float", */ + "string", /* [TSTRING] "string", */ + "list", /* [TLIST] "list", */ + "code", /* [TCODE] "code", */ +}; + +int +cmp(const void *a, const void *b) +{ + return strcmp(*(char**)a, *(char**)b); +} + +void +fundefs(void) +{ + Lsym *l; + char **vec; + int i, j, n, max, col, f, g, s; + + max = 0; + f = 0; + g = 100; + vec = gmalloc(sizeof(char*)*g); + if(vec == 0) + fatal("out of memory"); + + for(i = 0; i < Hashsize; i++) { + for(l = hash[i]; l; l = l->hash) { + if(l->proc == 0 && l->builtin == 0) + continue; + n = strlen(l->name); + if(n > max) + max = n; + if(f >= g) { + g *= 2; + vec = realloc(vec, sizeof(char*)*g); + if(vec == 0) + fatal("out of memory"); + } + vec[f++] = l->name; + } + } + qsort(vec, f, sizeof(char*), cmp); + max++; + col = 60/max; + s = (f+col-1)/col; + + for(i = 0; i < s; i++) { + for(j = i; j < f; j += s) + Bprint(bout, "%-*s", max, vec[j]); + Bprint(bout, "\n"); + } +} + +void +whatis(Lsym *l) +{ + int t; + int def; + Type *ti; + + if(l == 0) { + fundefs(); + return; + } + + def = 0; + if(l->v->set) { + t = l->v->type; + Bprint(bout, "%s variable", typenames[t]); + if(t == TINT || t == TFLOAT) + Bprint(bout, " format %c", l->v->vstore.fmt); + if(l->v->vstore.comt) + Bprint(bout, " complex %s", + l->v->vstore.comt->base->name); + Bputc(bout, '\n'); + def = 1; + } + if(l->lt) { + Bprint(bout, "complex %s {\n", l->name); + for(ti = l->lt; ti; ti = ti->next) { + if(ti->type) { + if(ti->fmt == 'a') { + Bprint(bout, "\t%s %d %s;\n", + ti->type->name, ti->offset, + ti->tag->name); + } + else { + Bprint(bout, "\t'%c' %s %d %s;\n", + ti->fmt, ti->type->name, ti->offset, + ti->tag->name); + } + } + else + Bprint(bout, "\t'%c' %d %s;\n", + ti->fmt, ti->offset, ti->tag->name); + } + Bprint(bout, "};\n"); + def = 1; + } + if(l->proc) { + Bprint(bout, "defn %s(", l->name); + pexpr(l->proc->left); + Bprint(bout, ") {\n"); + pcode(l->proc->right, 1); + Bprint(bout, "}\n"); + def = 1; + } + if(l->builtin) { + Bprint(bout, "builtin function\n"); + def = 1; + } + if(def == 0) + Bprint(bout, "%s is undefined\n", l->name); +} + +void +slist(Node *n, int d) +{ + if(n == 0) + return; + if(n->op == OLIST) + Bprint(bout, "%.*s{\n", d-1, tabs); + pcode(n, d); + if(n->op == OLIST) + Bprint(bout, "%.*s}\n", d-1, tabs); +} + +void +pcode(Node *n, int d) +{ + Node *r, *l; + + if(n == 0) + return; + + r = n->right; + l = n->left; + + switch(n->op) { + default: + Bprint(bout, "%.*s", d, tabs); + pexpr(n); + Bprint(bout, ";\n"); + break; + case OLIST: + pcode(n->left, d); + pcode(n->right, d); + break; + case OLOCAL: + Bprint(bout, "%.*slocal", d, tabs); + while(l) { + Bprint(bout, " %s", l->sym->name); + l = l->left; + if(l == 0) + Bprint(bout, ";\n"); + else + Bprint(bout, ","); + } + break; + case OCOMPLEX: + Bprint(bout, "%.*scomplex %s %s;\n", d, tabs, n->sym->name, l->sym->name); + break; + case OIF: + Bprint(bout, "%.*sif ", d, tabs); + pexpr(l); + d++; + Bprint(bout, " then\n", d, tabs); + if(r && r->op == OELSE) { + slist(r->left, d); + Bprint(bout, "%.*selse\n", d-1, tabs, d, tabs); + slist(r->right, d); + } + else + slist(r, d); + break; + case OWHILE: + Bprint(bout, "%.*swhile ", d, tabs); + pexpr(l); + d++; + Bprint(bout, " do\n", d, tabs); + slist(r, d); + break; + case ORET: + Bprint(bout, "%.*sreturn ", d, tabs); + pexpr(l); + Bprint(bout, ";\n"); + break; + case ODO: + Bprint(bout, "%.*sloop ", d, tabs); + pexpr(l->left); + Bprint(bout, ", "); + pexpr(l->right); + Bprint(bout, " do\n"); + slist(r, d+1); + } +} + +void +pexpr(Node *n) +{ + Node *r, *l; + + if(n == 0) + return; + + r = n->right; + l = n->left; + + switch(n->op) { + case ONAME: + Bprint(bout, "%s", n->sym->name); + break; + case OCONST: + switch(n->type) { + case TINT: + Bprint(bout, "%d", (int)n->nstore.u0.sival); + break; + case TFLOAT: + Bprint(bout, "%g", n->nstore.u0.sfval); + break; + case TSTRING: + pstr(n->nstore.u0.sstring); + break; + case TLIST: + break; + } + break; + case OMUL: + case ODIV: + case OMOD: + case OADD: + case OSUB: + case ORSH: + case OLSH: + case OLT: + case OGT: + case OLEQ: + case OGEQ: + case OEQ: + case ONEQ: + case OLAND: + case OXOR: + case OLOR: + case OCAND: + case OCOR: + Bputc(bout, '('); + pexpr(l); + Bprint(bout, binop[n->op]); + pexpr(r); + Bputc(bout, ')'); + break; + case OASGN: + pexpr(l); + Bprint(bout, binop[n->op]); + pexpr(r); + break; + case OINDM: + Bprint(bout, "*"); + pexpr(l); + break; + case OEDEC: + Bprint(bout, "--"); + pexpr(l); + break; + case OEINC: + Bprint(bout, "++"); + pexpr(l); + break; + case OPINC: + pexpr(l); + Bprint(bout, "++"); + break; + case OPDEC: + pexpr(l); + Bprint(bout, "--"); + break; + case ONOT: + Bprint(bout, "!"); + pexpr(l); + break; + case OLIST: + pexpr(l); + if(r) { + Bprint(bout, ","); + pexpr(r); + } + break; + case OCALL: + pexpr(l); + Bprint(bout, "("); + pexpr(r); + Bprint(bout, ")"); + break; + case OCTRUCT: + Bprint(bout, "{"); + pexpr(l); + Bprint(bout, "}"); + break; + case OHEAD: + Bprint(bout, "head "); + pexpr(l); + break; + case OTAIL: + Bprint(bout, "tail "); + pexpr(l); + break; + case OAPPEND: + Bprint(bout, "append "); + pexpr(l); + Bprint(bout, ","); + pexpr(r); + break; + case ODELETE: + Bprint(bout, "delete "); + pexpr(l); + Bprint(bout, ","); + pexpr(r); + break; + case ORET: + Bprint(bout, "return "); + pexpr(l); + break; + case OINDEX: + pexpr(l); + Bprint(bout, "["); + pexpr(r); + Bprint(bout, "]"); + break; + case OINDC: + Bprint(bout, "@"); + pexpr(l); + break; + case ODOT: + pexpr(l); + Bprint(bout, ".%s", n->sym->name); + break; + case OFRAME: + Bprint(bout, "%s:%s", n->sym->name, l->sym->name); + break; + case OCAST: + Bprint(bout, "(%s)", n->sym->name); + pexpr(l); + break; + case OFMT: + pexpr(l); + Bprint(bout, "\\%c", (int)r->nstore.u0.sival); + break; + case OEVAL: + Bprint(bout, "eval "); + pexpr(l); + break; + case OWHAT: + Bprint(bout, "whatis", n->sym->name); + if(n->sym) + Bprint(bout, " %s", n->sym->name); + break; + } +} + +void +pstr(String *s) +{ + int i, c; + + Bputc(bout, '"'); + for(i = 0; i < s->len; i++) { + c = s->string[i]; + switch(c) { + case '\0': + c = '0'; + break; + case '\n': + c = 'n'; + break; + case '\r': + c = 'r'; + break; + case '\t': + c = 't'; + break; + case '\b': + c = 'b'; + break; + case '\f': + c = 'f'; + break; + case '\a': + c = 'a'; + break; + case '\v': + c = 'v'; + break; + case '\\': + c = '\\'; + break; + case '"': + c = '"'; + break; + default: + Bputc(bout, c); + continue; + } + Bputc(bout, '\\'); + Bputc(bout, c); + } + Bputc(bout, '"'); +} diff --git a/utils/acid/proc.c b/utils/acid/proc.c new file mode 100644 index 00000000..f13dbf95 --- /dev/null +++ b/utils/acid/proc.c @@ -0,0 +1,274 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +void +nocore(void) +{ + int i; + + if(cormap == 0) + return; + + for (i = 0; i < cormap->nsegs; i++) + if (cormap->seg[i].mget == 0 && cormap->seg[i].inuse && cormap->seg[i].fd >= 0) + close(cormap->seg[i].fd); + free(cormap); + cormap = 0; +} + +void +sproc(int pid) +{ + Lsym *s; + char buf[64]; + ulong proctab; + int fd, i, fcor; + + if(symmap == 0) + error("no map"); + + if(rdebug) { + fcor = -1; + proctab = 0; + i = remoteio(pid, "proc", buf, sizeof(buf)); + if(i >= 0) { + buf[i] = '\0'; + proctab = strtoul(buf, 0, 16); + } else + error("can't access pid %d: %r", pid); + s = look("proc"); + if(s != 0) + s->v->vstore.u0.sival = proctab; + } else { + sprint(buf, "/proc/%d/mem", pid); + fcor = open(buf, ORDWR); + if(fcor < 0) + error("setproc: open %s: %r", buf); + + checkqid(symmap->seg[0].fd, pid); + + if(kernel) { + proctab = 0; + sprint(buf, "/proc/%d/proc", pid); + fd = open(buf, OREAD); + if(fd >= 0) { + i = read(fd, buf, sizeof(buf)); + if(i >= 0) { + buf[i] = '\0'; + proctab = strtoul(buf, 0, 0); + } + close(fd); + } + s = look("proc"); + if(s != 0) + s->v->vstore.u0.sival = proctab; + } + } + + s = look("pid"); + s->v->vstore.u0.sival = pid; + + nocore(); + if(rdebug) { + cormap = attachremt(remfd, &fhdr); + for(i = 0; i < cormap->nsegs; i++) + setmapio(cormap, i, remget, remput); + } else + cormap = attachproc(pid, kernel, fcor, &fhdr); + if (cormap == 0) + error("setproc: cant make coremap"); + i = findseg(cormap, "text"); + if (i >= 0) + cormap->seg[i].name = "*text"; + i = findseg(cormap, "data"); + if (i >= 0) + cormap->seg[i].name = "*data"; + install(pid); +} + +void +notes(int pid) +{ + Lsym *s; + Value *v; + int i, fd; + char buf[128]; + List *l, **tail; + + s = look("notes"); + if(s == 0) + return; + v = s->v; + + if(!rdebug) { + sprint(buf, "/proc/%d/note", pid); + fd = open(buf, OREAD); + if(fd < 0) + error("pid=%d: open note: %r", pid); + } else + fd = -1; + + v->set = 1; + v->type = TLIST; + v->vstore.u0.sl = 0; + tail = &v->vstore.u0.sl; + for(;;) { + if(rdebug) + i = remoteio(pid, "note", buf, sizeof(buf)); + else + i = read(fd, buf, sizeof(buf)); + if(i <= 0) + break; + buf[i] = '\0'; + l = al(TSTRING); + l->lstore.u0.sstring = strnode(buf); + l->lstore.fmt = 's'; + *tail = l; + tail = &l->next; + } + if(fd >= 0) + close(fd); +} + +void +dostop(int pid) +{ + Lsym *s; + Node *np, *p; + + s = look("stopped"); + if(s && s->proc) { + np = an(ONAME, ZN, ZN); + np->sym = s; + np->nstore.fmt = 'D'; + np->type = TINT; + p = con(pid); + p->nstore.fmt = 'D'; + np = an(OCALL, np, p); + execute(np); + } +} + +void +install(int pid) +{ + Lsym *s; + List *l; + char buf[128]; + int i, fd, new, p; + + new = -1; + for(i = 0; i < Maxproc; i++) { + p = ptab[i].pid; + if(p == pid) + return; + if(p == 0 && new == -1) + new = i; + } + if(new == -1) + error("no free process slots"); + + if(!rdebug) { + sprint(buf, "/proc/%d/ctl", pid); + fd = open(buf, OWRITE); + if(fd < 0) + error("pid=%d: open ctl: %r", pid); + } else + fd = -1; + ptab[new].pid = pid; + ptab[new].ctl = fd; + + s = look("proclist"); + l = al(TINT); + l->lstore.fmt = 'D'; + l->lstore.u0.sival = pid; + l->next = s->v->vstore.u0.sl; + s->v->vstore.u0.sl = l; + s->v->set = 1; +} + +void +deinstall(int pid) +{ + int i; + Lsym *s; + List *f, **d; + + for(i = 0; i < Maxproc; i++) { + if(ptab[i].pid == pid) { + if(ptab[i].ctl >= 0) + close(ptab[i].ctl); + ptab[i].pid = 0; + s = look("proclist"); + d = &s->v->vstore.u0.sl; + for(f = *d; f; f = f->next) { + if(f->lstore.u0.sival == pid) { + *d = f->next; + break; + } + } + s = look("pid"); + if(s->v->vstore.u0.sival == pid) + s->v->vstore.u0.sival = 0; + return; + } + } +} + +void +msg(int pid, char *msg) +{ + int i; + int l; + int ok; + char err[ERRMAX]; + + for(i = 0; i < Maxproc; i++) { + if(ptab[i].pid == pid) { + l = strlen(msg); + if(rdebug) + ok = sendremote(pid, msg) >= 0; + else + ok = write(ptab[i].ctl, msg, l) == l; + if(!ok) { + errstr(err, sizeof err); + if(strcmp(err, "process exited") == 0) + deinstall(pid); + error("msg: pid=%d %s: %s", pid, msg, err); + } + return; + } + } + error("msg: pid=%d: not found for %s", pid, msg); +} + +char * +getstatus(int pid) +{ + int fd; + char *p; + + static char buf[128]; + + if(rdebug) { + if(remoteio(pid, "status", buf, sizeof(buf)) < 0) + error("remote status: pid %d: %r", pid); + return buf; + } + sprint(buf, "/proc/%d/status", pid); + fd = open(buf, OREAD); + if(fd < 0) + error("open %s: %r", buf); + read(fd, buf, sizeof(buf)); + close(fd); + p = buf+56+12; /* Do better! */ + while(*p == ' ') + p--; + p[1] = '\0'; + return buf+56; /* ditto */ +} diff --git a/utils/acid/rdebug.c b/utils/acid/rdebug.c new file mode 100644 index 00000000..8903711e --- /dev/null +++ b/utils/acid/rdebug.c @@ -0,0 +1,274 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +#include "../../include/rdbg.h" + +/* + * remote kernel debugging + */ + +enum { + chatty = 0 +}; + +static long myreadn(int, void*, long); +static int rproto(int, char*, int); + +void +remotemap(Map *m, int i) +{ + setmapio(m, i, remget, remput); +} + +/* + * send a /proc control message to remote pid, + * and await a reply + */ +int +sendremote(int pid, char *msg) +{ + int tag; + char dbg[RDBMSGLEN]; + + if(protodebug) + fprint(2, "sendremote: pid %d: %s\n", pid, msg); + if(strcmp(msg, "startstop") == 0) + tag = Tstartstop; + else if(strcmp(msg, "waitstop") == 0) + tag = Twaitstop; + else if(strcmp(msg, "start") == 0) + tag = Tstart; + else if(strcmp(msg, "stop") == 0) + tag = Tstop; + else if(strcmp(msg, "kill") == 0) + tag = Tkill; + else { + werrstr("invalid sendremote: %s", msg); + return -1; + } + memset(dbg, 0, sizeof(dbg)); + dbg[0] = tag; + dbg[1] = pid>>24; + dbg[2] = pid>>16; + dbg[3] = pid>>8; + dbg[4] = pid; + if(rproto(remfd, dbg, sizeof(dbg)) < 0) + return -1; + return 0; +} + +/* + * read a line from /proc/<pid>/<file> into buf + */ +int +remoteio(int pid, char *file, char *buf, int nb) +{ + char dbg[RDBMSGLEN]; + int tag; + + if(protodebug) + fprint(2, "remoteio %d: %s\n", pid, file); + memset(buf, nb, 0); + if(strcmp(file, "proc") == 0) + tag = Tproc; + else if(strcmp(file, "status") == 0) + tag = Tstatus; + else if(strcmp(file, "note") == 0) + tag = Trnote; + else { + werrstr("invalid remoteio: %s", file); + return -1; + } + memset(dbg, 0, sizeof(dbg)); + dbg[0] = tag; + dbg[1] = pid>>24; + dbg[2] = pid>>16; + dbg[3] = pid>>8; + dbg[4] = pid; + if(rproto(remfd, dbg, sizeof(dbg)) < 0) + return -1; + if(nb > sizeof(dbg)-1) + nb = sizeof(dbg)-1; + memmove(buf, dbg+1, nb); + return strlen(buf); +} + +int +remget(struct segment *s, ulong addr, long off, char *buf, int size) +{ + int n, t; + char dbg[RDBMSGLEN]; + + if (protodebug) + fprint(2, "remget addr %#lux off %#lux\n", addr, off); + for (t = 0; t < size; t += n) { + n = size; + if(n > 9) + n = 9; + memset(dbg, 0, sizeof(dbg)); + dbg[0] = Tmget; + dbg[1] = off>>24; + dbg[2] = off>>16; + dbg[3] = off>>8; + dbg[4] = off; + dbg[5] = n; + if(rproto(s->fd, dbg, sizeof(dbg)) < 0) { + werrstr("can't read address %#lux: %r", addr); + return -1; + } + memmove(buf, dbg+1, n); + buf += n; + } + return t; +} + +int +remput(struct segment *s, ulong addr, long off, char *buf, int size) +{ + int n, i, t; + char dbg[RDBMSGLEN]; + + if (protodebug) + fprint(2, "remput addr %#lux off %#lux\n", addr, off); + for (t = 0; t < size; t += n) { + n = size; + if(n > 4) + n = 4; + memset(dbg, 0, sizeof(dbg)); + dbg[0] = Tmput; + dbg[1] = off>>24; + dbg[2] = off>>16; + dbg[3] = off>>8; + dbg[4] = off; + dbg[5] = n; + for(i=0; i<n; i++) + dbg[6+i] = *buf++; + if(rproto(s->fd, dbg, sizeof(dbg)) < 0) { + werrstr("can't write address %#lux: %r", addr); + return -1; + } + } + return t; +} + +int +remcondset(char op, ulong val) +{ + char dbg[RDBMSGLEN]; + + if (protodebug) + fprint(2, "remcondset op %c val: %#lux\n", op, val); + memset(dbg, 0, sizeof(dbg)); + + dbg[0] = Tcondbreak; + dbg[1] = val>>24; + dbg[2] = val>>16; + dbg[3] = val>>8; + dbg[4] = val; + dbg[5] = op; + if(rproto(remfd, dbg, sizeof(dbg)) < 0) { + werrstr("can't set condbreak: %c %#lux: %r", op, val); + return -1; + } + return 0; +} + +int +remcondstartstop(int pid) +{ + char dbg[RDBMSGLEN]; + + if (protodebug) + fprint(2, "remcondstartstop pid %d\n", pid); + memset(dbg, 0, sizeof(dbg)); + + dbg[0] = Tstartstop; + dbg[1] = pid>>24; + dbg[2] = pid>>16; + dbg[3] = pid>>8; + dbg[4] = pid; + + if(rproto(remfd, dbg, sizeof(dbg)) < 0) { + werrstr("can't send Tstartstop"); + return -1; + } + + return dbg[1]; +} + +static int +rproto(int fd, char *buf, int nb) +{ + int tag; + + if (protodebug) { + int i; + print("rproto remote write fd %d bytes: %d\n", fd, nb); + for (i=0; i < nb; i++) { + print(" %2.2ux", buf[i]&0xFF); + } + print("\n"); + } + tag = buf[0]; + if(remote_write(fd, buf, nb) != nb || + myreadn(fd, buf, nb) != nb){ /* could set alarm */ + werrstr("remote i/o: %r"); + return -1; + } + if(buf[0] == Rerr){ + buf[nb-1] = 0; + werrstr("remote err: %s", buf+1); + return -1; + } + if(buf[0] != tag+1) { + werrstr("remote proto err: %.2ux", buf[0]&0xff); + return -1; + } + if(chatty) { + int i; + fprint(2, "remote [%d]: ", nb); + for(i=0; i<nb; i++) + fprint(2, " %.2ux", buf[i]&0xff); + fprint(2, "\n"); + } + return nb; +} + +/* + * this should probably be in lib9 as readn + */ +static long +myreadn(int f, void *av, long n) +{ + char *a; + long m, t; + + if (protodebug) { + print("remote read fd %d bytes: %ld", f, n); + } + a = av; + t = 0; + while(t < n){ + m = remote_read(f, a+t, n-t); + if(m < 0){ + if(t == 0) + return m; + break; + } + if (protodebug) { + print(" rtn: %ld\n", m); + if (m) { + int i; + + for (i=0; i < m; i++) + print(" %2.2ux", a[i+t]&0xFF); + print("\n"); + } + } + t += m; + } + return t; +} diff --git a/utils/acid/sparc b/utils/acid/sparc new file mode 100644 index 00000000..76a1eba3 --- /dev/null +++ b/utils/acid/sparc @@ -0,0 +1,218 @@ +// Sparc support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'X'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/sparc/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn stk() // trace +{ + _stk(*PC, *R1, linkreg(0), 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *R1, linkreg(0), 1); +} + +defn gpr() // print general purpose registers +{ + print("R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n"); + print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "\n"); + print("R7\t", *R7, "R8\t", *R8, "R9\t", *R9, "\n"); + print("R10\t", *R10, "R11\t", *R11, "R12\t", *R12, "\n"); + print("R13\t", *R13, "R14\t", *R14, "R15\t", *R15, "\n"); + print("R16\t", *R16, "R17\t", *R17, "R18\t", *R18, "\n"); + print("R19\t", *R19, "R20\t", *R20, "R21\t", *R21, "\n"); + print("R22\t", *R22, "R23\t", *R23, "R24\t", *R24, "\n"); + print("R25\t", *R25, "R26\t", *R26, "R27\t", *R27, "\n"); + print("R28\t", *R28, "R29\t", *R29, "R30\t", *R30, "\n"); + print("R31\t", *R31, "\n"); +} + +defn spr() // print special processor registers +{ + local pc; + local link; + local cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + print("PSR\t", *PSR, "\n"); + + link = *R15; + print("SP\t", *R1, "\tLINK\t\t", link, " ", fmt(link, 'a')); + pfl(link); + + cause = *TBR; + print("Y\t", *Y, "\tCAUSE\t", *Y, cause, " ", reason(cause), "\n"); +} + +defn Fpr() +{ + print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n"); + print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n"); + print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n"); + print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n"); + print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n"); + print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n"); + print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n"); + print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n"); +} + +defn fpr() +{ + print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n"); + print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n"); + print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n"); + print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n"); + print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n"); + print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n"); + print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n"); + print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n"); + print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n"); + print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n"); + print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n"); + print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n"); + print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n"); + print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n"); + print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n"); + print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l; + local pc; + + pc = *PC; + + print(pid,": ", reason(*TBR), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +aggr Ureg +{ + 'U' 0 r0; + { + 'U' 4 sp; + 'U' 4 usp; + 'U' 4 r1; + }; + 'U' 8 r2; + 'U' 12 r3; + 'U' 16 r4; + 'U' 20 r5; + 'U' 24 r6; + 'U' 28 r7; + 'U' 32 r8; + 'U' 36 r9; + 'U' 40 r10; + 'U' 44 r11; + 'U' 48 r12; + 'U' 52 r13; + 'U' 56 r14; + 'U' 60 r15; + 'U' 64 r16; + 'U' 68 r17; + 'U' 72 r18; + 'U' 76 r19; + 'U' 80 r20; + 'U' 84 r21; + 'U' 88 r22; + 'U' 92 r23; + 'U' 96 r24; + 'U' 100 r25; + 'U' 104 r26; + 'U' 108 r27; + 'U' 112 r28; + 'U' 116 r29; + 'U' 120 r30; + 'U' 124 r31; + 'U' 128 y; + 'U' 132 tbr; + 'U' 136 psr; + 'U' 140 npc; + 'U' 144 pc; + 'U' 148 pad; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" r0 ", addr.r0, "\n"); + print(" sp ", addr.sp, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" r8 ", addr.r8, "\n"); + print(" r9 ", addr.r9, "\n"); + print(" r10 ", addr.r10, "\n"); + print(" r11 ", addr.r11, "\n"); + print(" r12 ", addr.r12, "\n"); + print(" r13 ", addr.r13, "\n"); + print(" r14 ", addr.r14, "\n"); + print(" r15 ", addr.r15, "\n"); + print(" r16 ", addr.r16, "\n"); + print(" r17 ", addr.r17, "\n"); + print(" r18 ", addr.r18, "\n"); + print(" r19 ", addr.r19, "\n"); + print(" r20 ", addr.r20, "\n"); + print(" r21 ", addr.r21, "\n"); + print(" r22 ", addr.r22, "\n"); + print(" r23 ", addr.r23, "\n"); + print(" r24 ", addr.r24, "\n"); + print(" r25 ", addr.r25, "\n"); + print(" r26 ", addr.r26, "\n"); + print(" r27 ", addr.r27, "\n"); + print(" r28 ", addr.r28, "\n"); + print(" r29 ", addr.r29, "\n"); + print(" r30 ", addr.r30, "\n"); + print(" r31 ", addr.r31, "\n"); + print(" y ", addr.y, "\n"); + print(" tbr ", addr.tbr, "\n"); + print(" psr ", addr.psr, "\n"); + print(" npc ", addr.npc, "\n"); + print(" pc ", addr.pc, "\n"); + print(" pad ", addr.pad, "\n"); +}; + +defn linkreg(addr) +{ + complex Ureg addr; + return addr.r15\X; +} + +print("/sys/lib/acid/sparc"); diff --git a/utils/acid/util.c b/utils/acid/util.c new file mode 100644 index 00000000..0de244fd --- /dev/null +++ b/utils/acid/util.c @@ -0,0 +1,295 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> +#include "mach.h" +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +static int syren; + +Lsym* +unique(char *buf, Sym *s) +{ + Lsym *l; + int i, renamed; + + renamed = 0; + strcpy(buf, s->name); + for(;;) { + l = look(buf); + if(l == 0 || (l->lexval == Tid && l->v->set == 0)) + break; + + if(syren == 0 && !quiet) { + print("Symbol renames:\n"); + syren = 1; + } + i = strlen(buf)+1; + memmove(buf+1, buf, i); + buf[0] = '$'; + renamed++; + if(renamed > 5 && !quiet) { + print("Too many renames; must be X source!\n"); + break; + } + } + if(renamed && !quiet) + print("\t%s=%s %c/%lux\n", s->name, buf, s->type, s->value); + if(l == 0) + l = enter(buf, Tid); + return l; +} + +void +varsym(void) +{ + int i; + Sym *s; + long n; + Lsym *l; + ulong v; + char buf[1024]; + List *list, **tail, *l2, *tl; + + tail = &l2; + l2 = 0; + + symbase(&n); + for(i = 0; i < n; i++) { + s = getsym(i); + switch(s->type) { + case 'T': + case 'L': + case 'D': + case 'B': + case 'b': + case 'd': + case 'l': + case 't': + if(s->name[0] == '.') + continue; + + v = s->value; + tl = al(TLIST); + *tail = tl; + tail = &tl->next; + + l = unique(buf, s); + + l->v->set = 1; + l->v->type = TINT; + l->v->vstore.u0.sival = v; + if(l->v->vstore.comt == 0) + l->v->vstore.fmt = 'X'; + + /* Enter as list of { name, type, value } */ + list = al(TSTRING); + tl->lstore.u0.sl = list; + list->lstore.u0.sstring = strnode(buf); + list->lstore.fmt = 's'; + list->next = al(TINT); + list = list->next; + list->lstore.fmt = 'c'; + list->lstore.u0.sival = s->type; + list->next = al(TINT); + list = list->next; + list->lstore.fmt = 'X'; + list->lstore.u0.sival = v; + + } + } + l = mkvar("symbols"); + l->v->set = 1; + l->v->type = TLIST; + l->v->vstore.u0.sl = l2; + if(l2 == 0) + print("no symbol information\n"); +} + +void +varreg(void) +{ + Lsym *l; + Value *v; + Reglist *r; + List **tail, *li; + + l = mkvar("registers"); + v = l->v; + v->set = 1; + v->type = TLIST; + v->vstore.u0.sl = 0; + tail = &v->vstore.u0.sl; + + for(r = mach->reglist; r->rname; r++) { + l = mkvar(r->rname); + v = l->v; + v->set = 1; + v->vstore.u0.sival = r->roffs; + v->vstore.fmt = r->rformat; + v->type = TINT; + + li = al(TSTRING); + li->lstore.u0.sstring = strnode(r->rname); + li->lstore.fmt = 's'; + *tail = li; + tail = &li->next; + } + + if(machdata == 0) + return; + + l = mkvar("bpinst"); /* Breakpoint text */ + v = l->v; + v->type = TSTRING; + v->vstore.fmt = 's'; + v->set = 1; + v->vstore.u0.sstring = gmalloc(sizeof(String)); + v->vstore.u0.sstring->len = machdata->bpsize; + v->vstore.u0.sstring->string = gmalloc(machdata->bpsize); + memmove(v->vstore.u0.sstring->string, machdata->bpinst, machdata->bpsize); +} + +void +loadvars(void) +{ + Lsym *l; + Value *v; + + l = mkvar("proc"); + v = l->v; + v->type = TINT; + v->vstore.fmt = 'X'; + v->set = 1; + v->vstore.u0.sival = 0; + + l = mkvar("pid"); /* Current process */ + v = l->v; + v->type = TINT; + v->vstore.fmt = 'D'; + v->set = 1; + v->vstore.u0.sival = 0; + + mkvar("notes"); /* Pending notes */ + + l = mkvar("proclist"); /* Attached processes */ + l->v->type = TLIST; + + l = mkvar("rdebug"); /* remote debugging enabled? */ + v = l->v; + v->type = TINT; + v->vstore.fmt = 'D'; + v->set = 1; + v->vstore.u0.sival = rdebug; + + if(rdebug) { + l = mkvar("_breakid"); + v = l->v; + v->type = TINT; + v->vstore.fmt = 'D'; + v->set = 1; + v->vstore.u0.sival = -1; + } +} + +vlong +rget(Map *map, char *reg) +{ + Lsym *s; + long x; + vlong v; + int ret; + + s = look(reg); + if(s == 0) + fatal("rget: %s\n", reg); + + if(s->v->vstore.fmt == 'Y') + ret = get8(map, (long)s->v->vstore.u0.sival, &v); + else { + ret = get4(map, (long)s->v->vstore.u0.sival, &x); + v = x; + } + if(ret < 0) + error("can't get register %s: %r\n", reg); + return v; +} + +String* +strnodlen(char *name, int len) +{ + String *s; + + s = gmalloc(sizeof(String)+len+1); + s->string = (char*)s+sizeof(String); + s->len = len; + if(name != 0) + memmove(s->string, name, len); + s->string[len] = '\0'; + + s->sgc.gclink = gcl; + gcl = &s->sgc; + + return s; +} + +String* +strnode(char *name) +{ + return strnodlen(name, strlen(name)); +} + +String* +runenode(Rune *name) +{ + int len; + Rune *p; + String *s; + + p = name; + for(len = 0; *p; p++) + len++; + + len++; + len *= sizeof(Rune); + s = gmalloc(sizeof(String)+len); + s->string = (char*)s+sizeof(String); + s->len = len; + memmove(s->string, name, len); + + s->sgc.gclink = gcl; + gcl = &s->sgc; + + return s; +} + +String* +stradd(String *l, String *r) +{ + int len; + String *s; + + len = l->len+r->len; + s = gmalloc(sizeof(String)+len+1); + s->sgc.gclink = gcl; + gcl = &s->sgc; + s->len = len; + s->string = (char*)s+sizeof(String); + memmove(s->string, l->string, l->len); + memmove(s->string+l->len, r->string, r->len); + s->string[s->len] = 0; + return s; +} + +int +scmp(String *sr, String *sl) +{ + if(sr->len != sl->len) + return 0; + + if(memcmp(sr->string, sl->string, sl->len)) + return 0; + + return 1; +} diff --git a/utils/awk/FIXES b/utils/awk/FIXES new file mode 100644 index 00000000..236323fc --- /dev/null +++ b/utils/awk/FIXES @@ -0,0 +1,703 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +This file lists all bug fixes, changes, etc., made since the AWK book +was sent to the printers in August, 1987. + +Nov 15, 2000: + fixed a bug introduced in august 1997 that caused expressions + like $f[1] to be syntax errors. thanks to arnold robbins for + noticing this and providing a fix. + +Oct 30, 2000: + fixed some nextfile bugs: not handling all cases. thanks to + arnold robbins for pointing this out. new regressions added. + + close() is now a function. it returns whatever the library + fclose returns, and -1 for closing a file or pipe that wasn't + opened. + +Sep 24, 2000: + permit \n explicitly in character classes; won't work right + if comes in as "[\n]" but ok as /[\n]/, because of multiple + processing of \'s. thanks to arnold robbins. + +July 5, 2000: + minor fiddles in tran.c to keep compilers happy about uschar. + thanks to norman wilson. + +May 25, 2000: + yet another attempt at making 8-bit input work, with another + band-aid in b.c (member()), and some (uschar) casts to head + off potential errors in subscripts (like isdigit). also + changed HAT to NCHARS-2. thanks again to santiago vila. + + changed maketab.c to ignore apparently out of range definitions + instead of halting; new freeBSD generates one. thanks to + jon snader <jsnader@ix.netcom.com> for pointing out the problem. + +May 2, 2000: + fixed an 8-bit problem in b.c by making several char*'s into + unsigned char*'s. not clear i have them all yet. thanks to + Santiago Vila <sanvila@unex.es> for the bug report. + +Apr 21, 2000: + finally found and fixed a memory leak in function call; it's + been there since functions were added ~1983. thanks to + jon bentley for the test case that found it. + + added test in envinit to catch environment "variables" with + names begining with '='; thanks to Berend Hasselman. + +Jul 28, 1999: + added test in defn() to catch function foo(foo), which + otherwise recurses until core dump. thanks to arnold + robbins for noticing this. + +Jun 20, 1999: + added *bp in gettok in lex.c; appears possible to exit function + without terminating the string. thanks to russ cox. + +Jun 2, 1999: + added function stdinit() to run to initialize files[] array, + in case stdin, etc., are not constants; some compilers care. + +May 10, 1999: + replaced the ERROR ... FATAL, etc., macros with functions + based on vprintf, to avoid problems caused by overrunning + fixed-size errbuf array. thanks to ralph corderoy for the + impetus, and for pointing out a string termination bug in + qstring as well. + +Apr 21, 1999: + fixed bug that caused occasional core dumps with commandline + variable with value ending in \. (thanks to nelson beebe for + the test case.) + +Apr 16, 1999: + with code kindly provided by Bruce Lilly, awk now parses + /=/ and similar constructs more sensibly in more places. + Bruce also provided some helpful test cases. + +Apr 5, 1999: + changed true/false to True/False in run.c to make it + easier to compile with C++. Added some casts on malloc + and realloc to be honest about casts; ditto. changed + ltype int to long in struct rrow to reduce some 64-bit + complaints; other changes scattered throughout for the + same purpose. thanks to Nelson Beebe for these portability + improvements. + + removed some horrible pointer-int casting in b.c and elsewhere + by adding ptoi and itonp to localize the casts, which are + all benign. fixed one incipient bug that showed up on sgi + in 64-bit mode. + + reset lineno for new source file; include filename in error + message. also fixed line number error in continuation lines. + (thanks to Nelson Beebe for both of these.) + +Mar 24, 1999: + Nelson Beebe notes that irix 5.3 yacc dies with a bogus + error; use a newer version or switch to bison, since sgi + is unlikely to fix it. + +Mar 5, 1999: + changed isnumber to is_number to avoid the problem caused by + versions of ctype.h that include the name isnumber. + + distribution now includes a script for building on a Mac, + thanks to Dan Allen. + +Feb 20, 1999: + fixed memory leaks in run.c (call) and tran.c (setfval). + thanks to Stephen Nutt for finding these and providing the fixes. + +Jan 13, 1999: + replaced srand argument by (unsigned int) in run.c; + avoids problem on Mac and potentially on Unix & Windows. + thanks to Dan Allen. + + added a few (int) casts to silence useless compiler warnings. + e.g., errorflag= in run.c jump(). + + added proctab.c to the bundle outout; one less thing + to have to compile out of the box. + + added calls to _popen and _pclose to the win95 stub for + pipes (thanks to Steve Adams for this helpful suggestion). + seems to work, though properties are not well understood + by me, and it appears that under some circumstances the + pipe output is truncated. Be careful. + +Oct 19, 1998: + fixed a couple of bugs in getrec: could fail to update $0 + after a getline var; because inputFS wasn't initialized, + could split $0 on every character, a misleading diversion. + + fixed caching bug in makedfa: LRU was actually removing + least often used. + + thanks to ross ridge for finding these, and for providing + great bug reports. + +May 12, 1998: + fixed potential bug in readrec: might fail to update record + pointer after growing. thanks to dan levy for spotting this + and suggesting the fix. + +Mar 12, 1998: + added -V to print version number and die. + +Feb 11, 1998: + subtle silent bug in lex.c: if the program ended with a number + longer than 1 digit, part of the input would be pushed back and + parsed again because token buffer wasn't terminated right. + example: awk 'length($0) > 10'. blush. at least i found it + myself. + +Aug 31, 1997: + s/adelete/awkdelete/: SGI uses this in malloc.h. + thanks to nelson beebe for pointing this one out. + +Aug 21, 1997: + fixed some bugs in sub and gsub when replacement includes \\. + this is a dark, horrible corner, but at least now i believe that + the behavior is the same as gawk and the intended posix standard. + thanks to arnold robbins for advice here. + +Aug 9, 1997: + somewhat regretfully, replaced the ancient lex-based lexical + analyzer with one written in C. it's longer, generates less code, + and more portable; the old one depended too much on mysterious + properties of lex that were not preserved in other environments. + in theory these recognize the same language. + + now using strtod to test whether a string is a number, instead of + the convoluted original function. should be more portable and + reliable if strtod is implemented right. + + removed now-pointless optimization in makefile that tries to avoid + recompilation when awkgram.y is changed but symbols are not. + + removed most fixed-size arrays, though a handful remain, some + of which are unchecked. you have been warned. + +Aug 4, 1997: + with some trepidation, replaced the ancient code that managed + fields and $0 in fixed-size arrays with arrays that grow on + demand. there is still some tension between trying to make this + run fast and making it clean; not sure it's right yet. + + the ill-conceived -mr and -mf arguments are now useful only + for debugging. previous dynamic string code removed. + + numerous other minor cleanups along the way. + +Jul 30, 1997: + using code provided by dan levy (to whom profuse thanks), replaced + fixed-size arrays and awkward kludges by a fairly uniform mechanism + to grow arrays as needed for printf, sub, gsub, etc. + +Jul 23, 1997: + falling off the end of a function returns "" and 0, not 0. + thanks to arnold robbins. + +Jun 17, 1997: + replaced several fixed-size arrays by dynamically-created ones + in run.c; added overflow tests to some previously unchecked cases. + getline, toupper, tolower. + + getline code is still broken in that recursive calls may wind + up using the same space. [fixed later] + + increased RECSIZE to 8192 to push problems further over the horizon. + + added \r to \n as input line separator for programs, not data. + damn CRLFs. + + modified format() to permit explicit printf("%c", 0) to include + a null byte in output. thanks to ken stailey for the fix. + + added a "-safe" argument that disables file output (print >, + print >>), process creation (cmd|getline, print |, system), and + access to the environment (ENVIRON). this is a first approximation + to a "safe" version of awk, but don't rely on it too much. thanks + to joan feigenbaum and matt blaze for the inspiration long ago. + +Jul 8, 1996: + fixed long-standing bug in sub, gsub(/a/, "\\\\&"); thanks to + ralph corderoy. + +Jun 29, 1996: + fixed awful bug in new field splitting; didn't get all the places + where input was done. + +Jun 28, 1996: + changed field-splitting to conform to posix definition: fields are + split using the value of FS at the time of input; it used to be + the value when the field or NF was first referred to, a much less + predictable definition. thanks to arnold robbins for encouragement + to do the right thing. + +May 28, 1996: + fixed appalling but apparently unimportant bug in parsing octal + numbers in reg exprs. + + explicit hex in reg exprs now limited to 2 chars: \xa, \xaa. + +May 27, 1996: + cleaned up some declarations so gcc -Wall is now almost silent. + + makefile now includes backup copies of ytab.c and lexyy.c in case + one makes before looking; it also avoids recreating lexyy.c unless + really needed. + + s/aprintf/awkprint, s/asprintf/awksprintf/ to avoid some name clashes + with unwisely-written header files. + + thanks to jeffrey friedl for several of these. + +May 26, 1996: + an attempt to rationalize the (unsigned) char issue. almost all + instances of unsigned char have been removed; the handful of places + in b.c where chars are used as table indices have been hand-crafted. + added some latin-1 tests to the regression, but i'm not confident; + none of my compilers seem to care much. thanks to nelson beebe for + pointing out some others that do care. + +May 2, 1996: + removed all register declarations. + + enhanced split(), as in gawk, etc: split(s, a, "") splits s into + a[1]...a[length(s)] with each character a single element. + + made the same changes for field-splitting if FS is "". + + added nextfile, as in gawk: causes immediate advance to next + input file. (thanks to arnold robbins for inspiration and code). + + small fixes to regexpr code: can now handle []], [[], and + variants; [] is now a syntax error, rather than matching + everything; [z-a] is now empty, not z. far from complete + or correct, however. (thanks to jeffrey friedl for pointing out + some awful behaviors.) + +Apr 29, 1996: + replaced uchar by uschar everwhere; apparently some compilers + usurp this name and this causes conflicts. + + fixed call to time in run.c (bltin); arg is time_t *. + + replaced horrible pointer/long punning in b.c by a legitimate + union. should be safer on 64-bit machines and cleaner everywhere. + (thanks to nelson beebe for pointing out some of these problems.) + + replaced nested comments by #if 0...#endif in run.c, lib.c. + + removed getsval, setsval, execute macros from run.c and lib.c. + machines are 100x faster than they were when these macros were + first used. + + revised filenames: awk.g.y => awkgram.y, awk.lx.l => awklex.l, + y.tab.[ch] => ytab.[ch], lex.yy.c => lexyy.c, all in the aid of + portability to nameless systems. + + "make bundle" now includes yacc and lex output files for recipients + who don't have yacc or lex. + +Aug 15, 1995: + initialized Cells in setsymtab more carefully; some fields + were not set. (thanks to purify, all of whose complaints i + think i now understand.) + + fixed at least one error in gsub that looked at -1-th element + of an array when substituting for a null match (e.g., $). + + delete arrayname is now legal; it clears the elements but leaves + the array, which may not be the right behavior. + + modified makefile: my current make can't cope with the test used + to avoid unnecessary yacc invocations. + +Jul 17, 1995: + added dynamically growing strings to awk.lx.l and b.c + to permit regular expressions to be much bigger. + the state arrays can still overflow. + +Aug 24, 1994: + detect duplicate arguments in function definitions (mdm). + +May 11, 1994: + trivial fix to printf to limit string size in sub(). + +Apr 22, 1994: + fixed yet another subtle self-assignment problem: + $1 = $2; $1 = $1 clobbered $1. + + Regression tests now use private echo, to avoid quoting problems. + +Feb 2, 1994: + changed error() to print line number as %d, not %g. + +Jul 23, 1993: + cosmetic changes: increased sizes of some arrays, + reworded some error messages. + + added CONVFMT as in posix (just replaced OFMT in getsval) + + FILENAME is now "" until the first thing that causes a file + to be opened. + +Nov 28, 1992: + deleted yyunput and yyoutput from proto.h; + different versions of lex give these different declarations. + +May 31, 1992: + added -mr N and -mf N options: more record and fields. + these really ought to adjust automatically. + + cleaned up some error messages; "out of space" now means + malloc returned NULL in all cases. + + changed rehash so that if it runs out, it just returns; + things will continue to run slow, but maybe a bit longer. + +Apr 24, 1992: + remove redundant close of stdin when using -f -. + + got rid of core dump with -d; awk -d just prints date. + +Apr 12, 1992: + added explicit check for /dev/std(in,out,err) in redirection. + unlike gawk, no /dev/fd/n yet. + + added (file/pipe) builtin. hard to test satisfactorily. + not posix. + +Feb 20, 1992: + recompile after abortive changes; should be unchanged. + +Dec 2, 1991: + die-casting time: converted to ansi C, installed that. + +Nov 30, 1991: + fixed storage leak in freefa, failing to recover [N]CCL. + thanks to Bill Jones (jones@cs.usask.ca) + +Nov 19, 1991: + use RAND_MAX instead of literal in builtin(). + +Nov 12, 1991: + cranked up some fixed-size arrays in b.c, and added a test for + overflow in penter. thanks to mark larsen. + +Sep 24, 1991: + increased buffer in gsub. a very crude fix to a general problem. + and again on Sep 26. + +Aug 18, 1991: + enforce variable name syntax for commandline variables: has to + start with letter or _. + +Jul 27, 1991: + allow newline after ; in for statements. + +Jul 21, 1991: + fixed so that in self-assignment like $1=$1, side effects + like recomputing $0 take place. (this is getting subtle.) + +Jun 30, 1991: + better test for detecting too-long output record. + +Jun 2, 1991: + better defense against very long printf strings. + made break and continue illegal outside of loops. + +May 13, 1991: + removed extra arg on gettemp, tempfree. minor error message rewording. + +May 6, 1991: + fixed silly bug in hex parsing in hexstr(). + removed an apparently unnecessary test in isnumber(). + warn about weird printf conversions. + fixed unchecked array overwrite in relex(). + + changed for (i in array) to access elements in sorted order. + then unchanged it -- it really does run slower in too many cases. + left the code in place, commented out. + +Feb 10, 1991: + check error status on all writes, to avoid banging on full disks. + +Jan 28, 1991: + awk -f - reads the program from stdin. + +Jan 11, 1991: + failed to set numeric state on $0 in cmd|getline context in run.c. + +Nov 2, 1990: + fixed sleazy test for integrality in getsval; use modf. + +Oct 29, 1990: + fixed sleazy buggy code in lib.c that looked (incorrectly) for + too long input lines. + +Oct 14, 1990: + fixed the bug on p. 198 in which it couldn't deduce that an + argument was an array in some contexts. replaced the error + message in intest() by code that damn well makes it an array. + +Oct 8, 1990: + fixed horrible bug: types and values were not preserved in + some kinds of self-assignment. (in assign().) + +Aug 24, 1990: + changed NCHARS to 256 to handle 8-bit characters in strings + presented to match(), etc. + +Jun 26, 1990: + changed struct rrow (awk.h) to use long instead of int for lval, + since cfoll() stores a pointer in it. now works better when int's + are smaller than pointers! + +May 6, 1990: + AVA fixed the grammar so that ! is uniformly of the same precedence as + unary + and -. This renders illegal some constructs like !x=y, which + now has to be parenthesized as !(x=y), and makes others work properly: + !x+y is (!x)+y, and x!y is x !y, not two pattern-action statements. + (These problems were pointed out by Bob Lenk of Posix.) + + Added \x to regular expressions (already in strings). + Limited octal to octal digits; \8 and \9 are not octal. + Centralized the code for parsing escapes in regular expressions. + Added a bunch of tests to T.re and T.sub to verify some of this. + +Feb 9, 1990: + fixed null pointer dereference bug in main.c: -F[nothing]. sigh. + + restored srand behavior: it returns the current seed. + +Jan 18, 1990: + srand now returns previous seed value (0 to start). + +Jan 5, 1990: + fix potential problem in tran.c -- something was freed, + then used in freesymtab. + +Oct 18, 1989: + another try to get the max number of open files set with + relatively machine-independent code. + + small fix to input() in case of multiple reads after EOF. + +Oct 11, 1989: + FILENAME is now defined in the BEGIN block -- too many old + programs broke. + + "-" means stdin in getline as well as on the commandline. + + added a bunch of casts to the code to tell the truth about + char * vs. unsigned char *, a right royal pain. added a + setlocale call to the front of main, though probably no one + has it usefully implemented yet. + +Aug 24, 1989: + removed redundant relational tests against nullnode if parse + tree already had a relational at that point. + +Aug 11, 1989: + fixed bug: commandline variable assignment has to look like + var=something. (consider the man page for =, in file =.1) + + changed number of arguments to functions to static arrays + to avoid repeated malloc calls. + +Aug 2, 1989: + restored -F (space) separator + +Jul 30, 1989: + added -v x=1 y=2 ... for immediate commandline variable assignment; + done before the BEGIN block for sure. they have to precede the + program if the program is on the commandline. + Modified Aug 2 to require a separate -v for each assignment. + +Jul 10, 1989: + fixed ref-thru-zero bug in environment code in tran.c + +Jun 23, 1989: + add newline to usage message. + +Jun 14, 1989: + added some missing ansi printf conversion letters: %i %X %E %G. + no sensible meaning for h or L, so they may not do what one expects. + + made %* conversions work. + + changed x^y so that if n is a positive integer, it's done + by explicit multiplication, thus achieving maximum accuracy. + (this should be done by pow() but it seems not to be locally.) + done to x ^= y as well. + +Jun 4, 1989: + ENVIRON array contains environment: if shell variable V=thing, + ENVIRON["V"] is "thing" + + multiple -f arguments permitted. error reporting is naive. + (they were permitted before, but only the last was used.) + + fixed a really stupid botch in the debugging macro dprintf + + fixed order of evaluation of commandline assignments to match + what the book claims: an argument of the form x=e is evaluated + at the time it would have been opened if it were a filename (p 63). + this invalidates the suggested answer to ex 4-1 (p 195). + + removed some code that permitted -F (space) fieldseparator, + since it didn't quite work right anyway. (restored aug 2) + +Apr 27, 1989: + Line number now accumulated correctly for comment lines. + +Apr 26, 1989: + Debugging output now includes a version date, + if one compiles it into the source each time. + +Apr 9, 1989: + Changed grammar to prohibit constants as 3rd arg of sub and gsub; + prevents class of overwriting-a-constant errors. (Last one?) + This invalidates the "banana" example on page 43 of the book. + + Added \a ("alert"), \v (vertical tab), \xhhh (hexadecimal), + as in ANSI, for strings. Rescinded the sloppiness that permitted + non-octal digits in \ooo. Warning: not all compilers and libraries + will be able to deal with \x correctly. + +Jan 9, 1989: + Fixed bug that caused tempcell list to contain a duplicate. + The fix is kludgy. + +Dec 17, 1988: + Catches some more commandline errors in main. + Removed redundant decl of modf in run.c (confuses some compilers). + Warning: there's no single declaration of malloc, etc., in awk.h + that seems to satisfy all compilers. + +Dec 7, 1988: + Added a bit of code to error printing to avoid printing nulls. + (Not clear that it actually would.) + +Nov 27, 1988: + With fear and trembling, modified the grammar to permit + multiple pattern-action statements on one line without + an explicit separator. By definition, this capitulation + to the ghost of ancient implementations remains undefined + and thus subject to change without notice or apology. + DO NOT COUNT ON IT. + +Oct 30, 1988: + Fixed bug in call() that failed to recover storage. + + A warning is now generated if there are more arguments + in the call than in the definition (in lieu of fixing + another storage leak). + +Oct 20, 1988: + Fixed %c: if expr is numeric, use numeric value; + otherwise print 1st char of string value. still + doesn't work if the value is 0 -- won't print \0. + + Added a few more checks for running out of malloc. + +Oct 12, 1988: + Fixed bug in call() that freed local arrays twice. + + Fixed to handle deletion of non-existent array right; + complains about attempt to delete non-array element. + +Sep 30, 1988: + Now guarantees to evaluate all arguments of built-in + functions, as in C; the appearance is that arguments + are evaluated before the function is called. Places + affected are sub (gsub was ok), substr, printf, and + all the built-in arithmetic functions in bltin(). + A warning is generated if a bltin() is called with + the wrong number of arguments. + + This requires changing makeprof on p167 of the book. + +Aug 23, 1988: + setting FILENAME in BEGIN caused core dump, apparently + because it was freeing space not allocated by malloc. + +July 24, 1988: + fixed egregious error in toupper/tolower functions. + still subject to rescinding, however. + +July 2, 1988: + flush stdout before opening file or pipe + +July 2, 1988: + performance bug in b.c/cgoto(): not freeing some sets of states. + partial fix only right now, and the number of states increased + to make it less obvious. + +June 1, 1988: + check error status on close + +May 28, 1988: + srand returns seed value it's using. + see 1/18/90 + +May 22, 1988: + Removed limit on depth of function calls. + +May 10, 1988: + Fixed lib.c to permit _ in commandline variable names. + +Mar 25, 1988: + main.c fixed to recognize -- as terminator of command- + line options. Illegal options flagged. + Error reporting slightly cleaned up. + +Dec 2, 1987: + Newer C compilers apply a strict scope rule to extern + declarations within functions. Two extern declarations in + lib.c and tran.c have been moved to obviate this problem. + +Oct xx, 1987: + Reluctantly added toupper and tolower functions. + Subject to rescinding without notice. + +Sep 17, 1987: + Error-message printer had printf(s) instead of + printf("%s",s); got core dumps when the message + included a %. + +Sep 12, 1987: + Very long printf strings caused core dump; + fixed aprintf, asprintf, format to catch them. + Can still get a core dump in printf itself. + + diff --git a/utils/awk/NOTICE b/utils/awk/NOTICE new file mode 100644 index 00000000..790db512 --- /dev/null +++ b/utils/awk/NOTICE @@ -0,0 +1,7 @@ +This is a copy of Brian Kernighan's awk from netlib, +which can be used on systems that don't provide a reasonably +modern version of awk. Awk is needed for kernel builds, +amongst other things. + +See the README for the terms +under which it is distributed. diff --git a/utils/awk/README b/utils/awk/README new file mode 100644 index 00000000..bdb7e503 --- /dev/null +++ b/utils/awk/README @@ -0,0 +1,83 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +This is the version of awk described in "The AWK Programming Language", +by Al Aho, Brian Kernighan, and Peter Weinberger +(Addison-Wesley, 1988, ISBN 0-201-07981-X). + +Changes, mostly bug fixes and occasional enhancements, are listed +in FIXES. If you distribute this code further, please please please +distribute FIXES with it. If you find errors, please report them +to bwk@bell-labs.com. Thanks. + +The program itself is created by + make +which should produce a sequence of messages roughly like this: + + yacc -d awkgram.y + +conflicts: 43 shift/reduce, 85 reduce/reduce + mv y.tab.c ytab.c + mv y.tab.h ytab.h + cc -O -c ytab.c + cc -O -c b.c + cc -O -c main.c + cc -O -c parse.c + cc -O maketab.c -o maketab + ./maketab >proctab.c + cc -O -c proctab.c + cc -O -c tran.c + cc -O -c lib.c + cc -O -c run.c + cc -O -c lex.c + cc -O ytab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm + +This produces an executable a.out; you will eventually want to +move this to some place like /usr/bin/awk. + +If your system is does not have yacc or bison (the GNU +equivalent), you must compile the pieces manually. We have +included yacc output in ytab.c and ytab.h, and backup copies in +case you overwrite them. We have also included a copy of +proctab.c so you do not need to run maketab. + +NOTE: This version uses ANSI C, as you should also. We have +compiled this without any changes using gcc -Wall and/or local C +compilers on a variety of systems, but new systems or compilers +may raise some new complaint; reports of difficulties are +welcome. + +This also compiles with Visual C++ on Windows 95 and Windows NT, +*if* you provide versions of popen and pclose. The file +missing95.c contains versions that can be used to get started +with, though the underlying support has mysterious properties, +the symptom of which can be truncated pipe output. Beware. + +This is also said to compile on Macintosh systems, using the +file "buildmac" provided by Dan Allen (danallen@microsoft.com), +to whom many thanks. Dan also provided buildwin.bat, a simple +script for compiling on NT if you prefer. + +The version of malloc that comes with some systems is sometimes +astonishly slow. If awk seems slow, you might try fixing that. diff --git a/utils/awk/awk.1 b/utils/awk/awk.1 new file mode 100644 index 00000000..6119613c --- /dev/null +++ b/utils/awk/awk.1 @@ -0,0 +1,529 @@ +.de EX +.nf +.ft CW +.. +.de EE +.br +.fi +.ft 1 +.. +awk +.TH AWK 1 +.CT 1 files prog_other +.SH NAME +awk \- pattern-directed scanning and processing language +.SH SYNOPSIS +.B awk +[ +.BI \-F +.I fs +] +[ +.BI \-v +.I var=value +] +[ +.I 'prog' +| +.BI \-f +.I progfile +] +[ +.I file ... +] +.SH DESCRIPTION +.I Awk +scans each input +.I file +for lines that match any of a set of patterns specified literally in +.IR prog +or in one or more files +specified as +.B \-f +.IR progfile . +With each pattern +there can be an associated action that will be performed +when a line of a +.I file +matches the pattern. +Each line is matched against the +pattern portion of every pattern-action statement; +the associated action is performed for each matched pattern. +The file name +.B \- +means the standard input. +Any +.IR file +of the form +.I var=value +is treated as an assignment, not a filename, +and is executed at the time it would have been opened if it were a filename. +The option +.B \-v +followed by +.I var=value +is an assignment to be done before +.I prog +is executed; +any number of +.B \-v +options may be present. +The +.B \-F +.IR fs +option defines the input field separator to be the regular expression +.IR fs. +.PP +An input line is normally made up of fields separated by white space, +or by regular expression +.BR FS . +The fields are denoted +.BR $1 , +.BR $2 , +\&..., while +.B $0 +refers to the entire line. +If +.BR FS +is null, the input line is split into one field per character. +.PP +A pattern-action statement has the form +.IP +.IB pattern " { " action " } +.PP +A missing +.BI { " action " } +means print the line; +a missing pattern always matches. +Pattern-action statements are separated by newlines or semicolons. +.PP +An action is a sequence of statements. +A statement can be one of the following: +.PP +.EX +.ta \w'\f(CWdelete array[expression]'u +.RS +.nf +.ft CW +if(\fI expression \fP)\fI statement \fP\fR[ \fPelse\fI statement \fP\fR]\fP +while(\fI expression \fP)\fI statement\fP +for(\fI expression \fP;\fI expression \fP;\fI expression \fP)\fI statement\fP +for(\fI var \fPin\fI array \fP)\fI statement\fP +do\fI statement \fPwhile(\fI expression \fP) +break +continue +{\fR [\fP\fI statement ... \fP\fR] \fP} +\fIexpression\fP #\fR commonly\fP\fI var = expression\fP +print\fR [ \fP\fIexpression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP +printf\fI format \fP\fR[ \fP,\fI expression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP +return\fR [ \fP\fIexpression \fP\fR]\fP +next #\fR skip remaining patterns on this input line\fP +nextfile #\fR skip rest of this file, open next, start at top\fP +delete\fI array\fP[\fI expression \fP] #\fR delete an array element\fP +delete\fI array\fP #\fR delete all elements of array\fP +exit\fR [ \fP\fIexpression \fP\fR]\fP #\fR exit immediately; status is \fP\fIexpression\fP +.fi +.RE +.EE +.DT +.PP +Statements are terminated by +semicolons, newlines or right braces. +An empty +.I expression-list +stands for +.BR $0 . +String constants are quoted \&\f(CW"\ "\fR, +with the usual C escapes recognized within. +Expressions take on string or numeric values as appropriate, +and are built using the operators +.B + \- * / % ^ +(exponentiation), and concatenation (indicated by white space). +The operators +.B +! ++ \-\- += \-= *= /= %= ^= > >= < <= == != ?: +are also available in expressions. +Variables may be scalars, array elements +(denoted +.IB x [ i ] ) +or fields. +Variables are initialized to the null string. +Array subscripts may be any string, +not necessarily numeric; +this allows for a form of associative memory. +Multiple subscripts such as +.B [i,j,k] +are permitted; the constituents are concatenated, +separated by the value of +.BR SUBSEP . +.PP +The +.B print +statement prints its arguments on the standard output +(or on a file if +.BI > file +or +.BI >> file +is present or on a pipe if +.BI | cmd +is present), separated by the current output field separator, +and terminated by the output record separator. +.I file +and +.I cmd +may be literal names or parenthesized expressions; +identical string values in different statements denote +the same open file. +The +.B printf +statement formats its expression list according to the format +(see +.IR printf (3)) . +The built-in function +.BI close( expr ) +closes the file or pipe +.IR expr . +The built-in function +.BI fflush( expr ) +flushes any buffered output for the file or pipe +.IR expr . +.PP +The mathematical functions +.BR exp , +.BR log , +.BR sqrt , +.BR sin , +.BR cos , +and +.BR atan2 +are built in. +Other built-in functions: +.TF length +.TP +.B length +the length of its argument +taken as a string, +or of +.B $0 +if no argument. +.TP +.B rand +random number on (0,1) +.TP +.B srand +sets seed for +.B rand +and returns the previous seed. +.TP +.B int +truncates to an integer value +.TP +.BI substr( s , " m" , " n\fB) +the +.IR n -character +substring of +.I s +that begins at position +.IR m +counted from 1. +.TP +.BI index( s , " t" ) +the position in +.I s +where the string +.I t +occurs, or 0 if it does not. +.TP +.BI match( s , " r" ) +the position in +.I s +where the regular expression +.I r +occurs, or 0 if it does not. +The variables +.B RSTART +and +.B RLENGTH +are set to the position and length of the matched string. +.TP +.BI split( s , " a" , " fs\fB) +splits the string +.I s +into array elements +.IB a [1] , +.IB a [2] , +\&..., +.IB a [ n ] , +and returns +.IR n . +The separation is done with the regular expression +.I fs +or with the field separator +.B FS +if +.I fs +is not given. +An empty string as field separator splits the string +into one array element per character. +.TP +.BI sub( r , " t" , " s\fB) +substitutes +.I t +for the first occurrence of the regular expression +.I r +in the string +.IR s . +If +.I s +is not given, +.B $0 +is used. +.TP +.B gsub +same as +.B sub +except that all occurrences of the regular expression +are replaced; +.B sub +and +.B gsub +return the number of replacements. +.TP +.BI sprintf( fmt , " expr" , " ...\fB ) +the string resulting from formatting +.I expr ... +according to the +.IR printf (3) +format +.I fmt +.TP +.BI system( cmd ) +executes +.I cmd +and returns its exit status +.TP +.BI tolower( str ) +returns a copy of +.I str +with all upper-case characters translated to their +corresponding lower-case equivalents. +.TP +.BI toupper( str ) +returns a copy of +.I str +with all lower-case characters translated to their +corresponding upper-case equivalents. +.PD +.PP +The ``function'' +.B getline +sets +.B $0 +to the next input record from the current input file; +.B getline +.BI < file +sets +.B $0 +to the next record from +.IR file . +.B getline +.I x +sets variable +.I x +instead. +Finally, +.IB cmd " | getline +pipes the output of +.I cmd +into +.BR getline ; +each call of +.B getline +returns the next line of output from +.IR cmd . +In all cases, +.B getline +returns 1 for a successful input, +0 for end of file, and \-1 for an error. +.PP +Patterns are arbitrary Boolean combinations +(with +.BR "! || &&" ) +of regular expressions and +relational expressions. +Regular expressions are as in +.IR egrep ; +see +.IR grep (1). +Isolated regular expressions +in a pattern apply to the entire line. +Regular expressions may also occur in +relational expressions, using the operators +.BR ~ +and +.BR !~ . +.BI / re / +is a constant regular expression; +any string (constant or variable) may be used +as a regular expression, except in the position of an isolated regular expression +in a pattern. +.PP +A pattern may consist of two patterns separated by a comma; +in this case, the action is performed for all lines +from an occurrence of the first pattern +though an occurrence of the second. +.PP +A relational expression is one of the following: +.IP +.I expression matchop regular-expression +.br +.I expression relop expression +.br +.IB expression " in " array-name +.br +.BI ( expr , expr,... ") in " array-name +.PP +where a relop is any of the six relational operators in C, +and a matchop is either +.B ~ +(matches) +or +.B !~ +(does not match). +A conditional is an arithmetic expression, +a relational expression, +or a Boolean combination +of these. +.PP +The special patterns +.B BEGIN +and +.B END +may be used to capture control before the first input line is read +and after the last. +.B BEGIN +and +.B END +do not combine with other patterns. +.PP +Variable names with special meanings: +.TF FILENAME +.TP +.B CONVFMT +conversion format used when converting numbers +(default +.BR "%.6g" ) +.TP +.B FS +regular expression used to separate fields; also settable +by option +.BI \-F fs. +.TP +.BR NF +number of fields in the current record +.TP +.B NR +ordinal number of the current record +.TP +.B FNR +ordinal number of the current record in the current file +.TP +.B FILENAME +the name of the current input file +.TP +.B RS +input record separator (default newline) +.TP +.B OFS +output field separator (default blank) +.TP +.B ORS +output record separator (default newline) +.TP +.B OFMT +output format for numbers (default +.BR "%.6g" ) +.TP +.B SUBSEP +separates multiple subscripts (default 034) +.TP +.B ARGC +argument count, assignable +.TP +.B ARGV +argument array, assignable; +non-null members are taken as filenames +.TP +.B ENVIRON +array of environment variables; subscripts are names. +.PD +.PP +Functions may be defined (at the position of a pattern-action statement) thus: +.IP +.B +function foo(a, b, c) { ...; return x } +.PP +Parameters are passed by value if scalar and by reference if array name; +functions may be called recursively. +Parameters are local to the function; all other variables are global. +Thus local variables may be created by providing excess parameters in +the function definition. +.SH EXAMPLES +.TP +.EX +length($0) > 72 +.EE +Print lines longer than 72 characters. +.TP +.EX +{ print $2, $1 } +.EE +Print first two fields in opposite order. +.PP +.EX +BEGIN { FS = ",[ \et]*|[ \et]+" } + { print $2, $1 } +.EE +.ns +.IP +Same, with input fields separated by comma and/or blanks and tabs. +.PP +.EX +.nf + { s += $1 } +END { print "sum is", s, " average is", s/NR } +.fi +.EE +.ns +.IP +Add up first column, print sum and average. +.TP +.EX +/start/, /stop/ +.EE +Print all lines between start/stop pairs. +.PP +.EX +.nf +BEGIN { # Simulate echo(1) + for (i = 1; i < ARGC; i++) printf "%s ", ARGV[i] + printf "\en" + exit } +.fi +.EE +.SH SEE ALSO +.IR lex (1), +.IR sed (1) +.br +A. V. Aho, B. W. Kernighan, P. J. Weinberger, +.I +The AWK Programming Language, +Addison-Wesley, 1988. ISBN 0-201-07981-X +.SH BUGS +There are no explicit conversions between numbers and strings. +To force an expression to be treated as a number add 0 to it; +to force it to be treated as a string concatenate +\&\f(CW""\fP to it. +.br +The scope rules for variables in functions are a botch; +the syntax is worse. diff --git a/utils/awk/awk.h b/utils/awk/awk.h new file mode 100644 index 00000000..25fed144 --- /dev/null +++ b/utils/awk/awk.h @@ -0,0 +1,231 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +typedef double Awkfloat; + +/* unsigned char is more trouble than it's worth */ + +typedef unsigned char uschar; + +#define xfree(a) { if ((a) != NULL) { free((char *) a); a = NULL; } } + +#define DEBUG +#ifdef DEBUG + /* uses have to be doubly parenthesized */ +# define dprintf(x) if (dbg) printf x +#else +# define dprintf(x) +#endif + +extern char errbuf[]; + +extern int compile_time; /* 1 if compiling, 0 if running */ +extern int safe; /* 0 => unsafe, 1 => safe */ + +#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */ +extern int recsize; /* size of current record, orig RECSIZE */ + +extern char **FS; +extern char **RS; +extern char **ORS; +extern char **OFS; +extern char **OFMT; +extern Awkfloat *NR; +extern Awkfloat *FNR; +extern Awkfloat *NF; +extern char **FILENAME; +extern char **SUBSEP; +extern Awkfloat *RSTART; +extern Awkfloat *RLENGTH; + +extern char *record; /* points to $0 */ +extern int lineno; /* line number in awk program */ +extern int errorflag; /* 1 if error has occurred */ +extern int donefld; /* 1 if record broken into fields */ +extern int donerec; /* 1 if record is valid (no fld has changed */ +extern char inputFS[]; /* FS at time of input, for field splitting */ + +extern int dbg; + +extern char *patbeg; /* beginning of pattern matched */ +extern int patlen; /* length of pattern matched. set in b.c */ + +/* Cell: all information about a variable or constant */ + +typedef struct Cell { + uschar ctype; /* OCELL, OBOOL, OJUMP, etc. */ + uschar csub; /* CCON, CTEMP, CFLD, etc. */ + char *nval; /* name, for variables only */ + char *sval; /* string value */ + Awkfloat fval; /* value as number */ + int tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE */ + struct Cell *cnext; /* ptr to next if chained */ +} Cell; + +typedef struct Array { /* symbol table array */ + int nelem; /* elements in table right now */ + int size; /* size of tab */ + Cell **tab; /* hash table pointers */ +} Array; + +#define NSYMTAB 50 /* initial size of a symbol table */ +extern Array *symtab; + +extern Cell *nrloc; /* NR */ +extern Cell *fnrloc; /* FNR */ +extern Cell *nfloc; /* NF */ +extern Cell *rstartloc; /* RSTART */ +extern Cell *rlengthloc; /* RLENGTH */ + +/* Cell.tval values: */ +#define NUM 01 /* number value is valid */ +#define STR 02 /* string value is valid */ +#define DONTFREE 04 /* string space is not freeable */ +#define CON 010 /* this is a constant */ +#define ARR 020 /* this is an array */ +#define FCN 040 /* this is a function name */ +#define FLD 0100 /* this is a field $1, $2, ... */ +#define REC 0200 /* this is $0 */ + + +/* function types */ +#define FLENGTH 1 +#define FSQRT 2 +#define FEXP 3 +#define FLOG 4 +#define FINT 5 +#define FSYSTEM 6 +#define FRAND 7 +#define FSRAND 8 +#define FSIN 9 +#define FCOS 10 +#define FATAN 11 +#define FTOUPPER 12 +#define FTOLOWER 13 +#define FFLUSH 14 + +/* Node: parse tree is made of nodes, with Cell's at bottom */ + +typedef struct Node { + int ntype; + struct Node *nnext; + int lineno; + int nobj; + struct Node *narg[1]; /* variable: actual size set by calling malloc */ +} Node; + +#define NIL ((Node *) 0) + +extern Node *winner; +extern Node *nullstat; +extern Node *nullnode; + +/* ctypes */ +#define OCELL 1 +#define OBOOL 2 +#define OJUMP 3 + +/* Cell subtypes: csub */ +#define CFREE 7 +#define CCOPY 6 +#define CCON 5 +#define CTEMP 4 +#define CNAME 3 +#define CVAR 2 +#define CFLD 1 +#define CUNK 0 + +/* bool subtypes */ +#define BTRUE 11 +#define BFALSE 12 + +/* jump subtypes */ +#define JEXIT 21 +#define JNEXT 22 +#define JBREAK 23 +#define JCONT 24 +#define JRET 25 +#define JNEXTFILE 26 + +/* node types */ +#define NVALUE 1 +#define NSTAT 2 +#define NEXPR 3 + + +extern int pairstack[], paircnt; + +#define notlegal(n) (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN] == nullproc) +#define isvalue(n) ((n)->ntype == NVALUE) +#define isexpr(n) ((n)->ntype == NEXPR) +#define isjump(n) ((n)->ctype == OJUMP) +#define isexit(n) ((n)->csub == JEXIT) +#define isbreak(n) ((n)->csub == JBREAK) +#define iscont(n) ((n)->csub == JCONT) +#define isnext(n) ((n)->csub == JNEXT || (n)->csub == JNEXTFILE) +#define isret(n) ((n)->csub == JRET) +#define isrec(n) ((n)->tval & REC) +#define isfld(n) ((n)->tval & FLD) +#define isstr(n) ((n)->tval & STR) +#define isnum(n) ((n)->tval & NUM) +#define isarr(n) ((n)->tval & ARR) +#define isfcn(n) ((n)->tval & FCN) +#define istrue(n) ((n)->csub == BTRUE) +#define istemp(n) ((n)->csub == CTEMP) +#define isargument(n) ((n)->nobj == ARG) +/* #define freeable(p) (!((p)->tval & DONTFREE)) */ +#define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR ) + +/* structures used by regular expression matching machinery, mostly b.c: */ + +#define NCHARS (256+1) /* 256 handles 8-bit chars; 128 does 7-bit */ + /* watch out in match(), etc. */ +#define NSTATES 32 + +typedef struct rrow { + long ltype; /* long avoids pointer warnings on 64-bit */ + union { + int i; + Node *np; + uschar *up; + } lval; /* because Al stores a pointer in it! */ + int *lfollow; +} rrow; + +typedef struct fa { + uschar gototab[NSTATES][NCHARS]; + uschar out[NSTATES]; + uschar *restr; + int *posns[NSTATES]; + int anchor; + int use; + int initstat; + int curstat; + int accept; + int reset; + struct rrow re[1]; /* variable: actual size set by calling malloc */ +} fa; + + +#include "proto.h" diff --git a/utils/awk/awkgram.y b/utils/awk/awkgram.y new file mode 100644 index 00000000..f9f6fd28 --- /dev/null +++ b/utils/awk/awkgram.y @@ -0,0 +1,486 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +%{ +#include <stdio.h> +#include <string.h> +#include "awk.h" + +void checkdup(Node *list, Cell *item); +int yywrap(void) { return(1); } + +Node *beginloc = 0; +Node *endloc = 0; +int infunc = 0; /* = 1 if in arglist or body of func */ +int inloop = 0; /* = 1 if in while, for, do */ +char *curfname = 0; /* current function name */ +Node *arglist = 0; /* list of args for current function */ +%} + +%union { + Node *p; + Cell *cp; + int i; + char *s; +} + +%token <i> FIRSTTOKEN /* must be first */ +%token <p> PROGRAM PASTAT PASTAT2 XBEGIN XEND +%token <i> NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']' +%token <i> ARRAY +%token <i> MATCH NOTMATCH MATCHOP +%token <i> FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS +%token <i> AND BOR APPEND EQ GE GT LE LT NE IN +%token <i> ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC +%token <i> SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE +%token <i> ADD MINUS MULT DIVIDE MOD +%token <i> ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ +%token <i> PRINT PRINTF SPRINTF +%token <p> ELSE INTEST CONDEXPR +%token <i> POSTINCR PREINCR POSTDECR PREDECR +%token <cp> VAR IVAR VARNF CALL NUMBER STRING +%token <s> REGEXPR + +%type <p> pas pattern ppattern plist pplist patlist prarg term re +%type <p> pa_pat pa_stat pa_stats +%type <s> reg_expr +%type <p> simple_stmt opt_simple_stmt stmt stmtlist +%type <p> var varname funcname varlist +%type <p> for if else while +%type <i> do st +%type <i> pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor +%type <i> subop print + +%right ASGNOP +%right '?' +%right ':' +%left BOR +%left AND +%left GETLINE +%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|' +%left ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC +%left GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER +%left PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR +%left REGEXPR VAR VARNF IVAR WHILE '(' +%left CAT +%left '+' '-' +%left '*' '/' '%' +%left NOT UMINUS +%right POWER +%right DECR INCR +%left INDIRECT +%token LASTTOKEN /* must be last */ + +%% + +program: + pas { if (errorflag==0) + winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); } + | error { yyclearin; bracecheck(); SYNTAX("bailing out"); } + ; + +and: + AND | and NL + ; + +bor: + BOR | bor NL + ; + +comma: + ',' | comma NL + ; + +do: + DO | do NL + ; + +else: + ELSE | else NL + ; + +for: + FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt + { --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); } + | FOR '(' opt_simple_stmt ';' ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt + { --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); } + | FOR '(' varname IN varname rparen {inloop++;} stmt + { --inloop; $$ = stat3(IN, $3, makearr($5), $8); } + ; + +funcname: + VAR { setfname($1); } + | CALL { setfname($1); } + ; + +if: + IF '(' pattern rparen { $$ = notnull($3); } + ; + +lbrace: + '{' | lbrace NL + ; + +nl: + NL | nl NL + ; + +opt_nl: + /* empty */ { $$ = 0; } + | nl + ; + +opt_pst: + /* empty */ { $$ = 0; } + | pst + ; + + +opt_simple_stmt: + /* empty */ { $$ = 0; } + | simple_stmt + ; + +pas: + opt_pst { $$ = 0; } + | opt_pst pa_stats opt_pst { $$ = $2; } + ; + +pa_pat: + pattern { $$ = notnull($1); } + ; + +pa_stat: + pa_pat { $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); } + | pa_pat lbrace stmtlist '}' { $$ = stat2(PASTAT, $1, $3); } + | pa_pat ',' pa_pat { $$ = pa2stat($1, $3, stat2(PRINT, rectonode(), NIL)); } + | pa_pat ',' pa_pat lbrace stmtlist '}' { $$ = pa2stat($1, $3, $5); } + | lbrace stmtlist '}' { $$ = stat2(PASTAT, NIL, $2); } + | XBEGIN lbrace stmtlist '}' + { beginloc = linkum(beginloc, $3); $$ = 0; } + | XEND lbrace stmtlist '}' + { endloc = linkum(endloc, $3); $$ = 0; } + | FUNC funcname '(' varlist rparen {infunc++;} lbrace stmtlist '}' + { infunc--; curfname=0; defn((Cell *)$2, $4, $8); $$ = 0; } + ; + +pa_stats: + pa_stat + | pa_stats opt_pst pa_stat { $$ = linkum($1, $3); } + ; + +patlist: + pattern + | patlist comma pattern { $$ = linkum($1, $3); } + ; + +ppattern: + var ASGNOP ppattern { $$ = op2($2, $1, $3); } + | ppattern '?' ppattern ':' ppattern %prec '?' + { $$ = op3(CONDEXPR, notnull($1), $3, $5); } + | ppattern bor ppattern %prec BOR + { $$ = op2(BOR, notnull($1), notnull($3)); } + | ppattern and ppattern %prec AND + { $$ = op2(AND, notnull($1), notnull($3)); } + | ppattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); } + | ppattern MATCHOP ppattern + { if (constnode($3)) + $$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0)); + else + $$ = op3($2, (Node *)1, $1, $3); } + | ppattern IN varname { $$ = op2(INTEST, $1, makearr($3)); } + | '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); } + | ppattern term %prec CAT { $$ = op2(CAT, $1, $2); } + | re + | term + ; + +pattern: + var ASGNOP pattern { $$ = op2($2, $1, $3); } + | pattern '?' pattern ':' pattern %prec '?' + { $$ = op3(CONDEXPR, notnull($1), $3, $5); } + | pattern bor pattern %prec BOR + { $$ = op2(BOR, notnull($1), notnull($3)); } + | pattern and pattern %prec AND + { $$ = op2(AND, notnull($1), notnull($3)); } + | pattern EQ pattern { $$ = op2($2, $1, $3); } + | pattern GE pattern { $$ = op2($2, $1, $3); } + | pattern GT pattern { $$ = op2($2, $1, $3); } + | pattern LE pattern { $$ = op2($2, $1, $3); } + | pattern LT pattern { $$ = op2($2, $1, $3); } + | pattern NE pattern { $$ = op2($2, $1, $3); } + | pattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); } + | pattern MATCHOP pattern + { if (constnode($3)) + $$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0)); + else + $$ = op3($2, (Node *)1, $1, $3); } + | pattern IN varname { $$ = op2(INTEST, $1, makearr($3)); } + | '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); } + | pattern '|' GETLINE var { + if (safe) SYNTAX("cmd | getline is unsafe"); + else $$ = op3(GETLINE, $4, itonp($2), $1); } + | pattern '|' GETLINE { + if (safe) SYNTAX("cmd | getline is unsafe"); + else $$ = op3(GETLINE, (Node*)0, itonp($2), $1); } + | pattern term %prec CAT { $$ = op2(CAT, $1, $2); } + | re + | term + ; + +plist: + pattern comma pattern { $$ = linkum($1, $3); } + | plist comma pattern { $$ = linkum($1, $3); } + ; + +pplist: + ppattern + | pplist comma ppattern { $$ = linkum($1, $3); } + ; + +prarg: + /* empty */ { $$ = rectonode(); } + | pplist + | '(' plist ')' { $$ = $2; } + ; + +print: + PRINT | PRINTF + ; + +pst: + NL | ';' | pst NL | pst ';' + ; + +rbrace: + '}' | rbrace NL + ; + +re: + reg_expr + { $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); } + | NOT re { $$ = op1(NOT, notnull($2)); } + ; + +reg_expr: + '/' {startreg();} REGEXPR '/' { $$ = $3; } + ; + +rparen: + ')' | rparen NL + ; + +simple_stmt: + print prarg '|' term { + if (safe) SYNTAX("print | is unsafe"); + else $$ = stat3($1, $2, itonp($3), $4); } + | print prarg APPEND term { + if (safe) SYNTAX("print >> is unsafe"); + else $$ = stat3($1, $2, itonp($3), $4); } + | print prarg GT term { + if (safe) SYNTAX("print > is unsafe"); + else $$ = stat3($1, $2, itonp($3), $4); } + | print prarg { $$ = stat3($1, $2, NIL, NIL); } + | DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); } + | DELETE varname { $$ = stat2(DELETE, makearr($2), 0); } + | pattern { $$ = exptostat($1); } + | error { yyclearin; SYNTAX("illegal statement"); } + ; + +st: + nl + | ';' opt_nl + ; + +stmt: + BREAK st { if (!inloop) SYNTAX("break illegal outside of loops"); + $$ = stat1(BREAK, NIL); } + | CONTINUE st { if (!inloop) SYNTAX("continue illegal outside of loops"); + $$ = stat1(CONTINUE, NIL); } + | do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st + { $$ = stat2(DO, $3, notnull($7)); } + | EXIT pattern st { $$ = stat1(EXIT, $2); } + | EXIT st { $$ = stat1(EXIT, NIL); } + | for + | if stmt else stmt { $$ = stat3(IF, $1, $2, $4); } + | if stmt { $$ = stat3(IF, $1, $2, NIL); } + | lbrace stmtlist rbrace { $$ = $2; } + | NEXT st { if (infunc) + SYNTAX("next is illegal inside a function"); + $$ = stat1(NEXT, NIL); } + | NEXTFILE st { if (infunc) + SYNTAX("nextfile is illegal inside a function"); + $$ = stat1(NEXTFILE, NIL); } + | RETURN pattern st { $$ = stat1(RETURN, $2); } + | RETURN st { $$ = stat1(RETURN, NIL); } + | simple_stmt st + | while {inloop++;} stmt { --inloop; $$ = stat2(WHILE, $1, $3); } + | ';' opt_nl { $$ = 0; } + ; + +stmtlist: + stmt + | stmtlist stmt { $$ = linkum($1, $2); } + ; + +subop: + SUB | GSUB + ; + +term: + term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); } + | term '+' term { $$ = op2(ADD, $1, $3); } + | term '-' term { $$ = op2(MINUS, $1, $3); } + | term '*' term { $$ = op2(MULT, $1, $3); } + | term '/' term { $$ = op2(DIVIDE, $1, $3); } + | term '%' term { $$ = op2(MOD, $1, $3); } + | term POWER term { $$ = op2(POWER, $1, $3); } + | '-' term %prec UMINUS { $$ = op1(UMINUS, $2); } + | '+' term %prec UMINUS { $$ = $2; } + | NOT term %prec UMINUS { $$ = op1(NOT, notnull($2)); } + | BLTIN '(' ')' { $$ = op2(BLTIN, itonp($1), rectonode()); } + | BLTIN '(' patlist ')' { $$ = op2(BLTIN, itonp($1), $3); } + | BLTIN { $$ = op2(BLTIN, itonp($1), rectonode()); } + | CALL '(' ')' { $$ = op2(CALL, celltonode($1,CVAR), NIL); } + | CALL '(' patlist ')' { $$ = op2(CALL, celltonode($1,CVAR), $3); } + | CLOSE term { $$ = op1(CLOSE, $2); } + | DECR var { $$ = op1(PREDECR, $2); } + | INCR var { $$ = op1(PREINCR, $2); } + | var DECR { $$ = op1(POSTDECR, $1); } + | var INCR { $$ = op1(POSTINCR, $1); } + | GETLINE var LT term { $$ = op3(GETLINE, $2, itonp($3), $4); } + | GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($2), $3); } + | GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); } + | GETLINE { $$ = op3(GETLINE, NIL, NIL, NIL); } + | INDEX '(' pattern comma pattern ')' + { $$ = op2(INDEX, $3, $5); } + | INDEX '(' pattern comma reg_expr ')' + { SYNTAX("index() doesn't permit regular expressions"); + $$ = op2(INDEX, $3, (Node*)$5); } + | '(' pattern ')' { $$ = $2; } + | MATCHFCN '(' pattern comma reg_expr ')' + { $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); } + | MATCHFCN '(' pattern comma pattern ')' + { if (constnode($5)) + $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1)); + else + $$ = op3(MATCHFCN, (Node *)1, $3, $5); } + | NUMBER { $$ = celltonode($1, CCON); } + | SPLIT '(' pattern comma varname comma pattern ')' /* string */ + { $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); } + | SPLIT '(' pattern comma varname comma reg_expr ')' /* const /regexp/ */ + { $$ = op4(SPLIT, $3, makearr($5), (Node*)makedfa($7, 1), (Node *)REGEXPR); } + | SPLIT '(' pattern comma varname ')' + { $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */ + | SPRINTF '(' patlist ')' { $$ = op1($1, $3); } + | STRING { $$ = celltonode($1, CCON); } + | subop '(' reg_expr comma pattern ')' + { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); } + | subop '(' pattern comma pattern ')' + { if (constnode($3)) + $$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode()); + else + $$ = op4($1, (Node *)1, $3, $5, rectonode()); } + | subop '(' reg_expr comma pattern comma var ')' + { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); } + | subop '(' pattern comma pattern comma var ')' + { if (constnode($3)) + $$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7); + else + $$ = op4($1, (Node *)1, $3, $5, $7); } + | SUBSTR '(' pattern comma pattern comma pattern ')' + { $$ = op3(SUBSTR, $3, $5, $7); } + | SUBSTR '(' pattern comma pattern ')' + { $$ = op3(SUBSTR, $3, $5, NIL); } + | var + ; + +var: + varname + | varname '[' patlist ']' { $$ = op2(ARRAY, makearr($1), $3); } + | IVAR { $$ = op1(INDIRECT, celltonode($1, CVAR)); } + | INDIRECT term { $$ = op1(INDIRECT, $2); } + ; + +varlist: + /* nothing */ { arglist = $$ = 0; } + | VAR { arglist = $$ = celltonode($1,CVAR); } + | varlist comma VAR { + checkdup($1, $3); + arglist = $$ = linkum($1,celltonode($3,CVAR)); } + ; + +varname: + VAR { $$ = celltonode($1, CVAR); } + | ARG { $$ = op1(ARG, itonp($1)); } + | VARNF { $$ = op1(VARNF, (Node *) $1); } + ; + + +while: + WHILE '(' pattern rparen { $$ = notnull($3); } + ; + +%% + +void setfname(Cell *p) +{ + if (isarr(p)) + SYNTAX("%s is an array, not a function", p->nval); + else if (isfcn(p)) + SYNTAX("you can't define function %s more than once", p->nval); + curfname = p->nval; +} + +int constnode(Node *p) +{ + return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON; +} + +char *strnode(Node *p) +{ + return ((Cell *)(p->narg[0]))->sval; +} + +Node *notnull(Node *n) +{ + switch (n->nobj) { + case LE: case LT: case EQ: case NE: case GT: case GE: + case BOR: case AND: case NOT: + return n; + default: + return op2(NE, n, nullnode); + } +} + +void checkdup(Node *vl, Cell *cp) /* check if name already in list */ +{ + char *s = cp->nval; + for ( ; vl; vl = vl->nnext) { + if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) { + SYNTAX("duplicate argument %s", s); + break; + } + } +} diff --git a/utils/awk/b.c b/utils/awk/b.c new file mode 100644 index 00000000..3153151f --- /dev/null +++ b/utils/awk/b.c @@ -0,0 +1,855 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +/* lasciate ogne speranza, voi ch'entrate. */ + +#define DEBUG + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "awk.h" +#include "ytab.h" + +#define HAT (NCHARS-2) /* matches ^ in regular expr */ + /* NCHARS is 2**n */ +#define MAXLIN 22 + +#define type(v) (v)->nobj /* badly overloaded here */ +#define info(v) (v)->ntype /* badly overloaded here */ +#define left(v) (v)->narg[0] +#define right(v) (v)->narg[1] +#define parent(v) (v)->nnext + +#define LEAF case CCL: case NCCL: case CHAR: case DOT: case FINAL: case ALL: +#define UNARY case STAR: case PLUS: case QUEST: + +/* encoding in tree Nodes: + leaf (CCL, NCCL, CHAR, DOT, FINAL, ALL): + left is index, right contains value or pointer to value + unary (STAR, PLUS, QUEST): left is child, right is null + binary (CAT, OR): left and right are children + parent contains pointer to parent +*/ + + +int *setvec; +int *tmpset; +int maxsetvec = 0; + +int rtok; /* next token in current re */ +int rlxval; +static uschar *rlxstr; +static uschar *prestr; /* current position in current re */ +static uschar *lastre; /* origin of last re */ + +static int setcnt; +static int poscnt; + +char *patbeg; +int patlen; + +#define NFA 20 /* cache this many dynamic fa's */ +fa *fatab[NFA]; +int nfatab = 0; /* entries in fatab */ + +fa *makedfa(char *s, int anchor) /* returns dfa for reg expr s */ +{ + int i, use, nuse; + fa *pfa; + static int now = 1; + + if (setvec == 0) { /* first time through any RE */ + maxsetvec = MAXLIN; + setvec = (int *) malloc(maxsetvec * sizeof(int)); + tmpset = (int *) malloc(maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("out of space initializing makedfa"); + } + + if (compile_time) /* a constant for sure */ + return mkdfa(s, anchor); + for (i = 0; i < nfatab; i++) /* is it there already? */ + if (fatab[i]->anchor == anchor + && strcmp(fatab[i]->restr, s) == 0) { + fatab[i]->use = now++; + return fatab[i]; + } + pfa = mkdfa(s, anchor); + if (nfatab < NFA) { /* room for another */ + fatab[nfatab] = pfa; + fatab[nfatab]->use = now++; + nfatab++; + return pfa; + } + use = fatab[0]->use; /* replace least-recently used */ + nuse = 0; + for (i = 1; i < nfatab; i++) + if (fatab[i]->use < use) { + use = fatab[i]->use; + nuse = i; + } + freefa(fatab[nuse]); + fatab[nuse] = pfa; + pfa->use = now++; + return pfa; +} + +fa *mkdfa(char *s, int anchor) /* does the real work of making a dfa */ + /* anchor = 1 for anchored matches, else 0 */ +{ + Node *p, *p1; + fa *f; + + p = reparse(s); + p1 = op2(CAT, op2(STAR, op2(ALL, NIL, NIL), NIL), p); + /* put ALL STAR in front of reg. exp. */ + p1 = op2(CAT, p1, op2(FINAL, NIL, NIL)); + /* put FINAL after reg. exp. */ + + poscnt = 0; + penter(p1); /* enter parent pointers and leaf indices */ + if ((f = (fa *) calloc(1, sizeof(fa) + poscnt*sizeof(rrow))) == NULL) + overflo("out of space for fa"); + f->accept = poscnt-1; /* penter has computed number of positions in re */ + cfoll(f, p1); /* set up follow sets */ + freetr(p1); + if ((f->posns[0] = (int *) calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL) + overflo("out of space in makedfa"); + if ((f->posns[1] = (int *) calloc(1, sizeof(int))) == NULL) + overflo("out of space in makedfa"); + *f->posns[1] = 0; + f->initstat = makeinit(f, anchor); + f->anchor = anchor; + f->restr = (uschar *) tostring(s); + return f; +} + +int makeinit(fa *f, int anchor) +{ + int i, k; + + f->curstat = 2; + f->out[2] = 0; + f->reset = 0; + k = *(f->re[0].lfollow); + xfree(f->posns[2]); + if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + overflo("out of space in makeinit"); + for (i=0; i <= k; i++) { + (f->posns[2])[i] = (f->re[0].lfollow)[i]; + } + if ((f->posns[2])[1] == f->accept) + f->out[2] = 1; + for (i=0; i < NCHARS; i++) + f->gototab[2][i] = 0; + f->curstat = cgoto(f, 2, HAT); + if (anchor) { + *f->posns[2] = k-1; /* leave out position 0 */ + for (i=0; i < k; i++) { + (f->posns[0])[i] = (f->posns[2])[i]; + } + + f->out[0] = f->out[2]; + if (f->curstat != 2) + --(*f->posns[f->curstat]); + } + return f->curstat; +} + +void penter(Node *p) /* set up parent pointers and leaf indices */ +{ + switch (type(p)) { + LEAF + info(p) = poscnt; + poscnt++; + break; + UNARY + penter(left(p)); + parent(left(p)) = p; + break; + case CAT: + case OR: + penter(left(p)); + penter(right(p)); + parent(left(p)) = p; + parent(right(p)) = p; + break; + default: /* can't happen */ + FATAL("can't happen: unknown type %d in penter", type(p)); + break; + } +} + +void freetr(Node *p) /* free parse tree */ +{ + switch (type(p)) { + LEAF + xfree(p); + break; + UNARY + freetr(left(p)); + xfree(p); + break; + case CAT: + case OR: + freetr(left(p)); + freetr(right(p)); + xfree(p); + break; + default: /* can't happen */ + FATAL("can't happen: unknown type %d in freetr", type(p)); + break; + } +} + +/* in the parsing of regular expressions, metacharacters like . have */ +/* to be seen literally; \056 is not a metacharacter. */ + +int hexstr(char **pp) /* find and eval hex string at pp, return new p */ +{ /* only pick up one 8-bit byte (2 chars) */ + uschar *p; + int n = 0; + int i; + + for (i = 0, p = (uschar *) *pp; i < 2 && isxdigit(*p); i++, p++) { + if (isdigit(*p)) + n = 16 * n + *p - '0'; + else if (*p >= 'a' && *p <= 'f') + n = 16 * n + *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + n = 16 * n + *p - 'A' + 10; + } + *pp = (char *) p; + return n; +} + +#define isoctdigit(c) ((c) >= '0' && (c) <= '7') /* multiple use of arg */ + +int quoted(char **pp) /* pick up next thing after a \\ */ + /* and increment *pp */ +{ + char *p = *pp; + int c; + + if ((c = *p++) == 't') + c = '\t'; + else if (c == 'n') + c = '\n'; + else if (c == 'f') + c = '\f'; + else if (c == 'r') + c = '\r'; + else if (c == 'b') + c = '\b'; + else if (c == '\\') + c = '\\'; + else if (c == 'x') { /* hexadecimal goo follows */ + c = hexstr(&p); /* this adds a null if number is invalid */ + } else if (isoctdigit(c)) { /* \d \dd \ddd */ + int n = c - '0'; + if (isoctdigit(*p)) { + n = 8 * n + *p++ - '0'; + if (isoctdigit(*p)) + n = 8 * n + *p++ - '0'; + } + c = n; + } /* else */ + /* c = c; */ + *pp = p; + return c; +} + +char *cclenter(char *argp) /* add a character class */ +{ + int i, c, c2; + uschar *p = (uschar *) argp; + uschar *op, *bp; + static uschar *buf = 0; + static int bufsz = 100; + + op = p; + if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL) + FATAL("out of space for character class [%.10s...] 1", p); + bp = buf; + for (i = 0; (c = *p++) != 0; ) { + if (c == '\\') { + c = quoted((char **) &p); + } else if (c == '-' && i > 0 && bp[-1] != 0) { + if (*p != 0) { + c = bp[-1]; + c2 = *p++; + if (c2 == '\\') + c2 = quoted((char **) &p); + if (c > c2) { /* empty; ignore */ + bp--; + i--; + continue; + } + while (c < c2) { + if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, 0)) + FATAL("out of space for character class [%.10s...] 2", p); + *bp++ = ++c; + i++; + } + continue; + } + } + if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, 0)) + FATAL("out of space for character class [%.10s...] 3", p); + *bp++ = c; + i++; + } + *bp = 0; + dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) ); + xfree(op); + return (char *) tostring((char *) buf); +} + +void overflo(char *s) +{ + FATAL("regular expression too big: %.30s...", s); +} + +void cfoll(fa *f, Node *v) /* enter follow set of each leaf of vertex v into lfollow[leaf] */ +{ + int i; + int *p; + + switch (type(v)) { + LEAF + f->re[info(v)].ltype = type(v); + f->re[info(v)].lval.np = right(v); + while (f->accept >= maxsetvec) { /* guessing here! */ + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("out of space in cfoll()"); + } + for (i = 0; i <= f->accept; i++) + setvec[i] = 0; + setcnt = 0; + follow(v); /* computes setvec and setcnt */ + if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL) + overflo("out of space building follow set"); + f->re[info(v)].lfollow = p; + *p = setcnt; + for (i = f->accept; i >= 0; i--) + if (setvec[i] == 1) + *++p = i; + break; + UNARY + cfoll(f,left(v)); + break; + case CAT: + case OR: + cfoll(f,left(v)); + cfoll(f,right(v)); + break; + default: /* can't happen */ + FATAL("can't happen: unknown type %d in cfoll", type(v)); + } +} + +int first(Node *p) /* collects initially active leaves of p into setvec */ + /* returns 1 if p matches empty string */ +{ + int b, lp; + + switch (type(p)) { + LEAF + lp = info(p); /* look for high-water mark of subscripts */ + while (setcnt >= maxsetvec || lp >= maxsetvec) { /* guessing here! */ + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("out of space in first()"); + } + if (setvec[lp] != 1) { + setvec[lp] = 1; + setcnt++; + } + if (type(p) == CCL && (*(char *) right(p)) == '\0') + return(0); /* empty CCL */ + else return(1); + case PLUS: + if (first(left(p)) == 0) return(0); + return(1); + case STAR: + case QUEST: + first(left(p)); + return(0); + case CAT: + if (first(left(p)) == 0 && first(right(p)) == 0) return(0); + return(1); + case OR: + b = first(right(p)); + if (first(left(p)) == 0 || b == 0) return(0); + return(1); + } + FATAL("can't happen: unknown type %d in first", type(p)); /* can't happen */ + return(-1); +} + +void follow(Node *v) /* collects leaves that can follow v into setvec */ +{ + Node *p; + + if (type(v) == FINAL) + return; + p = parent(v); + switch (type(p)) { + case STAR: + case PLUS: + first(v); + follow(p); + return; + + case OR: + case QUEST: + follow(p); + return; + + case CAT: + if (v == left(p)) { /* v is left child of p */ + if (first(right(p)) == 0) { + follow(p); + return; + } + } else /* v is right child */ + follow(p); + return; + } +} + +int member(int c, char *sarg) /* is c in s? */ +{ + uschar *s = (uschar *) sarg; + + while (*s) + if (c == *s++) + return(1); + return(0); +} + +int match(fa *f, char *p0) /* shortest match ? */ +{ + int s, ns; + uschar *p = (uschar *) p0; + + s = f->reset ? makeinit(f,0) : f->initstat; + if (f->out[s]) + return(1); + do { + if ((ns = f->gototab[s][*p]) != 0) + s = ns; + else + s = cgoto(f, s, *p); + if (f->out[s]) + return(1); + } while (*p++ != 0); + return(0); +} + +int pmatch(fa *f, char *p0) /* longest match, for sub */ +{ + int s, ns; + uschar *p = (uschar *) p0; + uschar *q; + int i, k; + + s = f->reset ? makeinit(f,1) : f->initstat; + patbeg = (char *) p; + patlen = -1; + do { + q = p; + do { + if (f->out[s]) /* final state */ + patlen = q-p; + if ((ns = f->gototab[s][*q]) != 0) + s = ns; + else + s = cgoto(f, s, *q); + if (s == 1) { /* no transition */ + if (patlen >= 0) { + patbeg = (char *) p; + return(1); + } + else + goto nextin; /* no match */ + } + } while (*q++ != 0); + if (f->out[s]) + patlen = q-p-1; /* don't count $ */ + if (patlen >= 0) { + patbeg = (char *) p; + return(1); + } + nextin: + s = 2; + if (f->reset) { + for (i = 2; i <= f->curstat; i++) + xfree(f->posns[i]); + k = *f->posns[0]; + if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + overflo("out of space in pmatch"); + for (i = 0; i <= k; i++) + (f->posns[2])[i] = (f->posns[0])[i]; + f->initstat = f->curstat = 2; + f->out[2] = f->out[0]; + for (i = 0; i < NCHARS; i++) + f->gototab[2][i] = 0; + } + } while (*p++ != 0); + return (0); +} + +int nematch(fa *f, char *p0) /* non-empty match, for sub */ +{ + int s, ns; + uschar *p = (uschar *) p0; + uschar *q; + int i, k; + + s = f->reset ? makeinit(f,1) : f->initstat; + patlen = -1; + while (*p) { + q = p; + do { + if (f->out[s]) /* final state */ + patlen = q-p; + if ((ns = f->gototab[s][*q]) != 0) + s = ns; + else + s = cgoto(f, s, *q); + if (s == 1) { /* no transition */ + if (patlen > 0) { + patbeg = (char *) p; + return(1); + } else + goto nnextin; /* no nonempty match */ + } + } while (*q++ != 0); + if (f->out[s]) + patlen = q-p-1; /* don't count $ */ + if (patlen > 0 ) { + patbeg = (char *) p; + return(1); + } + nnextin: + s = 2; + if (f->reset) { + for (i = 2; i <= f->curstat; i++) + xfree(f->posns[i]); + k = *f->posns[0]; + if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + overflo("out of state space"); + for (i = 0; i <= k; i++) + (f->posns[2])[i] = (f->posns[0])[i]; + f->initstat = f->curstat = 2; + f->out[2] = f->out[0]; + for (i = 0; i < NCHARS; i++) + f->gototab[2][i] = 0; + } + p++; + } + return (0); +} + +Node *reparse(char *p) /* parses regular expression pointed to by p */ +{ /* uses relex() to scan regular expression */ + Node *np; + + dprintf( ("reparse <%s>\n", p) ); + lastre = prestr = (uschar *) p; /* prestr points to string to be parsed */ + rtok = relex(); + if (rtok == '\0') + FATAL("empty regular expression"); + np = regexp(); + if (rtok != '\0') + FATAL("syntax error in regular expression %s at %s", lastre, prestr); + return(np); +} + +Node *regexp(void) /* top-level parse of reg expr */ +{ + return (alt(concat(primary()))); +} + +Node *primary(void) +{ + Node *np; + + switch (rtok) { + case CHAR: + np = op2(CHAR, NIL, itonp(rlxval)); + rtok = relex(); + return (unary(np)); + case ALL: + rtok = relex(); + return (unary(op2(ALL, NIL, NIL))); + case DOT: + rtok = relex(); + return (unary(op2(DOT, NIL, NIL))); + case CCL: + np = op2(CCL, NIL, (Node*) cclenter((char *) rlxstr)); + rtok = relex(); + return (unary(np)); + case NCCL: + np = op2(NCCL, NIL, (Node *) cclenter((char *) rlxstr)); + rtok = relex(); + return (unary(np)); + case '^': + rtok = relex(); + return (unary(op2(CHAR, NIL, itonp(HAT)))); + case '$': + rtok = relex(); + return (unary(op2(CHAR, NIL, NIL))); + case '(': + rtok = relex(); + if (rtok == ')') { /* special pleading for () */ + rtok = relex(); + return unary(op2(CCL, NIL, (Node *) tostring(""))); + } + np = regexp(); + if (rtok == ')') { + rtok = relex(); + return (unary(np)); + } + else + FATAL("syntax error in regular expression %s at %s", lastre, prestr); + default: + FATAL("illegal primary in regular expression %s at %s", lastre, prestr); + } + return 0; /*NOTREACHED*/ +} + +Node *concat(Node *np) +{ + switch (rtok) { + case CHAR: case DOT: case ALL: case CCL: case NCCL: case '$': case '(': + return (concat(op2(CAT, np, primary()))); + } + return (np); +} + +Node *alt(Node *np) +{ + if (rtok == OR) { + rtok = relex(); + return (alt(op2(OR, np, concat(primary())))); + } + return (np); +} + +Node *unary(Node *np) +{ + switch (rtok) { + case STAR: + rtok = relex(); + return (unary(op2(STAR, np, NIL))); + case PLUS: + rtok = relex(); + return (unary(op2(PLUS, np, NIL))); + case QUEST: + rtok = relex(); + return (unary(op2(QUEST, np, NIL))); + default: + return (np); + } +} + +int relex(void) /* lexical analyzer for reparse */ +{ + int c, n; + int cflag; + static uschar *buf = 0; + static int bufsz = 100; + uschar *bp; + + switch (c = *prestr++) { + case '|': return OR; + case '*': return STAR; + case '+': return PLUS; + case '?': return QUEST; + case '.': return DOT; + case '\0': prestr--; return '\0'; + case '^': + case '$': + case '(': + case ')': + return c; + case '\\': + rlxval = quoted((char **) &prestr); + return CHAR; + default: + rlxval = c; + return CHAR; + case '[': + if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL) + FATAL("out of space in reg expr %.10s..", lastre); + bp = buf; + if (*prestr == '^') { + cflag = 1; + prestr++; + } + else + cflag = 0; + n = 2 * strlen(prestr)+1; + if (!adjbuf((char **) &buf, &bufsz, n, n, (char **) &bp, 0)) + FATAL("out of space for reg expr %.10s...", lastre); + for (; ; ) { + if ((c = *prestr++) == '\\') { + *bp++ = '\\'; + if ((c = *prestr++) == '\0') + FATAL("nonterminated character class %.20s...", lastre); + *bp++ = c; + /* } else if (c == '\n') { */ + /* FATAL("newline in character class %.20s...", lastre); */ + } else if (c == '\0') { + FATAL("nonterminated character class %.20s", lastre); + } else if (bp == buf) { /* 1st char is special */ + *bp++ = c; + } else if (c == ']') { + *bp++ = 0; + rlxstr = (uschar *) tostring((char *) buf); + if (cflag == 0) + return CCL; + else + return NCCL; + } else + *bp++ = c; + } + } +} + +int cgoto(fa *f, int s, int c) +{ + int i, j, k; + int *p, *q; + + if (c < 0 || c > 255) + FATAL("can't happen: neg char %d in cgoto", c); + while (f->accept >= maxsetvec) { /* guessing here! */ + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("out of space in cgoto()"); + } + for (i = 0; i <= f->accept; i++) + setvec[i] = 0; + setcnt = 0; + /* compute positions of gototab[s,c] into setvec */ + p = f->posns[s]; + for (i = 1; i <= *p; i++) { + if ((k = f->re[p[i]].ltype) != FINAL) { + if ((k == CHAR && c == ptoi(f->re[p[i]].lval.np)) + || (k == DOT && c != 0 && c != HAT) + || (k == ALL && c != 0) + || (k == CCL && member(c, (char *) f->re[p[i]].lval.up)) + || (k == NCCL && !member(c, (char *) f->re[p[i]].lval.up) && c != 0 && c != HAT)) { + q = f->re[p[i]].lfollow; + for (j = 1; j <= *q; j++) { + if (q[j] >= maxsetvec) { + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(setvec, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("cgoto overflow"); + } + if (setvec[q[j]] == 0) { + setcnt++; + setvec[q[j]] = 1; + } + } + } + } + } + /* determine if setvec is a previous state */ + tmpset[0] = setcnt; + j = 1; + for (i = f->accept; i >= 0; i--) + if (setvec[i]) { + tmpset[j++] = i; + } + /* tmpset == previous state? */ + for (i = 1; i <= f->curstat; i++) { + p = f->posns[i]; + if ((k = tmpset[0]) != p[0]) + goto different; + for (j = 1; j <= k; j++) + if (tmpset[j] != p[j]) + goto different; + /* setvec is state i */ + f->gototab[s][c] = i; + return i; + different:; + } + + /* add tmpset to current set of states */ + if (f->curstat >= NSTATES-1) { + f->curstat = 2; + f->reset = 1; + for (i = 2; i < NSTATES; i++) + xfree(f->posns[i]); + } else + ++(f->curstat); + for (i = 0; i < NCHARS; i++) + f->gototab[f->curstat][i] = 0; + xfree(f->posns[f->curstat]); + if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL) + overflo("out of space in cgoto"); + + f->posns[f->curstat] = p; + f->gototab[s][c] = f->curstat; + for (i = 0; i <= setcnt; i++) + p[i] = tmpset[i]; + if (setvec[f->accept]) + f->out[f->curstat] = 1; + else + f->out[f->curstat] = 0; + return f->curstat; +} + + +void freefa(fa *f) /* free a finite automaton */ +{ + int i; + + if (f == NULL) + return; + for (i = 0; i <= f->curstat; i++) + xfree(f->posns[i]); + for (i = 0; i <= f->accept; i++) { + xfree(f->re[i].lfollow); + if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL) + xfree((f->re[i].lval.np)); + } + xfree(f->restr); + xfree(f); +} diff --git a/utils/awk/buildwin.bat b/utils/awk/buildwin.bat new file mode 100644 index 00000000..77513429 --- /dev/null +++ b/utils/awk/buildwin.bat @@ -0,0 +1,12 @@ +@echo off
+rem buildwin.bat - build AWK under Windows NT using Visual C++.
+rem 22 Jan 1999 - Created by Dan Allen.
+rem
+rem If you delete the call to setlocal it will probably work under Win95/Win98 as well.
+
+setlocal
+set cl=-w -Ox -QIfdiv- -nologo -link -nologo setargv.obj
+
+cl maketab.c -o maketab.exe
+maketab.exe > proctab.c
+cl -o awk.exe b.c main.c parse.c proctab.c tran.c lib.c run.c lex.c ytab.c missing95.c
diff --git a/utils/awk/lex.c b/utils/awk/lex.c new file mode 100644 index 00000000..a9471098 --- /dev/null +++ b/utils/awk/lex.c @@ -0,0 +1,571 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "awk.h" +#include "ytab.h" + +extern YYSTYPE yylval; +extern int infunc; + +int lineno = 1; +int bracecnt = 0; +int brackcnt = 0; +int parencnt = 0; + +typedef struct Keyword { + char *word; + int sub; + int type; +} Keyword; + +Keyword keywords[] ={ /* keep sorted: binary searched */ + { "BEGIN", XBEGIN, XBEGIN }, + { "END", XEND, XEND }, + { "NF", VARNF, VARNF }, + { "atan2", FATAN, BLTIN }, + { "break", BREAK, BREAK }, + { "close", CLOSE, CLOSE }, + { "continue", CONTINUE, CONTINUE }, + { "cos", FCOS, BLTIN }, + { "delete", DELETE, DELETE }, + { "do", DO, DO }, + { "else", ELSE, ELSE }, + { "exit", EXIT, EXIT }, + { "exp", FEXP, BLTIN }, + { "fflush", FFLUSH, BLTIN }, + { "for", FOR, FOR }, + { "func", FUNC, FUNC }, + { "function", FUNC, FUNC }, + { "getline", GETLINE, GETLINE }, + { "gsub", GSUB, GSUB }, + { "if", IF, IF }, + { "in", IN, IN }, + { "index", INDEX, INDEX }, + { "int", FINT, BLTIN }, + { "length", FLENGTH, BLTIN }, + { "log", FLOG, BLTIN }, + { "match", MATCHFCN, MATCHFCN }, + { "next", NEXT, NEXT }, + { "nextfile", NEXTFILE, NEXTFILE }, + { "print", PRINT, PRINT }, + { "printf", PRINTF, PRINTF }, + { "rand", FRAND, BLTIN }, + { "return", RETURN, RETURN }, + { "sin", FSIN, BLTIN }, + { "split", SPLIT, SPLIT }, + { "sprintf", SPRINTF, SPRINTF }, + { "sqrt", FSQRT, BLTIN }, + { "srand", FSRAND, BLTIN }, + { "sub", SUB, SUB }, + { "substr", SUBSTR, SUBSTR }, + { "system", FSYSTEM, BLTIN }, + { "tolower", FTOLOWER, BLTIN }, + { "toupper", FTOUPPER, BLTIN }, + { "while", WHILE, WHILE }, +}; + +#define DEBUG +#ifdef DEBUG +#define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); } +#else +#define RET(x) return(x) +#endif + +int peek(void) +{ + int c = input(); + unput(c); + return c; +} + +int gettok(char **pbuf, int *psz) /* get next input token */ +{ + int c; + char *buf = *pbuf; + int sz = *psz; + char *bp = buf; + + c = input(); + if (c == 0) + return 0; + buf[0] = c; + buf[1] = 0; + if (!isalnum(c) && c != '.' && c != '_') + return c; + + *bp++ = c; + if (isalpha(c) || c == '_') { /* it's a varname */ + for ( ; (c = input()) != 0; ) { + if (bp-buf >= sz) + if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) + FATAL( "out of space for name %.10s...", buf ); + if (isalnum(c) || c == '_') + *bp++ = c; + else { + *bp = 0; + unput(c); + break; + } + } + *bp = 0; + } else { /* it's a number */ + char *rem; + /* read input until can't be a number */ + for ( ; (c = input()) != 0; ) { + if (bp-buf >= sz) + if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) + FATAL( "out of space for number %.10s...", buf ); + if (isdigit(c) || c == 'e' || c == 'E' + || c == '.' || c == '+' || c == '-') + *bp++ = c; + else { + unput(c); + break; + } + } + *bp = 0; + strtod(buf, &rem); /* parse the number */ + unputstr(rem); /* put rest back for later */ + rem[0] = 0; + } + *pbuf = buf; + *psz = sz; + return buf[0]; +} + +int word(char *); +int string(void); +int regexpr(void); +int sc = 0; /* 1 => return a } right now */ +int reg = 0; /* 1 => return a REGEXPR now */ + +int yylex(void) +{ + int c; + static char *buf = 0; + static int bufsize = 500; + + if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL) + FATAL( "out of space in yylex" ); + if (sc) { + sc = 0; + RET('}'); + } + if (reg) { + reg = 0; + return regexpr(); + } + for (;;) { + c = gettok(&buf, &bufsize); + if (c == 0) + return 0; + if (isalpha(c) || c == '_') + return word(buf); + if (isdigit(c) || c == '.') { + yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab); + /* should this also have STR set? */ + RET(NUMBER); + } + + yylval.i = c; + switch (c) { + case '\n': /* {EOL} */ + RET(NL); + case '\r': /* assume \n is coming */ + case ' ': /* {WS}+ */ + case '\t': + break; + case '#': /* #.* strip comments */ + while ((c = input()) != '\n' && c != 0) + ; + unput(c); + break; + case ';': + RET(';'); + case '\\': + if (peek() == '\n') { + input(); + } else if (peek() == '\r') { + input(); input(); /* \n */ + lineno++; + } else { + RET(c); + } + break; + case '&': + if (peek() == '&') { + input(); RET(AND); + } else + RET('&'); + case '|': + if (peek() == '|') { + input(); RET(BOR); + } else + RET('|'); + case '!': + if (peek() == '=') { + input(); yylval.i = NE; RET(NE); + } else if (peek() == '~') { + input(); yylval.i = NOTMATCH; RET(MATCHOP); + } else + RET(NOT); + case '~': + yylval.i = MATCH; + RET(MATCHOP); + case '<': + if (peek() == '=') { + input(); yylval.i = LE; RET(LE); + } else { + yylval.i = LT; RET(LT); + } + case '=': + if (peek() == '=') { + input(); yylval.i = EQ; RET(EQ); + } else { + yylval.i = ASSIGN; RET(ASGNOP); + } + case '>': + if (peek() == '=') { + input(); yylval.i = GE; RET(GE); + } else if (peek() == '>') { + input(); yylval.i = APPEND; RET(APPEND); + } else { + yylval.i = GT; RET(GT); + } + case '+': + if (peek() == '+') { + input(); yylval.i = INCR; RET(INCR); + } else if (peek() == '=') { + input(); yylval.i = ADDEQ; RET(ASGNOP); + } else + RET('+'); + case '-': + if (peek() == '-') { + input(); yylval.i = DECR; RET(DECR); + } else if (peek() == '=') { + input(); yylval.i = SUBEQ; RET(ASGNOP); + } else + RET('-'); + case '*': + if (peek() == '=') { /* *= */ + input(); yylval.i = MULTEQ; RET(ASGNOP); + } else if (peek() == '*') { /* ** or **= */ + input(); /* eat 2nd * */ + if (peek() == '=') { + input(); yylval.i = POWEQ; RET(ASGNOP); + } else { + RET(POWER); + } + } else + RET('*'); + case '/': + RET('/'); + case '%': + if (peek() == '=') { + input(); yylval.i = MODEQ; RET(ASGNOP); + } else + RET('%'); + case '^': + if (peek() == '=') { + input(); yylval.i = POWEQ; RET(ASGNOP); + } else + RET(POWER); + + case '$': + /* BUG: awkward, if not wrong */ + c = gettok(&buf, &bufsize); + if (isalpha(c)) { + if (strcmp(buf, "NF") == 0) { /* very special */ + unputstr("(NF)"); + RET(INDIRECT); + } + c = peek(); + if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) { + unputstr(buf); + RET(INDIRECT); + } + yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab); + RET(IVAR); + } else { + unputstr(buf); + RET(INDIRECT); + } + + case '}': + if (--bracecnt < 0) + SYNTAX( "extra }" ); + sc = 1; + RET(';'); + case ']': + if (--brackcnt < 0) + SYNTAX( "extra ]" ); + RET(']'); + case ')': + if (--parencnt < 0) + SYNTAX( "extra )" ); + RET(')'); + case '{': + bracecnt++; + RET('{'); + case '[': + brackcnt++; + RET('['); + case '(': + parencnt++; + RET('('); + + case '"': + return string(); /* BUG: should be like tran.c ? */ + + default: + RET(c); + } + } +} + +int string(void) +{ + int c, n; + char *s, *bp; + static char *buf = 0; + static int bufsz = 500; + + if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of space for strings"); + for (bp = buf; (c = input()) != '"'; ) { + if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0)) + FATAL("out of space for string %.10s...", buf); + switch (c) { + case '\n': + case '\r': + case 0: + SYNTAX( "non-terminated string %.10s...", buf ); + lineno++; + break; + case '\\': + c = input(); + switch (c) { + case '"': *bp++ = '"'; break; + case 'n': *bp++ = '\n'; break; + case 't': *bp++ = '\t'; break; + case 'f': *bp++ = '\f'; break; + case 'r': *bp++ = '\r'; break; + case 'b': *bp++ = '\b'; break; + case 'v': *bp++ = '\v'; break; + case 'a': *bp++ = '\007'; break; + case '\\': *bp++ = '\\'; break; + + case '0': case '1': case '2': /* octal: \d \dd \ddd */ + case '3': case '4': case '5': case '6': case '7': + n = c - '0'; + if ((c = peek()) >= '0' && c < '8') { + n = 8 * n + input() - '0'; + if ((c = peek()) >= '0' && c < '8') + n = 8 * n + input() - '0'; + } + *bp++ = n; + break; + + case 'x': /* hex \x0-9a-fA-F + */ + { char xbuf[100], *px; + for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) { + if (isdigit(c) + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')) + *px++ = c; + else + break; + } + *px = 0; + unput(c); + sscanf(xbuf, "%x", &n); + *bp++ = n; + break; + } + + default: + *bp++ = c; + break; + } + break; + default: + *bp++ = c; + break; + } + } + *bp = 0; + s = tostring(buf); + *bp++ = ' '; *bp++ = 0; + yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab); + RET(STRING); +} + + +int binsearch(char *w, Keyword *kp, int n) +{ + int cond, low, mid, high; + + low = 0; + high = n - 1; + while (low <= high) { + mid = (low + high) / 2; + if ((cond = strcmp(w, kp[mid].word)) < 0) + high = mid - 1; + else if (cond > 0) + low = mid + 1; + else + return mid; + } + return -1; +} + +int word(char *w) +{ + Keyword *kp; + int c, n; + + n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0])); + kp = keywords + n; + if (n != -1) { /* found in table */ + yylval.i = kp->sub; + switch (kp->type) { /* special handling */ + case FSYSTEM: + if (safe) + SYNTAX( "system is unsafe" ); + RET(kp->type); + case FUNC: + if (infunc) + SYNTAX( "illegal nested function" ); + RET(kp->type); + case RETURN: + if (!infunc) + SYNTAX( "return not in function" ); + RET(kp->type); + case VARNF: + yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab); + RET(VARNF); + default: + RET(kp->type); + } + } + c = peek(); /* look for '(' */ + if (c != '(' && infunc && (n=isarg(w)) >= 0) { + yylval.i = n; + RET(ARG); + } else { + yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab); + if (c == '(') { + RET(CALL); + } else { + RET(VAR); + } + } +} + +void startreg(void) /* next call to yyles will return a regular expression */ +{ + reg = 1; +} + +int regexpr(void) +{ + int c; + static char *buf = 0; + static int bufsz = 500; + char *bp; + + if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of space for rex expr"); + bp = buf; + for ( ; (c = input()) != '/' && c != 0; ) { + if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0)) + FATAL("out of space for reg expr %.10s...", buf); + if (c == '\n') { + SYNTAX( "newline in regular expression %.10s...", buf ); + unput('\n'); + break; + } else if (c == '\\') { + *bp++ = '\\'; + *bp++ = input(); + } else { + *bp++ = c; + } + } + *bp = 0; + yylval.s = tostring(buf); + unput('/'); + RET(REGEXPR); +} + +/* low-level lexical stuff, sort of inherited from lex */ + +char ebuf[300]; +char *ep = ebuf; +char yysbuf[100]; /* pushback buffer */ +char *yysptr = yysbuf; +FILE *yyin = 0; + +int input(void) /* get next lexical input character */ +{ + int c; + extern char *lexprog; + + if (yysptr > yysbuf) + c = *--yysptr; + else if (lexprog != NULL) { /* awk '...' */ + if ((c = *lexprog) != 0) + lexprog++; + } else /* awk -f ... */ + c = pgetc(); + if (c == '\n') + lineno++; + else if (c == EOF) + c = 0; + if (ep >= ebuf + sizeof ebuf) + ep = ebuf; + return *ep++ = c; +} + +void unput(int c) /* put lexical character back on input */ +{ + if (c == '\n') + lineno--; + if (yysptr >= yysbuf + sizeof(yysbuf)) + FATAL("pushed back too much: %.20s...", yysbuf); + *yysptr++ = c; + if (--ep < ebuf) + ep = ebuf + sizeof(ebuf) - 1; +} + +void unputstr(char *s) /* put a string back on input */ +{ + int i; + + for (i = strlen(s)-1; i >= 0; i--) + unput(s[i]); +} diff --git a/utils/awk/lib.c b/utils/awk/lib.c new file mode 100644 index 00000000..a44466f1 --- /dev/null +++ b/utils/awk/lib.c @@ -0,0 +1,682 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include "awk.h" +#include "ytab.h" + +FILE *infile = NULL; +char *file = ""; +char *record; +int recsize = RECSIZE; +char *fields; +int fieldssize = RECSIZE; + +Cell **fldtab; /* pointers to Cells */ +char inputFS[100] = " "; + +#define MAXFLD 200 +int nfields = MAXFLD; /* last allocated slot for $i */ + +int donefld; /* 1 = implies rec broken into fields */ +int donerec; /* 1 = record is valid (no flds have changed) */ + +int lastfld = 0; /* last used field */ +int argno = 1; /* current input argument number */ +extern Awkfloat *ARGC; + +static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; +static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; + +void recinit(unsigned int n) +{ + record = (char *) malloc(n); + fields = (char *) malloc(n); + fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *)); + if (record == NULL || fields == NULL || fldtab == NULL) + FATAL("out of space for $0 and fields"); + + fldtab[0] = (Cell *) malloc(sizeof (Cell)); + *fldtab[0] = dollar0; + fldtab[0]->sval = record; + fldtab[0]->nval = tostring("0"); + makefields(1, nfields); +} + +void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ +{ + char temp[50]; + int i; + + for (i = n1; i <= n2; i++) { + fldtab[i] = (Cell *) malloc(sizeof (struct Cell)); + if (fldtab[i] == NULL) + FATAL("out of space in makefields %d", i); + *fldtab[i] = dollar1; + sprintf(temp, "%d", i); + fldtab[i]->nval = tostring(temp); + } +} + +void initgetrec(void) +{ + int i; + char *p; + + for (i = 1; i < *ARGC; i++) { + if (!isclvar(p = getargv(i))) { /* find 1st real filename */ + setsval(lookup("FILENAME", symtab), getargv(i)); + return; + } + setclvar(p); /* a commandline assignment before filename */ + argno++; + } + infile = stdin; /* no filenames, so use stdin */ +} + +int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */ +{ /* note: cares whether buf == record */ + int c; + static int firsttime = 1; + char *buf = *pbuf; + int bufsize = *pbufsize; + + if (firsttime) { + firsttime = 0; + initgetrec(); + } + dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", + *RS, *FS, *ARGC, *FILENAME) ); + if (isrecord) { + donefld = 0; + donerec = 1; + } + buf[0] = 0; + while (argno < *ARGC || infile == stdin) { + dprintf( ("argno=%d, file=|%s|\n", argno, file) ); + if (infile == NULL) { /* have to open a new file */ + file = getargv(argno); + if (*file == '\0') { /* it's been zapped */ + argno++; + continue; + } + if (isclvar(file)) { /* a var=value arg */ + setclvar(file); + argno++; + continue; + } + *FILENAME = file; + dprintf( ("opening file %s\n", file) ); + if (*file == '-' && *(file+1) == '\0') + infile = stdin; + else if ((infile = fopen(file, "r")) == NULL) + FATAL("can't open file %s", file); + setfval(fnrloc, 0.0); + } + c = readrec(&buf, &bufsize, infile); + if (c != 0 || buf[0] != '\0') { /* normal record */ + if (isrecord) { + if (freeable(fldtab[0])) + xfree(fldtab[0]->sval); + fldtab[0]->sval = buf; /* buf == record */ + fldtab[0]->tval = REC | STR | DONTFREE; + if (is_number(fldtab[0]->sval)) { + fldtab[0]->fval = atof(fldtab[0]->sval); + fldtab[0]->tval |= NUM; + } + } + setfval(nrloc, nrloc->fval+1); + setfval(fnrloc, fnrloc->fval+1); + *pbuf = buf; + *pbufsize = bufsize; + return 1; + } + /* EOF arrived on this file; set up next */ + if (infile != stdin) + fclose(infile); + infile = NULL; + argno++; + } + *pbuf = buf; + *pbufsize = bufsize; + return 0; /* true end of file */ +} + +void nextfile(void) +{ + if (infile != stdin) + fclose(infile); + infile = NULL; + argno++; +} + +int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */ +{ + int sep, c; + char *rr, *buf = *pbuf; + int bufsize = *pbufsize; + + if (strlen(*FS) >= sizeof(inputFS)) + FATAL("field separator %.10s... is too long", *FS); + strcpy(inputFS, *FS); /* for subsequent field splitting */ + if ((sep = **RS) == 0) { + sep = '\n'; + while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ + ; + if (c != EOF) + ungetc(c, inf); + } + for (rr = buf; ; ) { + for (; (c=getc(inf)) != sep && c != EOF; ) { + if (rr-buf+1 > bufsize) + if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1")) + FATAL("input record `%.30s...' too long", buf); + *rr++ = c; + } + if (**RS == sep || c == EOF) + break; + if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ + break; + if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2")) + FATAL("input record `%.30s...' too long", buf); + *rr++ = '\n'; + *rr++ = c; + } + if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) + FATAL("input record `%.30s...' too long", buf); + *rr = 0; + dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) ); + *pbuf = buf; + *pbufsize = bufsize; + return c == EOF && rr == buf ? 0 : 1; +} + +char *getargv(int n) /* get ARGV[n] */ +{ + Cell *x; + char *s, temp[50]; + extern Array *ARGVtab; + + sprintf(temp, "%d", n); + x = setsymtab(temp, "", 0.0, STR, ARGVtab); + s = getsval(x); + dprintf( ("getargv(%d) returns |%s|\n", n, s) ); + return s; +} + +void setclvar(char *s) /* set var=value from s */ +{ + char *p; + Cell *q; + + for (p=s; *p != '='; p++) + ; + *p++ = 0; + p = qstring(p, '\0'); + q = setsymtab(s, p, 0.0, STR, symtab); + setsval(q, p); + if (is_number(q->sval)) { + q->fval = atof(q->sval); + q->tval |= NUM; + } + dprintf( ("command line set %s to |%s|\n", s, p) ); +} + + +void fldbld(void) /* create fields from current record */ +{ + /* this relies on having fields[] the same length as $0 */ + /* the fields are all stored in this one array with \0's */ + char *r, *fr, sep; + Cell *p; + int i, j, n; + + if (donefld) + return; + if (!isstr(fldtab[0])) + getsval(fldtab[0]); + r = fldtab[0]->sval; + n = strlen(r); + if (n > fieldssize) { + xfree(fields); + if ((fields = (char *) malloc(n+1)) == NULL) + FATAL("out of space for fields in fldbld %d", n); + fieldssize = n; + } + fr = fields; + i = 0; /* number of fields accumulated here */ + if (strlen(inputFS) > 1) { /* it's a regular expression */ + i = refldbld(r, inputFS); + } else if ((sep = *inputFS) == ' ') { /* default whitespace */ + for (i = 0; ; ) { + while (*r == ' ' || *r == '\t' || *r == '\n') + r++; + if (*r == 0) + break; + i++; + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + fldtab[i]->sval = fr; + fldtab[i]->tval = FLD | STR | DONTFREE; + do + *fr++ = *r++; + while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); + *fr++ = 0; + } + *fr = 0; + } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ + for (i = 0; *r != 0; r++) { + char buf[2]; + i++; + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + buf[0] = *r; + buf[1] = 0; + fldtab[i]->sval = tostring(buf); + fldtab[i]->tval = FLD | STR; + } + *fr = 0; + } else if (*r != 0) { /* if 0, it's a null field */ + for (;;) { + i++; + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + fldtab[i]->sval = fr; + fldtab[i]->tval = FLD | STR | DONTFREE; + while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */ + *fr++ = *r++; + *fr++ = 0; + if (*r++ == 0) + break; + } + *fr = 0; + } + if (i > nfields) + FATAL("record `%.30s...' has too many fields; can't happen", r); + cleanfld(i+1, lastfld); /* clean out junk from previous record */ + lastfld = i; + donefld = 1; + for (j = 1; j <= lastfld; j++) { + p = fldtab[j]; + if(is_number(p->sval)) { + p->fval = atof(p->sval); + p->tval |= NUM; + } + } + setfval(nfloc, (Awkfloat) lastfld); + if (dbg) { + for (j = 0; j <= lastfld; j++) { + p = fldtab[j]; + printf("field %d (%s): |%s|\n", j, p->nval, p->sval); + } + } +} + +void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ +{ /* nvals remain intact */ + Cell *p; + int i; + + for (i = n1; i <= n2; i++) { + p = fldtab[i]; + if (freeable(p)) + xfree(p->sval); + p->sval = ""; + p->tval = FLD | STR | DONTFREE; + } +} + +void newfld(int n) /* add field n after end of existing lastfld */ +{ + if (n > nfields) + growfldtab(n); + cleanfld(lastfld+1, n); + lastfld = n; + setfval(nfloc, (Awkfloat) n); +} + +Cell *fieldadr(int n) /* get nth field */ +{ + if (n < 0) + FATAL("trying to access field %d", n); + if (n > nfields) /* fields after NF are empty */ + growfldtab(n); /* but does not increase NF */ + return(fldtab[n]); +} + +void growfldtab(int n) /* make new fields up to at least $n */ +{ + int nf = 2 * nfields; + + if (n > nf) + nf = n; + fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *))); + if (fldtab == NULL) + FATAL("out of space creating %d fields", nf); + makefields(nfields+1, nf); + nfields = nf; +} + +int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */ +{ + /* this relies on having fields[] the same length as $0 */ + /* the fields are all stored in this one array with \0's */ + char *fr; + int i, tempstat, n; + fa *pfa; + + n = strlen(rec); + if (n > fieldssize) { + xfree(fields); + if ((fields = (char *) malloc(n+1)) == NULL) + FATAL("out of space for fields in refldbld %d", n); + fieldssize = n; + } + fr = fields; + *fr = '\0'; + if (*rec == '\0') + return 0; + pfa = makedfa(fs, 1); + dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); + tempstat = pfa->initstat; + for (i = 1; ; i++) { + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + fldtab[i]->tval = FLD | STR | DONTFREE; + fldtab[i]->sval = fr; + dprintf( ("refldbld: i=%d\n", i) ); + if (nematch(pfa, rec)) { + pfa->initstat = 2; /* horrible coupling to b.c */ + dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); + strncpy(fr, rec, patbeg-rec); + fr += patbeg - rec + 1; + *(fr-1) = '\0'; + rec = patbeg + patlen; + } else { + dprintf( ("no match %s\n", rec) ); + strcpy(fr, rec); + pfa->initstat = tempstat; + break; + } + } + return i; +} + +void recbld(void) /* create $0 from $1..$NF if necessary */ +{ + int i; + char *r, *p; + + if (donerec == 1) + return; + r = record; + for (i = 1; i <= *NF; i++) { + p = getsval(fldtab[i]); + if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1")) + FATAL("created $0 `%.30s...' too long", record); + while ((*r = *p++) != 0) + r++; + if (i < *NF) { + if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2")) + FATAL("created $0 `%.30s...' too long", record); + for (p = *OFS; (*r = *p++) != 0; ) + r++; + } + } + if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) + FATAL("built giant record `%.30s...'", record); + *r = '\0'; + dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) ); + + if (freeable(fldtab[0])) + xfree(fldtab[0]->sval); + fldtab[0]->tval = REC | STR | DONTFREE; + fldtab[0]->sval = record; + + dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) ); + dprintf( ("recbld = |%s|\n", record) ); + donerec = 1; +} + +int errorflag = 0; + +void yyerror(char *s) +{ + SYNTAX(s); +} + +void SYNTAX(char *fmt, ...) +{ + extern char *cmdname, *curfname; + static int been_here = 0; + va_list varg; + + if (been_here++ > 2) + return; + fprintf(stderr, "%s: ", cmdname); + va_start(varg, fmt); + vfprintf(stderr, fmt, varg); + va_end(varg); + fprintf(stderr, " at source line %d", lineno); + if (curfname != NULL) + fprintf(stderr, " in function %s", curfname); + if (compile_time == 1 && cursource() != NULL) + fprintf(stderr, " source file %s", cursource()); + fprintf(stderr, "\n"); + errorflag = 2; + eprint(); +} + +void fpecatch(int n) +{ + FATAL("floating point exception %d", n); +} + +extern int bracecnt, brackcnt, parencnt; + +void bracecheck(void) +{ + int c; + static int beenhere = 0; + + if (beenhere++) + return; + while ((c = input()) != EOF && c != '\0') + bclass(c); + bcheck2(bracecnt, '{', '}'); + bcheck2(brackcnt, '[', ']'); + bcheck2(parencnt, '(', ')'); +} + +void bcheck2(int n, int c1, int c2) +{ + if (n == 1) + fprintf(stderr, "\tmissing %c\n", c2); + else if (n > 1) + fprintf(stderr, "\t%d missing %c's\n", n, c2); + else if (n == -1) + fprintf(stderr, "\textra %c\n", c2); + else if (n < -1) + fprintf(stderr, "\t%d extra %c's\n", -n, c2); +} + +void FATAL(char *fmt, ...) +{ + extern char *cmdname; + va_list varg; + + fflush(stdout); + fprintf(stderr, "%s: ", cmdname); + va_start(varg, fmt); + vfprintf(stderr, fmt, varg); + va_end(varg); + error(); + if (dbg > 1) /* core dump if serious debugging on */ + abort(); + exit(2); +} + +void WARNING(char *fmt, ...) +{ + extern char *cmdname; + va_list varg; + + fflush(stdout); + fprintf(stderr, "%s: ", cmdname); + va_start(varg, fmt); + vfprintf(stderr, fmt, varg); + va_end(varg); + error(); +} + +void error() +{ + extern Node *curnode; + + fprintf(stderr, "\n"); + if (compile_time != 2 && NR && *NR > 0) { + fprintf(stderr, " input record number %d", (int) (*FNR)); + if (strcmp(*FILENAME, "-") != 0) + fprintf(stderr, ", file %s", *FILENAME); + fprintf(stderr, "\n"); + } + if (compile_time != 2 && curnode) + fprintf(stderr, " source line number %d", curnode->lineno); + else if (compile_time != 2 && lineno) + fprintf(stderr, " source line number %d", lineno); + if (compile_time == 1 && cursource() != NULL) + fprintf(stderr, " source file %s", cursource()); + fprintf(stderr, "\n"); + eprint(); +} + +void eprint(void) /* try to print context around error */ +{ + char *p, *q; + int c; + static int been_here = 0; + extern char ebuf[], *ep; + + if (compile_time == 2 || compile_time == 0 || been_here++ > 0) + return; + p = ep - 1; + if (p > ebuf && *p == '\n') + p--; + for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) + ; + while (*p == '\n') + p++; + fprintf(stderr, " context is\n\t"); + for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) + ; + for ( ; p < q; p++) + if (*p) + putc(*p, stderr); + fprintf(stderr, " >>> "); + for ( ; p < ep; p++) + if (*p) + putc(*p, stderr); + fprintf(stderr, " <<< "); + if (*ep) + while ((c = input()) != '\n' && c != '\0' && c != EOF) { + putc(c, stderr); + bclass(c); + } + putc('\n', stderr); + ep = ebuf; +} + +void bclass(int c) +{ + switch (c) { + case '{': bracecnt++; break; + case '}': bracecnt--; break; + case '[': brackcnt++; break; + case ']': brackcnt--; break; + case '(': parencnt++; break; + case ')': parencnt--; break; + } +} + +double errcheck(double x, char *s) +{ + + if (errno == EDOM) { + errno = 0; + WARNING("%s argument out of domain", s); + x = 1; + } else if (errno == ERANGE) { + errno = 0; + WARNING("%s result out of range", s); + x = 1; + } + return x; +} + +int isclvar(char *s) /* is s of form var=something ? */ +{ + char *os = s; + + if (!isalpha((uschar) *s) && *s != '_') + return 0; + for ( ; *s; s++) + if (!(isalnum((uschar) *s) || *s == '_')) + break; + return *s == '=' && s > os && *(s+1) != '='; +} + +/* strtod is supposed to be a proper test of what's a valid number */ +/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ +/* wrong: violates 4.10.1.4 of ansi C standard */ + +#include <math.h> +int is_number(char *s) +{ + double r; + char *ep; + errno = 0; + r = strtod(s, &ep); + if (ep == s || r == HUGE_VAL || errno == ERANGE) + return 0; + while (*ep == ' ' || *ep == '\t' || *ep == '\n') + ep++; + if (*ep == '\0') + return 1; + else + return 0; +} diff --git a/utils/awk/mac.code b/utils/awk/mac.code new file mode 100644 index 00000000..269d2105 --- /dev/null +++ b/utils/awk/mac.code @@ -0,0 +1,65 @@ +This file contains a make shell script and a version +of the file missing95.c for the Mac, courtesy of +Dan Allen. + +make shell script: + +# MPW Shell script to build Awk using Apple's MRC compiler. +# 22 Jan 1999 - Created by Dan Allen. +# 25 Mar 1999 - Updated for newer Awk. +# +# Porting notes for the Mac: +# +# 1. main in main.c needs to have its prototype changed to: +# +# int main(int argc, char *argv[], char *environ[]) +# +# 2. popen and pclose in missing95.c need to have as their body the +# older style +# +# return NULL; +# +# as parallel pipes are not supported by MPW. +# +# 3. To make your Mac more responsive while long awk scripts run, +# you may want to add some SpinCursor calls to support cooperative multitasking. +# +# All of these minor changes can be put under "#ifdef powerc" for portability's sake. +# +# + +If {1} == "clean" + Delete -i awk maketab maketab.c.o ytab.c.o b.c.o main.c.o parse.c.o proctab.c proctab.c.o tran.c.o lib.c.o run.c.o lex.c.o missing95.c.o +Else + MRC ytab.c -w off -opt speed + MRC b.c -w off -opt speed + MRC main.c -w off -opt speed + MRC parse.c -w off -opt speed + MRC maketab.c -w off -opt speed + PPCLink -o maketab maketab.c.o "{PPCLibraries}InterfaceLib" "{PPCLibraries}MathLib" "{PPCLibraries}StdCLib" "{PPCLibraries}StdCRuntime.o" "{PPCLibraries}PPCCRuntime.o" "{PPCLibraries}PPCToolLibs.o" -t MPST -c 'MPS ' + maketab > proctab.c + MRC proctab.c -w off -opt speed + MRC tran.c -w off -opt speed + MRC lib.c -w off -opt speed + MRC run.c -w off -opt speed + MRC lex.c -w off -opt speed + MRC missing95.c -w off -opt speed + PPCLink -o awk ytab.c.o b.c.o main.c.o parse.c.o proctab.c.o tran.c.o lib.c.o run.c.o lex.c.o missing95.c.o "{PPCLibraries}InterfaceLib" "{PPCLibraries}MathLib" "{PPCLibraries}StdCLib" "{PPCLibraries}StdCRuntime.o" "{PPCLibraries}PPCCRuntime.o" "{PPCLibraries}PPCToolLibs.o" -d + SetFile awk -d . -m . -t MPST -c 'MPS ' +End + + +missing95.c for the Mac: + +/* popen and pclose are not available on the Mac. */ + +#include <stdio.h> + +FILE *popen(char *s, char *m) { + return NULL; +} + +int pclose(FILE *f) { + return NULL; +} + diff --git a/utils/awk/main.c b/utils/awk/main.c new file mode 100644 index 00000000..d807ca5b --- /dev/null +++ b/utils/awk/main.c @@ -0,0 +1,197 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +char *version = "version 20001115"; + +#define DEBUG +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include "awk.h" +#include "ytab.h" + +extern char **environ; +extern int nfields; + +int dbg = 0; +char *cmdname; /* gets argv[0] for error messages */ +extern FILE *yyin; /* lex input file */ +char *lexprog; /* points to program argument if it exists */ +extern int errorflag; /* non-zero if any syntax errors; set by yyerror */ +int compile_time = 2; /* for error printing: */ + /* 2 = cmdline, 1 = compile, 0 = running */ + +char *pfile[20]; /* program filenames from -f's */ +int npfile = 0; /* number of filenames */ +int curpfile = 0; /* current filename */ + +int safe = 0; /* 1 => "safe" mode */ + +int main(int argc, char *argv[]) +{ + char *fs = NULL, *marg; + int temp; + + cmdname = argv[0]; + if (argc == 1) { + fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname); + exit(1); + } + signal(SIGFPE, fpecatch); + yyin = NULL; + symtab = makesymtab(NSYMTAB); + while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') { + if (strcmp(argv[1], "--") == 0) { /* explicit end of args */ + argc--; + argv++; + break; + } + switch (argv[1][1]) { + case 's': + if (strcmp(argv[1], "-safe") == 0) + safe = 1; + break; + case 'f': /* next argument is program filename */ + argc--; + argv++; + if (argc <= 1) + FATAL("no program filename"); + pfile[npfile++] = argv[1]; + break; + case 'F': /* set field separator */ + if (argv[1][2] != 0) { /* arg is -Fsomething */ + if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */ + fs = "\t"; + else if (argv[1][2] != 0) + fs = &argv[1][2]; + } else { /* arg is -F something */ + argc--; argv++; + if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */ + fs = "\t"; + else if (argc > 1 && argv[1][0] != 0) + fs = &argv[1][0]; + } + if (fs == NULL || *fs == '\0') + WARNING("field separator FS is empty"); + break; + case 'v': /* -v a=1 to be done NOW. one -v for each */ + if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1])) + setclvar(argv[1]); + break; + case 'm': /* more memory: -mr=record, -mf=fields */ + /* no longer needed */ + marg = argv[1]; + if (argv[1][3]) + temp = atoi(&argv[1][3]); + else { + argv++; argc--; + temp = atoi(&argv[1][0]); + } + switch (marg[2]) { + case 'r': recsize = temp; break; + case 'f': nfields = temp; break; + default: FATAL("unknown option %s\n", marg); + } + break; + case 'd': + dbg = atoi(&argv[1][2]); + if (dbg == 0) + dbg = 1; + printf("awk %s\n", version); + break; + case 'V': /* added for exptools "standard" */ + printf("awk %s\n", version); + exit(0); + break; + default: + WARNING("unknown option %s ignored", argv[1]); + break; + } + argc--; + argv++; + } + /* argv[1] is now the first argument */ + if (npfile == 0) { /* no -f; first argument is program */ + if (argc <= 1) { + if (dbg) + exit(0); + FATAL("no program given"); + } + dprintf( ("program = |%s|\n", argv[1]) ); + lexprog = argv[1]; + argc--; + argv++; + } + recinit(recsize); + syminit(); + compile_time = 1; + argv[0] = cmdname; /* put prog name at front of arglist */ + dprintf( ("argc=%d, argv[0]=%s\n", argc, argv[0]) ); + arginit(argc, argv); + if (!safe) + envinit(environ); + yyparse(); + if (fs) + *FS = qstring(fs, '\0'); + dprintf( ("errorflag=%d\n", errorflag) ); + if (errorflag == 0) { + compile_time = 0; + run(winner); + } else + bracecheck(); + return(errorflag); +} + +int pgetc(void) /* get 1 character from awk program */ +{ + int c; + + for (;;) { + if (yyin == NULL) { + if (curpfile >= npfile) + return EOF; + if (strcmp(pfile[curpfile], "-") == 0) + yyin = stdin; + else if ((yyin = fopen(pfile[curpfile], "r")) == NULL) + FATAL("can't open file %s", pfile[curpfile]); + lineno = 1; + } + if ((c = getc(yyin)) != EOF) + return c; + if (yyin != stdin) + fclose(yyin); + yyin = NULL; + curpfile++; + } +} + +char *cursource(void) /* current source file name */ +{ + if (npfile > 0) + return pfile[curpfile]; + else + return NULL; +} diff --git a/utils/awk/makefile b/utils/awk/makefile new file mode 100644 index 00000000..86520c9e --- /dev/null +++ b/utils/awk/makefile @@ -0,0 +1,81 @@ +# /**************************************************************** +# Copyright (C) Lucent Technologies 1997 +# All Rights Reserved +# +# Permission to use, copy, modify, and distribute this software and +# its documentation for any purpose and without fee is hereby +# granted, provided that the above copyright notice appear in all +# copies and that both that the copyright notice and this +# permission notice and warranty disclaimer appear in supporting +# documentation, and that the name Lucent Technologies or any of +# its entities not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. +# +# LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +# IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +# THIS SOFTWARE. +# ****************************************************************/ + +CFLAGS = -g +CFLAGS = -O2 +CFLAGS = + +CC = gcc -Wall -g +CC = /opt/pure/purify/purify cc +CC = cc + +YACC = bison -y +YACC = yacc +YFLAGS = -d + +OFILES = b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o + +SOURCE = awk.h ytab.c ytab.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c lib.c run.c tran.c proctab.c missing95.c + +LISTING = awk.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c lib.c run.c tran.c missing95.c + +SHIP = README FIXES $(SOURCE) ytab[ch].bak makefile awk.1 buildwin.bat mac.code + +a.out: ytab.o $(OFILES) + $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC) -lm + +$(OFILES): awk.h ytab.h proto.h + +ytab.o: awk.h proto.h awkgram.y + $(YACC) $(YFLAGS) awkgram.y + mv y.tab.c ytab.c + mv y.tab.h ytab.h + $(CC) $(CFLAGS) -c ytab.c + +proctab.c: maketab + ./maketab >proctab.c + +maketab: ytab.h maketab.c + $(CC) $(CFLAGS) maketab.c -o maketab + +bundle: + @cp ytab.h ytabh.bak + @cp ytab.c ytabc.bak + @bundle $(SHIP) + +tar: + @cp ytab.h ytabh.bak + @cp ytab.c ytabc.bak + @bundle $(SHIP) >awk.shar + @tar cf awk.tar $(SHIP) + gzip awk.tar + ls -l awk.tar.gz + @zip awk.zip $(SHIP) + ls -l awk.zip + +names: + @echo $(LISTING) + +clean: + rm -f a.out *.o maketab # proctab.c diff --git a/utils/awk/maketab.c b/utils/awk/maketab.c new file mode 100644 index 00000000..10a038c4 --- /dev/null +++ b/utils/awk/maketab.c @@ -0,0 +1,168 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +/* + * this program makes the table to link function names + * and type indices that is used by execute() in run.c. + * it finds the indices in ytab.h, produced by yacc. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "awk.h" +#include "ytab.h" + +struct xx +{ int token; + char *name; + char *pname; +} proc[] = { + { PROGRAM, "program", NULL }, + { BOR, "boolop", " || " }, + { AND, "boolop", " && " }, + { NOT, "boolop", " !" }, + { NE, "relop", " != " }, + { EQ, "relop", " == " }, + { LE, "relop", " <= " }, + { LT, "relop", " < " }, + { GE, "relop", " >= " }, + { GT, "relop", " > " }, + { ARRAY, "array", NULL }, + { INDIRECT, "indirect", "$(" }, + { SUBSTR, "substr", "substr" }, + { SUB, "sub", "sub" }, + { GSUB, "gsub", "gsub" }, + { INDEX, "sindex", "sindex" }, + { SPRINTF, "awksprintf", "sprintf " }, + { ADD, "arith", " + " }, + { MINUS, "arith", " - " }, + { MULT, "arith", " * " }, + { DIVIDE, "arith", " / " }, + { MOD, "arith", " % " }, + { UMINUS, "arith", " -" }, + { POWER, "arith", " **" }, + { PREINCR, "incrdecr", "++" }, + { POSTINCR, "incrdecr", "++" }, + { PREDECR, "incrdecr", "--" }, + { POSTDECR, "incrdecr", "--" }, + { CAT, "cat", " " }, + { PASTAT, "pastat", NULL }, + { PASTAT2, "dopa2", NULL }, + { MATCH, "matchop", " ~ " }, + { NOTMATCH, "matchop", " !~ " }, + { MATCHFCN, "matchop", "matchop" }, + { INTEST, "intest", "intest" }, + { PRINTF, "awkprintf", "printf" }, + { PRINT, "printstat", "print" }, + { CLOSE, "closefile", "closefile" }, + { DELETE, "awkdelete", "awkdelete" }, + { SPLIT, "split", "split" }, + { ASSIGN, "assign", " = " }, + { ADDEQ, "assign", " += " }, + { SUBEQ, "assign", " -= " }, + { MULTEQ, "assign", " *= " }, + { DIVEQ, "assign", " /= " }, + { MODEQ, "assign", " %= " }, + { POWEQ, "assign", " ^= " }, + { CONDEXPR, "condexpr", " ?: " }, + { IF, "ifstat", "if(" }, + { WHILE, "whilestat", "while(" }, + { FOR, "forstat", "for(" }, + { DO, "dostat", "do" }, + { IN, "instat", "instat" }, + { NEXT, "jump", "next" }, + { NEXTFILE, "jump", "nextfile" }, + { EXIT, "jump", "exit" }, + { BREAK, "jump", "break" }, + { CONTINUE, "jump", "continue" }, + { RETURN, "jump", "ret" }, + { BLTIN, "bltin", "bltin" }, + { CALL, "call", "call" }, + { ARG, "arg", "arg" }, + { VARNF, "getnf", "NF" }, + { GETLINE, "getline", "getline" }, + { 0, "", "" }, +}; + +#define SIZE (LASTTOKEN - FIRSTTOKEN + 1) +char *table[SIZE]; +char *names[SIZE]; + +int main(int argc, char *argv[]) +{ + struct xx *p; + int i, n, tok; + char c; + FILE *fp; + char buf[200], name[200], def[200]; + + printf("#include <stdio.h>\n"); + printf("#include \"awk.h\"\n"); + printf("#include \"ytab.h\"\n\n"); + for (i = SIZE; --i >= 0; ) + names[i] = ""; + + if ((fp = fopen("ytab.h", "r")) == NULL) { + fprintf(stderr, "maketab can't open ytab.h!\n"); + exit(1); + } + printf("static char *printname[%d] = {\n", SIZE); + i = 0; + while (fgets(buf, sizeof buf, fp) != NULL) { + n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok); + if (c != '#' || (n != 4 && strcmp(def,"define") != 0)) /* not a valid #define */ + continue; + if (tok < FIRSTTOKEN || tok > LASTTOKEN) { + fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); + continue; + } + names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1); + strcpy(names[tok-FIRSTTOKEN], name); + printf("\t(char *) \"%s\",\t/* %d */\n", name, tok); + i++; + } + printf("};\n\n"); + + for (p=proc; p->token!=0; p++) + table[p->token-FIRSTTOKEN] = p->name; + printf("\nCell *(*proctab[%d])(Node **, int) = {\n", SIZE); + for (i=0; i<SIZE; i++) + if (table[i]==0) + printf("\tnullproc,\t/* %s */\n", names[i]); + else + printf("\t%s,\t/* %s */\n", table[i], names[i]); + printf("};\n\n"); + + printf("char *tokname(int n)\n"); /* print a tokname() function */ + printf("{\n"); + printf(" static char buf[100];\n\n"); + printf(" if (n < FIRSTTOKEN || n > LASTTOKEN) {\n"); + printf(" sprintf(buf, \"token %%d\", n);\n"); + printf(" return buf;\n"); + printf(" }\n"); + printf(" return printname[n-FIRSTTOKEN];\n"); + printf("}\n"); + return 0; +} diff --git a/utils/awk/missing95.c b/utils/awk/missing95.c new file mode 100644 index 00000000..64138ade --- /dev/null +++ b/utils/awk/missing95.c @@ -0,0 +1,12 @@ +/* popen and pclose are not part of win 95 and nt, + but it appears that _popen and _pclose "work". + if this won't load, use the return NULL statements. */ + +#include <stdio.h> +FILE *popen(char *s, char *m) { + return _popen(s, m); /* return NULL; */ +} + +int pclose(FILE *f) { + return _pclose(f); /* return NULL; */ +} diff --git a/utils/awk/mkfile b/utils/awk/mkfile new file mode 100644 index 00000000..78847147 --- /dev/null +++ b/utils/awk/mkfile @@ -0,0 +1,29 @@ +<../../mkconfig + +TARG=awk + +OFILES=\ + b.$O\ + lex.$O\ + lib.$O\ + main.$O\ + missing95.$O\ + parse.$O\ + proctab.$O\ + run.$O\ + tran.$O\ + ytab.$O\ + +HFILES=\ + awk.h\ + proto.h\ + ytab.h\ + +LIBS=bio # order is important + +CFLAGS=$CFLAGS -QIfdiv- +LDFLAGS=$LDFLAGS setargv.obj + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/awk/parse.c b/utils/awk/parse.c new file mode 100644 index 00000000..ec7faca8 --- /dev/null +++ b/utils/awk/parse.c @@ -0,0 +1,276 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "awk.h" +#include "ytab.h" + +Node *nodealloc(int n) +{ + Node *x; + + x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *)); + if (x == NULL) + FATAL("out of space in nodealloc"); + x->nnext = NULL; + x->lineno = lineno; + return(x); +} + +Node *exptostat(Node *a) +{ + a->ntype = NSTAT; + return(a); +} + +Node *node1(int a, Node *b) +{ + Node *x; + + x = nodealloc(1); + x->nobj = a; + x->narg[0]=b; + return(x); +} + +Node *node2(int a, Node *b, Node *c) +{ + Node *x; + + x = nodealloc(2); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + return(x); +} + +Node *node3(int a, Node *b, Node *c, Node *d) +{ + Node *x; + + x = nodealloc(3); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + return(x); +} + +Node *node4(int a, Node *b, Node *c, Node *d, Node *e) +{ + Node *x; + + x = nodealloc(4); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + x->narg[3] = e; + return(x); +} + +Node *stat1(int a, Node *b) +{ + Node *x; + + x = node1(a,b); + x->ntype = NSTAT; + return(x); +} + +Node *stat2(int a, Node *b, Node *c) +{ + Node *x; + + x = node2(a,b,c); + x->ntype = NSTAT; + return(x); +} + +Node *stat3(int a, Node *b, Node *c, Node *d) +{ + Node *x; + + x = node3(a,b,c,d); + x->ntype = NSTAT; + return(x); +} + +Node *stat4(int a, Node *b, Node *c, Node *d, Node *e) +{ + Node *x; + + x = node4(a,b,c,d,e); + x->ntype = NSTAT; + return(x); +} + +Node *op1(int a, Node *b) +{ + Node *x; + + x = node1(a,b); + x->ntype = NEXPR; + return(x); +} + +Node *op2(int a, Node *b, Node *c) +{ + Node *x; + + x = node2(a,b,c); + x->ntype = NEXPR; + return(x); +} + +Node *op3(int a, Node *b, Node *c, Node *d) +{ + Node *x; + + x = node3(a,b,c,d); + x->ntype = NEXPR; + return(x); +} + +Node *op4(int a, Node *b, Node *c, Node *d, Node *e) +{ + Node *x; + + x = node4(a,b,c,d,e); + x->ntype = NEXPR; + return(x); +} + +Node *celltonode(Cell *a, int b) +{ + Node *x; + + a->ctype = OCELL; + a->csub = b; + x = node1(0, (Node *) a); + x->ntype = NVALUE; + return(x); +} + +Node *rectonode(void) /* make $0 into a Node */ +{ + extern Cell *literal0; + return op1(INDIRECT, celltonode(literal0, CUNK)); +} + +Node *makearr(Node *p) +{ + Cell *cp; + + if (isvalue(p)) { + cp = (Cell *) (p->narg[0]); + if (isfcn(cp)) + SYNTAX( "%s is a function, not an array", cp->nval ); + else if (!isarr(cp)) { + xfree(cp->sval); + cp->sval = (char *) makesymtab(NSYMTAB); + cp->tval = ARR; + } + } + return p; +} + +#define PA2NUM 50 /* max number of pat,pat patterns allowed */ +int paircnt; /* number of them in use */ +int pairstack[PA2NUM]; /* state of each pat,pat */ + +Node *pa2stat(Node *a, Node *b, Node *c) /* pat, pat {...} */ +{ + Node *x; + + x = node4(PASTAT2, a, b, c, itonp(paircnt)); + if (paircnt++ >= PA2NUM) + SYNTAX( "limited to %d pat,pat statements", PA2NUM ); + x->ntype = NSTAT; + return(x); +} + +Node *linkum(Node *a, Node *b) +{ + Node *c; + + if (errorflag) /* don't link things that are wrong */ + return a; + if (a == NULL) + return(b); + else if (b == NULL) + return(a); + for (c = a; c->nnext != NULL; c = c->nnext) + ; + c->nnext = b; + return(a); +} + +void defn(Cell *v, Node *vl, Node *st) /* turn on FCN bit in definition, */ +{ /* body of function, arglist */ + Node *p; + int n; + + if (isarr(v)) { + SYNTAX( "`%s' is an array name and a function name", v->nval ); + return; + } + if (isarg(v->nval) != -1) { + SYNTAX( "`%s' is both function name and argument name", v->nval ); + return; + } + + v->tval = FCN; + v->sval = (char *) st; + n = 0; /* count arguments */ + for (p = vl; p; p = p->nnext) + n++; + v->fval = n; + dprintf( ("defining func %s (%d args)\n", v->nval, n) ); +} + +int isarg(char *s) /* is s in argument list for current function? */ +{ /* return -1 if not, otherwise arg # */ + extern Node *arglist; + Node *p = arglist; + int n; + + for (n = 0; p != 0; p = p->nnext, n++) + if (strcmp(((Cell *)(p->narg[0]))->nval, s) == 0) + return n; + return -1; +} + +int ptoi(void *p) /* convert pointer to integer */ +{ + return (int) (long) p; /* swearing that p fits, of course */ +} + +Node *itonp(int i) /* and vice versa */ +{ + return (Node *) (long) i; +} diff --git a/utils/awk/proctab.c b/utils/awk/proctab.c new file mode 100644 index 00000000..def5b67a --- /dev/null +++ b/utils/awk/proctab.c @@ -0,0 +1,205 @@ +#include <stdio.h> +#include "awk.h" +#include "ytab.h" + +static char *printname[92] = { + (char *) "FIRSTTOKEN", /* 57346 */ + (char *) "PROGRAM", /* 57347 */ + (char *) "PASTAT", /* 57348 */ + (char *) "PASTAT2", /* 57349 */ + (char *) "XBEGIN", /* 57350 */ + (char *) "XEND", /* 57351 */ + (char *) "NL", /* 57352 */ + (char *) "ARRAY", /* 57353 */ + (char *) "MATCH", /* 57354 */ + (char *) "NOTMATCH", /* 57355 */ + (char *) "MATCHOP", /* 57356 */ + (char *) "FINAL", /* 57357 */ + (char *) "DOT", /* 57358 */ + (char *) "ALL", /* 57359 */ + (char *) "CCL", /* 57360 */ + (char *) "NCCL", /* 57361 */ + (char *) "CHAR", /* 57362 */ + (char *) "OR", /* 57363 */ + (char *) "STAR", /* 57364 */ + (char *) "QUEST", /* 57365 */ + (char *) "PLUS", /* 57366 */ + (char *) "AND", /* 57367 */ + (char *) "BOR", /* 57368 */ + (char *) "APPEND", /* 57369 */ + (char *) "EQ", /* 57370 */ + (char *) "GE", /* 57371 */ + (char *) "GT", /* 57372 */ + (char *) "LE", /* 57373 */ + (char *) "LT", /* 57374 */ + (char *) "NE", /* 57375 */ + (char *) "IN", /* 57376 */ + (char *) "ARG", /* 57377 */ + (char *) "BLTIN", /* 57378 */ + (char *) "BREAK", /* 57379 */ + (char *) "CLOSE", /* 57380 */ + (char *) "CONTINUE", /* 57381 */ + (char *) "DELETE", /* 57382 */ + (char *) "DO", /* 57383 */ + (char *) "EXIT", /* 57384 */ + (char *) "FOR", /* 57385 */ + (char *) "FUNC", /* 57386 */ + (char *) "SUB", /* 57387 */ + (char *) "GSUB", /* 57388 */ + (char *) "IF", /* 57389 */ + (char *) "INDEX", /* 57390 */ + (char *) "LSUBSTR", /* 57391 */ + (char *) "MATCHFCN", /* 57392 */ + (char *) "NEXT", /* 57393 */ + (char *) "NEXTFILE", /* 57394 */ + (char *) "ADD", /* 57395 */ + (char *) "MINUS", /* 57396 */ + (char *) "MULT", /* 57397 */ + (char *) "DIVIDE", /* 57398 */ + (char *) "MOD", /* 57399 */ + (char *) "ASSIGN", /* 57400 */ + (char *) "ASGNOP", /* 57401 */ + (char *) "ADDEQ", /* 57402 */ + (char *) "SUBEQ", /* 57403 */ + (char *) "MULTEQ", /* 57404 */ + (char *) "DIVEQ", /* 57405 */ + (char *) "MODEQ", /* 57406 */ + (char *) "POWEQ", /* 57407 */ + (char *) "PRINT", /* 57408 */ + (char *) "PRINTF", /* 57409 */ + (char *) "SPRINTF", /* 57410 */ + (char *) "ELSE", /* 57411 */ + (char *) "INTEST", /* 57412 */ + (char *) "CONDEXPR", /* 57413 */ + (char *) "POSTINCR", /* 57414 */ + (char *) "PREINCR", /* 57415 */ + (char *) "POSTDECR", /* 57416 */ + (char *) "PREDECR", /* 57417 */ + (char *) "VAR", /* 57418 */ + (char *) "IVAR", /* 57419 */ + (char *) "VARNF", /* 57420 */ + (char *) "CALL", /* 57421 */ + (char *) "NUMBER", /* 57422 */ + (char *) "STRING", /* 57423 */ + (char *) "REGEXPR", /* 57424 */ + (char *) "GETLINE", /* 57425 */ + (char *) "RETURN", /* 57426 */ + (char *) "SPLIT", /* 57427 */ + (char *) "SUBSTR", /* 57428 */ + (char *) "WHILE", /* 57429 */ + (char *) "CAT", /* 57430 */ + (char *) "NOT", /* 57431 */ + (char *) "UMINUS", /* 57432 */ + (char *) "POWER", /* 57433 */ + (char *) "DECR", /* 57434 */ + (char *) "INCR", /* 57435 */ + (char *) "INDIRECT", /* 57436 */ + (char *) "LASTTOKEN", /* 57437 */ +}; + + +Cell *(*proctab[92])(Node **, int) = { + nullproc, /* FIRSTTOKEN */ + program, /* PROGRAM */ + pastat, /* PASTAT */ + dopa2, /* PASTAT2 */ + nullproc, /* XBEGIN */ + nullproc, /* XEND */ + nullproc, /* NL */ + array, /* ARRAY */ + matchop, /* MATCH */ + matchop, /* NOTMATCH */ + nullproc, /* MATCHOP */ + nullproc, /* FINAL */ + nullproc, /* DOT */ + nullproc, /* ALL */ + nullproc, /* CCL */ + nullproc, /* NCCL */ + nullproc, /* CHAR */ + nullproc, /* OR */ + nullproc, /* STAR */ + nullproc, /* QUEST */ + nullproc, /* PLUS */ + boolop, /* AND */ + boolop, /* BOR */ + nullproc, /* APPEND */ + relop, /* EQ */ + relop, /* GE */ + relop, /* GT */ + relop, /* LE */ + relop, /* LT */ + relop, /* NE */ + instat, /* IN */ + arg, /* ARG */ + bltin, /* BLTIN */ + jump, /* BREAK */ + closefile, /* CLOSE */ + jump, /* CONTINUE */ + awkdelete, /* DELETE */ + dostat, /* DO */ + jump, /* EXIT */ + forstat, /* FOR */ + nullproc, /* FUNC */ + sub, /* SUB */ + gsub, /* GSUB */ + ifstat, /* IF */ + sindex, /* INDEX */ + nullproc, /* LSUBSTR */ + matchop, /* MATCHFCN */ + jump, /* NEXT */ + jump, /* NEXTFILE */ + arith, /* ADD */ + arith, /* MINUS */ + arith, /* MULT */ + arith, /* DIVIDE */ + arith, /* MOD */ + assign, /* ASSIGN */ + nullproc, /* ASGNOP */ + assign, /* ADDEQ */ + assign, /* SUBEQ */ + assign, /* MULTEQ */ + assign, /* DIVEQ */ + assign, /* MODEQ */ + assign, /* POWEQ */ + printstat, /* PRINT */ + awkprintf, /* PRINTF */ + awksprintf, /* SPRINTF */ + nullproc, /* ELSE */ + intest, /* INTEST */ + condexpr, /* CONDEXPR */ + incrdecr, /* POSTINCR */ + incrdecr, /* PREINCR */ + incrdecr, /* POSTDECR */ + incrdecr, /* PREDECR */ + nullproc, /* VAR */ + nullproc, /* IVAR */ + getnf, /* VARNF */ + call, /* CALL */ + nullproc, /* NUMBER */ + nullproc, /* STRING */ + nullproc, /* REGEXPR */ + getline, /* GETLINE */ + jump, /* RETURN */ + split, /* SPLIT */ + substr, /* SUBSTR */ + whilestat, /* WHILE */ + cat, /* CAT */ + boolop, /* NOT */ + arith, /* UMINUS */ + arith, /* POWER */ + nullproc, /* DECR */ + nullproc, /* INCR */ + indirect, /* INDIRECT */ + nullproc, /* LASTTOKEN */ +}; + +char *tokname(int n) +{ + static char buf[100]; + + if (n < FIRSTTOKEN || n > LASTTOKEN) { + sprintf(buf, "token %d", n); + return buf; + } + return printname[n-FIRSTTOKEN]; +} diff --git a/utils/awk/proto.h b/utils/awk/proto.h new file mode 100644 index 00000000..45f2908d --- /dev/null +++ b/utils/awk/proto.h @@ -0,0 +1,194 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +extern int yywrap(void); +extern void setfname(Cell *); +extern int constnode(Node *); +extern char *strnode(Node *); +extern Node *notnull(Node *); +extern int yyparse(void); + +extern int yylex(void); +extern void startreg(void); +extern int input(void); +extern void unput(int); +extern void unputstr(char *); +extern int yylook(void); +extern int yyback(int *, int); +extern int yyinput(void); + +extern fa *makedfa(char *, int); +extern fa *mkdfa(char *, int); +extern int makeinit(fa *, int); +extern void penter(Node *); +extern void freetr(Node *); +extern int hexstr(char **); +extern int quoted(char **); +extern char *cclenter(char *); +extern void overflo(char *); +extern void cfoll(fa *, Node *); +extern int first(Node *); +extern void follow(Node *); +extern int member(int, char *); +extern int match(fa *, char *); +extern int pmatch(fa *, char *); +extern int nematch(fa *, char *); +extern Node *reparse(char *); +extern Node *regexp(void); +extern Node *primary(void); +extern Node *concat(Node *); +extern Node *alt(Node *); +extern Node *unary(Node *); +extern int relex(void); +extern int cgoto(fa *, int, int); +extern void freefa(fa *); + +extern int pgetc(void); +extern char *cursource(void); + +extern Node *nodealloc(int); +extern Node *exptostat(Node *); +extern Node *node1(int, Node *); +extern Node *node2(int, Node *, Node *); +extern Node *node3(int, Node *, Node *, Node *); +extern Node *node4(int, Node *, Node *, Node *, Node *); +extern Node *stat3(int, Node *, Node *, Node *); +extern Node *op2(int, Node *, Node *); +extern Node *op1(int, Node *); +extern Node *stat1(int, Node *); +extern Node *op3(int, Node *, Node *, Node *); +extern Node *op4(int, Node *, Node *, Node *, Node *); +extern Node *stat2(int, Node *, Node *); +extern Node *stat4(int, Node *, Node *, Node *, Node *); +extern Node *celltonode(Cell *, int); +extern Node *rectonode(void); +extern Node *makearr(Node *); +extern Node *pa2stat(Node *, Node *, Node *); +extern Node *linkum(Node *, Node *); +extern void defn(Cell *, Node *, Node *); +extern int isarg(char *); +extern char *tokname(int); +extern Cell *(*proctab[])(Node **, int); +extern int ptoi(void *); +extern Node *itonp(int); + +extern void syminit(void); +extern void arginit(int, char **); +extern void envinit(char **); +extern Array *makesymtab(int); +extern void freesymtab(Cell *); +extern void freeelem(Cell *, char *); +extern Cell *setsymtab(char *, char *, double, unsigned int, Array *); +extern int hash(char *, int); +extern void rehash(Array *); +extern Cell *lookup(char *, Array *); +extern double setfval(Cell *, double); +extern void funnyvar(Cell *, char *); +extern char *setsval(Cell *, char *); +extern double getfval(Cell *); +extern char *getsval(Cell *); +extern char *tostring(char *); +extern char *qstring(char *, int); + +extern void recinit(unsigned int); +extern void initgetrec(void); +extern void makefields(int, int); +extern void growfldtab(int n); +extern int getrec(char **, int *, int); +extern void nextfile(void); +extern int readrec(char **buf, int *bufsize, FILE *inf); +extern char *getargv(int); +extern void setclvar(char *); +extern void fldbld(void); +extern void cleanfld(int, int); +extern void newfld(int); +extern int refldbld(char *, char *); +extern void recbld(void); +extern Cell *fieldadr(int); +extern void yyerror(char *); +extern void fpecatch(int); +extern void bracecheck(void); +extern void bcheck2(int, int, int); +extern void SYNTAX(char *, ...); +extern void FATAL(char *, ...); +extern void WARNING(char *, ...); +extern void error(void); +extern void eprint(void); +extern void bclass(int); +extern double errcheck(double, char *); +extern int isclvar(char *); +extern int is_number(char *); + +extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, char *what); +extern void run(Node *); +extern Cell *execute(Node *); +extern Cell *program(Node **, int); +extern Cell *call(Node **, int); +extern Cell *copycell(Cell *); +extern Cell *arg(Node **, int); +extern Cell *jump(Node **, int); +extern Cell *getline(Node **, int); +extern Cell *getnf(Node **, int); +extern Cell *array(Node **, int); +extern Cell *awkdelete(Node **, int); +extern Cell *intest(Node **, int); +extern Cell *matchop(Node **, int); +extern Cell *boolop(Node **, int); +extern Cell *relop(Node **, int); +extern void tfree(Cell *); +extern Cell *gettemp(void); +extern Cell *field(Node **, int); +extern Cell *indirect(Node **, int); +extern Cell *substr(Node **, int); +extern Cell *sindex(Node **, int); +extern int format(char **, int *, char *, Node *); +extern Cell *awksprintf(Node **, int); +extern Cell *awkprintf(Node **, int); +extern Cell *arith(Node **, int); +extern double ipow(double, int); +extern Cell *incrdecr(Node **, int); +extern Cell *assign(Node **, int); +extern Cell *cat(Node **, int); +extern Cell *pastat(Node **, int); +extern Cell *dopa2(Node **, int); +extern Cell *split(Node **, int); +extern Cell *condexpr(Node **, int); +extern Cell *ifstat(Node **, int); +extern Cell *whilestat(Node **, int); +extern Cell *dostat(Node **, int); +extern Cell *forstat(Node **, int); +extern Cell *instat(Node **, int); +extern Cell *bltin(Node **, int); +extern Cell *printstat(Node **, int); +extern Cell *nullproc(Node **, int); +extern FILE *redirect(int, Node *); +extern FILE *openfile(int, char *); +extern char *filename(FILE *); +extern Cell *closefile(Node **, int); +extern void closeall(void); +extern Cell *sub(Node **, int); +extern Cell *gsub(Node **, int); + +extern FILE *popen(const char *, const char *); +extern int pclose(FILE *); diff --git a/utils/awk/run.c b/utils/awk/run.c new file mode 100644 index 00000000..a6cbb406 --- /dev/null +++ b/utils/awk/run.c @@ -0,0 +1,1891 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include <stdio.h> +#include <ctype.h> +#include <setjmp.h> +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include "awk.h" +#include "ytab.h" + +#define tempfree(x) if (istemp(x)) tfree(x); else + +/* +#undef tempfree + +void tempfree(Cell *p) { + if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) { + WARNING("bad csub %d in Cell %d %s", + p->csub, p->ctype, p->sval); + } + if (istemp(p)) + tfree(p); +} +*/ + +#ifdef _NFILE +#ifndef FOPEN_MAX +#define FOPEN_MAX _NFILE +#endif +#endif + +#ifndef FOPEN_MAX +#define FOPEN_MAX 40 /* max number of open files */ +#endif + +#ifndef RAND_MAX +#define RAND_MAX 32767 /* all that ansi guarantees */ +#endif + +jmp_buf env; +extern int pairstack[]; + +Node *winner = NULL; /* root of parse tree */ +Cell *tmps; /* free temporary cells for execution */ + +static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; +Cell *True = &truecell; +static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; +Cell *False = &falsecell; +static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; +Cell *jbreak = &breakcell; +static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; +Cell *jcont = &contcell; +static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; +Cell *jnext = &nextcell; +static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM }; +Cell *jnextfile = &nextfilecell; +static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; +Cell *jexit = &exitcell; +static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; +Cell *jret = &retcell; +static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE }; + +Node *curnode = NULL; /* the node being executed, for debugging */ + +/* buffer memory management */ +int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, + char *whatrtn) +/* pbuf: address of pointer to buffer being managed + * psiz: address of buffer size variable + * minlen: minimum length of buffer needed + * quantum: buffer size quantum + * pbptr: address of movable pointer into buffer, or 0 if none + * whatrtn: name of the calling routine if failure should cause fatal error + * + * return 0 for realloc failure, !=0 for success + */ +{ + if (minlen > *psiz) { + char *tbuf; + int rminlen = quantum ? minlen % quantum : 0; + int boff = pbptr ? *pbptr - *pbuf : 0; + /* round up to next multiple of quantum */ + if (rminlen) + minlen += quantum - rminlen; + tbuf = (char *) realloc(*pbuf, minlen); + if (tbuf == NULL) { + if (whatrtn) + FATAL("out of memory in %s", whatrtn); + return 0; + } + *pbuf = tbuf; + *psiz = minlen; + if (pbptr) + *pbptr = tbuf + boff; + } + return 1; +} + +void run(Node *a) /* execution of parse tree starts here */ +{ + extern void stdinit(void); + + stdinit(); + execute(a); + closeall(); +} + +Cell *execute(Node *u) /* execute a node of the parse tree */ +{ + Cell *(*proc)(Node **, int); + Cell *x; + Node *a; + + if (u == NULL) + return(True); + for (a = u; ; a = a->nnext) { + curnode = a; + if (isvalue(a)) { + x = (Cell *) (a->narg[0]); + if (isfld(x) && !donefld) + fldbld(); + else if (isrec(x) && !donerec) + recbld(); + return(x); + } + if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ + FATAL("illegal statement"); + proc = proctab[a->nobj-FIRSTTOKEN]; + x = (*proc)(a->narg, a->nobj); + if (isfld(x) && !donefld) + fldbld(); + else if (isrec(x) && !donerec) + recbld(); + if (isexpr(a)) + return(x); + if (isjump(x)) + return(x); + if (a->nnext == NULL) + return(x); + tempfree(x); + } +} + + +Cell *program(Node **a, int n) /* execute an awk program */ +{ /* a[0] = BEGIN, a[1] = body, a[2] = END */ + Cell *x; + + if (setjmp(env) != 0) + goto ex; + if (a[0]) { /* BEGIN */ + x = execute(a[0]); + if (isexit(x)) + return(True); + if (isjump(x)) + FATAL("illegal break, continue, next or nextfile from BEGIN"); + tempfree(x); + } + if (a[1] || a[2]) + while (getrec(&record, &recsize, 1) > 0) { + x = execute(a[1]); + if (isexit(x)) + break; + tempfree(x); + } + ex: + if (setjmp(env) != 0) /* handles exit within END */ + goto ex1; + if (a[2]) { /* END */ + x = execute(a[2]); + if (isbreak(x) || isnext(x) || iscont(x)) + FATAL("illegal break, continue, next or nextfile from END"); + tempfree(x); + } + ex1: + return(True); +} + +struct Frame { /* stack frame for awk function calls */ + int nargs; /* number of arguments in this call */ + Cell *fcncell; /* pointer to Cell for function */ + Cell **args; /* pointer to array of arguments after execute */ + Cell *retval; /* return value */ +}; + +#define NARGS 50 /* max args in a call */ + +struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ +int nframe = 0; /* number of frames allocated */ +struct Frame *fp = NULL; /* frame pointer. bottom level unused */ + +Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ +{ + static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; + int i, ncall, ndef; + Node *x; + Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ + Cell *y, *z, *fcn; + char *s; + + fcn = execute(a[0]); /* the function itself */ + s = fcn->nval; + if (!isfcn(fcn)) + FATAL("calling undefined function %s", s); + if (frame == NULL) { + fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); + if (frame == NULL) + FATAL("out of space for stack frames calling %s", s); + } + for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ + ncall++; + ndef = (int) fcn->fval; /* args in defn */ + dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) ); + if (ncall > ndef) + WARNING("function %s called with %d args, uses only %d", + s, ncall, ndef); + if (ncall + ndef > NARGS) + FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS); + for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ + dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) ); + y = execute(x); + oargs[i] = y; + dprintf( ("args[%d]: %s %f <%s>, t=%o\n", + i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) ); + if (isfcn(y)) + FATAL("can't use function %s as argument in %s", y->nval, s); + if (isarr(y)) + args[i] = y; /* arrays by ref */ + else + args[i] = copycell(y); + tempfree(y); + } + for ( ; i < ndef; i++) { /* add null args for ones not provided */ + args[i] = gettemp(); + *args[i] = newcopycell; + } + fp++; /* now ok to up frame */ + if (fp >= frame + nframe) { + int dfp = fp - frame; /* old index */ + frame = (struct Frame *) + realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); + if (frame == NULL) + FATAL("out of space for stack frames in %s", s); + fp = frame + dfp; + } + fp->fcncell = fcn; + fp->args = args; + fp->nargs = ndef; /* number defined with (excess are locals) */ + fp->retval = gettemp(); + + dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) ); + y = execute((Node *)(fcn->sval)); /* execute body */ + dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) ); + + for (i = 0; i < ndef; i++) { + Cell *t = fp->args[i]; + if (isarr(t)) { + if (t->csub == CCOPY) { + if (i >= ncall) { + freesymtab(t); + t->csub = CTEMP; + tempfree(t); + } else { + oargs[i]->tval = t->tval; + oargs[i]->tval &= ~(STR|NUM|DONTFREE); + oargs[i]->sval = t->sval; + tempfree(t); + } + } + } else if (t != y) { /* kludge to prevent freeing twice */ + t->csub = CTEMP; + tempfree(t); + } + } + tempfree(fcn); + if (isexit(y) || isnext(y)) + return y; + tempfree(y); /* this can free twice! */ + z = fp->retval; /* return value */ + dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); + fp--; + return(z); +} + +Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ +{ + Cell *y; + + y = gettemp(); + y->csub = CCOPY; /* prevents freeing until call is over */ + y->nval = x->nval; /* BUG? */ + if (isstr(x)) + y->sval = tostring(x->sval); + y->fval = x->fval; + y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ + /* is DONTFREE right? */ + return y; +} + +Cell *arg(Node **a, int n) /* nth argument of a function */ +{ + + n = ptoi(a[0]); /* argument number, counting from 0 */ + dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); + if (n+1 > fp->nargs) + FATAL("argument #%d of function %s was not supplied", + n+1, fp->fcncell->nval); + return fp->args[n]; +} + +Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ +{ + Cell *y; + + switch (n) { + case EXIT: + if (a[0] != NULL) { + y = execute(a[0]); + errorflag = (int) getfval(y); + tempfree(y); + } + longjmp(env, 1); + case RETURN: + if (a[0] != NULL) { + y = execute(a[0]); + if ((y->tval & (STR|NUM)) == (STR|NUM)) { + setsval(fp->retval, getsval(y)); + fp->retval->fval = getfval(y); + fp->retval->tval |= NUM; + } + else if (y->tval & STR) + setsval(fp->retval, getsval(y)); + else if (y->tval & NUM) + setfval(fp->retval, getfval(y)); + else /* can't happen */ + FATAL("bad type variable %d", y->tval); + tempfree(y); + } + return(jret); + case NEXT: + return(jnext); + case NEXTFILE: + nextfile(); + return(jnextfile); + case BREAK: + return(jbreak); + case CONTINUE: + return(jcont); + default: /* can't happen */ + FATAL("illegal jump type %d", n); + } + return 0; /* not reached */ +} + +Cell *getline(Node **a, int n) /* get next line from specific input */ +{ /* a[0] is variable, a[1] is operator, a[2] is filename */ + Cell *r, *x; + extern Cell **fldtab; + FILE *fp; + char *buf; + int bufsize = recsize; + int mode; + + if ((buf = (char *) malloc(bufsize)) == NULL) + FATAL("out of memory in getline"); + + fflush(stdout); /* in case someone is waiting for a prompt */ + r = gettemp(); + if (a[1] != NULL) { /* getline < file */ + x = execute(a[2]); /* filename */ + mode = ptoi(a[1]); + if (mode == '|') /* input pipe */ + mode = LE; /* arbitrary flag */ + fp = openfile(mode, getsval(x)); + tempfree(x); + if (fp == NULL) + n = -1; + else + n = readrec(&buf, &bufsize, fp); + if (n <= 0) { + ; + } else if (a[0] != NULL) { /* getline var <file */ + x = execute(a[0]); + setsval(x, buf); + tempfree(x); + } else { /* getline <file */ + setsval(fldtab[0], buf); + if (is_number(fldtab[0]->sval)) { + fldtab[0]->fval = atof(fldtab[0]->sval); + fldtab[0]->tval |= NUM; + } + } + } else { /* bare getline; use current input */ + if (a[0] == NULL) /* getline */ + n = getrec(&record, &recsize, 1); + else { /* getline var */ + n = getrec(&buf, &bufsize, 0); + x = execute(a[0]); + setsval(x, buf); + tempfree(x); + } + } + setfval(r, (Awkfloat) n); + free(buf); + return r; +} + +Cell *getnf(Node **a, int n) /* get NF */ +{ + if (donefld == 0) + fldbld(); + return (Cell *) a[0]; +} + +Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ +{ + Cell *x, *y, *z; + char *s; + Node *np; + char *buf; + int bufsz = recsize; + int nsub = strlen(*SUBSEP); + + if ((buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of memory in array"); + + x = execute(a[0]); /* Cell* for symbol table */ + buf[0] = 0; + for (np = a[1]; np; np = np->nnext) { + y = execute(np); /* subscript */ + s = getsval(y); + if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) + FATAL("out of memory for %s[%s...]", x->nval, buf); + strcat(buf, s); + if (np->nnext) + strcat(buf, *SUBSEP); + tempfree(y); + } + if (!isarr(x)) { + dprintf( ("making %s into an array\n", x->nval) ); + if (freeable(x)) + xfree(x->sval); + x->tval &= ~(STR|NUM|DONTFREE); + x->tval |= ARR; + x->sval = (char *) makesymtab(NSYMTAB); + } + z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); + z->ctype = OCELL; + z->csub = CVAR; + tempfree(x); + free(buf); + return(z); +} + +Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ +{ + Cell *x, *y; + Node *np; + char *s; + int nsub = strlen(*SUBSEP); + + x = execute(a[0]); /* Cell* for symbol table */ + if (!isarr(x)) + return True; + if (a[1] == 0) { /* delete the elements, not the table */ + freesymtab(x); + x->tval &= ~STR; + x->tval |= ARR; + x->sval = (char *) makesymtab(NSYMTAB); + } else { + int bufsz = recsize; + char *buf; + if ((buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of memory in adelete"); + buf[0] = 0; + for (np = a[1]; np; np = np->nnext) { + y = execute(np); /* subscript */ + s = getsval(y); + if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) + FATAL("out of memory deleting %s[%s...]", x->nval, buf); + strcat(buf, s); + if (np->nnext) + strcat(buf, *SUBSEP); + tempfree(y); + } + freeelem(x, buf); + free(buf); + } + tempfree(x); + return True; +} + +Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ +{ + Cell *x, *ap, *k; + Node *p; + char *buf; + char *s; + int bufsz = recsize; + int nsub = strlen(*SUBSEP); + + ap = execute(a[1]); /* array name */ + if (!isarr(ap)) { + dprintf( ("making %s into an array\n", ap->nval) ); + if (freeable(ap)) + xfree(ap->sval); + ap->tval &= ~(STR|NUM|DONTFREE); + ap->tval |= ARR; + ap->sval = (char *) makesymtab(NSYMTAB); + } + if ((buf = (char *) malloc(bufsz)) == NULL) { + FATAL("out of memory in intest"); + } + buf[0] = 0; + for (p = a[0]; p; p = p->nnext) { + x = execute(p); /* expr */ + s = getsval(x); + if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) + FATAL("out of memory deleting %s[%s...]", x->nval, buf); + strcat(buf, s); + tempfree(x); + if (p->nnext) + strcat(buf, *SUBSEP); + } + k = lookup(buf, (Array *) ap->sval); + tempfree(ap); + free(buf); + if (k == NULL) + return(False); + else + return(True); +} + + +Cell *matchop(Node **a, int n) /* ~ and match() */ +{ + Cell *x, *y; + char *s, *t; + int i; + fa *pfa; + int (*mf)(fa *, char *) = match, mode = 0; + + if (n == MATCHFCN) { + mf = pmatch; + mode = 1; + } + x = execute(a[1]); /* a[1] = target text */ + s = getsval(x); + if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ + i = (*mf)((fa *) a[2], s); + else { + y = execute(a[2]); /* a[2] = regular expr */ + t = getsval(y); + pfa = makedfa(t, mode); + i = (*mf)(pfa, s); + tempfree(y); + } + tempfree(x); + if (n == MATCHFCN) { + int start = patbeg - s + 1; + if (patlen < 0) + start = 0; + setfval(rstartloc, (Awkfloat) start); + setfval(rlengthloc, (Awkfloat) patlen); + x = gettemp(); + x->tval = NUM; + x->fval = start; + return x; + } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) + return(True); + else + return(False); +} + + +Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ +{ + Cell *x, *y; + int i; + + x = execute(a[0]); + i = istrue(x); + tempfree(x); + switch (n) { + case BOR: + if (i) return(True); + y = execute(a[1]); + i = istrue(y); + tempfree(y); + if (i) return(True); + else return(False); + case AND: + if ( !i ) return(False); + y = execute(a[1]); + i = istrue(y); + tempfree(y); + if (i) return(True); + else return(False); + case NOT: + if (i) return(False); + else return(True); + default: /* can't happen */ + FATAL("unknown boolean operator %d", n); + } + return 0; /*NOTREACHED*/ +} + +Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */ +{ + int i; + Cell *x, *y; + Awkfloat j; + + x = execute(a[0]); + y = execute(a[1]); + if (x->tval&NUM && y->tval&NUM) { + j = x->fval - y->fval; + i = j<0? -1: (j>0? 1: 0); + } else { + i = strcmp(getsval(x), getsval(y)); + } + tempfree(x); + tempfree(y); + switch (n) { + case LT: if (i<0) return(True); + else return(False); + case LE: if (i<=0) return(True); + else return(False); + case NE: if (i!=0) return(True); + else return(False); + case EQ: if (i == 0) return(True); + else return(False); + case GE: if (i>=0) return(True); + else return(False); + case GT: if (i>0) return(True); + else return(False); + default: /* can't happen */ + FATAL("unknown relational operator %d", n); + } + return 0; /*NOTREACHED*/ +} + +void tfree(Cell *a) /* free a tempcell */ +{ + if (freeable(a)) { + dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) ); + xfree(a->sval); + } + if (a == tmps) + FATAL("tempcell list is curdled"); + a->cnext = tmps; + tmps = a; +} + +Cell *gettemp(void) /* get a tempcell */ +{ int i; + Cell *x; + + if (!tmps) { + tmps = (Cell *) calloc(100, sizeof(Cell)); + if (!tmps) + FATAL("out of space for temporaries"); + for(i = 1; i < 100; i++) + tmps[i-1].cnext = &tmps[i]; + tmps[i-1].cnext = 0; + } + x = tmps; + tmps = x->cnext; + *x = tempcell; + return(x); +} + +Cell *indirect(Node **a, int n) /* $( a[0] ) */ +{ + Cell *x; + int m; + char *s; + + x = execute(a[0]); + m = (int) getfval(x); + if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ + FATAL("illegal field $(%s), name \"%s\"", s, x->nval); + /* BUG: can x->nval ever be null??? */ + tempfree(x); + x = fieldadr(m); + x->ctype = OCELL; /* BUG? why are these needed? */ + x->csub = CFLD; + return(x); +} + +Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ +{ + int k, m, n; + char *s; + int temp; + Cell *x, *y, *z = 0; + + x = execute(a[0]); + y = execute(a[1]); + if (a[2] != 0) + z = execute(a[2]); + s = getsval(x); + k = strlen(s) + 1; + if (k <= 1) { + tempfree(x); + tempfree(y); + if (a[2] != 0) { + tempfree(z); + } + x = gettemp(); + setsval(x, ""); + return(x); + } + m = (int) getfval(y); + if (m <= 0) + m = 1; + else if (m > k) + m = k; + tempfree(y); + if (a[2] != 0) { + n = (int) getfval(z); + tempfree(z); + } else + n = k - 1; + if (n < 0) + n = 0; + else if (n > k - m) + n = k - m; + dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); + y = gettemp(); + temp = s[n+m-1]; /* with thanks to John Linderman */ + s[n+m-1] = '\0'; + setsval(y, s + m - 1); + s[n+m-1] = temp; + tempfree(x); + return(y); +} + +Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ +{ + Cell *x, *y, *z; + char *s1, *s2, *p1, *p2, *q; + Awkfloat v = 0.0; + + x = execute(a[0]); + s1 = getsval(x); + y = execute(a[1]); + s2 = getsval(y); + + z = gettemp(); + for (p1 = s1; *p1 != '\0'; p1++) { + for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) + ; + if (*p2 == '\0') { + v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */ + break; + } + } + tempfree(x); + tempfree(y); + setfval(z, v); + return(z); +} + +#define MAXNUMSIZE 50 + +int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */ +{ + char *fmt; + char *p, *t, *os; + Cell *x; + int flag = 0, n; + int fmtwd; /* format width */ + int fmtsz = recsize; + char *buf = *pbuf; + int bufsize = *pbufsize; + + os = s; + p = buf; + if ((fmt = (char *) malloc(fmtsz)) == NULL) + FATAL("out of memory in format()"); + while (*s) { + adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format"); + if (*s != '%') { + *p++ = *s++; + continue; + } + if (*(s+1) == '%') { + *p++ = '%'; + s += 2; + continue; + } + /* have to be real careful in case this is a huge number, eg, %100000d */ + fmtwd = atoi(s+1); + if (fmtwd < 0) + fmtwd = -fmtwd; + adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); + for (t = fmt; (*t++ = *s) != '\0'; s++) { + if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0)) + FATAL("format item %.30s... ran format() out of memory", os); + if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L') + break; /* the ansi panoply */ + if (*s == '*') { + x = execute(a); + a = a->nnext; + sprintf(t-1, "%d", fmtwd=(int) getfval(x)); + if (fmtwd < 0) + fmtwd = -fmtwd; + adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); + t = fmt + strlen(fmt); + tempfree(x); + } + } + *t = '\0'; + if (fmtwd < 0) + fmtwd = -fmtwd; + adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); + + switch (*s) { + case 'f': case 'e': case 'g': case 'E': case 'G': + flag = 1; + break; + case 'd': case 'i': + flag = 2; + if(*(s-1) == 'l') break; + *(t-1) = 'l'; + *t = 'd'; + *++t = '\0'; + break; + case 'o': case 'x': case 'X': case 'u': + flag = *(s-1) == 'l' ? 2 : 3; + break; + case 's': + flag = 4; + break; + case 'c': + flag = 5; + break; + default: + WARNING("weird printf conversion %s", fmt); + flag = 0; + break; + } + if (a == NULL) + FATAL("not enough args in printf(%s)", os); + x = execute(a); + a = a->nnext; + n = MAXNUMSIZE; + if (fmtwd > n) + n = fmtwd; + adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format"); + switch (flag) { + case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */ + t = getsval(x); + n = strlen(t); + if (fmtwd > n) + n = fmtwd; + adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format"); + p += strlen(p); + sprintf(p, "%s", t); + break; + case 1: sprintf(p, fmt, getfval(x)); break; + case 2: sprintf(p, fmt, (long) getfval(x)); break; + case 3: sprintf(p, fmt, (int) getfval(x)); break; + case 4: + t = getsval(x); + n = strlen(t); + if (fmtwd > n) + n = fmtwd; + if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0)) + FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t); + sprintf(p, fmt, t); + break; + case 5: + if (isnum(x)) { + if (getfval(x)) + sprintf(p, fmt, (int) getfval(x)); + else + *p++ = '\0'; + } else + sprintf(p, fmt, getsval(x)[0]); + break; + } + tempfree(x); + p += strlen(p); + s++; + } + *p = '\0'; + free(fmt); + for ( ; a; a = a->nnext) /* evaluate any remaining args */ + execute(a); + *pbuf = buf; + *pbufsize = bufsize; + return p - buf; +} + +Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ +{ + Cell *x; + Node *y; + char *buf; + int bufsz=3*recsize; + + if ((buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of memory in awksprintf"); + y = a[0]->nnext; + x = execute(a[0]); + if (format(&buf, &bufsz, getsval(x), y) == -1) + FATAL("sprintf string %.30s... too long. can't happen.", buf); + tempfree(x); + x = gettemp(); + x->sval = buf; + x->tval = STR; + return(x); +} + +Cell *awkprintf(Node **a, int n) /* printf */ +{ /* a[0] is list of args, starting with format string */ + /* a[1] is redirection operator, a[2] is redirection file */ + FILE *fp; + Cell *x; + Node *y; + char *buf; + int len; + int bufsz=3*recsize; + + if ((buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of memory in awkprintf"); + y = a[0]->nnext; + x = execute(a[0]); + if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) + FATAL("printf string %.30s... too long. can't happen.", buf); + tempfree(x); + if (a[1] == NULL) { + /* fputs(buf, stdout); */ + fwrite(buf, len, 1, stdout); + if (ferror(stdout)) + FATAL("write error on stdout"); + } else { + fp = redirect(ptoi(a[1]), a[2]); + /* fputs(buf, fp); */ + fwrite(buf, len, 1, fp); + fflush(fp); + if (ferror(fp)) + FATAL("write error on %s", filename(fp)); + } + free(buf); + return(True); +} + +Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ +{ + Awkfloat i, j = 0; + double v; + Cell *x, *y, *z; + + x = execute(a[0]); + i = getfval(x); + tempfree(x); + if (n != UMINUS) { + y = execute(a[1]); + j = getfval(y); + tempfree(y); + } + z = gettemp(); + switch (n) { + case ADD: + i += j; + break; + case MINUS: + i -= j; + break; + case MULT: + i *= j; + break; + case DIVIDE: + if (j == 0) + FATAL("division by zero"); + i /= j; + break; + case MOD: + if (j == 0) + FATAL("division by zero in mod"); + modf(i/j, &v); + i = i - j * v; + break; + case UMINUS: + i = -i; + break; + case POWER: + if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ + i = ipow(i, (int) j); + else + i = errcheck(pow(i, j), "pow"); + break; + default: /* can't happen */ + FATAL("illegal arithmetic operator %d", n); + } + setfval(z, i); + return(z); +} + +double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */ +{ + double v; + + if (n <= 0) + return 1; + v = ipow(x, n/2); + if (n % 2 == 0) + return v * v; + else + return x * v * v; +} + +Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */ +{ + Cell *x, *z; + int k; + Awkfloat xf; + + x = execute(a[0]); + xf = getfval(x); + k = (n == PREINCR || n == POSTINCR) ? 1 : -1; + if (n == PREINCR || n == PREDECR) { + setfval(x, xf + k); + return(x); + } + z = gettemp(); + setfval(z, xf); + setfval(x, xf + k); + tempfree(x); + return(z); +} + +Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ +{ /* this is subtle; don't muck with it. */ + Cell *x, *y; + Awkfloat xf, yf; + double v; + + y = execute(a[1]); + x = execute(a[0]); + if (n == ASSIGN) { /* ordinary assignment */ + if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */ + ; /* leave alone unless it's a field */ + else if ((y->tval & (STR|NUM)) == (STR|NUM)) { + setsval(x, getsval(y)); + x->fval = getfval(y); + x->tval |= NUM; + } + else if (isstr(y)) + setsval(x, getsval(y)); + else if (isnum(y)) + setfval(x, getfval(y)); + else + funnyvar(y, "read value of"); + tempfree(y); + return(x); + } + xf = getfval(x); + yf = getfval(y); + switch (n) { + case ADDEQ: + xf += yf; + break; + case SUBEQ: + xf -= yf; + break; + case MULTEQ: + xf *= yf; + break; + case DIVEQ: + if (yf == 0) + FATAL("division by zero in /="); + xf /= yf; + break; + case MODEQ: + if (yf == 0) + FATAL("division by zero in %%="); + modf(xf/yf, &v); + xf = xf - yf * v; + break; + case POWEQ: + if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ + xf = ipow(xf, (int) yf); + else + xf = errcheck(pow(xf, yf), "pow"); + break; + default: + FATAL("illegal assignment operator %d", n); + break; + } + tempfree(y); + setfval(x, xf); + return(x); +} + +Cell *cat(Node **a, int q) /* a[0] cat a[1] */ +{ + Cell *x, *y, *z; + int n1, n2; + char *s; + + x = execute(a[0]); + y = execute(a[1]); + getsval(x); + getsval(y); + n1 = strlen(x->sval); + n2 = strlen(y->sval); + s = (char *) malloc(n1 + n2 + 1); + if (s == NULL) + FATAL("out of space concatenating %.15s... and %.15s...", + x->sval, y->sval); + strcpy(s, x->sval); + strcpy(s+n1, y->sval); + tempfree(y); + z = gettemp(); + z->sval = s; + z->tval = STR; + tempfree(x); + return(z); +} + +Cell *pastat(Node **a, int n) /* a[0] { a[1] } */ +{ + Cell *x; + + if (a[0] == 0) + x = execute(a[1]); + else { + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } + } + return x; +} + +Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ +{ + Cell *x; + int pair; + + pair = ptoi(a[3]); + if (pairstack[pair] == 0) { + x = execute(a[0]); + if (istrue(x)) + pairstack[pair] = 1; + tempfree(x); + } + if (pairstack[pair] == 1) { + x = execute(a[1]); + if (istrue(x)) + pairstack[pair] = 0; + tempfree(x); + x = execute(a[2]); + return(x); + } + return(False); +} + +Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ +{ + Cell *x = 0, *y, *ap; + char *s; + int sep; + char *t, temp, num[50], *fs = 0; + int n, tempstat, arg3type; + + y = execute(a[0]); /* source string */ + s = getsval(y); + arg3type = ptoi(a[3]); + if (a[2] == 0) /* fs string */ + fs = *FS; + else if (arg3type == STRING) { /* split(str,arr,"string") */ + x = execute(a[2]); + fs = getsval(x); + } else if (arg3type == REGEXPR) + fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ + else + FATAL("illegal type of split"); + sep = *fs; + ap = execute(a[1]); /* array name */ + freesymtab(ap); + dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) ); + ap->tval &= ~STR; + ap->tval |= ARR; + ap->sval = (char *) makesymtab(NSYMTAB); + + n = 0; + if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */ + fa *pfa; + if (arg3type == REGEXPR) { /* it's ready already */ + pfa = (fa *) a[2]; + } else { + pfa = makedfa(fs, 1); + } + if (nematch(pfa,s)) { + tempstat = pfa->initstat; + pfa->initstat = 2; + do { + n++; + sprintf(num, "%d", n); + temp = *patbeg; + *patbeg = '\0'; + if (is_number(s)) + setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, s, 0.0, STR, (Array *) ap->sval); + *patbeg = temp; + s = patbeg + patlen; + if (*(patbeg+patlen-1) == 0 || *s == 0) { + n++; + sprintf(num, "%d", n); + setsymtab(num, "", 0.0, STR, (Array *) ap->sval); + pfa->initstat = tempstat; + goto spdone; + } + } while (nematch(pfa,s)); + } + n++; + sprintf(num, "%d", n); + if (is_number(s)) + setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, s, 0.0, STR, (Array *) ap->sval); + spdone: + pfa = NULL; + } else if (sep == ' ') { + for (n = 0; ; ) { + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + if (*s == 0) + break; + n++; + t = s; + do + s++; + while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); + temp = *s; + *s = '\0'; + sprintf(num, "%d", n); + if (is_number(t)) + setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, t, 0.0, STR, (Array *) ap->sval); + *s = temp; + if (*s != 0) + s++; + } + } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */ + for (n = 0; *s != 0; s++) { + char buf[2]; + n++; + sprintf(num, "%d", n); + buf[0] = *s; + buf[1] = 0; + if (isdigit((uschar)buf[0])) + setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, buf, 0.0, STR, (Array *) ap->sval); + } + } else if (*s != 0) { + for (;;) { + n++; + t = s; + while (*s != sep && *s != '\n' && *s != '\0') + s++; + temp = *s; + *s = '\0'; + sprintf(num, "%d", n); + if (is_number(t)) + setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, t, 0.0, STR, (Array *) ap->sval); + *s = temp; + if (*s++ == 0) + break; + } + } + tempfree(ap); + tempfree(y); + if (a[2] != 0 && arg3type == STRING) { + tempfree(x); + } + x = gettemp(); + x->tval = NUM; + x->fval = n; + return(x); +} + +Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ +{ + Cell *x; + + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } else { + tempfree(x); + x = execute(a[2]); + } + return(x); +} + +Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ +{ + Cell *x; + + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } else if (a[2] != 0) { + tempfree(x); + x = execute(a[2]); + } + return(x); +} + +Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ +{ + Cell *x; + + for (;;) { + x = execute(a[0]); + if (!istrue(x)) + return(x); + tempfree(x); + x = execute(a[1]); + if (isbreak(x)) { + x = True; + return(x); + } + if (isnext(x) || isexit(x) || isret(x)) + return(x); + tempfree(x); + } +} + +Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ +{ + Cell *x; + + for (;;) { + x = execute(a[0]); + if (isbreak(x)) + return True; + if (isnext(x) || isexit(x) || isret(x)) + return(x); + tempfree(x); + x = execute(a[1]); + if (!istrue(x)) + return(x); + tempfree(x); + } +} + +Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ +{ + Cell *x; + + x = execute(a[0]); + tempfree(x); + for (;;) { + if (a[1]!=0) { + x = execute(a[1]); + if (!istrue(x)) return(x); + else tempfree(x); + } + x = execute(a[3]); + if (isbreak(x)) /* turn off break */ + return True; + if (isnext(x) || isexit(x) || isret(x)) + return(x); + tempfree(x); + x = execute(a[2]); + tempfree(x); + } +} + +Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ +{ + Cell *x, *vp, *arrayp, *cp, *ncp; + Array *tp; + int i; + + vp = execute(a[0]); + arrayp = execute(a[1]); + if (!isarr(arrayp)) { + return True; + } + tp = (Array *) arrayp->sval; + tempfree(arrayp); + for (i = 0; i < tp->size; i++) { /* this routine knows too much */ + for (cp = tp->tab[i]; cp != NULL; cp = ncp) { + setsval(vp, cp->nval); + ncp = cp->cnext; + x = execute(a[2]); + if (isbreak(x)) { + tempfree(vp); + return True; + } + if (isnext(x) || isexit(x) || isret(x)) { + tempfree(vp); + return(x); + } + tempfree(x); + } + } + return True; +} + +Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ +{ + Cell *x, *y; + Awkfloat u; + int t; + char *p, *buf; + Node *nextarg; + FILE *fp; + + t = ptoi(a[0]); + x = execute(a[1]); + nextarg = a[1]->nnext; + switch (t) { + case FLENGTH: + u = strlen(getsval(x)); break; + case FLOG: + u = errcheck(log(getfval(x)), "log"); break; + case FINT: + modf(getfval(x), &u); break; + case FEXP: + u = errcheck(exp(getfval(x)), "exp"); break; + case FSQRT: + u = errcheck(sqrt(getfval(x)), "sqrt"); break; + case FSIN: + u = sin(getfval(x)); break; + case FCOS: + u = cos(getfval(x)); break; + case FATAN: + if (nextarg == 0) { + WARNING("atan2 requires two arguments; returning 1.0"); + u = 1.0; + } else { + y = execute(a[1]->nnext); + u = atan2(getfval(x), getfval(y)); + tempfree(y); + nextarg = nextarg->nnext; + } + break; + case FSYSTEM: + fflush(stdout); /* in case something is buffered already */ + u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ + break; + case FRAND: + /* in principle, rand() returns something in 0..RAND_MAX */ + u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; + break; + case FSRAND: + if (isrec(x)) /* no argument provided */ + u = time((time_t *)0); + else + u = getfval(x); + srand((unsigned int) u); + break; + case FTOUPPER: + case FTOLOWER: + buf = tostring(getsval(x)); + if (t == FTOUPPER) { + for (p = buf; *p; p++) + if (islower((uschar) *p)) + *p = toupper(*p); + } else { + for (p = buf; *p; p++) + if (isupper((uschar) *p)) + *p = tolower(*p); + } + tempfree(x); + x = gettemp(); + setsval(x, buf); + free(buf); + return x; + case FFLUSH: + if ((fp = openfile(FFLUSH, getsval(x))) == NULL) + u = EOF; + else + u = fflush(fp); + break; + default: /* can't happen */ + FATAL("illegal function type %d", t); + break; + } + tempfree(x); + x = gettemp(); + setfval(x, u); + if (nextarg != 0) { + WARNING("warning: function has too many arguments"); + for ( ; nextarg; nextarg = nextarg->nnext) + execute(nextarg); + } + return(x); +} + +Cell *printstat(Node **a, int n) /* print a[0] */ +{ + Node *x; + Cell *y; + FILE *fp; + + if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ + fp = stdout; + else + fp = redirect(ptoi(a[1]), a[2]); + for (x = a[0]; x != NULL; x = x->nnext) { + y = execute(x); + fputs(getsval(y), fp); + tempfree(y); + if (x->nnext == NULL) + fputs(*ORS, fp); + else + fputs(*OFS, fp); + } + if (a[1] != 0) + fflush(fp); + if (ferror(fp)) + FATAL("write error on %s", filename(fp)); + return(True); +} + +Cell *nullproc(Node **a, int n) +{ + n = n; + a = a; + return 0; +} + + +FILE *redirect(int a, Node *b) /* set up all i/o redirections */ +{ + FILE *fp; + Cell *x; + char *fname; + + x = execute(b); + fname = getsval(x); + fp = openfile(a, fname); + if (fp == NULL) + FATAL("can't open file %s", fname); + tempfree(x); + return fp; +} + +struct files { + FILE *fp; + char *fname; + int mode; /* '|', 'a', 'w' => LE/LT, GT */ +} files[FOPEN_MAX] ={ + { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */ + { NULL, "/dev/stdout", GT }, + { NULL, "/dev/stderr", GT } +}; + +void stdinit(void) /* in case stdin, etc., are not constants */ +{ + files[0].fp = stdin; + files[1].fp = stdout; + files[2].fp = stderr; +} + +FILE *openfile(int a, char *us) +{ + char *s = us; + int i, m; + FILE *fp = 0; + + if (*s == '\0') + FATAL("null file name in print or getline"); + for (i=0; i < FOPEN_MAX; i++) + if (files[i].fname && strcmp(s, files[i].fname) == 0) { + if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) + return files[i].fp; + if (a == FFLUSH) + return files[i].fp; + } + if (a == FFLUSH) /* didn't find it, so don't create it! */ + return NULL; + + for (i=0; i < FOPEN_MAX; i++) + if (files[i].fp == 0) + break; + if (i >= FOPEN_MAX) + FATAL("%s makes too many open files", s); + fflush(stdout); /* force a semblance of order */ + m = a; + if (a == GT) { + fp = fopen(s, "w"); + } else if (a == APPEND) { + fp = fopen(s, "a"); + m = GT; /* so can mix > and >> */ + } else if (a == '|') { /* output pipe */ + fp = popen(s, "w"); + } else if (a == LE) { /* input pipe */ + fp = popen(s, "r"); + } else if (a == LT) { /* getline <file */ + fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */ + } else /* can't happen */ + FATAL("illegal redirection %d", a); + if (fp != NULL) { + files[i].fname = tostring(s); + files[i].fp = fp; + files[i].mode = m; + } + return fp; +} + +char *filename(FILE *fp) +{ + int i; + + for (i = 0; i < FOPEN_MAX; i++) + if (fp == files[i].fp) + return files[i].fname; + return "???"; +} + +Cell *closefile(Node **a, int n) +{ + Cell *x; + int i, stat; + + n = n; + x = execute(a[0]); + getsval(x); + stat = -1; + for (i = 0; i < FOPEN_MAX; i++) { + if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { + if (ferror(files[i].fp)) + WARNING( "i/o error occurred on %s", files[i].fname ); + if (files[i].mode == '|' || files[i].mode == LE) + stat = pclose(files[i].fp); + else + stat = fclose(files[i].fp); + if (stat == EOF) + WARNING( "i/o error occurred closing %s", files[i].fname ); + if (i > 2) /* don't do /dev/std... */ + xfree(files[i].fname); + files[i].fname = NULL; /* watch out for ref thru this */ + files[i].fp = NULL; + } + } + tempfree(x); + x = gettemp(); + setfval(x, (Awkfloat) stat); + return(x); +} + +void closeall(void) +{ + int i, stat; + + for (i = 0; i < FOPEN_MAX; i++) { + if (files[i].fp) { + if (ferror(files[i].fp)) + WARNING( "i/o error occurred on %s", files[i].fname ); + if (files[i].mode == '|' || files[i].mode == LE) + stat = pclose(files[i].fp); + else + stat = fclose(files[i].fp); + if (stat == EOF && i != 0) + WARNING( "i/o error occurred while closing %s", files[i].fname ); + } + } +} + +void backsub(char **pb_ptr, char **sptr_ptr); + +Cell *sub(Node **a, int nnn) /* substitute command */ +{ + char *sptr, *pb, *q; + Cell *x, *y, *result; + char *t, *buf; + fa *pfa; + int bufsz = recsize; + + if ((buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of memory in sub"); + x = execute(a[3]); /* target string */ + t = getsval(x); + if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ + pfa = (fa *) a[1]; /* regular expression */ + else { + y = execute(a[1]); + pfa = makedfa(getsval(y), 1); + tempfree(y); + } + y = execute(a[2]); /* replacement string */ + result = False; + if (pmatch(pfa, t)) { + sptr = t; + adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); + pb = buf; + while (sptr < patbeg) + *pb++ = *sptr++; + sptr = getsval(y); + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + *pb = '\0'; + if (pb > buf + bufsz) + FATAL("sub result1 %.30s too big; can't happen", buf); + sptr = patbeg + patlen; + if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { + adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); + while ((*pb++ = *sptr++) != 0) + ; + } + if (pb > buf + bufsz) + FATAL("sub result2 %.30s too big; can't happen", buf); + setsval(x, buf); /* BUG: should be able to avoid copy */ + result = True;; + } + tempfree(x); + tempfree(y); + free(buf); + return result; +} + +Cell *gsub(Node **a, int nnn) /* global substitute */ +{ + Cell *x, *y; + char *rptr, *sptr, *t, *pb, *q; + char *buf; + fa *pfa; + int mflag, tempstat, num; + int bufsz = recsize; + + if ((buf = (char *) malloc(bufsz)) == NULL) + FATAL("out of memory in gsub"); + mflag = 0; /* if mflag == 0, can replace empty string */ + num = 0; + x = execute(a[3]); /* target string */ + t = getsval(x); + if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ + pfa = (fa *) a[1]; /* regular expression */ + else { + y = execute(a[1]); + pfa = makedfa(getsval(y), 1); + tempfree(y); + } + y = execute(a[2]); /* replacement string */ + if (pmatch(pfa, t)) { + tempstat = pfa->initstat; + pfa->initstat = 2; + pb = buf; + rptr = getsval(y); + do { + if (patlen == 0 && *patbeg != 0) { /* matched empty string */ + if (mflag == 0) { /* can replace empty */ + num++; + sptr = rptr; + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + } + if (*t == 0) /* at end */ + goto done; + adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub"); + *pb++ = *t++; + if (pb > buf + bufsz) /* BUG: not sure of this test */ + FATAL("gsub result0 %.30s too big; can't happen", buf); + mflag = 0; + } + else { /* matched nonempty string */ + num++; + sptr = t; + adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub"); + while (sptr < patbeg) + *pb++ = *sptr++; + sptr = rptr; + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + t = patbeg + patlen; + if (patlen == 0 || *t == 0 || *(t-1) == 0) + goto done; + if (pb > buf + bufsz) + FATAL("gsub result1 %.30s too big; can't happen", buf); + mflag = 1; + } + } while (pmatch(pfa,t)); + sptr = t; + adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); + while ((*pb++ = *sptr++) != 0) + ; + done: if (pb > buf + bufsz) + FATAL("gsub result2 %.30s too big; can't happen", buf); + *pb = '\0'; + setsval(x, buf); /* BUG: should be able to avoid copy + free */ + pfa->initstat = tempstat; + } + tempfree(x); + tempfree(y); + x = gettemp(); + x->tval = NUM; + x->fval = num; + free(buf); + return(x); +} + +void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ +{ /* sptr[0] == '\\' */ + char *pb = *pb_ptr, *sptr = *sptr_ptr; + + if (sptr[1] == '\\') { + if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ + *pb++ = '\\'; + *pb++ = '&'; + sptr += 4; + } else if (sptr[2] == '&') { /* \\& -> \ + matched */ + *pb++ = '\\'; + sptr += 2; + } else { /* \\x -> \\x */ + *pb++ = *sptr++; + *pb++ = *sptr++; + } + } else if (sptr[1] == '&') { /* literal & */ + sptr++; + *pb++ = *sptr++; + } else /* literal \ */ + *pb++ = *sptr++; + + *pb_ptr = pb; + *sptr_ptr = sptr; +} diff --git a/utils/awk/tran.c b/utils/awk/tran.c new file mode 100644 index 00000000..8e0faf0d --- /dev/null +++ b/utils/awk/tran.c @@ -0,0 +1,437 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include <stdio.h> +#include <math.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include "awk.h" +#include "ytab.h" + +#define FULLTAB 2 /* rehash when table gets this x full */ +#define GROWTAB 4 /* grow table by this factor */ + +Array *symtab; /* main symbol table */ + +char **FS; /* initial field sep */ +char **RS; /* initial record sep */ +char **OFS; /* output field sep */ +char **ORS; /* output record sep */ +char **OFMT; /* output format for numbers */ +char **CONVFMT; /* format for conversions in getsval */ +Awkfloat *NF; /* number of fields in current record */ +Awkfloat *NR; /* number of current record */ +Awkfloat *FNR; /* number of current record in current file */ +char **FILENAME; /* current filename argument */ +Awkfloat *ARGC; /* number of arguments from command line */ +char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ +Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ +Awkfloat *RLENGTH; /* length of same */ + +Cell *nrloc; /* NR */ +Cell *nfloc; /* NF */ +Cell *fnrloc; /* FNR */ +Array *ARGVtab; /* symbol table containing ARGV[...] */ +Array *ENVtab; /* symbol table containing ENVIRON[...] */ +Cell *rstartloc; /* RSTART */ +Cell *rlengthloc; /* RLENGTH */ +Cell *symtabloc; /* SYMTAB */ + +Cell *nullloc; /* a guaranteed empty cell */ +Node *nullnode; /* zero&null, converted into a node for comparisons */ +Cell *literal0; + +extern Cell **fldtab; + +void syminit(void) /* initialize symbol table with builtin vars */ +{ + literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); + /* this is used for if(x)... tests: */ + nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); + nullnode = celltonode(nullloc, CCON); + + FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; + RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; + OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; + ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; + OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; + CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; + FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; + nfloc = setsymtab("NF", "", 0.0, NUM, symtab); + NF = &nfloc->fval; + nrloc = setsymtab("NR", "", 0.0, NUM, symtab); + NR = &nrloc->fval; + fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); + FNR = &fnrloc->fval; + SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; + rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); + RSTART = &rstartloc->fval; + rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); + RLENGTH = &rlengthloc->fval; + symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); + symtabloc->sval = (char *) symtab; +} + +void arginit(int ac, char **av) /* set up ARGV and ARGC */ +{ + Cell *cp; + int i; + char temp[50]; + + ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; + cp = setsymtab("ARGV", "", 0.0, ARR, symtab); + ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ + cp->sval = (char *) ARGVtab; + for (i = 0; i < ac; i++) { + sprintf(temp, "%d", i); + if (is_number(*av)) + setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); + else + setsymtab(temp, *av, 0.0, STR, ARGVtab); + av++; + } +} + +void envinit(char **envp) /* set up ENVIRON variable */ +{ + Cell *cp; + char *p; + + cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); + ENVtab = makesymtab(NSYMTAB); + cp->sval = (char *) ENVtab; + for ( ; *envp; envp++) { + if ((p = strchr(*envp, '=')) == NULL) + continue; + if( p == *envp ) /* no left hand side name in env string */ + continue; + *p++ = 0; /* split into two strings at = */ + if (is_number(p)) + setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); + else + setsymtab(*envp, p, 0.0, STR, ENVtab); + p[-1] = '='; /* restore in case env is passed down to a shell */ + } +} + +Array *makesymtab(int n) /* make a new symbol table */ +{ + Array *ap; + Cell **tp; + + ap = (Array *) malloc(sizeof(Array)); + tp = (Cell **) calloc(n, sizeof(Cell *)); + if (ap == NULL || tp == NULL) + FATAL("out of space in makesymtab"); + ap->nelem = 0; + ap->size = n; + ap->tab = tp; + return(ap); +} + +void freesymtab(Cell *ap) /* free a symbol table */ +{ + Cell *cp, *temp; + Array *tp; + int i; + + if (!isarr(ap)) + return; + tp = (Array *) ap->sval; + if (tp == NULL) + return; + for (i = 0; i < tp->size; i++) { + for (cp = tp->tab[i]; cp != NULL; cp = temp) { + xfree(cp->nval); + if (freeable(cp)) + xfree(cp->sval); + temp = cp->cnext; /* avoids freeing then using */ + free(cp); + } + tp->tab[i] = 0; + } + free(tp->tab); + free(tp); +} + +void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */ +{ + Array *tp; + Cell *p, *prev = NULL; + int h; + + tp = (Array *) ap->sval; + h = hash(s, tp->size); + for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) + if (strcmp(s, p->nval) == 0) { + if (prev == NULL) /* 1st one */ + tp->tab[h] = p->cnext; + else /* middle somewhere */ + prev->cnext = p->cnext; + if (freeable(p)) + xfree(p->sval); + free(p->nval); + free(p); + tp->nelem--; + return; + } +} + +Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp) +{ + int h; + Cell *p; + + if (n != NULL && (p = lookup(n, tp)) != NULL) { + dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", + p, p->nval, p->sval, p->fval, p->tval) ); + return(p); + } + p = (Cell *) malloc(sizeof(Cell)); + if (p == NULL) + FATAL("out of space for symbol table at %s", n); + p->nval = tostring(n); + p->sval = s ? tostring(s) : tostring(""); + p->fval = f; + p->tval = t; + p->csub = CUNK; + p->ctype = OCELL; + tp->nelem++; + if (tp->nelem > FULLTAB * tp->size) + rehash(tp); + h = hash(n, tp->size); + p->cnext = tp->tab[h]; + tp->tab[h] = p; + dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", + p, p->nval, p->sval, p->fval, p->tval) ); + return(p); +} + +int hash(char *s, int n) /* form hash value for string s */ +{ + unsigned hashval; + + for (hashval = 0; *s != '\0'; s++) + hashval = (*s + 31 * hashval); + return hashval % n; +} + +void rehash(Array *tp) /* rehash items in small table into big one */ +{ + int i, nh, nsz; + Cell *cp, *op, **np; + + nsz = GROWTAB * tp->size; + np = (Cell **) calloc(nsz, sizeof(Cell *)); + if (np == NULL) /* can't do it, but can keep running. */ + return; /* someone else will run out later. */ + for (i = 0; i < tp->size; i++) { + for (cp = tp->tab[i]; cp; cp = op) { + op = cp->cnext; + nh = hash(cp->nval, nsz); + cp->cnext = np[nh]; + np[nh] = cp; + } + } + free(tp->tab); + tp->tab = np; + tp->size = nsz; +} + +Cell *lookup(char *s, Array *tp) /* look for s in tp */ +{ + Cell *p; + int h; + + h = hash(s, tp->size); + for (p = tp->tab[h]; p != NULL; p = p->cnext) + if (strcmp(s, p->nval) == 0) + return(p); /* found it */ + return(NULL); /* not found */ +} + +Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ +{ + int fldno; + + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "assign to"); + if (isfld(vp)) { + donerec = 0; /* mark $0 invalid */ + fldno = atoi(vp->nval); + if (fldno > *NF) + newfld(fldno); + dprintf( ("setting field %d to %g\n", fldno, f) ); + } else if (isrec(vp)) { + donefld = 0; /* mark $1... invalid */ + donerec = 1; + } + if (freeable(vp)) + xfree(vp->sval); /* free any previous string */ + vp->tval &= ~STR; /* mark string invalid */ + vp->tval |= NUM; /* mark number ok */ + dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); + return vp->fval = f; +} + +void funnyvar(Cell *vp, char *rw) +{ + if (isarr(vp)) + FATAL("can't %s %s; it's an array name.", rw, vp->nval); + if (vp->tval & FCN) + FATAL("can't %s %s; it's a function.", rw, vp->nval); + WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", + vp, vp->nval, vp->sval, vp->fval, vp->tval); +} + +char *setsval(Cell *vp, char *s) /* set string val of a Cell */ +{ + char *t; + int fldno; + + dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) ); + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "assign to"); + if (isfld(vp)) { + donerec = 0; /* mark $0 invalid */ + fldno = atoi(vp->nval); + if (fldno > *NF) + newfld(fldno); + dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); + } else if (isrec(vp)) { + donefld = 0; /* mark $1... invalid */ + donerec = 1; + } + t = tostring(s); /* in case it's self-assign */ + vp->tval &= ~NUM; + vp->tval |= STR; + if (freeable(vp)) + xfree(vp->sval); + vp->tval &= ~DONTFREE; + dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) ); + return(vp->sval = t); +} + +Awkfloat getfval(Cell *vp) /* get float val of a Cell */ +{ + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "read value of"); + if (isfld(vp) && donefld == 0) + fldbld(); + else if (isrec(vp) && donerec == 0) + recbld(); + if (!isnum(vp)) { /* not a number */ + vp->fval = atof(vp->sval); /* best guess */ + if (is_number(vp->sval) && !(vp->tval&CON)) + vp->tval |= NUM; /* make NUM only sparingly */ + } + dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); + return(vp->fval); +} + +char *getsval(Cell *vp) /* get string val of a Cell */ +{ + char s[100]; /* BUG: unchecked */ + double dtemp; + + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "read value of"); + if (isfld(vp) && donefld == 0) + fldbld(); + else if (isrec(vp) && donerec == 0) + recbld(); + if (isstr(vp) == 0) { + if (freeable(vp)) + xfree(vp->sval); + if (modf(vp->fval, &dtemp) == 0) /* it's integral */ + sprintf(s, "%.30g", vp->fval); + else + sprintf(s, *CONVFMT, vp->fval); + vp->sval = tostring(s); + vp->tval &= ~DONTFREE; + vp->tval |= STR; + } + dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) ); + return(vp->sval); +} + +char *tostring(char *s) /* make a copy of string s */ +{ + char *p; + + p = (char *) malloc(strlen(s)+1); + if (p == NULL) + FATAL("out of space in tostring on %s", s); + strcpy(p, s); + return(p); +} + +char *qstring(char *is, int delim) /* collect string up to next delim */ +{ + char *os = is; + int c, n; + uschar *s = (uschar *) is; + uschar *buf, *bp; + + if ((buf = (uschar *) malloc(strlen(s)+3)) == NULL) + FATAL( "out of space in qstring(%s)", s); + for (bp = buf; (c = *s) != delim; s++) { + if (c == '\n') + SYNTAX( "newline in string %.20s...", os ); + else if (c != '\\') + *bp++ = c; + else { /* \something */ + c = *++s; + if (c == 0) { /* \ at end */ + *bp++ = '\\'; + break; /* for loop */ + } + switch (c) { + case '\\': *bp++ = '\\'; break; + case 'n': *bp++ = '\n'; break; + case 't': *bp++ = '\t'; break; + case 'b': *bp++ = '\b'; break; + case 'f': *bp++ = '\f'; break; + case 'r': *bp++ = '\r'; break; + default: + if (!isdigit(c)) { + *bp++ = c; + break; + } + n = c - '0'; + if (isdigit(s[1])) { + n = 8 * n + *++s - '0'; + if (isdigit(s[1])) + n = 8 * n + *++s - '0'; + } + *bp++ = n; + break; + } + } + } + *bp++ = 0; + return (char *) buf; +} diff --git a/utils/awk/ytab.c b/utils/awk/ytab.c new file mode 100644 index 00000000..2a6a938b --- /dev/null +++ b/utils/awk/ytab.c @@ -0,0 +1,1623 @@ + +#line 26 "/n/bopp/v7/bwk/awk/awkgram.y" +#include <stdio.h> +#include <string.h> +#include "awk.h" + +void checkdup(Node *list, Cell *item); +int yywrap(void) { return(1); } + +Node *beginloc = 0; +Node *endloc = 0; +int infunc = 0; /* = 1 if in arglist or body of func */ +int inloop = 0; /* = 1 if in while, for, do */ +char *curfname = 0; /* current function name */ +Node *arglist = 0; /* list of args for current function */ + +#line 41 "/n/bopp/v7/bwk/awk/awkgram.y" +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval; +YYSTYPE yyval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 +#define YYEOFCODE 1 +#define YYERRCODE 2 + +#line 445 "/n/bopp/v7/bwk/awk/awkgram.y" + + +void setfname(Cell *p) +{ + if (isarr(p)) + SYNTAX("%s is an array, not a function", p->nval); + else if (isfcn(p)) + SYNTAX("you can't define function %s more than once", p->nval); + curfname = p->nval; +} + +int constnode(Node *p) +{ + return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON; +} + +char *strnode(Node *p) +{ + return ((Cell *)(p->narg[0]))->sval; +} + +Node *notnull(Node *n) +{ + switch (n->nobj) { + case LE: case LT: case EQ: case NE: case GT: case GE: + case BOR: case AND: case NOT: + return n; + default: + return op2(NE, n, nullnode); + } +} + +void checkdup(Node *vl, Cell *cp) /* check if name already in list */ +{ + char *s = cp->nval; + for ( ; vl; vl = vl->nnext) { + if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) { + SYNTAX("duplicate argument %s", s); + break; + } + } +} +short yyexca[] = +{-1, 0, + 1, 28, + 8, 28, + 9, 28, + 12, 28, + 13, 28, + 16, 28, + 45, 28, + 46, 28, + 48, 28, + 54, 28, + 55, 28, + 56, 28, + 58, 28, + 60, 28, + 78, 28, + 86, 28, + 87, 28, + 88, 28, + 89, 28, + 90, 28, + 91, 28, + 95, 28, + 97, 28, + 98, 28, + 101, 28, + 102, 28, + 105, 28, + 108, 28, + 109, 28, + 110, 28, + -2, 0, +-1, 1, + 1, -1, + -2, 0, +-1, 157, + 15, 30, + -2, 0, +-1, 176, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 63, +-1, 177, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 64, +-1, 178, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 65, +-1, 179, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 66, +-1, 180, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 67, +-1, 181, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 68, +-1, 183, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 70, +-1, 289, + 24, 0, + 44, 0, + -2, 53, +-1, 333, + 17, 30, + -2, 0, +-1, 355, + 17, 30, + -2, 0, +}; +#define YYNPROD 185 +#define YYPRIVATE 57344 +#define YYLAST 4177 +short yyact[] = +{ + 17, 277, 138, 66, 243, 228, 253, 54, 24, 43, + 125, 112, 200, 43, 103, 104, 100, 139, 102, 155, + 308, 185, 215, 249, 100, 253, 100, 100, 100, 107, + 105, 100, 122, 123, 124, 223, 107, 206, 43, 82, + 162, 43, 83, 103, 104, 10, 113, 314, 9, 252, + 42, 22, 44, 244, 42, 22, 44, 103, 104, 134, + 142, 113, 146, 190, 278, 352, 149, 150, 152, 153, + 148, 276, 316, 163, 23, 100, 351, 350, 23, 42, + 62, 44, 42, 22, 44, 11, 156, 168, 169, 85, + 253, 51, 321, 79, 80, 232, 190, 86, 135, 133, + 100, 318, 182, 320, 269, 258, 23, 100, 100, 100, + 100, 100, 100, 100, 108, 109, 110, 111, 233, 275, + 112, 234, 190, 110, 111, 43, 100, 112, 335, 190, + 190, 11, 203, 205, 190, 324, 278, 190, 190, 212, + 284, 190, 211, 265, 260, 190, 100, 259, 221, 3, + 141, 188, 100, 16, 226, 140, 331, 6, 156, 141, + 219, 230, 7, 100, 310, 6, 42, 170, 44, 167, + 7, 158, 100, 157, 100, 131, 100, 100, 100, 100, + 100, 100, 100, 130, 100, 48, 251, 100, 100, 129, + 49, 128, 236, 127, 100, 126, 120, 119, 52, 16, + 190, 19, 100, 312, 141, 274, 218, 100, 143, 100, + 100, 100, 4, 154, 100, 100, 217, 271, 144, 132, + 317, 50, 347, 361, 364, 270, 1, 115, 72, 40, + 224, 5, 100, 100, 100, 100, 163, 58, 163, 163, + 163, 163, 20, 67, 163, 222, 100, 293, 61, 288, + 294, 60, 238, 248, 81, 100, 100, 292, 96, 8, + 239, 159, 160, 2, 0, 0, 114, 0, 116, 117, + 118, 300, 301, 121, 164, 0, 282, 0, 285, 286, + 287, 289, 0, 100, 291, 0, 100, 100, 100, 0, + 100, 0, 100, 156, 0, 309, 0, 100, 0, 100, + 100, 0, 0, 100, 0, 100, 100, 100, 0, 0, + 0, 0, 0, 334, 313, 165, 163, 96, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 341, 156, 342, + 333, 0, 340, 100, 0, 0, 0, 230, 100, 346, + 100, 0, 116, 0, 100, 100, 348, 0, 356, 96, + 194, 195, 196, 197, 198, 199, 337, 359, 0, 230, + 0, 360, 362, 156, 0, 355, 0, 0, 207, 0, + 0, 0, 238, 0, 0, 238, 238, 238, 0, 238, + 239, 238, 0, 239, 239, 239, 0, 239, 96, 239, + 0, 0, 21, 0, 96, 0, 0, 0, 338, 0, + 0, 0, 0, 0, 257, 242, 0, 0, 55, 0, + 0, 0, 0, 0, 96, 0, 96, 0, 96, 96, + 96, 96, 96, 96, 96, 0, 96, 238, 0, 96, + 96, 0, 0, 0, 0, 239, 256, 164, 0, 164, + 164, 164, 164, 0, 96, 164, 0, 0, 0, 261, + 0, 96, 96, 96, 0, 0, 96, 96, 0, 0, + 0, 0, 0, 137, 0, 0, 166, 0, 0, 0, + 147, 0, 0, 0, 96, 279, 280, 281, 165, 0, + 165, 165, 165, 165, 0, 0, 165, 184, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 96, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, + 189, 191, 0, 15, 0, 0, 0, 164, 0, 0, + 0, 0, 0, 0, 0, 242, 0, 106, 242, 242, + 242, 0, 242, 0, 242, 0, 0, 0, 0, 96, + 0, 96, 96, 137, 0, 96, 0, 96, 96, 96, + 229, 0, 0, 220, 0, 0, 0, 137, 165, 15, + 0, 15, 0, 227, 0, 235, 0, 0, 145, 0, + 0, 0, 0, 0, 151, 96, 0, 137, 137, 0, + 242, 0, 96, 0, 0, 0, 96, 96, 0, 0, + 0, 0, 0, 171, 173, 175, 176, 177, 178, 179, + 180, 181, 183, 0, 0, 0, 0, 0, 0, 0, + 186, 187, 0, 262, 263, 264, 0, 266, 267, 268, + 0, 0, 201, 0, 0, 0, 0, 0, 201, 201, + 0, 273, 0, 0, 290, 208, 209, 210, 201, 213, + 214, 189, 0, 0, 0, 297, 0, 0, 0, 101, + 0, 0, 0, 295, 0, 0, 0, 303, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 231, 0, 311, + 106, 98, 97, 0, 0, 0, 245, 0, 0, 137, + 241, 43, 28, 0, 30, 0, 0, 0, 0, 0, + 0, 46, 47, 0, 34, 0, 35, 0, 254, 0, + 255, 0, 0, 0, 0, 0, 0, 336, 323, 326, + 328, 329, 0, 0, 38, 0, 0, 0, 189, 0, + 0, 0, 42, 22, 44, 29, 36, 39, 0, 237, + 315, 33, 0, 37, 41, 0, 0, 27, 26, 0, + 0, 99, 0, 0, 31, 32, 23, 0, 0, 0, + 0, 0, 0, 201, 0, 0, 357, 137, 0, 296, + 0, 0, 0, 0, 0, 0, 298, 0, 0, 0, + 363, 299, 302, 365, 0, 304, 305, 306, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 106, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, 18, + 0, 68, 45, 0, 358, 0, 0, 0, 332, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 339, 0, 0, 0, 0, 0, 343, 0, + 344, 43, 28, 56, 30, 57, 73, 69, 59, 70, + 0, 46, 47, 71, 34, 0, 35, 63, 64, 0, + 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, + 0, 0, 77, 78, 38, 53, 0, 16, 18, 0, + 68, 45, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 33, 65, 37, 41, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 31, 32, 23, 0, 0, 0, + 43, 28, 56, 30, 57, 73, 69, 59, 70, 0, + 46, 47, 71, 34, 0, 35, 63, 64, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, + 0, 77, 78, 38, 16, 18, 0, 68, 45, 0, + 307, 42, 22, 44, 29, 36, 39, 0, 0, 0, + 33, 65, 37, 41, 76, 0, 27, 26, 0, 0, + 25, 0, 0, 31, 32, 23, 0, 43, 28, 56, + 30, 57, 73, 69, 59, 70, 0, 46, 47, 71, + 34, 0, 35, 63, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 75, 0, 0, 0, 0, 77, 78, + 38, 272, 0, 16, 18, 0, 68, 45, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 65, 37, + 41, 76, 0, 27, 26, 0, 0, 25, 0, 0, + 31, 32, 23, 0, 0, 0, 43, 28, 56, 30, + 57, 73, 69, 59, 70, 0, 46, 47, 71, 34, + 0, 35, 63, 64, 0, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 0, 0, 0, 77, 78, 38, + 16, 18, 0, 68, 45, 0, 247, 42, 22, 44, + 29, 36, 39, 0, 0, 0, 33, 65, 37, 41, + 76, 0, 27, 26, 0, 0, 25, 0, 0, 31, + 32, 23, 0, 43, 28, 56, 30, 57, 73, 69, + 59, 70, 0, 46, 47, 71, 34, 0, 35, 63, + 64, 0, 0, 0, 0, 0, 0, 75, 0, 0, + 0, 0, 0, 0, 77, 78, 38, 16, 18, 0, + 68, 45, 0, 246, 42, 22, 44, 29, 36, 39, + 0, 0, 0, 33, 65, 37, 41, 76, 0, 27, + 26, 0, 0, 25, 0, 0, 31, 32, 23, 0, + 43, 28, 56, 30, 57, 73, 69, 59, 70, 0, + 46, 47, 71, 34, 0, 35, 63, 64, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, + 0, 77, 78, 38, 16, 18, 0, 68, 45, 0, + 225, 42, 22, 44, 29, 36, 39, 0, 0, 0, + 33, 65, 37, 41, 76, 0, 27, 26, 0, 0, + 25, 0, 0, 31, 32, 23, 0, 43, 28, 56, + 30, 57, 73, 69, 59, 70, 0, 46, 47, 71, + 34, 0, 35, 63, 64, 0, 0, 0, 0, 0, + 0, 75, 0, 0, 0, 0, 0, 0, 77, 78, + 38, 16, 18, 0, 68, 45, 0, 216, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 65, 37, + 41, 76, 0, 27, 26, 0, 0, 25, 0, 0, + 31, 32, 23, 0, 43, 28, 56, 30, 57, 73, + 69, 59, 70, 0, 46, 47, 71, 34, 0, 35, + 63, 64, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 77, 78, 38, 16, 18, + 0, 68, 45, 0, 136, 42, 22, 44, 29, 36, + 39, 0, 0, 0, 33, 65, 37, 41, 76, 0, + 27, 26, 0, 0, 25, 0, 0, 31, 32, 23, + 0, 43, 28, 56, 30, 57, 73, 69, 59, 70, + 0, 46, 47, 71, 34, 0, 35, 63, 64, 0, + 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 77, 78, 38, 16, 18, 0, 68, 45, + 0, 0, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 33, 65, 37, 41, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 31, 32, 23, 0, 43, 28, + 56, 30, 57, 73, 69, 59, 70, 0, 46, 47, + 71, 34, 0, 35, 63, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, + 78, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 0, 0, 33, 65, + 37, 41, 76, 0, 27, 26, 0, 0, 25, 0, + 0, 31, 32, 23, 190, 0, 101, 95, 0, 0, + 330, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 43, 28, + 0, 30, 0, 0, 0, 0, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 84, 0, 33, 0, + 37, 41, 0, 0, 27, 26, 0, 0, 99, 0, + 0, 31, 32, 23, 190, 0, 101, 95, 0, 0, + 327, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 43, 28, + 0, 30, 0, 0, 0, 0, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 84, 0, 33, 0, + 37, 41, 0, 0, 27, 26, 0, 0, 99, 0, + 0, 31, 32, 23, 190, 0, 101, 95, 0, 0, + 325, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 43, 28, + 0, 30, 0, 0, 0, 0, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 84, 0, 33, 0, + 37, 41, 0, 0, 27, 26, 0, 0, 99, 0, + 0, 31, 32, 23, 141, 0, 0, 101, 95, 140, + 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 31, 32, 23, 190, 0, 101, 95, 0, + 0, 192, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 101, 95, 99, + 0, 354, 31, 32, 23, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 101, 95, 99, + 0, 353, 31, 32, 23, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 101, 95, 99, + 0, 349, 31, 32, 23, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 31, 32, 23, 101, 95, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 101, 95, 99, 0, 322, + 31, 32, 23, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 101, 95, 99, 0, 319, + 31, 32, 23, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 101, 95, 99, 0, 278, + 31, 32, 23, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 0, 190, 99, 101, 95, + 31, 32, 23, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 192, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 250, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 0, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 101, 95, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 93, 0, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 0, + 0, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 18, 0, 0, 45, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 0, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 31, 32, 23, 43, 28, 0, 30, 0, + 73, 0, 0, 0, 0, 46, 47, 0, 34, 0, + 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 78, 38, 0, + 0, 101, 0, 0, 0, 0, 42, 22, 44, 29, + 36, 39, 240, 0, 0, 33, 0, 37, 41, 0, + 0, 27, 26, 98, 97, 25, 0, 0, 31, 32, + 23, 0, 241, 43, 28, 0, 30, 0, 0, 0, + 0, 0, 0, 46, 47, 0, 34, 0, 35, 0, + 0, 0, 0, 0, 12, 13, 0, 0, 16, 18, + 0, 0, 45, 0, 0, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 42, 22, 44, 29, 36, 39, + 0, 237, 0, 33, 0, 37, 41, 0, 0, 27, + 26, 43, 28, 99, 30, 0, 31, 32, 23, 0, + 14, 46, 47, 0, 34, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 0, 0, 101, 0, 0, + 0, 0, 42, 22, 44, 29, 36, 39, 240, 0, + 0, 33, 0, 37, 41, 0, 0, 27, 26, 98, + 0, 25, 0, 0, 31, 32, 23, 0, 241, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 141, 0, 0, 18, 0, 140, 45, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 253, 0, 33, + 18, 37, 41, 45, 0, 27, 26, 43, 28, 99, + 30, 0, 31, 32, 23, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 28, 0, 30, 0, 0, 0, 0, + 38, 0, 46, 47, 0, 34, 0, 35, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 38, 0, 25, 101, 0, + 31, 32, 23, 42, 22, 44, 29, 36, 39, 240, + 0, 0, 33, 0, 37, 41, 0, 0, 27, 26, + 0, 0, 25, 0, 0, 31, 32, 23, 0, 241, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 174, 0, 0, 283, 0, 0, 45, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 172, 0, + 33, 283, 37, 41, 45, 0, 27, 26, 43, 28, + 99, 30, 0, 31, 32, 23, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 28, 0, 30, 0, 0, 0, + 0, 38, 0, 46, 47, 0, 34, 0, 35, 42, + 22, 44, 29, 36, 39, 0, 253, 0, 33, 283, + 37, 41, 45, 0, 27, 26, 38, 0, 25, 0, + 0, 31, 32, 23, 42, 22, 44, 29, 36, 39, + 0, 0, 0, 33, 18, 37, 41, 45, 204, 27, + 26, 43, 28, 25, 30, 0, 31, 32, 23, 0, + 0, 46, 47, 0, 34, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 43, 28, 0, 30, + 0, 0, 0, 0, 38, 0, 46, 47, 0, 34, + 0, 35, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 33, 18, 37, 41, 45, 202, 27, 26, 38, + 0, 25, 0, 0, 31, 32, 23, 42, 22, 44, + 29, 36, 39, 0, 174, 0, 33, 18, 37, 41, + 45, 0, 27, 26, 43, 28, 25, 30, 0, 31, + 32, 23, 0, 0, 46, 47, 0, 34, 0, 35, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, + 28, 0, 30, 0, 0, 0, 0, 38, 0, 46, + 47, 0, 34, 0, 35, 42, 22, 44, 29, 36, + 39, 0, 172, 0, 33, 18, 37, 41, 45, 0, + 27, 26, 38, 0, 25, 0, 0, 31, 32, 23, + 42, 22, 44, 29, 36, 39, 0, 0, 0, 33, + 18, 37, 41, 45, 0, 27, 26, 43, 28, 25, + 30, 0, 31, 32, 23, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 28, 0, 30, 0, 0, 0, 0, + 38, 0, 46, 47, 0, 34, 0, 35, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 283, 37, + 41, 45, 0, 27, 26, 38, 0, 25, 0, 0, + 31, 32, 23, 42, 22, 44, 29, 36, 39, 0, + 0, 0, 33, 101, 37, 41, 0, 0, 27, 26, + 43, 28, 25, 30, 0, 31, 32, 23, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 43, 28, 0, 30, 0, + 0, 0, 0, 38, 0, 46, 47, 0, 34, 0, + 35, 42, 22, 44, 29, 36, 39, 0, 0, 193, + 33, 161, 37, 41, 45, 0, 27, 26, 38, 0, + 25, 0, 0, 31, 32, 23, 42, 22, 44, 29, + 36, 39, 0, 0, 0, 33, 101, 37, 41, 45, + 0, 27, 26, 43, 28, 99, 30, 0, 31, 32, + 23, 0, 0, 46, 47, 0, 34, 0, 35, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 28, + 0, 30, 0, 0, 0, 0, 38, 0, 46, 47, + 0, 34, 0, 35, 42, 22, 44, 29, 36, 39, + 0, 0, 0, 33, 101, 37, 41, 0, 0, 27, + 26, 38, 0, 25, 0, 0, 31, 32, 23, 42, + 22, 44, 29, 36, 39, 0, 0, 0, 33, 101, + 37, 41, 0, 0, 27, 26, 43, 28, 25, 30, + 0, 31, 32, 23, 0, 0, 46, 47, 0, 34, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 43, 28, 0, 30, 0, 0, 0, 0, 38, + 0, 46, 47, 0, 34, 0, 35, 42, 22, 44, + 29, 36, 39, 0, 0, 0, 33, 0, 37, 41, + 0, 0, 27, 26, 38, 0, 99, 0, 0, 31, + 32, 23, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 0, 0, 37, 41, 0, 0, 27, 26, 0, + 0, 99, 0, 0, 31, 32, 23 +}; +short yypact[] = +{ + 147,-1000,-1000,-1000,3266, 175,-1000,-1000, 155,-1000, + 187, 865, 141, 141, -47,2905,-1000, -51,3817,-1000, + 13, 42,-1000,4041,-1000,3983,4041,4041, 184, 183, +4041, -36, -36, -32, 182, 180,-1000, 178, 176,-1000, + 170, 162,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, +3266, 865,3817,-1000,1336,-1000, 140, 140, 198,3392, +-1000,1403, 865, 140, 140,3392, 140,-1000, 194,-1000, + 160, 158,3958, -7,2905,-1000, 156,-1000,-1000, 865, + 865, 154,-1000,-1000,3817,3792,3734,3817,3817,3817, +3817,3817,3817,3817, -7, -74, 13,-1000,-1000,4041, + -94,3817,3817,-1000,-1000, 134,1904,3900,4041,4041, +4041,4041,4041,3817,-1000,-1000, -96, -96, -96,3709, +3651, 13,-1000,-1000, -5,4041,3817,3817,3817,3817, +3817,3817, -70,-1000,1269, 141,-1000,-1000,-1000, 196, + 194,-1000,-1000,-1000,1403,1804,-1000, -44,1202,-1000, +-1000,1804,-1000,-1000,1403,-1000, 196,3140,3817, 81, + 189,3817,3208, -65,-1000, 13, 34,3817,1135,1068, + -63,2815,-1000,2995,-1000,3074,4066,4066,4066,4066, +4066,4066,-1000,4066,-1000, -36,2725,2905, 5,3417, +-1000,3417,-1000,4041, -96, 20, 20, -96, -96, -96, + 85,2905,-1000, 130,-1000, 127,4041, 13,2635,2635, +2635, 126, 189,2635,2635, 88,-1000, 865,-1000,-1000, +-1000,-1000,1001,-1000, 195,-1000,-1000,-1000, 104, 27, +-1000,2542,4041,4041,4041,3626, 123,3875,3568,3543, +3875, -7, 13,3875,3817,2542,-1000,-1000, 119,-1000, +3817,-1000, -7,-1000,2905,2905, 13,3417,-1000,-1000, +-1000, 13,3417,3417, 80,-1000,3417,3417,3417,-1000, + 932, -79,-1000,-1000,-1000, 149, -7, 193,-1000, 13, + 13, 13,3208,3817, 3, 636,3334,3485,-1000,4066, +-1000,3208, 52, 193, 193, 15,2905,-1000,2905,2452, + 86, 75,2362, 118,1703,1603,1503,-1000, 143,3817, + 194, 47,-1000, 111, -7,3875,-1000, 141,-1000,-1000, +-1000,-1000,-1000,3417,-1000,-1000, -4,-1000, -4,3417, +-1000,3817,2272,3140, 193, 3,-1000,3208, 865,2174, + 60, 59, 48,2084,1994, 194, 47,1403, 796,-1000, +-1000,-1000,-1000,-1000, 140,3140, 193,-1000,-1000,-1000, + 47,1403, 193,-1000,1403,-1000 +}; +short yypgo[] = +{ + 0, 263, 508, 40, 30, 262, 12, 261, 242, 201, + 45, 48, 259, 8, 3, 5, 408, 7, 0, 392, + 254, 253, 251, 248, 245, 243, 237, 2, 231, 212, + 80, 230, 1, 404, 17, 19, 97, 89, 229, 228, + 226, 224, 223, 222, 220, 219, 218, 217, 213 +}; +short yyr1[] = +{ + 0, 40, 40, 36, 36, 37, 37, 33, 33, 26, + 26, 24, 24, 41, 22, 42, 22, 43, 22, 20, + 20, 23, 30, 30, 34, 34, 35, 35, 29, 29, + 15, 15, 1, 1, 10, 11, 11, 11, 11, 11, + 11, 11, 44, 11, 12, 12, 6, 6, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 5, 5, 7, 7, 7, 39, 39, 28, 28, 28, + 28, 31, 31, 9, 9, 45, 13, 32, 32, 14, + 14, 14, 14, 14, 14, 14, 14, 27, 27, 16, + 16, 46, 47, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 48, 16, 16, 17, 17, + 38, 38, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 18, 18, 18, 18, 21, 21, + 21, 19, 19, 19, 25 +}; +short yyr2[] = +{ + 0, 1, 1, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 0, 12, 0, 10, 0, 8, 1, + 1, 4, 1, 2, 1, 2, 0, 1, 0, 1, + 0, 1, 1, 3, 1, 1, 4, 3, 6, 3, + 4, 4, 0, 9, 1, 3, 1, 3, 3, 5, + 3, 3, 3, 3, 3, 5, 2, 1, 1, 3, + 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 4, 3, 2, 1, 1, 3, 3, + 1, 3, 0, 1, 3, 1, 1, 1, 1, 2, + 2, 1, 2, 1, 2, 0, 4, 1, 2, 4, + 4, 4, 2, 5, 2, 1, 1, 1, 2, 2, + 2, 0, 0, 9, 3, 2, 1, 4, 2, 3, + 2, 2, 3, 2, 2, 0, 3, 2, 1, 2, + 1, 1, 4, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 3, 4, 1, 3, 4, 2, 2, 2, + 2, 2, 4, 3, 2, 1, 6, 6, 3, 6, + 6, 1, 8, 8, 6, 4, 1, 6, 6, 8, + 8, 8, 6, 1, 1, 4, 1, 2, 0, 1, + 3, 1, 1, 1, 4 +}; +short yychk[] = +{ +-1000, -40, -1, 2, -29, -28, 10, 15, -12, -11, + -10, -30, 8, 9, 54, -2, 12, -18, 13, -9, + -8, -19, 87, 110, -13, 105, 102, 101, 46, 89, + 48, 108, 109, 95, 58, 60, 90, 97, 78, 91, + -38, 98, 86, 45, 88, 16, 55, 56, 10, 15, + -29, -30, 11, 10, -17, -16, 47, 49, -26, 52, + -22, -23, -30, 61, 62, 96, -14, -25, 15, 51, + 53, 57, -39, 50, -2, 2, 99, 76, 77, -30, + -30, -20, 86, 89, 93, -37, -36, 38, 39, 40, + 41, 42, 43, 24, 44, 14, -8, 36, 35, 105, + -18, 13, 69, 108, 109, -4, -2, 16, 101, 102, + 103, 104, 107, 19, -8, -9, -8, -8, -8, 13, + 13, -8, -18, -18, -18, 42, 13, 13, 13, 13, + 13, 13, -45, -11, -17, -10, 18, -16, -27, -34, + 15, 10, -27, 10, -46, -2, -27, -16, -17, -27, + -27, -2, -27, -27, -48, -35, -34, 13, 13, -7, + -5, 13, -3, -18, -9, -8, -19, 13, -17, -17, + 13, -2, 10, -2, 10, -2, -2, -2, -2, -2, + -2, -2, -13, -2, -19, 95, -2, -2, 17, -33, + 11, -33, 17, 69, -8, -8, -8, -8, -8, -8, + -6, -2, 17, -6, 17, -6, 42, -8, -2, -2, + -2, -6, -13, -2, -2, 92, 18, -30, 10, -35, + -16, -27, -24, 79, -31, 18, -27, -16, -15, -19, + -14, -2, 14, 37, 40, -33, -4, 93, -37, -36, + 24, 44, -8, 69, 19, -2, 18, 18, -21, 86, + 94, -18, 44, 10, -2, -2, -8, -33, 20, 17, + 17, -8, -33, -33, -33, 17, -33, -33, -33, 16, + -17, -47, 10, -16, 10, 15, 44, -32, 17, -8, + -8, -8, -3, 13, 17, -3, -3, -3, -13, -3, + -19, -3, -6, -32, -32, -33, -2, -19, -2, -2, + -13, -13, -2, -19, -2, -2, -2, 18, 99, -35, + 15, -19, 10, -4, 44, 94, 20, -44, 86, 17, + 17, 17, 17, -33, 17, 17, -33, 17, -33, -33, + 17, 13, -2, -35, -32, 17, -19, -3, -30, -2, + -13, -18, -18, -2, -2, 15, -15, -43, -17, 17, + 17, 17, 17, 17, 17, -35, -32, -16, 18, -27, + -15, -42, -32, -16, -41, -16 +}; +short yydef[] = +{ + -2, -2, 1, 2, 32, 29, 87, 88, 28, 44, + 35, 0, 0, 0, 0, 34, 22, 173, 0, 76, + 77, 174, 176, 0, 93, 0, 0, 0, 144, 0, + 0, 0, 0, 155, 0, 0, 161, 0, 0, 166, + 0, 0, 181, 182, 183, 95, 130, 131, 89, 90, + 33, 0, 0, 23, 0, 128, 0, 0, 111, 0, + 116, 0, 0, 0, 0, 0, 0, 125, 26, 9, + 0, 0, 82, 0, 105, 106, 0, 85, 86, 0, + 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 5, 3, 0, + 173, 0, 0, 150, 151, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 177, 94, 141, 139, 140, 0, + 0, 147, 148, 149, 154, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 0, 37, 39, 129, 109, 107, + 26, 24, 110, 10, 0, 0, 115, 118, 0, 120, + 121, 0, 123, 124, 0, 127, 27, -2, 0, 102, + 83, 0, 80, 173, 57, 58, 104, 0, 0, 0, + 178, 0, 6, 61, 4, 62, -2, -2, -2, -2, + -2, -2, 69, -2, 71, 74, 0, 59, 0, 0, + 7, 0, 158, 0, 136, 133, 134, 135, 137, 138, + 0, 46, 142, 0, 145, 0, 0, 153, 0, 0, + 0, 0, 93, 0, 0, 0, 36, 0, 25, 108, + 112, 114, 0, 11, 119, 91, 122, 126, 0, 174, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 0, 40, 41, 0, 179, + 0, 73, 0, 8, 79, 78, 132, 0, 175, 143, + 146, 152, 0, 0, 0, 165, 0, 0, 0, 96, + 0, 0, 12, 117, 92, 26, 0, 21, 97, 99, + 100, 101, 81, 0, 84, 0, 50, 51, 52, -2, + 54, 48, 0, 184, 42, 0, 60, 72, 47, 0, + 93, 93, 0, 0, 0, 0, 0, 38, 0, 0, + 26, 0, 98, 0, 0, 0, 103, 0, 180, 156, + 157, 159, 160, 0, 164, 167, 0, 168, 0, 0, + 172, 0, 0, -2, 17, 0, 55, 49, 0, 0, + 93, 0, 0, 0, 0, 26, 0, 0, 0, 162, + 163, 169, 170, 171, 0, -2, 15, 18, 43, 113, + 0, 0, 13, 16, 0, 14 +}; +short yytok1[] = +{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, + 13, 17, 103, 101, 11, 102, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 15, + 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 14, 18 +}; +short yytok2[] = +{ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 95, 96, 97, 98, 99, 100, 105, 106, 107, + 108, 109, 110, 111 +}; +long yytok3[] = +{ + 0 +}; +#define YYFLAG -1000 +#define YYERROR goto yyerrlab +#define YYACCEPT return(0) +#define YYABORT return(1) +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 + +#ifdef yydebug +#include "y.debug" +#else +#define yydebug 0 +char* yytoknames[1]; /* for debugging */ +char* yystates[1]; /* for debugging */ +#endif + +/* parser for yacc output */ + +int yynerrs = 0; /* number of errors */ +int yyerrflag = 0; /* error recovery flag */ + +extern int fprint(int, char*, ...); +extern int sprint(char*, char*, ...); + +char* +yytokname(int yyc) +{ + static char x[10]; + + if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0])) + if(yytoknames[yyc-1]) + return yytoknames[yyc-1]; + sprintf(x, "<%d>", yyc); + return x; +} + +char* +yystatname(int yys) +{ + static char x[10]; + + if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0])) + if(yystates[yys]) + return yystates[yys]; + sprintf(x, "<%d>\n", yys); + return x; +} + +long +yylex1(void) +{ + long yychar; + long *t3p; + int c; + + yychar = yylex(); + if(yychar <= 0) { + c = yytok1[0]; + goto out; + } + if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) { + c = yytok1[yychar]; + goto out; + } + if(yychar >= YYPRIVATE) + if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) { + c = yytok2[yychar-YYPRIVATE]; + goto out; + } + for(t3p=yytok3;; t3p+=2) { + c = t3p[0]; + if(c == yychar) { + c = t3p[1]; + goto out; + } + if(c == 0) + break; + } + c = 0; + +out: + if(c == 0) + c = yytok2[1]; /* unknown char */ + if(yydebug >= 3) + printf("lex %.4lX %s\n", yychar, yytokname(c)); + return c; +} + +int +yyparse(void) +{ + struct + { + YYSTYPE yyv; + int yys; + } yys[YYMAXDEPTH], *yyp, *yypt; + short *yyxi; + int yyj, yym, yystate, yyn, yyg; + YYSTYPE save1, save2; + int save3, save4; + long yychar; + + save1 = yylval; + save2 = yyval; + save3 = yynerrs; + save4 = yyerrflag; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyp = &yys[-1]; + goto yystack; + +ret0: + yyn = 0; + goto ret; + +ret1: + yyn = 1; + goto ret; + +ret: + yylval = save1; + yyval = save2; + yynerrs = save3; + yyerrflag = save4; + return yyn; + +yystack: + /* put a state and value onto the stack */ + if(yydebug >= 4) + printf("char %s in %s", yytokname(yychar), yystatname(yystate)); + + yyp++; + if(yyp >= &yys[YYMAXDEPTH]) { + yyerror("yacc stack overflow"); + goto ret1; + } + yyp->yys = yystate; + yyp->yyv = yyval; + +yynewstate: + yyn = yypact[yystate]; + if(yyn <= YYFLAG) + goto yydefault; /* simple state */ + if(yychar < 0) + yychar = yylex1(); + yyn += yychar; + if(yyn < 0 || yyn >= YYLAST) + goto yydefault; + yyn = yyact[yyn]; + if(yychk[yyn] == yychar) { /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if(yyerrflag > 0) + yyerrflag--; + goto yystack; + } + +yydefault: + /* default state action */ + yyn = yydef[yystate]; + if(yyn == -2) { + if(yychar < 0) + yychar = yylex1(); + + /* look through exception table */ + for(yyxi=yyexca;; yyxi+=2) + if(yyxi[0] == -1 && yyxi[1] == yystate) + break; + for(yyxi += 2;; yyxi += 2) { + yyn = yyxi[0]; + if(yyn < 0 || yyn == yychar) + break; + } + yyn = yyxi[1]; + if(yyn < 0) + goto ret0; + } + if(yyn == 0) { + /* error ... attempt to resume parsing */ + switch(yyerrflag) { + case 0: /* brand new error */ + yyerror("syntax error"); + if(yydebug >= 1) { + printf("%s", yystatname(yystate)); + printf("saw %s\n", yytokname(yychar)); + } +yyerrlab: + yynerrs++; + + case 1: + case 2: /* incompletely recovered error ... try again */ + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + while(yyp >= yys) { + yyn = yypact[yyp->yys] + YYERRCODE; + if(yyn >= 0 && yyn < YYLAST) { + yystate = yyact[yyn]; /* simulate a shift of "error" */ + if(yychk[yystate] == YYERRCODE) + goto yystack; + } + + /* the current yyp has no shift onn "error", pop stack */ + if(yydebug >= 2) + printf("error recovery pops state %d, uncovers %d\n", + yyp->yys, (yyp-1)->yys ); + yyp--; + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1; + + case 3: /* no shift yet; clobber input char */ + if(yydebug >= YYEOFCODE) + printf("error recovery discards %s\n", yytokname(yychar)); + if(yychar == YYEOFCODE) + goto ret1; + yychar = -1; + goto yynewstate; /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if(yydebug >= 2) + printf("reduce %d in:\n\t%s", yyn, yystatname(yystate)); + + yypt = yyp; + yyp -= yyr2[yyn]; + yyval = (yyp+1)->yyv; + yym = yyn; + + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyg = yypgo[yyn]; + yyj = yyg + yyp->yys + 1; + + if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) + yystate = yyact[yyg]; + switch(yym) { + +case 1: +#line 98 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (errorflag==0) + winner = (Node *)stat3(PROGRAM, beginloc, yypt[-0].yyv.p, endloc); } break; +case 2: +#line 100 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyclearin; bracecheck(); SYNTAX("bailing out"); } break; +case 13: +#line 124 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 14: +#line 125 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-9].yyv.p, notnull(yypt[-6].yyv.p), yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 15: +#line 126 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 16: +#line 127 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-7].yyv.p, NIL, yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 17: +#line 128 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 18: +#line 129 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat3(IN, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-0].yyv.p); } break; +case 19: +#line 133 "/n/bopp/v7/bwk/awk/awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 20: +#line 134 "/n/bopp/v7/bwk/awk/awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 21: +#line 138 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; +case 26: +#line 150 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.i = 0; } break; +case 28: +#line 155 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.i = 0; } break; +case 30: +#line 161 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = 0; } break; +case 32: +#line 166 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = 0; } break; +case 33: +#line 167 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 34: +#line 171 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = notnull(yypt[-0].yyv.p); } break; +case 35: +#line 175 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 36: +#line 176 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 37: +#line 177 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = pa2stat(yypt[-2].yyv.p, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 38: +#line 178 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = pa2stat(yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 39: +#line 179 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(PASTAT, NIL, yypt[-1].yyv.p); } break; +case 40: +#line 181 "/n/bopp/v7/bwk/awk/awkgram.y" +{ beginloc = linkum(beginloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 41: +#line 183 "/n/bopp/v7/bwk/awk/awkgram.y" +{ endloc = linkum(endloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 42: +#line 184 "/n/bopp/v7/bwk/awk/awkgram.y" +{infunc++;} break; +case 43: +#line 185 "/n/bopp/v7/bwk/awk/awkgram.y" +{ infunc--; curfname=0; defn((Cell *)yypt[-7].yyv.p, yypt[-5].yyv.p, yypt[-1].yyv.p); yyval.p = 0; } break; +case 45: +#line 190 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 47: +#line 195 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 48: +#line 199 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 49: +#line 201 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 50: +#line 203 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 51: +#line 205 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 52: +#line 206 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 53: +#line 208 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 54: +#line 212 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 55: +#line 213 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 56: +#line 214 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 59: +#line 220 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 60: +#line 222 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 61: +#line 224 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 62: +#line 226 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 63: +#line 227 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 64: +#line 228 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 65: +#line 229 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 66: +#line 230 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 67: +#line 231 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 68: +#line 232 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 69: +#line 233 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 70: +#line 235 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 71: +#line 239 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 72: +#line 240 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 73: +#line 241 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("cmd | getline is unsafe"); + else yyval.p = op3(GETLINE, yypt[-0].yyv.p, itonp(yypt[-2].yyv.i), yypt[-3].yyv.p); } break; +case 74: +#line 244 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("cmd | getline is unsafe"); + else yyval.p = op3(GETLINE, (Node*)0, itonp(yypt[-1].yyv.i), yypt[-2].yyv.p); } break; +case 75: +#line 247 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 78: +#line 253 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 79: +#line 254 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 81: +#line 259 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 82: +#line 263 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = rectonode(); } break; +case 84: +#line 265 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 93: +#line 282 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(MATCH, NIL, rectonode(), (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 94: +#line 283 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 95: +#line 287 "/n/bopp/v7/bwk/awk/awkgram.y" +{startreg();} break; +case 96: +#line 287 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.s = yypt[-1].yyv.s; } break; +case 99: +#line 295 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("print | is unsafe"); + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 100: +#line 298 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("print >> is unsafe"); + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 101: +#line 301 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("print > is unsafe"); + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 102: +#line 304 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat3(yypt[-1].yyv.i, yypt[-0].yyv.p, NIL, NIL); } break; +case 103: +#line 305 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 104: +#line 306 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-0].yyv.p), 0); } break; +case 105: +#line 307 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = exptostat(yypt[-0].yyv.p); } break; +case 106: +#line 308 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyclearin; SYNTAX("illegal statement"); } break; +case 109: +#line 317 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (!inloop) SYNTAX("break illegal outside of loops"); + yyval.p = stat1(BREAK, NIL); } break; +case 110: +#line 319 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (!inloop) SYNTAX("continue illegal outside of loops"); + yyval.p = stat1(CONTINUE, NIL); } break; +case 111: +#line 321 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 112: +#line 321 "/n/bopp/v7/bwk/awk/awkgram.y" +{--inloop;} break; +case 113: +#line 322 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(DO, yypt[-6].yyv.p, notnull(yypt[-2].yyv.p)); } break; +case 114: +#line 323 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(EXIT, yypt[-1].yyv.p); } break; +case 115: +#line 324 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(EXIT, NIL); } break; +case 117: +#line 326 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat3(IF, yypt[-3].yyv.p, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 118: +#line 327 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat3(IF, yypt[-1].yyv.p, yypt[-0].yyv.p, NIL); } break; +case 119: +#line 328 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 120: +#line 329 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (infunc) + SYNTAX("next is illegal inside a function"); + yyval.p = stat1(NEXT, NIL); } break; +case 121: +#line 332 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (infunc) + SYNTAX("nextfile is illegal inside a function"); + yyval.p = stat1(NEXTFILE, NIL); } break; +case 122: +#line 335 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(RETURN, yypt[-1].yyv.p); } break; +case 123: +#line 336 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(RETURN, NIL); } break; +case 125: +#line 338 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 126: +#line 338 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat2(WHILE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 127: +#line 339 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = 0; } break; +case 129: +#line 344 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 132: +#line 352 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(DIVEQ, yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 133: +#line 353 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(ADD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 134: +#line 354 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(MINUS, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 135: +#line 355 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(MULT, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 136: +#line 356 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(DIVIDE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 137: +#line 357 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(MOD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 138: +#line 358 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(POWER, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 139: +#line 359 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(UMINUS, yypt[-0].yyv.p); } break; +case 140: +#line 360 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-0].yyv.p; } break; +case 141: +#line 361 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 142: +#line 362 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BLTIN, itonp(yypt[-2].yyv.i), rectonode()); } break; +case 143: +#line 363 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BLTIN, itonp(yypt[-3].yyv.i), yypt[-1].yyv.p); } break; +case 144: +#line 364 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BLTIN, itonp(yypt[-0].yyv.i), rectonode()); } break; +case 145: +#line 365 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-2].yyv.cp,CVAR), NIL); } break; +case 146: +#line 366 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-3].yyv.cp,CVAR), yypt[-1].yyv.p); } break; +case 147: +#line 367 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(CLOSE, yypt[-0].yyv.p); } break; +case 148: +#line 368 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(PREDECR, yypt[-0].yyv.p); } break; +case 149: +#line 369 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(PREINCR, yypt[-0].yyv.p); } break; +case 150: +#line 370 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(POSTDECR, yypt[-1].yyv.p); } break; +case 151: +#line 371 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(POSTINCR, yypt[-1].yyv.p); } break; +case 152: +#line 372 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 153: +#line 373 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, NIL, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 154: +#line 374 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-0].yyv.p, NIL, NIL); } break; +case 155: +#line 375 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, NIL, NIL, NIL); } break; +case 156: +#line 377 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INDEX, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 157: +#line 379 "/n/bopp/v7/bwk/awk/awkgram.y" +{ SYNTAX("index() doesn't permit regular expressions"); + yyval.p = op2(INDEX, yypt[-3].yyv.p, (Node*)yypt[-1].yyv.s); } break; +case 158: +#line 381 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 159: +#line 383 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(yypt[-1].yyv.s, 1)); } break; +case 160: +#line 385 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-1].yyv.p)) + yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(strnode(yypt[-1].yyv.p), 1)); + else + yyval.p = op3(MATCHFCN, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 161: +#line 389 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 162: +#line 391 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p, (Node*)STRING); } break; +case 163: +#line 393 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), (Node*)makedfa(yypt[-1].yyv.s, 1), (Node *)REGEXPR); } break; +case 164: +#line 395 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-3].yyv.p, makearr(yypt[-1].yyv.p), NIL, (Node*)STRING); } break; +case 165: +#line 396 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(yypt[-3].yyv.i, yypt[-1].yyv.p); } break; +case 166: +#line 397 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 167: +#line 399 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(yypt[-3].yyv.s, 1), yypt[-1].yyv.p, rectonode()); } break; +case 168: +#line 401 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-3].yyv.p)) + yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-3].yyv.p), 1), yypt[-1].yyv.p, rectonode()); + else + yyval.p = op4(yypt[-5].yyv.i, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p, rectonode()); } break; +case 169: +#line 406 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(yypt[-5].yyv.s, 1), yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 170: +#line 408 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-5].yyv.p)) + yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-5].yyv.p), 1), yypt[-3].yyv.p, yypt[-1].yyv.p); + else + yyval.p = op4(yypt[-7].yyv.i, (Node *)1, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 171: +#line 413 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 172: +#line 415 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-3].yyv.p, yypt[-1].yyv.p, NIL); } break; +case 175: +#line 421 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(ARRAY, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 176: +#line 422 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(INDIRECT, celltonode(yypt[-0].yyv.cp, CVAR)); } break; +case 177: +#line 423 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(INDIRECT, yypt[-0].yyv.p); } break; +case 178: +#line 427 "/n/bopp/v7/bwk/awk/awkgram.y" +{ arglist = yyval.p = 0; } break; +case 179: +#line 428 "/n/bopp/v7/bwk/awk/awkgram.y" +{ arglist = yyval.p = celltonode(yypt[-0].yyv.cp,CVAR); } break; +case 180: +#line 429 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + checkdup(yypt[-2].yyv.p, yypt[-0].yyv.cp); + arglist = yyval.p = linkum(yypt[-2].yyv.p,celltonode(yypt[-0].yyv.cp,CVAR)); } break; +case 181: +#line 435 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CVAR); } break; +case 182: +#line 436 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(ARG, itonp(yypt[-0].yyv.i)); } break; +case 183: +#line 437 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(VARNF, (Node *) yypt[-0].yyv.cp); } break; +case 184: +#line 442 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; + } + goto yystack; /* stack new state and value */ +} diff --git a/utils/awk/ytab.h b/utils/awk/ytab.h new file mode 100644 index 00000000..d18ddfdb --- /dev/null +++ b/utils/awk/ytab.h @@ -0,0 +1,100 @@ + +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern YYSTYPE yylval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 diff --git a/utils/awk/ytabc.bak b/utils/awk/ytabc.bak new file mode 100644 index 00000000..2a6a938b --- /dev/null +++ b/utils/awk/ytabc.bak @@ -0,0 +1,1623 @@ + +#line 26 "/n/bopp/v7/bwk/awk/awkgram.y" +#include <stdio.h> +#include <string.h> +#include "awk.h" + +void checkdup(Node *list, Cell *item); +int yywrap(void) { return(1); } + +Node *beginloc = 0; +Node *endloc = 0; +int infunc = 0; /* = 1 if in arglist or body of func */ +int inloop = 0; /* = 1 if in while, for, do */ +char *curfname = 0; /* current function name */ +Node *arglist = 0; /* list of args for current function */ + +#line 41 "/n/bopp/v7/bwk/awk/awkgram.y" +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval; +YYSTYPE yyval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 +#define YYEOFCODE 1 +#define YYERRCODE 2 + +#line 445 "/n/bopp/v7/bwk/awk/awkgram.y" + + +void setfname(Cell *p) +{ + if (isarr(p)) + SYNTAX("%s is an array, not a function", p->nval); + else if (isfcn(p)) + SYNTAX("you can't define function %s more than once", p->nval); + curfname = p->nval; +} + +int constnode(Node *p) +{ + return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON; +} + +char *strnode(Node *p) +{ + return ((Cell *)(p->narg[0]))->sval; +} + +Node *notnull(Node *n) +{ + switch (n->nobj) { + case LE: case LT: case EQ: case NE: case GT: case GE: + case BOR: case AND: case NOT: + return n; + default: + return op2(NE, n, nullnode); + } +} + +void checkdup(Node *vl, Cell *cp) /* check if name already in list */ +{ + char *s = cp->nval; + for ( ; vl; vl = vl->nnext) { + if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) { + SYNTAX("duplicate argument %s", s); + break; + } + } +} +short yyexca[] = +{-1, 0, + 1, 28, + 8, 28, + 9, 28, + 12, 28, + 13, 28, + 16, 28, + 45, 28, + 46, 28, + 48, 28, + 54, 28, + 55, 28, + 56, 28, + 58, 28, + 60, 28, + 78, 28, + 86, 28, + 87, 28, + 88, 28, + 89, 28, + 90, 28, + 91, 28, + 95, 28, + 97, 28, + 98, 28, + 101, 28, + 102, 28, + 105, 28, + 108, 28, + 109, 28, + 110, 28, + -2, 0, +-1, 1, + 1, -1, + -2, 0, +-1, 157, + 15, 30, + -2, 0, +-1, 176, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 63, +-1, 177, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 64, +-1, 178, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 65, +-1, 179, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 66, +-1, 180, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 67, +-1, 181, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 68, +-1, 183, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 70, +-1, 289, + 24, 0, + 44, 0, + -2, 53, +-1, 333, + 17, 30, + -2, 0, +-1, 355, + 17, 30, + -2, 0, +}; +#define YYNPROD 185 +#define YYPRIVATE 57344 +#define YYLAST 4177 +short yyact[] = +{ + 17, 277, 138, 66, 243, 228, 253, 54, 24, 43, + 125, 112, 200, 43, 103, 104, 100, 139, 102, 155, + 308, 185, 215, 249, 100, 253, 100, 100, 100, 107, + 105, 100, 122, 123, 124, 223, 107, 206, 43, 82, + 162, 43, 83, 103, 104, 10, 113, 314, 9, 252, + 42, 22, 44, 244, 42, 22, 44, 103, 104, 134, + 142, 113, 146, 190, 278, 352, 149, 150, 152, 153, + 148, 276, 316, 163, 23, 100, 351, 350, 23, 42, + 62, 44, 42, 22, 44, 11, 156, 168, 169, 85, + 253, 51, 321, 79, 80, 232, 190, 86, 135, 133, + 100, 318, 182, 320, 269, 258, 23, 100, 100, 100, + 100, 100, 100, 100, 108, 109, 110, 111, 233, 275, + 112, 234, 190, 110, 111, 43, 100, 112, 335, 190, + 190, 11, 203, 205, 190, 324, 278, 190, 190, 212, + 284, 190, 211, 265, 260, 190, 100, 259, 221, 3, + 141, 188, 100, 16, 226, 140, 331, 6, 156, 141, + 219, 230, 7, 100, 310, 6, 42, 170, 44, 167, + 7, 158, 100, 157, 100, 131, 100, 100, 100, 100, + 100, 100, 100, 130, 100, 48, 251, 100, 100, 129, + 49, 128, 236, 127, 100, 126, 120, 119, 52, 16, + 190, 19, 100, 312, 141, 274, 218, 100, 143, 100, + 100, 100, 4, 154, 100, 100, 217, 271, 144, 132, + 317, 50, 347, 361, 364, 270, 1, 115, 72, 40, + 224, 5, 100, 100, 100, 100, 163, 58, 163, 163, + 163, 163, 20, 67, 163, 222, 100, 293, 61, 288, + 294, 60, 238, 248, 81, 100, 100, 292, 96, 8, + 239, 159, 160, 2, 0, 0, 114, 0, 116, 117, + 118, 300, 301, 121, 164, 0, 282, 0, 285, 286, + 287, 289, 0, 100, 291, 0, 100, 100, 100, 0, + 100, 0, 100, 156, 0, 309, 0, 100, 0, 100, + 100, 0, 0, 100, 0, 100, 100, 100, 0, 0, + 0, 0, 0, 334, 313, 165, 163, 96, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 341, 156, 342, + 333, 0, 340, 100, 0, 0, 0, 230, 100, 346, + 100, 0, 116, 0, 100, 100, 348, 0, 356, 96, + 194, 195, 196, 197, 198, 199, 337, 359, 0, 230, + 0, 360, 362, 156, 0, 355, 0, 0, 207, 0, + 0, 0, 238, 0, 0, 238, 238, 238, 0, 238, + 239, 238, 0, 239, 239, 239, 0, 239, 96, 239, + 0, 0, 21, 0, 96, 0, 0, 0, 338, 0, + 0, 0, 0, 0, 257, 242, 0, 0, 55, 0, + 0, 0, 0, 0, 96, 0, 96, 0, 96, 96, + 96, 96, 96, 96, 96, 0, 96, 238, 0, 96, + 96, 0, 0, 0, 0, 239, 256, 164, 0, 164, + 164, 164, 164, 0, 96, 164, 0, 0, 0, 261, + 0, 96, 96, 96, 0, 0, 96, 96, 0, 0, + 0, 0, 0, 137, 0, 0, 166, 0, 0, 0, + 147, 0, 0, 0, 96, 279, 280, 281, 165, 0, + 165, 165, 165, 165, 0, 0, 165, 184, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 96, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, + 189, 191, 0, 15, 0, 0, 0, 164, 0, 0, + 0, 0, 0, 0, 0, 242, 0, 106, 242, 242, + 242, 0, 242, 0, 242, 0, 0, 0, 0, 96, + 0, 96, 96, 137, 0, 96, 0, 96, 96, 96, + 229, 0, 0, 220, 0, 0, 0, 137, 165, 15, + 0, 15, 0, 227, 0, 235, 0, 0, 145, 0, + 0, 0, 0, 0, 151, 96, 0, 137, 137, 0, + 242, 0, 96, 0, 0, 0, 96, 96, 0, 0, + 0, 0, 0, 171, 173, 175, 176, 177, 178, 179, + 180, 181, 183, 0, 0, 0, 0, 0, 0, 0, + 186, 187, 0, 262, 263, 264, 0, 266, 267, 268, + 0, 0, 201, 0, 0, 0, 0, 0, 201, 201, + 0, 273, 0, 0, 290, 208, 209, 210, 201, 213, + 214, 189, 0, 0, 0, 297, 0, 0, 0, 101, + 0, 0, 0, 295, 0, 0, 0, 303, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 231, 0, 311, + 106, 98, 97, 0, 0, 0, 245, 0, 0, 137, + 241, 43, 28, 0, 30, 0, 0, 0, 0, 0, + 0, 46, 47, 0, 34, 0, 35, 0, 254, 0, + 255, 0, 0, 0, 0, 0, 0, 336, 323, 326, + 328, 329, 0, 0, 38, 0, 0, 0, 189, 0, + 0, 0, 42, 22, 44, 29, 36, 39, 0, 237, + 315, 33, 0, 37, 41, 0, 0, 27, 26, 0, + 0, 99, 0, 0, 31, 32, 23, 0, 0, 0, + 0, 0, 0, 201, 0, 0, 357, 137, 0, 296, + 0, 0, 0, 0, 0, 0, 298, 0, 0, 0, + 363, 299, 302, 365, 0, 304, 305, 306, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 106, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, 18, + 0, 68, 45, 0, 358, 0, 0, 0, 332, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 339, 0, 0, 0, 0, 0, 343, 0, + 344, 43, 28, 56, 30, 57, 73, 69, 59, 70, + 0, 46, 47, 71, 34, 0, 35, 63, 64, 0, + 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, + 0, 0, 77, 78, 38, 53, 0, 16, 18, 0, + 68, 45, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 33, 65, 37, 41, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 31, 32, 23, 0, 0, 0, + 43, 28, 56, 30, 57, 73, 69, 59, 70, 0, + 46, 47, 71, 34, 0, 35, 63, 64, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, + 0, 77, 78, 38, 16, 18, 0, 68, 45, 0, + 307, 42, 22, 44, 29, 36, 39, 0, 0, 0, + 33, 65, 37, 41, 76, 0, 27, 26, 0, 0, + 25, 0, 0, 31, 32, 23, 0, 43, 28, 56, + 30, 57, 73, 69, 59, 70, 0, 46, 47, 71, + 34, 0, 35, 63, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 75, 0, 0, 0, 0, 77, 78, + 38, 272, 0, 16, 18, 0, 68, 45, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 65, 37, + 41, 76, 0, 27, 26, 0, 0, 25, 0, 0, + 31, 32, 23, 0, 0, 0, 43, 28, 56, 30, + 57, 73, 69, 59, 70, 0, 46, 47, 71, 34, + 0, 35, 63, 64, 0, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 0, 0, 0, 77, 78, 38, + 16, 18, 0, 68, 45, 0, 247, 42, 22, 44, + 29, 36, 39, 0, 0, 0, 33, 65, 37, 41, + 76, 0, 27, 26, 0, 0, 25, 0, 0, 31, + 32, 23, 0, 43, 28, 56, 30, 57, 73, 69, + 59, 70, 0, 46, 47, 71, 34, 0, 35, 63, + 64, 0, 0, 0, 0, 0, 0, 75, 0, 0, + 0, 0, 0, 0, 77, 78, 38, 16, 18, 0, + 68, 45, 0, 246, 42, 22, 44, 29, 36, 39, + 0, 0, 0, 33, 65, 37, 41, 76, 0, 27, + 26, 0, 0, 25, 0, 0, 31, 32, 23, 0, + 43, 28, 56, 30, 57, 73, 69, 59, 70, 0, + 46, 47, 71, 34, 0, 35, 63, 64, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, + 0, 77, 78, 38, 16, 18, 0, 68, 45, 0, + 225, 42, 22, 44, 29, 36, 39, 0, 0, 0, + 33, 65, 37, 41, 76, 0, 27, 26, 0, 0, + 25, 0, 0, 31, 32, 23, 0, 43, 28, 56, + 30, 57, 73, 69, 59, 70, 0, 46, 47, 71, + 34, 0, 35, 63, 64, 0, 0, 0, 0, 0, + 0, 75, 0, 0, 0, 0, 0, 0, 77, 78, + 38, 16, 18, 0, 68, 45, 0, 216, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 65, 37, + 41, 76, 0, 27, 26, 0, 0, 25, 0, 0, + 31, 32, 23, 0, 43, 28, 56, 30, 57, 73, + 69, 59, 70, 0, 46, 47, 71, 34, 0, 35, + 63, 64, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 77, 78, 38, 16, 18, + 0, 68, 45, 0, 136, 42, 22, 44, 29, 36, + 39, 0, 0, 0, 33, 65, 37, 41, 76, 0, + 27, 26, 0, 0, 25, 0, 0, 31, 32, 23, + 0, 43, 28, 56, 30, 57, 73, 69, 59, 70, + 0, 46, 47, 71, 34, 0, 35, 63, 64, 0, + 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 77, 78, 38, 16, 18, 0, 68, 45, + 0, 0, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 33, 65, 37, 41, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 31, 32, 23, 0, 43, 28, + 56, 30, 57, 73, 69, 59, 70, 0, 46, 47, + 71, 34, 0, 35, 63, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, + 78, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 0, 0, 33, 65, + 37, 41, 76, 0, 27, 26, 0, 0, 25, 0, + 0, 31, 32, 23, 190, 0, 101, 95, 0, 0, + 330, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 43, 28, + 0, 30, 0, 0, 0, 0, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 84, 0, 33, 0, + 37, 41, 0, 0, 27, 26, 0, 0, 99, 0, + 0, 31, 32, 23, 190, 0, 101, 95, 0, 0, + 327, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 43, 28, + 0, 30, 0, 0, 0, 0, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 84, 0, 33, 0, + 37, 41, 0, 0, 27, 26, 0, 0, 99, 0, + 0, 31, 32, 23, 190, 0, 101, 95, 0, 0, + 325, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 43, 28, + 0, 30, 0, 0, 0, 0, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 42, + 22, 44, 29, 36, 39, 0, 84, 0, 33, 0, + 37, 41, 0, 0, 27, 26, 0, 0, 99, 0, + 0, 31, 32, 23, 141, 0, 0, 101, 95, 140, + 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 31, 32, 23, 190, 0, 101, 95, 0, + 0, 192, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 101, 95, 99, + 0, 354, 31, 32, 23, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 101, 95, 99, + 0, 353, 31, 32, 23, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 101, 95, 99, + 0, 349, 31, 32, 23, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 84, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 31, 32, 23, 101, 95, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 101, 95, 99, 0, 322, + 31, 32, 23, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 101, 95, 99, 0, 319, + 31, 32, 23, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 101, 95, 99, 0, 278, + 31, 32, 23, 0, 0, 0, 93, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 98, 97, 0, + 87, 88, 89, 90, 91, 92, 94, 43, 28, 0, + 30, 0, 0, 0, 0, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 42, 22, + 44, 29, 36, 39, 0, 84, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 0, 190, 99, 101, 95, + 31, 32, 23, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 192, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 250, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 84, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 101, 95, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 0, 0, 87, 88, 89, 90, 91, 92, 94, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 101, 95, 0, + 33, 0, 37, 41, 0, 0, 27, 26, 93, 0, + 99, 0, 0, 31, 32, 23, 0, 0, 0, 0, + 0, 0, 87, 88, 89, 90, 91, 92, 94, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 18, 0, 0, 45, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 0, 0, 33, + 0, 37, 41, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 31, 32, 23, 43, 28, 0, 30, 0, + 73, 0, 0, 0, 0, 46, 47, 0, 34, 0, + 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 78, 38, 0, + 0, 101, 0, 0, 0, 0, 42, 22, 44, 29, + 36, 39, 240, 0, 0, 33, 0, 37, 41, 0, + 0, 27, 26, 98, 97, 25, 0, 0, 31, 32, + 23, 0, 241, 43, 28, 0, 30, 0, 0, 0, + 0, 0, 0, 46, 47, 0, 34, 0, 35, 0, + 0, 0, 0, 0, 12, 13, 0, 0, 16, 18, + 0, 0, 45, 0, 0, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 42, 22, 44, 29, 36, 39, + 0, 237, 0, 33, 0, 37, 41, 0, 0, 27, + 26, 43, 28, 99, 30, 0, 31, 32, 23, 0, + 14, 46, 47, 0, 34, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 0, 0, 101, 0, 0, + 0, 0, 42, 22, 44, 29, 36, 39, 240, 0, + 0, 33, 0, 37, 41, 0, 0, 27, 26, 98, + 0, 25, 0, 0, 31, 32, 23, 0, 241, 43, + 28, 0, 30, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 34, 0, 35, 0, 0, 0, 0, 0, + 0, 0, 141, 0, 0, 18, 0, 140, 45, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 42, 22, 44, 29, 36, 39, 0, 253, 0, 33, + 18, 37, 41, 45, 0, 27, 26, 43, 28, 99, + 30, 0, 31, 32, 23, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 28, 0, 30, 0, 0, 0, 0, + 38, 0, 46, 47, 0, 34, 0, 35, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 0, 37, + 41, 0, 0, 27, 26, 38, 0, 25, 101, 0, + 31, 32, 23, 42, 22, 44, 29, 36, 39, 240, + 0, 0, 33, 0, 37, 41, 0, 0, 27, 26, + 0, 0, 25, 0, 0, 31, 32, 23, 0, 241, + 43, 28, 0, 30, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 174, 0, 0, 283, 0, 0, 45, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 42, 22, 44, 29, 36, 39, 0, 172, 0, + 33, 283, 37, 41, 45, 0, 27, 26, 43, 28, + 99, 30, 0, 31, 32, 23, 0, 0, 46, 47, + 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 28, 0, 30, 0, 0, 0, + 0, 38, 0, 46, 47, 0, 34, 0, 35, 42, + 22, 44, 29, 36, 39, 0, 253, 0, 33, 283, + 37, 41, 45, 0, 27, 26, 38, 0, 25, 0, + 0, 31, 32, 23, 42, 22, 44, 29, 36, 39, + 0, 0, 0, 33, 18, 37, 41, 45, 204, 27, + 26, 43, 28, 25, 30, 0, 31, 32, 23, 0, + 0, 46, 47, 0, 34, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 43, 28, 0, 30, + 0, 0, 0, 0, 38, 0, 46, 47, 0, 34, + 0, 35, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 33, 18, 37, 41, 45, 202, 27, 26, 38, + 0, 25, 0, 0, 31, 32, 23, 42, 22, 44, + 29, 36, 39, 0, 174, 0, 33, 18, 37, 41, + 45, 0, 27, 26, 43, 28, 25, 30, 0, 31, + 32, 23, 0, 0, 46, 47, 0, 34, 0, 35, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, + 28, 0, 30, 0, 0, 0, 0, 38, 0, 46, + 47, 0, 34, 0, 35, 42, 22, 44, 29, 36, + 39, 0, 172, 0, 33, 18, 37, 41, 45, 0, + 27, 26, 38, 0, 25, 0, 0, 31, 32, 23, + 42, 22, 44, 29, 36, 39, 0, 0, 0, 33, + 18, 37, 41, 45, 0, 27, 26, 43, 28, 25, + 30, 0, 31, 32, 23, 0, 0, 46, 47, 0, + 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 28, 0, 30, 0, 0, 0, 0, + 38, 0, 46, 47, 0, 34, 0, 35, 42, 22, + 44, 29, 36, 39, 0, 0, 0, 33, 283, 37, + 41, 45, 0, 27, 26, 38, 0, 25, 0, 0, + 31, 32, 23, 42, 22, 44, 29, 36, 39, 0, + 0, 0, 33, 101, 37, 41, 0, 0, 27, 26, + 43, 28, 25, 30, 0, 31, 32, 23, 0, 0, + 46, 47, 0, 34, 0, 35, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 43, 28, 0, 30, 0, + 0, 0, 0, 38, 0, 46, 47, 0, 34, 0, + 35, 42, 22, 44, 29, 36, 39, 0, 0, 193, + 33, 161, 37, 41, 45, 0, 27, 26, 38, 0, + 25, 0, 0, 31, 32, 23, 42, 22, 44, 29, + 36, 39, 0, 0, 0, 33, 101, 37, 41, 45, + 0, 27, 26, 43, 28, 99, 30, 0, 31, 32, + 23, 0, 0, 46, 47, 0, 34, 0, 35, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 28, + 0, 30, 0, 0, 0, 0, 38, 0, 46, 47, + 0, 34, 0, 35, 42, 22, 44, 29, 36, 39, + 0, 0, 0, 33, 101, 37, 41, 0, 0, 27, + 26, 38, 0, 25, 0, 0, 31, 32, 23, 42, + 22, 44, 29, 36, 39, 0, 0, 0, 33, 101, + 37, 41, 0, 0, 27, 26, 43, 28, 25, 30, + 0, 31, 32, 23, 0, 0, 46, 47, 0, 34, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 43, 28, 0, 30, 0, 0, 0, 0, 38, + 0, 46, 47, 0, 34, 0, 35, 42, 22, 44, + 29, 36, 39, 0, 0, 0, 33, 0, 37, 41, + 0, 0, 27, 26, 38, 0, 99, 0, 0, 31, + 32, 23, 42, 22, 44, 29, 36, 39, 0, 0, + 0, 0, 0, 37, 41, 0, 0, 27, 26, 0, + 0, 99, 0, 0, 31, 32, 23 +}; +short yypact[] = +{ + 147,-1000,-1000,-1000,3266, 175,-1000,-1000, 155,-1000, + 187, 865, 141, 141, -47,2905,-1000, -51,3817,-1000, + 13, 42,-1000,4041,-1000,3983,4041,4041, 184, 183, +4041, -36, -36, -32, 182, 180,-1000, 178, 176,-1000, + 170, 162,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, +3266, 865,3817,-1000,1336,-1000, 140, 140, 198,3392, +-1000,1403, 865, 140, 140,3392, 140,-1000, 194,-1000, + 160, 158,3958, -7,2905,-1000, 156,-1000,-1000, 865, + 865, 154,-1000,-1000,3817,3792,3734,3817,3817,3817, +3817,3817,3817,3817, -7, -74, 13,-1000,-1000,4041, + -94,3817,3817,-1000,-1000, 134,1904,3900,4041,4041, +4041,4041,4041,3817,-1000,-1000, -96, -96, -96,3709, +3651, 13,-1000,-1000, -5,4041,3817,3817,3817,3817, +3817,3817, -70,-1000,1269, 141,-1000,-1000,-1000, 196, + 194,-1000,-1000,-1000,1403,1804,-1000, -44,1202,-1000, +-1000,1804,-1000,-1000,1403,-1000, 196,3140,3817, 81, + 189,3817,3208, -65,-1000, 13, 34,3817,1135,1068, + -63,2815,-1000,2995,-1000,3074,4066,4066,4066,4066, +4066,4066,-1000,4066,-1000, -36,2725,2905, 5,3417, +-1000,3417,-1000,4041, -96, 20, 20, -96, -96, -96, + 85,2905,-1000, 130,-1000, 127,4041, 13,2635,2635, +2635, 126, 189,2635,2635, 88,-1000, 865,-1000,-1000, +-1000,-1000,1001,-1000, 195,-1000,-1000,-1000, 104, 27, +-1000,2542,4041,4041,4041,3626, 123,3875,3568,3543, +3875, -7, 13,3875,3817,2542,-1000,-1000, 119,-1000, +3817,-1000, -7,-1000,2905,2905, 13,3417,-1000,-1000, +-1000, 13,3417,3417, 80,-1000,3417,3417,3417,-1000, + 932, -79,-1000,-1000,-1000, 149, -7, 193,-1000, 13, + 13, 13,3208,3817, 3, 636,3334,3485,-1000,4066, +-1000,3208, 52, 193, 193, 15,2905,-1000,2905,2452, + 86, 75,2362, 118,1703,1603,1503,-1000, 143,3817, + 194, 47,-1000, 111, -7,3875,-1000, 141,-1000,-1000, +-1000,-1000,-1000,3417,-1000,-1000, -4,-1000, -4,3417, +-1000,3817,2272,3140, 193, 3,-1000,3208, 865,2174, + 60, 59, 48,2084,1994, 194, 47,1403, 796,-1000, +-1000,-1000,-1000,-1000, 140,3140, 193,-1000,-1000,-1000, + 47,1403, 193,-1000,1403,-1000 +}; +short yypgo[] = +{ + 0, 263, 508, 40, 30, 262, 12, 261, 242, 201, + 45, 48, 259, 8, 3, 5, 408, 7, 0, 392, + 254, 253, 251, 248, 245, 243, 237, 2, 231, 212, + 80, 230, 1, 404, 17, 19, 97, 89, 229, 228, + 226, 224, 223, 222, 220, 219, 218, 217, 213 +}; +short yyr1[] = +{ + 0, 40, 40, 36, 36, 37, 37, 33, 33, 26, + 26, 24, 24, 41, 22, 42, 22, 43, 22, 20, + 20, 23, 30, 30, 34, 34, 35, 35, 29, 29, + 15, 15, 1, 1, 10, 11, 11, 11, 11, 11, + 11, 11, 44, 11, 12, 12, 6, 6, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 5, 5, 7, 7, 7, 39, 39, 28, 28, 28, + 28, 31, 31, 9, 9, 45, 13, 32, 32, 14, + 14, 14, 14, 14, 14, 14, 14, 27, 27, 16, + 16, 46, 47, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 48, 16, 16, 17, 17, + 38, 38, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 18, 18, 18, 18, 21, 21, + 21, 19, 19, 19, 25 +}; +short yyr2[] = +{ + 0, 1, 1, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 0, 12, 0, 10, 0, 8, 1, + 1, 4, 1, 2, 1, 2, 0, 1, 0, 1, + 0, 1, 1, 3, 1, 1, 4, 3, 6, 3, + 4, 4, 0, 9, 1, 3, 1, 3, 3, 5, + 3, 3, 3, 3, 3, 5, 2, 1, 1, 3, + 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 4, 3, 2, 1, 1, 3, 3, + 1, 3, 0, 1, 3, 1, 1, 1, 1, 2, + 2, 1, 2, 1, 2, 0, 4, 1, 2, 4, + 4, 4, 2, 5, 2, 1, 1, 1, 2, 2, + 2, 0, 0, 9, 3, 2, 1, 4, 2, 3, + 2, 2, 3, 2, 2, 0, 3, 2, 1, 2, + 1, 1, 4, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 3, 4, 1, 3, 4, 2, 2, 2, + 2, 2, 4, 3, 2, 1, 6, 6, 3, 6, + 6, 1, 8, 8, 6, 4, 1, 6, 6, 8, + 8, 8, 6, 1, 1, 4, 1, 2, 0, 1, + 3, 1, 1, 1, 4 +}; +short yychk[] = +{ +-1000, -40, -1, 2, -29, -28, 10, 15, -12, -11, + -10, -30, 8, 9, 54, -2, 12, -18, 13, -9, + -8, -19, 87, 110, -13, 105, 102, 101, 46, 89, + 48, 108, 109, 95, 58, 60, 90, 97, 78, 91, + -38, 98, 86, 45, 88, 16, 55, 56, 10, 15, + -29, -30, 11, 10, -17, -16, 47, 49, -26, 52, + -22, -23, -30, 61, 62, 96, -14, -25, 15, 51, + 53, 57, -39, 50, -2, 2, 99, 76, 77, -30, + -30, -20, 86, 89, 93, -37, -36, 38, 39, 40, + 41, 42, 43, 24, 44, 14, -8, 36, 35, 105, + -18, 13, 69, 108, 109, -4, -2, 16, 101, 102, + 103, 104, 107, 19, -8, -9, -8, -8, -8, 13, + 13, -8, -18, -18, -18, 42, 13, 13, 13, 13, + 13, 13, -45, -11, -17, -10, 18, -16, -27, -34, + 15, 10, -27, 10, -46, -2, -27, -16, -17, -27, + -27, -2, -27, -27, -48, -35, -34, 13, 13, -7, + -5, 13, -3, -18, -9, -8, -19, 13, -17, -17, + 13, -2, 10, -2, 10, -2, -2, -2, -2, -2, + -2, -2, -13, -2, -19, 95, -2, -2, 17, -33, + 11, -33, 17, 69, -8, -8, -8, -8, -8, -8, + -6, -2, 17, -6, 17, -6, 42, -8, -2, -2, + -2, -6, -13, -2, -2, 92, 18, -30, 10, -35, + -16, -27, -24, 79, -31, 18, -27, -16, -15, -19, + -14, -2, 14, 37, 40, -33, -4, 93, -37, -36, + 24, 44, -8, 69, 19, -2, 18, 18, -21, 86, + 94, -18, 44, 10, -2, -2, -8, -33, 20, 17, + 17, -8, -33, -33, -33, 17, -33, -33, -33, 16, + -17, -47, 10, -16, 10, 15, 44, -32, 17, -8, + -8, -8, -3, 13, 17, -3, -3, -3, -13, -3, + -19, -3, -6, -32, -32, -33, -2, -19, -2, -2, + -13, -13, -2, -19, -2, -2, -2, 18, 99, -35, + 15, -19, 10, -4, 44, 94, 20, -44, 86, 17, + 17, 17, 17, -33, 17, 17, -33, 17, -33, -33, + 17, 13, -2, -35, -32, 17, -19, -3, -30, -2, + -13, -18, -18, -2, -2, 15, -15, -43, -17, 17, + 17, 17, 17, 17, 17, -35, -32, -16, 18, -27, + -15, -42, -32, -16, -41, -16 +}; +short yydef[] = +{ + -2, -2, 1, 2, 32, 29, 87, 88, 28, 44, + 35, 0, 0, 0, 0, 34, 22, 173, 0, 76, + 77, 174, 176, 0, 93, 0, 0, 0, 144, 0, + 0, 0, 0, 155, 0, 0, 161, 0, 0, 166, + 0, 0, 181, 182, 183, 95, 130, 131, 89, 90, + 33, 0, 0, 23, 0, 128, 0, 0, 111, 0, + 116, 0, 0, 0, 0, 0, 0, 125, 26, 9, + 0, 0, 82, 0, 105, 106, 0, 85, 86, 0, + 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 5, 3, 0, + 173, 0, 0, 150, 151, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 177, 94, 141, 139, 140, 0, + 0, 147, 148, 149, 154, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 0, 37, 39, 129, 109, 107, + 26, 24, 110, 10, 0, 0, 115, 118, 0, 120, + 121, 0, 123, 124, 0, 127, 27, -2, 0, 102, + 83, 0, 80, 173, 57, 58, 104, 0, 0, 0, + 178, 0, 6, 61, 4, 62, -2, -2, -2, -2, + -2, -2, 69, -2, 71, 74, 0, 59, 0, 0, + 7, 0, 158, 0, 136, 133, 134, 135, 137, 138, + 0, 46, 142, 0, 145, 0, 0, 153, 0, 0, + 0, 0, 93, 0, 0, 0, 36, 0, 25, 108, + 112, 114, 0, 11, 119, 91, 122, 126, 0, 174, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 0, 40, 41, 0, 179, + 0, 73, 0, 8, 79, 78, 132, 0, 175, 143, + 146, 152, 0, 0, 0, 165, 0, 0, 0, 96, + 0, 0, 12, 117, 92, 26, 0, 21, 97, 99, + 100, 101, 81, 0, 84, 0, 50, 51, 52, -2, + 54, 48, 0, 184, 42, 0, 60, 72, 47, 0, + 93, 93, 0, 0, 0, 0, 0, 38, 0, 0, + 26, 0, 98, 0, 0, 0, 103, 0, 180, 156, + 157, 159, 160, 0, 164, 167, 0, 168, 0, 0, + 172, 0, 0, -2, 17, 0, 55, 49, 0, 0, + 93, 0, 0, 0, 0, 26, 0, 0, 0, 162, + 163, 169, 170, 171, 0, -2, 15, 18, 43, 113, + 0, 0, 13, 16, 0, 14 +}; +short yytok1[] = +{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, + 13, 17, 103, 101, 11, 102, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 15, + 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 14, 18 +}; +short yytok2[] = +{ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 95, 96, 97, 98, 99, 100, 105, 106, 107, + 108, 109, 110, 111 +}; +long yytok3[] = +{ + 0 +}; +#define YYFLAG -1000 +#define YYERROR goto yyerrlab +#define YYACCEPT return(0) +#define YYABORT return(1) +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 + +#ifdef yydebug +#include "y.debug" +#else +#define yydebug 0 +char* yytoknames[1]; /* for debugging */ +char* yystates[1]; /* for debugging */ +#endif + +/* parser for yacc output */ + +int yynerrs = 0; /* number of errors */ +int yyerrflag = 0; /* error recovery flag */ + +extern int fprint(int, char*, ...); +extern int sprint(char*, char*, ...); + +char* +yytokname(int yyc) +{ + static char x[10]; + + if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0])) + if(yytoknames[yyc-1]) + return yytoknames[yyc-1]; + sprintf(x, "<%d>", yyc); + return x; +} + +char* +yystatname(int yys) +{ + static char x[10]; + + if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0])) + if(yystates[yys]) + return yystates[yys]; + sprintf(x, "<%d>\n", yys); + return x; +} + +long +yylex1(void) +{ + long yychar; + long *t3p; + int c; + + yychar = yylex(); + if(yychar <= 0) { + c = yytok1[0]; + goto out; + } + if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) { + c = yytok1[yychar]; + goto out; + } + if(yychar >= YYPRIVATE) + if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) { + c = yytok2[yychar-YYPRIVATE]; + goto out; + } + for(t3p=yytok3;; t3p+=2) { + c = t3p[0]; + if(c == yychar) { + c = t3p[1]; + goto out; + } + if(c == 0) + break; + } + c = 0; + +out: + if(c == 0) + c = yytok2[1]; /* unknown char */ + if(yydebug >= 3) + printf("lex %.4lX %s\n", yychar, yytokname(c)); + return c; +} + +int +yyparse(void) +{ + struct + { + YYSTYPE yyv; + int yys; + } yys[YYMAXDEPTH], *yyp, *yypt; + short *yyxi; + int yyj, yym, yystate, yyn, yyg; + YYSTYPE save1, save2; + int save3, save4; + long yychar; + + save1 = yylval; + save2 = yyval; + save3 = yynerrs; + save4 = yyerrflag; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyp = &yys[-1]; + goto yystack; + +ret0: + yyn = 0; + goto ret; + +ret1: + yyn = 1; + goto ret; + +ret: + yylval = save1; + yyval = save2; + yynerrs = save3; + yyerrflag = save4; + return yyn; + +yystack: + /* put a state and value onto the stack */ + if(yydebug >= 4) + printf("char %s in %s", yytokname(yychar), yystatname(yystate)); + + yyp++; + if(yyp >= &yys[YYMAXDEPTH]) { + yyerror("yacc stack overflow"); + goto ret1; + } + yyp->yys = yystate; + yyp->yyv = yyval; + +yynewstate: + yyn = yypact[yystate]; + if(yyn <= YYFLAG) + goto yydefault; /* simple state */ + if(yychar < 0) + yychar = yylex1(); + yyn += yychar; + if(yyn < 0 || yyn >= YYLAST) + goto yydefault; + yyn = yyact[yyn]; + if(yychk[yyn] == yychar) { /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if(yyerrflag > 0) + yyerrflag--; + goto yystack; + } + +yydefault: + /* default state action */ + yyn = yydef[yystate]; + if(yyn == -2) { + if(yychar < 0) + yychar = yylex1(); + + /* look through exception table */ + for(yyxi=yyexca;; yyxi+=2) + if(yyxi[0] == -1 && yyxi[1] == yystate) + break; + for(yyxi += 2;; yyxi += 2) { + yyn = yyxi[0]; + if(yyn < 0 || yyn == yychar) + break; + } + yyn = yyxi[1]; + if(yyn < 0) + goto ret0; + } + if(yyn == 0) { + /* error ... attempt to resume parsing */ + switch(yyerrflag) { + case 0: /* brand new error */ + yyerror("syntax error"); + if(yydebug >= 1) { + printf("%s", yystatname(yystate)); + printf("saw %s\n", yytokname(yychar)); + } +yyerrlab: + yynerrs++; + + case 1: + case 2: /* incompletely recovered error ... try again */ + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + while(yyp >= yys) { + yyn = yypact[yyp->yys] + YYERRCODE; + if(yyn >= 0 && yyn < YYLAST) { + yystate = yyact[yyn]; /* simulate a shift of "error" */ + if(yychk[yystate] == YYERRCODE) + goto yystack; + } + + /* the current yyp has no shift onn "error", pop stack */ + if(yydebug >= 2) + printf("error recovery pops state %d, uncovers %d\n", + yyp->yys, (yyp-1)->yys ); + yyp--; + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1; + + case 3: /* no shift yet; clobber input char */ + if(yydebug >= YYEOFCODE) + printf("error recovery discards %s\n", yytokname(yychar)); + if(yychar == YYEOFCODE) + goto ret1; + yychar = -1; + goto yynewstate; /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if(yydebug >= 2) + printf("reduce %d in:\n\t%s", yyn, yystatname(yystate)); + + yypt = yyp; + yyp -= yyr2[yyn]; + yyval = (yyp+1)->yyv; + yym = yyn; + + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyg = yypgo[yyn]; + yyj = yyg + yyp->yys + 1; + + if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) + yystate = yyact[yyg]; + switch(yym) { + +case 1: +#line 98 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (errorflag==0) + winner = (Node *)stat3(PROGRAM, beginloc, yypt[-0].yyv.p, endloc); } break; +case 2: +#line 100 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyclearin; bracecheck(); SYNTAX("bailing out"); } break; +case 13: +#line 124 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 14: +#line 125 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-9].yyv.p, notnull(yypt[-6].yyv.p), yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 15: +#line 126 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 16: +#line 127 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-7].yyv.p, NIL, yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 17: +#line 128 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 18: +#line 129 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat3(IN, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-0].yyv.p); } break; +case 19: +#line 133 "/n/bopp/v7/bwk/awk/awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 20: +#line 134 "/n/bopp/v7/bwk/awk/awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 21: +#line 138 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; +case 26: +#line 150 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.i = 0; } break; +case 28: +#line 155 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.i = 0; } break; +case 30: +#line 161 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = 0; } break; +case 32: +#line 166 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = 0; } break; +case 33: +#line 167 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 34: +#line 171 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = notnull(yypt[-0].yyv.p); } break; +case 35: +#line 175 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 36: +#line 176 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 37: +#line 177 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = pa2stat(yypt[-2].yyv.p, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 38: +#line 178 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = pa2stat(yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 39: +#line 179 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(PASTAT, NIL, yypt[-1].yyv.p); } break; +case 40: +#line 181 "/n/bopp/v7/bwk/awk/awkgram.y" +{ beginloc = linkum(beginloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 41: +#line 183 "/n/bopp/v7/bwk/awk/awkgram.y" +{ endloc = linkum(endloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 42: +#line 184 "/n/bopp/v7/bwk/awk/awkgram.y" +{infunc++;} break; +case 43: +#line 185 "/n/bopp/v7/bwk/awk/awkgram.y" +{ infunc--; curfname=0; defn((Cell *)yypt[-7].yyv.p, yypt[-5].yyv.p, yypt[-1].yyv.p); yyval.p = 0; } break; +case 45: +#line 190 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 47: +#line 195 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 48: +#line 199 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 49: +#line 201 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 50: +#line 203 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 51: +#line 205 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 52: +#line 206 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 53: +#line 208 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 54: +#line 212 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 55: +#line 213 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 56: +#line 214 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 59: +#line 220 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 60: +#line 222 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 61: +#line 224 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 62: +#line 226 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 63: +#line 227 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 64: +#line 228 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 65: +#line 229 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 66: +#line 230 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 67: +#line 231 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 68: +#line 232 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 69: +#line 233 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 70: +#line 235 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 71: +#line 239 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 72: +#line 240 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 73: +#line 241 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("cmd | getline is unsafe"); + else yyval.p = op3(GETLINE, yypt[-0].yyv.p, itonp(yypt[-2].yyv.i), yypt[-3].yyv.p); } break; +case 74: +#line 244 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("cmd | getline is unsafe"); + else yyval.p = op3(GETLINE, (Node*)0, itonp(yypt[-1].yyv.i), yypt[-2].yyv.p); } break; +case 75: +#line 247 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 78: +#line 253 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 79: +#line 254 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 81: +#line 259 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 82: +#line 263 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = rectonode(); } break; +case 84: +#line 265 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 93: +#line 282 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(MATCH, NIL, rectonode(), (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 94: +#line 283 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 95: +#line 287 "/n/bopp/v7/bwk/awk/awkgram.y" +{startreg();} break; +case 96: +#line 287 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.s = yypt[-1].yyv.s; } break; +case 99: +#line 295 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("print | is unsafe"); + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 100: +#line 298 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("print >> is unsafe"); + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 101: +#line 301 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + if (safe) SYNTAX("print > is unsafe"); + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 102: +#line 304 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat3(yypt[-1].yyv.i, yypt[-0].yyv.p, NIL, NIL); } break; +case 103: +#line 305 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 104: +#line 306 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-0].yyv.p), 0); } break; +case 105: +#line 307 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = exptostat(yypt[-0].yyv.p); } break; +case 106: +#line 308 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyclearin; SYNTAX("illegal statement"); } break; +case 109: +#line 317 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (!inloop) SYNTAX("break illegal outside of loops"); + yyval.p = stat1(BREAK, NIL); } break; +case 110: +#line 319 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (!inloop) SYNTAX("continue illegal outside of loops"); + yyval.p = stat1(CONTINUE, NIL); } break; +case 111: +#line 321 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 112: +#line 321 "/n/bopp/v7/bwk/awk/awkgram.y" +{--inloop;} break; +case 113: +#line 322 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat2(DO, yypt[-6].yyv.p, notnull(yypt[-2].yyv.p)); } break; +case 114: +#line 323 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(EXIT, yypt[-1].yyv.p); } break; +case 115: +#line 324 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(EXIT, NIL); } break; +case 117: +#line 326 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat3(IF, yypt[-3].yyv.p, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 118: +#line 327 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat3(IF, yypt[-1].yyv.p, yypt[-0].yyv.p, NIL); } break; +case 119: +#line 328 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 120: +#line 329 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (infunc) + SYNTAX("next is illegal inside a function"); + yyval.p = stat1(NEXT, NIL); } break; +case 121: +#line 332 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (infunc) + SYNTAX("nextfile is illegal inside a function"); + yyval.p = stat1(NEXTFILE, NIL); } break; +case 122: +#line 335 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(RETURN, yypt[-1].yyv.p); } break; +case 123: +#line 336 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = stat1(RETURN, NIL); } break; +case 125: +#line 338 "/n/bopp/v7/bwk/awk/awkgram.y" +{inloop++;} break; +case 126: +#line 338 "/n/bopp/v7/bwk/awk/awkgram.y" +{ --inloop; yyval.p = stat2(WHILE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 127: +#line 339 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = 0; } break; +case 129: +#line 344 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = linkum(yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 132: +#line 352 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(DIVEQ, yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 133: +#line 353 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(ADD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 134: +#line 354 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(MINUS, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 135: +#line 355 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(MULT, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 136: +#line 356 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(DIVIDE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 137: +#line 357 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(MOD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 138: +#line 358 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(POWER, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 139: +#line 359 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(UMINUS, yypt[-0].yyv.p); } break; +case 140: +#line 360 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-0].yyv.p; } break; +case 141: +#line 361 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 142: +#line 362 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BLTIN, itonp(yypt[-2].yyv.i), rectonode()); } break; +case 143: +#line 363 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BLTIN, itonp(yypt[-3].yyv.i), yypt[-1].yyv.p); } break; +case 144: +#line 364 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(BLTIN, itonp(yypt[-0].yyv.i), rectonode()); } break; +case 145: +#line 365 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-2].yyv.cp,CVAR), NIL); } break; +case 146: +#line 366 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-3].yyv.cp,CVAR), yypt[-1].yyv.p); } break; +case 147: +#line 367 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(CLOSE, yypt[-0].yyv.p); } break; +case 148: +#line 368 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(PREDECR, yypt[-0].yyv.p); } break; +case 149: +#line 369 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(PREINCR, yypt[-0].yyv.p); } break; +case 150: +#line 370 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(POSTDECR, yypt[-1].yyv.p); } break; +case 151: +#line 371 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(POSTINCR, yypt[-1].yyv.p); } break; +case 152: +#line 372 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-2].yyv.p, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 153: +#line 373 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, NIL, itonp(yypt[-1].yyv.i), yypt[-0].yyv.p); } break; +case 154: +#line 374 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-0].yyv.p, NIL, NIL); } break; +case 155: +#line 375 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(GETLINE, NIL, NIL, NIL); } break; +case 156: +#line 377 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(INDEX, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 157: +#line 379 "/n/bopp/v7/bwk/awk/awkgram.y" +{ SYNTAX("index() doesn't permit regular expressions"); + yyval.p = op2(INDEX, yypt[-3].yyv.p, (Node*)yypt[-1].yyv.s); } break; +case 158: +#line 381 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 159: +#line 383 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(yypt[-1].yyv.s, 1)); } break; +case 160: +#line 385 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-1].yyv.p)) + yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(strnode(yypt[-1].yyv.p), 1)); + else + yyval.p = op3(MATCHFCN, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 161: +#line 389 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 162: +#line 391 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p, (Node*)STRING); } break; +case 163: +#line 393 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), (Node*)makedfa(yypt[-1].yyv.s, 1), (Node *)REGEXPR); } break; +case 164: +#line 395 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-3].yyv.p, makearr(yypt[-1].yyv.p), NIL, (Node*)STRING); } break; +case 165: +#line 396 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(yypt[-3].yyv.i, yypt[-1].yyv.p); } break; +case 166: +#line 397 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 167: +#line 399 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(yypt[-3].yyv.s, 1), yypt[-1].yyv.p, rectonode()); } break; +case 168: +#line 401 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-3].yyv.p)) + yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-3].yyv.p), 1), yypt[-1].yyv.p, rectonode()); + else + yyval.p = op4(yypt[-5].yyv.i, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p, rectonode()); } break; +case 169: +#line 406 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(yypt[-5].yyv.s, 1), yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 170: +#line 408 "/n/bopp/v7/bwk/awk/awkgram.y" +{ if (constnode(yypt[-5].yyv.p)) + yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-5].yyv.p), 1), yypt[-3].yyv.p, yypt[-1].yyv.p); + else + yyval.p = op4(yypt[-7].yyv.i, (Node *)1, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 171: +#line 413 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 172: +#line 415 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-3].yyv.p, yypt[-1].yyv.p, NIL); } break; +case 175: +#line 421 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op2(ARRAY, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 176: +#line 422 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(INDIRECT, celltonode(yypt[-0].yyv.cp, CVAR)); } break; +case 177: +#line 423 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(INDIRECT, yypt[-0].yyv.p); } break; +case 178: +#line 427 "/n/bopp/v7/bwk/awk/awkgram.y" +{ arglist = yyval.p = 0; } break; +case 179: +#line 428 "/n/bopp/v7/bwk/awk/awkgram.y" +{ arglist = yyval.p = celltonode(yypt[-0].yyv.cp,CVAR); } break; +case 180: +#line 429 "/n/bopp/v7/bwk/awk/awkgram.y" +{ + checkdup(yypt[-2].yyv.p, yypt[-0].yyv.cp); + arglist = yyval.p = linkum(yypt[-2].yyv.p,celltonode(yypt[-0].yyv.cp,CVAR)); } break; +case 181: +#line 435 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CVAR); } break; +case 182: +#line 436 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(ARG, itonp(yypt[-0].yyv.i)); } break; +case 183: +#line 437 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = op1(VARNF, (Node *) yypt[-0].yyv.cp); } break; +case 184: +#line 442 "/n/bopp/v7/bwk/awk/awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; + } + goto yystack; /* stack new state and value */ +} diff --git a/utils/awk/ytabh.bak b/utils/awk/ytabh.bak new file mode 100644 index 00000000..d18ddfdb --- /dev/null +++ b/utils/awk/ytabh.bak @@ -0,0 +1,100 @@ + +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern YYSTYPE yylval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 diff --git a/utils/c2l/Nt.c b/utils/c2l/Nt.c new file mode 100644 index 00000000..bf36e0dd --- /dev/null +++ b/utils/c2l/Nt.c @@ -0,0 +1,131 @@ +#include <windows.h> +#include <lib9.h> + +#define Windows (1<<2) /* hack - can't include cc.h because of clashes */ +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +int +mycreat(char *n, int p) +{ + + return create(n, 1, p); +} + +int +mywait(int *s) +{ + fprint(2, "mywait called\n"); + abort(); + return 0; +} + +int +mydup(int f1, int f2) +{ + int ok; + + ok = _dup2(f1, f2); + if(ok < 0) + return -1; + return f2; +/* + fprint(2, "mydup called\n"); + abort(); + return 0; +*/ +} + +int +mypipe(int *fd) +{ + fprint(2, "mypipe called\n"); + abort(); + return 0; +} + +int +systemtype(int sys) +{ + + return sys&Windows; +} + +int +pathchar(void) +{ + return '/'; +} + +char* +mygetwd(char *path, int len) +{ + return getcwd(path, len); +} + +int +myexec(char *path, char *argv[]) +{ + fprint(2, "myexec called\n"); + abort(); + return 0; +} + +int +myfork(void) +{ + fprint(2, "myfork called\n"); + abort(); + return 0; +} + +/* + * fake mallocs + */ +void* +malloc(uint n) +{ + return mysbrk(n); +} + +void* +calloc(uint m, uint n) +{ + return mysbrk(m*n); +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +void +free(void *p) +{ +} diff --git a/utils/c2l/Plan9.c b/utils/c2l/Plan9.c new file mode 100644 index 00000000..853df40b --- /dev/null +++ b/utils/c2l/Plan9.c @@ -0,0 +1,108 @@ +#include "cc.h" + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +int +mycreat(char *n, int p) +{ + + return create(n, 1, p); +} + +int +mywait(int *s) +{ + int p; + Waitmsg *w; + + if((w = wait()) == nil) + return -1; + else{ + p = w->pid; + *s = 0; + if(w->msg[0]) + *s = 1; + free(w); + return p; + } +} + +int +mydup(int f1, int f2) +{ + return dup(f1,f2); +} + +int +mypipe(int *fd) +{ + return pipe(fd); +} + +int +systemtype(int sys) +{ + + return sys&Plan9; +} + +int +pathchar(void) +{ + return '/'; +} + +char* +mygetwd(char *path, int len) +{ + return getwd(path, len); +} + +int +myexec(char *path, char *argv[]) +{ + return exec(path, argv); +} + +/* + * fake mallocs + */ +void* +malloc(ulong n) +{ + return alloc(n); +} + +void* +calloc(ulong m, ulong n) +{ + return alloc(m*n); +} + +void* +realloc(void*, ulong) +{ + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void +free(void*) +{ +} + +int +myfork(void) +{ + return fork(); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/c2l/Posix.c b/utils/c2l/Posix.c new file mode 100644 index 00000000..065f1e20 --- /dev/null +++ b/utils/c2l/Posix.c @@ -0,0 +1,91 @@ +#include "cc.h" + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +int +mycreat(char *n, int p) +{ + + return create(n, 1, p); +} + +int +mywait(int *s) +{ + return wait(s); +} + +int +mydup(int f1, int f2) +{ + return dup2(f1,f2); +} + +int +mypipe(int *fd) +{ + return pipe(fd); +} + +int +systemtype(int sys) +{ + + return sys&Unix; +} + +int +pathchar(void) +{ + return '/'; +} + +char* +mygetwd(char *path, int len) +{ + return (char*)getcwd(path, len); +} + +int +myexec(char *path, char *argv[]) +{ + return execvp(path, argv); +} + +/* + * fake mallocs + */ +void* +malloc(size_t n) +{ + return alloc(n); +} + +void* +calloc(size_t m, size_t n) +{ + return alloc(m*n); +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void +free(void *p) +{ +} + +int +myfork(void) +{ + return fork(); +} diff --git a/utils/c2l/acid.c b/utils/c2l/acid.c new file mode 100644 index 00000000..c31e600f --- /dev/null +++ b/utils/c2l/acid.c @@ -0,0 +1,13 @@ +#include "cc.h" + +void +acidtype(Type *t) +{ + USED(t); +} + +void +acidvar(Sym *s) +{ + USED(s); +} diff --git a/utils/c2l/bits.c b/utils/c2l/bits.c new file mode 100644 index 00000000..a22ba512 --- /dev/null +++ b/utils/c2l/bits.c @@ -0,0 +1,89 @@ +#include "cc.h" + +Bits +bor(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = a.b[i] | b.b[i]; + return c; +} + +Bits +band(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = a.b[i] & b.b[i]; + return c; +} + +/* +Bits +bnot(Bits a) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = ~a.b[i]; + return c; +} +*/ + +int +bany(Bits *a) +{ + int i; + + for(i=0; i<BITS; i++) + if(a->b[i]) + return 1; + return 0; +} + +int +beq(Bits a, Bits b) +{ + int i; + + for(i=0; i<BITS; i++) + if(a.b[i] != b.b[i]) + return 0; + return 1; +} + +int +bnum(Bits a) +{ + int i; + long b; + + for(i=0; i<BITS; i++) + if(b = a.b[i]) + return 32*i + bitno(b); + diag(Z, "bad in bnum"); + return 0; +} + +Bits +blsh(uint n) +{ + Bits c; + + c = zbits; + c.b[n/32] = 1L << (n%32); + return c; +} + +int +bset(Bits a, uint n) +{ + if(a.b[n/32] & (1L << (n%32))) + return 1; + return 0; +} diff --git a/utils/c2l/c2l.c b/utils/c2l/c2l.c new file mode 100644 index 00000000..f870d640 --- /dev/null +++ b/utils/c2l/c2l.c @@ -0,0 +1,5118 @@ +#define EXTERN + +#include "cc.h" + +/* + * locals, parameters, globals etc of the same name should work ok without having + * to duplicate Syms because the details are on the containing Nodes + */ + +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_FLOAT 4 +#define SZ_IND 4 +#define SZ_VLONG 8 +#define SZ_DOUBLE 8 + +char buf[128], mbuf[128]; +static Sym *sysop, *bioop, *libcop; +static int again; + +#define INFINITY 0x7fffffff +#define STAR 0x80 +#define RET 0x80 + +#define LARR (-1729) + +static void swalk(void); +static int isdec(Node*); +static int isconst(Node*, vlong); +static int cktype(Node*, Node*, int, int); +static void addnode(int, Node*); +static int argpos(Node*, Node*); +static void setdec(Sym*, Type*); +static Type* tcp(Type*); +static int isadt(Type*); +static void aargs(Node*); +static int iteq(Type*, Type*); +static Node* arg(Node*, int); +static void etgen2(Sym*); +static Node* ckneg(Node*); +static Sym* suename(Type*); +static int isnil(Node*); +static void sliceasgn(Node*); +static Node* lastn(Node*); +static char* hasm(void); +static void prn(Node*, int); +static int isfn(Type*); + +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] */ +}; + +enum{ + TCFD = 1, + TCFC = 2, + TCPC = 4, + TCAR = 8, + TCIN = 16, + TCGEN = TCFD|TCFC|TCPC|TCAR, + TCALL = TCFD|TCFC|TCPC|TCAR|TCIN, +}; + +enum{ + SGLOB, + SPARM, + SAUTO, +}; + +typedef struct Scope Scope; + +struct Scope{ + Node *n; + int k; + Scope *nxt; +}; + +static void +prtyp(Type *t, char *s, int nl) +{ + print("%s: ", s); + if(t == T){ + print("nil"); + if(nl) + print("\n"); + return; + } + while(t != T){ + print("%d(%d)[%x] ", t->etype, t->mark, (int)t); + if(isadt(t)) + break; + t = t->link; + } + if(nl) + print("\n"); +} + +static Node* +func(Node *n) +{ + while(n != Z && n->op != OFUNC) + n = n->left; + return n; +} + +static void +setmain(Node *n) +{ + inmain |= n->left->op == ONAME && strcmp(n->left->sym->name, "main") == 0; +} + +static Node* +protoname(Node *n) +{ + do + n = n->left; + while(n != Z && n->op != ONAME && n->op != ODOTDOT); + return n; +} + +static Type* +prototype(Node *n, Type *t) +{ + for( ; n != Z ; n = n->left){ + switch(n->op){ + case OARRAY: + t = typ(TARRAY, t); + t->width = 0; + break; + case OIND: + t = typ(TIND, t); + break; + case OFUNC: + t = typ(TFUNC, t); + t->down = fnproto(n); + break; + } + } + return t; +} + +static Scope *scopes, *freescopes; + +static void +pushdcl(Node *n, int c) +{ + Sym *s; + + if(passes){ + s = n->sym; + push1(s); + if(c != CAUTO || s->class != CSTATIC) + s->class = c; + s->type = n->type; + } +} + +static void +pushparams(Node *n) +{ + if(n == Z) + return; + if(passes){ + if(n->op == OLIST){ + pushparams(n->left); + pushparams(n->right); + } + else if(n->op == OPROTO){ + n = protoname(n); + if(n != Z && n->op == ONAME) + pushdcl(n, CPARAM); + } + else if(n->op == ONAME){ + addnode(OPROTO, n); + pushdcl(n, CPARAM); + } + else if(n->op != ODOTDOT) + diag(Z, "bad op in pushparams"); + } +} + +static void +pushscope(Node *n, int k) +{ + Scope *s; + + if(freescopes != nil){ + s = freescopes; + freescopes = freescopes->nxt; + } + else + s = (Scope*)malloc(sizeof(Scope)); + s->n = n; + s->k = k; + s->nxt = scopes; + scopes = s; + if(passes && (k == SPARM || k == SAUTO)) + markdcl(); + if(k == SPARM) + pushparams(n->right); +} + +static void +popscope(void) +{ + int k; + Scope *s; + + s = scopes; + k = s->k; + scopes = scopes->nxt; + s->nxt = freescopes; + freescopes = s; + if(passes && (k == SPARM || k == SAUTO)) + revertdcl(); +} + +static Node* +curfn(void) +{ + Scope *s; + + for(s = scopes; s != nil; s = s->nxt) + if(s->k == SPARM) + return s->n; + return Z; +} + +static void +marktype(Type *t, int tc) +{ + t->mark = tc; +} + +static int +marked(Type *t) +{ + return t == T ? 0 : t->mark; +} + +static Sym* +decsym(Node *n) +{ + if(n == Z) + return S; + if(n->op == OFUNC){ + if(n->left->op == ONAME) + return n->left->sym; + return S; + } + if(n->op == ODAS) + return n->left->sym; + return n->sym; +} + +static void +trep(Type *t1, Type *t) +{ + int l; + Sym *s; + Type *t2; + + if(t1 != T){ + l = t1->lineno; + s = t1->sym; + t2 = t1->down; + *t1 = *t; + t1->down = t2; + t1->sym = s; + t1->lineno = l; + } +} + +static void +tind(Node *n) +{ + if(n == Z) + return; + n = protoname(n); + if(n != Z && n->type != T){ + n->type = tcp(n->type->link); + marktype(n->type, TCIN); + } +} + +static void +tcon(Node *n, Type *t) +{ + Type *tt; + + if(n->garb) + return; + n->garb = 1; + again = 1; + switch(n->op){ + case OCONST: + if(t->mark == TCFD && !isnil(n)) + addnode(OFILDES, n); + n->type = t; + break; + case OCAST: + tcon(n->left, t); + *n = *n->left; + n->type = t; + break; + case ONAME: + n->sym->type = t; + n->type = t; + setdec(n->sym, t); + break; + case ODOT: + case ODOTIND: + trep(n->type, t); + n->type = t; + break; + case OARRIND: + tt = n->left->type; + if(tt != T) + tt->link = t; + n->type = t; + break; + case OFUNC: + n->left->type->link = t; + if(n->left->op == ONAME) + n->left->sym->type->link = t; + n->type = t; + break; + } +} + +static Node* +retval(Node *n) +{ + int i; + Type *t; + Node *a, *l, *cf; + + cf = curfn(); + t = cf->left->type->link; + if(t->mark&(TCPC|TCFC) && (n == Z || !(n->type->mark&(TCPC|TCFC)))){ + if(n == Z) + n = new1(ORETURN, Z, Z); + l = n->left; + for(i = 0; ; i++){ + a = arg(cf->right, i); + if(a == Z) + break; + a = protoname(a); + if(a == Z || a->op != ONAME) + break; + if(a->type->mark == TCIN){ + if(l == Z) + l = ncopy(a); + else + l = new1(OTUPLE, l, ncopy(a)); + } + } + n->left = l; + n->type = l->type = t; + } + return n; +} + +static void +sube(Node *n) +{ + Node *l, *r, *nn; + Type *tt; + static Node *gn; + int p; + + if(n == Z) + return; + l = n->left; + r = n->right; + switch(n->op){ + default: + sube(l); + sube(r); + break; + case OIND: + if(l == Z) + return; + tt = l->type; + sube(l); + if(cktype(l, n, TCIN, 0) && iteq(tt, l->type)) + *n = *n->left; + break; + case OARRIND: + tt = l->type; + sube(l); + sube(r); + if(!isconst(r, 0)) + break; + if(cktype(l, n, TCIN, 0) && iteq(tt, l->type)) + *n = *n->left; + break; + case ONAME: + if(cktype(n, n, TCALL, 0)) + setdec(n->sym, n->type); + break; + case OCAST: + sube(l); + if(cktype(l, n, TCALL, 0)) + n->type = l->type; + break; + case OPROTO: + sube(l); + sube(r); + nn = protoname(n); + if(nn != Z && cktype(nn, n, TCALL, 0)){ + n->type = nn->type; + p = argpos(n, gn->right); + for(tt = gn->left->type->down; tt != T && p >= 0; tt = tt->down){ + if(p == 0){ + trep(tt, nn->type); + break; + } + --p; + } + } + break; + case OFUNC: + if(n->kind == KEXP) + aargs(n); + if(n->left->op == ONAME) + gn = n; + sube(l); + sube(r); + if(l != Z && cktype(n, n, TCGEN, 0)) + l->type->link = n->type; + break; + case OAS: + sube(l); + sube(r); + if(r->op == ORETV){ + n->left = new1(OTUPLE, l, r->right); + n->right = r->left; + n->left->type = n->type; + break; + } + if(cktype(r, n, TCGEN, 0)){ + tcon(l, r->type); + n->type = r->type; + } + if(cktype(l, n, TCGEN, 1)){ + tcon(r, l->type); + n->type = l->type; + } + break; + case OLT: + case OGE: + sube(l); + sube(r); + if(cktype(l, n, TCFD, 0) && isconst(r, 0)){ + n->op = n->op == OLT ? OEQ : ONE; + r->op = ONIL; + r->type = l->type; + } + break; + case OGT: + case OLE: + sube(l); + sube(r); + if(cktype(r, n, TCFD, 0) && isconst(l, 0)){ + n->op = n->op == OGT ? OEQ : ONE; + l->op = ONIL; + l->type = r->type; + } + break; + } +} + +static void +subs(Node *n, int blk, int aut) +{ + Node *l, *r; + + if(n == Z) + return; + if(blk) + pushscope(n, SAUTO); + nearln = n->lineno; + l = n->left; + r = n->right; + switch(n->op){ + default: + sube(n); + break; + case ONAME: + if(aut && n->kind != KEXP) + pushdcl(n, CAUTO); + if(cktype(n, n, TCALL, 0)) + setdec(n->sym, n->type); + break; + case ODAS: + if(aut) + pushdcl(l, CAUTO); + subs(l, 0, aut); + if(cktype(l, n, TCALL, 0)) + tcon(r, l->type); + break; + case OSBREAK: + case ONUL: + case OLABEL: + case OGOTO: + case OCONTINUE: + case OBREAK: + case OSET: + case OUSED: + break; + case OBLK: + subs(l, 1, aut); + break; + case OCASE: + subs(r, 1, aut); + break; + case OLIST: + subs(l, 0, aut); + subs(r, 0, aut); + break; + case ORETURN: + sube(l); + if(l != Z && cktype(l, n, TCGEN, 0)){ + n->type = l->type; + tcon(curfn(), l->type); + } + retval(n); + break; + case OSWITCH: + case OWHILE: + case ODWHILE: + sube(l); + subs(r, 1, aut); + break; + case OIF: + sube(l); + subs(r->left, 1, aut); + subs(r->right, 1, aut); + break; + case OFOR: + sube(l->left); + sube(l->right->left); + sube(l->right->right); + subs(r, 1, aut); + break; + } + if(blk) + popscope(); +} + +static Node* +finddec0(Sym *s, Node *n) +{ + Node *nn; + + if(n == Z) + return ZZ; + switch(n->op){ + case OLIST: + nn = finddec0(s, n->left); + if(nn != Z) + return nn; + return finddec0(s, n->right); + case OFUNC: + if(n->op != KEXP){ + if(s == decsym(n)) + return n; + return finddec0(s, n->right); + } + else + return ZZ; + case OPROTO: + case OIND: + case OARRAY: + return finddec0(s, n->left); + case ODOTDOT: + return ZZ; + case ONOOP: + case OPUSH: + case OPOP: + case OCODE: + case ODECE: + case ODECT: + return finddec0(s, n->right); + case ODECV: + case ODECF: + if(s == decsym(n->left) && !isfn(n->left->type)) + return n->left; + return finddec0(s, n->right); + } + if(isdec(n)){ + if(s == decsym(n) && !isfn(n->type)) + return n; + return Z; + } + return ZZ; +} + +static Node* +finddec(Sym *s, int g) +{ + Node *n; + Scope *sc; + + for(sc = scopes; sc != nil; sc = sc->nxt){ + if(!g || sc->k == SGLOB){ + n = finddec0(s, sc->n); + if(n != Z && n != ZZ) + return n; + } + } + return Z; +} + +static void +setdec(Sym *s, Type *t) +{ + Node *n; + + if((n = finddec(s, 0)) != Z){ + n->type = t; + if(n->op == ODAS){ + n = n->left; + n->type = t; + } + n->sym->type = t; + } +} + +typedef struct Syml Syml; + +struct Syml{ + Sym *sym; + Syml *nxt; +}; + +typedef struct Symq Symq; + +struct Symq{ + Syml *f; + Syml *r; +}; + +typedef struct Modl Modl; + +struct Modl{ + char *mod; + int ld; + Modl *nxt; +}; + +static void +prn(Node *n, int i) +{ + int j; + + for(j = 0; j < i; j++) + print("\t"); + if(n == Z){ + print("Z\n"); + return; + } + print("%s", onames[n->op]); + if(n->blk) + print(" block"); + if(n->type == T) + print(" T"); + else + print(" %s", tnames[n->type->etype]); + if(n->op == OCONST) + print(" %d", (int)n->vconst); + else if(n->op == OSTRING) + print(" %s", n->cstring); + else if(n->op == ONAME) + print(" %s", n->sym->name); + print("\n"); + if(n->op != OLIST) + i++; + prn(n->left, i); + prn(n->right, i); +} + +static int +isbigv(vlong v) +{ + return v > 0xffffffff; +} + +static int +islbigv(vlong v) +{ + return v > 0x7fffffff || v < -0x7fffffff; +} + +static int +isuintv(vlong v) +{ + return !isbigv(v) && (v&0x80000000) != 0; +} + +static int +isadt(Type *t) +{ + return t != T && (t->etype == TSTRUCT || t->etype == TUNION); +} + +static int +isreal(Type *t) +{ + return t != T && (t->etype == TDOUBLE || t->etype == TFLOAT); +} + +static int +isbyte(Type *t) +{ + return t != T && (t->etype == TCHAR || t->etype == TUCHAR); +} + +static int +isshort(Type *t) +{ + return t != T && (t->etype == TSHORT || t->etype == TUSHORT); +} + +static int +isint(Type *t) +{ + return t != T && (t->etype == TINT || t->etype == TUINT); +} + +static int +islong(Type *t) +{ + return t != T && (t->etype == TLONG || t->etype == TULONG); +} + +static int +isbig(Type *t) +{ + return t != T && (t->etype == TVLONG || t->etype == TUVLONG); +} + +static int +isinteger(Type *t) +{ + return isbyte(t) || isshort(t) || isint(t) || islong(t) || isbig(t); +} + +static int +isptr(Type *t) +{ + return t != T && (t->etype == TIND || t->etype == TARRAY || t->etype == TFUNC); +} + +static int +isscalar(Type *t) +{ + return t != T && !isadt(t) && t->etype != TTUPLE; +} + +static int +isvoid(Type *t) +{ + return t == T || t->etype == TVOID; +} + +static int +isnum(Type *t) +{ + return t != T && isscalar(t) && !isptr(t) && !isvoid(t); +} + +static int +isarray(Type *t) +{ + return t != T && (t->etype == TARRAY || (t->etype == TIND && !isadt(t->link))); +} + +static int +isstr(Type *t) +{ + return t != T && (t->etype == TSTRING || isarray(t) && isbyte(t->link)); +} + +static int +isfn(Type *t) +{ + return t != T && t->etype == TFUNC; +} + +static int +iscastable(Type *t, Type *tt) +{ + return t != T && (!isptr(t) || isarray(t) && isbyte(t->link) && isstr(tt)); +} + +static int +isname(Node *n) +{ + return n->op == ONAME; +} + +static int +isstring(Node *n) +{ + return n->op == OSTRING || n->op == OLSTRING || n->op == ONAME && n->sym->tenum != T && n->sym->tenum->etype == TIND; +} + +static int +isnil(Node *n) +{ + if(!isptr(n->type)) + return 0; + while(n->op == OCAST) + n = n->left; + return n->op == OCONST && n->vconst == 0 || n->op == ONIL; +} + +static int +isconst(Node *n, vlong v) +{ + while(n->op == OCAST) + n = n->left; + return n->op == OCONST && n->vconst == v; +} + +static Node* +cknil(Node *n) +{ + if(isconst(n, 0)) + n->op = ONIL; + return n; +} + +static int +cktype(Node *n, Node *t, int mask, int lev) +{ + int g, m, m0; + + g = t->garb > lev; + m = marked(n->type) & mask; + if(n->op == ONAME){ + m0 = marked(n->sym->type) & mask; + if(m && !m0){ + n->sym->type = n->type; + if(!g) + again = 1; + } + if(!m && m0){ + n->type = n->sym->type; + if(!g) + again = 1; + } + m |= m0; + } + if(m && t->garb < 2) + t->garb++; + return m && !g ? m : 0; +} + +int +isconsym(Sym *s) +{ + switch(s->class){ + case CXXX: + case CTYPEDEF: + return 1; + case CEXTERN: + case CGLOBL: + case CSTATIC: + case CLOCAL: + return s->type != T && s->type->etype == TENUM; + } + return -1; +} + +static void genstart(void); + +static char* +mprolog[] = +{ + "%%: module", + "{", + "\tPATH: con \"%%%.dis\";", + "", + nil +}; + +static char* +mepilog[] = +{ + "};", + nil +}; + +static char* +bprolog[] = +{ + "implement %%;", + "", + "include \"draw.m\";", + "", + "%%: module", + "{", + " init: fn(nil: ref Draw->Context, argl: list of string);", + "};", + "", + nil +}; + +static char* +bmprolog[] = +{ + "implement %%;", + "", + "include \"draw.m\";", + "", + nil +}; + +static char* +bepilog[] = +{ + nil +}; + +static void +pgen0(char **txt) +{ + int sub; + char *b, *s, *t, **p; + + p = txt; + for(;;){ + s = *p++; + if(s == nil) + break; + sub = 0; + for(t = s; *t != 0; t++){ + if(*t == '%' && *(t+1) == '%'){ + sub = 1; + break; + } + } + if(sub){ + strcpy(buf, s); + b = buf; + for(t = s; *t != 0; t++){ + if(*t == '%' && *(t+1) == '%'){ + if(*(t+2) == '%'){ + outmod(mbuf, 0); + t++; + } + else + outmod(mbuf, 1); + strcpy(b, mbuf); + b += strlen(mbuf); + t++; + } + else + *b++ = *t; + } + *b = 0; + prline(buf); + } + else + prline(s); + } +} + +static char* +hasm() +{ + outmod(mbuf, 0); + strcat(mbuf, ".m"); + if(exists(mbuf)) + return mbuf; + else if(domod){ + outmod(buf, 0); + strcat(buf, ".h"); + if(exists(buf)) + return mbuf; + } + return nil; +} + +void +pgen(int b) +{ + char **p; + + if(!dolog()) + return; + if(b) + p = hasm() ? bmprolog : bprolog; + else + p = mprolog; + pgen0(p); + if(b && passes) + genstart(); + if(!b) + incind(); +} + +void +epgen(int b) +{ + char **p; + + /* output(INFINITY, 1); */ + if(!dolog()) + return; + if(b){ + if(!passes) + genstart(); + p = bepilog; + } + else + p = mepilog; + if(!b) + decind(); + pgen0(p); +} + +static int lastsec = 0; + +#define ASSOC 1 +#define RASSOC 2 +#define POSTOP 4 + +#define LEFT 1 +#define RIGHT 2 +#define PRE 4 +#define POST 8 + +static int space[] = { 0, 0, 2, 0, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static struct{ + char *name; + int prec; + int kind; +} ops[] = { + "", 0, 0, /* ONOOP */ + "", 16, 0, /* OXXX, */ + "+", 12, ASSOC, /* OADD, */ + "&", 14, RASSOC, /* OADDR, */ + "&", 8, ASSOC, /* OAND, */ + "&&", 5, ASSOC, /* OANDAND, */ + "", 16, 0, /* OARRAY, */ + "=", 2, RASSOC, /* OAS, */ + "=", 2, RASSOC, /* OASI, */ + "+=", 2, RASSOC, /* OASADD, */ + "&=", 2, RASSOC, /* OASAND, */ + "<<=", 2, RASSOC, /* OASASHL, */ + ">>=", 2, RASSOC, /* OASASHR, */ + "/=", 2, RASSOC, /* OASDIV, */ + "<<", 11, 0, /* OASHL, */ + ">>", 11, 0, /* OASHR, */ + "/=", 2, RASSOC, /* OASLDIV, */ + "%=", 2, RASSOC, /* OASLMOD, */ + "*=", 2, RASSOC, /* OASLMUL, */ + ">>=", 2, RASSOC, /* OASLSHR, */ + "%=", 2, RASSOC, /* OASMOD, */ + "*=", 2, RASSOC, /* OASMUL, */ + "|=", 2, RASSOC, /* OASOR, */ + "-=", 2, RASSOC, /* OASSUB, */ + "^=", 2, RASSOC, /* OASXOR, */ + "", -1, 0, /* OBIT, */ + "", -1, 0, /* OBREAK, */ + "", -1, 0, /* OCASE, */ + "", 14, RASSOC, /* OCAST, */ + "", 1, ASSOC, /* OCOMMA, */ + "", 3, RASSOC, /* OCOND, */ + "", 16, 0, /* OCONST, */ + "", -1, 0, /* OCONTINUE, */ + "/", 13, 0, /* ODIV, */ + ".", 15, 0, /* ODOT, */ + "...", 16, 0, /* ODOTDOT, */ + "", -1, 0, /* ODWHILE, */ + "", -1, 0, /* OENUM, */ + "==", 9, 0, /* OEQ, */ + "", -1, 0, /* OFOR, */ + "", 15, 0, /* OFUNC, */ + ">=", 10, 0, /* OGE, */ + "", -1, 0, /* OGOTO, */ + ">", 10, 0, /* OGT, */ + ">", 10, 0, /* OHI, */ + ">=", 10, 0, /* OHS, */ + "", -1, 0, /* OIF, */ + "*", 14, RASSOC, /* OIND, */ + "", -1, 0, /* OINDREG, */ + "", 16, 0, /* OINIT, */ + "", -1, 0, /* OLABEL, */ + "/", 13, 0, /* OLDIV, */ + "<=", 10, 0, /* OLE, */ + "", 16, 0, /* OLIST, */ + "%", 13, 0, /* OLMOD, */ + "*", 13, ASSOC, /* OLMUL, */ + "<", 10, 0, /* OLO, */ + "<=", 10, 0, /* OLS, */ + ">>", 11, 0, /* OLSHR, */ + "<", 10, 0, /* OLT, */ + "%", 13, 0, /* OMOD, */ + "*", 13, ASSOC, /* OMUL, */ + "", 16, 0, /* ONAME, */ + "!=", 9, 0, /* ONE, */ + "!", 14, RASSOC, /* ONOT, */ + "|", 6, ASSOC, /* OOR, */ + "||", 4, ASSOC, /* OOROR, */ + "--", 14, RASSOC|POSTOP, /* OPOSTDEC, */ + "++", 14, RASSOC|POSTOP, /* OPOSTINC, */ + "--", 14, RASSOC, /* OPREDEC, */ + "++", 14, RASSOC, /* OPREINC, */ + "", 16, 0, /* OPROTO, */ + "", -1, 0, /* OREGISTER, */ + "", 0, 0, /* ORETURN, */ + "SET", -1, 0, /* OSET, */ + "signof", 14, RASSOC, /* OSIGN, */ + "sizeof", 14, RASSOC, /* OSIZE, */ + "", 16, 0, /* OSTRING, */ + "", 16, 0, /* OLSTRING, */ + "", 16, 0, /* OSTRUCT, */ + "-", 12, 0, /* OSUB, */ + "", -1, 0, /* OSWITCH, */ + "", 16, 0, /* OUNION, */ + "USED", -1, 0, /* OUSED, */ + "", -1, 0, /* OWHILE, */ + "^", 7, ASSOC, /* OXOR, */ + "-", 14, RASSOC, /* ONEG, */ + "~", 14, RASSOC, /* OCOM, */ + "", 16, 0, /* OELEM, */ + "", -1, 0, /* OTST, */ + "", -1, 0, /* OINDEX, */ + "", -1, 0, /* OFAS, */ + "", -1, 0, /* OBLK */ + "+", 14, RASSOC, /* OPOS */ + "", -1, 0, /* ONUL */ + ".", 15, 0, /* ODOTIND */ + "", 15, 0, /* OARRIND */ + "", -1, 0, /* ODAS */ + ":=", 2, RASSOC, /* OASD */ + "", 16, 0, /* OIOTA */ + "", 14, RASSOC, /* OLEN */ + "", 17, 0, /* OBRACKET */ + "", 14, RASSOC, /* OREF */ + "", 14, RASSOC, /* OARRAYOF */ + "", 15, 0, /* OSLICE */ + "&", 14, RASSOC, /* OSADDR, */ + "", 16, 0, /* ONIL */ + "", 16, 0, /* OS2AB */ + "", 16, 0, /* OAB2S */ + "", 16, 0, /* OFILDES */ + ".", 15, 0, /* OFD */ + "", 16, 0, /* OTUPLE */ + ".", 15, 0, /* OT0 */ + "", 15, 0, /* ORETV */ + "+", 12, ASSOC, /* OCAT */ + "", -1, 0, /* OSBREAK, */ + ".", 15, 0, /* OLDOT */ + "->", 15, 0, /* OMDOT */ + nil, -1, 0, /* OCODE */ + nil, -1, 0, /* ODECE */ + nil, -1, 0, /* ODECT */ + nil, -1, 0, /* ODECV */ + nil, -1, 0, /* ODECF */ + nil, -1, 0, /* OPUSH */ + nil, -1, 0, /* OPOP */ + "", -1, 0, /* OEND */ +}; + +#define COMPLEX 32 + +#define NOBR 2 +#define NOIN 4 +#define YESBR 8 +#define NONL 16 +#define NOENL 32 + +enum{ + LNONE, + LSTRLEN, + LSTRCMP, + LSTRCPY, + LSTRCAT, + LSTRNCMP, + LSTRNCPY, + LSTRNCAT, + LSTRDUP, + LMEMMOVE, + LMALLOC, + LFREE, + LEXIT, + LCLOSE, + LATOI, + LATOL, + LATOF, + LPRINT, + LFPRINT, + LSPRINT, + LSELF, +}; + +static int tmp; + +static void egen(Node*, int, int); +static Node* buildcases(Node*); +static void tdgen(Node *, int); +static Node* cfind(Node*); +static Node* cgen(Node*, Node*); +static void cgen0(Node*, Node*); +static int lteq(Type*, Type*); +static Type* ntype(Node*); +static int rewe(Node*, Type*, int); +static void rewlc(Node*, int, Type*); +static Node* con(vlong); +static void clrbrk(Node*); +static int hasbrk(Node*); +static int isgen(char*); +static int simple(Node*); +static void pfmt(char*); +static void lpfmt(ushort*); +static int lline(Node*); +static void args(Node*); +static void addmodn(Sym*); +static void scomplex(Node*); +static void mset(Node*); + +static Node *lastd; + +static int +rev(int op) +{ + switch(op){ + case OLT: return OGT; + case OLE: return OGE; + case OGT: return OLT; + case OGE: return OLE; + } + return op; +} + +void +newsec(int l) +{ + if(l != 1 && lastd != Z){ + tdgen(lastd, 1); + lastd = Z; + } + if(l != 2) + etgen2(nil); + if(lastsec && l != lastsec) + newline(); + lastsec = l; +} + +static Node* +defval(Type *t) +{ + Node *n; + + if(t == T) + t = types[TINT]; + n = con(0); + n->type = types[TINT]; + n->kind = KDEC; + switch(t->etype){ + case TFLOAT: + case TDOUBLE: + n->type = types[TDOUBLE]; + n->fconst = 0.0; + n->cstring = "0.0"; + return n; + default: + break; + case TIND: + case TFUNC: + case TARRAY: + n->type = typ1(TIND, types[TVOID]); + return n; + case TVOID: + case TSTRUCT: + case TUNION: + free(n); + return Z; + } + if(!lteq(n->type, t)){ + n = new1(OCAST, n, Z); + n->type = t; + } + return n; +} + +static int +teq(Type *t1, Type *t2) +{ + if(t1 == t2) + return 1; + return sametype(t1, t2); +/* + if(t1->etype != t2->etype) + return 0; + switch(t1->etype){ + case TARRAY: + if(t1->width != t2->width) + return 0; + break; + case TFUNC: + if(!teq(t1->down, t2->down)) + return 0; + break; + case TSTRUCT: + case TUNION: + return t1->link == t2->link; + case TENUM: + return 1; + } + return teq(t1->link, t2->link); +*/ +} + +static int +tequiv(Type *t1, Type *t2) +{ + if(!teq(t1, t2)) + return 0; + if(t1->etype == TSTRUCT || t1->etype == TUNION) + return suename(t1) == suename(t2); + return 1; +} + +static int +iteq(Type *t1, Type *t2) +{ + if(t1 == T || t2 == T) + return 0; + return t1->etype == TIND && (teq(t1->link, t2) || (t1->link->etype == TVOID && isnum(t2))); +} + +static Type * +ltype(Type *t) +{ + switch(t->etype){ + case TUCHAR: + return types[TCHAR]; + case TSHORT: + case TUSHORT: + case TUINT: + case TLONG: + case TULONG: + case TENUM: + return types[TINT]; + case TUVLONG: + return types[TVLONG]; + case TFLOAT: + return types[TDOUBLE]; + default: + return t; + } + return t; +} + +static int +lteq(Type *t1, Type *t2) +{ + if(t1 == T || t2 == T) + return 0; + if(t1 == t2) + return 1; + if(t1->etype == TIND && t2->etype == TIND) + return lteq(t1->link, t2->link); + return sametype(ltype(t1), ltype(t2)); +} + +static Type* +tcp(Type *t) +{ + Type *nt; + + if(t == T) + return T; + nt = typ1(TXXX, T); + *nt = *t; + return nt; +} + +static Type* +tuple(Type *t1, Type *t2) +{ + Type *t, **at, *l; + + if(t1 == T || t1->etype == TVOID) + return tcp(t2); + if(t2 == T || t2->etype == TVOID) + return tcp(t1); + if(t2->etype == TTUPLE) + diag(Z, "bad tuple type"); + t = typ1(TTUPLE, T); + at = &t->link; + if(t1->etype == TTUPLE){ + for(l = t1->link; l != T; l = l->down){ + *at = tcp(l); + at = &(*at)->down; + } + } + else{ + *at = tcp(t1); + at = &(*at)->down; + } + *at = tcp(t2); + return t; +} + +static Sym* +sue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->suetag && s->suetag->link == t) + return s; + return S; +} + +static void +pranon(int i) +{ + prid("anon_"); + prnum(i+1, KDEC, T); +} + +static int +dotpath(Sym *s, Type *t, int pr) +{ + int i; + Type *t1; + + if(t == T) + return 0; + for(t1 = t->link; t1 != T; t1 = t1->down){ + if(t1->sym == s){ + if(pr){ + prdelim("."); + prsym(s, 0); + } + return 1; + } + } + i = 0; + for(t1 = t->link; t1 != T; t1 = t1->down){ + if(t1->sym == S){ + i++; + if(typesu[t1->etype] && sametype(s->type, t1)){ + if(pr){ + prdelim("."); + pranon(i-1); + } + return 1; + } + } + } + i = 0; + for(t1 = t->link; t1 != T; t1 = t1->down){ + if(t1->sym == S){ + i++; + if(typesu[t1->etype] && dotpath(s, t1, 0)){ + if(pr){ + prdelim("."); + pranon(i-1); + dotpath(s, t1, 1); + } + return 1; + } + } + } + return 0; +} + +static Sym* +suename(Type *t) +{ + Sym *s; + + s = sue(t->link); + if(s != S) + return s; + else if(t->tag != S) + return t->tag; + else if(t->sym != S) + return t->sym; + return S; +} + +static int +cycle(Type *t, Type *base) +{ + int r; + Type *l; + + if(t->vis){ + /* sametype() does structural comparison so have to check names */ + if(t == base || tequiv(t, base)) + return 1; + return 0; + } + r = 0; + t->vis = 1; + switch(t->etype){ + case TIND: + case TARRAY: + r = cycle(t->link, base); + break; + case TSTRUCT: + case TUNION: + case TTUPLE: + for(l = t->link; l != T; l = l->down) + r |= cycle(l, base); + break; + } + t->vis = 0; + return r; +} + +static void +addnode(int op, Node *n) +{ + Node *nn; + + nn = new1(OXXX, Z, Z); + *nn = *n; + n->op = op; + n->left = nn; + n->right = Z; + n->type = nn->type; +} + +static void +cast(Node *n, Type *t) +{ + addnode(OCAST, n); + n->type = t; +} + +static void +intcast(Node *n) +{ + if(isptr(n->type)){ + addnode(ONE, n); + n->right = con(0); + n->right->type = n->left->type; + n->type = types[TINT]; + } + else + cast(n, types[TINT]); +} + +static void +strcast(Node *n) +{ + cast(n, stringtype); +} + +static void +bptr(Node *n) +{ + if(n == Z) + return; + switch(n->op){ + default: + if(!lteq(n->type, types[TINT])) + intcast(n); + break; + case ONOT: + if(!lteq(n->left->type, types[TINT])){ + intcast(n->left); + if(n->left->op == ONE){ + n->left->op = OEQ; + *n = *n->left; + } + } + break; + case OANDAND: + case OOROR: + bptr(n->left); + bptr(n->right); + break; + case OCOND: + bptr(n->right->left); + bptr(n->right->right); + break; + } +} + +static void +bcomplex(Node *n) +{ + if(n == Z) + return; + if(!passes) + complex(n); + bptr(n); +} + +static void +ecomplex(Node *n) +{ + if(!passes) + complex(n); + rewe(n, T, 0); +} + +static void +becomplex(Node *n) +{ + bcomplex(n); + rewe(n, T, 0); +} + +static void +tgen(Type *t, int dec, int arinit) +{ + Type *l; + + if(t == T) + return; + switch(t->etype){ + case TXXX: + prid("int"); + break; + case TCHAR: + case TUCHAR: + prid("byte"); + break; + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TENUM: + prid("int"); + break; + case TVLONG: + case TUVLONG: + prid("big"); + break; + case TFLOAT: + case TDOUBLE: + prid("real"); + break; + case TIND: + if(strings == 2 && t->link && t->link->etype == TCHAR){ + prid("string"); + break; + } + if(isadt(t->link) || t->link->etype == TFUNC) + prid("ref "); + else + prid("array of "); + if(t->link && t->link->etype == TVOID){ + prid("byte"); + prcom("was void*", Z); + } + else + tgen(t->link, 1, 0); + break; + case TFUNC: + if(0){ + prid("int"); + prcom("was function", Z); + break; + } + prid("fn"); + prdelim("("); + for(l = t->down; l != T; l = l->down){ + if(l->etype == TVOID && l->down == T) + break; + if(l->etype == TDOT){ + prcom("was ...", Z); + break; + } + if(l->sym != S) + prsym(l->sym, 0); + else + prid("nil"); + prdelim(": "); + tgen(l, 1, 0); + if(l->down != T && l->down->etype != TDOT) + prdelim(", "); + } + /* tgen(t->down, dec, 0, 0); */ + prdelim(")"); + if(!isvoid(t->link)){ + prdelim(": "); + tgen(t->link, dec, 0); + } + break; + case TARRAY: + prid("array"); + if(t->width == LARR) + t->width = LARR; + else if(dec){ + if(t->nwidth != Z) + prcom("array index was ", t->nwidth); + else if(t->width != 0){ + sprint(buf, "array index was %ld", t->width/t->link->width); + prcom(buf, Z); + } + } + else{ + prdelim("["); + if(t->nwidth != Z) + egen(t->nwidth, ONOOP, PRE); + else if(t->width != 0) + prnum(t->width/t->link->width, KDEC, T); + prdelim("]"); + } + prdelim(" of "); + if(!arinit) + tgen(t->link, 1, 0); + break; + case TVOID: + /* prid("void"); */ + prid("byte"); + prcom("was void", Z); + break; + case TSTRUCT: + case TUNION: + if(t->link != T && t->link->etype == TFD){ + prid("Sys->FD"); + usemod(sysop, 0); + } + else + prsym(suename(t), 1); + break; + case TTUPLE: + prdelim("("); + for(l = t->link; l != T; l = l->down){ + tgen(l, dec, 0); + if(l->down != T) + prdelim(", "); + } + prdelim(")"); + break; + case TDOT: + prdelim("..."); + break; + case TSTRING: + prid("string"); + break; + case TFD: + prid("fd"); + break; + default: + diag(Z, "unknown type"); + break; + } +} + +static Type* +typn(Type *t, int i) +{ + Type *l; + + for(l = t->down; l != T && --i >= 0; l = l->down) + ; + return l; +} + +void +ttgen2(Type *t) +{ + Type *l; + Sym *s; + int anon = 0; + + switch(t->etype){ + case TSTRUCT: + case TUNION: + newsec(0); + output(t->lineno, 1); + s = suename(t); + if(isgen(s->name)) + addmodn(s); + setmod(s); + prsym(s, 0); + prdelim(": "); + prid("adt"); + prdelim("{"); + if(t->etype == TUNION) + prcom("was union", Z); + newline(); + incind(); + t->vis = 1; + for(l = t->link; l != T; l = l->down){ + output(l->lineno, 1); + if(l->nbits) + prcom("was bit field", Z); + if(l->sym != S) + prsym(l->sym, 0); + else + pranon(anon++); + prdelim(": "); + if(cycle(l, t)) + prid("cyclic "); + tgen(l, 1, 0); + prdelim(";"); + newline(); + } + t->vis = 0; + decind(); + prdelim("};"); + newline(); + newline(); + break; + default: + break; + } +} + +static int +canjoin(Node *n, Node *nn) +{ + return teq(n->type, nn->type) && isname(n) && isname(nn) && n->type->etype != TARRAY; +} + +void +vtgen2(Node *n) +{ + int t, c, comma = 0; + Node *nn; + Sym *s; + + nn = n; + if(n->op == ODAS) + nn = n->left; + if(nn->type == T || nn->sym == S) + return; + t = nn->type->etype; + c = nn->sym->class; + if(0 && c == CTYPEDEF){ + /* egen(nn, ONOOP, PRE); */ + /* tdgen(n, 1, 0); */ + if(isadt(n->type)){ + s = suename(n->type); + if(isgen(s->name)){ + s->lname = nn->sym->name; + ttgen2(n->type); + } + } + } + if(c != CGLOBL && c != CSTATIC && c != CLOCAL && c != CEXREG) + return; + newsec(1); + if(lastd != Z){ + if(t != TFUNC && canjoin(lastd, n)) + comma = 1; + else + tdgen(lastd, 1); + } + output(nn->lineno, 1); + if(t == TFUNC){ + if(ism()){ + setmod(nn->sym); + egen(nn, ONOOP, PRE); + tdgen(n, 1); + } + lastd = Z; + return; + } + if(comma) + prdelim(", "); + if(nn->op != ONAME) + diag(nn, "internal: not name in vtgen"); + setmod(nn->sym); + prsym(nn->sym, 0); + /* egen(nn, ONOOP, PRE); */ + /* tdgen(n, 1, 0); */ + lastd = n; + if(n->op == ODAS) + rewe(n->right, T, 1); +} + +static void minseq(Syml*); + +static Node* +con(vlong v) +{ + int neg = 0; + Node *n; + + if(v < 0){ + neg = 1; + v = -v; + } + n = new1(OCONST, Z, Z); + n->vconst = v; + n->kind = KDEC; + n->type = types[TINT]; + if(neg) + n = new1(ONEG, n, Z); + return n; +} + +/* +static Node* +fcon(double v) +{ + int neg = 0; + Node *n; + + if(v < 0){ + neg = 1; + v = -v; + } + n = new1(OCONST, Z, Z); + n->fconst = v; + n->kind = KDEC; + n->type = types[TDOUBLE]; + if(neg) + n = new1(ONEG, n, Z); + return n; +} +*/ + +static Node* +add(vlong v, Node *n) +{ + if(v == 0) + return n; + return new1(OADD, con(v), n); +} + +static Node* +addn(Node *n1, Node *n2) +{ + if(n1 == Z || n2 == Z) + return Z; + if(isconst(n1, 0)) + return n2; + if(isconst(n2, 0)) + return n1; + return new1(OADD, n1, n2); +} + +static Node* +mul(vlong v, Node *n) +{ + if(v == 0) + return con(0); + else if(v == 1) + return n; + else if(v == -1) + return new1(ONEG, n, Z); + return new1(OMUL, con(v), n); +} + +static Node* +mydiv(Node *n, vlong w) +{ + Node *nn; + + if(w == 0) + return Z; + if(w == 1) + return n; + else if(w == -1) + return new1(ONEG, n, Z); + switch(n->op){ + case OCONST: + if(n->vconst % w == 0){ + n->vconst /= w; + if(n->left != Z && mydiv(n->left, w) == Z){ + n->vconst *= w; + break; + } + return n; + } + break; + case OCAST: + return mydiv(n->left, w); + case OMUL: + nn = mydiv(n->right, w); + if(nn != Z){ + if(isconst(nn, 1)) + *n = *n->left; + return n; + } + nn = mydiv(n->left, w); + if(nn != Z){ + if(isconst(nn, 1)) + *n = *n->right; + return n; + } + break; + default: + break; + } + return Z; +} + +static Node* +iota(void) +{ + return new1(OIOTA, Z, Z); +} + +static Node* +symcon(Sym *s) +{ + Node *n; + + if(s->nconst != Z) + return s->nconst; + n = con(s->vconst); + n->kind = s->kind; + return n; +} + +#define ARITH 1 +#define GEOM 2 + +static Syml* +newsyml(Sym *s, Syml **frees) +{ + Syml *sl, *f; + + if((f = *frees) != nil){ + sl = f; + *frees = f->nxt; + } + else + sl = (Syml*)malloc(sizeof(Syml)); + sl->sym = s; + sl->nxt = nil; + return sl; +} + +static Syml* +etseq(Syml *syml) +{ + int e, pio, io, comma; + vlong d, dd, v0, v1, v, t, tt; + Node *expr; + Sym *s; + Syml *sl, *lsl; + + lsl = nil; + pio = io = ARITH|GEOM; + e = 0; + dd = 0; + for(sl = syml; sl != nil; sl = sl->nxt){ + s = sl->sym; + if(isreal(s->tenum) || s->tenum->etype == TIND) + break; + if(e == 0) + v0 = s->vconst; + if(e == 1){ + v1 = s->vconst; + d = v1-v0; + } + if(e > 0 && (v <= 0 || s->vconst != 2*v)) + io &= ~GEOM; + if(0 && e > 1 && s->vconst-v != d) + io &= ~ARITH; + if(e > 1){ + t = s->vconst-v; + tt = t-d; + if(e > 2 && tt != dd) + io &= ~ARITH; + else{ + d = t; + dd = tt; + } + } + if(io == 0) + break; + v = s->vconst; + lsl = sl; + pio = io; + e++; + } + if(e < 2) + pio = 0; + if(pio&GEOM){ + if(e < 3) + pio = 0; + } + else if(pio&ARITH){ + int n; + + if(d == 0 && dd == 0) + n = 2; + else if(dd == 0) + n = 3; + else + n = 4; + if(e < n || (dd&1) != 0) + pio = 0; + } + if(lsl == nil || pio == 0) + lsl = syml; + comma = 0; + for(sl = syml; sl != nil; sl = sl->nxt){ + s = sl->sym; + nearln = s->lineno; + output(s->lineno, 1); + if(pio){ + if(comma) + prdelim(", "); + setmod(s); + prsym(s, 0); + comma = 1; + } + else{ + setmod(s); + prsym(s, 0); + prdelim(": "); + prid("con "); + if(isbyte(s->tenum) || isbig(s->tenum) && !islbigv(s->vconst) || !isbig(s->tenum) && isuintv(s->vconst)){ + tgen(s->tenum, 1, 0); + prdelim(" "); + } + if(s->nconst != Z) + egen(s->nconst, ONOOP, PRE); + else if(s->kind == KCHR) + prchar(s->vconst); + else if(isreal(s->tenum)) + prreal(s->fconst, s->cstring, s->kind); + else + prnum(s->vconst, s->kind, s->tenum); + prdelim(";"); + newline(); + } + if(sl == lsl) + break; + } + if(pio){ + s = syml->sym; + prdelim(": "); + prid("con "); + if(isbyte(s->tenum) || isbig(s->tenum)){ + tgen(s->tenum, 1, 0); + prdelim(" "); + } + if(pio&GEOM){ + if(v0 == 0 || v0 == 1 || v0 == -1) + expr = mul(v0, new1(OASHL, con(1), iota())); + else + expr = new1(OMUL, symcon(s), new1(OASHL, con(1), iota())); + } + else if(d == 0 && dd == 0) + expr = symcon(s); + else if(dd == 0) + expr = add(v0, mul(d, iota())); + else + expr = add(v0, new1(OADD, mul(v1-dd/2-v0, iota()), mul(dd/2, new1(OMUL, iota(), iota())))); + complex(expr); + expr = ckneg(expr); + egen(expr, ONOOP, PRE); + prdelim(";"); + newline(); + } + return lsl->nxt; +} + +static void +adde(Syml *sl, Symq *q) +{ + if(q->f == nil) + q->f = sl; + else + q->r->nxt = sl; + q->r = sl; +} + +static void +freeq(Symq *q, Syml **frees) +{ + if(q->f){ + q->r->nxt = *frees; + *frees = q->f; + q->f = q->r = nil; + } +} + +static void +etgen2(Sym *s) +{ + Syml *sl; + static Syml *frees; + static Symq symq, symq1; + + if(s != nil){ + newsec(2); + sl = newsyml(s, &frees); + adde(sl, &symq); + if(isinteger(s->tenum) && isbigv(s->vconst) && !isbig(s->tenum)) + s->tenum = types[TVLONG]; + return; + } + /* end of enums */ + if(symq.f && symq.f == symq.r){ /* try to merge with other singletons */ + adde(symq.f, &symq1); + symq.f = symq.r = nil; + return; + } + if(symq1.f){ + for(sl = symq1.f; sl != nil; sl = etseq(sl)) + ; + freeq(&symq1, &frees); + } + if(symq.f){ + for(sl = symq.f; sl != nil; sl = etseq(sl)) + ; + freeq(&symq, &frees); + } +} + +static void +lgen(Node *n, int br, int first) +{ + if(br) + prdelim("("); + if(n == Z){ + if(br) + prdelim(")"); + return; + } + if(n->op == OLIST || n->op == OTUPLE){ + lgen(n->left, 0, first); + lgen(n->right, 0, 0); + } + else if(n->op != ODOTDOT){ + if(!first) + prdelim(", "); + egen(n, ONOOP, PRE); + } + else + prcom("was ...", Z); + if(br) + prdelim(")"); +} + +static void +preced(int op1, int op2, int s, int c) +{ + int p1, p2, k1, k2, br; + char buf[2]; + + br = 0; + p1 = ops[op1].prec; + p2 = ops[op2].prec; + if(p1 < 0 || p2 < 0) + diag(Z, "-ve precedence"); + if(p1 > p2) + br = 1; + else if(p1 == p2){ + k1 = ops[op1].kind; + k2 = ops[op2].kind; + if(op1 == op2){ + if(k1&RASSOC) + br = s == LEFT; + else + br = s == RIGHT && !(k1&ASSOC); + } + else{ + if(k1&RASSOC) + br = s == LEFT; + else + br = s == RIGHT && op1 != OADD; + + if(k1&POSTOP && !(k2&POSTOP)) + br = 1; + + /* funny case */ + if(op2 == OMDOT && s == LEFT && (op1 == ODOT || op1 == ODOTIND)) + br = 1; + } + } + if(br){ + buf[0] = c; + buf[1] = '\0'; + prdelim(buf); + } +} + +static void +egen(Node *n, int op0, int side) +{ + int op, p; + Type *t; + Node *nn; + + if(n == Z){ + if(op0 == OBRACKET) + prdelim("()"); + return; + } + if(n->op == OCONST && n->left != Z){ /* actual node in source */ + n->left->type = n->type; + n = n->left; + } + if((n->op == OSTRING || n->op == OLSTRING) && n->left != Z) /* actual node in source */ + n = n->left; + if(n->op == OCAST && (lteq(n->type, n->left->type) || isnil(n) || !iscastable(n->type, n->left->type))){ + if(isnil(n)) + prid("nil"); + else + egen(n->left, op0, side); + return; + } + if(n->op == ONAME && arrow(n->sym)) + n->op = OMDOT; + if(n->op != OLIST) + output(n->lineno, 0); + op = n->op; + preced(op0, op, side, '('); + switch(op){ + case OLIST: + case OTUPLE: + lgen(n, 1, 1); + break; + case OIOTA: + prid("iota"); + break; + case OMDOT: + case ONAME: + case OXXX: + prsym(n->sym, 1); + break; + case OCONST: + if(n->kind == KCHR) + prchar(n->vconst); + else if(isreal(n->type)) + prreal(n->fconst, n->cstring, n->kind); + else if(isnil(n)) + prid("nil"); + else + prnum(n->vconst, n->kind, n->type); + if(n->right != Z) + prcom("was ", n->right); + break; + case OSTRING: + prstr(n->cstring); + break; + case OLSTRING: + prlstr(n->rstring); + break; + case OCOND: + egen(n->left, op, POST); + prdelim(" ? "); + egen(n->right->left, op, PRE|POST); + prdelim(" : "); + egen(n->right->right, op, PRE); + prcom("?", Z); + break; + case OCOMMA: + if(op0 != OCOMMA) + prdelim("("); + egen(n->left, op, LEFT); + prdelim(", "); + egen(n->right, op, RIGHT); + if(op0 != OCOMMA) + prdelim(")"); + break; + case OLDOT: + egen(n->left, OMOD, LEFT); /* any precedence 13 operator */ + prdelim("."); + egen(n->right, op, RIGHT); + break; + default: + p = ops[op].prec; + egen(n->left, op, LEFT); + if(space[p]) + prdelim(" "); + prdelim(ops[op].name); + if(space[p]) + prdelim(" "); + egen(n->right, op, RIGHT); + break; + case OIND: case OADDR: case OSADDR: + case OPOS: case ONEG: + case ONOT: case OCOM: + case OPREINC: case OPREDEC: + if(op == OADDR){ + n->op = OSADDR; + if(!isfn(n->left->type)) + prcom("was ", n); + } + else + prdelim(ops[op].name); + egen(n->left, op, PRE); + break; + case OPOSTINC: case OPOSTDEC: + egen(n->left, op, POST); + prdelim(ops[op].name); + break; + case ODOT: + egen(n->left, op, LEFT); + dotpath(n->sym, n->left->type, 1); + /* prdelim(ops[op].name); */ + /* prsym(n->sym, 0); */ + break; + case ODOTIND: + egen(n->left, op, LEFT); + if(isadt(n->left->type)) + dotpath(n->sym, n->left->type, 1); /* type may be demoted arg */ + else + dotpath(n->sym, n->left->type->link, 1); + /* prdelim(ops[op].name); */ + /* prsym(n->sym, 0); */ + break; + case OARRIND: + egen(n->left, op, LEFT); + prdelim("["); + egen(n->right, ONOOP, RIGHT); + prdelim("]"); + if(n->right->op == OCONST && n->right->vconst < 0) + prcom("negative array index", Z); + break; + case OLEN: + prid("len "); + egen(n->right, op, PRE); + break; + case OREF: + prid("ref "); + tgen(n->type->link, 0, 0); + break; + case OARRAYOF: + prid("array"); + prdelim("["); + egen(n->left, ONOOP, LEFT); + prdelim("]"); + prid(" of "); + tgen(n->type->link, 0, 0); + break; + case OSLICE: + egen(n->left, op, LEFT); + prdelim("["); + egen(n->right->left, ONOOP, RIGHT); + prdelim(": "); + egen(n->right->right, ONOOP, RIGHT); + prdelim("]"); + break; + case OFUNC: + if(n->kind == KEXP) + egen(n->left, op, LEFT); + else + prsym(n->left->sym, 0); + lgen(n->right, 1, 1); + if(n->kind != KEXP && !isvoid(n->left->type->link)){ + prdelim(": "); + tgen(n->left->type->link, 0, 0); + } + break; + case ONIL: + prid("nil"); + break; + case OCAST: + if(isnil(n)) + prid("nil"); + else if(iscastable(n->type, n->left->type)){ + tgen(n->type, 0, 0); + prdelim(" "); + egen(n->left, op, RIGHT); + } + else + egen(n->left, op0, RIGHT); + break; + case OARRAY: + tgen(n->type, 0, 0); + egen(n->left, op, LEFT); + prdelim("["); + egen(n->right, ONOOP, RIGHT); + prdelim("]"); + break; + case OSTRUCT: + case OUNION: + tgen(n->type, 0, 0); + lgen(n->left, 1, 1); + break; + case OELEM: + prdelim("."); + /* tgen(n->type, 0, 0, 0); */ + prsym(n->sym, 0); + break; + case OSIZE: + case OSIGN: + prid(ops[op].name); + if(n->left != Z) + egen(n->left, OBRACKET, RIGHT); + else{ + prdelim(" "); + prid(tnames[n->type->etype]); + if(typesu[n->type->etype] && n->type->tag){ + prdelim(" "); + prid(n->type->tag->name); + } + } + break; + case OPROTO: + nn = n; + t = n->type; + n = protoname(n); + if(n != Z) + t = n->type; + else + t = prototype(nn->left, t); + if(!isvoid(t) || n != Z){ + if(n == Z) + prid("nil"); + else if(n->op == ODOTDOT){ + prcom("was ...", Z); + break; + } + else + prsym(n->sym, 0); + /* egen(n, ONOOP, PRE); */ + prdelim(": "); + tgen(t, 1, 0); + } + break; + case ODOTDOT: + prid("..."); + break; + case OINIT: + egen(n->left, ONOOP, PRE); + break; + case OS2AB: + prid("libc0->s2ab"); + prdelim("("); + egen(n->left, ONOOP, PRE); + prdelim(")"); + usemod(libcop, 1); + break; + case OAB2S: + prid("libc0->ab2s"); + prdelim("("); + egen(n->left, ONOOP, PRE); + prdelim(")"); + usemod(libcop, 1); + break; + case OFILDES: + prid("sys->fildes"); + prdelim("("); + egen(n->left, ONOOP, PRE); + prdelim(")"); + usemod(sysop, 1); + break; + case OFD: + egen(n->left, op, LEFT); + prdelim(ops[op].name); + prid("fd"); + break; + case OT0: + egen(n->left, op, LEFT); + prdelim(ops[op].name); + prid("t0"); + break; + case ORETV: + n->op = OAS; + nn = n->left; + p = isvoid(n->type) || n->type->etype != TTUPLE || n->type->mark == TCPC; + if(p) + n->left = n->right; + else + n->left = new1(OTUPLE, new1(ONIL, Z, Z), n->right); + n->right = nn; + n->left->type = n->type; + if(!p && op0 != ONOOP) + addnode(OT0, n); + egen(n, op0, side); + break; + case OCAT: + egen(n->left, op, LEFT); + prdelim(" + "); + egen(n->right, op, RIGHT); + break; + } + preced(op0, op, side, ')'); +} + +static int +isexpr(Node *n, Type *t) +{ + if(n == Z) + return 0; + if(n->op == OLIST || n->op == OINIT || n->op == OSTRUCT) + return 0; + if(teq(t, n->type)) + return 1; + return 0; +} + +static Node * +nxtval(Node *n, Node **nn) +{ + if(n == Z){ + *nn = Z; + return Z; + } + if(n->op == OLIST){ + *nn = n->right; + return n->left; + } + *nn = Z; + return n; +} + +static Node* +eagen(Node *n, Type *t, int ar, int *nz, int depth) +{ + int i, w, nw, down; + Type *t1; + Node *nn, *tn; + + if(n != Z){ + if(n->type == T && t == T){ + egen(n, ONOOP, PRE); + if(ar){ + prdelim(","); + newline(); + } + return Z; + } + if(ar && n->op == OLIST && n->left->op == OARRAY){ + egen(n->left->left, ONOOP, PRE); + prdelim(" => "); + n = n->right; + } + if(n->op == OLIST && n->left->op == OELEM){ + prcom("cannot do ", n->left); + n = n->right; + } + if(n->op == OUSED || n->op == ODOTDOT) + n = n->left; + if(t == T) + t = n->type; + } + switch(t->etype){ + case TSTRUCT: + case TUNION: + if(isexpr(n, t)) + goto Default; + down = 0; + tn = nxtval(n, &nn); + if(tn != Z && (tn->op == OINIT || tn->op == OSTRUCT)){ + down = 1; + n = tn->left; + } + if(depth > 0){ + tgen(t, 0, 0); + prdelim(" "); + } + prdelim("("); + for(t1 = t->link; t1 != T; t1 = t1->down){ + if(n == Z) + n = defval(t1); + n = eagen(n, t1, 0, nil, depth+1); + if(t1->down != T){ + prdelim(","); + if(ar) + prdelim("\t"); + else + prdelim(" "); + } + } + prdelim(")"); + if(down) + n = nn; + break; + case TARRAY: + if(isexpr(n, t)) + goto Default; + if(depth > 0){ + tgen(t, 0, 1); + prdelim(" "); + } + prdelim("{"); + newline(); + incind(); + w = t->width/t->link->width; + nw = 0; + for(i = 0; i < w; i++){ + down = 0; + tn = nxtval(n, &nn); + if(tn != Z && (tn->op == OINIT || tn->op == OSTRUCT)){ + down = 1; + n = tn->left; + } + n = eagen(n, t->link, 1, &nw, depth+1); + if(down) + n = nn; + } + if(nw > 0){ + if(nw > 1) + prdelim("* => "); + egen(defval(t->link), ONOOP, PRE); + newline(); + } + decind(); + prdelim("}"); + break; + default: +Default: + if(n == Z){ + if(ar) + (*nz)++; + else + egen(defval(t), ONOOP, PRE); + return Z; + } + n = nxtval(n, &nn); + if(ar && isnil(n) && iscastable(t, types[TINT])){ + tgen(t, 0, 0); + prdelim(" "); + } + egen(n, ONOOP, PRE); + n = nn; + break; + } + if(ar){ + prdelim(","); + newline(); + } + return n; +} + +/* better is + * array of byte "abcde\0" + * but limbo compiler does not accept this as a constant expression + */ +static void +stob(Node *n) +{ + int m; + char *s = nil, buf[UTFmax]; + ushort *u = nil; + + while(n->op == ONAME) + n = n->sym->nconst; + if(n->op == OSTRING) + s = n->cstring; + else + u = n->rstring; + prdelim("{ "); + if(s){ + while(*s){ + prid("byte "); + prchar(*s++); + prdelim(", "); + } + } + else{ + while(*u){ + m = runetochar(buf, u++); + s = buf; + while(--m >= 0){ + prid("byte "); + prchar(*s++); + prdelim(", "); + } + } + } + prid("byte "); + prchar('\0'); + prdelim(" }"); +} + +static Type *arrayofchar; + +static void +sdgen(Node *n, int glob) +{ + int sop = 0; + + prdelim(" := "); + if(glob && n->right->op == OS2AB && isstring(n->right->left)){ + if(arrayofchar == T){ + arrayofchar = typ1(TARRAY, types[TCHAR]); + arrayofchar->width = 0; + } + n->type = n->right->type = arrayofchar; + sop = 1; + } + else + n->type = n->right->type = T; + tgen(n->type, 0, 1); + if(sop) + stob(n->right->left); + else + eagen(n->right, n->type, 0, nil, 0); + prdelim(";"); + newline(); +} + +static void +tdgen(Node *n, int glob) +{ + int ar, arinit; + + if(ism()){ + prdelim(": "); + tgen(n->type, 1, 0); + if(n->op == ODAS) + prcom("initial value was ", n->right); + prdelim(";"); + newline(); + return; + } + if(n->op == ODAS && (isstring(n->right) || n->right->op == OS2AB)){ + sdgen(n, glob); + return; + } + ar = n->type->etype == TARRAY && n->type->width != LARR; + arinit = ar && n->op == ODAS; + if(ar) + prdelim(" := "); + else + prdelim(": "); + tgen(n->type, 0, arinit); + if(n->op == ODAS){ + if(!arinit) + prdelim(" = "); + eagen(n->right, n->type, 0, nil, 0); + } + prdelim(";"); + newline(); +} + +static int +isdec(Node *n) +{ + return isname(n) && n->kind != KEXP || n->op == ODAS; +} + +static void +sgen(Node *n, int blk, Node **ln) +{ + int comma = 0; + Node *nn; + + if(n == Z) + return; + if(blk){ + pushscope(n, SAUTO); + if(n->op == OLIST && !(blk&NOBR) || (blk&YESBR)){ + prdelim("{"); + newline(); + } + else if(!(blk&NONL)) + newline(); + if(!(blk&NOIN)) + incind(); + } + if((nn = *ln) != Z && isdec(nn)){ + if(isdec(n)){ + if(canjoin(nn, n)) + comma = 1; + else + tdgen(nn, 0); + } + else if(n->op != OLIST){ + tdgen(nn, 0); + newline(); + } + } + if(n->op != OLIST){ + *ln = n; + output(n->lineno, 1); + } + switch(n->op){ + default: + egen(n, ONOOP, PRE); + prdelim(";"); + newline(); + break; + case ODAS: + pushdcl(n->left, CAUTO); + egen(n->left, ONOOP, PRE); + break; + case ONAME: + if(n->kind == KEXP){ + egen(n, ONOOP, PRE); + prdelim(";"); + newline(); + } + else{ + pushdcl(n, CAUTO); + if(comma) + prdelim(", "); + if(n->op != ONAME) + diag(n, "internal: not name in sgen"); + prsym(n->sym, 0); + /* egen(n, ONOOP, PRE); */ +/* + prdelim(": "); + tgen(n->type, 0, 0, 0); + prdelim(";"); + newline(); +*/ + } + break; + case OSBREAK: + break; + case ONUL: + prdelim(";"); + newline(); + break; + case OBLK: + sgen(n->left, 1|YESBR, ln); + break; + case OLIST: + sgen(n->left, 0, ln); + sgen(n->right, 0, ln); + break; + case ORETURN: + prkeywd("return"); + if(n->left != Z) + prdelim(" "); + egen(n->left, ONOOP, PRE); + prdelim(";"); + newline(); + break; + case OLABEL: + prcom("was label ", n->left); + /* i = zeroind(); */ + /* egen(n->left, ONOOP, PRE); */ + /* prdelim(":"); */ + newline(); + /* restoreind(i); */ + break; + case OGOTO: + prcom("was goto ", n->left); + /* prkeywd("goto "); */ + /* egen(n->left, ONOOP, PRE); */ + prdelim(";"); + newline(); + break; + case OCASE: + for(nn = n->left; nn != Z; nn = nn->right){ + if(nn != n->left) + prkeywd(" or "); + if(nn->left != Z) + egen(nn->left, ONOOP, PRE); + else + prkeywd("*"); + } + prdelim(" =>"); + clrbrk(n->right); + sgen(n->right, 1|NOBR, ln); + if(n->kind != KLAST && !hasbrk(n->right)){ + prcom("fall through", Z); + newline(); + } + break; + case OSWITCH: + prkeywd("case"); + egen(n->left, OBRACKET, PRE); + sgen(n->right, 1|NOIN|YESBR, ln); + break; + case OWHILE: + prkeywd("while"); + egen(n->left, OBRACKET, PRE); + sgen(n->right, 1, ln); + break; + case ODWHILE: + prkeywd("do"); + sgen(n->right, 1|NOENL, ln); + prkeywd("while"); + egen(n->left, OBRACKET, PRE); + prdelim(";"); + newline(); + break; + case OFOR: + prkeywd("for"); + prdelim("("); + egen(n->left->right->left, ONOOP, PRE); + prdelim(";"); + if(n->left->left != Z) + prdelim(" "); + egen(n->left->left, ONOOP, PRE); + prdelim(";"); + if(n->left->right->right != Z) + prdelim(" "); + egen(n->left->right->right, ONOOP, PRE); + prdelim(")"); + sgen(n->right, 1, ln); + break; + case OCONTINUE: + prkeywd("continue"); + prdelim(";"); + newline(); + break; + case OBREAK: + prkeywd("break"); + prdelim(";"); + newline(); + break; + case OIF: + prkeywd("if"); + egen(n->left, OBRACKET, PRE); + if(n->right->left->op == OIF && n->right->left->right->right == Z && n->right->right != Z) /* avoid dangling else */ + sgen(n->right->left, 1|YESBR, ln); + else + sgen(n->right->left, 1, ln); + if(n->right->right != Z){ + prdelim("else"); + if(n->right->right->op == OIF){ /* merge else and if */ + prdelim(" "); + sgen(n->right->right, 1|NONL|NOIN, ln); + } + else + sgen(n->right->right, 1, ln); + } + break; + case OSET: + case OUSED: + prkeywd(ops[n->op].name); + lgen(n->left, 1, 1); + prdelim(";"); + newline(); + break; + } + if(blk){ + if(!(blk&NOIN)) + decind(); + if(n->op == OLIST&& !(blk&NOBR) || (blk&YESBR)){ + prdelim("}"); + if(!(blk&NOENL)) + newline(); + } + popscope(); + } +} + +static void rew(Node*, int); + +static void +rewc0(Node *n, Node *r) +{ + Node *nn; + + if((nn = cfind(n)) != Z){ + cgen0(nn, n); + if(r->op == ORETURN){ + n->right->left = new1(ORETURN, n->right->left, Z); + n->right->right = new1(ORETURN, n->right->right, Z); + n->right->left->type = n->right->left->left->type; + n->right->right->type = n->right->right->left->type; + *r = *n; + } + } +} + +static void +rewc1(Node *n) +{ + Node *c, *nc; + + if(n == Z || n->op != OCOND || side(n) || !simple(n)) + return; + c = n->left; + nc = new1(ONOT, ncopy(c), Z); + n->op = OOROR; + n->left = new1(OANDAND, c, n->right->left); + n->right = new1(OANDAND, nc, n->right->right); +} + +static void +rewc(Node *n, Node *r) +{ + Node *nn, *rr, *i; + + if((nn = cfind(n)) != Z){ + i = cgen(nn, n); + rr = new1(OXXX, Z, Z); + if(n == r && nn == n) + *rr = *nn; + else + *rr = *r; + r->op = OLIST; + r->left = i; + r->right = rr; + } +} + +static int +rewe(Node *n, Type *t, int lev) +{ + int op, k, k1, k2; + int v; + Node *nn; + + if(n == Z) + return -1; + switch(n->op){ + case OCONST: + break; + case ONAME: + if(strings || !isstring(n)) + break; + case OSTRING: + case OLSTRING: + if(!strings) + addnode(OS2AB, n); + break; + case OCOND: + bptr(n->left); + rewe(n->left, T, 1); + rewe(n->right, T, 1); + break; + case OIND: + if(isfn(n->type)){ + *n = *n->left; + rewe(n, T, 1); + break; + } + if(!isadt(n->type)){ + n->op = OARRIND; + n->right = con(0); + rewe(n, T, 1); + break; + } + rewe(n->left, T, 1); + break; + case OADDR: + if(n->left->op == OARRIND){ + n->right = n->left; + n->left = n->right->left; + n->right->left = n->right->right; + n->right->right = Z; + n->right->op = OLIST; + n->op = OSLICE; + rewe(n, T, 1); + break; + } + rewe(n->left, T, 1); + break; + case OSLICE: + rewe(n->left, T, 1); + rewe(n->right, T, 1); + if(n->left->op == OSLICE){ + n->right->left = addn(n->left->right->left, n->right->left); + n->right->right = addn(n->left->right->left, n->right->right); + n->left = n->left->left; + rewe(n, T, 1); + break; + } + break; + case OCOMMA: + rewe(n->left, T, 1); + rewe(n->right, T, 1); + if(n->left->op == OAS && n->right->op == OAS){ + n->op = OAS; + n->left->op = n->right->op = OLIST; + nn = n->left->right; + n->left->right = n->right->left; + n->right->left = nn; + rewe(n, T, 1); + break; + } + break; + case OFUNC: + if(n->left->op == ONAME){ + if((k = n->left->sym->kind) != LNONE){ + rewlc(n, k, t); + rewe(n->left, T, 1); + rewe(n->right, T, 1); + args(n); + return k; + } + } + else + rewe(n->left, T, 1); + rewe(n->right, T, 1); + args(n); + break; + case OCAST: + rewe(n->left, n->type, 1); + break; + case OAS: + case OASI: + case OASD: + rewe(n->left, T, 1); + rewe(n->right, n->type, 1); + break; + case ONOT: + case OANDAND: + case OOROR: + bptr(n); + rewe(n->left, T, 1); + rewe(n->right, T, 1); + break; + case OPREINC: + case OPOSTINC: + case OASADD: + if(n->op != OPOSTINC || lev == 0){ + sliceasgn(n); + if(n->op == OAS){ + rewe(n, T, 1); + break; + } + } + rewe(n->left, T, 1); + rewe(n->right, T, 1); + break; + case OEQ: + case ONE: + case OLT: + case OLE: + case OGT: + case OGE: + k1 = rewe(n->left, T, 1); + k2 = rewe(n->right, T, 1); + if(k1 == LSTRCMP && n->right->op == OCONST){ + op = -1; + v = n->right->vconst; + switch(v){ + case -1: + if(n->op == OEQ) + op = OLT; + else if(n->op == ONE) + op = OGE; + break; + case 0: + op = n->op; + break; + case 1: + if(n->op == OEQ) + op = OGT; + else if(n->op == ONE) + op = OLE; + break; + } + if(op != -1){ + *n = *n->left; + n->op = op; + } + } + if(k2 == LSTRCMP && n->left->op == OCONST){ + op = -1; + v = n->left->vconst; + switch(v){ + case -1: + if(n->op == OEQ) + op = OLT; + else if(n->op == ONE) + op = OGE; + break; + case 0: + op = rev(n->op); + break; + case 1: + if(n->op == OEQ) + op = OGT; + else if(n->op == ONE) + op = OLE; + break; + } + if(op != -1){ + *n = *n->right; + n->op = op; + } + } + break; + default: + rewe(n->left, T, 1); + rewe(n->right, T, 1); + break; + } + return -1; +} + +/* +static void +rewf(Node *n) +{ + if(n == Z) + return; + switch(n->op){ + case OFUNC: + if(n->left->op == ONAME) + fdargs(n); + break; + default: + rewf(n->left); + rewf(n->right); + break; + } +} +*/ + +static void +rew(Node *n, int blk) +{ + int i; + Node *a, *nn; + + if(n == Z) + return; + if(blk) + pushscope(n, SAUTO); + nearln = n->lineno; + if(n->blk){ + n->blk = 0; + addnode(OBLK, n); + } + switch(n->op){ + default: + if(simple(n)) + rewc0(n, n); + else + rewc(n, n); + if(n->op == OLIST || n->op == OIF){ + rew(n, 0); + break; + } + ecomplex(n); + break; + case ODAS: + pushdcl(n->left, CAUTO); + rewe(n->right, T, 1); + break; + case OSBREAK: + case ONUL: + break; + case ONAME: + if(n->kind == KEXP) + ecomplex(n); + else + pushdcl(n, CAUTO); + break; + case OBLK: + rew(n->left, 1); + break; + case OLIST: + rew(n->left, 0); + rew(n->right, 0); + break; + case ORETURN: + if(simple(n->left)) + rewc0(n->left, n); + else + rewc(n->left, n); + if(n->op != ORETURN){ + rew(n, 0); + break; + } + ecomplex(n); + break; + case OLABEL: + case OGOTO: + break; + case OCASE: + for(nn = n->left; nn != Z; nn = nn->right) + if(nn->left != Z) + ecomplex(nn->left); + rew(n->right, 1); + break; + case OSWITCH: + rewc(n->left, n); + if(n->op == OLIST){ + rew(n, 0); + break; + } + ecomplex(n->left); + if(!lteq(n->left->type, types[TINT])) + intcast(n->left); + n->right = buildcases(n->right); + rew(n->right, 1); + break; + case OWHILE: + case ODWHILE: + rewc1(n->left); + becomplex(n->left); + rew(n->right, 1); + break; + case OFOR: + rewc1(n->left->left); + rewc(n->left->right->left, n); + if(n->op == OLIST){ + rew(n, 0); + break; + } + becomplex(n->left->left); + ecomplex(n->left->right->left); + ecomplex(n->left->right->right); + rew(n->right, 1); + break; + case OCONTINUE: + break; + case OBREAK: + break; + case OIF: + rewc1(n->left); + rewc(n->left, n); + if(n->op == OLIST){ + rew(n, 0); + break; + } + becomplex(n->left); + rew(n->right->left, 1); + rew(n->right->right, 1); + break; + case OSET: + if(n->left == Z){ + n->op = ONUL; + n->left = n->right = Z; + break; + } + if(n->left->op != OLIST){ + n->op = OAS; + n->right = defval(n->left->type); + rew(n, 0); + break; + } + i = 0; + nn = Z; + for(;;){ + a = arg(n->left, i); + if(a == Z) + break; + a = new1(OAS, a, defval(a->type)); + if(i == 0) + nn = a; + else + nn = new1(OLIST, nn, a); + i++; + } + *n = *nn; + rew(n, 0); + break; + case OUSED: + if(n->left == Z){ + n->op = ONUL; + n->left = n->right = Z; + break; + } + i = 0; + nn = Z; + for(;;){ + a = arg(n->left, i); + if(a == Z) + break; + if(i == 0) + nn = a; + else + nn = new1(OOROR, nn, a); + i++; + } + n->op = OIF; + n->left = nn; + n->right = new1(OLIST, Z, Z); + n->right->left = new1(ONUL, Z, Z); + rew(n, 0); + break; + } + if(blk) + popscope(); +} + +void +codgen2(Node *n, Node *nn, int lastlno, int rw) +{ + Node *ln = Z; + + newsec(0); + output(nn->lineno, 1); + tmp = 0; + /* t = types[TVOID]; */ + nn = func(nn); + pushscope(nn, SPARM); + if(rw) + rew(n, 1); + egen(nn, ONOOP, PRE); + newline(); + prdelim("{"); + newline(); + incind(); + /* rewf(n); */ + pushscope(n, SAUTO); + sgen(n, 0, &ln); + if(ln != Z && isdec(ln)) + tdgen(ln, 0); + popscope(); + popscope(); + if(n != Z) + output(lline(n), 1); + output(lastlno, 1); + decind(); + prdelim("}"); + newline(); + newline(); + setmain(nn); +} + +void +rewall(Node *n, Node *nn, int lastlno) +{ + USED(lastlno); + tmp = 0; + nn = func(nn); + pushscope(nn, SPARM); + rew(n, 1); + popscope(); + setmain(nn); +} + +void +suball(Node *n, Node *nn) +{ + Node *rn; + + nn = func(nn); + pushscope(nn, SPARM); + subs(nn, 0, 0); + subs(n, 1, 1); + nn = lastn(n); + if(nn != Z && nn->op != ORETURN){ + rn = retval(Z); + if(rn != Z){ + addnode(OLIST, nn); + nn->right = rn; + } + } + popscope(); +} + +void +ginit(void) +{ + thechar = 'o'; + thestring = "386"; + tfield = types[TLONG]; +} + +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; + 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; + 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, Ael2); + o = align(o, t, Ael1); + w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ + break; + } + o = round(o, w); + if(0) + print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + return o; +} + +long +maxround(long max, long v) +{ + v = round(v, SZ_LONG); + if(v > max) + return v; + return max; +} + +static int +nlen(Node *n) +{ + if(n == Z) + return 0; + if(n->op == OLIST) + return nlen(n->left)+nlen(n->right); + return 1; +} + +static void +flatten(Node *n, Node **a, int *i) +{ + if(n == Z) + return; + if(n->op == OLIST){ + flatten(n->left, a, i); + flatten(n->right, a, i); + free(n); + return; + } + a[(*i)++] = n; +} + +static Node* +addcase(Node *n, Node **e, Node **s, int k) +{ + Node *nn; + + if(*e != Z){ + nn = new1(OCASE, *e, *s); + nn->right->blk = 0; + nn->kind = k; + } + else + nn = *s; + *e = *s = Z; + if(n == Z) + return nn; + return new1(OLIST, n, nn); +} + +/* collect case code together */ +static Node* +buildcases(Node *n) +{ + int i, m, m0, c; + Node *e, *s, *nn, **a, **ep; + + m = nlen(n); + a = (Node **)malloc(m*sizeof(Node*)); + m0 = 0; + flatten(n, a, &m0); + if(m != m0) + diag(Z, "internal: bad buildcases()"); + c = 1; + e = s = nn = Z; + ep = &e; + for(i = 0; i < m; i++){ + n = a[i]; + if(n->op == OCASE){ + if(!c){ + nn = addcase(nn, &e, &s, KNIL); + ep = &e; + } + *ep = new1(OLIST, n->left, Z); + if(n->left == Z) + (*ep)->lineno = n->lineno; + ep = &(*ep)->right; + c = 1; + } + else{ + if(s == Z) + s = n; + else + s = new1(OLIST, s, n); + c = 0; + } + } + nn = addcase(nn, &e, &s, KLAST); + free(a); + return nn; +} + +static Sym * +tmpgen(Type *t) +{ + Sym *s; + + sprint(buf, "tmp_%d", ++tmp); + s = slookup(buf); + s->type = t; + s->class = CAUTO; + if(t->etype == TENUM) + s->type = types[TINT]; + return s; +} + +static Node* +cfind(Node *n) +{ + Node *nn; + + if(n == Z) + return Z; + if(n->op == OCOND) + return n; + nn = cfind(n->left); + if(nn != Z) + return nn; + return cfind(n->right); +} + +Node* +ncopy(Node *n) +{ + Node *nn; + + if(n == Z) + return Z; + nn = new1(n->op, Z, Z); + *nn = *n; + nn->left = ncopy(n->left); + nn->right = ncopy(n->right); + return nn; +} + +static int +complexity(Node *n, int *cond) +{ + int c; + + if(n == Z) + return 0; + c = complexity(n->left, cond)+1+complexity(n->right, cond); + if(n->op == OCOND) + (*cond)++; + return c; +} + +static int +simple(Node *n) +{ + int c; + + c = 0; + return complexity(n, &c) < COMPLEX && c <= 1; +} + +static Type* +intype(Node *n) +{ + Type *t; + + t = ntype(n); + if(t == T) + return T; + return t->link; +} + +static Type* +ntype(Node *n) +{ + Type *t; + + if(n == Z) + return T; + t = n->type; + if(t != T){ + if(t->etype == TENUM) + return n->sym->tenum; + return t; + } + switch(n->op){ + case OEQ: + case ONE: + case OLT: + case OGE: + case OGT: + case OLE: + case ONOT: + case OANDAND: + case OOROR: + case OIOTA: + return types[TINT]; + case OCOMMA: + return ntype(n->right); + case OCOND: + return maxtype(ntype(n->right->left), ntype(n->right->right)); + case OFUNC: + return intype(n->left); + case ODOT: + tcomd(n, ntype(n->left)); + t = n->type; + n->type = T; + return t; + case ODOTIND: + tcomd(n, intype(n->left)); + t = n->type; + n->type = T; + return t; + case OARRIND: + return intype(n->left); + case OADDR: + return typ1(TIND, ntype(n->left)); + case OIND: + return intype(n->left); + case OSTRUCT: + return T; + } + return maxtype(ntype(n->left), ntype(n->right)); +} + +static Type* +gettype(Node *n1, Node *n2) +{ + Type *t; + + t = maxtype(n1->type, n2->type); + if(t != T) + return t; + return maxtype(ntype(n1), ntype(n2)); +} + +static void +cgen0(Node *n, Node *e) +{ + Node *c, *nn, *ed, *ee; + + if(n == e){ + n->op = OIF; + return; + } + c = n->left; + ed = new1(OXXX, Z, Z); + *ed = *e; + ee = ncopy(e); + nn = cfind(ee); + *n = *n->right->left; + *nn = *nn->right->right; + e->op = OIF; + e->left = c; + e->right = new1(OLIST, ed, ee); +} + +static Node* +cgen(Node *n, Node *e) +{ + Type *t; + Node *tn, *i; + + USED(e); + tn = new1(ONAME, Z, Z); + t = gettype(n->right->left, n->right->right); + tn->sym = tmpgen(t); + tn->type = tn->sym->type; +/* + if(n == e){ + n->op = OIF; + n->right->left = new1(OASD, tn, n->right->left); + n->right->right = new1(OAS, tn, n->right->right); + return n; + } +*/ + i = new1(OIF, n->left, new1(OLIST, new1(OASD, tn, n->right->left), new1(OAS, tn, n->right->right))); + *n = *tn; + return i; +} + +static struct{ + char *name; + int args; + int fd; + char *lname; +} sysops[] = { + "create", 1, RET, nil, + "dirstat", 1, 0, "stat", + "dirfstat", 0, 1, "fstat", + "dirwstat", 1, 0, "wstat", + "dirfwstat", 0, 1, "fwstat", + "dirread", 0, 1, nil, + "dup", 0, 0, nil, + "fprint", 2|STAR, 1, nil, + "fprintf", 2|STAR, 1, "fprint", + "open", 1, RET, nil, + "print", 1|STAR, 0, nil, + "printf", 1|STAR, 0, "print", + "read", 0, 1, nil, + "remove", 1, 0, nil, + "seek", 0, 1, nil, + "sleep", 0, 0, nil, + "sprint", 1|STAR, 0, nil, + "sprintf", 1|STAR, 0, "sprint", + "write", 0, 1, nil, + 0 +}; + +/* dummy entry for module */ +#define BIOTMP "__bio__" + +static struct{ + char *name; + char *lname; +} bioops[] = { + "Bflush", "flush", + "Bgetc", "getc", + "Bprint", "puts", + "Bputc", "putc", + "Bread", "read", + "Bseek", "seek", + "Bungetc", "ungetc", + "Bwrite", "write", + BIOTMP, nil, + 0 +}; + +char *libcops[] = { + "isalnum", + "isalpha", + "isascii", + "iscntrl", + "isdigit", + "isgraph", + "islower", + "isprint", + "ispunct", + "isspace", + "isupper", + "isxdigit", + "strchr", + "strrchr", + "toascii", + "tolower", + "toupper", + "abs", + "min", + "max", + 0, +}; + +static struct{ + char *name; + int type; + int string; +} xops[] = { + "strlen", LSTRLEN, 1, + "strcmp", LSTRCMP, 1, + "strcpy", LSTRCPY, 1, + "strcat", LSTRCAT, 1, + "strncmp", LSTRNCMP, 1, + "strncpy", LSTRNCPY, 1, + "strncat", LSTRNCAT, 1, + "strdup", LSTRDUP, 1, + "memcpy", LMEMMOVE, 0, + "memmove", LMEMMOVE, 0, + "malloc", LMALLOC, 0, + "free", LFREE, 0, + "exit", LEXIT, 0, + "exits", LEXIT, 0, + "close", LCLOSE, 0, + "atoi", LATOI, 0, + "atol", LATOI, 0, + "atoll", LATOL, 0, + "atof", LATOF, 0, + "atod", LATOF, 0, + "print", LPRINT, 0, + "printf", LPRINT, 0, + "fprint", LFPRINT, 0, + "fprintf", LFPRINT, 0, + "sprint", LSPRINT, 0, + "sprintf", LSPRINT, 0, + 0 +}; + +char *mathsops[] = { + "sin", + "cos", + "tan", + "sinh", + "cosh", + "tanh", + "asin", + "acos", + "atan", + "asinh", + "acosh", + "atanh", + "atan2", + "sqrt", + "cbrt", + "pow", + "pow10", + "exp", + "log", + "log10", + 0 +}; + +Node *glob, *globe; + +void +sysinit(void) +{ + int i; + Sym *s; + + glob = globe = new1(ONOOP, Z, Z); + for(i = 0; sysops[i].name; i++){ + s = slookup(sysops[i].name); + s->class = CEXTERN; + s->args = sysops[i].args; + s->fd = sysops[i].fd; + s->mod = "sys"; + s->lname = sysops[i].lname; + s->limbo = 1; + sysop = s; + } + for(i = 0; bioops[i].name; i++){ + s = slookup(bioops[i].name); + s->class = CEXTERN; + if(strcmp(bioops[i].name, BIOTMP) == 0){ + s->mod = "bufio"; + bioop = s; + } + s->lname = bioops[i].lname; + s->kind = LSELF; + s->limbo = 1; + } + for(i = 0; mathsops[i]; i++){ + s = slookup(mathsops[i]); + s->class = CEXTERN; + s->mod = "math"; + s->limbo = 1; + } + for(i = 0; libcops[i]; i++){ + s = slookup(libcops[i]); + s->class = CEXTERN; + s->mod = strings ? "libc" : "libc0"; + s->limbo = 1; + libcop = s; + } + for(i = 0; xops[i].name; i++){ + s = slookup(xops[i].name); + s->class = CEXTERN; + if(strings || !xops[i].string) + s->kind = xops[i].type; + else + s->mod = "libc0"; + if(s->kind == LEXIT) + s->lname = "exit"; + s->limbo = 1; + } + usemod(sysop, 1); + if(!strings) + usemod(libcop, 1); +} + +void +clbegin(void) +{ + pushscope(glob, SGLOB); +} + +void +clend(void) +{ + if(passes) + swalk(); + popscope(); +} + +static Modl *mods; + +void +usemod(Sym *s, int ld) +{ + Modl *ml; + + for(ml = mods; ml != nil; ml = ml->nxt) + if(strcmp(ml->mod, s->mod) == 0){ + ml->ld |= ld; + return; + } + ml = (Modl *)malloc(sizeof(Modl)); + ml->mod = s->mod; + ml->ld = ld; + ml->nxt = mods; + mods = ml; +} + +static void +ginc(Modl *ml) +{ + int c; + char *s; + + if(ml == nil) + return; + if(ml->nxt != nil) + ginc(ml->nxt); + s = ml->mod; + c = toupper(s[0]); + sprint(buf, "include \"%s.m\";", s); + prline(buf); + if(ml->ld){ + sprint(buf, " %s: %c%s;", s, c, s+1); + prline(buf); + } +} + +static void +gload(Modl *ml) +{ + int c; + char *s; + + if(ml == nil) + return; + if(ml->nxt != nil) + gload(ml->nxt); + if(ml->ld){ + s = ml->mod; + c = toupper(s[0]); + sprint(buf, " %s = load %c%s %c%s->PATH;", s, c, s+1, c, s+1); + prline(buf); + } +} + +static void +callmain(void) +{ + if(inmain){ + if(strings) + prline(" main(len argl, argl);"); + else + prline(" main(len argl, libc0->ls2aab(argl));"); + } +} + +static void +genstart(void) +{ + char *s; + + if(!strings && inmain) + usemod(libcop, 1); + ginc(mods); + s = hasm(); + if(s){ + sprint(buf, "include \"%s\";", s); + prline(buf); + } + prline(""); + prline("init(nil: ref Draw->Context, argl: list of string)"); + prline("{"); + gload(mods); + callmain(); + prline("}"); + prline(""); +} + +static int +argpos0(Node *nn, Node *n, int *p) +{ + int pp; + + if(n == Z) + return -1; + if(n->op == OLIST){ + pp = argpos0(nn, n->left, p); + if(pp >= 0) + return pp; + return argpos0(nn, n->right, p); + } + if(n == nn) + return *p; + (*p)++; + return -1; +} + +static int +argpos(Node *nn, Node *n) +{ + int p = 0; + + p = argpos0(nn, n, &p); + if(p < 0) + diag(Z, "-ve argpos"); + return p; +} + +static Node* +arg0(Node *n, int a, int *i) +{ + Node *nn; + + if(n == Z) + return Z; + if(n->op == OLIST){ + nn = arg0(n->left, a, i); + if(nn != Z) + return nn; + return arg0(n->right, a, i); + } + if(a == (*i)++) + return n; + return Z; +} + +static Node* +arg(Node *n, int a) +{ + int i = 0; + + return arg0(n, a, &i); +} + +static Node* +list(Node *l, Node *r) +{ + if(r == Z) + return l; + if(l == Z) + return r; + return new1(OLIST, l, r); +} + +static Node* +droparg(Node *n, int a, int *i) +{ + if(n == Z) + return Z; + if(n->op == OLIST) + return list(droparg(n->left, a, i), droparg(n->right, a, i)); + if(a == (*i)++) + return Z; + return n; +} + +static void +sargs(Node *n) +{ + int s, f, i, j; + Node *a; + + if(strings || (f = n->left->sym->args) == 0) + return; + s = 0; + for(i = 1, j = 0; i < STAR || s; i *= 2, j++){ + if(f&i || s){ + a = arg(n->right, j); + if(a == Z) + break; + if(s && !isstr(a->type)) + continue; + if(f&STAR) + s++; + if(a->op == OS2AB){ + *a = *a->left; + continue; + } + addnode(OAB2S, a); + } + } +} + +static void +fdargs(Node *n) +{ + int f, i, j; + Node *a; + + if((f = n->left->sym->fd) == 0) + return; + marktype(pfdtype, TCFD); + if(f&RET) + tcon(n, pfdtype); + for(i = 1, j = 0; i < RET; i *= 2, j++){ + if(f&i){ + a = arg(n->right, j); + if(a == Z) + break; + tcon(a, pfdtype); + } + } +} + +static void +aargs(Node *n) +{ + int i; + Node *a, *nn, *fn; + Type *t, *t0, *ft, *at, *st; + + if(!doaddr) + return; + if(n->op != OFUNC || n->left->op != ONAME) + return; + /* ft = n->left->type; */ + ft = n->left->sym->type; + t = t0 = ft->link; + nn = Z; + for(i = 0; ; i++){ + a = arg(n->right, i); + if(a == Z) + break; + at = typn(ft, i); + if(at != T && at->etype != TDOT && (a->op == OADDR || iteq(a->type, at) || iteq(at, a->type))){ + if(iteq(at, a->type)) + st = at->link; + else + st = a->type->link; + if(doalladdr || isscalar(st)){ + if(a->op == OADDR) + *a = *a->left; + else if(iteq(a->type, at)) + a->type = at; + if(t->mark == 0){ + t = tuple(t, a->type); + trep(at, at->link); + fn = finddec(n->left->sym, 1); + if(fn != Z && fn->op == OFUNC) + tind(arg(fn->right, i)); + } + if(nn == Z) + nn = cknil(ncopy(a)); + else{ + nn = new1(OTUPLE, nn, cknil(ncopy(a))); + nn->type = t; + } + } + } + } + if(nn != Z){ + if(isvoid(t0) || t->mark == TCPC) + marktype(t, TCPC); + else + marktype(t, TCFC); + tcon(n, t); + addnode(ORETV, n); + n->right = nn; + } +} + +static void +args(Node *n) +{ + if(n->op != OFUNC || n->left->op != ONAME) + return; + sargs(n); + if(passes){ + fdargs(n); + aargs(n); + } +} + +static Node* +indir(Node *n) +{ + if(n->op == OADDR) + return n->left; + return new1(OIND, n, Z); +} + +static void +rewlc(Node *n, int k, Type *t) +{ + int i; + Type *tt; + Node *a0, *a1, *a2, *nn; + + if(t == T) + t = n->type; + a0 = arg(n->right, 0); + a1 = arg(n->right, 1); + switch(k){ + case LSTRLEN: + n->op = OLEN; + break; + case LSTRCMP: + n->op = ONE; + n->left = a0; + n->right = a1; + break; + case LSTRCPY: + n->op = OAS; + n->left = a0; + n->right = a1; + n->type = n->left->type; + break; + case LSTRCAT: + n->op = OASADD; + n->left = a0; + n->right = a1; + n->type = n->left->type; + break; + case LSTRDUP: + *n = *a0; + break; + case LMEMMOVE: + if(!teq(a0->type, a1->type)) + break; + if(a0->type->etype == TIND){ + tt = a0->type->link; + a2 = arg(n->right, 2); + if(isadt(tt) && isconst(a2, tt->width)){ + n->op = OAS; + n->left = indir(a0); + n->right = indir(a1); + n->type = n->left->type = n->right->type = tt; + break; + } + if(mydiv(a2, tt->width) != Z){ + n->op = OAS; + n->left = new1(OSLICE, a0, new1(OLIST, con(0), Z)); + n->right = new1(OSLICE, a1, new1(OLIST, con(0), a2)); + n->type = n->left->type = n->right->type = a0->type; + } + } + break; + case LMALLOC: + if(t->etype == TIND){ + tt = t->link; + if(isadt(tt) && isconst(a0, tt->width)){ + n->op = OREF; + n->left = Z; + n->right = Z; + n->type = t; + break; + } + if(mydiv(a0, tt->width) != Z){ + n->op = OARRAYOF; + n->left = a0; + n->right = Z; + n->type = t; + if(isadt(tt)){ + n->type = typ1(TARRAY, tt); + n->type->width = LARR; /* limbo array without bounds */ + marktype(n->type, TCAR); + } + } + } + break; + case LFREE: + n->op = OAS; + n->left = a0; + n->right = con(0); + n->type = n->left->type; + n->right->type = n->type; + break; + case LEXIT: + i = n->kind; + *n = *n->left; + n->kind = i; + break; + case LCLOSE: + n->op = OAS; + n->left = a0; + n->right = con(0); + n->left->type = typ1(TIND, n->left->type); + n->type = n->left->type; + n->right->type = n->type; + break; + case LATOI: + if(!strings) + strcast(a0); + n->op = OCAST; + n->left = a0; + n->right = Z; + n->type = types[TINT]; + break; + case LATOL: + if(!strings) + strcast(a0); + n->op = OCAST; + n->left = a0; + n->right = Z; + n->type = types[TVLONG]; + break; + case LATOF: + if(!strings) + strcast(a0); + n->op = OCAST; + n->left = a0; + n->right = Z; + n->type = types[TDOUBLE]; + break; + case LPRINT: + if(a0->op == OSTRING) + pfmt(a0->cstring); + else if(a0->op == OLSTRING) + lpfmt(a0->rstring); + break; + case LFPRINT: + if(a1->op == OSTRING) + pfmt(a1->cstring); + else if(a1->op == OLSTRING) + lpfmt(a1->rstring); + break; + case LSPRINT: + if(n->right->kind != KDROP){ + if(a1->op == OSTRING) + pfmt(a1->cstring); + else if(a1->op == OLSTRING) + lpfmt(a1->rstring); + nn = new1(OXXX, Z, Z); + *nn = *n; + i = 0; + nn->right = droparg(nn->right, 0, &i); + nn->right->kind = KDROP; + n->op = OAS; + n->left = a0; + n->right = nn; + n->type = nn->type; + } + break; + case LSELF: + if(n->right != Z && n->right->kind != KDROP){ + i = 0; + n->right = droparg(n->right, 0, &i); + if(n->right != Z) + n->right->kind = KDROP; + addnode(OLDOT, n->left); + n->left->right = n->left->left; + n->left->left = a0; + usemod(bioop, 1); + } + break; + } +} + +void +expgen(Node *n) +{ + egen(n, ONOOP, PRE); +} + +static void +clrbrk(Node *n) +{ + if(n == Z) + return; + switch(n->op){ + case OLIST: + clrbrk(n->right); + break; + case OBREAK: + n->op = OSBREAK; + n->left = n->right = Z; + break; + } +} + +static int +hasbrk(Node *n) +{ + if(n == Z) + return 0; + switch(n->op){ + case OLIST: + case OWHILE: + case ODWHILE: + case OFOR: + return hasbrk(n->right); + case OIF: + if(n->right->right == Z) + return 0; + return hasbrk(n->right->left) && hasbrk(n->right->right); + case ORETURN: + case OGOTO: + case OCONTINUE: + case OBREAK: + case OSBREAK: + return 1; + default: + return 0; + } + return 0; +} + +static int +isgen(char *s) +{ + char *s1, *s2; + + s1 = strchr(s, '_'); + s2 = strrchr(s, '_'); + if(s1 == nil || s2-s1 != 4) + return 0; + return s1[1] == 'a' && s1[2] == 'd' && s1[3] == 't'; +} + +static void +addmodn(Sym *s) +{ + char buf[128], *ns; + + if(s->name[0] == '_'){ + outmod(buf, -1); + ns = malloc(strlen(buf)+strlen(s->name)+1); + strcpy(ns, buf); + strcat(ns, s->name); + s->name = ns; + } +} + +static void +pfmt(char *s) +{ + char *t = s; + + while(*s != '\0'){ + if(*s == '%'){ + *t++ = *s++; + if(*s == 'l'){ + s++; + if(*s == 'l') + *t++ = 'b'; + else + *t++ = *s; + s++; + } + else if(*s == 'p'){ + *t++ = 'x'; + s++; + } + else + *t++ = *s++; + } + else + *t++ = *s++; + } + *t = '\0'; +} + +static void +lpfmt(ushort *s) +{ + ushort*t = s; + + while(*s != '\0'){ + if(*s == '%'){ + *t++ = *s++; + if(*s == 'l'){ + s++; + if(*s == 'l') + *t++ = 'b'; + else + *t++ = *s; + s++; + } + else if(*s == 'p'){ + *t++ = 'x'; + s++; + } + else + *t++ = *s++; + } + else + *t++ = *s++; + } + *t = '\0'; +} + +int +line(Node *n) +{ + if(n == Z) + return 0; + if(n->op == OLIST) + return line(n->left); + return n->lineno; +} + +static int +lline(Node *n) +{ + if(n == Z) + return 0; + if(n->op == OLIST) + return lline(n->right); + return n->lineno+1; +} + +static Node* +lastn(Node *n) +{ + while(n != Z && n->op == OLIST) + n = n->right; + return n; +} + +static Node* +newnode(int op, Node *l) +{ + Node *n; + + n = new1(op, l, Z); + globe->right = n; + globe = n; + return n; +} + +void +codgen1(Node *n, Node *nn, int lastlno) +{ + Node *nnn; + + scomplex(n); + nnn = newnode(OCODE, new1(OLIST, n, nn)); + nnn->lineno = lastlno; + mset(n); + mset(nn); + nn = func(nn); + newnode(ODECF, nn); + setmain(nn); +} + +void +vtgen1(Node *n) +{ + int c; + Node *nn = n; + + if(n->op == ODAS) + nn = n->left; + if(nn->type == T || nn->sym == S) + return; + c = nn->sym->class; + if(c == CGLOBL || c == CSTATIC || c == CLOCAL || c == CEXREG){ + newnode(ODECV, n); + if(nn->type->etype != TFUNC || ism()) + setmod(nn->sym); + } + mset(n); +} + +void +etgen1(Sym *s) +{ + Node *n; + + n = newnode(ODECE, Z); + n->sym = s; + if(s != S) + setmod(s); +} + +void +ttgen1(Type *t) +{ + Node *n; + + n = newnode(ODECT, Z); + n->type = t; + if(isadt(t)) + setmod(suename(t)); +} + +void +outpush1(char *s) +{ + Node *n; + char *t; + + n = newnode(OPUSH, Z); + if(s == nil) + t = nil; + else{ + t = malloc(strlen(s)+1); + strcpy(t, s); + } + n->cstring = t; + outpush0(s, n); +} + +void +outpop1(int lno) +{ + Node *n; + + n = newnode(OPOP, Z); + n->lineno = lno; + outpop0(lno); +} + +void +codgen(Node *n, Node *nn, int lastlno) +{ + if(passes) + codgen1(n, nn, lastlno); + else + codgen2(n, nn, lastlno, 1); +} + +void +vtgen(Node *n) +{ + if(passes) + vtgen1(n); + else + vtgen2(n); +} + +void +etgen(Sym *s) +{ + if(passes) + etgen1(s); + else + etgen2(s); +} + +void +ttgen(Type *t) +{ + if(passes) + ttgen1(t); + else + ttgen2(t); +} + +void +outpush(char *s) +{ + if(passes) + outpush1(s); + else + outpush2(s, Z); +} + +void +outpop(int lno) +{ + if(passes) + outpop1(lno); + else + outpop2(lno); +} + +static void +swalk(void) +{ + Node *n, *l; + + for(n = glob; n != Z; n = n->right){ + l = n->left; + switch(n->op){ + case OCODE: + rewall(l->left, l->right, n->lineno); + break; + default: + break; + } + } + while(again){ + again = 0; + for(n = glob; n != Z; n = n->right){ + l = n->left; + switch(n->op){ + case OCODE: + suball(l->left, l->right); + break; + case ODECV: + subs(l, 0, 0); + break; + case ODECE: + case ODECT: + case ODECF: + break; + default: + break; + } + } + } + for(n = glob; n != Z; n = n->right){ + l = n->left; + switch(n->op){ + case ONOOP: + break; + case OPUSH: + outpush2(n->cstring, n); + break; + case OPOP: + outpop2(n->lineno); + break; + case OCODE: + codgen2(l->left, l->right, n->lineno, 0); + break; + case ODECV: + vtgen2(l); + break; + case ODECE: + etgen2(n->sym); + break; + case ODECT: + ttgen2(n->type); + break; + case ODECF: + break; + } + } +} + +static void +scomplex(Node *n) +{ + if(n == Z) + return; + switch(n->op){ + default: + complex(n); + break; + case ODAS: + case OSBREAK: + case ONUL: + case OLABEL: + case OGOTO: + case OCONTINUE: + case OBREAK: + break; + case ONAME: + if(n->kind == KEXP) + complex(n); + break; + case OBLK: + case OSET: + case OUSED: + scomplex(n->left); + break; + case OLIST: + scomplex(n->left); + scomplex(n->right); + break; + case ORETURN: + complex(n); + break; + case OCASE: + complex(n->left); + break; + case OSWITCH: + case OWHILE: + case ODWHILE: + complex(n->left); + scomplex(n->right); + break; + case OFOR: + complex(n->left->left); + complex(n->left->right->left); + complex(n->left->right->right); + scomplex(n->right); + break; + case OIF: + complex(n->left); + scomplex(n->right->left); + scomplex(n->right->right); + break; + } +} + +static void +mtset(Type *t) +{ + if(t == T) + return; + switch(t->etype){ + case TIND: + case TARRAY: + mtset(t->link); + break; + case TSTRUCT: + case TUNION: + prsym0(suename(t)); + /* + for(l = t->link; l != T; l = l->down) + mtset(l); + */ + break; + } +} + +static void +mset(Node *n) +{ + if(n == Z) + return; + n->garb = 0; + if(n->op == ONAME) + prsym0(n->sym); + mtset(n->type); + mset(n->left); + mset(n->right); +} + +static int +sign(Node *n) +{ + int s; + + if(n == Z) + return 1; + switch(n->op){ + case OCONST: + sign(n->left); + if(n->vconst < 0){ + n->vconst = -n->vconst; + return -1; + } + break; + case OPOS: + s = sign(n->left); + *n = *n->left; + return s; + case ONEG: + s = sign(n->left); + *n = *n->left; + return -s; + case OADD: + if(sign(n->right) < 0) + n->op = OSUB; + break; + case OSUB: + if(sign(n->right) < 0) + n->op = OADD; + break; + case OMUL: + case ODIV: + return sign(n->left)*sign(n->right); + default: + break; + } + return 1; +} + +static Node* +ckneg(Node *n) +{ + if(sign(n) < 0) + return new1(ONEG, n, Z); + return n; +} + +static void +sliceasgn(Node *n) +{ + Type *t; + Node *nn; + + if(side(n->left) || (n->right != Z && side(n->right))) + return; + t = n->type; + if(isarray(t) && (!strings || t->link->etype != TCHAR)){ + if(n->op == OASADD) + nn = n->right; + else + nn = con(1); + n->op = OAS; + n->right = new1(OSLICE, ncopy(n->left), new1(OLIST, nn, Z)); + } +} diff --git a/utils/c2l/cc.h b/utils/c2l/cc.h new file mode 100644 index 00000000..3900506d --- /dev/null +++ b/utils/c2l/cc.h @@ -0,0 +1,849 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Node Node; +typedef struct Sym Sym; +typedef struct Type Type; +typedef struct Decl Decl; +typedef struct Io Io; +typedef struct Hist Hist; +typedef struct Term Term; +typedef struct Init Init; +typedef struct Bits Bits; + +#define NHUNK 50000L +#define BUFSIZ 8192 +#define NSYMB 500 +#define NHASH 1024 +#define STRINGSZ 200 +#define HISTSZ 20 +#define YYMAXDEPTH 500 +#define NTERM 10 +#define MAXALIGN 7 + +#define SIGN(n) ((vlong)1<<(n-1)) +#define MASK(n) (SIGN(n)|(SIGN(n)-1)) + +#define BITS 5 +#define NVAR (BITS*sizeof(ulong)*8) +struct Bits +{ + ulong b[BITS]; +}; + +EXTERN int lastnumbase; + +#define KNIL 0 +#define KCHR 1 +#define KOCT 2 +#define KDEC 3 +#define KHEX 4 +#define KEXP 5 +#define KDROP 6 +#define KLAST 7 + +struct Node +{ + Node* left; + Node* right; + double fconst; /* fp constant */ + vlong vconst; /* non fp const */ + char* cstring; /* character string */ + ushort* rstring; /* rune string */ + + Sym* sym; + Type* type; + long lineno; + char op; + char garb; + char kind; + char blk; +}; +#define Z ((Node*)0) +#define ZZ ((Node*)-1) + +struct Sym +{ + Sym* link; + Type* type; + Type* suetag; + Type* tenum; + char* macro; + long lineno; + long offset; + vlong vconst; + double fconst; + Node* nconst; + char* cstring; + Node* label; + char *name; + char *lname; + char *mod; + ushort lexical; + ushort block; + ushort sueblock; + char class; + char kind; + char lkw; + char args; + char fd; + char limbo; +}; +#define S ((Sym*)0) + +struct Decl +{ + Decl* link; + Sym* sym; + Type* type; + long offset; + long lineno; + short val; + ushort block; + char class; +}; +#define D ((Decl*)0) + +struct Type +{ + Sym* sym; + Sym* tag; + Type* link; + Type* down; + Node* nwidth; + long width; + long offset; + long lineno; + char shift; + char nbits; + char etype; + char garb; + char vis; + char mark; +}; +#define T ((Type*)0) +#define NODECL ((void(*)(int, Type*, Sym*))0) + +struct Init /* general purpose initialization */ +{ + int code; + ulong value; + char* s; +}; + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char* p; + char b[BUFSIZ]; + short c; + short f; +}; +#define I ((Io*)0) + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) +EXTERN Hist* hist; + +struct Term +{ + vlong mult; + Node *node; +}; + +enum +{ + Axxx, + Ael1, + Ael2, + Asu2, + Aarg0, + Aarg1, + Aarg2, + Aaut3, + NALIGN, +}; + +enum /* also in ../{8a,0a}.h */ +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +enum +{ + DMARK, + DAUTO, + DSUE, + DLABEL, +}; +enum +{ + ONOOP, + OXXX, + OADD, + OADDR, + OAND, + OANDAND, + OARRAY, + OAS, + OASI, + OASADD, + OASAND, + OASASHL, + OASASHR, + OASDIV, + OASHL, + OASHR, + OASLDIV, + OASLMOD, + OASLMUL, + OASLSHR, + OASMOD, + OASMUL, + OASOR, + OASSUB, + OASXOR, + OBIT, + OBREAK, + OCASE, + OCAST, + OCOMMA, + OCOND, + OCONST, + OCONTINUE, + ODIV, + ODOT, + ODOTDOT, + ODWHILE, + OENUM, + OEQ, + OFOR, + OFUNC, + OGE, + OGOTO, + OGT, + OHI, + OHS, + OIF, + OIND, + OINDREG, + OINIT, + OLABEL, + OLDIV, + OLE, + OLIST, + OLMOD, + OLMUL, + OLO, + OLS, + OLSHR, + OLT, + OMOD, + OMUL, + ONAME, + ONE, + ONOT, + OOR, + OOROR, + OPOSTDEC, + OPOSTINC, + OPREDEC, + OPREINC, + OPROTO, + OREGISTER, + ORETURN, + OSET, + OSIGN, + OSIZE, + OSTRING, + OLSTRING, + OSTRUCT, + OSUB, + OSWITCH, + OUNION, + OUSED, + OWHILE, + OXOR, + ONEG, + OCOM, + OELEM, + + OTST, /* used in some compilers */ + OINDEX, + OFAS, + + OBLK, + OPOS, + ONUL, + ODOTIND, + OARRIND, + ODAS, + OASD, + OIOTA, + OLEN, + OBRACKET, + OREF, + OARRAYOF, + OSLICE, + OSADDR, + ONIL, + OS2AB, + OAB2S, + OFILDES, + OFD, + OTUPLE, + OT0, + ORETV, + OCAT, + OSBREAK, + OLDOT, + OMDOT, + + OCODE, + ODECE, + ODECT, + ODECV, + ODECF, + OPUSH, + OPOP, + + OEND +}; +enum +{ + TXXX, + TCHAR, + TUCHAR, + TSHORT, + TUSHORT, + TINT, + TUINT, + TLONG, + TULONG, + TVLONG, + TUVLONG, + TFLOAT, + TDOUBLE, + TIND, + TFUNC, + TARRAY, + TVOID, + TSTRUCT, + TUNION, + TENUM, + NTYPE, + + TAUTO = NTYPE, + TEXTERN, + TSTATIC, + TTYPEDEF, + TREGISTER, + TCONSTNT, + TVOLATILE, + TUNSIGNED, + TSIGNED, + TDOT, + TFILE, + TOLD, + + TSTRING, + TFD, + TTUPLE, + + NALLTYPES, +}; +enum +{ + CXXX, + CAUTO, + CEXTERN, + CGLOBL, + CSTATIC, + CLOCAL, + CTYPEDEF, + CPARAM, + CSELEM, + CLABEL, + CEXREG, + NCTYPES, +}; +enum +{ + GXXX = 0, + GCONSTNT = 1<<0, + GVOLATILE = 1<<1, + NGTYPES = 1<<2, +}; +enum +{ + BCHAR = 1L<<TCHAR, + BUCHAR = 1L<<TUCHAR, + BSHORT = 1L<<TSHORT, + BUSHORT = 1L<<TUSHORT, + BINT = 1L<<TINT, + BUINT = 1L<<TUINT, + BLONG = 1L<<TLONG, + BULONG = 1L<<TULONG, + BVLONG = 1L<<TVLONG, + BUVLONG = 1L<<TUVLONG, + BFLOAT = 1L<<TFLOAT, + BDOUBLE = 1L<<TDOUBLE, + BIND = 1L<<TIND, + BFUNC = 1L<<TFUNC, + BARRAY = 1L<<TARRAY, + BVOID = 1L<<TVOID, + BSTRUCT = 1L<<TSTRUCT, + BUNION = 1L<<TUNION, + BENUM = 1L<<TENUM, + BFILE = 1L<<TFILE, + BOLD = 1L<<TOLD, + BDOT = 1L<<TDOT, + BCONSTNT = 1L<<TCONSTNT, + BVOLATILE = 1L<<TVOLATILE, + BUNSIGNED = 1L<<TUNSIGNED, + BSIGNED = 1L<<TSIGNED, + BAUTO = 1L<<TAUTO, + BEXTERN = 1L<<TEXTERN, + BSTATIC = 1L<<TSTATIC, + BTYPEDEF = 1L<<TTYPEDEF, + BREGISTER = 1L<<TREGISTER, + + BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT| + BLONG|BULONG|BVLONG|BUVLONG, + BNUMBER = BINTEGER|BFLOAT|BDOUBLE, + +/* these can be overloaded with complex types */ + + BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BREGISTER, + + BGARB = BCONSTNT|BVOLATILE, +}; + +EXTERN struct +{ + Type* tenum; /* type of entire enum */ + Type* cenum; /* type of current enum run */ + vlong lastenum; /* value of current enum */ + double floatenum; /* value of current enum */ +} en; + +EXTERN int autobn; +EXTERN long autoffset; +EXTERN int blockno; +EXTERN int comm; +EXTERN Decl* dclstack; +EXTERN int doaddr; +EXTERN int doalladdr; +EXTERN int doinc; +EXTERN int doloc; +EXTERN int domod; +EXTERN Hist* ehist; +EXTERN long firstbit; +EXTERN Decl* firstdcl; +EXTERN int fperror; +EXTERN Sym* hash[NHASH]; +EXTERN char* hunk; +EXTERN char* include[20]; +EXTERN Type* fdtype; +EXTERN int inmain; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN int justcode; +EXTERN long lastbit; +EXTERN char lastclass; +EXTERN Type* lastdcl; +EXTERN long lastfield; +EXTERN Type* lasttype; +EXTERN long lineno; +EXTERN long nearln; +EXTERN int nerrors; +EXTERN int newflag; +EXTERN long nhunk; +EXTERN int ninclude; +EXTERN Node* nodproto; +EXTERN Node* nodcast; +EXTERN int passes; +EXTERN char* pathname; +EXTERN int peekc; +EXTERN Type* pfdtype; +EXTERN long pline; +EXTERN long saveline; +EXTERN Type* strf; +EXTERN int strings; +EXTERN Type* stringtype; +EXTERN Type* strl; +EXTERN char symb[NSYMB]; +EXTERN Sym* symstring; +EXTERN int taggen; +EXTERN Type* tfield; +EXTERN Type* tufield; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN Type* thisfn; +EXTERN long thunk; +EXTERN Type* types[NTYPE]; +EXTERN Node* initlist; +EXTERN int nterm; +EXTERN int hjdickflg; +EXTERN int fproundflg; +EXTERN Bits zbits; + +extern char *onames[], *tnames[], *gnames[]; +extern char *cnames[], *qnames[], *bnames[]; +extern char tab[NTYPE][NTYPE]; +extern char comrel[], invrel[], logrel[]; +extern long ncast[], tadd[], tand[]; +extern long targ[], tasadd[], tasign[], tcast[]; +extern long tdot[], tfunct[], tindir[], tmul[]; +extern long tnot[], trel[], tsub[]; + +extern char typeaf[]; +extern char typefd[]; +extern char typei[]; +extern char typesu[]; +extern char typesuv[]; +extern char typeu[]; +extern char typev[]; +extern char typec[]; +extern char typeh[]; +extern char typeil[]; +extern char typeilp[]; +extern char typechl[]; +extern char typechlp[]; +extern char typechlpfd[]; + +extern ulong thash1; +extern ulong thash2; +extern ulong thash3; +extern ulong thash[]; + +/* + * Inferno.c/Posix.c/Nt.c + */ +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); + +/* + * parser + */ +int yyparse(void); +int mpatof(char*, double*); +int mpatov(char*, vlong*); + +/* + * lex.c + */ +void* allocn(void*, long, long); +void* alloc(long); +void cinit(void); +int compile(char*, char**, int); +void errorexit(void); +int filbuf(void); +int getc(void); +long getr(void); +int getnsc(void); +Sym* lookup(void); +void main(int, char*[]); +void newfile(char*, int); +void newio(void); +void outbegin(char *); +void outend(void); +void outfun(Node*); +void pushio(void); +long escchar(long, int, int); +Sym* slookup(char*); +void syminit(Sym*); +void unget(int); +long yylex(void); +int Lconv(Fmt*); +int Tconv(Fmt*); +int FNconv(Fmt*); +int Oconv(Fmt*); +int Qconv(Fmt*); +int VBconv(Fmt*); +void setinclude(char*); + +/* + * mac.c + */ +void dodefine(char*); +void domacro(void); +Sym* getsym(void); +long getnsn(void); +void linehist(char*, int); +void macdef(void); +void macprag(void); +void macend(void); +void macexpand(Sym*, char*); +void macif(int); +void macinc(void); +void maclin(void); +void macund(void); + +/* + * dcl.c + */ +Node* doinit(Sym*, Type*, long, Node*); +Type* tcopy(Type*); +void init1(Sym*, Type*, long, int); +Node* newlist(Node*, Node*); +void adecl(int, Type*, Sym*); +int anyproto(Node*); +void argmark(Node*, int); +void dbgdecl(Sym*); +Node* dcllabel(Sym*, int); +Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*, int); +Sym* mkstatic(Sym*); +void doenum(Sym*, Node*); +void snap(Type*); +Type* dotag(Sym*, int, int); +void edecl(int, Type*, Sym*); +Type* fnproto(Node*); +Type* fnproto1(Node*); +void markdcl(void); +Type* paramconv(Type*, int); +void pdecl(int, Type*, Sym*); +Decl* push(void); +Decl* push1(Sym*); +Node* revertdcl(void); +#define round ccround +long round(long, int); +int rsametype(Type*, Type*, int, int); +int sametype(Type*, Type*); +ulong signature(Type*, int); +void suallign(Type*); +void tmerge(Type*, Sym*); +void walkparam(Node*, int); +void xdecl(int, Type*, Sym*); +Node* contig(Sym*, Node*, long); + +/* + * com.c + */ +void ccom(Node*); +void complex(Node*); +int tcom(Node*); +int tcoma(Node*, Node*, Type*, int); +int tcomd(Node*, Type*); +int tcomo(Node*, int); +int tcomx(Node*); +int tlvalue(Node*); +void constas(Node*, Type*, Type*); + +/* + * con.c + */ +void acom(Node*); +void acom1(vlong, Node*); +void acom2(Node*, Type*); +int acomcmp1(const void*, const void*); +int acomcmp2(const void*, const void*); +int addo(Node*); +void evconst(Node*); + +/* + * sub.c + */ +void arith(Node*, int); +Type* dotsearch(Sym*, Type*, Node*); +long dotoffset(Type*, Type*, Node*); +void gethunk(void); +Node* invert(Node*); +int bitno(long); +void makedot(Node*, Type*, long); +Node* new(int, Node*, Node*); +Node* new1(int, Node*, Node*); +int nilcast(Type*, Type*); +int nocast(Type*, Type*); +void prtree(Node*, char*); +void prtree1(Node*, int, int); +void relcon(Node*, Node*); +int relindex(int); +int simpleg(long); +Type* garbt(Type*, long); +int simplec(long); +Type* simplet(long); +int stcompat(Node*, Type*, Type*, long[]); +int tcompat(Node*, Type*, Type*, long[]); +void tinit(void); +Type* typ(int, Type*); +Type* typ1(int, Type*); +void typeext(Type*, Node*); +void typeext1(Type*, Node*); +int side(Node*); +int vconst(Node*); +int vlog(Node*); +int topbit(ulong); +long typebitor(long, long); +void diag(Node*, char*, ...); +void warn(Node*, char*, ...); +void yyerror(char*, ...); +void fatal(Node*, char*, ...); + +/* + * acid.c + */ +void acidtype(Type*); +void acidvar(Sym*); + +/* + * bits.c + */ +Bits bor(Bits, Bits); +Bits band(Bits, Bits); +Bits bnot(Bits); +int bany(Bits*); +int bnum(Bits); +Bits blsh(uint); +int beq(Bits, Bits); +int bset(Bits, uint); + +/* + * dpchk.c + */ +void dpcheck(Node*); +void arginit(void); +void pragvararg(void); +void praghjdicks(void); +void pragfpround(void); + +/* + * calls to machine depend part + */ +void codgen(Node*, Node*, int); +void gclean(void); +void gextern(Sym*, Node*, long, long); +void ginit(void); +long outstring(char*, long); +long outlstring(ushort*, long); +void sextern(Sym*, Node*, long, long); +void xcom(Node*); +long exreg(Type*); +long align(long, Type*, int); +long maxround(long, long); + +extern schar ewidth[]; + +/* + * com64 + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); +double convvtof(vlong); +vlong convftov(double); +double convftox(double, int); +vlong convvtox(vlong, int); + +#pragma varargck argpos warn 2 +#pragma varargck argpos diag 2 +#pragma varargck argpos yyerror 1 + +#pragma varargck type "F" Node* +#pragma varargck type "L" long +#pragma varargck type "Q" long +#pragma varargck type "O" int +#pragma varargck type "T" Type* +#pragma varargck type "|" int + +/* output routines */ + +void prline(char*); +void prstr(char *); +void prlstr(ushort *); +void prkeywd(char *); +void prid(char *); +void prsym(Sym*, int); +void prsym0(Sym*); +void prdelim(char *); +void prchar(vlong); +void prreal(double, char*, int); +void prnum(vlong, int, Type*); +void prcom(char *, Node*); +void newline(void); +void incind(void); +void decind(void); +int zeroind(void); +void restoreind(int); +void startcom(int); +void addcom(int); +void endcom(void); +int outcom(int); +int arrow(Sym*); + +/* limbo generating routines */ + +void pgen(int); +void epgen(int); +void ttgen(Type*); +void vtgen(Node*); +void etgen(Sym*); +void expgen(Node*); + +/* -m routines */ + +void newsec(int); + +void outpush(char*); +void outpop(int); +void outpush0(char*, Node*); +void outpop0(int); +void outpush2(char*, Node*); +void outpop2(int); +char* outmod(char*, int); + +/* miscellaneous */ + +int iscon(char*); +Node* ncopy(Node*); +void doasenum(Sym*); +Type *maxtype(Type*, Type*); + +void linit(void); +void sysinit(void); + +int ism(void); +int isb(void); +int dolog(void); + +int line(Node*); + +void output(long, int); +void usemod(Sym*, int); +void setmod(Sym*); + +int exists(char*); +int isconsym(Sym *); + +void clbegin(void); +void clend(void); + +int gfltconv(Fmt*); diff --git a/utils/c2l/cc.y b/utils/c2l/cc.y new file mode 100644 index 00000000..22dc6c0c --- /dev/null +++ b/utils/c2l/cc.y @@ -0,0 +1,1239 @@ +%{ +#include "cc.h" +%} +%union { + Node* node; + Sym* sym; + Type* type; + struct + { + Type* t; + char c; + } tycl; + struct + { + Type* t1; + Type* t2; + } tyty; + struct + { + char* s; + long l; + } sval; + long lval; + double dval; + vlong vval; +} +%type <sym> ltag +%type <lval> gctname cname gname tname +%type <lval> gctnlist zgnlist tnlist +%type <type> tlist etlist sbody complex +%type <tycl> types etypes +%type <node> zarglist arglist zcexpr +%type <node> name block stmnt cexpr expr xuexpr pexpr +%type <node> zelist elist adecl slist uexpr string lstring sstring slstring +%type <node> xdecor xdecor2 labels label ulstmnt +%type <node> adlist edecor tag qual qlist +%type <node> abdecor abdecor1 abdecor2 abdecor3 +%type <node> zexpr lexpr init ilist + +%left ';' +%left ',' +%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE +%right '?' ':' +%left LOROR +%left LANDAND +%left '|' +%left '^' +%left '&' +%left LEQ LNE +%left '<' '>' LLE LGE +%left LLSH LRSH +%left '+' '-' +%left '*' '/' '%' +%right LMM LPP LMG '.' '[' '(' + +%token <sym> LNAME LCTYPE LSTYPE +%token <dval> LFCONST LDCONST +%token <vval> LCHARACTER LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST +%token <sval> LSTRING LLSTRING +%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO +%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO +%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED +%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LUNION LUNSIGNED LWHILE +%token LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF LVLONG +%% +prog: +| prog xdecl + +/* + * external declarator + */ +xdecl: + zctlist ';' + { + dodecl(xdecl, lastclass, lasttype, Z, 1); + } +| zctlist xdlist ';' +| zctlist xdecor + { + lastdcl = T; + dodecl(xdecl, lastclass, lasttype, $2, 0); + if(lastdcl == T || lastdcl->etype != TFUNC) { + diag($2, "not a function"); + lastdcl = types[TFUNC]; + } + thisfn = lastdcl; + markdcl(); + firstdcl = dclstack; + argmark($2, 0); + } + pdecl + { + argmark($2, 1); + } + block + { + $6->blk = 0; + codgen($6, $2, lineno); + revertdcl(); + } + +xdlist: + xdecor + { + dodecl(xdecl, lastclass, lasttype, $1, 1); + } +| xdecor + { + $1 = dodecl(xdecl, lastclass, lasttype, $1, 0); + } + '=' init + { + $4 = doinit($1->sym, $1->type, 0L, $4); + $4 = new(ODAS, $1, $4); + $4->type = $1->type; + $4->lineno = $1->lineno; + vtgen($4); + } +| xdlist ',' xdlist + +xdecor: + xdecor2 +| '*' zgnlist xdecor + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } + +xdecor2: + tag +| '(' xdecor ')' + { + $$ = $2; + } +| xdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + /* outfun($$); */ + } +| xdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +/* + * automatic declarator + */ +adecl: + { + $$ = Z; + } +| adecl ctlist ';' + { + $$ = dodecl(adecl, lastclass, lasttype, Z, 1); + if($1 != Z) + if($$ != Z) + $$ = new(OLIST, $1, $$); + else + $$ = $1; + } +| adecl ctlist adlist ';' + { + $$ = $1; + if($3 != Z) { + $$ = $3; + if($1 != Z) + $$ = new(OLIST, $1, $3); + } + } + +adlist: + xdecor + { + $$ = dodecl(adecl, lastclass, lasttype, $1, 1); + if($$->sym->class == CSTATIC) + $$ = Z; + } +| xdecor + { + $1 = dodecl(adecl, lastclass, lasttype, $1, 0); + } + '=' init + { + /* long w; */ + + /* w = $1->sym->type->width; */ + $$ = doinit($1->sym, $1->type, 0L, $4); + /* $$ = contig($1->sym, $$, w); */ + $$ = new(ODAS, $1, $$); + $$->type = $1->type; + $$->lineno = $1->lineno; + vtgen($$); + if($1->sym->class == CSTATIC) + $$ = Z; + } +| adlist ',' adlist + { + $$ = $1; + if($3 != Z) { + $$ = $3; + if($1 != Z) + $$ = new(OLIST, $1, $3); + } + } + +/* + * parameter declarator + */ +pdecl: +| pdecl ctlist pdlist ';' + +pdlist: + xdecor + { + dodecl(pdecl, lastclass, lasttype, $1, 1); + } +| pdlist ',' pdlist + +/* + * structure element declarator + */ +edecl: + etlist + { + lasttype = $1; + } + zedlist ';' +| edecl etlist + { + lasttype = $2; + } + zedlist ';' + +zedlist: /* extension */ + { + lastfield = 0; + edecl(CXXX, lasttype, S); + } +| edlist + +edlist: + edecor + { + dodecl(edecl, CXXX, lasttype, $1, 1); + } +| edlist ',' edlist + +edecor: + xdecor + { + lastbit = 0; + firstbit = 1; + } +| tag ':' lexpr + { + $$ = new(OBIT, $1, $3); + } +| ':' lexpr + { + $$ = new(OBIT, Z, $2); + } + +/* + * abstract declarator + */ +abdecor: + { + $$ = (Z); + } +| abdecor1 + +abdecor1: + '*' zgnlist + { + $$ = new(OIND, (Z), Z); + $$->garb = simpleg($2); + } +| '*' zgnlist abdecor1 + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } +| abdecor2 + +abdecor2: + abdecor3 +| abdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| abdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +abdecor3: + '(' ')' + { + $$ = new(OFUNC, (Z), Z); + } +| '[' zexpr ']' + { + $$ = new(OARRAY, (Z), $2); + } +| '(' abdecor1 ')' + { + $$ = $2; + } + +init: + expr +| '{' ilist '}' + { + $$ = new(OINIT, invert($2), Z); + } + +qual: + '[' lexpr ']' + { + $$ = new(OARRAY, $2, Z); + } +| '.' ltag + { + $$ = new(OELEM, Z, Z); + $$->sym = $2; + } +| qual '=' + +qlist: + init ',' +| qlist init ',' + { + $$ = new(OLIST, $1, $2); + } +| qual +| qlist qual + { + $$ = new(OLIST, $1, $2); + } + +ilist: + qlist +| init +| qlist init + { + $$ = new(OLIST, $1, $2); + } + +zarglist: + { + $$ = Z; + } +| arglist + { + $$ = invert($1); + } + + +arglist: + name +| tlist abdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| tlist xdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| '.' '.' '.' + { + $$ = new(ODOTDOT, Z, Z); + } +| arglist ',' arglist + { + $$ = new(OLIST, $1, $3); + } + +block: + '{' adecl slist '}' + { + $$ = invert($3); + if($2 != Z) + $$ = new(OLIST, $2, $$); + if($$ == Z) + $$ = new(ONUL, Z, Z); + $$->blk = 1; + } + +slist: + { + $$ = Z; + } +| slist stmnt + { + if($1 == Z) + $$ = $2; + else + $$ = new(OLIST, $1, $2); + } + +labels: + label +| labels label + { + $$ = new(OLIST, $1, $2); + } + +label: + LCASE expr ':' + { + $$ = new(OCASE, $2, Z); + $$->lineno = $2->lineno; + } +| LDEFAULT ':' + { + $$ = new(OCASE, Z, Z); + } +| LNAME ':' + { + $$ = new(OLABEL, dcllabel($1, 1), Z); + $1->lineno = lineno; + } + +stmnt: + error ';' + { + $$ = Z; + } +| ulstmnt +| labels ulstmnt + { + $$ = new(OLIST, $1, $2); + } + +ulstmnt: + zcexpr ';' + { + if($$ == Z) + $$ = new(ONUL, Z, Z); + $$->kind = KEXP; + } +| { + markdcl(); + } + block + { + revertdcl(); + $$ = $2; + } +| LIF '(' cexpr ')' stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, Z)); + $$->lineno = $3->lineno; + $5->blk = 0; + } +| LIF '(' cexpr ')' stmnt LELSE stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, $7)); + $$->lineno = $3->lineno; + $5->blk = $7->blk = 0; + } +| LFOR '(' zcexpr ';' zcexpr ';' zcexpr ')' stmnt + { + $$ = new(OFOR, new(OLIST, $5, new(OLIST, $3, $7)), $9); + if($3 != Z) + $$->lineno = $3->lineno; + else if($5 != Z) + $$->lineno = $5->lineno; + else if($7 != Z) + $$->lineno = $7->lineno; + else + $$->lineno = line($9); + $9->blk = 0; + } +| LWHILE '(' cexpr ')' stmnt + { + $$ = new(OWHILE, $3, $5); + $$->lineno = $3->lineno; + $5->blk = 0; + } +| LDO stmnt LWHILE '(' cexpr ')' ';' + { + $$ = new(ODWHILE, $5, $2); + $$->lineno = line($2); + $2->blk = 0; + } +| LRETURN zcexpr ';' + { + $$ = new(ORETURN, $2, Z); + $$->type = thisfn->link; + if($2 != Z) + $$->lineno = $2->lineno; + } +| LSWITCH '(' cexpr ')' stmnt + { + $$ = new(OSWITCH, $3, $5); + $$->lineno = $3->lineno; + $5->blk = 0; + } +| LBREAK ';' + { + $$ = new(OBREAK, Z, Z); + } +| LCONTINUE ';' + { + $$ = new(OCONTINUE, Z, Z); + } +| LGOTO LNAME ';' + { + $$ = new(OGOTO, dcllabel($2, 0), Z); + $2->lineno = lineno; + } +| LUSED '(' zelist ')' ';' + { + $$ = new(OUSED, $3, Z); + $$->lineno = line($3); + } +| LSET '(' zelist ')' ';' + { + $$ = new(OSET, $3, Z); + $$->lineno = line($3); + } + +zcexpr: + { + $$ = Z; + } +| cexpr + +zexpr: + { + $$ = Z; + } +| lexpr + +lexpr: + expr + { + $$ = new(OCAST, $1, Z); + $$->type = types[TLONG]; + } + +cexpr: + expr +| cexpr ',' cexpr + { + $$ = new(OCOMMA, $1, $3); + } + +expr: + xuexpr +| expr '*' expr + { + $$ = new(OMUL, $1, $3); + } +| expr '/' expr + { + $$ = new(ODIV, $1, $3); + } +| expr '%' expr + { + $$ = new(OMOD, $1, $3); + } +| expr '+' expr + { + $$ = new(OADD, $1, $3); + } +| expr '-' expr + { + $$ = new(OSUB, $1, $3); + } +| expr LRSH expr + { + $$ = new(OASHR, $1, $3); + } +| expr LLSH expr + { + $$ = new(OASHL, $1, $3); + } +| expr '<' expr + { + $$ = new(OLT, $1, $3); + } +| expr '>' expr + { + $$ = new(OGT, $1, $3); + } +| expr LLE expr + { + $$ = new(OLE, $1, $3); + } +| expr LGE expr + { + $$ = new(OGE, $1, $3); + } +| expr LEQ expr + { + $$ = new(OEQ, $1, $3); + } +| expr LNE expr + { + $$ = new(ONE, $1, $3); + } +| expr '&' expr + { + $$ = new(OAND, $1, $3); + } +| expr '^' expr + { + $$ = new(OXOR, $1, $3); + } +| expr '|' expr + { + $$ = new(OOR, $1, $3); + } +| expr LANDAND expr + { + $$ = new(OANDAND, $1, $3); + } +| expr LOROR expr + { + $$ = new(OOROR, $1, $3); + } +| expr '?' cexpr ':' expr + { + $$ = new(OCOND, $1, new(OLIST, $3, $5)); + } +| expr '=' expr + { + $$ = new(OAS, $1, $3); + } +| expr LPE expr + { + $$ = new(OASADD, $1, $3); + } +| expr LME expr + { + $$ = new(OASSUB, $1, $3); + } +| expr LMLE expr + { + $$ = new(OASMUL, $1, $3); + } +| expr LDVE expr + { + $$ = new(OASDIV, $1, $3); + } +| expr LMDE expr + { + $$ = new(OASMOD, $1, $3); + } +| expr LLSHE expr + { + $$ = new(OASASHL, $1, $3); + } +| expr LRSHE expr + { + $$ = new(OASASHR, $1, $3); + } +| expr LANDE expr + { + $$ = new(OASAND, $1, $3); + } +| expr LXORE expr + { + $$ = new(OASXOR, $1, $3); + } +| expr LORE expr + { + $$ = new(OASOR, $1, $3); + } + +xuexpr: + uexpr +| '(' tlist abdecor ')' xuexpr + { + $$ = new(OCAST, $5, Z); + dodecl(NODECL, CXXX, $2, $3, 1); + $$->type = lastdcl; + } +| '(' tlist abdecor ')' '{' ilist '}' /* extension */ + { + $$ = new(OSTRUCT, $6, Z); + dodecl(NODECL, CXXX, $2, $3, 1); + $$->type = lastdcl; + } + +uexpr: + pexpr +| '*' xuexpr + { + $$ = new(OIND, $2, Z); + } +| '&' xuexpr + { + $$ = new(OADDR, $2, Z); + } +| '+' xuexpr + { + $$ = new(OPOS, $2, Z); + } +| '-' xuexpr + { + $$ = new(ONEG, $2, Z); + } +| '!' xuexpr + { + $$ = new(ONOT, $2, Z); + } +| '~' xuexpr + { + $$ = new(OCOM, $2, Z); + } +| LPP xuexpr + { + $$ = new(OPREINC, $2, Z); + } +| LMM xuexpr + { + $$ = new(OPREDEC, $2, Z); + } +| LSIZEOF uexpr + { + $$ = new(OSIZE, $2, Z); + } +| LSIGNOF uexpr + { + $$ = new(OSIGN, $2, Z); + } + +pexpr: + '(' cexpr ')' + { + $$ = $2; + } +| LSIZEOF '(' tlist abdecor ')' + { + $$ = new(OSIZE, Z, Z); + dodecl(NODECL, CXXX, $3, $4, 1); + $$->type = lastdcl; + } +| LSIGNOF '(' tlist abdecor ')' + { + $$ = new(OSIGN, Z, Z); + dodecl(NODECL, CXXX, $3, $4, 1); + $$->type = lastdcl; + } +| pexpr '(' zelist ')' + { + $$ = new(OFUNC, $1, Z); + if($1->op == ONAME) + if($1->type == T) + dodecl(xdecl, CXXX, types[TINT], $$, 1); + $$->right = invert($3); + $$->kind = KEXP; + } +| pexpr '[' cexpr ']' + { + $$ = new(OARRIND, $1, $3); + } +| pexpr LMG ltag + { + $$ = new(ODOTIND, $1, Z); + $$->sym = $3; + } +| pexpr '.' ltag + { + $$ = new(ODOT, $1, Z); + $$->sym = $3; + } +| pexpr LPP + { + $$ = new(OPOSTINC, $1, Z); + } +| pexpr LMM + { + $$ = new(OPOSTDEC, $1, Z); + } +| name +| LCHARACTER + { + $$ = new(OCONST, Z, Z); + $$->type = types[TINT]; + $$->vconst = $1; + $$->kind = KCHR; + } +| LCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TINT]; + $$->vconst = $1; + $$->kind = lastnumbase; + } +| LLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TLONG]; + $$->vconst = $1; + $$->kind = lastnumbase; + } +| LUCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUINT]; + $$->vconst = $1; + $$->kind = lastnumbase; + } +| LULCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TULONG]; + $$->vconst = $1; + $$->kind = lastnumbase; + } +| LDCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TDOUBLE]; + $$->fconst = $1; + $$->cstring = strdup(symb); + $$->kind = lastnumbase; + } +| LFCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TFLOAT]; + $$->fconst = $1; + $$->cstring = strdup(symb); + $$->kind = lastnumbase; + } +| LVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TVLONG]; + $$->vconst = $1; + $$->kind = lastnumbase; + } +| LUVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUVLONG]; + $$->vconst = $1; + $$->kind = lastnumbase; + } +| string +| lstring + +sstring: + LSTRING + { + $$ = new(OSTRING, Z, Z); + $$->type = typ(TARRAY, types[TCHAR]); + $$->type->width = $1.l + 1; + $$->cstring = $1.s; + $$->sym = symstring; + } + +string: + sstring + { + $$ = $1; + } +| string sstring + { + char *s; + int n1, n2; + + n1 = $1->type->width - 1; + n2 = $2->type->width - 1; + s = alloc(n1+n2+MAXALIGN); + + memcpy(s, $1->cstring, n1); + memcpy(s+n1, $2->cstring, n2); + s[n1+n2] = 0; + + $1->left = new(OCAT, ncopy($1), $2); + + $$ = $1; + $$->type->width += n2; + $$->cstring = s; + } + +slstring: + LLSTRING + { + $$ = new(OLSTRING, Z, Z); + $$->type = typ(TARRAY, types[TUSHORT]); + $$->type->width = $1.l + sizeof(ushort); + $$->rstring = (ushort*)$1.s; + $$->sym = symstring; + } + +lstring: + slstring + { + $$ = $1; + } +| lstring slstring + { + char *s; + int n1, n2; + + n1 = $1->type->width - sizeof(ushort); + n2 = $2->type->width - sizeof(ushort); + s = alloc(n1+n2+MAXALIGN); + + memcpy(s, $1->rstring, n1); + memcpy(s+n1, $2->rstring, n2); + *(ushort*)(s+n1+n2) = 0; + + $1->left = new(OCAT, ncopy($1), $2); + + $$ = $1; + $$->type->width += n2; + $$->rstring = (ushort*)s; + } + +zelist: + { + $$ = Z; + } +| elist + +elist: + expr +| elist ',' elist + { + $$ = new(OLIST, $1, $3); + } + +sbody: + '{' + { + $<tyty>$.t1 = strf; + $<tyty>$.t2 = strl; + strf = T; + strl = T; + lastbit = 0; + firstbit = 1; + } + edecl '}' + { + $$ = strf; + strf = $<tyty>2.t1; + strl = $<tyty>2.t2; + } + +zctlist: + { + lastclass = CXXX; + lasttype = types[TINT]; + } +| ctlist + +etypes: + complex + { + $$.t = $1; + $$.c = CXXX; + } +| tnlist + { + $$.t = simplet($1); + $$.c = simplec($1); + } + +types: + complex + { + $$.t = $1; + $$.c = CXXX; + } +| complex gctnlist + { + $$.t = $1; + $$.c = simplec($2); + if($2 & ~BCLASS & ~BGARB) + diag(Z, "illegal combination of types 1: %Q/%T", $2, $1); + } +| gctnlist + { + $$.t = simplet($1); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| gctnlist complex + { + $$.t = $2; + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + if($1 & ~BCLASS & ~BGARB) + diag(Z, "illegal combination of types 2: %Q/%T", $1, $2); + } +| gctnlist complex gctnlist + { + $$.t = $2; + $$.c = simplec($1|$3); + $$.t = garbt($$.t, $1|$3); + if(($1|$3) & ~BCLASS & ~BGARB || $3 & BCLASS) + diag(Z, "illegal combination of types 3: %Q/%T/%Q", $1, $2, $3); + } + +etlist: + zgnlist etypes + { + $$ = $2.t; + if($2.c != CXXX) + diag(Z, "illegal combination of class 4: %s", cnames[$2.c]); + $$ = garbt($$, $1); + } + +tlist: + types + { + $$ = $1.t; + if($1.c != CXXX) + diag(Z, "illegal combination of class 4: %s", cnames[$1.c]); + } + +ctlist: + types + { + lasttype = $1.t; + lastclass = $1.c; + } + +complex: + LSTRUCT ltag + { + dotag($2, TSTRUCT, 0); + $$ = $2->suetag; + $2->lineno = lineno; + } +| LSTRUCT ltag + { + dotag($2, TSTRUCT, autobn); + saveline = $2->lineno = lineno; + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + $$->lineno = saveline; + suallign($$); + } +| LSTRUCT + { + saveline = lineno; + } + sbody + { + char buf[128]; + + taggen++; + sprint(symb, "%s_adt_%d", outmod(buf, -1), taggen); + $$ = dotag(lookup(), TSTRUCT, autobn); + $$->link = $3; + $$->lineno = saveline; + lookup()->lineno = saveline; + suallign($$); + } +| LUNION ltag + { + dotag($2, TUNION, 0); + $$ = $2->suetag; + $2->lineno = lineno; + } +| LUNION ltag + { + dotag($2, TUNION, autobn); + saveline = $2->lineno = lineno; + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + $$->lineno = saveline; + suallign($$); + } +| LUNION + { + saveline = lineno; + } + sbody + { + char buf[128]; + + taggen++; + sprint(symb, "%s_adt_%d", outmod(buf, -1), taggen); + $$ = dotag(lookup(), TUNION, autobn); + $$->link = $3; + $$->lineno = saveline; + lookup()->lineno = saveline; + suallign($$); + } +| LENUM ltag + { + dotag($2, TENUM, 0); + $$ = $2->suetag; + if($$->link == T) + $$->link = types[TINT]; + $$ = $$->link; + $2->lineno = lineno; + } +| LENUM ltag + { + dotag($2, TENUM, autobn); + $2->lineno = lineno; + } + '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + if(en.tenum == T) { + diag(Z, "enum type ambiguous: %s", $2->name); + en.tenum = types[TINT]; + } + $$->link = en.tenum; + $$ = en.tenum; + etgen(nil); + } +| LENUM '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = en.tenum; + etgen(nil); + } +| LCTYPE + { + $$ = tcopy($1->type); + } +| LSTYPE + { + $$ = tcopy($1->type); + } + +tnlist: + tname +| tnlist tname + { + $$ = typebitor($1, $2); + } + +gctnlist: + gctname +| gctnlist gctname + { + $$ = typebitor($1, $2); + } + +zgnlist: + { + $$ = 0; + } +| zgnlist gname + { + $$ = typebitor($1, $2); + } + +gctname: + tname +| gname +| cname + +enum: + LNAME + { + doenum($1, Z); + $1->lineno = lineno; + } +| LNAME '=' expr + { + doenum($1, $3); + $1->lineno = lineno; + } +| enum ',' +| enum ',' enum + +tname: /* type words */ + LCHAR { $$ = BCHAR; } +| LSHORT { $$ = BSHORT; } +| LINT { $$ = BINT; } +| LLONG { $$ = BLONG; } +| LSIGNED { $$ = BSIGNED; } +| LUNSIGNED { $$ = BUNSIGNED; } +| LFLOAT { $$ = BFLOAT; } +| LDOUBLE { $$ = BDOUBLE; } +| LVOID { $$ = BVOID; } +| LVLONG { $$ = BVLONG|BLONG; } + +cname: /* class words */ + LAUTO { $$ = BAUTO; } +| LSTATIC { $$ = BSTATIC; } +| LEXTERN { $$ = BEXTERN; } +| LTYPEDEF { $$ = BTYPEDEF; } +| LREGISTER { $$ = BREGISTER; } + +gname: + LCONSTNT { $$ = BCONSTNT; } +| LVOLATILE { $$ = BVOLATILE; } + +name: + LNAME + { + $$ = new(ONAME, Z, Z); + if($1->class == CLOCAL) + $1 = mkstatic($1); + $$->sym = $1; + $$->type = $1->type; + } +tag: + ltag + { + $$ = new(ONAME, Z, Z); + $$->sym = $1; + $$->type = $1->type; + } +ltag: + LNAME +| LCTYPE +| LSTYPE + +%% diff --git a/utils/c2l/com.c b/utils/c2l/com.c new file mode 100644 index 00000000..283c2ae9 --- /dev/null +++ b/utils/c2l/com.c @@ -0,0 +1,918 @@ +#include "cc.h" + +void +complex(Node *n) +{ + + if(n == Z) + return; + + nearln = n->lineno; + if(tcom(n)) + return; + ccom(n); + acom(n); +} + +/* + * evaluate types + * evaluate lvalues (addable == 1) + */ +enum +{ + ADDROF = 1<<0, + CASTOF = 1<<1, + ADDROP = 1<<2, +}; + +int +tcom(Node *n) +{ + + return tcomo(n, ADDROF); +} + +int +tcomo(Node *n, int f) +{ + Node *l, *r; + Type *t; + int o; + + if(n == Z) { + diag(Z, "Z in tcom"); + errorexit(); + } + l = n->left; + r = n->right; + + switch(n->op) { + default: + diag(n, "unknown op in type complex: %O", n->op); + goto bad; + + case ODOTDOT: + /* + * tcom has already been called on this subtree + */ + *n = *n->left; + if(n->type == T) + goto bad; + break; + + case OCAST: + if(n->type == T) + break; + if(n->type->width == types[TLONG]->width) { + if(tcomo(l, ADDROF|CASTOF)) + goto bad; + } else + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, n->type, tcast)) + goto bad; + break; + + case ORETURN: + if(l == Z) { + if(n->type->etype != TVOID) + warn(n, "null return of a typed function"); + break; + } + if(tcom(l)) + goto bad; + typeext(n->type, l); + if(tcompat(n, n->type, l->type, tasign)) + break; + constas(n, n->type, l->type); + if(!sametype(n->type, l->type)) { + l = new1(OCAST, l, Z); + l->type = n->type; + n->left = l; + } + break; + + case OASI: /* same as as, but no test for const */ + n->op = OAS; + o = tcom(l); + if(o | tcom(r)) + goto bad; + + typeext(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tasign)) + goto bad; + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OAS: + case OASD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + + typeext(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tasign)) + goto bad; + constas(n, l->type, r->type); + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OASADD: + case OASSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + typeext1(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tasadd)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + break; + + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + typeext1(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tmul)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASDIV) + n->op = OASLDIV; + if(n->op == OASMUL) + n->op = OASLMUL; + } + break; + + case OASLSHR: + case OASASHR: + case OASASHL: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l) || tcompat(n, l->type, r->type, tand)) + goto bad; + n->type = l->type; + if(typeu[n->type->etype]) { + if(n->op == OASASHR) + n->op = OASLSHR; + } + break; + + case OASMOD: + case OASLMOD: + case OASOR: + case OASAND: + case OASXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l) || tcompat(n, l->type, r->type, tand)) + goto bad; + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASMOD) + n->op = OASLMOD; + } + break; + + case OPREINC: + case OPREDEC: + case OPOSTINC: + case OPOSTDEC: + if(tcom(l)) + goto bad; + if(tlvalue(l) || tcompat(n, l->type, types[TINT], tadd)) + goto bad; + n->type = l->type; + if(n->type->etype == TIND) + if(n->type->link->width < 1) + diag(n, "inc/dec of a void pointer"); + break; + + case OEQ: + case ONE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + typeext(l->type, r); + typeext(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + n->type = types[TINT]; + break; + + case OLT: + case OGE: + case OGT: + case OLE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + typeext1(l->type, r); + typeext1(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + if(typeu[n->type->etype]) + n->op = logrel[relindex(n->op)]; + n->type = types[TINT]; + break; + + case OCOND: + o = tcom(l); + o |= tcom(r->left); + if(o | tcom(r->right)) + goto bad; + if(r->right->type->etype == TIND && vconst(r->left) == 0) { + r->left->type = r->right->type; + r->left->vconst = 0; + } + if(r->left->type->etype == TIND && vconst(r->right) == 0) { + r->right->type = r->left->type; + r->right->vconst = 0; + } + if(sametype(r->right->type, r->left->type)) { + r->type = r->right->type; + n->type = r->type; + break; + } + if(tcompat(r, r->left->type, r->right->type, trel)) + goto bad; + arith(r, 0); + n->type = r->type; + break; + + case OADD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, l->type, r->type, tadd)) + goto bad; + arith(n, 1); + break; + + case OSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) { + if(n->op == ODIV) + n->op = OLDIV; + if(n->op == OMUL) + n->op = OLMUL; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->right = Z; + arith(n, 1); + n->right = new1(OCAST, r, Z); + n->right->type = types[TINT]; + if(typeu[n->type->etype]) + if(n->op == OASHR) + n->op = OLSHR; + break; + + case OAND: + case OOR: + case OXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + break; + + case OMOD: + case OLMOD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) + n->op = OLMOD; + break; + + case ONOT: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OPOS: + case ONEG: + case OCOM: + if(tcom(l)) + goto bad; + n->type = l->type; + break; + + case ONUL: + break; + + case OIOTA: + n->type = types[TINT]; + break; + + case ODAS: + n->type = n->left->type; + break; + + case OANDAND: + case OOROR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, T, l->type, tnot) | + tcompat(n, T, r->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OCOMMA: + o = tcom(l); + if(o | tcom(r)) + goto bad; + n->type = r->type; + break; + + + case OSIGN: /* extension signof(type) returns a hash */ + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "signof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width < 0) { + diag(n, "signof undefined type"); + goto bad; + } + n->right = ncopy(n); + n->op = OCONST; + n->left = Z; + /* n->right = Z; */ + n->vconst = convvtox(signature(n->type, 10), TULONG); + n->type = types[TULONG]; + break; + + case OSIZE: + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "sizeof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width <= 0) { + diag(n, "sizeof undefined type"); + goto bad; + } + if(n->type->etype == TFUNC) { + diag(n, "sizeof function"); + goto bad; + } + n->right = ncopy(n); + n->op = OCONST; + n->left = Z; + /* n->right = Z; */ + n->vconst = convvtox(n->type->width, TINT); + n->type = types[TINT]; + break; + + case OFUNC: + o = tcomo(l, 0); + if(o) + goto bad; + if(l->type->etype == TIND && l->type->link->etype == TFUNC) { + l = new1(OIND, l, Z); + l->type = l->left->type->link; + n->left = l; + } + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(o | tcoma(l, r, l->type->down, 1)) + goto bad; + n->type = l->type->link; + if(1) + if(l->type->down == T || l->type->down->etype == TOLD) { + nerrors--; + diag(n, "function args not checked: %F", l); + } + dpcheck(n); + break; + + case ONAME: + if(n->type == T) { + diag(n, "name not declared: %F", n); + goto bad; + } + if(n->type->etype == TENUM) { + if(n->sym->tenum->etype == TIND){ + /* n->op = OSTRING; */ + n->type = n->sym->tenum; + /* n->cstring = n->sym->sconst; */ + break; + } + n->left = ncopy(n); + n->op = OCONST; + n->type = n->sym->tenum; + if(!typefd[n->type->etype]) + n->vconst = n->sym->vconst; + else{ + n->fconst = n->sym->fconst; + n->cstring = n->sym->cstring; + } + break; + } + break; + + case OLSTRING: + case OSTRING: + case OCONST: + break; + + case ODOT: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tdot)) + goto bad; + if(tcomd(n, l->type)) + goto bad; + break; + + case ODOTIND: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tindir)) + goto bad; + if(tcompat(n, T, l->type->link, tdot)) + goto bad; + if(tcomd(n, l->type->link)) + goto bad; + break; + + case OARRIND: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tindir)) + goto bad; + n->type = l->type->link; + if(tcom(r)) + goto bad; + break; + + case OADDR: + if(tcomo(l, ADDROP)) + goto bad; + if(tlvalue(l)) + goto bad; + if(l->type->nbits) { + diag(n, "address of a bit field"); + goto bad; + } + if(l->op == OREGISTER) { + diag(n, "address of a register"); + goto bad; + } + n->type = typ1(TIND, l->type); + n->type->width = types[TIND]->width; + break; + + case OIND: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tindir)) + goto bad; + n->type = l->type->link; + break; + + case OSTRUCT: + if(tcomx(n)) + goto bad; + break; + } + t = n->type; + if(t == T) + goto bad; + if(t->width < 0) { + snap(t); + if(t->width < 0) { + if(typesu[t->etype] && t->tag) + diag(n, "structure not fully declared %s", t->tag->name); + else + diag(n, "structure not fully declared"); + goto bad; + } + } + if(typeaf[t->etype]) { + if(f & ADDROF) + goto addaddr; + if(f & ADDROP) + warn(n, "address of array/func ignored"); + } + return 0; + +addaddr: + if(n->type->etype == TARRAY) + n->type = typ1(TIND, n->type->link); + return 0; + if(tlvalue(n)) + goto bad; + l = new1(OXXX, Z, Z); + *l = *n; + n->op = OADDR; + if(l->type->etype == TARRAY) + l->type = l->type->link; + n->left = l; + n->right = Z; + n->type = typ1(TIND, l->type); + n->type->width = types[TIND]->width; + return 0; + +bad: + n->type = T; + return 1; +} + +int +tcoma(Node *l, Node *n, Type *t, int f) +{ + Node *n1; + int o; + + if(t != T) + if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */ + t = T; + if(n == Z) { + if(t != T && !sametype(t, types[TVOID])) { + diag(n, "not enough function arguments: %F", l); + return 1; + } + return 0; + } + if(n->op == OLIST) { + o = tcoma(l, n->left, t, 0); + if(t != T) { + t = t->down; + if(t == T) + t = types[TVOID]; + } + return o | tcoma(l, n->right, t, 1); + } + if(f && t != T) + tcoma(l, Z, t->down, 0); + if(tcom(n) || tcompat(n, T, n->type, targ)) + return 1; + if(sametype(t, types[TVOID])) { + diag(n, "too many function arguments: %F", l); + return 1; + } + if(t != T) { + typeext(t, n); + if(stcompat(nodproto, t, n->type, tasign)) { + diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F", + n->type, t, l); + return 1; + } + switch(t->etype) { + case TCHAR: + case TSHORT: + /* t = types[TINT]; */ + break; + + case TUCHAR: + case TUSHORT: + /* t = types[TUINT]; */ + break; + } + } else { + switch(n->type->etype) + { + case TCHAR: + case TSHORT: + /* t = types[TINT]; */ + t = n->type; + break; + + case TUCHAR: + case TUSHORT: + /* t = types[TUINT]; */ + t = n->type; + break; + + case TFLOAT: + /* t = types[TDOUBLE]; */ + t = n->type; + } + } + if(t != T && !sametype(t, n->type)) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = t; + } + return 0; +} + +int +tcomd(Node *n, Type *t) +{ + long o; + + o = 0; + /* t = n->left->type; */ + for(;;) { + t = dotsearch(n->sym, t->link, n); + if(t == T) { + diag(n, "not a member of struct/union: %F", n); + return 1; + } + o += t->offset; + if(t->sym == n->sym) + break; + if(sametype(t, n->sym->type)) + break; + } + n->type = t; + return 0; +} + +int +tcomx(Node *n) +{ + Type *t; + Node *l, *r, **ar, **al; + int e; + + e = 0; + if(n->type->etype != TSTRUCT) { + diag(n, "constructor must be a structure"); + return 1; + } + l = invert(n->left); + n->left = l; + al = &n->left; + for(t = n->type->link; t != T; t = t->down) { + if(l == Z) { + diag(n, "constructor list too short"); + return 1; + } + if(l->op == OLIST) { + r = l->left; + ar = &l->left; + al = &l->right; + l = l->right; + } else { + r = l; + ar = al; + l = Z; + } + if(tcom(r)) + e++; + typeext(t, r); + if(tcompat(n, t, r->type, tasign)) + e++; + constas(n, t, r->type); + if(!e && !sametype(t, r->type)) { + r = new1(OCAST, r, Z); + r->type = t; + *ar = r; + } + } + if(l != Z) { + diag(n, "constructor list too long"); + return 1; + } + return e; +} + +int +tlvalue(Node *n) +{ + + if(0) { + diag(n, "not an l-value"); + return 1; + } + return 0; +} + +/* + * general rewrite + * (IND(ADDR x)) ==> x + * (ADDR(IND x)) ==> x + * remove some zero operands + * remove no op casts + * evaluate constants + */ +void +ccom(Node *n) +{ + Node *l, *r; + int t; + + if(n == Z) + return; + l = n->left; + r = n->right; + switch(n->op) { + + case OAS: + case OASD: + case OASXOR: + case OASAND: + case OASOR: + case OASMOD: + case OASLMOD: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASDIV: + case OASLDIV: + case OASMUL: + case OASLMUL: + case OASSUB: + case OASADD: + ccom(l); + ccom(r); + if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL) + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst < 0) + warn(n, "stupid shift: %lld", r->vconst); + } + break; + + case OCAST: + ccom(l); + if(l->op == OCONST) { + evconst(n); + if(n->op == OCONST) + break; + } + if(nocast(l->type, n->type)) { + l->type = n->type; + *n = *l; + } + break; + + case OCOND: + ccom(l); + ccom(r); + break; + + case OREGISTER: + case OINDREG: + case OCONST: + case ONAME: + break; + + case OADDR: + ccom(l); + /* l->etype = TVOID; */ + if(l->op == OIND) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OIND: + ccom(l); + if(l->op == OADDR) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OEQ: + case ONE: + + case OLE: + case OGE: + case OLT: + case OGT: + + case OLS: + case OHS: + case OLO: + case OHI: + ccom(l); + ccom(r); + relcon(l, r); + relcon(r, l); + goto common; + + case OASHR: + case OASHL: + case OLSHR: + ccom(l); + ccom(r); + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst <= -t) + warn(n, "stupid shift: %lld", r->vconst); + } + goto common; + + default: + if(l != Z) + ccom(l); + if(r != Z) + ccom(r); + common: + if(l != Z) + if(l->op != OCONST) + break; + if(r != Z) + if(r->op != OCONST) + break; + evconst(n); + } +} diff --git a/utils/c2l/com64.c b/utils/c2l/com64.c new file mode 100644 index 00000000..9a193ef3 --- /dev/null +++ b/utils/c2l/com64.c @@ -0,0 +1,52 @@ +#include "cc.h" + +/* + * this is machine depend, but it is totally + * common on all of the 64-bit symulating machines. + */ + +/* + * more machine depend stuff. + * this is common for 8,16,32,64 bit machines. + * this is common for ieee machines. + */ +double +convvtof(vlong v) +{ + double d; + + d = v; /* BOTCH */ + return d; +} + +vlong +convftov(double d) +{ + vlong v; + + + v = d; /* BOTCH */ + return v; +} + +double +convftox(double d, int et) +{ + + if(!typefd[et]) + diag(Z, "bad type in castftox %s", tnames[et]); + return d; +} + +vlong +convvtox(vlong c, int et) +{ + int n; + + n = 8 * ewidth[et]; + c &= MASK(n); + if(!typeu[et]) + if(c & SIGN(n)) + c |= ~MASK(n); + return c; +} diff --git a/utils/c2l/dcl.c b/utils/c2l/dcl.c new file mode 100644 index 00000000..6fb6977a --- /dev/null +++ b/utils/c2l/dcl.c @@ -0,0 +1,1387 @@ +#include "cc.h" + +Node* +dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n, int gen) +{ + Sym *s; + Node *n1; + long v; + + nearln = lineno; + lastfield = 0; + +loop: + if(n != Z) + switch(n->op) { + default: + diag(n, "unknown declarator: %O", n->op); + break; + + case OARRAY: + t = typ(TARRAY, t); + t->width = 0; + n1 = n->right; + n = n->left; + if(n1 != Z) { + complex(n1); + v = -1; + if(n1->op == OCONST) + v = n1->vconst; + if(v <= 0) { + diag(n, "array size must be a positive constant"); + v = 1; + } + t->width = v * t->link->width; + t->nwidth = n1->left; + } + goto loop; + + case OIND: + t = typ(TIND, t); + t->garb = n->garb; + n = n->left; + goto loop; + + case OFUNC: + t = typ(TFUNC, t); + t->down = fnproto(n); + n = n->left; + goto loop; + + case OBIT: + n1 = n->right; + complex(n1); + lastfield = -1; + if(n1->op == OCONST) + lastfield = n1->vconst; + if(lastfield < 0) { + diag(n, "field width must be non-negative constant"); + lastfield = 1; + } + if(lastfield == 0) { + lastbit = 0; + firstbit = 1; + if(n->left != Z) { + diag(n, "zero width named field"); + lastfield = 1; + } + } + if(!typei[t->etype]) { + diag(n, "field type must be int-like"); + t = types[TINT]; + lastfield = 1; + } + if(lastfield > tfield->width*8) { + diag(n, "field width larger than field unit"); + lastfield = 1; + } + lastbit += lastfield; + if(lastbit > tfield->width*8) { + lastbit = lastfield; + firstbit = 1; + } + n = n->left; + goto loop; + + case ONAME: + if(f == NODECL) + break; + s = n->sym; + (*f)(c, t, s); + if(s->class == CLOCAL) + s = mkstatic(s); + firstbit = 0; + n->sym = s; + n->type = s->type; + acidvar(s); + if(gen) + vtgen(n); + break; + } + lastdcl = t; + return n; +} + +Sym* +mkstatic(Sym *s) +{ + Sym *s1; + + if(s->class != CLOCAL) + return s; + snprint(symb, NSYMB, "%s$%d", s->name, s->block); + s1 = lookup(); + if(s1->class != CSTATIC) { + s1->type = s->type; + s1->offset = s->offset; + s1->block = s->block; + s1->class = CSTATIC; + } + return s1; +} + +/* + * make a copy of a typedef + * the problem is to split out incomplete + * arrays so that it is in the variable + * rather than the typedef. + */ +Type* +tcopy(Type *t) +{ + Type *tl, *tx; + int et; + + if(t == T) + return t; + et = t->etype; + if(typesu[et]) + return t; + tl = tcopy(t->link); + if(tl != t->link || + (et == TARRAY && t->width == 0)) { + tx = typ(TXXX, 0); + *tx = *t; + tx->link = tl; + return tx; + } + return t; +} + +Node* +doinit(Sym *s, Type *t, long o, Node *a) +{ + Node *n, *reta; + + if(t == T) + return Z; + if(s->class == CEXTERN) + s->class = CGLOBL; + if(0) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "doinit value"); + } + + n = initlist; + if(a->op == OINIT) + a = a->left; + initlist = a; + + reta = a; + init1(s, t, o, 0); + if(initlist != Z) + diag(initlist, "more initializers than structure: %s", + s->name); + initlist = n; + + return reta; +} + +/* + * get next major operator, + * dont advance initlist. + */ +Node* +peekinit(void) +{ + Node *a; + + a = initlist; + +loop: + if(a == Z) + return a; + if(a->op == OLIST) { + a = a->left; + goto loop; + } + return a; +} + +/* + * consume and return next element on + * initlist. expand strings. + */ +Node* +nextinit(void) +{ + Node *a, *n; + + a = initlist; + n = Z; + + if(a == Z) + return a; + if(a->op == OLIST) { + n = a->right; + a = a->left; + } + initlist = n; + return a; +} + +int +isstruct(Node *a, Type *t) +{ + Node *n; + + switch(a->op) { + case ODOTDOT: + n = a->left; + if(n && n->type && sametype(n->type, t)) + return 1; + case OSTRING: + case OLSTRING: + case OCONST: + case OINIT: + case OELEM: + return 0; + } + + n = new(ODOTDOT, Z, Z); + *n = *a; + + /* + * ODOTDOT is a flag for tcom + * a second tcom will not be performed + */ + a->op = ODOTDOT; + a->left = n; + a->right = Z; + + if(tcom(n)) + return 0; + + if(sametype(n->type, t)) + return 1; + return 0; +} + +void +init1(Sym *s, Type *t, long o, int exflag) +{ + Node *a, *r, nod; + Type *t1; + long e, w, so, mw; + + a = peekinit(); + if(a == Z) + return; + + if(0) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "init1 value"); + } + + if(exflag && a->op == OINIT){ + doinit(s, t, o, nextinit()); + return; + } + + switch(t->etype) { + default: + diag(Z, "unknown type in initialization: %T to: %s", t, s->name); + return; + + case TCHAR: + case TUCHAR: + case TINT: + case TUINT: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TIND: + single: + if(a->op == OARRAY || a->op == OELEM) + return; + + a = nextinit(); + if(a == Z) + return; + + if(t->nbits) + diag(Z, "cannot initialize bitfields"); + if(0 && s->class == CAUTO) + return; + + complex(a); + if(a->type == T) + return; + + if(a->op == OCONST) { + if(!sametype(a->type, t)) { + /* hoop jumping to save malloc */ + if(nodcast == Z) + nodcast = new(OCAST, Z, Z); + nod = *nodcast; + nod.left = a; + nod.type = t; + nod.lineno = a->lineno; + complex(&nod); + if(nod.type) + *a = nod; + } + if(a->op != OCONST) { +/* + diag(a, "initializer is not a constant: %s", + s->name); +*/ + return; + } + if(vconst(a) == 0) + return; + return; + } + if(t->etype == TIND) { + while(a->op == OCAST) { + warn(a, "CAST in initialization ignored"); + a = a->left; + } + if(0 && !sametype(t, a->type)) { + diag(a, "initialization of incompatible pointers: %s", + s->name); + print("%T and %T\n", t, a->type); + } +/* + if(a->op == OADDR) + a = a->left; +*/ + return; + } + + while(a->op == OCAST) + a = a->left; + if(a->op == OADDR) { + warn(a, "initialize pointer to an integer: %s", s->name); + /* a = a->left; */ + return; + } + /* diag(a, "initializer is not a constant: %s", s->name); */ + return; + + case TARRAY: + w = t->link->width; + if(a->op == OSTRING || a->op == OLSTRING) + if(typei[t->link->etype]) { + + /* + * get rid of null if sizes match exactly + */ + a = nextinit(); + /* mw = t->width/w; */ + so = a->type->width/a->type->link->width; + if(t->width <= 0) + t->width = w*(so-1); + USED(a); + return; + } + + mw = -w; + for(e=0;;) { + /* + * peek ahead for element initializer + */ + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM && t->link->etype != TSTRUCT) + break; + if(a->op == OARRAY) { + if(e && exflag) + break; + a = nextinit(); + r = a->left; + complex(r); + if(r->op != OCONST) { + diag(r, "initializer subscript must be constant"); + return; + } + e = r->vconst; + if(t->width != 0) + if(e < 0 || e*w >= t->width) { + diag(a, "initialization index out of range: %ld", e); + continue; + } + } + + so = e*w; + if(so > mw) + mw = so; + if(t->width != 0) + if(mw >= t->width) + break; + init1(s, t->link, o+so, 1); + e++; + } + if(t->width == 0) + t->width = mw+w; + return; + + case TUNION: + case TSTRUCT: + /* + * peek ahead to find type of rhs. + * if its a structure, then treat + * this element as a variable + * rather than an aggregate. + */ + if(isstruct(a, t)) + goto single; + + if(t->width <= 0) { + diag(Z, "incomplete structure: %s", s->name); + return; + } + + again: + for(t1 = t->link; t1 != T; t1 = t1->down) { + if(a->op == OARRAY && t1->etype != TARRAY) + break; + if(a->op == OELEM) { + if(t1->sym != a->sym) + continue; + nextinit(); + } + init1(s, t1, o+t1->offset, 1); + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM) + goto again; + } + if(a && a->op == OELEM) + diag(a, "structure element not found %F", a); + return; + } +} + +/* +Node* +newlist(Node *l, Node *r) +{ + if(r == Z) + return l; + if(l == Z) + return r; + return new(OLIST, l, r); +} +*/ + +void +suallign(Type *t) +{ + Type *l; + long o, w; + + o = 0; + switch(t->etype) { + + case TSTRUCT: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->nbits) { + if(l->shift <= 0) { + l->shift = -l->shift; + w = round(w, tfield->width); + o = w; + w += tfield->width; + } + l->offset = o; + } else { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete structure element: %s", + l->sym->name); + else + diag(Z, "incomplete structure element"); + w = align(w, l, Ael1); + l->offset = w; + w = align(w, l, Ael2); + } + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + ttgen(t); + return; + + case TUNION: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete union element: %s", + l->sym->name); + else + diag(Z, "incomplete union element"); + l->offset = 0; + l->shift = 0; + o = align(align(0, l, Ael1), l, Ael2); + if(o > w) + w = o; + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + ttgen(t); + return; + + default: + diag(Z, "unknown type in suallign: %T", t); + break; + } +} + +long +round(long v, int w) +{ + int r; + + if(w <= 0 || w > 8) { + diag(Z, "rounding by %d", w); + w = 1; + } + r = v%w; + if(r) + v += w-r; + return v; +} + +Type* +ofnproto(Node *n) +{ + Type *tl, *tr, *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + tl = ofnproto(n->left); + tr = ofnproto(n->right); + if(tl == T) + return tr; + tl->down = tr; + return tl; + + case ONAME: + if(n->type == T) + n->type = n->sym->type; + t = typ(TXXX, T); + *t = *n->sym->type; + t->down = T; + return t; + } + return T; +} + +#define ANSIPROTO 1 +#define OLDPROTO 2 + +void +argmark(Node *n, int pass) +{ + Type *t; + + autoffset = align(0, thisfn->link, Aarg0); + for(; n->left != Z; n = n->left) { + if(n->op != OFUNC || n->left->op != ONAME) + continue; + walkparam(n->right, pass); + if(pass != 0 && anyproto(n->right) == OLDPROTO) { + t = typ(TFUNC, n->left->sym->type->link); + t->down = typ(TOLD, T); + t->down->down = ofnproto(n->right); + tmerge(t, n->left->sym); + n->left->sym->type = t; + } + break; + } + autoffset = 0; +} + +void +walkparam(Node *n, int pass) +{ + Sym *s; + Node *n1; + + if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID]) + return; + +loop: + if(n == Z) + return; + switch(n->op) { + default: + diag(n, "argument not a name/prototype: %O", n->op); + break; + + case OLIST: + walkparam(n->left, pass); + n = n->right; + goto loop; + + case OPROTO: + for(n1 = n; n1 != Z; n1=n1->left) + if(n1->op == ONAME) { + if(pass == 0) { + s = n1->sym; + push1(s); + s->offset = -1; + break; + } + dodecl(pdecl, CPARAM, n->type, n->left, 1); + break; + } + if(n1) + break; + if(pass == 0) { + /* + * extension: + * allow no name in argument declaration + diag(Z, "no name in argument declaration"); + */ + break; + } + dodecl(NODECL, CPARAM, n->type, n->left, 1); + pdecl(CPARAM, lastdcl, S); + break; + + case ODOTDOT: + break; + + case ONAME: + s = n->sym; + if(pass == 0) { + push1(s); + s->offset = -1; + break; + } + if(s->offset != -1) { + autoffset = align(autoffset, s->type, Aarg1); + s->offset = autoffset; + autoffset = align(autoffset, s->type, Aarg2); + } else + dodecl(pdecl, CXXX, types[TINT], n, 1); + break; + } +} + +void +markdcl(void) +{ + Decl *d; + + blockno++; + d = push(); + d->val = DMARK; + d->offset = autoffset; + d->block = autobn; + autobn = blockno; +} + +Node* +revertdcl(void) +{ + Decl *d; + Sym *s; + + for(;;) { + d = dclstack; + if(d == D) { + diag(Z, "pop off dcl stack"); + break; + } + dclstack = d->link; + s = d->sym; + switch(d->val) { + case DMARK: + autoffset = d->offset; + autobn = d->block; + free(d); + return Z; + + case DAUTO: + if(0) { + if(s->class == CAUTO) + warn(Z, "auto declared and not used: %s", s->name); + if(s->class == CPARAM) + warn(Z, "param declared and not used: %s", s->name); + } + s->type = d->type; + s->class = d->class; + s->offset = d->offset; + s->block = d->block; + s->lineno = d->lineno; + break; + + case DSUE: + s->suetag = d->type; + s->sueblock = d->block; + s->lineno = d->lineno; + break; + + case DLABEL: + if(0 && s->label) + warn(s->label, "label declared and not used \"%s\"", s->name); + s->label = Z; + s->lineno = d->lineno; + break; + } + free(d); + } + return Z; +} + +Type* +fnproto(Node *n) +{ + int r; + + r = anyproto(n->right); + if(r == 0 || (r & OLDPROTO)) { + if(r & ANSIPROTO) + diag(n, "mixed ansi/old function declaration: %F", n->left); + return T; + } + return fnproto1(n->right); +} + +int +anyproto(Node *n) +{ + int r; + + r = 0; + +loop: + if(n == Z) + return r; + switch(n->op) { + case OLIST: + r |= anyproto(n->left); + n = n->right; + goto loop; + + case ODOTDOT: + case OPROTO: + return r | ANSIPROTO; + } + return r | OLDPROTO; +} + +Type* +fnproto1(Node *n) +{ + Type *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + t = fnproto1(n->left); + if(t != T) + t->down = fnproto1(n->right); + return t; + + case OPROTO: + lastdcl = T; + n = dodecl(NODECL, CXXX, n->type, n->left, 1); + t = typ(TXXX, T); + if(lastdcl != T) + *t = *paramconv(lastdcl, 1); + if(n != Z && n->op == ONAME) + t->sym = n->sym; + return t; + + case ONAME: + diag(n, "incomplete argument prototype"); + return typ(TINT, T); + + case ODOTDOT: + return typ(TDOT, T); + } + diag(n, "unknown op in fnproto"); + return T; +} + +void +dbgdecl(Sym *s) +{ + + print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n", + s->name, cnames[s->class], s->block, s->offset, s->type); +} + +Decl* +push(void) +{ + static Decl zdecl; + Decl *d; + + d = alloc(sizeof(*d)); + *d = zdecl; + d->link = dclstack; + dclstack = d; + return d; +} + +Decl* +push1(Sym *s) +{ + Decl *d; + + d = push(); + d->sym = s; + d->val = DAUTO; + d->type = s->type; + d->class = s->class; + d->offset = s->offset; + d->block = s->block; + d->lineno = s->lineno; + return d; +} + +int +sametype(Type *t1, Type *t2) +{ + + if(t1 == t2) + return 1; + return rsametype(t1, t2, 5, 1); +} + +int +rsametype(Type *t1, Type *t2, int n, int f) +{ + int et; + + n--; + for(;;) { + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + if(n <= 0) + return 1; + et = t1->etype; + if(et != t2->etype) + return 0; + if(et == TFUNC) { + if(!rsametype(t1->link, t2->link, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + while(t1 != T && t2 != T) { + if(t1->etype == TOLD) { + t1 = t1->down; + continue; + } + if(t2->etype == TOLD) { + t2 = t2->down; + continue; + } + while(t1 != T || t2 != T) { + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + break; + } + return 1; + } + if(et == TARRAY) + if(t1->width != t2->width && t1->width != 0 && t2->width != 0) + return 0; + if(typesu[et] || et == TTUPLE) { + if(t1->link == T) + snap(t1); + if(t2->link == T) + snap(t2); + t1 = t1->link; + t2 = t2->link; + for(;;) { + if(t1 == t2) + return 1; + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + } + t1 = t1->link; + t2 = t2->link; + if((f || 1) && et == TIND) { + if(t1 != T && t1->etype == TVOID) + return 1; + if(t2 != T && t2->etype == TVOID) + return 1; + } + } + return 0; +} + +ulong +signature(Type *t, int n) +{ + Type *t1; + long s; + + s = 0; + if(n > 0) + for(; t; t=t->link) { + s = s*thash1 + thash[t->etype]; + switch(t->etype) { + default: + return s; + case TARRAY: + s = s*thash2 + t->width; + break; + case TFUNC: + case TSTRUCT: + case TUNION: + for(t1=t; t1; t1=t1->down) + s = s*thash3 + signature(t1, n-1); + case TIND: + break; + } + } + return s; +} + +void +snap(Type *t) +{ + if(typesu[t->etype]) + if(t->link == T && t->tag && t->tag->suetag) { + t->link = t->tag->suetag->link; + t->width = t->tag->suetag->width; + } +} + +Type* +dotag(Sym *s, int et, int bn) +{ + Decl *d; + + if(bn != 0 && bn != s->sueblock) { + d = push(); + d->sym = s; + d->val = DSUE; + d->type = s->suetag; + d->block = s->sueblock; + d->lineno = s->lineno; + s->suetag = T; + } + if(s->suetag == T) { + s->suetag = typ(et, T); + s->sueblock = autobn; + } + if(s->suetag->etype != et) + diag(Z, "tag used for more than one type: %s", + s->name); + if(s->suetag->tag == S) + s->suetag->tag = s; + return s->suetag; +} + +Node* +dcllabel(Sym *s, int f) +{ + Decl *d, d1; + Node *n; + + n = s->label; + if(n != Z) { + if(f) { + if(0) + diag(Z, "label reused: %s", s->name); + } + return n; + } + + d = push(); + d->sym = s; + d->val = DLABEL; + d->lineno = s->lineno; + dclstack = d->link; + + d1 = *firstdcl; + *firstdcl = *d; + *d = d1; + + firstdcl->link = d; + firstdcl = d; + + n = new(OXXX, Z, Z); + n->sym = s; + s->label = n; + return n; +} + +Type* +paramconv(Type *t, int f) +{ + f = 1; + switch(t->etype) { + case TUNION: + case TSTRUCT: + if(t->width <= 0) + diag(Z, "incomplete structure: %s", t->tag->name); + break; + + case TARRAY: + t = typ(TIND, t->link); + t->width = types[TIND]->width; + break; + + case TFUNC: + t = typ(TIND, t); + t->width = types[TIND]->width; + break; + + case TFLOAT: + if(!f) + t = types[TDOUBLE]; + break; + + case TCHAR: + case TSHORT: + if(!f) + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + if(!f) + t = types[TUINT]; + break; + } + return t; +} + +void +adecl(int c, Type *t, Sym *s) +{ + + if(c == CSTATIC) + c = CLOCAL; + if(t->etype == TFUNC) { + if(c == CXXX) + c = CEXTERN; + if(c == CLOCAL) + c = CSTATIC; + if(c == CAUTO || c == CEXREG) + diag(Z, "function cannot be %s %s", cnames[c], s->name); + } + if(c == CXXX) + c = CAUTO; + if(s) { + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "just say static: %s", s->name); + c = CSTATIC; + } + if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL) + if(s->block == autobn) + diag(Z, "auto redeclaration of: %s", s->name); + if(c != CPARAM) + push1(s); + s->block = autobn; + s->offset = 0; + s->type = t; + s->class = c; + } + switch(c) { + case CAUTO: + autoffset = align(autoffset, t, Aaut3); + s->offset = -autoffset; + break; + + case CPARAM: + autoffset = align(autoffset, t, Aarg1); + if(s) + s->offset = autoffset; + autoffset = align(autoffset, t, Aarg2); + break; + } + if(s) + s->lineno = lineno; +} + +void +pdecl(int c, Type *t, Sym *s) +{ + if(s && s->offset != -1) { + diag(Z, "not a parameter: %s", s->name); + return; + } + t = paramconv(t, c==CPARAM); + if(c == CXXX) + c = CPARAM; + if(c != CPARAM) { + diag(Z, "parameter cannot have class: %s", s->name); + c = CPARAM; + } + adecl(c, t, s); + if(s) + s->lineno = lineno; +} + +void +xdecl(int c, Type *t, Sym *s) +{ + long o; + + o = 0; + if(c == CEXREG) + c = CEXTERN; + if(c == CXXX) { + c = CGLOBL; + if(s->class == CEXTERN) + s->class = c; + } + if(c == CEXTERN) + if(s->class == CGLOBL) + c = CGLOBL; + if(c == CAUTO) { + diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CEXTERN; + } + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CSTATIC; + } + if(s->type != T) + if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) { + diag(Z, "external redeclaration of: %s", s->name); + print(" %s %T; %s %T\n", cnames[c], t, cnames[s->class], s->type); + } + tmerge(t, s); + s->type = t; + s->class = c; + s->block = 0; + s->offset = o; +} + +void +tmerge(Type *t1, Sym *s) +{ + Type *ta, *tb, *t2; + + t2 = s->type; +/*print("merge %T; %T\n", t1, t2);/**/ + for(;;) { + if(t1 == T || t2 == T || t1 == t2) + break; + if(t1->etype != t2->etype) + break; + switch(t1->etype) { + case TFUNC: + ta = t1->down; + tb = t2->down; + if(ta == T) { + t1->down = tb; + break; + } + if(tb == T) + break; + while(ta != T && tb != T) { + if(ta == tb) + break; + /* ignore old-style flag */ + if(ta->etype == TOLD) { + ta = ta->down; + continue; + } + if(tb->etype == TOLD) { + tb = tb->down; + continue; + } + /* checking terminated by ... */ + if(ta->etype == TDOT && tb->etype == TDOT) { + ta = T; + tb = T; + break; + } + if(!sametype(ta, tb)) + break; + ta = ta->down; + tb = tb->down; + } + if(ta != tb) + diag(Z, "function inconsistently declared: %s", s->name); + + /* take new-style over old-style */ + ta = t1->down; + tb = t2->down; + if(ta != T && ta->etype == TOLD) + if(tb != T && tb->etype != TOLD) + t1->down = tb; + break; + + case TARRAY: + /* should we check array size change? */ + if(t2->width > t1->width) + t1->width = t2->width; + break; + + case TUNION: + case TSTRUCT: + return; + } + t1 = t1->link; + t2 = t2->link; + } +} + +void +edecl(int c, Type *t, Sym *s) +{ + long l; + Type *t1; + + if(s == S) { + if(!typesu[t->etype]) + diag(Z, "unnamed structure element must be struct/union"); + if(c != CXXX) + diag(Z, "unnamed structure element cannot have class"); + } else + if(c != CXXX) + diag(Z, "structure element cannot have class: %s", s->name); + t1 = t; + t = typ(TXXX, T); + l = t->lineno; + *t = *t1; + t->lineno = l; + t->sym = s; + t->down = T; + if(lastfield) { + t->shift = lastbit - lastfield; + t->nbits = lastfield; + if(firstbit) + t->shift = -t->shift; + if(typeu[t->etype]) + t->etype = tufield->etype; + else + t->etype = tfield->etype; + } + if(strf == T) + strf = t; + else + strl->down = t; + strl = t; +} + +/* + * this routine is very suspect. + * ansi requires the enum type to + * be represented as an 'int' + * this means that 0x81234567 + * would be illegal. this routine + * makes signed and unsigned go + * to unsigned. + */ +Type* +maxtype(Type *t1, Type *t2) +{ + + if(t1 == T) + return t2; + if(t2 == T) + return t1; + if(t1->etype > t2->etype) + return t1; + return t2; +} + +void +doenum(Sym *s, Node *n) +{ + int k = KDEC; + Node *nc; + + nc = Z; + if(n) { + k = n->kind; + complex(n); + if(n->op != OCONST && n->op != OSTRING && n->op != OLSTRING) { + diag(n, "enum not a constant: %s", s->name); + return; + } + nc = n->left; + en.cenum = n->type; + en.tenum = maxtype(en.cenum, en.tenum); + + if(!typefd[en.cenum->etype]) + en.lastenum = n->vconst; + else + en.floatenum = n->fconst; + } + if(dclstack) + push1(s); + xdecl(CXXX, types[TENUM], s); + + if(en.cenum == T) { + en.tenum = types[TINT]; + en.cenum = types[TINT]; + en.lastenum = 0; + } + s->tenum = en.cenum; + + if(s->tenum->etype == TIND){ /* string */ + nc = n; + s->tenum = n->type; + } + else if(!typefd[s->tenum->etype]) { + s->vconst = convvtox(en.lastenum, s->tenum->etype); + en.lastenum++; + s->tenum = types[TINT]; + } else { + s->fconst = en.floatenum; + if(n) + s->cstring = n->cstring; + else + s->cstring = nil; + en.floatenum++; + s->tenum = types[TDOUBLE]; + } + s->nconst = nc; + + acidvar(s); + s->kind = k; + etgen(s); +} + +void +symadjust(Sym *s, Node *n, long del) +{ + + switch(n->op) { + default: + if(n->left) + symadjust(s, n->left, del); + if(n->right) + symadjust(s, n->right, del); + return; + + case ONAME: + return; + + case OCONST: + case OSTRING: + case OLSTRING: + case OINDREG: + case OREGISTER: + return; + } +} diff --git a/utils/c2l/dpchk.c b/utils/c2l/dpchk.c new file mode 100644 index 00000000..78865cb8 --- /dev/null +++ b/utils/c2l/dpchk.c @@ -0,0 +1,392 @@ +#include "cc.h" +#include "y.tab.h" + +enum +{ + Fnone = 0, + Fl, + Fvl, + Fignor, + Fstar, + Fadj, + + Fverb = 10, +}; + +typedef struct Tprot Tprot; +struct Tprot +{ + Type* type; + Bits flag; + Tprot* link; +}; + +typedef struct Tname Tname; +struct Tname +{ + char* name; + int param; + Tname* link; +}; + +static Type* indchar; +static uchar flagbits[256]; +static char fmtbuf[100]; +static int lastadj; +static int lastverb; +static int nstar; +static Tprot* tprot; +static Tname* tname; + +void +argflag(int c, int v) +{ + + switch(v) { + case Fignor: + case Fstar: + case Fl: + case Fvl: + flagbits[c] = v; + break; + case Fverb: + flagbits[c] = lastverb; +/*print("flag-v %c %d\n", c, lastadj);*/ + lastverb++; + break; + case Fadj: + flagbits[c] = lastadj; +/*print("flag-l %c %d\n", c, lastadj);*/ + lastadj++; + break; + } +} + +Bits +getflag(char *s) +{ + Bits flag; + int c, f; + char *fmt; + + fmt = fmtbuf; + flag = zbits; + nstar = 0; + while(c = *s++) { + *fmt++ = c; + f = flagbits[c]; + switch(f) { + case Fnone: + argflag(c, Fverb); + f = flagbits[c]; + break; + case Fstar: + nstar++; + case Fignor: + continue; + case Fl: + if(bset(flag, Fl)) + flag = bor(flag, blsh(Fvl)); + } + flag = bor(flag, blsh(f)); + if(f >= Fverb) + break; + } + *fmt = 0; + return flag; +} + +void +newprot(Sym *m, Type *t, char *s) +{ + Bits flag; + Tprot *l; + + if(t == T) { + warn(Z, "%s: newprot: type not defined", m->name); + return; + } + flag = getflag(s); + for(l=tprot; l; l=l->link) + if(beq(flag, l->flag) && sametype(t, l->type)) + return; + l = alloc(sizeof(*l)); + l->type = t; + l->flag = flag; + l->link = tprot; + tprot = l; +} + +void +newname(char *s, int p) +{ + Tname *l; + + for(l=tname; l; l=l->link) + if(strcmp(l->name, s) == 0) { + if(l->param != p) + yyerror("vargck %s already defined\n", s); + return; + } + l = alloc(sizeof(*l)); + l->name = s; + l->param = p; + l->link = tname; + tname = l; +} + +void +arginit(void) +{ + int i; + + lastadj = Fadj; + lastverb = Fverb; + indchar = typ(TIND, types[TCHAR]); + + memset(flagbits, Fnone, sizeof(flagbits)); + + for(i='0'; i<='9'; i++) + argflag(i, Fignor); + argflag('.', Fignor); + argflag('#', Fignor); + argflag('u', Fignor); + argflag('+', Fignor); + argflag('-', Fignor); + + argflag('*', Fstar); + argflag('l', Fl); + + argflag('o', Fverb); + flagbits['x'] = flagbits['o']; + flagbits['X'] = flagbits['o']; +} + +void +pragvararg(void) +{ + Sym *s; + int n, c; + char *t; + + if(1) + goto out; + s = getsym(); + if(s && strcmp(s->name, "argpos") == 0) + goto ckpos; + if(s && strcmp(s->name, "type") == 0) + goto cktype; + yyerror("syntax in #pragma varargck"); + goto out; + +ckpos: +/*#pragma varargck argpos warn 2*/ + s = getsym(); + if(s == S) + goto bad; + n = getnsn(); + if(n < 0) + goto bad; + newname(s->name, n); + goto out; + +cktype: +/*#pragma varargck type O int*/ + c = getnsc(); + if(c != '"') + goto bad; + t = fmtbuf; + for(;;) { + c = getc(); + if(c == ' ' || c == '\n') + goto bad; + if(c == '"') + break; + *t++ = c; + } + *t = 0; + t = strdup(fmtbuf); + s = getsym(); + if(s == S) + goto bad; + c = getnsc(); + unget(c); + if(c == '*') + newprot(s, typ(TIND, s->type), t); + else + newprot(s, s->type, t); + goto out; + +bad: + yyerror("syntax in #pragma varargck"); + +out: + while(getnsc() != '\n') + ; +} + +Node* +nextarg(Node *n, Node **a) +{ + if(n == Z) { + *a = Z; + return Z; + } + if(n->op == OLIST) { + *a = n->left; + return n->right; + } + *a = n; + return Z; +} + +void +checkargs(Node *nn, char *s, int pos) +{ + Node *a, *n; + Bits flag; + Tprot *l; + + if(1) + return; + n = nn; + for(;;) { + s = strchr(s, '%'); + if(s == 0) { + nextarg(n, &a); + if(a != Z) + warn(nn, "more arguments than format %T", + a->type); + return; + } + s++; + flag = getflag(s); + while(nstar > 0) { + n = nextarg(n, &a); + pos++; + nstar--; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == T) + continue; + if(!sametype(types[TINT], a->type) && + !sametype(types[TUINT], a->type)) + warn(nn, "format mismatch '*' in %s %T, arg %d", + fmtbuf, a->type, pos); + } + for(l=tprot; l; l=l->link) + if(sametype(types[TVOID], l->type)) { + if(beq(flag, l->flag)) { + s++; + goto loop; + } + } + + n = nextarg(n, &a); + pos++; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == 0) + continue; + for(l=tprot; l; l=l->link) + if(sametype(a->type, l->type)) + if(beq(flag, l->flag)) + goto loop; + warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos); + loop:; + } +} + +void +dpcheck(Node *n) +{ + char *s; + Node *a, *b; + Tname *l; + int i; + + if(n == Z) + return; + b = n->left; + if(b == Z || b->op != ONAME) + return; + s = b->sym->name; + for(l=tname; l; l=l->link) + if(strcmp(s, l->name) == 0) + break; + if(l == 0) + return; + + i = l->param; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + warn(n, "cant find format arg"); + return; + } + if(!sametype(indchar, a->type)) { + warn(n, "format arg type %T", a->type); + return; + } + if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { +/* warn(n, "format arg not constant string");*/ + return; + } + s = a->left->cstring; + checkargs(b, s, l->param); +} + +void +praghjdicks(void) +{ + Sym *s; + + hjdickflg = 0; + s = getsym(); + if(s) { + hjdickflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0 || + strcmp(s->name, "dick") == 0) + hjdickflg = 1; + } + while(getnsc() != '\n') + ; + if(0) + if(hjdickflg) + print("%4ld: hjdicks %d\n", lineno, hjdickflg); + else + print("%4ld: hjdicks off\n", lineno); +} + +void +pragfpround(void) +{ + Sym *s; + + fproundflg = 0; + s = getsym(); + if(s) { + hjdickflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0 || + strcmp(s->name, "dick") == 0) + fproundflg = 1; + } + while(getnsc() != '\n') + ; + if(0) + if(fproundflg) + print("%4ld: fproundflg %d\n", lineno, fproundflg); + else + print("%4ld: fproundflg off\n", lineno); +} diff --git a/utils/c2l/lex.c b/utils/c2l/lex.c new file mode 100644 index 00000000..5701dd99 --- /dev/null +++ b/utils/c2l/lex.c @@ -0,0 +1,1675 @@ +#include "cc.h" +#include "y.tab.h" + +#ifndef CPP +#define CPP "/bin/cpp" +#endif + +static int ansip; + +void +main(int argc, char *argv[]) +{ + char *defs[50], *p; + int nproc, nout, status, i, c, ndef; + + tinit(); + cinit(); + ginit(); + arginit(); + + tufield = simplet((1L<<tfield->etype) | BUNSIGNED); + ndef = 0; + include[ninclude++] = "."; + strings = 1; + passes = 1; + + ARGBEGIN { + default: + break; + + case 'p': + ansip = 1; + break; + + case 'D': + p = ARGF(); + if(p) { + defs[ndef++] = p; + dodefine(p); + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + + case 'm': + domod = 1; + break; + + case 'i': + doinc = 1; + break; + + case 'l': + doloc = 1; + break; + + case 'c': + justcode = 1; + break; + + case 'v': + comm = 1; + break; + + case 's': + strings = 0; + break; + + case 'S': + strings = 2; + break; + + case 'M': + inmain = 1; + break; + + case 'q': + passes = 0; + break; + + case 'a': + doaddr = 1; + break; + + case 'A': + doaddr = 1; + doalladdr = 1; + break; + + } ARGEND + + if(doinc) + domod = doloc = 0; + + linit(); + + if(argc != 1) { + print("usage: c2l [-options] file\n"); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't compile 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) { + print("cannot create a process\n"); + errorexit(); + } + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + fprint(2, "%s:\n", *argv); + if (compile(*argv, defs, ndef)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + + if(argc == 0) + c = compile("stdin", defs, ndef); + else + c = compile(argv[0], defs, ndef); + + if(c) + errorexit(); + exits(0); +} + +int +compile(char *file, char **defs, int ndef) +{ + char ofile[200], incfile[20]; + char *p, *av[100], opt[256]; + int i, c, fd[2]; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + *p++ = 0; + include[0] = strdup(ofile); + } else + p = ofile; + + USED(p); + if(p = getenv("INCLUDE")) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile, "/%s/include", thestring); + setinclude(strdup(incfile)); + setinclude("/sys/include"); + } + } + newio(); + + /* Use an ANSI preprocessor */ + if(ansip) { + if(systemtype(Windows)) { + diag(Z, "-p option not supported on windows"); + errorexit(); + } + if(mypipe(fd) < 0) { + diag(Z, "pipe failed"); + errorexit(); + } + switch(myfork()) { + case -1: + diag(Z, "fork failed"); + errorexit(); + case 0: + close(fd[0]); + mydup(fd[1], 1); + close(fd[1]); + av[0] = CPP; + i = 1; + for(c = 0; c < ndef; c++) { + sprint(opt, "-D%s", defs[c]); + av[i++] = strdup(opt); + } + for(c = 0; c < ninclude; c++) { + sprint(opt, "-I%s", include[c]); + av[i++] = strdup(opt); + } + if(strcmp(file, "stdin") != 0) + av[i++] = file; + av[i] = 0; + if(0) { + for(c = 0; c < i; c++) + fprint(2, "%s ", av[c]); + print("\n"); + } + myexec(av[0], av); + fprint(2, "can't exec C preprocessor %s: %r\n", CPP); + errorexit(); + default: + close(fd[1]); + newfile(file, fd[0]); + break; + } + } else { + if(strcmp(file, "stdin") == 0) + newfile(file, 0); + else + newfile(file, -1); + } + + clbegin(); + yyparse(); + clend(); + newsec(0); + return nerrors; +} + +void +errorexit(void) +{ + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + if(0) + print("%L: %s\n", lineno, s); + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("c2l: %r: %s", s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); + outpush(s); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + static Sym zsym; + Sym *s; + ulong h; + char *p; + int c, n; + + h = 0; + for(p=symb; *p;) { + h = h * 3; + h += *p++; + } + n = (p - symb) + 1; + if((long)h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(strcmp(s->name, symb) == 0) + return s; + } + s = alloc(sizeof(*s)); + *s = zsym; + s->name = alloc(n); + memmove(s->name, symb, n); + + strcpy(s->name, symb); + s->link = hash[h]; + hash[h] = s; + syminit(s); + + return s; +} + +void +syminit(Sym *s) +{ + s->lexical = LNAME; + s->type = T; + s->suetag = T; + s->class = CXXX; + s->lname = s->mod = nil; + s->lineno = lineno; + s->tenum = T; +} + +#define EOF (-1) +#define IGN (-2) +#define ESC (1<<20) +#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)) + +enum +{ + Numdec = 1<<0, + Numlong = 1<<1, + Numuns = 1<<2, + Numvlong = 1<<3, + Numflt = 1<<4, +}; + +static int ypeek = 0; + +long +yylex(void) +{ + vlong vv; + long c, c1; + char *cp; + Rune rune; + Sym *s; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c >= Runeself) { + /* + * extension -- + * all multibyte runes are alpha + */ + cp = symb; + goto talph; + } + if(isspace(c)) { + if(c == '\n') + lineno++; + goto l0; + } + if(isalpha(c)) { + cp = symb; + if(c != 'L') + goto talph; + *cp++ = c; + c = GETC(); + if(c == '\'') { + /* L'x' */ + c = escchar('\'', 1, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 1, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + yylval.vval = convvtox(c, TUSHORT); + return LUCONST; + } + if(c == '"') { + goto caselq; + } + goto talph; + } + if(isdigit(c)) + goto tnum; + switch(c) + { + + case EOF: + peekc = EOF; + return -1; + + case '_': + cp = symb; + goto talph; + + case '#': + domacro(); + goto l0; + + case '.': + c1 = GETC(); + if(isdigit(c1)) { + cp = symb; + *cp++ = c; + c = c1; + c1 = 0; + goto casedot; + } + break; + + case '"': + strcpy(symb, "\"<string>\""); + cp = alloc(0); + c1 = 0; + + /* "..." */ + for(;;) { + c = escchar('"', 0, 1); + if(c == EOF) + break; + if(c & ESC) { + cp = allocn(cp, c1, 1); + cp[c1++] = c; + } else { + rune = c; + c = runelen(rune); + cp = allocn(cp, c1, c); + runetochar(cp+c1, &rune); + c1 += c; + } + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, 1); + cp[c1++] = 0; + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LSTRING; + + caselq: + /* L"..." */ + strcpy(symb, "\"L<string>\""); + cp = alloc(0); + c1 = 0; + for(;;) { + c = escchar('"', 1, 0); + if(c == EOF) + break; + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = c; + c1 += sizeof(ushort); + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = 0; + c1 += sizeof(ushort); + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LLSTRING; + + case '\'': + /* '.' */ + c = escchar('\'', 0, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 0, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + vv = c; + yylval.vval = convvtox(vv, TUCHAR); + if(yylval.vval != vv) + yyerror("overflow in character constant: 0x%lx", c); + else + if(c & 0x80) + warn(Z, "sign-extended character constant"); + yylval.vval = convvtox(vv, TCHAR); + return LCHARACTER; + + case '/': + c1 = GETC(); + if(c1 == '*') { + startcom(lineno); + for(;;) { + c = getr(); + if(c == '*'){ + while(c == '*') { + c = getr(); + if(c == '/'){ + endcom(); + goto l0; + } + addcom('*'); + } + addcom(c); + } + else + addcom(c); + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '/') { + startcom(lineno); + for(;;) { + c = getr(); + if(c == '\n'){ + endcom(); + goto l0; + } + addcom(c); + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '=') + return LDVE; + break; + + case '*': + c1 = GETC(); + if(c1 == '=') + return LMLE; + break; + + case '%': + c1 = GETC(); + if(c1 == '=') + return LMDE; + break; + + case '+': + c1 = GETC(); + if(c1 == '+') + return LPP; + if(c1 == '=') + return LPE; + break; + + case '-': + c1 = GETC(); + if(c1 == '-') + return LMM; + if(c1 == '=') + return LME; + if(c1 == '>') + return LMG; + break; + + case '>': + c1 = GETC(); + if(c1 == '>') { + c = LRSH; + c1 = GETC(); + if(c1 == '=') + return LRSHE; + break; + } + if(c1 == '=') + return LGE; + break; + + case '<': + c1 = GETC(); + if(c1 == '<') { + c = LLSH; + c1 = GETC(); + if(c1 == '=') + return LLSHE; + break; + } + if(c1 == '=') + return LLE; + break; + + case '=': + c1 = GETC(); + if(c1 == '=') + return LEQ; + break; + + case '!': + c1 = GETC(); + if(c1 == '=') + return LNE; + break; + + case '&': + c1 = GETC(); + if(c1 == '&') + return LANDAND; + if(c1 == '=') + return LANDE; + break; + + case '|': + c1 = GETC(); + if(c1 == '|') + return LOROR; + if(c1 == '=') + return LORE; + break; + + case '^': + c1 = GETC(); + if(c1 == '=') + return LXORE; + break; + + default: + return c; + } + peekc = c1; + return c; + +talph: + /* + * cp is set to symb and some + * prefix has been stored + */ + for(;;) { + if(c >= Runeself) { + for(c1=0;;) { + cp[c1++] = c; + if(fullrune(cp, c1)) + break; + c = GETC(); + } + cp += c1; + c = GETC(); + continue; + } + if(!isalnum(c) && c != '_') + break; + *cp++ = c; + c = GETC(); + } + *cp = 0; + if(0) + print("%L: %s\n", lineno, symb); + peekc = c; + s = lookup(); + if(s->macro && !ypeek) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + /* outpush(nil); */ + goto l0; + } + yylval.sym = s; + if(s->class == CTYPEDEF) { + if(s->type && typesu[s->type->etype]) + return LCTYPE; + return LSTYPE; + } + return s->lexical; + +tnum: + lastnumbase = KDEC; + c1 = 0; + cp = symb; + if(c != '0') { + c1 |= Numdec; + for(;;) { + *cp++ = c; + c = GETC(); + if(isdigit(c)) + continue; + goto dc; + } + } + *cp++ = c; + c = GETC(); + if(c == 'x' || c == 'X'){ + lastnumbase = KHEX; + for(;;) { + *cp++ = c; + c = GETC(); + if(isdigit(c)) + continue; + if(c >= 'a' && c <= 'f') + continue; + if(c >= 'A' && c <= 'F') + continue; + if(cp == symb+2) + yyerror("malformed hex constant"); + goto ncu; + } + } + else + lastnumbase = KOCT; + if(c < '0' || c > '7'){ + lastnumbase = KDEC; + goto dc; + } + for(;;) { + if(c >= '0' && c <= '7') { + *cp++ = c; + c = GETC(); + continue; + } + goto ncu; + } + +dc: + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + +ncu: + if((c == 'U' || c == 'u') && !(c1 & Numuns)) { + c = GETC(); + c1 |= Numuns; + goto ncu; + } + if((c == 'L' || c == 'l') && !(c1 & Numvlong)) { + c = GETC(); + if(c1 & Numlong) + c1 |= Numvlong; + c1 |= Numlong; + goto ncu; + } + *cp = 0; + peekc = c; + if(mpatov(symb, &yylval.vval)) + yyerror("overflow in constant"); + + vv = yylval.vval; + if(c1 & Numvlong) { + if(c1 & Numuns) { + c = LUVLCONST; + goto nret; + } + yylval.vval = convvtox(yylval.vval, TVLONG); + if(yylval.vval < 0) { + c = LUVLCONST; + goto nret; + } + c = LVLCONST; + goto nret; + } + if(c1 & Numlong) { + if(c1 & Numuns) { + c = LULCONST; + goto nret; + } + yylval.vval = convvtox(yylval.vval, TLONG); + if(yylval.vval < 0) { + c = LULCONST; + goto nret; + } + c = LLCONST; + goto nret; + } + if(c1 & Numuns) { + c = LUCONST; + goto nret; + } + yylval.vval = convvtox(yylval.vval, TINT); + if(yylval.vval < 0) { + c = LUCONST; + goto nret; + } + c = LCONST; + goto nret; + +nret: + return c; + +casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c != 'e' && c != 'E') + goto caseout; + +casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + if(!isdigit(c)) + yyerror("malformed fp constant exponent"); + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + +caseout: + if(c == 'L' || c == 'l') { + c = GETC(); + c1 |= Numlong; + } else + if(c == 'F' || c == 'f') { + c = GETC(); + c1 |= Numflt; + } + *cp = 0; + peekc = c; + if(mpatof(symb, &yylval.dval)) { + yyerror("overflow in float constant"); + yylval.dval = 0; + } + if(c1 & Numflt) + return LFCONST; + return LDCONST; +} + +int +getc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +long +getr(void) +{ + int c, i; + char str[UTFmax+1]; + Rune rune; + + + c = getc(); + if(c < Runeself) + return c; + i = 0; + str[i++] = c; + +loop: + c = getc(); + str[i++] = c; + if(!fullrune(str, i)) + goto loop; + c = chartorune(&rune, str); + if(rune == Runeerror && c == 1) { + /* nearln = lineno; */ + diag(Z, "illegal rune in string"); + for(c=0; c<i; c++) + print(" %.2x", *(uchar*)(str+c)); + print("\n"); + } + return rune; +} + +int +getnsc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + for(;;) { + if(!isspace(c)) + return c; + if(c == '\n') { + lineno++; + return c; + } + c = GETC(); + } + return 0; +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +long +escchar(long e, int longflg, int escflg) +{ + long c, l; + int i; + +loop: + c = getr(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + c = EOF; + return c; + } + c = getr(); + if(c == 'x') { + /* + * note this is not ansi, + * supposed to only accept 2 hex + */ + i = 2; + if(longflg) + i = 4; + l = 0; + for(; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '9') { + l = l*16 + c-'0'; + continue; + } + if(c >= 'a' && c <= 'f') { + l = l*16 + c-'a' + 10; + continue; + } + if(c >= 'A' && c <= 'F') { + l = l*16 + c-'A' + 10; + continue; + } + unget(c); + break; + } + if(escflg) + l |= ESC; + return l; + } + if(c >= '0' && c <= '7') { + /* + * note this is not ansi, + * supposed to only accept 3 oct + */ + i = 2; + if(longflg) + i = 5; + l = c - '0'; + for(; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + continue; + } + unget(c); + } + if(escflg) + l |= ESC; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return '\a'; + case 'v': return '\v'; + } + return c; +} + +struct +{ + char *name; + ushort lexical; + ushort type; +} itab[] = +{ + "auto", LAUTO, 0, + "break", LBREAK, 0, + "case", LCASE, 0, + "char", LCHAR, TCHAR, + "const", LCONSTNT, 0, + "continue", LCONTINUE, 0, + "default", LDEFAULT, 0, + "do", LDO, 0, + "double", LDOUBLE, TDOUBLE, + "else", LELSE, 0, + "enum", LENUM, 0, + "extern", LEXTERN, 0, + "float", LFLOAT, TFLOAT, + "for", LFOR, 0, + "goto", LGOTO, 0, + "if", LIF, 0, + "int", LINT, TINT, + "long", LLONG, TLONG, + "register", LREGISTER, 0, + "return", LRETURN, 0, + "SET", LSET, 0, + "short", LSHORT, TSHORT, + "signed", LSIGNED, 0, + "signof", LSIGNOF, 0, + "sizeof", LSIZEOF, 0, + "static", LSTATIC, 0, + "struct", LSTRUCT, 0, + "switch", LSWITCH, 0, + "typedef", LTYPEDEF, 0, + "union", LUNION, 0, + "unsigned", LUNSIGNED, 0, + "USED", LUSED, 0, + "void", LVOID, TVOID, + "volatile", LVOLATILE, 0, + "while", LWHILE, 0, + "__int64", LVLONG, TVLONG, /* for windows */ + 0 +}; + +static char *litab[] = +{ + "adt", + "alt", + "array", + "big", + "break", + "byte", + "case", + "chan", + "con", + "continue", + "cyclic", + "do", + "else", + "exit", + "fn", + "for", + "hd", + "if", + "implement", + "import", + "include", + "int", + "len", + "list", + "load", + "module", + "nil", + "of", + "or", + "pick", + "real", + "ref", + "return", + "self", + "spawn", + "string", + "tagof", + "tl", + "to", + "type", + "while", + 0, +}; + +void +cinit(void) +{ + Sym *s; + int i; + Type *t; + + nerrors = 0; + lineno = 1; + iostack = I; + iofree = I; + peekc = IGN; + nhunk = 0; + + types[TXXX] = T; + types[TCHAR] = typ(TCHAR, T); + types[TUCHAR] = typ(TUCHAR, T); + types[TSHORT] = typ(TSHORT, T); + types[TUSHORT] = typ(TUSHORT, T); + types[TINT] = typ(TINT, T); + types[TUINT] = typ(TUINT, T); + types[TLONG] = typ(TLONG, T); + types[TULONG] = typ(TULONG, T); + types[TVLONG] = typ(TVLONG, T); + types[TUVLONG] = typ(TUVLONG, T); + types[TFLOAT] = typ(TFLOAT, T); + types[TDOUBLE] = typ(TDOUBLE, T); + types[TVOID] = typ(TVOID, T); + types[TENUM] = typ(TENUM, T); + types[TFUNC] = typ(TFUNC, types[TINT]); + types[TIND] = typ(TIND, types[TVOID]); + stringtype = typ(TSTRING, T); + fdtype = typ(TSTRUCT, typ(TFD, T)); + fdtype->width = 4; + pfdtype = typ(TIND, fdtype); + + for(i=0; i<NHASH; i++) + hash[i] = S; + for(i=0; itab[i].name; i++) { + s = slookup(itab[i].name); + s->lexical = itab[i].lexical; + if(itab[i].type != 0) + s->type = types[itab[i].type]; + } + for(i=0; litab[i]; i++){ + s = slookup(litab[i]); + s->lkw = 1; + } + blockno = 0; + autobn = 0; + autoffset = 0; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + symstring = slookup(".string"); + symstring->class = CSTATIC; + symstring->type = t; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + + nodproto = new(OPROTO, Z, Z); + dclstack = D; + + pathname = allocn(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } + + fmtinstall('f', gfltconv); + fmtinstall('F', gfltconv); + fmtinstall('g', gfltconv); + fmtinstall('G', gfltconv); + fmtinstall('e', gfltconv); + fmtinstall('E', gfltconv); + + fmtinstall('O', Oconv); + fmtinstall('T', Tconv); + fmtinstall('F', FNconv); + fmtinstall('L', Lconv); + fmtinstall('Q', Qconv); + fmtinstall('|', VBconv); +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0] & 0xff; + +pop: + if(i->f >= 0) + outpop(lineno); + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++ & 0xff; +} + +int +Oconv(Fmt *fp) +{ + int a; + char s[STRINGSZ]; + + a = va_arg(fp->args, int); + if(a < OXXX || a > OEND) { + sprint(s, "***badO %d***", a); + fmtstrcpy(fp, s); + } else + fmtstrcpy(fp, onames[a]); + return 0; +} + +int +Lconv(Fmt *fp) +{ + char str[STRINGSZ], s[STRINGSZ]; + Hist *h; + struct + { + Hist* incl; /* start of this include file */ + long idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + long ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + long l, d; + int i, n; + + l = va_arg(fp->args, long); + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset != 0) { /* #line directive, not #pragma */ + if(n > 0 && n < HISTSZ && h->offset >= 0) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + if(n < HISTSZ) { /* beginning of file */ + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; + } + continue; + } + n--; + if(n > 0 && n < HISTSZ) { + d = h->line - a[n].incl->line; + a[n-1].ldel += d; + a[n-1].idel += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + str[0] = 0; + for(i=n-1; i>=0; i--) { + if(i != n-1) { + if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */ + break; + strcat(str, " "); + } + if(a[i].line) + snprint(s, STRINGSZ, "%s:%ld[%s:%ld]", + a[i].line->name, l-a[i].ldel+1, + a[i].incl->name, l-a[i].idel+1); + else + snprint(s, STRINGSZ, "%s:%ld", + a[i].incl->name, l-a[i].idel+1); + if(strlen(s)+strlen(str) >= STRINGSZ-10) + break; + strcat(str, s); + l = a[i].incl->line - 1; /* now print out start of this file */ + } + if(n == 0) + strcat(str, "<eof>"); + fmtstrcpy(fp, str); + return 0; +} + +int +Tconv(Fmt *fp) +{ + char str[STRINGSZ+20], s[STRINGSZ+20]; + Type *t, *t1; + int et; + long n; + + str[0] = 0; + for(t = va_arg(fp->args, Type*); t != T; t = t->link) { + et = t->etype; + if(str[0]) + strcat(str, " "); + if(t->garb) { + sprint(s, "%s ", gnames[t->garb]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + sprint(s, "%s", tnames[et]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + if(et == TFUNC && (t1 = t->down)) { + sprint(s, "(%T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + while(t1 = t1->down) { + sprint(s, ", %T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, ")"); + } + if(et == TARRAY) { + n = t->width; + if(t->link && t->link->width) + n /= t->link->width; + sprint(s, "[%ld]", n); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(t->nbits) { + sprint(s, " %d:%d", t->shift, t->nbits); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(typesu[et]) { + if(t->tag) { + strcat(str, " "); + if(strlen(str) + strlen(t->tag->name) < STRINGSZ) + strcat(str, t->tag->name); + } else + strcat(str, " {}"); + break; + } + } + fmtstrcpy(fp, str); + return 0; +} + +int +FNconv(Fmt *fp) +{ + char *str; + Node *n; + + n = va_arg(fp->args, Node*); + str = "<indirect>"; + if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM)) + str = n->sym->name; + fmtstrcpy(fp, str); + return 0; +} + +int +Qconv(Fmt *fp) +{ + char str[STRINGSZ+20], *s; + long b; + int i; + + str[0] = 0; + for(b = va_arg(fp->args, long); b;) { + i = bitno(b); + if(str[0]) + strcat(str, " "); + s = qnames[i]; + if(strlen(str) + strlen(s) >= STRINGSZ) + break; + strcat(str, s); + b &= ~(1L << i); + } + fmtstrcpy(fp, str); + return 0; +} + +int +VBconv(Fmt *fp) +{ + char str[STRINGSZ]; + int i, n, t, pc; + + n = va_arg(fp->args, int); + pc = 0; /*was printcol */ + i = 0; + while(pc < n) { + t = (pc+8) & ~7; + if(t <= n) { + str[i++] = '\t'; + pc = t; + continue; + } + str[i++] = ' '; + pc++; + } + str[i] = 0; + fmtstrcpy(fp, str); + return 0; +} + +/* + * real allocs + */ +void* +alloc(long n) +{ + void *p; + + while((ulong)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +void +setinclude(char *p) +{ + int i; + char *e; + + while(*p != 0) { + e = strchr(p, ' '); + if(e != 0) + *e = '\0'; + + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + break; + + if(i >= ninclude) + include[ninclude++] = p; + + if(ninclude > nelem(include)) { + diag(Z, "ninclude too small %d", nelem(include)); + exits("ninclude"); + } + + if(e == 0) + break; + p = e+1; + } +} + +static void +doio(char *s) +{ + char *cp; + + newio(); + cp = ionext->b; + strcpy(cp, s); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } +} + +static void +undoio(void) +{ + Io *i; + + i = iostack; + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + fi.p = i->p; + fi.c = i->c; +} + +/* rm // comment from a string */ +static void +slashslash(char *s) +{ + for( ; *s != '\0'; s++) + if(*s == '/' && s[1] == '/'){ + *s = '\0'; + return; + } +} + +int +iscon(char *str) +{ + int olineno, opeekc, con, tok, t; + Sym *s; + char buf[1024]; + + if(str == nil || *str == 0 || strlen(str)+16 > 1024) + return 0; + ypeek = 1; + olineno = lineno; + opeekc = peekc; + peekc = IGN; + strcpy(buf, str); + slashslash(buf); + strcat(buf, " break break"); + doio(buf); + tok = 0; + con = 1; + while(con){ + t = yylex(); + if(t == LBREAK) + break; + switch(t){ + case LSTRING: + case LLSTRING: + tok = 1; + free(yylval.sval.s); + break; + case LNAME: + tok = 1; + s = yylval.sym; + if(s->macro || s->type == T || s->type->etype != TENUM) + con = 0; + break; + case LCHARACTER: + case LCONST: + case LLCONST: + case LUCONST: + case LULCONST: + case LVLCONST: + case LUVLCONST: + case LFCONST: + case LDCONST: + tok = 1; + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case LPP: + case LMM: + case '<': + case '>': + case LGE: + case LLE: + case LEQ: + case LNE: + case LLSH: + case LRSH: + case '!': + case '~': + case '&': + case '|': + case '^': + case '(': + case ')': + break; + default: + con = 0; + break; + } + } + undoio(); + peekc = opeekc; + lineno = olineno; + ypeek = 0; + return con && tok; +} + +void +doasenum(Sym *s) +{ + char *b, buf[1024]; + + b = s->macro; + s->macro = nil; + lineno--; + slashslash(b+1); + sprint(buf, "enum{ %s = %s };\n", s->name, b+1); + doio(buf); + /* outpush(nil); */ + free(b); +} diff --git a/utils/c2l/lexbody b/utils/c2l/lexbody new file mode 100644 index 00000000..ab7e2439 --- /dev/null +++ b/utils/c2l/lexbody @@ -0,0 +1,650 @@ +/* + * common code for all the assemblers + */ + +/* + * real allocs + */ +void* +alloc(long n) +{ + void *p; + + while((ulong)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +void +setinclude(char *p) +{ + int i; + + if(p == 0) + return; + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + return; + + if(ninclude >= nelem(include)) { + yyerror("ninclude too small %d", nelem(include)); + exits("ninclude"); + } + include[ninclude++] = p; +} + +void +errorexit(void) +{ + + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%ca: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + static Sym zsym; + Sym *s; + long h; + char *p; + int c, l; + + h = 0; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(memcmp(s->name, symb, l) == 0) + return s; + } + s = alloc(sizeof(*s)); + *s = zsym; + s->name = alloc(l); + memmove(s->name, symb, l); + + s->link = hash[h]; + hash[h] = s; + syminit(s); + return s; +} + +long +yylex(void) +{ + int c, c1; + char *cp; + Sym *s; + + c = peekc; + if(c != IGN) { + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c == EOF) { + peekc = EOF; + return -1; + } + if(isspace(c)) { + if(c == '\n') { + lineno++; + return ';'; + } + goto l0; + } + if(isalpha(c)) + goto talph; + if(isdigit(c)) + goto tnum; + switch(c) + { + case '\n': + lineno++; + return ';'; + + case '#': + domacro(); + goto l0; + + case '.': + c = GETC(); + if(isalpha(c)) { + cp = symb; + *cp++ = '.'; + goto aloop; + } + if(isdigit(c)) { + cp = symb; + *cp++ = '.'; + goto casedot; + } + peekc = c; + return '.'; + + talph: + case '_': + case '@': + cp = symb; + + aloop: + *cp++ = c; + c = GETC(); + if(isalpha(c) || isdigit(c) || c == '_' || c == '$') + goto aloop; + *cp = 0; + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + if(s->type == 0) + s->type = LNAME; + if(s->type == LNAME || + s->type == LVAR || + s->type == LLAB) { + yylval.sym = s; + return s->type; + } + yylval.lval = s->value; + return s->type; + + tnum: + cp = symb; + if(c != '0') + goto dc; + *cp++ = c; + c = GETC(); + c1 = 3; + if(c == 'x' || c == 'X') { + c1 = 4; + c = GETC(); + } else + if(c < '0' || c > '7') + goto dc; + yylval.lval = 0; + for(;;) { + if(c >= '0' && c <= '9') { + if(c > '7' && c1 == 3) + break; + yylval.lval <<= c1; + yylval.lval += c - '0'; + c = GETC(); + continue; + } + if(c1 == 3) + break; + if(c >= 'A' && c <= 'F') + c += 'a' - 'A'; + if(c >= 'a' && c <= 'f') { + yylval.lval <<= c1; + yylval.lval += c - 'a' + 10; + c = GETC(); + continue; + } + break; + } + goto ncu; + + dc: + for(;;) { + if(!isdigit(c)) + break; + *cp++ = c; + c = GETC(); + } + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + *cp = 0; + yylval.lval = atol(symb); + + ncu: + peekc = c; + return LCONST; + + casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c == 'e' || c == 'E') + goto casee; + goto caseout; + + casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + + caseout: + *cp = 0; + peekc = c; + if(FPCHIP) { + yylval.dval = atof(symb); + return LFCONST; + } + yyerror("assembler cannot interpret fp constants"); + yylval.lval = 1L; + return LCONST; + + case '"': + memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval)); + cp = yylval.sval; + c1 = 0; + for(;;) { + c = escchar('"'); + if(c == EOF) + break; + if(c1 < sizeof(yylval.sval)) + *cp++ = c; + c1++; + } + if(c1 > sizeof(yylval.sval)) + yyerror("string constant too long"); + return LSCONST; + + case '\'': + c = escchar('\''); + if(c == EOF) + c = '\''; + if(escchar('\'') != EOF) + yyerror("missing '"); + yylval.lval = c; + return LCONST; + + case '/': + c1 = GETC(); + if(c1 == '/') { + for(;;) { + c = GETC(); + if(c == '\n') { + lineno++; + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '*') { + for(;;) { + c = GETC(); + while(c == '*') { + c = GETC(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + if(c == '\n') + lineno++; + } + } + break; + + default: + return c; + } + peekc = c1; + return c; +} + +int +getc(void) +{ + int c; + + c = peekc; + if(c != IGN) { + peekc = IGN; + return c; + } + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +int +getnsc(void) +{ + int c; + + for(;;) { + c = getc(); + if(!isspace(c) || c == '\n') + return c; + } +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +int +escchar(int e) +{ + int c, l; + +loop: + c = getc(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + return EOF; + return c; + } + c = getc(); + if(c >= '0' && c <= '7') { + l = c - '0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + return l; + } + } + peekc = c; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return 0x07; + case 'v': return 0x0b; + case 'z': return 0x00; + } + return c; +} + +void +pinit(char *f) +{ + int i; + Sym *s; + + lineno = 1; + newio(); + newfile(f, -1); + pc = 0; + peekc = IGN; + sym = 1; + for(i=0; i<NSYM; i++) { + h[i].type = 0; + h[i].sym = S; + } + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + s->macro = 0; +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0]; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++; +} + +void +yyerror(char *a, ...) +{ + char buf[200]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(a, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + prfile(lineno); + va_start(arg, a); + doprint(buf, buf+sizeof(buf), a, arg); + va_end(arg); + print("%s\n", buf); + nerrors++; + if(nerrors > 10) { + print("too many errors\n"); + errorexit(); + } +} + +void +prfile(long l) +{ + int i, n; + Hist a[HISTSZ], *h; + long d; + + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset == 0) { + if(n >= 0 && n < HISTSZ) + a[n] = *h; + n++; + continue; + } + if(n > 0 && n < HISTSZ) + if(a[n-1].offset == 0) { + a[n] = *h; + n++; + } else + a[n-1] = *h; + continue; + } + n--; + if(n >= 0 && n < HISTSZ) { + d = h->line - a[n].line; + for(i=0; i<n; i++) + a[i].line += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + for(i=0; i<n; i++) + print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1)); +} + +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); +} diff --git a/utils/c2l/mac.c b/utils/c2l/mac.c new file mode 100644 index 00000000..7ec6e393 --- /dev/null +++ b/utils/c2l/mac.c @@ -0,0 +1,3 @@ +#include "cc.h" + +#include "macbody" diff --git a/utils/c2l/macbody b/utils/c2l/macbody new file mode 100644 index 00000000..aacb1e6f --- /dev/null +++ b/utils/c2l/macbody @@ -0,0 +1,773 @@ + +long +getnsn(void) +{ + long n; + int c; + + c = getnsc(); + if(c < '0' || c > '9') + return -1; + n = 0; + while(c >= '0' && c <= '9') { + n = n*10 + c-'0'; + c = getc(); + } + unget(c); + return n; +} + +Sym* +getsym(void) +{ + int c; + char *cp; + + c = getnsc(); + if(!isalpha(c) && c != '_') { + unget(c); + return S; + } + for(cp = symb;;) { + if(cp <= symb+NSYMB-4) + *cp++ = c; + c = getc(); + if(isalnum(c) || c == '_') + continue; + unget(c); + break; + } + *cp = 0; + if(cp > symb+NSYMB-4) + yyerror("symbol too large: %s", symb); + return lookup(); +} + +int +getcom(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c != '/') + break; + c = getc(); + if(c == '/') { + while(c != '\n') + c = getc(); + break; + } + if(c != '*') + break; + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment across newline"); + break; + } + c = getc(); + } + if(c == '\n') + break; + } + return c; +} + +void +dodefine(char *cp) +{ + Sym *s; + char *p; + long l; + + strcpy(symb, cp); + p = strchr(symb, '='); + if(p) { + *p++ = 0; + s = lookup(); + l = strlen(p) + 2; /* +1 null, +1 nargs */ + while(l & 3) + l++; + while(nhunk < l) + gethunk(); + *hunk = 0; + strcpy(hunk+1, p); + s->macro = hunk; + hunk += l; + nhunk -= l; + } else { + s = lookup(); + s->macro = "\0001"; /* \000 is nargs */ + } + if(0) + print("#define (-D) %s %s\n", s->name, s->macro+1); +} + +struct +{ + char *macname; + void (*macf)(void); +} mactab[] = +{ + "ifdef", 0, /* macif(0) */ + "ifndef", 0, /* macif(1) */ + "else", 0, /* macif(2) */ + + "line", maclin, + "define", macdef, + "include", macinc, + "undef", macund, + + "pragma", macprag, + "endif", macend, + 0 +}; + +void +domacro(void) +{ + int i; + Sym *s; + + s = getsym(); + if(s == S) + s = slookup("endif"); + for(i=0; mactab[i].macname; i++) + if(strcmp(s->name, mactab[i].macname) == 0) { + if(mactab[i].macf) + (*mactab[i].macf)(); + else + macif(i); + return; + } + yyerror("unknown #: %s", s->name); + macend(); +} + +void +macund(void) +{ + Sym *s; + + s = getsym(); + macend(); + if(s == S) { + yyerror("syntax in #undef"); + return; + } + s->macro = 0; +} + +#define NARG 25 +void +macdef(void) +{ + Sym *s, *a; + char *args[NARG], *np, *base; + int n, i, c, len; + + s = getsym(); + if(s == S) + goto bad; + if(s->macro) + yyerror("macro redefined: %s", s->name); + c = getc(); + n = -1; + if(c == '(') { + n++; + c = getnsc(); + if(c != ')') { + unget(c); + for(;;) { + a = getsym(); + if(a == S) + goto bad; + if(n >= NARG) { + yyerror("too many arguments in #define: %s", s->name); + goto bad; + } + args[n++] = a->name; + c = getnsc(); + if(c == ')') + break; + if(c != ',') + goto bad; + } + } + c = getc(); + } + if(isspace(c)) + if(c != '\n') + c = getnsc(); + base = hunk; + len = 1; + for(;;) { + if(isalpha(c) || c == '_') { + np = symb; + *np++ = c; + c = getc(); + while(isalnum(c) || c == '_') { + *np++ = c; + c = getc(); + } + *np = 0; + for(i=0; i<n; i++) + if(strcmp(symb, args[i]) == 0) + break; + if(i >= n) { + i = strlen(symb); + base = allocn(base, len, i); + memcpy(base+len, symb, i); + len += i; + continue; + } + base = allocn(base, len, 2); + base[len++] = '#'; + base[len++] = 'a' + i; + continue; + } + if(c == '/') { + c = getc(); + if(c != '*') { + base = allocn(base, len, 1); + base[len++] = '/'; + continue; + } + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment and newline in define: %s", s->name); + break; + } + c = getc(); + } + continue; + } + if(c == '\\') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + else if(c == '\r') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + } + base = allocn(base, len, 1); + base[len++] = '\\'; + continue; + } + if(c == '\n') + break; + if(c == '#') + if(n > 0) { + base = allocn(base, len, 1); + base[len++] = c; + } + base = allocn(base, len, 1); + base[len++] = c; + c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)); + if(c == '\n') + lineno++; + if(c == -1) { + yyerror("eof in a macro: %s", s->name); + break; + } + } + do { + base = allocn(base, len, 1); + base[len++] = 0; + } while(len & 3); + + *base = n+1; + s->macro = base; + if(0) + print("#define %s %s\n", s->name, s->macro+1); + if(n == -1 && iscon(base+1)) + doasenum(s); + return; + +bad: + if(s == S) + yyerror("syntax in #define"); + else + yyerror("syntax in #define: %s", s->name); + macend(); +} + +void +macexpand(Sym *s, char *b) +{ + char buf[2000]; + int n, l, c, nargs; + char *arg[NARG], *cp, *ob, *ecp; + + ob = b; + USED(ob); + nargs = *s->macro - 1; + if(nargs < 0) { + strcpy(b, s->macro+1); + if(0) + print("#expand %s %s\n", s->name, ob); + return; + } + c = getnsc(); + if(c != '(') + goto bad; + n = 0; + c = getc(); + if(c != ')') { + unget(c); + l = 0; + cp = buf; + ecp = cp + sizeof(buf)-4; + arg[n++] = cp; + for(;;) { + if(cp >= ecp) + goto toobig; + c = getc(); + if(c == '"') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '"') + break; + } + if(c == '\'') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '\'') + break; + } + if(l == 0) { + if(c == ',') { + *cp++ = 0; + arg[n++] = cp; + if(n > nargs) + break; + continue; + } + if(c == ')') + break; + } + if(c == '\n') + c = ' '; + *cp++ = c; + if(c == '(') + l++; + if(c == ')') + l--; + } + *cp = 0; + } + if(n != nargs) { + yyerror("argument mismatch expanding: %s", s->name); + *b = 0; + return; + } + cp = s->macro+1; + for(;;) { + c = *cp++; + if(c != '#') { + *b++ = c; + if(c == 0) + break; + continue; + } + c = *cp++; + if(c == 0) + goto bad; + if(c == '#') { + *b++ = c; + continue; + } + c -= 'a'; + if(c < 0 || c >= n) + continue; + strcpy(b, arg[c]); + b += strlen(arg[c]); + } + *b = 0; + if(0) + print("#expand %s %s\n", s->name, ob); + return; + +bad: + yyerror("syntax in macro expansion: %s", s->name); + *b = 0; + return; + +toobig: + yyerror("too much text in macro expansion: %s", s->name); + *b = 0; +} + +void +macinc(void) +{ + int c0, c, i, f; + char str[STRINGSZ], *hp; + + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = str;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + + c = getcom(); + if(c != '\n') + goto bad; + + f = -1; + for(i=0; i<ninclude; i++) { + if(i == 0 && c0 == '>') + continue; + strcpy(symb, include[i]); + strcat(symb, "/"); + if(strcmp(symb, "./") == 0) + symb[0] = 0; + strcat(symb, str); + f = open(symb, 0); + if(f >= 0) + break; + } + if(f < 0) + strcpy(symb, str); + c = strlen(symb) + 1; + while(c & 3) + c++; + while(nhunk < c) + gethunk(); + hp = hunk; + memcpy(hunk, symb, c); + nhunk -= c; + hunk += c; + newio(); + pushio(); + newfile(hp, f); + return; + +bad: + unget(c); + yyerror("syntax in #include"); + macend(); +} + +void +maclin(void) +{ + char *cp; + int c; + long n; + + n = getnsn(); + c = getc(); + if(n < 0) + goto bad; + + for(;;) { + if(c == ' ' || c == '\t') { + c = getc(); + continue; + } + if(c == '"') + break; + if(c == '\n') { + strcpy(symb, "<noname>"); + goto nn; + } + goto bad; + } + cp = symb; + for(;;) { + c = getc(); + if(c == '"') + break; + *cp++ = c; + } + *cp = 0; + c = getcom(); + if(c != '\n') + goto bad; + +nn: + c = strlen(symb) + 1; + while(c & 3) + c++; + while(nhunk < c) + gethunk(); + cp = hunk; + memcpy(hunk, symb, c); + nhunk -= c; + hunk += c; + + linehist(cp, n); + return; + +bad: + unget(c); + yyerror("syntax in #line"); + macend(); +} + +void +macif(int f) +{ + int c, l, bol; + Sym *s; + + if(f == 2) + goto skip; + s = getsym(); + if(s == S) + goto bad; + if(getcom() != '\n') + goto bad; + if(s->macro == 0 && s->type != T && s->type->etype == TENUM){ + if(!f) + return; + } + else if((s->macro != 0) ^ f) + return; + +skip: + bol = 1; + l = 0; + for(;;) { + c = getc(); + if(c != '#') { + if(!isspace(c)) + bol = 0; + if(c == '\n') + bol = 1; + continue; + } + if(!bol) + continue; + s = getsym(); + if(s == S) + continue; + if(strcmp(s->name, "endif") == 0) { + if(l) { + l--; + continue; + } + macend(); + return; + } + if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) { + l++; + continue; + } + if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) { + macend(); + return; + } + } + +bad: + yyerror("syntax in #if(n)def"); + macend(); +} + +void +macprag(void) +{ + Sym *s; + int c0, c; + char *hp; + Hist *h; + + s = getsym(); + + if(s && strcmp(s->name, "lib") == 0) + goto praglib; + if(s && strcmp(s->name, "hjdicks") == 0) { + praghjdicks(); + return; + } + if(s && strcmp(s->name, "fpround") == 0) { + pragfpround(); + return; + } + if(s && strcmp(s->name, "varargck") == 0) { + pragvararg(); + return; + } + + while(getnsc() != '\n') + ; + return; + +praglib: + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = symb;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + c = getcom(); + if(c != '\n') + goto bad; + + /* + * put pragma-line in as a funny history + */ + c = strlen(symb) + 1; + while(c & 3) + c++; + while(nhunk < c) + gethunk(); + hp = hunk; + memcpy(hunk, symb, c); + nhunk -= c; + hunk += c; + + h = alloc(sizeof(Hist)); + h->name = hp; + h->line = lineno; + h->offset = -1; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; + return; + +bad: + unget(c); + yyerror("syntax in #pragma lib"); + macend(); +} + +void +macend(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c < 0 || c == '\n') + return; + } +} + +void +linehist(char *f, int offset) +{ + Hist *h; + + /* + * overwrite the last #line directive if + * no alloc has happened since the last one + */ + if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0) + if(f && ehist->name && strcmp(f, ehist->name) == 0) { + ehist->line = lineno; + ehist->offset = offset; + return; + } + + if(0) + if(f) { + if(offset) + print("%4ld: %s (#line %d)\n", lineno, f, offset); + else + print("%4ld: %s\n", lineno, f); + } else + print("%4ld: <pop>\n", lineno); + newflag = 0; + + h = alloc(sizeof(Hist)); + h->name = f; + h->line = lineno; + h->offset = offset; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(thunk >= 10L*NHUNK) + nh = 10L*NHUNK; + h = (char*)mysbrk(nh); + if(h == (char*)-1) { + yyerror("out of memory"); + errorexit(); + } + hunk = h; + nhunk = nh; + thunk += nh; +} diff --git a/utils/c2l/mkfile b/utils/c2l/mkfile new file mode 100644 index 00000000..219d36e1 --- /dev/null +++ b/utils/c2l/mkfile @@ -0,0 +1,38 @@ +<../../mkconfig + +TARG=c2l + +OFILES=\ + acid.$O\ + bits.$O\ + com.$O\ + com64.$O\ + $TARGMODEL.$O\ + dcl.$O\ + dpchk.$O\ + lex.$O\ + mac.$O\ + mpatof.$O\ + out.$O\ + scon.$O\ + sub.$O\ + y.tab.$O\ + c2l.$O\ + +HFILES= cc.h\ + y.tab.h\ + +YFILES= cc.y\ + +LIBS=math bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +mac.$O: macbody + +lex.$O: lex.c + $CC $CFLAGS '-DCPP="/bin/cpp"' lex.c diff --git a/utils/c2l/mpatof.c b/utils/c2l/mpatof.c new file mode 100644 index 00000000..d55ddab4 --- /dev/null +++ b/utils/c2l/mpatof.c @@ -0,0 +1,337 @@ +#include "cc.h" + +enum +{ + Mpscale = 29, /* safely smaller than bits in a long */ + Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */ + Mpbase = 1L<<Mpscale, +}; + +typedef +struct +{ + long a[Mpprec]; + char ovf; +} Mp; + +int mpatof(char*, double*); +int mpatov(char *s, vlong *v); +void mpint(Mp*, int); +void mppow(Mp*, int, int); +void mpmul(Mp*, int); +void mpadd(Mp*, Mp*); +int mptof(Mp*, double*); + +/* + * convert a string, s, to floating in *d + * return conversion overflow. + * required syntax is [+-]d*[.]d*[e[+-]d*] + */ +int +mpatof(char *s, double *d) +{ + Mp a, b; + int dp, c, f, ef, ex, zer; + double d1, d2; + + dp = 0; /* digits after decimal point */ + f = 0; /* sign */ + ex = 0; /* exponent */ + zer = 1; /* zero */ + memset(&a, 0, sizeof(a)); + for(;;) { + switch(c = *s++) { + default: + goto bad; + case '-': + f = 1; + case ' ': + case '\t': + case '+': + continue; + case '.': + dp = 1; + continue; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + zer = 0; + case '0': + mpint(&b, c-'0'); + mpmul(&a, 10); + mpadd(&a, &b); + if(dp) + dp++; + continue; + case 'E': + case 'e': + ex = 0; + ef = 0; + for(;;) { + c = *s++; + if(c == '+' || c == ' ' || c == '\t') + continue; + if(c == '-') { + ef = 1; + continue; + } + if(c >= '0' && c <= '9') { + ex = ex*10 + (c-'0'); + continue; + } + break; + } + if(ef) + ex = -ex; + case 0: + break; + } + break; + } + if(a.ovf) + goto bad; + if(zer) { + *d = 0; + return 0; + } + if(dp) + dp--; + dp -= ex; + if(dp > 0) { + /* + * must divide by 10**dp + */ + if(mptof(&a, &d1)) + goto bad; + + /* + * trial exponent of 8**dp + * 8 (being between 5 and 10) + * should pick up all underflows + * in the division of 5**dp. + */ + d2 = frexp(d1, &ex); + d2 = ldexp(d2, ex-3*dp); + if(d2 == 0) + goto bad; + + /* + * decompose each 10 into 5*2. + * create 5**dp in fixed point + * and then play with the exponent + * for the remaining 2**dp. + * note that 5**dp will overflow + * with as few as 134 input digits. + */ + mpint(&a, 1); + mppow(&a, 5, dp); + if(mptof(&a, &d2)) + goto bad; + d1 = frexp(d1/d2, &ex); + d1 = ldexp(d1, ex-dp); + if(d1 == 0) + goto bad; + } else { + /* + * must multiply by 10**|dp| -- + * just do it in fixed point. + */ + mppow(&a, 10, -dp); + if(mptof(&a, &d1)) + goto bad; + } + if(f) + d1 = -d1; + *d = d1; + return 0; + +bad: + return 1; +} + +/* + * convert a to floating in *d + * return conversion overflow + */ +int +mptof(Mp *a, double *d) +{ + double f, g; + long x, *a1; + int i; + + if(a->ovf) + return 1; + a1 = a->a; + f = ldexp(*a1++, 0); + for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale) + if(x = *a1++) { + g = ldexp(x, i); + /* + * NOTE: the test (g==0) is plan9 + * specific. ansi compliant overflow + * is signaled by HUGE and errno==ERANGE. + * change this for your particular ldexp. + */ + if(g == 0) + return 1; + f += g; /* this could bomb! */ + } + *d = f; + return 0; +} + +/* + * return a += b + */ +void +mpadd(Mp *a, Mp *b) +{ + int i, c; + long x, *a1, *b1; + + if(b->ovf) + a->ovf = 1; + if(a->ovf) + return; + c = 0; + a1 = a->a; + b1 = b->a; + for(i=0; i<Mpprec; i++) { + x = *a1 + *b1++ + c; + c = 0; + if(x >= Mpbase) { + x -= Mpbase; + c = 1; + } + *a1++ = x; + } + a->ovf = c; +} + +/* + * return a = c + */ +void +mpint(Mp *a, int c) +{ + + memset(a, 0, sizeof(*a)); + a->a[0] = c; +} + +/* + * return a *= c + */ +void +mpmul(Mp *a, int c) +{ + Mp p; + int b; + + memmove(&p, a, sizeof(p)); + if(!(c & 1)) + memset(a, 0, sizeof(*a)); + c &= ~1; + for(b=2; c; b<<=1) { + mpadd(&p, &p); + if(c & b) { + mpadd(a, &p); + c &= ~b; + } + } +} + +/* + * return a *= b**e + */ +void +mppow(Mp *a, int b, int e) +{ + int b1; + + b1 = b*b; + b1 = b1*b1; + while(e >= 4) { + mpmul(a, b1); + e -= 4; + if(a->ovf) + return; + } + while(e > 0) { + mpmul(a, b); + e--; + } +} + +/* + * convert a string, s, to vlong in *v + * return conversion overflow. + * required syntax is [0[x]]d* + */ +int +mpatov(char *s, vlong *v) +{ + vlong n, nn; + int c; + n = 0; + c = *s; + if(c == '0') + goto oct; + while(c = *s++) { + if(c >= '0' && c <= '9') + nn = n*10 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; +oct: + s++; + c = *s; + if(c == 'x' || c == 'X') + goto hex; + while(c = *s++) { + if(c >= '0' || c <= '7') + nn = n*8 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; +hex: + s++; + while(c = *s++) { + if(c >= '0' && c <= '9') + c += 0-'0'; + else + if(c >= 'a' && c <= 'f') + c += 10-'a'; + else + if(c >= 'A' && c <= 'F') + c += 10-'A'; + else + goto bad; + nn = n*16 + c; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } +out: + *v = n; + return 0; + +bad: + *v = ~0; + return 1; +} diff --git a/utils/c2l/out.c b/utils/c2l/out.c new file mode 100644 index 00000000..ab81a995 --- /dev/null +++ b/utils/c2l/out.c @@ -0,0 +1,825 @@ +#include "cc.h" + +#define INCREMENT 8 +#define DEVNULL "/dev/null" + +static int indent = 0; +static int fd = -1; +static int nf = 0; +static int mylineno = 1; + +typedef struct Com{ + int lno; + char *s; + Node *n; + int tba; + struct Com *nxt; +} Com; + +Com *hdc, *curc; + +typedef struct File{ + char *s; + char *f; + char *m; + int b; + int loc; + int in; + int tg; + Node *n; + Com *c; + struct File *nxt; +} File; + +typedef struct Create{ + char *s; + struct Create *nxt; +} Create; + +File *fs; +Create *cs; + +static void genmsg(void); +static int isloc(void); + +static void +addcreate(char *s) +{ + Create *c; + + if(strcmp(s, DEVNULL) == 0) + return; + c = (Create*)malloc(sizeof(Create)); + c->s = malloc(strlen(s)+1); + strcpy(c->s, s); + c->nxt = cs; + cs = c; +} + +static int +created(char *s) +{ + Create *c; + + for(c = cs; c != nil; c = c->nxt) + if(strcmp(s, c->s) == 0) + return 1; + return 0; +} + +int +dolog(void) +{ + if(justcode) + return 0; + return domod || !doinc || inmain; +} + +static char* +curf(void) +{ + File *f; + + for(f = fs; f != nil; f = f->nxt) + if(f->f != nil) + return f->s; + return nil; +} + +static char* +curm(void) +{ + File *f; + + for(f = fs; f != nil; f = f->nxt) + if(f->f != nil) + return f->m; + return nil; +} + +void +setmod(Sym *s) +{ + if(domod && s->mod == nil && ism() && !(doloc && !isloc())) + s->mod = curm(); +} + +char * +outmod(char *buf, int up) +{ + char *s, *t; + + s = curf(); + if(s == nil) + return ""; + t = strchr(s, '.'); + if(t != nil) + *t = '\0'; + strcpy(buf, s); + if(t != nil) + *t = '.'; + if(up == 1 || (up < 0 && ism())) + buf[0] = toupper(buf[0]); + return buf; +} + +int +ism(void) +{ + return !isb(); +} + +int +isb(void) +{ + File *f; + + for(f = fs; f != nil; f = f->nxt) + if(f->f != nil) + return f->b; + return 0; +} + +static int +isloc(void) +{ + File *f; + + for(f = fs; f != nil; f = f->nxt) + if(f->f != nil) + return f->loc; + return 0; +} + +static File* +pushf(void) +{ + static File zfile; + File *f; + + f = (File*)malloc(sizeof(File)); + *f = zfile; + f->s = nil; + f->f = nil; + f->m = nil; + f->nxt = fs; + fs = f; + return f; +} + +static void +popf(void) +{ + File *f; + + f = fs; + fs = fs->nxt; + if(f->s != nil) + free(f->s); + free(f); +} + +static void +setf(File *f, char *s) +{ + int n; + char *t; + + if(s != nil){ + t = strrchr(s, '/'); + f->loc = t == nil; + if(t != nil) + s = t+1; + n = strlen(s); + f->s = malloc(n+1); + strcpy(f->s, s); + s = f->s; + if(n > 2 && s[n-2] == '.'){ + f->m = malloc(n-1); + strncpy(f->m, s, n-2); + if(s[n-1] == 'h') + s[n-1] = 'm'; + else if(s[n-1] == 'c'){ + s[n-1] = 'b'; + f->b = 1; + } + else + s = nil; + } + else + s = nil; + if(s == nil){ + free(f->s); + if(f->m != nil) + free(f->m); + f->s = nil; + f->m = nil; + } + } + f->f = f->s; + if(f->s != nil && nf > 0){ + if(doinc || doloc && !f->loc) + f->f = DEVNULL; + else if(!domod) + f->f = nil; + } +} + +void +outpush0(char *s, Node *n) +{ + File *f; + + f = pushf(); + setf(f, s); + if(f->f != nil){ + nf++; + f->tg = taggen; + taggen = 0; + f->n = n; + f->c = hdc; + hdc = nil; + } +} + +void +outpop0(int lno) +{ + File *f; + + USED(lno); + f = fs; + if(f->f != nil){ + nf--; + taggen = f->tg; + f->n->left = (void*)hdc; + hdc = f->c; + } + popf(); +} + +void +outpush2(char *s, Node *n) +{ + File *f; + + f = pushf(); + setf(f, s); + if(f->f != nil){ + if(fd >= 0){ + newsec(0); + close(fd); + close(1); + fd = -1; + } + if(created(f->f)) + f->f = DEVNULL; /* don't overwrite original if included again */ + fd = create(f->f, OWRITE, 0664); + if(fd >= 0) + addcreate(f->f); + mydup(fd, 1); + nf++; + f->tg = taggen; + taggen = 0; + f->c = hdc; + if(n != Z) + hdc = (void*)n->left; + else + hdc = nil; + f->in = indent; + indent = 0; + genmsg(); + pgen(f->b); + } +} + +void +outpop2(int lno) +{ + File *f, *g; + + f = fs; + if(f->f != nil){ + if(fd >= 0){ + newsec(0); + output(lno, 1); + epgen(f->b); + close(fd); + close(1); + fd = -1; + } + for(g = fs->nxt; g != nil; g = g->nxt){ + if(g->f != nil){ + fd = open(g->f, OWRITE); + seek(fd, 0, 2); + mydup(fd, 1); + break; + } + } + nf--; + taggen = f->tg; + hdc = f->c; + indent = f->in; + } + popf(); +} + +static void +xprint(char *s) +{ + if(nerrors == 0) + print(s); +} + +static int tot = 0; + +static void +doindent(int d) +{ + int i; + + for(i = 0; i < d/8; i++) + xprint("\t"); + for(i = 0; i < d%8; i++) + xprint(" "); +} + +void +incind(void) +{ + indent += INCREMENT; +} + +void +decind(void) +{ + indent -= INCREMENT; +} + +int +zeroind(void) +{ + int i = indent; + + indent = 0; + return i; +} + +void +restoreind(int i) +{ + indent = i; +} + +void +newline0(void) +{ + xprint("\n"); + tot = 0; + mylineno++; +} + +void +newline(void) +{ + if(!outcom(1)){ + xprint("\n"); + mylineno++; + } + tot = 0; +} + +static void +lprint(char *s) +{ + if(tot == 0) { + doindent(indent); + tot += indent; + } + xprint(s); + tot += strlen(s); +} + +void +prline(char *s) +{ + xprint(s); + xprint("\n"); + mylineno++; +} + +void +prdelim(char *s) +{ + if(*s == '%'){ + if(*++s == '=') + lprint("%%="); + else + lprint("%%"); + return; + } + lprint(s); +} + +void +prkeywd(char *kw) +{ + lprint(kw); +} + +void +prid(char *s) +{ + lprint(s); +} + +static void +priddol(char *s, int dol) +{ + char *t; + char buf[128]; + + if(dol){ + t = strchr(s, '$'); + if(t != nil) + *t = '_'; + lprint(s); + if(t != nil){ + strcpy(buf, s); + while(slookup(buf)->type != T){ + strcat(buf, "x"); + lprint("x"); + } + *t = '$'; + } + } + else + lprint(s); +} + +void +prsym(Sym *s, int mod) +{ + char buf[128]; + int c; + + if(mod && s->mod && strcmp(s->mod, curm()) != 0 && (!s->limbo || s->class == CEXTERN)){ + c = isconsym(s); + if(c >= 0){ + if(c){ + s->mod[0] = toupper(s->mod[0]); + lprint(s->mod); + s->mod[0] = tolower(s->mod[0]); + } + else + lprint(s->mod); + lprint("->"); + usemod(s, !c); + } + } + if(s->lname) + prid(s->lname); + else{ + priddol(s->name, s->class == CSTATIC); + if(s->lkw){ + strcpy(buf, s->name); + for(;;){ + strcat(buf, "x"); + lprint("x"); + s = slookup(buf); + if(s->type == T) + break; + } + } + } +} + +int +arrow(Sym *s) +{ + if(s->mod && strcmp(s->mod, curm()) != 0) + return isconsym(s) >= 0; + return 0; +} + +void +prsym0(Sym *s) +{ + int c; + + if(s->mod && strcmp(s->mod, curm()) != 0){ + c = isconsym(s); + if(c >= 0) + usemod(s, !c); + } +} + +static int +isprintable(int c) +{ + if(c >= 0x20 && c <= 0x7e) + return 1; + return c == '\0' || c == '\n' || c == '\t' || c == '\b' || c == '\r' || c == '\f' || c == '\a' || c == '\v'; +} + +static int +hex(int c) +{ + if(c < 10) + return c+'0'; + return c+'a'-10; +} + +void +prchar0(vlong x, int quote) +{ + int c, e, i = 0; + static char buf[16]; + + if(quote) + buf[i++] = '\''; + c = x; + if(c < 0 || c > 255 || !isprintable(c)){ + if(c&0xffff0000) + diag(Z, "character too big"); + buf[i++] = '\\'; + buf[i++] = 'u'; + buf[i++] = hex((c>>12)&0xf); + buf[i++] = hex((c>>8)&0xf); + buf[i++] = hex((c>>4)&0xf); + buf[i++] = hex((c>>0)&0xf); + } + else{ + e = 0; + switch(c){ + case '\n': e = 'n'; break; + case '\t': e = 't'; break; + case '\b': e = 'b'; break; + case '\r': e = 'r'; break; + case '\f': e = 'f'; break; + case '\a': e = 'a'; break; + case '\v': e = 'v'; break; + case '"': if(!quote) e = '"'; break; + case '\'': if(quote) e = '\''; break; + case '\\': e = '\\'; break; + case '%': buf[i++] = c; break; + case 0: e = '0'; if(strings) prcom("nul byte in string ?", Z); break; + } + if(e != 0){ + buf[i++] = '\\'; + c = e; + } + buf[i++] = c; + } + if(quote) + buf[i++] = '\''; + buf[i] = '\0'; + lprint(buf); +} + +void +prchar(vlong x) +{ + prchar0(x, 1); +} + +void +prstr(char *s) +{ + uchar *t; + Rune r; + + t = (uchar*)s; + lprint("\""); + while(*t != 0){ + if(*t & 0x80){ + t += chartorune(&r, (char*)t); + prchar0(r, 0); + } + else + prchar0(*t++, 0); + } + lprint("\""); +} + +void +prlstr(ushort *s) +{ + lprint("\""); + while(*s != 0) + prchar0(*s++, 0); + lprint("\""); +} + +void +prreal(double x, char *s, int b) +{ + static char buf[128]; + + if(b != KDEC) + diag(Z, "not base 10 in prreal"); + if(s != nil) + lprint(s); + else{ + sprint(buf, "%f", x); + lprint(buf); + } +} + +void +prnum(vlong x, int b, Type *t) +{ + static char buf[128]; + int w; + vlong m; + + w = 4; + if(t != T) + w = ewidth[t->etype]; + m = MASK(8*w); + if(b == KHEX) + sprint(buf, "16r%llux", x&m); + else if(b == KOCT) + sprint(buf, "8r%lluo", x&m); + else + sprint(buf, "%lld", x); + lprint(buf); +} + +char *cb; +int cn, csz; + +static void +outcom0(Com *c) +{ + Node *n; + char *s, *t, *u; + + s = c->s; + n = c->n; + if(comm && c->tba){ + t = strchr(s, '\n'); + *t = '\0'; + fprint(2, "%s:%d: %s", curf(), mylineno, s); + *t = '\n'; + if(n != Z){ + mydup(2, 1); + expgen(n); + mydup(fd, 1); + } + fprint(2, "\n"); + } + while(*s != '\0'){ + t = strchr(s, '\n'); + *t = '\0'; + if(tot != 0) + prdelim("\t"); + prdelim("# "); + while((u = strchr(s, '%')) != nil){ + /* do not let print interpret % ! */ + *u = 0; + lprint(s); + *u = '%'; + lprint("%%"); + s = u+1; + } + lprint(s); + if(n == Z) + newline0(); + *t = '\n'; + s = t+1; + } + if(n != Z){ + expgen(n); + newline0(); + } +} + +int +outcom(int f) +{ + int lno, nl; + Com *c; + + nl = 0; + lno = pline+f; + c = hdc; + while(c != nil && c->lno < lno){ +/* print("outcom: %d < %d (f=%d)\n", c->lno, lno, f); */ + nl = 1; + outcom0(c); + hdc = hdc->nxt; + free(c->s); + free(c); + c = hdc; + } + return nl; +} + +void +startcom(int lno) +{ + Com *c, **ac; + + c = (Com *)malloc(sizeof(Com)); + c->lno = lno; + c->s = nil; + c->n = Z; + c->tba = 0; + c->nxt = nil; + for(ac = &hdc; *ac != nil && (*ac)->lno <= lno; ac = &(*ac)->nxt) + ; + c->nxt = *ac; + curc = *ac = c; +} + +void +addcom(int rr) +{ + int i, nb; + char *ncb; + char s[UTFmax]; + Rune r[1]; + + if(rr >= Runeself){ + r[0] = rr; + nb = runetochar(s, r); + } + else{ + nb = 1; + s[0] = rr; + } + if(cn+nb-1 >= csz){ + csz += 32; + ncb = malloc(csz); + memcpy(ncb, cb, cn); + free(cb); + cb = ncb; + } + for(i = 0; i < nb; i++) + cb[cn++] = s[i]; +} + +void +endcom(void) +{ + char *s; + + addcom('\n'); + addcom('\0'); + s = malloc(strlen(cb)+1); + strcpy(s, cb); + curc->s = s; +/* print("com %d %s\n", curc->lno, s); */ + cn = 0; +} + +void +linit() +{ + csz = 32; + cb = malloc(csz); + sysinit(); +} + +static void +genmsg(void) +{ + prline("#"); + prline("# initially generated by c2l"); + prline("#"); + prline(""); +} + +void +prcom(char *s, Node *n) +{ + Com *c; + + startcom(pline); + c = curc; + sprint(cb, "TBA %s", s); + cn = strlen(cb); + c->n = n; + c->tba = 1; + endcom(); +} + +void +output(long lno, int com) +{ +/* print("output(%ld)\n", lno); */ + pline = lno; + if(com) + outcom(0); +} + +int +exists(char *f) +{ + int fd; + + fd = open(f, OREAD); + close(fd); + return fd >= 0; +} diff --git a/utils/c2l/scon.c b/utils/c2l/scon.c new file mode 100644 index 00000000..89f87332 --- /dev/null +++ b/utils/c2l/scon.c @@ -0,0 +1,250 @@ +#include "cc.h" + +void +evconst(Node *n) +{ + Node *l, *r; + int et, isf; + vlong v; + double d; + + if(n == Z || n->type == T) + return; + + et = n->type->etype; + isf = typefd[et]; + + l = n->left; + r = n->right; + + d = 0; + v = 0; + + switch(n->op) { + default: + return; + + case OCAST: + if(et == TVOID) + return; + et = l->type->etype; + if(isf) { + if(typefd[et]) + d = l->fconst; + else + d = l->vconst; + } else { + if(typefd[et]) + v = l->fconst; + else + v = convvtox(l->vconst, n->type->etype); + } + break; + + case OCONST: + break; + + case OADD: + if(isf) + d = l->fconst + r->fconst; + else { + v = l->vconst + r->vconst; + } + break; + + case OSUB: + if(isf) + d = l->fconst - r->fconst; + else + v = l->vconst - r->vconst; + break; + + case OMUL: + if(isf) + d = l->fconst * r->fconst; + else { + v = l->vconst * r->vconst; + } + break; + + case OLMUL: + v = (uvlong)l->vconst * (uvlong)r->vconst; + break; + + + case ODIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + if(isf) + d = l->fconst / r->fconst; + else + v = l->vconst / r->vconst; + break; + + case OLDIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + v = (uvlong)l->vconst / (uvlong)r->vconst; + break; + + case OMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = l->vconst % r->vconst; + break; + + case OLMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = (uvlong)l->vconst % (uvlong)r->vconst; + break; + + case OAND: + v = l->vconst & r->vconst; + break; + + case OOR: + v = l->vconst | r->vconst; + break; + + case OXOR: + v = l->vconst ^ r->vconst; + break; + + case OLSHR: + v = (uvlong)l->vconst >> r->vconst; + break; + + case OASHR: + v = l->vconst >> r->vconst; + break; + + case OASHL: + v = l->vconst << r->vconst; + break; + + case OLO: + v = (uvlong)l->vconst < (uvlong)r->vconst; + break; + + case OLT: + if(typefd[l->type->etype]) + v = l->fconst < r->fconst; + else + v = l->vconst < r->vconst; + break; + + case OHI: + v = (uvlong)l->vconst > (uvlong)r->vconst; + break; + + case OGT: + if(typefd[l->type->etype]) + v = l->fconst > r->fconst; + else + v = l->vconst > r->vconst; + break; + + case OLS: + v = (uvlong)l->vconst <= (uvlong)r->vconst; + break; + + case OLE: + if(typefd[l->type->etype]) + v = l->fconst <= r->fconst; + else + v = l->vconst <= r->vconst; + break; + + case OHS: + v = (uvlong)l->vconst >= (uvlong)r->vconst; + break; + + case OGE: + if(typefd[l->type->etype]) + v = l->fconst >= r->fconst; + else + v = l->vconst >= r->vconst; + break; + + case OEQ: + if(typefd[l->type->etype]) + v = l->fconst == r->fconst; + else + v = l->vconst == r->vconst; + break; + + case ONE: + if(typefd[l->type->etype]) + v = l->fconst != r->fconst; + else + v = l->vconst != r->vconst; + break; + + case ONOT: + if(typefd[l->type->etype]) + v = !l->fconst; + else + v = !l->vconst; + break; + + case OANDAND: + if(typefd[l->type->etype]) + v = l->fconst && r->fconst; + else + v = l->vconst && r->vconst; + break; + + case OOROR: + if(typefd[l->type->etype]) + v = l->fconst || r->fconst; + else + v = l->vconst || r->vconst; + break; + + case OPOS: + if(isf) + d = l->fconst; + else + v = l->vconst; + break; + + case ONEG: + if(isf) + d = -l->fconst; + else + v = -l->vconst; + break; + + case OCOM: + if(typefd[l->type->etype]) + v = 0; /* ~l->fconst */ + else + v = ~l->vconst; + break; + } + + n->left = ncopy(n); + n->op = OCONST; + /* n->left = Z; */ + n->right = Z; + if(isf) { + n->fconst = d; + } else { + n->vconst = convvtox(v, n->type->etype); + } +} + +void +acom(Node *n) +{ + USED(n); +} diff --git a/utils/c2l/sub.c b/utils/c2l/sub.c new file mode 100644 index 00000000..a696cb0f --- /dev/null +++ b/utils/c2l/sub.c @@ -0,0 +1,1694 @@ +#include "cc.h" + +Node* +new(int t, Node *l, Node *r) +{ + static Node znode; + Node *n; + + n = alloc(sizeof(*n)); + *n = znode; + n->op = t; + n->left = l; + n->right = r; + n->lineno = lineno; + n->kind = KNIL; + newflag = 1; + return n; +} + +Node* +new1(int o, Node *l, Node *r) +{ + Node *n; + + n = new(o, l, r); + if(l != Z) + n->lineno = l->lineno; + else if(r != Z) + n->lineno = r->lineno; + else + n->lineno = nearln; + return n; +} + +void +prtree(Node *n, char *s) +{ + + print(" == %s ==\n", s); + prtree1(n, 0, 0); + print("\n"); +} + +void +prtree1(Node *n, int d, int f) +{ + int i; + + if(f) + for(i=0; i<d; i++) + print(" "); + if(n == Z) { + print("Z\n"); + return; + } + if(n->op == OLIST) { + prtree1(n->left, d, 0); + prtree1(n->right, d, 1); + return; + } + d++; + print("%O", n->op); + i = 3; + switch(n->op) + { + case ONAME: + print(" \"%F\"", n); + i = 0; + break; + + case OINDREG: + i = 0; + break; + + case OREGISTER: + i = 0; + break; + + case OSTRING: + print(" \"%s\"", n->cstring); + i = 0; + break; + + case OLSTRING: + print(" \"%S\"", n->rstring); + i = 0; + break; + + case ODOT: + case OELEM: + print(" \"%F\"", n); + break; + + case OCONST: + if(typefd[n->type->etype]) + print(" \"%.8e\"", n->fconst); + else + print(" \"%lld\"", n->vconst); + i = 0; + break; + } + if(n->type != T) + print(" %T", n->type); + print("\n"); + if(i & 2) + prtree1(n->left, d, 1); + if(i & 1) + prtree1(n->right, d, 1); +} + +Type* +typ(int et, Type *d) +{ + static Type ztype; + Type *t; + + t = alloc(sizeof(*t)); + *t = ztype; + t->etype = et; + t->link = d; + t->down = T; + t->sym = S; + t->width = ewidth[et]; + t->nwidth = Z; + t->lineno = lineno; + return t; +} + +Type* +typ1(int et, Type *d) +{ + Type *t; + + t = typ(et, d); + t->lineno = nearln; + return t; +} + +Type* +garbt(Type *t, long b) +{ + Type *t1; + + if(b & BGARB) { + t1 = typ(TXXX, T); + *t1 = *t; + t1->garb = simpleg(b); + return t1; + } + return t; +} + +int +simpleg(long b) +{ + + b &= BGARB; + switch(b) { + case BCONSTNT: + return GCONSTNT; + case BVOLATILE: + return GVOLATILE; + case BVOLATILE|BCONSTNT: + return GCONSTNT|GVOLATILE; + } + return GXXX; +} + +int +simplec(long b) +{ + + b &= BCLASS; + switch(b) { + case 0: + case BREGISTER: + return CXXX; + case BAUTO: + case BAUTO|BREGISTER: + return CAUTO; + case BEXTERN: + return CEXTERN; + case BEXTERN|BREGISTER: + return CEXREG; + case BSTATIC: + return CSTATIC; + case BTYPEDEF: + return CTYPEDEF; + } + diag(Z, "illegal combination of classes %Q", b); + return CXXX; +} + +Type* +simplet(long b) +{ + + b &= ~BCLASS & ~BGARB; + switch(b) { + case BCHAR: + case BCHAR|BSIGNED: + return types[TCHAR]; + + case BCHAR|BUNSIGNED: + return types[TUCHAR]; + + case BSHORT: + case BSHORT|BINT: + case BSHORT|BSIGNED: + case BSHORT|BINT|BSIGNED: + return types[TSHORT]; + + case BUNSIGNED|BSHORT: + case BUNSIGNED|BSHORT|BINT: + return types[TUSHORT]; + + case 0: + case BINT: + case BINT|BSIGNED: + case BSIGNED: + return types[TINT]; + + case BUNSIGNED: + case BUNSIGNED|BINT: + return types[TUINT]; + + case BLONG: + case BLONG|BINT: + case BLONG|BSIGNED: + case BLONG|BINT|BSIGNED: + return types[TLONG]; + + case BUNSIGNED|BLONG: + case BUNSIGNED|BLONG|BINT: + return types[TULONG]; + + case BVLONG|BLONG: + case BVLONG|BLONG|BINT: + case BVLONG|BLONG|BSIGNED: + case BVLONG|BLONG|BINT|BSIGNED: + return types[TVLONG]; + + case BVLONG|BLONG|BUNSIGNED: + case BVLONG|BLONG|BINT|BUNSIGNED: + return types[TUVLONG]; + + case BFLOAT: + return types[TFLOAT]; + + case BDOUBLE: + case BDOUBLE|BLONG: + case BFLOAT|BLONG: + return types[TDOUBLE]; + + case BVOID: + return types[TVOID]; + } + + diag(Z, "illegal combination of types %Q", b); + return types[TINT]; +} + +int +stcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + int i; + ulong b; + + return 0; + i = 0; + if(t2 != T) + i = t2->etype; + b = 1L << i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ttab[i]) { + if(ttab == tasign) + if(b == BSTRUCT || b == BUNION) + if(!sametype(t1, t2)) + return 1; + if(n->op != OCAST) + if(b == BIND && i == TIND) + if(!sametype(t1, t2)) + return 1; + return 0; + } + return 1; +} + +int +tcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + + if(0 && stcompat(n, t1, t2, ttab)) { + if(t1 == T) + diag(n, "incompatible type: \"%T\" for op \"%O\"", + t2, n->op); + else + diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"", + t1, t2, n->op); + return 1; + } + return 0; +} + +void +makedot(Node *n, Type *t, long o) +{ + USED(n); + USED(o); + USED(t); + return; +} + +Type* +dotsearch(Sym *s, Type *t, Node *n) +{ + Type *t1, *xt; + + xt = T; + + /* + * look it up by name + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == s) { + if(xt != T) + goto ambig; + xt = t1; + } + if(xt != T) + return xt; + + /* + * look it up by type + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]) + if(sametype(s->type, t1)) { + if(xt != T) + goto ambig; + xt = t1; + } + if(xt != T) + return xt; + + /* + * look it up in unnamed substructures + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]) + if(dotsearch(s, t1->link, n) != T) { + if(xt != T) + goto ambig; + xt = t1; + } + return xt; + +ambig: + diag(n, "ambiguous structure element: %s", s->name); + return xt; +} + +long +dotoffset(Type *st, Type *lt, Node *n) +{ + Type *t; + Sym *g; + long o, o1; + + o = -1; + /* + * first try matching at the top level + * for matching tag names + */ + g = st->tag; + if(g != S) + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(g == t->tag) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * second try matching at the top level + * for similar types + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(sametype(st, t)) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * last try matching sub-levels + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(typesu[t->etype]) { + o1 = dotoffset(st, t, n); + if(o1 >= 0) { + if(o >= 0) + goto ambig; + o = o1 + t->offset; + } + } + return o; + +ambig: + diag(n, "ambiguous unnamed structure element"); + return o; +} + +/* + * look into tree for floating point constant expressions + */ +int +allfloat(Node *n, int flag) +{ + + if(n != Z) { + if(n->type->etype != TDOUBLE) + return 1; + switch(n->op) { + case OCONST: + if(flag) + n->type = types[TFLOAT]; + return 1; + case OADD: /* no need to get more exotic than this */ + case OSUB: + case OMUL: + case ODIV: + if(!allfloat(n->right, flag)) + break; + case OCAST: + if(!allfloat(n->left, flag)) + break; + if(flag) + n->type = types[TFLOAT]; + return 1; + } + } + return 0; +} + +void +constas(Node *n, Type *il, Type *ir) +{ + Type *l, *r; + + l = il; + r = ir; + + if(l == T) + return; + if(l->garb & GCONSTNT) { + warn(n, "assignment to a constant type (%T)", il); + return; + } + if(r == T) + return; + for(;;) { + if(l->etype != TIND || r->etype != TIND) + break; + l = l->link; + r = r->link; + if(l == T || r == T) + break; + if(r->garb & GCONSTNT) + if(!(l->garb & GCONSTNT)) { + warn(n, "assignment of a constant pointer type (%T)", ir); + break; + } + } +} + +void +typeext1(Type *st, Node *l) +{ + if(st->etype == TFLOAT && allfloat(l, 0)) + allfloat(l, 1); +} + +void +typeext(Type *st, Node *l) +{ + Type *lt; + + lt = l->type; + if(lt == T) + return; + if(st->etype == TIND && vconst(l) == 0) { + l->type = st; + l->vconst = 0; + return; + } + typeext1(st, l); +} + +/* + * a cast that generates no code + * (same size move) + */ +int +nocast(Type *t1, Type *t2) +{ + int i, b; + + if(t1->nbits) + return 0; + i = 0; + if(t2 != T) + i = t2->etype; + b = 1<<i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ncast[i]) + return 1; + return 0; +} + +/* + * a cast that has a noop semantic + * (small to large, convert) + */ +int +nilcast(Type *t1, Type *t2) +{ + int et1, et2; + + if(t1 == T) + return 0; + if(t1->nbits) + return 0; + if(t2 == T) + return 0; + et1 = t1->etype; + et2 = t2->etype; + if(et1 == et2) + return 1; + if(typefd[et1] && typefd[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + if(typechlp[et1] && typechlp[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + return 0; +} + +/* + * "the usual arithmetic conversions are performed" + */ +void +arith(Node *n, int f) +{ + Type *t1, *t2; + int i, j, k; + long w; + + t1 = n->left->type; + if(n->right == Z) + t2 = t1; + else + t2 = n->right->type; + i = TXXX; + if(t1 != T) + i = t1->etype; + j = TXXX; + if(t2 != T) + j = t2->etype; + k = tab[i][j]; + if(k == TIND) { + if(i == TIND) + n->type = t1; + else + if(j == TIND) + n->type = t2; + } else { + /* convert up to at least int */ + if(f == 1) + while(k < TINT) + k += 2; + n->type = types[k]; + } + if(n->op == OSUB) + if(i == TIND && j == TIND) { + w = n->right->type->link->width; + if(w < 1) + goto bad; + n->type = types[TLONG]; + return; + } + if(!sametype(n->type, n->left->type)) { + n->left = new1(OCAST, n->left, Z); + n->left->type = n->type; + } + if(n->right != Z) + if(!sametype(n->type, n->right->type)) { + n->right = new1(OCAST, n->right, Z); + n->right->type = n->type; + } + return; +bad: + diag(n, "pointer addition not fully declared: %T", n->type->link); +} + +int +side(Node *n) +{ + +loop: + if(n != Z) + switch(n->op) { + case OCAST: + case ONOT: + case OADDR: + case OIND: + n = n->left; + goto loop; + + case OCOND: + if(side(n->left)) + break; + n = n->right; + + case OEQ: + case ONE: + case OLT: + case OGE: + case OGT: + case OLE: + case OADD: + case OSUB: + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + case OLSHR: + case OASHL: + case OASHR: + case OAND: + case OOR: + case OXOR: + case OMOD: + case OLMOD: + case OANDAND: + case OOROR: + case OCOMMA: + case ODOT: + if(side(n->left)) + break; + n = n->right; + goto loop; + + case OSIGN: + case OSIZE: + case OCONST: + case OSTRING: + case OLSTRING: + case ONAME: + return 0; + } + return 1; +} + +int +vconst(Node *n) +{ + int i; + + if(n == Z) + goto no; + if(n->op != OCONST) + goto no; + if(n->type == T) + goto no; + switch(n->type->etype) + { + case TFLOAT: + case TDOUBLE: + i = 100; + if(n->fconst > i || n->fconst < -i) + goto no; + i = n->fconst; + if(i != n->fconst) + goto no; + return i; + + case TVLONG: + case TUVLONG: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + } +no: + return -159; /* first uninteresting constant */ +} + +/* + * return log(n) if n is a power of 2 constant + */ +int +vlog(Node *n) +{ + int s, i; + uvlong m, v; + + if(n->op != OCONST) + goto bad; + if(typefd[n->type->etype]) + goto bad; + + v = n->vconst; + + s = 0; + m = MASK(8*sizeof(uvlong)); + for(i=32; i; i>>=1) { + m >>= i; + if(!(v & m)) { + v >>= i; + s += i; + } + } + if(v == 1) + return s; + +bad: + return -1; +} + +int +topbit(ulong v) +{ + int i; + + for(i = -1; v; i++) + v >>= 1; + return i; +} + +/* + * try to cast a constant down + * rather than cast a variable up + * example: + * if(c == 'a') + */ +void +relcon(Node *l, Node *r) +{ + vlong v; + Node *t; + + if(l->op != OCONST) + return; + if(r->op != OCAST) + return; + if(!nilcast(r->left->type, r->type)) + return; + switch(r->type->etype) { + default: + return; + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + v = convvtox(l->vconst, r->type->etype); + if(v != l->vconst) + return; + break; + } + t = new1(OXXX, Z, Z); + *t = *l; + l->op = OCAST; + l->left = t; + l->right = Z; + l->type = r->left->type; + *r = *r->left; +} + +int +relindex(int o) +{ + + switch(o) { + default: + diag(Z, "bad in relindex: %O", o); + case OEQ: return 0; + case ONE: return 1; + case OLE: return 2; + case OLS: return 3; + case OLT: return 4; + case OLO: return 5; + case OGE: return 6; + case OHS: return 7; + case OGT: return 8; + case OHI: return 9; + } +} + +Node* +invert(Node *n) +{ + Node *i; + + if(n == Z || n->op != OLIST || n->blk) + return n; + i = n; + for(n = n->left; n != Z; n = n->left) { + if(n->op != OLIST || n->blk) + break; + i->left = n->right; + n->right = i; + i = n; + } + i->left = n; + return i; +} + +int +bitno(long b) +{ + int i; + + for(i=0; i<32; i++) + if(b & (1L<<i)) + return i; + diag(Z, "bad in bitno"); + return 0; +} + +long +typebitor(long a, long b) +{ + long c; + + c = a | b; + if(a & b) + if((a & b) == BLONG) + c |= BVLONG; /* long long => vlong */ + else + warn(Z, "once is enough: %Q", a & b); + return c; +} + +void +diag(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(0) + abort(); + if(n != Z) + if(0) + prtree(n, "diagnostic"); + + nerrors++; + if(nerrors > 10) { + fprint(2, "too many errors\n"); + errorexit(); + } +} + +void +warn(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + if(0) { + fprint(2, "warning: "); + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(n != Z) + if(0) + prtree(n, "warning"); + } +} + +void +yyerror(char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(fmt, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%L %s\n", lineno, buf); + nerrors++; + if(nerrors > 10) { + fprint(2, "too many errors\n"); + errorexit(); + } +} + +void +fatal(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(0) + abort(); + if(n != Z) + if(0) + prtree(n, "diagnostic"); + + nerrors++; + errorexit(); +} + +ulong thash1 = 0x2edab8c9; +ulong thash2 = 0x1dc74fb8; +ulong thash3 = 0x1f241331; +ulong thash[NALLTYPES]; +Init thashinit[] = +{ + TXXX, 0x17527bbd, 0, + TCHAR, 0x5cedd32b, 0, + TUCHAR, 0x552c4454, 0, + TSHORT, 0x63040b4b, 0, + TUSHORT, 0x32a45878, 0, + TINT, 0x4151d5bd, 0, + TUINT, 0x5ae707d6, 0, + TLONG, 0x5ef20f47, 0, + TULONG, 0x36d8eb8f, 0, + TVLONG, 0x6e5e9590, 0, + TUVLONG, 0x75910105, 0, + TFLOAT, 0x25fd7af1, 0, + TDOUBLE, 0x7c40a1b2, 0, + TIND, 0x1b832357, 0, + TFUNC, 0x6babc9cb, 0, + TARRAY, 0x7c50986d, 0, + TVOID, 0x44112eff, 0, + TSTRUCT, 0x7c2da3bf, 0, + TUNION, 0x3eb25e98, 0, + TENUM, 0x44b54f61, 0, + TFILE, 0x19242ac3, 0, + TOLD, 0x22b15988, 0, + TDOT, 0x0204f6b3, 0, + -1, 0, 0, +}; + +char* bnames[NALIGN]; +Init bnamesinit[] = +{ + Axxx, 0, "Axxx", + Ael1, 0, "el1", + Ael2, 0, "el2", + Asu2, 0, "su2", + Aarg0, 0, "arg0", + Aarg1, 0, "arg1", + Aarg2, 0, "arg2", + Aaut3, 0, "aut3", + -1, 0, 0, +}; + +char* tnames[NALLTYPES]; +Init tnamesinit[] = +{ + TXXX, 0, "xxx", + TCHAR, 0, "char", + TUCHAR, 0, "uchar", + TSHORT, 0, "short", + TUSHORT, 0, "ushort", + TINT, 0, "int", + TUINT, 0, "uint", + TLONG, 0, "long", + TULONG, 0, "ulong", + TVLONG, 0, "vlong", + TUVLONG, 0, "uvlong", + TFLOAT, 0, "float", + TDOUBLE, 0, "double", + TIND, 0, "pointer", + TFUNC, 0, "function", + TARRAY, 0, "array", + TVOID, 0, "void", + TSTRUCT, 0, "struct", + TUNION, 0, "union", + TENUM, 0, "enum", + TFILE, 0, "file", + TOLD, 0, "old", + TDOT, 0, "dot", + TSTRING, 0, "string", + TFD, 0, "fd", + TTUPLE, 0, "tuple", + -1, 0, 0, +}; + +char* gnames[NGTYPES]; +Init gnamesinit[] = +{ + GXXX, 0, "GXXX", + GCONSTNT, 0, "CONST", + GVOLATILE, 0, "VOLATILE", + GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE", + -1, 0, 0, +}; + +char* qnames[NALLTYPES]; +Init qnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + + TAUTO, 0, "AUTO", + TEXTERN, 0, "EXTERN", + TSTATIC, 0, "STATIC", + TTYPEDEF, 0, "TYPEDEF", + TREGISTER, 0, "REGISTER", + TCONSTNT, 0, "CONSTNT", + TVOLATILE, 0, "VOLATILE", + TUNSIGNED, 0, "UNSIGNED", + TSIGNED, 0, "SIGNED", + TDOT, 0, "DOT", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + -1, 0, 0, +}; +char* cnames[NCTYPES]; +Init cnamesinit[] = +{ + CXXX, 0, "CXXX", + CAUTO, 0, "AUTO", + CEXTERN, 0, "EXTERN", + CGLOBL, 0, "GLOBL", + CSTATIC, 0, "STATIC", + CLOCAL, 0, "LOCAL", + CTYPEDEF, 0, "TYPEDEF", + CPARAM, 0, "PARAM", + CSELEM, 0, "SELEM", + CLABEL, 0, "LABEL", + CEXREG, 0, "EXREG", + -1, 0, 0, +}; + +char* onames[OEND+1]; +Init onamesinit[] = +{ + ONOOP, 0, "NOOP", + OXXX, 0, "OXXX", + OADD, 0, "ADD", + OADDR, 0, "ADDR", + OAND, 0, "AND", + OANDAND, 0, "ANDAND", + OARRAY, 0, "ARRAY", + OAS, 0, "AS", + OASI, 0, "ASI", + OASADD, 0, "ASADD", + OASAND, 0, "ASAND", + OASASHL, 0, "ASASHL", + OASASHR, 0, "ASASHR", + OASDIV, 0, "ASDIV", + OASHL, 0, "ASHL", + OASHR, 0, "ASHR", + OASLDIV, 0, "ASLDIV", + OASLMOD, 0, "ASLMOD", + OASLMUL, 0, "ASLMUL", + OASLSHR, 0, "ASLSHR", + OASMOD, 0, "ASMOD", + OASMUL, 0, "ASMUL", + OASOR, 0, "ASOR", + OASSUB, 0, "ASSUB", + OASXOR, 0, "ASXOR", + OBIT, 0, "BIT", + OBREAK, 0, "BREAK", + OCASE, 0, "CASE", + OCAST, 0, "CAST", + OCOMMA, 0, "COMMA", + OCOND, 0, "COND", + OCONST, 0, "CONST", + OCONTINUE, 0, "CONTINUE", + ODIV, 0, "DIV", + ODOT, 0, "DOT", + ODOTDOT, 0, "DOTDOT", + ODWHILE, 0, "DWHILE", + OENUM, 0, "ENUM", + OEQ, 0, "EQ", + OFOR, 0, "FOR", + OFUNC, 0, "FUNC", + OGE, 0, "GE", + OGOTO, 0, "GOTO", + OGT, 0, "GT", + OHI, 0, "HI", + OHS, 0, "HS", + OIF, 0, "IF", + OIND, 0, "IND", + OINDREG, 0, "INDREG", + OINIT, 0, "INIT", + OLABEL, 0, "LABEL", + OLDIV, 0, "LDIV", + OLE, 0, "LE", + OLIST, 0, "LIST", + OLMOD, 0, "LMOD", + OLMUL, 0, "LMUL", + OLO, 0, "LO", + OLS, 0, "LS", + OLSHR, 0, "LSHR", + OLT, 0, "LT", + OMOD, 0, "MOD", + OMUL, 0, "MUL", + ONAME, 0, "NAME", + ONE, 0, "NE", + ONOT, 0, "NOT", + OOR, 0, "OR", + OOROR, 0, "OROR", + OPOSTDEC, 0, "POSTDEC", + OPOSTINC, 0, "POSTINC", + OPREDEC, 0, "PREDEC", + OPREINC, 0, "PREINC", + OPROTO, 0, "PROTO", + OREGISTER, 0, "REGISTER", + ORETURN, 0, "RETURN", + OSET, 0, "SET", + OSIGN, 0, "SIGN", + OSIZE, 0, "SIZE", + OSTRING, 0, "STRING", + OLSTRING, 0, "LSTRING", + OSTRUCT, 0, "STRUCT", + OSUB, 0, "SUB", + OSWITCH, 0, "SWITCH", + OUNION, 0, "UNION", + OUSED, 0, "USED", + OWHILE, 0, "WHILE", + OXOR, 0, "XOR", + ONEG, 0, "NEG", + OCOM, 0, "COM", + OELEM, 0, "ELEM", + OTST, 0, "TST", + OINDEX, 0, "INDEX", + OFAS, 0, "FAS", + OBLK, 0, "BLK", + OPOS, 0, "POS", + ONUL, 0, "NUL", + ODOTIND, 0, "DOTIND", + OARRIND, 0, "ARRIND", + ODAS, 0, "ODAS", + OASD, 0, "OASD", + OIOTA, 0, "IOTA", + OLEN, 0, "LEN", + OBRACKET, 0, "BRACKET", + OREF, 0, "REF", + OARRAYOF, 0, "ARRAYOF", + OSLICE, 0, "SLICE", + OSADDR, 0, "SADDR", + ONIL, 0, "NIL", + OS2AB, 0, "S2AB", + OAB2S, 0, "AB2S", + OFILDES, 0, "FILDES", + OFD, 0, "FD", + OTUPLE, 0, "TUPLE", + OT0, 0, "T0", + ORETV, 0, "RETV", + OCAT, 0, "CAT", + OSBREAK, 0, "SBREAK", + OLDOT, 0, "LDOT", + OMDOT, 0, "MDOT", + OCODE, 0, "CODE", + ODECE, 0, "DECE", + ODECT, 0, "DECT", + ODECV, 0, "DECV", + ODECF, 0, "DECF", + OPUSH, 0, "PUSH", + OPOP, 0, "POP", + OEND, 0, "END", + -1, 0, 0, +}; + +char comrel[12] = +{ + ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS, +}; +char invrel[12] = +{ + OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO, +}; +char logrel[12] = +{ + OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI, +}; + +char typei[NTYPE]; +int typeiinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1, +}; +char typeu[NTYPE]; +int typeuinit[] = +{ + TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1, +}; + +char typesuv[NTYPE]; +int typesuvinit[] = +{ + TVLONG, TUVLONG, TSTRUCT, TUNION, -1, +}; + +char typeilp[NTYPE]; +int typeilpinit[] = +{ + TINT, TUINT, TLONG, TULONG, TIND, -1 +}; + +char typechl[NTYPE]; +int typechlinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1, +}; + +char typechlp[NTYPE]; +int typechlpinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1, +}; + +char typechlpfd[NTYPE]; +int typechlpfdinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1, +}; + +char typec[NTYPE]; +int typecinit[] = +{ + TCHAR, TUCHAR, -1 +}; + +char typeh[NTYPE]; +int typehinit[] = +{ + TSHORT, TUSHORT, -1, +}; + +char typeil[NTYPE]; +int typeilinit[] = +{ + TINT, TUINT, TLONG, TULONG, -1, +}; + +char typev[NTYPE]; +int typevinit[] = +{ + TVLONG, TUVLONG, -1, +}; + +char typefd[NTYPE]; +int typefdinit[] = +{ + TFLOAT, TDOUBLE, -1, +}; + +char typeaf[NTYPE]; +int typeafinit[] = +{ + TFUNC, TARRAY, -1, +}; + +char typesu[NTYPE]; +int typesuinit[] = +{ + TSTRUCT, TUNION, -1, +}; + +long tasign[NTYPE]; +Init tasigninit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + TSTRUCT, BSTRUCT, 0, + TUNION, BUNION, 0, + -1, 0, 0, +}; + +long tasadd[NTYPE]; +Init tasaddinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tcast[NTYPE]; +Init tcastinit[] = +{ + TCHAR, BNUMBER|BIND|BVOID, 0, + TUCHAR, BNUMBER|BIND|BVOID, 0, + TSHORT, BNUMBER|BIND|BVOID, 0, + TUSHORT, BNUMBER|BIND|BVOID, 0, + TINT, BNUMBER|BIND|BVOID, 0, + TUINT, BNUMBER|BIND|BVOID, 0, + TLONG, BNUMBER|BIND|BVOID, 0, + TULONG, BNUMBER|BIND|BVOID, 0, + TVLONG, BNUMBER|BIND|BVOID, 0, + TUVLONG, BNUMBER|BIND|BVOID, 0, + TFLOAT, BNUMBER|BVOID, 0, + TDOUBLE, BNUMBER|BVOID, 0, + TIND, BINTEGER|BIND|BVOID, 0, + TVOID, BVOID, 0, + TSTRUCT, BSTRUCT|BVOID, 0, + TUNION, BUNION|BVOID, 0, + -1, 0, 0, +}; + +long tadd[NTYPE]; +Init taddinit[] = +{ + TCHAR, BNUMBER|BIND, 0, + TUCHAR, BNUMBER|BIND, 0, + TSHORT, BNUMBER|BIND, 0, + TUSHORT, BNUMBER|BIND, 0, + TINT, BNUMBER|BIND, 0, + TUINT, BNUMBER|BIND, 0, + TLONG, BNUMBER|BIND, 0, + TULONG, BNUMBER|BIND, 0, + TVLONG, BNUMBER|BIND, 0, + TUVLONG, BNUMBER|BIND, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tsub[NTYPE]; +Init tsubinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER|BIND, 0, + -1, 0, 0, +}; + +long tmul[NTYPE]; +Init tmulinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + -1, 0, 0, +}; + +long tand[NTYPE]; +Init tandinit[] = +{ + TCHAR, BINTEGER, 0, + TUCHAR, BINTEGER, 0, + TSHORT, BINTEGER, 0, + TUSHORT, BINTEGER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BINTEGER, 0, + TULONG, BINTEGER, 0, + TVLONG, BINTEGER, 0, + TUVLONG, BINTEGER, 0, + -1, 0, 0, +}; + +long trel[NTYPE]; +Init trelinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + -1, 0, 0, +}; + +long tfunct[1] = +{ + BFUNC, +}; + +long tindir[1] = +{ + BIND, +}; + +long tdot[1] = +{ + BSTRUCT|BUNION, +}; + +long tnot[1] = +{ + BNUMBER|BIND, +}; + +long targ[1] = +{ + BNUMBER|BIND|BSTRUCT|BUNION, +}; + +char tab[NTYPE][NTYPE] = +{ +/*TXXX*/ { 0, + }, + +/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, + TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, + TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, + TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND, + }, +/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, + TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND, + }, +/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND, + TIND, TIND, TIND, TIND, TIND, TIND, + }, +}; + +void +urk(char *name, int max, int i) +{ + if(i >= max) { + fprint(2, "bad tinit: %s %d>=%d\n", name, i, max); + exits("init"); + } +} + +void +tinit(void) +{ + int i; + Init *p; + + for(p=thashinit; p->code >= 0; p++) { + urk("thash", nelem(thash), p->code); + thash[p->code] = p->value; + } + for(p=bnamesinit; p->code >= 0; p++) { + urk("bnames", nelem(bnames), p->code); + bnames[p->code] = p->s; + } + for(p=tnamesinit; p->code >= 0; p++) { + urk("tnames", nelem(tnames), p->code); + tnames[p->code] = p->s; + } + for(p=gnamesinit; p->code >= 0; p++) { + urk("gnames", nelem(gnames), p->code); + gnames[p->code] = p->s; + } + for(p=qnamesinit; p->code >= 0; p++) { + urk("qnames", nelem(qnames), p->code); + qnames[p->code] = p->s; + } + for(p=cnamesinit; p->code >= 0; p++) { + urk("cnames", nelem(cnames), p->code); + cnames[p->code] = p->s; + } + for(p=onamesinit; p->code >= 0; p++) { + urk("onames", nelem(onames), p->code); + onames[p->code] = p->s; + } + for(i=0; typeiinit[i] >= 0; i++) { + urk("typei", nelem(typei), typeiinit[i]); + typei[typeiinit[i]] = 1; + } + for(i=0; typeuinit[i] >= 0; i++) { + urk("typeu", nelem(typeu), typeuinit[i]); + typeu[typeuinit[i]] = 1; + } + for(i=0; typesuvinit[i] >= 0; i++) { + urk("typesuv", nelem(typesuv), typesuvinit[i]); + typesuv[typesuvinit[i]] = 1; + } + for(i=0; typeilpinit[i] >= 0; i++) { + urk("typeilp", nelem(typeilp), typeilpinit[i]); + typeilp[typeilpinit[i]] = 1; + } + for(i=0; typechlinit[i] >= 0; i++) { + urk("typechl", nelem(typechl), typechlinit[i]); + typechl[typechlinit[i]] = 1; + } + for(i=0; typechlpinit[i] >= 0; i++) { + urk("typechlp", nelem(typechlp), typechlpinit[i]); + typechlp[typechlpinit[i]] = 1; + } + for(i=0; typechlpfdinit[i] >= 0; i++) { + urk("typechlpfd", nelem(typechlpfd), typechlpfdinit[i]); + typechlpfd[typechlpfdinit[i]] = 1; + } + for(i=0; typecinit[i] >= 0; i++) { + urk("typec", nelem(typec), typecinit[i]); + typec[typecinit[i]] = 1; + } + for(i=0; typehinit[i] >= 0; i++) { + urk("typeh", nelem(typeh), typehinit[i]); + typeh[typehinit[i]] = 1; + } + for(i=0; typeilinit[i] >= 0; i++) { + urk("typeil", nelem(typeil), typeilinit[i]); + typeil[typeilinit[i]] = 1; + } + for(i=0; typevinit[i] >= 0; i++) { + urk("typev", nelem(typev), typevinit[i]); + typev[typevinit[i]] = 1; + } + for(i=0; typefdinit[i] >= 0; i++) { + urk("typefd", nelem(typefd), typefdinit[i]); + typefd[typefdinit[i]] = 1; + } + for(i=0; typeafinit[i] >= 0; i++) { + urk("typeaf", nelem(typeaf), typeafinit[i]); + typeaf[typeafinit[i]] = 1; + } + for(i=0; typesuinit[i] >= 0; i++) { + urk("typesu", nelem(typesu), typesuinit[i]); + typesu[typesuinit[i]] = 1; + } + for(p=tasigninit; p->code >= 0; p++) { + urk("tasign", nelem(tasign), p->code); + tasign[p->code] = p->value; + } + for(p=tasaddinit; p->code >= 0; p++) { + urk("tasadd", nelem(tasadd), p->code); + tasadd[p->code] = p->value; + } + for(p=tcastinit; p->code >= 0; p++) { + urk("tcast", nelem(tcast), p->code); + tcast[p->code] = p->value; + } + for(p=taddinit; p->code >= 0; p++) { + urk("tadd", nelem(tadd), p->code); + tadd[p->code] = p->value; + } + for(p=tsubinit; p->code >= 0; p++) { + urk("tsub", nelem(tsub), p->code); + tsub[p->code] = p->value; + } + for(p=tmulinit; p->code >= 0; p++) { + urk("tmul", nelem(tmul), p->code); + tmul[p->code] = p->value; + } + for(p=tandinit; p->code >= 0; p++) { + urk("tand", nelem(tand), p->code); + tand[p->code] = p->value; + } + for(p=trelinit; p->code >= 0; p++) { + urk("trel", nelem(trel), p->code); + trel[p->code] = p->value; + } +} diff --git a/utils/cat/cat.c b/utils/cat/cat.c new file mode 100644 index 00000000..22d8d354 --- /dev/null +++ b/utils/cat/cat.c @@ -0,0 +1,35 @@ +#include <lib9.h> + +void +cat(int f, char *s) +{ + char buf[8192]; + long n; + + while((n=read(f, buf, (long)sizeof buf))>0) + if(write(1, buf, n)!=n) + sysfatal("write error copying %s: %r", s); + if(n < 0) + sysfatal("error reading %s: %r", s); +} + +void +main(int argc, char *argv[]) +{ + int f, i; + + argv0 = "cat"; + if(argc == 1) + cat(0, "<stdin>"); + else for(i=1; i<argc; i++){ + f = open(argv[i], OREAD); + if(f < 0) + sysfatal("can't open %s: %r", argv[i]); + else{ + cat(f, argv[i]); + close(f); + } + } + exits(0); +} + diff --git a/utils/cat/mkfile b/utils/cat/mkfile new file mode 100644 index 00000000..48679b92 --- /dev/null +++ b/utils/cat/mkfile @@ -0,0 +1,10 @@ +<../../mkconfig + +TARG=cat + +OFILES= cat.$O\ + +LIBS=9 +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/cc/Nt.c b/utils/cc/Nt.c new file mode 100644 index 00000000..11209ea4 --- /dev/null +++ b/utils/cc/Nt.c @@ -0,0 +1,135 @@ +#include <windows.h> +#include <lib9.h> + +#define Windows (1<<2) /* hack - can't include cc.h because of clashes */ +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +int +mycreat(char *n, int p) +{ + + return create(n, 1, p); +} + +int +mywait(int *s) +{ + fprint(2, "mywait called\n"); + abort(); + return 0; +} + +int +mydup(int f1, int f2) +{ + fprint(2, "mydup called\n"); + abort(); + return 0; +} + +int +mypipe(int *fd) +{ + fprint(2, "mypipe called\n"); + abort(); + return 0; +} + +int +systemtype(int sys) +{ + + return sys&Windows; +} + +int +pathchar(void) +{ + return '/'; +} + +char* +mygetwd(char *path, int len) +{ + return getcwd(path, len); +} + +int +myexec(char *path, char *argv[]) +{ + fprint(2, "myexec called\n"); + abort(); + return 0; +} + +int +myfork(void) +{ + fprint(2, "myfork called\n"); + abort(); + return 0; +} + +/* + * fake mallocs + */ +void* +malloc(uint n) +{ + return mysbrk(n); +} + +void* +calloc(uint m, uint n) +{ + return mysbrk(m*n); +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +void +free(void *p) +{ +} + +int +myaccess(char *f) +{ + int fd; + + fd = open(f, OREAD); + if(fd < 0) + return -1; + close(fd); + return 0; +} diff --git a/utils/cc/Plan9.c b/utils/cc/Plan9.c new file mode 100644 index 00000000..f4d80364 --- /dev/null +++ b/utils/cc/Plan9.c @@ -0,0 +1,114 @@ +#include "cc.h" + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +int +mycreat(char *n, int p) +{ + + return create(n, 1, p); +} + +int +mywait(int *s) +{ + int p; + Waitmsg *w; + + if((w = wait()) == nil) + return -1; + else{ + p = w->pid; + *s = 0; + if(w->msg[0]) + *s = 1; + free(w); + return p; + } +} + +int +mydup(int f1, int f2) +{ + return dup(f1,f2); +} + +int +mypipe(int *fd) +{ + return pipe(fd); +} + +int +systemtype(int sys) +{ + + return sys&Plan9; +} + +int +pathchar(void) +{ + return '/'; +} + +char* +mygetwd(char *path, int len) +{ + return getwd(path, len); +} + +int +myexec(char *path, char *argv[]) +{ + return exec(path, argv); +} + +int +myfork(void) +{ + return fork(); +} + +/* + * fake mallocs + */ +void* +malloc(ulong n) +{ + return alloc(n); +} + +void* +calloc(ulong m, ulong n) +{ + return alloc(m*n); +} + +void* +realloc(void*, ulong) +{ + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void +free(void*) +{ +} + +int +myaccess(char *f) +{ + return access(f, AEXIST); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/cc/Posix.c b/utils/cc/Posix.c new file mode 100644 index 00000000..dfe28d60 --- /dev/null +++ b/utils/cc/Posix.c @@ -0,0 +1,98 @@ +#include "cc.h" +#include <sys/wait.h> + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +int +mycreat(char *n, int p) +{ + + return create(n, 1, p); +} + +int +mywait(int *s) +{ + return wait(s); +} + +int +mydup(int f1, int f2) +{ + return dup2(f1,f2); +} + +int +mypipe(int *fd) +{ + return pipe(fd); +} + +int +systemtype(int sys) +{ + + return sys&Unix; +} + +int +pathchar(void) +{ + return '/'; +} + +char* +mygetwd(char *path, int len) +{ + return (char*)getcwd(path, len); +} + +int +myexec(char *path, char *argv[]) +{ + return execvp(path, argv); +} + +/* + * fake mallocs + */ +void* +malloc(size_t n) +{ + return alloc(n); +} + +void* +calloc(size_t m, size_t n) +{ + return alloc(m*n); +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void +free(void *p) +{ +} + +int +myfork(void) +{ + return fork(); +} + +int +myaccess(char *f) +{ + return access(f, 0); +} diff --git a/utils/cc/acid.c b/utils/cc/acid.c new file mode 100644 index 00000000..3d898883 --- /dev/null +++ b/utils/cc/acid.c @@ -0,0 +1,301 @@ +#include "cc.h" + +static char *kwd[] = +{ + "$adt", "$aggr", "$append", "$complex", "$defn", + "$delete", "$do", "$else", "$eval", "$head", "$if", + "$local", "$loop", "$return", "$tail", "$then", + "$union", "$whatis", "$while", +}; + +char* +amap(char *s) +{ + int i, bot, top, new; + + bot = 0; + top = bot + nelem(kwd) - 1; + while(bot <= top){ + new = bot + (top - bot)/2; + i = strcmp(kwd[new]+1, s); + if(i == 0) + return kwd[new]; + + if(i < 0) + bot = new + 1; + else + top = new - 1; + } + return s; +} + +Sym* +acidsue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +Sym* +acidfun(Type *t) +{ + int h; + Sym *s; + + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->type == t) + return s; + return 0; +} + +char acidchar[NTYPE]; +Init acidcinit[] = +{ + TCHAR, 'C', 0, + TUCHAR, 'b', 0, + TSHORT, 'd', 0, + TUSHORT, 'u', 0, + TLONG, 'D', 0, + TULONG, 'U', 0, + TVLONG, 'V', 0, + TUVLONG, 'W', 0, + TFLOAT, 'f', 0, + TDOUBLE, 'F', 0, + TARRAY, 'a', 0, + TIND, 'X', 0, + -1, 0, 0, +}; + +static void +acidinit(void) +{ + Init *p; + + for(p=acidcinit; p->code >= 0; p++) + acidchar[p->code] = p->value; + + acidchar[TINT] = acidchar[TLONG]; + acidchar[TUINT] = acidchar[TULONG]; + if(types[TINT]->width != types[TLONG]->width) { + acidchar[TINT] = acidchar[TSHORT]; + acidchar[TUINT] = acidchar[TUSHORT]; + if(types[TINT]->width != types[TSHORT]->width) + warn(Z, "acidmember int not long or short"); + } + +} + +void +acidmember(Type *t, long off, int flag) +{ + Sym *s, *s1; + Type *l; + static int acidcharinit = 0; + + if(acidcharinit == 0) { + acidinit(); + acidcharinit = 1; + } + s = t->sym; + switch(t->etype) { + default: + Bprint(&outbuf, " T%d\n", t->etype); + break; + + case TIND: + if(s == S) + break; + if(flag) { + for(l=t; l->etype==TIND; l=l->link) + ; + if(typesu[l->etype]) { + s1 = acidsue(l->link); + if(s1 != S) { + Bprint(&outbuf, " 'A' %s %ld %s;\n", + amap(s1->name), + t->offset+off, amap(s->name)); + break; + } + } + } else { + Bprint(&outbuf, + "\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n", + amap(s->name), amap(s->name)); + break; + } + + case TINT: + case TUINT: + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TARRAY: + if(s == S) + break; + if(flag) { + Bprint(&outbuf, " '%c' %ld %s;\n", + acidchar[t->etype], t->offset+off, amap(s->name)); + } else { + Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n", + amap(s->name), amap(s->name)); + } + break; + + case TSTRUCT: + case TUNION: + s1 = acidsue(t->link); + if(s1 == S) + break; + if(flag) { + if(s == S) { + Bprint(&outbuf, " {\n"); + for(l = t->link; l != T; l = l->down) + acidmember(l, t->offset+off, flag); + Bprint(&outbuf, " };\n"); + } else { + Bprint(&outbuf, " %s %ld %s;\n", + amap(s1->name), + t->offset+off, amap(s->name)); + } + } else { + if(s != S) { + Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n", + amap(s1->name), amap(s->name)); + Bprint(&outbuf, "\t%s(addr.%s);\n", + amap(s1->name), amap(s->name)); + Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + } else { + Bprint(&outbuf, "\tprint(\"%s {\\n\");\n", + amap(s1->name)); + Bprint(&outbuf, "\t\t%s(addr+%ld);\n", + amap(s1->name), t->offset+off); + Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + } + } + break; + } +} + +void +acidtype(Type *t) +{ + Sym *s; + Type *l; + Io *i; + int n; + char *an; + + if(!debug['a']) + return; + if(debug['a'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + s = acidsue(t->link); + if(s == S) + return; + switch(t->etype) { + default: + Bprint(&outbuf, "T%d\n", t->etype); + return; + + case TUNION: + case TSTRUCT: + if(debug['s']) + goto asmstr; + an = amap(s->name); + Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width); + Bprint(&outbuf, "aggr %s\n{\n", an); + for(l = t->link; l != T; l = l->down) + acidmember(l, 0, 1); + Bprint(&outbuf, "};\n\n"); + + Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an); + for(l = t->link; l != T; l = l->down) + acidmember(l, 0, 0); + Bprint(&outbuf, "};\n\n"); + break; + asmstr: + if(s == S) + break; + for(l = t->link; l != T; l = l->down) + if(l->sym != S) + Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + s->name, + l->sym->name, + l->offset); + break; + } +} + +void +acidvar(Sym *s) +{ + int n; + Io *i; + Type *t; + Sym *s1, *s2; + + if(!debug['a'] || debug['s']) + return; + if(debug['a'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + t = s->type; + while(t && t->etype == TIND) + t = t->link; + if(t == T) + return; + if(t->etype == TENUM) { + Bprint(&outbuf, "%s = ", amap(s->name)); + if(!typefd[t->etype]) + Bprint(&outbuf, "%lld;\n", s->vconst); + else + Bprint(&outbuf, "%f\n;", s->fconst); + return; + } + if(!typesu[t->etype]) + return; + s1 = acidsue(t->link); + if(s1 == S) + return; + switch(s->class) { + case CAUTO: + case CPARAM: + s2 = acidfun(thisfn); + if(s2) + Bprint(&outbuf, "complex %s %s:%s;\n", + amap(s1->name), amap(s2->name), amap(s->name)); + break; + + case CSTATIC: + case CEXTERN: + case CGLOBL: + case CLOCAL: + Bprint(&outbuf, "complex %s %s;\n", + amap(s1->name), amap(s->name)); + break; + } +} diff --git a/utils/cc/bits.c b/utils/cc/bits.c new file mode 100644 index 00000000..a22ba512 --- /dev/null +++ b/utils/cc/bits.c @@ -0,0 +1,89 @@ +#include "cc.h" + +Bits +bor(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = a.b[i] | b.b[i]; + return c; +} + +Bits +band(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = a.b[i] & b.b[i]; + return c; +} + +/* +Bits +bnot(Bits a) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = ~a.b[i]; + return c; +} +*/ + +int +bany(Bits *a) +{ + int i; + + for(i=0; i<BITS; i++) + if(a->b[i]) + return 1; + return 0; +} + +int +beq(Bits a, Bits b) +{ + int i; + + for(i=0; i<BITS; i++) + if(a.b[i] != b.b[i]) + return 0; + return 1; +} + +int +bnum(Bits a) +{ + int i; + long b; + + for(i=0; i<BITS; i++) + if(b = a.b[i]) + return 32*i + bitno(b); + diag(Z, "bad in bnum"); + return 0; +} + +Bits +blsh(uint n) +{ + Bits c; + + c = zbits; + c.b[n/32] = 1L << (n%32); + return c; +} + +int +bset(Bits a, uint n) +{ + if(a.b[n/32] & (1L << (n%32))) + return 1; + return 0; +} diff --git a/utils/cc/cc.h b/utils/cc/cc.h new file mode 100644 index 00000000..d05b4397 --- /dev/null +++ b/utils/cc/cc.h @@ -0,0 +1,768 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Node Node; +typedef struct Sym Sym; +typedef struct Type Type; +typedef struct Funct Funct; +typedef struct Decl Decl; +typedef struct Io Io; +typedef struct Hist Hist; +typedef struct Term Term; +typedef struct Init Init; +typedef struct Bits Bits; + +#define NHUNK 50000L +#define BUFSIZ 8192 +#define NSYMB 500 +#define NHASH 1024 +#define STRINGSZ 200 +#define HISTSZ 20 +#define YYMAXDEPTH 500 +#define NTERM 10 +#define MAXALIGN 7 + +#define SIGN(n) ((vlong)1<<(n-1)) +#define MASK(n) (SIGN(n)|(SIGN(n)-1)) + +#define BITS 5 +#define NVAR (BITS*sizeof(ulong)*8) +struct Bits +{ + ulong b[BITS]; +}; + +struct Node +{ + Node* left; + Node* right; + void* label; + long pc; + int reg; + long xoffset; + double fconst; /* fp constant */ + vlong vconst; /* non fp const */ + char* cstring; /* character string */ + ushort* rstring; /* rune string */ + + Sym* sym; + Type* type; + long lineno; + char op; + + char oldop; + char xcast; + char class; + char etype; + char complex; + char addable; + char scale; + char garb; +}; +#define Z ((Node*)0) + +struct Sym +{ + Sym* link; + Type* type; + Type* suetag; + Type* tenum; + char* macro; + long varlineno; + long offset; + vlong vconst; + double fconst; + Node* label; + ushort lexical; + char *name; + ushort block; + ushort sueblock; + char class; + char sym; + char aused; + char sig; +}; +#define S ((Sym*)0) + +enum{ + SIGNONE = 0, + SIGDONE = 1, + SIGINTERN = 2, + + SIGNINTERN = 1729*325*1729, +}; + +struct Decl +{ + Decl* link; + Sym* sym; + Type* type; + long varlineno; + long offset; + short val; + ushort block; + char class; + char aused; +}; +#define D ((Decl*)0) + +struct Type +{ + Sym* sym; + Sym* tag; + Funct* funct; + Type* link; + Type* down; + long width; + long offset; + long lineno; + char shift; + char nbits; + char etype; + char garb; +}; + +#define T ((Type*)0) +#define NODECL ((void(*)(int, Type*, Sym*))0) + +struct Init /* general purpose initialization */ +{ + int code; + ulong value; + char* s; +}; + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char* p; + char b[BUFSIZ]; + short c; + short f; +}; +#define I ((Io*)0) + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) +EXTERN Hist* hist; + +struct Term +{ + vlong mult; + Node *node; +}; + +enum +{ + Axxx, + Ael1, + Ael2, + Asu2, + Aarg0, + Aarg1, + Aarg2, + Aaut3, + NALIGN, +}; + +enum /* also in ../{8a,0a}.h */ +{ + Plan9 = 1<<0, + Unix = 1<<1, + Windows = 1<<2, +}; + +enum +{ + DMARK, + DAUTO, + DSUE, + DLABEL, +}; +enum +{ + OXXX, + OADD, + OADDR, + OAND, + OANDAND, + OARRAY, + OAS, + OASI, + OASADD, + OASAND, + OASASHL, + OASASHR, + OASDIV, + OASHL, + OASHR, + OASLDIV, + OASLMOD, + OASLMUL, + OASLSHR, + OASMOD, + OASMUL, + OASOR, + OASSUB, + OASXOR, + OBIT, + OBREAK, + OCASE, + OCAST, + OCOMMA, + OCOND, + OCONST, + OCONTINUE, + ODIV, + ODOT, + ODOTDOT, + ODWHILE, + OENUM, + OEQ, + OFOR, + OFUNC, + OGE, + OGOTO, + OGT, + OHI, + OHS, + OIF, + OIND, + OINDREG, + OINIT, + OLABEL, + OLDIV, + OLE, + OLIST, + OLMOD, + OLMUL, + OLO, + OLS, + OLSHR, + OLT, + OMOD, + OMUL, + ONAME, + ONE, + ONOT, + OOR, + OOROR, + OPOSTDEC, + OPOSTINC, + OPREDEC, + OPREINC, + OPROTO, + OREGISTER, + ORETURN, + OSET, + OSIGN, + OSIZE, + OSTRING, + OLSTRING, + OSTRUCT, + OSUB, + OSWITCH, + OUNION, + OUSED, + OWHILE, + OXOR, + ONEG, + OCOM, + OPOS, + OELEM, + + OTST, /* used in some compilers */ + OINDEX, + OFAS, + OREGPAIR, + + OEND +}; +enum +{ + TXXX, + TCHAR, + TUCHAR, + TSHORT, + TUSHORT, + TINT, + TUINT, + TLONG, + TULONG, + TVLONG, + TUVLONG, + TFLOAT, + TDOUBLE, + TIND, + TFUNC, + TARRAY, + TVOID, + TSTRUCT, + TUNION, + TENUM, + NTYPE, + + TAUTO = NTYPE, + TEXTERN, + TSTATIC, + TTYPEDEF, + TTYPESTR, + TREGISTER, + TCONSTNT, + TVOLATILE, + TUNSIGNED, + TSIGNED, + TDOT, + TFILE, + TOLD, + NALLTYPES, +}; +enum +{ + CXXX, + CAUTO, + CEXTERN, + CGLOBL, + CSTATIC, + CLOCAL, + CTYPEDEF, + CTYPESTR, + CPARAM, + CSELEM, + CLABEL, + CEXREG, + NCTYPES, +}; +enum +{ + GXXX = 0, + GCONSTNT = 1<<0, + GVOLATILE = 1<<1, + NGTYPES = 1<<2, + + GINCOMPLETE = 1<<2, +}; +enum +{ + BCHAR = 1L<<TCHAR, + BUCHAR = 1L<<TUCHAR, + BSHORT = 1L<<TSHORT, + BUSHORT = 1L<<TUSHORT, + BINT = 1L<<TINT, + BUINT = 1L<<TUINT, + BLONG = 1L<<TLONG, + BULONG = 1L<<TULONG, + BVLONG = 1L<<TVLONG, + BUVLONG = 1L<<TUVLONG, + BFLOAT = 1L<<TFLOAT, + BDOUBLE = 1L<<TDOUBLE, + BIND = 1L<<TIND, + BFUNC = 1L<<TFUNC, + BARRAY = 1L<<TARRAY, + BVOID = 1L<<TVOID, + BSTRUCT = 1L<<TSTRUCT, + BUNION = 1L<<TUNION, + BENUM = 1L<<TENUM, + BFILE = 1L<<TFILE, + BDOT = 1L<<TDOT, + BCONSTNT = 1L<<TCONSTNT, + BVOLATILE = 1L<<TVOLATILE, + BUNSIGNED = 1L<<TUNSIGNED, + BSIGNED = 1L<<TSIGNED, + BAUTO = 1L<<TAUTO, + BEXTERN = 1L<<TEXTERN, + BSTATIC = 1L<<TSTATIC, + BTYPEDEF = 1L<<TTYPEDEF, + BTYPESTR = 1L<<TTYPESTR, + BREGISTER = 1L<<TREGISTER, + + BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT| + BLONG|BULONG|BVLONG|BUVLONG, + BNUMBER = BINTEGER|BFLOAT|BDOUBLE, + +/* these can be overloaded with complex types */ + + BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER, + BGARB = BCONSTNT|BVOLATILE, +}; + +struct Funct +{ + Sym* sym[OEND]; + Sym* castto[NTYPE]; + Sym* castfr[NTYPE]; +}; + +EXTERN struct +{ + Type* tenum; /* type of entire enum */ + Type* cenum; /* type of current enum run */ + vlong lastenum; /* value of current enum */ + double floatenum; /* value of current enum */ +} en; + +EXTERN int autobn; +EXTERN long autoffset; +EXTERN int blockno; +EXTERN Decl* dclstack; +EXTERN char debug[256]; +EXTERN Hist* ehist; +EXTERN long firstbit; +EXTERN Sym* firstarg; +EXTERN Type* firstargtype; +EXTERN Decl* firstdcl; +EXTERN int fperror; +EXTERN Sym* hash[NHASH]; +EXTERN char* hunk; +EXTERN char* include[20]; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN long lastbit; +EXTERN char lastclass; +EXTERN Type* lastdcl; +EXTERN long lastfield; +EXTERN Type* lasttype; +EXTERN long lineno; +EXTERN long nearln; +EXTERN int nerrors; +EXTERN int newflag; +EXTERN long nhunk; +EXTERN int ninclude; +EXTERN Node* nodproto; +EXTERN Node* nodcast; +EXTERN Biobuf outbuf; +EXTERN Biobuf diagbuf; +EXTERN char* outfile; +EXTERN char* pathname; +EXTERN int peekc; +EXTERN long stkoff; +EXTERN Type* strf; +EXTERN Type* strl; +EXTERN char symb[NSYMB]; +EXTERN Sym* symstring; +EXTERN int taggen; +EXTERN Type* tfield; +EXTERN Type* tufield; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN Type* thisfn; +EXTERN long thunk; +EXTERN Type* types[NTYPE]; +EXTERN Type* fntypes[NTYPE]; +EXTERN Node* initlist; +EXTERN Term term[NTERM]; +EXTERN int nterm; +EXTERN int packflg; +EXTERN int fproundflg; +EXTERN int profileflg; +EXTERN Bits zbits; + +extern char *onames[], *tnames[], *gnames[]; +extern char *cnames[], *qnames[], *bnames[]; +extern char tab[NTYPE][NTYPE]; +extern char comrel[], invrel[], logrel[]; +extern long ncast[], tadd[], tand[]; +extern long targ[], tasadd[], tasign[], tcast[]; +extern long tdot[], tfunct[], tindir[], tmul[]; +extern long tnot[], trel[], tsub[]; + +extern char typeaf[]; +extern char typefd[]; +extern char typei[]; +extern char typesu[]; +extern char typesuv[]; +extern char typeu[]; +extern char typev[]; +extern char typec[]; +extern char typeh[]; +extern char typeil[]; +extern char typeilp[]; +extern char typechl[]; +extern char typechlv[]; +extern char typechlvp[]; +extern char typechlp[]; +extern char typechlpfd[]; + +extern ulong thash1; +extern ulong thash2; +extern ulong thash3; +extern ulong thash[]; + +/* + * Inferno.c/Posix.c/Nt.c + */ +int mywait(int*); +int mycreat(char*, int); +int systemtype(int); +int pathchar(void); +int myaccess(char*); +char* mygetwd(char*, int); +int myexec(char*, char*[]); +int mydup(int, int); +int myfork(void); +int mypipe(int*); +void* mysbrk(ulong); + +/* + * parser + */ +int yyparse(void); +int mpatof(char*, double*); +int mpatov(char*, vlong*); + +/* + * lex.c + */ +void* allocn(void*, long, long); +void* alloc(long); +void cinit(void); +int compile(char*, char**, int); +void errorexit(void); +int filbuf(void); +int getc(void); +long getr(void); +int getnsc(void); +Sym* lookup(void); +void main(int, char*[]); +void newfile(char*, int); +void newio(void); +void pushio(void); +long escchar(long, int, int); +Sym* slookup(char*); +void syminit(Sym*); +void unget(int); +long yylex(void); +int Lconv(Fmt*); +int Tconv(Fmt*); +int FNconv(Fmt*); +int Oconv(Fmt*); +int Qconv(Fmt*); +int VBconv(Fmt*); +void setinclude(char*); + +/* + * mac.c + */ +void dodefine(char*); +void domacro(void); +Sym* getsym(void); +long getnsn(void); +void linehist(char*, int); +void macdef(void); +void macprag(void); +void macend(void); +void macexpand(Sym*, char*); +void macif(int); +void macinc(void); +void maclin(void); +void macund(void); + +/* + * dcl.c + */ +Node* doinit(Sym*, Type*, long, Node*); +Type* tcopy(Type*); +Node* init1(Sym*, Type*, long, int); +Node* newlist(Node*, Node*); +void adecl(int, Type*, Sym*); +int anyproto(Node*); +void argmark(Node*, int); +void dbgdecl(Sym*); +Node* dcllabel(Sym*, int); +Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*); +Sym* mkstatic(Sym*); +void doenum(Sym*, Node*); +void snap(Type*); +Type* dotag(Sym*, int, int); +void edecl(int, Type*, Sym*); +Type* fnproto(Node*); +Type* fnproto1(Node*); +void markdcl(void); +Type* paramconv(Type*, int); +void pdecl(int, Type*, Sym*); +Decl* push(void); +Decl* push1(Sym*); +Node* revertdcl(void); +#undef round +#define round ccround +#undef log2 +#define log2 cclog2 +long round(long, int); +int rsametype(Type*, Type*, int, int); +int sametype(Type*, Type*); +ulong sign(Sym*); +ulong signature(Type*); +void suallign(Type*); +void tmerge(Type*, Sym*); +void walkparam(Node*, int); +void xdecl(int, Type*, Sym*); +Node* contig(Sym*, Node*, long); + +/* + * com.c + */ +void ccom(Node*); +void complex(Node*); +int tcom(Node*); +int tcoma(Node*, Node*, Type*, int); +int tcomd(Node*); +int tcomo(Node*, int); +int tcomx(Node*); +int tlvalue(Node*); +void constas(Node*, Type*, Type*); + +/* + * con.c + */ +void acom(Node*); +void acom1(vlong, Node*); +void acom2(Node*, Type*); +int acomcmp1(const void*, const void*); +int acomcmp2(const void*, const void*); +int addo(Node*); +void evconst(Node*); + +/* + * funct.c + */ +int isfunct(Node*); +void dclfunct(Type*, Sym*); + +/* + * sub.c + */ +void arith(Node*, int); +int deadheads(Node*); +Type* dotsearch(Sym*, Type*, Node*, long*); +long dotoffset(Type*, Type*, Node*); +void gethunk(void); +Node* invert(Node*); +int bitno(long); +void makedot(Node*, Type*, long); +int mixedasop(Type*, Type*); +Node* new(int, Node*, Node*); +Node* new1(int, Node*, Node*); +int nilcast(Type*, Type*); +int nocast(Type*, Type*); +void prtree(Node*, char*); +void prtree1(Node*, int, int); +void relcon(Node*, Node*); +int relindex(int); +int simpleg(long); +Type* garbt(Type*, long); +int simplec(long); +Type* simplet(long); +int stcompat(Node*, Type*, Type*, long[]); +int tcompat(Node*, Type*, Type*, long[]); +void tinit(void); +Type* typ(int, Type*); +Type* copytyp(Type*); +void typeext(Type*, Node*); +void typeext1(Type*, Node*); +int side(Node*); +int vconst(Node*); +int log2(uvlong); +int vlog(Node*); +int topbit(ulong); +void simplifyshift(Node*); +long typebitor(long, long); +void diag(Node*, char*, ...); +void warn(Node*, char*, ...); +void yyerror(char*, ...); +void fatal(Node*, char*, ...); + +/* + * acid.c + */ +void acidtype(Type*); +void acidvar(Sym*); + +/* + * pickle.c + */ +void pickletype(Type*); + +/* + * bits.c + */ +Bits bor(Bits, Bits); +Bits band(Bits, Bits); +Bits bnot(Bits); +int bany(Bits*); +int bnum(Bits); +Bits blsh(uint); +int beq(Bits, Bits); +int bset(Bits, uint); + +/* + * dpchk.c + */ +void dpcheck(Node*); +void arginit(void); +void pragvararg(void); +void pragpack(void); +void pragfpround(void); +void pragprofile(void); +void pragincomplete(void); + +/* + * calls to machine depend part + */ +void codgen(Node*, Node*); +void gclean(void); +void gextern(Sym*, Node*, long, long); +void ginit(void); +long outstring(char*, long); +long outlstring(ushort*, long); +void sextern(Sym*, Node*, long, long); +void xcom(Node*); +long exreg(Type*); +long align(long, Type*, int); +long maxround(long, long); + +extern schar ewidth[]; + +/* + * com64 + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); +double convvtof(vlong); +vlong convftov(double); +double convftox(double, int); +vlong convvtox(vlong, int); + +/* + * machcap + */ +int machcap(Node*); + +#pragma varargck argpos warn 2 +#pragma varargck argpos diag 2 +#pragma varargck argpos yyerror 1 + +#pragma varargck type "F" Node* +#pragma varargck type "L" long +#pragma varargck type "Q" long +#pragma varargck type "O" int +#pragma varargck type "T" Type* +#pragma varargck type "|" int diff --git a/utils/cc/cc.y b/utils/cc/cc.y new file mode 100644 index 00000000..9ddb1976 --- /dev/null +++ b/utils/cc/cc.y @@ -0,0 +1,1167 @@ +%{ +#include "cc.h" +%} +%union { + Node* node; + Sym* sym; + Type* type; + struct + { + Type* t; + char c; + } tycl; + struct + { + Type* t1; + Type* t2; + } tyty; + struct + { + char* s; + long l; + } sval; + long lval; + double dval; + vlong vval; +} +%type <sym> ltag +%type <lval> gctname gcname cname gname tname +%type <lval> gctnlist gcnlist zgnlist +%type <type> tlist sbody complex +%type <tycl> types +%type <node> zarglist arglist zcexpr +%type <node> name block stmnt cexpr expr xuexpr pexpr +%type <node> zelist elist adecl slist uexpr string lstring +%type <node> xdecor xdecor2 labels label ulstmnt +%type <node> adlist edecor tag qual qlist +%type <node> abdecor abdecor1 abdecor2 abdecor3 +%type <node> zexpr lexpr init ilist + +%left ';' +%left ',' +%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE +%right '?' ':' +%left LOROR +%left LANDAND +%left '|' +%left '^' +%left '&' +%left LEQ LNE +%left '<' '>' LLE LGE +%left LLSH LRSH +%left '+' '-' +%left '*' '/' '%' +%right LMM LPP LMG '.' '[' '(' + +%token <sym> LNAME LTYPE +%token <dval> LFCONST LDCONST +%token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST +%token <sval> LSTRING LLSTRING +%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO +%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO +%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED +%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED +%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF +%% +prog: +| prog xdecl + +/* + * external declarator + */ +xdecl: + zctlist ';' + { + dodecl(xdecl, lastclass, lasttype, Z); + } +| zctlist xdlist ';' +| zctlist xdecor + { + lastdcl = T; + firstarg = S; + dodecl(xdecl, lastclass, lasttype, $2); + if(lastdcl == T || lastdcl->etype != TFUNC) { + diag($2, "not a function"); + lastdcl = types[TFUNC]; + } + thisfn = lastdcl; + markdcl(); + firstdcl = dclstack; + argmark($2, 0); + } + pdecl + { + argmark($2, 1); + } + block + { + Node *n; + + n = revertdcl(); + if(n) + $6 = new(OLIST, n, $6); + if(!debug['a'] && !debug['Z']) + codgen($6, $2); + } + +xdlist: + xdecor + { + dodecl(xdecl, lastclass, lasttype, $1); + } +| xdecor + { + $1 = dodecl(xdecl, lastclass, lasttype, $1); + } + '=' init + { + doinit($1->sym, $1->type, 0L, $4); + } +| xdlist ',' xdlist + +xdecor: + xdecor2 +| '*' zgnlist xdecor + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } + +xdecor2: + tag +| '(' xdecor ')' + { + $$ = $2; + } +| xdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| xdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +/* + * automatic declarator + */ +adecl: + { + $$ = Z; + } +| adecl ctlist ';' + { + $$ = dodecl(adecl, lastclass, lasttype, Z); + if($1 != Z) + if($$ != Z) + $$ = new(OLIST, $1, $$); + else + $$ = $1; + } +| adecl ctlist adlist ';' + { + $$ = $1; + if($3 != Z) { + $$ = $3; + if($1 != Z) + $$ = new(OLIST, $1, $3); + } + } + +adlist: + xdecor + { + dodecl(adecl, lastclass, lasttype, $1); + $$ = Z; + } +| xdecor + { + $1 = dodecl(adecl, lastclass, lasttype, $1); + } + '=' init + { + long w; + + w = $1->sym->type->width; + $$ = doinit($1->sym, $1->type, 0L, $4); + $$ = contig($1->sym, $$, w); + } +| adlist ',' adlist + { + $$ = $1; + if($3 != Z) { + $$ = $3; + if($1 != Z) + $$ = new(OLIST, $1, $3); + } + } + +/* + * parameter declarator + */ +pdecl: +| pdecl ctlist pdlist ';' + +pdlist: + xdecor + { + dodecl(pdecl, lastclass, lasttype, $1); + } +| pdlist ',' pdlist + +/* + * structure element declarator + */ +edecl: + tlist + { + lasttype = $1; + } + zedlist ';' +| edecl tlist + { + lasttype = $2; + } + zedlist ';' + +zedlist: /* extension */ + { + lastfield = 0; + edecl(CXXX, lasttype, S); + } +| edlist + +edlist: + edecor + { + dodecl(edecl, CXXX, lasttype, $1); + } +| edlist ',' edlist + +edecor: + xdecor + { + lastbit = 0; + firstbit = 1; + } +| tag ':' lexpr + { + $$ = new(OBIT, $1, $3); + } +| ':' lexpr + { + $$ = new(OBIT, Z, $2); + } + +/* + * abstract declarator + */ +abdecor: + { + $$ = (Z); + } +| abdecor1 + +abdecor1: + '*' zgnlist + { + $$ = new(OIND, (Z), Z); + $$->garb = simpleg($2); + } +| '*' zgnlist abdecor1 + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } +| abdecor2 + +abdecor2: + abdecor3 +| abdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| abdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +abdecor3: + '(' ')' + { + $$ = new(OFUNC, (Z), Z); + } +| '[' zexpr ']' + { + $$ = new(OARRAY, (Z), $2); + } +| '(' abdecor1 ')' + { + $$ = $2; + } + +init: + expr +| '{' ilist '}' + { + $$ = new(OINIT, invert($2), Z); + } + +qual: + '[' lexpr ']' + { + $$ = new(OARRAY, $2, Z); + } +| '.' ltag + { + $$ = new(OELEM, Z, Z); + $$->sym = $2; + } +| qual '=' + +qlist: + init ',' +| qlist init ',' + { + $$ = new(OLIST, $1, $2); + } +| qual +| qlist qual + { + $$ = new(OLIST, $1, $2); + } + +ilist: + qlist +| init +| qlist init + { + $$ = new(OLIST, $1, $2); + } + +zarglist: + { + $$ = Z; + } +| arglist + { + $$ = invert($1); + } + + +arglist: + name +| tlist abdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| tlist xdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| '.' '.' '.' + { + $$ = new(ODOTDOT, Z, Z); + } +| arglist ',' arglist + { + $$ = new(OLIST, $1, $3); + } + +block: + '{' adecl slist '}' + { + $$ = invert($3); + if($2 != Z) + $$ = new(OLIST, $2, $$); + if($$ == Z) + $$ = new(OLIST, Z, Z); + } + +slist: + { + $$ = Z; + } +| slist stmnt + { + $$ = new(OLIST, $1, $2); + } + +labels: + label +| labels label + { + $$ = new(OLIST, $1, $2); + } + +label: + LCASE expr ':' + { + $$ = new(OCASE, $2, Z); + } +| LDEFAULT ':' + { + $$ = new(OCASE, Z, Z); + } +| LNAME ':' + { + $$ = new(OLABEL, dcllabel($1, 1), Z); + } + +stmnt: + error ';' + { + $$ = Z; + } +| ulstmnt +| labels ulstmnt + { + $$ = new(OLIST, $1, $2); + } + +ulstmnt: + zcexpr ';' +| { + markdcl(); + } + block + { + $$ = revertdcl(); + if($$) + $$ = new(OLIST, $$, $2); + else + $$ = $2; + } +| LIF '(' cexpr ')' stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, Z)); + if($5 == Z) + warn($3, "empty if body"); + } +| LIF '(' cexpr ')' stmnt LELSE stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, $7)); + if($5 == Z) + warn($3, "empty if body"); + if($7 == Z) + warn($3, "empty else body"); + } +| LFOR '(' zcexpr ';' zcexpr ';' zcexpr ')' stmnt + { + $$ = new(OFOR, new(OLIST, $5, new(OLIST, $3, $7)), $9); + } +| LWHILE '(' cexpr ')' stmnt + { + $$ = new(OWHILE, $3, $5); + } +| LDO stmnt LWHILE '(' cexpr ')' ';' + { + $$ = new(ODWHILE, $5, $2); + } +| LRETURN zcexpr ';' + { + $$ = new(ORETURN, $2, Z); + $$->type = thisfn->link; + } +| LSWITCH '(' cexpr ')' stmnt + { + $$ = new(OCONST, Z, Z); + $$->vconst = 0; + $$->type = types[TINT]; + $3 = new(OSUB, $$, $3); + + $$ = new(OCONST, Z, Z); + $$->vconst = 0; + $$->type = types[TINT]; + $3 = new(OSUB, $$, $3); + + $$ = new(OSWITCH, $3, $5); + } +| LBREAK ';' + { + $$ = new(OBREAK, Z, Z); + } +| LCONTINUE ';' + { + $$ = new(OCONTINUE, Z, Z); + } +| LGOTO ltag ';' + { + $$ = new(OGOTO, dcllabel($2, 0), Z); + } +| LUSED '(' zelist ')' ';' + { + $$ = new(OUSED, $3, Z); + } +| LSET '(' zelist ')' ';' + { + $$ = new(OSET, $3, Z); + } + +zcexpr: + { + $$ = Z; + } +| cexpr + +zexpr: + { + $$ = Z; + } +| lexpr + +lexpr: + expr + { + $$ = new(OCAST, $1, Z); + $$->type = types[TLONG]; + } + +cexpr: + expr +| cexpr ',' cexpr + { + $$ = new(OCOMMA, $1, $3); + } + +expr: + xuexpr +| expr '*' expr + { + $$ = new(OMUL, $1, $3); + } +| expr '/' expr + { + $$ = new(ODIV, $1, $3); + } +| expr '%' expr + { + $$ = new(OMOD, $1, $3); + } +| expr '+' expr + { + $$ = new(OADD, $1, $3); + } +| expr '-' expr + { + $$ = new(OSUB, $1, $3); + } +| expr LRSH expr + { + $$ = new(OASHR, $1, $3); + } +| expr LLSH expr + { + $$ = new(OASHL, $1, $3); + } +| expr '<' expr + { + $$ = new(OLT, $1, $3); + } +| expr '>' expr + { + $$ = new(OGT, $1, $3); + } +| expr LLE expr + { + $$ = new(OLE, $1, $3); + } +| expr LGE expr + { + $$ = new(OGE, $1, $3); + } +| expr LEQ expr + { + $$ = new(OEQ, $1, $3); + } +| expr LNE expr + { + $$ = new(ONE, $1, $3); + } +| expr '&' expr + { + $$ = new(OAND, $1, $3); + } +| expr '^' expr + { + $$ = new(OXOR, $1, $3); + } +| expr '|' expr + { + $$ = new(OOR, $1, $3); + } +| expr LANDAND expr + { + $$ = new(OANDAND, $1, $3); + } +| expr LOROR expr + { + $$ = new(OOROR, $1, $3); + } +| expr '?' cexpr ':' expr + { + $$ = new(OCOND, $1, new(OLIST, $3, $5)); + } +| expr '=' expr + { + $$ = new(OAS, $1, $3); + } +| expr LPE expr + { + $$ = new(OASADD, $1, $3); + } +| expr LME expr + { + $$ = new(OASSUB, $1, $3); + } +| expr LMLE expr + { + $$ = new(OASMUL, $1, $3); + } +| expr LDVE expr + { + $$ = new(OASDIV, $1, $3); + } +| expr LMDE expr + { + $$ = new(OASMOD, $1, $3); + } +| expr LLSHE expr + { + $$ = new(OASASHL, $1, $3); + } +| expr LRSHE expr + { + $$ = new(OASASHR, $1, $3); + } +| expr LANDE expr + { + $$ = new(OASAND, $1, $3); + } +| expr LXORE expr + { + $$ = new(OASXOR, $1, $3); + } +| expr LORE expr + { + $$ = new(OASOR, $1, $3); + } + +xuexpr: + uexpr +| '(' tlist abdecor ')' xuexpr + { + $$ = new(OCAST, $5, Z); + dodecl(NODECL, CXXX, $2, $3); + $$->type = lastdcl; + $$->xcast = 1; + } +| '(' tlist abdecor ')' '{' ilist '}' /* extension */ + { + $$ = new(OSTRUCT, $6, Z); + dodecl(NODECL, CXXX, $2, $3); + $$->type = lastdcl; + } + +uexpr: + pexpr +| '*' xuexpr + { + $$ = new(OIND, $2, Z); + } +| '&' xuexpr + { + $$ = new(OADDR, $2, Z); + } +| '+' xuexpr + { + $$ = new(OPOS, $2, Z); + } +| '-' xuexpr + { + $$ = new(ONEG, $2, Z); + } +| '!' xuexpr + { + $$ = new(ONOT, $2, Z); + } +| '~' xuexpr + { + $$ = new(OCOM, $2, Z); + } +| LPP xuexpr + { + $$ = new(OPREINC, $2, Z); + } +| LMM xuexpr + { + $$ = new(OPREDEC, $2, Z); + } +| LSIZEOF uexpr + { + $$ = new(OSIZE, $2, Z); + } +| LSIGNOF uexpr + { + $$ = new(OSIGN, $2, Z); + } + +pexpr: + '(' cexpr ')' + { + $$ = $2; + } +| LSIZEOF '(' tlist abdecor ')' + { + $$ = new(OSIZE, Z, Z); + dodecl(NODECL, CXXX, $3, $4); + $$->type = lastdcl; + } +| LSIGNOF '(' tlist abdecor ')' + { + $$ = new(OSIGN, Z, Z); + dodecl(NODECL, CXXX, $3, $4); + $$->type = lastdcl; + } +| pexpr '(' zelist ')' + { + $$ = new(OFUNC, $1, Z); + if($1->op == ONAME) + if($1->type == T) + dodecl(xdecl, CXXX, types[TINT], $$); + $$->right = invert($3); + } +| pexpr '[' cexpr ']' + { + $$ = new(OIND, new(OADD, $1, $3), Z); + } +| pexpr LMG ltag + { + $$ = new(ODOT, new(OIND, $1, Z), Z); + $$->sym = $3; + } +| pexpr '.' ltag + { + $$ = new(ODOT, $1, Z); + $$->sym = $3; + } +| pexpr LPP + { + $$ = new(OPOSTINC, $1, Z); + } +| pexpr LMM + { + $$ = new(OPOSTDEC, $1, Z); + } +| name +| LCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TINT]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LUCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUINT]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LULCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TULONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LDCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TDOUBLE]; + $$->fconst = $1; + $$->cstring = strdup(symb); + } +| LFCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TFLOAT]; + $$->fconst = $1; + $$->cstring = strdup(symb); + } +| LVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TVLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LUVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUVLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| string +| lstring + +string: + LSTRING + { + $$ = new(OSTRING, Z, Z); + $$->type = typ(TARRAY, types[TCHAR]); + $$->type->width = $1.l + 1; + $$->cstring = $1.s; + $$->sym = symstring; + $$->etype = TARRAY; + $$->class = CSTATIC; + } +| string LSTRING + { + char *s; + int n; + + n = $1->type->width - 1; + s = alloc(n+$2.l+MAXALIGN); + + memcpy(s, $1->cstring, n); + memcpy(s+n, $2.s, $2.l); + s[n+$2.l] = 0; + + $$ = $1; + $$->type->width += $2.l; + $$->cstring = s; + } + +lstring: + LLSTRING + { + $$ = new(OLSTRING, Z, Z); + $$->type = typ(TARRAY, types[TUSHORT]); + $$->type->width = $1.l + sizeof(ushort); + $$->rstring = (ushort*)$1.s; + $$->sym = symstring; + $$->etype = TARRAY; + $$->class = CSTATIC; + } +| lstring LLSTRING + { + char *s; + int n; + + n = $1->type->width - sizeof(ushort); + s = alloc(n+$2.l+MAXALIGN); + + memcpy(s, $1->rstring, n); + memcpy(s+n, $2.s, $2.l); + *(ushort*)(s+n+$2.l) = 0; + + $$ = $1; + $$->type->width += $2.l; + $$->rstring = (ushort*)s; + } + +zelist: + { + $$ = Z; + } +| elist + +elist: + expr +| elist ',' elist + { + $$ = new(OLIST, $1, $3); + } + +sbody: + '{' + { + $<tyty>$.t1 = strf; + $<tyty>$.t2 = strl; + strf = T; + strl = T; + lastbit = 0; + firstbit = 1; + } + edecl '}' + { + $$ = strf; + strf = $<tyty>2.t1; + strl = $<tyty>2.t2; + } + +zctlist: + { + lastclass = CXXX; + lasttype = types[TINT]; + } +| ctlist + +types: + complex + { + $$.t = $1; + $$.c = CXXX; + } +| tname + { + $$.t = simplet($1); + $$.c = CXXX; + } +| gcnlist + { + $$.t = simplet($1); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| complex gctnlist + { + $$.t = $1; + $$.c = simplec($2); + $$.t = garbt($$.t, $2); + if($2 & ~BCLASS & ~BGARB) + diag(Z, "duplicate types given: %T and %Q", $1, $2); + } +| tname gctnlist + { + $$.t = simplet(typebitor($1, $2)); + $$.c = simplec($2); + $$.t = garbt($$.t, $2); + } +| gcnlist complex zgnlist + { + $$.t = $2; + $$.c = simplec($1); + $$.t = garbt($$.t, $1|$3); + } +| gcnlist tname + { + $$.t = simplet($2); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| gcnlist tname gctnlist + { + $$.t = simplet(typebitor($2, $3)); + $$.c = simplec($1|$3); + $$.t = garbt($$.t, $1|$3); + } + +tlist: + types + { + $$ = $1.t; + if($1.c != CXXX) + diag(Z, "illegal combination of class 4: %s", cnames[$1.c]); + } + +ctlist: + types + { + lasttype = $1.t; + lastclass = $1.c; + } + +complex: + LSTRUCT ltag + { + dotag($2, TSTRUCT, 0); + $$ = $2->suetag; + } +| LSTRUCT ltag + { + dotag($2, TSTRUCT, autobn); + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + suallign($$); + } +| LSTRUCT sbody + { + taggen++; + sprint(symb, "_%d_", taggen); + $$ = dotag(lookup(), TSTRUCT, autobn); + $$->link = $2; + suallign($$); + } +| LUNION ltag + { + dotag($2, TUNION, 0); + $$ = $2->suetag; + } +| LUNION ltag + { + dotag($2, TUNION, autobn); + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + suallign($$); + } +| LUNION sbody + { + taggen++; + sprint(symb, "_%d_", taggen); + $$ = dotag(lookup(), TUNION, autobn); + $$->link = $2; + suallign($$); + } +| LENUM ltag + { + dotag($2, TENUM, 0); + $$ = $2->suetag; + if($$->link == T) + $$->link = types[TINT]; + $$ = $$->link; + } +| LENUM ltag + { + dotag($2, TENUM, autobn); + } + '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + if(en.tenum == T) { + diag(Z, "enum type ambiguous: %s", $2->name); + en.tenum = types[TINT]; + } + $$->link = en.tenum; + $$ = en.tenum; + } +| LENUM '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = en.tenum; + } +| LTYPE + { + $$ = tcopy($1->type); + } + +gctnlist: + gctname +| gctnlist gctname + { + $$ = typebitor($1, $2); + } + +zgnlist: + { + $$ = 0; + } +| zgnlist gname + { + $$ = typebitor($1, $2); + } + +gctname: + tname +| gname +| cname + +gcnlist: + gcname +| gcnlist gcname + { + $$ = typebitor($1, $2); + } + +gcname: + gname +| cname + +enum: + LNAME + { + doenum($1, Z); + } +| LNAME '=' expr + { + doenum($1, $3); + } +| enum ',' +| enum ',' enum + +tname: /* type words */ + LCHAR { $$ = BCHAR; } +| LSHORT { $$ = BSHORT; } +| LINT { $$ = BINT; } +| LLONG { $$ = BLONG; } +| LSIGNED { $$ = BSIGNED; } +| LUNSIGNED { $$ = BUNSIGNED; } +| LFLOAT { $$ = BFLOAT; } +| LDOUBLE { $$ = BDOUBLE; } +| LVOID { $$ = BVOID; } + +cname: /* class words */ + LAUTO { $$ = BAUTO; } +| LSTATIC { $$ = BSTATIC; } +| LEXTERN { $$ = BEXTERN; } +| LTYPEDEF { $$ = BTYPEDEF; } +| LTYPESTR { $$ = BTYPESTR; } +| LREGISTER { $$ = BREGISTER; } + +gname: /* garbage words */ + LCONSTNT { $$ = BCONSTNT; } +| LVOLATILE { $$ = BVOLATILE; } + +name: + LNAME + { + $$ = new(ONAME, Z, Z); + if($1->class == CLOCAL) + $1 = mkstatic($1); + $$->sym = $1; + $$->type = $1->type; + $$->etype = TVOID; + if($$->type != T) + $$->etype = $$->type->etype; + $$->xoffset = $1->offset; + $$->class = $1->class; + $1->aused = 1; + } +tag: + ltag + { + $$ = new(ONAME, Z, Z); + $$->sym = $1; + $$->type = $1->type; + $$->etype = TVOID; + if($$->type != T) + $$->etype = $$->type->etype; + $$->xoffset = $1->offset; + $$->class = $1->class; + } +ltag: + LNAME +| LTYPE +%% diff --git a/utils/cc/com.c b/utils/cc/com.c new file mode 100644 index 00000000..af16e8d9 --- /dev/null +++ b/utils/cc/com.c @@ -0,0 +1,1164 @@ +#include "cc.h" + +void +complex(Node *n) +{ + + if(n == Z) + return; + + nearln = n->lineno; + if(debug['t']) + if(n->op != OCONST) + prtree(n, "pre complex"); + if(tcom(n)) + return; + if(debug['t']) + if(n->op != OCONST) + prtree(n, "t complex"); + ccom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "c complex"); + acom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "a complex"); + xcom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "x complex"); +} + +/* + * evaluate types + * evaluate lvalues (addable == 1) + */ +enum +{ + ADDROF = 1<<0, + CASTOF = 1<<1, + ADDROP = 1<<2, +}; + +int +tcom(Node *n) +{ + + return tcomo(n, ADDROF); +} + +int +tcomo(Node *n, int f) +{ + Node *l, *r; + Type *t; + int o; + + if(n == Z) { + diag(Z, "Z in tcom"); + errorexit(); + } + n->addable = 0; + l = n->left; + r = n->right; + + switch(n->op) { + default: + diag(n, "unknown op in type complex: %O", n->op); + goto bad; + + case ODOTDOT: + /* + * tcom has already been called on this subtree + */ + *n = *n->left; + if(n->type == T) + goto bad; + break; + + case OCAST: + if(n->type == T) + break; + if(n->type->width == types[TLONG]->width) { + if(tcomo(l, ADDROF|CASTOF)) + goto bad; + } else + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, n->type, tcast)) + goto bad; + break; + + case ORETURN: + if(l == Z) { + if(n->type->etype != TVOID) + warn(n, "null return of a typed function"); + break; + } + if(tcom(l)) + goto bad; + typeext(n->type, l); + if(tcompat(n, n->type, l->type, tasign)) + break; + constas(n, n->type, l->type); + if(!sametype(n->type, l->type)) { + l = new1(OCAST, l, Z); + l->type = n->type; + n->left = l; + } + break; + + case OASI: /* same as as, but no test for const */ + n->op = OAS; + o = tcom(l); + if(o | tcom(r)) + goto bad; + + typeext(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tasign)) + goto bad; + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OAS: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext(l->type, r); + if(tcompat(n, l->type, r->type, tasign)) + goto bad; + constas(n, l->type, r->type); + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OASADD: + case OASSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + if(tcompat(n, l->type, r->type, tasadd)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + break; + + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASDIV) + n->op = OASLDIV; + if(n->op == OASMUL) + n->op = OASLMUL; + } + break; + + case OASLSHR: + case OASASHR: + case OASASHL: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->type = l->type; + if(typeu[n->type->etype]) { + if(n->op == OASASHR) + n->op = OASLSHR; + } + break; + + case OASMOD: + case OASLMOD: + case OASOR: + case OASAND: + case OASXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASMOD) + n->op = OASLMOD; + } + break; + + case OPREINC: + case OPREDEC: + case OPOSTINC: + case OPOSTDEC: + if(tcom(l)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, types[TINT], tadd)) + goto bad; + n->type = l->type; + if(n->type->etype == TIND) + if(n->type->link->width < 1) + diag(n, "inc/dec of a void pointer"); + break; + + case OEQ: + case ONE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + typeext(l->type, r); + typeext(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + n->type = types[TINT]; + break; + + case OLT: + case OGE: + case OGT: + case OLE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + typeext1(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + if(typeu[n->type->etype]) + n->op = logrel[relindex(n->op)]; + n->type = types[TINT]; + break; + + case OCOND: + o = tcom(l); + o |= tcom(r->left); + if(o | tcom(r->right)) + goto bad; + if(r->right->type->etype == TIND && vconst(r->left) == 0) { + r->left->type = r->right->type; + r->left->vconst = 0; + } + if(r->left->type->etype == TIND && vconst(r->right) == 0) { + r->right->type = r->left->type; + r->right->vconst = 0; + } + if(sametype(r->right->type, r->left->type)) { + r->type = r->right->type; + n->type = r->type; + break; + } + if(tcompat(r, r->left->type, r->right->type, trel)) + goto bad; + arith(r, 0); + n->type = r->type; + break; + + case OADD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tadd)) + goto bad; + arith(n, 1); + break; + + case OSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) { + if(n->op == ODIV) + n->op = OLDIV; + if(n->op == OMUL) + n->op = OLMUL; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->right = Z; + arith(n, 1); + n->right = new1(OCAST, r, Z); + n->right->type = types[TINT]; + if(typeu[n->type->etype]) + if(n->op == OASHR) + n->op = OLSHR; + break; + + case OAND: + case OOR: + case OXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + break; + + case OMOD: + case OLMOD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) + n->op = OLMOD; + break; + + case OPOS: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + r = l; + l = new(OCONST, Z, Z); + l->vconst = 0; + l->type = types[TINT]; + n->op = OADD; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case ONEG: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + if(!machcap(n)) { + r = l; + l = new(OCONST, Z, Z); + l->vconst = 0; + l->type = types[TINT]; + n->op = OSUB; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + } + arith(n, 1); + break; + + case OCOM: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + if(!machcap(n)) { + r = l; + l = new(OCONST, Z, Z); + l->vconst = -1; + l->type = types[TINT]; + n->op = OXOR; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + } + arith(n, 1); + break; + + case ONOT: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, T, l->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OANDAND: + case OOROR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, T, l->type, tnot) | + tcompat(n, T, r->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OCOMMA: + o = tcom(l); + if(o | tcom(r)) + goto bad; + n->type = r->type; + break; + + + case OSIGN: /* extension signof(type) returns a hash */ + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "signof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width < 0) { + diag(n, "signof undefined type"); + goto bad; + } + n->op = OCONST; + n->left = Z; + n->right = Z; + n->vconst = convvtox(signature(n->type), TULONG); + n->type = types[TULONG]; + break; + + case OSIZE: + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "sizeof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width <= 0) { + diag(n, "sizeof undefined type"); + goto bad; + } + if(n->type->etype == TFUNC) { + diag(n, "sizeof function"); + goto bad; + } + n->op = OCONST; + n->left = Z; + n->right = Z; + n->vconst = convvtox(n->type->width, TINT); + n->type = types[TINT]; + break; + + case OFUNC: + o = tcomo(l, 0); + if(o) + goto bad; + if(l->type->etype == TIND && l->type->link->etype == TFUNC) { + l = new1(OIND, l, Z); + l->type = l->left->type->link; + n->left = l; + } + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(o | tcoma(l, r, l->type->down, 1)) + goto bad; + n->type = l->type->link; + if(!debug['B']) + if(l->type->down == T || l->type->down->etype == TOLD) { + nerrors--; + diag(n, "function args not checked: %F", l); + } + dpcheck(n); + break; + + case ONAME: + if(n->type == T) { + diag(n, "name not declared: %F", n); + goto bad; + } + if(n->type->etype == TENUM) { + n->op = OCONST; + n->type = n->sym->tenum; + if(!typefd[n->type->etype]) + n->vconst = n->sym->vconst; + else + n->fconst = n->sym->fconst; + break; + } + n->addable = 1; + if(n->class == CEXREG) { + n->op = OREGISTER; + n->reg = n->sym->offset; + n->xoffset = 0; + break; + } + break; + + case OLSTRING: + if(n->type->link != types[TUSHORT]) { + o = outstring(0, 0); + while(o & 3) { + outlstring(L"", sizeof(ushort)); + o = outlstring(0, 0); + } + } + n->op = ONAME; + n->xoffset = outlstring(n->rstring, n->type->width); + n->addable = 1; + break; + + case OSTRING: + if(n->type->link != types[TCHAR]) { + o = outstring(0, 0); + while(o & 3) { + outstring("", 1); + o = outstring(0, 0); + } + } + n->op = ONAME; + n->xoffset = outstring(n->cstring, n->type->width); + n->addable = 1; + break; + + case OCONST: + break; + + case ODOT: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tdot)) + goto bad; + if(tcomd(n)) + goto bad; + break; + + case OADDR: + if(tcomo(l, ADDROP)) + goto bad; + if(tlvalue(l)) + goto bad; + if(l->type->nbits) { + diag(n, "address of a bit field"); + goto bad; + } + if(l->op == OREGISTER) { + diag(n, "address of a register"); + goto bad; + } + n->type = typ(TIND, l->type); + n->type->width = types[TIND]->width; + break; + + case OIND: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tindir)) + goto bad; + n->type = l->type->link; + n->addable = 1; + break; + + case OSTRUCT: + if(tcomx(n)) + goto bad; + break; + } + t = n->type; + if(t == T) + goto bad; + if(t->width < 0) { + snap(t); + if(t->width < 0) { + if(typesu[t->etype] && t->tag) + diag(n, "structure not fully declared %s", t->tag->name); + else + diag(n, "structure not fully declared"); + goto bad; + } + } + if(typeaf[t->etype]) { + if(f & ADDROF) + goto addaddr; + if(f & ADDROP) + warn(n, "address of array/func ignored"); + } + return 0; + +addaddr: + if(tlvalue(n)) + goto bad; + l = new1(OXXX, Z, Z); + *l = *n; + n->op = OADDR; + if(l->type->etype == TARRAY) + l->type = l->type->link; + n->left = l; + n->right = Z; + n->addable = 0; + n->type = typ(TIND, l->type); + n->type->width = types[TIND]->width; + return 0; + +bad: + n->type = T; + return 1; +} + +int +tcoma(Node *l, Node *n, Type *t, int f) +{ + Node *n1; + int o; + + if(t != T) + if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */ + t = T; + if(n == Z) { + if(t != T && !sametype(t, types[TVOID])) { + diag(n, "not enough function arguments: %F", l); + return 1; + } + return 0; + } + if(n->op == OLIST) { + o = tcoma(l, n->left, t, 0); + if(t != T) { + t = t->down; + if(t == T) + t = types[TVOID]; + } + return o | tcoma(l, n->right, t, 1); + } + if(f && t != T) + tcoma(l, Z, t->down, 0); + if(tcom(n) || tcompat(n, T, n->type, targ)) + return 1; + if(sametype(t, types[TVOID])) { + diag(n, "too many function arguments: %F", l); + return 1; + } + if(t != T) { + typeext(t, n); + if(stcompat(nodproto, t, n->type, tasign)) { + diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F", + n->type, t, l); + return 1; + } + switch(t->etype) { + case TCHAR: + case TSHORT: + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + t = types[TUINT]; + break; + } + } else + switch(n->type->etype) + { + case TCHAR: + case TSHORT: + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + t = types[TUINT]; + break; + + case TFLOAT: + t = types[TDOUBLE]; + } + if(t != T && !sametype(t, n->type)) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = t; + n->addable = 0; + } + return 0; +} + +int +tcomd(Node *n) +{ + Type *t; + long o; + + o = 0; + t = dotsearch(n->sym, n->left->type->link, n, &o); + if(t == T) { + diag(n, "not a member of struct/union: %F", n); + return 1; + } + makedot(n, t, o); + return 0; +} + +int +tcomx(Node *n) +{ + Type *t; + Node *l, *r, **ar, **al; + int e; + + e = 0; + if(n->type->etype != TSTRUCT) { + diag(n, "constructor must be a structure"); + return 1; + } + l = invert(n->left); + n->left = l; + al = &n->left; + for(t = n->type->link; t != T; t = t->down) { + if(l == Z) { + diag(n, "constructor list too short"); + return 1; + } + if(l->op == OLIST) { + r = l->left; + ar = &l->left; + al = &l->right; + l = l->right; + } else { + r = l; + ar = al; + l = Z; + } + if(tcom(r)) + e++; + typeext(t, r); + if(tcompat(n, t, r->type, tasign)) + e++; + constas(n, t, r->type); + if(!e && !sametype(t, r->type)) { + r = new1(OCAST, r, Z); + r->type = t; + *ar = r; + } + } + if(l != Z) { + diag(n, "constructor list too long"); + return 1; + } + return e; +} + +int +tlvalue(Node *n) +{ + + if(!n->addable) { + diag(n, "not an l-value"); + return 1; + } + return 0; +} + +/* + * general rewrite + * (IND(ADDR x)) ==> x + * (ADDR(IND x)) ==> x + * remove some zero operands + * remove no op casts + * evaluate constants + */ +void +ccom(Node *n) +{ + Node *l, *r; + int t; + +loop: + if(n == Z) + return; + l = n->left; + r = n->right; + switch(n->op) { + + case OAS: + case OASXOR: + case OASAND: + case OASOR: + case OASMOD: + case OASLMOD: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASDIV: + case OASLDIV: + case OASMUL: + case OASLMUL: + case OASSUB: + case OASADD: + ccom(l); + ccom(r); + if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL) + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst < 0) + warn(n, "stupid shift: %lld", r->vconst); + } + break; + + case OCAST: + ccom(l); + if(l->op == OCONST) { + evconst(n); + if(n->op == OCONST) + break; + } + if(nocast(l->type, n->type)) { + l->type = n->type; + *n = *l; + } + break; + + case OCOND: + ccom(l); + ccom(r); + if(l->op == OCONST) + if(vconst(l) == 0) + *n = *r->right; + else + *n = *r->left; + break; + + case OREGISTER: + case OINDREG: + case OCONST: + case ONAME: + break; + + case OADDR: + ccom(l); + l->etype = TVOID; + if(l->op == OIND) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OIND: + ccom(l); + if(l->op == OADDR) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OEQ: + case ONE: + + case OLE: + case OGE: + case OLT: + case OGT: + + case OLS: + case OHS: + case OLO: + case OHI: + ccom(l); + ccom(r); + relcon(l, r); + relcon(r, l); + goto common; + + case OASHR: + case OASHL: + case OLSHR: + ccom(l); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + ccom(r); + if(vconst(r) == 0) { + *n = *l; + break; + } + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst <= -t) + warn(n, "stupid shift: %lld", r->vconst); + } + goto common; + + case OMUL: + case OLMUL: + ccom(l); + t = vconst(l); + if(t == 0 && !side(r)) { + *n = *l; + break; + } + if(t == 1) { + *n = *r; + goto loop; + } + ccom(r); + t = vconst(r); + if(t == 0 && !side(l)) { + *n = *r; + break; + } + if(t == 1) { + *n = *l; + break; + } + goto common; + + case ODIV: + case OLDIV: + ccom(l); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + ccom(r); + t = vconst(r); + if(t == 0) { + diag(n, "divide check"); + *n = *r; + break; + } + if(t == 1) { + *n = *l; + break; + } + goto common; + + case OSUB: + ccom(r); + if(r->op == OCONST) { + if(typefd[r->type->etype]) { + n->op = OADD; + r->fconst = -r->fconst; + goto loop; + } else { + n->op = OADD; + r->vconst = -r->vconst; + goto loop; + } + } + ccom(l); + goto common; + + case OXOR: + case OOR: + case OADD: + ccom(l); + if(vconst(l) == 0) { + *n = *r; + goto loop; + } + ccom(r); + if(vconst(r) == 0) { + *n = *l; + break; + } + goto commun; + + case OAND: + ccom(l); + ccom(r); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + if(vconst(r) == 0 && !side(l)) { + *n = *r; + break; + } + + commun: + /* look for commutative constant */ + if(r->op == OCONST) { + if(l->op == n->op) { + if(l->left->op == OCONST) { + n->right = l->right; + l->right = r; + goto loop; + } + if(l->right->op == OCONST) { + n->right = l->left; + l->left = r; + goto loop; + } + } + } + if(l->op == OCONST) { + if(r->op == n->op) { + if(r->left->op == OCONST) { + n->left = r->right; + r->right = l; + goto loop; + } + if(r->right->op == OCONST) { + n->left = r->left; + r->left = l; + goto loop; + } + } + } + goto common; + + case OANDAND: + ccom(l); + if(vconst(l) == 0) { + *n = *l; + break; + } + ccom(r); + goto common; + + case OOROR: + ccom(l); + if(l->op == OCONST && l->vconst != 0) { + *n = *l; + n->vconst = 1; + break; + } + ccom(r); + goto common; + + default: + if(l != Z) + ccom(l); + if(r != Z) + ccom(r); + common: + if(l != Z) + if(l->op != OCONST) + break; + if(r != Z) + if(r->op != OCONST) + break; + evconst(n); + } +} diff --git a/utils/cc/com64.c b/utils/cc/com64.c new file mode 100644 index 00000000..88bf11bf --- /dev/null +++ b/utils/cc/com64.c @@ -0,0 +1,611 @@ +#include "cc.h" + +/* + * this is machine depend, but it is totally + * common on all of the 64-bit symulating machines. + */ + +#define FNX 100 /* botch -- redefinition */ + +Node* nodaddv; +Node* nodsubv; +Node* nodmulv; +Node* noddivv; +Node* noddivvu; +Node* nodmodv; +Node* nodmodvu; +Node* nodlshv; +Node* nodrshav; +Node* nodrshlv; +Node* nodandv; +Node* nodorv; +Node* nodxorv; +Node* nodnegv; +Node* nodcomv; + +Node* nodtestv; +Node* nodeqv; +Node* nodnev; +Node* nodlev; +Node* nodltv; +Node* nodgev; +Node* nodgtv; +Node* nodhiv; +Node* nodhsv; +Node* nodlov; +Node* nodlsv; + +Node* nodf2v; +Node* nodd2v; +Node* nodp2v; +Node* nodsi2v; +Node* nodui2v; +Node* nodsl2v; +Node* nodul2v; +Node* nodsh2v; +Node* noduh2v; +Node* nodsc2v; +Node* noduc2v; + +Node* nodv2f; +Node* nodv2d; +Node* nodv2ui; +Node* nodv2si; +Node* nodv2ul; +Node* nodv2sl; +Node* nodv2uh; +Node* nodv2sh; +Node* nodv2uc; +Node* nodv2sc; + +Node* nodvpp; +Node* nodppv; +Node* nodvmm; +Node* nodmmv; + +Node* nodvasop; + +char etconv[NTYPE]; /* for _vasop */ +Init initetconv[] = +{ + TCHAR, 1, 0, + TUCHAR, 2, 0, + TSHORT, 3, 0, + TUSHORT, 4, 0, + TLONG, 5, 0, + TULONG, 6, 0, + TVLONG, 7, 0, + TUVLONG, 8, 0, + TINT, 9, 0, + TUINT, 10, 0, + -1, 0, 0, +}; + +Node* +fvn(char *name, int type) +{ + Node *n; + + n = new(ONAME, Z, Z); + n->sym = slookup(name); + n->sym->sig = SIGINTERN; + if(fntypes[type] == 0) + fntypes[type] = typ(TFUNC, types[type]); + n->type = fntypes[type]; + n->etype = type; + n->class = CGLOBL; + n->addable = 10; + n->complex = 0; + return n; +} + +void +com64init(void) +{ + Init *p; + + nodaddv = fvn("_addv", TVLONG); + nodsubv = fvn("_subv", TVLONG); + nodmulv = fvn("_mulv", TVLONG); + noddivv = fvn("_divv", TVLONG); + noddivvu = fvn("_divvu", TVLONG); + nodmodv = fvn("_modv", TVLONG); + nodmodvu = fvn("_modvu", TVLONG); + nodlshv = fvn("_lshv", TVLONG); + nodrshav = fvn("_rshav", TVLONG); + nodrshlv = fvn("_rshlv", TVLONG); + nodandv = fvn("_andv", TVLONG); + nodorv = fvn("_orv", TVLONG); + nodxorv = fvn("_xorv", TVLONG); + nodnegv = fvn("_negv", TVLONG); + nodcomv = fvn("_comv", TVLONG); + + nodtestv = fvn("_testv", TLONG); + nodeqv = fvn("_eqv", TLONG); + nodnev = fvn("_nev", TLONG); + nodlev = fvn("_lev", TLONG); + nodltv = fvn("_ltv", TLONG); + nodgev = fvn("_gev", TLONG); + nodgtv = fvn("_gtv", TLONG); + nodhiv = fvn("_hiv", TLONG); + nodhsv = fvn("_hsv", TLONG); + nodlov = fvn("_lov", TLONG); + nodlsv = fvn("_lsv", TLONG); + + nodf2v = fvn("_f2v", TVLONG); + nodd2v = fvn("_d2v", TVLONG); + nodp2v = fvn("_p2v", TVLONG); + nodsi2v = fvn("_si2v", TVLONG); + nodui2v = fvn("_ui2v", TVLONG); + nodsl2v = fvn("_sl2v", TVLONG); + nodul2v = fvn("_ul2v", TVLONG); + nodsh2v = fvn("_sh2v", TVLONG); + noduh2v = fvn("_uh2v", TVLONG); + nodsc2v = fvn("_sc2v", TVLONG); + noduc2v = fvn("_uc2v", TVLONG); + + nodv2f = fvn("_v2f", TFLOAT); + nodv2d = fvn("_v2d", TDOUBLE); + nodv2sl = fvn("_v2sl", TLONG); + nodv2ul = fvn("_v2ul", TULONG); + nodv2si = fvn("_v2si", TINT); + nodv2ui = fvn("_v2ui", TUINT); + nodv2sh = fvn("_v2sh", TSHORT); + nodv2uh = fvn("_v2ul", TUSHORT); + nodv2sc = fvn("_v2sc", TCHAR); + nodv2uc = fvn("_v2uc", TUCHAR); + + nodvpp = fvn("_vpp", TVLONG); + nodppv = fvn("_ppv", TVLONG); + nodvmm = fvn("_vmm", TVLONG); + nodmmv = fvn("_mmv", TVLONG); + + nodvasop = fvn("_vasop", TVLONG); + + for(p = initetconv; p->code >= 0; p++) + etconv[p->code] = p->value; +} + +int +com64(Node *n) +{ + Node *l, *r, *a, *t; + int lv, rv; + + if(n->type == 0) + return 0; + + l = n->left; + r = n->right; + + lv = 0; + if(l && l->type && typev[l->type->etype]) + lv = 1; + rv = 0; + if(r && r->type && typev[r->type->etype]) + rv = 1; + + if(lv) { + switch(n->op) { + case OEQ: + a = nodeqv; + goto setbool; + case ONE: + a = nodnev; + goto setbool; + case OLE: + a = nodlev; + goto setbool; + case OLT: + a = nodltv; + goto setbool; + case OGE: + a = nodgev; + goto setbool; + case OGT: + a = nodgtv; + goto setbool; + case OHI: + a = nodhiv; + goto setbool; + case OHS: + a = nodhsv; + goto setbool; + case OLO: + a = nodlov; + goto setbool; + case OLS: + a = nodlsv; + goto setbool; + + case OANDAND: + case OOROR: + if(machcap(n)) + return 1; + + if(rv) { + r = new(OFUNC, nodtestv, r); + n->right = r; + r->complex = FNX; + r->op = OFUNC; + r->type = types[TLONG]; + } + + case OCOND: + case ONOT: + if(machcap(n)) + return 1; + + l = new(OFUNC, nodtestv, l); + n->left = l; + l->complex = FNX; + l->op = OFUNC; + l->type = types[TLONG]; + n->complex = FNX; + return 1; + } + } + + if(rv) { + if(machcap(n)) + return 1; + switch(n->op) { + case OANDAND: + case OOROR: + r = new(OFUNC, nodtestv, r); + n->right = r; + r->complex = FNX; + r->op = OFUNC; + r->type = types[TLONG]; + return 1; + } + } + + if(typev[n->type->etype]) { + if(machcap(n)) + return 1; + switch(n->op) { + default: + diag(n, "unknown vlong %O", n->op); + case OFUNC: + n->complex = FNX; + case ORETURN: + case OAS: + case OIND: + return 1; + case OADD: + a = nodaddv; + goto setbop; + case OSUB: + a = nodsubv; + goto setbop; + case OMUL: + case OLMUL: + a = nodmulv; + goto setbop; + case ODIV: + a = noddivv; + goto setbop; + case OLDIV: + a = noddivvu; + goto setbop; + case OMOD: + a = nodmodv; + goto setbop; + case OLMOD: + a = nodmodvu; + goto setbop; + case OASHL: + a = nodlshv; + goto setbop; + case OASHR: + a = nodrshav; + goto setbop; + case OLSHR: + a = nodrshlv; + goto setbop; + case OAND: + a = nodandv; + goto setbop; + case OOR: + a = nodorv; + goto setbop; + case OXOR: + a = nodxorv; + goto setbop; + case OPOSTINC: + a = nodvpp; + goto setvinc; + case OPOSTDEC: + a = nodvmm; + goto setvinc; + case OPREINC: + a = nodppv; + goto setvinc; + case OPREDEC: + a = nodmmv; + goto setvinc; + case ONEG: + a = nodnegv; + goto setfnx; + case OCOM: + a = nodcomv; + goto setfnx; + case OCAST: + switch(l->type->etype) { + case TCHAR: + a = nodsc2v; + goto setfnxl; + case TUCHAR: + a = noduc2v; + goto setfnxl; + case TSHORT: + a = nodsh2v; + goto setfnxl; + case TUSHORT: + a = noduh2v; + goto setfnxl; + case TINT: + a = nodsi2v; + goto setfnx; + case TUINT: + a = nodui2v; + goto setfnx; + case TLONG: + a = nodsl2v; + goto setfnx; + case TULONG: + a = nodul2v; + goto setfnx; + case TFLOAT: + a = nodf2v; + goto setfnx; + case TDOUBLE: + a = nodd2v; + goto setfnx; + case TIND: + a = nodp2v; + goto setfnx; + } + diag(n, "unknown %T->vlong cast", l->type); + return 1; + case OASADD: + a = nodaddv; + goto setasop; + case OASSUB: + a = nodsubv; + goto setasop; + case OASMUL: + case OASLMUL: + a = nodmulv; + goto setasop; + case OASDIV: + a = noddivv; + goto setasop; + case OASLDIV: + a = noddivvu; + goto setasop; + case OASMOD: + a = nodmodv; + goto setasop; + case OASLMOD: + a = nodmodvu; + goto setasop; + case OASASHL: + a = nodlshv; + goto setasop; + case OASASHR: + a = nodrshav; + goto setasop; + case OASLSHR: + a = nodrshlv; + goto setasop; + case OASAND: + a = nodandv; + goto setasop; + case OASOR: + a = nodorv; + goto setasop; + case OASXOR: + a = nodxorv; + goto setasop; + } + } + + if(typefd[n->type->etype] && l && l->op == OFUNC) { + switch(n->op) { + case OASADD: + case OASSUB: + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + case OASMOD: + case OASLMOD: + case OASASHL: + case OASASHR: + case OASLSHR: + case OASAND: + case OASOR: + case OASXOR: + if(l->right && typev[l->right->etype]) { + diag(n, "sorry float <asop> vlong not implemented\n"); + } + } + } + + if(n->op == OCAST) { + if(l->type && typev[l->type->etype]) { + if(machcap(n)) + return 1; + switch(n->type->etype) { + case TDOUBLE: + a = nodv2d; + goto setfnx; + case TFLOAT: + a = nodv2f; + goto setfnx; + case TLONG: + a = nodv2sl; + goto setfnx; + case TULONG: + a = nodv2ul; + goto setfnx; + case TINT: + a = nodv2si; + goto setfnx; + case TUINT: + a = nodv2ui; + goto setfnx; + case TSHORT: + a = nodv2sh; + goto setfnx; + case TUSHORT: + a = nodv2uh; + goto setfnx; + case TCHAR: + a = nodv2sc; + goto setfnx; + case TUCHAR: + a = nodv2uc; + goto setfnx; + case TIND: // small pun here + a = nodv2ul; + goto setfnx; + } + diag(n, "unknown vlong->%T cast", n->type); + return 1; + } + } + + return 0; + +setbop: + n->left = a; + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + return 1; + +setfnxl: + l = new(OCAST, l, 0); + l->type = types[TLONG]; + l->complex = l->left->complex; + +setfnx: + n->left = a; + n->right = l; + n->complex = FNX; + n->op = OFUNC; + return 1; + +setvinc: + n->left = a; + l = new(OADDR, l, Z); + l->type = typ(TIND, l->left->type); + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + return 1; + +setbool: + if(machcap(n)) + return 1; + n->left = a; + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + n->type = types[TLONG]; + return 1; + +setasop: + if(l->op == OFUNC) { + l = l->right; + goto setasop; + } + + t = new(OCONST, 0, 0); + t->vconst = etconv[l->type->etype]; + t->type = types[TLONG]; + t->addable = 20; + r = new(OLIST, t, r); + + t = new(OADDR, a, 0); + t->type = typ(TIND, a->type); + r = new(OLIST, t, r); + + t = new(OADDR, l, 0); + t->type = typ(TIND, l->type); + r = new(OLIST, t, r); + + n->left = nodvasop; + n->right = r; + n->complex = FNX; + n->op = OFUNC; + + return 1; +} + +void +bool64(Node *n) +{ + Node *n1; + + if(typev[n->type->etype]) { + n1 = new(OXXX, 0, 0); + *n1 = *n; + + n->right = n1; + n->left = nodtestv; + n->complex = FNX; + n->addable = 0; + n->op = OFUNC; + n->type = types[TLONG]; + } +} + +/* + * more machine depend stuff. + * this is common for 8,16,32,64 bit machines. + * this is common for ieee machines. + */ +double +convvtof(vlong v) +{ + double d; + + d = v; /* BOTCH */ + return d; +} + +vlong +convftov(double d) +{ + vlong v; + + + v = d; /* BOTCH */ + return v; +} + +double +convftox(double d, int et) +{ + + if(!typefd[et]) + diag(Z, "bad type in castftox %s", tnames[et]); + return d; +} + +vlong +convvtox(vlong c, int et) +{ + int n; + + n = 8 * ewidth[et]; + c &= MASK(n); + if(!typeu[et]) + if(c & SIGN(n)) + c |= ~MASK(n); + return c; +} diff --git a/utils/cc/dcl.c b/utils/cc/dcl.c new file mode 100644 index 00000000..71925701 --- /dev/null +++ b/utils/cc/dcl.c @@ -0,0 +1,1630 @@ +#include "cc.h" + +Node* +dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) +{ + Sym *s; + Node *n1; + long v; + + nearln = lineno; + lastfield = 0; + +loop: + if(n != Z) + switch(n->op) { + default: + diag(n, "unknown declarator: %O", n->op); + break; + + case OARRAY: + t = typ(TARRAY, t); + t->width = 0; + n1 = n->right; + n = n->left; + if(n1 != Z) { + complex(n1); + v = -1; + if(n1->op == OCONST) + v = n1->vconst; + if(v <= 0) { + diag(n, "array size must be a positive constant"); + v = 1; + } + t->width = v * t->link->width; + } + goto loop; + + case OIND: + t = typ(TIND, t); + t->garb = n->garb; + n = n->left; + goto loop; + + case OFUNC: + t = typ(TFUNC, t); + t->down = fnproto(n); + n = n->left; + goto loop; + + case OBIT: + n1 = n->right; + complex(n1); + lastfield = -1; + if(n1->op == OCONST) + lastfield = n1->vconst; + if(lastfield < 0) { + diag(n, "field width must be non-negative constant"); + lastfield = 1; + } + if(lastfield == 0) { + lastbit = 0; + firstbit = 1; + if(n->left != Z) { + diag(n, "zero width named field"); + lastfield = 1; + } + } + if(!typei[t->etype]) { + diag(n, "field type must be int-like"); + t = types[TINT]; + lastfield = 1; + } + if(lastfield > tfield->width*8) { + diag(n, "field width larger than field unit"); + lastfield = 1; + } + lastbit += lastfield; + if(lastbit > tfield->width*8) { + lastbit = lastfield; + firstbit = 1; + } + n = n->left; + goto loop; + + case ONAME: + if(f == NODECL) + break; + s = n->sym; + (*f)(c, t, s); + if(s->class == CLOCAL) + s = mkstatic(s); + firstbit = 0; + n->sym = s; + n->type = s->type; + n->xoffset = s->offset; + n->class = s->class; + n->etype = TVOID; + if(n->type != T) + n->etype = n->type->etype; + if(debug['d']) + dbgdecl(s); + acidvar(s); + s->varlineno = lineno; + break; + } + lastdcl = t; + return n; +} + +Sym* +mkstatic(Sym *s) +{ + Sym *s1; + + if(s->class != CLOCAL) + return s; + snprint(symb, NSYMB, "%s$%d", s->name, s->block); + s1 = lookup(); + if(s1->class != CSTATIC) { + s1->type = s->type; + s1->offset = s->offset; + s1->block = s->block; + s1->class = CSTATIC; + } + return s1; +} + +/* + * make a copy of a typedef + * the problem is to split out incomplete + * arrays so that it is in the variable + * rather than the typedef. + */ +Type* +tcopy(Type *t) +{ + Type *tl, *tx; + int et; + + if(t == T) + return t; + et = t->etype; + if(typesu[et]) + return t; + tl = tcopy(t->link); + if(tl != t->link || + (et == TARRAY && t->width == 0)) { + tx = copytyp(t); + tx->link = tl; + return tx; + } + return t; +} + +Node* +doinit(Sym *s, Type *t, long o, Node *a) +{ + Node *n; + + if(t == T) + return Z; + if(s->class == CEXTERN) { + s->class = CGLOBL; + if(debug['d']) + dbgdecl(s); + } + if(debug['i']) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "doinit value"); + } + + + n = initlist; + if(a->op == OINIT) + a = a->left; + initlist = a; + + a = init1(s, t, o, 0); + if(initlist != Z) + diag(initlist, "more initializers than structure: %s", + s->name); + initlist = n; + + return a; +} + +/* + * get next major operator, + * dont advance initlist. + */ +Node* +peekinit(void) +{ + Node *a; + + a = initlist; + +loop: + if(a == Z) + return a; + if(a->op == OLIST) { + a = a->left; + goto loop; + } + return a; +} + +/* + * consume and return next element on + * initlist. expand strings. + */ +Node* +nextinit(void) +{ + Node *a, *b, *n; + + a = initlist; + n = Z; + + if(a == Z) + return a; + if(a->op == OLIST) { + n = a->right; + a = a->left; + } + if(a->op == OUSED) { + a = a->left; + b = new(OCONST, Z, Z); + b->type = a->type->link; + if(a->op == OSTRING) { + b->vconst = convvtox(*a->cstring, TCHAR); + a->cstring++; + } + if(a->op == OLSTRING) { + b->vconst = convvtox(*a->rstring, TUSHORT); + a->rstring++; + } + a->type->width -= b->type->width; + if(a->type->width <= 0) + initlist = n; + return b; + } + initlist = n; + return a; +} + +int +isstruct(Node *a, Type *t) +{ + Node *n; + + switch(a->op) { + case ODOTDOT: + n = a->left; + if(n && n->type && sametype(n->type, t)) + return 1; + case OSTRING: + case OLSTRING: + case OCONST: + case OINIT: + case OELEM: + return 0; + } + + n = new(ODOTDOT, Z, Z); + *n = *a; + + /* + * ODOTDOT is a flag for tcom + * a second tcom will not be performed + */ + a->op = ODOTDOT; + a->left = n; + a->right = Z; + + if(tcom(n)) + return 0; + + if(sametype(n->type, t)) + return 1; + return 0; +} + +Node* +init1(Sym *s, Type *t, long o, int exflag) +{ + Node *a, *l, *r, nod; + Type *t1; + long e, w, so, mw; + + a = peekinit(); + if(a == Z) + return Z; + + if(debug['i']) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "init1 value"); + } + + if(exflag && a->op == OINIT) + return doinit(s, t, o, nextinit()); + + switch(t->etype) { + default: + diag(Z, "unknown type in initialization: %T to: %s", t, s->name); + return Z; + + case TCHAR: + case TUCHAR: + case TINT: + case TUINT: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TIND: + single: + if(a->op == OARRAY || a->op == OELEM) + return Z; + + a = nextinit(); + if(a == Z) + return Z; + + if(t->nbits) + diag(Z, "cannot initialize bitfields"); + if(s->class == CAUTO) { + l = new(ONAME, Z, Z); + l->sym = s; + l->type = t; + l->etype = TVOID; + if(s->type) + l->etype = s->type->etype; + l->xoffset = s->offset + o; + l->class = s->class; + + l = new(OASI, l, a); + return l; + } + + complex(a); + if(a->type == T) + return Z; + + if(a->op == OCONST) { + if(!sametype(a->type, t)) { + /* hoop jumping to save malloc */ + if(nodcast == Z) + nodcast = new(OCAST, Z, Z); + nod = *nodcast; + nod.left = a; + nod.type = t; + nod.lineno = a->lineno; + complex(&nod); + if(nod.type) + *a = nod; + } + if(a->op != OCONST) { + diag(a, "initializer is not a constant: %s", + s->name); + return Z; + } + if(vconst(a) == 0) + return Z; + goto gext; + } + if(t->etype == TIND) { + while(a->op == OCAST) { + warn(a, "CAST in initialization ignored"); + a = a->left; + } + if(!sametype(t, a->type)) { + diag(a, "initialization of incompatible pointers: %s\n%T and %T", + s->name, t, a->type); + } + if(a->op == OADDR) + a = a->left; + goto gext; + } + + while(a->op == OCAST) + a = a->left; + if(a->op == OADDR) { + warn(a, "initialize pointer to an integer: %s", s->name); + a = a->left; + goto gext; + } + diag(a, "initializer is not a constant: %s", s->name); + return Z; + + gext: + gextern(s, a, o, t->width); + + return Z; + + case TARRAY: + w = t->link->width; + if(a->op == OSTRING || a->op == OLSTRING) + if(typei[t->link->etype]) { + /* + * get rid of null if sizes match exactly + */ + a = nextinit(); + mw = t->width/w; + so = a->type->width/a->type->link->width; + if(mw && so > mw) { + if(so != mw+1) + diag(a, "string initialization larger than array"); + a->type->width -= a->type->link->width; + } + + /* + * arrange strings to be expanded + * inside OINIT braces. + */ + a = new(OUSED, a, Z); + return doinit(s, t, o, a); + } + + mw = -w; + l = Z; + for(e=0;;) { + /* + * peek ahead for element initializer + */ + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM && t->link->etype != TSTRUCT) + break; + if(a->op == OARRAY) { + if(e && exflag) + break; + a = nextinit(); + r = a->left; + complex(r); + if(r->op != OCONST) { + diag(r, "initializer subscript must be constant"); + return Z; + } + e = r->vconst; + if(t->width != 0) + if(e < 0 || e*w >= t->width) { + diag(a, "initialization index out of range: %ld", e); + continue; + } + } + + so = e*w; + if(so > mw) + mw = so; + if(t->width != 0) + if(mw >= t->width) + break; + r = init1(s, t->link, o+so, 1); + l = newlist(l, r); + e++; + } + if(t->width == 0) + t->width = mw+w; + return l; + + case TUNION: + case TSTRUCT: + /* + * peek ahead to find type of rhs. + * if its a structure, then treat + * this element as a variable + * rather than an aggregate. + */ + if(isstruct(a, t)) + goto single; + + if(t->width <= 0) { + diag(Z, "incomplete structure: %s", s->name); + return Z; + } + l = Z; + + again: + for(t1 = t->link; t1 != T; t1 = t1->down) { + if(a->op == OARRAY && t1->etype != TARRAY) + break; + if(a->op == OELEM) { + if(t1->sym != a->sym) + continue; + nextinit(); + } + r = init1(s, t1, o+t1->offset, 1); + l = newlist(l, r); + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM) + goto again; + } + if(a && a->op == OELEM) + diag(a, "structure element not found %F", a); + return l; + } +} + +Node* +newlist(Node *l, Node *r) +{ + if(r == Z) + return l; + if(l == Z) + return r; + return new(OLIST, l, r); +} + +void +suallign(Type *t) +{ + Type *l; + long o, w; + + o = 0; + switch(t->etype) { + + case TSTRUCT: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->nbits) { + if(l->shift <= 0) { + l->shift = -l->shift; + w = round(w, tfield->width); + o = w; + w += tfield->width; + } + l->offset = o; + } else { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete structure element: %s", + l->sym->name); + else + diag(Z, "incomplete structure element"); + w = align(w, l, Ael1); + l->offset = w; + w = align(w, l, Ael2); + } + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + pickletype(t); + return; + + case TUNION: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete union element: %s", + l->sym->name); + else + diag(Z, "incomplete union element"); + l->offset = 0; + l->shift = 0; + o = align(align(0, l, Ael1), l, Ael2); + if(o > w) + w = o; + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + pickletype(t); + return; + + default: + diag(Z, "unknown type in suallign: %T", t); + break; + } +} + +long +round(long v, int w) +{ + int r; + + if(w <= 0 || w > 8) { + diag(Z, "rounding by %d", w); + w = 1; + } + r = v%w; + if(r) + v += w-r; + return v; +} + +Type* +ofnproto(Node *n) +{ + Type *tl, *tr, *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + tl = ofnproto(n->left); + tr = ofnproto(n->right); + if(tl == T) + return tr; + tl->down = tr; + return tl; + + case ONAME: + t = copytyp(n->sym->type); + t->down = T; + return t; + } + return T; +} + +#define ANSIPROTO 1 +#define OLDPROTO 2 + +void +argmark(Node *n, int pass) +{ + Type *t; + + autoffset = align(0, thisfn->link, Aarg0); + stkoff = 0; + for(; n->left != Z; n = n->left) { + if(n->op != OFUNC || n->left->op != ONAME) + continue; + walkparam(n->right, pass); + if(pass != 0 && anyproto(n->right) == OLDPROTO) { + t = typ(TFUNC, n->left->sym->type->link); + t->down = typ(TOLD, T); + t->down->down = ofnproto(n->right); + tmerge(t, n->left->sym); + n->left->sym->type = t; + } + break; + } + autoffset = 0; + stkoff = 0; +} + +void +walkparam(Node *n, int pass) +{ + Sym *s; + Node *n1; + + if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID]) + return; + +loop: + if(n == Z) + return; + switch(n->op) { + default: + diag(n, "argument not a name/prototype: %O", n->op); + break; + + case OLIST: + walkparam(n->left, pass); + n = n->right; + goto loop; + + case OPROTO: + for(n1 = n; n1 != Z; n1=n1->left) + if(n1->op == ONAME) { + if(pass == 0) { + s = n1->sym; + push1(s); + s->offset = -1; + break; + } + dodecl(pdecl, CPARAM, n->type, n->left); + break; + } + if(n1) + break; + if(pass == 0) { + /* + * extension: + * allow no name in argument declaration + diag(Z, "no name in argument declaration"); + */ + break; + } + dodecl(NODECL, CPARAM, n->type, n->left); + pdecl(CPARAM, lastdcl, S); + break; + + case ODOTDOT: + break; + + case ONAME: + s = n->sym; + if(pass == 0) { + push1(s); + s->offset = -1; + break; + } + if(s->offset != -1) { + if(autoffset == 0) { + firstarg = s; + firstargtype = s->type; + } + autoffset = align(autoffset, s->type, Aarg1); + s->offset = autoffset; + autoffset = align(autoffset, s->type, Aarg2); + } else + dodecl(pdecl, CXXX, types[TINT], n); + break; + } +} + +void +markdcl(void) +{ + Decl *d; + + blockno++; + d = push(); + d->val = DMARK; + d->offset = autoffset; + d->block = autobn; + autobn = blockno; +} + +Node* +revertdcl(void) +{ + Decl *d; + Sym *s; + Node *n, *n1; + + n = Z; + for(;;) { + d = dclstack; + if(d == D) { + diag(Z, "pop off dcl stack"); + break; + } + dclstack = d->link; + s = d->sym; + switch(d->val) { + case DMARK: + autoffset = d->offset; + autobn = d->block; + return n; + + case DAUTO: + if(debug['d']) + print("revert1 \"%s\"\n", s->name); + if(s->aused == 0) { + nearln = s->varlineno; + if(s->class == CAUTO) + warn(Z, "auto declared and not used: %s", s->name); + if(s->class == CPARAM) + warn(Z, "param declared and not used: %s", s->name); + } + if(s->type && (s->type->garb & GVOLATILE)) { + n1 = new(ONAME, Z, Z); + n1->sym = s; + n1->type = s->type; + n1->etype = TVOID; + if(n1->type != T) + n1->etype = n1->type->etype; + n1->xoffset = s->offset; + n1->class = s->class; + + n1 = new(OADDR, n1, Z); + n1 = new(OUSED, n1, Z); + if(n == Z) + n = n1; + else + n = new(OLIST, n1, n); + } + s->type = d->type; + s->class = d->class; + s->offset = d->offset; + s->block = d->block; + s->varlineno = d->varlineno; + s->aused = d->aused; + break; + + case DSUE: + if(debug['d']) + print("revert2 \"%s\"\n", s->name); + s->suetag = d->type; + s->sueblock = d->block; + break; + + case DLABEL: + if(debug['d']) + print("revert3 \"%s\"\n", s->name); + if(s->label && s->label->addable == 0) + warn(s->label, "label declared and not used \"%s\"", s->name); + s->label = Z; + break; + } + } + return n; +} + +Type* +fnproto(Node *n) +{ + int r; + + r = anyproto(n->right); + if(r == 0 || (r & OLDPROTO)) { + if(r & ANSIPROTO) + diag(n, "mixed ansi/old function declaration: %F", n->left); + return T; + } + return fnproto1(n->right); +} + +int +anyproto(Node *n) +{ + int r; + + r = 0; + +loop: + if(n == Z) + return r; + switch(n->op) { + case OLIST: + r |= anyproto(n->left); + n = n->right; + goto loop; + + case ODOTDOT: + case OPROTO: + return r | ANSIPROTO; + } + return r | OLDPROTO; +} + +Type* +fnproto1(Node *n) +{ + Type *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + t = fnproto1(n->left); + if(t != T) + t->down = fnproto1(n->right); + return t; + + case OPROTO: + lastdcl = T; + dodecl(NODECL, CXXX, n->type, n->left); + t = typ(TXXX, T); + if(lastdcl != T) + *t = *paramconv(lastdcl, 1); + return t; + + case ONAME: + diag(n, "incomplete argument prototype"); + return typ(TINT, T); + + case ODOTDOT: + return typ(TDOT, T); + } + diag(n, "unknown op in fnproto"); + return T; +} + +void +dbgdecl(Sym *s) +{ + print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n", + s->name, cnames[s->class], s->block, s->offset, s->type); +} + +Decl* +push(void) +{ + Decl *d; + + d = alloc(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Decl* +push1(Sym *s) +{ + Decl *d; + + d = push(); + d->sym = s; + d->val = DAUTO; + d->type = s->type; + d->class = s->class; + d->offset = s->offset; + d->block = s->block; + d->varlineno = s->varlineno; + d->aused = s->aused; + return d; +} + +int +sametype(Type *t1, Type *t2) +{ + + if(t1 == t2) + return 1; + return rsametype(t1, t2, 5, 1); +} + +int +rsametype(Type *t1, Type *t2, int n, int f) +{ + int et; + + n--; + for(;;) { + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + if(n <= 0) + return 1; + et = t1->etype; + if(et != t2->etype) + return 0; + if(et == TFUNC) { + if(!rsametype(t1->link, t2->link, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + while(t1 != T && t2 != T) { + if(t1->etype == TOLD) { + t1 = t1->down; + continue; + } + if(t2->etype == TOLD) { + t2 = t2->down; + continue; + } + while(t1 != T || t2 != T) { + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + break; + } + return 1; + } + if(et == TARRAY) + if(t1->width != t2->width && t1->width != 0 && t2->width != 0) + return 0; + if(typesu[et]) { + if(t1->link == T) + snap(t1); + if(t2->link == T) + snap(t2); + t1 = t1->link; + t2 = t2->link; + for(;;) { + if(t1 == t2) + return 1; + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + } + t1 = t1->link; + t2 = t2->link; + if((f || !debug['V']) && et == TIND) { + if(t1 != T && t1->etype == TVOID) + return 1; + if(t2 != T && t2->etype == TVOID) + return 1; + } + } + return 0; +} + +typedef struct Typetab Typetab; + +struct Typetab{ + int n; + Type **a; +}; + +static int +sigind(Type *t, Typetab *tt) +{ + int n; + Type **a, **na, **p, **e; + + n = tt->n; + a = tt->a; + e = a+n; + /* linear search seems ok */ + for(p = a ; p < e; p++) + if(sametype(*p, t)) + return p-a; + if((n&15) == 0){ + na = malloc((n+16)*sizeof(Type*)); + memmove(na, a, n*sizeof(Type*)); + free(a); + a = tt->a = na; + } + a[tt->n++] = t; + return -1; +} + +static ulong +signat(Type *t, Typetab *tt) +{ + int i; + Type *t1; + long s; + + s = 0; + for(; t; t=t->link) { + s = s*thash1 + thash[t->etype]; + if(t->garb&GINCOMPLETE) + return s; + switch(t->etype) { + default: + return s; + case TARRAY: + s = s*thash2 + 0; /* was t->width */ + break; + case TFUNC: + for(t1=t->down; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + break; + case TSTRUCT: + case TUNION: + if((i = sigind(t, tt)) >= 0){ + s = s*thash2 + i; + return s; + } + for(t1=t->link; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + return s; + case TIND: + break; + } + } + return s; +} + +ulong +signature(Type *t) +{ + ulong s; + Typetab tt; + + tt.n = 0; + tt.a = nil; + s = signat(t, &tt); + free(tt.a); + return s; +} + +ulong +sign(Sym *s) +{ + ulong v; + Type *t; + + if(s->sig == SIGINTERN) + return SIGNINTERN; + if((t = s->type) == T) + return 0; + v = signature(t); + if(v == 0) + v = SIGNINTERN; + return v; +} + +void +snap(Type *t) +{ + if(typesu[t->etype]) + if(t->link == T && t->tag && t->tag->suetag) { + t->link = t->tag->suetag->link; + t->width = t->tag->suetag->width; + } +} + +Type* +dotag(Sym *s, int et, int bn) +{ + Decl *d; + + if(bn != 0 && bn != s->sueblock) { + d = push(); + d->sym = s; + d->val = DSUE; + d->type = s->suetag; + d->block = s->sueblock; + s->suetag = T; + } + if(s->suetag == T) { + s->suetag = typ(et, T); + s->sueblock = autobn; + } + if(s->suetag->etype != et) + diag(Z, "tag used for more than one type: %s", + s->name); + if(s->suetag->tag == S) + s->suetag->tag = s; + return s->suetag; +} + +Node* +dcllabel(Sym *s, int f) +{ + Decl *d, d1; + Node *n; + + n = s->label; + if(n != Z) { + if(f) { + if(n->complex) + diag(Z, "label reused: %s", s->name); + n->complex = 1; // declared + } else + n->addable = 1; // used + return n; + } + + d = push(); + d->sym = s; + d->val = DLABEL; + dclstack = d->link; + + d1 = *firstdcl; + *firstdcl = *d; + *d = d1; + + firstdcl->link = d; + firstdcl = d; + + n = new(OXXX, Z, Z); + n->sym = s; + n->complex = f; + n->addable = !f; + s->label = n; + + if(debug['d']) + dbgdecl(s); + return n; +} + +Type* +paramconv(Type *t, int f) +{ + + switch(t->etype) { + case TUNION: + case TSTRUCT: + if(t->width <= 0) + diag(Z, "incomplete structure: %s", t->tag->name); + break; + + case TARRAY: + t = typ(TIND, t->link); + t->width = types[TIND]->width; + break; + + case TFUNC: + t = typ(TIND, t); + t->width = types[TIND]->width; + break; + + case TFLOAT: + if(!f) + t = types[TDOUBLE]; + break; + + case TCHAR: + case TSHORT: + if(!f) + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + if(!f) + t = types[TUINT]; + break; + } + return t; +} + +void +adecl(int c, Type *t, Sym *s) +{ + + if(c == CSTATIC) + c = CLOCAL; + if(t->etype == TFUNC) { + if(c == CXXX) + c = CEXTERN; + if(c == CLOCAL) + c = CSTATIC; + if(c == CAUTO || c == CEXREG) + diag(Z, "function cannot be %s %s", cnames[c], s->name); + } + if(c == CXXX) + c = CAUTO; + if(s) { + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "just say static: %s", s->name); + c = CSTATIC; + } + if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL) + if(s->block == autobn) + diag(Z, "auto redeclaration of: %s", s->name); + if(c != CPARAM) + push1(s); + s->block = autobn; + s->offset = 0; + s->type = t; + s->class = c; + s->aused = 0; + } + switch(c) { + case CAUTO: + autoffset = align(autoffset, t, Aaut3); + stkoff = maxround(stkoff, autoffset); + s->offset = -autoffset; + break; + + case CPARAM: + if(autoffset == 0) { + firstarg = s; + firstargtype = t; + } + autoffset = align(autoffset, t, Aarg1); + if(s) + s->offset = autoffset; + autoffset = align(autoffset, t, Aarg2); + break; + } +} + +void +pdecl(int c, Type *t, Sym *s) +{ + if(s && s->offset != -1) { + diag(Z, "not a parameter: %s", s->name); + return; + } + t = paramconv(t, c==CPARAM); + if(c == CXXX) + c = CPARAM; + if(c != CPARAM) { + diag(Z, "parameter cannot have class: %s", s->name); + c = CPARAM; + } + adecl(c, t, s); +} + +void +xdecl(int c, Type *t, Sym *s) +{ + long o; + + o = 0; + switch(c) { + case CEXREG: + o = exreg(t); + if(o == 0) + c = CEXTERN; + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CEXTERN: + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CXXX: + c = CGLOBL; + if(s->class == CEXTERN) + s->class = CGLOBL; + break; + + case CAUTO: + diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CEXTERN; + break; + + case CTYPESTR: + if(!typesuv[t->etype]) { + diag(Z, "typestr must be struct/union: %s", s->name); + break; + } + dclfunct(t, s); + break; + } + + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CSTATIC; + } + if(s->type != T) + if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) { + diag(Z, "external redeclaration of: %s", s->name); + Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln); + Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno); + } + tmerge(t, s); + s->type = t; + s->class = c; + s->block = 0; + s->offset = o; +} + +void +tmerge(Type *t1, Sym *s) +{ + Type *ta, *tb, *t2; + + t2 = s->type; +/*print("merge %T; %T\n", t1, t2);/**/ + for(;;) { + if(t1 == T || t2 == T || t1 == t2) + break; + if(t1->etype != t2->etype) + break; + switch(t1->etype) { + case TFUNC: + ta = t1->down; + tb = t2->down; + if(ta == T) { + t1->down = tb; + break; + } + if(tb == T) + break; + while(ta != T && tb != T) { + if(ta == tb) + break; + /* ignore old-style flag */ + if(ta->etype == TOLD) { + ta = ta->down; + continue; + } + if(tb->etype == TOLD) { + tb = tb->down; + continue; + } + /* checking terminated by ... */ + if(ta->etype == TDOT && tb->etype == TDOT) { + ta = T; + tb = T; + break; + } + if(!sametype(ta, tb)) + break; + ta = ta->down; + tb = tb->down; + } + if(ta != tb) + diag(Z, "function inconsistently declared: %s", s->name); + + /* take new-style over old-style */ + ta = t1->down; + tb = t2->down; + if(ta != T && ta->etype == TOLD) + if(tb != T && tb->etype != TOLD) + t1->down = tb; + break; + + case TARRAY: + /* should we check array size change? */ + if(t2->width > t1->width) + t1->width = t2->width; + break; + + case TUNION: + case TSTRUCT: + return; + } + t1 = t1->link; + t2 = t2->link; + } +} + +void +edecl(int c, Type *t, Sym *s) +{ + Type *t1; + + if(s == S) { + if(!typesu[t->etype]) + diag(Z, "unnamed structure element must be struct/union"); + if(c != CXXX) + diag(Z, "unnamed structure element cannot have class"); + } else + if(c != CXXX) + diag(Z, "structure element cannot have class: %s", s->name); + t1 = t; + t = copytyp(t1); + t->sym = s; + t->down = T; + if(lastfield) { + t->shift = lastbit - lastfield; + t->nbits = lastfield; + if(firstbit) + t->shift = -t->shift; + if(typeu[t->etype]) + t->etype = tufield->etype; + else + t->etype = tfield->etype; + } + if(strf == T) + strf = t; + else + strl->down = t; + strl = t; +} + +/* + * this routine is very suspect. + * ansi requires the enum type to + * be represented as an 'int' + * this means that 0x81234567 + * would be illegal. this routine + * makes signed and unsigned go + * to unsigned. + */ +Type* +maxtype(Type *t1, Type *t2) +{ + + if(t1 == T) + return t2; + if(t2 == T) + return t1; + if(t1->etype > t2->etype) + return t1; + return t2; +} + +void +doenum(Sym *s, Node *n) +{ + + if(n) { + complex(n); + if(n->op != OCONST) { + diag(n, "enum not a constant: %s", s->name); + return; + } + en.cenum = n->type; + en.tenum = maxtype(en.cenum, en.tenum); + + if(!typefd[en.cenum->etype]) + en.lastenum = n->vconst; + else + en.floatenum = n->fconst; + } + if(dclstack) + push1(s); + xdecl(CXXX, types[TENUM], s); + + if(en.cenum == T) { + en.tenum = types[TINT]; + en.cenum = types[TINT]; + en.lastenum = 0; + } + s->tenum = en.cenum; + + if(!typefd[s->tenum->etype]) { + s->vconst = convvtox(en.lastenum, s->tenum->etype); + en.lastenum++; + } else { + s->fconst = en.floatenum; + en.floatenum++; + } + + if(debug['d']) + dbgdecl(s); + acidvar(s); +} + +void +symadjust(Sym *s, Node *n, long del) +{ + + switch(n->op) { + default: + if(n->left) + symadjust(s, n->left, del); + if(n->right) + symadjust(s, n->right, del); + return; + + case ONAME: + if(n->sym == s) + n->xoffset -= del; + return; + + case OCONST: + case OSTRING: + case OLSTRING: + case OINDREG: + case OREGISTER: + return; + } +} + +Node* +contig(Sym *s, Node *n, long v) +{ + Node *p, *r, *q, *m; + long w; + Type *zt; + + if(debug['i']) { + print("contig v = %ld; s = %s\n", v, s->name); + prtree(n, "doinit value"); + } + + if(n == Z) + goto no; + w = s->type->width; + + /* + * nightmare: an automatic array whose size + * increases when it is initialized + */ + if(v != w) { + if(v != 0) + diag(n, "automatic adjustable array: %s", s->name); + v = s->offset; + autoffset = align(autoffset, s->type, Aaut3); + s->offset = -autoffset; + stkoff = maxround(stkoff, autoffset); + symadjust(s, n, v - s->offset); + } + if(w <= ewidth[TIND]) + goto no; + if(n->op == OAS) + diag(Z, "oops in contig"); +/*ZZZ this appears incorrect +need to check if the list completely covers the data. +if not, bail + */ + if(n->op == OLIST) + goto no; + if(n->op == OASI) + if(n->left->type) + if(n->left->type->width == w) + goto no; + while(w & (ewidth[TIND]-1)) + w++; +/* + * insert the following code, where long becomes vlong if pointers are fat + * + *(long**)&X = (long*)((char*)X + sizeof(X)); + do { + *(long**)&X -= 1; + **(long**)&X = 0; + } while(*(long**)&X); + */ + + for(q=n; q->op != ONAME; q=q->left) + ; + + zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG]; + + p = new(ONAME, Z, Z); + *p = *q; + p->type = typ(TIND, zt); + p->xoffset = s->offset; + + r = new(ONAME, Z, Z); + *r = *p; + r = new(OPOSTDEC, r, Z); + + q = new(ONAME, Z, Z); + *q = *p; + q = new(OIND, q, Z); + + m = new(OCONST, Z, Z); + m->vconst = 0; + m->type = zt; + + q = new(OAS, q, m); + + r = new(OLIST, r, q); + + q = new(ONAME, Z, Z); + *q = *p; + r = new(ODWHILE, q, r); + + q = new(ONAME, Z, Z); + *q = *p; + q->type = q->type->link; + q->xoffset += w; + q = new(OADDR, q, 0); + + q = new(OASI, p, q); + r = new(OLIST, q, r); + + n = new(OLIST, r, n); + +no: + return n; +} diff --git a/utils/cc/dpchk.c b/utils/cc/dpchk.c new file mode 100644 index 00000000..a061b12c --- /dev/null +++ b/utils/cc/dpchk.c @@ -0,0 +1,463 @@ +#include "cc.h" +#include "y.tab.h" + +enum +{ + Fnone = 0, + Fl, + Fvl, + Fignor, + Fstar, + Fadj, + + Fverb = 10, +}; + +typedef struct Tprot Tprot; +struct Tprot +{ + Type* type; + Bits flag; + Tprot* link; +}; + +typedef struct Tname Tname; +struct Tname +{ + char* name; + int param; + Tname* link; +}; + +static Type* indchar; +static uchar flagbits[512]; +static char fmtbuf[100]; +static int lastadj; +static int lastverb; +static int nstar; +static Tprot* tprot; +static Tname* tname; + +void +argflag(int c, int v) +{ + + switch(v) { + case Fignor: + case Fstar: + case Fl: + case Fvl: + flagbits[c] = v; + break; + case Fverb: + flagbits[c] = lastverb; +/*print("flag-v %c %d\n", c, lastadj);*/ + lastverb++; + break; + case Fadj: + flagbits[c] = lastadj; +/*print("flag-l %c %d\n", c, lastadj);*/ + lastadj++; + break; + } +} + +Bits +getflag(char *s) +{ + Bits flag; + int f; + char *fmt; + Rune c; + + fmt = fmtbuf; + flag = zbits; + nstar = 0; + for(;;) { + s += chartorune(&c, s); + if(c == 0 || c >= nelem(flagbits)) + break; + fmt += runetochar(fmt, &c); + f = flagbits[c]; + switch(f) { + case Fnone: + argflag(c, Fverb); + f = flagbits[c]; + break; + case Fstar: + nstar++; + case Fignor: + continue; + case Fl: + if(bset(flag, Fl)) + flag = bor(flag, blsh(Fvl)); + } + flag = bor(flag, blsh(f)); + if(f >= Fverb) + break; + } + *fmt = 0; + return flag; +} + +void +newprot(Sym *m, Type *t, char *s) +{ + Bits flag; + Tprot *l; + + if(t == T) { + warn(Z, "%s: newprot: type not defined", m->name); + return; + } + flag = getflag(s); + for(l=tprot; l; l=l->link) + if(beq(flag, l->flag) && sametype(t, l->type)) + return; + l = alloc(sizeof(*l)); + l->type = t; + l->flag = flag; + l->link = tprot; + tprot = l; +} + +void +newname(char *s, int p) +{ + Tname *l; + + for(l=tname; l; l=l->link) + if(strcmp(l->name, s) == 0) { + if(l->param != p) + yyerror("vargck %s already defined\n", s); + return; + } + l = alloc(sizeof(*l)); + l->name = s; + l->param = p; + l->link = tname; + tname = l; +} + +void +arginit(void) +{ + int i; + +/* debug['F'] = 1;*/ +/* debug['w'] = 1;*/ + + lastadj = Fadj; + lastverb = Fverb; + indchar = typ(TIND, types[TCHAR]); + + memset(flagbits, Fnone, sizeof(flagbits)); + + for(i='0'; i<='9'; i++) + argflag(i, Fignor); + argflag('.', Fignor); + argflag('#', Fignor); + argflag('u', Fignor); + argflag('+', Fignor); + argflag('-', Fignor); + + argflag('*', Fstar); + argflag('l', Fl); + + argflag('o', Fverb); + flagbits['x'] = flagbits['o']; + flagbits['X'] = flagbits['o']; +} + +void +pragvararg(void) +{ + Sym *s; + int n, c; + char *t; + Rune r; + Type *ty; + + if(!debug['F']) + goto out; + s = getsym(); + if(s && strcmp(s->name, "argpos") == 0) + goto ckpos; + if(s && strcmp(s->name, "type") == 0) + goto cktype; + if(s && strcmp(s->name, "flag") == 0) + goto ckflag; + yyerror("syntax in #pragma varargck"); + goto out; + +ckpos: +/*#pragma varargck argpos warn 2*/ + s = getsym(); + if(s == S) + goto bad; + n = getnsn(); + if(n < 0) + goto bad; + newname(s->name, n); + goto out; + +ckflag: +/*#pragma varargck flag 'c'*/ + c = getnsc(); + if(c != '\'') + goto bad; + c = getr(); + if(c == '\\') + c = getr(); + else if(c == '\'') + goto bad; + if(c == '\n') + goto bad; + if(getc() != '\'') + goto bad; + argflag(c, Fignor); + goto out; + +cktype: +/*#pragma varargck type O int*/ + c = getnsc(); + if(c != '"') + goto bad; + t = fmtbuf; + for(;;) { + r = getr(); + if(r == ' ' || r == '\n') + goto bad; + if(r == '"') + break; + t += runetochar(t, &r); + } + *t = 0; + t = strdup(fmtbuf); + s = getsym(); + if(s == S) + goto bad; + ty = s->type; + while((c = getnsc()) == '*') + ty = typ(TIND, ty); + unget(c); + newprot(s, ty, t); + goto out; + +bad: + yyerror("syntax in #pragma varargck"); + +out: + while(getnsc() != '\n') + ; +} + +Node* +nextarg(Node *n, Node **a) +{ + if(n == Z) { + *a = Z; + return Z; + } + if(n->op == OLIST) { + *a = n->left; + return n->right; + } + *a = n; + return Z; +} + +void +checkargs(Node *nn, char *s, int pos) +{ + Node *a, *n; + Bits flag; + Tprot *l; + + if(!debug['F']) + return; + n = nn; + for(;;) { + s = strchr(s, '%'); + if(s == 0) { + nextarg(n, &a); + if(a != Z) + warn(nn, "more arguments than format %T", + a->type); + return; + } + s++; + flag = getflag(s); + while(nstar > 0) { + n = nextarg(n, &a); + pos++; + nstar--; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == T) + continue; + if(!sametype(types[TINT], a->type) && + !sametype(types[TUINT], a->type)) + warn(nn, "format mismatch '*' in %s %T, arg %d", + fmtbuf, a->type, pos); + } + for(l=tprot; l; l=l->link) + if(sametype(types[TVOID], l->type)) { + if(beq(flag, l->flag)) { + s++; + goto loop; + } + } + + n = nextarg(n, &a); + pos++; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == 0) + continue; + for(l=tprot; l; l=l->link) + if(sametype(a->type, l->type)) { +/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ + if(beq(flag, l->flag)) + goto loop; + } + warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos); + loop:; + } +} + +void +dpcheck(Node *n) +{ + char *s; + Node *a, *b; + Tname *l; + int i; + + if(n == Z) + return; + b = n->left; + if(b == Z || b->op != ONAME) + return; + s = b->sym->name; + for(l=tname; l; l=l->link) + if(strcmp(s, l->name) == 0) + break; + if(l == 0) + return; + + i = l->param; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + warn(n, "cant find format arg"); + return; + } + if(!sametype(indchar, a->type)) { + warn(n, "format arg type %T", a->type); + return; + } + if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { +/* warn(n, "format arg not constant string");*/ + return; + } + s = a->left->cstring; + checkargs(b, s, l->param); +} + +void +pragpack(void) +{ + Sym *s; + + packflg = 0; + s = getsym(); + if(s) { + packflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + packflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(packflg) + print("%4ld: pack %d\n", lineno, packflg); + else + print("%4ld: pack off\n", lineno); +} + +void +pragfpround(void) +{ + Sym *s; + + fproundflg = 0; + s = getsym(); + if(s) { + fproundflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + fproundflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(fproundflg) + print("%4ld: fproundflg %d\n", lineno, fproundflg); + else + print("%4ld: fproundflg off\n", lineno); +} + +void +pragprofile(void) +{ + Sym *s; + + profileflg = 0; + s = getsym(); + if(s) { + profileflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + profileflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(profileflg) + print("%4ld: profileflg %d\n", lineno, profileflg); + else + print("%4ld: profileflg off\n", lineno); +} + +void +pragincomplete(void) +{ + Sym *s; + + s = getsym(); + if(s){ + if(strcmp(s->name, "_off_") == 0) + debug['T'] = 0; + else if(strcmp(s->name, "_on_") == 0) + debug['T'] = 1; + else if(s->type == T) + diag(Z, "unknown type %s in pragma incomplete", s->name); + else + s->type->garb |= GINCOMPLETE; + } + while(getnsc() != '\n') + ; + if(debug['f']) + print("%s incomplete\n", s->name); +} diff --git a/utils/cc/funct.c b/utils/cc/funct.c new file mode 100644 index 00000000..3a236be3 --- /dev/null +++ b/utils/cc/funct.c @@ -0,0 +1,400 @@ +#include "cc.h" + +typedef struct Ftab Ftab; +struct Ftab +{ + char op; + char* name; + char typ; +}; +typedef struct Gtab Gtab; +struct Gtab +{ + char etype; + char* name; +}; + +Ftab ftabinit[OEND]; +Gtab gtabinit[NTYPE]; + +int +isfunct(Node *n) +{ + Type *t, *t1; + Funct *f; + Node *l; + Sym *s; + int o; + + o = n->op; + if(n->left == Z) + goto no; + t = n->left->type; + if(t == T) + goto no; + f = t->funct; + + switch(o) { + case OAS: // put cast on rhs + case OASI: + case OASADD: + case OASAND: + case OASASHL: + case OASASHR: + case OASDIV: + case OASLDIV: + case OASLMOD: + case OASLMUL: + case OASLSHR: + case OASMOD: + case OASMUL: + case OASOR: + case OASSUB: + case OASXOR: + if(n->right == Z) + goto no; + t1 = n->right->type; + if(t1 == T) + goto no; + if(t1->funct == f) + break; + + l = new(OXXX, Z, Z); + *l = *n->right; + + n->right->left = l; + n->right->right = Z; + n->right->type = t; + n->right->op = OCAST; + + if(!isfunct(n->right)) + prtree(n, "isfunc !"); + break; + + case OCAST: // t f(T) or T f(t) + t1 = n->type; + if(t1 == T) + goto no; + if(f != nil) { + s = f->castfr[t1->etype]; + if(s == S) + goto no; + n->right = n->left; + goto build; + } + f = t1->funct; + if(f != nil) { + s = f->castto[t->etype]; + if(s == S) + goto no; + n->right = n->left; + goto build; + } + goto no; + } + + if(f == nil) + goto no; + s = f->sym[o]; + if(s == S) + goto no; + + /* + * the answer is yes, + * now we rewrite the node + * and give diagnostics + */ + switch(o) { + default: + diag(n, "isfunct op missing %O\n", o); + goto bad; + + case OADD: // T f(T, T) + case OAND: + case OASHL: + case OASHR: + case ODIV: + case OLDIV: + case OLMOD: + case OLMUL: + case OLSHR: + case OMOD: + case OMUL: + case OOR: + case OSUB: + case OXOR: + + case OEQ: // int f(T, T) + case OGE: + case OGT: + case OHI: + case OHS: + case OLE: + case OLO: + case OLS: + case OLT: + case ONE: + if(n->right == Z) + goto bad; + t1 = n->right->type; + if(t1 == T) + goto bad; + if(t1->funct != f) + goto bad; + n->right = new(OLIST, n->left, n->right); + break; + + case OAS: // structure copies done by the compiler + case OASI: + goto no; + + case OASADD: // T f(T*, T) + case OASAND: + case OASASHL: + case OASASHR: + case OASDIV: + case OASLDIV: + case OASLMOD: + case OASLMUL: + case OASLSHR: + case OASMOD: + case OASMUL: + case OASOR: + case OASSUB: + case OASXOR: + if(n->right == Z) + goto bad; + t1 = n->right->type; + if(t1 == T) + goto bad; + if(t1->funct != f) + goto bad; + n->right = new(OLIST, new(OADDR, n->left, Z), n->right); + break; + + case OPOS: // T f(T) + case ONEG: + case ONOT: + case OCOM: + n->right = n->left; + break; + + + } + +build: + l = new(ONAME, Z, Z); + l->sym = s; + l->type = s->type; + l->etype = s->type->etype; + l->xoffset = s->offset; + l->class = s->class; + tcomo(l, 0); + + n->op = OFUNC; + n->left = l; + n->type = l->type->link; + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(tcoma(n->left, n->right, l->type->down, 1)) + goto bad; + return 1; + +no: + return 0; + +bad: + diag(n, "cant rewrite typestr for op %O\n", o); + prtree(n, "isfunct"); + n->type = T; + return 1; +} + +void +dclfunct(Type *t, Sym *s) +{ + Funct *f; + Node *n; + Type *f1, *f2, *f3, *f4; + int o, i, c; + char str[100]; + + if(t->funct) + return; + + // recognize generated tag of dorm _%d_ + if(t->tag == S) + goto bad; + for(i=0; c = t->tag->name[i]; i++) { + if(c == '_') { + if(i == 0 || t->tag->name[i+1] == 0) + continue; + break; + } + if(c < '0' || c > '9') + break; + } + if(c == 0) + goto bad; + + f = alloc(sizeof(*f)); + for(o=0; o<sizeof(f->sym); o++) + f->sym[o] = S; + + t->funct = f; + + f1 = typ(TFUNC, t); + f1->down = copytyp(t); + f1->down->down = t; + + f2 = typ(TFUNC, types[TINT]); + f2->down = copytyp(t); + f2->down->down = t; + + f3 = typ(TFUNC, t); + f3->down = typ(TIND, t); + f3->down->down = t; + + f4 = typ(TFUNC, t); + f4->down = t; + + for(i=0;; i++) { + o = ftabinit[i].op; + if(o == OXXX) + break; + sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->sym[o] = n->sym; + switch(ftabinit[i].typ) { + default: + diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ); + break; + + case 1: // T f(T,T) + + dodecl(xdecl, CEXTERN, f1, n); + break; + + case 2: // int f(T,T) == + dodecl(xdecl, CEXTERN, f2, n); + break; + + case 3: // void f(T*,T) += + dodecl(xdecl, CEXTERN, f3, n); + break; + + case 4: // T f(T) ~ + dodecl(xdecl, CEXTERN, f4, n); + break; + } + } + for(i=0;; i++) { + o = gtabinit[i].etype; + if(o == TXXX) + break; + + /* + * OCAST types T1 _T2_T1_(T2) + */ + sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->castto[o] = n->sym; + + f1 = typ(TFUNC, t); + f1->down = types[o]; + dodecl(xdecl, CEXTERN, f1, n); + + sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->castfr[o] = n->sym; + + f1 = typ(TFUNC, types[o]); + f1->down = t; + dodecl(xdecl, CEXTERN, f1, n); + } + return; +bad: + diag(Z, "dclfunct bad %T %s\n", t, s->name); +} + +Gtab gtabinit[NTYPE] = +{ + TCHAR, "c", + TUCHAR, "uc", + TSHORT, "h", + TUSHORT, "uh", + TINT, "i", + TUINT, "ui", + TLONG, "l", + TULONG, "ul", + TVLONG, "v", + TUVLONG, "uv", + TFLOAT, "f", + TDOUBLE, "d", + TXXX +}; + +Ftab ftabinit[OEND] = +{ + OADD, "add", 1, + OAND, "and", 1, + OASHL, "ashl", 1, + OASHR, "ashr", 1, + ODIV, "div", 1, + OLDIV, "ldiv", 1, + OLMOD, "lmod", 1, + OLMUL, "lmul", 1, + OLSHR, "lshr", 1, + OMOD, "mod", 1, + OMUL, "mul", 1, + OOR, "or", 1, + OSUB, "sub", 1, + OXOR, "xor", 1, + + OEQ, "eq", 2, + OGE, "ge", 2, + OGT, "gt", 2, + OHI, "hi", 2, + OHS, "hs", 2, + OLE, "le", 2, + OLO, "lo", 2, + OLS, "ls", 2, + OLT, "lt", 2, + ONE, "ne", 2, + + OASADD, "asadd", 3, + OASAND, "asand", 3, + OASASHL, "asashl", 3, + OASASHR, "asashr", 3, + OASDIV, "asdiv", 3, + OASLDIV, "asldiv", 3, + OASLMOD, "aslmod", 3, + OASLMUL, "aslmul", 3, + OASLSHR, "aslshr", 3, + OASMOD, "asmod", 3, + OASMUL, "asmul", 3, + OASOR, "asor", 3, + OASSUB, "assub", 3, + OASXOR, "asxor", 3, + + OPOS, "pos", 4, + ONEG, "neg", 4, + OCOM, "com", 4, + ONOT, "not", 4, + +// OPOSTDEC, +// OPOSTINC, +// OPREDEC, +// OPREINC, + + OXXX, +}; + +// Node* nodtestv; + +// Node* nodvpp; +// Node* nodppv; +// Node* nodvmm; +// Node* nodmmv; diff --git a/utils/cc/lex.c b/utils/cc/lex.c new file mode 100644 index 00000000..7a99164b --- /dev/null +++ b/utils/cc/lex.c @@ -0,0 +1,1518 @@ +#include "cc.h" +#include "y.tab.h" + +#ifndef CPP +#define CPP "/bin/cpp" +#endif + +/* + * known debug flags + * -o file output file + * -D name define + * -I path include + * -a acid declaration output + * -M constant multiplication + * -B non ANSI + * -A !B + * -d print declarations + * -t print type trees + * -L print every NAME symbol + * -i print initialization + * -F format specification check + * -r print registerization + * -v verbose printing + * -X abort on error + * -w print warnings + * -m print add/sub/mul trees + * -s print structure offsets (with -a or -aa) + * -n print acid to file (%.c=%.acid) (with -a or -aa) + * -p use standard cpp ANSI preprocessor (not on windows) + * -V enable void* conversion warnings + */ + +void +main(int argc, char *argv[]) +{ + char *defs[50], *p; + int nproc, nout, status, i, c, ndef; + + memset(debug, 0, sizeof(debug)); + tinit(); + cinit(); + ginit(); + arginit(); + + profileflg = 1; /* #pragma can turn it off */ + tufield = simplet((1L<<tfield->etype) | BUNSIGNED); + ndef = 0; + outfile = 0; + include[ninclude++] = "."; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) { + defs[ndef++] = p; + dodefine(p); + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + } ARGEND + if(argc < 1 && outfile == 0) { + print("usage: %cc [-options] files\n", thechar); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't compile 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) { + print("cannot create a process\n"); + errorexit(); + } + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + fprint(2, "%s:\n", *argv); + if (compile(*argv, defs, ndef)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + + if(argc == 0) + c = compile("stdin", defs, ndef); + else + c = compile(argv[0], defs, ndef); + + if(c) + errorexit(); + exits(0); +} + +int +compile(char *file, char **defs, int ndef) +{ + char ofile[400], incfile[20]; + char *p, *av[100], opt[256]; + int i, c, fd[2]; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + *p++ = 0; + if(!debug['.']) + include[0] = strdup(ofile); + } else + p = ofile; + if(outfile == 0) { + outfile = p; + if(outfile) { + if(p = utfrrune(outfile, '.')) + if(p[1] == 'c' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + if(debug['a'] && debug['n']) + strcat(p, ".acid"); + else if(debug['Z'] && debug['n']) + strcat(p, "_pickle.c"); + else { + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } + } else + outfile = "/dev/null"; + } + + if(p = getenv("INCLUDE")) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile, "/%s/include", thestring); + setinclude(strdup(incfile)); + setinclude("/sys/include"); + } + } + if((debug['a'] || debug['Z']) && !debug['n']) { + outfile = 0; + Binit(&outbuf, 1, OWRITE); + Binit(&diagbuf, 2, OWRITE); + } else { + c = mycreat(outfile, 0664); + if(c < 0) { + diag(Z, "cannot open %s", outfile); + outfile = 0; + errorexit(); + } + Binit(&outbuf, c, OWRITE); + Binit(&diagbuf, 1, OWRITE); + } + newio(); + + /* Use an ANSI preprocessor */ + if(debug['p']) { + if(systemtype(Windows)) { + diag(Z, "-p option not supported on windows"); + errorexit(); + } + if(myaccess(file) < 0) { + diag(Z, "%s does not exist", file); + errorexit(); + } + if(mypipe(fd) < 0) { + diag(Z, "pipe failed"); + errorexit(); + } + switch(myfork()) { + case -1: + diag(Z, "fork failed"); + errorexit(); + case 0: + close(fd[0]); + mydup(fd[1], 1); + close(fd[1]); + av[0] = CPP; + i = 1; + if(debug['+']) { + sprint(opt, "-+"); + av[i++] = strdup(opt); + } + for(c = 0; c < ndef; c++) { + sprint(opt, "-D%s", defs[c]); + av[i++] = strdup(opt); + } + for(c = 0; c < ninclude; c++) { + sprint(opt, "-I%s", include[c]); + av[i++] = strdup(opt); + } + if(strcmp(file, "stdin") != 0) + av[i++] = file; + av[i] = 0; + if(debug['p'] > 1) { + for(c = 0; c < i; c++) + fprint(2, "%s ", av[c]); + fprint(2, "\n"); + } + myexec(av[0], av); + fprint(2, "can't exec C preprocessor %s: %r\n", CPP); + errorexit(); + default: + close(fd[1]); + newfile(file, fd[0]); + break; + } + } else { + if(strcmp(file, "stdin") == 0) + newfile(file, 0); + else + newfile(file, -1); + } + yyparse(); + if(!debug['a'] && !debug['Z']) + gclean(); + return nerrors; +} + +void +errorexit(void) +{ + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static int pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + if(debug['e']) + print("%L: %s\n", lineno, s); + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%cc: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + Sym *s; + ulong h; + char *p; + int c, n; + + h = 0; + for(p=symb; *p;) { + h = h * 3; + h += *p++; + } + n = (p - symb) + 1; + if((long)h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(strcmp(s->name, symb) == 0) + return s; + } + s = alloc(sizeof(*s)); + s->name = alloc(n); + memmove(s->name, symb, n); + + strcpy(s->name, symb); + s->link = hash[h]; + hash[h] = s; + syminit(s); + + return s; +} + +void +syminit(Sym *s) +{ + s->lexical = LNAME; + s->block = 0; + s->offset = 0; + s->type = T; + s->suetag = T; + s->class = CXXX; + s->aused = 0; + s->sig = SIGNONE; +} + +#define EOF (-1) +#define IGN (-2) +#define ESC (1<<20) +#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)) + +enum +{ + Numdec = 1<<0, + Numlong = 1<<1, + Numuns = 1<<2, + Numvlong = 1<<3, + Numflt = 1<<4, +}; + +long +yylex(void) +{ + vlong vv; + long c, c1, t; + char *cp; + Rune rune; + Sym *s; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c >= Runeself) { + /* + * extension -- + * all multibyte runes are alpha + */ + cp = symb; + goto talph; + } + if(isspace(c)) { + if(c == '\n') + lineno++; + goto l0; + } + if(isalpha(c)) { + cp = symb; + if(c != 'L') + goto talph; + *cp++ = c; + c = GETC(); + if(c == '\'') { + /* L'x' */ + c = escchar('\'', 1, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 1, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + yylval.vval = convvtox(c, TUSHORT); + return LUCONST; + } + if(c == '"') { + goto caselq; + } + goto talph; + } + if(isdigit(c)) + goto tnum; + switch(c) + { + + case EOF: + peekc = EOF; + return -1; + + case '_': + cp = symb; + goto talph; + + case '#': + domacro(); + goto l0; + + case '.': + c1 = GETC(); + if(isdigit(c1)) { + cp = symb; + *cp++ = c; + c = c1; + c1 = 0; + goto casedot; + } + break; + + case '"': + strcpy(symb, "\"<string>\""); + cp = alloc(0); + c1 = 0; + + /* "..." */ + for(;;) { + c = escchar('"', 0, 1); + if(c == EOF) + break; + if(c & ESC) { + cp = allocn(cp, c1, 1); + cp[c1++] = c; + } else { + rune = c; + c = runelen(rune); + cp = allocn(cp, c1, c); + runetochar(cp+c1, &rune); + c1 += c; + } + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, 1); + cp[c1++] = 0; + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LSTRING; + + caselq: + /* L"..." */ + strcpy(symb, "\"L<string>\""); + cp = alloc(0); + c1 = 0; + for(;;) { + c = escchar('"', 1, 0); + if(c == EOF) + break; + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = c; + c1 += sizeof(ushort); + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = 0; + c1 += sizeof(ushort); + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LLSTRING; + + case '\'': + /* '.' */ + c = escchar('\'', 0, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 0, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + vv = c; + yylval.vval = convvtox(vv, TUCHAR); + if(yylval.vval != vv) + yyerror("overflow in character constant: 0x%lx", c); + else + if(c & 0x80){ + nearln = lineno; + warn(Z, "sign-extended character constant"); + } + yylval.vval = convvtox(vv, TCHAR); + return LCONST; + + case '/': + c1 = GETC(); + if(c1 == '*') { + for(;;) { + c = getr(); + while(c == '*') { + c = getr(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '/') { + for(;;) { + c = getr(); + if(c == '\n') + goto l0; + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '=') + return LDVE; + break; + + case '*': + c1 = GETC(); + if(c1 == '=') + return LMLE; + break; + + case '%': + c1 = GETC(); + if(c1 == '=') + return LMDE; + break; + + case '+': + c1 = GETC(); + if(c1 == '+') + return LPP; + if(c1 == '=') + return LPE; + break; + + case '-': + c1 = GETC(); + if(c1 == '-') + return LMM; + if(c1 == '=') + return LME; + if(c1 == '>') + return LMG; + break; + + case '>': + c1 = GETC(); + if(c1 == '>') { + c = LRSH; + c1 = GETC(); + if(c1 == '=') + return LRSHE; + break; + } + if(c1 == '=') + return LGE; + break; + + case '<': + c1 = GETC(); + if(c1 == '<') { + c = LLSH; + c1 = GETC(); + if(c1 == '=') + return LLSHE; + break; + } + if(c1 == '=') + return LLE; + break; + + case '=': + c1 = GETC(); + if(c1 == '=') + return LEQ; + break; + + case '!': + c1 = GETC(); + if(c1 == '=') + return LNE; + break; + + case '&': + c1 = GETC(); + if(c1 == '&') + return LANDAND; + if(c1 == '=') + return LANDE; + break; + + case '|': + c1 = GETC(); + if(c1 == '|') + return LOROR; + if(c1 == '=') + return LORE; + break; + + case '^': + c1 = GETC(); + if(c1 == '=') + return LXORE; + break; + + default: + return c; + } + peekc = c1; + return c; + +talph: + /* + * cp is set to symb and some + * prefix has been stored + */ + for(;;) { + if(c >= Runeself) { + for(c1=0;;) { + cp[c1++] = c; + if(fullrune(cp, c1)) + break; + c = GETC(); + } + cp += c1; + c = GETC(); + continue; + } + if(!isalnum(c) && c != '_') + break; + *cp++ = c; + c = GETC(); + } + *cp = 0; + if(debug['L']) + print("%L: %s\n", lineno, symb); + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + yylval.sym = s; + if(s->class == CTYPEDEF || s->class == CTYPESTR) + return LTYPE; + return s->lexical; + +tnum: + c1 = 0; + cp = symb; + if(c != '0') { + c1 |= Numdec; + for(;;) { + *cp++ = c; + c = GETC(); + if(isdigit(c)) + continue; + goto dc; + } + } + *cp++ = c; + c = GETC(); + if(c == 'x' || c == 'X') + for(;;) { + *cp++ = c; + c = GETC(); + if(isdigit(c)) + continue; + if(c >= 'a' && c <= 'f') + continue; + if(c >= 'A' && c <= 'F') + continue; + if(cp == symb+2) + yyerror("malformed hex constant"); + goto ncu; + } + if(c < '0' || c > '7') + goto dc; + for(;;) { + if(c >= '0' && c <= '7') { + *cp++ = c; + c = GETC(); + continue; + } + goto ncu; + } + +dc: + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + +ncu: + if((c == 'U' || c == 'u') && !(c1 & Numuns)) { + c = GETC(); + c1 |= Numuns; + goto ncu; + } + if((c == 'L' || c == 'l') && !(c1 & Numvlong)) { + c = GETC(); + if(c1 & Numlong) + c1 |= Numvlong; + c1 |= Numlong; + goto ncu; + } + *cp = 0; + peekc = c; + if(mpatov(symb, &yylval.vval)) + yyerror("overflow in constant"); + + vv = yylval.vval; + if(c1 & Numvlong) { + if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) { + c = LUVLCONST; + t = TUVLONG; + goto nret; + } + c = LVLCONST; + t = TVLONG; + goto nret; + } + if(c1 & Numlong) { + if((c1 & Numuns) || convvtox(vv, TLONG) < 0) { + c = LULCONST; + t = TULONG; + goto nret; + } + c = LLCONST; + t = TLONG; + goto nret; + } + if((c1 & Numuns) || convvtox(vv, TINT) < 0) { + c = LUCONST; + t = TUINT; + goto nret; + } + c = LCONST; + t = TINT; + goto nret; + +nret: + yylval.vval = convvtox(vv, t); + if(yylval.vval != vv){ + nearln = lineno; + warn(Z, "truncated constant: %T %s", types[t], symb); + } + return c; + +casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c != 'e' && c != 'E') + goto caseout; + +casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + if(!isdigit(c)) + yyerror("malformed fp constant exponent"); + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + +caseout: + if(c == 'L' || c == 'l') { + c = GETC(); + c1 |= Numlong; + } else + if(c == 'F' || c == 'f') { + c = GETC(); + c1 |= Numflt; + } + *cp = 0; + peekc = c; + if(mpatof(symb, &yylval.dval)) { + yyerror("overflow in float constant"); + yylval.dval = 0; + } + if(c1 & Numflt) + return LFCONST; + return LDCONST; +} + +/* + * convert a string, s, to vlong in *v + * return conversion overflow. + * required syntax is [0[x]]d* + */ +int +mpatov(char *s, vlong *v) +{ + vlong n, nn; + int c; + + n = 0; + c = *s; + if(c == '0') + goto oct; + while(c = *s++) { + if(c >= '0' && c <= '9') + nn = n*10 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; + +oct: + s++; + c = *s; + if(c == 'x' || c == 'X') + goto hex; + while(c = *s++) { + if(c >= '0' || c <= '7') + nn = n*8 + c-'0'; + else + goto bad; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } + goto out; + +hex: + s++; + while(c = *s++) { + if(c >= '0' && c <= '9') + c += 0-'0'; + else + if(c >= 'a' && c <= 'f') + c += 10-'a'; + else + if(c >= 'A' && c <= 'F') + c += 10-'A'; + else + goto bad; + nn = n*16 + c; + if(n < 0 && nn >= 0) + goto bad; + n = nn; + } +out: + *v = n; + return 0; + +bad: + *v = ~0; + return 1; +} + +int +getc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +long +getr(void) +{ + int c, i; + char str[UTFmax+1]; + Rune rune; + + + c = getc(); + if(c < Runeself) + return c; + i = 0; + str[i++] = c; + +loop: + c = getc(); + str[i++] = c; + if(!fullrune(str, i)) + goto loop; + c = chartorune(&rune, str); + if(rune == Runeerror && c == 1) { + nearln = lineno; + diag(Z, "illegal rune in string"); + for(c=0; c<i; c++) + print(" %.2x", *(uchar*)(str+c)); + print("\n"); + } + return rune; +} + +int +getnsc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + for(;;) { + if(!isspace(c)) + return c; + if(c == '\n') { + lineno++; + return c; + } + c = GETC(); + } + return 0; +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +long +escchar(long e, int longflg, int escflg) +{ + long c, l; + int i; + +loop: + c = getr(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + c = EOF; + return c; + } + c = getr(); + if(c == 'x') { + /* + * note this is not ansi, + * supposed to only accept 2 hex + */ + i = 2; + if(longflg) + i = 4; + l = 0; + for(; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '9') { + l = l*16 + c-'0'; + continue; + } + if(c >= 'a' && c <= 'f') { + l = l*16 + c-'a' + 10; + continue; + } + if(c >= 'A' && c <= 'F') { + l = l*16 + c-'A' + 10; + continue; + } + unget(c); + break; + } + if(escflg) + l |= ESC; + return l; + } + if(c >= '0' && c <= '7') { + /* + * note this is not ansi, + * supposed to only accept 3 oct + */ + i = 2; + if(longflg) + i = 5; + l = c - '0'; + for(; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + continue; + } + unget(c); + } + if(escflg) + l |= ESC; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return '\a'; + case 'v': return '\v'; + } + return c; +} + +struct +{ + char *name; + ushort lexical; + ushort type; +} itab[] = +{ + "auto", LAUTO, 0, + "break", LBREAK, 0, + "case", LCASE, 0, + "char", LCHAR, TCHAR, + "const", LCONSTNT, 0, + "continue", LCONTINUE, 0, + "default", LDEFAULT, 0, + "do", LDO, 0, + "double", LDOUBLE, TDOUBLE, + "else", LELSE, 0, + "enum", LENUM, 0, + "extern", LEXTERN, 0, + "float", LFLOAT, TFLOAT, + "for", LFOR, 0, + "goto", LGOTO, 0, + "if", LIF, 0, + "int", LINT, TINT, + "long", LLONG, TLONG, + "register", LREGISTER, 0, + "return", LRETURN, 0, + "SET", LSET, 0, + "short", LSHORT, TSHORT, + "signed", LSIGNED, 0, + "signof", LSIGNOF, 0, + "sizeof", LSIZEOF, 0, + "static", LSTATIC, 0, + "struct", LSTRUCT, 0, + "switch", LSWITCH, 0, + "typedef", LTYPEDEF, 0, + "typestr", LTYPESTR, 0, + "union", LUNION, 0, + "unsigned", LUNSIGNED, 0, + "USED", LUSED, 0, + "void", LVOID, TVOID, + "volatile", LVOLATILE, 0, + "while", LWHILE, 0, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + Type *t; + + nerrors = 0; + lineno = 1; + iostack = I; + iofree = I; + peekc = IGN; + nhunk = 0; + + types[TXXX] = T; + types[TCHAR] = typ(TCHAR, T); + types[TUCHAR] = typ(TUCHAR, T); + types[TSHORT] = typ(TSHORT, T); + types[TUSHORT] = typ(TUSHORT, T); + types[TINT] = typ(TINT, T); + types[TUINT] = typ(TUINT, T); + types[TLONG] = typ(TLONG, T); + types[TULONG] = typ(TULONG, T); + types[TVLONG] = typ(TVLONG, T); + types[TUVLONG] = typ(TUVLONG, T); + types[TFLOAT] = typ(TFLOAT, T); + types[TDOUBLE] = typ(TDOUBLE, T); + types[TVOID] = typ(TVOID, T); + types[TENUM] = typ(TENUM, T); + types[TFUNC] = typ(TFUNC, types[TINT]); + types[TIND] = typ(TIND, types[TVOID]); + + for(i=0; i<NHASH; i++) + hash[i] = S; + for(i=0; itab[i].name; i++) { + s = slookup(itab[i].name); + s->lexical = itab[i].lexical; + if(itab[i].type != 0) + s->type = types[itab[i].type]; + } + blockno = 0; + autobn = 0; + autoffset = 0; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + symstring = slookup(".string"); + symstring->class = CSTATIC; + symstring->type = t; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + + nodproto = new(OPROTO, Z, Z); + dclstack = D; + + pathname = allocn(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } + + fmtinstall('O', Oconv); + fmtinstall('T', Tconv); + fmtinstall('F', FNconv); + fmtinstall('L', Lconv); + fmtinstall('Q', Qconv); + fmtinstall('|', VBconv); +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0] & 0xff; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++ & 0xff; +} + +int +Oconv(Fmt *fp) +{ + int a; + + a = va_arg(fp->args, int); + if(a < OXXX || a > OEND) + return fmtprint(fp, "***badO %d***", a); + + return fmtstrcpy(fp, onames[a]); +} + +int +Lconv(Fmt *fp) +{ + char str[STRINGSZ], s[STRINGSZ]; + Hist *h; + struct + { + Hist* incl; /* start of this include file */ + long idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + long ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + long l, d; + int i, n; + + l = va_arg(fp->args, long); + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset != 0) { /* #line directive, not #pragma */ + if(n > 0 && n < HISTSZ && h->offset >= 0) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + if(n < HISTSZ) { /* beginning of file */ + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; + } + continue; + } + n--; + if(n > 0 && n < HISTSZ) { + d = h->line - a[n].incl->line; + a[n-1].ldel += d; + a[n-1].idel += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + str[0] = 0; + for(i=n-1; i>=0; i--) { + if(i != n-1) { + if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */ + break; + strcat(str, " "); + } + if(a[i].line) + snprint(s, STRINGSZ, "%s:%ld[%s:%ld]", + a[i].line->name, l-a[i].ldel+1, + a[i].incl->name, l-a[i].idel+1); + else + snprint(s, STRINGSZ, "%s:%ld", + a[i].incl->name, l-a[i].idel+1); + if(strlen(s)+strlen(str) >= STRINGSZ-10) + break; + strcat(str, s); + l = a[i].incl->line - 1; /* now print out start of this file */ + } + if(n == 0) + strcat(str, "<eof>"); + return fmtstrcpy(fp, str); +} + +int +Tconv(Fmt *fp) +{ + char str[STRINGSZ+20], s[STRINGSZ+20]; + Type *t, *t1; + int et; + long n; + + str[0] = 0; + for(t = va_arg(fp->args, Type*); t != T; t = t->link) { + et = t->etype; + if(str[0]) + strcat(str, " "); + if(t->garb&~GINCOMPLETE) { + sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + sprint(s, "%s", tnames[et]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + if(et == TFUNC && (t1 = t->down)) { + sprint(s, "(%T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + while(t1 = t1->down) { + sprint(s, ", %T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, ")"); + } + if(et == TARRAY) { + n = t->width; + if(t->link && t->link->width) + n /= t->link->width; + sprint(s, "[%ld]", n); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(t->nbits) { + sprint(s, " %d:%d", t->shift, t->nbits); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(typesu[et]) { + if(t->tag) { + strcat(str, " "); + if(strlen(str) + strlen(t->tag->name) < STRINGSZ) + strcat(str, t->tag->name); + } else + strcat(str, " {}"); + break; + } + } + return fmtstrcpy(fp, str); +} + +int +FNconv(Fmt *fp) +{ + char *str; + Node *n; + + n = va_arg(fp->args, Node*); + str = "<indirect>"; + if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM)) + str = n->sym->name; + return fmtstrcpy(fp, str); +} + +int +Qconv(Fmt *fp) +{ + char str[STRINGSZ+20], *s; + long b; + int i; + + str[0] = 0; + for(b = va_arg(fp->args, long); b;) { + i = bitno(b); + if(str[0]) + strcat(str, " "); + s = qnames[i]; + if(strlen(str) + strlen(s) >= STRINGSZ) + break; + strcat(str, s); + b &= ~(1L << i); + } + return fmtstrcpy(fp, str); +} + +int +VBconv(Fmt *fp) +{ + char str[STRINGSZ]; + int i, n, t, pc; + + n = va_arg(fp->args, int); + pc = 0; /* BUG: was printcol */ + i = 0; + while(pc < n) { + t = (pc+4) & ~3; + if(t <= n) { + str[i++] = '\t'; + pc = t; + continue; + } + str[i++] = ' '; + pc++; + } + str[i] = 0; + + return fmtstrcpy(fp, str); +} + +/* + * real allocs + */ +void* +alloc(long n) +{ + void *p; + + while((uintptr)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +void +setinclude(char *p) +{ + int i; + char *e; + + while(*p != 0) { + e = strchr(p, ' '); + if(e != 0) + *e = '\0'; + + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + break; + + if(i >= ninclude) + include[ninclude++] = p; + + if(ninclude > nelem(include)) { + diag(Z, "ninclude too small %d", nelem(include)); + exits("ninclude"); + } + + if(e == 0) + break; + p = e+1; + } +} diff --git a/utils/cc/lexbody b/utils/cc/lexbody new file mode 100644 index 00000000..d8e3f6eb --- /dev/null +++ b/utils/cc/lexbody @@ -0,0 +1,688 @@ +/* + * common code for all the assemblers + */ + +void +pragpack(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragvararg(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragfpround(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragprofile(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragincomplete(void) +{ + while(getnsc() != '\n') + ; +} + +/* + * real allocs + */ +void* +alloc(long n) +{ + void *p; + + while((uintptr)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +void +setinclude(char *p) +{ + int i; + + if(p == 0) + return; + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + return; + + if(ninclude >= nelem(include)) { + yyerror("ninclude too small %d", nelem(include)); + exits("ninclude"); + } + include[ninclude++] = p; +} + +void +errorexit(void) +{ + + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static int pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%ca: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + Sym *s; + long h; + char *p; + int c, l; + + h = 0; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(memcmp(s->name, symb, l) == 0) + return s; + } + s = alloc(sizeof(*s)); + s->name = alloc(l); + memmove(s->name, symb, l); + + s->link = hash[h]; + hash[h] = s; + syminit(s); + return s; +} + +long +yylex(void) +{ + int c, c1; + char *cp; + Sym *s; + + c = peekc; + if(c != IGN) { + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c == EOF) { + peekc = EOF; + return -1; + } + if(isspace(c)) { + if(c == '\n') { + lineno++; + return ';'; + } + goto l0; + } + if(isalpha(c)) + goto talph; + if(isdigit(c)) + goto tnum; + switch(c) + { + case '\n': + lineno++; + return ';'; + + case '#': + domacro(); + goto l0; + + case '.': + c = GETC(); + if(isalpha(c)) { + cp = symb; + *cp++ = '.'; + goto aloop; + } + if(isdigit(c)) { + cp = symb; + *cp++ = '.'; + goto casedot; + } + peekc = c; + return '.'; + + talph: + case '_': + case '@': + cp = symb; + + aloop: + *cp++ = c; + c = GETC(); + if(isalpha(c) || isdigit(c) || c == '_' || c == '$') + goto aloop; + *cp = 0; + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + if(s->type == 0) + s->type = LNAME; + if(s->type == LNAME || + s->type == LVAR || + s->type == LLAB) { + yylval.sym = s; + return s->type; + } + yylval.lval = s->value; + return s->type; + + tnum: + cp = symb; + if(c != '0') + goto dc; + *cp++ = c; + c = GETC(); + c1 = 3; + if(c == 'x' || c == 'X') { + c1 = 4; + c = GETC(); + } else + if(c < '0' || c > '7') + goto dc; + yylval.lval = 0; + for(;;) { + if(c >= '0' && c <= '9') { + if(c > '7' && c1 == 3) + break; + yylval.lval <<= c1; + yylval.lval += c - '0'; + c = GETC(); + continue; + } + if(c1 == 3) + break; + if(c >= 'A' && c <= 'F') + c += 'a' - 'A'; + if(c >= 'a' && c <= 'f') { + yylval.lval <<= c1; + yylval.lval += c - 'a' + 10; + c = GETC(); + continue; + } + break; + } + goto ncu; + + dc: + for(;;) { + if(!isdigit(c)) + break; + *cp++ = c; + c = GETC(); + } + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + *cp = 0; + if(sizeof(yylval.lval) == sizeof(vlong)) + yylval.lval = strtoll(symb, nil, 10); + else + yylval.lval = strtol(symb, nil, 10); + + ncu: + while(c == 'U' || c == 'u' || c == 'l' || c == 'L') + c = GETC(); + peekc = c; + return LCONST; + + casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c == 'e' || c == 'E') + goto casee; + goto caseout; + + casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + + caseout: + *cp = 0; + peekc = c; + if(FPCHIP) { + yylval.dval = atof(symb); + return LFCONST; + } + yyerror("assembler cannot interpret fp constants"); + yylval.lval = 1L; + return LCONST; + + case '"': + memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval)); + cp = yylval.sval; + c1 = 0; + for(;;) { + c = escchar('"'); + if(c == EOF) + break; + if(c1 < sizeof(yylval.sval)) + *cp++ = c; + c1++; + } + if(c1 > sizeof(yylval.sval)) + yyerror("string constant too long"); + return LSCONST; + + case '\'': + c = escchar('\''); + if(c == EOF) + c = '\''; + if(escchar('\'') != EOF) + yyerror("missing '"); + yylval.lval = c; + return LCONST; + + case '/': + c1 = GETC(); + if(c1 == '/') { + for(;;) { + c = GETC(); + if(c == '\n') { + lineno++; + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '*') { + for(;;) { + c = GETC(); + while(c == '*') { + c = GETC(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + if(c == '\n') + lineno++; + } + } + break; + + default: + return c; + } + peekc = c1; + return c; +} + +int +getc(void) +{ + int c; + + c = peekc; + if(c != IGN) { + peekc = IGN; + return c; + } + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +int +getnsc(void) +{ + int c; + + for(;;) { + c = getc(); + if(!isspace(c) || c == '\n') + return c; + } +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +int +escchar(int e) +{ + int c, l; + +loop: + c = getc(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + return EOF; + return c; + } + c = getc(); + if(c >= '0' && c <= '7') { + l = c - '0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + return l; + } + } + peekc = c; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return 0x07; + case 'v': return 0x0b; + case 'z': return 0x00; + } + return c; +} + +void +pinit(char *f) +{ + int i; + Sym *s; + + lineno = 1; + newio(); + newfile(f, -1); + pc = 0; + peekc = IGN; + sym = 1; + for(i=0; i<NSYM; i++) { + h[i].type = 0; + h[i].sym = S; + } + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + s->macro = 0; +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0]; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++; +} + +void +yyerror(char *a, ...) +{ + char buf[200]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(a, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + prfile(lineno); + va_start(arg, a); + vseprint(buf, buf+sizeof(buf), a, arg); + va_end(arg); + print("%s\n", buf); + nerrors++; + if(nerrors > 10) { + print("too many errors\n"); + errorexit(); + } +} + +void +prfile(long l) +{ + int i, n; + Hist a[HISTSZ], *h; + long d; + + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset == 0) { + if(n >= 0 && n < HISTSZ) + a[n] = *h; + n++; + continue; + } + if(n > 0 && n < HISTSZ) + if(a[n-1].offset == 0) { + a[n] = *h; + n++; + } else + a[n-1] = *h; + continue; + } + n--; + if(n >= 0 && n < HISTSZ) { + d = h->line - a[n].line; + for(i=0; i<n; i++) + a[i].line += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + for(i=0; i<n; i++) + print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1)); +} + +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); +} diff --git a/utils/cc/mac.c b/utils/cc/mac.c new file mode 100644 index 00000000..7ec6e393 --- /dev/null +++ b/utils/cc/mac.c @@ -0,0 +1,3 @@ +#include "cc.h" + +#include "macbody" diff --git a/utils/cc/macbody b/utils/cc/macbody new file mode 100644 index 00000000..91181875 --- /dev/null +++ b/utils/cc/macbody @@ -0,0 +1,822 @@ + +long +getnsn(void) +{ + long n; + int c; + + c = getnsc(); + if(c < '0' || c > '9') + return -1; + n = 0; + while(c >= '0' && c <= '9') { + n = n*10 + c-'0'; + c = getc(); + } + unget(c); + return n; +} + +Sym* +getsym(void) +{ + int c; + char *cp; + + c = getnsc(); + if(!isalpha(c) && c != '_') { + unget(c); + return S; + } + for(cp = symb;;) { + if(cp <= symb+NSYMB-4) + *cp++ = c; + c = getc(); + if(isalnum(c) || c == '_') + continue; + unget(c); + break; + } + *cp = 0; + if(cp > symb+NSYMB-4) + yyerror("symbol too large: %s", symb); + return lookup(); +} + +int +getcom(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c != '/') + break; + c = getc(); + if(c == '/') { + while(c != '\n') + c = getc(); + break; + } + if(c != '*') + break; + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment across newline"); + break; + } + c = getc(); + } + if(c == '\n') + break; + } + return c; +} + +void +dodefine(char *cp) +{ + Sym *s; + char *p; + long l; + + strcpy(symb, cp); + p = strchr(symb, '='); + if(p) { + *p++ = 0; + s = lookup(); + l = strlen(p) + 2; /* +1 null, +1 nargs */ + while(l & 3) + l++; + while(nhunk < l) + gethunk(); + *hunk = 0; + strcpy(hunk+1, p); + s->macro = hunk; + hunk += l; + nhunk -= l; + } else { + s = lookup(); + s->macro = "\0001"; /* \000 is nargs */ + } + if(debug['m']) + print("#define (-D) %s %s\n", s->name, s->macro+1); +} + +struct +{ + char *macname; + void (*macf)(void); +} mactab[] = +{ + "ifdef", 0, /* macif(0) */ + "ifndef", 0, /* macif(1) */ + "else", 0, /* macif(2) */ + + "line", maclin, + "define", macdef, + "include", macinc, + "undef", macund, + + "pragma", macprag, + "endif", macend, + 0 +}; + +void +domacro(void) +{ + int i; + Sym *s; + + s = getsym(); + if(s == S) + s = slookup("endif"); + for(i=0; mactab[i].macname; i++) + if(strcmp(s->name, mactab[i].macname) == 0) { + if(mactab[i].macf) + (*mactab[i].macf)(); + else + macif(i); + return; + } + yyerror("unknown #: %s", s->name); + macend(); +} + +void +macund(void) +{ + Sym *s; + + s = getsym(); + macend(); + if(s == S) { + yyerror("syntax in #undef"); + return; + } + s->macro = 0; +} + +#define NARG 25 +void +macdef(void) +{ + Sym *s, *a; + char *args[NARG], *np, *base; + int n, i, c, len; + int ischr; + + s = getsym(); + if(s == S) + goto bad; + if(s->macro) + yyerror("macro redefined: %s", s->name); + c = getc(); + n = -1; + if(c == '(') { + n++; + c = getnsc(); + if(c != ')') { + unget(c); + for(;;) { + a = getsym(); + if(a == S) + goto bad; + if(n >= NARG) { + yyerror("too many arguments in #define: %s", s->name); + goto bad; + } + args[n++] = a->name; + c = getnsc(); + if(c == ')') + break; + if(c != ',') + goto bad; + } + } + c = getc(); + } + if(isspace(c)) + if(c != '\n') + c = getnsc(); + base = hunk; + len = 1; + ischr = 0; + for(;;) { + if(isalpha(c) || c == '_') { + np = symb; + *np++ = c; + c = getc(); + while(isalnum(c) || c == '_') { + *np++ = c; + c = getc(); + } + *np = 0; + for(i=0; i<n; i++) + if(strcmp(symb, args[i]) == 0) + break; + if(i >= n) { + i = strlen(symb); + base = allocn(base, len, i); + memcpy(base+len, symb, i); + len += i; + continue; + } + base = allocn(base, len, 2); + base[len++] = '#'; + base[len++] = 'a' + i; + continue; + } + if(ischr){ + if(c == '\\'){ + base = allocn(base, len, 1); + base[len++] = c; + c = getc(); + }else if(c == ischr) + ischr = 0; + }else{ + if(c == '"' || c == '\''){ + base = allocn(base, len, 1); + base[len++] = c; + ischr = c; + c = getc(); + continue; + } + if(c == '/') { + c = getc(); + if(c == '/'){ + c = getc(); + for(;;) { + if(c == '\n') + break; + c = getc(); + } + continue; + } + if(c == '*'){ + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment and newline in define: %s", s->name); + break; + } + c = getc(); + } + continue; + } + base = allocn(base, len, 1); + base[len++] = '/'; + continue; + } + } + if(c == '\\') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + else if(c == '\r') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + } + base = allocn(base, len, 1); + base[len++] = '\\'; + continue; + } + if(c == '\n') + break; + if(c == '#') + if(n > 0) { + base = allocn(base, len, 1); + base[len++] = c; + } + base = allocn(base, len, 1); + base[len++] = c; + c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)); + if(c == '\n') + lineno++; + if(c == -1) { + yyerror("eof in a macro: %s", s->name); + break; + } + } + do { + base = allocn(base, len, 1); + base[len++] = 0; + } while(len & 3); + + *base = n+1; + s->macro = base; + if(debug['m']) + print("#define %s %s\n", s->name, s->macro+1); + return; + +bad: + if(s == S) + yyerror("syntax in #define"); + else + yyerror("syntax in #define: %s", s->name); + macend(); +} + +void +macexpand(Sym *s, char *b) +{ + char buf[2000]; + int n, l, c, nargs; + char *arg[NARG], *cp, *ob, *ecp; + + ob = b; + nargs = *s->macro - 1; + if(nargs < 0) { + strcpy(b, s->macro+1); + if(debug['m']) + print("#expand %s %s\n", s->name, ob); + return; + } + c = getnsc(); + if(c != '(') + goto bad; + n = 0; + c = getc(); + if(c != ')') { + unget(c); + l = 0; + cp = buf; + ecp = cp + sizeof(buf)-4; + arg[n++] = cp; + for(;;) { + if(cp >= ecp) + goto toobig; + c = getc(); + if(c == '"') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '"') + break; + } + if(c == '\'') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '\'') + break; + } + if(c == '/') { + c = getc(); + switch(c) { + case '*': + for(;;) { + c = getc(); + if(c == '*') { + c = getc(); + if(c == '/') + break; + } + } + *cp++ = ' '; + continue; + case '/': + while((c = getc()) != '\n') + ; + break; + default: + unget(c); + c = '/'; + } + } + if(l == 0) { + if(c == ',') { + *cp++ = 0; + arg[n++] = cp; + if(n > nargs) + break; + continue; + } + if(c == ')') + break; + } + if(c == '\n') + c = ' '; + *cp++ = c; + if(c == '(') + l++; + if(c == ')') + l--; + } + *cp = 0; + } + if(n != nargs) { + yyerror("argument mismatch expanding: %s", s->name); + *b = 0; + return; + } + cp = s->macro+1; + for(;;) { + c = *cp++; + if(c != '#') { + *b++ = c; + if(c == 0) + break; + continue; + } + c = *cp++; + if(c == 0) + goto bad; + if(c == '#') { + *b++ = c; + continue; + } + c -= 'a'; + if(c < 0 || c >= n) + continue; + strcpy(b, arg[c]); + b += strlen(arg[c]); + } + *b = 0; + if(debug['m']) + print("#expand %s %s\n", s->name, ob); + return; + +bad: + yyerror("syntax in macro expansion: %s", s->name); + *b = 0; + return; + +toobig: + yyerror("too much text in macro expansion: %s", s->name); + *b = 0; +} + +void +macinc(void) +{ + int c0, c, i, f; + char str[STRINGSZ], *hp; + + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = str;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + + c = getcom(); + if(c != '\n') + goto bad; + + f = -1; + for(i=0; i<ninclude; i++) { + if(i == 0 && c0 == '>') + continue; + strcpy(symb, include[i]); + strcat(symb, "/"); + if(strcmp(symb, "./") == 0) + symb[0] = 0; + strcat(symb, str); + f = open(symb, 0); + if(f >= 0) + break; + } + if(f < 0) + strcpy(symb, str); + c = strlen(symb) + 1; + while(c & 3) + c++; + while(nhunk < c) + gethunk(); + hp = hunk; + memcpy(hunk, symb, c); + nhunk -= c; + hunk += c; + newio(); + pushio(); + newfile(hp, f); + return; + +bad: + unget(c); + yyerror("syntax in #include"); + macend(); +} + +void +maclin(void) +{ + char *cp; + int c; + long n; + + n = getnsn(); + c = getc(); + if(n < 0) + goto bad; + + for(;;) { + if(c == ' ' || c == '\t') { + c = getc(); + continue; + } + if(c == '"') + break; + if(c == '\n') { + strcpy(symb, "<noname>"); + goto nn; + } + goto bad; + } + cp = symb; + for(;;) { + c = getc(); + if(c == '"') + break; + *cp++ = c; + } + *cp = 0; + c = getcom(); + if(c != '\n') + goto bad; + +nn: + c = strlen(symb) + 1; + while(c & 3) + c++; + while(nhunk < c) + gethunk(); + cp = hunk; + memcpy(hunk, symb, c); + nhunk -= c; + hunk += c; + linehist(cp, n); + return; + +bad: + unget(c); + yyerror("syntax in #line"); + macend(); +} + +void +macif(int f) +{ + int c, l, bol; + Sym *s; + + if(f == 2) + goto skip; + s = getsym(); + if(s == S) + goto bad; + if(getcom() != '\n') + goto bad; + if((s->macro != 0) ^ f) + return; + +skip: + bol = 1; + l = 0; + for(;;) { + c = getc(); + if(c != '#') { + if(!isspace(c)) + bol = 0; + if(c == '\n') + bol = 1; + continue; + } + if(!bol) + continue; + s = getsym(); + if(s == S) + continue; + if(strcmp(s->name, "endif") == 0) { + if(l) { + l--; + continue; + } + macend(); + return; + } + if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) { + l++; + continue; + } + if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) { + macend(); + return; + } + } + +bad: + yyerror("syntax in #if(n)def"); + macend(); +} + +void +macprag(void) +{ + Sym *s; + int c0, c; + char *hp; + Hist *h; + + s = getsym(); + + if(s && strcmp(s->name, "lib") == 0) + goto praglib; + if(s && strcmp(s->name, "pack") == 0) { + pragpack(); + return; + } + if(s && strcmp(s->name, "fpround") == 0) { + pragfpround(); + return; + } + if(s && strcmp(s->name, "profile") == 0) { + pragprofile(); + return; + } + if(s && strcmp(s->name, "varargck") == 0) { + pragvararg(); + return; + } + if(s && strcmp(s->name, "incomplete") == 0) { + pragincomplete(); + return; + } + while(getnsc() != '\n') + ; + return; + +praglib: + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = symb;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + c = getcom(); + if(c != '\n') + goto bad; + + /* + * put pragma-line in as a funny history + */ + c = strlen(symb) + 1; + while(c & 3) + c++; + while(nhunk < c) + gethunk(); + hp = hunk; + memcpy(hunk, symb, c); + nhunk -= c; + hunk += c; + + h = alloc(sizeof(Hist)); + h->name = hp; + h->line = lineno; + h->offset = -1; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; + return; + +bad: + unget(c); + yyerror("syntax in #pragma lib"); + macend(); +} + +void +macend(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c < 0 || c == '\n') + return; + } +} + +void +linehist(char *f, int offset) +{ + Hist *h; + + /* + * overwrite the last #line directive if + * no alloc has happened since the last one + */ + if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0) + if(f && ehist->name && strcmp(f, ehist->name) == 0) { + ehist->line = lineno; + ehist->offset = offset; + return; + } + + if(debug['f']) + if(f) { + if(offset) + print("%4ld: %s (#line %d)\n", lineno, f, offset); + else + print("%4ld: %s\n", lineno, f); + } else + print("%4ld: <pop>\n", lineno); + newflag = 0; + + h = alloc(sizeof(Hist)); + h->name = f; + h->line = lineno; + h->offset = offset; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(thunk >= 10L*NHUNK) + nh = 10L*NHUNK; + h = (char*)mysbrk(nh); + if(h == (char*)-1) { + yyerror("out of memory"); + errorexit(); + } + hunk = h; + nhunk = nh; + thunk += nh; +} diff --git a/utils/cc/machcap.c b/utils/cc/machcap.c new file mode 100644 index 00000000..06b5684a --- /dev/null +++ b/utils/cc/machcap.c @@ -0,0 +1,9 @@ +#include "cc.h" + +/* default, like old cc */ +int +machcap(Node *n) +{ + USED(n); + return 0; +} diff --git a/utils/cc/mkfile b/utils/cc/mkfile new file mode 100644 index 00000000..c2df13a5 --- /dev/null +++ b/utils/cc/mkfile @@ -0,0 +1,35 @@ +<../../mkconfig + +LIB=libcc.a + +OFILES=\ + acid.$O\ + bits.$O\ + com.$O\ + com64.$O\ + $TARGMODEL.$O\ + dcl.$O\ + dpchk.$O\ + funct.$O\ + lex.$O\ + mac.$O\ + mpatof.$O\ + pickle.$O\ + scon.$O\ + sub.$O\ + y.tab.$O\ + machcap.$O\ + +HFILES=cc.h\ + y.tab.h\ + +YFILES=cc.y\ + +<$ROOT/mkfiles/mksyslib-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +mac.$O: macbody + +lex.$O: lex.c + $CC $CFLAGS '-DCPP="/bin/cpp"' lex.c diff --git a/utils/cc/mpatof.c b/utils/cc/mpatof.c new file mode 100644 index 00000000..a59164b7 --- /dev/null +++ b/utils/cc/mpatof.c @@ -0,0 +1,271 @@ +#include "cc.h" + +enum +{ + Mpscale = 29, /* safely smaller than bits in a long */ + Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */ + Mpbase = 1L<<Mpscale, +}; + +typedef +struct +{ + long a[Mpprec]; + char ovf; +} Mp; + +int mpatof(char*, double*); +int mpatov(char *s, vlong *v); +void mpint(Mp*, int); +void mppow(Mp*, int, int); +void mpmul(Mp*, int); +void mpadd(Mp*, Mp*); +int mptof(Mp*, double*); + +/* + * convert a string, s, to floating in *d + * return conversion overflow. + * required syntax is [+-]d*[.]d*[e[+-]d*] + */ +int +mpatof(char *s, double *d) +{ + Mp a, b; + int dp, c, f, ef, ex, zer; + double d1, d2; + + dp = 0; /* digits after decimal point */ + f = 0; /* sign */ + ex = 0; /* exponent */ + zer = 1; /* zero */ + memset(&a, 0, sizeof(a)); + for(;;) { + switch(c = *s++) { + default: + goto bad; + case '-': + f = 1; + case ' ': + case '\t': + case '+': + continue; + case '.': + dp = 1; + continue; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + zer = 0; + case '0': + mpint(&b, c-'0'); + mpmul(&a, 10); + mpadd(&a, &b); + if(dp) + dp++; + continue; + case 'E': + case 'e': + ex = 0; + ef = 0; + for(;;) { + c = *s++; + if(c == '+' || c == ' ' || c == '\t') + continue; + if(c == '-') { + ef = 1; + continue; + } + if(c >= '0' && c <= '9') { + ex = ex*10 + (c-'0'); + continue; + } + break; + } + if(ef) + ex = -ex; + case 0: + break; + } + break; + } + if(a.ovf) + goto bad; + if(zer) { + *d = 0; + return 0; + } + if(dp) + dp--; + dp -= ex; + if(dp > 0) { + /* + * must divide by 10**dp + */ + if(mptof(&a, &d1)) + goto bad; + + /* + * trial exponent of 8**dp + * 8 (being between 5 and 10) + * should pick up all underflows + * in the division of 5**dp. + */ + d2 = frexp(d1, &ex); + d2 = ldexp(d2, ex-3*dp); + if(d2 == 0) + goto bad; + + /* + * decompose each 10 into 5*2. + * create 5**dp in fixed point + * and then play with the exponent + * for the remaining 2**dp. + * note that 5**dp will overflow + * with as few as 134 input digits. + */ + mpint(&a, 1); + mppow(&a, 5, dp); + if(mptof(&a, &d2)) + goto bad; + d1 = frexp(d1/d2, &ex); + d1 = ldexp(d1, ex-dp); + if(d1 == 0) + goto bad; + } else { + /* + * must multiply by 10**|dp| -- + * just do it in fixed point. + */ + mppow(&a, 10, -dp); + if(mptof(&a, &d1)) + goto bad; + } + if(f) + d1 = -d1; + *d = d1; + return 0; + +bad: + return 1; +} + +/* + * convert a to floating in *d + * return conversion overflow + */ +int +mptof(Mp *a, double *d) +{ + double f, g; + long x, *a1; + int i; + + if(a->ovf) + return 1; + a1 = a->a; + f = ldexp(*a1++, 0); + for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale) + if(x = *a1++) { + g = ldexp(x, i); + /* + * NOTE: the test (g==0) is plan9 + * specific. ansi compliant overflow + * is signaled by HUGE and errno==ERANGE. + * change this for your particular ldexp. + */ + if(g == 0) + return 1; + f += g; /* this could bomb! */ + } + *d = f; + return 0; +} + +/* + * return a += b + */ +void +mpadd(Mp *a, Mp *b) +{ + int i, c; + long x, *a1, *b1; + + if(b->ovf) + a->ovf = 1; + if(a->ovf) + return; + c = 0; + a1 = a->a; + b1 = b->a; + for(i=0; i<Mpprec; i++) { + x = *a1 + *b1++ + c; + c = 0; + if(x >= Mpbase) { + x -= Mpbase; + c = 1; + } + *a1++ = x; + } + a->ovf = c; +} + +/* + * return a = c + */ +void +mpint(Mp *a, int c) +{ + + memset(a, 0, sizeof(*a)); + a->a[0] = c; +} + +/* + * return a *= c + */ +void +mpmul(Mp *a, int c) +{ + Mp p; + int b; + + memmove(&p, a, sizeof(p)); + if(!(c & 1)) + memset(a, 0, sizeof(*a)); + c &= ~1; + for(b=2; c; b<<=1) { + mpadd(&p, &p); + if(c & b) { + mpadd(a, &p); + c &= ~b; + } + } +} + +/* + * return a *= b**e + */ +void +mppow(Mp *a, int b, int e) +{ + int b1; + + b1 = b*b; + b1 = b1*b1; + while(e >= 4) { + mpmul(a, b1); + e -= 4; + if(a->ovf) + return; + } + while(e > 0) { + mpmul(a, b); + e--; + } +} diff --git a/utils/cc/pickle.c b/utils/cc/pickle.c new file mode 100644 index 00000000..370b9983 --- /dev/null +++ b/utils/cc/pickle.c @@ -0,0 +1,268 @@ +#include "cc.h" + +static char *kwd[] = +{ + "$adt", "$aggr", "$append", "$complex", "$defn", + "$delete", "$do", "$else", "$eval", "$head", "$if", + "$local", "$loop", "$return", "$tail", "$then", + "$union", "$whatis", "$while", +}; +static char picklestr[] = "\tbp = pickle(bp, ep, un, "; + +static char* +pmap(char *s) +{ + int i, bot, top, new; + + bot = 0; + top = bot + nelem(kwd) - 1; + while(bot <= top){ + new = bot + (top - bot)/2; + i = strcmp(kwd[new]+1, s); + if(i == 0) + return kwd[new]; + + if(i < 0) + bot = new + 1; + else + top = new - 1; + } + return s; +} + +Sym* +picklesue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +Sym* +picklefun(Type *t) +{ + int h; + Sym *s; + + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->type == t) + return s; + return 0; +} + +char picklechar[NTYPE]; +Init picklecinit[] = +{ + TCHAR, 'C', 0, + TUCHAR, 'b', 0, + TSHORT, 'd', 0, + TUSHORT, 'u', 0, + TLONG, 'D', 0, + TULONG, 'U', 0, + TVLONG, 'V', 0, + TUVLONG, 'W', 0, + TFLOAT, 'f', 0, + TDOUBLE, 'F', 0, + TARRAY, 'a', 0, + TIND, 'X', 0, + -1, 0, 0, +}; + +static void +pickleinit(void) +{ + Init *p; + + for(p=picklecinit; p->code >= 0; p++) + picklechar[p->code] = p->value; + + picklechar[TINT] = picklechar[TLONG]; + picklechar[TUINT] = picklechar[TULONG]; + if(types[TINT]->width != types[TLONG]->width) { + picklechar[TINT] = picklechar[TSHORT]; + picklechar[TUINT] = picklechar[TUSHORT]; + if(types[TINT]->width != types[TSHORT]->width) + warn(Z, "picklemember int not long or short"); + } + +} + +void +picklemember(Type *t, long off) +{ + Sym *s, *s1; + static int picklecharinit = 0; + + if(picklecharinit == 0) { + pickleinit(); + picklecharinit = 1; + } + s = t->sym; + switch(t->etype) { + default: + Bprint(&outbuf, " T%d\n", t->etype); + break; + + case TIND: + if(s == S) + Bprint(&outbuf, + "%s\"p\", (char*)addr+%ld+_i*%ld);\n", + picklestr, t->offset+off, t->width); + else + Bprint(&outbuf, + "%s\"p\", &addr->%s);\n", + picklestr, pmap(s->name)); + break; + + case TINT: + case TUINT: + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + if(s == S) + Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n", + picklestr, picklechar[t->etype], t->offset+off, t->width); + else + Bprint(&outbuf, "%s\"%c\", &addr->%s);\n", + picklestr, picklechar[t->etype], pmap(s->name)); + break; + case TARRAY: + Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t", + t->width/t->link->width); + picklemember(t->link, t->offset+off); + Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n"); + break; + + case TSTRUCT: + case TUNION: + s1 = picklesue(t->link); + if(s1 == S) + break; + if(s == S) { + Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n", + pmap(s1->name), pmap(s1->name), t->offset+off, t->width); + } else { + Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n", + pmap(s1->name), pmap(s->name)); + } + break; + } +} + +void +pickletype(Type *t) +{ + Sym *s; + Type *l; + Io *i; + int n; + char *an; + + if(!debug['P']) + return; + if(debug['P'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + s = picklesue(t->link); + if(s == S) + return; + switch(t->etype) { + default: + Bprint(&outbuf, "T%d\n", t->etype); + return; + + case TUNION: + case TSTRUCT: + if(debug['s']) + goto asmstr; + an = pmap(s->name); + + Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an); + for(l = t->link; l != T; l = l->down) + picklemember(l, 0); + Bprint(&outbuf, "\treturn bp;\n}\n\n"); + break; + asmstr: + if(s == S) + break; + for(l = t->link; l != T; l = l->down) + if(l->sym != S) + Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + s->name, + l->sym->name, + l->offset); + break; + } +} + +void +picklevar(Sym *s) +{ + int n; + Io *i; + Type *t; + Sym *s1, *s2; + + if(!debug['P'] || debug['s']) + return; + if(debug['P'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + t = s->type; + while(t && t->etype == TIND) + t = t->link; + if(t == T) + return; + if(t->etype == TENUM) { + Bprint(&outbuf, "%s = ", pmap(s->name)); + if(!typefd[t->etype]) + Bprint(&outbuf, "%lld;\n", s->vconst); + else + Bprint(&outbuf, "%f\n;", s->fconst); + return; + } + if(!typesu[t->etype]) + return; + s1 = picklesue(t->link); + if(s1 == S) + return; + switch(s->class) { + case CAUTO: + case CPARAM: + s2 = picklefun(thisfn); + if(s2) + Bprint(&outbuf, "complex %s %s:%s;\n", + pmap(s1->name), pmap(s2->name), pmap(s->name)); + break; + + case CSTATIC: + case CEXTERN: + case CGLOBL: + case CLOCAL: + Bprint(&outbuf, "complex %s %s;\n", + pmap(s1->name), pmap(s->name)); + break; + } +} diff --git a/utils/cc/scon.c b/utils/cc/scon.c new file mode 100644 index 00000000..f0c2bd13 --- /dev/null +++ b/utils/cc/scon.c @@ -0,0 +1,606 @@ +#include "cc.h" + +static Node* +acast(Type *t, Node *n) +{ + if(n->type->etype != t->etype || n->op == OBIT) { + n = new1(OCAST, n, Z); + if(nocast(n->left->type, t)) + *n = *n->left; + n->type = t; + } + return n; +} + + +void +evconst(Node *n) +{ + Node *l, *r; + int et, isf; + vlong v; + double d; + + if(n == Z || n->type == T) + return; + + et = n->type->etype; + isf = typefd[et]; + + l = n->left; + r = n->right; + + d = 0; + v = 0; + + switch(n->op) { + default: + return; + + case ONEG: + if(isf) + d = -l->fconst; + else + v = -l->vconst; + break; + + case OCOM: + v = ~l->vconst; + break; + + case OCAST: + if(et == TVOID) + return; + et = l->type->etype; + if(isf) { + if(typefd[et]) + d = l->fconst; + else + d = l->vconst; + } else { + if(typefd[et]) + v = l->fconst; + else + v = convvtox(l->vconst, n->type->etype); + } + break; + + case OCONST: + break; + + case OADD: + if(isf) + d = l->fconst + r->fconst; + else { + v = l->vconst + r->vconst; + } + break; + + case OSUB: + if(isf) + d = l->fconst - r->fconst; + else + v = l->vconst - r->vconst; + break; + + case OMUL: + if(isf) + d = l->fconst * r->fconst; + else { + v = l->vconst * r->vconst; + } + break; + + case OLMUL: + v = (uvlong)l->vconst * (uvlong)r->vconst; + break; + + + case ODIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + if(isf) + d = l->fconst / r->fconst; + else + v = l->vconst / r->vconst; + break; + + case OLDIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + v = (uvlong)l->vconst / (uvlong)r->vconst; + break; + + case OMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = l->vconst % r->vconst; + break; + + case OLMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = (uvlong)l->vconst % (uvlong)r->vconst; + break; + + case OAND: + v = l->vconst & r->vconst; + break; + + case OOR: + v = l->vconst | r->vconst; + break; + + case OXOR: + v = l->vconst ^ r->vconst; + break; + + case OLSHR: + v = (uvlong)l->vconst >> r->vconst; + break; + + case OASHR: + v = l->vconst >> r->vconst; + break; + + case OASHL: + v = l->vconst << r->vconst; + break; + + case OLO: + v = (uvlong)l->vconst < (uvlong)r->vconst; + break; + + case OLT: + if(typefd[l->type->etype]) + v = l->fconst < r->fconst; + else + v = l->vconst < r->vconst; + break; + + case OHI: + v = (uvlong)l->vconst > (uvlong)r->vconst; + break; + + case OGT: + if(typefd[l->type->etype]) + v = l->fconst > r->fconst; + else + v = l->vconst > r->vconst; + break; + + case OLS: + v = (uvlong)l->vconst <= (uvlong)r->vconst; + break; + + case OLE: + if(typefd[l->type->etype]) + v = l->fconst <= r->fconst; + else + v = l->vconst <= r->vconst; + break; + + case OHS: + v = (uvlong)l->vconst >= (uvlong)r->vconst; + break; + + case OGE: + if(typefd[l->type->etype]) + v = l->fconst >= r->fconst; + else + v = l->vconst >= r->vconst; + break; + + case OEQ: + if(typefd[l->type->etype]) + v = l->fconst == r->fconst; + else + v = l->vconst == r->vconst; + break; + + case ONE: + if(typefd[l->type->etype]) + v = l->fconst != r->fconst; + else + v = l->vconst != r->vconst; + break; + + case ONOT: + if(typefd[l->type->etype]) + v = !l->fconst; + else + v = !l->vconst; + break; + + case OANDAND: + if(typefd[l->type->etype]) + v = l->fconst && r->fconst; + else + v = l->vconst && r->vconst; + break; + + case OOROR: + if(typefd[l->type->etype]) + v = l->fconst || r->fconst; + else + v = l->vconst || r->vconst; + break; + } + if(isf) { + n->fconst = d; + } else { + n->vconst = convvtox(v, n->type->etype); + } + n->oldop = n->op; + n->op = OCONST; +} + +void +acom(Node *n) +{ + Type *t; + Node *l, *r; + int i; + + switch(n->op) + { + + case ONAME: + case OCONST: + case OSTRING: + case OINDREG: + case OREGISTER: + return; + + case ONEG: + l = n->left; + if(addo(n) && addo(l)) + break; + acom(l); + return; + + case OADD: + case OSUB: + case OMUL: + l = n->left; + r = n->right; + if(addo(n)) { + if(addo(r)) + break; + if(addo(l)) + break; + } + acom(l); + acom(r); + return; + + default: + l = n->left; + r = n->right; + if(l != Z) + acom(l); + if(r != Z) + acom(r); + return; + } + + /* bust terms out */ + t = n->type; + term[0].mult = 0; + term[0].node = Z; + nterm = 1; + acom1(1, n); + if(debug['m']) + for(i=0; i<nterm; i++) { + print("%d %3lld ", i, term[i].mult); + prtree1(term[i].node, 1, 0); + } + if(nterm < NTERM) + acom2(n, t); + n->type = t; +} + +int +acomcmp1(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + if(c1 < 0) + c1 = -c1; + c2 = t2->mult; + if(c2 < 0) + c2 = -c2; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + c1 = 1; + if(t1->mult < 0) + c1 = 0; + c2 = 1; + if(t2->mult < 0) + c2 = 0; + if(c2 -= c1) + return c2; + if(t2 > t1) + return 1; + return -1; +} + +int +acomcmp2(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + c2 = t2->mult; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + if(t2 > t1) + return 1; + return -1; +} + +void +acom2(Node *n, Type *t) +{ + Node *l, *r; + Term trm[NTERM]; + int et, nt, i, j; + vlong c1, c2; + + /* + * copy into automatic + */ + c2 = 0; + nt = nterm; + for(i=0; i<nt; i++) + trm[i] = term[i]; + /* + * recur on subtrees + */ + j = 0; + for(i=1; i<nt; i++) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + l = trm[i].node; + if(l != Z) { + j = 1; + acom(l); + } + } + c1 = trm[0].mult; + if(j == 0) { + n->oldop = n->op; + n->op = OCONST; + n->vconst = c1; + return; + } + et = t->etype; + + /* + * prepare constant term, + * combine it with an addressing term + */ + if(c1 != 0) { + l = new1(OCONST, Z, Z); + l->type = t; + l->vconst = c1; + trm[0].mult = 1; + for(i=1; i<nt; i++) { + if(trm[i].mult != 1) + continue; + r = trm[i].node; + if(r->op != OADDR) + continue; + r->type = t; + l = new1(OADD, r, l); + l->type = t; + trm[i].mult = 0; + break; + } + trm[0].node = l; + } + /* + * look for factorable terms + * c1*i + c1*c2*j -> c1*(i + c2*j) + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1); + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 < 0) + c1 = -c1; + if(c1 <= 1) + continue; + for(j=i+1; j<nt; j++) { + c2 = trm[j].mult; + if(c2 < 0) + c2 = -c2; + if(c2 <= 1) + continue; + if(c2 % c1) + continue; + r = trm[j].node; + if(r->type->etype != et) + r = acast(t, r); + c2 = trm[j].mult/trm[i].mult; + if(c2 != 1 && c2 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + r->right->vconst = c2; + } + l = trm[i].node; + if(l->type->etype != et) + l = acast(t, l); + r = new1(OADD, l, r); + r->type = t; + if(c2 == -1) + r->op = OSUB; + trm[i].node = r; + trm[j].mult = 0; + } + } + if(debug['m']) { + print("\n"); + for(i=0; i<nt; i++) { + print("%d %3lld ", i, trm[i].mult); + prtree1(trm[i].node, 1, 0); + } + } + + /* + * put it all back together + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2); + l = Z; + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + r = trm[i].node; + if(r->type->etype != et || r->op == OBIT) + r = acast(t, r); + if(c1 != 1 && c1 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + if(c1 < 0) { + r->right->vconst = -c1; + c1 = -1; + } else { + r->right->vconst = c1; + c1 = 1; + } + } + if(l == Z) { + l = r; + c2 = c1; + continue; + } + if(c1 < 0) + if(c2 < 0) + l = new1(OADD, l, r); + else + l = new1(OSUB, l, r); + else + if(c2 < 0) { + l = new1(OSUB, r, l); + c2 = 1; + } else + l = new1(OADD, l, r); + l->type = t; + } + if(c2 < 0) { + r = new1(OCONST, 0, 0); + r->vconst = 0; + r->type = t; + l = new1(OSUB, r, l); + l->type = t; + } + *n = *l; +} + +void +acom1(vlong v, Node *n) +{ + Node *l, *r; + + if(v == 0 || nterm >= NTERM) + return; + if(!addo(n)) { + if(n->op == OCONST) + if(!typefd[n->type->etype]) { + term[0].mult += v*n->vconst; + return; + } + term[nterm].mult = v; + term[nterm].node = n; + nterm++; + return; + } + switch(n->op) { + + case OCAST: + acom1(v, n->left); + break; + + case ONEG: + acom1(-v, n->left); + break; + + case OADD: + acom1(v, n->left); + acom1(v, n->right); + break; + + case OSUB: + acom1(v, n->left); + acom1(-v, n->right); + break; + + case OMUL: + l = n->left; + r = n->right; + if(l->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*l->vconst, r); + break; + } + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*r->vconst, l); + break; + } + break; + + default: + diag(n, "not addo"); + } +} + +int +addo(Node *n) +{ + + if(n != Z) + if(!typefd[n->type->etype]) + if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND]) + switch(n->op) { + + case OCAST: + if(nilcast(n->left->type, n->type)) + return 1; + break; + + case ONEG: + case OADD: + case OSUB: + return 1; + + case OMUL: + if(n->left->op == OCONST) + return 1; + if(n->right->op == OCONST) + return 1; + } + return 0; +} diff --git a/utils/cc/sub.c b/utils/cc/sub.c new file mode 100644 index 00000000..f1572291 --- /dev/null +++ b/utils/cc/sub.c @@ -0,0 +1,2012 @@ +#include "cc.h" + +Node* +new(int t, Node *l, Node *r) +{ + Node *n; + + n = alloc(sizeof(*n)); + n->op = t; + n->left = l; + n->right = r; + n->lineno = lineno; + newflag = 1; + return n; +} + +Node* +new1(int o, Node *l, Node *r) +{ + Node *n; + + n = new(o, l, r); + n->lineno = nearln; + return n; +} + +void +prtree(Node *n, char *s) +{ + + print(" == %s ==\n", s); + prtree1(n, 0, 0); + print("\n"); +} + +void +prtree1(Node *n, int d, int f) +{ + int i; + + if(f) + for(i=0; i<d; i++) + print(" "); + if(n == Z) { + print("Z\n"); + return; + } + if(n->op == OLIST) { + prtree1(n->left, d, 0); + prtree1(n->right, d, 1); + return; + } + d++; + print("%O", n->op); + i = 3; + switch(n->op) + { + case ONAME: + print(" \"%F\"", n); + print(" %ld", n->xoffset); + i = 0; + break; + + case OINDREG: + print(" %ld(R%d)", n->xoffset, n->reg); + i = 0; + break; + + case OREGISTER: + if(n->xoffset) + print(" %ld+R%d", n->xoffset, n->reg); + else + print(" R%d", n->reg); + i = 0; + break; + + case OSTRING: + print(" \"%s\"", n->cstring); + i = 0; + break; + + case OLSTRING: + print(" \"%S\"", n->rstring); + i = 0; + break; + + case ODOT: + case OELEM: + print(" \"%F\"", n); + break; + + case OCONST: + if(typefd[n->type->etype]) + print(" \"%.8e\"", n->fconst); + else + print(" \"%lld\"", n->vconst); + i = 0; + break; + } + if(n->addable != 0) + print(" <%d>", n->addable); + if(n->type != T) + print(" %T", n->type); + if(n->complex != 0) + print(" (%d)", n->complex); + print("\n"); + if(i & 2) + prtree1(n->left, d, 1); + if(i & 1) + prtree1(n->right, d, 1); +} + +Type* +typ(int et, Type *d) +{ + Type *t; + + t = alloc(sizeof(*t)); + t->etype = et; + t->link = d; + t->down = T; + t->sym = S; + t->width = ewidth[et]; + t->offset = 0; + t->shift = 0; + t->nbits = 0; + t->garb = 0; + return t; +} + +Type* +copytyp(Type *t) +{ + Type *nt; + + nt = typ(TXXX, T); + *nt = *t; + return nt; +} + +Type* +garbt(Type *t, long b) +{ + Type *t1; + + if(b & BGARB) { + t1 = copytyp(t); + t1->garb = simpleg(b); + return t1; + } + return t; +} + +int +simpleg(long b) +{ + + b &= BGARB; + switch(b) { + case BCONSTNT: + return GCONSTNT; + case BVOLATILE: + return GVOLATILE; + case BVOLATILE|BCONSTNT: + return GCONSTNT|GVOLATILE; + } + return GXXX; +} + +int +simplec(long b) +{ + + b &= BCLASS; + switch(b) { + case 0: + case BREGISTER: + return CXXX; + case BAUTO: + case BAUTO|BREGISTER: + return CAUTO; + case BEXTERN: + return CEXTERN; + case BEXTERN|BREGISTER: + return CEXREG; + case BSTATIC: + return CSTATIC; + case BTYPEDEF: + return CTYPEDEF; + case BTYPESTR: + return CTYPESTR; + } + diag(Z, "illegal combination of classes %Q", b); + return CXXX; +} + +Type* +simplet(long b) +{ + + b &= ~BCLASS & ~BGARB; + switch(b) { + case BCHAR: + case BCHAR|BSIGNED: + return types[TCHAR]; + + case BCHAR|BUNSIGNED: + return types[TUCHAR]; + + case BSHORT: + case BSHORT|BINT: + case BSHORT|BSIGNED: + case BSHORT|BINT|BSIGNED: + return types[TSHORT]; + + case BUNSIGNED|BSHORT: + case BUNSIGNED|BSHORT|BINT: + return types[TUSHORT]; + + case 0: + case BINT: + case BINT|BSIGNED: + case BSIGNED: + return types[TINT]; + + case BUNSIGNED: + case BUNSIGNED|BINT: + return types[TUINT]; + + case BLONG: + case BLONG|BINT: + case BLONG|BSIGNED: + case BLONG|BINT|BSIGNED: + return types[TLONG]; + + case BUNSIGNED|BLONG: + case BUNSIGNED|BLONG|BINT: + return types[TULONG]; + + case BVLONG|BLONG: + case BVLONG|BLONG|BINT: + case BVLONG|BLONG|BSIGNED: + case BVLONG|BLONG|BINT|BSIGNED: + return types[TVLONG]; + + case BVLONG|BLONG|BUNSIGNED: + case BVLONG|BLONG|BINT|BUNSIGNED: + return types[TUVLONG]; + + case BFLOAT: + return types[TFLOAT]; + + case BDOUBLE: + case BDOUBLE|BLONG: + case BFLOAT|BLONG: + return types[TDOUBLE]; + + case BVOID: + return types[TVOID]; + } + + diag(Z, "illegal combination of types %Q", b); + return types[TINT]; +} + +int +stcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + int i; + ulong b; + + i = 0; + if(t2 != T) + i = t2->etype; + b = 1L << i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ttab[i]) { + if(ttab == tasign) + if(b == BSTRUCT || b == BUNION) + if(!sametype(t1, t2)) + return 1; + if(n->op != OCAST) + if(b == BIND && i == TIND) + if(!sametype(t1, t2)) + return 1; + return 0; + } + return 1; +} + +int +tcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + + if(stcompat(n, t1, t2, ttab)) { + if(t1 == T) + diag(n, "incompatible type: \"%T\" for op \"%O\"", + t2, n->op); + else + diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"", + t1, t2, n->op); + return 1; + } + return 0; +} + +void +makedot(Node *n, Type *t, long o) +{ + Node *n1, *n2; + + if(t->nbits) { + n1 = new(OXXX, Z, Z); + *n1 = *n; + n->op = OBIT; + n->left = n1; + n->right = Z; + n->type = t; + n->addable = n1->left->addable; + n = n1; + } + n->addable = n->left->addable; + if(n->addable == 0) { + n1 = new1(OCONST, Z, Z); + n1->vconst = o; + n1->type = types[TLONG]; + n->right = n1; + n->type = t; + return; + } + n->left->type = t; + if(o == 0) { + *n = *n->left; + return; + } + n->type = t; + n1 = new1(OCONST, Z, Z); + n1->vconst = o; + t = typ(TIND, t); + t->width = types[TIND]->width; + n1->type = t; + + n2 = new1(OADDR, n->left, Z); + n2->type = t; + + n1 = new1(OADD, n1, n2); + n1->type = t; + + n->op = OIND; + n->left = n1; + n->right = Z; +} + +Type* +dotsearch(Sym *s, Type *t, Node *n, long *off) +{ + Type *t1, *xt, *rt; + + xt = T; + + /* + * look it up by name + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == s) { + if(xt != T) + goto ambig; + xt = t1; + } + + /* + * look it up by type + */ + if(s->class == CTYPEDEF || s->class == CTYPESTR) + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]) + if(sametype(s->type, t1)) { + if(xt != T) + goto ambig; + xt = t1; + } + if(xt != T) { + *off = xt->offset; + return xt; + } + + /* + * look it up in unnamed substructures + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]){ + rt = dotsearch(s, t1->link, n, off); + if(rt != T) { + if(xt != T) + goto ambig; + xt = rt; + *off += t1->offset; + } + } + return xt; + +ambig: + diag(n, "ambiguous structure element: %s", s->name); + return xt; +} + +long +dotoffset(Type *st, Type *lt, Node *n) +{ + Type *t; + Sym *g; + long o, o1; + + o = -1; + /* + * first try matching at the top level + * for matching tag names + */ + g = st->tag; + if(g != S) + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(g == t->tag) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * second try matching at the top level + * for similar types + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(sametype(st, t)) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * last try matching sub-levels + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(typesu[t->etype]) { + o1 = dotoffset(st, t, n); + if(o1 >= 0) { + if(o >= 0) + goto ambig; + o = o1 + t->offset; + } + } + return o; + +ambig: + diag(n, "ambiguous unnamed structure element"); + return o; +} + +/* + * look into tree for floating point constant expressions + */ +int +allfloat(Node *n, int flag) +{ + + if(n != Z) { + if(n->type->etype != TDOUBLE) + return 1; + switch(n->op) { + case OCONST: + if(flag) + n->type = types[TFLOAT]; + return 1; + case OADD: /* no need to get more exotic than this */ + case OSUB: + case OMUL: + case ODIV: + if(!allfloat(n->right, flag)) + break; + case OCAST: + if(!allfloat(n->left, flag)) + break; + if(flag) + n->type = types[TFLOAT]; + return 1; + } + } + return 0; +} + +void +constas(Node *n, Type *il, Type *ir) +{ + Type *l, *r; + + l = il; + r = ir; + + if(l == T) + return; + if(l->garb & GCONSTNT) { + warn(n, "assignment to a constant type (%T)", il); + return; + } + if(r == T) + return; + for(;;) { + if(l->etype != TIND || r->etype != TIND) + break; + l = l->link; + r = r->link; + if(l == T || r == T) + break; + if(r->garb & GCONSTNT) + if(!(l->garb & GCONSTNT)) { + warn(n, "assignment of a constant pointer type (%T)", ir); + break; + } + } +} + +void +typeext1(Type *st, Node *l) +{ + if(st->etype == TFLOAT && allfloat(l, 0)) + allfloat(l, 1); +} + +void +typeext(Type *st, Node *l) +{ + Type *lt; + Node *n1, *n2; + long o; + + lt = l->type; + if(lt == T) + return; + if(st->etype == TIND && vconst(l) == 0) { + l->type = st; + l->vconst = 0; + return; + } + typeext1(st, l); + + /* + * extension of C + * if assign of struct containing unnamed sub-struct + * to type of sub-struct, insert the DOT. + * if assign of *struct containing unnamed substruct + * to type of *sub-struct, insert the add-offset + */ + if(typesu[st->etype] && typesu[lt->etype]) { + o = dotoffset(st, lt, l); + if(o >= 0) { + n1 = new1(OXXX, Z, Z); + *n1 = *l; + l->op = ODOT; + l->left = n1; + l->right = Z; + makedot(l, st, o); + } + return; + } + if(st->etype == TIND && typesu[st->link->etype]) + if(lt->etype == TIND && typesu[lt->link->etype]) { + o = dotoffset(st->link, lt->link, l); + if(o >= 0) { + l->type = st; + if(o == 0) + return; + n1 = new1(OXXX, Z, Z); + *n1 = *l; + n2 = new1(OCONST, Z, Z); + n2->vconst = o; + n2->type = st; + l->op = OADD; + l->left = n1; + l->right = n2; + } + return; + } +} + +/* + * a cast that generates no code + * (same size move) + */ +int +nocast(Type *t1, Type *t2) +{ + int i, b; + + if(t1->nbits) + return 0; + i = 0; + if(t2 != T) + i = t2->etype; + b = 1<<i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ncast[i]) + return 1; + return 0; +} + +/* + * a cast that has a noop semantic + * (small to large, convert) + */ +int +nilcast(Type *t1, Type *t2) +{ + int et1, et2; + + if(t1 == T) + return 0; + if(t1->nbits) + return 0; + if(t2 == T) + return 0; + et1 = t1->etype; + et2 = t2->etype; + if(et1 == et2) + return 1; + if(typefd[et1] && typefd[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + if(typechlp[et1] && typechlp[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + return 0; +} + +/* + * "the usual arithmetic conversions are performed" + */ +void +arith(Node *n, int f) +{ + Type *t1, *t2; + int i, j, k; + Node *n1; + long w; + + t1 = n->left->type; + if(n->right == Z) + t2 = t1; + else + t2 = n->right->type; + i = TXXX; + if(t1 != T) + i = t1->etype; + j = TXXX; + if(t2 != T) + j = t2->etype; + k = tab[i][j]; + if(k == TIND) { + if(i == TIND) + n->type = t1; + else + if(j == TIND) + n->type = t2; + } else { + /* convert up to at least int */ + if(f == 1) + while(k < TINT) + k += 2; + n->type = types[k]; + } + if(n->op == OSUB) + if(i == TIND && j == TIND) { + w = n->right->type->link->width; + if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1) + goto bad; + n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG]; + if(1 && ewidth[TIND] > ewidth[TLONG]){ + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = types[TLONG]; + } + if(w > 1) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = ODIV; + n->left = n1; + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->right = n1; + w = vlog(n1); + if(w >= 0) { + n->op = OASHR; + n1->vconst = w; + } + } + return; + } + if(!sametype(n->type, n->left->type)) { + n->left = new1(OCAST, n->left, Z); + n->left->type = n->type; + if(n->type->etype == TIND) { + w = n->type->link->width; + if(w < 1) { + snap(n->type->link); + w = n->type->link->width; + if(w < 1) + goto bad; + } + if(w > 1) { + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->left = new1(OMUL, n->left, n1); + n->left->type = n->type; + } + } + } + if(n->right != Z) + if(!sametype(n->type, n->right->type)) { + n->right = new1(OCAST, n->right, Z); + n->right->type = n->type; + if(n->type->etype == TIND) { + w = n->type->link->width; + if(w < 1) { + snap(n->type->link); + w = n->type->link->width; + if(w < 1) + goto bad; + } + if(w != 1) { + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->right = new1(OMUL, n->right, n1); + n->right->type = n->type; + } + } + } + return; +bad: + diag(n, "pointer addition not fully declared: %T", n->type->link); +} + +/* + * try to rewrite shift & mask + */ +void +simplifyshift(Node *n) +{ + ulong c3; + int o, s1, s2, c1, c2; + + if(!typechlp[n->type->etype]) + return; + switch(n->op) { + default: + return; + case OASHL: + s1 = 0; + break; + case OLSHR: + s1 = 1; + break; + case OASHR: + s1 = 2; + break; + } + if(n->right->op != OCONST) + return; + if(n->left->op != OAND) + return; + if(n->left->right->op != OCONST) + return; + switch(n->left->left->op) { + default: + return; + case OASHL: + s2 = 0; + break; + case OLSHR: + s2 = 1; + break; + case OASHR: + s2 = 2; + break; + } + if(n->left->left->right->op != OCONST) + return; + + c1 = n->right->vconst; + c2 = n->left->left->right->vconst; + c3 = n->left->right->vconst; + +/* + if(debug['h']) + print("%.3o %ld %ld %d #%.lux\n", + (s1<<3)|s2, c1, c2, topbit(c3), c3); +*/ + + o = n->op; + switch((s1<<3)|s2) { + case 000: /* (((e <<u c2) & c3) <<u c1) */ + c3 >>= c2; + c1 += c2; + if(c1 >= 32) + break; + goto rewrite1; + + case 002: /* (((e >>s c2) & c3) <<u c1) */ + if(topbit(c3) >= (32-c2)) + break; + case 001: /* (((e >>u c2) & c3) <<u c1) */ + if(c1 > c2) { + c3 <<= c2; + c1 -= c2; + o = OASHL; + goto rewrite1; + } + c3 <<= c1; + if(c1 == c2) + goto rewrite0; + c1 = c2-c1; + o = OLSHR; + goto rewrite2; + + case 022: /* (((e >>s c2) & c3) >>s c1) */ + if(c2 <= 0) + break; + case 012: /* (((e >>s c2) & c3) >>u c1) */ + if(topbit(c3) >= (32-c2)) + break; + goto s11; + case 021: /* (((e >>u c2) & c3) >>s c1) */ + if(topbit(c3) >= 31 && c2 <= 0) + break; + goto s11; + case 011: /* (((e >>u c2) & c3) >>u c1) */ + s11: + c3 <<= c2; + c1 += c2; + if(c1 >= 32) + break; + o = OLSHR; + goto rewrite1; + + case 020: /* (((e <<u c2) & c3) >>s c1) */ + if(topbit(c3) >= 31) + break; + case 010: /* (((e <<u c2) & c3) >>u c1) */ + c3 >>= c1; + if(c1 == c2) + goto rewrite0; + if(c1 > c2) { + c1 -= c2; + goto rewrite2; + } + c1 = c2 - c1; + o = OASHL; + goto rewrite2; + } + return; + +rewrite0: /* get rid of both shifts */ +if(debug['<'])prtree(n, "rewrite0"); + *n = *n->left; + n->left = n->left->left; + n->right->vconst = c3; + return; +rewrite1: /* get rid of lower shift */ +if(debug['<'])prtree(n, "rewrite1"); + n->left->left = n->left->left->left; + n->left->right->vconst = c3; + n->right->vconst = c1; + n->op = o; + return; +rewrite2: /* get rid of upper shift */ +if(debug['<'])prtree(n, "rewrite2"); + *n = *n->left; + n->right->vconst = c3; + n->left->right->vconst = c1; + n->left->op = o; +} + +int +side(Node *n) +{ + +loop: + if(n != Z) + switch(n->op) { + case OCAST: + case ONOT: + case OADDR: + case OIND: + n = n->left; + goto loop; + + case OCOND: + if(side(n->left)) + break; + n = n->right; + + case OEQ: + case ONE: + case OLT: + case OGE: + case OGT: + case OLE: + case OADD: + case OSUB: + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + case OLSHR: + case OASHL: + case OASHR: + case OAND: + case OOR: + case OXOR: + case OMOD: + case OLMOD: + case OANDAND: + case OOROR: + case OCOMMA: + case ODOT: + if(side(n->left)) + break; + n = n->right; + goto loop; + + case OSIGN: + case OSIZE: + case OCONST: + case OSTRING: + case OLSTRING: + case ONAME: + return 0; + } + return 1; +} + +int +vconst(Node *n) +{ + int i; + + if(n == Z) + goto no; + if(n->op != OCONST) + goto no; + if(n->type == T) + goto no; + switch(n->type->etype) + { + case TFLOAT: + case TDOUBLE: + i = 100; + if(n->fconst > i || n->fconst < -i) + goto no; + i = n->fconst; + if(i != n->fconst) + goto no; + return i; + + case TVLONG: + case TUVLONG: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + } +no: + return -159; /* first uninteresting constant */ +} + +/* + * return log(n) if n is a power of 2 constant + */ +int +log2(uvlong v) +{ + int s, i; + uvlong m; + + s = 0; + m = MASK(8*sizeof(uvlong)); + for(i=32; i; i>>=1) { + m >>= i; + if(!(v & m)) { + v >>= i; + s += i; + } + } + if(v == 1) + return s; + return -1; +} + +int +vlog(Node *n) +{ + if(n->op != OCONST) + goto bad; + if(typefd[n->type->etype]) + goto bad; + + return log2(n->vconst); + +bad: + return -1; +} + +int +topbit(ulong v) +{ + int i; + + for(i = -1; v; i++) + v >>= 1; + return i; +} + +/* + * try to cast a constant down + * rather than cast a variable up + * example: + * if(c == 'a') + */ +void +relcon(Node *l, Node *r) +{ + vlong v; + + if(l->op != OCONST) + return; + if(r->op != OCAST) + return; + if(!nilcast(r->left->type, r->type)) + return; + switch(r->type->etype) { + default: + return; + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + v = convvtox(l->vconst, r->type->etype); + if(v != l->vconst) + return; + break; + } + l->type = r->left->type; + *r = *r->left; +} + +int +relindex(int o) +{ + + switch(o) { + default: + diag(Z, "bad in relindex: %O", o); + case OEQ: return 0; + case ONE: return 1; + case OLE: return 2; + case OLS: return 3; + case OLT: return 4; + case OLO: return 5; + case OGE: return 6; + case OHS: return 7; + case OGT: return 8; + case OHI: return 9; + } +} + +Node* +invert(Node *n) +{ + Node *i; + + if(n == Z || n->op != OLIST) + return n; + i = n; + for(n = n->left; n != Z; n = n->left) { + if(n->op != OLIST) + break; + i->left = n->right; + n->right = i; + i = n; + } + i->left = n; + return i; +} + +int +bitno(long b) +{ + int i; + + for(i=0; i<32; i++) + if(b & (1L<<i)) + return i; + diag(Z, "bad in bitno"); + return 0; +} + +long +typebitor(long a, long b) +{ + long c; + + c = a | b; + if(a & b) + if((a & b) == BLONG) + c |= BVLONG; /* long long => vlong */ + else + warn(Z, "once is enough: %Q", a & b); + return c; +} + +void +diag(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(debug['X']){ + Bflush(&diagbuf); + abort(); + } + if(n != Z) + if(debug['v']) + prtree(n, "diagnostic"); + + nerrors++; + if(nerrors > 10) { + Bprint(&diagbuf, "too many errors\n"); + errorexit(); + } +} + +void +warn(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + if(debug['w']) { + Bprint(&diagbuf, "warning: "); + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(n != Z) + if(debug['v']) + prtree(n, "warning"); + } +} + +void +yyerror(char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(fmt, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", lineno, buf); + nerrors++; + if(nerrors > 10) { + Bprint(&diagbuf, "too many errors\n"); + errorexit(); + } +} + +void +fatal(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(debug['X']){ + Bflush(&diagbuf); + abort(); + } + if(n != Z) + if(debug['v']) + prtree(n, "diagnostic"); + + nerrors++; + errorexit(); +} + +ulong thash1 = 0x2edab8c9; +ulong thash2 = 0x1dc74fb8; +ulong thash3 = 0x1f241331; +ulong thash[NALLTYPES]; +Init thashinit[] = +{ + TXXX, 0x17527bbd, 0, + TCHAR, 0x5cedd32b, 0, + TUCHAR, 0x552c4454, 0, + TSHORT, 0x63040b4b, 0, + TUSHORT, 0x32a45878, 0, + TINT, 0x4151d5bd, 0, + TUINT, 0x5ae707d6, 0, + TLONG, 0x5ef20f47, 0, + TULONG, 0x36d8eb8f, 0, + TVLONG, 0x6e5e9590, 0, + TUVLONG, 0x75910105, 0, + TFLOAT, 0x25fd7af1, 0, + TDOUBLE, 0x7c40a1b2, 0, + TIND, 0x1b832357, 0, + TFUNC, 0x6babc9cb, 0, + TARRAY, 0x7c50986d, 0, + TVOID, 0x44112eff, 0, + TSTRUCT, 0x7c2da3bf, 0, + TUNION, 0x3eb25e98, 0, + TENUM, 0x44b54f61, 0, + TFILE, 0x19242ac3, 0, + TOLD, 0x22b15988, 0, + TDOT, 0x0204f6b3, 0, + -1, 0, 0, +}; + +char* bnames[NALIGN]; +Init bnamesinit[] = +{ + Axxx, 0, "Axxx", + Ael1, 0, "el1", + Ael2, 0, "el2", + Asu2, 0, "su2", + Aarg0, 0, "arg0", + Aarg1, 0, "arg1", + Aarg2, 0, "arg2", + Aaut3, 0, "aut3", + -1, 0, 0, +}; + +char* tnames[NALLTYPES]; +Init tnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + TDOT, 0, "DOT", + -1, 0, 0, +}; + +char* gnames[NGTYPES]; +Init gnamesinit[] = +{ + GXXX, 0, "GXXX", + GCONSTNT, 0, "CONST", + GVOLATILE, 0, "VOLATILE", + GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE", + -1, 0, 0, +}; + +char* qnames[NALLTYPES]; +Init qnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + + TAUTO, 0, "AUTO", + TEXTERN, 0, "EXTERN", + TSTATIC, 0, "STATIC", + TTYPEDEF, 0, "TYPEDEF", + TTYPESTR, 0, "TYPESTR", + TREGISTER, 0, "REGISTER", + TCONSTNT, 0, "CONSTNT", + TVOLATILE, 0, "VOLATILE", + TUNSIGNED, 0, "UNSIGNED", + TSIGNED, 0, "SIGNED", + TDOT, 0, "DOT", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + -1, 0, 0, +}; +char* cnames[NCTYPES]; +Init cnamesinit[] = +{ + CXXX, 0, "CXXX", + CAUTO, 0, "AUTO", + CEXTERN, 0, "EXTERN", + CGLOBL, 0, "GLOBL", + CSTATIC, 0, "STATIC", + CLOCAL, 0, "LOCAL", + CTYPEDEF, 0, "TYPEDEF", + CTYPESTR, 0, "TYPESTR", + CPARAM, 0, "PARAM", + CSELEM, 0, "SELEM", + CLABEL, 0, "LABEL", + CEXREG, 0, "EXREG", + -1, 0, 0, +}; + +char* onames[OEND+1]; +Init onamesinit[] = +{ + OXXX, 0, "OXXX", + OADD, 0, "ADD", + OADDR, 0, "ADDR", + OAND, 0, "AND", + OANDAND, 0, "ANDAND", + OARRAY, 0, "ARRAY", + OAS, 0, "AS", + OASI, 0, "ASI", + OASADD, 0, "ASADD", + OASAND, 0, "ASAND", + OASASHL, 0, "ASASHL", + OASASHR, 0, "ASASHR", + OASDIV, 0, "ASDIV", + OASHL, 0, "ASHL", + OASHR, 0, "ASHR", + OASLDIV, 0, "ASLDIV", + OASLMOD, 0, "ASLMOD", + OASLMUL, 0, "ASLMUL", + OASLSHR, 0, "ASLSHR", + OASMOD, 0, "ASMOD", + OASMUL, 0, "ASMUL", + OASOR, 0, "ASOR", + OASSUB, 0, "ASSUB", + OASXOR, 0, "ASXOR", + OBIT, 0, "BIT", + OBREAK, 0, "BREAK", + OCASE, 0, "CASE", + OCAST, 0, "CAST", + OCOMMA, 0, "COMMA", + OCOND, 0, "COND", + OCONST, 0, "CONST", + OCONTINUE, 0, "CONTINUE", + ODIV, 0, "DIV", + ODOT, 0, "DOT", + ODOTDOT, 0, "DOTDOT", + ODWHILE, 0, "DWHILE", + OENUM, 0, "ENUM", + OEQ, 0, "EQ", + OFOR, 0, "FOR", + OFUNC, 0, "FUNC", + OGE, 0, "GE", + OGOTO, 0, "GOTO", + OGT, 0, "GT", + OHI, 0, "HI", + OHS, 0, "HS", + OIF, 0, "IF", + OIND, 0, "IND", + OINDREG, 0, "INDREG", + OINIT, 0, "INIT", + OLABEL, 0, "LABEL", + OLDIV, 0, "LDIV", + OLE, 0, "LE", + OLIST, 0, "LIST", + OLMOD, 0, "LMOD", + OLMUL, 0, "LMUL", + OLO, 0, "LO", + OLS, 0, "LS", + OLSHR, 0, "LSHR", + OLT, 0, "LT", + OMOD, 0, "MOD", + OMUL, 0, "MUL", + ONAME, 0, "NAME", + ONE, 0, "NE", + ONOT, 0, "NOT", + OOR, 0, "OR", + OOROR, 0, "OROR", + OPOSTDEC, 0, "POSTDEC", + OPOSTINC, 0, "POSTINC", + OPREDEC, 0, "PREDEC", + OPREINC, 0, "PREINC", + OPROTO, 0, "PROTO", + OREGISTER, 0, "REGISTER", + ORETURN, 0, "RETURN", + OSET, 0, "SET", + OSIGN, 0, "SIGN", + OSIZE, 0, "SIZE", + OSTRING, 0, "STRING", + OLSTRING, 0, "LSTRING", + OSTRUCT, 0, "STRUCT", + OSUB, 0, "SUB", + OSWITCH, 0, "SWITCH", + OUNION, 0, "UNION", + OUSED, 0, "USED", + OWHILE, 0, "WHILE", + OXOR, 0, "XOR", + OPOS, 0, "POS", + ONEG, 0, "NEG", + OCOM, 0, "COM", + OELEM, 0, "ELEM", + OTST, 0, "TST", + OINDEX, 0, "INDEX", + OFAS, 0, "FAS", + OREGPAIR, 0, "REGPAIR", + OEND, 0, "END", + -1, 0, 0, +}; + +/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */ +char comrel[12] = +{ + ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS, +}; +char invrel[12] = +{ + OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO, +}; +char logrel[12] = +{ + OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI, +}; + +char typei[NTYPE]; +int typeiinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1, +}; +char typeu[NTYPE]; +int typeuinit[] = +{ + TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1, +}; + +char typesuv[NTYPE]; +int typesuvinit[] = +{ + TVLONG, TUVLONG, TSTRUCT, TUNION, -1, +}; + +char typeilp[NTYPE]; +int typeilpinit[] = +{ + TINT, TUINT, TLONG, TULONG, TIND, -1 +}; + +char typechl[NTYPE]; +char typechlv[NTYPE]; +char typechlvp[NTYPE]; +int typechlinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1, +}; + +char typechlp[NTYPE]; +int typechlpinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1, +}; + +char typechlpfd[NTYPE]; +int typechlpfdinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1, +}; + +char typec[NTYPE]; +int typecinit[] = +{ + TCHAR, TUCHAR, -1 +}; + +char typeh[NTYPE]; +int typehinit[] = +{ + TSHORT, TUSHORT, -1, +}; + +char typeil[NTYPE]; +int typeilinit[] = +{ + TINT, TUINT, TLONG, TULONG, -1, +}; + +char typev[NTYPE]; +int typevinit[] = +{ + TVLONG, TUVLONG, -1, +}; + +char typefd[NTYPE]; +int typefdinit[] = +{ + TFLOAT, TDOUBLE, -1, +}; + +char typeaf[NTYPE]; +int typeafinit[] = +{ + TFUNC, TARRAY, -1, +}; + +char typesu[NTYPE]; +int typesuinit[] = +{ + TSTRUCT, TUNION, -1, +}; + +long tasign[NTYPE]; +Init tasigninit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + TSTRUCT, BSTRUCT, 0, + TUNION, BUNION, 0, + -1, 0, 0, +}; + +long tasadd[NTYPE]; +Init tasaddinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tcast[NTYPE]; +Init tcastinit[] = +{ + TCHAR, BNUMBER|BIND|BVOID, 0, + TUCHAR, BNUMBER|BIND|BVOID, 0, + TSHORT, BNUMBER|BIND|BVOID, 0, + TUSHORT, BNUMBER|BIND|BVOID, 0, + TINT, BNUMBER|BIND|BVOID, 0, + TUINT, BNUMBER|BIND|BVOID, 0, + TLONG, BNUMBER|BIND|BVOID, 0, + TULONG, BNUMBER|BIND|BVOID, 0, + TVLONG, BNUMBER|BIND|BVOID, 0, + TUVLONG, BNUMBER|BIND|BVOID, 0, + TFLOAT, BNUMBER|BVOID, 0, + TDOUBLE, BNUMBER|BVOID, 0, + TIND, BINTEGER|BIND|BVOID, 0, + TVOID, BVOID, 0, + TSTRUCT, BSTRUCT|BVOID, 0, + TUNION, BUNION|BVOID, 0, + -1, 0, 0, +}; + +long tadd[NTYPE]; +Init taddinit[] = +{ + TCHAR, BNUMBER|BIND, 0, + TUCHAR, BNUMBER|BIND, 0, + TSHORT, BNUMBER|BIND, 0, + TUSHORT, BNUMBER|BIND, 0, + TINT, BNUMBER|BIND, 0, + TUINT, BNUMBER|BIND, 0, + TLONG, BNUMBER|BIND, 0, + TULONG, BNUMBER|BIND, 0, + TVLONG, BNUMBER|BIND, 0, + TUVLONG, BNUMBER|BIND, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tsub[NTYPE]; +Init tsubinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER|BIND, 0, + -1, 0, 0, +}; + +long tmul[NTYPE]; +Init tmulinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + -1, 0, 0, +}; + +long tand[NTYPE]; +Init tandinit[] = +{ + TCHAR, BINTEGER, 0, + TUCHAR, BINTEGER, 0, + TSHORT, BINTEGER, 0, + TUSHORT, BINTEGER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BINTEGER, 0, + TULONG, BINTEGER, 0, + TVLONG, BINTEGER, 0, + TUVLONG, BINTEGER, 0, + -1, 0, 0, +}; + +long trel[NTYPE]; +Init trelinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + -1, 0, 0, +}; + +long tfunct[1] = +{ + BFUNC, +}; + +long tindir[1] = +{ + BIND, +}; + +long tdot[1] = +{ + BSTRUCT|BUNION, +}; + +long tnot[1] = +{ + BNUMBER|BIND, +}; + +long targ[1] = +{ + BNUMBER|BIND|BSTRUCT|BUNION, +}; + +char tab[NTYPE][NTYPE] = +{ +/*TXXX*/ { 0, + }, + +/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, + TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, + TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, + TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND, + }, +/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, + TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND, + }, +/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND, + TIND, TIND, TIND, TIND, TIND, TIND, + }, +}; + +void +urk(char *name, int max, int i) +{ + if(i >= max) { + fprint(2, "bad tinit: %s %d>=%d\n", name, i, max); + exits("init"); + } +} + +void +tinit(void) +{ + int i; + Init *p; + + for(p=thashinit; p->code >= 0; p++) { + urk("thash", nelem(thash), p->code); + thash[p->code] = p->value; + } + for(p=bnamesinit; p->code >= 0; p++) { + urk("bnames", nelem(bnames), p->code); + bnames[p->code] = p->s; + } + for(p=tnamesinit; p->code >= 0; p++) { + urk("tnames", nelem(tnames), p->code); + tnames[p->code] = p->s; + } + for(p=gnamesinit; p->code >= 0; p++) { + urk("gnames", nelem(gnames), p->code); + gnames[p->code] = p->s; + } + for(p=qnamesinit; p->code >= 0; p++) { + urk("qnames", nelem(qnames), p->code); + qnames[p->code] = p->s; + } + for(p=cnamesinit; p->code >= 0; p++) { + urk("cnames", nelem(cnames), p->code); + cnames[p->code] = p->s; + } + for(p=onamesinit; p->code >= 0; p++) { + urk("onames", nelem(onames), p->code); + onames[p->code] = p->s; + } + for(i=0; typeiinit[i] >= 0; i++) { + urk("typei", nelem(typei), typeiinit[i]); + typei[typeiinit[i]] = 1; + } + for(i=0; typeuinit[i] >= 0; i++) { + urk("typeu", nelem(typeu), typeuinit[i]); + typeu[typeuinit[i]] = 1; + } + for(i=0; typesuvinit[i] >= 0; i++) { + urk("typesuv", nelem(typesuv), typesuvinit[i]); + typesuv[typesuvinit[i]] = 1; + } + for(i=0; typeilpinit[i] >= 0; i++) { + urk("typeilp", nelem(typeilp), typeilpinit[i]); + typeilp[typeilpinit[i]] = 1; + } + for(i=0; typechlinit[i] >= 0; i++) { + urk("typechl", nelem(typechl), typechlinit[i]); + typechl[typechlinit[i]] = 1; + typechlv[typechlinit[i]] = 1; + typechlvp[typechlinit[i]] = 1; + } + for(i=0; typechlpinit[i] >= 0; i++) { + urk("typechlp", nelem(typechlp), typechlpinit[i]); + typechlp[typechlpinit[i]] = 1; + typechlvp[typechlinit[i]] = 1; + } + for(i=0; typechlpfdinit[i] >= 0; i++) { + urk("typechlpfd", nelem(typechlpfd), typechlpfdinit[i]); + typechlpfd[typechlpfdinit[i]] = 1; + } + for(i=0; typecinit[i] >= 0; i++) { + urk("typec", nelem(typec), typecinit[i]); + typec[typecinit[i]] = 1; + } + for(i=0; typehinit[i] >= 0; i++) { + urk("typeh", nelem(typeh), typehinit[i]); + typeh[typehinit[i]] = 1; + } + for(i=0; typeilinit[i] >= 0; i++) { + urk("typeil", nelem(typeil), typeilinit[i]); + typeil[typeilinit[i]] = 1; + } + for(i=0; typevinit[i] >= 0; i++) { + urk("typev", nelem(typev), typevinit[i]); + typev[typevinit[i]] = 1; + typechlv[typevinit[i]] = 1; + typechlvp[typechlinit[i]] = 1; + } + for(i=0; typefdinit[i] >= 0; i++) { + urk("typefd", nelem(typefd), typefdinit[i]); + typefd[typefdinit[i]] = 1; + } + for(i=0; typeafinit[i] >= 0; i++) { + urk("typeaf", nelem(typeaf), typeafinit[i]); + typeaf[typeafinit[i]] = 1; + } + for(i=0; typesuinit[i] >= 0; i++) { + urk("typesu", nelem(typesu), typesuinit[i]); + typesu[typesuinit[i]] = 1; + } + for(p=tasigninit; p->code >= 0; p++) { + urk("tasign", nelem(tasign), p->code); + tasign[p->code] = p->value; + } + for(p=tasaddinit; p->code >= 0; p++) { + urk("tasadd", nelem(tasadd), p->code); + tasadd[p->code] = p->value; + } + for(p=tcastinit; p->code >= 0; p++) { + urk("tcast", nelem(tcast), p->code); + tcast[p->code] = p->value; + } + for(p=taddinit; p->code >= 0; p++) { + urk("tadd", nelem(tadd), p->code); + tadd[p->code] = p->value; + } + for(p=tsubinit; p->code >= 0; p++) { + urk("tsub", nelem(tsub), p->code); + tsub[p->code] = p->value; + } + for(p=tmulinit; p->code >= 0; p++) { + urk("tmul", nelem(tmul), p->code); + tmul[p->code] = p->value; + } + for(p=tandinit; p->code >= 0; p++) { + urk("tand", nelem(tand), p->code); + tand[p->code] = p->value; + } + for(p=trelinit; p->code >= 0; p++) { + urk("trel", nelem(trel), p->code); + trel[p->code] = p->value; + } +} + +static int +deadhead(Node *n, int caseok) +{ +loop: + if(n == Z) + return 1; + switch(n->op) { + case OLIST: + if(!deadhead(n->left, caseok)) + return 0; + rloop: + n = n->right; + goto loop; + + case ORETURN: + break; + + case OLABEL: + return 0; + + case OGOTO: + break; + + case OCASE: + if(!caseok) + return 0; + goto rloop; + + case OSWITCH: + return deadhead(n->right, 1); + + case OWHILE: + case ODWHILE: + goto rloop; + + case OFOR: + goto rloop; + + case OCONTINUE: + break; + + case OBREAK: + break; + + case OIF: + return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok); + + case OSET: + case OUSED: + break; + } + return 1; +} + +int +deadheads(Node *c) +{ + return deadhead(c->left, 0) && deadhead(c->right, 0); +} + +int +mixedasop(Type *l, Type *r) +{ + return !typefd[l->etype] && typefd[r->etype]; +} diff --git a/utils/cp/cp.c b/utils/cp/cp.c new file mode 100644 index 00000000..7395e16c --- /dev/null +++ b/utils/cp/cp.c @@ -0,0 +1,118 @@ +#include <lib9.h> + +#define DEFB (8*1024) + +void copy(char *from, char *to, int todir); +void copy1(int fdf, int fdt, char *from, char *to); +void fixbackslash(char *file); + +void +main(int argc, char *argv[]) +{ + Dir *dirb; + int todir, i; + + if(argc<3){ + fprint(2, "usage:\tcp fromfile tofile\n"); + fprint(2, "\tcp fromfile ... todir\n"); + exits("usage"); + } + + for(i=0; i<argc; i++) + fixbackslash(argv[i]); + + + todir=0; + if((dirb = dirstat(argv[argc-1]))!=nil && (dirb->mode&DMDIR)) + todir=1; + if(argc>3 && !todir){ + fprint(2, "cp: %s not a directory\n", argv[argc-1]); + exits("bad usage"); + } + for(i=1; i<argc-1; i++) + copy(argv[i], argv[argc-1], todir); + exits(0); +} + +void +copy(char *from, char *to, int todir) +{ + Dir *dirb, *dirt; + char name[256]; + int fdf, fdt; + + if(todir){ + char *s, *elem; + elem=s=from; + while(*s++) + if(s[-1]=='/') + elem=s; + sprint(name, "%s/%s", to, elem); + to=name; + } + if((dirb = dirstat(from))==nil){ + fprint(2,"cp: can't stat %s: %r\n", from); + return; + } + if(dirb->mode&DMDIR){ + fprint(2, "cp: %s is a directory\n", from); + return; + } + dirb->mode &= 0777; + if((dirt = dirstat(to))!=nil) + if(dirb->qid.path==dirt->qid.path && dirb->qid.vers==dirt->qid.vers) + if(dirb->dev==dirt->dev && dirb->type==dirt->type){ + fprint(2, "cp: %s and %s are the same file\n", from, to); + return; + } + fdf=open(from, OREAD); + if(fdf<0){ + fprint(2, "cp: can't open %s: %r\n", from); + return; + } + fdt=create(to, OWRITE, dirb->mode); + if(fdt<0){ + fprint(2, "cp: can't create %s: %r\n", to); + close(fdf); + return; + } + copy1(fdf, fdt, from, to); + close(fdf); + close(fdt); +} + +void +copy1(int fdf, int fdt, char *from, char *to) +{ + char *buf; + long n, n1, rcount; + char err[ERRMAX]; + + buf = malloc(DEFB); + /* clear any residual error */ + err[0] = '\0'; + errstr(err, ERRMAX); + for(rcount=0;; rcount++) { + n = read(fdf, buf, DEFB); + if(n <= 0) + break; + n1 = write(fdt, buf, n); + if(n1 != n) { + fprint(2, "cp: error writing %s: %r\n", to); + break; + } + } + if(n < 0) + fprint(2, "cp: error reading %s: %r\n", from); + free(buf); +} + +void +fixbackslash(char *file) +{ + char *p; + + for(p=file; *p; p++) + if(*p == '\\') + *p = '/'; +} diff --git a/utils/cp/mkfile b/utils/cp/mkfile new file mode 100644 index 00000000..722c269e --- /dev/null +++ b/utils/cp/mkfile @@ -0,0 +1,22 @@ +<../../mkconfig + +TARG=cp + +OFILES= cp.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +# +# override install so that cp doesn't try to copy onto itself +# + +$BIN/%: $O.out + cp $target cpx.exe + ./cpx $O.out $target + rm cpx.exe diff --git a/utils/data2c/data2c.c b/utils/data2c/data2c.c new file mode 100644 index 00000000..faf597c5 --- /dev/null +++ b/utils/data2c/data2c.c @@ -0,0 +1,33 @@ +#include <lib9.h> +#include <bio.h> + +void +main(int argc, char *argv[]) +{ + Biobuf bin, bout; + long len; + int n; + uchar block[16], *c; + + if(argc != 2){ + fprint(2, "usage: data2s name\n"); + exits("usage"); + } + setbinmode(); + Binit(&bin, 0, OREAD); + Binit(&bout, 1, OWRITE); + Bprint(&bout, "unsigned char %scode[] = {\n", argv[1]); + for(len=0; (n=Bread(&bin, block, sizeof(block))) > 0; len += n){ + for(c=block; c < block+n; c++) + if(*c) + Bprint(&bout, "0x%ux,", *c); + else + Bprint(&bout, "0,"); + Bprint(&bout, "\n"); + } + if(len == 0) + Bprint(&bout, "0\n"); /* avoid empty initialiser */ + Bprint(&bout, "};\n"); + Bprint(&bout, "int %slen = %ld;\n", argv[1], len); + exits(0); +} diff --git a/utils/data2c/mkfile b/utils/data2c/mkfile new file mode 100644 index 00000000..047ddb3e --- /dev/null +++ b/utils/data2c/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=data2c + +OFILES= data2c.$O\ + +HFILES=../../include/bio.h + +LIBS=bio 9 #order matters + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/data2s/data2s.c b/utils/data2s/data2s.c new file mode 100644 index 00000000..97244fb1 --- /dev/null +++ b/utils/data2s/data2s.c @@ -0,0 +1,32 @@ +#include <lib9.h> +#include <bio.h> + +void +main(int argc, char *argv[]) +{ + Biobuf bin, bout; + long len; + int n; + uchar block[8], *c; + + if(argc != 2){ + fprint(2, "usage: data2s name\n"); + exits("usage"); + } + setbinmode(); + Binit(&bin, 0, OREAD); + Binit(&bout, 1, OWRITE); + for(len=0; (n=Bread(&bin, block, sizeof(block))) > 0; len += n){ + Bprint(&bout, "DATA %scode+%ld(SB)/%d, $\"", argv[1], len, n); + for(c=block; c < block+n; c++) + if(*c) + Bprint(&bout, "\\%uo", *c); + else + Bprint(&bout, "\\z"); + Bprint(&bout, "\"\n"); + } + Bprint(&bout, "GLOBL %scode+0(SB), $%ld\n", argv[1], len); + Bprint(&bout, "GLOBL %slen+0(SB), $4\n", argv[1]); + Bprint(&bout, "DATA %slen+0(SB)/4, $%ld\n", argv[1], len); + exits(0); +} diff --git a/utils/data2s/mkfile b/utils/data2s/mkfile new file mode 100644 index 00000000..9b712aa8 --- /dev/null +++ b/utils/data2s/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=data2s + +OFILES= data2s.$O\ + +HFILES=../../include/bio.h + +LIBS=bio 9 #order matters + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/echo/echo.c b/utils/echo/echo.c new file mode 100644 index 00000000..9574e129 --- /dev/null +++ b/utils/echo/echo.c @@ -0,0 +1,33 @@ +#include <lib9.h> + +void +main(int argc, char *argv[]) +{ + int nflag; + int i, len; + char *buf, *p; + + nflag = 0; + if(argc > 1 && strcmp(argv[1], "-n") == 0) + nflag = 1; + + len = 1; + for(i = 1+nflag; i < argc; i++) + len += strlen(argv[i])+1; + + buf = malloc(len); + if(buf == 0) + exits("no memory"); + + p = buf; + for(i = 1+nflag; i < argc; i++) + p += sprint(p, i == argc-1 ? "%s":"%s ", argv[i]); + + if(!nflag) + sprint(p, "\n"); + + if(write(1, buf, strlen(buf)) < 0) + fprint(2, "echo: write error: %r\n"); + + exits((char *)0); +} diff --git a/utils/echo/mkfile b/utils/echo/mkfile new file mode 100644 index 00000000..fed9561b --- /dev/null +++ b/utils/echo/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=echo + +OFILES= echo.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/format/Nt.c b/utils/format/Nt.c new file mode 100644 index 00000000..f2239f3c --- /dev/null +++ b/utils/format/Nt.c @@ -0,0 +1,47 @@ +#include <lib9.h> + +int +initfflag() +{ + return 1; +} + +Tm * +getlocaltime() +{ + static Tm tmstruct; + + time_t t = time((time_t *)0); + struct tm *ts = localtime(&t); + Tm *tt = &tmstruct; + + tt->hour = ts->tm_hour; + tt->min = ts->tm_min; + tt->sec = ts->tm_sec; + tt->year = ts->tm_year; + tt->mon = ts->tm_mon; + tt->mday = ts->tm_mday; + tt->wday = ts->tm_wday; + tt->yday = ts->tm_yday; + return tt; +} + +int +openfloppy(char *dev) +{ + char buf[16]; + + /* if dev is of the form "x:" use "\\.\x:" instead */ + if (strlen(dev) == 2 && dev[1] == ':') { + if (dev[0] == 'a' || dev[0] == 'A') { + strcpy(buf, "\\\\.\\"); + strcat(buf, dev); + return open(buf, ORDWR); + } + else { + print("can only open A: drive\n"); + return -1; + } + } + return open(dev, ORDWR); +} diff --git a/utils/format/Plan9.c b/utils/format/Plan9.c new file mode 100644 index 00000000..2cf97970 --- /dev/null +++ b/utils/format/Plan9.c @@ -0,0 +1,19 @@ +#include <lib9.h> + +int +initfflag() +{ + return 0; +} + +Tm * +getlocaltime() +{ + return localtime(time(0)); +} + +int +openfloppy(char *dev) +{ + return create(dev, ORDWR, 0666); +} diff --git a/utils/format/format.c b/utils/format/format.c new file mode 100644 index 00000000..f9963572 --- /dev/null +++ b/utils/format/format.c @@ -0,0 +1,574 @@ +#include <lib9.h> + +/* + * floppy types (all MFM encoding) + */ +typedef struct Type Type; +struct Type +{ + char *name; + int bytes; /* bytes/sector */ + int sectors; /* sectors/track */ + int heads; /* number of heads */ + int tracks; /* tracks/disk */ + int media; /* media descriptor byte */ + int cluster; /* default cluster size */ +}; +Type floppytype[] = +{ + { "3½HD", 512, 18, 2, 80, 0xf0, 1, }, + { "3½DD", 512, 9, 2, 80, 0xf9, 2, }, + { "5¼HD", 512, 15, 2, 80, 0xf9, 1, }, + { "5¼DD", 512, 9, 2, 40, 0xfd, 2, }, +}; +#define NTYPES (sizeof(floppytype)/sizeof(Type)) + +typedef struct Dosboot Dosboot; +struct Dosboot{ + uchar magic[3]; /* really an xx86 JMP instruction */ + uchar version[8]; + uchar sectsize[2]; + uchar clustsize; + uchar nresrv[2]; + uchar nfats; + uchar rootsize[2]; + uchar volsize[2]; + uchar mediadesc; + uchar fatsize[2]; + uchar trksize[2]; + uchar nheads[2]; + uchar nhidden[4]; + uchar bigvolsize[4]; + uchar driveno; + uchar reserved0; + uchar bootsig; + uchar volid[4]; + uchar label[11]; + uchar type[8]; +}; +#define PUTSHORT(p, v) { (p)[1] = (v)>>8; (p)[0] = (v); } +#define PUTLONG(p, v) { PUTSHORT((p), (v)); PUTSHORT((p)+2, (v)>>16); } + +typedef struct Dosdir Dosdir; +struct Dosdir +{ + uchar name[8]; + uchar ext[3]; + uchar attr; + uchar reserved[10]; + uchar time[2]; + uchar date[2]; + uchar start[2]; + uchar length[4]; +}; + +#define DRONLY 0x01 +#define DHIDDEN 0x02 +#define DSYSTEM 0x04 +#define DVLABEL 0x08 +#define DDIR 0x10 +#define DARCH 0x20 + +/* + * the boot program for the boot sector. + */ +uchar bootprog[512]; +uchar bootprog1[16] = +{ + 0xEB, 0x3C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +uchar bootprog2[128] = +{ + 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0, + 0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19, + 0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00, + 0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12, + 0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF, + 0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4, + 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2, + 0xC3, 'N', 'o', 't', ' ', 'a', ' ', 'b', + 'o', 'o', 't', 'a', 'b', 'l', 'e', ' ', + 'd', 'i', 's', 'c', ' ', 'o', 'r', ' ', + 'd', 'i', 's', 'c', ' ', 'e', 'r', 'r', + 'o', 'r', '\r', '\n', 'P', 'r', 'e', 's', + 's', ' ', 'a', 'l', 'm', 'o', 's', 't', + ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y', + ' ', 't', 'o', ' ', 'r', 'e', 'b', 'o', + 'o', 't', '.', '.', '.', 0x00, 0x00, 0x00, +}; +uchar bootprog3[16] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA, +}; + +static void +mkbootprog(void) +{ + int i; + + for (i = 0; i < 512; i++) + bootprog[i] = 0; + for (i = 0; i < 16; i++) + bootprog[i+0x000] = bootprog1[i]; + for (i = 0; i < 128; i++) + bootprog[i+0x03E] = bootprog2[i]; + for (i = 0; i < 16; i++) + bootprog[i+0x1F0] = bootprog3[i]; +} + +char *dev; +int clustersize; +uchar *fat; /* the fat */ +int fatbits; +int fatsecs; +int fatlast; /* last cluster allocated */ +int clusters; +int fatsecs; +int volsecs; +uchar *root; /* first block of root */ +int rootsecs; +int rootfiles; +int rootnext; +Type *t; +int fflag; +char file[64]; /* output file name */ +char *bootfile; +char *type; + +enum +{ + Sof = 1, /* start of file */ + Eof = 2, /* end of file */ +}; + + +void dosfs(int, char*, int, char*[]); +ulong clustalloc(int); +void addrname(uchar*, Dir*, ulong, char *); + +int initfflag(void); +Tm *getlocaltime(void); +int openfloppy(char *); + +void +usage(void) +{ + fprint(2, "usage: format [-b bfile] [-c csize] [-df] [-l label] [-t type] file [args ...]\n"); + exits("usage"); +} + +void +fatal(char *fmt, ...) +{ + char err[128]; + va_list arg; + + va_start(arg, fmt); + vseprint(err, err+sizeof(err), fmt, arg); + va_end(arg); + fprint(2, "format: %s\n", err); + if(fflag && file[0]) + remove(file); + exits(err); +} + +void +main(int argc, char **argv) +{ + int n, dos; + int cfd; + char buf[512]; + char label[11]; + char *a; + + fflag = initfflag(); + mkbootprog(); + dos = 0; + type = 0; + clustersize = 0; + memmove(label, "CYLINDRICAL", sizeof(label)); + ARGBEGIN { + case 'b': + bootfile = ARGF(); + break; + case 'd': + dos = 1; + break; + case 'c': + clustersize = atoi(ARGF()); + break; + case 'f': + fflag = 1; + break; + case 'l': + a = ARGF(); + n = strlen(a); + if(n > sizeof(label)) + n = sizeof(label); + memmove(label, a, n); + while(n < sizeof(label)) + label[n++] = ' '; + break; + case 't': + type = ARGF(); + break; + default: + usage(); + } ARGEND + + if(argc < 1) + usage(); + + dev = argv[0]; + cfd = -1; + if(fflag == 0){ + n = strlen(argv[0]); + if(n > 4 && strcmp(argv[0]+n-4, "disk") == 0) + *(argv[0]+n-4) = 0; + else if(n > 3 && strcmp(argv[0]+n-3, "ctl") == 0) + *(argv[0]+n-3) = 0; + + sprint(buf, "%sctl", dev); + cfd = open(buf, ORDWR); + if(cfd < 0) + fatal("opening %s: %r", buf); + print("Formatting floppy %s\n", dev); + if(type) + sprint(buf, "format %s", type); + else + strcpy(buf, "format"); + if(write(cfd, buf, strlen(buf)) < 0) + fatal("formatting tracks: %r"); + } + + if(dos) + dosfs(cfd, label, argc-1, argv+1); + if(cfd >= 0) + close(cfd); + exits(0); +} + +void +dosfs(int cfd, char *label, int argc, char *argv[]) +{ + char r[16]; + Dosboot *b; + uchar *buf; + Dir *d; + int n, fd, sysfd; + ulong length, x; + uchar *p; + + print("Initialising MS-DOS file system\n"); + + if(fflag){ + sprint(file, "%s", dev); + if ((fd = openfloppy(dev)) < 0) + fatal("create %s: %r", file); + t = floppytype; + if(type){ + for(t = floppytype; t < &floppytype[NTYPES]; t++) + if(strcmp(type, t->name) == 0) + break; + if(t == &floppytype[NTYPES]) + fatal("unknown floppy type %s", type); + } + length = t->bytes*t->sectors*t->heads*t->tracks; + } + else{ + sprint(file, "%sdisk", dev); + fd = open(file, ORDWR); + if(fd < 0) + fatal("open %s: %r", file); + d = dirfstat(fd); + if(d == nil) + fatal("stat %s: %r", file); + length = d->length; + free(d); + + t = 0; + seek(cfd, 0, 0); + n = read(cfd, file, sizeof(file)-1); + if(n < 0) + fatal("reading floppy type"); + else { + file[n] = 0; + for(t = floppytype; t < &floppytype[NTYPES]; t++) + if(strcmp(file, t->name) == 0) + break; + if(t == &floppytype[NTYPES]) + fatal("unknown floppy type %s", file); + } + } + print("floppy type %s, %d tracks, %d heads, %d sectors/track, %d bytes/sec\n", + t->name, t->tracks, t->heads, t->sectors, t->bytes); + + if(clustersize == 0) + clustersize = t->cluster; + clusters = length/(t->bytes*clustersize); + if(clusters < 4087) + fatbits = 12; + else + fatbits = 16; + volsecs = length/t->bytes; + fatsecs = (fatbits*clusters + 8*t->bytes - 1)/(8*t->bytes); + rootsecs = volsecs/200; + rootfiles = rootsecs * (t->bytes/sizeof(Dosdir)); + buf = malloc(t->bytes); + if(buf == 0) + fatal("out of memory"); + + /* + * write bootstrap & parameter block + */ + if(bootfile){ + if((sysfd = open(bootfile, OREAD)) < 0) + fatal("open %s: %r", bootfile); + if(read(sysfd, buf, t->bytes) < 0) + fatal("read %s: %r", bootfile); + close(sysfd); + } + else + memmove(buf, bootprog, sizeof(bootprog)); + b = (Dosboot*)buf; + b->magic[0] = 0xEB; + b->magic[1] = 0x3C; + b->magic[2] = 0x90; + memmove(b->version, "Plan9.00", sizeof(b->version)); + PUTSHORT(b->sectsize, t->bytes); + b->clustsize = clustersize; + PUTSHORT(b->nresrv, 1); + b->nfats = 2; + PUTSHORT(b->rootsize, rootfiles); + if(volsecs < (1<<16)){ + PUTSHORT(b->volsize, volsecs); + } + PUTLONG(b->bigvolsize, volsecs); + b->mediadesc = t->media; + PUTSHORT(b->fatsize, fatsecs); + PUTSHORT(b->trksize, t->sectors); + PUTSHORT(b->nheads, t->heads); + PUTLONG(b->nhidden, 0); + b->driveno = 0; + b->bootsig = 0x29; + x = time(0); + PUTLONG(b->volid, x); + memmove(b->label, label, sizeof(b->label)); + sprint(r, "FAT%d ", fatbits); + memmove(b->type, r, sizeof(b->type)); + buf[t->bytes-2] = 0x55; + buf[t->bytes-1] = 0xAA; + if(seek(fd, 0, 0) < 0) + fatal("seek to boot sector: %r\n"); + if(write(fd, buf, t->bytes) != t->bytes) + fatal("writing boot sector: %r"); + free(buf); + + /* + * allocate an in memory fat + */ + fat = malloc(fatsecs*t->bytes); + if(fat == 0) + fatal("out of memory"); + memset(fat, 0, fatsecs*t->bytes); + fat[0] = t->media; + fat[1] = 0xff; + fat[2] = 0xff; + if(fatbits == 16) + fat[3] = 0xff; + fatlast = 1; + if (seek(fd, 2*fatsecs*t->bytes, 1) < 0) + fatal("seek to 2 fats: %r"); /* 2 fats */ + + /* + * allocate an in memory root + */ + root = malloc(rootsecs*t->bytes); + if(root == 0) + fatal("out of memory"); + memset(root, 0, rootsecs*t->bytes); + if (seek(fd, rootsecs*t->bytes, 1) < 0) + fatal("seek to root: %r"); /* rootsecs */ + + /* + * Now positioned at the Files Area. + * If we have any arguments, process + * them and write out. + */ + for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){ + if(p >= (root+(rootsecs*t->bytes))) + fatal("too many files in root"); + /* + * Open the file and get its length. + */ + if((sysfd = open(*argv, OREAD)) < 0) + fatal("open %s: %r", *argv); + d = dirfstat(sysfd); + if(d == nil) + fatal("stat %s: %r", *argv); + print("Adding file %s, length %lld\n", *argv, d->length); + + length = d->length; + if(length){ + /* + * Allocate a buffer to read the entire file into. + * This must be rounded up to a cluster boundary. + * + * Read the file and write it out to the Files Area. + */ + length += t->bytes*clustersize - 1; + length /= t->bytes*clustersize; + length *= t->bytes*clustersize; + if((buf = malloc(length)) == 0) + fatal("out of memory"); + + if(read(sysfd, buf, d->length) < 0) + fatal("read %s: %r", *argv); + memset(buf+d->length, 0, length-d->length); + /* if(write(fd, buf, length) < 0) */ + if (write(fd, buf, length) != length) + fatal("write %s: %r", *argv); + free(buf); + + close(sysfd); + + /* + * Allocate the FAT clusters. + * We're assuming here that where we + * wrote the file is in sync with + * the cluster allocation. + * Save the starting cluster. + */ + length /= t->bytes*clustersize; + x = clustalloc(Sof); + for(n = 0; n < length-1; n++) + clustalloc(0); + clustalloc(Eof); + } + else + x = 0; + + /* + * Add the filename to the root. + */ + addrname(p, d, x, *argv); + free(d); + } + + /* + * write the fats and root + */ + if (seek(fd, t->bytes, 0) < 0) + fatal("seek to fat1: %r"); + /* if(write(fd, fat, fatsecs*t->bytes) < 0) */ + if (write(fd, fat, fatsecs*t->bytes) != fatsecs*t->bytes) + fatal("writing fat #1: %r"); + /* if(write(fd, fat, fatsecs*t->bytes) < 0) */ + if (write(fd, fat, fatsecs*t->bytes) != fatsecs*t->bytes) + fatal("writing fat #2: %r"); + /* if(write(fd, root, rootsecs*t->bytes) < 0) */ + if (write(fd, root, rootsecs*t->bytes) != rootsecs*t->bytes) + fatal("writing root: %r"); + + if(fflag){ + if (seek(fd, t->bytes*t->sectors*t->heads*t->tracks-1, 0) < 0) + /* fatal("seek to 9: %r") */ {} + if (write(fd, "9", 1) != 1) + /* fatal("writing 9: %r") */ {} + } +} + +/* + * allocate a cluster + */ +ulong +clustalloc(int flag) +{ + ulong o, x; + + if(flag != Sof){ + x = (flag == Eof) ? 0xffff : (fatlast+1); + if(fatbits == 12){ + x &= 0xfff; + o = (3*fatlast)/2; + if(fatlast & 1){ + fat[o] = (fat[o]&0x0f) | (x<<4); + fat[o+1] = (x>>4); + } else { + fat[o] = x; + fat[o+1] = (fat[o+1]&0xf0) | ((x>>8) & 0x0F); + } + } else { + o = 2*fatlast; + fat[o] = x; + fat[o+1] = x>>8; + } + } + + if(flag == Eof) + return 0; + else + return ++fatlast; +} + +void +putname(char *p, Dosdir *d) +{ + int i; + char *q; + + q = strrchr(p, '/'); + if (q) + p = q+1; + q = strrchr(p, '\\'); + if (q) + p = q+1; + memset(d->name, ' ', sizeof d->name+sizeof d->ext); + for(i = 0; i< sizeof(d->name); i++){ + if(*p == 0 || *p == '.') + break; + d->name[i] = toupper(*p++); + } + p = strrchr(p, '.'); + if(p){ + for(i = 0; i < sizeof d->ext; i++){ + if(*++p == 0) + break; + d->ext[i] = toupper(*p); + } + } +} + +void +puttime(Dosdir *d) +{ + Tm *t = getlocaltime(); + ushort x; + + x = (t->hour<<11) | (t->min<<5) | (t->sec>>1); + d->time[0] = x; + d->time[1] = x>>8; + x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday; + d->date[0] = x; + d->date[1] = x>>8; +} + +void +addrname(uchar *entry, Dir *dir, ulong start, char *nm) +{ + Dosdir *d; + + d = (Dosdir*)entry; + /* putname(dir->name, d); */ + putname(nm, d); + d->attr = DRONLY; + puttime(d); + d->start[0] = start; + d->start[1] = start>>8; + d->length[0] = dir->length; + d->length[1] = dir->length>>8; + d->length[2] = dir->length>>16; + d->length[3] = dir->length>>24; +} diff --git a/utils/format/mkfile b/utils/format/mkfile new file mode 100644 index 00000000..02b153d3 --- /dev/null +++ b/utils/format/mkfile @@ -0,0 +1,14 @@ +<../../mkconfig + +TARG=format + +OFILES= format.$O\ + $TARGMODEL.$O\ + +HFILES= + +LIBS=9 # libbio.a uses lib9.a so order matters. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/ftl/ftl.c b/utils/ftl/ftl.c new file mode 100644 index 00000000..231f1ae5 --- /dev/null +++ b/utils/ftl/ftl.c @@ -0,0 +1,867 @@ +/* + * basic Flash Translation Layer driver + * see for instance the Intel technical paper + * ``Understanding the Flash Translation Layer (FTL) Specification'' + * Order number 297816-001 (online at www.intel.com) + * + * a public driver by David Hinds, dhinds@allegro.stanford.edu + * further helps with some details. + * + * this driver uses the common simplification of never storing + * the VBM on the medium (a waste of precious flash!) but + * rather building it on the fly as the block maps are read. + * + * Plan 9 driver (c) 1997 by C H Forsyth (forsyth@caldo.demon.co.uk) + * This driver may be used or adapted by anyone for any non-commercial purpose. + * + * adapted for Inferno 1998 by C H Forsyth, Vita Nuova Limited, York, England (charles@vitanuova.com) + * + * C H Forsyth and Vita Nuova Limited expressly allow Lucent Technologies + * to use this driver freely for any Inferno-related purposes whatever, + * including commercial applications. + * + * TO DO: + * check error handling details for get/put flash + * bad block handling + * reserved space in formatted size + * possibly block size as parameter + * fetch parameters from header on init + * + * Adapted to a ftl formatter for Inferno 2000 by J R Firth, Vita Nuova Limited + * usage : ftl flashsize secsize inputfile outputfile + * outputfile will then be a ftl image of inputfile + * nb assumes the base address is zero + * + */ + +#include <lib9.h> + +ulong flashsize, secsize; +char *flashm; +int trace = 0; + +#ifndef offsetof +#define offsetof(T,X) ((ulong)&(((T*)0)->X)) +#endif + +typedef struct Ftl Ftl; +typedef struct Merase Merase; +typedef struct Terase Terase; + +enum { + Eshift = 18, /* 2^18=256k; log2(eraseunit) */ + Flashseg = 1<<Eshift, + Bshift = 9, /* 2^9=512 */ + Bsize = 1<<Bshift, + BAMoffset = 0x100, + Nolimit = ~0, + USABLEPCT = 95, /* release only this % to client */ + + FTLDEBUG = 0 +}; + +/* erase unit header (defined by FTL specification) */ +struct Merase { + uchar linktuple[5]; + uchar orgtuple[10]; + uchar nxfer; + uchar nerase[4]; + uchar id[2]; + uchar bshift; + uchar eshift; + uchar pstart[2]; + uchar nunits[2]; + uchar psize[4]; + uchar vbmbase[4]; + uchar nvbm[2]; + uchar flags; + uchar code; + uchar serial[4]; + uchar altoffset[4]; + uchar bamoffset[4]; + uchar rsv2[12]; +}; +#define ERASEHDRLEN 64 + +enum { + /* special unit IDs */ + XferID = 0xffff, + XferBusy = 0x7fff, + + /* special BAM addresses */ + Bfree = 0xffffffff, + Bwriting = 0xfffffffe, + Bdeleted = 0, + + /* block types */ + TypeShift = 7, + BlockType = (1<<TypeShift)-1, + ControlBlock = 0x30, + DataBlock = 0x40, + ReplacePage = 0x60, + BadBlock = 0x70, +}; + +#define BTYPE(b) ((b) & BlockType) +#define BADDR(b) ((b) & ~BlockType) +#define BNO(va) (((ulong)(va))>>Bshift) +#define MKBAM(b,t) (((b)<<Bshift)|(t)) + +struct Terase { + int x; + int id; + ulong offset; + ulong bamoffset; + ulong nbam; + ulong* bam; + ulong bamx; + ulong nfree; + ulong nused; + ulong ndead; + ulong nbad; + ulong nerase; +}; + +struct Ftl { + ulong base; /* base of flash region */ + ulong size; /* size of flash region */ + ulong segsize; /* size of flash segment (erase unit) */ + int eshift; /* log2(erase-unit-size) */ + int bshift; /* log2(bsize) */ + int bsize; + int nunit; /* number of segments (erase units) */ + Terase** unit; + int lastx; /* index in unit of last allocation */ + int xfer; /* index in unit of current transfer unit (-1 if none) */ + ulong nfree; /* total free space in blocks */ + ulong nblock; /* total space in blocks */ + ulong rwlimit; /* user-visible block limit (`formatted size') */ + ulong* vbm; /* virtual block map */ + ulong fstart; /* address of first block of data in a segment */ + int trace; /* (debugging) trace of read/write actions */ + int detach; /* free Ftl on last close */ + + /* scavenging variables */ + int needspace; + int hasproc; +}; + +enum { + /* Ftl.detach */ + Detached = 1, /* detach on close */ + Deferred /* scavenger must free it */ +}; + +/* little endian */ +#define GET2(p) (((p)[1]<<8)|(p)[0]) +#define GET4(p) (((((((p)[3]<<8)|(p)[2])<<8)|(p)[1])<<8)|(p)[0]) +#define PUT2(p,v) (((p)[1]=(v)>>8),((p)[0]=(v))) +#define PUT4(p,v) (((p)[3]=(v)>>24),((p)[2]=(v)>>16),((p)[1]=(v)>>8),((p)[0]=(v))) + +static Ftl *ftls; + +static ulong allocblk(Ftl*); +static void eraseflash(Ftl*, ulong); +static void erasefree(Terase*); +static void eraseinit(Ftl*, ulong, int, int); +static Terase* eraseload(Ftl*, int, ulong); +static void ftlfree(Ftl*); +static void getflash(Ftl*, void*, ulong, long); +static int mapblk(Ftl*, ulong, Terase**, ulong*); +static Ftl* mkftl(char*, ulong, ulong, int, char*); +static void putbam(Ftl*, Terase*, int, ulong); +static void putflash(Ftl*, ulong, void*, long); +static int scavenge(Ftl*); + +static void +ftlstat(int sz) +{ + print("0x%lux:0x%ux:0x%lux\n", ftls->rwlimit*Bsize, sz, flashsize); + print("%lud:%d:%lud in 512b blocks\n", ftls->rwlimit, sz>>Bshift, flashsize>>Bshift); +} + +static long +ftlread(void *buf, long n, ulong offset) +{ + Ftl *ftl; + Terase *e; + int nb; + uchar *a; + ulong pb; + + if(n <= 0 || n%Bsize || offset%Bsize) { + fprint(2, "bad read\n"); + exits("1"); + } + ftl = ftls; + nb = n/Bsize; + offset /= Bsize; + if(offset >= ftl->rwlimit) + return 0; + if(offset+nb > ftl->rwlimit) + nb = ftl->rwlimit - offset; + a = buf; + for(n = 0; n < nb; n++){ + if(mapblk(ftl, offset+n, &e, &pb)) + getflash(ftl, a, e->offset + pb*Bsize, Bsize); + else + memset(a, 0, Bsize); + a += Bsize; + } + return a-(uchar*)buf; + return 0; /* not reached */ +} + +static long +ftlwrite(void *buf, long n, ulong offset) +{ + int ns, nb; + uchar *a; + Terase *e, *oe; + ulong ob, v; + Ftl *ftl; + + if(n <= 0) + return 0; + ftl = ftls; + if(n <= 0 || n%Bsize || offset%Bsize) { + fprint(2, "bad write\n"); + exits("1"); + } + nb = n/Bsize; + offset /= Bsize; + if(offset >= ftl->rwlimit) + return 0; + if(offset+nb > ftl->rwlimit) + nb = ftl->rwlimit - offset; + a = buf; + for(n = 0; n < nb; n++){ + ns = 0; + while((v = allocblk(ftl)) == 0) + if(!scavenge(ftl) || ++ns > 3){ + print("ftl: flash memory full\n"); + } + if(!mapblk(ftl, offset+n, &oe, &ob)) + oe = nil; + e = ftl->unit[v>>16]; + v &= 0xffff; + putflash(ftl, e->offset + v*Bsize, a, Bsize); + putbam(ftl, e, v, MKBAM(offset+n, DataBlock)); + /* both old and new block references exist in this window (can't be closed?) */ + ftl->vbm[offset+n] = (e->x<<16) | v; + if(oe != nil){ + putbam(ftl, oe, ob, Bdeleted); + oe->ndead++; + } + a += Bsize; + } + return a-(uchar*)buf; + return 0; /* not reached */ +} + +static Ftl * +mkftl(char *fname, ulong base, ulong size, int eshift, char *op) +{ + int i, j, nov, segblocks; + ulong limit; + Terase *e; + Ftl *ftl; + + ftl = malloc(sizeof(*ftl)); + if(ftl == nil) { + fprint(2, "out of memory\n"); + exits("1"); + } + ftl->lastx = 0; + ftl->detach = 0; + ftl->needspace = 0; + ftl->hasproc = 0; + ftl->trace = 0; + limit = flashsize; + if(size == Nolimit) + size = limit-base; + if(base >= limit || size > limit || base+size > limit || eshift < 8 || (1<<eshift) > size) { + fprint(2, "bad flash space parameters"); + exits("1"); + } + if(FTLDEBUG || ftl->trace || trace) + print("%s flash %s #%lux:#%lux limit #%lux\n", op, fname, base, size, limit); + ftl->base = base; + ftl->size = size; + ftl->bshift = Bshift; + ftl->bsize = Bsize; + ftl->eshift = eshift; + ftl->segsize = 1<<eshift; + ftl->nunit = size>>eshift; + nov = ((ftl->segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize; /* number of overhead blocks per segment (header, and BAM itself) */ + ftl->fstart = nov; + segblocks = ftl->segsize/Bsize - nov; + ftl->nblock = ftl->nunit*segblocks; + if(ftl->nblock >= 0x10000) + ftl->nblock = 0x10000; + ftl->vbm = malloc(ftl->nblock*sizeof(*ftl->vbm)); + ftl->unit = malloc(ftl->nunit*sizeof(*ftl->unit)); + if(ftl->vbm == nil || ftl->unit == nil) { + fprint(2, "out of mem"); + exits("1"); + } + for(i=0; i<ftl->nblock; i++) + ftl->vbm[i] = 0; + if(strcmp(op, "format") == 0){ + for(i=0; i<ftl->nunit-1; i++) + eraseinit(ftl, i*ftl->segsize, i, 1); + eraseinit(ftl, i*ftl->segsize, XferID, 1); + } + ftl->xfer = -1; + for(i=0; i<ftl->nunit; i++){ + e = eraseload(ftl, i, i*ftl->segsize); + if(e == nil){ + print("ftl: logical segment %d: bad format\n", i); + continue; + } + if(e->id == XferBusy){ + e->nerase++; + eraseinit(ftl, e->offset, XferID, e->nerase); + e->id = XferID; + } + for(j=0; j<ftl->nunit; j++) + if(ftl->unit[j] != nil && ftl->unit[j]->id == e->id){ + print("ftl: duplicate erase unit #%x\n", e->id); + erasefree(e); + e = nil; + break; + } + if(e){ + ftl->unit[e->x] = e; + if(e->id == XferID) + ftl->xfer = e->x; + if (FTLDEBUG || ftl->trace || trace) + print("ftl: unit %d:#%x used %lud free %lud dead %lud bad %lud nerase %lud\n", + e->x, e->id, e->nused, e->nfree, e->ndead, e->nbad, e->nerase); + } + } + if(ftl->xfer < 0 && ftl->nunit <= 0 || ftl->xfer >= 0 && ftl->nunit <= 1) { + fprint(2, "no valid flash data units"); + exits("1"); + } + if(ftl->xfer < 0) + print("ftl: no transfer unit: device is WORM\n"); + else + ftl->nblock -= segblocks; /* discount transfer segment */ + if(ftl->nblock >= 1000) + ftl->rwlimit = ftl->nblock-100; /* TO DO: variable reserve */ + else + ftl->rwlimit = ftl->nblock*USABLEPCT/100; + return ftl; +} + +static void +ftlfree(Ftl *ftl) +{ + if(ftl != nil){ + free(ftl->unit); + free(ftl->vbm); + free(ftl); + } +} + +/* + * this simple greedy algorithm weighted by nerase does seem to lead + * to even wear of erase units (cf. the eNVy file system) + */ +static Terase * +bestcopy(Ftl *ftl) +{ + Terase *e, *be; + int i; + + be = nil; + for(i=0; i<ftl->nunit; i++) + if((e = ftl->unit[i]) != nil && e->id != XferID && e->id != XferBusy && e->ndead+e->nbad && + (be == nil || e->nerase <= be->nerase && e->ndead >= be->ndead)) + be = e; + return be; +} + +static int +copyunit(Ftl *ftl, Terase *from, Terase *to) +{ + int i, nb; + uchar id[2]; + ulong *bam; + uchar *buf; + ulong v, bno; + + if(FTLDEBUG || ftl->trace || trace) + print("ftl: copying %d (#%lux) to #%lux\n", from->id, from->offset, to->offset); + to->nbam = 0; + free(to->bam); + to->bam = nil; + buf = malloc(Bsize); + if(buf == nil) + return 0; + PUT2(id, XferBusy); + putflash(ftl, to->offset+offsetof(Merase,id[0]), id, 2); + /* make new BAM */ + nb = from->nbam*sizeof(*to->bam); + bam = malloc(nb); + if(bam == nil) { + fprint(2, "nomem\n"); + exits("1"); + } + memmove(bam, from->bam, nb); + to->nused = 0; + to->nbad = 0; + to->nfree = 0; + to->ndead = 0; + for(i = 0; i < from->nbam; i++) + switch(bam[i]){ + case Bwriting: + case Bdeleted: + case Bfree: + bam[i] = Bfree; + to->nfree++; + break; + default: + switch(bam[i]&BlockType){ + default: + case BadBlock: /* it isn't necessarily bad in this unit */ + to->nfree++; + bam[i] = Bfree; + break; + case DataBlock: + case ReplacePage: + v = bam[i]; + bno = BNO(v & ~BlockType); + if(i < ftl->fstart || bno >= ftl->nblock){ + print("ftl: unit %d:#%x bad bam[%d]=#%lux\n", from->x, from->id, i, v); + to->nfree++; + bam[i] = Bfree; + break; + } + getflash(ftl, buf, from->offset+i*Bsize, Bsize); + putflash(ftl, to->offset+i*Bsize, buf, Bsize); + to->nused++; + break; + case ControlBlock: + to->nused++; + break; + } + } + for(i=0; i<from->nbam; i++){ + uchar *p = (uchar*)&bam[i]; + v = bam[i]; + if(v != Bfree && ftl->trace > 1) + print("to[%d]=#%lux\n", i, v); + PUT4(p, v); + } + putflash(ftl, to->bamoffset, bam, nb); /* BUG: PUT4 */ + for(i=0; i<from->nbam; i++){ + uchar *p = (uchar*)&bam[i]; + v = bam[i]; + PUT4(p, v); + } + to->id = from->id; + PUT2(id, to->id); + putflash(ftl, to->offset+offsetof(Merase,id[0]), id, 2); + to->nbam = from->nbam; + to->bam = bam; + ftl->nfree += to->nfree - from->nfree; + free(buf); + return 1; +} + +static int +mustscavenge(void *a) +{ + return ((Ftl*)a)->needspace || ((Ftl*)a)->detach == Deferred; +} + +static int +donescavenge(void *a) +{ + return ((Ftl*)a)->needspace == 0; +} + +static void +scavengeproc(void *arg) +{ + Ftl *ftl; + int i; + Terase *e, *ne; + + ftl = arg; + if(mustscavenge(ftl)){ + if(ftl->detach == Deferred){ + ftlfree(ftl); + fprint(2, "scavenge out of memory\n"); + exits("1"); + } + if(FTLDEBUG || ftl->trace || trace) + print("ftl: scavenge %ld\n", ftl->nfree); + e = bestcopy(ftl); + if(e == nil || ftl->xfer < 0 || (ne = ftl->unit[ftl->xfer]) == nil || ne->id != XferID || e == ne) + goto Fail; + if(copyunit(ftl, e, ne)){ + i = ne->x; ne->x = e->x; e->x = i; + ftl->unit[ne->x] = ne; + ftl->unit[e->x] = e; + ftl->xfer = e->x; + e->id = XferID; + e->nbam = 0; + free(e->bam); + e->bam = nil; + e->bamx = 0; + e->nerase++; + eraseinit(ftl, e->offset, XferID, e->nerase); + } + Fail: + if(FTLDEBUG || ftl->trace || trace) + print("ftl: end scavenge %ld\n", ftl->nfree); + ftl->needspace = 0; + } +} + +static int +scavenge(Ftl *ftl) +{ + if(ftl->xfer < 0 || bestcopy(ftl) == nil) + return 0; /* you worm! */ + + if(!ftl->hasproc){ + ftl->hasproc = 1; + } + ftl->needspace = 1; + + scavengeproc(ftls); + + return ftl->nfree; +} + +static void +putbam(Ftl *ftl, Terase *e, int n, ulong entry) +{ + uchar b[4]; + + e->bam[n] = entry; + PUT4(b, entry); + putflash(ftl, e->bamoffset + n*4, b, 4); +} + +static ulong +allocblk(Ftl *ftl) +{ + Terase *e; + int i, j; + + i = ftl->lastx; + do{ + e = ftl->unit[i]; + if(e != nil && e->id != XferID && e->nfree){ + ftl->lastx = i; + for(j=e->bamx; j<e->nbam; j++) + if(e->bam[j] == Bfree){ + putbam(ftl, e, j, Bwriting); + ftl->nfree--; + e->nfree--; + e->bamx = j+1; + return (e->x<<16) | j; + } + e->nfree = 0; + print("ftl: unit %d:#%x nfree %ld but not free in BAM\n", e->x, e->id, e->nfree); + } + if(++i >= ftl->nunit) + i = 0; + }while(i != ftl->lastx); + return 0; +} + +static int +mapblk(Ftl *ftl, ulong bno, Terase **ep, ulong *bp) +{ + ulong v; + int x; + + if(bno < ftl->nblock){ + v = ftl->vbm[bno]; + if(v == 0 || v == ~0) + return 0; + x = v>>16; + if(x >= ftl->nunit || x == ftl->xfer || ftl->unit[x] == nil){ + print("ftl: corrupt format: bad block mapping %lud -> unit #%x\n", bno, x); + return 0; + } + *ep = ftl->unit[x]; + *bp = v & 0xFFFF; + return 1; + } + return 0; +} + +static void +eraseinit(Ftl *ftl, ulong offset, int id, int nerase) +{ + union { + Merase m; + uchar block[ERASEHDRLEN]; + } *m; + uchar *bam, *p; + int i, nov; + + nov = ((ftl->segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize; /* number of overhead blocks (header, and BAM itself) */ + if(nov*Bsize >= ftl->segsize) { + fprint(2, "ftl -- too small for files"); + exits("1"); + } + eraseflash(ftl, offset); + m = malloc(sizeof(*m)); + if(m == nil) { + fprint(2, "nomem\n"); + exits("1"); + } + memset(m, 0xFF, sizeof(*m)); + m->m.linktuple[0] = 0x13; + m->m.linktuple[1] = 0x3; + memmove(m->m.linktuple+2, "CIS", 3); + m->m.orgtuple[0] = 0x46; + m->m.orgtuple[1] = 0x57; + m->m.orgtuple[2] = 0x00; + memmove(m->m.orgtuple+3, "FTL100", 7); + m->m.nxfer = 1; + PUT4(m->m.nerase, nerase); + PUT2(m->m.id, id); + m->m.bshift = ftl->bshift; + m->m.eshift = ftl->eshift; + PUT2(m->m.pstart, 0); + PUT2(m->m.nunits, ftl->nunit); + PUT4(m->m.psize, ftl->size - nov*Bsize); + PUT4(m->m.vbmbase, 0xffffffff); /* we always calculate the VBM */ + PUT2(m->m.nvbm, 0); + m->m.flags = 0; + m->m.code = 0xFF; + memmove(m->m.serial, "Inf1", 4); + PUT4(m->m.altoffset, 0); + PUT4(m->m.bamoffset, BAMoffset); + putflash(ftl, offset, m, ERASEHDRLEN); + free(m); + if(id == XferID) + return; + nov *= 4; /* now bytes of BAM */ + bam = malloc(nov); + if(bam == nil) { + fprint(2, "nomem"); + exits("1"); + } + for(i=0; i<nov; i += 4){ + p = bam+i; + PUT4(p, ControlBlock); /* reserve them */ + } + putflash(ftl, offset+BAMoffset, bam, nov); + free(bam); +} + +static Terase * +eraseload(Ftl *ftl, int x, ulong offset) +{ + union { + Merase m; + uchar block[ERASEHDRLEN]; + } *m; + Terase *e; + uchar *p; + int i, nbam; + ulong bno, v; + + m = malloc(sizeof(*m)); + if(m == nil) { + fprint(2, "nomem"); + exits("1"); + } + getflash(ftl, m, offset, ERASEHDRLEN); + if(memcmp(m->m.orgtuple+3, "FTL100", 7) != 0 || + memcmp(m->m.serial, "Inf1", 4) != 0){ + free(m); + return nil; + } + e = malloc(sizeof(*e)); + if(e == nil){ + free(m); + fprint(2, "nomem"); + exits("1"); + } + e->x = x; + e->id = GET2(m->m.id); + e->offset = offset; + e->bamoffset = GET4(m->m.bamoffset); + e->nerase = GET4(m->m.nerase); + e->bamx = 0; + e->nfree = 0; + e->nused = 0; + e->ndead = 0; + e->nbad = 0; + free(m); + if(e->bamoffset != BAMoffset){ + free(e); + return nil; + } + e->bamoffset += offset; + if(e->id == XferID || e->id == XferBusy){ + e->bam = nil; + e->nbam = 0; + return e; + } + nbam = ftl->segsize/Bsize; + e->bam = malloc(nbam*sizeof(*e->bam)); + e->nbam = nbam; + getflash(ftl, e->bam, e->bamoffset, nbam*4); + /* scan BAM to build VBM */ + e->bamx = 0; + for(i=0; i<nbam; i++){ + p = (uchar*)&e->bam[i]; + e->bam[i] = v = GET4(p); + if(v == Bwriting || v == Bdeleted) + e->ndead++; + else if(v == Bfree){ + if(e->bamx == 0) + e->bamx = i; + e->nfree++; + ftl->nfree++; + }else{ + switch(v & BlockType){ + case ControlBlock: + break; + case DataBlock: + /* add to VBM */ + if(v & (1<<31)) + break; /* negative => VBM page, ignored */ + bno = BNO(v & ~BlockType); + if(i < ftl->fstart || bno >= ftl->nblock){ + print("ftl: unit %d:#%x bad bam[%d]=#%lux\n", e->x, e->id, i, v); + e->nbad++; + break; + } + ftl->vbm[bno] = (e->x<<16) | i; + e->nused++; + break; + case ReplacePage: + /* replacement VBM page; ignored */ + break; + default: + print("ftl: unit %d:#%x bad bam[%d]=%lux\n", e->x, e->id, i, v); + case BadBlock: + e->nbad++; + break; + } + } + } + return e; +} + +static void +erasefree(Terase *e) +{ + free(e->bam); + free(e); +} + +static void +eraseflash(Ftl *ftl, ulong offset) +{ + offset += ftl->base; + if(FTLDEBUG || ftl->trace || trace) + print("ftl: erase seg @#%lux\n", offset); + memset(flashm+offset, 0xff, secsize); +} + +static void +putflash(Ftl *ftl, ulong offset, void *buf, long n) +{ + offset += ftl->base; + if(ftl->trace || trace) + print("ftl: write(#%lux, %ld)\n", offset, n); + memcpy(flashm+offset, buf, n); +} + +static void +getflash(Ftl *ftl, void *buf, ulong offset, long n) +{ + offset += ftl->base; + if(ftl->trace || trace) + print("ftl: read(#%lux, %ld)\n", offset, n); + memcpy(buf, flashm+offset, n); +} + +#define BUFSIZE 8192 + +void +main(int argc, char **argv) +{ + int k, r, sz, offset = 0; + char *buf, *buf1; + int fd1, fd2; + + if (argc != 5) { + fprint(2, "usage: %s flashsize secsize kfsfile flashfile\n", argv[0]); + exits("1"); + } + flashsize = strtol(argv[1], nil, 0); + secsize = strtol(argv[2], nil , 0); + fd1 = open(argv[3], OREAD); + fd2 = create(argv[4], OWRITE, 0644); + if (fd1 < 0 || fd2 < 0) { + fprint(2, "bad io files\n"); + exits("1"); + } + if(secsize == 0 || secsize > flashsize || secsize&(secsize-1) || 0&(secsize-1) || flashsize == 0 || flashsize != Nolimit && flashsize&(secsize-1)) { + fprint(2, "bad sizes\n"); + exits("1"); + } + for(k=0; k<32 && (1<<k) != secsize; k++) + ; + flashm = malloc(flashsize); + buf = malloc(BUFSIZE); + if (flashm == nil) { + fprint(2, "no mem for flash\n"); + exits("1"); + } + ftls = mkftl("FLASH", 0, Nolimit, k, "format"); + for (;;) { + r = read(fd1, buf, BUFSIZE); + if (r <= 0) + break; + if (ftlwrite(buf, r, offset) != r) { + fprint(2, "ftlwrite failed - input file too big\n"); + exits("1"); + } + offset += r; + } + write(fd2, flashm, flashsize); + close(fd1); + close(fd2); + ftlstat(offset); + /* ftls = mkftl("FLASH", 0, Nolimit, k, "init"); */ + sz = offset; + offset = 0; + buf1 = malloc(BUFSIZE); + fd1 = open(argv[3], OREAD); + for (;;) { + r = read(fd1, buf1, BUFSIZE); + if (r <= 0) + break; + if (ftlread(buf, r, offset) != r) { + fprint(2, "ftlread failed\n"); + exits("1"); + } + if (memcmp(buf, buf1, r) != 0) { + fprint(2, "bad read\n"); + exits("1"); + } + offset += r; + } + close(fd1); + if (offset != sz) { + fprint(2, "bad final offset\n"); + exits("1"); + } + exits("0"); +} diff --git a/utils/ftl/mkfile b/utils/ftl/mkfile new file mode 100644 index 00000000..cd9c4f2f --- /dev/null +++ b/utils/ftl/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=ftl + +OFILES= ftl.$O\ + +HFILES= + +LIBS=9 # libbio.a uses lib9.a so order matters. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/iar/Nt.c b/utils/iar/Nt.c new file mode 100644 index 00000000..dbb038ba --- /dev/null +++ b/utils/iar/Nt.c @@ -0,0 +1,10 @@ +#include <lib9.h> + +char * +myctime(long x) +{ + time_t t; + + t = x; + return ctime(&t); +} diff --git a/utils/iar/Plan9.c b/utils/iar/Plan9.c new file mode 100644 index 00000000..49f03f06 --- /dev/null +++ b/utils/iar/Plan9.c @@ -0,0 +1,7 @@ +#include <lib9.h> + +char * +myctime(long x) +{ + return ctime(x); +} diff --git a/utils/iar/Posix.c b/utils/iar/Posix.c new file mode 100644 index 00000000..dbb038ba --- /dev/null +++ b/utils/iar/Posix.c @@ -0,0 +1,10 @@ +#include <lib9.h> + +char * +myctime(long x) +{ + time_t t; + + t = x; + return ctime(&t); +} diff --git a/utils/iar/ar.c b/utils/iar/ar.c new file mode 100644 index 00000000..aff05d3a --- /dev/null +++ b/utils/iar/ar.c @@ -0,0 +1,1197 @@ +/* + * ar - portable (ascii) format version + */ +#include <lib9.h> +#include <bio.h> +#include <mach.h> +#include <ar.h> + +/* + * The algorithm uses up to 3 temp files. The "pivot member" is the + * archive member specified by and a, b, or i option. The temp files are + * astart - contains existing members up to and including the pivot member. + * amiddle - contains new files moved or inserted behind the pivot. + * aend - contains the existing members that follow the pivot member. + * When all members have been processed, function 'install' streams the + * temp files, in order, back into the archive. + */ + +typedef struct Arsymref +{ + char *name; + int type; + int len; + long offset; + struct Arsymref *next; +} Arsymref; + +typedef struct Armember /* Temp file entry - one per archive member */ +{ + struct Armember *next; + struct ar_hdr hdr; + long size; + long date; + void *member; +} Armember; + +typedef struct Arfile /* Temp file control block - one per tempfile */ +{ + int paged; /* set when some data paged to disk */ + char *fname; /* paging file name */ + int fd; /* paging file descriptor */ + long size; + Armember *head; /* head of member chain */ + Armember *tail; /* tail of member chain */ + Arsymref *sym; /* head of defined symbol chain */ +} Arfile; + +typedef struct Hashchain +{ + char *name; + struct Hashchain *next; +} Hashchain; + +#define NHASH 1024 + +/* + * macro to portably read/write archive header. + * 'cmd' is read/write/Bread/Bwrite, etc. + */ +#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\ + || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\ + || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\ + || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\ + || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\ + || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\ + || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag) + + /* constants and flags */ +char *man = "mrxtdpq"; +char *opt = "uvnbailo"; +char artemp[] = "/tmp/vXXXXX"; +char movtemp[] = "/tmp/v1XXXXX"; +char tailtemp[] = "/tmp/v2XXXXX"; +char symdef[] = "__.SYMDEF"; + +int aflag; /* command line flags */ +int bflag; +int cflag; +int oflag; +int uflag; +int vflag; + +Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */ +int allobj = 1; /* set when all members are object files of the same type */ +int symdefsize; /* size of symdef file */ +int dupfound; /* flag for duplicate symbol */ +Hashchain *hash[NHASH]; /* hash table of text symbols */ + +#define ARNAMESIZE sizeof(astart->tail->hdr.name) + +char poname[ARNAMESIZE+1]; /* name of pivot member */ +char *file; /* current file or member being worked on */ +Biobuf bout; +Biobuf bar; + +void arcopy(Biobuf*, Arfile*, Armember*); +int arcreate(char*); +void arfree(Arfile*); +void arinsert(Arfile*, Armember*); +char *armalloc(int); +void armove(Biobuf*, Arfile*, Armember*); +void arread(Biobuf*, Armember*, int); +void arstream(int, Arfile*); +int arwrite(int, Armember*); +int bamatch(char*, char*); +int duplicate(char*); +Armember *getdir(Biobuf*); +int getspace(void); +void install(char*, Arfile*, Arfile*, Arfile*, int); +void longt(Armember*); +int match(int, char**); +void mesg(int, char*); +char *myctime(long); /* $TARGMODEL.c */ +Arfile *newtempfile(char*); +Armember *newmember(void); +void objsym(Sym*, void*); +int openar(char*, int, int); +int page(Arfile*); +void pmode(long); +void rl(int); +void scanobj(Biobuf*, Arfile*, int); +void ar_select(int*, long); +void setcom(void(*)(char*, int, char**)); +void skip(Biobuf*, long); +int symcomp(void*, void*); +void trim(char*, char*, int); +void usage(void); +void wrerr(void); +void wrsym(Biobuf*, int, Arsymref*); + +void arcmd(char*, int, char**); /* command processing */ +void dcmd(char*, int, char**); +void xcmd(char*, int, char**); +void tcmd(char*, int, char**); +void pcmd(char*, int, char**); +void mcmd(char*, int, char**); +void qcmd(char*, int, char**); +void (*comfun)(char*, int, char**); + +void +main(int argc, char *argv[]) +{ + char *cp; + + Binit(&bout, 1, OWRITE); + if(argc < 3) + usage(); + for (cp = argv[1]; *cp; cp++) { + switch(*cp) { + case 'a': aflag = 1; break; + case 'b': bflag = 1; break; + case 'c': cflag = 1; break; + case 'd': setcom(dcmd); break; + case 'i': bflag = 1; break; + case 'l': + strcpy(artemp, "vXXXXX"); + strcpy(movtemp, "v1XXXXX"); + strcpy(tailtemp, "v2XXXXX"); + break; + case 'm': setcom(mcmd); break; + case 'o': oflag = 1; break; + case 'p': setcom(pcmd); break; + case 'q': setcom(qcmd); break; + case 'r': setcom(arcmd); break; + case 't': setcom(tcmd); break; + case 'u': uflag = 1; break; + case 'v': vflag = 1; break; + case 'x': setcom(xcmd); break; + default: + fprint(2, "ar: bad option `%c'\n", *cp); + exits("error"); + } + } + if (aflag && bflag) { + fprint(2, "ar: only one of 'a' and 'b' can be specified\n"); + usage(); + } + if(aflag || bflag) { + trim(argv[2], poname, sizeof(poname)); + argv++; + argc--; + if(argc < 3) + usage(); + } + if(comfun == 0) { + if(uflag == 0) { + fprint(2, "ar: one of [%s] must be specified\n", man); + usage(); + } + setcom(arcmd); + } + cp = argv[2]; + argc -= 3; + argv += 3; + (*comfun)(cp, argc, argv); /* do the command */ + cp = 0; + while (argc--) { + if (*argv) { + fprint(2, "ar: %s not found\n", *argv); + cp = "error"; + } + argv++; + } + if(allobj && dupfound) + exits("dup found"); + exits(cp); +} +/* + * select a command + */ +void +setcom(void (*fun)(char *, int, char**)) +{ + + if(comfun != 0) { + fprint(2, "ar: only one of [%s] allowed\n", man); + usage(); + } + comfun = fun; +} +/* + * perform the 'r' and 'u' commands + */ +void +arcmd(char *arname, int count, char **files) +{ + int fd; + int i; + Arfile *ap; + Armember *bp; + Dir *d; + Biobuf *bfile; + + fd = openar(arname, ORDWR, 1); + if (fd >= 0) { + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + } + astart = newtempfile(artemp); + ap = astart; + aend = 0; + for(i = 0; fd >= 0; i++) { + bp = getdir(&bar); + if (!bp) + break; + if (bamatch(file, poname)) { /* check for pivot */ + aend = newtempfile(tailtemp); + ap = aend; + } + /* pitch symdef file */ + if (i == 0 && strcmp(file, symdef) == 0) { + skip(&bar, bp->size); + continue; + } + if (count && !match(count, files)) { + scanobj(&bar, ap, bp->size); + arcopy(&bar, ap, bp); + continue; + } + bfile = Bopen(file, OREAD); + if (!bfile) { + if (count != 0) + fprint(2, "ar: cannot open %s\n", file); + scanobj(&bar, ap, bp->size); + arcopy(&bar, ap, bp); + continue; + } + d = dirfstat(Bfildes(bfile)); + if (d == nil) + fprint(2, "ar: cannot stat %s: %r\n", file); + if (uflag && (d == nil || d->mtime <= bp->date)) { + scanobj(&bar, ap, bp->size); + arcopy(&bar, ap, bp); + Bterm(bfile); + free(d); + continue; + } + mesg('r', file); + skip(&bar, bp->size); + scanobj(bfile, ap, d->length); + free(d); + armove(bfile, ap, bp); + Bterm(bfile); + } + if(fd >= 0) + close(fd); + /* copy in remaining files named on command line */ + for (i = 0; i < count; i++) { + file = files[i]; + if(file == 0) + continue; + files[i] = 0; + bfile = Bopen(file, OREAD); + if (!bfile) + fprint(2, "ar: %s cannot open\n", file); + else { + mesg('a', file); + d = dirfstat(Bfildes(bfile)); + if (d == nil) + fprint(2, "ar: can't stat %s: %r\n", file); + else { + scanobj(bfile, astart, d->length); + armove(bfile, astart, newmember()); + free(d); + } + Bterm(bfile); + } + } + if(fd < 0 && !cflag) + install(arname, astart, 0, aend, 1); /* issue 'creating' msg */ + else + install(arname, astart, 0, aend, 0); +} + +void +dcmd(char *arname, int count, char **files) +{ + Armember *bp; + int fd, i; + + + if (!count) + return; + fd = openar(arname, ORDWR, 0); + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + astart = newtempfile(artemp); + for (i = 0; bp = getdir(&bar); i++) { + if(match(count, files)) { + mesg('d', file); + skip(&bar, bp->size); + if (strcmp(file, symdef) == 0) + allobj = 0; + } else if (i == 0 && strcmp(file, symdef) == 0) + skip(&bar, bp->size); + else { + scanobj(&bar, astart, bp->size); + arcopy(&bar, astart, bp); + } + } + close(fd); + install(arname, astart, 0, 0, 0); +} + +void +xcmd(char *arname, int count, char **files) +{ + int fd, f, mode, i; + Armember *bp; + Dir dx; + + fd = openar(arname, OREAD, 0); + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + i = 0; + while (bp = getdir(&bar)) { + if(count == 0 || match(count, files)) { + mode = strtoul(bp->hdr.mode, 0, 8) & 0777; + f = create(file, OWRITE, mode); + if(f < 0) { + fprint(2, "ar: %s cannot create\n", file); + skip(&bar, bp->size); + } else { + mesg('x', file); + arcopy(&bar, 0, bp); + if (write(f, bp->member, bp->size) < 0) + wrerr(); + if(oflag) { + nulldir(&dx); + dx.atime = bp->date; + dx.mtime = bp->date; + if(dirwstat(file, &dx) < 0) + perror(file); + } + free(bp->member); + close(f); + } + free(bp); + if (count && ++i >= count) + break; + } else { + skip(&bar, bp->size); + free(bp); + } + } + close(fd); +} +void +pcmd(char *arname, int count, char **files) +{ + int fd; + Armember *bp; + + fd = openar(arname, OREAD, 0); + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + while(bp = getdir(&bar)) { + if(count == 0 || match(count, files)) { + if(vflag) + print("\n<%s>\n\n", file); + arcopy(&bar, 0, bp); + if (write(1, bp->member, bp->size) < 0) + wrerr(); + } else + skip(&bar, bp->size); + free(bp); + } + close(fd); +} +void +mcmd(char *arname, int count, char **files) +{ + int fd, i; + Arfile *ap; + Armember *bp; + + if (count == 0) + return; + fd = openar(arname, ORDWR, 0); + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + astart = newtempfile(artemp); + amiddle = newtempfile(movtemp); + aend = 0; + ap = astart; + for (i = 0; bp = getdir(&bar); i++) { + if (bamatch(file, poname)) { + aend = newtempfile(tailtemp); + ap = aend; + } + if(match(count, files)) { + mesg('m', file); + scanobj(&bar, amiddle, bp->size); + arcopy(&bar, amiddle, bp); + } else + /* + * pitch the symdef file if it is at the beginning + * of the archive and we aren't inserting in front + * of it (ap == astart). + */ + if (ap == astart && i == 0 && strcmp(file, symdef) == 0) + skip(&bar, bp->size); + else { + scanobj(&bar, ap, bp->size); + arcopy(&bar, ap, bp); + } + } + close(fd); + if (poname[0] && aend == 0) + fprint(2, "ar: %s not found - files moved to end.\n", poname); + install(arname, astart, amiddle, aend, 0); +} +void +tcmd(char *arname, int count, char **files) +{ + int fd; + Armember *bp; + char name[ARNAMESIZE+1]; + + fd = openar(arname, OREAD, 0); + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + while(bp = getdir(&bar)) { + if(count == 0 || match(count, files)) { + if(vflag) + longt(bp); + trim(file, name, ARNAMESIZE); + Bprint(&bout, "%s\n", name); + } + skip(&bar, bp->size); + free(bp); + } + close(fd); +} +void +qcmd(char *arname, int count, char **files) +{ + int fd, i; + Armember *bp; + Biobuf *bfile; + + if(aflag || bflag) { + fprint(2, "ar: abi not allowed with q\n"); + exits("error"); + } + fd = openar(arname, ORDWR, 1); + if (fd < 0) { + if(!cflag) + fprint(2, "ar: creating %s\n", arname); + fd = arcreate(arname); + } + Binit(&bar, fd, OREAD); + Bseek(&bar,seek(fd,0,1), 1); + Bseek(&bar, 0, 2); + bp = newmember(); + for(i=0; i<count && files[i]; i++) { + file = files[i]; + files[i] = 0; + bfile = Bopen(file, OREAD); + if(!bfile) + fprint(2, "ar: %s cannot open\n", file); + else { + mesg('q', file); + armove(bfile, 0, bp); + if (!arwrite(fd, bp)) + wrerr(); + free(bp->member); + bp->member = 0; + Bterm(bfile); + } + } + free(bp); + close(fd); +} + +/* + * extract the symbol references from an object file + */ +void +scanobj(Biobuf *b, Arfile *ap, int size) +{ + int obj; + long offset; + Dir *d; + static int lastobj = -1; + + if (!allobj) /* non-object file encountered */ + return; + offset = Boffset(b); + obj = objtype(b, 0); + if (obj < 0) { /* not an object file */ + allobj = 0; + d = dirfstat(Bfildes(b)); + if (d != nil && d->length == 0) + fprint(2, "ar: zero length file %s\n", file); + free(d); + Bseek(b, offset, 0); + return; + } + if (lastobj >= 0 && obj != lastobj) { + fprint(2, "ar: inconsistent object file %s\n", file); + allobj = 0; + Bseek(b, offset, 0); + return; + } + lastobj = obj; + if (!readar(b, obj, offset+size, 0)) { + fprint(2, "ar: invalid symbol reference in file %s\n", file); + allobj = 0; + Bseek(b, offset, 0); + return; + } + Bseek(b, offset, 0); + objtraverse(objsym, ap); +} + +/* + * add text and data symbols to the symbol list + */ +void +objsym(Sym *s, void *p) +{ + int n; + Arsymref *as; + Arfile *ap; + + if (s->type != 'T' && s->type != 'D') + return; + ap = (Arfile*)p; + as = (Arsymref*)armalloc(sizeof(Arsymref)); + as->offset = ap->size; + n = strlen(s->name); + as->name = armalloc(n+1); + strcpy(as->name, s->name); + if(s->type == 'T' && duplicate(as->name)) { + dupfound = 1; + fprint(2, "duplicate text symbol: %s\n", as->name); + free(as->name); + free(as); + return; + } + as->type = s->type; + symdefsize += 4+(n+1)+1; + as->len = n; + as->next = ap->sym; + ap->sym = as; +} + +/* + * Check the symbol table for duplicate text symbols + */ +int +duplicate(char *name) +{ + Hashchain *p; + char *cp; + int h; + + h = 0; + for(cp = name; *cp; h += *cp++) + h *= 1119; + if(h < 0) + h = ~h; + h %= NHASH; + + for(p = hash[h]; p; p = p->next) + if(strcmp(p->name, name) == 0) + return 1; + p = (Hashchain*) armalloc(sizeof(Hashchain)); + p->next = hash[h]; + p->name = name; + hash[h] = p; + return 0; +} + +/* + * open an archive and validate its header + */ +int +openar(char *arname, int mode, int errok) +{ + int fd; + char mbuf[SARMAG]; + + fd = open(arname, mode); + if(fd >= 0){ + if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) { + fprint(2, "ar: %s not in archive format\n", arname); + exits("error"); + } + }else if(!errok){ + fprint(2, "ar: cannot open %s: %r\n", arname); + exits("error"); + } + return fd; +} +/* + * create an archive and set its header + */ +int +arcreate(char *arname) +{ + int fd; + + fd = create(arname, OWRITE, 0664); + if(fd < 0){ + fprint(2, "ar: cannot create %s: %r\n", arname); + exits("error"); + } + if(write(fd, ARMAG, SARMAG) != SARMAG) + wrerr(); + return fd; +} +/* + * error handling + */ +void +wrerr(void) +{ + perror("ar: write error"); + exits("error"); +} + +void +rderr(void) +{ + perror("ar: read error"); + exits("error"); +} + +void +phaseerr(int offset) +{ + fprint(2, "ar: phase error at offset %d\n", offset); + exits("error"); +} + +void +usage(void) +{ + fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man); + exits("error"); +} +/* + * read the header for the next archive member + */ +Armember * +getdir(Biobuf *b) +{ + Armember *bp; + char *cp; + static char name[ARNAMESIZE+1]; + + bp = newmember(); + if(HEADER_IO(Bread, b, bp->hdr)) { + free(bp); + return 0; + } + if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag))) + phaseerr(Boffset(b)); + strncpy(name, bp->hdr.name, sizeof(bp->hdr.name)); + cp = name+sizeof(name)-1; + while(*--cp==' ') + ; + cp[1] = '\0'; + file = name; + bp->date = atol(bp->hdr.date); + bp->size = atol(bp->hdr.size); + return bp; +} +/* + * Copy the file referenced by fd to the temp file + */ +void +armove(Biobuf *b, Arfile *ap, Armember *bp) +{ + char *cp; + Dir *d; + + if ((d = dirfstat(Bfildes(b))) == nil) { + fprint(2, "ar: cannot stat %s: %r\n", file); + return; + } + trim(file, bp->hdr.name, sizeof(bp->hdr.name)); + for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */ + cp < bp->hdr.name+sizeof(bp->hdr.name); cp++) + *cp = ' '; + sprint(bp->hdr.date, "%-12ld", d->mtime); + sprint(bp->hdr.uid, "%-6d", 0); + sprint(bp->hdr.gid, "%-6d", 0); + sprint(bp->hdr.mode, "%-8lo", d->mode); + sprint(bp->hdr.size, "%-10lld", (vlong)d->length); + strncpy(bp->hdr.fmag, ARFMAG, 2); + bp->size = d->length; + bp->date = d->mtime; + arread(b, bp, bp->size); + if (d->length&0x01) + d->length++; + if (ap) { + arinsert(ap, bp); + ap->size += d->length+SAR_HDR; + } + free(d); +} +/* + * Copy the archive member at the current offset into the temp file. + */ +void +arcopy(Biobuf *b, Arfile *ap, Armember *bp) +{ + int n; + + n = bp->size; + if (n & 01) + n++; + arread(b, bp, n); + if (ap) { + arinsert(ap, bp); + ap->size += n+SAR_HDR; + } +} +/* + * Skip an archive member + */ +void +skip(Biobuf *bp, long len) +{ + if (len & 01) + len++; + Bseek(bp, len, 1); +} +/* + * Stream the three temp files to an archive + */ +void +install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag) +{ + int fd; + + if(allobj && dupfound) { + fprint(2, "%s not changed\n", arname); + return; + } + + if(createflag) + fprint(2, "ar: creating %s\n", arname); + fd = arcreate(arname); + + if(allobj) + rl(fd); + + if (astart) { + arstream(fd, astart); + arfree(astart); + } + if (amiddle) { + arstream(fd, amiddle); + arfree(amiddle); + } + if (aend) { + arstream(fd, aend); + arfree(aend); + } + close(fd); +} + +void +rl(int fd) +{ + + Biobuf b; + char *cp; + struct ar_hdr a; + long len; + + Binit(&b, fd, OWRITE); + Bseek(&b,seek(fd,0,1), 0); + + len = symdefsize; + if(len&01) + len++; + sprint(a.date, "%-12ld", time(0)); + sprint(a.uid, "%-6d", 0); + sprint(a.gid, "%-6d", 0); + sprint(a.mode, "%-8o", 0644); + sprint(a.size, "%-10ld", len); + strncpy(a.fmag, ARFMAG, 2); + strcpy(a.name, symdef); + for (cp = strchr(a.name, 0); /* blank pad on right */ + cp < a.name+sizeof(a.name); cp++) + *cp = ' '; + if(HEADER_IO(Bwrite, &b, a)) + wrerr(); + + len += Boffset(&b); + if (astart) { + wrsym(&b, len, astart->sym); + len += astart->size; + } + if(amiddle) { + wrsym(&b, len, amiddle->sym); + len += amiddle->size; + } + if(aend) + wrsym(&b, len, aend->sym); + + if(symdefsize&0x01) + Bputc(&b, 0); + Bterm(&b); +} +/* + * Write the defined symbols to the symdef file + */ +void +wrsym(Biobuf *bp, int offset, Arsymref *as) +{ + int off; + + while(as) { + Bputc(bp, as->type); + off = as->offset+offset; + Bputc(bp, off); + Bputc(bp, off>>8); + Bputc(bp, off>>16); + Bputc(bp, off>>24); + if (Bwrite(bp, as->name, as->len+1) != as->len+1) + wrerr(); + as = as->next; + } +} +/* + * Check if the archive member matches an entry on the command line. + */ +int +match(int count, char **files) +{ + int i; + char name[ARNAMESIZE+1]; + + for(i=0; i<count; i++) { + if(files[i] == 0) + continue; + trim(files[i], name, ARNAMESIZE); + if(strncmp(name, file, ARNAMESIZE) == 0) { + file = files[i]; + files[i] = 0; + return 1; + } + } + return 0; +} +/* + * compare the current member to the name of the pivot member + */ +int +bamatch(char *file, char *pivot) +{ + static int state = 0; + + switch(state) + { + case 0: /* looking for position file */ + if (aflag) { + if (strncmp(file, pivot, ARNAMESIZE) == 0) + state = 1; + } else if (bflag) { + if (strncmp(file, pivot, ARNAMESIZE) == 0) { + state = 2; /* found */ + return 1; + } + } + break; + case 1: /* found - after previous file */ + state = 2; + return 1; + case 2: /* already found position file */ + break; + } + return 0; +} +/* + * output a message, if 'v' option was specified + */ +void +mesg(int c, char *file) +{ + + if(vflag) + Bprint(&bout, "%c - %s\n", c, file); +} +/* + * isolate file name by stripping leading directories and trailing slashes + */ +void +trim(char *s, char *buf, int n) +{ + char *p; + + for(;;) { + p = strrchr(s, '/'); + if (!p) { /* no slash in name */ + strncpy(buf, s, n); + return; + } + if (p[1] != 0) { /* p+1 is first char of file name */ + strncpy(buf, p+1, n); + return; + } + *p = 0; /* strip trailing slash */ + } +} +/* + * utilities for printing long form of 't' command + */ +#define SUID 04000 +#define SGID 02000 +#define ROWN 0400 +#define WOWN 0200 +#define XOWN 0100 +#define RGRP 040 +#define WGRP 020 +#define XGRP 010 +#define ROTH 04 +#define WOTH 02 +#define XOTH 01 +#define STXT 01000 + +void +longt(Armember *bp) +{ + char *cp; + + pmode(strtoul(bp->hdr.mode, 0, 8)); + Bprint(&bout, "%3ld/%1ld", atol(bp->hdr.uid), atol(bp->hdr.gid)); + Bprint(&bout, "%7ld", bp->size); + cp = myctime(bp->date); + Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); +} + +int m1[] = { 1, ROWN, 'r', '-' }; +int m2[] = { 1, WOWN, 'w', '-' }; +int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; +int m4[] = { 1, RGRP, 'r', '-' }; +int m5[] = { 1, WGRP, 'w', '-' }; +int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; +int m7[] = { 1, ROTH, 'r', '-' }; +int m8[] = { 1, WOTH, 'w', '-' }; +int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; + +int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; + +void +pmode(long mode) +{ + int **mp; + + for(mp = &m[0]; mp < &m[9];) + ar_select(*mp++, mode); +} + +void +ar_select(int *ap, long mode) +{ + int n; + + n = *ap++; + while(--n>=0 && (mode&*ap++)==0) + ap++; + Bputc(&bout, *ap); +} +/* + * Temp file I/O subsystem. We attempt to cache all three temp files in + * core. When we run out of memory we spill to disk. + * The I/O model assumes that temp files: + * 1) are only written on the end + * 2) are only read from the beginning + * 3) are only read after all writing is complete. + * The architecture uses one control block per temp file. Each control + * block anchors a chain of buffers, each containing an archive member. + */ +Arfile * +newtempfile(char *name) /* allocate a file control block */ +{ + Arfile *ap; + + ap = (Arfile *) armalloc(sizeof(Arfile)); + ap->fname = name; + return ap; +} + +Armember * +newmember(void) /* allocate a member buffer */ +{ + return (Armember *)armalloc(sizeof(Armember)); +} + +void +arread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */ +{ + int i; + + bp->member = armalloc(n); + i = Bread(b, bp->member, n); + if (i < 0) { + free(bp->member); + bp->member = 0; + rderr(); + } +} +/* + * insert a member buffer into the member chain + */ +void +arinsert(Arfile *ap, Armember *bp) +{ + bp->next = 0; + if (!ap->tail) + ap->head = bp; + else + ap->tail->next = bp; + ap->tail = bp; +} +/* + * stream the members in a temp file to the file referenced by 'fd'. + */ +void +arstream(int fd, Arfile *ap) +{ + Armember *bp; + int i; + char buf[8192]; + + if (ap->paged) { /* copy from disk */ + seek(ap->fd, 0, 0); + for (;;) { + i = read(ap->fd, buf, sizeof(buf)); + if (i < 0) + rderr(); + if (i == 0) + break; + if (write(fd, buf, i) != i) + wrerr(); + } + close(ap->fd); + ap->paged = 0; + } + /* dump the in-core buffers */ + for (bp = ap->head; bp; bp = bp->next) { + if (!arwrite(fd, bp)) + wrerr(); + } +} +/* + * write a member to 'fd'. + */ +int +arwrite(int fd, Armember *bp) +{ + int len; + + if(HEADER_IO(write, fd, bp->hdr)) + return 0; + len = bp->size; + if (len & 01) + len++; + if (write(fd, bp->member, len) != len) + return 0; + return 1; +} +/* + * Spill a member to a disk copy of a temp file + */ +int +page(Arfile *ap) +{ + Armember *bp; + + bp = ap->head; + if (!ap->paged) { /* not yet paged - create file */ + ap->fname = mktemp(ap->fname); + ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600); + if (ap->fd < 0) { + fprint(2,"ar: can't create temp file\n"); + return 0; + } + ap->paged = 1; + } + if (!arwrite(ap->fd, bp)) /* write member and free buffer block */ + return 0; + ap->head = bp->next; + if (ap->tail == bp) + ap->tail = bp->next; + free(bp->member); + free(bp); + return 1; +} +/* + * try to reclaim space by paging. we try to spill the start, middle, + * and end files, in that order. there is no particular reason for the + * ordering. + */ +int +getspace(void) +{ + if (astart && astart->head && page(astart)) + return 1; + if (amiddle && amiddle->head && page(amiddle)) + return 1; + if (aend && aend->head && page(aend)) + return 1; + return 0; +} + +void +arfree(Arfile *ap) /* free a member buffer */ +{ + Armember *bp, *next; + + for (bp = ap->head; bp; bp = next) { + next = bp->next; + if (bp->member) + free(bp->member); + free(bp); + } + free(ap); +} +/* + * allocate space for a control block or member buffer. if the malloc + * fails we try to reclaim space by spilling previously allocated + * member buffers. + */ +char * +armalloc(int n) +{ + char *cp; + + do { + cp = malloc(n); + if (cp) { + memset(cp, 0, n); + return cp; + } + } while (getspace()); + fprint(2, "ar: out of memory\n"); + exits("malloc"); + return 0; +} +/* + * Nt stub for GetNameFromID() in lib9\dirstat-Nt.c. + * Other architectures never call it. + */ +char * +GetNameFromID(int id) +{ + USED(id); + return "unknown"; +} diff --git a/utils/iar/mkfile b/utils/iar/mkfile new file mode 100644 index 00000000..35f60249 --- /dev/null +++ b/utils/iar/mkfile @@ -0,0 +1,18 @@ +<../../mkconfig + +TARG=iar # inferno archiver + +OFILES= ar.$O\ + $TARGMODEL.$O\ + +HFILES= ../include/a.out.h\ + ../../include/bio.h\ + ../include/mach.h\ + +LIBS=mach bio 9 # libbio.a uses lib9.a so order matters. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/idea/NOTICE b/utils/idea/NOTICE new file mode 100644 index 00000000..48e4162a --- /dev/null +++ b/utils/idea/NOTICE @@ -0,0 +1,27 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 2002 Vita Nuova Holdings Limited (www.vitanuova.com) + +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. diff --git a/utils/idea/idea.c b/utils/idea/idea.c new file mode 100644 index 00000000..0db0591c --- /dev/null +++ b/utils/idea/idea.c @@ -0,0 +1,254 @@ +/* + * Copyright © 2002 Vita Nuova Holdings Limited. All rights reserved. + */ +#include <lib9.h> +#include <bio.h> + +/* CBC, ECB, integrate, SSL */ + +#define KEYLEN 52 + +#define MODA 0x10000 +#define MODM 0x10001 +#define MASKA (MODA-1) + +#define OP1(x, y) ((x) ^ (y)) +#define OP2(x, y) (((x) + (y)) & MASKA) +#define OP3(x, y) mod(x, y) + +#define OP2INV(x) (-(x)) +#define OP3INV(x) inv(x) + +#define BIGEND(k, i) ((k[i]<<8)|k[i+1]) +#define MSB(x) ((x)>>8) +#define LSB(x) ((x)&0xff) + +static ushort +mod(ushort x, ushort y) +{ + ushort q, r; + uint z; + + if (x == 0) + return 1-y; + if (y == 0) + return 1-x; + z = (uint)x*(uint)y; + q = z >> 16; + r = z & MASKA; + return r-q+(r<q); +} + +static ushort +inv(ushort x) +{ + int q, r0, r1, r2, v0, v1, v2; + + if (x <= 1) + return x; + r0 = MODM; + r1 = x; + v0 = 0; + v1 = 1; + while (r1 != 0) { + q = r0/r1; + r2 = r0-q*r1; + v2 = v0-q*v1; + r0 = r1; + r1 = r2; + v0 = v1; + v1 = v2; + } + if (v0 < 0) + v0 += MODM; + return v0 & MASKA; +} + +static void +idea_key_setup_decrypt(ushort ek[KEYLEN], ushort dk[KEYLEN]) +{ + int i; + + for (i = 0; i < 54; i += 6) { + dk[i] = OP3INV(ek[48-i]); + dk[i+1] = OP2INV(ek[50-i]); + dk[i+2] = OP2INV(ek[49-i]); + dk[i+3] = OP3INV(ek[51-i]); + if (i < 48) { + dk[i+4] = ek[46-i]; + dk[i+5] = ek[47-i]; + } + } +} + +void +idea_key_setup(uchar key[16], ushort ek[2*KEYLEN]) +{ + int i, j; + ushort tmp, *e = ek; + + for (i = 0; i < 8; i++) + ek[i] = BIGEND(key, 2*i); + for (i = 8, j = 1; i < KEYLEN; i++, j++) { + ek[i] = (e[j&7]<<9)|(e[(j+1)&7]>>7); + if (((i+1) & 7) == 0) + e += 8; + } + tmp = ek[49]; + ek[49] = ek[50]; + ek[50] = tmp; + idea_key_setup_decrypt(ek, &ek[KEYLEN]); +} + +void +idea_cipher(ushort key[2*KEYLEN], uchar text[8], int decrypting) +{ + int i; + ushort *k; + ushort x[4]; + ushort tmp, yout, zout; + + k = decrypting ? &key[KEYLEN] : key; + for (i = 0; i < 4; i++) + x[i] = BIGEND(text, 2*i); + for (i = 0; i < 17; i++) { + if (!(i&1)) { /* odd round */ + x[0] = OP3(x[0], k[3*i]); + tmp = OP2(x[2], k[3*i+2]); + x[2] = OP2(x[1], k[3*i+1]); + x[3] = OP3(x[3], k[3*i+3]); + x[1] = tmp; + } + else { + tmp = OP3(k[3*i+1], OP1(x[0], x[1])); + yout = OP3(OP2(tmp, OP1(x[2], x[3])), k[3*i+2]); + zout = OP2(tmp, yout); + x[0] = OP1(x[0], yout); + x[1] = OP1(x[1], yout); + x[2] = OP1(x[2], zout); + x[3] = OP1(x[3], zout); + } + } + for (i = 0; i < 4; i++) { + text[2*i] = MSB(x[i]); + text[2*i+1] = LSB(x[i]); + } +} + +static void +decerr(char *s) +{ + fprint(2, "decrypt error: %s (wrong password ?)\n", s); + exits("decrypt"); +} + +void +main(int argc, char **argv) +{ +/* + uchar key[] = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }; + uchar plain[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 }; + uchar cipher[] = { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 }; + uchar tmp[8]; +*/ + ushort edkey[2*KEYLEN]; + uchar obuf[8], buf[8], key[16]; + long i, m, n, om; + int dec, stdin = 0, stdout = 1; + Biobuf *bin, *bout; + +/* + memcpy(tmp, plain, 8); + idea_key_setup(key, edkey); + idea_cipher(edkey, tmp, 0); + if (memcmp(tmp, cipher, 8)) { + print("encrypt wrong\n"); + exits(""); + } + idea_cipher(edkey, tmp, 1); + if (memcmp(tmp, plain, 8)) { + print("decrypt wrong\n"); + exits(""); + } +*/ + + if((argc != 3 && argc != 4) || (strcmp(argv[1], "-e") != 0 && strcmp(argv[1], "-d") != 0) || strlen(argv[2]) != 16){ + fprint(2, "usage: idea -[e | d] <16 char key> [inputfile]\n"); + exits("usage"); + } + dec = strcmp(argv[1], "-d") == 0; + if(argc == 4){ + char s[128]; + + stdin = open(argv[3], OREAD); + if(stdin < 0){ + fprint(2, "cannot open %s\n", argv[3]); + exits(""); + } + strcpy(s, argv[3]); + if(dec){ + if(strcmp(s+strlen(s)-3, ".id") != 0){ + fprint(2, "input file not a .id file\n"); + exits(""); + } + s[strlen(s)-3] = '\0'; + } + else + strcat(s, ".id"); + stdout = create(s, OWRITE, 0666); + if(stdout < 0){ + fprint(2, "cannot create %s\n", s); + exits(""); + } + } + for(i = 0; i < 16; i++) + key[i] = argv[2][i]; + idea_key_setup(key, edkey); + m = om = 0; + bin = (Biobuf*)malloc(sizeof(Biobuf)); + bout = (Biobuf*)malloc(sizeof(Biobuf)); + Binit(bin, stdin, OREAD); + Binit(bout, stdout, OWRITE); + for(;;){ + n = Bread(bin, &buf[m], 8-m); + if(n <= 0) + break; + m += n; + if(m == 8){ + idea_cipher(edkey, buf, dec); + if(dec){ /* leave last block around */ + if(om > 0) + Bwrite(bout, obuf, 8); + memcpy(obuf, buf, 8); + om = 8; + } + else + Bwrite(bout, buf, 8); + m = 0; + } + } + if(dec){ + if(om != 8) + decerr("no last block"); + if(m != 0) + decerr("last block not 8 bytes long"); + m = obuf[7]; + if(m < 0 || m > 7) + decerr("bad modulus"); + for(i = m; i < 8-1; i++) + if(obuf[i] != 0) + decerr("byte not 0"); + Bwrite(bout, obuf, m); + } + else{ + for(i = m; i < 8; i++) + buf[i] = 0; + buf[7] = m; + idea_cipher(edkey, buf, dec); + Bwrite(bout, buf, 8); + } + Bflush(bout); + Bterm(bin); + Bterm(bout); +} diff --git a/utils/idea/mkfile b/utils/idea/mkfile new file mode 100644 index 00000000..2721022f --- /dev/null +++ b/utils/idea/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=idea + +OFILES= idea.$O\ + +HFILES= + +LIBS=bio 9 # libbio.a uses lib9.a so order matters. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/include/a.out.h b/utils/include/a.out.h new file mode 100644 index 00000000..8c0b7137 --- /dev/null +++ b/utils/include/a.out.h @@ -0,0 +1,45 @@ +typedef struct Exec Exec; +struct Exec +{ + long magic; /* magic number */ + long text; /* size of text segment */ + long data; /* size of initialized data */ + long bss; /* size of uninitialized data */ + long syms; /* size of symbol table */ + long entry; /* entry point */ + long spsz; /* size of pc/sp offset table */ + long pcsz; /* size of pc/line number table */ +}; + + +#define HDR_MAGIC 0x00008000 /* header expansion */ + +#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7)) +#define A_MAGIC _MAGIC(0, 8) /* 68020 */ +#define I_MAGIC _MAGIC(0, 11) /* intel 386 */ +#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */ +#define K_MAGIC _MAGIC(0, 13) /* sparc */ +#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */ +#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */ +#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */ +#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */ +#define E_MAGIC _MAGIC(0, 20) /* arm */ +#define Q_MAGIC _MAGIC(0, 21) /* powerpc */ +#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */ +#define L_MAGIC _MAGIC(0, 23) /* dec alpha */ +#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */ +#define U_MAGIC _MAGIC(0, 25) /* sparc64 */ +#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */ + +#define MIN_MAGIC 8 +#define MAX_MAGIC 26 /* <= 90 */ + +#define DYN_MAGIC 0x80000000 /* or'd in for dynamically loaded modules */ + +typedef struct Sym Sym; +struct Sym +{ + long value; + char type; + char *name; +}; diff --git a/utils/include/ar.h b/utils/include/ar.h new file mode 100644 index 00000000..cd538fab --- /dev/null +++ b/utils/include/ar.h @@ -0,0 +1,17 @@ +#define ARMAG "!<arch>\n" +#define SARMAG 8 + +#define ARFMAG "`\n" +#define SARNAME 16 + +struct ar_hdr +{ + char name[SARNAME]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char fmag[2]; +}; +#define SAR_HDR (SARNAME+44) diff --git a/utils/include/mach.h b/utils/include/mach.h new file mode 100644 index 00000000..f809aa2d --- /dev/null +++ b/utils/include/mach.h @@ -0,0 +1,295 @@ +/* + * Architecture-dependent application data + */ +#include "a.out.h" +/* + * Supported architectures: + * mips, + * 68020, + * i386, + * sparc, + * i960 (limited) + * 3210DSP (limited) + * mips2 (R4000) + * arm (limited) + */ +enum +{ + MMIPS, /* machine types */ + MSPARC, + M68020, + MI386, + MI960, + M3210, + MMIPS2, + NMIPS2, + M29000, + MARM, + MPOWER, + /* types of exectables */ + FNONE = 0, /* unidentified */ + FMIPS, /* v.out */ + FMIPSB, /* mips bootable */ + FSPARC, /* k.out */ + FSPARCB, /* Sparc bootable */ + F68020, /* 2.out */ + F68020B, /* 68020 bootable */ + FNEXTB, /* Next bootable */ + FI386, /* 8.out */ + FI386B, /* I386 bootable */ + FI960, /* 6.out */ + FI960B, /* I960 bootable */ + F3210, /* x.out */ + FMIPS2BE, /* 4.out */ + F29000, /* 9.out */ + FARM, /* 5.out */ + FARMB, /* ARM bootable */ + FPOWER, /* q.out */ + FPOWERB, /* power pc bootable */ + FMIPS2LE, /* 4k little endian */ + + ANONE = 0, /* dissembler types */ + AMIPS, + AMIPSCO, /* native mips */ + ASPARC, + ASUNSPARC, /* native sun */ + A68020, + AI386, + AI8086, /* oh god */ + AI960, + A29000, + AARM, + APOWER, + /* object file types */ + Obj68020 = 0, /* .2 */ + ObjSparc, /* .k */ + ObjMips, /* .v */ + Obj386, /* .8 */ + Obj960, /* .6 */ + Obj3210, /* .x */ + ObjMips2, /* .4 */ + Obj29000, /* .9 */ + ObjArm, /* .5 */ + ObjPower, /* .q */ + ObjMips2le, /* .0 */ + Maxobjtype, + + CNONE = 0, /* symbol table classes */ + CAUTO, + CPARAM, + CSTAB, + CTEXT, + CDATA, + CANY /* to look for any class */ +}; + +typedef struct Map Map; +typedef struct Symbol Symbol; +typedef struct Reglist Reglist; +typedef struct Mach Mach; +typedef struct Machdata Machdata; +typedef struct segment segment; + +typedef int (*Rsegio)(segment*, ulong, long, char*, int); + +/* + * Structure to map a segment to a position in a file + */ +struct Map { + int nsegs; /* number of segments */ + struct segment { /* per-segment map */ + char *name; /* the segment name */ + int fd; /* file descriptor */ + int inuse; /* in use - not in use */ + ulong b; /* base */ + ulong e; /* end */ + ulong f; /* offset within file */ + Rsegio mget; /* special get if not 0 */ + Rsegio mput; /* special put if not 0 */ + } seg[1]; /* actually n of these */ +}; + + + +/* + * Internal structure describing a symbol table entry + */ +struct Symbol { + void *handle; /* used internally - owning func */ + /*struct {*/ + char *name; + long value; /* address or stack offset */ + char type; /* as in a.out.h */ + char class; /* as above */ + /*};*/ +}; + +/* + * machine register description + */ +struct Reglist { + char *rname; /* register name */ + short roffs; /* offset in u-block */ + char rflags; /* INTEGER/FLOAT, WRITABLE */ + char rformat; /* print format: 'x', 'X', 'f', '8' */ +}; + +enum { /* bits in rflags field */ + RINT = (0<<0), + RFLT = (1<<0), + RRDONLY = (1<<1) +}; +/* + * Machine-dependent data is stored in two structures: + * Mach - miscellaneous general parameters + * Machdata - jump vector of service functions used by debuggers + * + * Mach is defined in 2.c, 4.c, v.c, k.c, 8.c, 6.c and set in executable.c + * + * Machdata is defined in 2db.c, 4db.c, vdb.c, kdb.c, 8db.c, and 6db.c + * and set in the debugger startup. + */ + + +struct Mach{ + char *name; + int mtype; /* machine type code */ + Reglist *reglist; /* register set */ + ulong regsize; /* sizeof registers in bytes*/ + ulong fpregsize; /* sizeof fp registers in bytes*/ + char *pc; /* pc name */ + char *sp; /* sp name */ + char *link; /* link register name */ + char *sbreg; /* static base register name */ + ulong sb; /* static base register value */ + int pgsize; /* page size */ + ulong kbase; /* kernel base address */ + ulong ktmask; /* ktzero = kbase & ~ktmask */ + int pcquant; /* quantization of pc */ + int szaddr; /* sizeof(void*) */ + int szreg; /* sizeof(register) */ + int szfloat; /* sizeof(float) */ + int szdouble; /* sizeof(double) */ +}; + +extern Mach *mach; /* Current machine */ + +typedef vlong (*Rgetter)(Map*, char*); +typedef void (*Tracer)(Map*, ulong, ulong, Symbol*); + +struct Machdata { /* Machine-dependent debugger support */ + uchar bpinst[4]; /* break point instr. */ + short bpsize; /* size of break point instr. */ + + ushort (*swab)(ushort); /* short to local byte order */ + long (*swal)(long); /* long to local byte order */ + vlong (*swav)(vlong); /* vlong to local byte order */ + int (*ctrace)(Map*, ulong, ulong, ulong, Tracer); /* C traceback */ + ulong (*findframe)(Map*, ulong, ulong, ulong, ulong);/* frame finder */ + char* (*excep)(Map*, Rgetter); /* last exception */ + ulong (*bpfix)(ulong); /* breakpoint fixup */ + int (*sftos)(char*, int, void*); /* single precision float */ + int (*dftos)(char*, int, void*); /* double precision float */ + int (*foll)(Map*, ulong, Rgetter, ulong*); /* follow set */ + int (*das)(Map*, ulong, char, char*, int); /* symbolic disassembly */ + int (*hexinst)(Map*, ulong, char*, int); /* hex disassembly */ + int (*instsize)(Map*, ulong); /* instruction size */ +}; + +/* + * Common a.out header describing all architectures + */ +typedef struct Fhdr +{ + char *name; /* identifier of executable */ + short type; /* file type - see codes above*/ + short hdrsz; /* size of this header */ + long magic; /* magic number */ + long txtaddr; /* text address */ + long entry; /* entry point */ + long txtsz; /* text size */ + long txtoff; /* start of text in file */ + long dataddr; /* start of data segment */ + long datsz; /* size of data seg */ + long datoff; /* offset to data seg in file */ + long bsssz; /* size of bss */ + long symsz; /* size of symbol table */ + long symoff; /* offset of symbol table in file */ + long sppcsz; /* size of sp-pc table */ + long sppcoff; /* offset of sp-pc table in file */ + long lnpcsz; /* size of line number-pc table */ + long lnpcoff; /* size of line number-pc table */ +} Fhdr; + +extern int asstype; /* dissembler type - machdata.c */ +extern Machdata *machdata; /* jump vector - machdata.c */ + +Map* attachproc(int, int, int, Fhdr*); +Map* attachremt(int, Fhdr*); +int beieee80ftos(char*, int, void*); +int beieeesftos(char*, int, void*); +int beieeedftos(char*, int, void*); +ushort beswab(ushort); +long beswal(long); +vlong beswav(vlong); +int cisctrace(Map*, ulong, ulong, ulong, Tracer); +ulong ciscframe(Map*, ulong, ulong, ulong, ulong); +int crackhdr(int fd, Fhdr*); +long file2pc(char*, ulong); +int fileelem(Sym**, uchar *, char*, int); +int fileline(char*, int, ulong); +int filesym(int, char*, int); +int findlocal(Symbol*, char*, Symbol*); +int findseg(Map*, char*); +int findsym(long, int, Symbol *); +int fnbound(long, ulong*); +int fpformat(Map*, Reglist*, char*, int, int); +int get1(Map*, ulong, uchar*, int); +int get2(Map*, ulong, ushort*); +int get4(Map*, ulong, long*); +int get8(Map*, ulong, vlong*); +int getauto(Symbol*, int, int, Symbol*); +Sym* getsym(int); +int globalsym(Symbol *, int); +int gsymoff(char*, int, long, int); +char* _hexify(char*, ulong, int); +int ieeesftos(char*, int, ulong); +int ieeedftos(char*, int, ulong, ulong); +int isar(Biobuf*); +int leieee80ftos(char*, int, void*); +int leieeesftos(char*, int, void*); +int leieeedftos(char*, int, void*); +ushort leswab(ushort); +long leswal(long); +vlong leswav(vlong); +long line2addr(ulong, ulong, ulong); +Map* loadmap(Map*, int, Fhdr*); +int localaddr(Map*, char*, char*, long*, Rgetter); +int localsym(Symbol*, int); +int lookup(char*, char*, Symbol*); +void machbytype(int); +int machbyname(char*); +int nextar(Biobuf*, int, char*); +Map* newmap(Map*, int); +void objtraverse(void(*)(Sym*, void*), void*); +int objtype(Biobuf*, char**); +long pc2sp(ulong); +long pc2line(ulong); +int put1(Map*, ulong, uchar*, int); +int put2(Map*, ulong, ushort); +int put4(Map*, ulong, long); +int put8(Map*, ulong, vlong); +int readar(Biobuf*, int, int, int); +int readobj(Biobuf*, int); +struct segment* reloc(Map*, ulong, long*); +ulong riscframe(Map*, ulong, ulong, ulong, ulong); +int risctrace(Map*, ulong, ulong, ulong, Tracer); +int setmap(Map*, int, ulong, ulong, ulong, char*); +void setmapio(Map*, int, Rsegio, Rsegio); +Sym* symbase(long*); +int syminit(int, Fhdr*); +int symoff(char*, int, long, int); +void textseg(ulong, Fhdr*); +int textsym(Symbol*, int); +void unusemap(Map*, int); + diff --git a/utils/include/regexp.h b/utils/include/regexp.h new file mode 100644 index 00000000..bcd06f3e --- /dev/null +++ b/utils/include/regexp.h @@ -0,0 +1,66 @@ +#pragma src "/usr/inferno/libregexp" +#pragma lib "libregexp.a" + +typedef struct Resub Resub; +typedef struct Reclass Reclass; +typedef struct Reinst Reinst; +typedef struct Reprog Reprog; + +/* + * Sub expression matches + */ +struct Resub{ + union + { + char *sp; + Rune *rsp; + }s; + union + { + char *ep; + Rune *rep; + }e; +}; + +/* + * character class, each pair of rune's defines a range + */ +struct Reclass{ + Rune *end; + Rune spans[64]; +}; + +/* + * Machine instructions + */ +struct Reinst{ + int type; + union { + Reclass *cp; /* class pointer */ + Rune r; /* character */ + int subid; /* sub-expression id for RBRA and LBRA */ + Reinst *right; /* right child of OR */ + }u1; + union { /* regexp relies on these two being in the same union */ + Reinst *left; /* left child of OR */ + Reinst *next; /* next instruction for CAT & LBRA */ + }u2; +}; + +/* + * Reprogram definition + */ +struct Reprog{ + Reinst *startinst; /* start pc */ + Reclass class[16]; /* .data */ + Reinst firstinst[5]; /* .text */ +}; + +extern Reprog *regcomp(char*); +extern Reprog *regcomplit(char*); +extern Reprog *regcompnl(char*); +extern void regerror(char*); +extern int regexec(Reprog*, char*, Resub*, int); +extern void regsub(char*, char*, Resub*, int); +extern int rregexec(Reprog*, Rune*, Resub*, int); +extern void rregsub(Rune*, Rune*, Resub*, int); diff --git a/utils/ka/a.h b/utils/ka/a.h new file mode 100644 index 00000000..05016089 --- /dev/null +++ b/utils/ka/a.h @@ -0,0 +1,181 @@ +#include <lib9.h> +#include <bio.h> +#include "../kc/k.out.h" + + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#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; + char* macro; + long value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym *sym; + long offset; + short type; + short reg; + short xreg; + short name; + double dval; + char sval[8]; +}; + +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 int nosched; +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* alloc(long); +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 pinit(char*); +void cclean(void); +void outcode(int, Gen*, int, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, 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 outhist(void); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); +int assemble(char*); + +/* + * system-dependent stuff from ../cc/compat.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); diff --git a/utils/ka/a.y b/utils/ka/a.y new file mode 100644 index 00000000..4d927203 --- /dev/null +++ b/utils/ka/a.y @@ -0,0 +1,734 @@ +%{ +#include "a.h" +%} +%union +{ + Sym *sym; + long lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LMOVW LMOVD LMOVB LSWAP LADDW LCMP +%token <lval> LBRA LFMOV LFCONV LFADD LCPOP LTRAP LJMPL LXORW +%token <lval> LNOP LEND LRETT LUNIMP LTEXT LDATA LRETRN +%token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH +%token <lval> LREG LFREG LR LC LF +%token <lval> LFSR LFPQ LPSR LSCHED +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr pointer offset sreg +%type <gen> addr rreg name psr creg freg +%type <gen> imm ximm fimm rel fsr fpq +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| LSCHED ';' + { + nosched = $1; + } +| ';' +| inst ';' +| error ';' + +inst: +/* + * B.1 load integer instructions + */ + LMOVW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.2 load floating instructions + * includes CSR + */ +| LMOVD addr ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV addr ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV fimm ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV freg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW addr ',' fsr + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.3 load coprocessor instructions + * excludes CSR + */ +| LMOVW addr ',' creg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD addr ',' creg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.4 store integer instructions + */ +| LMOVW rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW imm ',' addr + { + if($2.offset != 0) + yyerror("constant must be zero"); + outcode($1, &$2, NREG, &$4); + } +| LMOVD rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB imm ',' addr + { + if($2.offset != 0) + yyerror("constant must be zero"); + outcode($1, &$2, NREG, &$4); + } +/* + * B.5 store floating instructions + * includes CSR and CQ + */ +| LMOVW freg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD freg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW fsr ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD fpq ',' addr + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.6 store coprocessor instructions + * excludes CSR and CQ + */ +| LMOVW creg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD creg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.7 atomic load unsigned byte (TAS) + * B.8 swap + */ +| LSWAP addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.9 add instructions + * B.10 tagged add instructions + * B.11 subtract instructions + * B.12 tagged subtract instructions + * B.13 multiply step instruction + * B.14 logical instructions + * B.15 shift instructions + * B.17 save/restore + */ +| LADDW rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LADDW imm ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LADDW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LADDW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LXORW rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LXORW imm ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LXORW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LXORW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.16 set hi + * other pseudo moves + */ +| LMOVW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW ximm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVD ximm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.18 branch on integer condition + * B.19 floating point branch on condition + * B.20 coprocessor branch on condition + */ +| LBRA comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * B.21 call instruction + * B.22 jump and link instruction + */ +| LJMPL comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +| LJMPL comma addr + { + outcode($1, &nullgen, NREG, &$3); + } +| LJMPL comma sreg ',' rel + { + outcode($1, &nullgen, $3, &$5); + } +| LJMPL comma sreg ',' addr + { + outcode($1, &nullgen, $3, &$5); + } +/* + * B.23 return from trap + */ +| LRETT rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.28 instruction cache flush + */ +| LFLUSH rel comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LFLUSH addr comma + { + outcode($1, &$2, NREG, &nullgen); + } +/* + * B.24 trap on condition + */ +| LTRAP rreg ',' sreg + { + outcode($1, &$2, $4, &nullgen); + } +| LTRAP imm ',' sreg + { + outcode($1, &$2, $4, &nullgen); + } +| LTRAP rreg comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LTRAP comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +/* + * B.25 read state register instructions + */ +| LMOVW psr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * B.26 write state register instructions BOTCH XOR + */ +| LMOVW rreg ',' psr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW imm ',' psr + { + outcode($1, &$2, NREG, &$4); + } +| LXORW rreg ',' sreg ',' psr + { + outcode($1, &$2, $4, &$6); + } +| LXORW imm ',' sreg ',' psr + { + outcode($1, &$2, $4, &$6); + } +/* + * B.27 unimplemented trap + */ +| LUNIMP comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LUNIMP imm comma + { + outcode($1, &$2, NREG, &nullgen); + } +/* + * B.29 floating point operate + */ +| LFCONV freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFADD freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFADD freg ',' freg ',' freg + { + outcode($1, &$2, $4.reg, &$6); + } +/* + * B.30 coprocessor operate + */ +| LCPOP creg ',' creg + { + outcode($1, &$2, NREG, &$4); + } +| LCPOP creg ',' creg ',' creg + { + outcode($1, &$2, $4.reg, &$6); + } +/* + * CMP + */ +| LCMP rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LCMP rreg ',' imm + { + outcode($1, &$2, NREG, &$4); + } +/* + * NOP + */ +| LNOP comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LNOP rreg comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LNOP freg comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LNOP ',' rreg + { + outcode($1, &nullgen, NREG, &$3); + } +| LNOP ',' freg + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * END + */ +| LEND comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +/* + * TEXT/GLOBL + */ +| LTEXT name ',' imm + { + outcode($1, &$2, NREG, &$4); + } +| LTEXT name ',' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +/* + * DATA + */ +| LDATA name '/' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +| LDATA name '/' con ',' ximm + { + outcode($1, &$2, $4, &$6); + } +| LDATA name '/' con ',' fimm + { + outcode($1, &$2, $4, &$6); + } +/* + * RETURN + */ +| LRETRN comma + { + outcode($1, &nullgen, NREG, &nullgen); + } + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $1->value + $2; + } + +rreg: + sreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +fsr: + LFSR + { + $$ = nullgen; + $$.type = D_PREG; + $$.reg = $1; + } + +fpq: + LFPQ + { + $$ = nullgen; + $$.type = D_PREG; + $$.reg = $1; + } + +psr: + LPSR + { + $$ = nullgen; + $$.type = D_PREG; + $$.reg = $1; + } + +creg: + LCREG + { + $$ = nullgen; + $$.type = D_CREG; + $$.reg = $1; + } +| LC '(' con ')' + { + $$ = nullgen; + $$.type = D_CREG; + $$.reg = $3; + } + +freg: + LFREG + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } +| LF '(' con ')' + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $3; + } + +ximm: + '$' addr + { + $$ = $2; + $$.type = D_CONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } + +fimm: + '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +imm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } + +sreg: + LREG +| LR '(' con ')' + { + if($$ < 0 || $$ >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +addr: + '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } +| '(' sreg ',' con ')' + { + $$ = nullgen; + $$.type = D_ASI; + $$.reg = $2; + $$.offset = $4; + } +| '(' sreg '+' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.xreg = $4; + $$.offset = 0; + } +| name +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +comma: +| ',' + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/ka/l.s b/utils/ka/l.s new file mode 100644 index 00000000..b982e553 --- /dev/null +++ b/utils/ka/l.s @@ -0,0 +1,696 @@ +/* + * 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 */ + +/* + * PSR bits + */ +#define PSREC 0x00002000 +#define PSREF 0x00001000 +#define PSRSUPER 0x00000080 +#define PSRPSUPER 0x00000040 +#define PSRET 0x00000020 +#define SPL(n) (n<<8) + +/* + * Magic registers + */ + +#define MACH 6 /* R6 is m-> */ +#define USER 5 /* R5 is u-> */ + +/* + * Fundamental addresses + */ + +#define USERADDR 0xE0000000 +#define UREGADDR (USERADDR+BY2PG-((32+6)*BY2WD)) +#define BOOTSTACK (KTZERO-0*BY2PG) +#define TRAPS (KTZERO-2*BY2PG) + +/* + * MMU + */ + +#define VAMASK 0x3FFFFFFF +#define NPMEG (1<<12) +#define BY2SEGM (1<<18) +#define PG2SEGM (1<<6) +#define NTLBPID (1+NCONTEXT) /* TLBPID 0 is unallocated */ +#define NCONTEXT 8 +#define CONTEXT 0x30000000 /* in ASI 2 */ + +/* + * MMU regions + */ +#define INVALIDSEGM 0xFFFC0000 /* highest seg of VA reserved as invalid */ +#define INVALIDPMEG 0x7F +#define SCREENSEGM 0xFFF80000 +#define SCREENPMEG 0x7E +#define ROMSEGM 0xFFE80000 +#define ROMEND 0xFFEA0000 +#define PG2ROM ((ROMEND-ROMSEGM)/BY2PG) +#define IOSEGM0 ROMSEGM /* see mmuinit() */ +#define NIOSEGM ((SCREENSEGM-ROMSEGM)/BY2SEGM) +#define IOPMEG0 (SCREENPMEG-NIOSEGM) +#define IOSEGM ROMEND +#define IOEND SCREENSEGM +#define TOPPMEG IOPMEG0 + +/* + * MMU entries + */ +#define PTEVALID (1<<31) +#define PTERONLY (0<<30) +#define PTEWRITE (1<<30) +#define PTEKERNEL (1<<29) +#define PTENOCACHE (1<<28) +#define PTEMAINMEM (0<<26) +#define PTEIO (1<<26) +#define PTEACCESS (1<<25) +#define PTEMODIFY (1<<24) +#define PTEUNCACHED 0 +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 16 + +#define INVALIDPTE 0 +#define PPN(pa) ((pa>>12)&0xFFFF) + +/* + * Weird addresses in various ASI's + */ +#define CACHETAGS 0x80000000 /* ASI 2 */ +#define CACHEDATA 0x90000000 /* ASI 2 */ +#define SER 0x60000000 /* ASI 2 */ +#define SEVAR 0x60000004 /* ASI 2 */ +#define ASER 0x60000008 /* ASI 2 */ +#define ASEVAR 0x6000000C /* ASI 2 */ +#define ENAB 0x40000000 /* ASI 2 */ +#define ENABCACHE 0x10 +#define ENABRESET 0x04 + +/* + * Virtual addresses + */ +#define VTAG(va) ((va>>22)&0x03F) +#define VPN(va) ((va>>13)&0x1FF) + +#define PARAM ((char*)0x40500000) +#define TLBFLUSH_ 0x01 + +/* + * Address spaces + */ + +#define UZERO 0x00000000 /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define TSTKTOP 0x10000000 /* end of new stack in sysexec */ +#define TSTKSIZ 32 +#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */ +#define KZERO 0xE0000000 /* base of kernel address space */ +#define KTZERO (KZERO+4*BY2PG) /* first address in kernel text */ +#define USTKSIZE (4*1024*1024) /* size of user stack */ + +#define MACHSIZE 4096 + +#define isphys(x) (((ulong)(x)&0xF0000000) == KZERO) + +#define SYSPSR (SPL(0x0)|PSREF|PSRSUPER|0) +#define NOOP OR R0, R0; OR R0, R0; OR R0, R0 + +TEXT start(SB), $-4 + + /* get virtual, fast */ + /* we are executing in segment 0, mapped to pmeg 0. stack is there too */ + /* get virtual by mapping segment(KZERO) to pmeg 0., and next to 1 */ + MOVW $KZERO, R7 + MOVB R0, (R7, 3) + MOVW $(KZERO+BY2SEGM), R7 + MOVW $1, R8 + MOVB R8, (R7, 3) + /* now mapped correctly. jmpl to where we want to be */ + MOVW $setSB(SB), R2 + MOVW $startvirt(SB), R7 + JMPL (R7) + MOVW $_mul(SB), R0 /* touch _mul etc.; doesn't need to execute */ + RETURN /* can't get here */ + +TEXT startvirt(SB), $-4 + + MOVW $BOOTSTACK, R1 + + MOVW $(SPL(0xF)|PSREF|PSRSUPER), R7 + MOVW R7, PSR + + MOVW $(0x35<<22), R7 /* NVM OFM DZM AU */ + MOVW R7, fsr+0(SB) + MOVW fsr+0(SB), FSR + FMOVD $0.5, F26 /* 0.5 -> F26 */ + FSUBD F26, F26, F24 /* 0.0 -> F24 */ + FADDD F26, F26, F28 /* 1.0 -> F28 */ + FADDD F28, F28, F30 /* 2.0 -> F30 */ + + FMOVD F24, F0 + FMOVD F24, F2 + FMOVD F24, F4 + FMOVD F24, F6 + FMOVD F24, F8 + FMOVD F24, F10 + FMOVD F24, F12 + FMOVD F24, F14 + FMOVD F24, F16 + FMOVD F24, F18 + FMOVD F24, F20 + FMOVD F24, F22 + + MOVW $mach0(SB), R(MACH) +/* MOVW $0x8, R7 /**/ + MOVW R0, WIM + JMPL main(SB) + MOVW (R0), R0 + RETURN + +TEXT swap1(SB), $0 + + TAS (R7), R7 /* LDSTUB, thank you ken */ + RETURN + +TEXT swap1_should_work(SB), $0 + + MOVW R7, R8 + MOVW $1, R7 + SWAP (R8), R7 + RETURN + +TEXT swap1x(SB), $0 + + MOVW PSR, R9 + MOVW R9, R10 + AND $~PSRET, R10 /* BUG: book says this is buggy */ + MOVW R10, PSR + NOOP + MOVW (R7), R7 + CMP R7, R0 + BNE was1 + MOVW $1, R10 + MOVW R10, (R8) +was1: + MOVW R9, PSR + RETURN + +TEXT spllo(SB), $0 + + MOVW PSR, R7 + MOVW R7, R10 + OR $PSRET, R10 + MOVW R10, PSR + NOOP + RETURN + +TEXT splhi(SB), $0 + + MOVW R15, 4(R(MACH)) /* save PC in m->splpc */ + MOVW PSR, R7 + MOVW R7, R10 + AND $~PSRET, R10 /* BUG: book says this is buggy */ + MOVW R10, PSR + NOOP + RETURN + +TEXT splx(SB), $0 + + MOVW R15, 4(R(MACH)) /* save PC in m->splpc */ + MOVW R7, PSR /* BUG: book says this is buggy */ + NOOP + RETURN + +TEXT spldone(SB), $0 + + RETURN + +TEXT touser(SB), $0 + MOVW $(SYSPSR&~PSREF), R8 + MOVW R8, PSR + NOOP + + MOVW R7, R1 + SAVE R0, R0 /* RETT is implicit RESTORE */ + MOVW $(UTZERO+32), R7 /* PC; header appears in text */ + MOVW $(UTZERO+32+4), R8 /* nPC */ + RETT R7, R8 + +TEXT rfnote(SB), $0 + + MOVW R7, R1 /* 1st arg is &uregpointer */ + ADD $4, R1 /* point at ureg */ + JMP restore + +TEXT traplink(SB), $-4 + + /* R8 to R23 are free to play with */ + /* R17 contains PC, R18 contains nPC */ + /* R19 has PSR loaded from vector code */ + + ANDCC $PSRPSUPER, R19, R0 + BE usertrap + +kerneltrap: + /* + * Interrupt or fault from kernel + */ + ANDN $7, R1, R20 /* dbl aligned */ + MOVW R1, (0-(4*(32+6))+(4*1))(R20) /* save R1=SP */ + /* really clumsy: store these in Ureg so can be restored below */ + MOVW R2, (0-(4*(32+6))+(4*2))(R20) /* SB */ + MOVW R5, (0-(4*(32+6))+(4*5))(R20) /* USER */ + MOVW R6, (0-(4*(32+6))+(4*6))(R20) /* MACH */ + SUB $(4*(32+6)), R20, R1 + +trap1: + MOVW Y, R20 + MOVW R20, (4*(32+0))(R1) /* Y */ + MOVW TBR, R20 + MOVW R20, (4*(32+1))(R1) /* TBR */ + AND $~0x1F, R19 /* force CWP=0 */ + MOVW R19, (4*(32+2))(R1) /* PSR */ + MOVW R18, (4*(32+3))(R1) /* nPC */ + MOVW R17, (4*(32+4))(R1) /* PC */ + MOVW R0, (4*0)(R1) + MOVW R3, (4*3)(R1) + MOVW R4, (4*4)(R1) + MOVW R7, (4*7)(R1) + RESTORE R0, R0 + /* now our registers R8-R31 are same as before trap */ + /* save registers two at a time */ + MOVD R8, (4*8)(R1) + MOVD R10, (4*10)(R1) + MOVD R12, (4*12)(R1) + MOVD R14, (4*14)(R1) + MOVD R16, (4*16)(R1) + MOVD R18, (4*18)(R1) + MOVD R20, (4*20)(R1) + MOVD R22, (4*22)(R1) + MOVD R24, (4*24)(R1) + MOVD R26, (4*26)(R1) + MOVD R28, (4*28)(R1) + MOVD R30, (4*30)(R1) + /* SP and SB and u and m are already set; away we go */ + MOVW R1, R7 /* pointer to Ureg */ + SUB $8, R1 + MOVW $SYSPSR, R8 + MOVW R8, PSR + NOOP + JMPL trap(SB) + + ADD $8, R1 +restore: + MOVW (4*(32+2))(R1), R8 /* PSR */ + MOVW R8, PSR + NOOP + + MOVD (4*30)(R1), R30 + MOVD (4*28)(R1), R28 + MOVD (4*26)(R1), R26 + MOVD (4*24)(R1), R24 + MOVD (4*22)(R1), R22 + MOVD (4*20)(R1), R20 + MOVD (4*18)(R1), R18 + MOVD (4*16)(R1), R16 + MOVD (4*14)(R1), R14 + MOVD (4*12)(R1), R12 + MOVD (4*10)(R1), R10 + MOVD (4*8)(R1), R8 + SAVE R0, R0 + MOVD (4*6)(R1), R6 + MOVD (4*4)(R1), R4 + MOVD (4*2)(R1), R2 + MOVW (4*(32+0))(R1), R20 /* Y */ + MOVW R20, Y + MOVW (4*(32+4))(R1), R17 /* PC */ + MOVW (4*(32+3))(R1), R18 /* nPC */ + MOVW (4*1)(R1), R1 /* restore R1=SP */ + RETT R17, R18 + +usertrap: + /* + * Interrupt or fault from user + */ + MOVW R1, R8 + MOVW R2, R9 + MOVW $setSB(SB), R2 + MOVW $(USERADDR+BY2PG), R1 + MOVW R8, (0-(4*(32+6))+(4*1))(R1) /* save R1=SP */ + MOVW R9, (0-(4*(32+6))+(4*2))(R1) /* save R2=SB */ + MOVW R5, (0-(4*(32+6))+(4*5))(R1) /* save R5=USER */ + MOVW R6, (0-(4*(32+6))+(4*6))(R1) /* save R6=MACH */ + MOVW $USERADDR, R(USER) + MOVW $mach0(SB), R(MACH) + SUB $(4*(32+6)), R1 + JMP trap1 + +TEXT syslink(SB), $-4 + + /* R8 to R23 are free to play with */ + /* R17 contains PC, R18 contains nPC */ + /* R19 has PSR loaded from vector code */ + /* assume user did it; syscall checks */ + + MOVW R1, R8 + MOVW R2, R9 + MOVW $setSB(SB), R2 + MOVW $(USERADDR+BY2PG), R1 + MOVW R8, (0-(4*(32+6))+4)(R1) /* save R1=SP */ + SUB $(4*(32+6)), R1 + MOVW R9, (4*2)(R1) /* save R2=SB */ + MOVW R3, (4*3)(R1) /* global register */ + MOVD R4, (4*4)(R1) /* global register, R5=USER */ + MOVD R6, (4*6)(R1) /* save R6=MACH, R7=syscall# */ + MOVW $USERADDR, R(USER) + MOVW $mach0(SB), R(MACH) + MOVW TBR, R20 + MOVW R20, (4*(32+1))(R1) /* TBR */ + AND $~0x1F, R19 + MOVW R19, (4*(32+2))(R1) /* PSR */ + MOVW R18, (4*(32+3))(R1) /* nPC */ + MOVW R17, (4*(32+4))(R1) /* PC */ + RESTORE R0, R0 + /* now our registers R8-R31 are same as before trap */ + MOVW R15, (4*15)(R1) + /* SP and SB and u and m are already set; away we go */ + MOVW R1, R7 /* pointer to Ureg */ + SUB $8, R1 + MOVW $SYSPSR, R8 + MOVW R8, PSR + JMPL syscall(SB) + /* R7 contains return value from syscall */ + + ADD $8, R1 + MOVW (4*(32+2))(R1), R8 /* PSR */ + MOVW R8, PSR + NOOP + + MOVW (4*15)(R1), R15 + SAVE R0, R0 + MOVW (4*6)(R1), R6 + MOVD (4*4)(R1), R4 + MOVD (4*2)(R1), R2 + MOVW (4*(32+4))(R1), R17 /* PC */ + MOVW (4*(32+3))(R1), R18 /* nPC */ + MOVW (4*1)(R1), R1 /* restore R1=SP */ + RETT R17, R18 + +TEXT puttbr(SB), $0 + + MOVW R7, TBR + NOOP + RETURN + +TEXT gettbr(SB), $0 + + MOVW TBR, R7 + RETURN + +TEXT r1(SB), $0 + + MOVW R1, R7 + RETURN + +TEXT getwim(SB), $0 + + MOVW WIM, R7 + RETURN + +TEXT setlabel(SB), $0 + + MOVW R1, (R7) + MOVW R15, 4(R7) + MOVW $0, R7 + RETURN + +TEXT gotolabel(SB), $0 + + MOVW (R7), R1 + MOVW 4(R7), R15 + MOVW $1, R7 + RETURN + +TEXT putcxsegm(SB), $0 + + MOVW R7, R8 /* context */ + MOVW 4(FP), R9 /* segment addr */ + MOVW 8(FP), R10 /* segment value */ + MOVW $0xFFE80118, R7 + JMPL (R7) + RETURN + +TEXT getpsr(SB), $0 + + MOVW PSR, R7 + RETURN + +TEXT putcxreg(SB), $0 + + MOVW $CONTEXT, R8 + MOVB R7, (R8, 2) + RETURN + +TEXT putb2(SB), $0 + + MOVW 4(FP), R8 + MOVB R8, (R7, 2) + RETURN + +TEXT getb2(SB), $0 + + MOVB (R7, 2), R7 + RETURN + +TEXT getw2(SB), $0 + + MOVW (R7, 2), R7 + RETURN + +TEXT putw2(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 2) + RETURN + +TEXT putw4(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 4) + RETURN + +TEXT getw4(SB), $0 + + MOVW (R7, 4), R7 + RETURN + +TEXT putwC(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 0xC) + RETURN + +TEXT putwD(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 0xD) + RETURN + +TEXT putwD16(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xD) + RETURN + +TEXT putwE(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 0xE) + RETURN + +TEXT putwE16(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + ADD $(1<<4), R7 + MOVW R8, (R7, 0xE) + RETURN + +TEXT putsegm(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, 3) + RETURN + +/* + * in savefpregs and restfpregs, incoming R7 points to doubleword + * below where F0 will go; doubleword align in and backfill FSR + */ +TEXT savefpregs(SB), $0 + + ADD $8, R7 + ANDN $7, R7 /* now MOVD-aligned */ + MOVW FSR, -4(R7) + + MOVD F0, (0*4)(R7) + MOVD F2, (2*4)(R7) + MOVD F4, (4*4)(R7) + MOVD F6, (6*4)(R7) + MOVD F8, (8*4)(R7) + MOVD F10, (10*4)(R7) + MOVD F12, (12*4)(R7) + MOVD F14, (14*4)(R7) + MOVD F16, (16*4)(R7) + MOVD F18, (18*4)(R7) + MOVD F20, (20*4)(R7) + MOVD F22, (22*4)(R7) + MOVD F24, (24*4)(R7) + MOVD F26, (26*4)(R7) + MOVD F28, (28*4)(R7) + MOVD F30, (30*4)(R7) + + MOVW PSR, R8 + ANDN $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT restfpregs(SB), $0 + + MOVW PSR, R8 + OR $PSREF, R8 + MOVW R8, PSR + + ADD $8, R7 + ANDN $7, R7 /* now MOVD-aligned */ + OR R0, R0 + + MOVW -4(R7), FSR + + MOVD (0*4)(R7), F0 + MOVD (2*4)(R7), F2 + MOVD (4*4)(R7), F4 + MOVD (6*4)(R7), F6 + MOVD (8*4)(R7), F8 + MOVD (10*4)(R7), F10 + MOVD (12*4)(R7), F12 + MOVD (14*4)(R7), F14 + MOVD (16*4)(R7), F16 + MOVD (18*4)(R7), F18 + MOVD (20*4)(R7), F20 + MOVD (22*4)(R7), F22 + MOVD (24*4)(R7), F24 + MOVD (26*4)(R7), F26 + MOVD (28*4)(R7), F28 + MOVD (30*4)(R7), F30 + + ANDN $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT clearfpintr(SB), $0 + + MOVW $fpq+BY2WD(SB), R7 + ANDN $0x7, R7 /* must be D aligned */ + MOVW $fsr+0(SB), R9 +clrq: + MOVD FQ, (R7) + MOVW FSR, (R9) + MOVW (R9), R8 + AND $(1<<13), R8 /* queue not empty? */ + BNE clrq + RETURN + +TEXT getfsr(SB), $0 + MOVW $fsr+0(SB), R7 + MOVW FSR, (R7) + MOVW (R7), R7 + RETURN + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL fpq+0(SB), $(3*BY2WD) +GLOBL fsr+0(SB), $BY2WD diff --git a/utils/ka/lex.c b/utils/ka/lex.c new file mode 100644 index 00000000..39c8b507 --- /dev/null +++ b/utils/ka/lex.c @@ -0,0 +1,722 @@ +#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 = 'k'; + thestring = "sparc"; + 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, + + "FSR", LFSR, D_FSR, + "CSR", LFSR, D_CSR, + + "FQ", LFPQ, D_FPQ, + "CQ", LFPQ, D_CPQ, + + "Y", LPSR, D_Y, + "PSR", LPSR, D_PSR, + "WIM", LPSR, D_WIM, + "TBR", LPSR, D_TBR, + + "R", LR, 0, + "R0", LREG, 0, + "R1", LREG, 1, + "R2", LREG, 2, + "R3", LREG, 3, + "R4", LREG, 4, + "R5", LREG, 5, + "R6", LREG, 6, + "R7", LREG, 7, + "R8", LREG, 8, + "R9", LREG, 9, + "R10", LREG, 10, + "R11", LREG, 11, + "R12", LREG, 12, + "R13", LREG, 13, + "R14", LREG, 14, + "R15", LREG, 15, + "R16", LREG, 16, + "R17", LREG, 17, + "R18", LREG, 18, + "R19", LREG, 19, + "R20", LREG, 20, + "R21", LREG, 21, + "R22", LREG, 22, + "R23", LREG, 23, + "R24", LREG, 24, + "R25", LREG, 25, + "R26", LREG, 26, + "R27", LREG, 27, + "R28", LREG, 28, + "R29", LREG, 29, + "R30", LREG, 30, + "R31", LREG, 31, + + "C", LC, 0, + "C0", LCREG, 0, + "C1", LCREG, 1, + "C2", LCREG, 2, + "C3", LCREG, 3, + "C4", LCREG, 4, + "C5", LCREG, 5, + "C6", LCREG, 6, + "C7", LCREG, 7, + "C8", LCREG, 8, + "C9", LCREG, 9, + "C10", LCREG, 10, + "C11", LCREG, 11, + "C12", LCREG, 12, + "C13", LCREG, 13, + "C14", LCREG, 14, + "C15", LCREG, 15, + "C16", LCREG, 16, + "C17", LCREG, 17, + "C18", LCREG, 18, + "C19", LCREG, 19, + "C20", LCREG, 20, + "C21", LCREG, 21, + "C22", LCREG, 22, + "C23", LCREG, 23, + "C24", LCREG, 24, + "C25", LCREG, 25, + "C26", LCREG, 26, + "C27", LCREG, 27, + "C28", LCREG, 28, + "C29", LCREG, 29, + "C30", LCREG, 30, + "C31", LCREG, 31, + + "F", LF, 0, + "F0", LFREG, 0, + "F2", LFREG, 2, + "F4", LFREG, 4, + "F6", LFREG, 6, + "F8", LFREG, 8, + "F10", LFREG, 10, + "F12", LFREG, 12, + "F14", LFREG, 14, + "F16", LFREG, 16, + "F18", LFREG, 18, + "F20", LFREG, 20, + "F22", LFREG, 22, + "F24", LFREG, 24, + "F26", LFREG, 26, + "F28", LFREG, 28, + "F30", LFREG, 30, + "F1", LFREG, 1, + "F3", LFREG, 3, + "F5", LFREG, 5, + "F7", LFREG, 7, + "F9", LFREG, 9, + "F11", LFREG, 11, + "F13", LFREG, 13, + "F15", LFREG, 15, + "F17", LFREG, 17, + "F19", LFREG, 19, + "F21", LFREG, 21, + "F23", LFREG, 23, + "F25", LFREG, 25, + "F27", LFREG, 27, + "F29", LFREG, 29, + "F31", LFREG, 31, + + "ADD", LADDW, AADD, + "ADDCC", LADDW, AADDCC, + "ADDX", LADDW, AADDX, + "ADDXCC", LADDW, AADDXCC, + "AND", LADDW, AAND, + "ANDCC", LADDW, AANDCC, + "ANDN", LADDW, AANDN, + "ANDNCC", LADDW, AANDNCC, + "BA", LBRA, ABA, + "BCC", LBRA, ABCC, + "BCS", LBRA, ABCS, + "BE", LBRA, ABE, + "BG", LBRA, ABG, + "BGE", LBRA, ABGE, + "BGU", LBRA, ABGU, + "BL", LBRA, ABL, + "BLE", LBRA, ABLE, + "BLEU", LBRA, ABLEU, + "BN", LBRA, ABN, + "BNE", LBRA, ABNE, + "BNEG", LBRA, ABNEG, + "BPOS", LBRA, ABPOS, + "BVC", LBRA, ABVC, + "BVS", LBRA, ABVS, + "CB0", LBRA, ACB0, + "CB01", LBRA, ACB01, + "CB012", LBRA, ACB012, + "CB013", LBRA, ACB013, + "CB02", LBRA, ACB02, + "CB023", LBRA, ACB023, + "CB03", LBRA, ACB03, + "CB1", LBRA, ACB1, + "CB12", LBRA, ACB12, + "CB123", LBRA, ACB123, + "CB13", LBRA, ACB13, + "CB2", LBRA, ACB2, + "CB23", LBRA, ACB23, + "CB3", LBRA, ACB3, + "CBA", LBRA, ACBA, + "CBN", LBRA, ACBN, + "CMP", LCMP, ACMP, + "CPOP1", LCPOP, ACPOP1, + "CPOP2", LCPOP, ACPOP2, + "DATA", LDATA, ADATA, + "DIV", LADDW, ADIV, + "DIVL", LADDW, ADIVL, + "END", LEND, AEND, + "FABSD", LFCONV, AFABSD, + "FABSF", LFCONV, AFABSF, + "FABSX", LFCONV, AFABSX, + "FADDD", LFADD, AFADDD, + "FADDF", LFADD, AFADDF, + "FADDX", LFADD, AFADDX, + "FBA", LBRA, AFBA, + "FBE", LBRA, AFBE, + "FBG", LBRA, AFBG, + "FBGE", LBRA, AFBGE, + "FBL", LBRA, AFBL, + "FBLE", LBRA, AFBLE, + "FBLG", LBRA, AFBLG, + "FBN", LBRA, AFBN, + "FBNE", LBRA, AFBNE, + "FBO", LBRA, AFBO, + "FBU", LBRA, AFBU, + "FBUE", LBRA, AFBUE, + "FBUG", LBRA, AFBUG, + "FBUGE", LBRA, AFBUGE, + "FBUL", LBRA, AFBUL, + "FBULE", LBRA, AFBULE, + "FCMPD", LFADD, AFCMPD, + "FCMPED", LFADD, AFCMPED, + "FCMPEF", LFADD, AFCMPEF, + "FCMPEX", LFADD, AFCMPEX, + "FCMPF", LFADD, AFCMPF, + "FCMPX", LFADD, AFCMPX, + "FDIVD", LFADD, AFDIVD, + "FDIVF", LFADD, AFDIVF, + "FDIVX", LFADD, AFDIVX, + "FMOVD", LFMOV, AFMOVD, + "FMOVDF", LFCONV, AFMOVDF, + "FMOVDW", LFCONV, AFMOVDW, + "FMOVDX", LFCONV, AFMOVDX, + "FMOVF", LFMOV, AFMOVF, + "FMOVFD", LFCONV, AFMOVFD, + "FMOVFW", LFCONV, AFMOVFW, + "FMOVFX", LFCONV, AFMOVFX, + "FMOVWD", LFCONV, AFMOVWD, + "FMOVWF", LFCONV, AFMOVWF, + "FMOVWX", LFCONV, AFMOVWX, + "FMOVX", LFCONV, AFMOVX, + "FMOVXD", LFCONV, AFMOVXD, + "FMOVXF", LFCONV, AFMOVXF, + "FMOVXW", LFCONV, AFMOVXW, + "FMULD", LFADD, AFMULD, + "FMULF", LFADD, AFMULF, + "FMULX", LFADD, AFMULX, + "FNEGD", LFCONV, AFNEGD, + "FNEGF", LFCONV, AFNEGF, + "FNEGX", LFCONV, AFNEGX, + "FSQRTD", LFCONV, AFSQRTD, + "FSQRTF", LFCONV, AFSQRTF, + "FSQRTX", LFCONV, AFSQRTX, + "FSUBD", LFADD, AFSUBD, + "FSUBF", LFADD, AFSUBF, + "FSUBX", LFADD, AFSUBX, + "GLOBL", LTEXT, AGLOBL, + "IFLUSH", LFLUSH, AIFLUSH, + "JMPL", LJMPL, AJMPL, + "JMP", LJMPL, AJMP, + "MOD", LADDW, AMOD, + "MODL", LADDW, AMODL, + "MOVB", LMOVB, AMOVB, + "MOVBU", LMOVB, AMOVBU, + "MOVD", LMOVD, AMOVD, + "MOVH", LMOVB, AMOVH, + "MOVHU", LMOVB, AMOVHU, + "MOVW", LMOVW, AMOVW, + "MUL", LADDW, AMUL, + "MULSCC", LADDW, AMULSCC, + "NOP", LNOP, ANOP, + "OR", LADDW, AOR, + "ORCC", LADDW, AORCC, + "ORN", LADDW, AORN, + "ORNCC", LADDW, AORNCC, + "RESTORE", LADDW, ARESTORE, + "RETT", LRETT, ARETT, + "RETURN", LRETRN, ARETURN, + "SAVE", LADDW, ASAVE, + "SLL", LADDW, ASLL, + "SRA", LADDW, ASRA, + "SRL", LADDW, ASRL, + "SUB", LADDW, ASUB, + "SUBCC", LADDW, ASUBCC, + "SUBX", LADDW, ASUBX, + "SUBXCC", LADDW, ASUBXCC, + "SWAP", LSWAP, ASWAP, + "TA", LTRAP, ATA, + "TADDCC", LADDW, ATADDCC, + "TADDCCTV", LADDW, ATADDCCTV, + "TAS", LSWAP, ATAS, + "TCC", LTRAP, ATCC, + "TCS", LTRAP, ATCS, + "TE", LTRAP, ATE, + "TEXT", LTEXT, ATEXT, + "TG", LTRAP, ATG, + "TGE", LTRAP, ATGE, + "TGU", LTRAP, ATGU, + "TL", LTRAP, ATL, + "TLE", LTRAP, ATLE, + "TLEU", LTRAP, ATLEU, + "TN", LTRAP, ATN, + "TNE", LTRAP, ATNE, + "TNEG", LTRAP, ATNEG, + "TPOS", LTRAP, ATPOS, + "TSUBCC", LADDW, ATSUBCC, + "TSUBCCTV", LADDW, ATSUBCCTV, + "TVC", LTRAP, ATVC, + "TVS", LTRAP, ATVS, + "UNIMP", LUNIMP, AUNIMP, + "WORD", LUNIMP, AWORD, + "XNOR", LADDW, AXNOR, + "XNORCC", LADDW, AXNORCC, + "XOR", LXORW, AXOR, + "XORCC", LADDW, AXORCC, + + "SCHED", LSCHED, 0, + "NOSCHED", LSCHED, 0x80, + + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.sym = S; + nullgen.offset = 0; + nullgen.type = D_NONE; + nullgen.name = D_NONE; + nullgen.reg = NREG; + nullgen.xreg = NREG; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 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); + 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 +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +void +cclean(void) +{ + + outcode(AEND, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + 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; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + case D_CREG: + case D_PREG: + break; + + case D_OREG: + case D_ASI: + case D_CONST: + case D_BRANCH: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(&obuf, *n); + n++; + } + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +void +outcode(int a, Gen *g1, int reg, Gen *g2) +{ + int sf, st, t; + Sym *s; + + if(pass == 1) + goto out; + if(g1->xreg != NREG) { + if(reg != NREG || g2->xreg != NREG) + yyerror("bad addressing modes"); + reg = g1->xreg; + } else + if(g2->xreg != NREG) { + if(reg != NREG) + yyerror("bad addressing modes"); + reg = g2->xreg; + } +jackpot: + sf = 0; + s = g1->sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g1->name; + 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->sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->name; + 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, reg|nosched); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, sf); + zaddr(g2, 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, 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, 0); + 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" diff --git a/utils/ka/mkfile b/utils/ka/mkfile new file mode 100644 index 00000000..6251c038 --- /dev/null +++ b/utils/ka/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=ka + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../kc/k.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/ka/note b/utils/ka/note new file mode 100644 index 00000000..3ecf7bc7 --- /dev/null +++ b/utils/ka/note @@ -0,0 +1,274 @@ +/* load instructions */ + + LDSB MOVB x, R + LDSBA MOVB x, R, asi + LDSH MOVH x, R + LDSHA MOVH x, R, asi + LDUB MOVBU x, R + LDUBA MOVBU x, R, asi + LDUH MOVHU x, R + LDUHA MOVHU x, R, asi + LD MOVW x, R + LDA MOVW x, R, asi + LDD MOVD x, R + LDDA MOVD x, R, asi + +note: x is (R+R) or offset(R) +note: MOVD is a bad name, means double word + +/* load floating */ + + LDF MOVF x, FR + LDDF MOVD x, FR + LDFSR MOVW x, FPSR + +note: MOVF maybe is MOVW + +/* load coprocessor */ + + LDC MOVW x, CR + LDDC MOVD x, CR + LDCSR MOVW x, CPSR + +/* store */ + + STB MOVB R, x + STBA MOVB R, x, asi + STH MOVH R, x + STHA MOVH R, x, asi + ST MOVW R, x + STA MOVW R, x, asi + STD MOVD R, x + STDA MOVD R, x, asi + +/* store floating * + + STF MOVF FR, x + STDF MOVD FR, x + STFSR MOVW FPSR, x + STDFQ MOVD FPQ, x + +note: STDFQ gok + +/* store coprocessor */ + + STC MOVW CR, x + STDC MOVD CR, x + STCSR MOVW CPSR, x + STDCQ MOVD CPQ, x + +/* atomic load/store */ + + LDSTUB TAS x + LDSTUBA TAS x, asi + +/* swap */ + + SWAP SWAP R, x + SWAPA SWAP R, x, asi + +/* calc */ + + ADD ADDW y,R, R + ADDcc ADDWT y,R, R + ADDX ADDC y,R, R + ADDXcc ADDCT y,R, R + TADDcc + TADDccTV + SUB + SUBcc + SUBX + SUBXcc + TSUBcc + TSUBccTV + MULScc + AND + ANDcc + ANDN + ANDNcc + OR + ORcc + ORN + ORNcc + XOR + XORcc + XNOR + XNORcc + SLL + SRL + SRA + +note: y is R or $simm13 + +/* sethi */ + + SETHI MOVW $c, R /* high 22 bits */ + +/* save/restore (same as add) */ + + SAVE SAVE y,R, R + RESTORE RESTORE y,R, R + +/* branch on cc */ + + BA + BN + BNE + BE + BG + BLE + BGE + BL + BGU + BLEU + BCC + BCS + BPOS + BNEG + BVC + BVS + +note: annul bit? + +/* branch on fcc */ + + FBA + FBN + FBU + FBG + FBUG + FBL + FBUL + FBLG + FBNE + FBE + FBUE + FBGE + FBUGE + FBLE + FBULE + FBO + +note: annul bit? + +/* branch on coprocecssor cc */ + + CBA + CBN + CB3 + CB2 + CB23 + CB1 + CB13 + CB12 + CB123 + CB0 + CB03 + CB02 + CB023 + CB01 + CB013 + CB012 + +note: annul bit? + +/* call */ + + CALL + JAL x, R + +/* return from trap */ + + RETT x + +/* trap on integer cc */ + + TA + TN + TNE + TE + TG + TLE + TGE + TL + TGU + TLEU + TCC + TCS + TPOS + TNEG + TVC + TVS + +/* read state register */ + + RDY MOVW Y, R + RDPSR MOVW PSR, R + RDWIM MOVW WIM, R + RDTBR MOVW TBR, R + +/* write state register */ + + WRY MOVW R, Y + WRPSR MOVW R, PSR + WRWIM MOVW R, WIM + WRTBR MOVW R, TBR + +/* unimplemented */ + + UNIMP $C22 + +/* instruction cache flush */ + + IFLUSH x + +/* floating op */ + + FiTOs + FiTOd + FiTOx + + FsTOi + FdTOi + FxTOi + + FsTOd + FsTOx + FdTOs + FdTOx + FxTOs + FxTOd + + FMOVs + FNEGs + FABSs + + FSQRTs + FSQRTd + FSQRTx + + FADDs + FADDd + FADDx + FSUBs + FSUBd + FSUBx + + FMULs + FMULd + FMULx + FDIVs + FDIVd + FDIVx + + FCMPs + FCMPd + FCMPx + FCMPEs + FCMPEd + FCMPEx + +/* coprocessor op */ + + CPop1 + CPop2 diff --git a/utils/kc/cgen.c b/utils/kc/cgen.c new file mode 100644 index 00000000..e4e54d48 --- /dev/null +++ b/utils/kc/cgen.c @@ -0,0 +1,1087 @@ +#include "gc.h" + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o; + long v, curs; + + 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(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED) { + if(nn != Z || r->addable < INDEXED) { + 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) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OADD: + case OSUB: + case OAND: + case OOR: + case OXOR: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(l, nn); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OMUL: + case OLMUL: + case OLDIV: + case OLMOD: + case ODIV: + case OMOD: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + if(debug['M']) + print("%L multiply\n", n->lineno); + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, &nod1, Z, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, n, nn); + cgen(r, &nod); + } else { + regalloc(&nod, n, nn); + cgen(r, &nod); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + regalloc(&nod1, n, Z); + gopcode(OAS, &nod2, Z, &nod1); + gopcode(o, &nod, &nod1, &nod); + gopcode(OAS, &nod, Z, &nod2); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + asbitop: + regalloc(&nod4, n, nn); + regalloc(&nod3, r, Z); + if(l->complex >= r->complex) { + bitload(l, &nod, &nod1, &nod2, &nod4); + cgen(r, &nod3); + } else { + cgen(r, &nod3); + bitload(l, &nod, &nod1, &nod2, &nod4); + } + gmove(&nod, &nod4); + gopcode(n->op, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + break; + + case OIND: + if(nn == Z) { + cgen(l, nn); + break; + } + regialloc(&nod, n, nn); + r = l; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { + /* both null, gen l->nn */ + cgen(l, nn); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (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(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + 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; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + 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(n->op == OCONST) { + o = vconst(n); + if(!true) + o = !o; + gbranch(OGOTO); + if(o) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + } + regalloc(&nod, n, nn); + cgen(n, &nod); + o = ONE; + if(true) + o = comrel[relindex(o)]; + if(typefd[n->type->etype]) { + nodreg(&nod1, n, NREG+FREGZERO); + gopcode(o, &nod, Z, &nod1); + } else + gopcode(o, &nod, Z, nodconst(0)); + regfree(&nod); + goto com; + + case OCOMMA: + cgen(l, Z); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(sconst(r)) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod, Z, r); + regfree(&nod); + goto com; + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + gopcode(o, &nod1, Z, &nod); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1L), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0L), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + nod1.xoffset += SZ_LONG; + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + + regfree(&nod1); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && nn->complex >= FNX) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + cgen(&nod0, Z); + } + break; + + case OAS: + if(nn == Z) { + if(n->addable < INDEXED) + sugen(n->right, n->left, w); + break; + } + /* BOTCH -- functions can clobber rathole */ + sugen(n->right, nodrat, w); + warn(n, "non-interruptable temporary"); + sugen(nodrat, n->left, w); + sugen(nodrat, nn, w); + break; + + case OFUNC: + if(nn == Z) { + sugen(n, nodrat, w); + break; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + } + + w /= SZ_LONG; + if(w <= 5) { + layout(&nod1, &nod2, w, 0, Z); + goto out; + } + + /* + * minimize space for unrolling loop + * 3,4,5 times. (6 or more is never minimum) + * if small structure, try 2 also. + */ + c = 0; /* set */ + m = 100; + i = 3; + if(w <= 15) + i = 2; + for(; i<=5; i++) + if(i + w%i <= m) { + c = i; + m = c + w%c; + } + + regalloc(&nod3, ®node, Z); + layout(&nod1, &nod2, w%c, w/c, &nod3); + + pc1 = pc; + layout(&nod1, &nod2, c, 0, Z); + + gopcode(OSUB, nodconst(1L), Z, &nod3); + nod1.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1); + nod2.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2); + + gopcode(OGT, &nod3, Z, nodconst(0)); + patch(p, pc1); + + regfree(&nod3); +out: + regfree(&nod1); + regfree(&nod2); +} + +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, ®node, Z); + regalloc(&t2, ®node, Z); + if(c > 0) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(cn != Z) + gopcode(OAS, nodconst(cv), Z, cn); + if(c > 1) { + gopcode(OAS, f, Z, &t2); + f->xoffset += SZ_LONG; + } + if(c > 0) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(c > 1) { + gopcode(OAS, &t2, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + regfree(&t1); + regfree(&t2); +} diff --git a/utils/kc/enam.c b/utils/kc/enam.c new file mode 100644 index 00000000..fd7a8411 --- /dev/null +++ b/utils/kc/enam.c @@ -0,0 +1,175 @@ +char *anames[] = +{ + "XXX", + "ADD", + "ADDCC", + "ADDX", + "ADDXCC", + "AND", + "ANDCC", + "ANDN", + "ANDNCC", + "BA", + "BCC", + "BCS", + "BE", + "BG", + "BGE", + "BGU", + "BL", + "BLE", + "BLEU", + "BN", + "BNE", + "BNEG", + "BPOS", + "BVC", + "BVS", + "CB0", + "CB01", + "CB012", + "CB013", + "CB02", + "CB023", + "CB03", + "CB1", + "CB12", + "CB123", + "CB13", + "CB2", + "CB23", + "CB3", + "CBA", + "CBN", + "CMP", + "CPOP1", + "CPOP2", + "DATA", + "DIV", + "DIVL", + "FABSD", + "FABSF", + "FABSX", + "FADDD", + "FADDF", + "FADDX", + "FBA", + "FBE", + "FBG", + "FBGE", + "FBL", + "FBLE", + "FBLG", + "FBN", + "FBNE", + "FBO", + "FBU", + "FBUE", + "FBUG", + "FBUGE", + "FBUL", + "FBULE", + "FCMPD", + "FCMPED", + "FCMPEF", + "FCMPEX", + "FCMPF", + "FCMPX", + "FDIVD", + "FDIVF", + "FDIVX", + "FMOVD", + "FMOVDF", + "FMOVDW", + "FMOVDX", + "FMOVF", + "FMOVFD", + "FMOVFW", + "FMOVFX", + "FMOVWD", + "FMOVWF", + "FMOVWX", + "FMOVX", + "FMOVXD", + "FMOVXF", + "FMOVXW", + "FMULD", + "FMULF", + "FMULX", + "FNEGD", + "FNEGF", + "FNEGX", + "FSQRTD", + "FSQRTF", + "FSQRTX", + "FSUBD", + "FSUBF", + "FSUBX", + "GLOBL", + "GOK", + "HISTORY", + "IFLUSH", + "JMPL", + "JMP", + "MOD", + "MODL", + "MOVB", + "MOVBU", + "MOVD", + "MOVH", + "MOVHU", + "MOVW", + "MUL", + "MULSCC", + "NAME", + "NOP", + "OR", + "ORCC", + "ORN", + "ORNCC", + "RESTORE", + "RETT", + "RETURN", + "SAVE", + "SLL", + "SRA", + "SRL", + "SUB", + "SUBCC", + "SUBX", + "SUBXCC", + "SWAP", + "TA", + "TADDCC", + "TADDCCTV", + "TAS", + "TCC", + "TCS", + "TE", + "TEXT", + "TG", + "TGE", + "TGU", + "TL", + "TLE", + "TLEU", + "TN", + "TNE", + "TNEG", + "TPOS", + "TSUBCC", + "TSUBCCTV", + "TVC", + "TVS", + "UNIMP", + "WORD", + "XNOR", + "XNORCC", + "XOR", + "XORCC", + "END", + "DYNT", + "INIT", + "SIGNAME", + "LAST" +}; diff --git a/utils/kc/gc.h b/utils/kc/gc.h new file mode 100644 index 00000000..a081f4dd --- /dev/null +++ b/utils/kc/gc.h @@ -0,0 +1,338 @@ +#include "../cc/cc.h" +#include "../kc/k.out.h" + +/* + * kc/sparc + * Sun sparc + */ +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_VLONG 8 +#define SZ_IND 4 +#define SZ_FLOAT 4 +#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 Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + short as; + char reg; +}; +#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 Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +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) + +#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 int hintabsize; +EXTERN long maxargsafe; +EXTERN Multab multab[20]; +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 char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN char reg[NREG+NREG]; +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 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[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void usedset(Node*, int); +void noretval(int); +void xcom(Node*); +void bcomplex(Node*); + +/* + * cgen.c + */ +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nod32const(vlong); +Node* nodfconst(double); +void nodreg(Node*, 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 raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int sval(long); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(Node*, long); +int mulcon1(Node*, long, Node*); +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 Nconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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 regzer(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 copyau1(Prog*, 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); + +/* + * com64.c + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/kc/k.out.h b/utils/kc/k.out.h new file mode 100644 index 00000000..2b3bd7f2 --- /dev/null +++ b/utils/kc/k.out.h @@ -0,0 +1,263 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 32 +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +enum +{ + REGZERO = 0, /* always zero */ + REGSP = 1, /* stack pointer */ + REGSB = 2, /* static pointer */ + REGSB1 = 3, /* (possible) second static pointer */ + REGEXT = 6, /* first external register, grows-- */ + REGRET = 7, /* return register and first temp, grows++ */ + REGTMP = 14, /* used by the loader */ + REGLINK = 15, /* subroutine linkage */ + REGARG = 7, /* first arg passed in */ + + FREGRET = 0, + FREGEXT = 22, /* first external register */ + FREGZERO = 24, /* both float and double */ + FREGHALF = 26, /* double */ + FREGONE = 28, /* double */ + FREGTWO = 30 /* double */ +/* + * GENERAL: + * + * compiler allocates R7 up as temps + * compiler allocates external registers R6 down + * compiler allocates register variables F4-F22 + * compiler allocates external registers F22 down + */ +}; + +enum as +{ + AXXX = 0, + AADD, + AADDCC, + AADDX, + AADDXCC, + AAND, + AANDCC, + AANDN, + AANDNCC, + ABA, + ABCC, + ABCS, + ABE, + ABG, + ABGE, + ABGU, + ABL, + ABLE, + ABLEU, + ABN, + ABNE, + ABNEG, + ABPOS, + ABVC, + ABVS, + ACB0, + ACB01, + ACB012, + ACB013, + ACB02, + ACB023, + ACB03, + ACB1, + ACB12, + ACB123, + ACB13, + ACB2, + ACB23, + ACB3, + ACBA, + ACBN, + ACMP, /* pseudo op */ + ACPOP1, + ACPOP2, + ADATA, + ADIV, + ADIVL, + AFABSD, /* pseudo op */ + AFABSF, + AFABSX, /* pseudo op */ + AFADDD, + AFADDF, + AFADDX, + AFBA, + AFBE, + AFBG, + AFBGE, + AFBL, + AFBLE, + AFBLG, + AFBN, + AFBNE, + AFBO, + AFBU, + AFBUE, + AFBUG, + AFBUGE, + AFBUL, + AFBULE, + AFCMPD, + AFCMPED, + AFCMPEF, + AFCMPEX, + AFCMPF, + AFCMPX, + AFDIVD, + AFDIVF, + AFDIVX, + AFMOVD, /* pseudo op */ + AFMOVDF, + AFMOVDW, + AFMOVDX, + AFMOVF, + AFMOVFD, + AFMOVFW, + AFMOVFX, + AFMOVWD, + AFMOVWF, + AFMOVWX, + AFMOVX, /* pseudo op */ + AFMOVXD, + AFMOVXF, + AFMOVXW, + AFMULD, + AFMULF, + AFMULX, + AFNEGD, /* pseudo op */ + AFNEGF, + AFNEGX, /* pseudo op */ + AFSQRTD, + AFSQRTF, + AFSQRTX, + AFSUBD, + AFSUBF, + AFSUBX, + AGLOBL, + AGOK, + AHISTORY, + AIFLUSH, + AJMPL, + AJMP, + AMOD, + AMODL, + AMOVB, + AMOVBU, + AMOVD, + AMOVH, + AMOVHU, + AMOVW, + AMUL, + AMULSCC, + ANAME, + ANOP, + AOR, + AORCC, + AORN, + AORNCC, + ARESTORE, + ARETT, + ARETURN, + ASAVE, + ASLL, + ASRA, + ASRL, + ASUB, + ASUBCC, + ASUBX, + ASUBXCC, + ASWAP, + ATA, + ATADDCC, + ATADDCCTV, + ATAS, + ATCC, + ATCS, + ATE, + ATEXT, + ATG, + ATGE, + ATGU, + ATL, + ATLE, + ATLEU, + ATN, + ATNE, + ATNEG, + ATPOS, + ATSUBCC, + ATSUBCCTV, + ATVC, + ATVS, + AUNIMP, + AWORD, + AXNOR, + AXNORCC, + AXOR, + AXORCC, + AEND, + ADYNT, + AINIT, + ASIGNAME, + ALAST +}; + +/* type/name */ +enum +{ + D_GOK = 0, + D_NONE, + +/* name */ + D_EXTERN, + D_STATIC, + D_AUTO, + D_PARAM, + +/* type */ + D_BRANCH, + D_OREG, + D_ASI, + D_CONST, + D_FCONST, + D_SCONST, + D_REG, + D_FREG, + D_CREG, + D_PREG, + D_FILE, + D_FILE1, + +/* reg names iff type is D_PREG */ + D_CPQ = 0, + D_CSR, + D_FPQ, + D_FSR, + D_PSR, + D_TBR, + D_WIM, + D_Y +}; + +/* + * 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 */ +}; diff --git a/utils/kc/list.c b/utils/kc/list.c new file mode 100644 index 00000000..3538c621 --- /dev/null +++ b/utils/kc/list.c @@ -0,0 +1,229 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('D', Dconv); + fmtinstall('B', Bconv); +} + +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; + int a; + + p = va_arg(fp->args, Prog*); + a = p->as; + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a <= AEND) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(F%d)(REG)", a, a->reg); + break; + + case D_CREG: + sprint(str, "C%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(C%d)(REG)", a, a->reg); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<NSNAME; i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/kc/mkenam b/utils/kc/mkenam new file mode 100644 index 00000000..e0857f17 --- /dev/null +++ b/utils/kc/mkenam @@ -0,0 +1,17 @@ +ed - ../kc/k.out.h <<'!' +v/^ A/d +g/^ AEND/s//&,/ +g/[ ]*=.*,/s//,/ +v/,/p +,s/^ A/ "/ +,s/,.*$/",/ +1i +char *anames[] = +{ +. +,a +}; +. +w enam.c +Q +! diff --git a/utils/kc/mkfile b/utils/kc/mkfile new file mode 100644 index 00000000..26f16f10 --- /dev/null +++ b/utils/kc/mkfile @@ -0,0 +1,32 @@ +<../../mkconfig + +TARG=kc + +OFILES=\ + peep.$O\ + reg.$O\ + cgen.$O\ + enam.$O\ + list.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + mul.$O\ + +HFILES=\ + gc.h\ + k.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/kc/mul.c b/utils/kc/mul.c new file mode 100644 index 00000000..17e19be6 --- /dev/null +++ b/utils/kc/mul.c @@ -0,0 +1,609 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3 /* r0 has not been used */ +}; + +Multab* +mulcon0(Node *n, long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; g<nelem(multab); g++) { + if(m->val == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("%L: multiply table failure %ld\n", n->lineno, v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=6; g++) { + if(g >= 6 && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("%L: multiply table failure (g=%d h=%s) %ld\n", + n->lineno, g, hint, v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(n, v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<<c, r1)) + goto out; + break; + case 1: + if(docode(hp, cp, r1<<c, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r0, r0<<c)) + goto out; + break; + case 3: + if(docode(hp, cp, r0, r1<<c)) + goto out; + break; + } + } + break; + + case '+': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0+r1, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0+r1)) + goto out; + break; + } + } + break; + + case '-': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0-r1, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r1-r0, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0-r1)) + goto out; + break; + case 6: + if(docode(hp, cp, r0, r1-r0)) + goto out; + break; + } + } + break; + + case 0: + if(r0 == mulval) + return 1; + } + return 0; + +out: + cp[-1] = i+'0'; + return 1; +} + +static int +gen1(int len) +{ + int i; + + for(shmax=1; shmax<30; shmax++) { + valmax = 1<<shmax; + if(valmax >= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<<i)) { + *--mulcp = 'a'+i; + return 1; + } + return 0; +} + +static int +gen2(int len, long r1) +{ + int i; + + if(len <= 0) { + if(r1 == mulval) + return 1; + return 0; + } + + len--; + if(len == 0) + goto calcr0; + + if(gen3(len, r1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, r1-1, r1, UR0)) { + i = '-'; + goto out; + } + if(gen3(len, 1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, 1, r1-1, UR1)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + if(mulval == r1+1) { + i = '+'; + goto out; + } + if(mulval == r1-1) { + i = '-'; + goto out; + } + return 0; + +out: + *--mulcp = i; + return 1; +} + +static int +gen3(int len, long r0, long r1, int flag) +{ + int i, f1, f2; + long x; + + if(r0 <= 0 || + r0 >= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x >= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/kc/peep.c b/utils/kc/peep.c new file mode 100644 index 00000000..da6c1449 --- /dev/null +++ b/utils/kc/peep.c @@ -0,0 +1,691 @@ +#include "gc.h" + +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; + } + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVW || p->as == AFMOVF || p->as == AFMOVD) + if(regtyp(&p->to)) { + if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + if(regzer(&p->from)) + if(p->to.type == D_REG) { + p->from.type = D_REG; + p->from.reg = 0; + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +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; +} + +regzer(Adr *a) +{ + + if(a->type == D_CONST) + if(a->sym == S) + if(a->offset == 0) + return 1; + if(a->type == D_REG) + if(a->reg == 0) + return 1; + return 0; +} + +regtyp(Adr *a) +{ + + if(a->type == D_REG) { + if(a->reg != 0) + return 1; + return 0; + } + if(a->type == D_FREG) + 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 AJMPL: + return 0; + + case AADD: + case ASUB: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + + case AFADDD: + case AFADDF: + case AFSUBD: + case AFSUBF: + case AFMULD: + case AFMULF: + case AFDIVD: + case AFDIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AFMOVF: + case AFMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +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); +} + +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("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * 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(" (???)"); + return 2; + + + case ANOP: /* read, write */ + case AMOVW: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + + case AFMOVF: + case AFMOVD: + case AFMOVDW: + case AFMOVWD: + case AFMOVFW: + case AFMOVWF: + case AFMOVFD: + case AFMOVDF: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case AADD: /* read read write */ + case ASUB: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + + case AFADDF: + case AFADDD: + case AFSUBF: + case AFSUBD: + case AFMULF: + case AFMULD: + case AFDIVF: + case AFDIVD: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABA: /* no reference */ + case ABCC: + case ABCS: + case ABE: + case ABG: + case ABGE: + case ABGU: + case ABL: + case ABLE: + case ABLEU: + case ABN: + case ABNE: + case ABNEG: + case ABPOS: + case ABVC: + case ABVS: + case AFBA: + case AFBE: + case AFBG: + case AFBGE: + case AFBL: + case AFBLE: + case AFBNE: + case AFBN: + case AFBLG: + case AFBO: + case AFBU: + case AFBUE: + case AFBUG: + case AFBUGE: + case AFBUL: + case AFBULE: + break; + + case ACMP: /* read read */ + case AFCMPD: + case AFCMPF: + 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 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 ARETURN: /* funny */ + if(v->type == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case AJMPL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) { + if(v->reg <= FREGEXT && v->reg > exfregoffset) + 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; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } + return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + case AADD: + case ASUB: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + return D_REG; + + case AFADDF: + case AFADDD: + case AFSUBF: + case AFSUBD: + case AFMULF: + case AFMULD: + case AFDIVF: + case AFDIVD: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) + if(a->type == D_OREG) + if(v->reg == a->reg) + return 1; + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) + if(p->from.type == v->type || p->to.type == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) + a->reg = s->reg; + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} diff --git a/utils/kc/reg.c b/utils/kc/reg.c new file mode 100644 index 00000000..35c2e7db --- /dev/null +++ b/utils/kc/reg.c @@ -0,0 +1,1121 @@ +#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 = 0; + 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 ARETURN: + case AJMP: + case ARETT: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW); + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + case AMOVW: + case AFMOVF: + case AFMOVD: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case AJMPL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + 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 == ARETURN) + 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\n set = %B; rah = %B; cal = %B\n", + r->prog, r->set, r->refahead, r->calahead); + 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 an 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']) { + if(rgp->regno >= NREG) + print("%L$%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L$%d R%d: %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->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TFLOAT) + p1->as = AFMOVF; + if(v->etype == TDOUBLE) + p1->as = AFMOVD; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBU; + if(v->etype == TUSHORT) + p1->as = AMOVHU; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + n = a->name; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = et; + v->name = n; + 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]; + if(t == D_CONST) { + if(s == S) { + for(z=0; z<BITS; z++) + consts.b[z] |= bit.b[z]; + return bit; + } + if(et != TARRAY) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + return bit; + } + if(t == D_OREG) + 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 AJMPL: + 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 ARETURN: + 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: + i = BtoF(~b); + if(i && r->cost > 0) { + r->regno = i+NREG; + return FtoB(i); + } + 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->to.type == D_FREG && p->as == AMOVW) + change = -CINF; /* cant go Rreg to Freg */ + 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->from.type == D_FREG && p->as == AMOVW) + change = -CINF; /* cant go Rreg to Freg */ + 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(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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + 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->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * bit reg + * 0 R9 + * 1 R10 + * ... ... + * 4 R13 + * 5 R16 + * ... ... + * 20 R31 + */ +long +RtoB(int r) +{ + + if(r >= 9 && r <= 13) + return 1L << (r-9); + if(r >= 16 && r <= 31) + return 1L << (r-11); + return 0; +} + +int +BtoR(long b) +{ + int r; + + b &= 0x001fffffL; + if(b == 0) + return 0; + r = bitno(b) + 9; + if(r >= 14) + r += 2; + return r; +} + +/* + * bit reg + * 22 F4 + * 23 F6 + * ... ... + * 31 F22 + */ +long +FtoB(int f) +{ + + if(f < 4 || f > 22 || (f&1)) + return 0; + return 1L << (f/2 + 20); +} + +BtoF(long b) +{ + + b &= 0xffc00000L; + if(b == 0) + return 0; + return bitno(b)*2 - 40; +} diff --git a/utils/kc/sgen.c b/utils/kc/sgen.c new file mode 100644 index 00000000..3836f2f3 --- /dev/null +++ b/utils/kc/sgen.c @@ -0,0 +1,590 @@ +#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)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typesuv[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gopcode(OAS, &nod, Z, &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); + gopcode(OAS, &nod, Z, &nod1); + } + } + + 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); + gbranch(ORETURN); + + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); + + sp->to.offset += maxargsafe; +} + +void +gen(Node *n) +{ + Node *l, nod; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int 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); + 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; + } + 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); /* 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); + 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; + bcomplex(l); + 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 = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int v; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASASHL; + r->vconst = v; + r->type = types[TINT]; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASHL; + r->vconst = v; + r->type = types[TINT]; + } + v = vlog(l); + if(v >= 0) { + n->op = OASHL; + n->left = r; + n->right = l; + r = l; + l = n->left; + r->vconst = v; + r->type = types[TINT]; + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASLSHR; + r->vconst = v; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OLSHR; + r->vconst = v; + r->type = types[TINT]; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + + case OFUNC: + n->complex = FNX; + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + } +} + +void +bcomplex(Node *n) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type != T) { + bool64(n); + boolgen(n, 1, Z); + } else + gbranch(OGOTO); +} diff --git a/utils/kc/swt.c b/utils/kc/swt.c new file mode 100644 index 00000000..6b812c2f --- /dev/null +++ b/utils/kc/swt.c @@ -0,0 +1,715 @@ +#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; + Node tn; + + 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(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); + regalloc(&tn, ®node, Z); + swit1(iq, nc, def, n, &tn); + regfree(&tn); +} + +void +swit1(C1 *q, int nc, long def, Node *n, Node *tn) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; i<nc; i++) { + if(sval(q->val)) { + gopcode(OEQ, n, Z, nodconst(q->val)); + } else { + gopcode(OSUB, nodconst(q->val), n, tn); + gopcode(OEQ, tn, Z, nodconst(0)); + } + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); + return; + } + i = nc / 2; + r = q+i; + if(sval(r->val)) { + gopcode(OGT, n, Z, nodconst(r->val)); + sp = p; + } else { + gopcode(OSUB, nodconst(r->val), n, tn); + gopcode(OGT, tn, Z, nodconst(0)); + sp = p; + } + gbranch(OGOTO); + p->as = ABE; + patch(p, r->label); + swit1(q, i, def, n, tn); + + patch(sp, pc); + swit1(r+1, nc-i-1, def, n, tn); +} + +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); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, nodconst(0L)); + p->from.offset += nstring - NSNAME; + p->reg = NSNAME; + p->to.type = D_SCONST; + memmove(p->to.sval, string, NSNAME); + mnstring = 0; + } + n--; + } + return r; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + 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; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(n, v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + if(v < 0) + gopcode(OSUB, &nod1, nodconst(0), &nod1); + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +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(0)); + p->from.offset += o+e; + p->reg = 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]) { + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + else + gpseudo(ADATA, s, nod32const(a->vconst)); + p->from.offset += o; + p->reg = 4; + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst)); + else + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +void zaddr(Biobuf*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + 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++; + } + } + outhist(&outbuf); + 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.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, 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.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + firstp = P; + lastp = P; +} + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + long l; + + Bputc(b, p->as); + Bputc(b, p->reg); + l = p->lineno; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + zaddr(b, &p->from, sf); + zaddr(b, &p->to, st); +} + +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, 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; + + zwrite(b, &pg, 0, 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, sig); + Bputc(b, sig>>8); + Bputc(b, sig>>16); + Bputc(b, sig>>24); + s->sig = SIGDONE; + } + else + Bputc(b, ANAME); /* 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; + char *n; + Ieee e; + + Bputc(b, a->type); + Bputc(b, a->reg); + Bputc(b, s); + Bputc(b, a->name); + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_CREG: + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(b, *n); + n++; + } + break; + + case D_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); + break; + } +} + +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; + } + o += SZ_LONG - w; /* big endian adjustment */ + w = 1; + 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; +} diff --git a/utils/kc/txt.c b/utils/kc/txt.c new file mode 100644 index 00000000..71f804ba --- /dev/null +++ b/utils/kc/txt.c @@ -0,0 +1,1269 @@ +#include "gc.h" + +void +ginit(void) +{ + int i; + Type *t; + + thechar = 'k'; + thestring = "sparc"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + 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.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = 0; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + 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(); + + memset(reg, 0, sizeof(reg)); + reg[REGZERO] = 1; + reg[REGLINK] = 1; + reg[REGTMP] = 1; + for(i=NREG; i<NREG+NREG; i+=2) + reg[i+1] = 1; +} + +void +gclean(void) +{ + int i; + Sym *s; + + for(i=0; i<NREG; i++) + if(i != REGZERO && i != REGTMP && i != REGLINK) + if(reg[i]) + diag(Z, "reg %d left allocated", i); + for(i=NREG; i<NREG+NREG; i+=2) + if(reg[i]) + diag(Z, "freg %d left allocated", i-NREG); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + 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; +} + +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(typesuv[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 && typechlp[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + if(vconst(n) == 0) { + regaalloc(tn2, n); + gopcode(OAS, n, Z, tn2); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nod32const(vlong v) +{ + constnode.vconst = v & MASK(32); + return &constnode; +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i, j; + static int lasti; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i > 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<NREG; i++) { + if(j >= NREG) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + case TVLONG: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NREG) + goto out; + } + j = lasti*2 + NREG; + for(i=NREG; i<NREG+NREG; i+=2) { + if(j >= NREG+NREG) + j = NREG; + if(reg[j] == 0) { + i = j; + goto out; + } + j += 2; + } + diag(tn, "out of float registers"); + goto err; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + i = 0; +out: + if(i) + reg[i]++; + lasti++; + if(lasti >= 5) + lasti = 0; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + 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 + SZ_LONG; + 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 +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: <null>"); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +fop(int as, int f1, int f2, Node *t) +{ + Node nod1, nod2, nod3; + + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod; + Prog *p1; + double d; + + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + d = f->fconst; + if(d == 0.0) { + a = FREGZERO; + goto ffreg; + } + if(d == 0.5) { + a = FREGHALF; + goto ffreg; + } + if(d == 1.0) { + a = FREGONE; + goto ffreg; + } + if(d == 2.0) { + a = FREGTWO; + goto ffreg; + } + if(d == -.5) { + fop(OSUB, FREGHALF, FREGZERO, t); + return; + } + if(d == -1.0) { + fop(OSUB, FREGONE, FREGZERO, t); + return; + } + if(d == -2.0) { + fop(OSUB, FREGTWO, FREGZERO, t); + return; + } + if(d == 1.5) { + fop(OADD, FREGONE, FREGHALF, t); + return; + } + if(d == 2.5) { + fop(OADD, FREGTWO, FREGHALF, t); + return; + } + if(d == 3.0) { + fop(OADD, FREGTWO, FREGONE, t); + return; + } + } + if(ft == TFLOAT && f->op == OCONST) { + d = f->fconst; + if(d == 0) { + a = FREGZERO; + ffreg: + nodreg(&nod, f, NREG+a); + gmove(&nod, t); + return; + } + } + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + if(typefd[tt]) { + /* special case can load mem to Freg */ + regalloc(&nod, t, t); + gins(AMOVW, f, &nod); + a = AFMOVWD; + if(tt == TFLOAT) + a = AFMOVWF; + gins(a, &nod, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + a = AMOVW; + break; + case TFLOAT: + a = AFMOVF; + break; + case TDOUBLE: + a = AFMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + } + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + if(typefd[ft]) { + /* special case can store mem from Freg */ + regalloc(&nod, f, Z); + a = AFMOVDW; + if(ft == TFLOAT) + a = AFMOVFW; + gins(a, f, &nod); + gins(AMOVW, &nod, t); + regfree(&nod); + return; + } + a = AMOVW; + break; + case TUCHAR: + a = AMOVBU; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHU; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AFMOVF; + break; + case TVLONG: + case TDOUBLE: + a = AFMOVD; + break; + } + if(!typefd[ft] && vconst(f) == 0) { + gins(a, f, t); + return; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + switch(tt) { + case TDOUBLE: + case TVLONG: + a = AFMOVD; + if(ft == TFLOAT) + a = AFMOVFD; + break; + case TFLOAT: + a = AFMOVDF; + if(ft == TFLOAT) + a = AFMOVF; + break; + case TLONG: + case TULONG: + case TIND: + case TINT: + case TUINT: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + regalloc(&nod, f, Z); /* should be type float */ + a = AFMOVDW; + if(ft == TFLOAT) + a = AFMOVFW; + gins(a, f, &nod); + gins(AFMOVF, &nod, nodrat); + regfree(&nod); + gins(AMOVW, nodrat, t); + gmove(t, t); + if(nrathole < SZ_LONG) + nrathole = SZ_LONG; + return; + } + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + switch(tt) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + goto fxtofl; + case TLONG: + case TULONG: + case TINT: + case TUINT: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + goto fxtofl; + case TUINT: + case TINT: + case TULONG: + case TLONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + goto fxtofl; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + goto fxtofl; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + fxtofl: + regalloc(&nod, t, t); /* should be type float */ + gins(AMOVW, f, nodrat); + gins(AFMOVF, nodrat, &nod); + a = AFMOVWD; + if(tt == TFLOAT) + a = AFMOVWF; + gins(a, &nod, t); + regfree(&nod); + if(nrathole < SZ_LONG) + nrathole = SZ_LONG; + if(ft == TULONG) { + regalloc(&nod, t, Z); + if(tt == TFLOAT) { + gins(AFCMPF, t, Z); + p->to.type = D_FREG; + p->to.reg = FREGZERO; + gins(AFBGE, Z, Z); + p1 = p; + gins(AFMOVF, nodfconst(4294967296.), &nod); + gins(AFADDF, &nod, t); + } else { + gins(AFCMPD, t, Z); + p->to.type = D_FREG; + p->to.reg = FREGZERO; + gins(AFBGE, Z, Z); + p1 = p; + gins(AFMOVD, nodfconst(4294967296.), &nod); + gins(AFADDD, &nod, t); + } + patch(p1, pc); + regfree(&nod); + } + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AFMOVF || a == AFMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, et; + Adr ta; + + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = AADD; + if(et == TFLOAT) + a = AFADDF; + else + if(et == TDOUBLE || et == TVLONG) + a = AFADDD; + break; + + case OASSUB: + case OSUB: + a = ASUB; + if(et == TFLOAT) + a = AFSUBF; + else + if(et == TDOUBLE || et == TVLONG) + a = AFSUBD; + break; + + case OASOR: + case OOR: + a = AOR; + break; + + case OASAND: + case OAND: + a = AAND; + break; + + case OASXOR: + case OXOR: + a = AXOR; + break; + + case OASLSHR: + case OLSHR: + a = ASRL; + break; + + case OASASHR: + case OASHR: + a = ASRA; + break; + + case OASASHL: + case OASHL: + a = ASLL; + break; + + case OFUNC: + a = AJMPL; + break; + + case OASLMUL: + case OLMUL: + case OASMUL: + case OMUL: + if(et == TFLOAT) { + a = AFMULF; + break; + } else + if(et == TDOUBLE || et == TVLONG) { + a = AFMULD; + break; + } + a = AMUL; + break; + + case OASDIV: + case ODIV: + if(et == TFLOAT) { + a = AFDIVF; + break; + } else + if(et == TDOUBLE || et == TVLONG) { + a = AFDIVD; + break; + } + a = ADIV; + break; + + case OASMOD: + case OMOD: + a = AMOD; + break; + + case OASLMOD: + case OLMOD: + a = AMODL; + break; + + case OASLDIV: + case OLDIV: + a = ADIVL; + break; + + case OEQ: + a = ABE; + if(typefd[et]) + a = AFBE; + goto cmp; + + case ONE: + a = ABNE; + if(typefd[et]) + a = AFBLG; + goto cmp; + + case OLT: + a = ABL; + if(typefd[et]) + a = AFBL; + goto cmp; + + case OLE: + a = ABLE; + if(typefd[et]) + a = AFBLE; + goto cmp; + + case OGE: + a = ABGE; + if(typefd[et]) + a = AFBGE; + goto cmp; + + case OGT: + a = ABG; + if(typefd[et]) + a = AFBG; + goto cmp; + + case OLO: + a = ABCS; + goto cmp; + + case OLS: + a = ABLEU; + goto cmp; + + case OHS: + a = ABCC; + goto cmp; + + case OHI: + a = ABGU; + goto cmp; + + cmp: + nextpc(); + p->as = ACMP; + if(et == TFLOAT) + p->as = AFCMPF; + else + if(et == TDOUBLE || et == TVLONG) + p->as = AFCMPD; + if(f1 != Z) + naddr(f1, &p->from); + if(t != Z) + naddr(t, &p->to); + if(f1 == Z || t == Z || f2 != Z) + diag(Z, "bad cmp in gopcode %O", o); + if(debug['g']) + print("%P\n", p); + f1 = Z; + f2 = Z; + t = Z; + break; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + if(ta.type == D_CONST && ta.offset == 0) + p->reg = REGZERO; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +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 = ARETURN; + 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_OREG; + p->from.sym = s; + if(a == ATEXT) + p->reg = (profileflg ? 0 : NOPROF); + p->from.name = D_EXTERN; + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sval(long v) +{ + + if(v >= -(1<<12) && v < (1<<12)) + return 1; + return 0; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= -(vlong)(1<<12) && vv < (vlong)(1<<12)) + return 1; + } + } + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= 3) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 16) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; + +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] */ +}; diff --git a/utils/kl/Nt.c b/utils/kl/Nt.c new file mode 100644 index 00000000..6be99a36 --- /dev/null +++ b/utils/kl/Nt.c @@ -0,0 +1,88 @@ +#include <windows.h> + +/* + * We can't include l.h, because Windoze wants to use some names + * like FLOAT which we declare. Define what we need here. + */ +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; + +extern char *hunk; +extern long nhunk; + +void gethunk(void); + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/kl/Plan9.c b/utils/kl/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/kl/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/kl/Posix.c b/utils/kl/Posix.c new file mode 100644 index 00000000..7c3a661f --- /dev/null +++ b/utils/kl/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fials if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} diff --git a/utils/kl/asm.c b/utils/kl/asm.c new file mode 100644 index 00000000..dde73d6d --- /dev/null +++ b/utils/kl/asm.c @@ -0,0 +1,1237 @@ +#include "l.h" + +#define LPUT(c)\ + {\ + cbp[0] = (c)>>24;\ + cbp[1] = (c)>>16;\ + cbp[2] = (c)>>8;\ + cbp[3] = (c);\ + cbp += 4;\ + cbc -= 4;\ + if(cbc <= 0)\ + cflush();\ + } + +#define CPUT(c)\ + {\ + cbp[0] = (c);\ + cbp++;\ + cbc--;\ + if(cbc <= 0)\ + cflush();\ + } + +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; + if(s->type != STEXT && s->type != SLEAF) + diag("entry not text: %s", s->name); + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long t; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f asm\n", cputime()); + Bflush(&bso); + seek(cout, HEADR, 0); + pc = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + } + if(p->pc != pc) { + diag("phase error %lux sb %lux", + p->pc, pc); + if(!debug['a']) + prasm(curp); + pc = p->pc; + } + curp = p; + o = oplook(p); /* could probably avoid this call */ + if(asmout(p, o, 0)) { + p = p->link; + pc += 4; + } + pc += o->size; + } + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + + curtext = P; + switch(HEADTYPE) { + case 0: + case 3: + seek(cout, HEADR+textsize, 0); + break; + case 1: + case 2: + seek(cout, HEADR+textsize, 0); + break; + } + for(t = 0; t < datsize; t += sizeof(buf)-100) { + if(datsize-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100); + else + datblk(t, datsize-t); + } + + symsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + case 0: + case 3: + seek(cout, HEADR+textsize+datsize, 0); + break; + case 2: + case 1: + seek(cout, HEADR+textsize+datsize, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + /* round up file length for boot image */ + if(HEADTYPE == 0 || HEADTYPE == 3) + if((symsize+lcsize) & 1) + CPUT(0); + cflush(); + } + + seek(cout, 0L, 0); + switch(HEADTYPE) { + case 0: + lput(0x1030107); /* magic and sections */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 1: + break; + case 2: + lput(4*13*13+7); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 3: + lput(0x1030107); /* magic and sections */ + lput(0x90100000); +#define SPARC_NOOP 0x01000000 + lput(SPARC_NOOP); + lput(SPARC_NOOP); + lput(SPARC_NOOP); + lput(SPARC_NOOP); + lput(SPARC_NOOP); + lput(SPARC_NOOP); + break; + } + cflush(); +} + +void +lput(long l) +{ + + LPUT(l); +} + +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 +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->cond) { + s = p->from.sym; + if(s->type != STEXT && s->type != SLEAF) + 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); + + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + else + putsymb(s->name, 'L', 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 +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); + } +} + +#define MINLC 4 +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); +} + +void +datblk(long s, long n) +{ + Prog *p; + char *cast; + long l, fl, j, d; + int i, c; + + memset(buf.dbuf, 0, n+100); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->reg; + 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) { + default: + diag("unknown mode in initialization\n%P", p); + break; + + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (char*)&fl; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i+4]]; + l++; + } + break; + case 8: + cast = (char*)&p->to.ieee; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + for(; i<c; i++) { + buf.dbuf[l] = p->to.sval[i]; + l++; + } + break; + + case D_CONST: + d = p->to.offset; + if(p->to.sym) { + if(p->to.sym->type == STEXT || + p->to.sym->type == SLEAF) + d += p->to.sym->value; + if(p->to.sym->type == SDATA) + d += p->to.sym->value + INITDAT; + if(p->to.sym->type == SBSS) + d += p->to.sym->value + INITDAT; + } + cast = (char*)&d; + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + break; + case 1: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +#define OP2(x) (0x80000000|((x)<<19)) +#define OP3(x) (0xc0000000|((x)<<19)) +#define OPB(x) (0x00800000|((x)<<25)) +#define OPT(x) (0x81d02000|((x)<<25)) +#define OPF1(x) (0x81a00000|((x)<<5)) +#define OPF2(x) (0x81a80000|((x)<<5)) +#define OPFB(x) (0x01800000|((x)<<25)) + +#define OP_RRR(op,r1,r2,r3)\ + (0x00000000 | op |\ + (((r1)&31L)<<0) |\ + (((r2)&31L)<<14) |\ + (((r3)&31L)<<25)) +#define OP_IRR(op,i,r2,r3)\ + (0x00002000L | (op) |\ + (((i)&0x1fffL)<<0) |\ + (((r2)&31L)<<14) |\ + (((r3)&31L)<<25)) +#define OP_BRA(op,pc)\ + ((op) |\ + (((pc)&0x3fffff)<<0)) + +int +asmout(Prog *p, Optab *o, int aflag) +{ + long o1, o2, o3, o4, o5, v; + Prog *ct; + int r; + + o1 = 0; + o2 = 0; + o3 = 0; + o4 = 0; + o5 = 0; + + switch(o->type) { + default: + if(aflag) + return 0; + diag("unknown type %d", o->type); + if(!debug['a']) + prasm(p); + break; + + case 0: /* pseudo ops */ + if(aflag) { + if(p->link) { + if(p->as == ATEXT) { + ct = curtext; + o2 = autosize; + curtext = p; + autosize = p->to.offset + 4; + o1 = asmout(p->link, oplook(p->link), aflag); + curtext = ct; + autosize = o2; + } else + o1 = asmout(p->link, oplook(p->link), aflag); + } + return o1; + } + break; + + case 1: /* mov r1,r2 ==> OR r1,r0,r2 */ + o1 = OP_RRR(opcode(AOR), p->from.reg, REGZERO, p->to.reg); + break; + + case 2: /* mov $c,r ==> add r1,r0,r2 */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = OP_IRR(opcode(AADD), v, r, p->to.reg); + break; + + case 3: /* mov soreg, r */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + if(v == 0 && p->reg != NREG) + o1 = OP_RRR(opcode(p->as), p->reg, r, p->to.reg); + else + o1 = OP_IRR(opcode(p->as), v, r, p->to.reg); + break; + + case 4: /* mov r, soreg */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + if(v == 0 && p->reg != NREG) + o1 = OP_RRR(opcode(p->as+AEND), p->reg, r, p->from.reg); + else + o1 = OP_IRR(opcode(p->as+AEND), v, r, p->from.reg); + break; + + case 5: /* mov $lcon, reg => sethi, add */ + v = regoff(&p->from); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, p->to.reg); + break; + + case 6: /* mov asi, r[+r] */ + o1 = OP_RRR(opcode(p->as), p->reg, p->from.reg, p->to.reg); + o1 |= (1<<23) | ((p->from.offset&0xff)<<5); + break; + + case 7: /* mov [+r]r, asi */ + o1 = OP_RRR(opcode(p->as+AEND), p->reg, p->to.reg, p->from.reg); + o1 |= (1<<23) | ((p->to.offset&0xff)<<5); + break; + + case 8: /* mov r, preg and mov preg, r */ + if(p->to.type == D_PREG) { + r = p->from.reg; + switch(p->to.reg) + { + default: + diag("unknown register P%d", p->to.reg); + case D_Y: + o1 = OP2(48); /* wry */ + break; + case D_PSR: + o1 = OP2(49); /* wrpsr */ + break; + case D_WIM: + o1 = OP2(50); /* wrwim */ + break; + case D_TBR: + o1 = OP2(51); /* wrtbr */ + break; + } + o1 = OP_IRR(o1, 0, r, 0); + break; + } + if(p->from.type == D_PREG) { + r = p->to.reg; + switch(p->from.reg) + { + default: + diag("unknown register P%d", p->to.reg); + case D_Y: + o1 = OP2(40); /* rdy */ + break; + case D_PSR: + o1 = OP2(41); /* rdpsr */ + break; + case D_WIM: + o1 = OP2(42); /* rdwim */ + break; + case D_TBR: + o1 = OP2(43); /* rdtbr */ + break; + } + o1 = OP_RRR(o1, 0, 0, r); + break; + } + break; + + case 9: /* movb r,r */ + v = 24; + if(p->as == AMOVH || p->as == AMOVHU) + v = 16; + r = ASRA; + if(p->as == AMOVBU || p->as == AMOVHU) + r = ASRL; + o1 = OP_IRR(opcode(ASLL), v, p->from.reg, p->to.reg); + o2 = OP_IRR(opcode(r), v, p->to.reg, p->to.reg); + break; + + case 10: /* mov $loreg, reg */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, p->to.reg); + break; + + case 11: /* mov loreg, r */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(opcode(p->as), (v&0x3ff), REGTMP, p->to.reg); + break; + + case 12: /* mov r, loreg */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(opcode(p->as+AEND), (v&0x3ff), REGTMP, p->from.reg); + break; + + case 13: /* mov $ucon, r */ + v = regoff(&p->from); + o1 = 0x1000000 | (p->to.reg<<25) | ((v>>10) & 0x3fffff); /* sethi */ + break; + + case 20: /* op $scon,r */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(opcode(p->as), v, r, p->to.reg); + break; + + case 21: /* op r1,r2 */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_RRR(opcode(p->as), p->from.reg, r, p->to.reg); + break; + + case 22: /* op $lcon,r */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_IRR(opcode(AADD), (v&0x3ff), REGTMP, REGTMP); + o3 = OP_RRR(opcode(p->as), REGTMP, r, p->to.reg); + break; + + case 23: /* cmp r,r */ + o1 = OP_RRR(opcode(ASUBCC), p->to.reg, p->from.reg, REGZERO); + break; + + case 24: /* cmp r,$c */ + v = regoff(&p->to); + o1 = OP_IRR(opcode(ASUBCC), v, p->from.reg, REGZERO); + break; + + case 25: /* cmp $c,r BOTCH, fix compiler */ + v = regoff(&p->from); + o1 = OP_IRR(opcode(AADD), v, NREG, REGTMP); + o2 = OP_RRR(opcode(ASUBCC), p->to.reg, REGTMP, REGZERO); + break; + + case 26: /* op $ucon,r */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(p->as), REGTMP, r, p->to.reg); + break; + + case 30: /* jmp/jmpl soreg */ + if(aflag) + return 0; + v = regoff(&p->to); + r = p->reg; + if(r == NREG && p->as == AJMPL) + r = 15; + o1 = OP_IRR(opcode(AJMPL), v, p->to.reg, r); + break; + + case 31: /* ba jmp */ + if(aflag) + return 0; + r = p->as; + if(r == AJMP) + r = ABA; + v = 0; + if(p->cond) + v = p->cond->pc - p->pc; + o1 = OP_BRA(opcode(r), v/4); + if(r == ABA && p->link && p->cond && isnop(p->link)) { + o2 = asmout(p->cond, oplook(p->cond), 1); + if(o2) { + o1 += 1; + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p); + LPUT(o1); + LPUT(o2); + return 1; + } + /* cant set annul here because pc has already been counted */ + } + break; + + case 32: /* jmpl lbra */ + if(aflag) + return 0; + v = 0; + if(p->cond) + v = p->cond->pc - p->pc; + r = p->reg; + if(r != NREG && r != 15) + diag("cant jmpl other than R15"); + o1 = 0x40000000 | ((v/4) & 0x3fffffffL); /* call */ + if(p->link && p->cond && isnop(p->link)) { + o2 = asmout(p->cond, oplook(p->cond), 1); + if(o2) { + o1 += 1; + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p); + LPUT(o1); + LPUT(o2); + return 1; + } + } + break; + + case 33: /* trap r */ + if(aflag) + return 0; + o1 = opcode(p->as) | (p->from.reg<<14); + break; + + case 34: /* rett r1,r2 -> jmpl (r1); rett (r2) */ + if(aflag) + return 0; + o1 = OP_IRR(opcode(AJMPL), 0, p->from.reg, REGZERO); + o2 = OP_IRR(opcode(ARETT), 0, p->to.reg, REGZERO); + break; + + case 40: /* ldfsr, stfsr, stdq */ + if(p->to.type == D_PREG) { + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + if(p->to.reg == D_FSR) { + o1 = OP_IRR(OP3(33), v, r, 0); + break; + } + diag("unknown reg load %d", p->to.reg); + } else { + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + if(p->from.reg == D_FSR) { + o1 = OP_IRR(OP3(37), v, r, 0); + break; + } + if(p->as == AMOVD && p->from.reg == D_FPQ) { + o1 = OP_IRR(OP3(38), v, r, 0); + break; + } + diag("unknown reg store %d", p->from.reg); + } + break; + + case 41: /* ldf,ldd */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + if(p->as == AFMOVF || p->as == AMOVW) { + o1 = OP_IRR(OP3(32), v, r, p->to.reg); + break; + } + if(p->as == AMOVD || p->as == AFMOVD) { + o1 = OP_IRR(OP3(35), v, r, p->to.reg); + break; + } + diag("only MOVD and MOVW to FREG"); + break; + + case 42: /* ldd -> ldf,ldf */ + /* note should be ldd with proper allignment */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = OP_IRR(OP3(32), v, r, p->to.reg); + o2 = OP_IRR(OP3(32), v+4, r, p->to.reg+1); + break; + + case 43: /* stf */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + if(p->as == AFMOVF || p->as == AMOVW) { + o1 = OP_IRR(OP3(36), v, r, p->from.reg); + break; + } + if(p->as == AMOVD || p->as == AFMOVD) { + o1 = OP_IRR(OP3(39), v, r, p->from.reg); + break; + } + diag("only MOVD and MOVW from FREG"); + break; + + case 44: /* std -> stf,stf */ + /* note should be std with proper allignment */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + o1 = OP_IRR(OP3(36), v, r, p->from.reg); + o2 = OP_IRR(OP3(36), v+4, r, p->from.reg+1); + break; + + case 45: /* ldf lorg */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(OP3(32), v&0x3ff, REGTMP, p->to.reg); + break; + + case 46: /* ldd lorg -> ldf,ldf */ + /* note should be ldd with proper allignment */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(OP3(32), (v&0x3ff), REGTMP, p->to.reg); + o4 = OP_IRR(OP3(32), (v&0x3ff)+4, REGTMP, p->to.reg+1); + break; + + case 47: /* stf lorg */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(OP3(36), v&0x3ff, REGTMP, p->from.reg); + break; + + case 48: /* std lorg -> stf,stf */ + /* note should be std with proper allignment */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + o1 = 0x1000000 | (REGTMP<<25) | ((v>>10) & 0x3fffff); /* sethi */ + o2 = OP_RRR(opcode(AADD), r, REGTMP, REGTMP); + o3 = OP_IRR(OP3(36), (v&0x3ff), REGTMP, p->from.reg); + o4 = OP_IRR(OP3(36), (v&0x3ff)+4, REGTMP, p->from.reg+1); + break; + + case 49: /* fmovd -> fmovf,fmovf */ + o1 = OP_RRR(opcode(AFMOVF), p->from.reg, 0, p->to.reg); + o2 = OP_RRR(opcode(AFMOVF), p->from.reg+1, 0, p->to.reg+1); + break; + + case 50: /* fcmp */ + o1 = OP_RRR(opcode(p->as), p->to.reg, p->from.reg, 0); + break; + + case 51: /* word */ + if(aflag) + return 0; + o1 = regoff(&p->from); + break; + + case 52: /* div */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(opcode(ASRA), 31, r, REGTMP); + o2 = OP_IRR(OP2(48), 0, REGTMP, 0); + o3 = OP_RRR(opcode(ADIV), p->from.reg, r, p->to.reg); + break; + + case 53: /* divl */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(OP2(48), 0, REGZERO, 0); + o2 = OP_RRR(opcode(ADIVL), p->from.reg, r, p->to.reg); + break; + + case 54: /* mod */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(opcode(ASRA), 31, r, REGTMP); + o2 = OP_IRR(OP2(48), 0, REGTMP, 0); + o3 = OP_RRR(opcode(ADIV), p->from.reg, r, REGTMP); + o4 = OP_RRR(opcode(AMUL), p->from.reg, REGTMP, REGTMP); + o5 = OP_RRR(opcode(ASUB), REGTMP, r, p->to.reg); + break; + + case 55: /* modl */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(OP2(48), 0, REGZERO, 0); + o2 = OP_RRR(opcode(ADIVL), p->from.reg, r, REGTMP); + o3 = OP_RRR(opcode(AMUL), p->from.reg, REGTMP, REGTMP); + o4 = OP_RRR(opcode(ASUB), REGTMP, r, p->to.reg); + break; + + case 56: /* b(cc) -- annullable */ + if(aflag) + return 0; + r = p->as; + v = 0; + if(p->cond) + v = p->cond->pc - p->pc; + o1 = OP_BRA(opcode(r), v/4); + if(p->link && p->cond && isnop(p->link)) + if(!debug['A']) { + o2 = asmout(p->cond, oplook(p->cond), 2); + if(o2) { + o1 |= 1<<29; /* annul */ + o1 += 1; + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", p->pc, o1, o2, p); + LPUT(o1); + LPUT(o2); + return 1; + } + } + break; + } + if(aflag) + return o1; + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + LPUT(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + LPUT(o1); + LPUT(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + break; + case 16: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + LPUT(o4); + break; + case 20: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + LPUT(o4); + LPUT(o5); + break; + } + return 0; +} + +int +isnop(Prog *p) +{ + if(p->as != AORN) + return 0; + if(p->reg != REGZERO && p->reg != NREG) + return 0; + if(p->from.type != D_REG || p->from.reg != REGZERO) + return 0; + if(p->to.type != D_REG || p->to.reg != REGZERO) + return 0; + return 1; +} + +long +opcode(int a) +{ + switch(a) { + case AADD: return OP2(0); + case AADDCC: return OP2(16); + case AADDX: return OP2(8); + case AADDXCC: return OP2(24); + + case AMUL: return OP2(10); + case ADIV: return OP2(15); + case ADIVL: return OP2(14); + + case ATADDCC: return OP2(32); + case ATADDCCTV: return OP2(34); + + case ASUB: return OP2(4); + case ASUBCC: return OP2(20); + case ASUBX: return OP2(12); + case ASUBXCC: return OP2(28); + + case ATSUBCC: return OP2(33); + case ATSUBCCTV: return OP2(35); + + case AMULSCC: return OP2(36); + case ASAVE: return OP2(60); + case ARESTORE: return OP2(61); + + case AAND: return OP2(1); + case AANDCC: return OP2(17); + case AANDN: return OP2(5); + case AANDNCC: return OP2(21); + + case AOR: return OP2(2); + case AORCC: return OP2(18); + case AORN: return OP2(6); + case AORNCC: return OP2(22); + + case AXOR: return OP2(3); + case AXORCC: return OP2(19); + case AXNOR: return OP2(7); + case AXNORCC: return OP2(23); + + case ASLL: return OP2(37); + case ASRL: return OP2(38); + case ASRA: return OP2(39); + + case AJMPL: + case AJMP: return OP2(56); + case ARETT: return OP2(57); + + case AMOVBU: return OP3(1); /* ldub */ + case AMOVB: return OP3(9); /* ldsb */ + case AMOVHU: return OP3(2); /* lduh */ + case AMOVH: return OP3(10); /* ldsh */ + case AMOVW: return OP3(0); /* ld */ + case AMOVD: return OP3(3); /* ldd */ + + case AMOVBU+AEND: + case AMOVB+AEND:return OP3(5); /* stb */ + + case AMOVHU+AEND: + case AMOVH+AEND:return OP3(6); /* sth */ + + case AMOVW+AEND:return OP3(4); /* st */ + + case AMOVD+AEND:return OP3(7); /* std */ + + case ASWAP: /* swap is symmetric */ + case ASWAP+AEND:return OP3(15); + + case ATAS: return OP3(13); /* tas is really ldstub */ + + case ABN: return OPB(0); + case ABE: return OPB(1); + case ABLE: return OPB(2); + case ABL: return OPB(3); + case ABLEU: return OPB(4); + case ABCS: return OPB(5); + case ABNEG: return OPB(6); + case ABVS: return OPB(7); + case ABA: return OPB(8); + case ABNE: return OPB(9); + case ABG: return OPB(10); + case ABGE: return OPB(11); + case ABGU: return OPB(12); + case ABCC: return OPB(13); + case ABPOS: return OPB(14); + case ABVC: return OPB(15); + + case AFBA: return OPFB(8); + case AFBE: return OPFB(9); + case AFBG: return OPFB(6); + case AFBGE: return OPFB(11); + case AFBL: return OPFB(4); + case AFBLE: return OPFB(13); + case AFBLG: return OPFB(2); + case AFBN: return OPFB(0); + case AFBNE: return OPFB(1); + case AFBO: return OPFB(15); + case AFBU: return OPFB(7); + case AFBUE: return OPFB(10); + case AFBUG: return OPFB(5); + case AFBUGE: return OPFB(12); + case AFBUL: return OPFB(3); + case AFBULE: return OPFB(14); + + case ATN: return OPT(0); + case ATE: return OPT(1); + case ATLE: return OPT(2); + case ATL: return OPT(3); + case ATLEU: return OPT(4); + case ATCS: return OPT(5); + case ATNEG: return OPT(6); + case ATVS: return OPT(7); + case ATA: return OPT(8); + case ATNE: return OPT(9); + case ATG: return OPT(10); + case ATGE: return OPT(11); + case ATGU: return OPT(12); + case ATCC: return OPT(13); + case ATPOS: return OPT(14); + case ATVC: return OPT(15); + + case AFADDF: return OPF1(65); + case AFADDD: return OPF1(66); + case AFADDX: return OPF1(67); + case AFSUBF: return OPF1(69); + case AFSUBD: return OPF1(70); + case AFSUBX: return OPF1(71); + case AFMULF: return OPF1(73); + case AFMULD: return OPF1(74); + case AFMULX: return OPF1(75); + case AFDIVF: return OPF1(77); + case AFDIVD: return OPF1(78); + case AFDIVX: return OPF1(79); + + case AFMOVF: return OPF1(1); + case AFNEGF: return OPF1(5); + case AFABSF: return OPF1(9); + + case AFSQRTF: return OPF1(41); + case AFSQRTD: return OPF1(42); + case AFSQRTX: return OPF1(43); + + case AFMOVWF: return OPF1(196); + case AFMOVWD: return OPF1(200); + case AFMOVWX: return OPF1(204); + case AFMOVFW: return OPF1(209); + case AFMOVDW: return OPF1(210); + case AFMOVXW: return OPF1(211); + case AFMOVFD: return OPF1(201); + case AFMOVFX: return OPF1(205); + case AFMOVDF: return OPF1(198); + case AFMOVDX: return OPF1(206); + case AFMOVXF: return OPF1(199); + case AFMOVXD: return OPF1(203); + + case AFCMPF: return OPF2(81); + case AFCMPD: return OPF2(82); + case AFCMPX: return OPF2(83); + case AFCMPEF: return OPF2(85); + case AFCMPED: return OPF2(86); + case AFCMPEX: return OPF2(87); + + case AUNIMP: return 0; + } + diag("bad opcode %A", a); + return 0; +} diff --git a/utils/kl/foo.c b/utils/kl/foo.c new file mode 100644 index 00000000..5c8fa36b --- /dev/null +++ b/utils/kl/foo.c @@ -0,0 +1,15 @@ +int foo(void) +{ + return 100; +} + +main() +{ + int x; + + x = foo(); +} + +_main() +{ +} diff --git a/utils/kl/l.h b/utils/kl/l.h new file mode 100644 index 00000000..21ca6294 --- /dev/null +++ b/utils/kl/l.h @@ -0,0 +1,322 @@ +/* #include <u.h> */ +#include <lib9.h> +#include <bio.h> +#include "../kc/k.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Adr Adr; +typedef struct Sym Sym; +typedef struct Autom Auto; +typedef struct Prog Prog; +typedef struct Optab Optab; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Adr +{ + union + { + long u0offset; + char u0sval[NSNAME]; + Ieee u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + char type; + char reg; + char name; + char class; +}; + +#define offset u0.u0offset +#define sval u0.u0sval +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + Prog *forwd; + Prog *cond; + Prog *link; + long pc; + long regused; + short line; + short mark; + uchar optab; + uchar as; + char reg; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + long value; + Sym *link; +}; +struct Autom +{ + Sym *asym; + Auto *link; + long aoffset; + short type; +}; +struct Optab +{ + uchar as; + char a1; + char a2; + char a3; + char type; + char size; + char param; +}; +EXTERN struct +{ + Optab* start; + Optab* stop; +} oprange[AEND]; + +enum +{ + AXLD = AEND+1, + AXST, + FPCHIP = 1, + BIG = 4096-8, + STRINGSZ = 200, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + DATBLK = 1024, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 64, + NENT = 100, + NSCHED = 20, + +/* mark flags */ + LABEL = 1<<0, + LEAF = 1<<1, + FLOAT = 1<<2, + BRANCH = 1<<3, + LOAD = 1<<4, + FCMP = 1<<5, + SYNC = 1<<6, + LIST = 1<<7, + FOLL = 1<<8, + NOSCHED = 1<<9, + + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SLEAF, + SFILE, + SCONST, + + C_NONE = 0, + + C_REG, + C_FREG, + C_CREG, + C_PREG, + C_FSR, + C_FQ, + + C_ZCON, /* 0 */ + C_SCON, /* 13 bit signed */ + C_UCON, /* low 10 bits 0 */ + C_LCON, /* other */ + + C_SACON, + C_SECON, + C_LACON, + C_LECON, + + C_SBRA, + C_LBRA, + + C_ESAUTO, + C_OSAUTO, + C_SAUTO, + C_OLAUTO, + C_ELAUTO, + C_LAUTO, + + C_ESEXT, + C_OSEXT, + C_SEXT, + C_ELEXT, + C_OLEXT, + C_LEXT, + + C_ZOREG, + C_SOREG, + C_LOREG, + C_ASI, + + C_ANY, + + C_GOK, + + C_NCLASS +}; + +EXTERN union +{ + struct + { + uchar obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +EXTERN long HEADR; /* length of header */ +EXTERN int HEADTYPE; /* type of header */ +EXTERN long INITDAT; /* data location */ +EXTERN long INITRND; /* data round above text location */ +EXTERN long INITTEXT; /* text location */ +EXTERN char* INITENTRY; /* entry point */ +EXTERN long autosize; +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN Prog* prog_mul; +EXTERN Prog* prog_div; +EXTERN Prog* prog_divl; +EXTERN Prog* prog_mod; +EXTERN Prog* prog_modl; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* firstp; +EXTERN char fnuxi8[8]; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN char literal[32]; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN char* noname; +EXTERN long instoffset; +EXTERN char* outfile; +EXTERN long pc; +EXTERN long symsize; +EXTERN long staticgen; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long tothunk; +EXTERN char xcmp[C_NCLASS][C_NCLASS]; +EXTERN int version; +EXTERN Prog zprg; +EXTERN int dtype; + +extern Optab optab[]; +extern char* anames[]; + +#pragma varargck type "A" int +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Nconv(Fmt*); +int Pconv(Fmt*); +int Sconv(Fmt*); +int aclass(Adr*); +void addhist(long, int); +void histtoauto(void); +void addnop(Prog*); +void append(Prog*, Prog*); +void asmb(void); +void asmlc(void); +int asmout(Prog*, Optab*, int); +void asmsym(void); +long atolwhex(char*); +Prog* brloop(Prog*); +void buildop(void); +void cflush(void); +int cmp(int, int); +int compound(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +long entryvalue(void); +void errorexit(void); +void exchange(Prog*); +int find1(long, int); +void follow(void); +void gethunk(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +int isnop(Prog*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +void initmuldiv(void); +Sym* lookup(char*, int); +void lput(long); +void mkfwd(void); +void* mysbrk(ulong); +void names(void); +void nocache(Prog*); +void noops(void); +void nuxiinit(void); +void objfile(char*); +int ocmp(const void*, const void*); +long opcode(int); +Optab* oplook(Prog*); +void patch(void); +void prasm(Prog*); +void prepend(Prog*, Prog*); +Prog* prg(void); +int pseudo(Prog*); +void putsymb(char*, int, long, int); +long regoff(Adr*); +int relinv(int); +long rnd(long, long); +void sched(Prog*, Prog*); +void span(void); +void undef(void); +void xdefine(char*, int, long); +void xfol(Prog*); diff --git a/utils/kl/list.c b/utils/kl/list.c new file mode 100644 index 00000000..00fcb7ee --- /dev/null +++ b/utils/kl/list.c @@ -0,0 +1,258 @@ +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], *s; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + curp = p; + a = p->as; + if(a == ADATA || a == AINIT || a == ADYNT) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else{ + s = str; + if(p->mark & NOSCHED) + s += sprint(s, "*"); + if(p->reg == NREG) + sprint(s, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type == D_OREG) { + sprint(s, " %A %ld(R%d+R%d),%D", a, + p->from.offset, p->from.reg, p->reg, &p->to); + } else + if(p->to.type == D_OREG) { + sprint(s, " %A %D,%ld(R%d+R%d)", a, + &p->from, p->to.offset, p->to.reg, p->reg); + } else + if(p->from.type == D_FREG) + sprint(s, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(s, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a <= ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + long v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_ASI: + if(a->reg != NREG) + sprint(str, "(R%d,%ld)", a->reg, a->offset); + else + sprint(str, "(R%d,%ld)", 0, a->offset); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(F%d)(REG)", a, a->reg); + break; + + case D_CREG: + sprint(str, "C%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(C%d)(REG)", a, a->reg); + break; + + case D_PREG: + sprint(str, "P%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(P%d)(REG)", a, a->reg); + break; + + case D_BRANCH: + if(curp->cond != P) { + v = curp->cond->pc; + if(v >= INITTEXT) + v -= INITTEXT-HEADR; + if(a->sym != S) + sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + else + sprint(str, "%.5lux(BRANCH)", v); + } else + if(a->sym != S) + sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + else + sprint(str, "%ld(APC)", a->offset); + break; + + case D_FCONST: + sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(long); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/kl/mkfile b/utils/kl/mkfile new file mode 100644 index 00000000..cf406d8f --- /dev/null +++ b/utils/kl/mkfile @@ -0,0 +1,31 @@ +<../../mkconfig + +CFLAGS=$CFLAGS -I../include + +TARG=kl + +OFILES=\ + asm.$O\ + list.$O\ + noop.$O\ + sched.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + enam.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../kc/k.out.h\ + ../include/ar.h\ + +LIBS=bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +enam.$O: ../kc/enam.c + $CC $CFLAGS ../kc/enam.c diff --git a/utils/kl/noop.c b/utils/kl/noop.c new file mode 100644 index 00000000..23d157f2 --- /dev/null +++ b/utils/kl/noop.c @@ -0,0 +1,650 @@ +#include "l.h" + +void +noops(void) +{ + Prog *p, *p1, *q, *q1; + int o, curframe, curbecome, maxbecome; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + q = P; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + if(p->to.offset > curframe) + curframe = p->to.offset; + + switch(p->as) { + /* too hard, just leave alone */ + 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; + + q = p; + p->mark |= LABEL|LEAF|SYNC; + if(p->link) + p->link->mark |= LABEL; + curtext = p; + break; + + case AORN: + q = p; + if(p->to.type == D_REG) + if(p->to.reg == REGZERO) + p->mark |= LABEL|SYNC; + break; + + case AUNIMP: + case ATAS: + case ASWAP: + case ATA: + case ATCC: + case ATCS: + case ATE: + case ATG: + case ATGE: + case ATGU: + case ATL: + case ATLE: + case ATLEU: + case ATN: + case ATNE: + case ATNEG: + case ATPOS: + case ATVC: + case ATVS: + case AWORD: + q = p; + p->mark |= LABEL|SYNC; + continue; + + case AFABSD: + case AFABSF: + case AFABSX: + case AFADDD: + case AFADDF: + case AFADDX: + case AFDIVD: + case AFDIVF: + case AFDIVX: + case AFMOVD: + case AFMOVDF: + case AFMOVDW: + case AFMOVDX: + case AFMOVF: + case AFMOVFD: + case AFMOVFW: + case AFMOVFX: + case AFMOVWD: + case AFMOVWF: + case AFMOVWX: + case AFMOVX: + case AFMOVXD: + case AFMOVXF: + case AFMOVXW: + case AFMULD: + case AFMULF: + case AFMULX: + case AFNEGD: + case AFNEGF: + case AFNEGX: + case AFSQRTD: + case AFSQRTF: + case AFSQRTX: + case AFSUBD: + case AFSUBF: + case AFSUBX: + q = p; + p->mark |= FLOAT; + continue; + + case AMUL: + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + q = p; + if(!debug['M']) { + if(prog_mul == P) + initmuldiv(); + if(curtext != P) + curtext->mark &= ~LEAF; + } + continue; + + case AJMPL: + if(curtext != P) + curtext->mark &= ~LEAF; + + case AJMP: + + case ABA: + case ABN: + case ABE: + case ABNE: + case ABLE: + case ABG: + case ABL: + case ABGE: + case ABLEU: + case ABGU: + case ABCS: + case ABCC: + case ABNEG: + case ABPOS: + case ABVC: + case ABVS: + + case AFBN: + case AFBO: + case AFBE: + case AFBLG: + case AFBG: + case AFBLE: + case AFBGE: + case AFBL: + case AFBNE: + case AFBUE: + case AFBA: + case AFBU: + case AFBUG: + case AFBULE: + case AFBUGE: + case AFBUL: + p->mark |= BRANCH; + q = p; + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + if(!(q1->mark & LEAF)) + q1->mark |= LABEL; + } else + p->mark |= LABEL; + q1 = p->link; + if(q1 != P) + q1->mark |= LABEL; + continue; + + case AFCMPD: + case AFCMPED: + case AFCMPEF: + case AFCMPEX: + case AFCMPF: + case AFCMPX: + q = p; + p->mark |= FCMP|FLOAT; + continue; + + case ARETURN: + /* special form of RETURN is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + + q = p; + if(p->link != P) + p->link->mark |= LABEL; + continue; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + default: + q = p; + continue; + } + } + 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 AJMPL: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + curtext = P; + for(p = firstp; p != P; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + curtext = p; + autosize = p->to.offset + 4; + if((p->mark & LEAF) && autosize <= 4) + autosize = 0; + else + if(autosize & 4) + autosize += 4; + p->to.offset = autosize - 4; + + q = p; + if(autosize) { + q = prg(); + q->as = ASUB; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } else + if(!(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + curtext->mark |= LEAF; + } + + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; + break; + } + + q1 = prg(); + q1->as = AMOVW; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->from.offset = 0; + q1->to.reg = REGSP; + + q1->link = q->link; + q->link = q1; + break; + + case AMUL: + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + if(debug['M']) + break; + if(p->from.type != D_REG) + break; + if(p->to.type != D_REG) + break; + q1 = p; + + /* MOV a,4(SP) */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->from.reg; + p->to.type = D_OREG; + p->to.reg = REGSP; + p->to.offset = 4; + + /* MOV b,REGTMP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->reg; + if(q1->reg == NREG) + p->from.reg = q1->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMP; + p->to.offset = 0; + + /* CALL appropriate */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AJMPL; + p->line = q1->line; + p->to.type = D_BRANCH; + p->cond = p; + p->mark |= BRANCH; + switch(o) { + case AMUL: + p->cond = prog_mul; + break; + case ADIV: + p->cond = prog_div; + break; + case ADIVL: + p->cond = prog_divl; + break; + case AMOD: + p->cond = prog_mod; + break; + case AMODL: + p->cond = prog_modl; + break; + } + + /* MOV REGTMP, b */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = q1->to.reg; + + /* ADD $8,SP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AADD; + p->from.type = D_CONST; + p->from.reg = NREG; + p->from.offset = 8; + p->reg = NREG; + p->to.type = D_REG; + p->to.reg = REGSP; + + /* SUB $8,SP */ + q1->as = ASUB; + q1->from.type = D_CONST; + q1->from.offset = 8; + q1->from.reg = NREG; + q1->reg = NREG; + q1->to.type = D_REG; + q1->to.reg = REGSP; + break; + + case ARETURN: + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + p->as = AJMP; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 8; + p->to.reg = REGLINK; + p->mark |= BRANCH; + break; + } + + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_OREG; + q->to.offset = 8; + q->to.reg = REGLINK; + q->mark |= BRANCH; + + q->link = p->link; + p->link = q; + break; + } + + p->as = AMOVW; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGRET+1; + + q = p; + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + + q1 = prg(); + q1->as = AJMP; + q1->line = p->line; + q1->to.type = D_OREG; + q1->to.offset = 8; + q1->to.reg = REGRET+1; + q1->mark |= BRANCH; + + q1->link = q->link; + q->link = q1; + break; + + become: + if(curtext->mark & LEAF) { + + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; + } + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->mark |= BRANCH; + q->link = p->link; + p->link = q; + + q = prg(); + q->line = p->line; + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + + p->as = AMOVW; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGLINK; + + break; + } + } + + curtext = P; + q = P; /* p - 1 */ + q1 = firstp; /* top of block */ + o = 0; /* count of instructions */ + for(p = firstp; p != P; p = p1) { + p1 = p->link; + o++; + if(p->mark & NOSCHED){ + if(q1 != p){ + sched(q1, q); + } + for(; p != P; p = p->link){ + if(!(p->mark & NOSCHED)) + break; + q = p; + } + p1 = p; + q1 = p; + o = 0; + continue; + } + if(p->mark & (LABEL|SYNC)) { + if(q1 != p) + sched(q1, q); + q1 = p; + o = 1; + } + if(p->mark & (BRANCH|SYNC)) { + sched(q1, p); + q1 = p1; + o = 0; + } + if(o >= NSCHED) { + sched(q1, p); + q1 = p1; + o = 0; + } + q = p; + } +} + +void +addnop(Prog *p) +{ + Prog *q; + + q = prg(); + q->as = AORN; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGZERO; + q->to.type = D_REG; + q->to.reg = REGZERO; + + q->link = p->link; + p->link = q; +} + +void +initmuldiv(void) +{ + Sym *s1, *s2, *s3, *s4, *s5; + Prog *p; + + s1 = lookup("_mul", 0); + s2 = lookup("_div", 0); + s3 = lookup("_divl", 0); + s4 = lookup("_mod", 0); + s5 = lookup("_modl", 0); + for(p = firstp; p != P; p = p->link) + if(p->as == ATEXT) { + if(p->from.sym == s1) + prog_mul = p; + if(p->from.sym == s2) + prog_div = p; + if(p->from.sym == s3) + prog_divl = p; + if(p->from.sym == s4) + prog_mod = p; + if(p->from.sym == s5) + prog_modl = p; + } + if(prog_mul == P) { + diag("undefined: %s", s1->name); + prog_mul = curtext; + } + if(prog_div == P) { + diag("undefined: %s", s2->name); + prog_div = curtext; + } + if(prog_divl == P) { + diag("undefined: %s", s3->name); + prog_divl = curtext; + } + if(prog_mod == P) { + diag("undefined: %s", s4->name); + prog_mod = curtext; + } + if(prog_modl == P) { + diag("undefined: %s", s5->name); + prog_modl = curtext; + } +} diff --git a/utils/kl/obj.c b/utils/kl/obj.c new file mode 100644 index 00000000..4233326e --- /dev/null +++ b/utils/kl/obj.c @@ -0,0 +1,1277 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = 'k'; +char *thestring = "sparc"; + +/* + * -H0 -T0x200000 -R0 is boot + * -H2 -T4128 -R4096 is plan9 format + * -H3 -T0xE0004000 -R4 is javastation boot format + */ + +void +main(int argc, char *argv[]) +{ + int c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + outfile = 0; + nerrors = 0; + curtext = P; + 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': + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = 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 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + break; + } ARGEND + USED(argc); + if(*argv == 0) { + diag("usage: vl [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 0; + if(debug['B']) + HEADTYPE = 1; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + + case 0: /* boot */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 0x200000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096L; + break; + case 1: /* garbage */ + HEADR = 20L+60L; + if(INITTEXT == -1) + INITTEXT = 0x80020000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* javastation boot */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 0xE0004020L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + 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%d -T0x%lux -D0x%lux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + zprg.as = AGOK; + zprg.reg = NREG; + zprg.from.name = D_NONE; + zprg.from.type = D_NONE; + zprg.from.reg = NREG; + zprg.to = zprg.from; + buildop(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + dtype = 4; + if(outfile == 0) + outfile = "k.out"; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("%s: cannot create", outfile); + errorexit(); + } + nuxiinit(); + 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) + goto out; + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + dodata(); + follow(); + if(firstp == P) + goto out; + noops(); + span(); + asmb(); + undef(); + +out: + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld memory used\n", tothunk); + Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + 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) +{ + + Bflush(&bso); + 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 i, c; + long l; + Sym *s; + Auto *u; + + c = p[2]; + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + p[0] = AEND+1; + return 0; + } + a->type = p[0]; + a->reg = p[1]; + a->sym = h[c]; + a->name = p[3]; + c = 4; + + if(a->reg < 0 || a->reg > NREG) { + print("register out of range %d\n", a->reg); + p[0] = AEND+1; + return 0; /* force real diagnostic */ + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + p[0] = AEND+1; + return 0; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + case D_CREG: + case D_PREG: + break; + + case D_BRANCH: + case D_OREG: + case D_ASI: + case D_CONST: + a->offset = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + c += 4; + break; + + case D_SCONST: + memmove(a->sval, p+4, NSNAME); + c += NSNAME; + break; + + case D_FCONST: + a->ieee.l = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + a->ieee.h = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + } + s = a->sym; + if(s == S) + goto out; + i = a->name; + if(i != D_AUTO && i != D_PARAM) + goto out; + + l = a->offset; + for(u=curauto; u; u=u->link) + if(u->asym == s) + if(u->type == i) { + if(u->aoffset > l) + u->aoffset = l; + goto out; + } + + u = malloc(sizeof(Auto)); + + u->link = curauto; + curauto = u; + u->asym = s; + u->aoffset = l; + u->type = i; +out: + 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) +{ + Prog *p, *t; + Sym *h[NSYM], *s, *di; + int v, o, r, skip; + long ipc; + uchar *bloc, *bsize, *stop; + + bsize = buf.xbuf; + bloc = buf.xbuf; + di = S; + +newloop: + memset(h, 0, sizeof(h)); + histfrogp = 0; + version++; + 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]; /* as */ + if(o <= 0 || o >= ALAST) { + diag("%s: opcode out of range %d", pn, o); + print(" probably not a .k file\n"); + errorexit(); + } + if(o == ANAME || o == ASIGNAME) { + if(o == ASIGNAME) { + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[1]; /* type */ + o = bloc[2]; /* sym */ + bloc += 3; + c -= 3; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 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; + } + + if(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->reg = bloc[1] & 0x7f; + if(bloc[1] & 0x80) + p->mark = NOSCHED; + p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(p->reg < 0 || p->reg > NREG) + diag("register out of range %d", p->reg); + + p->link = P; + p->cond = P; + + if(debug['W']) + print("%P\n", p); + + switch(o) { + 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 == S) { + diag("GLOBL must have a name\n%P", p); + errorexit(); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("redefinition: %s\n%P", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + break; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->reg = 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_CONST; + p->link = datap; + datap = p; + break; + + 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; + p->link = datap; + datap = p; + break; + + case ADATA: + p->link = datap; + datap = p; + break; + + case AGOK: + diag("unknown opcode\n%P", p); + p->pc = pc; + pc++; + break; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + curtext = p; + autosize = (p->to.offset+3L) & ~3L; + p->to.offset = autosize; + autosize += 4; + s = p->from.sym; + if(s == S) { + diag("TEXT must have a name\n%P", p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->reg & DUPOK) { + skip = 1; + goto casedef; + } + diag("redefinition: %s\n%P", s->name, p); + } + s->type = STEXT; + s->value = pc; + if(textp != P) { + for(t = textp; t->cond != P; t = t->cond) + ; + t->cond = p; + } else + textp = p; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + + case AFMOVF: + if(skip) + goto casedef; + + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 4; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AFMOVD: + if(skip) + goto casedef; + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + default: + casedef: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + 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; + hash[h] = s; + return s; +} + +Prog* +prg(void) +{ + Prog *p; + int n; + + n = (sizeof(Prog) + 3) & ~3; + while(nhunk < n) + gethunk(); + + p = (Prog*)hunk; + nhunk -= n; + hunk += n; + + *p = zprg; + return p; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(tothunk >= 5L*NHUNK) { + nh = 5L*NHUNK; + if(tothunk >= 25L*NHUNK) + nh = 25L*NHUNK; + } + h = mysbrk(nh); + if(h == (char *)-1) { + diag("out of memory"); + errorexit(); + } + + hunk = h; + nhunk = nh; + tothunk += 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_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 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 = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_OREG; + p->to.name = 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_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 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->reg = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->reg = 1; + ps4 = p; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + + if(p->reg & 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 = AJMPL; + p->to.type = D_BRANCH; + p->cond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARETURN) { + + /* + * RETURN + */ + q = prg(); + q->as = ARETURN; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * JMPL profout + */ + p->as = AJMPL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x01020304L, i+1); + if(i >= 2) + inuxi2[i-2] = c; + if(i >= 3) + inuxi1[i-3] = c; + inuxi4[i] = c; + + fnuxi8[i] = c+4; + fnuxi8[i+4] = c; + } + 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<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; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->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 |= ieeep->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); +} diff --git a/utils/kl/optab.c b/utils/kl/optab.c new file mode 100644 index 00000000..31892430 --- /dev/null +++ b/utils/kl/optab.c @@ -0,0 +1,199 @@ +#include "l.h" + +#define X 99 + +Optab optab[] = +{ + { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, + { ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0 }, + + { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, + + { AMOVW, C_SCON, C_NONE, C_REG, 2, 4, 0 }, + { AMOVW, C_SACON,C_NONE, C_REG, 2, 4, REGSP }, + { AMOVW, C_SECON,C_NONE, C_REG, 2, 4, REGSB }, + + { AMOVW, C_SOREG,C_NONE, C_REG, 3, 4, 0 }, + { AMOVW, C_ZOREG,C_REG, C_REG, 3, 4, 0 }, + { AMOVW, C_SAUTO,C_NONE, C_REG, 3, 4, REGSP }, + { AMOVW, C_SEXT, C_NONE, C_REG, 3, 4, REGSB }, + { AMOVB, C_SOREG,C_NONE, C_REG, 3, 4, 0 }, + { AMOVB, C_ZOREG,C_REG, C_REG, 3, 4, 0 }, + { AMOVB, C_SAUTO,C_NONE, C_REG, 3, 4, REGSP }, + { AMOVB, C_SEXT, C_NONE, C_REG, 3, 4, REGSB }, + { AMOVD, C_SOREG,C_NONE, C_REG, 3, 4, 0 }, + { AMOVD, C_ZOREG,C_REG, C_REG, 3, 4, 0 }, + { AMOVD, C_SAUTO,C_NONE, C_REG, 3, 4, REGSP }, + { AMOVD, C_SEXT, C_NONE, C_REG, 3, 4, REGSB }, + + { AMOVW, C_REG, C_NONE, C_SOREG, 4, 4, 0 }, + { AMOVW, C_REG, C_REG, C_ZOREG, 4, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_SAUTO, 4, 4, REGSP }, + { AMOVW, C_REG, C_NONE, C_SEXT, 4, 4, REGSB }, + { AMOVB, C_REG, C_NONE, C_SOREG, 4, 4, 0 }, + { AMOVB, C_REG, C_REG, C_ZOREG, 4, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_SAUTO, 4, 4, REGSP }, + { AMOVB, C_REG, C_NONE, C_SEXT, 4, 4, REGSB }, + { AMOVD, C_REG, C_NONE, C_SOREG, 4, 4, 0 }, + { AMOVD, C_REG, C_REG, C_ZOREG, 4, 4, 0 }, + { AMOVD, C_REG, C_NONE, C_SAUTO, 4, 4, REGSP }, + { AMOVD, C_REG, C_NONE, C_SEXT, 4, 4, REGSB }, + + { AMOVW, C_LCON, C_NONE, C_REG, 5, 8, 0 }, + + { AMOVW, C_ASI, C_NONE, C_REG, 6, 4, 0 }, + { AMOVW, C_ASI, C_REG, C_REG, 6, 4, 0 }, + { AMOVB, C_ASI, C_NONE, C_REG, 6, 4, 0 }, + { AMOVB, C_ASI, C_REG, C_REG, 6, 4, 0 }, + { AMOVD, C_ASI, C_NONE, C_REG, 6, 4, 0 }, + { AMOVD, C_ASI, C_REG, C_REG, 6, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_ASI, 7, 4, 0 }, + { AMOVW, C_REG, C_REG, C_ASI, 7, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_ASI, 7, 4, 0 }, + { AMOVB, C_REG, C_REG, C_ASI, 7, 4, 0 }, + { AMOVD, C_REG, C_NONE, C_ASI, 7, 4, 0 }, + { AMOVD, C_REG, C_REG, C_ASI, 7, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_PREG, 8, 4, 0 }, + { AMOVW, C_PREG, C_NONE, C_REG, 8, 4, 0 }, + + { AMOVB, C_REG, C_NONE, C_REG, 9, 8, 0 }, + + { AMOVW, C_LACON,C_NONE, C_REG, 10,12, REGSP }, + { AMOVW, C_LECON,C_NONE, C_REG, 10,12, REGSB }, + + { AMOVW, C_LOREG,C_NONE, C_REG, 11,12, 0 }, + { AMOVW, C_LAUTO,C_NONE, C_REG, 11,12, REGSP }, + { AMOVW, C_LEXT, C_NONE, C_REG, 11,12, REGSB }, + { AMOVB, C_LOREG,C_NONE, C_REG, 11,12, 0 }, + { AMOVB, C_LAUTO,C_NONE, C_REG, 11,12, REGSP }, + { AMOVB, C_LEXT, C_NONE, C_REG, 11,12, REGSB }, + { AMOVD, C_LOREG,C_NONE, C_REG, 11,12, 0 }, + { AMOVD, C_LAUTO,C_NONE, C_REG, 11,12, REGSP }, + { AMOVD, C_LEXT, C_NONE, C_REG, 11,12, REGSB }, + + { AMOVW, C_REG, C_NONE, C_LOREG, 12,12, 0 }, + { AMOVW, C_REG, C_NONE, C_LAUTO, 12,12, REGSP }, + { AMOVW, C_REG, C_NONE, C_LEXT, 12,12, REGSB }, + { AMOVB, C_REG, C_NONE, C_LOREG, 12,12, 0 }, + { AMOVB, C_REG, C_NONE, C_LAUTO, 12,12, REGSP }, + { AMOVB, C_REG, C_NONE, C_LEXT, 12,12, REGSB }, + { AMOVD, C_REG, C_NONE, C_LOREG, 12,12, 0 }, + { AMOVD, C_REG, C_NONE, C_LAUTO, 12,12, REGSP }, + { AMOVD, C_REG, C_NONE, C_LEXT, 12,12, REGSB }, + + { AMOVW, C_UCON, C_NONE, C_REG, 13, 4, 0 }, + + { AADD, C_SCON, C_NONE, C_REG, 20, 4, 0 }, + { AADD, C_SCON, C_REG, C_REG, 20, 4, 0 }, + + { AADD, C_REG, C_NONE, C_REG, 21, 4, 0 }, + { AADD, C_REG, C_REG, C_REG, 21, 4, 0 }, + + { AADD, C_LCON, C_NONE, C_REG, 22,12, 0 }, + { AADD, C_LCON, C_REG, C_REG, 22,12, 0 }, + + { ACMP, C_REG, C_NONE, C_REG, 23, 4, 0 }, + { ACMP, C_REG, C_NONE, C_SCON, 24, 4, 0 }, + { ACMP, C_SCON, C_NONE, C_REG, 25, 8, 0 }, + + { AADD, C_UCON, C_NONE, C_REG, 26, 8, 0 }, + { AADD, C_UCON, C_REG, C_REG, 26, 8, 0 }, + + { AJMP, C_NONE, C_NONE, C_SOREG, 30, 4, 0 }, + { AJMPL, C_NONE, C_NONE, C_SOREG, 30, 4, 0 }, + + { AJMP, C_NONE, C_NONE, C_SBRA, 31, 4, 0 }, + { ABA, C_NONE, C_NONE, C_SBRA, 31, 4, 0 }, + + { AJMPL, C_NONE, C_NONE, C_LBRA, 32, 4, 0 }, + + { ATA, C_REG, C_NONE, C_NONE, 33, 4, 0 }, + { ARETT, C_REG, C_NONE, C_REG, 34, 8, 0 }, + + { AMOVW, C_SOREG,C_NONE, C_FSR, 40, 4, 0 }, + { AMOVW, C_SAUTO,C_NONE, C_FSR, 40, 4, REGSP }, + { AMOVW, C_SEXT, C_NONE, C_FSR, 40, 4, REGSB }, + { AMOVW, C_FSR, C_NONE, C_SOREG, 40, 4, 0 }, + { AMOVW, C_FSR, C_NONE, C_SAUTO, 40, 4, REGSP }, + { AMOVW, C_FSR, C_NONE, C_SEXT, 40, 4, REGSB }, + { AMOVD, C_FQ, C_NONE, C_SOREG, 40, 4, 0 }, + { AMOVD, C_FQ, C_NONE, C_SAUTO, 40, 4, REGSP }, + { AMOVD, C_FQ, C_NONE, C_SEXT, 40, 4, REGSB }, + + { AFMOVF, C_SOREG,C_NONE, C_FREG, 41, 4, 0 }, + { AFMOVF, C_SAUTO,C_NONE, C_FREG, 41, 4, REGSP }, + { AFMOVF, C_SEXT, C_NONE, C_FREG, 41, 4, REGSB }, + { AMOVW, C_SOREG,C_NONE, C_FREG, 41, 4, 0 }, + { AMOVW, C_SAUTO,C_NONE, C_FREG, 41, 4, REGSP }, + { AMOVW, C_SEXT, C_NONE, C_FREG, 41, 4, REGSB }, + { AMOVD, C_SOREG,C_NONE, C_FREG, 41, 4, 0 }, + { AMOVD, C_SAUTO,C_NONE, C_FREG, 41, 4, REGSP }, + { AFMOVD, C_ESAUTO,C_NONE,C_FREG, 41, 4, REGSP }, + { AMOVD, C_SEXT, C_NONE, C_FREG, 41, 4, REGSB }, + { AFMOVD, C_ESEXT,C_NONE, C_FREG, 41, 4, REGSB }, + + { AFMOVD, C_SOREG,C_NONE, C_FREG, 42, 8, 0 }, + { AFMOVD, C_SAUTO,C_NONE, C_FREG, 42, 8, REGSP }, + { AFMOVD, C_SEXT, C_NONE, C_FREG, 42, 8, REGSB }, + + { AFMOVF, C_FREG, C_NONE, C_SOREG, 43, 4, 0 }, + { AFMOVF, C_FREG, C_NONE, C_SAUTO, 43, 4, REGSP }, + { AFMOVF, C_FREG, C_NONE, C_SEXT, 43, 4, REGSB }, + { AMOVW, C_FREG, C_NONE, C_SOREG, 43, 4, 0 }, + { AMOVW, C_FREG, C_NONE, C_SAUTO, 43, 4, REGSP }, + { AMOVW, C_FREG, C_NONE, C_SEXT, 43, 4, REGSB }, + { AMOVD, C_FREG, C_NONE, C_SOREG, 43, 4, 0 }, + { AMOVD, C_FREG, C_NONE, C_SAUTO, 43, 4, REGSP }, + { AFMOVD, C_FREG, C_NONE, C_ESAUTO, 43, 4, REGSP }, + { AMOVD, C_FREG, C_NONE, C_SEXT, 43, 4, REGSB }, + { AFMOVD, C_FREG, C_NONE, C_ESEXT, 43, 4, REGSB }, + + { AFMOVD, C_FREG, C_NONE, C_SOREG, 44, 8, 0 }, + { AFMOVD, C_FREG, C_NONE, C_SAUTO, 44, 8, REGSP }, + { AFMOVD, C_FREG, C_NONE, C_SEXT, 44, 8, REGSB }, + + { AFMOVF, C_LOREG,C_NONE, C_FREG, 45,12, 0 }, + { AFMOVF, C_LAUTO,C_NONE, C_FREG, 45,12, REGSP }, + { AFMOVF, C_LEXT, C_NONE, C_FREG, 45,12, REGSB }, + + { AFMOVD, C_LOREG,C_NONE, C_FREG, 46,16, 0 }, + { AFMOVD, C_LAUTO,C_NONE, C_FREG, 46,16, REGSP }, + { AFMOVD, C_LEXT, C_NONE, C_FREG, 46,16, REGSB }, + + { AFMOVF, C_FREG, C_NONE, C_LOREG, 47,12, 0 }, + { AFMOVF, C_FREG, C_NONE, C_LAUTO, 47,12, REGSP }, + { AFMOVF, C_FREG, C_NONE, C_LEXT, 47,12, REGSB }, + + { AFMOVD, C_FREG, C_NONE, C_LOREG, 48,16, 0 }, + { AFMOVD, C_FREG, C_NONE, C_LAUTO, 48,16, REGSP }, + { AFMOVD, C_FREG, C_NONE, C_LEXT, 48,16, REGSB }, + + { AFMOVD, C_FREG, C_NONE, C_FREG, 49, 8, 0 }, + { AFCMPD, C_FREG, C_NONE, C_FREG, 50, 4, 0 }, + + { AFABSF, C_FREG, C_NONE, C_FREG, 57, 4, 0 }, + { AFMOVF, C_FREG, C_NONE, C_FREG, 57, 4, 0 }, + { AFADDD, C_FREG, C_NONE, C_FREG, 21, 4, 0 }, + { AFADDD, C_FREG, C_REG, C_FREG, 21, 4, 0 }, + + { AWORD, C_LCON, C_NONE, C_NONE, 51, 4, 0 }, + + { ADIV, C_REG, C_NONE, C_REG, 52,12, 0 }, + { ADIV, C_REG, C_REG, C_REG, 52,12, 0 }, + + { ADIVL, C_REG, C_NONE, C_REG, 53, 8, 0 }, + { ADIVL, C_REG, C_REG, C_REG, 53, 8, 0 }, + + { AMOD, C_REG, C_NONE, C_REG, 54,20, 0 }, + { AMOD, C_REG, C_REG, C_REG, 54,20, 0 }, + + { AMODL, C_REG, C_NONE, C_REG, 55,16, 0 }, + { AMODL, C_REG, C_REG, C_REG, 55,16, 0 }, + + { ABE, C_NONE, C_NONE, C_SBRA, 56, 4, 0 }, + + { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, +}; diff --git a/utils/kl/pass.c b/utils/kl/pass.c new file mode 100644 index 00000000..6c8fb526 --- /dev/null +++ b/utils/kl/pass.c @@ -0,0 +1,551 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p, *p1; + long orig, orig1, v; + + 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); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%ld): %s\n%P", + s->value, s->name, p); + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rational is that data segment is more easily + * addressed through offset on REGSB) + */ + orig = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + while(v & 3) + v++; + s->value = v; + if(v > MINSIZ) + continue; + if(v >= 8) + while(orig & 7) + orig++; + s->value = orig; + orig += v; + s->type = SDATA1; + } + orig1 = orig; + + /* + * pass 2 + * assign 'data' variables to data segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + if(v >= 8) + while(orig & 7) + orig++; + s->value = orig; + orig += v; + s->type = SDATA1; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + v = s->value; + if(v >= 8) + while(orig & 7) + orig++; + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + /* + * pass 4 + * add literals to all large values. + * at this time: + * small data is allocated DATA + * large data is allocated DATA1 + * large bss is allocated BSS + * the new literals are loaded between + * small data and large data. + */ + orig = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as != AMOVW) + continue; + if(p->from.type != D_CONST) + continue; + if(s = p->from.sym) { + t = s->type; + if(t != SDATA && t != SDATA1 && t != SBSS) + continue; + t = p->from.name; + if(t != D_EXTERN && t != D_STATIC) + continue; + v = s->value + p->from.offset; + if(v >= 0 && v <= 0xffff) + continue; + if(!strcmp(s->name, "setSB")) + continue; + /* size should be 19 max */ + if(strlen(s->name) >= 10) /* has loader address */ + sprint(literal, "$%p.%lux", s, p->from.offset); + else + sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset); + } else { + if(p->from.name != D_NONE) + continue; + if(p->from.reg != NREG) + continue; + v = p->from.offset; + if(v >= -0x7fff && v <= 0xffff) + continue; + if(!(v & 0xffff)) + continue; + /* size should be 9 max */ + sprint(literal, "$%lux", v); + } + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + s->value = orig1+orig; + orig += 4; + p1 = prg(); + p1->as = ADATA; + p1->line = p->line; + p1->from.type = D_OREG; + p1->from.sym = s; + p1->from.name = D_EXTERN; + p1->reg = 4; + p1->to = p->from; + p1->link = datap; + datap = p1; + } + if(s->type != SDATA) + diag("literal not data: %s", s->name); + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + continue; + } + while(orig & 7) + orig++; + /* + * pass 5 + * re-adjust offsets + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t == SBSS) { + s->value += orig; + continue; + } + if(t == SDATA1) { + s->type = SDATA; + s->value += orig; + continue; + } + } + datsize += orig; + xdefine("setSB", SDATA, 0L+BIG); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +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); +} + +int +relinv(int a) +{ + + switch(a) { + case ABA: return ABN; + case ABN: return ABA; + + case ABE: return ABNE; + case ABNE: return ABE; + + case ABLE: return ABG; + case ABG: return ABLE; + + case ABL: return ABGE; + case ABGE: return ABL; + + case ABLEU: return ABGU; + case ABGU: return ABLEU; + + case ABCS: return ABCC; + case ABCC: return ABCS; + + case ABNEG: return ABPOS; + case ABPOS: return ABNEG; + + case ABVC: return ABVS; + case ABVS: return ABVC; + + case AFBN: return AFBA; + case AFBA: return AFBN; + + case AFBE: return AFBLG; + case AFBLG: return AFBE; + + case AFBG: return AFBLE; + case AFBLE: return AFBG; + + case AFBGE: return AFBL; + case AFBL: return AFBGE; + + /* unordered fp compares have no inverse + that traps in the same way */ + } + return 0; +} + +void +follow(void) +{ + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, b, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(a == AJMP) { + q = p->cond; + if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){ + p->mark |= FOLL; + lastp->link = p; + lastp = p; + p = p->link; + xfol(p); + p = q; + if(p && !(p->mark & FOLL)) + goto loop; + return; + } + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp || (q->mark&NOSCHED)) + break; + b = 0; /* set */ + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == AJMP || a == ARETURN || a == ARETT) + goto copy; + if(!q->cond || (q->cond->mark&FOLL)) + continue; + b = relinv(a); + if(!b) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(a == AJMP || a == ARETURN || a == ARETT) + return; + r->as = b; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + + a = AJMP; + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(a == AJMP || a == ARETURN || a == ARETT){ + if(p->mark & NOSCHED){ + p = p->link; + goto loop; + } + return; + } + if(p->cond != P) + if(a != AJMPL && p->link != P) { + xfol(p->link); + p = p->cond; + if(p == P || (p->mark&FOLL)) + return; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((a == AJMPL || a == ARETURN) && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT) { + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + } + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH) + 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 %ld\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->cond != P) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + 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) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(p->as != AJMP || (p->mark&NOSCHED)) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +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; +} + +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; +} diff --git a/utils/kl/sched.c b/utils/kl/sched.c new file mode 100644 index 00000000..4bbfb164 --- /dev/null +++ b/utils/kl/sched.c @@ -0,0 +1,672 @@ +#include "l.h" + +enum +{ + E_ICC = 1<<0, + E_FCC = 1<<1, + E_MEM = 1<<2, + E_MEMSP = 1<<3, /* uses offset and size */ + E_MEMSB = 1<<4, /* uses offset and size */ + ANYMEM = E_MEM|E_MEMSP|E_MEMSB, + ALL = ~0 +}; + +typedef struct Sch Sch; +typedef struct Dep Dep; + +struct Dep +{ + ulong ireg; + ulong freg; + ulong cc; +}; +struct Sch +{ + Prog p; + Dep set; + Dep used; + long soffset; + char size; + char nop; + char comp; +}; + +void regsused(Sch*, Prog*); +int depend(Sch*, Sch*); +int conflict(Sch*, Sch*); +int offoverlap(Sch*, Sch*); +void dumpbits(Sch*, Dep*); + +void +sched(Prog *p0, Prog *pe) +{ + Prog *p, *q; + Sch sch[NSCHED], *s, *t, *u, *se, stmp; + + /* + * build side structure + */ + s = sch; + for(p=p0;; p=p->link) { + memset(s, 0, sizeof(*s)); + s->p = *p; + regsused(s, p); + if(debug['X']) { + Bprint(&bso, "%P\tset", &s->p); + dumpbits(s, &s->set); + Bprint(&bso, "; used"); + dumpbits(s, &s->used); + if(s->comp) + Bprint(&bso, "; compound"); + if(s->p.mark & LOAD) + Bprint(&bso, "; load"); + if(s->p.mark & BRANCH) + Bprint(&bso, "; branch"); + if(s->p.mark & FCMP) + Bprint(&bso, "; fcmp"); + Bprint(&bso, "\n"); + } + s++; + if(p == pe) + break; + } + se = s; + + for(s=se-1; s>=sch; s--) { + /* + * branch delay slot + */ + if(s->p.mark & BRANCH) { + /* t is the trial instruction to use */ + for(t=s-1; t>=sch; t--) { + if(t->comp || (t->p.mark & FCMP)) + goto no1; + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no1; + goto out1; + no1:; + } + if(debug['X']) + Bprint(&bso, "?b%P\n", &s->p); + s->nop = 1; + continue; + + out1: + if(debug['X']) { + Bprint(&bso, "!b%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + continue; + } + + /* + * load delay. interlocked. + */ + if(s->p.mark & LOAD) { + if(s >= se-1) + continue; + if(!conflict(s, (s+1))) + continue; + /* + * s is load, s+1 is immediate use of result + * t is the trial instruction to insert between s and s+1 + */ + for(t=s-1; t>=sch; t--) { + if(t->p.mark & BRANCH) + goto no2; + if(t->p.mark & FCMP) + if((s+1)->p.mark & BRANCH) + goto no2; + if(t->p.mark & LOAD) + if(conflict(t, (s+1))) + goto no2; + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no2; + goto out2; + no2:; + } + if(debug['X']) + Bprint(&bso, "?l%P\n", &s->p); + continue; + out2: + if(debug['X']) { + Bprint(&bso, "!l%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + continue; + } + + /* + * fop2 delay. + */ + if(s->p.mark & FCMP) { + if(s >= se-1) { + s->nop = 1; + continue; + } + if(!((s+1)->p.mark & BRANCH)) + continue; + /* t is the trial instruction to use */ + for(t=s-1; t>=sch; t--) { + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no3; + goto out3; + no3:; + } + if(debug['X']) + Bprint(&bso, "?f%P\n", &s->p); + s->nop = 1; + continue; + out3: + if(debug['X']) { + Bprint(&bso, "!f%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + continue; + } + } + + /* + * put it all back + */ + for(s=sch, p=p0; s<se; s++, p=q) { + q = p->link; + if(q != s->p.link) { + *p = s->p; + p->link = q; + } + if(s->nop) + addnop(p); + } + if(debug['X']) + Bprint(&bso, "\n"); +} + +void +regsused(Sch *s, Prog *realp) +{ + int c, ar, ad, ld, sz; + ulong m; + Prog *p; + + p = &s->p; + s->comp = compound(p); + s->nop = 0; + if(s->comp) { + s->set.ireg |= 1<<REGTMP; + s->used.ireg |= 1<<REGTMP; + } + ar = 0; /* dest is really reference */ + ad = 0; /* source/dest is really address */ + ld = 0; /* opcode is load instruction */ + sz = 20; /* size of load/store for overlap computation */ + +/* + * flags based on opcode + */ + switch(p->as) { + case ATEXT: + curtext = realp; + autosize = p->to.offset + 4; + ad = 1; + break; + case AJMPL: + c = p->reg; + if(c == NREG) + c = REGLINK; + s->set.ireg |= 1<<c; + ar = 1; + ad = 1; + break; + case AJMP: + ar = 1; + ad = 1; + break; + case ACMP: + s->set.cc |= E_ICC; + ar = 1; + break; + case AFCMPD: + case AFCMPED: + case AFCMPEF: + case AFCMPEX: + case AFCMPF: + case AFCMPX: + s->set.cc |= E_FCC; + ar = 1; + break; + case ABE: + case ABNE: + case ABLE: + case ABG: + case ABL: + case ABGE: + case ABLEU: + case ABGU: + case ABCS: + case ABCC: + case ABNEG: + case ABPOS: + case ABVC: + case ABVS: + s->used.cc |= E_ICC; + ar = 1; + break; + case AFBE: + case AFBLG: + case AFBG: + case AFBLE: + case AFBGE: + case AFBL: + s->used.cc |= E_FCC; + ar = 1; + break; + case AMOVB: + case AMOVBU: + sz = 1; + ld = 1; + break; + case AMOVH: + case AMOVHU: + sz = 2; + ld = 1; + break; + case AFMOVF: + case AMOVW: + sz = 4; + ld = 1; + break; + case AMOVD: + case AFMOVD: + sz = 8; + ld = 1; + break; + case AFMOVX: /* gok */ + sz = 16; + ld = 1; + break; + case AADDCC: + case AADDXCC: + case AANDCC: + case AANDNCC: + case AORCC: + case AORNCC: + case ASUBCC: + case ASUBXCC: + case ATADDCC: + case ATADDCCTV: + case ATSUBCC: + case ATSUBCCTV: + case AXNORCC: + case AXORCC: + s->set.cc |= E_ICC; + break; + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + case AMUL: + case AMULSCC: + case ATAS: + s->set.ireg = ALL; + s->set.freg = ALL; + s->set.cc = ALL; + break; + } + +/* + * flags based on 'to' field + */ + c = p->to.class; + if(c == 0) { + c = aclass(&p->to) + 1; + p->to.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->to); + + case C_ZCON: + case C_SCON: + case C_UCON: + case C_LCON: + case C_NONE: + case C_SBRA: + case C_LBRA: + break; + case C_CREG: + case C_FSR: + case C_FQ: + case C_PREG: + s->set.ireg = ALL; + s->set.freg = ALL; + s->set.cc = ALL; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + case C_ASI: + c = p->to.reg; + s->used.ireg |= 1<<c; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + if(ar) + s->used.cc |= m; + else + s->set.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + if(ar) + s->used.ireg |= 1<<p->to.reg; + else + s->set.ireg |= 1<<p->to.reg; + break; + case C_FREG: + /* do better -- determine double prec */ + if(ar) { + s->used.freg |= 1<<p->to.reg; + s->used.freg |= 1<<(p->to.reg|1); + } else { + s->set.freg |= 1<<p->to.reg; + s->set.freg |= 1<<(p->to.reg|1); + } + break; + case C_SAUTO: + case C_LAUTO: + case C_ESAUTO: + case C_OSAUTO: + case C_ELAUTO: + case C_OLAUTO: + s->used.ireg |= 1<<REGSP; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSP; + else + s->set.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + case C_ESEXT: + case C_OSEXT: + case C_ELEXT: + case C_OLEXT: + s->used.ireg |= 1<<REGSB; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSB; + else + s->set.cc |= E_MEMSB; + break; + } + +/* + * flags based on 'from' field + */ + c = p->from.class; + if(c == 0) { + c = aclass(&p->from) + 1; + p->from.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->from); + + case C_ZCON: + case C_SCON: + case C_UCON: + case C_LCON: + case C_NONE: + case C_SBRA: + case C_LBRA: + c = p->from.reg; + if(c != NREG) + s->used.ireg |= 1<<c; + break; + case C_CREG: + case C_FSR: + case C_FQ: + case C_PREG: + s->set.ireg = ALL; + s->set.freg = ALL; + s->set.cc = ALL; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + case C_ASI: + c = p->from.reg; + s->used.ireg |= 1<<c; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + s->used.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + s->used.ireg |= 1<<p->from.reg; + break; + case C_FREG: + /* do better -- determine double prec */ + s->used.freg |= 1<<p->from.reg; + s->used.freg |= 1<<(p->from.reg|1); + break; + case C_SAUTO: + case C_LAUTO: + case C_ESAUTO: + case C_ELAUTO: + case C_OSAUTO: + case C_OLAUTO: + s->used.ireg |= 1<<REGSP; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + case C_ESEXT: + case C_ELEXT: + case C_OSEXT: + case C_OLEXT: + s->used.ireg |= 1<<REGSB; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSB; + break; + } + + c = p->reg; + if(c != NREG) { + if(p->from.type == D_FREG || p->to.type == D_FREG) { + s->used.freg |= 1<<c; + s->used.freg |= 1<<(c|1); + } else + s->used.ireg |= 1<<c; + } + s->set.ireg &= ~(1<<0); /* R0 cant be set */ +} + +/* + * test to see if 2 instrictions can be + * interchanged without changing semantics + */ +int +depend(Sch *sa, Sch *sb) +{ + ulong x; + + if(sa->set.ireg & (sb->set.ireg|sb->used.ireg)) + return 1; + if(sb->set.ireg & sa->used.ireg) + return 1; + + if(sa->set.freg & (sb->set.freg|sb->used.freg)) + return 1; + if(sb->set.freg & sa->used.freg) + return 1; + + x = (sa->set.cc & (sb->set.cc|sb->used.cc)) | + (sb->set.cc & sa->used.cc); + if(x) { + /* + * allow SB and SP to pass each other. + * allow SB to pass SB iff doffsets are ok + * anything else conflicts + */ + if(x != E_MEMSP && x != E_MEMSB) + return 1; + x = sa->set.cc | sb->set.cc | + sa->used.cc | sb->used.cc; + if(x & E_MEM) + return 1; + if(offoverlap(sa, sb)) + return 1; + } + + return 0; +} + +int +offoverlap(Sch *sa, Sch *sb) +{ + + if(sa->soffset < sb->soffset) { + if(sa->soffset+sa->size > sb->soffset) + return 1; + return 0; + } + if(sb->soffset+sb->size > sa->soffset) + return 1; + return 0; +} + +/* + * test 2 adjacent instructions + * and find out if inserted instructions + * are desired to prevent stalls. + * first instruction is a load instruction. + */ +int +conflict(Sch *sa, Sch *sb) +{ + + if(sa->set.ireg & sb->used.ireg) + return 1; + if(sa->set.freg & sb->used.freg) + return 1; + return 0; +} + +int +compound(Prog *p) +{ + Optab *o; + + o = oplook(p); + if(o->size != 4) + return 1; + if(p->to.type == D_REG && p->to.reg == REGSB) + return 1; + return 0; +} + +void +dumpbits(Sch *s, Dep *d) +{ + int i; + + for(i=0; i<32; i++) + if(d->ireg & (1<<i)) + Bprint(&bso, " R%d", i); + for(i=0; i<32; i++) + if(d->freg & (1<<i)) + Bprint(&bso, " F%d", i); + for(i=0; i<32; i++) + switch(d->cc & (1<<i)) { + default: + break; + case E_ICC: + Bprint(&bso, " ICC"); + break; + case E_FCC: + Bprint(&bso, " FCC"); + break; + case E_MEM: + Bprint(&bso, " MEM%d", s->size); + break; + case E_MEMSB: + Bprint(&bso, " SB%d", s->size); + break; + case E_MEMSP: + Bprint(&bso, " SP%d", s->size); + break; + } +} diff --git a/utils/kl/span.c b/utils/kl/span.c new file mode 100644 index 00000000..fdfb8034 --- /dev/null +++ b/utils/kl/span.c @@ -0,0 +1,522 @@ +#include "l.h" + +void +span(void) +{ + Prog *p; + Sym *setext; + Optab *o; + int m; + long c; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + p->pc = c; + o = oplook(p); + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + if(p->as != ANOP) + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + c = rnd(c, 8); + + setext = lookup("etext", 0); + if(setext != S) { + setext->value = c; + textsize = c - INITTEXT; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(debug['v']) + Bprint(&bso, "tsize = %lux\n", textsize); + Bflush(&bso); +} + +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; + } +} + +long +regoff(Adr *a) +{ + + instoffset = 0; + aclass(a); + return instoffset; +} + +int +aclass(Adr *a) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_FREG: + return C_FREG; + + case D_CREG: + return C_CREG; + + case D_PREG: + if(a->reg == D_FSR) + return C_FSR; + if(a->reg == D_FPQ) + return C_FQ; + return C_PREG; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == S) + break; + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + instoffset = a->sym->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG) { + if(instoffset & 7) + return C_OSEXT; + return C_ESEXT; + } + if(instoffset & 7) + return C_OLEXT; + return C_ELEXT; + case D_AUTO: + instoffset = autosize + a->offset; + goto dauto; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + dauto: + if(instoffset >= -BIG && instoffset < BIG) { + if(instoffset & 7) + return C_OSAUTO; + return C_ESAUTO; + } + if(instoffset & 7) + return C_OLAUTO; + return C_ELAUTO; + case D_NONE: + instoffset = a->offset; + if(instoffset == 0) + return C_ZOREG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SOREG; + return C_LOREG; + } + return C_GOK; + + case D_ASI: + if(a->name == D_NONE) + return C_ASI; + return C_GOK; + + case D_CONST: + switch(a->name) { + + case D_NONE: + instoffset = a->offset; + consize: + if(instoffset == 0) + return C_ZCON; + if(instoffset >= -0x1000 && instoffset <= 0xfff) + return C_SCON; + if((instoffset & 0x3ff) == 0) + return C_UCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == S) + break; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + } + if(s->type == STEXT || s->type == SLEAF) { + instoffset = s->value + a->offset; + return C_LCON; + } + if(s->type == SCONST) { + instoffset = s->value + a->offset; + goto consize; + } + instoffset = s->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG && instoffset != 0) + return C_SECON; + instoffset = s->value + a->offset + INITDAT; +/* not sure why this barfs */ +return C_LCON; + if(instoffset == 0) + return C_ZCON; + if(instoffset >= -0x1000 && instoffset <= 0xfff) + return C_SCON; + if((instoffset & 0x3ff) == 0) + return C_UCON; + return C_LCON; + + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +Optab* +oplook(Prog *p) +{ + int a1, a2, a3, r; + char *c1, *c3; + Optab *o, *e; + + a1 = p->optab; + if(a1) + return optab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + a1 = aclass(&p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->to.class; + if(a3 == 0) { + a3 = aclass(&p->to) + 1; + p->to.class = a3; + } + a3--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = oprange[r].start; + if(o == 0) + o = oprange[r].stop; /* just generate an error */ + e = oprange[r].stop; + c1 = xcmp[a1]; + c3 = xcmp[a3]; + for(; o<e; o++) + if(o->a2 == a2) + if(c1[o->a1]) + if(c3[o->a3]) { + p->optab = (o-optab)+1; + return o; + } + diag("illegal combination %A %d %d %d", + p->as, a1, a2, a3); + if(1||!debug['a']) + prasm(p); + if(o == 0) + errorexit(); + return o; +} + +int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_ZCON || b == C_SCON || b == C_UCON) + return 1; + break; + case C_UCON: + if(b == C_ZCON) + return 1; + break; + case C_SCON: + if(b == C_ZCON) + return 1; + break; + case C_LACON: + if(b == C_SACON) + return 1; + break; + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + case C_ELEXT: + if(b == C_ESEXT) + return 1; + break; + case C_LEXT: + if(b == C_SEXT || + b == C_ESEXT || b == C_OSEXT || + b == C_ELEXT || b == C_OLEXT) + return 1; + break; + case C_SEXT: + if(b == C_ESEXT || b == C_OSEXT) + return 1; + break; + case C_ELAUTO: + if(b == C_ESAUTO) + return 1; + break; + case C_LAUTO: + if(b == C_SAUTO || + b == C_ESAUTO || b == C_OSAUTO || + b == C_ELAUTO || b == C_OLAUTO) + return 1; + break; + case C_SAUTO: + if(b == C_ESAUTO || b == C_OSAUTO) + return 1; + break; + case C_REG: + if(b == C_ZCON) + return 1; + break; + case C_LOREG: + if(b == C_ZOREG || b == C_SOREG) + return 1; + break; + case C_SOREG: + if(b == C_ZOREG) + return 1; + break; + + case C_ANY: + return 1; + } + return 0; +} + +int +ocmp(const void *a1, const void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = (Optab*)a1; + p2 = (Optab*)a2; + n = p1->as - p2->as; + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a2 - p2->a2; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + return 0; +} + +void +buildop(void) +{ + int i, n, r; + + for(i=0; i<C_NCLASS; i++) + for(n=0; n<C_NCLASS; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) + ; + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + diag("unknown op in build: %A", r); + errorexit(); + case AADD: + oprange[AADDX] = oprange[r]; + oprange[ASUB] = oprange[r]; + oprange[ASUBX] = oprange[r]; + oprange[AMUL] = oprange[r]; + oprange[AXOR] = oprange[r]; + oprange[AXNOR] = oprange[r]; + oprange[AAND] = oprange[r]; + oprange[AANDN] = oprange[r]; + oprange[AOR] = oprange[r]; + oprange[AORN] = oprange[r]; + oprange[ASLL] = oprange[r]; + oprange[ASRL] = oprange[r]; + oprange[ASRA] = oprange[r]; + oprange[AADDCC] = oprange[r]; + oprange[AADDXCC] = oprange[r]; + oprange[ATADDCC] = oprange[r]; + oprange[ATADDCCTV] = oprange[r]; + oprange[ASUBCC] = oprange[r]; + oprange[ASUBXCC] = oprange[r]; + oprange[ATSUBCC] = oprange[r]; + oprange[ATSUBCCTV] = oprange[r]; + oprange[AXORCC] = oprange[r]; + oprange[AXNORCC] = oprange[r]; + oprange[AANDCC] = oprange[r]; + oprange[AANDNCC] = oprange[r]; + oprange[AORCC] = oprange[r]; + oprange[AORNCC] = oprange[r]; + oprange[AMULSCC] = oprange[r]; + oprange[ASAVE] = oprange[r]; + oprange[ARESTORE] = oprange[r]; + break; + case AMOVB: + oprange[AMOVH] = oprange[r]; + oprange[AMOVHU] = oprange[r]; + oprange[AMOVBU] = oprange[r]; + oprange[ASWAP] = oprange[r]; + oprange[ATAS] = oprange[r]; + break; + case ABA: + oprange[ABN] = oprange[r]; + oprange[AFBA] = oprange[r]; + oprange[AFBN] = oprange[r]; + break; + case ABE: + oprange[ABCC] = oprange[r]; + oprange[ABCS] = oprange[r]; + oprange[ABGE] = oprange[r]; + oprange[ABGU] = oprange[r]; + oprange[ABG] = oprange[r]; + oprange[ABLEU] = oprange[r]; + oprange[ABLE] = oprange[r]; + oprange[ABL] = oprange[r]; + oprange[ABNEG] = oprange[r]; + oprange[ABNE] = oprange[r]; + oprange[ABPOS] = oprange[r]; + oprange[ABVC] = oprange[r]; + oprange[ABVS] = oprange[r]; + + oprange[AFBE] = oprange[r]; + oprange[AFBG] = oprange[r]; + oprange[AFBGE] = oprange[r]; + oprange[AFBL] = oprange[r]; + oprange[AFBLE] = oprange[r]; + oprange[AFBLG] = oprange[r]; + oprange[AFBNE] = oprange[r]; + oprange[AFBO] = oprange[r]; + oprange[AFBU] = oprange[r]; + oprange[AFBUE] = oprange[r]; + oprange[AFBUG] = oprange[r]; + oprange[AFBUGE] = oprange[r]; + oprange[AFBUL] = oprange[r]; + oprange[AFBULE] = oprange[r]; + break; + case ATA: + oprange[ATCC] = oprange[r]; + oprange[ATCS] = oprange[r]; + oprange[ATE] = oprange[r]; + oprange[ATGE] = oprange[r]; + oprange[ATGU] = oprange[r]; + oprange[ATG] = oprange[r]; + oprange[ATLEU] = oprange[r]; + oprange[ATLE] = oprange[r]; + oprange[ATL] = oprange[r]; + oprange[ATNEG] = oprange[r]; + oprange[ATNE] = oprange[r]; + oprange[ATN] = oprange[r]; + oprange[ATPOS] = oprange[r]; + oprange[ATVC] = oprange[r]; + oprange[ATVS] = oprange[r]; + break; + case AFADDD: + oprange[AFADDF] = oprange[r]; + oprange[AFADDX] = oprange[r]; + oprange[AFDIVD] = oprange[r]; + oprange[AFDIVF] = oprange[r]; + oprange[AFDIVX] = oprange[r]; + oprange[AFMULD] = oprange[r]; + oprange[AFMULF] = oprange[r]; + oprange[AFMULX] = oprange[r]; + oprange[AFSUBD] = oprange[r]; + oprange[AFSUBF] = oprange[r]; + oprange[AFSUBX] = oprange[r]; + break; + case AFCMPD: + oprange[AFCMPF] = oprange[r]; + oprange[AFCMPX] = oprange[r]; + oprange[AFCMPED] = oprange[r]; + oprange[AFCMPEF] = oprange[r]; + oprange[AFCMPEX] = oprange[r]; + break; + case AFABSF: + oprange[AFMOVDF] = oprange[r]; + oprange[AFMOVDW] = oprange[r]; + oprange[AFMOVFD] = oprange[r]; + oprange[AFMOVFW] = oprange[r]; + oprange[AFMOVWD] = oprange[r]; + oprange[AFMOVWF] = oprange[r]; + oprange[AFNEGF] = oprange[r]; + oprange[AFSQRTD] = oprange[r]; + oprange[AFSQRTF] = oprange[r]; + break; + case AFMOVF: + case AFMOVD: + case AMOVW: + case AMOVD: + case AWORD: + case ARETT: + case AJMPL: + case AJMP: + case ACMP: + case ANOP: + case ATEXT: + case ADIV: + case ADIVL: + case AMOD: + case AMODL: + break; + } + } +} diff --git a/utils/kprof/kprof.c b/utils/kprof/kprof.c new file mode 100644 index 00000000..a524815e --- /dev/null +++ b/utils/kprof/kprof.c @@ -0,0 +1,155 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +enum { + SpecialTotalTicks, + SpecialOutsideTicks, + SpecialMicroSecondsPerTick, + SpecialSamples, + SpecialSampleSize, + SpecialSampleLogBucketSize, + SpecialMax +}; + +int pcres = 8; +ulong uspertick; + +struct COUNTER +{ + char *name; /* function name */ + ulong time; /* ticks spent there */ +}; + +void +error(int perr, char *s) +{ + fprint(2, "kprof: %s", s); + if(perr) + fprint(2, ": %r\n"); + else + fprint(2, "\n"); + exits(s); +} + +int +compar(void *va, void *vb) +{ + struct COUNTER *a, *b; + + a = (struct COUNTER *)va; + b = (struct COUNTER *)vb; + if(a->time < b->time) + return -1; + if(a->time == b->time) + return 0; + return 1; +} + +ulong +tickstoms(ulong ticks) +{ + return ((vlong)ticks * uspertick) / 1000; +} + +void +main(int argc, char *argv[]) +{ + int fd; + long i, j, k, n; + Dir *d; + char *name; + ulong *data; + ulong tbase, sum; + long delta; + Symbol s; + Biobuf outbuf; + Fhdr f; + struct COUNTER *cp; + + if(argc != 3) + error(0, "usage: kprof text data"); + /* + * Read symbol table + */ + fd = open(argv[1], OREAD); + if(fd < 0) + error(1, argv[1]); + if (!crackhdr(fd, &f)) + error(1, "read text header"); + if (f.type == FNONE) + error(0, "text file not an a.out"); + if (syminit(fd, &f) < 0) + error(1, "syminit"); + close(fd); + /* + * Read timing data + */ + fd = open(argv[2], OREAD); + if(fd < 0) + error(1, argv[2]); + if((d = dirfstat(fd)) == nil) + error(1, "stat"); + n = d->length/sizeof(data[0]); + if(n < 2) + error(0, "data file too short"); + data = malloc(d->length); + if(data == 0) + error(1, "malloc"); + if(read(fd, data, d->length) < 0) + error(1, "text read"); + close(fd); + free(d); + for(i=0; i<n; i++) + data[i] = beswal(data[i]); + pcres = 1 << data[SpecialSampleLogBucketSize]; + uspertick = data[SpecialMicroSecondsPerTick]; + if (data[SpecialSampleSize] != sizeof(data[0])) + error(0, "only sample size 4 supported\n"); + delta = data[SpecialTotalTicks] - data[SpecialOutsideTicks]; + print("total: %lud in kernel text: %lud outside kernel text: %lud\n", + data[0], delta, data[1]); + if(data[0] == 0) + exits(0); + if (!textsym(&s, 0)) + error(0, "no text symbols"); + tbase = s.value & ~(mach->pgsize-1); /* align down to page */ + print("KTZERO %.8lux\n", tbase); + /* + * Accumulate counts for each function + */ + cp = 0; + k = 0; + for (i = 0, j = (s.value-tbase)/pcres+SpecialMax; j < n; i++) { + name = s.name; /* save name */ + if (!textsym(&s, i)) /* get next symbol */ + break; + sum = 0; + while (j < n && j*pcres < s.value-tbase) + sum += data[j++]; + if (sum) { + cp = realloc(cp, (k+1)*sizeof(struct COUNTER)); + if (cp == 0) + error(1, "realloc"); + cp[k].name = name; + cp[k].time = sum; + k++; + } + } + if (!k) + error(0, "no counts"); + cp[k].time = 0; /* "etext" can take no time */ + /* + * Sort by time and print + */ + qsort(cp, k, sizeof(struct COUNTER), compar); + Binit(&outbuf, 1, OWRITE); + Bprint(&outbuf, "ms %% sym\n"); + while(--k>=0) + Bprint(&outbuf, "%lud\t%3lud.%d\t%s\n", + tickstoms(cp[k].time), + 100*cp[k].time/delta, + (1000*cp[k].time/delta)%10, + cp[k].name); + exits(0); +} diff --git a/utils/kprof/mkfile b/utils/kprof/mkfile new file mode 100644 index 00000000..b8f53cd3 --- /dev/null +++ b/utils/kprof/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=kprof + +OFILES= kprof.$O\ + +LIBS= mach bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/ksize/ksize.c b/utils/ksize/ksize.c new file mode 100644 index 00000000..1bb84701 --- /dev/null +++ b/utils/ksize/ksize.c @@ -0,0 +1,49 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +int +size(char *file) +{ + int fd; + Fhdr f; + + if((fd = open(file, OREAD)) < 0){ + fprint(2, "size: "); + perror(file); + return 1; + } + if(crackhdr(fd, &f)) { + print("%ldt + %ldd + %ldb = %ld\t%s\n", f.txtsz, f.datsz, + f.bsssz, f.txtsz+f.datsz+f.bsssz, file); + close(fd); + return 0; + } + + /* get error string from libmach and display */ + fprint(2, "ksize: %s %r\n", file); + close(fd); + return 1; +} + +void +main(int argc, char *argv[]) +{ + char *err; + int i; + + ARGBEGIN { + default: + fprint(2, "usage: ksize [a.out ...]\n"); + exits("usage"); + } ARGEND; + + err = 0; + if(argc == 0) + if(size("8.out")) + err = "error"; + for(i=0; i<argc; i++) + if(size(argv[i])) + err = "error"; + exits(err); +} diff --git a/utils/ksize/mkfile b/utils/ksize/mkfile new file mode 100644 index 00000000..e4d9a113 --- /dev/null +++ b/utils/ksize/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=ksize + +OFILES= ksize.$O\ + +LIBS= mach bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/kstrip/kstrip.c b/utils/kstrip/kstrip.c new file mode 100644 index 00000000..2fab8bea --- /dev/null +++ b/utils/kstrip/kstrip.c @@ -0,0 +1,166 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +static void +error(char* fmt, ...) +{ + va_list arg; + + fprint(2, "kstrip: "); + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); + fprint(2, "\n"); +} + +static void +usage(void) +{ + error("usage: %s -o ofile file\n\t%s file ...\n", argv0, argv0); + exits("usage"); +} + +static int +strip(char* file, char* out) +{ + Dir *dir; + int fd, i; + Fhdr fhdr; + Exec *exec; + ulong mode; + void *data; + vlong length; + + if((fd = open(file, OREAD)) < 0){ + error("%s: open: %r", file); + return 1; + } + + if(!crackhdr(fd, &fhdr)){ + error("%s: %r", file); + close(fd); + return 1; + } + for(i = MIN_MAGIC; i <= MAX_MAGIC; i++){ + if(fhdr.magic == _MAGIC(0, i) || fhdr.magic == _MAGIC(HDR_MAGIC, i)) + break; + } + if(i > MAX_MAGIC){ + error("%s: not a recognizable binary", file); + close(fd); + return 1; + } + + if((dir = dirfstat(fd)) == nil){ + error("%s: stat: %r", file); + close(fd); + return 1; + } + + length = fhdr.datoff+fhdr.datsz; + if(length == dir->length){ + if(out == nil){ /* nothing to do */ + error("%s: already stripped", file); + free(dir); + close(fd); + return 0; + } + } + if(length > dir->length){ + error("%s: strange length", file); + close(fd); + free(dir); + return 1; + } + + mode = dir->mode; + free(dir); + + if((data = malloc(length)) == nil){ + error("%s: out of memory", file); + close(fd); + return 1; + } + seek(fd, 0, 0); + if(read(fd, data, length) != length){ + error("%s: read error: %r", file); + close(fd); + free(data); + return 1; + } + close(fd); + + exec = data; + exec->syms = 0; + exec->spsz = 0; + exec->pcsz = 0; + + if(out == nil){ + if(remove(file) < 0) { + error("%s: can't remove: %r", file); + free(data); + return 1; + } + out = file; + } + if((fd = create(out, OWRITE, mode)) < 0){ + error("%s: can't create: %r", out); + free(data); + return 1; + } + if(write(fd, data, length) != length){ + error("%s: write error: %r", out); + close(fd); + free(data); + return 1; + } + close(fd); + free(data); + + return 0; +} + +void +main(int argc, char* argv[]) +{ + int r; + char *p; + + p = nil; + + ARGBEGIN{ + default: + usage(); + break; + case 'o': + p = ARGF(); + if(p == nil) + usage(); + break; + }ARGEND; + + switch(argc){ + case 0: + usage(); + return; + case 1: + if(p != nil){ + r = strip(*argv, p); + break; + } + /*FALLTHROUGH*/ + default: + r = 0; + while(argc > 0){ + r |= strip(*argv, nil); + argc--; + argv++; + } + break; + } + + if(r) + exits("error"); + exits(0); +} diff --git a/utils/kstrip/mkfile b/utils/kstrip/mkfile new file mode 100644 index 00000000..c88945ac --- /dev/null +++ b/utils/kstrip/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=kstrip + +OFILES= kstrip.$O\ + +LIBS= mach bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/lib/rcmain b/utils/lib/rcmain new file mode 100644 index 00000000..f74190ca --- /dev/null +++ b/utils/lib/rcmain @@ -0,0 +1,29 @@ +# rcmain: 9pm version +if(~ $#home 0) home=/ +if(~ $#ifs 0) ifs=' +' +switch($#prompt){ +case 0 +case 1 + prompt=('% ' ' ') +} +if(~ $rcname v.out) prompt=('broken! ' ' ') +if(! ~ $#cflag 0){ + if(flag l && test -r $home/lib/profile) . $home/lib/profile + status='' + eval $cflag +} +if not if(flag i){ + if(flag l && test -r $home/lib/profile) . $home/lib/profile + status='' + if(! ~ $#* 0) . $* + if not . -i 'stdin$' +} +if not { + if(~ $#* 0) . 'stdin$' + if not{ + status='' + . $* + } +} +exit $status diff --git a/utils/lib/yaccpar b/utils/lib/yaccpar new file mode 100644 index 00000000..efc1da06 --- /dev/null +++ b/utils/lib/yaccpar @@ -0,0 +1,241 @@ +#define YYFLAG -1000 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 + +#ifdef yydebug +#include "y.debug" +#else +#define yydebug 0 +char* yytoknames[1]; /* for debugging */ +char* yystates[1]; /* for debugging */ +#endif + +/* parser for yacc output */ + +int yynerrs = 0; /* number of errors */ +int yyerrflag = 0; /* error recovery flag */ + +extern int fprint(int, char*, ...); +extern int sprint(char*, char*, ...); + +char* +yytokname(int yyc) +{ + static char x[10]; + + if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0])) + if(yytoknames[yyc-1]) + return yytoknames[yyc-1]; + sprint(x, "<%d>", yyc); + return x; +} + +char* +yystatname(int yys) +{ + static char x[10]; + + if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0])) + if(yystates[yys]) + return yystates[yys]; + sprint(x, "<%d>\n", yys); + return x; +} + +long +yylex1(void) +{ + long yychar; + long *t3p; + int c; + + yychar = yylex(); + if(yychar <= 0) { + c = yytok1[0]; + goto out; + } + if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) { + c = yytok1[yychar]; + goto out; + } + if(yychar >= YYPRIVATE) + if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) { + c = yytok2[yychar-YYPRIVATE]; + goto out; + } + for(t3p=yytok3;; t3p+=2) { + c = t3p[0]; + if(c == yychar) { + c = t3p[1]; + goto out; + } + if(c == 0) + break; + } + c = 0; + +out: + if(c == 0) + c = yytok2[1]; /* unknown char */ + if(yydebug >= 3) + fprint(2, "lex %.4lux %s\n", yychar, yytokname(c)); + return c; +} + +int +yyparse(void) +{ + struct + { + YYSTYPE yyv; + int yys; + } yys[YYMAXDEPTH], *yyp, *yypt; + short *yyxi; + int yyj, yym, yystate, yyn, yyg; + long yychar; + YYSTYPE save1, save2; + int save3, save4; + + save1 = yylval; + save2 = yyval; + save3 = yynerrs; + save4 = yyerrflag; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyp = &yys[-1]; + goto yystack; + +ret0: + yyn = 0; + goto ret; + +ret1: + yyn = 1; + goto ret; + +ret: + yylval = save1; + yyval = save2; + yynerrs = save3; + yyerrflag = save4; + return yyn; + +yystack: + /* put a state and value onto the stack */ + if(yydebug >= 4) + fprint(2, "char %s in %s", yytokname(yychar), yystatname(yystate)); + + yyp++; + if(yyp >= &yys[YYMAXDEPTH]) { + yyerror("yacc stack overflow"); + goto ret1; + } + yyp->yys = yystate; + yyp->yyv = yyval; + +yynewstate: + yyn = yypact[yystate]; + if(yyn <= YYFLAG) + goto yydefault; /* simple state */ + if(yychar < 0) + yychar = yylex1(); + yyn += yychar; + if(yyn < 0 || yyn >= YYLAST) + goto yydefault; + yyn = yyact[yyn]; + if(yychk[yyn] == yychar) { /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if(yyerrflag > 0) + yyerrflag--; + goto yystack; + } + +yydefault: + /* default state action */ + yyn = yydef[yystate]; + if(yyn == -2) { + if(yychar < 0) + yychar = yylex1(); + + /* look through exception table */ + for(yyxi=yyexca;; yyxi+=2) + if(yyxi[0] == -1 && yyxi[1] == yystate) + break; + for(yyxi += 2;; yyxi += 2) { + yyn = yyxi[0]; + if(yyn < 0 || yyn == yychar) + break; + } + yyn = yyxi[1]; + if(yyn < 0) + goto ret0; + } + if(yyn == 0) { + /* error ... attempt to resume parsing */ + switch(yyerrflag) { + case 0: /* brand new error */ + yyerror("syntax error"); + yynerrs++; + if(yydebug >= 1) { + fprint(2, "%s", yystatname(yystate)); + fprint(2, "saw %s\n", yytokname(yychar)); + } + + case 1: + case 2: /* incompletely recovered error ... try again */ + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + while(yyp >= yys) { + yyn = yypact[yyp->yys] + YYERRCODE; + if(yyn >= 0 && yyn < YYLAST) { + yystate = yyact[yyn]; /* simulate a shift of "error" */ + if(yychk[yystate] == YYERRCODE) + goto yystack; + } + + /* the current yyp has no shift onn "error", pop stack */ + if(yydebug >= 2) + fprint(2, "error recovery pops state %d, uncovers %d\n", + yyp->yys, (yyp-1)->yys ); + yyp--; + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1; + + case 3: /* no shift yet; clobber input char */ + if(yydebug >= 2) + fprint(2, "error recovery discards %s\n", yytokname(yychar)); + if(yychar == YYEOFCODE) + goto ret1; + yychar = -1; + goto yynewstate; /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if(yydebug >= 2) + fprint(2, "reduce %d in:\n\t%s", yyn, yystatname(yystate)); + + yypt = yyp; + yyp -= yyr2[yyn]; + yyval = (yyp+1)->yyv; + yym = yyn; + + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyg = yypgo[yyn]; + yyj = yyg + yyp->yys + 1; + + if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) + yystate = yyact[yyg]; + switch(yym) { + $A + } + goto yystack; /* stack new state and value */ +} diff --git a/utils/libmach/2.c b/utils/libmach/2.c new file mode 100644 index 00000000..2b1010f4 --- /dev/null +++ b/utils/libmach/2.c @@ -0,0 +1,85 @@ +/* + * 68020 definition + */ +#include <lib9.h> +#include "ureg2.h" +#include <bio.h> +#include "mach.h" + +#define MAXREG 0 +#define MINREG 0 + +#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x) + +#define VO REGOFF(vo) /* vo, 2 bytes */ +#define SR REGOFF(sr) /* sr, 2 bytes */ +#define R0 REGOFF(r0) +#define PC REGOFF(pc) +#define DBMAGIC REGOFF(magic) +#define SP REGOFF(usp) + +#define REGSIZE (R0+4) +#define FCTL(x) (REGSIZE+(x)*4) +#define FREG(x) (FCTL(3)+(x)*12) +#define FPREGSIZE (11*12) + +/* + * 68020 register set + */ +Reglist m68020reglist[] = { + {"VO", VO, RINT, 'x'}, + {"SR", SR, RINT, 'x'}, + {"MAGIC", DBMAGIC, RINT, 'X'}, + {"PC", PC, RINT, 'X'}, + {"A7", SP, RINT, 'X'}, + {"KSP", REGOFF(sp), RINT, 'X'}, + {"A6", REGOFF(a6), RINT, 'X'}, + {"A5", REGOFF(a5), RINT, 'X'}, + {"A4", REGOFF(a4), RINT, 'X'}, + {"A3", REGOFF(a3), RINT, 'X'}, + {"A2", REGOFF(a2), RINT, 'X'}, + {"A1", REGOFF(a1), RINT, 'X'}, + {"A0", REGOFF(a0), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + {"R0", REGOFF(r0), RINT, 'X'}, + {"FPCR", FCTL(0), RFLT, 'X'}, + {"FPSR", FCTL(1), RFLT, 'X'}, + {"FPIAR", FCTL(2), RFLT, 'X'}, + {"F0", FREG(0), RFLT, '8'}, + {"F1", FREG(1), RFLT, '8'}, + {"F2", FREG(2), RFLT, '8'}, + {"F3", FREG(3), RFLT, '8'}, + {"F4", FREG(4), RFLT, '8'}, + {"F5", FREG(5), RFLT, '8'}, + {"F6", FREG(6), RFLT, '8'}, + {"F7", FREG(7), RFLT, '8'}, + {0} +}; + +Mach m68020 = +{ + "68020", + M68020, /* machine type */ + m68020reglist, /* register list */ + REGSIZE, /* number of bytes in reg set */ + FPREGSIZE, /* number of bytes in fp reg set */ + "PC", + "A7", + 0, /* link register */ + "a6base", /* static base register name */ + 0, /* value */ + 0x2000, /* page size */ + 0x80000000, /* kernel base */ + 0, /* kernel text mask */ + 2, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/2db.c b/utils/libmach/2db.c new file mode 100644 index 00000000..5aa61fd3 --- /dev/null +++ b/utils/libmach/2db.c @@ -0,0 +1,2084 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +/* + * 68020-specific debugger interface + */ + +static char *m68020excep(Map*, Rgetter); + +static int m68020foll(Map*, ulong, Rgetter, ulong*); +static int m68020inst(Map*, ulong, char, char*, int); +static int m68020das(Map*, ulong, char*, int); +static int m68020instlen(Map*, ulong); + +Machdata m68020mach = +{ + {0x48,0x48,0,0}, /* break point #0 instr. */ + 2, /* size of break point instr. */ + + beswab, /* convert short to local byte order */ + beswal, /* convert long to local byte order */ + beswav, /* convert vlong to local byte order */ + cisctrace, /* C traceback */ + ciscframe, /* frame finder */ + m68020excep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, + beieeedftos, + m68020foll, /* follow-set calculation */ + m68020inst, /* print instruction */ + m68020das, /* dissembler */ + m68020instlen, /* instruction size */ +}; + +/* + * 68020 exception frames + */ + +#define BPTTRAP 4 /* breakpoint gives illegal inst */ + +static char * excep[] = { + 0, /* 0 */ + 0, /* 1 */ + "bus error", /* 2 */ + "address error", /* 3 */ + "illegal instruction", /* 4 */ + "zero divide", /* 5 */ + "CHK", /* 6 */ + "TRAP", /* 7 */ + "privilege violation", /* 8 */ + "Trace", /* 9 */ + "line 1010", /* 10 */ + "line 1011", /* 11 */ + 0, /* 12 */ + "coprocessor protocol violation", /* 13 */ + 0,0,0,0,0,0,0,0,0,0, /* 14-23 */ + "spurious", /* 24 */ + "incon", /* 25 */ + "tac", /* 26 */ + "auto 3", /* 27 */ + "clock", /* 28 */ + "auto 5", /* 29 */ + "parity", /* 30 */ + "mouse", /* 31 */ + "system call", /* 32 */ + "system call 1", /* 33 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 34-47 */ + "FPCP branch", /* 48 */ + "FPCP inexact", /* 49 */ + "FPCP zero div", /* 50 */ + "FPCP underflow", /* 51 */ + "FPCP operand err", /* 52 */ + "FPCP overflow", /* 53 */ + "FPCP signal NAN", /* 54 */ +}; + +static int m68020vec; +static +struct ftype{ + short fmt; + short len; + char *name; +} ftype[] = { /* section 6.5.7 page 6-24 */ + { 0, 4*2, "Short Format" }, + { 1, 4*2, "Throwaway" }, + { 2, 6*2, "Instruction Exception" }, + { 3, 6*2, "MC68040 Floating Point Exception" }, + { 8, 29*2, "MC68010 Bus Fault" }, + { 7, 30*2, "MC68040 Bus Fault" }, + { 9, 10*2, "Coprocessor mid-Instruction" }, + { 10, 16*2, "MC68020 Short Bus Fault" }, + { 11, 46*2, "MC68020 Long Bus Fault" }, + { 0, 0, 0 } +}; + +static int +m68020ufix(Map *map) +{ + struct ftype *ft; + int i, size, vec; + ulong efl[2], stktop; + uchar *ef=(uchar*)efl; + long l; + short fvo; + + /* The kernel proc pointer on a 68020 is always + * at #8xxxxxxx; on the 68040 NeXT, the address + * is always #04xxxxxx. the sun3 port at sydney + * uses 0xf8xxxxxx to 0xffxxxxxx. + */ + m68020vec = 0; + + if (get4(map, mach->kbase, (&l)) < 0) + return -1; + if ((l&0xfc000000) == 0x04000000) /* if NeXT */ + size = 30*2; + else + size = 46*2; /* 68020 */ + USED(size); /* kept because it might be re-used later */ + + stktop = mach->kbase+mach->pgsize; + for(i=3; i<100; i++){ + if (get1(map, stktop-i*4, (uchar*)&l, 4)< 0) + return -1; + + if(machdata->swal(l) == 0xBADC0C0A){ + if (get1(map, stktop-(i-1)*4, (uchar *)&efl[0], 4) < 0) + return -1; + if (get1(map, stktop-(i-2)*4, (uchar *)&efl[1], 4) < 0) + return -1; + fvo = (ef[6]<<8)|ef[7]; + vec = fvo & 0xfff; + vec >>= 2; + if(vec >= 256) + continue; + + for(ft=ftype; ft->name; ft++) { + if(ft->fmt == ((fvo>>12) & 0xF)){ + m68020vec = vec; + return 1; + } + } + break; + } + } + return -1; +} + +static char * +m68020excep(Map *map, Rgetter rget) +{ + ulong pc; + uchar buf[4]; + + if (m68020ufix(map) < 0) + return "bad exception frame"; + + if(excep[m68020vec] == 0) + return "bad exeception type"; + + if(m68020vec == BPTTRAP) { + pc = (*rget)(map, "PC"); + if (get1(map, pc, buf, machdata->bpsize) > 0) + if(memcmp(buf, machdata->bpinst, machdata->bpsize) == 0) + return "breakpoint"; + } + return excep[m68020vec]; +} + /* 68020 Disassembler and related functions */ +/* +not supported: cpBcc, cpDBcc, cpGEN, cpScc, cpTRAPcc, cpRESTORE, cpSAVE + +opcode: 1 1 1 1 1 1 + 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +%y - register number x x x +%f - trap vector x x x +%e - destination eff addr x x x x x x +%p - conditional predicate x x x x x x +%s - size code x x +%C - cache code x x +%E - source eff addr. x x x x x x +%d - direction bit x +%c - condition code x x x x +%x - register number x x x +%b - shift count x x x +%q - daffy 3-bit quick operand or shift count x x x +%i - immediate operand <varies> +%t - offset(PC) <varies> + +word 1: 1 1 1 1 1 1 + 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +%a - register number x x x +%w - bit field width x x x x x +%L - MMU function code (SFC/DFC/D%a/#[0-3]) x x x x x +%P - conditional predicate x x x x x x +%k - k factor x x x x x x x +%m - register mask x x x x x x x x +%N - control register id x x x x x x x x x x x x +%j - (Dq != Dr) ? Dq:Dr : Dr x x x x x x +%K - dynamic k register x x x +%h - register number x x x +%I - MMU function code mask x x x x +%o - bit field offset x x x x x +%u - register number x x x +%D - float dest reg x x x +%F - (fdr==fsr) ? "F%D" :"F%B,F%D" x x x x x x +%S - float source type x x x +%B - float source register x x x +%Z - ATC level number x x x +%H - MMU register x x x x +%r - register type/number x x x x + +word 2: 1 1 1 1 1 1 + 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +%A - register number x x x +%U - register number x x x +%R - register type,number x x x x + +----------------------------------------------------------------------------- + +%a - register [word 1: 0-2] +%c - condition code [opcode: 8-11] +%d - direction [opcode: 8] +%e - destination effective address [opcode: 0-5] +%f - trap vector [opcode: 0-3] +%h - register [word 1: 5-7] +%i - immediate operand (1, 2, or 4 bytes) +%j - Dq:Dr if Dq != Dr; else Dr => Dr [word 1: 0-2] Dq [word 1: 12-14] +%k - k factor [word 1: 0-6] +%m - register mask [word 1: 0-7] +%o - bit field offset [word 1: 6-10] +%p - conditional predicate [opcode: 0-5] +%q - daffy 3-bit quick operand [opcode: 9-11] +%r - register type, [word 1: 15], register [word 1: 12-14] +%s - size [opcode: 6-7] +%t - offset beyond pc (text address) (2 or 4 bytes) +%u - register [word 1: 6-8] +%w - bit field width [word 1: 0-4] +%x - register [opcode: 9-11] +%y - register [opcode: 0-2] +%A - register [word 2: 0-2] +%B - float source register [word 1: 10-12] +%C - cache identifier [opcode: 6-7] (IC, DC, or BC) +%D - float dest reg [word 1: 7-9] +%E - dest effective address [opcode: 6-11] +%F - float dest reg == float src reg => "F%D"; else "F%B,F%D" +%H - MMU reg [word 1: 10-13] (see above & p 4-53/54) +%I - MMU function code mask [word 1: 5-8] +%K - dynamic k factor register [word 1: 4-6] +%L - MMU function code [word 1: 0-4] (SFC, DFC, D%a, or #[0-3]) +%N - control register [word 1: 0-11] +%P - conditional predicate [word 1: 0-5] +%R - register type, [word 2: 15], register [word 2: 12-14] +%S - float source type code [word 1: 10-12] +%U - register [word 2: 6-8] +%Z - ATC level number [word 1: 10-12] +%1 - Special case: EA as second operand +*/ + /* Operand classes */ +enum { + EAPI = 1, /* extended address: pre decrement only */ + EACA, /* extended address: control alterable */ + EACAD, /* extended address: control alterable or Dreg */ + EACAPI, /* extended address: control alterable or post-incr */ + EACAPD, /* extended address: control alterable or pre-decr */ + EAMA, /* extended address: memory alterable */ + EADA, /* extended address: data alterable */ + EAA, /* extended address: alterable */ + EAC, /* extended address: control addressing */ + EACPI, /* extended address: control addressing or post-incr */ + EACD, /* extended address: control addressing or Dreg */ + EAD, /* extended address: data addressing */ + EAM, /* extended address: memory addressing */ + EAM_B, /* EAM with byte immediate data */ + EADI, /* extended address: data addressing or immediate */ + EADI_L, /* EADI with long immediate data */ + EADI_W, /* EADI with word immediate data */ + EAALL, /* extended address: all modes */ + EAALL_L, /* EAALL with long immediate data */ + EAALL_W, /* EAALL with word immediate data */ + EAALL_B, /* EAALL with byte immediate date */ + /* special codes not directly used for validation */ + EAFLT, /* extended address: EADI for B, W, L, or S; else EAM */ + EADDA, /* destination extended address: EADA */ + BREAC, /* EAC operand for JMP or CALL */ + OP8, /* low 8 bits of op word */ + I8, /* low 8-bits of first extension word */ + I16, /* 16 bits in first extension word */ + I32, /* 32 bits in first and second extension words */ + IV, /* 8, 16 or 32 bit data in first & 2nd extension words */ + C16, /* CAS2 16 bit immediate with bits 9-11 & 3-5 zero */ + BR8, /* 8 bits in op word or 16 or 32 bits in extension words + branch instruction format (p. 2-25) */ + BR16, /* 16-bit branch displacement */ + BR32, /* 32-bit branch displacement */ + STACK, /* return PC on stack - follow set only */ +}; + /* validation bit masks for various EA classes */ +enum { + Dn = 0x0001, /* Data register */ + An = 0x0002, /* Address register */ + Ind = 0x0004, /* Address register indirect */ + Pinc = 0x0008, /* Address register indirect post-increment */ + Pdec = 0x0010, /* Address register indirect pre-decrement */ + Bdisp = 0x0020, /* Base/Displacement in all its forms */ + PCrel = 0x0040, /* PC relative addressing in all its forms */ + Imm = 0x0080, /* Immediate data */ + Abs = 0x0100, /* Absolute */ +}; + /* EA validation table indexed by operand class number */ + +static short validea[] = +{ + 0, /* none */ + Pdec, /* EAPI */ + Abs|Bdisp|Ind, /* EACA */ + Abs|Bdisp|Ind|Dn, /* EACAD */ + Abs|Bdisp|Pinc|Ind, /* EACAPI */ + Abs|Bdisp|Pdec|Ind, /* EACAPD */ + Abs|Bdisp|Pdec|Pinc|Ind, /* EAMA */ + Abs|Bdisp|Pdec|Pinc|Ind|Dn, /* EADA */ + Abs|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAA */ + Abs|PCrel|Bdisp|Ind, /* EAC */ + Abs|PCrel|Bdisp|Pinc|Ind, /* EACPI */ + Abs|PCrel|Bdisp|Ind|Dn, /* EACD */ + Abs|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EAD */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind, /* EAM */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind, /* EAM_B */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI_L */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|Dn, /* EADI_W */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_L */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_W */ + Abs|Imm|PCrel|Bdisp|Pdec|Pinc|Ind|An|Dn, /* EAALL_B */ +}; + /* EA types */ +enum +{ + Dreg, /* Dn */ + Areg, /* An */ + AInd, /* (An) */ + APdec, /* -(An) */ + APinc, /* (An)+ */ + ADisp, /* Displacement beyond (An) */ + BXD, /* Base, Index, Displacement */ + PDisp, /* Displacement beyond PC */ + PXD, /* PC, Index, Displacement */ + ABS, /* absolute */ + IMM, /* immediate */ + IREAL, /* single precision real immediate */ + IEXT, /* extended precision real immediate */ + IPACK, /* packed real immediate */ + IDBL, /* double precision real immediate */ +}; + +typedef struct optable Optable; +typedef struct operand Operand; +typedef struct inst Inst; + +struct optable +{ + ushort opcode; + ushort mask0; + ushort op2; + ushort mask1; + char opdata[2]; + char *format; +}; + +struct operand +{ + int eatype; + short ext; + union { + long immediate; /* sign-extended integer byte/word/long */ + struct { /* index mode displacements */ + long disp; + long outer; + } s0; + char floater[24]; /* floating point immediates */ + } u0; +}; + +struct inst +{ + int n; /* # bytes in instruction */ + ulong addr; /* addr of start of instruction */ + ushort raw[4+12]; /* longest instruction: 24 byte packed immediate */ + Operand and[2]; + char *end; /* end of print buffer */ + char *curr; /* current fill point in buffer */ + char *errmsg; +}; + /* class 0: bit field, MOVEP & immediate instructions */ +static Optable t0[] = { +{ 0x003c, 0xffff, 0x0000, 0xff00, {I8}, "ORB %i,CCR" }, +{ 0x007c, 0xffff, 0x0000, 0x0000, {I16}, "ORW %i,SR" }, +{ 0x023c, 0xffff, 0x0000, 0xff00, {I8}, "ANDB %i,CCR" }, +{ 0x027c, 0xffff, 0x0000, 0x0000, {I16}, "ANDW %i,SR" }, +{ 0x0a3c, 0xffff, 0x0000, 0xff00, {I8}, "EORB %i,CCR" }, +{ 0x0a7c, 0xffff, 0x0000, 0x0000, {I16}, "EORW %i,SR" }, +{ 0x0cfc, 0xffff, 0x0000, 0x0000, {C16,C16}, "CAS2W R%a:R%A,R%u:R%U,(%r):(%R)"} , +{ 0x0efc, 0xffff, 0x0000, 0x0000, {C16,C16}, "CAS2L R%a:R%A,R%u:R%U,(%r):(%R)"} , + +{ 0x06c0, 0xfff8, 0x0000, 0x0000, {0}, "RTM R%y" }, +{ 0x06c8, 0xfff8, 0x0000, 0x0000, {0}, "RTM A%y" }, +{ 0x0800, 0xfff8, 0x0000, 0x0000, {I16}, "BTSTL %i,R%y" }, +{ 0x0840, 0xfff8, 0x0000, 0x0000, {I16}, "BCHGL %i,R%y" }, +{ 0x0880, 0xfff8, 0x0000, 0x0000, {I16}, "BCLRL %i,R%y" }, + +{ 0x00c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2B %e,%r" }, +{ 0x00c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2B %e,%r" }, +{ 0x02c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2W %e,%r" }, +{ 0x02c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2W %e,%r" }, +{ 0x04c0, 0xffc0, 0x0000, 0x0fff, {EAC}, "CMP2L %e,%r" }, +{ 0x04c0, 0xffc0, 0x0800, 0x0fff, {EAC}, "CHK2L %e,%r" }, +{ 0x06c0, 0xffc0, 0x0000, 0x0000, {I16, BREAC}, "CALLM %i,%e" }, +{ 0x0800, 0xffc0, 0x0000, 0x0000, {I16, EAD}, "BTSTB %i,%e" }, +{ 0x0840, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BCHG %i,%e" }, +{ 0x0880, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BCLR %i,%e" }, +{ 0x08c0, 0xffc0, 0x0000, 0x0000, {I16, EADA}, "BSET %i,%e" }, +{ 0x0ac0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASB R%a,R%u,%e" }, +{ 0x0cc0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASW R%a,R%u,%e" }, +{ 0x0ec0, 0xffc0, 0x0000, 0xfe38, {EAMA}, "CASL R%a,R%u,%e" }, + +{ 0x0000, 0xff00, 0x0000, 0x0000, {IV, EADA}, "OR%s %i,%e" }, +{ 0x0200, 0xff00, 0x0000, 0x0000, {IV, EADA}, "AND%s %i,%e" }, +{ 0x0400, 0xff00, 0x0000, 0x0000, {IV, EADA}, "SUB%s %i,%e" }, +{ 0x0600, 0xff00, 0x0000, 0x0000, {IV, EADA}, "ADD%s %i,%e" }, +{ 0x0a00, 0xff00, 0x0000, 0x0000, {IV, EADA}, "EOR%s %i,%e" }, +{ 0x0c00, 0xff00, 0x0000, 0x0000, {IV, EAD}, "CMP%s %i,%e" }, +{ 0x0e00, 0xff00, 0x0000, 0x0800, {EAMA}, "MOVES%s %e,%r" }, +{ 0x0e00, 0xff00, 0x0800, 0x0800, {EAMA}, "MOVES%s %r,%e" }, + +{ 0x0108, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPW (%i,A%y),R%x" }, +{ 0x0148, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPL (%i,A%y),R%x" }, +{ 0x0188, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPW R%x,(%i,A%y)" }, +{ 0x01c8, 0xf1f8, 0x0000, 0x0000, {I16}, "MOVEPL R%x,(%i,A%y)" }, +{ 0x0100, 0xf1f8, 0x0000, 0x0000, {0}, "BTSTL R%x,R%y" }, +{ 0x0140, 0xf1f8, 0x0000, 0x0000, {0}, "BCHGL R%x,R%y" }, +{ 0x0180, 0xf1f8, 0x0000, 0x0000, {0}, "BCLRL R%x,R%y" }, +{ 0x01c0, 0xf1f8, 0x0000, 0x0000, {0}, "BSET R%x,R%y" }, + +{ 0x0100, 0xf1c0, 0x0000, 0x0000, {EAM_B}, "BTSTB R%x,%e" }, +{ 0x0140, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BCHG R%x,%e" }, +{ 0x0180, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BCLR R%x,%e" }, +{ 0x01c0, 0xf1c0, 0x0000, 0x0000, {EAMA}, "BSET R%x,%e" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 1: move byte */ +static Optable t1[] = { +{ 0x1000, 0xf000, 0x0000, 0x0000, {EAALL_B,EADDA},"MOVB %e,%E" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 2: move long */ +static Optable t2[] = { +{ 0x2040, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "MOVL %e,A%x" }, + +{ 0x2000, 0xf000, 0x0000, 0x0000, {EAALL_L,EADDA},"MOVL %e,%E" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 3: move word */ +static Optable t3[] = { +{ 0x3040, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "MOVW %e,A%x" }, + +{ 0x3000, 0xf000, 0x0000, 0x0000, {EAALL_W,EADDA},"MOVW %e,%E" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 4: miscellaneous */ +static Optable t4[] = { +{ 0x4e75, 0xffff, 0x0000, 0x0000, {STACK}, "RTS" }, +{ 0x4e77, 0xffff, 0x0000, 0x0000, {STACK}, "RTR" }, +{ 0x4afc, 0xffff, 0x0000, 0x0000, {0}, "ILLEGAL" }, +{ 0x4e71, 0xffff, 0x0000, 0x0000, {0}, "NOP" }, +{ 0x4e74, 0xffff, 0x0000, 0x0000, {I16, STACK}, "RTD %i" }, +{ 0x4e76, 0xffff, 0x0000, 0x0000, {0}, "TRAPV" }, +{ 0x4e70, 0xffff, 0x0000, 0x0000, {0}, "RESET" }, +{ 0x4e72, 0xffff, 0x0000, 0x0000, {I16}, "STOP %i" }, +{ 0x4e73, 0xffff, 0x0000, 0x0000, {0}, "RTE" }, +{ 0x4e7a, 0xffff, 0x0000, 0x0000, {I16}, "MOVEL %N,%r" }, +{ 0x4e7b, 0xffff, 0x0000, 0x0000, {I16}, "MOVEL %r,%N" }, + +{ 0x4808, 0xfff8, 0x0000, 0x0000, {I32}, "LINKL A%y,%i" }, +{ 0x4840, 0xfff8, 0x0000, 0x0000, {0}, "SWAPW R%y" }, +{ 0x4848, 0xfff8, 0x0000, 0x0000, {0}, "BKPT #%y" }, +{ 0x4880, 0xfff8, 0x0000, 0x0000, {0}, "EXTW R%y" }, +{ 0x48C0, 0xfff8, 0x0000, 0x0000, {0}, "EXTL R%y" }, +{ 0x49C0, 0xfff8, 0x0000, 0x0000, {0}, "EXTBL R%y" }, +{ 0x4e50, 0xfff8, 0x0000, 0x0000, {I16}, "LINKW A%y,%i" }, +{ 0x4e58, 0xfff8, 0x0000, 0x0000, {0}, "UNLK A%y" }, +{ 0x4e60, 0xfff8, 0x0000, 0x0000, {0}, "MOVEL (A%y),USP" }, +{ 0x4e68, 0xfff8, 0x0000, 0x0000, {0}, "MOVEL USP,(A%y)" }, + +{ 0x4e40, 0xfff0, 0x0000, 0x0000, {0}, "SYS %f" }, + +{ 0x40c0, 0xffc0, 0x0000, 0x0000, {EADA}, "MOVW SR,%e" }, +{ 0x42c0, 0xffc0, 0x0000, 0x0000, {EADA}, "MOVW CCR,%e" }, +{ 0x44c0, 0xffc0, 0x0000, 0x0000, {EADI_W}, "MOVW %e,CCR" }, +{ 0x46c0, 0xffc0, 0x0000, 0x0000, {EADI_W}, "MOVW %e,SR" }, +{ 0x4800, 0xffc0, 0x0000, 0x0000, {EADA}, "NBCDB %e" }, +{ 0x4840, 0xffc0, 0x0000, 0x0000, {EAC}, "PEA %e" }, +{ 0x4880, 0xffc0, 0x0000, 0x0000, {I16, EACAPD},"MOVEMW %i,%e" }, +{ 0x48c0, 0xffc0, 0x0000, 0x0000, {I16, EACAPD},"MOVEML %i,%e" }, +{ 0x4ac0, 0xffc0, 0x0000, 0x0000, {EADA}, "TAS %e" }, +{ 0x4a00, 0xffc0, 0x0000, 0x0000, {EAD}, "TSTB %e" }, +{ 0x4c00, 0xffc0, 0x0000, 0x8ff8, {EADI_L}, "MULUL %e,%r" }, +{ 0x4c00, 0xffc0, 0x0400, 0x8ff8, {EADI_L}, "MULUL %e,R%a:%r" }, +{ 0x4c00, 0xffc0, 0x0800, 0x8ff8, {EADI_L}, "MULSL %e,%r" }, +{ 0x4c00, 0xffc0, 0x0c00, 0x8ff8, {EADI_L}, "MULSL %e,R%a:%r" }, +{ 0x4c40, 0xffc0, 0x0000, 0x8ff8, {EADI_L}, "DIVUL %e,%j" }, +{ 0x4c40, 0xffc0, 0x0400, 0x8ff8, {EADI_L}, "DIVUD %e,%r:R%a" }, +{ 0x4c40, 0xffc0, 0x0800, 0x8ff8, {EADI_L}, "DIVSL %e,%j" }, +{ 0x4c40, 0xffc0, 0x0c00, 0x8ff8, {EADI_L}, "DIVSD %e,%r:R%a" }, +{ 0x4c80, 0xffc0, 0x0000, 0x0000, {I16, EACPI}, "MOVEMW %1,%i" }, +{ 0x4cc0, 0xffc0, 0x0000, 0x0000, {I16, EACPI}, "MOVEML %1,%i" }, +{ 0x4e80, 0xffc0, 0x0000, 0x0000, {BREAC}, "JSR %e" }, +{ 0x4ec0, 0xffc0, 0x0000, 0x0000, {BREAC}, "JMP %e" }, + +{ 0x4000, 0xff00, 0x0000, 0x0000, {EADA}, "NEGX%s %e" }, +{ 0x4200, 0xff00, 0x0000, 0x0000, {EADA}, "CLR%s %e" }, +{ 0x4400, 0xff00, 0x0000, 0x0000, {EADA}, "NEG%s %e" }, +{ 0x4600, 0xff00, 0x0000, 0x0000, {EADA}, "NOT%s %e" }, +{ 0x4a00, 0xff00, 0x0000, 0x0000, {EAALL}, "TST%s %e" }, + +{ 0x4180, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "CHKW %e,R%x" }, +{ 0x41c0, 0xf1c0, 0x0000, 0x0000, {EAC}, "LEA %e,A%x" }, +{ 0x4100, 0xf1c0, 0x0000, 0x0000, {EADI_L}, "CHKL %e,R%x" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 5: miscellaneous quick, branch & trap instructions */ +static Optable t5[] = { +{ 0x5000, 0xf1c0, 0x0000, 0x0000, {EADA}, "ADDB $Q#%q,%e" }, +{ 0x5100, 0xf1c0, 0x0000, 0x0000, {EADA}, "SUBB $Q#%q,%e" }, + +{ 0x50c8, 0xf1f8, 0x0000, 0x0000, {BR16}, "DB%c R%y,%t" }, +{ 0x51c8, 0xf1f8, 0x0000, 0x0000, {BR16}, "DB%c R%y,%t" }, + +{ 0x5000, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDB $Q#%q,%e" }, +{ 0x5040, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDW $Q#%q,%e" }, +{ 0x5080, 0xf1c0, 0x0000, 0x0000, {EAA}, "ADDL $Q#%q,%e" }, +{ 0x5100, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBB $Q#%q,%e" }, +{ 0x5140, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBW $Q#%q,%e" }, +{ 0x5180, 0xf1c0, 0x0000, 0x0000, {EAA}, "SUBL $Q#%q,%e" }, + +{ 0x50fa, 0xf0ff, 0x0000, 0x0000, {I16}, "TRAP%cW %i" }, +{ 0x50fb, 0xf0ff, 0x0000, 0x0000, {I32}, "TRAP%cL %i" }, +{ 0x50fc, 0xf0ff, 0x0000, 0x0000, {0}, "TRAP%c" }, + +{ 0x50c0, 0xf0c0, 0x0000, 0x0000, {EADA}, "S%c %e" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 6: branch instructions */ +static Optable t6[] = { +{ 0x6000, 0xff00, 0x0000, 0x0000, {BR8}, "BRA %t" }, +{ 0x6100, 0xff00, 0x0000, 0x0000, {BR8}, "BSR %t" }, +{ 0x6000, 0xf000, 0x0000, 0x0000, {BR8}, "B%c %t" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 7: move quick */ +static Optable t7[] = { +{ 0x7000, 0xf100, 0x0000, 0x0000, {OP8}, "MOVL $Q%i,R%x" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 8: BCD operations, DIV, and OR instructions */ +static Optable t8[] = { +{ 0x8100, 0xf1f8, 0x0000, 0x0000, {0}, "SBCDB R%y,R%x" }, +{ 0x8108, 0xf1f8, 0x0000, 0x0000, {0}, "SBCDB -(A%y),-(A%x)" }, +{ 0x8140, 0xf1f8, 0x0000, 0x0000, {I16}, "PACK R%y,R%x,%i" }, +{ 0x8148, 0xf1f8, 0x0000, 0x0000, {I16}, "PACK -(A%y),-(A%x),%i" }, +{ 0x8180, 0xf1f8, 0x0000, 0x0000, {I16}, "UNPK R%y,R%x,%i" }, +{ 0x8188, 0xf1f8, 0x0000, 0x0000, {I16}, "UNPK -(A%y),-(A%x),%i" }, + +{ 0x80c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "DIVUW %e,R%x" }, +{ 0x81c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "DIVSW %e,R%x" }, + +{ 0x8000, 0xf100, 0x0000, 0x0000, {EADI}, "OR%s %e,R%x" }, +{ 0x8100, 0xf100, 0x0000, 0x0000, {EAMA}, "OR%s R%x,%e" }, +{ 0,0,0,0,{0},0 }, +}; + /* class 9: subtract instruction */ +static Optable t9[] = { +{ 0x90c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "SUBW %e,A%x" }, +{ 0x91c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "SUBL %e,A%x" }, + +{ 0x9100, 0xf138, 0x0000, 0x0000, {0}, "SUBX%s R%y,R%x" }, +{ 0x9108, 0xf138, 0x0000, 0x0000, {0}, "SUBX%s -(A%y),-(A%x)" }, + +{ 0x9000, 0xf100, 0x0000, 0x0000, {EAALL}, "SUB%s %e,R%x" }, +{ 0x9100, 0xf100, 0x0000, 0x0000, {EAMA}, "SUB%s R%x,%e" }, +{ 0,0,0,0,{0},0 }, +}; + /* class b: CMP & EOR */ +static Optable tb[] = { +{ 0xb000, 0xf1c0, 0x0000, 0x0000, {EADI}, "CMPB R%x,%e" }, +{ 0xb040, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "CMPW R%x,%e" }, +{ 0xb080, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "CMPL R%x,%e" }, +{ 0xb0c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "CMPW A%x,%e" }, +{ 0xb1c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "CMPL A%x,%e" }, + +{ 0xb108, 0xf138, 0x0000, 0x0000, {0}, "CMP%s (A%y)+,(A%x)+" }, + +{ 0xb100, 0xf100, 0x0000, 0x0000, {EADA}, "EOR%s %e,R%x" }, +{ 0,0,0,0,{0},0 }, +}; + /* class c: AND, MUL, BCD & Exchange */ +static Optable tc[] = { +{ 0xc100, 0xf1f8, 0x0000, 0x0000, {0}, "ABCDB R%y,R%x" }, +{ 0xc108, 0xf1f8, 0x0000, 0x0000, {0}, "ABCDB -(A%y),-(A%x)" }, +{ 0xc140, 0xf1f8, 0x0000, 0x0000, {0}, "EXG R%x,R%y" }, +{ 0xc148, 0xf1f8, 0x0000, 0x0000, {0}, "EXG A%x,A%y" }, +{ 0xc188, 0xf1f8, 0x0000, 0x0000, {0}, "EXG R%x,A%y" }, + +{ 0xc0c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "MULUW %e,R%x" }, +{ 0xc1c0, 0xf1c0, 0x0000, 0x0000, {EADI_W}, "MULSW %e,R%x" }, + +{ 0xc000, 0xf100, 0x0000, 0x0000, {EADI}, "AND%s %e,R%x" }, +{ 0xc100, 0xf100, 0x0000, 0x0000, {EAMA}, "AND%s R%x,%e" }, +{ 0,0,0,0,{0},0 }, +}; + /* class d: addition */ +static Optable td[] = { +{ 0xd000, 0xf1c0, 0x0000, 0x0000, {EADI}, "ADDB %e,R%x" }, +{ 0xd0c0, 0xf1c0, 0x0000, 0x0000, {EAALL_W}, "ADDW %e,A%x" }, +{ 0xd1c0, 0xf1c0, 0x0000, 0x0000, {EAALL_L}, "ADDL %e,A%x" }, + +{ 0xd100, 0xf138, 0x0000, 0x0000, {0}, "ADDX%s R%y,R%x" }, +{ 0xd108, 0xf138, 0x0000, 0x0000, {0}, "ADDX%s -(A%y),-(A%x)" }, + +{ 0xd000, 0xf100, 0x0000, 0x0000, {EAALL}, "ADD%s %e,R%x" }, +{ 0xd100, 0xf100, 0x0000, 0x0000, {EAMA}, "ADD%s R%x,%e" }, +{ 0,0,0,0,{0},0 }, +}; + /* class e: shift, rotate, bit field operations */ +static Optable te[] = { +{ 0xe8c0, 0xffc0, 0x0820, 0xfe38, {EACD}, "BFTST %e{R%u:R%a}" }, +{ 0xe8c0, 0xffc0, 0x0800, 0xfe20, {EACD}, "BFTST %e{R%u:%w}" }, +{ 0xe8c0, 0xffc0, 0x0020, 0xf838, {EACD}, "BFTST %e{%o:R%a}" }, +{ 0xe8c0, 0xffc0, 0x0000, 0xf820, {EACD}, "BFTST %e{%o:%w}" }, + +{ 0xe9c0, 0xffc0, 0x0820, 0x8e38, {EACD}, "BFEXTU %e{R%u:R%a},%r" }, +{ 0xe9c0, 0xffc0, 0x0800, 0x8e20, {EACD}, "BFEXTU %e{R%u:%w},%r" }, +{ 0xe9c0, 0xffc0, 0x0020, 0x8838, {EACD}, "BFEXTU %e{%o:R%a},%r" }, +{ 0xe9c0, 0xffc0, 0x0000, 0x8820, {EACD}, "BFEXTU %e{%o:%w},%r" }, + +{ 0xeac0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFCHG %e{R%u:R%a}" }, +{ 0xeac0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFCHG %e{R%u:%w}" }, +{ 0xeac0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFCHG %e{%o:R%a}" }, +{ 0xeac0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFCHG %e{%o:%w}" }, + +{ 0xebc0, 0xffc0, 0x0820, 0x8e38, {EACD}, "BFEXTS %e{R%u:R%a},%r" }, +{ 0xebc0, 0xffc0, 0x0800, 0x8e20, {EACD}, "BFEXTS %e{R%u:%w},%r" }, +{ 0xebc0, 0xffc0, 0x0020, 0x8838, {EACD}, "BFEXTS %e{%o:R%a},%r" }, +{ 0xebc0, 0xffc0, 0x0000, 0x8820, {EACD}, "BFEXTS %e{%o:%w},%r" }, + +{ 0xecc0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFCLR %e{R%u:R%a}" }, +{ 0xecc0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFCLR %e{R%u:%w}" }, +{ 0xecc0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFCLR %e{%o:R%a}" }, +{ 0xecc0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFCLR %e{%o:%w}" }, + +{ 0xedc0, 0xffc0, 0x0820, 0x8e38, {EACAD}, "BFFFO %e{R%u:R%a},%r" }, +{ 0xedc0, 0xffc0, 0x0800, 0x8e20, {EACAD}, "BFFFO %e{R%u:%w},%r" }, +{ 0xedc0, 0xffc0, 0x0020, 0x8838, {EACAD}, "BFFFO %e{%o:R%a},%r" }, +{ 0xedc0, 0xffc0, 0x0000, 0x8820, {EACAD}, "BFFFO %e{%o:%w},%r" }, + +{ 0xeec0, 0xffc0, 0x0820, 0xfe38, {EACAD}, "BFSET %e{R%u:R%a}" }, +{ 0xeec0, 0xffc0, 0x0800, 0xfe20, {EACAD}, "BFSET %e{R%u:%w}" }, +{ 0xeec0, 0xffc0, 0x0020, 0xf838, {EACAD}, "BFSET %e{%o:R%a}" }, +{ 0xeec0, 0xffc0, 0x0000, 0xf820, {EACAD}, "BFSET %e{%o:%w}" }, + +{ 0xefc0, 0xffc0, 0x0820, 0x8e38, {EACAD}, "BFINS %r,%e{R%u:R%a}" }, +{ 0xefc0, 0xffc0, 0x0800, 0x8e20, {EACAD}, "BFINS %r,%e{R%u:%w}" }, +{ 0xefc0, 0xffc0, 0x0020, 0x8838, {EACAD}, "BFINS %r,%e{%o:R%a}" }, +{ 0xefc0, 0xffc0, 0x0000, 0x8820, {EACAD}, "BFINS %r,%e{%o:%w}" }, + +{ 0xe0c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "AS%dW %e" }, +{ 0xe2c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "LS%dW %e" }, +{ 0xe4c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "ROX%dW %e" }, +{ 0xe6c0, 0xfec0, 0x0000, 0x0000, {EAMA}, "RO%dW %e" }, + +{ 0xe000, 0xf038, 0x0000, 0x0000, {0}, "AS%d%s #%q,R%y" }, +{ 0xe008, 0xf038, 0x0000, 0x0000, {0}, "LS%d%s #%q,R%y" }, +{ 0xe010, 0xf038, 0x0000, 0x0000, {0}, "ROX%d%s #%q,R%y" }, +{ 0xe018, 0xf038, 0x0000, 0x0000, {0}, "RO%d%s #%q,R%y" }, +{ 0xe020, 0xf038, 0x0000, 0x0000, {0}, "AS%d%s R%x,R%y" }, +{ 0xe028, 0xf038, 0x0000, 0x0000, {0}, "LS%d%s R%x,R%y" }, +{ 0xe030, 0xf038, 0x0000, 0x0000, {0}, "ROX%d%s R%x,R%y" }, +{ 0xe038, 0xf038, 0x0000, 0x0000, {0}, "RO%d%s R%x,R%y" }, +{ 0,0,0,0,{0},0 }, +}; + /* class f: coprocessor and mmu instructions */ +static Optable tf[] = { +{ 0xf280, 0xffff, 0x0000, 0xffff, {0}, "FNOP" }, +{ 0xf200, 0xffff, 0x5c00, 0xfc00, {0}, "FMOVECRX %k,F%D" }, +{ 0xf27a, 0xffff, 0x0000, 0xffc0, {I16}, "FTRAP%P %i" }, +{ 0xf27b, 0xffff, 0x0000, 0xffc0, {I32}, "FTRAP%P %i" }, +{ 0xf27c, 0xffff, 0x0000, 0xffc0, {0}, "FTRAP%P" }, + +{ 0xf248, 0xfff8, 0x0000, 0xffc0, {BR16}, "FDB%P R%y,%t" }, +{ 0xf620, 0xfff8, 0x8000, 0x8fff, {0}, "MOVE16 (A%y)+,(%r)+" }, +{ 0xf500, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHN (A%y)" }, +{ 0xf508, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSH (A%y)" }, +{ 0xf510, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHAN" }, +{ 0xf518, 0xfff8, 0x0000, 0x0000, {0}, "PFLUSHA" }, +{ 0xf548, 0xfff8, 0x0000, 0x0000, {0}, "PTESTW (A%y)" }, +{ 0xf568, 0xfff8, 0x0000, 0x0000, {0}, "PTESTR (A%y)" }, +{ 0xf600, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 (A%y)+,$%i" }, +{ 0xf608, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 $%i,(A%y)-" }, +{ 0xf610, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 (A%y),$%i" }, +{ 0xf618, 0xfff8, 0x0000, 0x0000, {I32}, "MOVE16 $%i,(A%y)" }, + +{ 0xf000, 0xffc0, 0x0800, 0xffff, {EACA}, "PMOVE %e,TT0" }, +{ 0xf000, 0xffc0, 0x0900, 0xffff, {EACA}, "PMOVEFD %e,TT0" }, +{ 0xf000, 0xffc0, 0x0a00, 0xffff, {EACA}, "PMOVE TT0,%e" }, +{ 0xf000, 0xffc0, 0x0b00, 0xffff, {EACA}, "PMOVEFD TT0,%e" }, +{ 0xf000, 0xffc0, 0x0c00, 0xffff, {EACA}, "PMOVE %e,TT1" }, +{ 0xf000, 0xffc0, 0x0d00, 0xffff, {EACA}, "PMOVEFD %e,TT1" }, +{ 0xf000, 0xffc0, 0x0e00, 0xffff, {EACA}, "PMOVE TT1,%e" }, +{ 0xf000, 0xffc0, 0x0f00, 0xffff, {EACA}, "PMOVEFD TT1,%e" }, +{ 0xf000, 0xffc0, 0x2400, 0xffff, {0}, "PFLUSHA" }, +{ 0xf000, 0xffc0, 0x2800, 0xffff, {EACA}, "PVALID VAL,%e" }, +{ 0xf000, 0xffc0, 0x6000, 0xffff, {EACA}, "PMOVE %e,MMUSR" }, +{ 0xf000, 0xffc0, 0x6200, 0xffff, {EACA}, "PMOVE MMUSR,%e" }, +{ 0xf000, 0xffc0, 0x2800, 0xfff8, {EACA}, "PVALID A%a,%e" }, +{ 0xf000, 0xffc0, 0x2000, 0xffe0, {EACA}, "PLOADW %L,%e" }, +{ 0xf000, 0xffc0, 0x2200, 0xffe0, {EACA}, "PLOADR %L,%e" }, +{ 0xf000, 0xffc0, 0x8000, 0xffe0, {EACA}, "PTESTW %L,%e,#0" }, +{ 0xf000, 0xffc0, 0x8200, 0xffe0, {EACA}, "PTESTR %L,%e,#0" }, +{ 0xf000, 0xffc0, 0x3000, 0xfe00, {0}, "PFLUSH %L,#%I" }, +{ 0xf000, 0xffc0, 0x3800, 0xfe00, {EACA}, "PFLUSH %L,#%I,%e" }, +{ 0xf000, 0xffc0, 0x8000, 0xe300, {EACA}, "PTESTW %L,%e,#%Z" }, +{ 0xf000, 0xffc0, 0x8100, 0xe300, {EACA}, "PTESTW %L,%e,#%Z,A%h" }, +{ 0xf000, 0xffc0, 0x8200, 0xe300, {EACA}, "PTESTR %L,%e,#%Z" }, +{ 0xf000, 0xffc0, 0x8300, 0xe300, {EACA}, "PTESTR %L,%e,#%Z,A%h" }, +{ 0xf000, 0xffc0, 0x4000, 0xc3ff, {EACA}, "PMOVE %e,%H" }, +{ 0xf000, 0xffc0, 0x4100, 0xc3ff, {EACA}, "PMOVEFD %e,%H" }, +{ 0xf000, 0xffc0, 0x4200, 0xc3ff, {EACA}, "PMOVE %H,%e" }, + + /* floating point (coprocessor 1)*/ + +{ 0xf200, 0xffc0, 0x8400, 0xffff, {EAALL_L}, "FMOVEL %e,FPIAR" }, +{ 0xf200, 0xffc0, 0x8800, 0xffff, {EADI_L}, "FMOVEL %e,FPSR" }, +{ 0xf200, 0xffc0, 0x9000, 0xffff, {EADI_L}, "FMOVEL %e,FPCR" }, +{ 0xf200, 0xffc0, 0xa400, 0xffff, {EAA}, "FMOVEL FPIAR,%e" }, +{ 0xf200, 0xffc0, 0xa800, 0xffff, {EADA}, "FMOVEL FPSR,%e" }, +{ 0xf200, 0xffc0, 0xb000, 0xffff, {EADA}, "FMOVEL FPCR,%e" }, + +{ 0xf240, 0xffc0, 0x0000, 0xffc0, {EADA}, "FS%P %e" }, + +{ 0xf200, 0xffc0, 0xd000, 0xff00, {EACPI}, "FMOVEMX %e,%m" }, +{ 0xf200, 0xffc0, 0xd800, 0xff00, {EACPI}, "FMOVEMX %e,R%K" }, +{ 0xf200, 0xffc0, 0xe000, 0xff00, {EAPI}, "FMOVEMX %m,-(A%y)" }, +{ 0xf200, 0xffc0, 0xe800, 0xff00, {EAPI}, "FMOVEMX R%K,-(A%y)" }, +{ 0xf200, 0xffc0, 0xf000, 0xff00, {EACAPD}, "FMOVEMX %m,%e" }, +{ 0xf200, 0xffc0, 0xf800, 0xff00, {EACAPD}, "FMOVEMX R%K,%e" }, + +{ 0xf200, 0xffc0, 0x6800, 0xfc00, {EAMA}, "FMOVEX F%D,%e" }, +{ 0xf200, 0xffc0, 0x6c00, 0xfc00, {EAMA}, "FMOVEP F%D,%e,{%k}" }, +{ 0xf200, 0xffc0, 0x7400, 0xfc00, {EAMA}, "FMOVED F%D,%e" }, +{ 0xf200, 0xffc0, 0x7c00, 0xfc00, {EAMA}, "FMOVEP F%D,%e,{R%K}" }, + +{ 0xf200, 0xffc0, 0x8000, 0xe3ff, {EAM}, "FMOVEML #%B,%e" }, +{ 0xf200, 0xffc0, 0xa000, 0xe3ff, {EAMA}, "FMOVEML %e,#%B" }, + +{ 0xf200, 0xffc0, 0x0000, 0xe07f, {0}, "FMOVE F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0001, 0xe07f, {0}, "FINTX %F" }, +{ 0xf200, 0xffc0, 0x0002, 0xe07f, {0}, "FSINHX %F" }, +{ 0xf200, 0xffc0, 0x0003, 0xe07f, {0}, "FINTRZ %F" }, +{ 0xf200, 0xffc0, 0x0004, 0xe07f, {0}, "FSQRTX %F" }, +{ 0xf200, 0xffc0, 0x0006, 0xe07f, {0}, "FLOGNP1X %F" }, +{ 0xf200, 0xffc0, 0x0009, 0xe07f, {0}, "FTANHX %F" }, +{ 0xf200, 0xffc0, 0x000a, 0xe07f, {0}, "FATANX %F" }, +{ 0xf200, 0xffc0, 0x000c, 0xe07f, {0}, "FASINX %F" }, +{ 0xf200, 0xffc0, 0x000d, 0xe07f, {0}, "FATANHX %F" }, +{ 0xf200, 0xffc0, 0x000e, 0xe07f, {0}, "FSINX %F" }, +{ 0xf200, 0xffc0, 0x000f, 0xe07f, {0}, "FTANX %F" }, +{ 0xf200, 0xffc0, 0x0010, 0xe07f, {0}, "FETOXX %F" }, +{ 0xf200, 0xffc0, 0x0011, 0xe07f, {0}, "FTWOTOXX %F" }, +{ 0xf200, 0xffc0, 0x0012, 0xe07f, {0}, "FTENTOXX %F" }, +{ 0xf200, 0xffc0, 0x0014, 0xe07f, {0}, "FLOGNX %F" }, +{ 0xf200, 0xffc0, 0x0015, 0xe07f, {0}, "FLOG10X %F" }, +{ 0xf200, 0xffc0, 0x0016, 0xe07f, {0}, "FLOG2X %F" }, +{ 0xf200, 0xffc0, 0x0018, 0xe07f, {0}, "FABSX %F" }, +{ 0xf200, 0xffc0, 0x0019, 0xe07f, {0}, "FCOSHX %F" }, +{ 0xf200, 0xffc0, 0x001a, 0xe07f, {0}, "FNEGX %F" }, +{ 0xf200, 0xffc0, 0x001c, 0xe07f, {0}, "FACOSX %F" }, +{ 0xf200, 0xffc0, 0x001d, 0xe07f, {0}, "FCOSX %F" }, +{ 0xf200, 0xffc0, 0x001e, 0xe07f, {0}, "FGETEXPX %F" }, +{ 0xf200, 0xffc0, 0x001f, 0xe07f, {0}, "FGETMANX %F" }, +{ 0xf200, 0xffc0, 0x0020, 0xe07f, {0}, "FDIVX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0021, 0xe07f, {0}, "FMODX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0022, 0xe07f, {0}, "FADDX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0023, 0xe07f, {0}, "FMULX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0024, 0xe07f, {0}, "FSGLDIVX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0025, 0xe07f, {0}, "FREMX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0026, 0xe07f, {0}, "FSCALEX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0027, 0xe07f, {0}, "FSGLMULX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0028, 0xe07f, {0}, "FSUBX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0038, 0xe07f, {0}, "FCMPX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x003a, 0xe07f, {0}, "FTSTX F%B" }, +{ 0xf200, 0xffc0, 0x0040, 0xe07f, {0}, "FSMOVE F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0041, 0xe07f, {0}, "FSSQRTX %F"}, +{ 0xf200, 0xffc0, 0x0044, 0xe07f, {0}, "FDMOVE F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0045, 0xe07f, {0}, "FDSQRTX %F" }, +{ 0xf200, 0xffc0, 0x0058, 0xe07f, {0}, "FSABSX %F" }, +{ 0xf200, 0xffc0, 0x005a, 0xe07f, {0}, "FSNEGX %F" }, +{ 0xf200, 0xffc0, 0x005c, 0xe07f, {0}, "FDABSX %F" }, +{ 0xf200, 0xffc0, 0x005e, 0xe07f, {0}, "FDNEGX %F" }, +{ 0xf200, 0xffc0, 0x0060, 0xe07f, {0}, "FSDIVX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0062, 0xe07f, {0}, "FSADDX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0063, 0xe07f, {0}, "FSMULX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0064, 0xe07f, {0}, "FDDIVX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0066, 0xe07f, {0}, "FDADDX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0067, 0xe07f, {0}, "FDMULX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x0068, 0xe07f, {0}, "FSSUBX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x006c, 0xe07f, {0}, "FDSUBX F%B,F%D" }, +{ 0xf200, 0xffc0, 0x4000, 0xe07f, {EAFLT}, "FMOVE%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4001, 0xe07f, {EAFLT}, "FINT%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4002, 0xe07f, {EAFLT}, "FSINH%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4003, 0xe07f, {EAFLT}, "FINTRZ%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4004, 0xe07f, {EAFLT}, "FSQRT%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4006, 0xe07f, {EAFLT}, "FLOGNP1%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4009, 0xe07f, {EAFLT}, "FTANH%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x400a, 0xe07f, {EAFLT}, "FATAN%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x400c, 0xe07f, {EAFLT}, "FASIN%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x400d, 0xe07f, {EAFLT}, "FATANH%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x400e, 0xe07f, {EAFLT}, "FSIN%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x400f, 0xe07f, {EAFLT}, "FTAN%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4010, 0xe07f, {EAFLT}, "FETOX%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4011, 0xe07f, {EAFLT}, "FTWOTOX%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4012, 0xe07f, {EAFLT}, "FTENTOX%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4014, 0xe07f, {EAFLT}, "FLOGN%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4015, 0xe07f, {EAFLT}, "FLOG10%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4016, 0xe07f, {EAFLT}, "FLOG2%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4018, 0xe07f, {EAFLT}, "FABS%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4019, 0xe07f, {EAFLT}, "FCOSH%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x401a, 0xe07f, {EAFLT}, "FNEG%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x401c, 0xe07f, {EAFLT}, "FACOS%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x401d, 0xe07f, {EAFLT}, "FCOS%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x401e, 0xe07f, {EAFLT}, "FGETEXP%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x401f, 0xe07f, {EAFLT}, "FGETMAN%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4020, 0xe07f, {EAFLT}, "FDIV%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4021, 0xe07f, {EAFLT}, "FMOD%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4022, 0xe07f, {EAFLT}, "FADD%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4023, 0xe07f, {EAFLT}, "FMUL%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4024, 0xe07f, {EAFLT}, "FSGLDIV%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4025, 0xe07f, {EAFLT}, "FREM%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4026, 0xe07f, {EAFLT}, "FSCALE%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4027, 0xe07f, {EAFLT}, "FSGLMUL%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4028, 0xe07f, {EAFLT}, "FSUB%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4038, 0xe07f, {EAFLT}, "FCMP%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x403a, 0xe07f, {EAFLT}, "FTST%S %e" }, +{ 0xf200, 0xffc0, 0x4040, 0xe07f, {EAFLT}, "FSMOVE%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4041, 0xe07f, {EAFLT}, "FSSQRT%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4044, 0xe07f, {EAFLT}, "FDMOVE%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4045, 0xe07f, {EAFLT}, "FDSQRT%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4058, 0xe07f, {EAFLT}, "FSABS%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x405a, 0xe07f, {EAFLT}, "FSNEG%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x405c, 0xe07f, {EAFLT}, "FDABS%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x405e, 0xe07f, {EAFLT}, "FDNEG%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4060, 0xe07f, {EAFLT}, "FSDIV%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4062, 0xe07f, {EAFLT}, "FSADD%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4063, 0xe07f, {EAFLT}, "FSMUL%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4064, 0xe07f, {EAFLT}, "FDDIV%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4066, 0xe07f, {EAFLT}, "FDADD%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4067, 0xe07f, {EAFLT}, "FDMUL%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x4068, 0xe07f, {EAFLT}, "FSSUB%S %e,F%D" }, +{ 0xf200, 0xffc0, 0x406c, 0xe07f, {EAFLT}, "FDSUB%S %e,F%D" }, + +{ 0xf200, 0xffc0, 0x0030, 0xe078, {0}, "FSINCOSX F%B,F%a:F%D" }, +{ 0xf200, 0xffc0, 0x4030, 0xe078, {EAFLT}, "FSINCOS%S %e,F%a:F%D" }, + +{ 0xf200, 0xffc0, 0x6000, 0xe000, {EADA}, "FMOVE%S F%D,%e" }, + +{ 0xf300, 0xffc0, 0x0000, 0x0000, {EACAPD}, "FSAVE %e" }, +{ 0xf340, 0xffc0, 0x0000, 0x0000, {EACAPI}, "FRESTORE %e" }, + +{ 0xf280, 0xffc0, 0x0000, 0x0000, {BR16}, "FB%p %t" }, +{ 0xf2c0, 0xffc0, 0x0000, 0x0000, {BR32}, "FB%p %t" }, + +{ 0xf408, 0xff38, 0x0000, 0x0000, {0}, "CINVL %C,(A%y)" }, +{ 0xf410, 0xff38, 0x0000, 0x0000, {0}, "CINVP %C,(A%y)" }, +{ 0xf418, 0xff38, 0x0000, 0x0000, {0}, "CINVA %C" }, +{ 0xf428, 0xff38, 0x0000, 0x0000, {0}, "CPUSHL %C,(A%y)" }, +{ 0xf430, 0xff38, 0x0000, 0x0000, {0}, "CPUSHP %C,(A%y)" }, +{ 0xf438, 0xff38, 0x0000, 0x0000, {0}, "CPUSHA %C" }, +{ 0,0,0,0,{0},0 }, +}; + +static Optable *optables[] = +{ + t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, 0, tb, tc, td, te, tf, +}; + +static Map *mymap; + +static int +dumpinst(Inst *ip, char *buf, int n) +{ + int i; + + if (n <= 0) + return 0; + + *buf++ = '#'; + for (i = 0; i < ip->n && i*4+1 < n-4; i++, buf += 4) + _hexify(buf, ip->raw[i], 3); + *buf = 0; + return i*4+1; +} + +static int +getword(Inst *ip, long offset) +{ + if (ip->n < nelem(ip->raw)) { + if (get2(mymap, offset, &ip->raw[ip->n++]) > 0) + return 1; + werrstr("can't read instruction: %r"); + } else + werrstr("instruction too big: %r"); + return -1; +} + +static int +getshorts(Inst *ip, void *where, int n) +{ + if (ip->n+n < nelem(ip->raw)) { + if (get1(mymap, ip->addr+ip->n*2, (uchar*)&ip->raw[ip->n], n*2) < 0) { + werrstr("can't read instruction: %r"); + return 0; + } + memmove(where, &ip->raw[ip->n], n*2); + ip->n += n; + return 1; + } + werrstr("instruction too big: %r"); + return 0; +} + +static int +i8(Inst *ip, long *l) +{ + if (getword(ip, ip->addr+ip->n*2) < 0) + return -1; + *l = ip->raw[ip->n-1]&0xff; + if (*l&0x80) + *l |= ~0xff; + return 1; +} + +static int +i16(Inst *ip, long *l) +{ + if (getword(ip, ip->addr+ip->n*2) < 0) + return -1; + *l = ip->raw[ip->n-1]; + if (*l&0x8000) + *l |= ~0xffff; + return 1; +} +static int +i32(Inst *ip, long *l) +{ + if (getword(ip, ip->addr+ip->n*2) < 0) + return -1; + if (getword(ip, ip->addr+ip->n*2) < 0) + return -1; + *l = (ip->raw[ip->n-2]<<16)|ip->raw[ip->n-1]; + return 1; +} + +static int +getimm(Inst *ip, Operand *ap, int mode) +{ + ap->eatype = IMM; + switch(mode) + { + case EAM_B: /* byte */ + case EAALL_B: + return i8(ip, &ap->u0.immediate); + case EADI_W: /* word */ + case EAALL_W: + return i16(ip, &ap->u0.immediate); + case EADI_L: /* long */ + case EAALL_L: + return i32(ip, &ap->u0.immediate); + case EAFLT: /* floating point - size in bits 10-12 or word 1 */ + switch((ip->raw[1]>>10)&0x07) + { + case 0: /* long integer */ + return i32(ip, &ap->u0.immediate); + case 1: /* single precision real */ + ap->eatype = IREAL; + return getshorts(ip, ap->u0.floater, 2); + case 2: /* extended precision real - not supported */ + ap->eatype = IEXT; + return getshorts(ip, ap->u0.floater, 6); + case 3: /* packed decimal real - not supported */ + ap->eatype = IPACK; + return getshorts(ip, ap->u0.floater, 12); + case 4: /* integer word */ + return i16(ip, &ap->u0.immediate); + case 5: /* double precision real */ + ap->eatype = IDBL; + return getshorts(ip, ap->u0.floater, 4); + case 6: /* integer byte */ + return i8(ip, &ap->u0.immediate); + default: + ip->errmsg = "bad immediate float data"; + return -1; + } + break; + case IV: /* size encoded in bits 6&7 of opcode word */ + default: + switch((ip->raw[0]>>6)&0x03) + { + case 0x00: /* integer byte */ + return i8(ip, &ap->u0.immediate); + case 0x01: /* integer word */ + return i16(ip, &ap->u0.immediate); + case 0x02: /* integer long */ + return i32(ip, &ap->u0.immediate); + default: + ip->errmsg = "bad immediate size"; + return -1; + } + break; + } + return 1; +} + +static int +getdisp(Inst *ip, Operand *ap) +{ + short ext; + + if (getword(ip, ip->addr+ip->n*2) < 0) + return -1; + ext = ip->raw[ip->n-1]; + ap->ext = ext; + if ((ext&0x100) == 0) { /* indexed with 7-bit displacement */ + ap->u0.s0.disp = ext&0x7f; + if (ap->u0.s0.disp&0x40) + ap->u0.s0.disp |= ~0x7f; + return 1; + } + switch(ext&0x30) /* first (inner) displacement */ + { + case 0x10: + break; + case 0x20: + if (i16(ip, &ap->u0.s0.disp) < 0) + return -1; + break; + case 0x30: + if (i32(ip, &ap->u0.s0.disp) < 0) + return -1; + break; + default: + ip->errmsg = "bad EA displacement"; + return -1; + } + switch (ext&0x03) /* outer displacement */ + { + case 0x02: /* 16 bit displacement */ + return i16(ip, &ap->u0.s0.outer); + case 0x03: /* 32 bit displacement */ + return i32(ip, &ap->u0.s0.outer); + default: + break; + } + return 1; +} + +static int +ea(Inst *ip, int ea, Operand *ap, int mode) +{ + int type, size; + + type = 0; + ap->ext = 0; + switch((ea>>3)&0x07) + { + case 0x00: + ap->eatype = Dreg; + type = Dn; + break; + case 0x01: + ap->eatype = Areg; + type = An; + break; + case 0x02: + ap->eatype = AInd; + type = Ind; + break; + case 0x03: + ap->eatype = APinc; + type = Pinc; + break; + case 0x04: + ap->eatype = APdec; + type = Pdec; + break; + case 0x05: + ap->eatype = ADisp; + type = Bdisp; + if (i16(ip, &ap->u0.s0.disp) < 0) + return -1; + break; + case 0x06: + ap->eatype = BXD; + type = Bdisp; + if (getdisp(ip, ap) < 0) + return -1; + break; + case 0x07: + switch(ea&0x07) + { + case 0x00: + type = Abs; + ap->eatype = ABS; + if (i16(ip, &ap->u0.immediate) < 0) + return -1; + break; + case 0x01: + type = Abs; + ap->eatype = ABS; + if (i32(ip, &ap->u0.immediate) < 0) + return -1; + break; + case 0x02: + type = PCrel; + ap->eatype = PDisp; + if (i16(ip, &ap->u0.s0.disp) < 0) + return -1; + break; + case 0x03: + type = PCrel; + ap->eatype = PXD; + if (getdisp(ip, ap) < 0) + return -1; + break; + case 0x04: + type = Imm; + if (getimm(ip, ap, mode) < 0) + return -1; + break; + default: + ip->errmsg = "bad EA mode"; + return -1; + } + } + /* Allowable floating point EAs are restricted for packed, + * extended, and double precision operands + */ + if (mode == EAFLT) { + size = (ip->raw[1]>>10)&0x07; + if (size == 2 || size == 3 || size == 5) + mode = EAM; + else + mode = EADI; + } + if (!(validea[mode]&type)) { + ip->errmsg = "invalid EA"; + return -1; + } + return 1; +} + +static int +decode(Inst *ip, Optable *op) +{ + int i, t, mode; + Operand *ap; + short opcode; + + opcode = ip->raw[0]; + for (i = 0; i < nelem(op->opdata) && op->opdata[i]; i++) { + ap = &ip->and[i]; + mode = op->opdata[i]; + switch(mode) + { + case EAPI: /* normal EA modes */ + case EACA: + case EACAD: + case EACAPI: + case EACAPD: + case EAMA: + case EADA: + case EAA: + case EAC: + case EACPI: + case EACD: + case EAD: + case EAM: + case EAM_B: + case EADI: + case EADI_L: + case EADI_W: + case EAALL: + case EAALL_L: + case EAALL_W: + case EAALL_B: + case EAFLT: + if (ea(ip, opcode&0x3f, ap, mode) < 0) + return -1; + break; + case EADDA: /* stupid bit flop required */ + t = ((opcode>>9)&0x07)|((opcode>>3)&0x38); + if (ea(ip, t, ap, EADA)< 0) + return -1; + break; + case BREAC: /* EAC JMP or CALL operand */ + if (ea(ip, opcode&0x3f, ap, EAC) < 0) + return -1; + break; + case OP8: /* weird movq instruction */ + ap->eatype = IMM; + ap->u0.immediate = opcode&0xff; + if (opcode&0x80) + ap->u0.immediate |= ~0xff; + break; + case I8: /* must be two-word opcode */ + ap->eatype = IMM; + ap->u0.immediate = ip->raw[1]&0xff; + if (ap->u0.immediate&0x80) + ap->u0.immediate |= ~0xff; + break; + case I16: /* 16 bit immediate */ + case BR16: + ap->eatype = IMM; + if (i16(ip, &ap->u0.immediate) < 0) + return -1; + break; + case C16: /* CAS2 16 bit immediate */ + ap->eatype = IMM; + if (i16(ip, &ap->u0.immediate) < 0) + return -1; + if (ap->u0.immediate & 0x0e38) { + ip->errmsg = "bad CAS2W operand"; + return 0; + } + break; + case I32: /* 32 bit immediate */ + case BR32: + ap->eatype = IMM; + if (i32(ip, &ap->u0.immediate) < 0) + return -1; + break; + case IV: /* immediate data depends on size field */ + if (getimm(ip, ap, IV) < 0) + return -1; + break; + case BR8: /* branch displacement format */ + ap->eatype = IMM; + ap->u0.immediate = opcode&0xff; + if (ap->u0.immediate == 0) { + if (i16(ip, &ap->u0.immediate) < 0) + return -1; + } else if (ap->u0.immediate == 0xff) { + if (i32(ip, &ap->u0.immediate) < 0) + return -1; + } else if (ap->u0.immediate & 0x80) + ap->u0.immediate |= ~0xff; + break; + case STACK: /* Dummy operand type for Return instructions */ + default: + break; + } + } + return 1; +} + +static Optable * +instruction(Inst *ip) +{ + ushort opcode, op2; + Optable *op; + int class; + + ip->n = 0; + if (getword(ip, ip->addr) < 0) + return 0; + opcode = ip->raw[0]; + if (get2(mymap, ip->addr+2, &op2) < 0) + op2 = 0; + class = (opcode>>12)&0x0f; + for (op = optables[class]; op && op->format; op++) { + if (op->opcode != (opcode&op->mask0)) + continue; + if (op->op2 != (op2&op->mask1)) + continue; + if (op->mask1) + ip->raw[ip->n++] = op2; + return op; + } + ip->errmsg = "Invalid opcode"; + return 0; +} + +static void +bprint(Inst *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static char *regname[] = +{ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "A0", + "A1", "A2", "A3", "A4", "A5", "A6", "A7", "PC", "SB" +}; + +static void +plocal(Inst *ip, Operand *ap) +{ + int ret, offset; + long moved; + Symbol s; + + offset = ap->u0.s0.disp; + if (!findsym(ip->addr, CTEXT, &s)) + goto none; + + moved = pc2sp(ip->addr); + if (moved == -1) + goto none; + + if (offset > moved) { /* above frame - must be argument */ + offset -= moved; + ret = getauto(&s, offset-mach->szaddr, CPARAM, &s); + } else /* below frame - must be automatic */ + ret = getauto(&s, moved-offset, CPARAM, &s); + if (ret) + bprint(ip, "%s+%lux", s.name, offset); + else +none: bprint(ip, "%lux", ap->u0.s0.disp); +} + +/* + * this guy does all the work of printing the base and index component + * of an EA. + */ +static int +pidx(Inst *ip, int ext, int reg, char *bfmt, char *ifmt, char *nobase) +{ + char *s; + int printed; + char buf[512]; + + printed = 1; + if (ext&0x80) { /* Base suppressed */ + if (reg == 16) + bprint(ip, bfmt, "(ZPC)"); + else if (nobase) + bprint(ip, nobase); + else + printed = 0; + } else /* format base reg */ + bprint(ip, bfmt, regname[reg]); + if (ext & 0x40) /* index suppressed */ + return printed; + switch ((ext>>9)&0x03) + { + case 0x01: + s = "*2"; + break; + case 0x02: + s = "*4"; + break; + case 0x03: + s = "*8"; + break; + default: + if (ext&0x80) + s = "*1"; + else + s = ""; + break; + } + sprint(buf, "%s.%c%s", regname[(ext>>12)&0x0f], (ext&0x800) ? 'L' : 'W', s); + if (!printed) + bprint(ip, ifmt, buf); + else + bprint(ip, "(%s)", buf); + return 1; +} + +static void +prindex(Inst *ip, int reg, Operand *ap) +{ + short ext; + int left; + int disp; + + left = ip->end-ip->curr; + if (left <= 0) + return; + ext = ap->ext; + disp = ap->u0.s0.disp; + /* look for static base register references */ + if ((ext&0xa0) == 0x20 && reg == 14 && mach->sb && disp) { + reg = 17; /* "A6" -> "SB" */ + disp += mach->sb; + } + if ((ext&0x100) == 0) { /* brief form */ + if (reg == 15) + plocal(ip, ap); + else if (disp) + ip->curr += symoff(ip->curr, left, disp, CANY); + pidx(ip, ext&0xff00, reg, "(%s)", "(%s)", 0); + return; + } + switch(ext&0x3f) /* bd size, && i/is */ + { + case 0x10: + if (!pidx(ip, ext, reg, "(%s)", "(%s)", 0)) + bprint(ip, "#0"); + break; + case 0x11: + if (pidx(ip, ext, reg, "((%s)", "((%s)", 0)) + bprint(ip, ")"); + else + bprint(ip, "#0"); + break; + case 0x12: + case 0x13: + ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY); + if (pidx(ip, ext, reg, "((%s)", "((%s)", 0)) + bprint(ip, ")"); + break; + case 0x15: + if (!pidx(ip, ext, reg, "((%s))", "(%s)", 0)) + bprint(ip, "#0"); + break; + case 0x16: + case 0x17: + ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY); + pidx(ip, ext, reg, "((%s))", "(%s)", 0); + break; + case 0x20: + case 0x30: + if (reg == 15) + plocal(ip, ap); + else + ip->curr += symoff(ip->curr, left, disp, CANY); + pidx(ip, ext, reg, "(%s)", "(%s)", 0); + break; + case 0x21: + case 0x31: + *ip->curr++ = '('; + if (reg == 15) + plocal(ip, ap); + else + ip->curr += symoff(ip->curr, left-1, disp, CANY); + pidx(ip, ext, reg, "(%s)", "(%s)", 0); + bprint(ip, ")"); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY); + bprint(ip, "("); + if (reg == 15) + plocal(ip, ap); + else + ip->curr += symoff(ip->curr, ip->end-ip->curr, disp, CANY); + pidx(ip, ext, reg, "(%s)", "(%s)", 0); + bprint(ip, ")"); + break; + case 0x25: + case 0x35: + *ip->curr++ = '('; + if (reg == 15) + plocal(ip, ap); + else + ip->curr += symoff(ip->curr, left-1, disp, CANY); + if (!pidx(ip, ext, reg, "(%s))", "(%s)", "())")) + bprint(ip, ")"); + break; + case 0x26: + case 0x27: + case 0x36: + case 0x37: + ip->curr += symoff(ip->curr, left, ap->u0.s0.outer, CANY); + bprint(ip, "("); + if (reg == 15) + plocal(ip, ap); + else + ip->curr += symoff(ip->curr, ip->end-ip->curr, disp, CANY); + pidx(ip, ext, reg, "(%s))", "(%s)", "())"); + break; + default: + bprint(ip, "??%x??", ext); + ip->errmsg = "bad EA"; + break; + } +} + +static void +pea(int reg, Inst *ip, Operand *ap) +{ + int i, left; + + left = ip->end-ip->curr; + if (left < 0) + return; + switch(ap->eatype) + { + case Dreg: + bprint(ip, "R%d", reg); + break; + case Areg: + bprint(ip, "A%d", reg); + break; + case AInd: + bprint(ip, "(A%d)", reg); + break; + case APinc: + bprint(ip, "(A%d)+", reg); + break; + case APdec: + bprint(ip, "-(A%d)", reg); + break; + case PDisp: + ip->curr += symoff(ip->curr, left, ip->addr+2+ap->u0.s0.disp, CANY); + break; + case PXD: + prindex(ip, 16, ap); + break; + case ADisp: /* references off the static base */ + if (reg == 6 && mach->sb && ap->u0.s0.disp) { + ip->curr += symoff(ip->curr, left, ap->u0.s0.disp+mach->sb, CANY); + bprint(ip, "(SB)", reg); + break; + } + /* reference autos and parameters off the stack */ + if (reg == 7) + plocal(ip, ap); + else + ip->curr += symoff(ip->curr, left, ap->u0.s0.disp, CANY); + bprint(ip, "(A%d)", reg); + break; + case BXD: + prindex(ip, reg+8, ap); + break; + case ABS: + ip->curr += symoff(ip->curr, left, ap->u0.immediate, CANY); + bprint(ip, "($0)"); + break; + case IMM: + *ip->curr++ = '$'; + ip->curr += symoff(ip->curr, left-1, ap->u0.immediate, CANY); + break; + case IREAL: + *ip->curr++ = '$'; + ip->curr += beieeesftos(ip->curr, left-1, (void*) ap->u0.floater); + break; + case IDBL: + *ip->curr++ = '$'; + ip->curr += beieeedftos(ip->curr, left-1, (void*) ap->u0.floater); + break; + case IPACK: + bprint(ip, "$#"); + for (i = 0; i < 24 && ip->curr < ip->end-1; i++) { + _hexify(ip->curr, ap->u0.floater[i], 1); + ip->curr += 2; + } + break; + case IEXT: + bprint(ip, "$#"); + ip->curr += beieee80ftos(ip->curr, left-2, (void*)ap->u0.floater); + break; + default: + bprint(ip, "??%x??", ap->eatype); + ip->errmsg = "bad EA type"; + break; + } +} + +static char *cctab[] = { "F", "T", "HI", "LS", "CC", "CS", "NE", "EQ", + "VC", "VS", "PL", "MI", "GE", "LT", "GT", "LE" }; +static char *fcond[] = +{ + "F", "EQ", "OGT", "OGE", "OLT", "OLE", "OGL", "OR", + "UN", "UEQ", "UGT", "UGE", "ULT", "ULE", "NE", "T", + "SF", "SEQ", "GT", "GE", "LT", "LE", "GL", "GLE", + "NGLE", "NGL", "NLE", "NLT", "NGE", "NGT", "SNE", "ST" +}; +static char *cachetab[] = { "NC", "DC", "IC", "BC" }; +static char *mmutab[] = { "TC", "??", "SRP", "CRP" }; +static char *crtab0[] = +{ + "SFC", "DFC", "CACR", "TC", "ITT0", "ITT1", "DTT0", "DTT1", +}; +static char *crtab1[] = +{ + "USP", "VBR", "CAAR", "MSP", "ISP", "MMUSR", "URP", "SRP", +}; +static char typetab[] = { 'L', 'S', 'X', 'P', 'W', 'D', 'B', '?', }; +static char sztab[] = {'?', 'B', 'W', 'L', '?' }; + +static void +formatins(char *fmt, Inst *ip) +{ + short op, w1; + int r1, r2; + int currand; + + op = ip->raw[0]; + w1 = ip->raw[1]; + currand = 0; + for (; *fmt && ip->curr < ip->end; fmt++) { + if (*fmt != '%') + *ip->curr++ = *fmt; + else switch(*++fmt) + { + case '%': + *ip->curr++ = '%'; + break; + case 'a': /* register number; word 1:[0-2] */ + *ip->curr++ = (w1&0x07)+'0'; + break; + case 'c': /* condition code; opcode: [8-11] */ + bprint(ip, cctab[(op>>8)&0x0f]); + break; + case 'd': /* shift direction; opcode: [8] */ + if (op&0x100) + *ip->curr++ = 'L'; + else + *ip->curr++ = 'R'; + break; + case 'e': /* source effective address */ + pea(op&0x07, ip, &ip->and[currand++]); + break; + case 'f': /* trap vector; op code: [0-3] */ + bprint(ip, "%x", op&0x0f); + break; + case 'h': /* register number; word 1: [5-7] */ + *ip->curr++ = (w1>>5)&0x07+'0'; + break; + case 'i': /* immediate operand */ + ip->curr += symoff(ip->curr, ip->end-ip->curr, + ip->and[currand++].u0.immediate, CANY); + break; + case 'j': /* data registers; word 1: [0-2] & [12-14] */ + r1 = w1&0x07; + r2 = (w1>>12)&0x07; + if (r1 == r2) + bprint(ip, "R%d", r1); + else + bprint(ip, "R%d:R%d", r2, r1); + break; + case 'k': /* k factor; word 1 [0-6] */ + bprint(ip, "%x", w1&0x7f); + break; + case 'm': /* register mask; word 1 [0-7] */ + bprint(ip, "%x", w1&0xff); + break; + case 'o': /* bit field offset; word1: [6-10] */ + bprint(ip, "%d", (w1>>6)&0x3f); + break; + case 'p': /* conditional predicate; opcode: [0-5] + only bits 0-4 are defined */ + bprint(ip, fcond[op&0x1f]); + break; + case 'q': /* 3-bit immediate value; opcode[9-11] */ + r1 = (op>>9)&0x07; + if (r1 == 0) + *ip->curr++ = '8'; + else + *ip->curr++ = r1+'0'; + break; + case 'r': /* register type & number; word 1: [12-15] */ + bprint(ip, regname[(w1>>12)&0x0f]); + break; + case 's': /* size; opcode [6-7] */ + *ip->curr = sztab[((op>>6)&0x03)+1]; + if (*ip->curr++ == '?') + ip->errmsg = "bad size code"; + break; + case 't': /* text offset */ + ip->curr += symoff(ip->curr, ip->end-ip->curr, + ip->and[currand++].u0.immediate+ip->addr+2, CTEXT); + break; + case 'u': /* register number; word 1: [6-8] */ + *ip->curr++ = ((w1>>6)&0x07)+'0'; + break; + case 'w': /* bit field width; word 1: [0-4] */ + bprint(ip, "%d", w1&0x0f); + break; + case 'x': /* register number; opcode: [9-11] */ + *ip->curr++ = ((op>>9)&0x07)+'0'; + break; + case 'y': /* register number; opcode: [0-2] */ + *ip->curr++ = (op&0x07)+'0'; + break; + case 'z': /* shift count; opcode: [9-11] */ + *ip->curr++ = ((op>>9)&0x07)+'0'; + break; + case 'A': /* register number; word 2: [0-2] */ + *ip->curr++ = (ip->raw[2]&0x07)+'0'; + break; + case 'B': /* float source reg; word 1: [10-12] */ + *ip->curr++ = ((w1>>10)&0x07)+'0'; + break; + case 'C': /* cache identifier; opcode: [6-7] */ + bprint(ip, cachetab[(op>>6)&0x03]); + break; + case 'D': /* float dest reg; word 1: [7-9] */ + *ip->curr++ = ((w1>>7)&0x07)+'0'; + break; + case 'E': /* destination EA; opcode: [6-11] */ + pea((op>>9)&0x07, ip, &ip->and[currand++]); + break; + case 'F': /* float dest register(s); word 1: [7-9] & [10-12] */ + r1 = (w1>>7)&0x07; + r2 = (w1>>10)&0x07; + if (r1 == r2) + bprint(ip, "F%d", r1); + else + bprint(ip, "F%d,F%d", r2, r1); + break; + case 'H': /* MMU register; word 1 [10-13] */ + bprint(ip, mmutab[(w1>>10)&0x03]); + if (ip->curr[-1] == '?') + ip->errmsg = "bad mmu register"; + break; + case 'I': /* MMU function code mask; word 1: [5-8] */ + bprint(ip, "%x", (w1>>4)&0x0f); + break; + case 'K': /* dynamic k-factor register; word 1: [5-8] */ + bprint(ip, "%d", (w1>>4)&0x0f); + break; + case 'L': /* MMU function code; word 1: [0-6] */ + if (w1&0x10) + bprint(ip, "%x", w1&0x0f); + else if (w1&0x08) + bprint(ip, "R%d",w1&0x07); + else if (w1&0x01) + bprint(ip, "DFC"); + else + bprint(ip, "SFC"); + break; + case 'N': /* control register; word 1: [0-11] */ + r1 = w1&0xfff; + if (r1&0x800) + bprint(ip, crtab1[r1&0x07]); + else + bprint(ip, crtab0[r1&0x07]); + break; + case 'P': /* conditional predicate; word 1: [0-5] */ + bprint(ip, fcond[w1&0x1f]); + break; + case 'R': /* register type & number; word 2 [12-15] */ + bprint(ip, regname[(ip->raw[2]>>12)&0x0f]); + break; + case 'S': /* float source type code; word 1: [10-12] */ + *ip->curr = typetab[(w1>>10)&0x07]; + if (*ip->curr++ == '?') + ip->errmsg = "bad float type"; + break; + case 'U': /* register number; word 2: [6-8] */ + *ip->curr++ = ((ip->raw[2]>>6)&0x07)+'0'; + break; + case 'Z': /* ATC level number; word 1: [10-12] */ + bprint(ip, "%x", (w1>>10)&0x07); + break; + case '1': /* effective address in second operand*/ + pea(op&0x07, ip, &ip->and[1]); + break; + default: + bprint(ip, "%%%c", *fmt); + break; + } + } + *ip->curr = 0; /* there's always room for 1 byte */ +} + +static int +dispsize(Inst *ip) +{ + ushort ext; + static int dsize[] = {0, 0, 1, 2}; /* in words */ + + if (get2(mymap, ip->addr+ip->n*2, &ext) < 0) + return -1; + if ((ext&0x100) == 0) + return 1; + return dsize[(ext>>4)&0x03]+dsize[ext&0x03]+1; +} + +static int +immsize(Inst *ip, int mode) +{ + static int fsize[] = { 2, 2, 6, 12, 1, 4, 1, -1 }; + static int isize[] = { 1, 1, 2, -1 }; + + switch(mode) + { + case EAM_B: /* byte */ + case EAALL_B: + case EADI_W: /* word */ + case EAALL_W: + return 1; + case EADI_L: /* long */ + case EAALL_L: + return 2; + case EAFLT: /* floating point - size in bits 10-12 or word 1 */ + return fsize[(ip->raw[1]>>10)&0x07]; + case IV: /* size encoded in bits 6&7 of opcode word */ + default: + return isize[(ip->raw[0]>>6)&0x03]; + } + return -1; +} + +static int +easize(Inst *ip, int ea, int mode) +{ + switch((ea>>3)&0x07) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + return 0; + case 0x05: + return 1; + case 0x06: + return dispsize(ip); + case 0x07: + switch(ea&0x07) + { + case 0x00: + case 0x02: + return 1; + case 0x01: + return 2; + case 0x03: + return dispsize(ip); + case 0x04: + return immsize(ip, mode); + default: + return -1; + } + } + return -1; +} + +static int +instrsize(Inst *ip, Optable *op) +{ + int i, t, mode; + short opcode; + + opcode = ip->raw[0]; + for (i = 0; i < nelem(op->opdata) && op->opdata[i]; i++) { + mode = op->opdata[i]; + switch(mode) + { + case EAPI: /* normal EA modes */ + case EACA: + case EACAD: + case EACAPI: + case EACAPD: + case EAMA: + case EADA: + case EAA: + case EAC: + case EACPI: + case EACD: + case EAD: + case EAM: + case EAM_B: + case EADI: + case EADI_L: + case EADI_W: + case EAALL: + case EAALL_L: + case EAALL_W: + case EAALL_B: + case EAFLT: + t = easize(ip, opcode&0x3f, mode); + if (t < 0) + return -1; + ip->n += t; + break; + case EADDA: /* stupid bit flop required */ + t = ((opcode>>9)&0x07)|((opcode>>3)&0x38); + t = easize(ip, t, mode); + if (t < 0) + return -1; + ip->n += t; + break; + case BREAC: /* EAC JMP or CALL operand */ + /* easy displacements for follow set */ + if ((opcode&0x038) == 0x28 || (opcode&0x3f) == 0x3a) { + if (i16(ip, &ip->and[i].u0.immediate) < 0) + return -1; + } else { + t = easize(ip, opcode&0x3f, mode); + if (t < 0) + return -1; + ip->n += t; + } + break; + case I16: /* 16 bit immediate */ + case C16: /* CAS2 16 bit immediate */ + ip->n++; + break; + case BR16: /* 16 bit branch displacement */ + if (i16(ip, &ip->and[i].u0.immediate) < 0) + return -1; + break; + case BR32: /* 32 bit branch displacement */ + if (i32(ip, &ip->and[i].u0.immediate) < 0) + return -1; + break; + case I32: /* 32 bit immediate */ + ip->n += 2; + break; + case IV: /* immediate data depends on size field */ + t = (ip->raw[0]>>6)&0x03; + if (t < 2) + ip->n++; + else if (t == 2) + ip->n += 2; + else + return -1; + break; + case BR8: /* loony branch displacement format */ + t = opcode&0xff; + if (t == 0) { + if (i16(ip, &ip->and[i].u0.immediate) < 0) + return -1; + } else if (t == 0xff) { + if (i32(ip, &ip->and[i].u0.immediate) < 0) + return -1; + } else { + ip->and[i].u0.immediate = t; + if (t & 0x80) + ip->and[i].u0.immediate |= ~0xff; + } + break; + case STACK: /* Dummy operand for Return instructions */ + case OP8: /* weird movq instruction */ + case I8: /* must be two-word opcode */ + default: + break; + } + } + return 1; +} + +static int +eaval(Inst *ip, Operand *ap, Rgetter rget) +{ + int reg; + char buf[8]; + + reg = ip->raw[0]&0x07; + switch(ap->eatype) + { + case AInd: + sprint(buf, "A%d", reg); + return (*rget)(mymap, buf); + case PDisp: + return ip->addr+2+ap->u0.s0.disp; + case ADisp: + sprint(buf, "A%d", reg); + return ap->u0.s0.disp+(*rget)(mymap, buf); + case ABS: + return ap->u0.immediate; + default: + return 0; + } +} + +static int +m68020instlen(Map *map, ulong pc) +{ + Inst i; + Optable *op; + + mymap = map; + i.addr = pc; + i.errmsg = 0; + op = instruction(&i); + if (op && instrsize(&i, op) > 0) + return i.n*2; + return -1; +} + +static int +m68020foll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + int j; + Inst i; + Optable *op; + + mymap = map; + i.addr = pc; + i.errmsg = 0; + op = instruction(&i); + if (op == 0 || instrsize(&i, op) < 0) + return -1; + for (j = 0; j < nelem(op->opdata) && op->opdata[j]; j++) { + switch(op->opdata[j]) + { + case BREAC: /* CALL, JMP, JSR */ + foll[0] = pc+2+eaval(&i, &i.and[j], rget); + return 1; + case BR8: /* Bcc, BSR, & BRA */ + case BR16: /* FBcc, FDBcc, DBcc */ + case BR32: /* FBcc */ + foll[0] = pc+i.n*2; + foll[1] = pc+2+i.and[j].u0.immediate; + return 2; + case STACK: /* RTR, RTS, RTD */ + if (get4(map, (*rget)(map, mach->sp), (long*) foll) < 0) + return -1; + return 1; + default: + break; + } + } + foll[0] = pc+i.n*2; + return 1; +} + +static int +m68020inst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + Inst i; + Optable *op; + + USED(modifier); + mymap = map; + i.addr = pc; + i.curr = buf; + i.end = buf+n-1; + i.errmsg = 0; + op = instruction(&i); + if (!op) + return -1; + if (decode(&i, op) > 0) + formatins(op->format, &i); + if (i.errmsg) { + if (i.curr != buf) + bprint(&i, "\t\t;"); + bprint(&i, "%s: ", i.errmsg); + dumpinst(&i, i.curr, i.end-i.curr); + } + return i.n*2; +} + +static int +m68020das(Map *map, ulong pc, char *buf, int n) +{ + Inst i; + Optable *op; + + mymap = map; + i.addr = pc; + i.curr = buf; + i.end = buf+n-1; + i.errmsg = 0; + + op = instruction(&i); + if (!op) + return -1; + decode(&i, op); + if (i.errmsg) + bprint(&i, "%s: ", i.errmsg); + dumpinst(&i, i.curr, i.end-i.curr); + return i.n*2; +} diff --git a/utils/libmach/2obj.c b/utils/libmach/2obj.c new file mode 100644 index 00000000..368e1ec7 --- /dev/null +++ b/utils/libmach/2obj.c @@ -0,0 +1,137 @@ +/* + * 2obj.c - identify and parse a 68020 object file + */ +#include <lib9.h> +#include <bio.h> +#include "2c/2.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char sym; + char flags; +}; +static Addr addr(Biobuf *); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_is2(char *t) +{ + uchar *s = (uchar *)t; + + return s[0] == (ANAME&0xff) /* aslo = ANAME */ + && s[1] == ((ANAME>>8)&0xff) /* ashi = ANAME */ + && s[2] == D_FILE /* type */ + && s[3] == 1 /* sym */ + && s[4] == '<'; /* name of file */ +} + +int +_read2(Biobuf *bp, Prog *p) +{ + int as, n, c; + Addr a; + + as = Bgetc(bp); /* as(low) */ + if(as < 0) + return 0; + c = Bgetc(bp); /* as(high) */ + if(c < 0) + return 0; + as |= ((c & 0xff) << 8); + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 4); /*lineno: low, high, lowhigh, highigh*/ + a = addr(bp); + addr(bp); + if(!(a.flags & T_SYM)) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + int t; + long off; + + a.flags = Bgetc(bp); /* flags */ + a.sym = -1; + off = 0; + if(a.flags & T_FIELD) + skip(bp, 2); + if(a.flags & T_INDEX) + skip(bp, 7); + if(a.flags & T_OFFSET){ + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + } + if(a.flags & T_SYM) + a.sym = Bgetc(bp); + if(a.flags & T_FCONST) + skip(bp, 8); + else if(a.flags & T_SCONST) + skip(bp, NSNAME); + else{ + t = Bgetc(bp); + if(a.flags & T_TYPE) + t |= Bgetc(bp) << 8; + t &= D_MASK; + if(a.sym > 0 && (t==D_PARAM || t==D_AUTO)) + _offset(a.sym, off); + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/4.c b/utils/libmach/4.c new file mode 100644 index 00000000..3b1f38dd --- /dev/null +++ b/utils/libmach/4.c @@ -0,0 +1,139 @@ +/* + * mips definition + */ +#include <lib9.h> +#include <bio.h> +#include "ureg4.h" +#include "mach.h" + +#define FPREGBYTES 4 +#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x) + +#define SP REGOFF(u0.sp) +#define PC REGOFF(pc) +#define R1 REGOFF(hr1) +#define R31 REGOFF(hr31) +#define FP_REG(x) (R1+8+FPREGBYTES*(x)) + +#define REGSIZE sizeof(struct Ureg) +#define FPREGSIZE (FPREGBYTES*33) + +Reglist mips2reglist[] = { + {"STATUS", REGOFF(status), RINT|RRDONLY, 'X'}, + {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'}, + {"BADVADDR", REGOFF(badvaddr), RINT|RRDONLY, 'X'}, + {"TLBVIRT", REGOFF(tlbvirt), RINT|RRDONLY, 'X'}, + {"HI", REGOFF(hhi), RINT|RRDONLY, 'Y'}, + {"LO", REGOFF(hlo), RINT|RRDONLY, 'Y'}, + {"PC", PC, RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"R31", R31, RINT, 'Y'}, + {"R30", REGOFF(hr30), RINT, 'Y'}, + {"R28", REGOFF(hr28), RINT, 'Y'}, + {"R27", REGOFF(hr27), RINT, 'Y'}, + {"R26", REGOFF(hr26), RINT, 'Y'}, + {"R25", REGOFF(hr25), RINT, 'Y'}, + {"R24", REGOFF(hr24), RINT, 'Y'}, + {"R23", REGOFF(hr23), RINT, 'Y'}, + {"R22", REGOFF(hr22), RINT, 'Y'}, + {"R21", REGOFF(hr21), RINT, 'Y'}, + {"R20", REGOFF(hr20), RINT, 'Y'}, + {"R19", REGOFF(hr19), RINT, 'Y'}, + {"R18", REGOFF(hr18), RINT, 'Y'}, + {"R17", REGOFF(hr17), RINT, 'Y'}, + {"R16", REGOFF(hr16), RINT, 'Y'}, + {"R15", REGOFF(hr15), RINT, 'Y'}, + {"R14", REGOFF(hr14), RINT, 'Y'}, + {"R13", REGOFF(hr13), RINT, 'Y'}, + {"R12", REGOFF(hr12), RINT, 'Y'}, + {"R11", REGOFF(hr11), RINT, 'Y'}, + {"R10", REGOFF(hr10), RINT, 'Y'}, + {"R9", REGOFF(hr9), RINT, 'Y'}, + {"R8", REGOFF(hr8), RINT, 'Y'}, + {"R7", REGOFF(hr7), RINT, 'Y'}, + {"R6", REGOFF(hr6), RINT, 'Y'}, + {"R5", REGOFF(hr5), RINT, 'Y'}, + {"R4", REGOFF(hr4), RINT, 'Y'}, + {"R3", REGOFF(hr3), RINT, 'Y'}, + {"R2", REGOFF(hr2), RINT, 'Y'}, + {"R1", REGOFF(hr1), RINT, 'Y'}, + {"F0", FP_REG(0), RFLT, 'F'}, + {"F1", FP_REG(1), RFLT, 'f'}, + {"F2", FP_REG(2), RFLT, 'F'}, + {"F3", FP_REG(3), RFLT, 'f'}, + {"F4", FP_REG(4), RFLT, 'F'}, + {"F5", FP_REG(5), RFLT, 'f'}, + {"F6", FP_REG(6), RFLT, 'F'}, + {"F7", FP_REG(7), RFLT, 'f'}, + {"F8", FP_REG(8), RFLT, 'F'}, + {"F9", FP_REG(9), RFLT, 'f'}, + {"F10", FP_REG(10), RFLT, 'F'}, + {"F11", FP_REG(11), RFLT, 'f'}, + {"F12", FP_REG(12), RFLT, 'F'}, + {"F13", FP_REG(13), RFLT, 'f'}, + {"F14", FP_REG(14), RFLT, 'F'}, + {"F15", FP_REG(15), RFLT, 'f'}, + {"F16", FP_REG(16), RFLT, 'F'}, + {"F17", FP_REG(17), RFLT, 'f'}, + {"F18", FP_REG(18), RFLT, 'F'}, + {"F19", FP_REG(19), RFLT, 'f'}, + {"F20", FP_REG(20), RFLT, 'F'}, + {"F21", FP_REG(21), RFLT, 'f'}, + {"F22", FP_REG(22), RFLT, 'F'}, + {"F23", FP_REG(23), RFLT, 'f'}, + {"F24", FP_REG(24), RFLT, 'F'}, + {"F25", FP_REG(25), RFLT, 'f'}, + {"F26", FP_REG(26), RFLT, 'F'}, + {"F27", FP_REG(27), RFLT, 'f'}, + {"F28", FP_REG(28), RFLT, 'F'}, + {"F29", FP_REG(29), RFLT, 'f'}, + {"F30", FP_REG(30), RFLT, 'F'}, + {"F31", FP_REG(31), RFLT, 'f'}, + {"FPCR", FP_REG(32), RFLT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mmips2be = +{ + "mips2", + MMIPS2, /* machine type */ + mips2reglist, /* register set */ + REGSIZE, /* number of bytes in reg set */ + FPREGSIZE, /* number of bytes in fp reg set */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R31", /* name of link register */ + "setR30", /* static base register name */ + 0, /* SB value */ + 0x1000, /* page size */ + 0xC0000000, /* kernel base */ + 0x40000000, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 8, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; + +Mach mmips2le = +{ + "mips2", + NMIPS2, /* machine type */ + mips2reglist, /* register set */ + REGSIZE, /* number of bytes in reg set */ + FPREGSIZE, /* number of bytes in fp reg set */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R31", /* name of link register */ + "setR30", /* static base register name */ + 0, /* SB value */ + 0x1000, /* page size */ + 0xC0000000, /* kernel base */ + 0x40000000, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 8, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/4db.c b/utils/libmach/4db.c new file mode 100644 index 00000000..d3fa97a4 --- /dev/null +++ b/utils/libmach/4db.c @@ -0,0 +1,57 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" +/* + * Mips-specific debugger interface + */ + +char *mipsexcep(Map*, Rgetter); +int mipsfoll(Map*, ulong, Rgetter, ulong*); +int mipsinst(Map*, ulong, char, char*, int); +int mipsdas(Map*, ulong, char*, int); +int mipsinstlen(Map*, ulong); +/* + * Debugger interface + */ +Machdata mipsmach2be = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + beswab, /* short to local byte order */ + beswal, /* long to local byte order */ + beswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; + +/* + * Debugger interface + */ +Machdata mipsmach2le = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + leieeesftos, /* single precision float printer */ + leieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; diff --git a/utils/libmach/5.c b/utils/libmach/5.c new file mode 100644 index 00000000..1210d7f2 --- /dev/null +++ b/utils/libmach/5.c @@ -0,0 +1,64 @@ +/* + * arm definition + */ +#include <lib9.h> +#include <bio.h> +#include "ureg5.h" +#include "mach.h" + + +#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x) + +#define SP REGOFF(r13) +#define PC REGOFF(pc) + +#define REGSIZE sizeof(struct Ureg) + +Reglist armreglist[] = +{ + {"LINK", REGOFF(link), RINT|RRDONLY, 'X'}, + {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'}, + {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'}, + {"PC", PC, RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"R15", PC, RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + {"R0", REGOFF(r0), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach marm = +{ + "arm", + MARM, /* machine type */ + armreglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R15", /* name of link register */ + "setR12", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0xC0000000, /* kernel base */ + 0, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/5db.c b/utils/libmach/5db.c new file mode 100644 index 00000000..1a125042 --- /dev/null +++ b/utils/libmach/5db.c @@ -0,0 +1,1063 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +static int debug = 0; + +#define BITS(a, b) ((1<<(b+1))-(1<<a)) + +#define LSR(v, s) ((ulong)(v) >> (s)) +#define ASR(v, s) ((long)(v) >> (s)) +#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s)))) + + + +typedef struct Instr Instr; +struct Instr +{ + Map *map; + ulong w; + ulong addr; + uchar op; /* super opcode */ + + uchar cond; /* bits 28-31 */ + uchar store; /* bit 20 */ + + uchar rd; /* bits 12-15 */ + uchar rn; /* bits 16-19 */ + uchar rs; /* bits 0-11 (shifter operand) */ + + long imm; /* rotated imm */ + char* curr; /* fill point in buffer */ + char* end; /* end of buffer */ + char* err; /* error message */ +}; + +typedef struct Opcode Opcode; +struct Opcode +{ + char* o; + void (*fmt)(Opcode*, Instr*); + ulong (*foll)(Map*, Rgetter, Instr*, ulong); + char* a; +}; + +static void format(char*, Instr*, char*); +static char FRAMENAME[] = ".frame"; + +/* + * Arm-specific debugger interface + */ + +extern char *armexcep(Map*, Rgetter); +static int armfoll(Map*, ulong, Rgetter, ulong*); +static int arminst(Map*, ulong, char, char*, int); +static int armdas(Map*, ulong, char*, int); +static int arminstlen(Map*, ulong); + +/* + * Debugger interface + */ +Machdata armmach = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + armexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precision float printer */ + armfoll, /* following addresses */ + arminst, /* print instruction */ + armdas, /* dissembler */ + arminstlen, /* instruction size */ +}; + +char* +armexcep(Map *map, Rgetter rget) +{ + long c; + + c = (*rget)(map, "TYPE"); + switch (c&0x1f) { + case 0x11: + return "Fiq interrupt"; + case 0x12: + return "Mirq interrupt"; + case 0x13: + return "SVC/SWI Exception"; + case 0x17: + return "Prefetch Abort/Data Abort"; + case 0x18: + return "Data Abort"; + case 0x1b: + return "Undefined instruction/Breakpoint"; + case 0x1f: + return "Sys trap"; + default: + return "Undefined trap"; + } +} + +static +char* cond[16] = +{ + "EQ", "NE", "CS", "CC", + "MI", "PL", "VS", "VC", + "HI", "LS", "GE", "LT", + "GT", "LE", 0, "NV" +}; + +static +char* shtype[4] = +{ + "<<", ">>", "->", "@>" +}; + +static +char *hb[4] = +{ + "???", "HU", "B", "H" +}; + +static +char* addsub[2] = +{ + "-", "+", +}; + +int +armclass(long w) +{ + int op; + + op = (w >> 25) & 0x7; + switch(op) { + case 0: /* data processing r,r,r */ + op = ((w >> 4) & 0xf); + if(op == 0x9) { + op = 48+16; /* mul */ + if(w & (1<<24)) { + op += 2; + if(w & (1<<22)) + op++; /* swap */ + break; + } + if(w & (1<<21)) + op++; /* mla */ + break; + } + if ((op & 0x9) == 0x9) /* ld/st byte/half s/u */ + { + op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + } + op = (w >> 21) & 0xf; + if(w & (1<<4)) + op += 32; + else + if(w & (31<<7)) + op += 16; + break; + case 1: /* data processing i,r,r */ + op = (48) + ((w >> 21) & 0xf); + break; + case 2: /* load/store byte/word i(r) */ + op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + case 3: /* load/store byte/word (r)(r) */ + op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + case 4: /* block data transfer (r)(r) */ + op = (48+24+4+4) + ((w >> 20) & 0x1); + break; + case 5: /* branch / branch link */ + op = (48+24+4+4+2) + ((w >> 24) & 0x1); + break; + case 7: /* coprocessor crap */ + op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1); + break; + default: + op = (48+24+4+4+2+2+4); + break; + } + return op; +} + +static int +decode(Map *map, ulong pc, Instr *i) +{ + long w; + + if(get4(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->w = w; + i->addr = pc; + i->cond = (w >> 28) & 0xF; + i->op = armclass(w); + i->map = map; + return 1; +} + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static int +plocal(Instr *i) +{ + char *reg; + Symbol s; + char *fn; + int class; + int offset; + + if(!findsym(i->addr, CTEXT, &s)) { + if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr); + return 0; + } + fn = s.name; + if (!findlocal(&s, FRAMENAME, &s)) { + if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name); + return 0; + } + if(s.value > i->imm) { + class = CAUTO; + offset = s.value-i->imm; + reg = "(SP)"; + } else { + class = CPARAM; + offset = i->imm-s.value-4; + reg = "(FP)"; + } + if(!getauto(&s, offset, class, &s)) { + if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn, + class == CAUTO ? " auto" : "param", offset); + return 0; + } + bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg); + return 1; +} + +/* + * Print value v as name[+offset] + */ +int +gsymoff(char *buf, int n, long v, int space) +{ + Symbol s; + int r; + long delta; + + r = delta = 0; /* to shut compiler up */ + if (v) { + r = findsym(v, space, &s); + if (r) + delta = v-s.value; + if (delta < 0) + delta = -delta; + } + if (v == 0 || r == 0 || delta >= 4096) + return snprint(buf, n, "#%lux", v); + if (strcmp(s.name, ".string") == 0) + return snprint(buf, n, "#%lux", v); + if (!delta) + return snprint(buf, n, "%s", s.name); + if (s.type != 't' && s.type != 'T') + return snprint(buf, n, "%s+%lux", s.name, v-s.value); + else + return snprint(buf, n, "#%lux", v); +} + +static void +armdps(Opcode *o, Instr *i) +{ + i->store = (i->w >> 20) & 1; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = (i->w >> 0) & 0xf; + if(i->rn == 15 && i->rs == 0) { + if(i->op == 8) { + format("MOVW", i,"CPSR, R%d"); + return; + } else + if(i->op == 10) { + format("MOVW", i,"SPSR, R%d"); + return; + } + } else + if(i->rn == 9 && i->rd == 15) { + if(i->op == 9) { + format("MOVW", i, "R%s, CPSR"); + return; + } else + if(i->op == 11) { + format("MOVW", i, "R%s, SPSR"); + return; + } + } + format(o->o, i, o->a); +} + +static void +armdpi(Opcode *o, Instr *i) +{ + ulong v; + int c; + + v = (i->w >> 0) & 0xff; + c = (i->w >> 8) & 0xf; + while(c) { + v = (v<<30) | (v>>2); + c--; + } + i->imm = v; + i->store = (i->w >> 20) & 1; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = i->w&0x0f; + + /* RET is encoded as ADD #0,R14,R15 */ + if((i->w & 0x0fffffff) == 0x028ef000){ + format("RET%C", i, ""); + return; + } + if((i->w & 0x0ff0ffff) == 0x0280f000){ + format("B%C", i, "0(R%n)"); + return; + } + format(o->o, i, o->a); +} + +static void +armsdti(Opcode *o, Instr *i) +{ + ulong v; + + v = i->w & 0xfff; + if(!(i->w & (1<<23))) + v = -v; + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->imm = v; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + /* RET is encoded as LW.P x,R13,R15 */ + if ((i->w & 0x0ffff000) == 0x049df000) + { + format("RET%C%p", i, "%I"); + return; + } + format(o->o, i, o->a); +} + +/* arm V4 ld/st halfword, signed byte */ +static void +armhwby(Opcode *o, Instr *i) +{ + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf); + if (!(i->w & (1 << 23))) + i->imm = - i->imm; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = (i->w >> 0) & 0xf; + format(o->o, i, o->a); +} + +static void +armsdts(Opcode *o, Instr *i) +{ + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->rs = (i->w >> 0) & 0xf; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + format(o->o, i, o->a); +} + +static void +armbdt(Opcode *o, Instr *i) +{ + i->store = (i->w >> 21) & 0x3; /* S & W bits */ + i->rn = (i->w >> 16) & 0xf; + i->imm = i->w & 0xffff; + if(i->w == 0xe8fd8000) + format("RFE", i, ""); + else + format(o->o, i, o->a); +} + +static void +armund(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armcdt(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armunk(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armb(Opcode *o, Instr *i) +{ + ulong v; + + v = i->w & 0xffffff; + if(v & 0x800000) + v |= ~0xffffff; + i->imm = (v<<2) + i->addr + 8; + format(o->o, i, o->a); +} + +static void +armco(Opcode *o, Instr *i) /* coprocessor instructions */ +{ + int op, p, cp; + + char buf[1024]; + + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = i->w&0xf; + cp = (i->w >> 8) & 0xf; + p = (i->w >> 5) & 0x7; + if(i->w&(1<<4)) { + op = (i->w >> 21) & 0x07; + snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p); + } else { + op = (i->w >> 20) & 0x0f; + snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p); + } + format(o->o, i, buf); +} + +static int +armcondpass(Map *map, Rgetter rget, uchar cond) +{ + ulong psr; + uchar n; + uchar z; + uchar c; + uchar v; + + psr = rget(map, "PSR"); + n = (psr >> 31) & 1; + z = (psr >> 30) & 1; + c = (psr >> 29) & 1; + v = (psr >> 28) & 1; + + switch(cond) { + case 0: return z; + case 1: return !z; + case 2: return c; + case 3: return !c; + case 4: return n; + case 5: return !n; + case 6: return v; + case 7: return !v; + case 8: return c && !z; + case 9: return !c || z; + case 10: return n == v; + case 11: return n != v; + case 12: return !z && (n == v); + case 13: return z && (n != v); + case 14: return 1; + case 15: return 0; + } + return 0; +} + +static ulong +armshiftval(Map *map, Rgetter rget, Instr *i) +{ + if(i->w & (1 << 25)) { /* immediate */ + ulong imm = i->w & BITS(0, 7); + ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */ + return ROR(imm, s); + } else { + char buf[8]; + ulong v; + ulong s = (i->w & BITS(7,11)) >> 7; + + sprint(buf, "R%ld", i->w & 0xf); + v = rget(map, buf); + + switch((i->w & BITS(4, 6)) >> 4) { + case 0: /* LSLIMM */ + return v << s; + case 1: /* LSLREG */ + sprint(buf, "R%lud", s >> 1); + s = rget(map, buf) & 0xFF; + if(s >= 32) return 0; + return v << s; + case 2: /* LSRIMM */ + return LSR(v, s); + case 3: /* LSRREG */ + sprint(buf, "R%ld", s >> 1); + s = rget(map, buf) & 0xFF; + if(s >= 32) return 0; + return LSR(v, s); + case 4: /* ASRIMM */ + if(s == 0) { + if((v & (1U<<31)) == 0) + return 0; + return 0xFFFFFFFF; + } + return ASR(v, s); + case 5: /* ASRREG */ + sprint(buf, "R%ld", s >> 1); + s = rget(map, buf) & 0xFF; + if(s >= 32) { + if((v & (1U<<31)) == 0) + return 0; + return 0xFFFFFFFF; + } + return ASR(v, s); + case 6: /* RORIMM */ + if(s == 0) { + ulong c = (rget(map, "PSR") >> 29) & 1; + + return (c << 31) | LSR(v, 1); + } + return ROR(v, s); + case 7: /* RORREG */ + sprint(buf, "R%ld", (s>>1)&0xF); + s = rget(map, buf); + if(s == 0 || (s & 0xF) == 0) + return v; + return ROR(v, s & 0xF); + } + } + return 0; +} + +static int +nbits(ulong v) +{ + int n = 0; + int i; + + for(i=0; i < 32 ; i++) { + if(v & 1) ++n; + v >>= 1; + } + + return n; +} + +static ulong +armmaddr(Map *map, Rgetter rget, Instr *i) +{ + ulong v; + ulong nb; + char buf[8]; + ulong rn; + + rn = (i->w >> 16) & 0xf; + sprint(buf,"R%ld", rn); + + v = rget(map, buf); + nb = nbits(i->w & ((1 << 15) - 1)); + + switch((i->w >> 23) & 3) { + case 0: return (v - (nb*4)) + 4; + case 1: return v; + case 2: return v - (nb*4); + case 3: return v + 4; + } + return 0; +} + +static ulong +armaddr(Map *map, Rgetter rget, Instr *i) +{ + char buf[8]; + ulong rn; + + sprint(buf, "R%ld", (i->w >> 16) & 0xf); + rn = rget(map, buf); + + if((i->w & (1<<24)) == 0) { /* POSTIDX */ + sprint(buf, "R%ld", rn); + return rget(map, buf); + } + + if((i->w & (1<<25)) == 0) { /* OFFSET */ + sprint(buf, "R%ld", rn); + if(i->w & (1U<<23)) + return rget(map, buf) + (i->w & BITS(0,11)); + return rget(map, buf) - (i->w & BITS(0,11)); + } else { /* REGOFF */ + ulong index = 0; + uchar c; + uchar rm; + + sprint(buf, "R%ld", i->w & 0xf); + rm = rget(map, buf); + + switch((i->w & BITS(5,6)) >> 5) { + case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break; + case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break; + case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break; + case 3: + if((i->w & BITS(7,11)) == 0) { + c = (rget(map, "PSR") >> 29) & 1; + index = c << 31 | LSR(rm, 1); + } else { + index = ROR(rm, ((i->w & BITS(7,11)) >> 7)); + } + break; + } + if(i->w & (1<<23)) + return rn + index; + return rn - index; + } +} + +static ulong +armfadd(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + char buf[8]; + int r; + + r = (i->w >> 12) & 0xf; + if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf)) + return pc+4; + + r = (i->w >> 16) & 0xf; + sprint(buf, "R%d", r); + + return rget(map, buf) + armshiftval(map, rget, i); +} + +static ulong +armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + ulong v; + ulong addr; + + v = i->w & 1<<15; + if(!v || !armcondpass(map, rget, (i->w>>28)&0xf)) + return pc+4; + + addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15)); + if(get4(map, addr, (long*)&v) < 0) { + werrstr("can't read addr: %r"); + return -1; + } + return v; +} + +static ulong +armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + if(!armcondpass(map, rget, (i->w >> 28) & 0xf)) + return pc+4; + + return pc + (((signed long)i->w << 8) >> 6) + 8; +} + +static ulong +armfmov(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + ulong rd; + ulong v; + + rd = (i->w >> 12) & 0xf; + if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf)) + return pc+4; + + /* LDR */ + /* BUG: Needs LDH/B, too */ + if((i->w>>26)&0x3 == 1) { + if(get4(map, armaddr(map, rget, i), (long*)&v) < 0) { + werrstr("can't read instruction: %r"); + return pc+4; + } + return v; + } + + /* MOV */ + v = armshiftval(map, rget, i); + + return v; +} + +static Opcode opcodes[] = +{ + "AND%C%S", armdps, 0, "R%s,R%n,R%d", + "EOR%C%S", armdps, 0, "R%s,R%n,R%d", + "SUB%C%S", armdps, 0, "R%s,R%n,R%d", + "RSB%C%S", armdps, 0, "R%s,R%n,R%d", + "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d", + "ADC%C%S", armdps, 0, "R%s,R%n,R%d", + "SBC%C%S", armdps, 0, "R%s,R%n,R%d", + "RSC%C%S", armdps, 0, "R%s,R%n,R%d", + "TST%C%S", armdps, 0, "R%s,R%n", + "TEQ%C%S", armdps, 0, "R%s,R%n", + "CMP%C%S", armdps, 0, "R%s,R%n", + "CMN%C%S", armdps, 0, "R%s,R%n", + "ORR%C%S", armdps, 0, "R%s,R%n,R%d", + "MOVW%C%S", armdps, armfmov, "R%s,R%d", + "BIC%C%S", armdps, 0, "R%s,R%n,R%d", + "MVN%C%S", armdps, 0, "R%s,R%d", + +/* 16 */ + "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d", + "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "TST%C%S", armdps, 0, "(R%s%h%m),R%n", + "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n", + "CMP%C%S", armdps, 0, "(R%s%h%m),R%n", + "CMN%C%S", armdps, 0, "(R%s%h%m),R%n", + "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d", + "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "MVN%C%S", armdps, 0, "(R%s%h%m),R%d", + +/* 32 */ + "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d", + "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "TST%C%S", armdps, 0, "(R%s%hR%M),R%n", + "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n", + "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n", + "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n", + "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d", + "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d", + +/* 48 */ + "AND%C%S", armdpi, 0, "$#%i,R%n,R%d", + "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d", + "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d", + "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d", + "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d", + "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "TST%C%S", armdpi, 0, "$#%i,R%n", + "TEQ%C%S", armdpi, 0, "$#%i,R%n", + "CMP%C%S", armdpi, 0, "$#%i,R%n", + "CMN%C%S", armdpi, 0, "$#%i,R%n", + "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d", + "MOVW%C%S", armdpi, armfmov, "$#%i,R%d", + "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "MVN%C%S", armdpi, 0, "$#%i,R%d", + +/* 48+16 */ + "MUL%C%S", armdpi, 0, "R%s,R%M,R%n", + "MULA%C%S", armdpi, 0, "R%s,R%M,R%n,R%d", + "SWPW", armdpi, 0, "R%s,(R%n),R%d", + "SWPB", armdpi, 0, "R%s,(R%n),R%d", + +/* 48+16+4 */ + "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)", + "MOV%u%C%p", armhwby, 0, "R%d,%I", + "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d", + "MOV%u%C%p", armhwby, armfmov, "%I,R%d", + +/* 48+24 */ + "MOVW%C%p", armsdti, 0, "R%d,%I", + "MOVB%C%p", armsdti, 0, "R%d,%I", + "MOVW%C%p", armsdti, armfmov, "%I,R%d", + "MOVBU%C%p", armsdti, armfmov, "%I,R%d", + + "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)", + "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)", + "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d", + "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d", + + "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)", + "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]", + + "B%C", armb, armfbranch, "%b", + "BL%C", armb, armfbranch, "%b", + + "CDP%C", armco, 0, "", + "CDP%C", armco, 0, "", + "MCR%C", armco, 0, "", + "MRC%C", armco, 0, "", + + "UNK", armunk, 0, "", +}; + +static void +gaddr(Instr *i) +{ + *i->curr++ = '$'; + i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY); +} + +static char *mode[] = { 0, "IA", "DB", "IB" }; +static char *pw[] = { "P", "PW", 0, "W" }; +static char *sw[] = { 0, "W", "S", "SW" }; + +static void +format(char *mnemonic, Instr *i, char *f) +{ + int j, k, m, n; + int g; + char *fmt; + + if(mnemonic) + format(0, i, mnemonic); + if(f == 0) + return; + if(mnemonic) + if(i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if(*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 'C': /* .CONDITION */ + if(cond[i->cond]) + bprint(i, ".%s", cond[i->cond]); + break; + + case 'S': /* .STORE */ + if(i->store) + bprint(i, ".S"); + break; + + case 'P': /* P & U bits for block move */ + n = (i->w >>23) & 0x3; + if (mode[n]) + bprint(i, ".%s", mode[n]); + break; + + case 'p': /* P & W bits for single data xfer*/ + if (pw[i->store]) + bprint(i, ".%s", pw[i->store]); + break; + + case 'a': /* S & W bits for single data xfer*/ + if (sw[i->store]) + bprint(i, ".%s", sw[i->store]); + break; + + case 's': + bprint(i, "%d", i->rs & 0xf); + break; + + case 'M': + bprint(i, "%d", (i->w>>8) & 0xf); + break; + + case 'm': + bprint(i, "%d", (i->w>>7) & 0x1f); + break; + + case 'h': + bprint(i, shtype[(i->w>>5) & 0x3]); + break; + + case 'u': /* Signed/unsigned Byte/Halfword */ + bprint(i, hb[(i->w>>5) & 0x3]); + break; + + case 'I': + if (i->rn == 13) { + if (plocal(i)) + break; + } + g = 0; + fmt = "#%lx(R%d)"; + if (i->rn == 15) { + /* convert load of offset(PC) to a load immediate */ + if (get4(i->map, i->addr+i->imm+8, &i->imm) > 0) + { + g = 1; + fmt = ""; + } + } + if (mach->sb) + { + if (i->rd == 11) { + ulong nxti; + + if (get4(i->map, i->addr+4, (long*)&nxti) > 0) { + if ((nxti & 0x0e0f0fff) == 0x060c000b) { + i->imm += mach->sb; + g = 1; + fmt = "-SB"; + } + } + } + if (i->rn == 12) + { + i->imm += mach->sb; + g = 1; + fmt = "-SB(SB)"; + } + } + if (g) + { + gaddr(i); + bprint(i, fmt, i->rn); + } + else + bprint(i, fmt, i->imm, i->rn); + break; + case 'U': /* Add/subtract from base */ + bprint(i, addsub[(i->w >> 23) & 1]); + break; + + case 'n': + bprint(i, "%d", i->rn); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'i': + bprint(i, "%lux", i->imm); + break; + + case 'b': + i->curr += symoff(i->curr, i->end-i->curr, + i->imm, CTEXT); + break; + + case 'g': + i->curr += gsymoff(i->curr, i->end-i->curr, + i->imm, CANY); + break; + + case 'r': + n = i->imm&0xffff; + j = 0; + k = 0; + while(n) { + m = j; + while(n&0x1) { + j++; + n >>= 1; + } + if(j != m) { + if(k) + bprint(i, ","); + if(j == m+1) + bprint(i, "R%d", m); + else + bprint(i, "R%d-R%d", m, j-1); + k = 1; + } + j++; + n >>= 1; + } + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n-1; + if(decode(map, pc, &i) < 0) + return -1; + + (*opcodes[i.op].fmt)(&opcodes[i.op], &i); + return 4; +} + +static int +arminst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + USED(modifier); + return printins(map, pc, buf, n); +} + +static int +armdas(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + if(i.end-i.curr > 8) + i.curr = _hexify(buf, i.w, 7); + *i.curr = 0; + return 4; +} + +static int +arminstlen(Map *map, ulong pc) +{ + Instr i; + + if(decode(map, pc, &i) < 0) + return -1; + return 4; +} + +static int +armfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + ulong d; + Instr i; + + if(decode(map, pc, &i) < 0) + return -1; + + if(opcodes[i.op].foll) { + d = (*opcodes[i.op].foll)(map, rget, &i, pc); + if(d == -1) + return -1; + } else + d = pc+4; + + foll[0] = d; + return 1; +} diff --git a/utils/libmach/5obj.c b/utils/libmach/5obj.c new file mode 100644 index 00000000..e7e3437c --- /dev/null +++ b/utils/libmach/5obj.c @@ -0,0 +1,133 @@ +/* + * 5obj.c - identify and parse a arm object file + */ +#include <lib9.h> +#include <bio.h> +#include "5c/5.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_is5(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + +int +_read5(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 6); /* scond(1), reg(1), lineno(4) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + case D_FPCR: + break; + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/6.c b/utils/libmach/6.c new file mode 100644 index 00000000..28c74a43 --- /dev/null +++ b/utils/libmach/6.c @@ -0,0 +1,117 @@ +/* + * x86-amd64 definition + */ +#include <lib9.h> +#include <bio.h> +#include "ureg6.h" +#include "mach.h" + +#define REGOFF(x) (uvlong)(&((struct Ureg *) 0)->x) + +#define PC REGOFF(pc) +#define SP REGOFF(sp) +#define AX REGOFF(ax) + +#define REGSIZE sizeof(struct Ureg) +#define FP_CTLS(x) (REGSIZE+2*(x)) +#define FP_CTL(x) (REGSIZE+4*(x)) +#define FP_REG(x) (FP_CTL(8)+16*(x)) +#define XM_REG(x) (FP_CTL(8)+8*16+16*(x)) + +#define FPREGSIZE 512 /* TO DO? currently only 0x1A0 used */ + +Reglist amd64reglist[] = { + {"R15", REGOFF(r15), RINT, 'Y'}, + {"R14", REGOFF(r14), RINT, 'Y'}, + {"R13", REGOFF(r13), RINT, 'Y'}, + {"R12", REGOFF(r12), RINT, 'Y'}, + {"R11", REGOFF(r11), RINT, 'Y'}, + {"R10", REGOFF(r10), RINT, 'Y'}, + {"R9", REGOFF(r9), RINT, 'Y'}, + {"R8", REGOFF(r8), RINT, 'Y'}, + {"DI", REGOFF(di), RINT, 'X'}, + {"SI", REGOFF(si), RINT, 'Y'}, + {"BP", REGOFF(bp), RINT, 'Y'}, + {"BX", REGOFF(bx), RINT, 'Y'}, + {"DX", REGOFF(dx), RINT, 'Y'}, + {"CX", REGOFF(cx), RINT, 'Y'}, + {"AX", REGOFF(ax), RINT, 'Y'}, + {"GS", REGOFF(gs), RINT, 'Y'}, + {"FS", REGOFF(fs), RINT, 'Y'}, + {"ES", REGOFF(es), RINT, 'Y'}, + {"DS", REGOFF(ds), RINT, 'Y'}, + {"TRAP", REGOFF(trap), RINT, 'Y'}, + {"ECODE", REGOFF(ecode), RINT, 'Y'}, + {"PC", PC, RINT, 'Y'}, + {"CS", REGOFF(cs), RINT, 'Y'}, + {"EFLAGS", REGOFF(flags), RINT, 'Y'}, + {"SP", SP, RINT, 'Y'}, + {"SS", REGOFF(ss), RINT, 'Y'}, + + {"FCW", FP_CTLS(0), RFLT, 'x'}, + {"FSW", FP_CTLS(1), RFLT, 'x'}, + {"FTW", FP_CTLS(2), RFLT, 'x'}, + {"FOP", FP_CTLS(3), RFLT, 'x'}, + {"FPC", FP_CTL(2), RFLT, 'Y'}, + {"RDP", FP_CTL(4), RFLT, 'Y'}, + {"MXCSR", FP_CTL(6), RFLT, 'X'}, + {"MXCSRMSK", FP_CTL(7), RFLT, 'X'}, + {"M0", FP_REG(0), RFLT, 'F'}, /* assumes double */ + {"M1", FP_REG(1), RFLT, 'F'}, + {"M2", FP_REG(2), RFLT, 'F'}, + {"M3", FP_REG(3), RFLT, 'F'}, + {"M4", FP_REG(4), RFLT, 'F'}, + {"M5", FP_REG(5), RFLT, 'F'}, + {"M6", FP_REG(6), RFLT, 'F'}, + {"M7", FP_REG(7), RFLT, 'F'}, + {"X0", XM_REG(0), RFLT, 'F'}, /* assumes double */ + {"X1", XM_REG(1), RFLT, 'F'}, + {"X2", XM_REG(2), RFLT, 'F'}, + {"X3", XM_REG(3), RFLT, 'F'}, + {"X4", XM_REG(4), RFLT, 'F'}, + {"X5", XM_REG(5), RFLT, 'F'}, + {"X6", XM_REG(6), RFLT, 'F'}, + {"X7", XM_REG(7), RFLT, 'F'}, + {"X8", XM_REG(8), RFLT, 'F'}, + {"X9", XM_REG(9), RFLT, 'F'}, + {"X10", XM_REG(10), RFLT, 'F'}, + {"X11", XM_REG(11), RFLT, 'F'}, + {"X12", XM_REG(12), RFLT, 'F'}, + {"X13", XM_REG(13), RFLT, 'F'}, + {"X14", XM_REG(14), RFLT, 'F'}, + {"X15", XM_REG(15), RFLT, 'F'}, + {"X16", XM_REG(16), RFLT, 'F'}, +/* + {"F0", FP_REG(7), RFLT, '3'}, + {"F1", FP_REG(6), RFLT, '3'}, + {"F2", FP_REG(5), RFLT, '3'}, + {"F3", FP_REG(4), RFLT, '3'}, + {"F4", FP_REG(3), RFLT, '3'}, + {"F5", FP_REG(2), RFLT, '3'}, + {"F6", FP_REG(1), RFLT, '3'}, + {"F7", FP_REG(0), RFLT, '3'}, +*/ + { 0 } +}; + +Mach mamd64= +{ + "amd64", + MI386, /* machine type */ /* TO DO */ + amd64reglist, /* register list */ + REGSIZE, /* size of registers in bytes */ + FPREGSIZE, /* size of fp registers in bytes */ + "PC", /* name of PC */ + "SP", /* name of SP */ + 0, /* link register */ + "setSB", /* static base register name (bogus anyways) */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80100000, /* kernel base */ /* TO DO: uvlong or vlong */ + 0, /* kernel text mask */ + 1, /* quantization of pc */ + 8, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/6obj.c b/utils/libmach/6obj.c new file mode 100644 index 00000000..7fb95115 --- /dev/null +++ b/utils/libmach/6obj.c @@ -0,0 +1,142 @@ +/* + * 6obj.c - identify and parse an amd64 object file + */ +#include <lib9.h> +#include <bio.h> +#include "6c/6.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char sym; + char flags; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_is6(char *t) +{ + uchar *s = (uchar*)t; + + return s[0] == (ANAME&0xff) /* aslo = ANAME */ + && s[1] == ((ANAME>>8)&0xff) + && s[2] == D_FILE /* type */ + && s[3] == 1 /* sym */ + && s[4] == '<'; /* name of file */ +} + +int +_read6(Biobuf *bp, Prog* p) +{ + int as, n, c; + Addr a; + + as = Bgetc(bp); /* as(low) */ + if(as < 0) + return 0; + c = Bgetc(bp); /* as(high) */ + if(c < 0) + return 0; + as |= ((c & 0xff) << 8); + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + if(as == AGLOBL) + p->kind = aData; + skip(bp, 4); /* lineno(4) */ + a = addr(bp); + addr(bp); + if(!(a.flags & T_SYM)) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + int t; + long l; + vlong off; + + off = 0; + a.sym = -1; + a.flags = Bgetc(bp); /* flags */ + if(a.flags & T_INDEX) + skip(bp, 2); + if(a.flags & T_OFFSET){ + l = Bgetc(bp); + l |= Bgetc(bp) << 8; + l |= Bgetc(bp) << 16; + l |= Bgetc(bp) << 24; + off = l; + if(a.flags & T_64){ + l = Bgetc(bp); + l |= Bgetc(bp) << 8; + l |= Bgetc(bp) << 16; + l |= Bgetc(bp) << 24; + off = ((vlong)l << 32) | (off & 0xFFFFFFFF); + } + if(off < 0) + off = -off; + } + if(a.flags & T_SYM) + a.sym = Bgetc(bp); + if(a.flags & T_FCONST) + skip(bp, 8); + else + if(a.flags & T_SCONST) + skip(bp, NSNAME); + if(a.flags & T_TYPE) { + t = Bgetc(bp); + if(a.sym > 0 && (t==D_PARAM || t==D_AUTO)) + _offset(a.sym, off); + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/8.c b/utils/libmach/8.c new file mode 100644 index 00000000..9c7bff11 --- /dev/null +++ b/utils/libmach/8.c @@ -0,0 +1,78 @@ +/* + * 386 definition + */ +#include <lib9.h> +#include <bio.h> +#include "ureg8.h" +#include "mach.h" + +#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x) + +#define PC REGOFF(pc) +#define SP REGOFF(u0.sp) +#define AX REGOFF(ax) + +#define REGSIZE sizeof(struct Ureg) +#define FP_CTL(x) (REGSIZE+4*(x)) +#define FP_REG(x) (FP_CTL(7)+10*(x)) +#define FPREGSIZE (6*4+8*10) + +Reglist i386reglist[] = { + {"DI", REGOFF(di), RINT, 'X'}, + {"SI", REGOFF(si), RINT, 'X'}, + {"BP", REGOFF(bp), RINT, 'X'}, + {"BX", REGOFF(bx), RINT, 'X'}, + {"DX", REGOFF(dx), RINT, 'X'}, + {"CX", REGOFF(cx), RINT, 'X'}, + {"AX", REGOFF(ax), RINT, 'X'}, + {"GS", REGOFF(gs), RINT, 'X'}, + {"FS", REGOFF(fs), RINT, 'X'}, + {"ES", REGOFF(es), RINT, 'X'}, + {"DS", REGOFF(ds), RINT, 'X'}, + {"TRAP", REGOFF(trap), RINT, 'X'}, + {"ECODE", REGOFF(ecode), RINT, 'X'}, + {"PC", PC, RINT, 'X'}, + {"CS", REGOFF(cs), RINT, 'X'}, + {"EFLAGS", REGOFF(flags), RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"SS", REGOFF(ss), RINT, 'X'}, + + {"E0", FP_CTL(0), RFLT, 'X'}, + {"E1", FP_CTL(1), RFLT, 'X'}, + {"E2", FP_CTL(2), RFLT, 'X'}, + {"E3", FP_CTL(3), RFLT, 'X'}, + {"E4", FP_CTL(4), RFLT, 'X'}, + {"E5", FP_CTL(5), RFLT, 'X'}, + {"E6", FP_CTL(6), RFLT, 'X'}, + {"F0", FP_REG(7), RFLT, '3'}, + {"F1", FP_REG(6), RFLT, '3'}, + {"F2", FP_REG(5), RFLT, '3'}, + {"F3", FP_REG(4), RFLT, '3'}, + {"F4", FP_REG(3), RFLT, '3'}, + {"F5", FP_REG(2), RFLT, '3'}, + {"F6", FP_REG(1), RFLT, '3'}, + {"F7", FP_REG(0), RFLT, '3'}, + { 0 } +}; + +Mach mi386 = +{ + "386", + MI386, /* machine type */ + i386reglist, /* register list */ + REGSIZE, /* size of registers in bytes */ + FPREGSIZE, /* size of fp registers in bytes */ + "PC", /* name of PC */ + "SP", /* name of SP */ + 0, /* link register */ + "setSB", /* static base register name (bogus anyways) */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80100000, /* kernel base */ + 0, /* kernel text mask */ + 1, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/8db.c b/utils/libmach/8db.c new file mode 100644 index 00000000..86b6e1f2 --- /dev/null +++ b/utils/libmach/8db.c @@ -0,0 +1,1850 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +/* + * i386-specific debugger interface + */ + +static char *i386excep(Map*, Rgetter); + +static int i386trace(Map*, ulong, ulong, ulong, Tracer); +static ulong i386frame(Map*, ulong, ulong, ulong, ulong); +static int i386foll(Map*, ulong, Rgetter, ulong*); +static int i386inst(Map*, ulong, char, char*, int); +static int i386das(Map*, ulong, char*, int); +static int i386instlen(Map*, ulong); + +static char STARTSYM[] = "_main"; +static char PROFSYM[] = "_mainp"; +static char FRAMENAME[] = ".frame"; +static char *excname[] = +{ + "divide error", /* 0 */ + "debug exception", /* 1 */ + 0,0, /* 2, 3 */ + "overflow", /* 4 */ + "bounds check", /* 5 */ + "invalid opcode", /* 6 */ + "math coprocessor emulation", /* 7 */ + "double fault", /* 8 */ + "math coprocessor overrun", /* 9 */ + "invalid TSS", /* 10 */ + "segment not present", /* 11 */ + "stack exception", /* 12 */ + "general protection violation", /* 13 */ + "page fault", /* 14 */ + 0, /* 15 */ + "math coprocessor error", /* 16 */ + 0,0,0,0,0,0,0, /* 17-23 */ + "clock", /* 24 */ + "keyboard", /* 25 */ + 0, /* 26 */ + "modem status", /* 27 */ + "serial line status", /* 28 */ + 0, /* 29 */ + "floppy disk", /* 30 */ + 0,0,0,0,0, /* 31-35 */ + "mouse", /* 36 */ + "math coprocessor", /* 37 */ + "hard disk", /* 38 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */ + 0,0,0,0,0,0,0,0,0, /* 55-63 */ + "system call", /* 64 */ +}; + +Machdata i386mach = +{ + {0xCC, 0, 0, 0}, /* break point: INT 3 */ + 1, /* break point size */ + + leswab, /* convert short to local byte order */ + leswal, /* convert long to local byte order */ + leswav, /* convert vlong to local byte order */ + i386trace, /* C traceback */ + i386frame, /* frame finder */ + i386excep, /* print exception */ + 0, /* breakpoint fixup */ + leieeesftos, /* single precision float printer */ + leieeedftos, /* double precision float printer */ + i386foll, /* following addresses */ + i386inst, /* print instruction */ + i386das, /* dissembler */ + i386instlen, /* instruction size calculation */ +}; + +static char* +i386excep(Map *map, Rgetter rget) +{ + ulong c; + ulong pc; + static char buf[16]; + + c = (*rget)(map, "TRAP"); + if(c > 64 || excname[c] == 0) { + if (c == 3) { + pc = (*rget)(map, "PC"); + if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0) + if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0) + return "breakpoint"; + } + sprint(buf, "exception %ld", c); + return buf; + } else + return excname[c]; +} + +static int +i386trace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace) +{ + int i; + ulong osp; + Symbol s, f; + + USED(link); + i = 0; + osp = 0; + while(findsym(pc, CTEXT, &s)) { + if (osp == sp) + break; + osp = sp; + + if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) + break; + + if(pc != s.value) { /* not at first instruction */ + if(findlocal(&s, FRAMENAME, &f) == 0) + break; + sp += f.value-mach->szaddr; + } + + if (get4(map, sp, (long *) &pc) < 0) + break; + + if(pc == 0) + break; + + (*trace)(map, pc, sp, &s); + sp += mach->szaddr; + + if(++i > 40) + break; + } + return i; +} + +static ulong +i386frame(Map *map, ulong addr, ulong pc, ulong sp, ulong link) +{ + Symbol s, f; + + USED(link); + while (findsym(pc, CTEXT, &s)) { + if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) + break; + + if(pc != s.value) { /* not first instruction */ + if(findlocal(&s, FRAMENAME, &f) == 0) + break; + sp += f.value-mach->szaddr; + } + + if (s.value == addr) + return sp; + + if (get4(map, sp, (long *)&pc) < 0) + break; + sp += mach->szaddr; + } + return 0; +} + + /* I386/486 - Disassembler and related functions */ + +/* + * an instruction + */ +typedef struct Instr Instr; +struct Instr +{ + uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */ + ulong addr; /* address of start of instruction */ + int n; /* number of bytes in instruction */ + char *prefix; /* instr prefix */ + char *segment; /* segment override */ + uchar jumptype; /* set to the operand type for jump/ret/call */ + char osize; /* 'W' or 'L' */ + char asize; /* address size 'W' or 'L' */ + uchar mod; /* bits 6-7 of mod r/m field */ + uchar reg; /* bits 3-5 of mod r/m field */ + char ss; /* bits 6-7 of SIB */ + char index; /* bits 3-5 of SIB */ + char base; /* bits 0-2 of SIB */ + short seg; /* segment of far address */ + ulong disp; /* displacement */ + ulong imm; /* immediate */ + ulong imm2; /* second immediate operand */ + char *curr; /* fill level in output buffer */ + char *end; /* end of output buffer */ + char *err; /* error message */ +}; + + /* 386 register (ha!) set */ +enum{ + AX=0, + CX, + DX, + BX, + SP, + BP, + SI, + DI, +}; + /* Operand Format codes */ +/* +%A - address size register modifier (!asize -> 'E') +%C - Control register CR0/CR1/CR2 +%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7 +%I - second immediate operand +%O - Operand size register modifier (!osize -> 'E') +%T - Test register TR6/TR7 +%S - size code ('W' or 'L') +%X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE" +%d - displacement 16-32 bits +%e - effective address - Mod R/M value +%f - floating point register F0-F7 - from Mod R/M register +%g - segment register +%i - immediate operand 8-32 bits +%p - PC-relative - signed displacement in immediate field +%r - Reg from Mod R/M +%x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ" +*/ + +typedef struct Optable Optable; +struct Optable +{ + char operand[2]; + void *proto; /* actually either (char*) or (Optable*) */ +}; + /* Operand decoding codes */ +enum { + Ib = 1, /* 8-bit immediate - (no sign extension)*/ + Ibs, /* 8-bit immediate (sign extended) */ + Jbs, /* 8-bit sign-extended immediate in jump or call */ + Iw, /* 16-bit immediate -> imm */ + Iw2, /* 16-bit immediate -> imm2 */ + Iwd, /* Operand-sized immediate (no sign extension)*/ + Awd, /* Address offset */ + Iwds, /* Operand-sized immediate (sign extended) */ + RM, /* Word or long R/M field with register (/r) */ + RMB, /* Byte R/M field with register (/r) */ + RMOP, /* Word or long R/M field with op code (/digit) */ + RMOPB, /* Byte R/M field with op code (/digit) */ + RMR, /* R/M register only (mod = 11) */ + RMM, /* R/M memory only (mod = 0/1/2) */ + R0, /* Base reg of Mod R/M is literal 0x00 */ + R1, /* Base reg of Mod R/M is literal 0x01 */ + FRMOP, /* Floating point R/M field with opcode */ + FRMEX, /* Extended floating point R/M field with opcode */ + JUMP, /* Jump or Call flag - no operand */ + RET, /* Return flag - no operand */ + OA, /* literal 0x0a byte */ + PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ + AUX, /* Multi-byte op code - Auxiliary table */ + PRE, /* Instr Prefix */ + SEG, /* Segment Prefix */ + OPOVER, /* Operand size override */ + ADDOVER, /* Address size override */ +}; + +static Optable optab0F00[8]= +{ + 0,0, "MOVW LDT,%e", /* 0x00 */ + 0,0, "MOVW TR,%e", /* 0x01 */ + 0,0, "MOVW %e,LDT", /* 0x02 */ + 0,0, "MOVW %e,TR", /* 0x03 */ + 0,0, "VERR %e", /* 0x04 */ + 0,0, "VERW %e", /* 0x05 */ +}; + +static Optable optab0F01[8]= +{ + 0,0, "MOVL GDTR,%e", /* 0x00 */ + 0,0, "MOVL IDTR,%e", /* 0x01 */ + 0,0, "MOVL %e,GDTR", /* 0x02 */ + 0,0, "MOVL %e,IDTR", /* 0x03 */ + 0,0, "MOVW MSW,%e", /* 0x04 */ /* word */ + 0,0, "", /* 0x05 */ + 0,0, "MOVW %e,MSW", /* 0x06 */ /* word */ +}; + +static Optable optab0FBA[8]= +{ + 0,0, "", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "", /* 0x02 */ + 0,0, "", /* 0x03 */ + Ib,0, "BT%S %i,%e", /* 0x04 */ + Ib,0, "BTS%S %i,%e", /* 0x05 */ + Ib,0, "BTR%S %i,%e", /* 0x06 */ + Ib,0, "BTC%S %i,%e", /* 0x07 */ +}; + +static Optable optab0F[256]= +{ + RMOP,0, optab0F00, /* 0x00 */ + RMOP,0, optab0F01, /* 0x01 */ + RM,0, "LAR %e,%r", /* 0x02 */ + RM,0, "LSL %e,%r", /* 0x03 */ + 0,0, "", /* 0x04 */ + 0,0, "", /* 0x05 */ + 0,0, "CLTS", /* 0x06 */ + 0,0, "", /* 0x07 */ + 0,0, "INVD", /* 0x08 */ + 0,0, "WBINVD", /* 0x09 */ + 0,0, "", /* 0x0a */ + 0,0, "", /* 0x0b */ + 0,0, "", /* 0x0c */ + 0,0, "", /* 0x0d */ + 0,0, "", /* 0x0e */ + 0,0, "", /* 0x0f */ + 0,0, "", /* 0x10 */ + 0,0, "", /* 0x11 */ + 0,0, "", /* 0x12 */ + 0,0, "", /* 0x13 */ + 0,0, "", /* 0x14 */ + 0,0, "", /* 0x15 */ + 0,0, "", /* 0x16 */ + 0,0, "", /* 0x17 */ + 0,0, "", /* 0x18 */ + 0,0, "", /* 0x19 */ + 0,0, "", /* 0x1a */ + 0,0, "", /* 0x1b */ + 0,0, "", /* 0x1c */ + 0,0, "", /* 0x1d */ + 0,0, "", /* 0x1e */ + 0,0, "", /* 0x1f */ + RMR,0, "MOVL %C,%e", /* 0x20 */ + RMR,0, "MOVL %D,%e", /* 0x21 */ + RMR,0, "MOVL %e,%C", /* 0x22 */ + RMR,0, "MOVL %e,%D", /* 0x23 */ + RMR,0, "MOVL %T,%e", /* 0x24 */ + 0,0, "", /* 0x25 */ + RMR,0, "MOVL %e,%T", /* 0x26 */ + 0,0, "", /* 0x27 */ + 0,0, "", /* 0x28 */ + 0,0, "", /* 0x29 */ + 0,0, "", /* 0x2a */ + 0,0, "", /* 0x2b */ + 0,0, "", /* 0x2c */ + 0,0, "", /* 0x2d */ + 0,0, "", /* 0x2e */ + 0,0, "", /* 0x2f */ + 0,0, "WRMSR", /* 0x30 */ + 0,0, "RDTSC", /* 0x31 */ + 0,0, "RDMSR", /* 0x32 */ + 0,0, "", /* 0x33 */ + 0,0, "", /* 0x34 */ + 0,0, "", /* 0x35 */ + 0,0, "", /* 0x36 */ + 0,0, "", /* 0x37 */ + 0,0, "", /* 0x38 */ + 0,0, "", /* 0x39 */ + 0,0, "", /* 0x3a */ + 0,0, "", /* 0x3b */ + 0,0, "", /* 0x3c */ + 0,0, "", /* 0x3d */ + 0,0, "", /* 0x3e */ + 0,0, "", /* 0x3f */ + 0,0, "", /* 0x40 */ + 0,0, "", /* 0x41 */ + 0,0, "", /* 0x42 */ + 0,0, "", /* 0x43 */ + 0,0, "", /* 0x44 */ + 0,0, "", /* 0x45 */ + 0,0, "", /* 0x46 */ + 0,0, "", /* 0x47 */ + 0,0, "", /* 0x48 */ + 0,0, "", /* 0x49 */ + 0,0, "", /* 0x4a */ + 0,0, "", /* 0x4b */ + 0,0, "", /* 0x4c */ + 0,0, "", /* 0x4d */ + 0,0, "", /* 0x4e */ + 0,0, "", /* 0x4f */ + 0,0, "", /* 0x50 */ + 0,0, "", /* 0x51 */ + 0,0, "", /* 0x52 */ + 0,0, "", /* 0x53 */ + 0,0, "", /* 0x54 */ + 0,0, "", /* 0x55 */ + 0,0, "", /* 0x56 */ + 0,0, "", /* 0x57 */ + 0,0, "", /* 0x58 */ + 0,0, "", /* 0x59 */ + 0,0, "", /* 0x5a */ + 0,0, "", /* 0x5b */ + 0,0, "", /* 0x5c */ + 0,0, "", /* 0x5d */ + 0,0, "", /* 0x5e */ + 0,0, "", /* 0x5f */ + 0,0, "", /* 0x60 */ + 0,0, "", /* 0x61 */ + 0,0, "", /* 0x62 */ + 0,0, "", /* 0x63 */ + 0,0, "", /* 0x64 */ + 0,0, "", /* 0x65 */ + 0,0, "", /* 0x66 */ + 0,0, "", /* 0x67 */ + 0,0, "", /* 0x68 */ + 0,0, "", /* 0x69 */ + 0,0, "", /* 0x6a */ + 0,0, "", /* 0x6b */ + 0,0, "", /* 0x6c */ + 0,0, "", /* 0x6d */ + 0,0, "", /* 0x6e */ + 0,0, "", /* 0x6f */ + 0,0, "", /* 0x70 */ + 0,0, "", /* 0x71 */ + 0,0, "", /* 0x72 */ + 0,0, "", /* 0x73 */ + 0,0, "", /* 0x74 */ + 0,0, "", /* 0x75 */ + 0,0, "", /* 0x76 */ + 0,0, "", /* 0x77 */ + 0,0, "", /* 0x78 */ + 0,0, "", /* 0x79 */ + 0,0, "", /* 0x7a */ + 0,0, "", /* 0x7b */ + 0,0, "", /* 0x7c */ + 0,0, "", /* 0x7d */ + 0,0, "", /* 0x7e */ + 0,0, "", /* 0x7f */ + Iwds,0, "JOS %p", /* 0x80 */ + Iwds,0, "JOC %p", /* 0x81 */ + Iwds,0, "JCS %p", /* 0x82 */ + Iwds,0, "JCC %p", /* 0x83 */ + Iwds,0, "JEQ %p", /* 0x84 */ + Iwds,0, "JNE %p", /* 0x85 */ + Iwds,0, "JLS %p", /* 0x86 */ + Iwds,0, "JHI %p", /* 0x87 */ + Iwds,0, "JMI %p", /* 0x88 */ + Iwds,0, "JPL %p", /* 0x89 */ + Iwds,0, "JPS %p", /* 0x8a */ + Iwds,0, "JPC %p", /* 0x8b */ + Iwds,0, "JLT %p", /* 0x8c */ + Iwds,0, "JGE %p", /* 0x8d */ + Iwds,0, "JLE %p", /* 0x8e */ + Iwds,0, "JGT %p", /* 0x8f */ + RMB,0, "SETOS %e", /* 0x90 */ + RMB,0, "SETOC %e", /* 0x91 */ + RMB,0, "SETCS %e", /* 0x92 */ + RMB,0, "SETCC %e", /* 0x93 */ + RMB,0, "SETEQ %e", /* 0x94 */ + RMB,0, "SETNE %e", /* 0x95 */ + RMB,0, "SETLS %e", /* 0x96 */ + RMB,0, "SETHI %e", /* 0x97 */ + RMB,0, "SETMI %e", /* 0x98 */ + RMB,0, "SETPL %e", /* 0x99 */ + RMB,0, "SETPS %e", /* 0x9a */ + RMB,0, "SETPC %e", /* 0x9b */ + RMB,0, "SETLT %e", /* 0x9c */ + RMB,0, "SETGE %e", /* 0x9d */ + RMB,0, "SETLE %e", /* 0x9e */ + RMB,0, "SETGT %e", /* 0x9f */ + 0,0, "PUSHL FS", /* 0xa0 */ + 0,0, "POPL FS", /* 0xa1 */ + 0,0, "CPUID", /* 0xa2 */ + RM,0, "BT%S %r,%e", /* 0xa3 */ + RM,Ib, "SHLD%S %r,%i,%e", /* 0xa4 */ + RM,0, "SHLD%S %r,CL,%e", /* 0xa5 */ + 0,0, "", /* 0xa6 */ + 0,0, "", /* 0xa7 */ + 0,0, "PUSHL GS", /* 0xa8 */ + 0,0, "POPL GS", /* 0xa9 */ + 0,0, "", /* 0xaa */ + RM,0, "BTS%S %r,%e", /* 0xab */ + RM,Ib, "SHRD%S %r,%i,%e", /* 0xac */ + RM,0, "SHRD%S %r,CL,%e", /* 0xad */ + 0,0, "", /* 0xae */ + RM,0, "IMUL%S %e,%r", /* 0xaf */ + 0,0, "", /* 0xb0 */ + 0,0, "", /* 0xb1 */ + RMM,0, "LSS %e,%r", /* 0xb2 */ + RM,0, "BTR%S %r,%e", /* 0xb3 */ + RMM,0, "LFS %e,%r", /* 0xb4 */ + RMM,0, "LGS %e,%r", /* 0xb5 */ + RMB,0, "MOVBZX %e,%R", /* 0xb6 */ + RM,0, "MOVWZX %e,%R", /* 0xb7 */ + 0,0, "", /* 0xb8 */ + 0,0, "", /* 0xb9 */ + RMOP,0, optab0FBA, /* 0xba */ + RM,0, "BTC%S %e,%r", /* 0xbb */ + RM,0, "BSF%S %e,%r", /* 0xbc */ + RM,0, "BSR%S %e,%r", /* 0xbd */ + RMB,0, "MOVBSX %e,%R", /* 0xbe */ + RM,0, "MOVWSX %e,%R", /* 0xbf */ +}; + +static Optable optab80[8]= +{ + Ib,0, "ADDB %i,%e", /* 0x00 */ + Ib,0, "ORB %i,%e", /* 0x01 */ + Ib,0, "ADCB %i,%e", /* 0x02 */ + Ib,0, "SBBB %i,%e", /* 0x03 */ + Ib,0, "ANDB %i,%e", /* 0x04 */ + Ib,0, "SUBB %i,%e", /* 0x05 */ + Ib,0, "XORB %i,%e", /* 0x06 */ + Ib,0, "CMPB %e,%i", /* 0x07 */ +}; + +static Optable optab81[8]= +{ + Iwd,0, "ADD%S %i,%e", /* 0x00 */ + Iwd,0, "OR%S %i,%e", /* 0x01 */ + Iwd,0, "ADC%S %i,%e", /* 0x02 */ + Iwd,0, "SBB%S %i,%e", /* 0x03 */ + Iwd,0, "AND%S %i,%e", /* 0x04 */ + Iwd,0, "SUB%S %i,%e", /* 0x05 */ + Iwd,0, "XOR%S %i,%e", /* 0x06 */ + Iwd,0, "CMP%S %e,%i", /* 0x07 */ +}; + +static Optable optab83[8]= +{ + Ibs,0, "ADD%S %i,%e", /* 0x00 */ + Ibs,0, "OR%S %i,%e", /* 0x01 */ + Ibs,0, "ADC%S %i,%e", /* 0x02 */ + Ibs,0, "SBB%S %i,%e", /* 0x03 */ + Ibs,0, "AND%S %i,%e", /* 0x04 */ + Ibs,0, "SUB%S %i,%e", /* 0x05 */ + Ibs,0, "XOR%S %i,%e", /* 0x06 */ + Ibs,0, "CMP%S %e,%i", /* 0x07 */ +}; + +static Optable optabC0[8] = +{ + Ib,0, "ROLB %i,%e", /* 0x00 */ + Ib,0, "RORB %i,%e", /* 0x01 */ + Ib,0, "RCLB %i,%e", /* 0x02 */ + Ib,0, "RCRB %i,%e", /* 0x03 */ + Ib,0, "SHLB %i,%e", /* 0x04 */ + Ib,0, "SHRB %i,%e", /* 0x05 */ + 0,0, "", /* 0x06 */ + Ib,0, "SARB %i,%e", /* 0x07 */ +}; + +static Optable optabC1[8] = +{ + Ib,0, "ROL%S %i,%e", /* 0x00 */ + Ib,0, "ROR%S %i,%e", /* 0x01 */ + Ib,0, "RCL%S %i,%e", /* 0x02 */ + Ib,0, "RCR%S %i,%e", /* 0x03 */ + Ib,0, "SHL%S %i,%e", /* 0x04 */ + Ib,0, "SHR%S %i,%e", /* 0x05 */ + 0,0, "", /* 0x06 */ + Ib,0, "SAR%S %i,%e", /* 0x07 */ +}; + +static Optable optabD0[8] = +{ + 0,0, "ROLB %e", /* 0x00 */ + 0,0, "RORB %e", /* 0x01 */ + 0,0, "RCLB %e", /* 0x02 */ + 0,0, "RCRB %e", /* 0x03 */ + 0,0, "SHLB %e", /* 0x04 */ + 0,0, "SHRB %e", /* 0x05 */ + 0,0, "", /* 0x06 */ + 0,0, "SARB %e", /* 0x07 */ +}; + +static Optable optabD1[8] = +{ + 0,0, "ROL%S %e", /* 0x00 */ + 0,0, "ROR%S %e", /* 0x01 */ + 0,0, "RCL%S %e", /* 0x02 */ + 0,0, "RCR%S %e", /* 0x03 */ + 0,0, "SHL%S %e", /* 0x04 */ + 0,0, "SHR%S %e", /* 0x05 */ + 0,0, "", /* 0x06 */ + 0,0, "SAR%S %e", /* 0x07 */ +}; + +static Optable optabD2[8] = +{ + 0,0, "ROLB CL,%e", /* 0x00 */ + 0,0, "RORB CL,%e", /* 0x01 */ + 0,0, "RCLB CL,%e", /* 0x02 */ + 0,0, "RCRB CL,%e", /* 0x03 */ + 0,0, "SHLB CL,%e", /* 0x04 */ + 0,0, "SHRB CL,%e", /* 0x05 */ + 0,0, "", /* 0x06 */ + 0,0, "SARB CL,%e", /* 0x07 */ +}; + +static Optable optabD3[8] = +{ + 0,0, "ROL%S CL,%e", /* 0x00 */ + 0,0, "ROR%S CL,%e", /* 0x01 */ + 0,0, "RCL%S CL,%e", /* 0x02 */ + 0,0, "RCR%S CL,%e", /* 0x03 */ + 0,0, "SHL%S CL,%e", /* 0x04 */ + 0,0, "SHR%S CL,%e", /* 0x05 */ + 0,0, "", /* 0x06 */ + 0,0, "SAR%S CL,%e", /* 0x07 */ +}; + +static Optable optabD8[8+8] = +{ + 0,0, "FADDF %e,F0", /* 0x00 */ + 0,0, "FMULF %e,F0", /* 0x01 */ + 0,0, "FCOMF %e,F0", /* 0x02 */ + 0,0, "FCOMFP %e,F0", /* 0x03 */ + 0,0, "FSUBF %e,F0", /* 0x04 */ + 0,0, "FSUBRF %e,F0", /* 0x05 */ + 0,0, "FDIVF %e,F0", /* 0x06 */ + 0,0, "FDIVRF %e,F0", /* 0x07 */ + 0,0, "FADDD %f,F0", /* 0x08 */ + 0,0, "FMULD %f,F0", /* 0x09 */ + 0,0, "FCOMD %f,F0", /* 0x0a */ + 0,0, "FCOMPD %f,F0", /* 0x0b */ + 0,0, "FSUBD %f,F0", /* 0x0c */ + 0,0, "FSUBRD %f,F0", /* 0x0d */ + 0,0, "FDIVD %f,F0", /* 0x0e */ + 0,0, "FDIVRD %f,F0", /* 0x0f */ +}; +/* + * optabD9 and optabDB use the following encoding: + * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07]; + * else instruction = optabDx[(modrm&0x3f)+8]; + * + * the instructions for MOD == 3, follow the 8 instructions + * for the other MOD values stored at the front of the table. + */ +static Optable optabD9[64+8] = +{ + 0,0, "FMOVF %e,F0", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "FMOVF F0,%e", /* 0x02 */ + 0,0, "FMOVFP F0,%e", /* 0x03 */ + 0,0, "FLDENV%S %e", /* 0x04 */ + 0,0, "FLDCW %e", /* 0x05 */ + 0,0, "FSTENV%S %e", /* 0x06 */ + 0,0, "FSTCW %e", /* 0x07 */ + 0,0, "FMOVD F0,F0", /* 0x08 */ /* Mod R/M = 11xx xxxx*/ + 0,0, "FMOVD F1,F0", /* 0x09 */ + 0,0, "FMOVD F2,F0", /* 0x0a */ + 0,0, "FMOVD F3,F0", /* 0x0b */ + 0,0, "FMOVD F4,F0", /* 0x0c */ + 0,0, "FMOVD F5,F0", /* 0x0d */ + 0,0, "FMOVD F6,F0", /* 0x0e */ + 0,0, "FMOVD F7,F0", /* 0x0f */ + 0,0, "FXCHD F0,F0", /* 0x10 */ + 0,0, "FXCHD F1,F0", /* 0x11 */ + 0,0, "FXCHD F2,F0", /* 0x12 */ + 0,0, "FXCHD F3,F0", /* 0x13 */ + 0,0, "FXCHD F4,F0", /* 0x14 */ + 0,0, "FXCHD F5,F0", /* 0x15 */ + 0,0, "FXCHD F6,F0", /* 0x16 */ + 0,0, "FXCHD F7,F0", /* 0x17 */ + 0,0, "FNOP", /* 0x18 */ + 0,0, "", /* 0x19 */ + 0,0, "", /* 0x1a */ + 0,0, "", /* 0x1b */ + 0,0, "", /* 0x1c */ + 0,0, "", /* 0x1d */ + 0,0, "", /* 0x1e */ + 0,0, "", /* 0x1f */ + 0,0, "", /* 0x20 */ + 0,0, "", /* 0x21 */ + 0,0, "", /* 0x22 */ + 0,0, "", /* 0x23 */ + 0,0, "", /* 0x24 */ + 0,0, "", /* 0x25 */ + 0,0, "", /* 0x26 */ + 0,0, "", /* 0x27 */ + 0,0, "FCHS", /* 0x28 */ + 0,0, "FABS", /* 0x29 */ + 0,0, "", /* 0x2a */ + 0,0, "", /* 0x2b */ + 0,0, "FTST", /* 0x2c */ + 0,0, "FXAM", /* 0x2d */ + 0,0, "", /* 0x2e */ + 0,0, "", /* 0x2f */ + 0,0, "FLD1", /* 0x30 */ + 0,0, "FLDL2T", /* 0x31 */ + 0,0, "FLDL2E", /* 0x32 */ + 0,0, "FLDPI", /* 0x33 */ + 0,0, "FLDLG2", /* 0x34 */ + 0,0, "FLDLN2", /* 0x35 */ + 0,0, "FLDZ", /* 0x36 */ + 0,0, "", /* 0x37 */ + 0,0, "F2XM1", /* 0x38 */ + 0,0, "FYL2X", /* 0x39 */ + 0,0, "FPTAN", /* 0x3a */ + 0,0, "FPATAN", /* 0x3b */ + 0,0, "FXTRACT", /* 0x3c */ + 0,0, "FPREM1", /* 0x3d */ + 0,0, "FDECSTP", /* 0x3e */ + 0,0, "FNCSTP", /* 0x3f */ + 0,0, "FPREM", /* 0x40 */ + 0,0, "FYL2XP1", /* 0x41 */ + 0,0, "FSQRT", /* 0x42 */ + 0,0, "FSINCOS", /* 0x43 */ + 0,0, "FRNDINT", /* 0x44 */ + 0,0, "FSCALE", /* 0x45 */ + 0,0, "FSIN", /* 0x46 */ + 0,0, "FCOS", /* 0x47 */ +}; + +static Optable optabDA[8+8] = +{ + 0,0, "FADDL %e,F0", /* 0x00 */ + 0,0, "FMULL %e,F0", /* 0x01 */ + 0,0, "FCOML %e,F0", /* 0x02 */ + 0,0, "FCOMLP %e,F0", /* 0x03 */ + 0,0, "FSUBL %e,F0", /* 0x04 */ + 0,0, "FSUBRL %e,F0", /* 0x05 */ + 0,0, "FDIVL %e,F0", /* 0x06 */ + 0,0, "FDIVRL %e,F0", /* 0x07 */ + 0,0, "", /* 0x08 */ + 0,0, "", /* 0x09 */ + 0,0, "", /* 0x0a */ + 0,0, "", /* 0x0b */ + 0,0, "", /* 0x0c */ + R1,0, "FUCOMPP", /* 0x0d */ +}; + +static Optable optabDB[8+64] = +{ + 0,0, "FMOVL %e,F0", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "FMOVL F0,%e", /* 0x02 */ + 0,0, "FMOVLP F0,%e", /* 0x03 */ + 0,0, "", /* 0x04 */ + 0,0, "FMOVX %e,F0", /* 0x05 */ + 0,0, "", /* 0x06 */ + 0,0, "FMOVXP F0,%e", /* 0x07 */ + 0,0, "", /* 0x08 */ + 0,0, "", /* 0x09 */ + 0,0, "", /* 0x0a */ + 0,0, "", /* 0x0b */ + 0,0, "", /* 0x0c */ + 0,0, "", /* 0x0d */ + 0,0, "", /* 0x0e */ + 0,0, "", /* 0x0f */ + 0,0, "", /* 0x10 */ + 0,0, "", /* 0x11 */ + 0,0, "", /* 0x12 */ + 0,0, "", /* 0x13 */ + 0,0, "", /* 0x14 */ + 0,0, "", /* 0x15 */ + 0,0, "", /* 0x16 */ + 0,0, "", /* 0x17 */ + 0,0, "", /* 0x18 */ + 0,0, "", /* 0x19 */ + 0,0, "", /* 0x1a */ + 0,0, "", /* 0x1b */ + 0,0, "", /* 0x1c */ + 0,0, "", /* 0x1d */ + 0,0, "", /* 0x1e */ + 0,0, "", /* 0x1f */ + 0,0, "", /* 0x20 */ + 0,0, "", /* 0x21 */ + 0,0, "", /* 0x22 */ + 0,0, "", /* 0x23 */ + 0,0, "", /* 0x24 */ + 0,0, "", /* 0x25 */ + 0,0, "", /* 0x26 */ + 0,0, "", /* 0x27 */ + 0,0, "", /* 0x28 */ + 0,0, "", /* 0x29 */ + 0,0, "FCLEX", /* 0x2a */ + 0,0, "FINIT", /* 0x2b */ +}; + +static Optable optabDC[8+8] = +{ + 0,0, "FADDD %e,F0", /* 0x00 */ + 0,0, "FMULD %e,F0", /* 0x01 */ + 0,0, "FCOMD %e,F0", /* 0x02 */ + 0,0, "FCOMDP %e,F0", /* 0x03 */ + 0,0, "FSUBD %e,F0", /* 0x04 */ + 0,0, "FSUBRD %e,F0", /* 0x05 */ + 0,0, "FDIVD %e,F0", /* 0x06 */ + 0,0, "FDIVRD %e,F0", /* 0x07 */ + 0,0, "FADDD F0,%f", /* 0x08 */ + 0,0, "FMULD F0,%f", /* 0x09 */ + 0,0, "", /* 0x0a */ + 0,0, "", /* 0x0b */ + 0,0, "FSUBRD F0,%f", /* 0x0c */ + 0,0, "FSUBD F0,%f", /* 0x0d */ + 0,0, "FDIVRD F0,%f", /* 0x0e */ + 0,0, "FDIVD F0,%f", /* 0x0f */ +}; + +static Optable optabDD[8+8] = +{ + 0,0, "FMOVD %e,F0", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "FMOVD F0,%e", /* 0x02 */ + 0,0, "FMOVDP F0,%e", /* 0x03 */ + 0,0, "FRSTOR%S %e", /* 0x04 */ + 0,0, "", /* 0x05 */ + 0,0, "FSAVE%S %e", /* 0x06 */ + 0,0, "FSTSW %e", /* 0x07 */ + 0,0, "FFREED %f", /* 0x08 */ + 0,0, "", /* 0x09 */ + 0,0, "FMOVD %f,F0", /* 0x0a */ + 0,0, "FMOVDP %f,F0", /* 0x0b */ + 0,0, "FUCOMD %f,F0", /* 0x0c */ + 0,0, "FUCOMDP %f,F0", /* 0x0d */ +}; + +static Optable optabDE[8+8] = +{ + 0,0, "FADDW %e,F0", /* 0x00 */ + 0,0, "FMULW %e,F0", /* 0x01 */ + 0,0, "FCOMW %e,F0", /* 0x02 */ + 0,0, "FCOMWP %e,F0", /* 0x03 */ + 0,0, "FSUBW %e,F0", /* 0x04 */ + 0,0, "FSUBRW %e,F0", /* 0x05 */ + 0,0, "FDIVW %e,F0", /* 0x06 */ + 0,0, "FDIVRW %e,F0", /* 0x07 */ + 0,0, "FADDDP F0,%f", /* 0x08 */ + 0,0, "FMULDP F0,%f", /* 0x09 */ + 0,0, "", /* 0x0a */ + R1,0, "FCOMPDP", /* 0x0b */ + 0,0, "FSUBRDP F0,%f", /* 0x0c */ + 0,0, "FSUBDP F0,%f", /* 0x0d */ + 0,0, "FDIVRDP F0,%f", /* 0x0e */ + 0,0, "FDIVDP F0,%f", /* 0x0f */ +}; + +static Optable optabDF[8+8] = +{ + 0,0, "FMOVW %e,F0", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "FMOVW F0,%e", /* 0x02 */ + 0,0, "FMOVWP F0,%e", /* 0x03 */ + 0,0, "FBLD %e", /* 0x04 */ + 0,0, "FMOVL %e,F0", /* 0x05 */ + 0,0, "FBSTP %e", /* 0x06 */ + 0,0, "FMOVLP F0,%e", /* 0x07 */ + 0,0, "", /* 0x08 */ + 0,0, "", /* 0x09 */ + 0,0, "", /* 0x0a */ + 0,0, "", /* 0x0b */ + R0,0, "FSTSW %OAX", /* 0x0c */ +}; + +static Optable optabF6[8] = +{ + Ib,0, "TESTB %i,%e", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "NOTB %e", /* 0x02 */ + 0,0, "NEGB %e", /* 0x03 */ + 0,0, "MULB AL,%e", /* 0x04 */ + 0,0, "IMULB AL,%e", /* 0x05 */ + 0,0, "DIVB AL,%e", /* 0x06 */ + 0,0, "IDIVB AL,%e", /* 0x07 */ +}; + +static Optable optabF7[8] = +{ + Iwd,0, "TEST%S %i,%e", /* 0x00 */ + 0,0, "", /* 0x01 */ + 0,0, "NOT%S %e", /* 0x02 */ + 0,0, "NEG%S %e", /* 0x03 */ + 0,0, "MUL%S %OAX,%e", /* 0x04 */ + 0,0, "IMUL%S %OAX,%e", /* 0x05 */ + 0,0, "DIV%S %OAX,%e", /* 0x06 */ + 0,0, "IDIV%S %OAX,%e", /* 0x07 */ +}; + +static Optable optabFE[8] = +{ + 0,0, "INCB %e", /* 0x00 */ + 0,0, "DECB %e", /* 0x01 */ +}; + +static Optable optabFF[8] = +{ + 0,0, "INC%S %e", /* 0x00 */ + 0,0, "DEC%S %e", /* 0x01 */ + JUMP,0, "CALL*%S %e", /* 0x02 */ + JUMP,0, "CALLF*%S %e", /* 0x03 */ + JUMP,0, "JMP*%S %e", /* 0x04 */ + JUMP,0, "JMPF*%S %e", /* 0x05 */ + 0,0, "PUSHL %e", /* 0x06 */ +}; + +static Optable optable[256] = +{ + RMB,0, "ADDB %r,%e", /* 0x00 */ + RM,0, "ADD%S %r,%e", /* 0x01 */ + RMB,0, "ADDB %e,%r", /* 0x02 */ + RM,0, "ADD%S %e,%r", /* 0x03 */ + Ib,0, "ADDB %i,AL", /* 0x04 */ + Iwd,0, "ADD%S %i,%OAX", /* 0x05 */ + 0,0, "PUSHL ES", /* 0x06 */ + 0,0, "POPL ES", /* 0x07 */ + RMB,0, "ORB %r,%e", /* 0x08 */ + RM,0, "OR%S %r,%e", /* 0x09 */ + RMB,0, "ORB %e,%r", /* 0x0a */ + RM,0, "OR%S %e,%r", /* 0x0b */ + Ib,0, "ORB %i,AL", /* 0x0c */ + Iwd,0, "OR%S %i,%OAX", /* 0x0d */ + 0,0, "PUSHL CS", /* 0x0e */ + AUX,0, optab0F, /* 0x0f */ + RMB,0, "ADCB %r,%e", /* 0x10 */ + RM,0, "ADC%S %r,%e", /* 0x11 */ + RMB,0, "ADCB %e,%r", /* 0x12 */ + RM,0, "ADC%S %e,%r", /* 0x13 */ + Ib,0, "ADCB %i,AL", /* 0x14 */ + Iwd,0, "ADC%S %i,%OAX", /* 0x15 */ + 0,0, "PUSHL SS", /* 0x16 */ + 0,0, "POPL SS", /* 0x17 */ + RMB,0, "SBBB %r,%e", /* 0x18 */ + RM,0, "SBB%S %r,%e", /* 0x19 */ + RMB,0, "SBBB %e,%r", /* 0x1a */ + RM,0, "SBB%S %e,%r", /* 0x1b */ + Ib,0, "SBBB %i,AL", /* 0x1c */ + Iwd,0, "SBB%S %i,%OAX", /* 0x1d */ + 0,0, "PUSHL DS", /* 0x1e */ + 0,0, "POPL DS", /* 0x1f */ + RMB,0, "ANDB %r,%e", /* 0x20 */ + RM,0, "AND%S %r,%e", /* 0x21 */ + RMB,0, "ANDB %e,%r", /* 0x22 */ + RM,0, "AND%S %e,%r", /* 0x23 */ + Ib,0, "ANDB %i,AL", /* 0x24 */ + Iwd,0, "AND%S %i,%OAX", /* 0x25 */ + SEG,0, "ES:", /* 0x26 */ + 0,0, "DAA", /* 0x27 */ + RMB,0, "SUBB %r,%e", /* 0x28 */ + RM,0, "SUB%S %r,%e", /* 0x29 */ + RMB,0, "SUBB %e,%r", /* 0x2a */ + RM,0, "SUB%S %e,%r", /* 0x2b */ + Ib,0, "SUBB %i,AL", /* 0x2c */ + Iwd,0, "SUB%S %i,%OAX", /* 0x2d */ + SEG,0, "CS:", /* 0x2e */ + 0,0, "DAS", /* 0x2f */ + RMB,0, "XORB %r,%e", /* 0x30 */ + RM,0, "XOR%S %r,%e", /* 0x31 */ + RMB,0, "XORB %e,%r", /* 0x32 */ + RM,0, "XOR%S %e,%r", /* 0x33 */ + Ib,0, "XORB %i,AL", /* 0x34 */ + Iwd,0, "XOR%S %i,%OAX", /* 0x35 */ + SEG,0, "SS:", /* 0x36 */ + 0,0, "AAA", /* 0x37 */ + RMB,0, "CMPB %r,%e", /* 0x38 */ + RM,0, "CMP%S %r,%e", /* 0x39 */ + RMB,0, "CMPB %e,%r", /* 0x3a */ + RM,0, "CMP%S %e,%r", /* 0x3b */ + Ib,0, "CMPB %i,AL", /* 0x3c */ + Iwd,0, "CMP%S %i,%OAX", /* 0x3d */ + SEG,0, "DS:", /* 0x3e */ + 0,0, "AAS", /* 0x3f */ + 0,0, "INC%S %OAX", /* 0x40 */ + 0,0, "INC%S %OCX", /* 0x41 */ + 0,0, "INC%S %ODX", /* 0x42 */ + 0,0, "INC%S %OBX", /* 0x43 */ + 0,0, "INC%S %OSP", /* 0x44 */ + 0,0, "INC%S %OBP", /* 0x45 */ + 0,0, "INC%S %OSI", /* 0x46 */ + 0,0, "INC%S %ODI", /* 0x47 */ + 0,0, "DEC%S %OAX", /* 0x48 */ + 0,0, "DEC%S %OCX", /* 0x49 */ + 0,0, "DEC%S %ODX", /* 0x4a */ + 0,0, "DEC%S %OBX", /* 0x4b */ + 0,0, "DEC%S %OSP", /* 0x4c */ + 0,0, "DEC%S %OBP", /* 0x4d */ + 0,0, "DEC%S %OSI", /* 0x4e */ + 0,0, "DEC%S %ODI", /* 0x4f */ + 0,0, "PUSH%S %OAX", /* 0x50 */ + 0,0, "PUSH%S %OCX", /* 0x51 */ + 0,0, "PUSH%S %ODX", /* 0x52 */ + 0,0, "PUSH%S %OBX", /* 0x53 */ + 0,0, "PUSH%S %OSP", /* 0x54 */ + 0,0, "PUSH%S %OBP", /* 0x55 */ + 0,0, "PUSH%S %OSI", /* 0x56 */ + 0,0, "PUSH%S %ODI", /* 0x57 */ + 0,0, "POP%S %OAX", /* 0x58 */ + 0,0, "POP%S %OCX", /* 0x59 */ + 0,0, "POP%S %ODX", /* 0x5a */ + 0,0, "POP%S %OBX", /* 0x5b */ + 0,0, "POP%S %OSP", /* 0x5c */ + 0,0, "POP%S %OBP", /* 0x5d */ + 0,0, "POP%S %OSI", /* 0x5e */ + 0,0, "POP%S %ODI", /* 0x5f */ + 0,0, "PUSHA%S", /* 0x60 */ + 0,0, "POPA%S", /* 0x61 */ + RMM,0, "BOUND %e,%r", /* 0x62 */ + RM,0, "ARPL %r,%e", /* 0x63 */ + SEG,0, "FS:", /* 0x64 */ + SEG,0, "GS:", /* 0x65 */ + OPOVER,0, "", /* 0x66 */ + ADDOVER,0, "", /* 0x67 */ + Iwd,0, "PUSH%S %i", /* 0x68 */ + RM,Iwd, "IMUL%S %e,%i,%r", /* 0x69 */ + Ib,0, "PUSH%S %i", /* 0x6a */ + RM,Ibs, "IMUL%S %e,%i,%r", /* 0x6b */ + 0,0, "INSB DX,(%ODI)", /* 0x6c */ + 0,0, "INS%S DX,(%ODI)", /* 0x6d */ + 0,0, "OUTSB (%ASI),DX", /* 0x6e */ + 0,0, "OUTS%S (%ASI),DX", /* 0x6f */ + Jbs,0, "JOS %p", /* 0x70 */ + Jbs,0, "JOC %p", /* 0x71 */ + Jbs,0, "JCS %p", /* 0x72 */ + Jbs,0, "JCC %p", /* 0x73 */ + Jbs,0, "JEQ %p", /* 0x74 */ + Jbs,0, "JNE %p", /* 0x75 */ + Jbs,0, "JLS %p", /* 0x76 */ + Jbs,0, "JHI %p", /* 0x77 */ + Jbs,0, "JMI %p", /* 0x78 */ + Jbs,0, "JPL %p", /* 0x79 */ + Jbs,0, "JPS %p", /* 0x7a */ + Jbs,0, "JPC %p", /* 0x7b */ + Jbs,0, "JLT %p", /* 0x7c */ + Jbs,0, "JGE %p", /* 0x7d */ + Jbs,0, "JLE %p", /* 0x7e */ + Jbs,0, "JGT %p", /* 0x7f */ + RMOPB,0, optab80, /* 0x80 */ + RMOP,0, optab81, /* 0x81 */ + 0,0, "", /* 0x82 */ + RMOP,0, optab83, /* 0x83 */ + RMB,0, "TESTB %r,%e", /* 0x84 */ + RM,0, "TEST%S %r,%e", /* 0x85 */ + RMB,0, "XCHGB %r,%e", /* 0x86 */ + RM,0, "XCHG%S %r,%e", /* 0x87 */ + RMB,0, "MOVB %r,%e", /* 0x88 */ + RM,0, "MOV%S %r,%e", /* 0x89 */ + RMB,0, "MOVB %e,%r", /* 0x8a */ + RM,0, "MOV%S %e,%r", /* 0x8b */ + RM,0, "MOVW %g,%e", /* 0x8c */ + RM,0, "LEA %e,%r", /* 0x8d */ + RM,0, "MOVW %e,%g", /* 0x8e */ + RM,0, "POP%S %e", /* 0x8f */ + 0,0, "NOP", /* 0x90 */ + 0,0, "XCHG %OCX,%OAX", /* 0x91 */ + 0,0, "XCHG %OCX,%OAX", /* 0x92 */ + 0,0, "XCHG %OCX,%OAX", /* 0x93 */ + 0,0, "XCHG %OSP,%OAX", /* 0x94 */ + 0,0, "XCHG %OBP,%OAX", /* 0x95 */ + 0,0, "XCHG %OSI,%OAX", /* 0x96 */ + 0,0, "XCHG %ODI,%OAX", /* 0x97 */ + 0,0, "%X", /* 0x98 */ /* miserable CBW or CWDE */ + 0,0, "%x", /* 0x99 */ /* idiotic CWD or CDQ */ + PTR,0, "CALL%S %d", /* 0x9a */ + 0,0, "WAIT", /* 0x9b */ + 0,0, "PUSHF", /* 0x9c */ + 0,0, "POPF", /* 0x9d */ + 0,0, "SAHF", /* 0x9e */ + 0,0, "LAHF", /* 0x9f */ + Awd,0, "MOVB %i,AL", /* 0xa0 */ + Awd,0, "MOV%S %i,%OAX", /* 0xa1 */ + Awd,0, "MOVB AL,%i", /* 0xa2 */ + Awd,0, "MOV%S %OAX,%i", /* 0xa3 */ + 0,0, "MOVSB (%ASI),(%ADI)", /* 0xa4 */ + 0,0, "MOVS%S (%ASI),(%ADI)", /* 0xa5 */ + 0,0, "CMPSB (%ASI),(%ADI)", /* 0xa6 */ + 0,0, "CMPS%S (%ASI),(%ADI)", /* 0xa7 */ + Ib,0, "TESTB %i,AL", /* 0xa8 */ + Iwd,0, "TEST%S %i,%OAX", /* 0xa9 */ + 0,0, "STOSB AL,(%ADI)", /* 0xaa */ + 0,0, "STOS%S %OAX,(%ADI)", /* 0xab */ + 0,0, "LODSB (%ASI),AL", /* 0xac */ + 0,0, "LODS%S (%ASI),%OAX", /* 0xad */ + 0,0, "SCASB (%ADI),AL", /* 0xae */ + 0,0, "SCAS%S (%ADI),%OAX", /* 0xaf */ + Ib,0, "MOVB %i,AL", /* 0xb0 */ + Ib,0, "MOVB %i,CL", /* 0xb1 */ + Ib,0, "MOVB %i,DL", /* 0xb2 */ + Ib,0, "MOVB %i,BL", /* 0xb3 */ + Ib,0, "MOVB %i,AH", /* 0xb4 */ + Ib,0, "MOVB %i,CH", /* 0xb5 */ + Ib,0, "MOVB %i,DH", /* 0xb6 */ + Ib,0, "MOVB %i,BH", /* 0xb7 */ + Iwd,0, "MOV%S %i,%OAX", /* 0xb8 */ + Iwd,0, "MOV%S %i,%OCX", /* 0xb9 */ + Iwd,0, "MOV%S %i,%ODX", /* 0xba */ + Iwd,0, "MOV%S %i,%OBX", /* 0xbb */ + Iwd,0, "MOV%S %i,%OSP", /* 0xbc */ + Iwd,0, "MOV%S %i,%OBP", /* 0xbd */ + Iwd,0, "MOV%S %i,%OSI", /* 0xbe */ + Iwd,0, "MOV%S %i,%ODI", /* 0xbf */ + RMOPB,0, optabC0, /* 0xc0 */ + RMOP,0, optabC1, /* 0xc1 */ + Iw,0, "RET %i", /* 0xc2 */ + RET,0, "RET", /* 0xc3 */ + RM,0, "LES %e,%r", /* 0xc4 */ + RM,0, "LDS %e,%r", /* 0xc5 */ + RMB,Ib, "MOVB %i,%e", /* 0xc6 */ + RM,Iwd, "MOV%S %i,%e", /* 0xc7 */ + Iw2,Ib, "ENTER %i,%I", /* 0xc8 */ /* loony ENTER */ + RET,0, "LEAVE", /* 0xc9 */ /* bizarre LEAVE */ + Iw,0, "RETF %i", /* 0xca */ + RET,0, "RETF", /* 0xcb */ + 0,0, "INT 3", /* 0xcc */ + Ib,0, "INTB %i", /* 0xcd */ + 0,0, "INTO", /* 0xce */ + 0,0, "IRET", /* 0xcf */ + RMOPB,0, optabD0, /* 0xd0 */ + RMOP,0, optabD1, /* 0xd1 */ + RMOPB,0, optabD2, /* 0xd2 */ + RMOP,0, optabD3, /* 0xd3 */ + OA,0, "AAM", /* 0xd4 */ + OA,0, "AAD", /* 0xd5 */ + 0,0, "", /* 0xd6 */ + 0,0, "XLAT", /* 0xd7 */ + FRMOP,0, optabD8, /* 0xd8 */ + FRMEX,0, optabD9, /* 0xd9 */ + FRMOP,0, optabDA, /* 0xda */ + FRMEX,0, optabDB, /* 0xdb */ + FRMOP,0, optabDC, /* 0xdc */ + FRMOP,0, optabDD, /* 0xdd */ + FRMOP,0, optabDE, /* 0xde */ + FRMOP,0, optabDF, /* 0xdf */ + Jbs,0, "LOOPNE %p", /* 0xe0 */ + Jbs,0, "LOOPE %p", /* 0xe1 */ + Jbs,0, "LOOP %p", /* 0xe2 */ + Jbs,0, "JCXZ %p", /* 0xe3 */ + Ib,0, "INB %i,AL", /* 0xe4 */ + Ib,0, "IN%S %i,%OAX", /* 0xe5 */ + Ib,0, "OUTB AL,%i", /* 0xe6 */ + Ib,0, "OUT%S %OAX,%i", /* 0xe7 */ + Iwds,0, "CALL %p", /* 0xe8 */ + Iwds,0, "JMP %p", /* 0xe9 */ + PTR,0, "JMP %d", /* 0xea */ + Jbs,0, "JMP %p", /* 0xeb */ + 0,0, "INB DX,AL", /* 0xec */ + 0,0, "IN%S DX,%OAX", /* 0xed */ + 0,0, "OUTB AL,DX", /* 0xee */ + 0,0, "OUT%S %OAX,DX", /* 0xef */ + PRE,0, "LOCK", /* 0xf0 */ + 0,0, "", /* 0xf1 */ + PRE,0, "REPNE", /* 0xf2 */ + PRE,0, "REP", /* 0xf3 */ + 0,0, "HALT", /* 0xf4 */ + 0,0, "CMC", /* 0xf5 */ + RMOPB,0, optabF6, /* 0xf6 */ + RMOP,0, optabF7, /* 0xf7 */ + 0,0, "CLC", /* 0xf8 */ + 0,0, "STC", /* 0xf9 */ + 0,0, "CLI", /* 0xfa */ + 0,0, "STI", /* 0xfb */ + 0,0, "CLD", /* 0xfc */ + 0,0, "STD", /* 0xfd */ + RMOPB,0, optabFE, /* 0xfe */ + RMOP,0, optabFF, /* 0xff */ +}; + +/* + * get a byte of the instruction + */ +static int +igetc(Map * map, Instr *ip, uchar *c) +{ + if(ip->n+1 > sizeof(ip->mem)){ + werrstr("instruction too long"); + return -1; + } + if (get1(map, ip->addr+ip->n, c, 1) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + ip->mem[ip->n++] = *c; + return 1; +} + +/* + * get two bytes of the instruction + */ +static int +igets(Map *map, Instr *ip, ushort *sp) +{ + uchar c; + ushort s; + + if (igetc(map, ip, &c) < 0) + return -1; + s = c; + if (igetc(map, ip, &c) < 0) + return -1; + s |= (c<<8); + *sp = s; + return 1; +} + +/* + * get 4 bytes of the instruction + */ +static int +igetl(Map *map, Instr *ip, ulong *lp) +{ + ushort s; + long l; + + if (igets(map, ip, &s) < 0) + return -1; + l = s; + if (igets(map, ip, &s) < 0) + return -1; + l |= (s<<16); + *lp = l; + return 1; +} + +static int +getdisp(Map *map, Instr *ip, int mod, int rm, int code) +{ + uchar c; + ushort s; + + if (mod > 2) + return 1; + if (mod == 1) { + if (igetc(map, ip, &c) < 0) + return -1; + if (c&0x80) + ip->disp = c|0xffffff00; + else + ip->disp = c&0xff; + } else if (mod == 2 || rm == code) { + if (ip->asize == 'E') { + if (igetl(map, ip, &ip->disp) < 0) + return -1; + } else { + if (igets(map, ip, &s) < 0) + return -1; + if (s&0x8000) + ip->disp = s|0xffff0000; + else + ip->disp = s; + } + if (mod == 0) + ip->base = -1; + } + return 1; +} + +static int +modrm(Map *map, Instr *ip, uchar c) +{ + uchar rm, mod; + + mod = (c>>6)&3; + rm = c&7; + ip->mod = mod; + ip->base = rm; + ip->reg = (c>>3)&7; + if (mod == 3) /* register */ + return 1; + if (ip->asize == 0) { /* 16-bit mode */ + switch(rm) + { + case 0: + ip->base = BX; ip->index = SI; + break; + case 1: + ip->base = BX; ip->index = DI; + break; + case 2: + ip->base = BP; ip->index = SI; + break; + case 3: + ip->base = BP; ip->index = DI; + break; + case 4: + ip->base = SI; + break; + case 5: + ip->base = DI; + break; + case 6: + ip->base = BP; + break; + case 7: + ip->base = BX; + break; + default: + break; + } + return getdisp(map, ip, mod, rm, 6); + } + if (rm == 4) { /* scummy sib byte */ + if (igetc(map, ip, &c) < 0) + return -1; + ip->ss = (c>>6)&0x03; + ip->index = (c>>3)&0x07; + if (ip->index == 4) + ip->index = -1; + ip->base = c&0x07; + return getdisp(map, ip, mod, ip->base, 5); + } + return getdisp(map, ip, mod, rm, 5); +} + +static Optable * +mkinstr(Map *map, Instr *ip, ulong pc) +{ + int i, n; + uchar c; + ushort s; + Optable *op, *obase; + char buf[128]; + + memset(ip, 0, sizeof(*ip)); + ip->base = -1; + ip->index = -1; + if(asstype == AI8086) + ip->osize = 'W'; + else { + ip->osize = 'L'; + ip->asize = 'E'; + } + ip->addr = pc; + if (igetc(map, ip, &c) < 0) + return 0; + obase = optable; +newop: + op = &obase[c]; + if (op->proto == 0) { +badop: + n = snprint(buf, sizeof(buf), "opcode: ??"); + for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2) + _hexify(buf+n, ip->mem[i], 1); + strcpy(buf+n, "??"); + werrstr(buf); + return 0; + } + for(i = 0; i < 2 && op->operand[i]; i++) { + switch(op->operand[i]) + { + case Ib: /* 8-bit immediate - (no sign extension)*/ + if (igetc(map, ip, &c) < 0) + return 0; + ip->imm = c&0xff; + break; + case Jbs: /* 8-bit jump immediate (sign extended) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (c&0x80) + ip->imm = c|0xffffff00; + else + ip->imm = c&0xff; + ip->jumptype = Jbs; + break; + case Ibs: /* 8-bit immediate (sign extended) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (c&0x80) + if (ip->osize == 'L') + ip->imm = c|0xffffff00; + else + ip->imm = c|0xff00; + else + ip->imm = c&0xff; + break; + case Iw: /* 16-bit immediate -> imm */ + if (igets(map, ip, &s) < 0) + return 0; + ip->imm = s&0xffff; + ip->jumptype = Iw; + break; + case Iw2: /* 16-bit immediate -> in imm2*/ + if (igets(map, ip, &s) < 0) + return 0; + ip->imm2 = s&0xffff; + break; + case Iwd: /* Operand-sized immediate (no sign extension)*/ + if (ip->osize == 'L') { + if (igetl(map, ip, &ip->imm) < 0) + return 0; + } else { + if (igets(map, ip, &s)< 0) + return 0; + ip->imm = s&0xffff; + } + break; + case Awd: /* Address-sized immediate (no sign extension)*/ + if (ip->asize == 'E') { + if (igetl(map, ip, &ip->imm) < 0) + return 0; + } else { + if (igets(map, ip, &s)< 0) + return 0; + ip->imm = s&0xffff; + } + break; + case Iwds: /* Operand-sized immediate (sign extended) */ + if (ip->osize == 'L') { + if (igetl(map, ip, &ip->imm) < 0) + return 0; + } else { + if (igets(map, ip, &s)< 0) + return 0; + if (s&0x8000) + ip->imm = s|0xffff0000; + else + ip->imm = s&0xffff; + } + ip->jumptype = Iwds; + break; + case OA: /* literal 0x0a byte */ + if (igetc(map, ip, &c) < 0) + return 0; + if (c != 0x0a) + goto badop; + break; + case R0: /* base register must be R0 */ + if (ip->base != 0) + goto badop; + break; + case R1: /* base register must be R1 */ + if (ip->base != 1) + goto badop; + break; + case RMB: /* R/M field with byte register (/r)*/ + if (igetc(map, ip, &c) < 0) + return 0; + if (modrm(map, ip, c) < 0) + return 0; + ip->osize = 'B'; + break; + case RM: /* R/M field with register (/r) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (modrm(map, ip, c) < 0) + return 0; + break; + case RMOPB: /* R/M field with op code (/digit) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (modrm(map, ip, c) < 0) + return 0; + c = ip->reg; /* secondary op code */ + obase = (Optable*)op->proto; + ip->osize = 'B'; + goto newop; + case RMOP: /* R/M field with op code (/digit) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (modrm(map, ip, c) < 0) + return 0; + c = ip->reg; + obase = (Optable*)op->proto; + goto newop; + case FRMOP: /* FP R/M field with op code (/digit) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (modrm(map, ip, c) < 0) + return 0; + if ((c&0xc0) == 0xc0) + c = ip->reg+8; /* 16 entry table */ + else + c = ip->reg; + obase = (Optable*)op->proto; + goto newop; + case FRMEX: /* Extended FP R/M field with op code (/digit) */ + if (igetc(map, ip, &c) < 0) + return 0; + if (modrm(map, ip, c) < 0) + return 0; + if ((c&0xc0) == 0xc0) + c = (c&0x3f)+8; /* 64-entry table */ + else + c = ip->reg; + obase = (Optable*)op->proto; + goto newop; + case RMR: /* R/M register only (mod = 11) */ + if (igetc(map, ip, &c) < 0) + return 0; + if ((c&0xc0) != 0xc0) { + werrstr("invalid R/M register: %x", c); + return 0; + } + if (modrm(map, ip, c) < 0) + return 0; + break; + case RMM: /* R/M register only (mod = 11) */ + if (igetc(map, ip, &c) < 0) + return 0; + if ((c&0xc0) == 0xc0) { + werrstr("invalid R/M memory mode: %x", c); + return 0; + } + if (modrm(map, ip, c) < 0) + return 0; + break; + case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ + if (ip->osize == 'L') { + if (igetl(map, ip, &ip->disp) < 0) + return 0; + } else { + if (igets(map, ip, &s)< 0) + return 0; + ip->disp = s&0xffff; + } + if (igets(map, ip, (ushort*)&ip->seg) < 0) + return 0; + ip->jumptype = PTR; + break; + case AUX: /* Multi-byte op code - Auxiliary table */ + obase = (Optable*)op->proto; + if (igetc(map, ip, &c) < 0) + return 0; + goto newop; + case PRE: /* Instr Prefix */ + ip->prefix = (char*)op->proto; + if (igetc(map, ip, &c) < 0) + return 0; + goto newop; + case SEG: /* Segment Prefix */ + ip->segment = (char*)op->proto; + if (igetc(map, ip, &c) < 0) + return 0; + goto newop; + case OPOVER: /* Operand size override */ + ip->osize = 'W'; + if (igetc(map, ip, &c) < 0) + return 0; + goto newop; + case ADDOVER: /* Address size override */ + ip->asize = 0; + if (igetc(map, ip, &c) < 0) + return 0; + goto newop; + case JUMP: /* mark instruction as JUMP or RET */ + case RET: + ip->jumptype = op->operand[i]; + break; + default: + werrstr("bad operand type %d", op->operand[i]); + return 0; + } + } + return op; +} + +static void +bprint(Instr *ip, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + ip->curr = vseprint(ip->curr, ip->end, fmt, arg); + va_end(arg); +} + +/* + * if we want to call 16 bit regs AX,BX,CX,... + * and 32 bit regs EAX,EBX,ECX,... then + * change the defs of ANAME and ONAME to: + * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "") + * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "") + */ +#define ANAME(ip) "" +#define ONAME(ip) "" + +static char *reg[] = { + "AX", /* 0 */ + "CX", /* 1 */ + "DX", /* 2 */ + "BX", /* 3 */ + "SP", /* 4 */ + "BP", /* 5 */ + "SI", /* 6 */ + "DI", /* 7 */ +}; + +static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" }; +static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; + +static void +plocal(Instr *ip) +{ + int ret, offset; + Symbol s; + char *reg; + + offset = ip->disp; + if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) { + bprint(ip, "%lux(SP)", offset); + return; + } + + if (s.value > ip->disp) { + ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s); + reg = "(SP)"; + } else { + offset -= s.value; + ret = getauto(&s, offset, CPARAM, &s); + reg = "(FP)"; + } + if (ret) + bprint(ip, "%s+", s.name); + else + offset = ip->disp; + bprint(ip, "%lux%s", offset, reg); +} + +static void +pea(Instr *ip) +{ + if (ip->mod == 3) { + if (ip->osize == 'B') + bprint(ip, breg[ip->base]); + else + bprint(ip, "%s%s", ANAME(ip), reg[ip->base]); + return; + } + if (ip->segment) + bprint(ip, ip->segment); + if (ip->asize == 'E' && ip->base == SP) + plocal(ip); + else { + bprint(ip,"%lux", ip->disp); + if (ip->base >= 0) + bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]); + } + if (ip->index >= 0) + bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss); +} + +static void +immediate(Instr *ip, long val) +{ + Symbol s; + long w; + + if (findsym(val, CANY, &s)) { + w = val - s.value; + if (w < 0) + w = -w; + if (w < 4096) { + if (w) + bprint(ip, "%s+%lux(SB)", s.name, w); + else + bprint(ip, "%s(SB)", s.name); + return; + } + } + bprint(ip, "%lux", val); +} + +static void +prinstr(Instr *ip, char *fmt) +{ + if (ip->prefix) + bprint(ip, "%s ", ip->prefix); + for (; *fmt && ip->curr < ip->end; fmt++) { + if (*fmt != '%') + *ip->curr++ = *fmt; + else switch(*++fmt) + { + case '%': + *ip->curr++ = '%'; + break; + case 'A': + bprint(ip, "%s", ANAME(ip)); + break; + case 'C': + bprint(ip, "CR%d", ip->reg); + break; + case 'D': + if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7) + bprint(ip, "DR%d",ip->reg); + else + bprint(ip, "???"); + break; + case 'I': + bprint(ip, "$"); + immediate(ip, ip->imm2); + break; + case 'O': + bprint(ip,"%s", ONAME(ip)); + break; + case 'i': + bprint(ip, "$"); + immediate(ip,ip->imm); + break; + case 'R': + bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]); + break; + case 'S': + bprint(ip, "%c", ip->osize); + break; + case 'T': + if (ip->reg == 6 || ip->reg == 7) + bprint(ip, "TR%d",ip->reg); + else + bprint(ip, "???"); + break; + case 'X': + if (ip->osize == 'L') + bprint(ip,"CWDE"); + else + bprint(ip, "CBW"); + break; + case 'd': + bprint(ip,"%lux:%lux",ip->seg,ip->disp); + break; + case 'e': + pea(ip); + break; + case 'f': + bprint(ip, "F%d", ip->base); + break; + case 'g': + if (ip->reg < 6) + bprint(ip,"%s",sreg[ip->reg]); + else + bprint(ip,"???"); + break; + case 'p': + immediate(ip, ip->imm+ip->addr+ip->n); + break; + case 'r': + if (ip->osize == 'B') + bprint(ip,"%s",breg[ip->reg]); + else + bprint(ip, reg[ip->reg]); + break; + case 'x': + if (ip->osize == 'L') + bprint(ip,"CDQ"); + else + bprint(ip, "CWD"); + break; + default: + bprint(ip, "%%%c", *fmt); + break; + } + } + *ip->curr = 0; /* there's always room for 1 byte */ +} + +static int +i386inst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + Instr instr; + Optable *op; + + USED(modifier); + op = mkinstr(map, &instr, pc); + if (op == 0) { + buf[0] = 0; + errstr(buf, n); + return -1; + } + instr.curr = buf; + instr.end = buf+n-1; + prinstr(&instr, op->proto); + return instr.n; +} + +static int +i386das(Map *map, ulong pc, char *buf, int n) +{ + Instr instr; + int i; + + if (mkinstr(map, &instr, pc) == 0) { + buf[0] = 0; + errstr(buf, n); + return -1; + } + for(i = 0; i < instr.n && n > 2; i++) { + _hexify(buf, instr.mem[i], 1); + buf += 2; + n -= 2; + } + *buf = 0; + return instr.n; +} + +static int +i386instlen(Map *map, ulong pc) +{ + Instr i; + + if (mkinstr(map, &i, pc)) + return i.n; + return -1; +} + +static int +i386foll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + Instr i; + Optable *op; + ushort s; + ulong l, addr; + int n; + + op = mkinstr(map, &i, pc); + if (!op) + return -1; + + n = 0; + + switch(i.jumptype) { + case RET: /* RETURN or LEAVE */ + case Iw: /* RETURN */ + if (strcmp(op->proto, "LEAVE") == 0) { + if (get4(map, (*rget)(map, "BP"), (long*)&l) < 0) + return -1; + } else if (get4(map, (*rget)(map, mach->sp), (long*)&l) < 0) + return -1; + foll[0] = l; + return 1; + case Iwds: /* pc relative JUMP or CALL*/ + case Jbs: /* pc relative JUMP or CALL */ + foll[0] = pc+i.imm+i.n; + n = 1; + break; + case PTR: /* seg:displacement JUMP or CALL */ + foll[0] = (i.seg<<4)+i.disp; + return 1; + case JUMP: /* JUMP or CALL EA */ + + if(i.mod == 3) { + foll[0] = (*rget)(map, reg[i.base]); + return 1; + } + /* calculate the effective address */ + addr = i.disp; + if (i.base >= 0) { + if (get4(map, (*rget)(map, reg[i.base]), (long*)&l) < 0) + return -1; + addr += l; + } + if (i.index >= 0) { + if (get4(map, (*rget)(map, reg[i.index]), (long*)&l) < 0) + return -1; + addr += l*(1<<i.ss); + } + /* now retrieve a seg:disp value at that address */ + if (get2(map, addr, &s) < 0) /* seg */ + return -1; + foll[0] = s<<4; + addr += 2; + if (i.asize == 'L') { + if (get4(map, addr, (long*)&l) < 0) /* disp32 */ + return -1; + foll[0] += l; + } else { /* disp16 */ + if (get2(map, addr, &s) < 0) + return -1; + foll[0] += s; + } + return 1; + default: + break; + } + if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0) + return 1; + foll[n++] = pc+i.n; + return n; +} diff --git a/utils/libmach/8obj.c b/utils/libmach/8obj.c new file mode 100644 index 00000000..9e322f12 --- /dev/null +++ b/utils/libmach/8obj.c @@ -0,0 +1,133 @@ +/* + * 8obj.c - identify and parse a 386 object file + */ +#include <lib9.h> +#include <bio.h> +#include "8c/8.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char sym; + char flags; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_is8(char *t) +{ + uchar *s = (uchar*)t; + + return s[0] == (ANAME&0xff) /* aslo = ANAME */ + && s[1] == ((ANAME>>8)&0xff) + && s[2] == D_FILE /* type */ + && s[3] == 1 /* sym */ + && s[4] == '<'; /* name of file */ +} + +int +_read8(Biobuf *bp, Prog* p) +{ + int as, n, c; + Addr a; + + as = Bgetc(bp); /* as(low) */ + if(as < 0) + return 0; + c = Bgetc(bp); /* as(high) */ + if(c < 0) + return 0; + as |= ((c & 0xff) << 8); + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + if(as == AGLOBL) + p->kind = aData; + skip(bp, 4); /* lineno(4) */ + a = addr(bp); + addr(bp); + if(!(a.flags & T_SYM)) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + int t; + long off; + + off = 0; + a.sym = -1; + a.flags = Bgetc(bp); /* flags */ + if(a.flags & T_INDEX) + skip(bp, 2); + if(a.flags & T_OFFSET){ + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + } + if(a.flags & T_SYM) + a.sym = Bgetc(bp); + if(a.flags & T_FCONST) + skip(bp, 8); + else + if(a.flags & T_SCONST) + skip(bp, NSNAME); + if(a.flags & T_TYPE) { + t = Bgetc(bp); + if(a.sym > 0 && (t==D_PARAM || t==D_AUTO)) + _offset(a.sym, off); + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/NOTICE b/utils/libmach/NOTICE new file mode 100644 index 00000000..53798daf --- /dev/null +++ b/utils/libmach/NOTICE @@ -0,0 +1,31 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 1994-1999 Lucent Technologies Inc. + Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). + Portions Copyright © 1997-1999 Vita Nuova Limited. + Portions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com). + Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. + +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. diff --git a/utils/libmach/a.out.h b/utils/libmach/a.out.h new file mode 100644 index 00000000..8c0b7137 --- /dev/null +++ b/utils/libmach/a.out.h @@ -0,0 +1,45 @@ +typedef struct Exec Exec; +struct Exec +{ + long magic; /* magic number */ + long text; /* size of text segment */ + long data; /* size of initialized data */ + long bss; /* size of uninitialized data */ + long syms; /* size of symbol table */ + long entry; /* entry point */ + long spsz; /* size of pc/sp offset table */ + long pcsz; /* size of pc/line number table */ +}; + + +#define HDR_MAGIC 0x00008000 /* header expansion */ + +#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7)) +#define A_MAGIC _MAGIC(0, 8) /* 68020 */ +#define I_MAGIC _MAGIC(0, 11) /* intel 386 */ +#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */ +#define K_MAGIC _MAGIC(0, 13) /* sparc */ +#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */ +#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */ +#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */ +#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */ +#define E_MAGIC _MAGIC(0, 20) /* arm */ +#define Q_MAGIC _MAGIC(0, 21) /* powerpc */ +#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */ +#define L_MAGIC _MAGIC(0, 23) /* dec alpha */ +#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */ +#define U_MAGIC _MAGIC(0, 25) /* sparc64 */ +#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */ + +#define MIN_MAGIC 8 +#define MAX_MAGIC 26 /* <= 90 */ + +#define DYN_MAGIC 0x80000000 /* or'd in for dynamically loaded modules */ + +typedef struct Sym Sym; +struct Sym +{ + long value; + char type; + char *name; +}; diff --git a/utils/libmach/access.c b/utils/libmach/access.c new file mode 100644 index 00000000..6a58cdea --- /dev/null +++ b/utils/libmach/access.c @@ -0,0 +1,215 @@ +/* + * functions to read and write an executable or file image + */ + +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +static int mget(Map*, ulong, char*, int); +static int mput(Map*, ulong, char*, int); +struct segment* reloc(Map*, ulong, long*); + +/* + * routines to get/put various types + */ + +int +get8(Map *map, ulong addr, vlong *x) +{ + if (!map) { + werrstr("get8: invalid map"); + return -1; + } + + if (map->nsegs == 1 && map->seg[0].fd < 0) { + *x = (vlong)addr; + return 1; + } + if (mget(map, addr, (char *)x, 8) < 0) + return -1; + *x = machdata->swav(*x); + return (1); +} + +int +get4(Map *map, ulong addr, long *x) +{ + if (!map) { + werrstr("get4: invalid map"); + return -1; + } + + if (map->nsegs == 1 && map->seg[0].fd < 0) { + *x = addr; + return 1; + } + if (mget(map, addr, (char *)x, 4) < 0) + return -1; + *x = machdata->swal(*x); + return (1); +} + +int +get2(Map *map, ulong addr, ushort *x) +{ + if (!map) { + werrstr("get2: invalid map"); + return -1; + } + + if (map->nsegs == 1 && map->seg[0].fd < 0) { + *x = addr; + return 1; + } + if (mget(map, addr, (char *)x, 2) < 0) + return -1; + *x = machdata->swab(*x); + return (1); +} + +int +get1(Map *map, ulong addr, uchar *x, int size) +{ + uchar *cp; + + if (!map) { + werrstr("get1: invalid map"); + return -1; + } + + if (map->nsegs == 1 && map->seg[0].fd < 0) { + cp = (uchar*)&addr; + while (cp < (uchar*)(&addr+1) && size-- > 0) + *x++ = *cp++; + while (size-- > 0) + *x++ = 0; + } else + return mget(map, addr, (char*)x, size); + return 1; +} + +int +put8(Map *map, ulong addr, vlong v) +{ + if (!map) { + werrstr("put8: invalid map"); + return -1; + } + v = machdata->swav(v); + return mput(map, addr, (char *)&v, 8); +} + +int +put4(Map *map, ulong addr, long v) +{ + if (!map) { + werrstr("put4: invalid map"); + return -1; + } + v = machdata->swal(v); + return mput(map, addr, (char *)&v, 4); +} + +int +put2(Map *map, ulong addr, ushort v) +{ + if (!map) { + werrstr("put2: invalid map"); + return -1; + } + v = machdata->swab(v); + return mput(map, addr, (char *)&v, 2); +} + +int +put1(Map *map, ulong addr, uchar *v, int size) +{ + if (!map) { + werrstr("put1: invalid map"); + return -1; + } + return mput(map, addr, (char *)v, size); +} + +static int +mget(Map *map, ulong addr, char *buf, int size) +{ + long off; + int i, j, k; + struct segment *s; + + s = reloc(map, addr, &off); + if (!s) + return -1; + if (s->fd < 0) { + werrstr("unreadable map"); + return -1; + } + if (s->mget) + return s->mget(s, addr, off, buf, size); + seek(s->fd, off, 0); + for (i = j = 0; i < 2; i++) { /* in case read crosses page */ + k = read(s->fd, buf, size-j); + if (k < 0) { + werrstr("can't read address %lux: %r", addr); + return -1; + } + j += k; + if (j == size) + return j; + } + werrstr("partial read at address %lux", addr); + return -1; +} + +static int +mput(Map *map, ulong addr, char *buf, int size) +{ + long off; + int i, j, k; + struct segment *s; + + s = reloc(map, addr, &off); + if (!s) + return -1; + if (s->fd < 0) { + werrstr("unwritable map"); + return -1; + } + if (s->mput) + return s->mput(s, addr, off, buf, size); + + seek(s->fd, off, 0); + for (i = j = 0; i < 2; i++) { /* in case read crosses page */ + k = write(s->fd, buf, size-j); + if (k < 0) { + werrstr("can't write address %lux: %r", addr); + return -1; + } + j += k; + if (j == size) + return j; + } + werrstr("partial write at address %lux", addr); + return -1; +} + +/* + * convert address to file offset; returns nonzero if ok + */ +struct segment* +reloc(Map *map, ulong addr, long *offp) +{ + int i; + + for (i = 0; i < map->nsegs; i++) { + if (map->seg[i].inuse) + if (map->seg[i].b <= addr && addr < map->seg[i].e) { + *offp = addr + map->seg[i].f - map->seg[i].b; + return &map->seg[i]; + } + } + werrstr("can't translate address %lux", addr); + return 0; +} diff --git a/utils/libmach/ar.h b/utils/libmach/ar.h new file mode 100644 index 00000000..71ffff12 --- /dev/null +++ b/utils/libmach/ar.h @@ -0,0 +1,18 @@ +#define ARMAG "!<arch>\n" +#define SARMAG 8 + +#define ARFMAG "`\n" +#define SARNAME 16 + +struct ar_hdr +{ + char name[SARNAME]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char fmag[2]; +}; +#define SAR_HDR 60 + diff --git a/utils/libmach/bootexec.h b/utils/libmach/bootexec.h new file mode 100644 index 00000000..a844ec7c --- /dev/null +++ b/utils/libmach/bootexec.h @@ -0,0 +1,172 @@ +struct coffsect +{ + char name[8]; + ulong phys; + ulong virt; + ulong size; + ulong fptr; + ulong fptrreloc; + ulong fptrlineno; + ulong nrelocnlineno; + ulong flags; +}; + +/* + * proprietary exec headers, needed to bootstrap various machines + */ +struct mipsexec +{ + short mmagic; /* (0x160) mips magic number */ + short nscns; /* (unused) number of sections */ + long timdat; /* (unused) time & date stamp */ + long symptr; /* offset to symbol table */ + long nsyms; /* size of symbol table */ + short opthdr; /* (0x38) sizeof(optional hdr) */ + short pcszs; /* flags */ + short amagic; /* see above */ + short vstamp; /* version stamp */ + long tsize; /* text size in bytes */ + long dsize; /* initialized data */ + long bsize; /* uninitialized data */ + long mentry; /* entry pt. */ + long text_start; /* base of text used for this file */ + long data_start; /* base of data used for this file */ + long bss_start; /* base of bss used for this file */ + long gprmask; /* general purpose register mask */ +union{ + long mcprmask[4]; /* co-processor register masks */ + long mpcsize; +} u0; + long gp_value; /* the gp value used for this object */ +}; + +struct mips4kexec +{ + struct mipsexec h; + struct coffsect itexts; + struct coffsect idatas; + struct coffsect ibsss; +}; + +struct sparcexec +{ + short sjunk; /* dynamic bit and version number */ + short smagic; /* 0407 */ + ulong stext; + ulong sdata; + ulong sbss; + ulong ssyms; + ulong sentry; + ulong strsize; + ulong sdrsize; +}; + +struct nextexec +{ + struct nexthdr{ + ulong nmagic; + ulong ncputype; + ulong ncpusubtype; + ulong nfiletype; + ulong ncmds; + ulong nsizeofcmds; + ulong nflags; + }texth; + + struct nextcmd{ + ulong cmd; + ulong cmdsize; + uchar segname[16]; + ulong vmaddr; + ulong vmsize; + ulong fileoff; + ulong filesize; + ulong maxprot; + ulong initprot; + ulong nsects; + ulong flags; + }textc; + struct nextsect{ + char sectname[16]; + char segname[16]; + ulong addr; + ulong size; + ulong offset; + ulong align; + ulong reloff; + ulong nreloc; + ulong flags; + ulong reserved1; + ulong reserved2; + }texts; + struct nextcmd datac; + struct nextsect datas; + struct nextsect bsss; + struct nextsym{ + ulong cmd; + ulong cmdsize; + ulong symoff; + ulong nsyms; + ulong spoff; + ulong pcoff; + }symc; +}; + +struct i386exec +{ + struct i386coff{ + ulong isectmagic; + ulong itime; + ulong isyms; + ulong insyms; + ulong iflags; + } icoff; + struct i386hdr{ + ulong imagic; + ulong itextsize; + ulong idatasize; + ulong ibsssize; + ulong ientry; + ulong itextstart; + ulong idatastart; + } ihdr; + struct coffsect itexts; + struct coffsect idatas; + struct coffsect ibsss; + struct coffsect icomments; +}; + +struct i960exec +{ + struct i960coff{ + ulong i6sectmagic; + ulong i6time; + ulong i6syms; + ulong i6nsyms; + ulong i6opthdrflags; + }i6coff; + struct i960hdr{ + ulong i6magic; + ulong i6textsize; + ulong i6datasize; + ulong i6bsssize; + ulong i6entry; + ulong i6textstart; + ulong i6datastart; + ulong i6tagentries; + }i6hdr; + struct i960sect{ + char name[8]; + ulong phys; + ulong virt; + ulong size; + ulong fptr; + ulong fptrreloc; + ulong fptrlineno; + ulong nrelocnlineno; + ulong flags; + ulong align; + }i6texts; + struct i960sect i6datas; +}; + diff --git a/utils/libmach/elf.h b/utils/libmach/elf.h new file mode 100644 index 00000000..b182135b --- /dev/null +++ b/utils/libmach/elf.h @@ -0,0 +1,101 @@ +/* + * Definitions needed for accessing Irix ELF headers + */ +typedef struct { + unsigned char ident[16]; /* ident bytes */ + ushort type; /* file type */ + ushort machine; /* target machine */ + int version; /* file version */ + ulong elfentry; /* start address */ + ulong phoff; /* phdr file offset */ + ulong shoff; /* shdr file offset */ + int flags; /* file flags */ + ushort ehsize; /* sizeof ehdr */ + ushort phentsize; /* sizeof phdr */ + ushort phnum; /* number phdrs */ + ushort shentsize; /* sizeof shdr */ + ushort shnum; /* number shdrs */ + ushort shstrndx; /* shdr string index */ +} Ehdr; + +typedef struct { + int type; /* entry type */ + ulong offset; /* file offset */ + ulong vaddr; /* virtual address */ + ulong paddr; /* physical address */ + int filesz; /* file size */ + ulong memsz; /* memory size */ + int flags; /* entry flags */ + int align; /* memory/file alignment */ +} Phdr; + +typedef struct { + ulong name; /* section name */ + ulong type; /* SHT_... */ + ulong flags; /* SHF_... */ + ulong addr; /* virtual address */ + ulong offset; /* file offset */ + ulong size; /* section size */ + ulong link; /* misc info */ + ulong info; /* misc info */ + ulong addralign; /* memory alignment */ + ulong entsize; /* entry size if table */ +} Shdr; + +enum { + /* Ehdr codes */ + MAG0 = 0, /* ident[] indexes */ + MAG1 = 1, + MAG2 = 2, + MAG3 = 3, + CLASS = 4, + DATA = 5, + VERSION = 6, + + ELFCLASSNONE = 0, /* ident[CLASS] */ + ELFCLASS32 = 1, + ELFCLASS64 = 2, + ELFCLASSNUM = 3, + + ELFDATANONE = 0, /* ident[DATA] */ + ELFDATA2LSB = 1, + ELFDATA2MSB = 2, + ELFDATANUM = 3, + + NOETYPE = 0, /* type */ + REL = 1, + EXEC = 2, + DYN = 3, + CORE = 4, + + NONE = 0, /* machine */ + M32 = 1, /* AT&T WE 32100 */ + SPARC = 2, /* Sun SPARC */ + I386 = 3, /* Intel 80386 */ + M68K = 4, /* Motorola 68000 */ + M88K = 5, /* Motorola 88000 */ + I486 = 6, /* Intel 80486 */ + I860 = 7, /* Intel i860 */ + MIPS = 8, /* Mips R2000 */ + S370 = 9, /* Amdhal */ + POWER = 20, /* PowerPC */ + AMD64 = 62, /* Amd64 */ + + NO_VERSION = 0, /* version, ident[VERSION] */ + CURRENT = 1, + + /* Phdr Codes */ + NOPTYPE = 0, /* type */ + LOAD = 1, + DYNAMIC = 2, + INTERP = 3, + NOTE = 4, + SHLIB = 5, + PHDR = 6, + + R = 0x4, /* flags */ + W = 0x2, + X = 0x1, +}; + +#define ELF_MAG ((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F') diff --git a/utils/libmach/executable.c b/utils/libmach/executable.c new file mode 100644 index 00000000..a17d6ae2 --- /dev/null +++ b/utils/libmach/executable.c @@ -0,0 +1,570 @@ +#include <lib9.h> +#include <bio.h> +#include "bootexec.h" +#include "mach.h" +#include "elf.h" + +/* + * All a.out header types. The dummy entry allows canonical + * processing of the union as a sequence of longs + */ + +typedef struct { + union{ + Exec exec; /* in a.out.h */ + Ehdr ehdr; /* in elf.h */ + struct mipsexec mipsexec; + struct mips4kexec mips4kexec; + struct sparcexec sparcexec; + struct nextexec nextexec; + } e; + long dummy; /* padding to ensure extra long */ +} ExecHdr; + +static int nextboot(int, Fhdr*, ExecHdr*); +static int sparcboot(int, Fhdr*, ExecHdr*); +static int mipsboot(int, Fhdr*, ExecHdr*); +static int mips4kboot(int, Fhdr*, ExecHdr*); +static int common(int, Fhdr*, ExecHdr*); +static int adotout(int, Fhdr*, ExecHdr*); +static int elfdotout(int, Fhdr*, ExecHdr*); +static int armdotout(int, Fhdr*, ExecHdr*); +static void setsym(Fhdr*, long, long, long, long); +static void setdata(Fhdr*, long, long, long, long); +static void settext(Fhdr*, long, long, long, long); +static void hswal(long*, int, long(*)(long)); +static long _round(long, long); + +/* + * definition of per-executable file type structures + */ + +typedef struct Exectable{ + long magic; /* big-endian magic number of file */ + char *name; /* executable identifier */ + int type; /* Internal code */ + Mach *mach; /* Per-machine data */ + ulong hsize; /* header size */ + long (*swal)(long); /* beswal or leswal */ + int (*hparse)(int, Fhdr*, ExecHdr*); +} ExecTable; + +extern Mach mmips; +extern Mach mmips2le; +extern Mach mmips2be; +extern Mach msparc; +extern Mach m68020; +extern Mach mi386; +extern Mach marm; +extern Mach mpower; + +ExecTable exectab[] = +{ + { V_MAGIC, /* Mips v.out */ + "mips plan 9 executable", + FMIPS, + &mmips, + sizeof(Exec), + beswal, + adotout }, + { M_MAGIC, /* Mips 4.out */ + "mips 4k plan 9 executable BE", + FMIPS2BE, + &mmips2be, + sizeof(Exec), + beswal, + adotout }, + { N_MAGIC, /* Mips 0.out */ + "mips 4k plan 9 executable LE", + FMIPS2LE, + &mmips2le, + sizeof(Exec), + beswal, + adotout }, + { 0x160<<16, /* Mips boot image */ + "mips plan 9 boot image", + FMIPSB, + &mmips, + sizeof(struct mipsexec), + beswal, + mipsboot }, + { (0x160<<16)|3, /* Mips boot image */ + "mips 4k plan 9 boot image", + FMIPSB, + &mmips, + sizeof(struct mips4kexec), + beswal, + mips4kboot }, + { K_MAGIC, /* Sparc k.out */ + "sparc plan 9 executable", + FSPARC, + &msparc, + sizeof(Exec), + beswal, + adotout }, + { 0x01030107, /* Sparc boot image */ + "sparc plan 9 boot image", + FSPARCB, + &msparc, + sizeof(struct sparcexec), + beswal, + sparcboot }, + { A_MAGIC, /* 68020 2.out & boot image */ + "68020 plan 9 executable", + F68020, + &m68020, + sizeof(Exec), + beswal, + common }, + { 0xFEEDFACE, /* Next boot image */ + "next plan 9 boot image", + FNEXTB, + &m68020, + sizeof(struct nextexec), + beswal, + nextboot }, + { I_MAGIC, /* I386 8.out & boot image */ + "386 plan 9 executable", + FI386, + &mi386, + sizeof(Exec), + beswal, + common }, + { ELF_MAG, + "Irix 5.X Elf executable", + FMIPS, + &mmips, + sizeof(Ehdr), + beswal, + elfdotout }, + { E_MAGIC, /* Arm 5.out */ + "Arm plan 9 executable", + FARM, + &marm, + sizeof(Exec), + beswal, + common }, + { (143<<16)|0413, /* (Free|Net)BSD Arm */ + "Arm *BSD executable", + FARM, + &marm, + sizeof(Exec), + leswal, + armdotout }, + { Q_MAGIC, /* PowerPC q.out */ + "power plan 9 executable", + FPOWER, + &mpower, + sizeof(Exec), + beswal, + common }, + { 0 }, +}; + +Mach *mach = &mmips; /* Global current machine table */ + +ExecTable* +couldbe4k(ExecTable *mp) +{ + Dir *d; + ExecTable *f; + + if((d=dirstat("/proc/1/regs")) == nil) + return mp; + if(d->length < 32*8){ /* R3000 */ + free(d); + return mp; + } + free(d); + for (f = exectab; f->magic; f++) + if(f->magic == M_MAGIC) { + f->name = "mips plan 9 executable on mips2 kernel"; + return f; + } + return mp; +} + + +int +crackhdr(int fd, Fhdr *fp) +{ + ExecTable *mp; + ExecHdr d; + int nb, magic, ret; + + fp->type = FNONE; + nb = read(fd, (char *)&d.e, sizeof(d.e)); + if (nb <= 0) + return 0; + + ret = 0; + fp->magic = magic = beswal(d.e.exec.magic); /* big-endian */ + for (mp = exectab; mp->magic; mp++) { + if (mp->magic == magic && nb >= mp->hsize) { + if(mp->magic == V_MAGIC) + mp = couldbe4k(mp); + + hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal); + fp->type = mp->type; + fp->name = mp->name; + fp->hdrsz = mp->hsize; /* zero on bootables */ + mach = mp->mach; + ret = mp->hparse(fd, fp, &d); + seek(fd, mp->hsize, 0); /* seek to end of header */ + break; + } + } + if(mp->magic == 0) + werrstr("unknown header type"); + return ret; +} +/* + * Convert header to canonical form + */ +static void +hswal(long *lp, int n, long (*swap) (long)) +{ + while (n--) { + *lp = (*swap) (*lp); + lp++; + } +} +/* + * Crack a normal a.out-type header + */ +static int +adotout(int fd, Fhdr *fp, ExecHdr *hp) +{ + long pgsize; + + USED(fd); + pgsize = mach->pgsize; + settext(fp, hp->e.exec.entry, pgsize+sizeof(Exec), + hp->e.exec.text, sizeof(Exec)); + setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize), + hp->e.exec.data, fp->txtsz+sizeof(Exec), hp->e.exec.bss); + setsym(fp, hp->e.exec.syms, hp->e.exec.spsz, hp->e.exec.pcsz, fp->datoff+fp->datsz); + return 1; +} + +/* + * 68020 2.out and 68020 bootable images + * 386I 8.out and 386I bootable images + * + */ +static int +common(int fd, Fhdr *fp, ExecHdr *hp) +{ + long kbase; + + adotout(fd, fp, hp); + kbase = mach->kbase; + if ((fp->entry & kbase) == kbase) { /* Boot image */ + switch(fp->type) { + case F68020: + fp->type = F68020B; + fp->name = "68020 plan 9 boot image"; + fp->hdrsz = 0; /* header stripped */ + break; + case FI386: + fp->type = FI386B; + fp->txtaddr = sizeof(Exec); + fp->name = "386 plan 9 boot image"; + fp->hdrsz = 0; /* header stripped */ + fp->dataddr = fp->txtaddr+fp->txtsz; + break; + case FARM: + fp->txtaddr = kbase+0x8000+sizeof(Exec); + fp->name = "ARM plan 9 boot image"; + fp->hdrsz = 0; /* header stripped */ + fp->dataddr = fp->txtaddr+fp->txtsz; + return 1; + default: + break; + } + fp->txtaddr |= kbase; + fp->entry |= kbase; + fp->dataddr |= kbase; + } + else if (fp->type == FARM && (fp->entry == 0x8020 || fp->entry == 0x8080)) { + fp->txtaddr = fp->entry; + fp->name = "ARM Inferno boot image"; + fp->hdrsz = 0; /* header stripped */ + fp->dataddr = fp->txtaddr+fp->txtsz; + } + else if (fp->type == FPOWER && fp->entry == 0x3020) { + fp->txtaddr = fp->entry; + fp->name = "Power Inferno boot image"; + fp->hdrsz = 0; /* header stripped */ + fp->dataddr = fp->txtaddr+fp->txtsz; + } + return 1; +} + +/* + * mips bootable image. + */ +static int +mipsboot(int fd, Fhdr *fp, ExecHdr *hp) +{ + USED(fd); + switch(hp->e.mipsexec.amagic) { + default: + case 0407: /* some kind of mips */ + fp->type = FMIPSB; + settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize, + sizeof(struct mipsexec)+4); + setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize, + fp->txtoff+hp->e.mipsexec.tsize, hp->e.mipsexec.bsize); + break; + case 0413: /* some kind of mips */ + fp->type = FMIPSB; + settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize, 0); + setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize, hp->e.mipsexec.tsize, + hp->e.mipsexec.bsize); + break; + } + setsym(fp, hp->e.mipsexec.nsyms, 0, hp->e.mipsexec.u0.mpcsize, hp->e.mipsexec.symptr); + fp->hdrsz = 0; /* header stripped */ + return 1; +} + +/* + * mips4k bootable image. + */ +static int +mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) +{ + USED(fd); + switch(hp->e.mipsexec.amagic) { + default: + case 0407: /* some kind of mips */ + fp->type = FMIPSB; + settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize, + sizeof(struct mips4kexec)); + setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize, + fp->txtoff+hp->e.mipsexec.tsize, hp->e.mipsexec.bsize); + break; + case 0413: /* some kind of mips */ + fp->type = FMIPSB; + settext(fp, hp->e.mipsexec.mentry, hp->e.mipsexec.text_start, hp->e.mipsexec.tsize, 0); + setdata(fp, hp->e.mipsexec.data_start, hp->e.mipsexec.dsize, hp->e.mipsexec.tsize, + hp->e.mipsexec.bsize); + break; + } + setsym(fp, hp->e.mipsexec.nsyms, 0, hp->e.mipsexec.u0.mpcsize, hp->e.mipsexec.symptr); + fp->hdrsz = 0; /* header stripped */ + return 1; +} + +/* + * sparc bootable image + */ +static int +sparcboot(int fd, Fhdr *fp, ExecHdr *hp) +{ + USED(fd); + fp->type = FSPARCB; + settext(fp, hp->e.sparcexec.sentry, hp->e.sparcexec.sentry, hp->e.sparcexec.stext, + sizeof(struct sparcexec)); + setdata(fp, hp->e.sparcexec.sentry+hp->e.sparcexec.stext, hp->e.sparcexec.sdata, + fp->txtoff+hp->e.sparcexec.stext, hp->e.sparcexec.sbss); + setsym(fp, hp->e.sparcexec.ssyms, 0, hp->e.sparcexec.sdrsize, fp->datoff+hp->e.sparcexec.sdata); + fp->hdrsz = 0; /* header stripped */ + return 1; +} + +/* + * next bootable image + */ +static int +nextboot(int fd, Fhdr *fp, ExecHdr *hp) +{ + USED(fd); + fp->type = FNEXTB; + settext(fp, hp->e.nextexec.textc.vmaddr, hp->e.nextexec.textc.vmaddr, + hp->e.nextexec.texts.size, hp->e.nextexec.texts.offset); + setdata(fp, hp->e.nextexec.datac.vmaddr, hp->e.nextexec.datas.size, + hp->e.nextexec.datas.offset, hp->e.nextexec.bsss.size); + setsym(fp, hp->e.nextexec.symc.nsyms, hp->e.nextexec.symc.spoff, hp->e.nextexec.symc.pcoff, + hp->e.nextexec.symc.symoff); + fp->hdrsz = 0; /* header stripped */ + return 1; +} + +static Shdr* +elfsectbyname(int fd, Ehdr *hp, Shdr *sp, char *name) +{ + int i, offset, n; + char s[64]; + + offset = sp[hp->shstrndx].offset; + for(i = 1; i < hp->shnum; i++) { + seek(fd, offset+sp[i].name, 0); + n = read(fd, s, sizeof(s)-1); + if(n < 0) + continue; + s[n] = 0; + if(strcmp(s, name) == 0) + return &sp[i]; + } + return 0; +} +/* + * Decode an Irix 5.x ELF header + */ +static int +elfdotout(int fd, Fhdr *fp, ExecHdr *hp) +{ + + Ehdr *ep; + Shdr *es, *txt, *init, *s; + long addr, size, offset, bsize; + + ep = &hp->e.ehdr; + fp->magic = ELF_MAG; + fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; + + if(ep->shnum <= 0) { + werrstr("no ELF header sections"); + return 0; + } + es = malloc(sizeof(Shdr)*ep->shnum); + if(es == 0) + return 0; + + seek(fd, ep->shoff, 0); + if(read(fd, es, sizeof(Shdr)*ep->shnum) < 0){ + free(es); + return 0; + } + + txt = elfsectbyname(fd, ep, es, ".text"); + init = elfsectbyname(fd, ep, es, ".init"); + if(txt == 0 || init == 0 || init != txt+1) + goto bad; + if(txt->addr+txt->size != init->addr) + goto bad; + settext(fp, ep->elfentry, txt->addr, txt->size+init->size, txt->offset); + + addr = 0; + offset = 0; + size = 0; + s = elfsectbyname(fd, ep, es, ".data"); + if(s) { + addr = s->addr; + size = s->size; + offset = s->offset; + } + + s = elfsectbyname(fd, ep, es, ".rodata"); + if(s) { + if(addr){ + if(addr+size != s->addr) + goto bad; + } else { + addr = s->addr; + offset = s->offset; + } + size += s->size; + } + + s = elfsectbyname(fd, ep, es, ".got"); + if(s) { + if(addr){ + if(addr+size != s->addr) + goto bad; + } else { + addr = s->addr; + offset = s->offset; + } + size += s->size; + } + + bsize = 0; + s = elfsectbyname(fd, ep, es, ".bss"); + if(s) { + if(addr){ + if(addr+size != s->addr) + goto bad; + } else { + addr = s->addr; + offset = s->offset; + } + bsize = s->size; + } + + if(addr == 0) + goto bad; + + setdata(fp, addr, size, offset, bsize); + fp->name = "IRIX Elf a.out executable"; + free(es); + return 1; +bad: + free(es); + werrstr("ELF sections scrambled"); + return 0; +} + +/* + * (Free|Net)BSD ARM header. + */ +static int +armdotout(int fd, Fhdr *fp, ExecHdr *hp) +{ + long kbase; + + USED(fd); + settext(fp, hp->e.exec.entry, sizeof(Exec), hp->e.exec.text, sizeof(Exec)); + setdata(fp, fp->txtsz, hp->e.exec.data, fp->txtsz, hp->e.exec.bss); + setsym(fp, hp->e.exec.syms, hp->e.exec.spsz, hp->e.exec.pcsz, fp->datoff+fp->datsz); + + kbase = 0xF0000000; + if ((fp->entry & kbase) == kbase) { /* Boot image */ + fp->txtaddr = kbase+sizeof(Exec); + fp->name = "ARM *BSD boot image"; + fp->hdrsz = 0; /* header stripped */ + fp->dataddr = kbase+fp->txtsz; + } + return 1; +} + +static void +settext(Fhdr *fp, long e, long a, long s, long off) +{ + fp->txtaddr = a; + fp->entry = e; + fp->txtsz = s; + fp->txtoff = off; +} +static void +setdata(Fhdr *fp, long a, long s, long off, long bss) +{ + fp->dataddr = a; + fp->datsz = s; + fp->datoff = off; + fp->bsssz = bss; +} +static void +setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff) +{ + fp->symsz = sy; + fp->symoff = symoff; + fp->sppcsz = sppc; + fp->sppcoff = fp->symoff+fp->symsz; + fp->lnpcsz = lnpc; + fp->lnpcoff = fp->sppcoff+fp->sppcsz; +} + + +static long +_round(long a, long b) +{ + long w; + + w = (a/b)*b; + if (a!=w) + w += b; + return(w); +} diff --git a/utils/libmach/k.c b/utils/libmach/k.c new file mode 100644 index 00000000..30ae15a0 --- /dev/null +++ b/utils/libmach/k.c @@ -0,0 +1,117 @@ +/* + * sparc definition + */ +#include <lib9.h> +#include <bio.h> +#include "uregk.h" +#include "mach.h" + +#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x) + +#define R1 REGOFF(u0.r1) +#define R7 REGOFF(r7) +#define PC REGOFF(pc) +#define R15 REGOFF(r15) + +#define REGSIZE sizeof(struct Ureg) +#define FP_REG(x) (REGSIZE+4*(x)) +#define FPREGSIZE (33*4) + +Reglist sparcreglist[] = { + {"Y", REGOFF(y), RINT|RRDONLY, 'X'}, + {"TBR", REGOFF(tbr), RINT|RRDONLY, 'X'}, + {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'}, + {"PC", REGOFF(pc), RINT, 'X'}, + {"R1", REGOFF(u0.r1), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R29", REGOFF(r29), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"NPC", REGOFF(npc), RINT, 'X'}, + + {"FSR", FP_REG(0), RINT, 'X'}, + {"F0", FP_REG(1), RFLT, 'F'}, + {"F1", FP_REG(2), RFLT, 'f'}, + {"F2", FP_REG(3), RFLT, 'F'}, + {"F3", FP_REG(4), RFLT, 'f'}, + {"F4", FP_REG(5), RFLT, 'F'}, + {"F5", FP_REG(6), RFLT, 'f'}, + {"F6", FP_REG(7), RFLT, 'F'}, + {"F7", FP_REG(8), RFLT, 'f'}, + {"F8", FP_REG(9), RFLT, 'F'}, + {"F9", FP_REG(10), RFLT, 'f'}, + {"F10", FP_REG(11), RFLT, 'F'}, + {"F11", FP_REG(12), RFLT, 'f'}, + {"F12", FP_REG(13), RFLT, 'F'}, + {"F13", FP_REG(14), RFLT, 'f'}, + {"F14", FP_REG(15), RFLT, 'F'}, + {"F15", FP_REG(16), RFLT, 'f'}, + {"F16", FP_REG(17), RFLT, 'F'}, + {"F17", FP_REG(18), RFLT, 'f'}, + {"F18", FP_REG(19), RFLT, 'F'}, + {"F19", FP_REG(20), RFLT, 'f'}, + {"F20", FP_REG(21), RFLT, 'F'}, + {"F21", FP_REG(22), RFLT, 'f'}, + {"F22", FP_REG(23), RFLT, 'F'}, + {"F23", FP_REG(24), RFLT, 'f'}, + {"F24", FP_REG(25), RFLT, 'F'}, + {"F25", FP_REG(26), RFLT, 'f'}, + {"F26", FP_REG(27), RFLT, 'F'}, + {"F27", FP_REG(28), RFLT, 'f'}, + {"F28", FP_REG(29), RFLT, 'F'}, + {"F29", FP_REG(30), RFLT, 'f'}, + {"F30", FP_REG(31), RFLT, 'F'}, + {"F31", FP_REG(32), RFLT, 'f'}, + { 0 } +}; + +/* + * sparc has same stack format as mips + */ +Mach msparc = +{ + "sparc", + MSPARC, /* machine type */ + sparcreglist, /* register list */ + REGSIZE, /* register set size in bytes */ + FPREGSIZE, /* floating point register size in bytes */ + "PC", /* name of PC */ + "R1", /* name of SP */ + "R15", /* name of link register */ + "setSB", /* static base register name */ + 0, /* value */ + 0x1000, /* page size */ + 0xE0000000, /* kernel base */ + 0, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/kdb.c b/utils/libmach/kdb.c new file mode 100644 index 00000000..bffd5e77 --- /dev/null +++ b/utils/libmach/kdb.c @@ -0,0 +1,1055 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +/* + * Sparc-specific debugger interface + */ + +static char *sparcexcep(Map*, Rgetter); +static int sparcfoll(Map*, ulong, Rgetter, ulong*); +static int sparcinst(Map*, ulong, char, char*, int); +static int sparcdas(Map*, ulong, char*, int); +static int sparcinstlen(Map*, ulong); + +Machdata sparcmach = +{ + {0x91, 0xd0, 0x20, 0x01}, /* breakpoint: TA $1 */ + 4, /* break point size */ + + beswab, /* convert short to local byte order */ + beswal, /* convert long to local byte order */ + beswav, /* convert vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* frame finder */ + sparcexcep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precision float printer */ + sparcfoll, /* following addresses */ + sparcinst, /* print instruction */ + sparcdas, /* dissembler */ + sparcinstlen, /* instruction size */ +}; + +static char *trapname[] = +{ + "reset", + "instruction access exception", + "illegal instruction", + "privileged instruction", + "fp disabled", + "window overflow", + "window underflow", + "unaligned address", + "fp exception", + "data access exception", + "tag overflow", +}; + +static char* +excname(ulong tbr) +{ + static char buf[32]; + + if(tbr < sizeof trapname/sizeof(char*)) + return trapname[tbr]; + if(tbr >= 130) + sprint(buf, "trap instruction %ld", tbr-128); + else if(17<=tbr && tbr<=31) + sprint(buf, "interrupt level %ld", tbr-16); + else switch(tbr){ + case 36: + return "cp disabled"; + case 40: + return "cp exception"; + case 128: + return "syscall"; + case 129: + return "breakpoint"; + default: + sprint(buf, "unknown trap %ld", tbr); + } + return buf; +} + +static char* +sparcexcep(Map *map, Rgetter rget) +{ + long tbr; + + tbr = (*rget)(map, "TBR"); + tbr = (tbr&0xFFF)>>4; + return excname(tbr); +} + + /* Sparc disassembler and related functions */ + +typedef struct instr Instr; + +struct opcode { + char *mnemonic; + void (*f)(Instr*, char*); + int flag; +}; + +static char FRAMENAME[] = ".frame"; + +struct instr { + uchar op; /* bits 31-30 */ + uchar rd; /* bits 29-25 */ + uchar op2; /* bits 24-22 */ + uchar a; /* bit 29 */ + uchar cond; /* bits 28-25 */ + uchar op3; /* bits 24-19 */ + uchar rs1; /* bits 18-14 */ + uchar i; /* bit 13 */ + uchar asi; /* bits 12-05 */ + uchar rs2; /* bits 04-00 */ + short simm13; /* bits 12-00, signed */ + ushort opf; /* bits 13-05 */ + ulong immdisp22; /* bits 21-00 */ + ulong simmdisp22; /* bits 21-00, signed */ + ulong disp30; /* bits 30-00 */ + ulong imm32; /* SETHI+ADD constant */ + int target; /* SETHI+ADD dest reg */ + long w0; + long w1; + ulong addr; /* pc of instruction */ + char *curr; /* current fill level in output buffer */ + char *end; /* end of buffer */ + int size; /* number of longs in instr */ + char *err; /* errmsg */ +}; + +static Map *mymap; /* disassembler context */ +static int dascase; + +static int mkinstr(ulong, Instr*); +static void bra1(Instr*, char*, char*[]); +static void bra(Instr*, char*); +static void fbra(Instr*, char*); +static void cbra(Instr*, char*); +static void unimp(Instr*, char*); +static void fpop(Instr*, char*); +static void shift(Instr*, char*); +static void sethi(Instr*, char*); +static void load(Instr*, char*); +static void loada(Instr*, char*); +static void store(Instr*, char*); +static void storea(Instr*, char*); +static void add(Instr*, char*); +static void cmp(Instr*, char*); +static void wr(Instr*, char*); +static void jmpl(Instr*, char*); +static void rd(Instr*, char*); +static void loadf(Instr*, char*); +static void storef(Instr*, char*); +static void loadc(Instr*, char*); +static void loadcsr(Instr*, char*); +static void trap(Instr*, char*); + +static struct opcode sparcop0[8] = { + "UNIMP", unimp, 0, /* page 137 */ /* 0 */ + "", 0, 0, /* 1 */ + "B", bra, 0, /* page 119 */ /* 2 */ + "", 0, 0, /* 3 */ + "SETHI", sethi, 0, /* page 104 */ /* 4 */ + "", 0, 0, /* 5 */ + "FB", fbra, 0, /* page 121 */ /* 6 */ + "CB", cbra, 0, /* page 123 */ /* 7 */ +}; + +static struct opcode sparcop2[64] = { + "ADD", add, 0, /* page 108 */ /* 0x00 */ + "AND", add, 0, /* page 106 */ /* 0x01 */ + "OR", add, 0, /* 0x02 */ + "XOR", add, 0, /* 0x03 */ + "SUB", add, 0, /* page 110 */ /* 0x04 */ + "ANDN", add, 0, /* 0x05 */ + "ORN", add, 0, /* 0x06 */ + "XORN", add, 0, /* 0x07 */ + "ADDX", add, 0, /* 0x08 */ + "", 0, 0, /* 0x09 */ + "UMUL", add, 0, /* page 113 */ /* 0x0a */ + "SMUL", add, 0, /* 0x0b */ + "SUBX", add, 0, /* 0x0c */ + "", 0, 0, /* 0x0d */ + "UDIV", add, 0, /* page 115 */ /* 0x0e */ + "SDIV", add, 0, /* 0x0f */ + "ADDCC", add, 0, /* 0x10 */ + "ANDCC", add, 0, /* 0x11 */ + "ORCC", add, 0, /* 0x12 */ + "XORCC", add, 0, /* 0x13 */ + "SUBCC", cmp, 0, /* 0x14 */ + "ANDNCC", add, 0, /* 0x15 */ + "ORNCC", add, 0, /* 0x16 */ + "XORNCC", add, 0, /* 0x17 */ + "ADDXCC", add, 0, /* 0x18 */ + "", 0, 0, /* 0x19 */ + "UMULCC", add, 0, /* 0x1a */ + "SMULCC", add, 0, /* 0x1b */ + "SUBXCC", add, 0, /* 0x1c */ + "", 0, 0, /* 0x1d */ + "UDIVCC", add, 0, /* 0x1e */ + "SDIVCC", add, 0, /* 0x1f */ + "TADD", add, 0, /* page 109 */ /* 0x20 */ + "TSUB", add, 0, /* page 111 */ /* 0x21 */ + "TADDCCTV", add, 0, /* 0x22 */ + "TSUBCCTV", add, 0, /* 0x23 */ + "MULSCC", add, 0, /* page 112 */ /* 0x24 */ + "SLL", shift, 0, /* page 107 */ /* 0x25 */ + "SRL", shift, 0, /* 0x26 */ + "SRA", shift, 0, /* 0x27 */ + "rdy", rd, 0, /* page 131 */ /* 0x28 */ + "rdpsr", rd, 0, /* 0x29 */ + "rdwim", rd, 0, /* 0x2a */ + "rdtbr", rd, 0, /* 0x2b */ + "", 0, 0, /* 0x2c */ + "", 0, 0, /* 0x2d */ + "", 0, 0, /* 0x2e */ + "", 0, 0, /* 0x2f */ + "wry", wr, 0, /* page 133 */ /* 0x30 */ + "wrpsr", wr, 0, /* 0x31 */ + "wrwim", wr, 0, /* 0x32 */ + "wrtbr", wr, 0, /* 0x33 */ + "FPOP", fpop, 0, /* page 140 */ /* 0x34 */ + "FPOP", fpop, 0, /* 0x35 */ + "", 0, 0, /* 0x36 */ + "", 0, 0, /* 0x37 */ + "JMPL", jmpl, 0, /* page 126 */ /* 0x38 */ + "RETT", add, 0, /* page 127 */ /* 0x39 */ + "T", trap, 0, /* page 129 */ /* 0x3a */ + "flush", add, 0, /* page 138 */ /* 0x3b */ + "SAVE", add, 0, /* page 117 */ /* 0x3c */ + "RESTORE", add, 0, /* 0x3d */ +}; + +static struct opcode sparcop3[64]={ + "ld", load, 0, /* 0x00 */ + "ldub", load, 0, /* 0x01 */ + "lduh", load, 0, /* 0x02 */ + "ldd", load, 0, /* 0x03 */ + "st", store, 0, /* 0x04 */ + "stb", store, 0, /* page 95 */ /* 0x05 */ + "sth", store, 0, /* 0x06 */ + "std", store, 0, /* 0x07 */ + "", 0, 0, /* 0x08 */ + "ldsb", load, 0, /* page 90 */ /* 0x09 */ + "ldsh", load, 0, /* 0x0a */ + "", 0, 0, /* 0x0b */ + "", 0, 0, /* 0x0c */ + "ldstub", store, 0, /* page 101 */ /* 0x0d */ + "", 0, 0, /* 0x0e */ + "swap", load, 0, /* page 102 */ /* 0x0f */ + "lda", loada, 0, /* 0x10 */ + "lduba", loada, 0, /* 0x11 */ + "lduha", loada, 0, /* 0x12 */ + "ldda", loada, 0, /* 0x13 */ + "sta", storea, 0, /* 0x14 */ + "stba", storea, 0, /* 0x15 */ + "stha", storea, 0, /* 0x16 */ + "stda", storea, 0, /* 0x17 */ + "", 0, 0, /* 0x18 */ + "ldsba", loada, 0, /* 0x19 */ + "ldsha", loada, 0, /* 0x1a */ + "", 0, 0, /* 0x1b */ + "", 0, 0, /* 0x1c */ + "ldstuba", storea, 0, /* 0x1d */ + "", 0, 0, /* 0x1e */ + "swapa", loada, 0, /* 0x1f */ + "ldf", loadf, 0, /* page 92 */ /* 0x20 */ + "ldfsr", loadf,0, /* 0x21 */ + "", 0, 0, /* 0x22 */ + "lddf", loadf, 0, /* 0x23 */ + "stf", storef, 0, /* page 97 */ /* 0x24 */ + "stfsr", storef,0, /* 0x25 */ + "stdfq", storef,0, /* 0x26 */ + "stdf", storef, 0, /* 0x27 */ + "", 0, 0, /* 0x28 */ + "", 0, 0, /* 0x29 */ + "", 0, 0, /* 0x2a */ + "", 0, 0, /* 0x2b */ + "", 0, 0, /* 0x2c */ + "", 0, 0, /* 0x2d */ + "", 0, 0, /* 0x2e */ + "", 0, 0, /* 0x2f */ + "ldc", loadc, 0, /* page 94 */ /* 0x30 */ + "ldcsr", loadcsr,0, /* 0x31 */ + "", 0, 0, /* 0x32 */ + "lddc", loadc, 0, /* 0x33 */ + "stc", loadc, 0, /* page 99 */ /* 0x34 */ + "stcsr", loadcsr,0, /* 0x35 */ + "stdcq", loadcsr,0, /* 0x36 */ + "stdc", loadc, 0, /* 0x37 */ +}; + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static int +decode(ulong pc, Instr *i) +{ + long w; + + if (get4(mymap, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->op = (w >> 30) & 0x03; + i->rd = (w >> 25) & 0x1F; + i->op2 = (w >> 22) & 0x07; + i->a = (w >> 29) & 0x01; + i->cond = (w >> 25) & 0x0F; + i->op3 = (w >> 19) & 0x3F; + i->rs1 = (w >> 14) & 0x1F; + i->i = (w >> 13) & 0x01; + i->asi = (w >> 5) & 0xFF; + i->rs2 = (w >> 0) & 0x1F; + i->simm13 = (w >> 0) & 0x1FFF; + if(i->simm13 & (1<<12)) + i->simm13 |= ~((1<<13)-1); + i->opf = (w >> 5) & 0x1FF; + i->immdisp22 = (w >> 0) & 0x3FFFFF; + i->simmdisp22 = i->immdisp22; + if(i->simmdisp22 & (1<<21)) + i->simmdisp22 |= ~((1<<22)-1); + i->disp30 = (w >> 0) & 0x3FFFFFFF; + i->w0 = w; + i->target = -1; + i->addr = pc; + i->size = 1; + return 1; +} + +static int +mkinstr(ulong pc, Instr *i) +{ + Instr xi; + + if (decode(pc, i) < 0) + return -1; + if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */ + if (decode(pc+4, &xi) < 0) + return -1; + if(xi.op==2 && xi.op3==0) /* ADD */ + if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */ + i->imm32 = xi.simm13 + (i->immdisp22<<10); + i->target = xi.rd; + i->w1 = xi.w0; + i->size++; + return 1; + } + } + if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */ + if (decode(pc+4, &xi) < 0) + return -1; + if(i->op==2 && i->opf==1) /* FMOVS */ + if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */ + i->w1 = xi.w0; + i->size++; + } + } + return 1; +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr instr; + void (*f)(Instr*, char*); + + mymap = map; + memset(&instr, 0, sizeof(instr)); + instr.curr = buf; + instr.end = buf+n-1; + if (mkinstr(pc, &instr) < 0) + return -1; + switch(instr.op){ + case 0: + f = sparcop0[instr.op2].f; + if(f) + (*f)(&instr, sparcop0[instr.op2].mnemonic); + else + bprint(&instr, "unknown %lux", instr.w0); + break; + + case 1: + bprint(&instr, "%X", "CALL\t"); + instr.curr += symoff(instr.curr, instr.end-instr.curr, + pc+instr.disp30*4, CTEXT); + if (!dascase) + bprint(&instr, "(SB)"); + break; + + case 2: + f = sparcop2[instr.op3].f; + if(f) + (*f)(&instr, sparcop2[instr.op3].mnemonic); + else + bprint(&instr, "unknown %lux", instr.w0); + break; + + case 3: + f = sparcop3[instr.op3].f; + if(f) + (*f)(&instr, sparcop3[instr.op3].mnemonic); + else + bprint(&instr, "unknown %lux", instr.w0); + break; + } + if (instr.err) { + if (instr.curr != buf) + bprint(&instr, "\t\t;"); + bprint(&instr, instr.err); + } + return instr.size*4; +} + +/* convert to lower case from upper, according to dascase */ +static int +Xconv(Fmt *f) +{ + char buf[128]; + char *s, *t, *oa; + + oa = va_arg(f->args, char*); + if(dascase){ + for(s=oa,t=buf; *t = *s; s++,t++) + if('A'<=*t && *t<='Z') + *t += 'a'-'A'; + return fmtstrcpy(f, buf); + } + return fmtstrcpy(f, oa); +} + +static int +sparcinst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + static int fmtinstalled = 0; + + /* a modifier of 'I' toggles the dissassembler type */ + if (!fmtinstalled) { + fmtinstalled = 1; + fmtinstall('X', Xconv); + } + if ((asstype == ASUNSPARC && modifier == 'i') + || (asstype == ASPARC && modifier == 'I')) + dascase = 'a'-'A'; + else + dascase = 0; + return printins(map, pc, buf, n); +} + +static int +sparcdas(Map *map, ulong pc, char *buf, int n) +{ + Instr instr; + + mymap = map; + memset(&instr, 0, sizeof(instr)); + instr.curr = buf; + instr.end = buf+n-1; + if (mkinstr(pc, &instr) < 0) + return -1; + if (instr.end-instr.curr > 8) + instr.curr = _hexify(instr.curr, instr.w0, 7); + if (instr.end-instr.curr > 9 && instr.size == 2) { + *instr.curr++ = ' '; + instr.curr = _hexify(instr.curr, instr.w1, 7); + } + *instr.curr = 0; + return instr.size*4; +} + +static int +sparcinstlen(Map *map, ulong pc) +{ + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + return i.size*4; +} + +static int +plocal(Instr *i) +{ + int offset; + Symbol s; + + if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) + return -1; + if (s.value > i->simm13) { + if(getauto(&s, s.value-i->simm13, CAUTO, &s)) { + bprint(i, "%s+%d(SP)", s.name, s.value); + return 1; + } + } else { + offset = i->simm13-s.value; + if (getauto(&s, offset-4, CPARAM, &s)) { + bprint(i, "%s+%d(FP)", s.name, offset); + return 1; + } + } + return -1; +} + +static void +address(Instr *i) +{ + Symbol s, s2; + long off, off1; + + if (i->rs1 == 1 && plocal(i) >= 0) + return; + off = mach->sb+i->simm13; + if(i->rs1 == 2 && findsym(off, CANY, &s) + && s.value-off < 4096 + && (s.class == CDATA || s.class == CTEXT)) { + if(off==s.value && s.name[0]=='$'){ + off1 = 0; + get4(mymap, s.value, &off1); + if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ + bprint(i, "$%s(SB)", s2.name); + return; + } + } + bprint(i, "%s", s.name); + if (s.value != off) + bprint(i, "+%lux", s.value-off); + bprint(i, "(SB)"); + return; + } + bprint(i, "%lux(R%d)", i->simm13, i->rs1); +} + +static void +unimp(Instr *i, char *m) +{ + bprint(i, "%X", m); +} + +static char *bratab[16] = { /* page 91 */ + "N", /* 0x0 */ + "E", /* 0x1 */ + "LE", /* 0x2 */ + "L", /* 0x3 */ + "LEU", /* 0x4 */ + "CS", /* 0x5 */ + "NEG", /* 0x6 */ + "VS", /* 0x7 */ + "A", /* 0x8 */ + "NE", /* 0x9 */ + "G", /* 0xa */ + "GE", /* 0xb */ + "GU", /* 0xc */ + "CC", /* 0xd */ + "POS", /* 0xe */ + "VC", /* 0xf */ +}; + +static char *fbratab[16] = { /* page 91 */ + "N", /* 0x0 */ + "NE", /* 0x1 */ + "LG", /* 0x2 */ + "UL", /* 0x3 */ + "L", /* 0x4 */ + "UG", /* 0x5 */ + "G", /* 0x6 */ + "U", /* 0x7 */ + "A", /* 0x8 */ + "E", /* 0x9 */ + "UE", /* 0xa */ + "GE", /* 0xb */ + "UGE", /* 0xc */ + "LE", /* 0xd */ + "ULE", /* 0xe */ + "O", /* 0xf */ +}; + +static char *cbratab[16] = { /* page 91 */ + "N", /* 0x0 */ + "123", /* 0x1 */ + "12", /* 0x2 */ + "13", /* 0x3 */ + "1", /* 0x4 */ + "23", /* 0x5 */ + "2", /* 0x6 */ + "3", /* 0x7 */ + "A", /* 0x8 */ + "0", /* 0x9 */ + "03", /* 0xa */ + "02", /* 0xb */ + "023", /* 0xc */ + "01", /* 0xd */ + "013", /* 0xe */ + "012", /* 0xf */ +}; + +static void +bra1(Instr *i, char *m, char *tab[]) +{ + long imm; + + imm = i->simmdisp22; + if(i->a) + bprint(i, "%X%X.%c\t", m, tab[i->cond], 'A'+dascase); + else + bprint(i, "%X%X\t", m, tab[i->cond]); + i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT); + if (!dascase) + bprint(i, "(SB)"); +} + +static void +bra(Instr *i, char *m) /* page 91 */ +{ + bra1(i, m, bratab); +} + +static void +fbra(Instr *i, char *m) /* page 93 */ +{ + bra1(i, m, fbratab); +} + +static void +cbra(Instr *i, char *m) /* page 95 */ +{ + bra1(i, m, cbratab); +} + +static void +trap(Instr *i, char *m) /* page 101 */ +{ + if(i->i == 0) + bprint(i, "%X%X\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1); + else + bprint(i, "%X%X\t$%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1); +} + +static void +sethi(Instr *i, char *m) /* page 89 */ +{ + ulong imm; + + imm = i->immdisp22<<10; + if(dascase){ + bprint(i, "%X\t%lux, R%d", m, imm, i->rd); + return; + } + if(imm==0 && i->rd==0){ + bprint(i, "NOP"); + return; + } + if(i->target < 0){ + bprint(i, "MOVW\t$%lux, R%d", imm, i->rd); + return; + } + bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target); +} + +static char ldtab[] = { + 'W', + 'B', + 'H', + 'D', +}; + +static char* +moveinstr(int op3, char *m) +{ + char *s; + int c; + static char buf[8]; + + if(!dascase){ + /* batshit cases */ + if(op3 == 0xF || op3 == 0x1F) + return "SWAP"; + if(op3 == 0xD || op3 == 0x1D) + return "TAS"; /* really LDSTUB */ + c = ldtab[op3&3]; + s = ""; + if((op3&11)==1 || (op3&11)==2) + s="U"; + sprint(buf, "MOV%c%s", c, s); + return buf; + } + return m; +} + +static void +load(Instr *i, char *m) /* page 68 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd); + else{ + bprint(i, "%s\t", m); + address(i); + bprint(i, ", R%d", i->rd); + } +} + +static void +loada(Instr *i, char *m) /* page 68 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd); + else + bprint(i, "unknown ld asi %lux", i->w0); +} + +static void +store(Instr *i, char *m) /* page 74 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\tR%d, (R%d+R%d)", + m, i->rd, i->rs1, i->rs2); + else{ + bprint(i, "%s\tR%d, ", m, i->rd); + address(i); + } +} + +static void +storea(Instr *i, char *m) /* page 74 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi); + else + bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi); +} + +static void +shift(Instr *i, char *m) /* page 88 */ +{ + if(i->i == 0){ + if(i->rs1 == i->rd) + if(dascase) + bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2); + else + bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1); + else + if(dascase) + bprint(i, "%X\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd); + else + bprint(i, "%X\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd); + }else{ + if(i->rs1 == i->rd) + if(dascase) + bprint(i, "%X\t$%d,R%d", m, i->simm13&0x1F, i->rs1); + else + bprint(i, "%X\tR%d, $%d", m, i->rs1, i->simm13&0x1F); + else + if(dascase) + bprint(i, "%X\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd); + else + bprint(i, "%X\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd); + } +} + +static void +add(Instr *i, char *m) /* page 82 */ +{ + if(i->i == 0){ + if(dascase) + bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2); + else + if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */ + bprint(i, "MOVW\tR%d", i->rs2); + else + bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1); + }else{ + if(dascase) + bprint(i, "%X\tR%d, $%lux", m, i->rs1, i->simm13); + else + if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */ + bprint(i, "MOVW\t$%lux", i->simm13); + else if(i->op3==0 && i->rd && i->rs1==2){ + /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */ + bprint(i, "MOVW\t$"); + address(i); + } else + bprint(i, "%X\t$%lux, R%d", m, i->simm13, i->rs1); + } + if(i->rs1 != i->rd) + bprint(i, ", R%d", i->rd); +} + +static void +cmp(Instr *i, char *m) +{ + if(dascase || i->rd){ + add(i, m); + return; + } + if(i->i == 0) + bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2); + else + bprint(i, "CMP\tR%d, $%lux", i->rs1, i->simm13); +} + +static char *regtab[4] = { + "Y", + "PSR", + "WIM", + "TBR", +}; + +static void +wr(Instr *i, char *m) /* page 82 */ +{ + if(dascase){ + if(i->i == 0) + bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2); + else + bprint(i, "%s\tR%d, $%lux", m, i->rs1, i->simm13); + }else{ + if(i->i && i->simm13==0) + bprint(i, "MOVW\tR%d", i->rs1); + else if(i->i == 0) + bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1); + else + bprint(i, "wr\t$%lux, R%d", i->simm13, i->rs1); + } + bprint(i, ", %s", regtab[i->op3&3]); +} + +static void +rd(Instr *i, char *m) /* page 103 */ +{ + if(i->rs1==15 && i->rd==0){ + m = "stbar"; + if(!dascase) + m = "STBAR"; + bprint(i, "%s", m); + }else{ + if(!dascase) + m = "MOVW"; + bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd); + } +} + +static void +jmpl(Instr *i, char *m) /* page 82 */ +{ + if(i->i == 0){ + if(i->rd == 15) + bprint(i, "%X\t(R%d+R%d)", "CALL", i->rs2, i->rs1); + else + bprint(i, "%X\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd); + }else{ + if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0) + bprint(i, "RETURN"); + else{ + bprint(i, "%X\t", m); + address(i); + bprint(i, ", R%d", i->rd); + } + } +} + +static void +loadf(Instr *i, char *m) /* page 70 */ +{ + if(!dascase){ + m = "FMOVD"; + if(i->op3 == 0x20) + m = "FMOVF"; + else if(i->op3 == 0x21) + m = "MOVW"; + } + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2); + else{ + bprint(i, "%s\t", m); + address(i); + } + if(i->op3 == 0x21) + bprint(i, ", FSR"); + else + bprint(i, ", R%d", i->rd); +} + +static +void storef(Instr *i, char *m) /* page 70 */ +{ + if(!dascase){ + m = "FMOVD"; + if(i->op3 == 0x25 || i->op3 == 0x26) + m = "MOVW"; + else if(i->op3 == 0x20) + m = "FMOVF"; + } + bprint(i, "%s\t", m); + if(i->op3 == 0x25) + bprint(i, "FSR, "); + else if(i->op3 == 0x26) + bprint(i, "FQ, "); + else + bprint(i, "R%d, ", i->rd); + if(i->i == 0) + bprint(i, "(R%d+R%d)", i->rs1, i->rs2); + else + address(i); +} + +static +void loadc(Instr *i, char *m) /* page 72 */ +{ + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd); + else{ + bprint(i, "%s\t", m); + address(i); + bprint(i, ", C%d", i->rd); + } +} + +static +void loadcsr(Instr *i, char *m) /* page 72 */ +{ + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2); + else{ + bprint(i, "%s\t", m); + address(i); + bprint(i, ", CSR"); + } +} + +static struct{ + int opf; + char *name; +} fptab1[] = { /* ignores rs1 */ + 0xC4, "FITOS", /* page 109 */ + 0xC8, "FITOD", + 0xCC, "FITOX", + + 0xD1, "FSTOI", /* page 110 */ + 0xD2, "FDTOI", + 0xD3, "FXTOI", + + 0xC9, "FSTOD", /* page 111 */ + 0xCD, "FSTOX", + 0xC6, "FDTOS", + 0xCE, "FDTOX", + 0xC7, "FXTOS", + 0xCB, "FXTOD", + + 0x01, "FMOVS", /* page 112 */ + 0x05, "FNEGS", + 0x09, "FABSS", + + 0x29, "FSQRTS", /* page 113 */ + 0x2A, "FSQRTD", + 0x2B, "FSQRTX", + + 0, 0, +}; + +static struct{ + int opf; + char *name; +} fptab2[] = { /* uses rs1 */ + + 0x41, "FADDS", /* page 114 */ + 0x42, "FADDD", + 0x43, "FADDX", + 0x45, "FSUBS", + 0x46, "FSUBD", + 0x47, "FSUBX", + + 0x49, "FMULS", /* page 115 */ + 0x4A, "FMULD", + 0x4B, "FMULX", + 0x4D, "FDIVS", + 0x4E, "FDIVD", + 0x4F, "FDIVX", + + 0x51, "FCMPS", /* page 116 */ + 0x52, "FCMPD", + 0x53, "FCMPX", + 0x55, "FCMPES", + 0x56, "FCMPED", + 0x57, "FCMPEX", + + 0, 0 +}; + +static void +fpop(Instr *i, char *m) /* page 108-116 */ +{ + int j; + + if(dascase==0 && i->size==2){ + bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd); + return; + } + for(j=0; fptab1[j].name; j++) + if(fptab1[j].opf == i->opf){ + bprint(i, "%X\tF%d, F%d", fptab1[j].name, i->rs2, i->rd); + return; + } + for(j=0; fptab2[j].name; j++) + if(fptab2[j].opf == i->opf){ + bprint(i, "%X\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd); + return; + } + bprint(i, "%X%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd); +} + +static int +sparcfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + ulong w, r1, r2; + char buf[8]; + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + w = i.w0; + switch(w & 0xC1C00000){ + case 0x00800000: /* branch on int cond */ + case 0x01800000: /* branch on fp cond */ + case 0x01C00000: /* branch on copr cond */ + foll[0] = pc+8; + foll[1] = pc + (i.simmdisp22<<2); + return 2; + } + + if((w&0xC0000000) == 0x40000000){ /* CALL */ + foll[0] = pc + (i.disp30<<2); + return 1; + } + + if((w&0xC1F80000) == 0x81C00000){ /* JMPL */ + sprint(buf, "R%ld", (w>>14)&0xF); + r1 = (*rget)(map, buf); + if(w & 0x2000) /* JMPL R1+simm13 */ + r2 = i.simm13; + else{ /* JMPL R1+R2 */ + sprint(buf, "R%ld", w&0xF); + r2 = (*rget)(map, buf); + } + foll[0] = r1 + r2; + return 1; + } + foll[0] = pc+i.size*4; + return 1; +} diff --git a/utils/libmach/kobj.c b/utils/libmach/kobj.c new file mode 100644 index 00000000..f8d7e613 --- /dev/null +++ b/utils/libmach/kobj.c @@ -0,0 +1,132 @@ +/* + * kobj.c - identify and parse a sparc object file + */ +#include <lib9.h> +#include <bio.h> +#include "kc/k.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + + +int +_isk(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + + +int +_readk(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 5); /* reg (1 byte); lineno (4 bytes) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp, 1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type) { + default: + case D_NONE: case D_REG: case D_FREG: case D_CREG: case D_PREG: + break; + case D_BRANCH: + case D_OREG: + case D_ASI: + case D_CONST: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym!=0 && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/mach.h b/utils/libmach/mach.h new file mode 100644 index 00000000..6a5d2569 --- /dev/null +++ b/utils/libmach/mach.h @@ -0,0 +1,294 @@ +/* + * Architecture-dependent application data + */ +#include "a.out.h" +/* + * Supported architectures: + * mips, + * 68020, + * i386, + * amd64, + * sparc, + * mips2 (R4000) + * arm + */ +enum +{ + MMIPS, /* machine types */ + MSPARC, + M68020, + MI386, + MI960, /* retired */ + M3210, /* retired */ + MMIPS2, + NMIPS2, + M29000, /* retired */ + MARM, + MPOWER, + + /* types of executables */ + FNONE = 0, /* unidentified */ + FMIPS, /* v.out */ + FMIPSB, /* mips bootable */ + FSPARC, /* k.out */ + FSPARCB, /* Sparc bootable */ + F68020, /* 2.out */ + F68020B, /* 68020 bootable */ + FNEXTB, /* Next bootable */ + FI386, /* 8.out */ + FI386B, /* I386 bootable */ + FI960, /* retired */ + FI960B, /* retired */ + F3210, /* retired */ + FMIPS2BE, /* 4.out */ + F29000, /* retired */ + FARM, /* 5.out */ + FARMB, /* ARM bootable */ + FPOWER, /* q.out */ + FPOWERB, /* power pc bootable */ + FMIPS2LE, /* 4k little endian */ + + ANONE = 0, /* dissembler types */ + AMIPS, + AMIPSCO, /* native mips */ + ASPARC, + ASUNSPARC, /* native sun */ + A68020, + AI386, + AI8086, /* oh god */ + AI960, /* retired */ + A29000, + AARM, + APOWER, + /* object file types */ + Obj68020 = 0, /* .2 */ + ObjSparc, /* .k */ + ObjMips, /* .v */ + Obj386, /* .8 */ + Obj960, /* retired */ + Obj3210, /* .x */ + ObjMips2, /* .4 */ + Obj29000, /* retired */ + ObjArm, /* .5 */ + ObjPower, /* .q */ + ObjMips2le, /* .0 */ + Maxobjtype, + + CNONE = 0, /* symbol table classes */ + CAUTO, + CPARAM, + CSTAB, + CTEXT, + CDATA, + CANY /* to look for any class */ +}; + +typedef struct Map Map; +typedef struct Symbol Symbol; +typedef struct Reglist Reglist; +typedef struct Mach Mach; +typedef struct Machdata Machdata; +typedef struct segment segment; + +typedef int (*Rsegio)(segment*, ulong, long, char*, int); + +/* + * Structure to map a segment to a position in a file + */ +struct Map { + int nsegs; /* number of segments */ + struct segment { /* per-segment map */ + char *name; /* the segment name */ + int fd; /* file descriptor */ + int inuse; /* in use - not in use */ + ulong b; /* base */ + ulong e; /* end */ + ulong f; /* offset within file */ + Rsegio mget; /* special get if not 0 */ + Rsegio mput; /* special put if not 0 */ + } seg[1]; /* actually n of these */ +}; + + + +/* + * Internal structure describing a symbol table entry + */ +struct Symbol { + void *handle; /* used internally - owning func */ + /*struct {*/ + char *name; + long value; /* address or stack offset */ + char type; /* as in a.out.h */ + char class; /* as above */ + /*};*/ +}; + +/* + * machine register description + */ +struct Reglist { + char *rname; /* register name */ + short roffs; /* offset in u-block */ + char rflags; /* INTEGER/FLOAT, WRITABLE */ + char rformat; /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */ +}; + +enum { /* bits in rflags field */ + RINT = (0<<0), + RFLT = (1<<0), + RRDONLY = (1<<1) +}; +/* + * Machine-dependent data is stored in two structures: + * Mach - miscellaneous general parameters + * Machdata - jump vector of service functions used by debuggers + * + * Mach is defined in 2.c, 4.c, v.c, k.c, 8.c, 6.c and set in executable.c + * + * Machdata is defined in 2db.c, 4db.c, vdb.c, kdb.c, 8db.c, and 6db.c + * and set in the debugger startup. + */ + + +struct Mach{ + char *name; + int mtype; /* machine type code */ + Reglist *reglist; /* register set */ + ulong regsize; /* sizeof registers in bytes*/ + ulong fpregsize; /* sizeof fp registers in bytes*/ + char *pc; /* pc name */ + char *sp; /* sp name */ + char *link; /* link register name */ + char *sbreg; /* static base register name */ + ulong sb; /* static base register value */ + int pgsize; /* page size */ + ulong kbase; /* kernel base address */ + ulong ktmask; /* ktzero = kbase & ~ktmask */ + int pcquant; /* quantization of pc */ + int szaddr; /* sizeof(void*) */ + int szreg; /* sizeof(register) */ + int szfloat; /* sizeof(float) */ + int szdouble; /* sizeof(double) */ +}; + +extern Mach *mach; /* Current machine */ + +typedef vlong (*Rgetter)(Map*, char*); +typedef void (*Tracer)(Map*, ulong, ulong, Symbol*); + +struct Machdata { /* Machine-dependent debugger support */ + uchar bpinst[4]; /* break point instr. */ + short bpsize; /* size of break point instr. */ + + ushort (*swab)(ushort); /* short to local byte order */ + long (*swal)(long); /* long to local byte order */ + vlong (*swav)(vlong); /* vlong to local byte order */ + int (*ctrace)(Map*, ulong, ulong, ulong, Tracer); /* C traceback */ + ulong (*findframe)(Map*, ulong, ulong, ulong, ulong);/* frame finder */ + char* (*excep)(Map*, Rgetter); /* last exception */ + ulong (*bpfix)(ulong); /* breakpoint fixup */ + int (*sftos)(char*, int, void*); /* single precision float */ + int (*dftos)(char*, int, void*); /* double precision float */ + int (*foll)(Map*, ulong, Rgetter, ulong*); /* follow set */ + int (*das)(Map*, ulong, char, char*, int); /* symbolic disassembly */ + int (*hexinst)(Map*, ulong, char*, int); /* hex disassembly */ + int (*instsize)(Map*, ulong); /* instruction size */ +}; + +/* + * Common a.out header describing all architectures + */ +typedef struct Fhdr +{ + char *name; /* identifier of executable */ + short type; /* file type - see codes above*/ + short hdrsz; /* size of this header */ + long magic; /* magic number */ + long txtaddr; /* text address */ + long entry; /* entry point */ + long txtsz; /* text size */ + long txtoff; /* start of text in file */ + long dataddr; /* start of data segment */ + long datsz; /* size of data seg */ + long datoff; /* offset to data seg in file */ + long bsssz; /* size of bss */ + long symsz; /* size of symbol table */ + long symoff; /* offset of symbol table in file */ + long sppcsz; /* size of sp-pc table */ + long sppcoff; /* offset of sp-pc table in file */ + long lnpcsz; /* size of line number-pc table */ + long lnpcoff; /* size of line number-pc table */ +} Fhdr; + +extern int asstype; /* dissembler type - machdata.c */ +extern Machdata *machdata; /* jump vector - machdata.c */ + +Map* attachproc(int, int, int, Fhdr*); +Map* attachremt(int, Fhdr*); +int beieee80ftos(char*, int, void*); +int beieeesftos(char*, int, void*); +int beieeedftos(char*, int, void*); +ushort beswab(ushort); +long beswal(long); +vlong beswav(vlong); +int cisctrace(Map*, ulong, ulong, ulong, Tracer); +ulong ciscframe(Map*, ulong, ulong, ulong, ulong); +int crackhdr(int fd, Fhdr*); +long file2pc(char*, ulong); +int fileelem(Sym**, uchar *, char*, int); +int fileline(char*, int, ulong); +int filesym(int, char*, int); +int findlocal(Symbol*, char*, Symbol*); +int findseg(Map*, char*); +int findsym(long, int, Symbol *); +int fnbound(long, ulong*); +int fpformat(Map*, Reglist*, char*, int, int); +int get1(Map*, ulong, uchar*, int); +int get2(Map*, ulong, ushort*); +int get4(Map*, ulong, long*); +int get8(Map*, ulong, vlong*); +int getauto(Symbol*, int, int, Symbol*); +Sym* getsym(int); +int globalsym(Symbol *, int); +char* _hexify(char*, ulong, int); +int ieeesftos(char*, int, ulong); +int ieeedftos(char*, int, ulong, ulong); +int isar(Biobuf*); +int leieee80ftos(char*, int, void*); +int leieeesftos(char*, int, void*); +int leieeedftos(char*, int, void*); +ushort leswab(ushort); +long leswal(long); +vlong leswav(vlong); +long line2addr(ulong, ulong, ulong); +Map* loadmap(Map*, int, Fhdr*); +int localaddr(Map*, char*, char*, long*, Rgetter); +int localsym(Symbol*, int); +int lookup(char*, char*, Symbol*); +void machbytype(int); +int machbyname(char*); +int nextar(Biobuf*, int, char*); +Map* newmap(Map*, int); +void objtraverse(void(*)(Sym*, void*), void*); +int objtype(Biobuf*, char**); +long pc2sp(ulong); +long pc2line(ulong); +int put1(Map*, ulong, uchar*, int); +int put2(Map*, ulong, ushort); +int put4(Map*, ulong, long); +int put8(Map*, ulong, vlong); +int readar(Biobuf*, int, int, int); +int readobj(Biobuf*, int); +struct segment* reloc(Map*, ulong, long*); +ulong riscframe(Map*, ulong, ulong, ulong, ulong); +int risctrace(Map*, ulong, ulong, ulong, Tracer); +int setmap(Map*, int, ulong, ulong, ulong, char*); +void setmapio(Map*, int, Rsegio, Rsegio); +Sym* symbase(long*); +int syminit(int, Fhdr*); +int symoff(char*, int, long, int); +void textseg(ulong, Fhdr*); +int textsym(Symbol*, int); +void unusemap(Map*, int); + diff --git a/utils/libmach/machdata.c b/utils/libmach/machdata.c new file mode 100644 index 00000000..a82e14e8 --- /dev/null +++ b/utils/libmach/machdata.c @@ -0,0 +1,450 @@ +/* + * Debugger utilities shared by at least two architectures + */ + +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +#define STARTSYM "_main" +#define PROFSYM "_mainp" +#define FRAMENAME ".frame" + +extern Machdata mipsmach; + +int asstype = AMIPS; /* disassembler type */ +Machdata *machdata; /* machine-dependent functions */ + +int +localaddr(Map *map, char *fn, char *var, long *r, Rgetter rget) +{ + Symbol s; + ulong fp; + ulong pc, sp, link; + + if (!lookup(fn, 0, &s)) { + werrstr("function not found"); + return -1; + } + pc = rget(map, mach->pc); + sp = rget(map, mach->sp); + if(mach->link) + link = rget(map, mach->link); + else + link = 0; + fp = machdata->findframe(map, s.value, pc, sp, link); + if (fp == 0) { + werrstr("stack frame not found"); + return -1; + } + + if (!var || !var[0]) { + *r = fp; + return 1; + } + + if (findlocal(&s, var, &s) == 0) { + werrstr("local variable not found"); + return -1; + } + + switch (s.class) { + case CAUTO: + *r = fp - s.value; + break; + case CPARAM: /* assume address size is stack width */ + *r = fp + s.value + mach->szaddr; + break; + default: + werrstr("local variable not found: %d", s.class); + return -1; + } + return 1; +} + +/* + * Print value v as name[+offset] and then the string s. + */ +int +symoff(char *buf, int n, long v, int space) +{ + Symbol s; + int r; + long delta; + + r = delta = 0; /* to shut compiler up */ + if (v) { + r = findsym(v, space, &s); + if (r) + delta = v-s.value; + if (delta < 0) + delta = -delta; + } + if (v == 0 || r == 0) + return snprint(buf, n, "%lux", v); + if (s.type != 't' && s.type != 'T' && delta >= 4096) + return snprint(buf, n, "%lux", v); + if (strcmp(s.name, ".string") == 0) + return snprint(buf, n, "%lux", v); + if (delta) + return snprint(buf, n, "%s+%lux", s.name, v-s.value); + else + return snprint(buf, n, "%s", s.name); +} +/* + * Format floating point registers + * + * Register codes in format field: + * 'X' - print as 32-bit hexadecimal value + * 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg + * 'f' - 32-bit ieee float + * '8' - big endian 80-bit ieee extended float + * '3' - little endian 80-bit ieee extended float with hole in bytes 8&9 + */ +int +fpformat(Map *map, Reglist *rp, char *buf, int n, int modif) +{ + char reg[12]; + long r; + + switch(rp->rformat) + { + case 'X': + if (get4(map, rp->roffs, &r) < 0) + return -1; + snprint(buf, n, "%lux", r); + break; + case 'F': /* first reg of double reg pair */ + if (modif == 'F') + if (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f') { + if (get1(map, rp->roffs, (uchar *)reg, 8) < 0) + return -1; + machdata->dftos(buf, n, reg); + return 2; + } + /* treat it like 'f' */ + if (get1(map, rp->roffs, (uchar *)reg, 4) < 0) + return -1; + machdata->sftos(buf, n, reg); + break; + case 'f': /* 32 bit float */ + if (get1(map, rp->roffs, (uchar *)reg, 4) < 0) + return -1; + machdata->sftos(buf, n, reg); + break; + case '3': /* little endian ieee 80 with hole in bytes 8&9 */ + if (get1(map, rp->roffs, (uchar *)reg, 10) < 0) + return -1; + memmove(reg+10, reg+8, 2); /* open hole */ + memset(reg+8, 0, 2); /* fill it */ + leieee80ftos(buf, n, reg); + break; + case '8': /* big-endian ieee 80 */ + if (get1(map, rp->roffs, (uchar *)reg, 10) < 0) + return -1; + beieee80ftos(buf, n, reg); + break; + default: /* unknown */ + break; + } + return 1; +} + +char * +_hexify(char *buf, ulong p, int zeros) +{ + ulong d; + + d = p/16; + if(d) + buf = _hexify(buf, d, zeros-1); + else + while(zeros--) + *buf++ = '0'; + *buf++ = "0123456789abcdef"[p&0x0f]; + return buf; +} + +/* + * These routines assume that if the number is representable + * in IEEE floating point, it will be representable in the native + * double format. Naive but workable, probably. + */ +int +ieeedftos(char *buf, int n, ulong h, ulong l) +{ + double fr; + int exp; + + if (n <= 0) + return 0; + + + if(h & (1L<<31)){ + *buf++ = '-'; + h &= ~(1L<<31); + }else + *buf++ = ' '; + n--; + if(l == 0 && h == 0) + return snprint(buf, n, "0."); + exp = (h>>20) & ((1L<<11)-1L); + if(exp == 0) + return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l); + if(exp == ((1L<<11)-1L)){ + if(l==0 && (h&((1L<<20)-1L)) == 0) + return snprint(buf, n, "Inf"); + else + return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l); + } + exp -= (1L<<10) - 2L; + fr = l & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (l>>16) & ((1L<<16)-1L); + fr /= 1L<<16; + fr += (h & (1L<<20)-1L) | (1L<<20); + fr /= 1L<<21; + fr = ldexp(fr, exp); + return snprint(buf, n, "%.18g", fr); +} + +int +ieeesftos(char *buf, int n, ulong h) +{ + double fr; + int exp; + + if (n <= 0) + return 0; + + if(h & (1L<<31)){ + *buf++ = '-'; + h &= ~(1L<<31); + }else + *buf++ = ' '; + n--; + if(h == 0) + return snprint(buf, n, "0."); + exp = (h>>23) & ((1L<<8)-1L); + if(exp == 0) + return snprint(buf, n, "DeN(%.8lux)", h); + if(exp == ((1L<<8)-1L)){ + if((h&((1L<<23)-1L)) == 0) + return snprint(buf, n, "Inf"); + else + return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L)); + } + exp -= (1L<<7) - 2L; + fr = (h & ((1L<<23)-1L)) | (1L<<23); + fr /= 1L<<24; + fr = ldexp(fr, exp); + return snprint(buf, n, "%.9g", fr); +} + +int +beieeesftos(char *buf, int n, void *s) +{ + return ieeesftos(buf, n, beswal(*(ulong*)s)); +} + +int +beieeedftos(char *buf, int n, void *s) +{ + return ieeedftos(buf, n, beswal(*(ulong*)s), beswal(((ulong*)(s))[1])); +} + +int +leieeesftos(char *buf, int n, void *s) +{ + return ieeesftos(buf, n, leswal(*(ulong*)s)); +} + +int +leieeedftos(char *buf, int n, void *s) +{ + return ieeedftos(buf, n, leswal(((ulong*)(s))[1]), leswal(*(ulong*)s)); +} + +/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/ +int +beieee80ftos(char *buf, int n, void *s) +{ + uchar *reg = (uchar*)s; + int i; + ulong x; + uchar ieee[8+8]; /* room for slop */ + uchar *p, *q; + + memset(ieee, 0, sizeof(ieee)); + /* sign */ + if(reg[0] & 0x80) + ieee[0] |= 0x80; + + /* exponent */ + x = ((reg[0]&0x7F)<<8) | reg[1]; + if(x == 0) /* number is ±0 */ + goto done; + if(x == 0x7FFF){ + if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */ + x = 2047; + }else{ /* NaN */ + x = 2047; + ieee[7] = 0x1; /* make sure */ + } + ieee[0] |= x>>4; + ieee[1] |= (x&0xF)<<4; + goto done; + } + x -= 0x3FFF; /* exponent bias */ + x += 1023; + if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0)) + return snprint(buf, n, "not in range"); + ieee[0] |= x>>4; + ieee[1] |= (x&0xF)<<4; + + /* mantissa */ + p = reg+4; + q = ieee+1; + for(i=0; i<56; i+=8, p++, q++){ /* move one byte */ + x = (p[0]&0x7F) << 1; + if(p[1] & 0x80) + x |= 1; + q[0] |= x>>4; + q[1] |= (x&0xF)<<4; + } + done: + return beieeedftos(buf, n, (void*)ieee); +} + + +int +leieee80ftos(char *buf, int n, void *s) +{ + int i; + char *cp; + char b[12]; + + cp = (char*) s; + for(i=0; i<12; i++) + b[11-i] = *cp++; + return beieee80ftos(buf, n, b); +} + +int +cisctrace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace) +{ + Symbol s; + int found; + ulong opc; + long moved, j; + + USED(link); + j = 0; + opc = 0; + while(pc && opc != pc) { + moved = pc2sp(pc); + if (moved == -1) + break; + found = findsym(pc, CTEXT, &s); + if (!found) + break; + if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) + break; + + sp += moved; + opc = pc; + if (get4(map, sp, (long *)&pc) < 0) + break; + (*trace)(map, pc, sp, &s); + sp += mach->szaddr; /*assumes address size = stack width*/ + if(++j > 40) + break; + } + return j; +} + +int +risctrace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace) +{ + int i; + Symbol s, f; + ulong oldpc; + + i = 0; + while(findsym(pc, CTEXT, &s)) { + if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) + break; + + if(pc == s.value) /* at first instruction */ + f.value = 0; + else if(findlocal(&s, FRAMENAME, &f) == 0) + break; + + oldpc = pc; + if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant) + pc = link; + else + if (get4(map, sp, (long *) &pc) < 0) + break; + + if(pc == 0 || (pc == oldpc && f.value == 0)) + break; + + sp += f.value; + (*trace)(map, pc-8, sp, &s); + + if(++i > 40) + break; + } + return i; +} + +ulong +ciscframe(Map *map, ulong addr, ulong pc, ulong sp, ulong link) +{ + Symbol s; + int moved; + + USED(link); + for(;;) { + moved = pc2sp(pc); + if (moved == -1) + break; + sp += moved; + findsym(pc, CTEXT, &s); + if (addr == s.value) + return sp; + if (get4(map, sp, (long *) &pc) < 0) + break; + sp += mach->szaddr; /*assumes sizeof(addr) = stack width*/ + } + return 0; +} + +ulong +riscframe(Map *map, ulong addr, ulong pc, ulong sp, ulong link) +{ + Symbol s, f; + + while (findsym(pc, CTEXT, &s)) { + if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) + break; + + if(pc == s.value) /* at first instruction */ + f.value = 0; + else + if(findlocal(&s, FRAMENAME, &f) == 0) + break; + + sp += f.value; + if (s.value == addr) + return sp; + + if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2) + pc = link; + else + if (get4(map, sp-f.value, (long *)&pc) < 0) + break; + } + return 0; +} diff --git a/utils/libmach/map.c b/utils/libmach/map.c new file mode 100644 index 00000000..afb19b11 --- /dev/null +++ b/utils/libmach/map.c @@ -0,0 +1,203 @@ +/* + * file map routines + */ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +Map * +newmap(Map *map, int n) +{ + int size; + + size = sizeof(Map)+(n-1)*sizeof(struct segment); + if (map == 0) + map = malloc(size); + else + map = realloc(map, size); + if (map == 0) { + werrstr("out of memory: %r"); + return 0; + } + memset(map, 0, size); + map->nsegs = n; + return map; +} + +int +setmap(Map *map, int fd, ulong b, ulong e, ulong f, char *name) +{ + int i; + + if (map == 0) + return 0; + for (i = 0; i < map->nsegs; i++) + if (!map->seg[i].inuse) + break; + if (i >= map->nsegs) + return 0; + map->seg[i].b = b; + map->seg[i].e = e; + map->seg[i].f = f; + map->seg[i].inuse = 1; + map->seg[i].name = name; + map->seg[i].fd = fd; + return 1; +} + +static ulong +stacktop(int pid) +{ + char buf[64]; + int fd; + int n; + char *cp; + + sprint(buf, "/proc/%d/segment", pid); + fd = open(buf, 0); + if (fd < 0) + return 0; + n = read(fd, buf, sizeof(buf)-1); + close(fd); + buf[n] = 0; + if (strncmp(buf, "Stack", 5)) + return 0; + for (cp = buf+5; *cp && *cp == ' '; cp++) + ; + if (!*cp) + return 0; + cp = strchr(cp, ' '); + if (!cp) + return 0; + while (*cp && *cp == ' ') + cp++; + if (!*cp) + return 0; + return strtoul(cp, 0, 16); +} + +Map* +attachproc(int pid, int kflag, int corefd, Fhdr *fp) +{ + char buf[64], *regs; + int fd; + Map *map; + ulong n; + int mode; + + map = newmap(0, 4); + if (!map) + return 0; + if(kflag) { + regs = "kregs"; + mode = OREAD; + } else { + regs = "regs"; + mode = ORDWR; + } + if (mach->regsize) { + sprint(buf, "/proc/%d/%s", pid, regs); + fd = open(buf, mode); + if(fd < 0) { + free(map); + return 0; + } + setmap(map, fd, 0, mach->regsize, 0, "regs"); + } + if (mach->fpregsize) { + sprint(buf, "/proc/%d/fpregs", pid); + fd = open(buf, mode); + if(fd < 0) { + close(map->seg[0].fd); + free(map); + return 0; + } + setmap(map, fd, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs"); + } + setmap(map, corefd, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "text"); + if(kflag || (ulong) fp->dataddr >= 0x7fffffff) { + setmap(map, corefd, fp->dataddr, 0xffffffff, fp->dataddr, "data"); + return map; + } + n = stacktop(pid); + if (n == 0) { + setmap(map, corefd, fp->dataddr, 0x7fffffff, fp->dataddr, "data"); + return map; + } + setmap(map, corefd, fp->dataddr, n, fp->dataddr, "data"); + return map; +} + +int +findseg(Map *map, char *name) +{ + int i; + + if (!map) + return -1; + for (i = 0; i < map->nsegs; i++) + if (map->seg[i].inuse && !strcmp(map->seg[i].name, name)) + return i; + return -1; +} + +void +unusemap(Map *map, int i) +{ + if (map != 0 && 0 <= i && i < map->nsegs) + map->seg[i].inuse = 0; +} + +Map* +attachremt(int fd, Fhdr *f) +{ + Map *m; + ulong txt; + + m = newmap(0, 3); + if (m == 0) + return 0; + + /* Space for mach structures */ + txt = f->txtaddr; + if(txt > 8*4096) + txt -= 8*4096; + + setmap(m, fd, txt, f->txtaddr+f->txtsz, txt, "*text"); + /*setmap(m, fd, f->dataddr, 0xffffffff, f->dataddr, "*data");*/ /* pc heap is < KTZERO */ + setmap(m, fd, 4096, 0xffffffff, 4096, "*data"); + setmap(m, fd, 0x0, mach->regsize, 0, "kreg"); + + return m; +} + +Map* +loadmap(Map *map, int fd, Fhdr *fp) +{ + map = newmap(map, 2); + if (map == 0) + return 0; + + map->seg[0].b = fp->txtaddr; + map->seg[0].e = fp->txtaddr+fp->txtsz; + map->seg[0].f = fp->txtoff; + map->seg[0].fd = fd; + map->seg[0].inuse = 1; + map->seg[0].name = "text"; + map->seg[1].b = fp->dataddr; + map->seg[1].e = fp->dataddr+fp->datsz; + map->seg[1].f = fp->datoff; + map->seg[1].fd = fd; + map->seg[1].inuse = 1; + map->seg[1].name = "data"; + return map; +} + +void +setmapio(Map *map, int i, Rsegio get, Rsegio put) +{ + if (map != 0 && 0 <= i && i < map->nsegs) { + map->seg[i].mget = get; + map->seg[i].mput = put; + } +} diff --git a/utils/libmach/mkfile b/utils/libmach/mkfile new file mode 100644 index 00000000..e2747136 --- /dev/null +++ b/utils/libmach/mkfile @@ -0,0 +1,46 @@ +<../../mkconfig + +LIB=libmach.a +OFILES=\ + 2.$O\ + 4.$O\ + 5.$O\ + 6.$O\ + 8.$O\ + k.$O\ + q.$O\ + t.$O\ + v.$O\ + 2db.$O\ + 4db.$O\ + 5db.$O\ + 8db.$O\ + kdb.$O\ + qdb.$O\ + tdb.$O\ + vdb.$O\ + 2obj.$O\ + 5obj.$O\ + 6obj.$O\ + 8obj.$O\ + kobj.$O\ + qobj.$O\ + tobj.$O\ + vobj.$O\ + obj.$O\ + map.$O\ + swap.$O\ + sym.$O\ + access.$O\ + machdata.$O\ + setmach.$O\ + executable.$O\ + vcodas.$O\ + +HFILES=mach.h a.out.h bootexec.h elf.h ureg2.h ureg4.h ureg6.h ureg8.h uregk.h uregv.h ureg5.h + +<$ROOT/mkfiles/mksyslib-$SHELLTYPE +CFLAGS= $CFLAGS -I.. + +package:QV: + $TRUE diff --git a/utils/libmach/obj.c b/utils/libmach/obj.c new file mode 100644 index 00000000..39f2fad4 --- /dev/null +++ b/utils/libmach/obj.c @@ -0,0 +1,326 @@ +/* + * obj.c + * routines universal to all object files + */ +#include <lib9.h> +#include <bio.h> +#include "ar.h" +#include "mach.h" +#include "obj.h" + +#define islocal(t) ((t)=='a' || (t)=='p') + +enum +{ + NNAMES = 50, + MAXIS = 8, /* max length to determine if a file is a .? file */ + MAXOFF = 0x7fffffff, /* larger than any possible local offset */ + NHASH = 1024, /* must be power of two */ + HASHMUL = 79L, +}; + +int _is2(char*), /* in [$OS].c */ + _is5(char*), + _is6(char*), + _is8(char*), + _is9(char*), + _isk(char*), + _isq(char*), + _ist(char*), + _isv(char*), + _isx(char*), + _read2(Biobuf*, Prog*), + _read5(Biobuf*, Prog*), + _read6(Biobuf*, Prog*), + _read8(Biobuf*, Prog*), + _read9(Biobuf*, Prog*), + _readk(Biobuf*, Prog*), + _readq(Biobuf*, Prog*), + _readt(Biobuf*, Prog*), + _readv(Biobuf*, Prog*), + _readx(Biobuf*, Prog*); + +typedef struct Obj Obj; +typedef struct Symtab Symtab; + +struct Obj /* functions to handle each intermediate (.$O) file */ +{ + char *name; /* name of each $O file */ + int (*is)(char*); /* test for each type of $O file */ + int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/ +}; + +static Obj obj[] = +{ /* functions to identify and parse each type of obj */ + /*[Obj68020]*/ "68020 .2", _is2, _read2, + /*[ObjSparc]*/ "sparc .k", _isk, _readk, + /*[ObjMips]*/ "mips .v", _isv, _readv, + /*[Obj386]*/ "386 .8", _is8, _read8, + /*[Obj960]*/ "960 .6", 0, 0, + /*[Obj3210]*/ "3210 .x", 0, 0, + /*[ObjMips2]*/ "mips2 .4", 0, 0, + /*[Obj29000]*/ "29000 .9", 0, 0, + /*[ObjArm]*/ "arm .5", _is5, _read5, + /*[ObjPower]*/ "power .q", _isq, _readq, + /*[ObjMips2le]*/ "mips2 .0", 0, 0, + /*[Maxobjtype]*/ 0, 0 +}; + +struct Symtab +{ + struct Sym s; + struct Symtab *next; +}; + +static Symtab *hash[NHASH]; +static Sym *names[NNAMES]; /* working set of active names */ + +static int processprog(Prog*,int); /* decode each symbol reference */ +static void objreset(void); +static void objlookup(int, char *, int ); +static void objupdate(int, int); + +int +objtype(Biobuf *bp, char **name) +{ + int i; + char buf[MAXIS]; + + if(Bread(bp, buf, MAXIS) < MAXIS) + return -1; + Bseek(bp, -MAXIS, 1); + for (i = 0; i < Maxobjtype; i++) { + if (obj[i].is && (*obj[i].is)(buf)) { + if (name) + *name = obj[i].name; + return i; + } + } + return -1; +} + +int +isar(Biobuf *bp) +{ + int n; + char magbuf[SARMAG]; + + n = Bread(bp, magbuf, SARMAG); + if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0) + return 1; + return 0; +} + +/* + * determine what kind of object file this is and process it. + * return whether or not this was a recognized intermediate file. + */ +int +readobj(Biobuf *bp, int objtype) +{ + Prog p; + + if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0) + return 1; + objreset(); + while ((*obj[objtype].read)(bp, &p)) + if (!processprog(&p, 1)) + return 0; + return 1; +} + +int +readar(Biobuf *bp, int objtype, int end, int doautos) +{ + Prog p; + + if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0) + return 1; + objreset(); + while ((*obj[objtype].read)(bp, &p) && BOFFSET(bp) < end) + if (!processprog(&p, doautos)) + return 0; + return 1; +} + +/* + * decode a symbol reference or definition + */ +static int +processprog(Prog *p, int doautos) +{ + if(p->kind == aNone) + return 1; + if(p->sym < 0 || p->sym >= NNAMES) + return 0; + switch(p->kind) + { + case aName: + if (!doautos) + if(p->type != 'U' && p->type != 'b') + break; + objlookup(p->sym, p->id, p->type); + break; + case aText: + objupdate(p->sym, 'T'); + break; + case aData: + objupdate(p->sym, 'D'); + break; + default: + break; + } + return 1; +} + +/* + * find the entry for s in the symbol array. + * make a new entry if it is not already there. + */ +static void +objlookup(int id, char *name, int type) +{ + long h; + char *cp; + Sym *s; + Symtab *sp; + + s = names[id]; + if(s && strcmp(s->name, name) == 0) { + s->type = type; + return; + } + + h = *name; + for(cp = name+1; *cp; h += *cp++) + h *= HASHMUL; + if(h < 0) + h = ~h; + h &= (NHASH-1); + if (type == 'U' || type == 'b' || islocal(type)) { + for(sp = hash[h]; sp; sp = sp->next) + if(strcmp(sp->s.name, name) == 0) { + switch(sp->s.type) { + case 'T': + case 'D': + case 'U': + if (type == 'U') { + names[id] = &sp->s; + return; + } + break; + case 't': + case 'd': + case 'b': + if (type == 'b') { + names[id] = &sp->s; + return; + } + break; + case 'a': + case 'p': + if (islocal(type)) { + names[id] = &sp->s; + return; + } + break; + default: + break; + } + } + } + sp = malloc(sizeof(Symtab)); + sp->s.name = name; + sp->s.type = type; + sp->s.value = islocal(type) ? MAXOFF : 0; + names[id] = &sp->s; + sp->next = hash[h]; + hash[h] = sp; + return; +} +/* + * traverse the symbol lists + */ +void +objtraverse(void (*fn)(Sym*, void*), void *pointer) +{ + int i; + Symtab *s; + + for(i = 0; i < NHASH; i++) + for(s = hash[i]; s; s = s->next) + (*fn)(&s->s, pointer); +} + +/* + * update the offset information for a 'a' or 'p' symbol in an intermediate file + */ +void +_offset(int id, long off) +{ + Sym *s; + + s = names[id]; + if (s && s->name[0] && islocal(s->type) && s->value > off) + s->value = off; +} + +/* + * update the type of a global text or data symbol + */ +static void +objupdate(int id, int type) +{ + Sym *s; + + s = names[id]; + if (s && s->name[0]) + if (s->type == 'U') + s->type = type; + else if (s->type == 'b') + s->type = tolower(type); +} + +/* + * look for the next file in an archive + */ +int +nextar(Biobuf *bp, int offset, char *buf) +{ + struct ar_hdr a; + int i, r; + long arsize; + + if (offset&01) + offset++; + Bseek(bp, offset, 0); + r = Bread(bp, &a, SAR_HDR); + if(r != SAR_HDR) + return 0; + if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag))) + return -1; + for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++) + buf[i] = a.name[i]; + buf[i] = 0; + arsize = atol(a.size); + if (arsize&1) + arsize++; + return arsize + SAR_HDR; +} + +static void +objreset(void) +{ + int i; + Symtab *s, *n; + + for(i = 0; i < NHASH; i++) { + for(s = hash[i]; s; s = n) { + n = s->next; + free(s->s.name); + free(s); + } + hash[i] = 0; + } + memset(names, 0, sizeof names); +} diff --git a/utils/libmach/obj.h b/utils/libmach/obj.h new file mode 100644 index 00000000..2d2dfea6 --- /dev/null +++ b/utils/libmach/obj.h @@ -0,0 +1,24 @@ +/* + * obj.h -- defs for dealing with object files + */ + +typedef enum Kind /* variable defs and references in obj */ +{ + aNone, /* we don't care about this prog */ + aName, /* introduces a name */ + aText, /* starts a function */ + aData, /* references to a global object */ +} Kind; + +typedef struct Prog Prog; + +struct Prog /* info from .$O files */ +{ + Kind kind; /* what kind of symbol */ + char type; /* type of the symbol: ie, 'T', 'a', etc. */ + char sym; /* index of symbol's name */ + char *id; /* name for the symbol, if it introduces one */ +}; + +#define UNKNOWN '?' +void _offset(int, long); diff --git a/utils/libmach/q.c b/utils/libmach/q.c new file mode 100644 index 00000000..858882bf --- /dev/null +++ b/utils/libmach/q.c @@ -0,0 +1,122 @@ +/* + * PowerPC definition + * forsyth@terzarima.net + */ +#include <lib9.h> +#include <bio.h> +#include "uregq.h" +#include "mach.h" + + +#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x) + +#define SP REGOFF(sp) +#define PC REGOFF(pc) +#define R3 REGOFF(r3) /* return reg */ +#define LR REGOFF(lr) +#define R31 REGOFF(r31) +#define FP_REG(x) (R31+4+8*(x)) + +#define REGSIZE sizeof(struct Ureg) +#define FPREGSIZE (8*33) + +Reglist powerreglist[] = { + {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'}, + {"SRR1", REGOFF(status), RINT|RRDONLY, 'X'}, + {"PC", REGOFF(pc), RINT, 'X'}, + {"LR", REGOFF(lr), RINT, 'X'}, + {"CR", REGOFF(cr), RINT, 'X'}, + {"XER", REGOFF(xer), RINT, 'X'}, + {"CTR", REGOFF(ctr), RINT, 'X'}, + {"PC", PC, RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"R0", REGOFF(r0), RINT, 'X'}, + /* R1 is SP */ + {"R2", REGOFF(r2), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R29", REGOFF(r29), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"F0", FP_REG(0), RFLT, 'D'}, + {"F1", FP_REG(1), RFLT, 'D'}, + {"F2", FP_REG(2), RFLT, 'D'}, + {"F3", FP_REG(3), RFLT, 'D'}, + {"F4", FP_REG(4), RFLT, 'D'}, + {"F5", FP_REG(5), RFLT, 'D'}, + {"F6", FP_REG(6), RFLT, 'D'}, + {"F7", FP_REG(7), RFLT, 'D'}, + {"F8", FP_REG(8), RFLT, 'D'}, + {"F9", FP_REG(9), RFLT, 'D'}, + {"F10", FP_REG(10), RFLT, 'D'}, + {"F11", FP_REG(11), RFLT, 'D'}, + {"F12", FP_REG(12), RFLT, 'D'}, + {"F13", FP_REG(13), RFLT, 'D'}, + {"F14", FP_REG(14), RFLT, 'D'}, + {"F15", FP_REG(15), RFLT, 'D'}, + {"F16", FP_REG(16), RFLT, 'D'}, + {"F17", FP_REG(17), RFLT, 'D'}, + {"F18", FP_REG(18), RFLT, 'D'}, + {"F19", FP_REG(19), RFLT, 'D'}, + {"F20", FP_REG(20), RFLT, 'D'}, + {"F21", FP_REG(21), RFLT, 'D'}, + {"F22", FP_REG(22), RFLT, 'D'}, + {"F23", FP_REG(23), RFLT, 'D'}, + {"F24", FP_REG(24), RFLT, 'D'}, + {"F25", FP_REG(25), RFLT, 'D'}, + {"F26", FP_REG(26), RFLT, 'D'}, + {"F27", FP_REG(27), RFLT, 'D'}, + {"F28", FP_REG(28), RFLT, 'D'}, + {"F29", FP_REG(29), RFLT, 'D'}, + {"F30", FP_REG(30), RFLT, 'D'}, + {"F31", FP_REG(31), RFLT, 'D'}, + {"FPSCR", FP_REG(32)+4, RFLT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mpower = +{ + "power", + MPOWER, /* machine type */ + powerreglist, /* register set */ + REGSIZE, /* register set size in bytes */ + FPREGSIZE, /* floating point register size in bytes */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "LR", /* name of link register */ + "setSB", /* static base register name */ + 0, /* value */ + 0x1000, /* page size */ + 0x20000000, /* kernel base */ + 0, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/qdb.c b/utils/libmach/qdb.c new file mode 100644 index 00000000..f2aa682a --- /dev/null +++ b/utils/libmach/qdb.c @@ -0,0 +1,1270 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +/* + * PowerPC-specific debugger interface + * forsyth@terzarima.net + */ + +static char *powerexcep(Map*, Rgetter); +static int powerfoll(Map*, ulong, Rgetter, ulong*); +static int powerinst(Map*, ulong, char, char*, int); +static int powerinstlen(Map*, ulong); +static int powerdas(Map*, ulong, char*, int); + +/* + * Machine description + */ +Machdata powermach = +{ + {0x07f, 0xe0, 0x00, 0x08}, /* breakpoint (tw 31,r0,r0) */ + 4, /* break point size */ + + beswab, /* convert short to local byte order */ + beswal, /* convert long to local byte order */ + beswav, /* vlong to local byte order */ + risctrace, /* print C traceback */ + riscframe, /* frame finder */ + powerexcep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precisioin float printer */ + powerfoll, /* following addresses */ + powerinst, /* print instruction */ + powerdas, /* dissembler */ + powerinstlen, /* instruction size */ +}; + +static char *excname[] = +{ + "reserved 0", + "system reset", + "machine check", + "data access", + "instruction access", + "external interrupt", + "alignment", + "program exception", + "floating-point unavailable", + "decrementer", + "i/o controller interface error", + "reserved B", + "system call", + "trace trap", + "floating point assist", + "reserved", + "ITLB miss", + "DTLB load miss", + "DTLB store miss", + "instruction address breakpoint" + "SMI interrupt" + "reserved 15", + "reserved 16", + "reserved 17", + "reserved 18", + "reserved 19", + "reserved 1A", + /* the following are made up on a program exception */ + "floating point exception", /* 1B: FPEXC */ + "illegal instruction", /* 1C */ + "privileged instruction", /* 1D */ + "trap", /* 1E */ + "illegal operation", /* 1F */ + "breakpoint", /* 20 */ +}; + +static char* +powerexcep(Map *map, Rgetter rget) +{ + long c; + static char buf[32]; + + c = (*rget)(map, "CAUSE") >> 8; + if(c < nelem(excname)) + return excname[c]; + sprint(buf, "unknown trap #%lx", c); + return buf; +} + +/* + * disassemble PowerPC opcodes + */ + +#define REGSP 1 /* should come from q.out.h, but there's a clash */ +#define REGSB 2 + +static char FRAMENAME[] = ".frame"; + +static Map *mymap; + +/* + * ibm conventions for these: bit 0 is top bit + * from table 10-1 + */ +typedef struct { + uchar aa; /* bit 30 */ + uchar crba; /* bits 11-15 */ + uchar crbb; /* bits 16-20 */ + long bd; /* bits 16-29 */ + uchar crfd; /* bits 6-8 */ + uchar crfs; /* bits 11-13 */ + uchar bi; /* bits 11-15 */ + uchar bo; /* bits 6-10 */ + uchar crbd; /* bits 6-10 */ + /*union {*/ + short d; /* bits 16-31 */ + short simm; + ushort uimm; + /*};*/ + uchar fm; /* bits 7-14 */ + uchar fra; /* bits 11-15 */ + uchar frb; /* bits 16-20 */ + uchar frc; /* bits 21-25 */ + uchar frs; /* bits 6-10 */ + uchar frd; /* bits 6-10 */ + uchar crm; /* bits 12-19 */ + long li; /* bits 6-29 || b'00' */ + uchar lk; /* bit 31 */ + uchar mb; /* bits 21-25 */ + uchar me; /* bits 26-30 */ + uchar nb; /* bits 16-20 */ + uchar op; /* bits 0-5 */ + uchar oe; /* bit 21 */ + uchar ra; /* bits 11-15 */ + uchar rb; /* bits 16-20 */ + uchar rc; /* bit 31 */ + /* union {*/ + uchar rs; /* bits 6-10 */ + uchar rd; + /*};*/ + uchar sh; /* bits 16-20 */ + ushort spr; /* bits 11-20 */ + uchar to; /* bits 6-10 */ + uchar imm; /* bits 16-19 */ + ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */ + long immediate; + long w0; + long w1; + ulong addr; /* pc of instruction */ + short target; + char *curr; /* current fill level in output buffer */ + char *end; /* end of buffer */ + int size; /* number of longs in instr */ + char *err; /* errmsg */ +} Instr; + +#define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1)))) +#define IB(v,b) IBF((v),(b),(b)) + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static int +decode(ulong pc, Instr *i) +{ + long w; + + if (get4(mymap, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->aa = IB(w, 30); + i->crba = IBF(w, 11, 15); + i->crbb = IBF(w, 16, 20); + i->bd = IBF(w, 16, 29)<<2; + if(i->bd & 0x8000) + i->bd |= ~0L<<16; + i->crfd = IBF(w, 6, 8); + i->crfs = IBF(w, 11, 13); + i->bi = IBF(w, 11, 15); + i->bo = IBF(w, 6, 10); + i->crbd = IBF(w, 6, 10); + i->uimm = IBF(w, 16, 31); /* also d, simm */ + i->simm = i->uimm; + i->d = i->uimm; + i->fm = IBF(w, 7, 14); + i->fra = IBF(w, 11, 15); + i->frb = IBF(w, 16, 20); + i->frc = IBF(w, 21, 25); + i->frs = IBF(w, 6, 10); + i->frd = IBF(w, 6, 10); + i->crm = IBF(w, 12, 19); + i->li = IBF(w, 6, 29)<<2; + if(IB(w, 6)) + i->li |= ~0<<25; + i->lk = IB(w, 31); + i->mb = IBF(w, 21, 25); + i->me = IBF(w, 26, 30); + i->nb = IBF(w, 16, 20); + i->op = IBF(w, 0, 5); + i->oe = IB(w, 21); + i->ra = IBF(w, 11, 15); + i->rb = IBF(w, 16, 20); + i->rc = IB(w, 31); + i->rs = IBF(w, 6, 10); /* also rd */ + i->rd = i->rs; + i->sh = IBF(w, 16, 20); + i->spr = IBF(w, 11, 20); + i->to = IBF(w, 6, 10); + i->imm = IBF(w, 16, 19); + i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */ + i->immediate = i->simm; + if(i->op == 15) + i->immediate <<= 16; + i->w0 = w; + i->target = -1; + i->addr = pc; + i->size = 1; + return 1; +} + +static int +mkinstr(ulong pc, Instr *i) +{ + Instr x; + + if(decode(pc, i) < 0) + return -1; + /* + * combine ADDIS/ORI (CAU/ORIL) into MOVW + */ + if (i->op == 15 && i->ra==0) { + if(decode(pc+4, &x) < 0) + return -1; + if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) { + i->immediate |= (x.immediate & 0xFFFF); + i->w1 = x.w0; + i->target = x.rd; + i->size++; + return 1; + } + } + if (i->op == 15 && i->ra==REGSB && mach->sb) { + if(decode(pc+4, &x) < 0) + return -1; + if (x.op >= 32 && x.op < 54 && i->rd == x.ra) { + i->op = x.op; + i->ra = REGSB; + i->rs = i->rd = x.rd; + i->immediate += x.simm; + i->w1 = x.w0; + i->target = x.rd; + i->size++; + return 1; + } + } + return 1; +} + +static int +plocal(Instr *i) +{ + int offset; + Symbol s; + + if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) + return -1; + offset = s.value - i->immediate; + if (offset > 0) { + if(getauto(&s, offset, CAUTO, &s)) { + bprint(i, "%s+%d(SP)", s.name, s.value); + return 1; + } + } else { + if (getauto(&s, -offset-4, CPARAM, &s)) { + bprint(i, "%s+%d(FP)", s.name, -offset); + return 1; + } + } + return -1; +} + +static int +pglobal(Instr *i, long off, int anyoff, char *reg) +{ + Symbol s, s2; + long off1; + + if(findsym(off, CANY, &s) && + strcmp(s.name, ".string") != 0 && + (ulong)(off-s.value) < 4096 && + (s.class == CDATA || s.class == CTEXT)) { + if(off==s.value && s.name[0]=='$'){ + off1 = 0; + get4(mymap, s.value, &off1); + if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ + bprint(i, "$%s%s", s2.name, reg); + return 1; + } + } + bprint(i, "%s", s.name); + if (s.value != off) + bprint(i, "+%lux", off-s.value); + bprint(i, reg); + return 1; + } + if(!anyoff) + return 0; + bprint(i, "%lux%s", off, reg); + return 1; +} + +static void +address(Instr *i) +{ + if (i->ra == REGSP && plocal(i) >= 0) + return; + if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") > 0) + return; + if(i->immediate < 0) + bprint(i, "-%lx", -i->immediate); + else + bprint(i, "%lux", i->immediate); + if (i->ra == REGSB && mach->sb) + bprint(i, "(SB)"); + else + bprint(i, "(R%d)", i->ra); +} + +static char *tcrbits[] = {"LT", "GT", "EQ", "VS"}; +static char *fcrbits[] = {"GE", "LE", "NE", "VC"}; + +typedef struct Opcode Opcode; + +struct Opcode { + uchar op; + ushort xo; + ushort xomask; + char *mnemonic; + void (*f)(Opcode *, Instr *); + char *ken; + int flags; +}; + +static void format(char *, Instr *, char *); + +static void +branch(Opcode *o, Instr *i) +{ + char buf[8]; + int bo, bi; + + bo = i->bo & ~1; /* ignore prediction bit */ + if(bo==4 || bo==12 || bo==20) { /* simple forms */ + if(bo != 20) { + bi = i->bi&3; + sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]); + format(buf, i, 0); + bprint(i, "\t"); + if(i->bi > 4) + bprint(i, "CR(%d),", i->bi/4); + } else + format("BR%L\t", i, 0); + if(i->op == 16) + format(0, i, "%J"); + else if(i->op == 19 && i->xo == 528) + format(0, i, "(CTR)"); + else if(i->op == 19 && i->xo == 16) + format(0, i, "(LR)"); + } else + format(o->mnemonic, i, o->ken); +} + +static void +addi(Opcode *o, Instr *i) +{ + if (i->op==14 && i->ra == 0) + format("MOVW", i, "%i,R%d"); + else if (i->ra == REGSP || i->ra == REGSB) { + bprint(i, "MOVW\t$"); + address(i); + bprint(i, ",R%d", i->rd); + } else if(i->op==14 && i->simm < 0) { + bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra); + if(i->rd != i->ra) + bprint(i, ",R%d", i->rd); + } else if(i->ra == i->rd) { + format(o->mnemonic, i, "%i"); + bprint(i, ",R%d", i->rd); + } else + format(o->mnemonic, i, o->ken); +} + +static void +addis(Opcode *o, Instr *i) +{ + long v; + + v = i->immediate; + if (i->op==15 && i->ra == 0) { + bprint(i, "MOVW\t$"); + pglobal(i, i->immediate, 1, ""); + bprint(i, ",R%d", i->rd); + } + else if (i->op==15 && i->ra == REGSB && mach->sb) { + bprint(i, "MOVW\t$"); + address(i); + bprint(i, ",R%d", i->rd); +/* how about auto/param addresses? */ + } else if(i->op==15 && v < 0) { + bprint(i, "SUB\t$%d,R%d", -v, i->ra); + if(i->rd != i->ra) + bprint(i, ",R%d", i->rd); + } else { + format(o->mnemonic, i, 0); + bprint(i, "\t$%ld,R%d", v, i->ra); + if(i->rd != i->ra) + bprint(i, ",R%d", i->rd); + } +} + +static void +andi(Opcode *o, Instr *i) +{ + if (i->ra == i->rs) + format(o->mnemonic, i, "%I,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +gencc(Opcode *o, Instr *i) +{ + format(o->mnemonic, i, o->ken); +} + +static void +gen(Opcode *o, Instr *i) +{ + format(o->mnemonic, i, o->ken); + if (i->rc) + bprint(i, " [illegal Rc]"); +} + +static void +ldx(Opcode *o, Instr *i) +{ + if(i->ra == 0) + format(o->mnemonic, i, "(R%b),R%d"); + else + format(o->mnemonic, i, "(R%b+R%a),R%d"); + if(i->rc) + bprint(i, " [illegal Rc]"); +} + +static void +stx(Opcode *o, Instr *i) +{ + if(i->ra == 0) + format(o->mnemonic, i, "R%d,(R%b)"); + else + format(o->mnemonic, i, "R%d,(R%b+R%a)"); + if(i->rc && i->xo != 150) + bprint(i, " [illegal Rc]"); +} + +static void +fldx(Opcode *o, Instr *i) +{ + if(i->ra == 0) + format(o->mnemonic, i, "(R%b),F%d"); + else + format(o->mnemonic, i, "(R%b+R%a),F%d"); + if(i->rc) + bprint(i, " [illegal Rc]"); +} + +static void +fstx(Opcode *o, Instr *i) +{ + if(i->ra == 0) + format(o->mnemonic, i, "F%d,(R%b)"); + else + format(o->mnemonic, i, "F%d,(R%b+R%a)"); + if(i->rc) + bprint(i, " [illegal Rc]"); +} + +static void +dcb(Opcode *o, Instr *i) +{ + if(i->ra == 0) + format(o->mnemonic, i, "(R%b)"); + else + format(o->mnemonic, i, "(R%b+R%a)"); + if(i->rd) + bprint(i, " [illegal Rd]"); + if(i->rc) + bprint(i, " [illegal Rc]"); +} + +static void +lw(Opcode *o, Instr *i, char r) +{ + bprint(i, "%s\t", o->mnemonic); + address(i); + bprint(i, ",%c%d", r, i->rd); +} + +static void +load(Opcode *o, Instr *i) +{ + lw(o, i, 'R'); +} + +static void +fload(Opcode *o, Instr *i) +{ + lw(o, i, 'F'); +} + +static void +sw(Opcode *o, Instr *i, char r) +{ + int offset; + char *m; + Symbol s; + + m = o->mnemonic; + if (i->ra == REGSP) { + if (findsym(i->addr, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) { + offset = s.value-i->immediate; + if (offset > 0 && getauto(&s, offset, CAUTO, &s)) { + bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rs, + s.name, offset); + return; + } + } + } + if (i->ra == REGSP || i->ra == REGSB && mach->sb) { + bprint(i, "%s\t%c%d,", m, r, i->rs); + address(i); + return; + } + if (r == 'F') + format(m, i, "F%d,%l"); + else + format(m, i, o->ken); +} + +static void +store(Opcode *o, Instr *i) +{ + sw(o, i, 'R'); +} + +static void +fstore(Opcode *o, Instr *i) +{ + sw(o, i, 'F'); +} + +static void +shifti(Opcode *o, Instr *i) +{ + if (i->ra == i->rs) + format(o->mnemonic, i, "$%k,R%a"); + else + format(o->mnemonic, i, o->ken); +} + +static void +shift(Opcode *o, Instr *i) +{ + if (i->ra == i->rs) + format(o->mnemonic, i, "R%b,R%a"); + else + format(o->mnemonic, i, o->ken); +} + +static void +add(Opcode *o, Instr *i) +{ + if (i->rd == i->ra) + format(o->mnemonic, i, "R%b,R%d"); + else if (i->rd == i->rb) + format(o->mnemonic, i, "R%a,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sub(Opcode *o, Instr *i) +{ + format(o->mnemonic, i, 0); + if(i->op == 31) { + bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */ + if(i->rd != i->rb) + bprint(i, ",R%d", i->rd); + } else + bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd); +} + +static void +qdiv(Opcode *o, Instr *i) +{ + format(o->mnemonic, i, 0); + if(i->op == 31) + bprint(i, "\tR%d,R%d", i->rb, i->ra); + else + bprint(i, "\t$%d,R%d", i->simm, i->ra); + if(i->ra != i->rd) + bprint(i, ",R%d", i->rd); +} + +static void +and(Opcode *o, Instr *i) +{ + if (i->op == 31) { + /* Rb,Rs,Ra */ + if (i->ra == i->rs) + format(o->mnemonic, i, "R%b,R%a"); + else if (i->ra == i->rb) + format(o->mnemonic, i, "R%s,R%a"); + else + format(o->mnemonic, i, o->ken); + } else { + /* imm,Rs,Ra */ + if (i->ra == i->rs) + format(o->mnemonic, i, "%I,R%a"); + else + format(o->mnemonic, i, o->ken); + } +} + +static void +or(Opcode *o, Instr *i) +{ + if (i->op == 31) { + /* Rb,Rs,Ra */ + if (i->rs == 0 && i->ra == 0 && i->rb == 0) + format("NOP", i, 0); + else if (i->rs == i->rb) + format("MOVW", i, "R%b,R%a"); + else + and(o, i); + } else + and(o, i); +} + +static void +shifted(Opcode *o, Instr *i) +{ + format(o->mnemonic, i, 0); + bprint(i, "\t$%lux,", (ulong)i->uimm<<16); + if (i->rs == i->ra) + bprint(i, "R%d", i->ra); + else + bprint(i, "R%d,R%d", i->rs, i->ra); +} + +static void +neg(Opcode *o, Instr *i) +{ + if (i->rd == i->ra) + format(o->mnemonic, i, "R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static char ir2[] = "R%a,R%d"; /* reverse of IBM order */ +static char ir3[] = "R%b,R%a,R%d"; +static char ir3r[] = "R%a,R%b,R%d"; +static char il3[] = "R%b,R%s,R%a"; +static char il2u[] = "%I,R%s,R%a"; +static char il3s[] = "$%k,R%s,R%a"; +static char il2[] = "R%s,R%a"; +static char icmp3[] = "R%a,R%b,%D"; +static char cr3op[] = "%b,%a,%d"; +static char ir2i[] = "%i,R%a,R%d"; +static char fp2[] = "F%b,F%d"; +static char fp3[] = "F%b,F%a,F%d"; +static char fp3c[] = "F%c,F%a,F%d"; +static char fp4[] = "F%a,F%c,F%b,F%d"; +static char fpcmp[] = "F%a,F%b,%D"; +static char ldop[] = "%l,R%d"; +static char stop[] = "R%d,%l"; +static char fldop[] = "%l,F%d"; +static char fstop[] = "F%d,%l"; +static char rlim[] = "R%b,R%s,$%z,R%a"; +static char rlimi[] = "$%k,R%s,$%z,R%a"; + +#define OEM IBF(~0,22,30) +#define FP4 IBF(~0,26,30) +#define ALL ((ushort)~0) +/* +notes: + 10-26: crfD = rD>>2; rD&3 mbz + also, L bit (bit 10) mbz or selects 64-bit operands +*/ + +static Opcode opcodes[] = { + {31, 360, OEM, "ABS%V%C", 0, ir2}, /* POWER */ + + {31, 266, OEM, "ADD%V%C", add, ir3}, + {31, 10, OEM, "ADDC%V%C", add, ir3}, + {31, 138, OEM, "ADDE%V%C", add, ir3}, + {14, 0, 0, "ADD", addi, ir2i}, + {12, 0, 0, "ADDC", addi, ir2i}, + {13, 0, 0, "ADDCCC", addi, ir2i}, + {15, 0, 0, "ADD", addis, 0}, + {31, 234, OEM, "ADDME%V%C", gencc, ir2}, + {31, 202, OEM, "ADDZE%V%C", gencc, ir2}, + + {31, 28, ALL, "AND%C", and, il3}, + {31, 60, ALL, "ANDN%C", and, il3}, + {28, 0, 0, "ANDCC", andi, il2u}, + {29, 0, 0, "ANDCC", shifted, 0}, + + {18, 0, 0, "B%L", gencc, "%j"}, + {16, 0, 0, "BC%L", branch, "%d,%a,%J"}, + {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"}, + {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"}, + + {31, 531, ALL, "CLCS", gen, ir2}, /* POWER */ + + {31, 0, ALL, "CMP", 0, icmp3}, + {11, 0, 0, "CMP", 0, "R%a,%i,%D"}, + {31, 32, ALL, "CMPU", 0, icmp3}, + {10, 0, 0, "CMPU", 0, "R%a,%I,%D"}, + + {31, 26, ALL, "CNTLZ%C", gencc, ir2}, + + {19, 257, ALL, "CRAND", gen, cr3op}, + {19, 129, ALL, "CRANDN", gen, cr3op}, + {19, 289, ALL, "CREQV", gen, cr3op}, + {19, 225, ALL, "CRNAND", gen, cr3op}, + {19, 33, ALL, "CRNOR", gen, cr3op}, + {19, 449, ALL, "CROR", gen, cr3op}, + {19, 417, ALL, "CRORN", gen, cr3op}, + {19, 193, ALL, "CRXOR", gen, cr3op}, + + {31, 86, ALL, "DCBF", dcb, 0}, + {31, 470, ALL, "DCBI", dcb, 0}, + {31, 54, ALL, "DCBST", dcb, 0}, + {31, 278, ALL, "DCBT", dcb, 0}, + {31, 246, ALL, "DCBTST", dcb, 0}, + {31, 1014, ALL, "DCBZ", dcb, 0}, + + {31, 331, OEM, "DIV%V%C", qdiv, ir3}, /* POWER */ + {31, 363, OEM, "DIVS%V%C", qdiv, ir3}, /* POWER */ + {31, 491, OEM, "DIVW%V%C", qdiv, ir3}, + {31, 459, OEM, "DIVWU%V%C", qdiv, ir3}, + + {31, 264, OEM, "DOZ%V%C", gencc, ir3r}, /* POWER */ + {9, 0, 0, "DOZ", gen, ir2i}, /* POWER */ + + {31, 310, ALL, "ECIWX", ldx, 0}, + {31, 438, ALL, "ECOWX", stx, 0}, + {31, 854, ALL, "EIEIO", gen, 0}, + + {31, 284, ALL, "EQV%C", gencc, il3}, + + {31, 954, ALL, "EXTSB%C", gencc, il2}, + {31, 922, ALL, "EXTSH%C", gencc, il2}, + + {63, 264, ALL, "FABS%C", gencc, fp2}, + {63, 21, ALL, "FADD%C", gencc, fp3}, + {59, 21, ALL, "FADDS%C", gencc, fp3}, + {63, 32, ALL, "FCMPO", gen, fpcmp}, + {63, 0, ALL, "FCMPU", gen, fpcmp}, + {63, 14, ALL, "FCTIW%C", gencc, fp2}, + {63, 15, ALL, "FCTIWZ%C", gencc, fp2}, + {63, 18, ALL, "FDIV%C", gencc, fp3}, + {59, 18, ALL, "FDIVS%C", gencc, fp3}, + {63, 29, FP4, "FMADD%C", gencc, fp4}, + {59, 29, FP4, "FMADDS%C", gencc, fp4}, + {63, 72, ALL, "FMOVD%C", gencc, fp2}, + {63, 28, FP4, "FMSUB%C", gencc, fp4}, + {59, 28, FP4, "FMSUBS%C", gencc, fp4}, + {63, 25, FP4, "FMUL%C", gencc, fp3c}, + {59, 25, FP4, "FMULS%C", gencc, fp3c}, + {63, 136, ALL, "FNABS%C", gencc, fp2}, + {63, 40, ALL, "FNEG%C", gencc, fp2}, + {63, 31, FP4, "FNMADD%C", gencc, fp4}, + {59, 31, FP4, "FNMADDS%C", gencc, fp4}, + {63, 30, FP4, "FNMSUB%C", gencc, fp4}, + {59, 30, FP4, "FNMSUBS%C", gencc, fp4}, + {63, 12, ALL, "FRSP%C", gencc, fp2}, + {63, 20, FP4, "FSUB%C", gencc, fp3}, + {59, 20, FP4, "FSUBS%C", gencc, fp3}, + + {31, 982, ALL, "ICBI", dcb, 0}, + {19, 150, ALL, "ISYNC", gen, 0}, + + {34, 0, 0, "MOVBZ", load, ldop}, + {35, 0, 0, "MOVBZU", load, ldop}, + {31, 119, ALL, "MOVBZU", ldx, 0}, + {31, 87, ALL, "MOVBZ", ldx, 0}, + {50, 0, 0, "FMOVD", fload, fldop}, + {51, 0, 0, "FMOVDU", fload, fldop}, + {31, 631, ALL, "FMOVDU", fldx, 0}, + {31, 599, ALL, "FMOVD", fldx, 0}, + {48, 0, 0, "FMOVS", load, fldop}, + {49, 0, 0, "FMOVSU", load, fldop}, + {31, 567, ALL, "FMOVSU", fldx, 0}, + {31, 535, ALL, "FMOVS", fldx, 0}, + {42, 0, 0, "MOVH", load, ldop}, + {43, 0, 0, "MOVHU", load, ldop}, + {31, 375, ALL, "MOVHU", ldx, 0}, + {31, 343, ALL, "MOVH", ldx, 0}, + {31, 790, ALL, "MOVHBR", ldx, 0}, + {40, 0, 0, "MOVHZ", load, ldop}, + {41, 0, 0, "MOVHZU", load, ldop}, + {31, 311, ALL, "MOVHZU", ldx, 0}, + {31, 279, ALL, "MOVHZ", ldx, 0}, + {46, 0, 0, "MOVMW", load, ldop}, + {31, 277, ALL, "LSCBX%C", ldx, 0}, /* POWER */ + {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"}, + {31, 533, ALL, "LSW", ldx, 0}, + {31, 20, ALL, "LWAR", ldx, 0}, + {31, 534, ALL, "MOVWBR", ldx, 0}, + {32, 0, 0, "MOVW", load, ldop}, + {33, 0, 0, "MOVWU", load, ldop}, + {31, 55, ALL, "MOVWU", ldx, 0}, + {31, 23, ALL, "MOVW", ldx, 0}, + + {31, 29, ALL, "MASKG%C", gencc, "R%s:R%b,R%d"}, /* POWER */ + {31, 541, ALL, "MASKIR%C", gencc, "R%s,R%b,R%a"}, /* POWER */ + + {19, 0, ALL, "MOVFL", gen, "%S,%D"}, + {63, 64, ALL, "MOVCRFS", gen, "%S,%D"}, + {31, 512, ALL, "MOVW", gen, "XER,%D"}, + {31, 19, ALL, "MOVW", gen, "CR,R%d"}, + + {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */ + {31, 83, ALL, "MOVW", gen, "MSR,R%d"}, + {31, 339, ALL, "MOVW", gen, "%P,R%d"}, + {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"}, + {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"}, + {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"}, + {63, 70, ALL, "MTFSB0%C", gencc, "%D"}, + {63, 38, ALL, "MTFSB1%C", gencc, "%D"}, + {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */ + {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"}, + {31, 146, ALL, "MOVW", gen, "R%s,MSR"}, + {31, 467, ALL, "MOVW", gen, "R%s,%P"}, + {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"}, + {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"}, + + {31, 107, OEM, "MUL%V%C", gencc, ir3}, /* POWER */ + {31, 75, ALL, "MULHW%C", gencc, ir3}, /* POWER */ + {31, 11, ALL, "MULHWU%C", gencc, ir3}, /* POWER */ + + {31, 235, OEM, "MULLW%V%C", gencc, ir3}, + {7, 0, 0, "MULLW", qdiv, "%i,R%a,R%d"}, + + {31, 488, OEM, "NABS%V%C", neg, ir2}, /* POWER */ + + {31, 476, ALL, "NAND%C", gencc, il3}, + {31, 104, OEM, "NEG%V%C", neg, ir2}, + {31, 124, ALL, "NOR%C", gencc, il3}, + {31, 444, ALL, "OR%C", or, il3}, + {31, 412, ALL, "ORN%C", or, il3}, + {24, 0, 0, "OR", and, "%I,R%d,R%a"}, + {25, 0, 0, "OR", shifted, 0}, + + {19, 50, ALL, "RFI", gen, 0}, + + {22, 0, 0, "RLMI%C", gencc, rlim}, /* POWER */ + {20, 0, 0, "RLWMI%C", gencc, rlimi}, + {21, 0, 0, "RLWNM%C", gencc, rlimi}, + {23, 0, 0, "RLWNM%C", gencc, rlim}, + + {31, 537, ALL, "RRIB%C", gencc, il3}, /* POWER */ + + {17, 1, ALL, "SYSCALL", gen, 0}, + + {31, 153, ALL, "SLE%C", shift, il3}, /* POWER */ + {31, 217, ALL, "SLEQ%C", shift, il3}, /* POWER */ + {31, 184, ALL, "SLQ%C", shifti, il3s}, /* POWER */ + {31, 248, ALL, "SLLQ%C", shifti, il3s}, /* POWER */ + {31, 216, ALL, "SLLQ%C", shift, il3}, /* POWER */ + {31, 152, ALL, "SLQ%C", shift, il3}, /* POWER */ + + {31, 24, ALL, "SLW%C", shift, il3}, + + {31, 920, ALL, "SRAQ%C", shift, il3}, /* POWER */ + {31, 952, ALL, "SRAQ%C", shifti, il3s}, /* POWER */ + + {31, 792, ALL, "SRAW%C", shift, il3}, + {31, 824, ALL, "SRAW%C", shifti, il3s}, + + {31, 665, ALL, "SRE%C", shift, il3}, /* POWER */ + {31, 921, ALL, "SREA%C", shift, il3}, /* POWER */ + {31, 729, ALL, "SREQ%C", shift, il3}, /* POWER */ + {31, 696, ALL, "SRQ%C", shifti, il3s}, /* POWER */ + {31, 760, ALL, "SRLQ%C", shifti, il3s}, /* POWER */ + {31, 728, ALL, "SRLQ%C", shift, il3}, /* POWER */ + {31, 664, ALL, "SRQ%C", shift, il3}, /* POWER */ + + {31, 536, ALL, "SRW%C", shift, il3}, + + {38, 0, 0, "MOVB", store, stop}, + {39, 0, 0, "MOVBU", store, stop}, + {31, 247, ALL, "MOVBU", stx, 0}, + {31, 215, ALL, "MOVB", stx, 0}, + {54, 0, 0, "FMOVD", fstore, fstop}, + {55, 0, 0, "FMOVDU", fstore, fstop}, + {31, 759, ALL, "FMOVDU", fstx, 0}, + {31, 727, ALL, "FMOVD", fstx, 0}, + {52, 0, 0, "FMOVS", fstore, fstop}, + {53, 0, 0, "FMOVSU", fstore, fstop}, + {31, 695, ALL, "FMOVSU", fstx, 0}, + {31, 663, ALL, "FMOVS", fstx, 0}, + {44, 0, 0, "MOVH", store, stop}, + {31, 918, ALL, "MOVHBR", stx, 0}, + {45, 0, 0, "MOVHU", store, stop}, + {31, 439, ALL, "MOVHU", stx, 0}, + {31, 407, ALL, "MOVH", stx, 0}, + {47, 0, 0, "MOVMW", store, stop}, + {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"}, + {31, 661, ALL, "STSW", stx, 0}, + {36, 0, 0, "MOVW", store, stop}, + {31, 662, ALL, "MOVWBR", stx, 0}, + {31, 150, ALL, "STWCCC", stx, 0}, + {37, 0, 0, "MOVWU", store, stop}, + {31, 183, ALL, "MOVWU", stx, 0}, + {31, 151, ALL, "MOVW", stx, 0}, + + {31, 40, OEM, "SUB%V%C", sub, ir3}, + {31, 8, OEM, "SUBC%V%C", sub, ir3}, + {31, 136, OEM, "SUBE%V%C", sub, ir3}, + {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"}, + {31, 232, OEM, "SUBME%V%C", sub, ir2}, + {31, 200, OEM, "SUBZE%V%C", sub, ir2}, + + {31, 598, ALL, "SYNC", gen, 0}, + {31, 306, ALL, "TLBIE", gen, "R%b"}, + {31, 370, ALL, "TLBIA", gen, 0}, + {31, 1010, ALL, "TLBLI", gen, "R%b"}, + {31, 978, ALL, "TLBLD", gen, "R%b"}, + {31, 4, ALL, "TW", gen, "%d,R%a,R%b"}, + {3, 0, 0, "TW", gen, "%d,R%a,%i"}, + + {31, 316, ALL, "XOR", and, il3}, + {26, 0, 0, "XOR", and, il2u}, + {27, 0, 0, "XOR", shifted, 0}, + + {0}, +}; + +typedef struct Spr Spr; +struct Spr { + int n; + char *name; +}; + +static Spr sprname[] = { + {0, "MQ"}, + {1, "XER"}, + {268, "TBL"}, + {269, "TBU"}, + {8, "LR"}, + {9, "CTR"}, + {528, "IBAT0U"}, + {529, "IBAT0L"}, + {530, "IBAT1U"}, + {531, "IBAT1L"}, + {532, "IBAT2U"}, + {533, "IBAT2L"}, + {534, "IBAT3U"}, + {535, "IBAT3L"}, + {536, "DBAT0U"}, + {537, "DBAT0L"}, + {538, "DBAT1U"}, + {539, "DBAT1L"}, + {540, "DBAT2U"}, + {541, "DBAT2L"}, + {542, "DBAT3U"}, + {543, "DBAT3L"}, + {25, "SDR1"}, + {19, "DAR"}, + {272, "SPRG0"}, + {273, "SPRG1"}, + {274, "SPRG2"}, + {275, "SPRG3"}, + {18, "DSISR"}, + {26, "SRR0"}, + {27, "SRR1"}, + {284, "TBLW"}, + {285, "TBUW"}, + {22, "DEC"}, + {282, "EAR"}, + {1008, "HID0"}, + {1009, "HID1"}, + {976, "DMISS"}, + {977, "DCMP"}, + {978, "HASH1"}, + {979, "HASH2"}, + {980, "IMISS"}, + {981, "ICMP"}, + {982, "RPA"}, + {1010, "IABR"}, + {1013, "DABR"}, + {0,0}, +}; + +static void +format(char *mnemonic, Instr *i, char *f) +{ + int n, s; + ulong mask; + + if (mnemonic) + format(0, i, mnemonic); + if (f == 0) + return; + if (mnemonic) + bprint(i, "\t"); + for ( ; *f; f++) { + if (*f != '%') { + bprint(i, "%c", *f); + continue; + } + switch (*++f) { + case 'V': + if(i->oe) + bprint(i, "V"); + break; + + case 'C': + if(i->rc) + bprint(i, "CC"); + break; + + case 'a': + bprint(i, "%d", i->ra); + break; + + case 'b': + bprint(i, "%d", i->rb); + break; + + case 'c': + bprint(i, "%d", i->frc); + break; + + case 'd': + case 's': + bprint(i, "%d", i->rd); + break; + + case 'S': + if(i->ra & 3) + bprint(i, "CR(INVAL:%d)", i->ra); + else if(i->op == 63) + bprint(i, "FPSCR(%d)", i->crfs); + else + bprint(i, "CR(%d)", i->crfs); + break; + + case 'D': + if(i->rd & 3) + bprint(i, "CR(INVAL:%d)", i->rd); + else if(i->op == 63) + bprint(i, "FPSCR(%d)", i->crfd); + else + bprint(i, "CR(%d)", i->crfd); + break; + + case 'l': + address(i); + break; + + case 'i': + bprint(i, "$%ld", i->simm); + break; + + case 'I': + bprint(i, "$%lx", i->uimm); + break; + + case 'w': + bprint(i, "[%lux]", i->w0); + break; + + case 'P': + n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f); + for(s=0; sprname[s].name; s++) + if(sprname[s].n == n) + break; + if(sprname[s].name) { + if(n < 10) + bprint(i, sprname[s].name); + else + bprint(i, "SPR(%s)", sprname[s].name); + } else + bprint(i, "SPR(%d)", n); + break; + + case 'n': + bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */ + break; + + case 'm': + bprint(i, "%lx", i->crm); + break; + + case 'M': + bprint(i, "%lx", i->fm); + break; + + case 'z': + if(i->mb <= i->me) + mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me)); + else + mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1)))); + bprint(i, "%lux", mask); + break; + + case 'k': + bprint(i, "%d", i->sh); + break; + + case 'K': + bprint(i, "$%x", i->imm); + break; + + case 'L': + if(i->lk) + bprint(i, "L"); + break; + + case 'j': + if(i->aa) + pglobal(i, i->li, 1, "(SB)"); + else + pglobal(i, i->addr+i->li, 1, ""); + break; + + case 'J': + if(i->aa) + pglobal(i, i->bd, 1, "(SB)"); + else + pglobal(i, i->addr+i->bd, 1, ""); + break; + + case '\0': + bprint(i, "%%"); + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + Opcode *o; + + mymap = map; + memset(&i, 0, sizeof(i)); + i.curr = buf; + i.end = buf+n-1; + if(mkinstr(pc, &i) < 0) + return -1; + for(o = opcodes; o->mnemonic != 0; o++) + if(i.op == o->op && (i.xo & o->xomask) == o->xo) { + if (o->f) + (*o->f)(o, &i); + else + format(o->mnemonic, &i, o->ken); + return i.size*4; + } + bprint(&i, "unknown %lux", i.w0); + return i.size*4; +} + +static int +powerinst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + USED(modifier); + return printins(map, pc, buf, n); +} + +static int +powerdas(Map *map, ulong pc, char *buf, int n) +{ + Instr instr; + + mymap = map; + memset(&instr, 0, sizeof(instr)); + instr.curr = buf; + instr.end = buf+n-1; + if (mkinstr(pc, &instr) < 0) + return -1; + if (instr.end-instr.curr > 8) + instr.curr = _hexify(instr.curr, instr.w0, 7); + if (instr.end-instr.curr > 9 && instr.size == 2) { + *instr.curr++ = ' '; + instr.curr = _hexify(instr.curr, instr.w1, 7); + } + *instr.curr = 0; + return instr.size*4; +} + +static int +powerinstlen(Map *map, ulong pc) +{ + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + return i.size*4; +} + +static int +powerfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + char *reg; + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + foll[0] = pc+4; + foll[1] = pc+4; + switch(i.op) { + default: + return 1; + + case 18: /* branch */ + foll[0] = i.li; + if(!i.aa) + foll[0] += pc; + break; + + case 16: /* conditional branch */ + foll[0] = i.bd; + if(!i.aa) + foll[0] += pc; + break; + + case 19: /* conditional branch to register */ + if(i.xo == 528) + reg = "CTR"; + else if(i.xo == 16) + reg = "LR"; + else + return 1; /* not a branch */ + foll[0] = (*rget)(map, reg); + break; + } + if(i.lk) + return 2; + return 1; +} diff --git a/utils/libmach/qobj.c b/utils/libmach/qobj.c new file mode 100644 index 00000000..5decad08 --- /dev/null +++ b/utils/libmach/qobj.c @@ -0,0 +1,134 @@ +/* + * qobj.c - identify and parse a PowerPC object file + * forsyth@terzarima.net + */ +#include <lib9.h> +#include <bio.h> +#include "qc/q.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_isq(char *s) +{ + return (s[0]&0377) == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + +int +_readq(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + n = Bgetc(bp); /* reg and flag */ + skip(bp, 4); /* lineno(4) */ + a = addr(bp); + if(n & 0x40) + addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: case D_REG: case D_FREG: case D_CREG: + case D_FPSCR: case D_MSR: case D_SREG: + break; + case D_SPR: + case D_OREG: + case D_CONST: + case D_BRANCH: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/setmach.c b/utils/libmach/setmach.c new file mode 100644 index 00000000..cdac45f6 --- /dev/null +++ b/utils/libmach/setmach.c @@ -0,0 +1,143 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + /* table for selecting machine-dependent parameters */ + +typedef struct machtab Machtab; + +struct machtab +{ + char *name; /* machine name */ + short type; /* executable type */ + short boottype; /* bootable type */ + int asstype; /* disassembler code */ + Mach *mach; /* machine description */ + Machdata *machdata; /* machine functions */ +}; + +extern Mach mmips, msparc, m68020, mi386, marm, mmips2be, mmips2le, mpower; +extern Machdata mipsmach, sparcmach, m68020mach, i386mach, + armmach, mipsmach2be, mipsmach2le, powermach; + +/* + * machine selection table. machines with native disassemblers should + * follow the plan 9 variant in the table; native modes are selectable + * only by name. + */ +Machtab machines[] = +{ + { "68020", /*68020*/ + F68020, + F68020B, + A68020, + &m68020, + &m68020mach, }, + { "68020", /*Next 68040 bootable*/ + F68020, + FNEXTB, + A68020, + &m68020, + &m68020mach, }, + { "mips2LE", /*plan 9 mips2 little endian*/ + FMIPS2LE, + 0, + AMIPS, + &mmips2le, + &mipsmach2le, }, + { "mips", /*plan 9 mips*/ + FMIPS, + FMIPSB, + AMIPS, + &mmips, + &mipsmach, }, + { "mips2", /*plan 9 mips2*/ + FMIPS2BE, + FMIPSB, + AMIPS, + &mmips2be, + &mipsmach2be, }, + { "mipsco", /*native mips - must follow plan 9*/ + FMIPS, + FMIPSB, + AMIPSCO, + &mmips, + &mipsmach, }, + { "sparc", /*plan 9 sparc */ + FSPARC, + FSPARCB, + ASPARC, + &msparc, + &sparcmach, }, + { "sunsparc", /*native sparc - must follow plan 9*/ + FSPARC, + FSPARCB, + ASUNSPARC, + &msparc, + &sparcmach, }, + { "386", /*plan 9 386*/ + FI386, + FI386B, + AI386, + &mi386, + &i386mach, }, + { "86", /*8086 - a peach of a machine*/ + FI386, + FI386B, + AI8086, + &mi386, + &i386mach, }, + { "arm", /*ARM*/ + FARM, + FNONE, + AARM, + &marm, + &armmach, }, + { "power", /*PowerPC*/ + FPOWER, + FNONE, + APOWER, + &mpower, + &powermach, }, + { 0 }, /*the terminator*/ +}; + +/* + * select a machine by executable file type + */ +void +machbytype(int type) +{ + Machtab *mp; + + for (mp = machines; mp->name; mp++){ + if (mp->type == type || mp->boottype == type) { + asstype = mp->asstype; + machdata = mp->machdata; + break; + } + } +} +/* + * select a machine by name + */ +int +machbyname(char *name) +{ + Machtab *mp; + + if (!name) { + asstype = AMIPS; + machdata = &mipsmach; + mach = &mmips; + return 1; + } + for (mp = machines; mp->name; mp++){ + if (strcmp(mp->name, name) == 0) { + asstype = mp->asstype; + machdata = mp->machdata; + mach = mp->mach; + return 1; + } + } + return 0; +} diff --git a/utils/libmach/swap.c b/utils/libmach/swap.c new file mode 100644 index 00000000..3ca9cf27 --- /dev/null +++ b/utils/libmach/swap.c @@ -0,0 +1,79 @@ +#include <lib9.h> + +/* + * big-endian short + */ +ushort +beswab(ushort s) +{ + uchar *p; + + p = (uchar*)&s; + return (p[0]<<8) | p[1]; +} + +/* + * big-endian long + */ +long +beswal(long l) +{ + uchar *p; + + p = (uchar*)&l; + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; +} + +/* + * big-endian vlong + */ +vlong +beswav(vlong v) +{ + uchar *p; + + p = (uchar*)&v; + return ((vlong)p[0]<<56) | ((vlong)p[1]<<48) | ((vlong)p[2]<<40) + | ((vlong)p[3]<<32) | ((vlong)p[4]<<24) + | ((vlong)p[5]<<16) | ((vlong)p[6]<<8) + | (vlong)p[7]; +} + +/* + * little-endian short + */ +ushort +leswab(ushort s) +{ + uchar *p; + + p = (uchar*)&s; + return (p[1]<<8) | p[0]; +} + +/* + * little-endian long + */ +long +leswal(long l) +{ + uchar *p; + + p = (uchar*)&l; + return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0]; +} + +/* + * little-endian vlong + */ +vlong +leswav(vlong v) +{ + uchar *p; + + p = (uchar*)&v; + return ((vlong)p[7]<<56) | ((vlong)p[6]<<48) | ((vlong)p[5]<<40) + | ((vlong)p[4]<<32) | ((vlong)p[3]<<24) + | ((vlong)p[2]<<16) | ((vlong)p[1]<<8) + | (vlong)p[0]; +} diff --git a/utils/libmach/sym.c b/utils/libmach/sym.c new file mode 100644 index 00000000..6b62c555 --- /dev/null +++ b/utils/libmach/sym.c @@ -0,0 +1,1405 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +#define HUGEINT 0x7fffffff +#define NNAME 20 /* a relic of the past */ + +typedef struct txtsym Txtsym; +typedef struct file File; +typedef struct hist Hist; +typedef struct pcl Pcl; + +struct txtsym { /* Text Symbol table */ + int n; /* number of local vars */ + Sym **locals; /* array of ptrs to autos */ + Sym *sym; /* function symbol entry */ +}; + +struct hist { /* Stack of include files & #line directives */ + char *name; /* Assumes names Null terminated in file */ + long line; /* line # where it was included */ + long offset; /* line # of #line directive */ +}; + +struct pcl { + uchar *pcline; /* start of pcline data for this file */ + long pc; /* starting pc for pcline crunch */ + long line; /* starting line for pcline crunch */ +}; + +struct file { /* Per input file header to history stack */ + long addr; /* address of first text sym */ + union { + Txtsym *ftxt; /* first text symbol */ + Sym *fsym; /* only during initilization */ + } u0; + int n; /* size of history stack */ + Hist *hist; /* history stack */ + Pcl pcl; /* pcline startup data */ +}; + +static int debug = 0; + +static Sym **autos; /* Base of auto variables */ +static File *files; /* Base of file arena */ +static int fmax; /* largest file path index */ +static Sym **fnames; /* file names path component table */ +static Sym **globals; /* globals by addr table */ +static Hist *hist; /* base of history stack */ +static int isbuilt; /* internal table init flag */ +static long nauto; /* number of automatics */ +static long nfiles; /* number of files */ +static long nglob; /* number of globals */ +static long nhist; /* number of history stack entries */ +static long nsym; /* number of symbols */ +static long ntxt; /* number of text symbols */ +static uchar *pcline; /* start of pc-line state table */ +static uchar *pclineend; /* end of pc-line table */ +static int npcl; /* number of files pcl-decoded so far */ +static uchar *spoff; /* start of pc-sp state table */ +static uchar *spoffend; /* end of pc-sp offset table */ +static Sym *symbols; /* symbol table */ +static Txtsym *txt; /* Base of text symbol table */ +static long txtstart; /* start of text segment */ +static long txtend; /* end of text segment */ + +static void cleansyms(void); +static int decodename(Biobuf*, Sym*); +static short *encfname(char*); +static int fline(char*, int, long, Hist*, Hist**); +static void fillsym(Sym*, Symbol*); +static int findglobal(char*, Symbol*); +static int findlocvar(Symbol*, char *, Symbol*); +static int findtext(char*, Symbol*); +static int hcomp(Hist*, short*); +static int hline(File*, short*, ulong*); +static void printhist(char*, Hist*, int); +static long pcl2line(ulong, Pcl *, Pcl *); +static long pc2fline(ulong, File **); +static int pc2filex(ulong); +static int buildtbls(void); +static int symcomp(void*, void*); +static int symerrmsg(int, char*); +static int txtcomp(void*, void*); +static int filecomp(void*, void*); + +/* + * initialize the symbol tables + */ +int +syminit(int fd, Fhdr *fp) +{ + Sym *p; + int i, size; + Biobuf b; + extern void thumbpctab(Biobuf*, Fhdr*); + + if(fp->symsz == 0) + return 0; + if(fp->type == FNONE) + return 0; + + cleansyms(); + textseg(fp->txtaddr, fp); + /* minimum symbol record size = 4+1+2 bytes */ + symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym)); + if(symbols == 0) { + werrstr("can't malloc %ld bytes", fp->symsz); + return -1; + } + + Binit(&b, fd, OREAD); + Bseek(&b, fp->symoff, 0); + nsym = 0; + size = 0; + for(p = symbols; size < fp->symsz; p++, nsym++) { + if(Bread(&b, &p->value, sizeof(p->value)) != sizeof(p->value)) + return symerrmsg(sizeof(p->value), "symbol"); + p->value = beswal(p->value); + if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type)) + return symerrmsg(sizeof(p->value), "symbol"); + + i = decodename(&b, p); + if(i < 0) + return -1; + size += i+sizeof(p->value)+sizeof(p->type); + + /* count global & auto vars, text symbols, and file names */ + switch (p->type) { + case 'l': + case 'L': + case 't': + case 'T': + ntxt++; + break; + case 'd': + case 'D': + case 'b': + case 'B': + nglob++; + break; + case 'f': + if(strcmp(p->name, ".frame") == 0) { + p->type = 'm'; + nauto++; + } + else if(p->value > fmax) + fmax = p->value; /* highest path index */ + break; + case 'a': + case 'p': + case 'm': + nauto++; + break; + case 'z': + if(p->value == 1) { /* one extra per file */ + nhist++; + nfiles++; + } + nhist++; + break; + default: + break; + } + } + if (debug) + fprint(2,"NG: %ld NT: %ld NF: %d\n", nglob, ntxt, fmax); + if (fp->sppcsz) { /* pc-sp offset table */ + spoff = (uchar *)malloc(fp->sppcsz); + if(spoff == 0) { + werrstr("can't malloc %ld bytes", fp->sppcsz); + return -1; + } + Bseek(&b, fp->sppcoff, 0); + i = Bread(&b, spoff, fp->sppcsz); + if(i != fp->sppcsz){ + spoff = 0; + return symerrmsg(fp->sppcsz, "sp-pc"); + } + spoffend = spoff+fp->sppcsz; + } + if (fp->lnpcsz) { /* pc-line number table */ + pcline = (uchar *)malloc(fp->lnpcsz); + if(pcline == 0) { + werrstr("can't malloc %ld bytes", fp->lnpcsz); + return -1; + } + Bseek(&b, fp->lnpcoff, 0); + i = Bread(&b, pcline, fp->lnpcsz); + if(i != fp->lnpcsz){ + pcline = 0; + return symerrmsg(fp->lnpcsz, "pc-line"); + } + pclineend = pcline+fp->lnpcsz; + } + if(fp->type == FARM) /* thumb pc table */ + thumbpctab(&b, fp); + return nsym; +} + +static int +symerrmsg(int n, char *table) +{ + werrstr("can't read %d bytes of %s table", n, table); + return -1; +} + +static int +decodename(Biobuf *bp, Sym *p) +{ + char *cp; + int c1, c2; + int n; + + if((p->type & 0x80) == 0) { /* old-style, fixed length names */ + p->name = malloc(NNAME); + if(p->name == 0) { + werrstr("can't malloc %d bytes", NNAME); + return -1; + } + if(Bread(bp, p->name, NNAME) != NNAME) + return symerrmsg(NNAME, "symbol"); + Bseek(bp, 3, 1); + return NNAME+3; + } + + p->type &= ~0x80; + if(p->type == 'z' || p->type == 'Z') { + n = Bseek(bp, 0, 1); + if(Bgetc(bp) < 0) { + werrstr("can't read symbol name"); + return -1; + } + for(;;) { + c1 = Bgetc(bp); + c2 = Bgetc(bp); + if(c1 < 0 || c2 < 0) { + werrstr("can't read symbol name"); + return -1; + } + if(c1 == 0 && c2 == 0) + break; + } + n = Bseek(bp, 0, 1)-n; + p->name = malloc(n); + if(p->name == 0) { + werrstr("can't malloc %d bytes", n); + return -1; + } + Bseek(bp, -n, 1); + if(Bread(bp, p->name, n) != n) { + werrstr("can't read %d bytes of symbol name", n); + return -1; + } + } else { + cp = Brdline(bp, '\0'); + if(cp == 0) { + werrstr("can't read symbol name"); + return -1; + } + n = Blinelen(bp); + p->name = malloc(n); + if(p->name == 0) { + werrstr("can't malloc %d bytes", n); + return -1; + } + strcpy(p->name, cp); + } + return n; +} +/* + * free any previously loaded symbol tables + */ +static void +cleansyms(void) +{ + if(globals) + free(globals); + globals = 0; + nglob = 0; + if(txt) + free(txt); + txt = 0; + ntxt = 0; + if(fnames) + free(fnames); + fnames = 0; + fmax = 0; + + if(files) + free(files); + files = 0; + nfiles = 0; + if(hist) + free(hist); + hist = 0; + nhist = 0; + if(autos) + free(autos); + autos = 0; + nauto = 0; + isbuilt = 0; + if(symbols) + free(symbols); + symbols = 0; + nsym = 0; + if(spoff) + free(spoff); + spoff = 0; + if(pcline) + free(pcline); + pcline = 0; + npcl = 0; +} +/* + * delimit the text segment + */ +void +textseg(ulong base, Fhdr *fp) +{ + txtstart = base; + txtend = base+fp->txtsz; + npcl = 0; /* all pcls must be recomputed */ +} +/* + * symbase: return base and size of raw symbol table + * (special hack for high access rate operations) + */ +Sym * +symbase(long *n) +{ + *n = nsym; + return symbols; +} +/* + * Get the ith symbol table entry + */ +Sym * +getsym(int index) +{ + if(index < nsym) + return &symbols[index]; + return 0; +} + +/* + * initialize internal symbol tables + */ +static int +buildtbls(void) +{ + int i, j, nh, ng, nt; + File *f; + Txtsym *tp; + Hist *hp; + Sym *p, **ap; + + if(isbuilt) + return 1; + isbuilt = 1; + /* allocate the tables */ + if(nglob) { + globals = malloc(nglob*sizeof(*globals)); + if(!globals) { + werrstr("can't malloc global symbol table"); + return 0; + } + } + if(ntxt) { + txt = malloc(ntxt*sizeof(*txt)); + if (!txt) { + werrstr("can't malloc text symbol table"); + return 0; + } + } + fmax++; + fnames = malloc(fmax*sizeof(*fnames)); + if (!fnames) { + werrstr("can't malloc file name table"); + return 0; + } + memset(fnames, 0, fmax*sizeof(*fnames)); + files = malloc(nfiles*sizeof(*files)); + if(!files) { + werrstr("can't malloc file table"); + return 0; + } + hist = malloc(nhist*sizeof(Hist)); + if(hist == 0) { + werrstr("can't malloc history stack"); + return 0; + } + autos = malloc(nauto*sizeof(Sym*)); + if(autos == 0) { + werrstr("can't malloc auto symbol table"); + return 0; + } + /* load the tables */ + ng = nt = nh = 0; + f = 0; + tp = 0; + i = nsym; + hp = hist; + ap = autos; + for(p = symbols; i-- > 0; p++) { + switch(p->type) { + case 'D': + case 'd': + case 'B': + case 'b': + if(debug) + fprint(2,"Global: %s %lux\n", p->name, p->value); + globals[ng++] = p; + break; + case 'z': + if(p->value == 1) { /* New file */ + if(f) { + f->n = nh; + f->hist[nh].name = 0; /* one extra */ + hp += nh+1; + f++; + } + else f = files; + f->hist = hp; + f->u0.fsym = 0; + f->addr = 0; + nh = 0; + } + /* alloc one slot extra as terminator */ + f->hist[nh].name = p->name; + f->hist[nh].line = p->value; + f->hist[nh].offset = 0; + if(debug) + printhist("-> ", &f->hist[nh], 1); + nh++; + break; + case 'Z': + if(f && nh > 0) + f->hist[nh-1].offset = p->value; + break; + case 'T': + case 't': /* Text: terminate history if first in file */ + case 'L': + case 'l': + tp = &txt[nt++]; + tp->n = 0; + tp->sym = p; + tp->locals = ap; + if(debug) + fprint(2,"TEXT: %s at %lux\n", p->name, p->value); + if(f && !f->u0.fsym) { /* first */ + f->u0.fsym = p; + f->addr = p->value; + } + break; + case 'a': + case 'p': + case 'm': /* Local Vars */ + if(!tp) + print("Warning: Free floating local var"); + else { + if(debug) + fprint(2,"Local: %s %lux\n", p->name, p->value); + tp->locals[tp->n] = p; + tp->n++; + ap++; + } + break; + case 'f': /* File names */ + if(debug) + fprint(2,"Fname: %s\n", p->name); + fnames[p->value] = p; + break; + default: + break; + } + } + /* sort global and text tables into ascending address order */ + qsort(globals, nglob, sizeof(Sym*), symcomp); + qsort(txt, ntxt, sizeof(Txtsym), txtcomp); + qsort(files, nfiles, sizeof(File), filecomp); + tp = txt; + for(i = 0, f = files; i < nfiles; i++, f++) { + for(j = 0; j < ntxt; j++) { + if(f->u0.fsym == tp->sym) { + if(debug) { + fprint(2,"LINK: %s to at %lux", f->u0.fsym->name, f->addr); + printhist("... ", f->hist, 1); + } + f->u0.ftxt = tp++; + break; + } + if(++tp >= txt+ntxt) /* wrap around */ + tp = txt; + } + } + return 1; +} + +/* + * find symbol function.var by name. + * fn != 0 && var != 0 => look for fn in text, var in data + * fn != 0 && var == 0 => look for fn in text + * fn == 0 && var != 0 => look for var first in text then in data space. + */ +int +lookup(char *fn, char *var, Symbol *s) +{ + int found; + + if(buildtbls() == 0) + return 0; + if(fn) { + found = findtext(fn, s); + if(var == 0) /* case 2: fn not in text */ + return found; + else if(!found) /* case 1: fn not found */ + return 0; + } else if(var) { + found = findtext(var, s); + if(found) + return 1; /* case 3: var found in text */ + } else return 0; /* case 4: fn & var == zero */ + + if(found) + return findlocal(s, var, s); /* case 1: fn found */ + return findglobal(var, s); /* case 3: var not found */ + +} +/* + * find a function by name + */ +static int +findtext(char *name, Symbol *s) +{ + int i; + + for(i = 0; i < ntxt; i++) { + if(strcmp(txt[i].sym->name, name) == 0) { + fillsym(txt[i].sym, s); + s->handle = (void *) &txt[i]; + return 1; + } + } + return 0; +} +/* + * find global variable by name + */ +static int +findglobal(char *name, Symbol *s) +{ + int i; + + for(i = 0; i < nglob; i++) { + if(strcmp(globals[i]->name, name) == 0) { + fillsym(globals[i], s); + return 1; + } + } + return 0; +} +/* + * find the local variable by name within a given function + */ +int +findlocal(Symbol *s1, char *name, Symbol *s2) +{ + if(s1 == 0) + return 0; + if(buildtbls() == 0) + return 0; + return findlocvar(s1, name, s2); +} +/* + * find the local variable by name within a given function + * (internal function - does no parameter validation) + */ +static int +findlocvar(Symbol *s1, char *name, Symbol *s2) +{ + Txtsym *tp; + int i; + + tp = (Txtsym *)s1->handle; + if(tp && tp->locals) { + for(i = 0; i < tp->n; i++) + if (strcmp(tp->locals[i]->name, name) == 0) { + fillsym(tp->locals[i], s2); + s2->handle = (void *)tp; + return 1; + } + } + return 0; +} +/* + * Get ith text symbol + */ +int +textsym(Symbol *s, int index) +{ + + if(buildtbls() == 0) + return 0; + if(index >= ntxt) + return 0; + fillsym(txt[index].sym, s); + s->handle = (void *)&txt[index]; + return 1; +} +/* + * Get ith file name + */ +int +filesym(int index, char *buf, int n) +{ + Hist *hp; + + if(buildtbls() == 0) + return 0; + if(index >= nfiles) + return 0; + hp = files[index].hist; + if(!hp || !hp->name) + return 0; + return fileelem(fnames, (uchar*)hp->name, buf, n); +} +/* + * Lookup name of local variable located at an offset into the frame. + * The type selects either a parameter or automatic. + */ +int +getauto(Symbol *s1, int off, int type, Symbol *s2) +{ + Txtsym *tp; + Sym *p; + int i, t; + + if(s1 == 0) + return 0; + if(type == CPARAM) + t = 'p'; + else if(type == CAUTO) + t = 'a'; + else + return 0; + if(buildtbls() == 0) + return 0; + tp = (Txtsym *)s1->handle; + if(tp == 0) + return 0; + for(i = 0; i < tp->n; i++) { + p = tp->locals[i]; + if(p->type == t && p->value == off) { + fillsym(p, s2); + s2->handle = s1->handle; + return 1; + } + } + return 0; +} + +/* + * Find text symbol containing addr; binary search assumes text array is sorted by addr + */ +static int +srchtext(long addr) +{ + ulong val; + int top, bot, mid; + Sym *sp; + + val = addr; + bot = 0; + top = ntxt; + for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { + sp = txt[mid].sym; + if(val < (ulong)sp->value) + top = mid; + else if(mid != ntxt-1 && val >= (ulong)txt[mid+1].sym->value) + bot = mid; + else + return mid; + } + return -1; +} + +/* + * Find data symbol containing addr; binary search assumes data array is sorted by addr + */ +static +int srchdata(long addr) +{ + ulong val; + int top, bot, mid; + Sym *sp; + + bot = 0; + top = nglob; + val = addr; + for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { + sp = globals[mid]; + if(val < (ulong)sp->value) + top = mid; + else if(mid < nglob-1 && val >= (ulong)globals[mid+1]->value) + bot = mid; + else + return mid; + } + return -1; +} +/* + * Find symbol containing val in specified search space + * There is a special case when a value falls beyond the end + * of the text segment; if the search space is CTEXT, that value + * (usually etext) is returned. If the search space is CANY, symbols in the + * data space are searched for a match. + */ +int +findsym(long w, int type, Symbol *s) +{ + int i; + + if(buildtbls() == 0) + return 0; + + if(type == CTEXT || type == CANY) { + i = srchtext(w); + if(i >= 0) { + if(type == CTEXT || i != ntxt-1) { + fillsym(txt[i].sym, s); + s->handle = (void *) &txt[i]; + return 1; + } + } + } + if(type == CDATA || type == CANY) { + i = srchdata(w); + if(i >= 0) { + fillsym(globals[i], s); + return 1; + } + } + return 0; +} + +/* + * Find the start and end address of the function containing addr + */ +int +fnbound(long addr, ulong *bounds) +{ + int i; + + if(buildtbls() == 0) + return 0; + + i = srchtext(addr); + if(0 <= i && i < ntxt-1) { + bounds[0] = txt[i].sym->value; + bounds[1] = txt[i+1].sym->value; + return 1; + } + return 0; +} + +/* + * get the ith local symbol for a function + * the input symbol table is reverse ordered, so we reverse + * accesses here to maintain approx. parameter ordering in a stack trace. + */ +int +localsym(Symbol *s, int index) +{ + Txtsym *tp; + + if(s == 0) + return 0; + if(buildtbls() == 0) + return 0; + + tp = (Txtsym *)s->handle; + if(tp && tp->locals && index < tp->n) { + fillsym(tp->locals[tp->n-index-1], s); /* reverse */ + s->handle = (void *)tp; + return 1; + } + return 0; +} +/* + * get the ith global symbol + */ +int +globalsym(Symbol *s, int index) +{ + if(s == 0) + return 0; + if(buildtbls() == 0) + return 0; + + if(index < nglob) { + fillsym(globals[index], s); + return 1; + } + return 0; +} +/* + * find the pc given a file name and line offset into it. + */ +long +file2pc(char *file, ulong line) +{ + File *fp; + int i; + long pc; + ulong start, end; + short *name; + + if(buildtbls() == 0 || files == 0) + return -1; + name = encfname(file); + if(name == 0) { /* encode the file name */ + werrstr("file %s not found", file); + return -1; + } + /* find this history stack */ + for(i = 0, fp = files; i < nfiles; i++, fp++) + if (hline(fp, name, &line)) + break; + free(name); + if(i >= nfiles) { + werrstr("line %ld in file %s not found", line, file); + return -1; + } + start = fp->addr; /* first text addr this file */ + if(i < nfiles-1) + end = (fp+1)->addr; /* first text addr next file */ + else + end = 0; /* last file in load module */ + /* + * At this point, line contains the offset into the file. + * run the state machine to locate the pc closest to that value. + */ + if(debug) + fprint(2,"find pc for %ld - between: %lux and %lux\n", line, start, end); + pc = line2addr(line, start, end); + if(pc == -1) { + werrstr("line %ld not in file %s", line, file); + return -1; + } + return pc; +} +/* + * search for a path component index + */ +static int +pathcomp(char *s, int n) +{ + int i; + + for(i = 0; i <= fmax; i++) + if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0 && fnames[i]->name[n] == 0) + return i; + return -1; +} +/* + * Encode a char file name as a sequence of short indices + * into the file name dictionary. + */ +static short* +encfname(char *file) +{ + int i, j; + char *cp, *cp2; + short *dest; + + if(*file == '/') /* always check first '/' */ + cp2 = file+1; + else { + cp2 = strchr(file, '/'); + if(!cp2) + cp2 = strchr(file, 0); + } + cp = file; + dest = 0; + for(i = 0; *cp; i++) { + j = pathcomp(cp, cp2-cp); + if(j < 0) + return 0; /* not found */ + dest = realloc(dest, (i+1)*sizeof(short)); + dest[i] = j; + cp = cp2; + while(*cp == '/') /* skip embedded '/'s */ + cp++; + cp2 = strchr(cp, '/'); + if(!cp2) + cp2 = strchr(cp, 0); + } + dest = realloc(dest, (i+1)*sizeof(short)); + dest[i] = 0; + return dest; +} +/* + * Search a history stack for a matching file name accumulating + * the size of intervening files in the stack. + */ +static int +hline(File *fp, short *name, ulong *line) +{ + Hist *hp; + int offset, depth; + long ln; + + for(hp = fp->hist; hp->name; hp++) /* find name in stack */ + if(hp->name[1] || hp->name[2]) { + if(hcomp(hp, name)) + break; + } + if(!hp->name) /* match not found */ + return 0; + if(debug) + printhist("hline found ... ", hp, 1); + /* + * unwind the stack until empty or we hit an entry beyond our line + */ + ln = *line; + offset = hp->line-1; + depth = 1; + for(hp++; depth && hp->name; hp++) { + if(debug) + printhist("hline inspect ... ", hp, 1); + if(hp->name[1] || hp->name[2]) { + if(hp->offset){ /* Z record */ + offset = 0; + if(hcomp(hp, name)) { + if(*line <= hp->offset) + break; + ln = *line+hp->line-hp->offset; + depth = 1; /* implicit pop */ + } else + depth = 2; /* implicit push */ + } else if(depth == 1 && ln < hp->line-offset) + break; /* Beyond our line */ + else if(depth++ == 1) /* push */ + offset -= hp->line; + } else if(--depth == 1) /* pop */ + offset += hp->line; + } + *line = ln+offset; + return 1; +} +/* + * compare two encoded file names + */ +static int +hcomp(Hist *hp, short *sp) +{ + uchar *cp; + int i, j; + short *s; + + cp = (uchar *)hp->name; + s = sp; + if (*s == 0) + return 0; + for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) { + if(j == 0) + break; + if(*s == j) + s++; + else + s = sp; + } + return *s == 0; +} +/* + * Convert a pc to a "file:line {file:line}" string. + */ +int +fileline(char *str, int n, ulong dot) +{ + long line; + File *f; + int i; + + *str = 0; + if(buildtbls() == 0) + return 0; + + i = pc2filex(dot); + if (i >= 0) + { + f = &files[i]; + line = pc2line(dot); + if(line >= 0 && fline(str, n, line, f->hist, 0) >= 0) + return 1; + } + return 0; +} +/* + * Convert a pc to an index to the file table + */ +static int +pc2filex(ulong dot) +{ + int top, bot, mid; + File *f; + + if(buildtbls() == 0) + return -1; + + /* binary search assumes file list is sorted by addr */ + bot = 0; + top = nfiles; + for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { + f = &files[mid]; + if(dot < f->addr) + top = mid; + else if(mid < nfiles-1 && dot >= (f+1)->addr) + bot = mid; + else + return mid; + } + return -1; +} + +/* + * Convert a line number within a composite file to relative line + * number in a source file. A composite file is the source + * file with included files inserted in line. + */ +static int +fline(char *str, int n, long line, Hist *base, Hist **ret) +{ + Hist *start; /* start of current level */ + Hist *h; /* current entry */ + int delta; /* sum of size of files this level */ + int k; + + start = base; + h = base; + delta = h->line; + while(h && h->name && line > h->line) { + if(h->name[1] || h->name[2]) { + if(h->offset != 0) { /* #line Directive */ + delta = h->line-h->offset+1; + start = h; + base = h++; + } else { /* beginning of File */ + if(start == base) + start = h++; + else { + k = fline(str, n, line, start, &h); + if(k <= 0) + return k; + } + } + } else { + if(start == base) { /* end of recursion level */ + if(ret) + *ret = h; + return 1; + } else { /* end of included file */ + delta += h->line-start->line; + h++; + start = base; + } + } + } + if(!h) + return -1; + if(start != base) + line = line-start->line+1; + else + line = line-delta+1; + if(!h->name) + strncpy(str, "<eof>", n); + else { + k = fileelem(fnames, (uchar*)start->name, str, n); + if(k+8 < n) + sprint(str+k, ":%ld", line); + } +/**********Remove comments for complete back-trace of include sequence + * if(start != base) { + * k = strlen(str); + * if(k+2 < n) { + * str[k++] = ' '; + * str[k++] = '{'; + * } + * k += fileelem(fnames, (uchar*) base->name, str+k, n-k); + * if(k+10 < n) + * sprint(str+k, ":%ld}", start->line-delta); + * } + ********************/ + return 0; +} +/* + * convert an encoded file name to a string. + */ +int +fileelem(Sym **fp, uchar *cp, char *buf, int n) +{ + int i, j; + char *c, *bp, *end; + + bp = buf; + end = buf+n-1; + for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){ + c = fp[j]->name; + if(bp != buf && bp[-1] != '/' && bp < end) + *bp++ = '/'; + while(bp < end && *c) + *bp++ = *c++; + } + *bp = 0; + return bp-buf; +} +/* + * compare the values of two symbol table entries. + */ +static int +symcomp(void *a, void *b) +{ + return (*(Sym**)a)->value - (*(Sym**)b)->value; +} +/* + * compare the values of the symbols referenced by two text table entries + */ +static int +txtcomp(void *a, void *b) +{ + return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value; +} +/* + * compare the values of the symbols referenced by two file table entries + */ +static int +filecomp(void *a, void *b) +{ + return ((File*)a)->addr - ((File*)b)->addr; +} +/* + * fill an interface Symbol structure from a symbol table entry + */ +static void +fillsym(Sym *sp, Symbol *s) +{ + s->type = sp->type; + s->value = sp->value; + s->name = sp->name; + switch(sp->type) { + case 'b': + case 'B': + case 'D': + case 'd': + s->class = CDATA; + break; + case 't': + case 'T': + case 'l': + case 'L': + s->class = CTEXT; + break; + case 'a': + s->class = CAUTO; + break; + case 'p': + s->class = CPARAM; + break; + case 'm': + s->class = CSTAB; + break; + default: + s->class = CNONE; + break; + } + s->handle = 0; +} +/* + * find the stack frame, given the pc + */ +long +pc2sp(ulong pc) +{ + uchar *c; + uchar u; + ulong currpc; + long currsp; + + if(spoff == 0) + return -1; + currsp = 0; + currpc = txtstart - mach->pcquant; + + if(pc<currpc || pc>txtend) + return -1; + for(c = spoff; c < spoffend; c++) { + if (currpc >= pc) + return currsp; + u = *c; + if (u == 0) { + currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4]; + c += 4; + } + else if (u < 65) + currsp += 4*u; + else if (u < 129) + currsp -= 4*(u-64); + else + currpc += mach->pcquant*(u-129); + currpc += mach->pcquant; + } + return -1; +} +/* + * find the source file line number for a given value of the pc + */ +long +pc2line(ulong pc) +{ + File *fp; + return pc2fline(pc, &fp); +} +/* + * Convert a pc into a file table pointer & line offset + */ +static long +pc2fline(ulong pc, File **fpp) +{ + File *f; + int i; + + i = pc2filex(pc); + if (i < 0) + return i; + if (i >= npcl){ + /* Precompute starting points by file, else too slow */ + if (npcl == 0){ + Pcl pcl; + + /* decode start for pcline machine */ + pcl.pcline = pcline; + pcl.pc = txtstart - mach->pcquant; + pcl.line = 0; + pcl2line(files->addr, &pcl, &files[0].pcl); + npcl = 1; + } + for (f = &files[npcl]; npcl <= i; npcl++, f++) + if (pcl2line(f->addr, &(f-1)->pcl, &f->pcl) < 0) + break; + } + f = &files[i]; + *fpp = f; + return pcl2line(pc, &f->pcl, 0); +} +/* + * Convert pc to line offset, given Pcl starting point, + * saving Pcl result. + */ +static long +pcl2line(ulong pc, Pcl *bp, Pcl *rp) +{ + uchar *c; + uchar u; + ulong currpc; + long currline; + + if(bp->pcline == 0) + return -1; + currpc = bp->pc; + currline = bp->line; + if(pc<currpc || pc>txtend) + return -1; + for(c = bp->pcline; c < pclineend; c++) { + if (currpc >= pc) { + if (rp){ + rp->pc = currpc; + rp->line = currline; + rp->pcline = c; + } + return currline; + } + u = *c; + if(u == 0) { + currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4]; + c += 4; + } + else if(u < 65) + currline += u; + else if(u < 129) + currline -= (u-64); + else + currpc += mach->pcquant*(u-129); + currpc += mach->pcquant; + } + return -1; +} +/* + * find the pc associated with a line number + * basepc and endpc are text addresses bounding the search. + * if endpc == 0, the end of the table is used (i.e., no upper bound). + * usually, basepc and endpc contain the first text address in + * a file and the first text address in the following file, respectively. + */ +long +line2addr(ulong line, ulong basepc, ulong endpc) +{ + uchar *c; + uchar u; + ulong currpc; + long currline; + long delta, d; + long pc, found; + + if(pcline == 0 || line == 0) + return -1; + + currline = 0; + currpc = txtstart-mach->pcquant; + pc = -1; + found = 0; + delta = HUGEINT; + + for(c = pcline; c < pclineend; c++) { + if(endpc && currpc >= endpc) /* end of file of interest */ + break; + if(currpc >= basepc) { /* proper file */ + if(currline >= line) { + d = currline-line; + found = 1; + } else + d = line-currline; + if(d < delta) { + delta = d; + pc = currpc; + } + } + u = *c; + if(u == 0) { + currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4]; + c += 4; + } + else if(u < 65) + currline += u; + else if(u < 129) + currline -= (u-64); + else + currpc += mach->pcquant*(u-129); + currpc += mach->pcquant; + } + if(found) + return pc; + return -1; +} +/* + * Print a history stack (debug). if count is 0, prints the whole stack + */ +static void +printhist(char *msg, Hist *hp, int count) +{ + int i; + uchar *cp; + char buf[128]; + + i = 0; + while(hp->name) { + if(count && ++i > count) + break; + fprint(2,"%s Line: %lx (%ld) Offset: %lx (%ld) Name: ", msg, + hp->line, hp->line, hp->offset, hp->offset); + for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) { + if (cp != (uchar *)hp->name+1) + fprint(2,"/"); + fprint(2,"%x", (*cp<<8)|cp[1]); + } + fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf)); + fprint(2," (%s)\n", buf); + hp++; + } +} + +#ifdef DEBUG +/* + * print the history stack for a file. (debug only) + * if (name == 0) => print all history stacks. + */ +void +dumphist(char *name) +{ + int i; + File *f; + short *fname; + + if(buildtbls() == 0) + return; + if(name) + fname = encfname(name); + for(i = 0, f = files; i < nfiles; i++, f++) + if(fname == 0 || hcomp(f->hist, fname)) + printhist("> ", f->hist, f->n); + + if(fname) + free(fname); +} +#endif diff --git a/utils/libmach/t.c b/utils/libmach/t.c new file mode 100644 index 00000000..adea089b --- /dev/null +++ b/utils/libmach/t.c @@ -0,0 +1,122 @@ +/* + * thumb definition + */ +#include <lib9.h> +#include <bio.h> +#include "uregt.h" +#include "mach.h" + + +#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x) + +#define SP REGOFF(r13) +#define PC REGOFF(pc) + +#define REGSIZE sizeof(struct Ureg) + +Reglist thumbreglist[] = +{ + {"LINK", REGOFF(link), RINT|RRDONLY, 'X'}, + {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'}, + {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'}, + {"PC", PC, RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"R15", PC, RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + {"R0", REGOFF(r0), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mthumb = +{ + "thumb", + MARM, /*MTHUMB,*/ /* machine type */ + thumbreglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R15", /* name of link register */ + "setR12", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80000000, /* kernel base */ + 0, /* kernel text mask */ + 2, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; + +typedef struct pcentry pcentry; + +struct pcentry{ + long start; + long stop; +}; + +static pcentry *pctab; +static int npctab; + +void +thumbpctab(Biobuf *b, Fhdr *fp) +{ + int n, o, ta; + uchar c[8]; + pcentry *tab; + + Bseek(b, fp->lnpcoff+fp->lnpcsz, 0); + o = (int)Boffset(b); + Bseek(b, 0, 2); + n = (int)Boffset(b)-o; + pctab = (pcentry*)malloc(n); + if(pctab == 0) + return; + ta = fp->txtaddr; + tab = pctab; + Bseek(b, fp->lnpcoff+fp->lnpcsz, 0); + while(Bread(b, c, sizeof(c)) == sizeof(c)){ + tab->start = ta + (c[0]<<24)|(c[1]<<16)|(c[2]<<8)|c[3]; + tab->stop = ta + (c[4]<<24)|(c[5]<<16)|(c[6]<<8)|c[7]; + tab++; + } + npctab = n/sizeof(c); +} + +int +thumbpclookup(ulong pc) +{ + ulong l, u, m; + pcentry *tab = pctab; + + l = 0; + u = npctab-1; + while(l < u){ + m = (l+u)/2; + if(pc < tab[m].start) + u = m-1; + else if(pc > tab[m].stop) + l = m+1; + else + l = u = m; + } + if(l == u && u >= 0 && u < npctab && tab[u].start <= pc && pc <= tab[u].stop) + return 1; // thumb + return 0; // arm +} + diff --git a/utils/libmach/tdb.c b/utils/libmach/tdb.c new file mode 100644 index 00000000..8eddc43a --- /dev/null +++ b/utils/libmach/tdb.c @@ -0,0 +1,839 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + +static int debug = 0; + +typedef struct Instr Instr; +struct Instr +{ + Map *map; + ulong w; + ulong addr; + uchar op; /* super opcode */ + + uchar rd; + uchar rn; + uchar rs; + + long imm; /* imm */ + + char* curr; /* fill point in buffer */ + char* end; /* end of buffer */ + char* err; /* error message */ +}; + +typedef struct Opcode Opcode; +struct Opcode +{ + char* o; + void (*fmt)(Opcode*, Instr*); + ulong (*foll)(Map*, Rgetter, Instr*, ulong); + char* a; +}; + +static void format(char*, Instr*, char*); +static char FRAMENAME[] = ".frame"; + +/* + * Thumb-specific debugger interface + */ + +static char *thumbexcep(Map*, Rgetter); +static int thumbfoll(Map*, ulong, Rgetter, ulong*); +static int thumbinst(Map*, ulong, char, char*, int); +static int thumbdas(Map*, ulong, char*, int); +static int thumbinstlen(Map*, ulong); + +/* + * Debugger interface + */ +Machdata thumbmach = +{ + {0x0, 0xE8}, /* break point */ + 2, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + thumbexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precision float printer */ + thumbfoll, /* following addresses */ + thumbinst, /* print instruction */ + thumbdas, /* dissembler */ + thumbinstlen, /* instruction size */ +}; + +static void thumbrrh(Opcode *, Instr *); +static void thumbbcc(Opcode *, Instr *); +static void thumbb(Opcode *, Instr *); +static void thumbbl(Opcode *, Instr *); + +static char* +thumbexcep(Map *map, Rgetter rget) +{ + long c; + + c = (*rget)(map, "TYPE"); + switch (c&0x1f) { + case 0x11: + return "Fiq interrupt"; + case 0x12: + return "Mirq interrupt"; + case 0x13: + return "SVC/SWI Exception"; + case 0x17: + return "Prefetch Abort/Data Abort"; + case 0x18: + return "Data Abort"; + case 0x1b: + return "Undefined instruction/Breakpoint"; + case 0x1f: + return "Sys trap"; + default: + return "Undefined trap"; + } +} + +static +char* cond[16] = +{ + "EQ", "NE", "CS", "CC", + "MI", "PL", "VS", "VC", + "HI", "LS", "GE", "LT", + "GT", "LE", "\0", "NV" +}; + +#define B(h, l) bits(ins, h, l) + +static int +bits(int i, int h, int l) +{ + if(h < l) + print("h < l in bits"); + return (i&(((1<<(h-l+1))-1)<<l))>>l; +} + +int +thumbclass(long w) +{ + int o; + int ins = w; + + if(ins&0xffff0000) + return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; + o = B(15, 13); + switch(o){ + case 0: + o = B(12, 11); + switch(o){ + case 0: + case 1: + case 2: + return B(12, 11); + case 3: + if(B(10, 10) == 0) + return 3+B(9, 9); + else + return 3+2+B(9, 9); + } + case 1: + return 3+2+2+B(12, 11); + case 2: + o = B(12, 10); + if(o == 0) + return 3+2+2+4+B(9, 6); + if(o == 1){ + o = B(9, 8); + if(o == 3) + return 3+2+2+4+16+B(9, 8); + return 3+2+2+4+16+B(9, 8); + } + if(o == 2 || o == 3) + return 3+2+2+4+16+4; + return 3+2+2+4+16+4+1+B(11, 9); + case 3: + return 3+2+2+4+16+4+1+8+B(12, 11); + case 4: + if(B(12, 12) == 0) + return 3+2+2+4+16+4+1+8+4+B(11, 11); + return 3+2+2+4+16+4+1+8+6+B(11, 11); + case 5: + if(B(12, 12) == 0) + return 3+2+2+4+16+4+1+8+6+2+B(11, 11); + if(B(11, 8) == 0) + return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7); + return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11); + case 6: + if(B(12, 12) == 0) + return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11); + if(B(11, 8) == 0xf) + return 3+2+2+4+16+4+1+8+6+2+2+2+4; + return 3+2+2+4+16+4+1+8+6+2+2+2+4+1; + case 7: + o = B(12, 11); + switch(o){ + case 0: + return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1; + case 1: + return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; + case 2: + return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1; + case 3: + return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1; + } + } + return 0; +} + +static int +decode(Map *map, ulong pc, Instr *i) +{ + ushort w; + + if(get2(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->w = w; + i->addr = pc; + i->op = thumbclass(w); + i->map = map; + return 1; +} + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static int +plocal(Instr *i) +{ + char *reg; + Symbol s; + char *fn; + int class; + int offset; + + if(!findsym(i->addr, CTEXT, &s)) { + if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr); + return 0; + } + fn = s.name; + if (!findlocal(&s, FRAMENAME, &s)) { + if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name); + return 0; + } + if(s.value > i->imm) { + class = CAUTO; + offset = s.value-i->imm; + reg = "(SP)"; + } else { + class = CPARAM; + offset = i->imm-s.value-4; + reg = "(FP)"; + } + if(!getauto(&s, offset, class, &s)) { + if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn, + class == CAUTO ? " auto" : "param", offset); + return 0; + } + bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg); + return 1; +} + +/* + * Print value v as name[+offset] + */ +static int +gsymoff(char *buf, int n, long v, int space) +{ + Symbol s; + int r; + long delta; + + r = delta = 0; /* to shut compiler up */ + if (v) { + r = findsym(v, space, &s); + if (r) + delta = v-s.value; + if (delta < 0) + delta = -delta; + } + if (v == 0 || r == 0 || delta >= 4096) + return snprint(buf, n, "#%lux", v); + if (strcmp(s.name, ".string") == 0) + return snprint(buf, n, "#%lux", v); + if (!delta) + return snprint(buf, n, "%s", s.name); + if (s.type != 't' && s.type != 'T') + return snprint(buf, n, "%s+%lux", s.name, v-s.value); + else + return snprint(buf, n, "#%lux", v); +} + +static int +thumbcondpass(Map *map, Rgetter rget, uchar cond) +{ + ulong psr; + uchar n; + uchar z; + uchar c; + uchar v; + + psr = rget(map, "PSR"); + n = (psr >> 31) & 1; + z = (psr >> 30) & 1; + c = (psr >> 29) & 1; + v = (psr >> 28) & 1; + + switch(cond) { + case 0: return z; + case 1: return !z; + case 2: return c; + case 3: return !c; + case 4: return n; + case 5: return !n; + case 6: return v; + case 7: return !v; + case 8: return c && !z; + case 9: return !c || z; + case 10: return n == v; + case 11: return n != v; + case 12: return !z && (n == v); + case 13: return z && (n != v); + case 14: return 1; + case 15: return 0; + } + return 0; +} + +static ulong +thumbfbranch(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + char buf[8]; + + if(i->op == 30){ // BX + thumbrrh(nil, i); + sprint(buf, "R%ud", i->rn); + return rget(map, buf)&~1; // clear T bit + } + if(i->op == 57){ // Bcc + thumbbcc(nil, i); + if(thumbcondpass(map, rget, (i->w >> 8) & 0xf)) + return i->imm; + return pc+2; + } + if(i->op == 58){ // B + thumbb(nil, i); + return i->imm; + } + if(i->op == 60){ // BL + thumbbl(nil, i); + return i->imm; + } + print("bad thumbfbranch call"); + return 0; +} + +static ulong +thumbfmov(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + char buf[8]; + ulong rd; + + thumbrrh(nil, i); + rd = i->rd; + if(rd != 15) + return pc+2; + sprint(buf, "R%ud", i->rn); + return rget(map, buf); +} + +static ulong +thumbfadd(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + char buf[8]; + ulong rd, v; + + thumbrrh(nil, i); + rd = i->rd; + if(rd != 15) + return pc+2; + sprint(buf, "R%ud", i->rn); + v = rget(map, buf); + sprint(buf, "R15"); + return rget(map, buf) + v; +} + +static void +thumbshift(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(2, 0); + i->rn = B(5, 3); + i->imm = B(10, 6); + format(o->o, i, o->a); +} + +static void +thumbrrr(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(2, 0); + i->rn = B(5, 3); + i->rs = B(8, 6); + format(o->o, i, o->a); +} + +static void +thumbirr(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(2, 0); + i->rn = B(5, 3); + i->imm = B(8, 6); + format(o->o, i, o->a); +} + +static void +thumbir(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(10, 8); + i->imm = B(7, 0); + format(o->o, i, o->a); +} + +static void +thumbrr(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(2, 0); + i->rn = B(5, 3); + format(o->o, i, o->a); +} + +static void +thumbrrh(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(2, 0); + i->rn = B(5, 3); + if(B(6, 6)) + i->rn += 8; + if(B(7, 7)) + i->rd += 8; + if(o != nil){ + if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770) // mov r6, pc or mov lr, pc or bx r6 or bx lr + format("RET", i, ""); + else + format(o->o, i, o->a); + } +} + +static void +thumbpcrel(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rn = 15; + i->rd = B(10, 8); + i->imm = 4*(B(7, 0)+1); + if(i->addr & 3) + i->imm -= 2; + format(o->o, i, o->a); +} + +static void +thumbmovirr(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(2, 0); + i->rn = B(5, 3); + i->imm = B(10, 6); + if(strcmp(o->o, "MOVW") == 0) + i->imm *= 4; + else if(strncmp(o->o, "MOVH", 4) == 0) + i->imm *= 2; + format(o->o, i, o->a); +} + +static void +thumbmovsp(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rn = 13; + i->rd = B(10, 8); + i->imm = 4*B(7, 0); + format(o->o, i, o->a); +} + +static void +thumbaddsppc(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->rd = B(10, 8); + i->imm = 4*B(7, 0); + if(i->op == 48) + i->imm += 4; + format(o->o, i, o->a); +} + +static void +thumbaddsp(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->imm = 4*B(6, 0); + format(o->o, i, o->a); +} + +static void +thumbswi(Opcode *o, Instr *i) +{ + int ins = i->w; + + i->imm = B(7, 0); + format(o->o, i, o->a); +} + +static void +thumbbcc(Opcode *o, Instr *i) +{ + int off, ins = i->w; + + off = B(7, 0); + if(off & 0x80) + off |= 0xffffff00; + i->imm = i->addr + 2*off + 4; + if(o != nil) + format(o->o, i, o->a); +} + +static void +thumbb(Opcode *o, Instr *i) +{ + int off, ins = i->w; + + off = B(10, 0); + if(off & 0x400) + off |= 0xfffff800; + i->imm = i->addr + 2*off + 4; + if(o != nil) + format(o->o, i, o->a); +} + +static void +thumbbl(Opcode *o, Instr *i) +{ + int off, h, ins = i->w; + static int reglink; + + h = B(11, 11); + off = B(10, 0); + if(h == 0){ + if(off & 0x400) + off |= 0xfffff800; + i->imm = i->addr + (off<<12) + 4; + reglink = i->imm; + } + else{ + i->imm = reglink + 2*off; + } + if(o != nil) + format(o->o, i, o->a); +} + +static void +thumbregs(Opcode *o, Instr *i) +{ + int ins = i->w; + + if(i->op == 52 || i->op == 53) + i->rd = 13; + else + i->rd = B(10, 8); + i->imm = B(7, 0); + format(o->o, i, o->a); +} + +static void +thumbunk(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static Opcode opcodes[] = +{ + "LSL", thumbshift, 0, "$#%i,R%n,R%d", // 0 + "LSR", thumbshift, 0, "$#%i,R%n,R%d", // 1 + "ASR", thumbshift, 0, "$#%i,R%n,R%d", // 2 + "ADD", thumbrrr, 0, "R%s,R%n,R%d", // 3 + "SUB", thumbrrr, 0, "R%s,R%n,R%d", // 4 + "ADD", thumbirr, 0, "$#%i,R%n,R%d", // 5 + "SUB", thumbirr, 0, "$#%i,R%n,R%d", // 6 + "MOVW", thumbir, 0, "$#%i,R%d", // 7 + "CMP", thumbir, 0, "$#%i,R%d", // 8 + "ADD", thumbir, 0, "$#%i,R%d,R%d", // 9 + "SUB", thumbir, 0, "$#%i,R%d,R%d", // 10 + "AND", thumbrr, 0, "R%n,R%d,R%d", // 11 + "EOR", thumbrr, 0, "R%n,R%d,R%d", // 12 + "LSL", thumbrr, 0, "R%n,R%d,R%d", // 13 + "LSR", thumbrr, 0, "R%n,R%d,R%d", // 14 + "ASR", thumbrr, 0, "R%n,R%d,R%d", // 15 + "ADC", thumbrr, 0, "R%n,R%d,R%d", // 16 + "SBC", thumbrr, 0, "R%n,R%d,R%d", // 17 + "ROR", thumbrr, 0, "R%n,R%d,R%d", // 18 + "TST", thumbrr, 0, "R%n,R%d", // 19 + "NEG", thumbrr, 0, "R%n,R%d", // 20 + "CMP", thumbrr, 0, "R%n,R%d", // 21 + "CMPN", thumbrr, 0, "R%n,R%d", // 22 + "OR", thumbrr, 0, "R%n,R%d,R%d", // 23 + "MUL", thumbrr, 0, "R%n,R%d,R%d", // 24 + "BITC", thumbrr, 0, "R%n,R%d,R%d", // 25 + "MOVN", thumbrr, 0, "R%n,R%d", // 26 + "ADD", thumbrrh, thumbfadd, "R%n,R%d,R%d", // 27 + "CMP", thumbrrh, 0, "R%n,R%d", // 28 + "MOVW", thumbrrh, thumbfmov, "R%n,R%d", // 29 + "BX", thumbrrh, thumbfbranch, "R%n", // 30 + "MOVW", thumbpcrel, 0, "$%I,R%d", // 31 + "MOVW", thumbrrr, 0, "R%d, [R%s,R%n]", // 32 + "MOVH", thumbrrr, 0, "R%d, [R%s,R%n]", // 33 + "MOVB", thumbrrr, 0, "R%d, [R%s,R%n]", // 34 + "MOVB", thumbrrr, 0, "[R%s,R%n],R%d", // 35 + "MOVW", thumbrrr, 0, "[R%s,R%n],R%d", // 36 + "MOVHU", thumbrrr, 0, "[R%s,R%n],R%d", // 37 + "MOVBU", thumbrrr, 0, "[R%s,R%n],R%d", // 38 + "MOVH", thumbrrr, 0, "[R%s,R%n],R%d", // 39 + "MOVW", thumbmovirr, 0, "R%d,%I", // 40 + "MOVW", thumbmovirr, 0, "%I,R%d", // 41 + "MOVB", thumbmovirr, 0, "R%d,%I", // 42 + "MOVBU", thumbmovirr, 0, "$%I,R%d", // 43 + "MOVH", thumbmovirr, 0, "R%d,%I", // 44 + "MOVHU", thumbmovirr, 0, "%I,R%d", // 45 + "MOVW", thumbmovsp, 0, "R%d,%I", // 46 + "MOVW", thumbmovsp, 0, "%I,R%d", // 47 + "ADD", thumbaddsppc,0, "$#%i,PC,R%d", // 48 + "ADD", thumbaddsppc,0, "$#%i,SP,R%d", // 49 + "ADD", thumbaddsp, 0, "$#%i,SP,SP", // 50 + "SUB", thumbaddsp, 0, "$#%i,SP,SP", // 51 + "PUSH", thumbregs, 0, "R%d, %r", // 52 + "POP", thumbregs, 0, "R%d, %r", // 53 + "STMIA", thumbregs, 0, "R%d, %r", // 54 + "LDMIA", thumbregs, 0, "R%d, %r", // 55 + "SWI", thumbswi, 0, "$#%i", // 56 + "B%c", thumbbcc, thumbfbranch, "%b", // 57 + "B", thumbb, thumbfbranch, "%b", // 58 + "BL", thumbbl, 0, "", // 59 + "BL", thumbbl, thumbfbranch, "%b", // 60 + "UNK", thumbunk, 0, "", // 61 +}; + +static void +gaddr(Instr *i) +{ + *i->curr++ = '$'; + i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY); +} + +static void +format(char *mnemonic, Instr *i, char *f) +{ + int j, k, m, n; + int g; + char *fmt; + int ins = i->w; + + if(mnemonic) + format(0, i, mnemonic); + if(f == 0) + return; + if(mnemonic) + if(i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if(*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 'c': /*Bcc */ + bprint(i, "%s", cond[B(11, 8)]); + break; + + case 's': + bprint(i, "%d", i->rs); + break; + + case 'n': + bprint(i, "%d", i->rn); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'i': + bprint(i, "%lux", i->imm); + break; + + case 'b': + i->curr += symoff(i->curr, i->end-i->curr, + i->imm, CTEXT); + break; + + case 'I': + if (i->rn == 13) { + if (plocal(i)) + break; + } + g = 0; + fmt = "#%lx(R%d)"; + if (i->rn == 15) { + /* convert load of offset(PC) to a load immediate */ + if (get4(i->map, i->addr + i->imm, &i->imm) > 0) + { + g = 1; + fmt = ""; + } + } + if (mach->sb) + { + if (i->rn == 12) + { + i->imm += mach->sb; + g = 1; + fmt = "-SB(SB)"; + } + } + if (g) + { + gaddr(i); + bprint(i, fmt, i->rn); + } + else + bprint(i, fmt, i->imm, i->rn); + break; + + case 'r': + n = i->imm&0xff; + j = 0; + k = 0; + while(n) { + m = j; + while(n&0x1) { + j++; + n >>= 1; + } + if(j != m) { + if(k) + bprint(i, ","); + if(j == m+1) + bprint(i, "R%d", m); + else + bprint(i, "R%d-R%d", m, j-1); + k = 1; + } + j++; + n >>= 1; + } + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n-1; + if(decode(map, pc, &i) < 0) + return -1; + + (*opcodes[i.op].fmt)(&opcodes[i.op], &i); + return 2; +} + +static int +thumbinst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + USED(modifier); + return printins(map, pc, buf, n); +} + +static int +thumbdas(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + if(i.end-i.curr > 8) + i.curr = _hexify(buf, i.w, 7); + *i.curr = 0; + return 2; +} + +static int +thumbinstlen(Map *map, ulong pc) +{ + Instr i; + + if(decode(map, pc, &i) < 0) + return -1; + return 2; +} + +static int +thumbfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + ulong d; + Instr i; + + if(decode(map, pc, &i) < 0) + return -1; + + if(opcodes[i.op].foll) { + d = (*opcodes[i.op].foll)(map, rget, &i, pc); + if(d == -1) + return -1; + } else + d = pc+2; + + foll[0] = d; + return 1; +} diff --git a/utils/libmach/tobj.c b/utils/libmach/tobj.c new file mode 100644 index 00000000..d18de434 --- /dev/null +++ b/utils/libmach/tobj.c @@ -0,0 +1,133 @@ +/* + * 5obj.c - identify and parse a arm object file + */ +#include <lib9.h> +#include <bio.h> +#include "5c/5.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_ist(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + +int +_readt(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 6); /* scond(1), reg(1), lineno(4) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + case D_FPCR: + break; + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/ureg2.h b/utils/libmach/ureg2.h new file mode 100644 index 00000000..e237cb3d --- /dev/null +++ b/utils/libmach/ureg2.h @@ -0,0 +1,28 @@ +struct Ureg +{ + ulong r0; + ulong r1; + ulong r2; + ulong r3; + ulong r4; + ulong r5; + ulong r6; + ulong r7; + ulong a0; + ulong a1; + ulong a2; + ulong a3; + ulong a4; + ulong a5; + ulong a6; + ulong sp; + ulong usp; + ulong magic; /* for db to find bottom of ureg */ + ushort sr; + ulong pc; + ushort vo; +#ifndef UREGVARSZ +#define UREGVARSZ 23 /* for 68040; 15 is enough on 68020 */ +#endif + uchar microstate[UREGVARSZ]; /* variable-sized portion */ +}; diff --git a/utils/libmach/ureg4.h b/utils/libmach/ureg4.h new file mode 100644 index 00000000..5f95dcd9 --- /dev/null +++ b/utils/libmach/ureg4.h @@ -0,0 +1,46 @@ +struct Ureg +{ + ulong status; + long pc; + union + { + long sp; /* r29 */ + long usp; /* r29 */ + } u0; + ulong cause; + ulong badvaddr; + ulong tlbvirt; + + long hhi; long hi; + long hlo; long lo; + long hr31; long r31; + long hr30; long r30; + long hr28; long r28; + long hr27; long r27; + long hr26; long r26; + long hr25; long r25; + long hr24; long r24; + long hr23; long r23; + long hr22; long r22; + long hr21; long r21; + long hr20; long r20; + long hr19; long r19; + long hr18; long r18; + long hr17; long r17; + long hr16; long r16; + long hr15; long r15; + long hr14; long r14; + long hr13; long r13; + long hr12; long r12; + long hr11; long r11; + long hr10; long r10; + long hr9; long r9; + long hr8; long r8; + long hr7; long r7; + long hr6; long r6; + long hr5; long r5; + long hr4; long r4; + long hr3; long r3; + long hr2; long r2; + long hr1; long r1; +}; diff --git a/utils/libmach/ureg5.h b/utils/libmach/ureg5.h new file mode 100644 index 00000000..ffdad423 --- /dev/null +++ b/utils/libmach/ureg5.h @@ -0,0 +1,21 @@ +struct Ureg { + uint r0; + uint r1; + uint r2; + uint r3; + uint r4; + uint r5; + uint r6; + uint r7; + uint r8; + uint r9; + uint r10; + uint r11; + uint r12; + uint r13; + uint r14; + uint link; + uint type; + uint psr; + uint pc; +}; diff --git a/utils/libmach/ureg6.h b/utils/libmach/ureg6.h new file mode 100644 index 00000000..46fa1f61 --- /dev/null +++ b/utils/libmach/ureg6.h @@ -0,0 +1,30 @@ +struct Ureg +{ + uvlong r15; /* general registers */ + uvlong r14; + uvlong r13; + uvlong r12; + uvlong r11; + uvlong r10; + uvlong r9; + uvlong r8; + uvlong di; + uvlong si; /* ... */ + uvlong bp; /* ... */ + uvlong nsp; + uvlong bx; /* ... */ + uvlong dx; /* ... */ + uvlong cx; /* ... */ + uvlong ax; /* ... */ + uvlong gs; /* data segments */ + uvlong fs; /* ... */ + uvlong es; /* ... */ + uvlong ds; /* ... */ + uvlong trap; /* trap type */ + uvlong ecode; /* error code (or zero) */ + uvlong pc; /* pc */ + uvlong cs; /* old context */ + uvlong flags; /* old flags */ + uvlong sp; + uvlong ss; /* old stack segment */ +}; diff --git a/utils/libmach/ureg8.h b/utils/libmach/ureg8.h new file mode 100644 index 00000000..8bdf178d --- /dev/null +++ b/utils/libmach/ureg8.h @@ -0,0 +1,25 @@ +struct Ureg +{ + ulong di; /* general registers */ + ulong si; /* ... */ + ulong bp; /* ... */ + ulong nsp; + ulong bx; /* ... */ + ulong dx; /* ... */ + ulong cx; /* ... */ + ulong ax; /* ... */ + ulong gs; /* data segments */ + ulong fs; /* ... */ + ulong es; /* ... */ + ulong ds; /* ... */ + ulong trap; /* trap type */ + ulong ecode; /* error code (or zero) */ + ulong pc; /* pc */ + ulong cs; /* old context */ + ulong flags; /* old flags */ + union { + ulong usp; + ulong sp; + } u0; + ulong ss; /* old stack segment */ +}; diff --git a/utils/libmach/uregk.h b/utils/libmach/uregk.h new file mode 100644 index 00000000..4ff12edc --- /dev/null +++ b/utils/libmach/uregk.h @@ -0,0 +1,45 @@ +struct Ureg +{ + ulong r0; /* unnecessary; just for symmetry */ + union{ + ulong sp; /* r1 */ + ulong usp; /* r1 */ + ulong r1; + } u0; + ulong r2; + ulong r3; + ulong r4; + ulong r5; + ulong r6; + ulong r7; + ulong r8; + ulong r9; + ulong r10; + ulong r11; + ulong r12; + ulong r13; + ulong r14; + ulong r15; + ulong r16; + ulong r17; + ulong r18; + ulong r19; + ulong r20; + ulong r21; + ulong r22; + ulong r23; + ulong r24; + ulong r25; + ulong r26; + ulong r27; + ulong r28; + ulong r29; + ulong r30; + ulong r31; + ulong y; + ulong tbr; + ulong psr; + ulong npc; + ulong pc; + ulong pad; /* so structure is double word aligned */ +}; diff --git a/utils/libmach/uregq.h b/utils/libmach/uregq.h new file mode 100644 index 00000000..409b13d3 --- /dev/null +++ b/utils/libmach/uregq.h @@ -0,0 +1,43 @@ +struct Ureg +{ + ulong cause; + ulong status; + ulong pc; /* SRR0 */ + ulong pad; + ulong lr; + ulong cr; + ulong xer; + ulong ctr; + ulong r0; + ulong sp; + ulong r2; + ulong r3; + ulong r4; + ulong r5; + ulong r6; + ulong r7; + ulong r8; + ulong r9; + ulong r10; + ulong r11; + ulong r12; + ulong r13; + ulong r14; + ulong r15; + ulong r16; + ulong r17; + ulong r18; + ulong r19; + ulong r20; + ulong r21; + ulong r22; + ulong r23; + ulong r24; + ulong r25; + ulong r26; + ulong r27; + ulong r28; + ulong r29; + ulong r30; + ulong r31; +}; diff --git a/utils/libmach/uregt.h b/utils/libmach/uregt.h new file mode 100644 index 00000000..ffdad423 --- /dev/null +++ b/utils/libmach/uregt.h @@ -0,0 +1,21 @@ +struct Ureg { + uint r0; + uint r1; + uint r2; + uint r3; + uint r4; + uint r5; + uint r6; + uint r7; + uint r8; + uint r9; + uint r10; + uint r11; + uint r12; + uint r13; + uint r14; + uint link; + uint type; + uint psr; + uint pc; +}; diff --git a/utils/libmach/uregv.h b/utils/libmach/uregv.h new file mode 100644 index 00000000..def45d2d --- /dev/null +++ b/utils/libmach/uregv.h @@ -0,0 +1,44 @@ +struct Ureg +{ + ulong status; + ulong pc; + union{ + ulong sp; /* r29 */ + ulong usp; /* r29 */ + } u0; + ulong cause; + ulong badvaddr; + ulong tlbvirt; + ulong hi; + ulong lo; + ulong r31; + ulong r30; + ulong r28; + ulong r27; /* unused */ + ulong r26; /* unused */ + ulong r25; + ulong r24; + ulong r23; + ulong r22; + ulong r21; + ulong r20; + ulong r19; + ulong r18; + ulong r17; + ulong r16; + ulong r15; + ulong r14; + ulong r13; + ulong r12; + ulong r11; + ulong r10; + ulong r9; + ulong r8; + ulong r7; + ulong r6; + ulong r5; + ulong r4; + ulong r3; + ulong r2; + ulong r1; +}; diff --git a/utils/libmach/v.c b/utils/libmach/v.c new file mode 100644 index 00000000..add94113 --- /dev/null +++ b/utils/libmach/v.c @@ -0,0 +1,116 @@ +/* + * mips definition + */ +#include <lib9.h> +#include <bio.h> +#include "uregv.h" +#include "mach.h" + +#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x) + +#define SP REGOFF(u0.sp) +#define PC REGOFF(pc) +#define R1 REGOFF(r1) +#define R31 REGOFF(r31) +#define FP_REG(x) (R1+4+4*(x)) + +#define REGSIZE sizeof(struct Ureg) +#define FPREGSIZE (4*33) + +Reglist mipsreglist[] = { + {"STATUS", REGOFF(status), RINT|RRDONLY, 'X'}, + {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'}, + {"BADVADDR", REGOFF(badvaddr), RINT|RRDONLY, 'X'}, + {"TLBVIRT", REGOFF(tlbvirt), RINT|RRDONLY, 'X'}, + {"HI", REGOFF(hi), RINT|RRDONLY, 'X'}, + {"LO", REGOFF(lo), RINT|RRDONLY, 'X'}, + {"PC", PC, RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"R31", R31, RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + {"F0", FP_REG(0), RFLT, 'F'}, + {"F1", FP_REG(1), RFLT, 'f'}, + {"F2", FP_REG(2), RFLT, 'F'}, + {"F3", FP_REG(3), RFLT, 'f'}, + {"F4", FP_REG(4), RFLT, 'F'}, + {"F5", FP_REG(5), RFLT, 'f'}, + {"F6", FP_REG(6), RFLT, 'F'}, + {"F7", FP_REG(7), RFLT, 'f'}, + {"F8", FP_REG(8), RFLT, 'F'}, + {"F9", FP_REG(9), RFLT, 'f'}, + {"F10", FP_REG(10), RFLT, 'F'}, + {"F11", FP_REG(11), RFLT, 'f'}, + {"F12", FP_REG(12), RFLT, 'F'}, + {"F13", FP_REG(13), RFLT, 'f'}, + {"F14", FP_REG(14), RFLT, 'F'}, + {"F15", FP_REG(15), RFLT, 'f'}, + {"F16", FP_REG(16), RFLT, 'F'}, + {"F17", FP_REG(17), RFLT, 'f'}, + {"F18", FP_REG(18), RFLT, 'F'}, + {"F19", FP_REG(19), RFLT, 'f'}, + {"F20", FP_REG(20), RFLT, 'F'}, + {"F21", FP_REG(21), RFLT, 'f'}, + {"F22", FP_REG(22), RFLT, 'F'}, + {"F23", FP_REG(23), RFLT, 'f'}, + {"F24", FP_REG(24), RFLT, 'F'}, + {"F25", FP_REG(25), RFLT, 'f'}, + {"F26", FP_REG(26), RFLT, 'F'}, + {"F27", FP_REG(27), RFLT, 'f'}, + {"F28", FP_REG(28), RFLT, 'F'}, + {"F29", FP_REG(29), RFLT, 'f'}, + {"F30", FP_REG(30), RFLT, 'F'}, + {"F31", FP_REG(31), RFLT, 'f'}, + {"FPCR", FP_REG(32), RFLT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mmips = +{ + "mips", + MMIPS, /* machine type */ + mipsreglist, /* register set */ + REGSIZE, /* number of bytes in reg set */ + FPREGSIZE, /* number of bytes in fp reg set */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R31", /* name of link register */ + "setR30", /* static base register name */ + 0, /* value */ + 0x1000, /* page size */ + 0xC0000000, /* kernel base */ + 0x40000000, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/vcodas.c b/utils/libmach/vcodas.c new file mode 100644 index 00000000..ce505ea2 --- /dev/null +++ b/utils/libmach/vcodas.c @@ -0,0 +1,553 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" + + /* mips native disassembler */ + +typedef struct { + long addr; /* pc of instr */ + uchar op; /* bits 31-26 */ + uchar rs; /* bits 25-21 */ + uchar rt; /* bits 20-16 */ + uchar rd; /* bits 15-11 */ + uchar sa; /* bits 10-6 */ + uchar function; /* bits 5-0 */ + long immediate; /* bits 15-0 */ + ulong cofun; /* bits 24-0 */ + ulong target; /* bits 25-0 */ + long w0; + char *curr; /* current fill point */ + char *end; /* end of buffer */ + char *err; +} Instr; + +typedef struct { + char *mnemonic; + char *mipsco; +} Opcode; + +static char mipscoload[] = "r%t,%l"; +static char mipscoalui[] = "r%t,r%s,%i"; +static char mipscoalu3op[] = "r%d,r%s,r%t"; +static char mipscoboc[] = "r%s,r%t,%b"; +static char mipscoboc0[] = "r%s,%b"; +static char mipscorsrt[] = "r%s,r%t"; +static char mipscorsi[] = "r%s,%i"; +static char mipscoxxx[] = "%w"; +static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */ +static char mipscofp2[] = "f%a,f%d"; /* fd,fs */ +static char mipscofpc[] = "f%d,f%t"; /* fs,ft */ + +static Opcode opcodes[64] = { + 0, 0, + 0, 0, + "j", "%j", + "jal", "%j", + "beq", mipscoboc, + "bne", mipscoboc, + "blez", mipscoboc0, + "bgtz", mipscoboc0, + "addi", mipscoalui, + "addiu", mipscoalui, + "slti", mipscoalui, + "sltiu", mipscoalui, + "andi", mipscoalui, + "ori", mipscoalui, + "xori", mipscoalui, + "lui", "r%t,%u", + "cop0", 0, + "cop1", 0, + "cop2", 0, + "cop3", 0, + "beql", mipscoboc, + "bnel", mipscoboc, + "blezl", mipscoboc0, + "bgtzl", mipscoboc0, + "instr18", mipscoxxx, + "instr19", mipscoxxx, + "instr1A", mipscoxxx, + "instr1B", mipscoxxx, + "instr1C", mipscoxxx, + "instr1D", mipscoxxx, + "instr1E", mipscoxxx, + "instr1F", mipscoxxx, + "lb", mipscoload, + "lh", mipscoload, + "lwl", mipscoload, + "lw", mipscoload, + "lbu", mipscoload, + "lhu", mipscoload, + "lwr", mipscoload, + "instr27", mipscoxxx, + "sb", mipscoload, + "sh", mipscoload, + "swl", mipscoload, + "sw", mipscoload, + "instr2C", mipscoxxx, + "instr2D", mipscoxxx, + "swr", mipscoload, + "cache", "", + "ll", mipscoload, + "lwc1", mipscoload, + "lwc2", mipscoload, + "lwc3", mipscoload, + "instr34", mipscoxxx, + "ld", mipscoload, + "ld", mipscoload, + "ld", mipscoload, + "sc", mipscoload, + "swc1", mipscoload, + "swc2", mipscoload, + "swc3", mipscoload, + "instr3C", mipscoxxx, + "sd", mipscoload, + "sd", mipscoload, + "sd", mipscoload, +}; + +static Opcode sopcodes[64] = { + "sll", "r%d,r%t,$%a", + "special01", mipscoxxx, + "srl", "r%d,r%t,$%a", + "sra", "r%d,r%t,$%a", + "sllv", "r%d,r%t,R%s", + "special05", mipscoxxx, + "srlv", "r%d,r%t,r%s", + "srav", "r%d,r%t,r%s", + "jr", "r%s", + "jalr", "r%d,r%s", + "special0A", mipscoxxx, + "special0B", mipscoxxx, + "syscall", "", + "break", "", + "special0E", mipscoxxx, + "sync", "", + "mfhi", "r%d", + "mthi", "r%s", + "mflo", "r%d", + "mtlo", "r%s", + "special14", mipscoxxx, + "special15", mipscoxxx, + "special16", mipscoxxx, + "special17", mipscoxxx, + "mult", mipscorsrt, + "multu", mipscorsrt, + "div", mipscorsrt, + "divu", mipscorsrt, + "special1C", mipscoxxx, + "special1D", mipscoxxx, + "special1E", mipscoxxx, + "special1F", mipscoxxx, + "add", mipscoalu3op, + "addu", mipscoalu3op, + "sub", mipscoalu3op, + "subu", mipscoalu3op, + "and", mipscoalu3op, + "or", mipscoalu3op, + "xor", mipscoalu3op, + "nor", mipscoalu3op, + "special28", mipscoxxx, + "special29", mipscoxxx, + "slt", mipscoalu3op, + "sltu", mipscoalu3op, + "special2C", mipscoxxx, + "special2D", mipscoxxx, + "special2E", mipscoxxx, + "special2F", mipscoxxx, + "tge", mipscorsrt, + "tgeu", mipscorsrt, + "tlt", mipscorsrt, + "tltu", mipscorsrt, + "teq", mipscorsrt, + "special35", mipscoxxx, + "tne", mipscorsrt, + "special37", mipscoxxx, + "special38", mipscoxxx, + "special39", mipscoxxx, + "special3A", mipscoxxx, + "special3B", mipscoxxx, + "special3C", mipscoxxx, + "special3D", mipscoxxx, + "special3E", mipscoxxx, + "special3F", mipscoxxx, +}; + +static Opcode ropcodes[32] = { + "bltz", mipscoboc0, + "bgez", mipscoboc0, + "bltzl", mipscoboc0, + "bgezl", mipscoboc0, + "regimm04", mipscoxxx, + "regimm05", mipscoxxx, + "regimm06", mipscoxxx, + "regimm07", mipscoxxx, + "tgei", mipscorsi, + "tgeiu", mipscorsi, + "tlti", mipscorsi, + "tltiu", mipscorsi, + "teqi", mipscorsi, + "regimm0D", mipscoxxx, + "tnei", mipscorsi, + "regimm0F", mipscoxxx, + "bltzal", mipscoboc0, + "bgezal", mipscoboc0, + "bltzall", mipscoboc0, + "bgezall", mipscoboc0, + "regimm14", mipscoxxx, + "regimm15", mipscoxxx, + "regimm16", mipscoxxx, + "regimm17", mipscoxxx, + "regimm18", mipscoxxx, + "regimm19", mipscoxxx, + "regimm1A", mipscoxxx, + "regimm1B", mipscoxxx, + "regimm1C", mipscoxxx, + "regimm1D", mipscoxxx, + "regimm1E", mipscoxxx, + "regimm1F", mipscoxxx, +}; + +static Opcode fopcodes[64] = { + "add.%f", mipscofp3, + "sub.%f", mipscofp3, + "mul.%f", mipscofp3, + "div.%f", mipscofp3, + "sqrt.%f", mipscofp2, + "abs.%f", mipscofp2, + "mov.%f", mipscofp2, + "neg.%f", mipscofp2, + "finstr08", mipscoxxx, + "finstr09", mipscoxxx, + "finstr0A", mipscoxxx, + "finstr0B", mipscoxxx, + "round.w.%f", mipscofp2, + "trunc.w%f", mipscofp2, + "ceil.w%f", mipscofp2, + "floor.w%f", mipscofp2, + "finstr10", mipscoxxx, + "finstr11", mipscoxxx, + "finstr12", mipscoxxx, + "finstr13", mipscoxxx, + "finstr14", mipscoxxx, + "finstr15", mipscoxxx, + "finstr16", mipscoxxx, + "finstr17", mipscoxxx, + "finstr18", mipscoxxx, + "finstr19", mipscoxxx, + "finstr1A", mipscoxxx, + "finstr1B", mipscoxxx, + "finstr1C", mipscoxxx, + "finstr1D", mipscoxxx, + "finstr1E", mipscoxxx, + "finstr1F", mipscoxxx, + "cvt.s.%f", mipscofp2, + "cvt.d.%f", mipscofp2, + "cvt.e.%f", mipscofp2, + "cvt.q.%f", mipscofp2, + "cvt.w.%f", mipscofp2, + "finstr25", mipscoxxx, + "finstr26", mipscoxxx, + "finstr27", mipscoxxx, + "finstr28", mipscoxxx, + "finstr29", mipscoxxx, + "finstr2A", mipscoxxx, + "finstr2B", mipscoxxx, + "finstr2C", mipscoxxx, + "finstr2D", mipscoxxx, + "finstr2E", mipscoxxx, + "finstr2F", mipscoxxx, + "c.f.%f", mipscofpc, + "c.un.%f", mipscofpc, + "c.eq.%f", mipscofpc, + "c.ueq.%f", mipscofpc, + "c.olt.%f", mipscofpc, + "c.ult.%f", mipscofpc, + "c.ole.%f", mipscofpc, + "c.ule.%f", mipscofpc, + "c.sf.%f", mipscofpc, + "c.ngle.%f", mipscofpc, + "c.seq.%f", mipscofpc, + "c.ngl.%f", mipscofpc, + "c.lt.%f", mipscofpc, + "c.nge.%f", mipscofpc, + "c.le.%f", mipscofpc, + "c.ngt.%f", mipscofpc, +}; + +static char fsub[16] = { + 's', 'd', 'e', 'q', 'w', '?', '?', '?', + '?', '?', '?', '?', '?', '?', '?', '?' +}; + + +static int +mkinstr(Instr *i, Map *map, ulong pc) +{ + long w; + + if (get4(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->addr = pc; + i->op = (w >> 26) & 0x3F; + i->rs = (w >> 21) & 0x1F; + i->rt = (w >> 16) & 0x1F; + i->rd = (w >> 11) & 0x1F; + i->sa = (w >> 6) & 0x1F; + i->function = w & 0x3F; + i->immediate = w & 0x0000FFFF; + if (i->immediate & 0x8000) + i->immediate |= ~0x0000FFFF; + i->cofun = w & 0x01FFFFFF; + i->target = w & 0x03FFFFFF; + i->w0 = w; + return 1; +} + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static void +format(char *mnemonic, Instr *i, char *f) +{ + if (mnemonic) + format(0, i, mnemonic); + if (f == 0) + return; + if (i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if (*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 's': + bprint(i, "%d", i->rs); + break; + + case 't': + bprint(i, "%d", i->rt); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'a': + bprint(i, "%d", i->sa); + break; + + case 'l': + if (i->rs == 30) { + i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); + bprint(i, "(SB)"); + } else + bprint(i, "%lx(r%d)", i->immediate, i->rs); + break; + + case 'i': + bprint(i, "$%lx", i->immediate); + break; + + case 'u': + *i->curr++ = '$'; + i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY); + bprint(i, "(SB)"); + break; + + case 'j': + i->curr += symoff(i->curr, i->end-i->curr, + (i->target<<2)|(i->addr & 0xF0000000), CANY); + bprint(i, "(SB)"); + break; + + case 'b': + i->curr += symoff(i->curr, i->end-i->curr, + (i->immediate<<2)+i->addr+4, CANY); + break; + + case 'c': + bprint(i, "%lux", i->cofun); + break; + + case 'w': + bprint(i, "[%lux]", i->w0); + break; + + case 'f': + *i->curr++ = fsub[i->rs & 0x0F]; + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } +} + +static void +copz(int cop, Instr *i) +{ + char *f, *m, buf[16]; + + m = buf; + f = "%t,%d"; + switch (i->rs) { + + case 0: + sprint(buf, "mfc%d", cop); + break; + + case 2: + sprint(buf, "cfc%d", cop); + break; + + case 4: + sprint(buf, "mtc%d", cop); + break; + + case 6: + sprint(buf, "ctc%d", cop); + break; + + case 8: + f = "%b"; + switch (i->rt) { + + case 0: + sprint(buf, "bc%df", cop); + break; + + case 1: + sprint(buf, "bc%dt", cop); + break; + + case 2: + sprint(buf, "bc%dfl", cop); + break; + + case 3: + sprint(buf, "bc%dtl", cop); + break; + + default: + sprint(buf, "cop%d", cop); + f = mipscoxxx; + break; + } + break; + + default: + sprint(buf, "cop%d", cop); + if (i->rs & 0x10) + f = "function %c"; + else + f = mipscoxxx; + break; + } + format(m, i, f); +} + +static void +cop0(Instr *i) +{ + char *m = 0; + + if (i->rs >= 0x10) { + switch (i->cofun) { + + case 1: + m = "tlbr"; + break; + + case 2: + m = "tlbwi"; + break; + + case 6: + m = "tlbwr"; + break; + + case 8: + m = "tlbp"; + break; + + case 16: + m = "rfe"; + break; + + case 32: + m = "eret"; + break; + } + if (m) { + format(m, i, 0); + if (i->curr < i->end) + *i->curr++ = 0; + return; + } + } + copz(0, i); +} + +int +_mipscoinst(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + Opcode *o; + uchar op; + + i.curr = buf; + i.end = buf+n-1; + if (mkinstr(&i, map, pc) < 0) + return -1; + switch (i.op) { + + case 0x00: /* SPECIAL */ + o = sopcodes; + op = i.function; + break; + + case 0x01: /* REGIMM */ + o = ropcodes; + op = i.rt; + break; + + case 0x10: /* COP0 */ + cop0(&i); + return 4; + + case 0x11: /* COP1 */ + if (i.rs & 0x10) { + o = fopcodes; + op = i.function; + break; + } + /*FALLTHROUGH*/ + case 0x12: /* COP2 */ + case 0x13: /* COP3 */ + copz(i.op-0x10, &i); + return 4; + + default: + o = opcodes; + op = i.op; + break; + } + format(o[op].mnemonic, &i, o[op].mipsco); + return 4; +} diff --git a/utils/libmach/vdb.c b/utils/libmach/vdb.c new file mode 100644 index 00000000..0624a106 --- /dev/null +++ b/utils/libmach/vdb.c @@ -0,0 +1,1094 @@ +#include <lib9.h> +#include <bio.h> +#include "mach.h" +/* + * Mips-specific debugger interface + */ + +extern char *mipsexcep(Map*, Rgetter); +extern int mipsfoll(Map*, ulong, Rgetter, ulong*); +extern int mipsinst(Map*, ulong, char, char*, int); +extern int mipsdas(Map*, ulong, char*, int); +extern int mipsinstlen(Map*, ulong); +/* + * Debugger interface + */ +Machdata mipsmach = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + beswab, /* short to local byte order */ + beswal, /* long to local byte order */ + beswav, /* vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + mipsexcep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precisioin float printer */ + mipsfoll, /* following addresses */ + mipsinst, /* print instruction */ + mipsdas, /* dissembler */ + mipsinstlen, /* instruction size */ +}; + +static char *excname[] = +{ + "external interrupt", + "TLB modification", + "TLB miss (load or fetch)", + "TLB miss (store)", + "address error (load or fetch)", + "address error (store)", + "bus error (fetch)", + "bus error (data load or store)", + "system call", + "breakpoint", + "reserved instruction", + "coprocessor unusable", + "arithmetic overflow", + "undefined 13", + "undefined 14", + "system call", + /* the following is made up */ + "floating point exception" /* FPEXC */ +}; + +char* +mipsexcep(Map *map, Rgetter rget) +{ + int e; + long c; + + c = (*rget)(map, "CAUSE"); + if(c & 0x00002000) /* INTR3 */ + e = 16; /* Floating point exception */ + else + e = (c>>2)&0x0F; + return excname[e]; +} + + /* mips disassembler and related functions */ + +static char FRAMENAME[] = ".frame"; + +typedef struct { + ulong addr; + uchar op; /* bits 31-26 */ + uchar rs; /* bits 25-21 */ + uchar rt; /* bits 20-16 */ + uchar rd; /* bits 15-11 */ + uchar sa; /* bits 10-6 */ + uchar function; /* bits 5-0 */ + long immediate; /* bits 15-0 */ + ulong cofun; /* bits 24-0 */ + ulong target; /* bits 25-0 */ + long w0; + long w1; + int size; /* instruction size */ + char *curr; /* fill point in buffer */ + char *end; /* end of buffer */ + char *err; /* error message */ +} Instr; + +static Map *mymap; + +static int +decode(ulong pc, Instr *i) +{ + long w; + + if (get4(mymap, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->addr = pc; + i->size = 1; + i->op = (w >> 26) & 0x3F; + i->rs = (w >> 21) & 0x1F; + i->rt = (w >> 16) & 0x1F; + i->rd = (w >> 11) & 0x1F; + i->sa = (w >> 6) & 0x1F; + i->function = w & 0x3F; + i->immediate = w & 0x0000FFFF; + if (i->immediate & 0x8000) + i->immediate |= ~0x0000FFFF; + i->cofun = w & 0x01FFFFFF; + i->target = w & 0x03FFFFFF; + i->w0 = w; + return 1; +} + +static int +mkinstr(ulong pc, Instr *i) +{ + Instr x; + + if (decode(pc, i) < 0) + return -1; + /* + * if it's a LUI followed by an ORI, + * it's an immediate load of a large constant. + * fix the LUI immediate in any case. + */ + if (i->op == 0x0F) { + if (decode(pc+4, &x) < 0) + return 0; + i->immediate <<= 16; + if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) { + i->immediate |= (x.immediate & 0xFFFF); + i->w1 = x.w0; + i->size++; + return 1; + } + } + /* + * if it's a LWC1 followed by another LWC1 + * into an adjacent register, it's a load of + * a floating point double. + */ + else if (i->op == 0x31 && (i->rt & 0x01)) { + if (decode(pc+4, &x) < 0) + return 0; + if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) { + i->rt -= 1; + i->w1 = x.w0; + i->size++; + return 1; + } + } + /* + * similarly for double stores + */ + else if (i->op == 0x39 && (i->rt & 0x01)) { + if (decode(pc+4, &x) < 0) + return 0; + if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) { + i->rt -= 1; + i->w1 = x.w0; + i->size++; + } + } + return 1; +} + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +typedef struct Opcode Opcode; + +struct Opcode { + char *mnemonic; + void (*f)(Opcode *, Instr *); + char *ken; +}; + +static void format(char *, Instr *, char *); + +static void +branch(Opcode *o, Instr *i) +{ + if (i->rs == 0 && i->rt == 0) + format("JMP", i, "%b"); + else if (i->rs == 0) + format(o->mnemonic, i, "R%t,%b"); + else if (i->rt < 2) + format(o->mnemonic, i, "R%s,%b"); + else + format(o->mnemonic, i, "R%s,R%t,%b"); +} + +static void +addi(Opcode *o, Instr *i) +{ + if (i->rs == i->rt) + format(o->mnemonic, i, "%i,R%t"); + else if (i->rs == 0) + format("MOVW", i, "%i,R%t"); + else if (i->rs == 30) { + bprint(i, "MOVW\t$"); + i->curr += symoff(i->curr, i->end-i->curr, + i->immediate+mach->sb, CANY); + bprint(i, "(SB),R%d", i->rt); + } + else + format(o->mnemonic, i, o->ken); +} + +static void +andi(Opcode *o, Instr *i) +{ + if (i->rs == i->rt) + format(o->mnemonic, i, "%i,R%t"); + else + format(o->mnemonic, i, o->ken); +} + +static int +plocal(Instr *i, char *m, char r, int store) +{ + int offset; + char *reg; + Symbol s; + + if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) + return 0; + if (s.value > i->immediate) { + if(!getauto(&s, s.value-i->immediate, CAUTO, &s)) + return 0; + reg = "(SP)"; + offset = i->immediate; + } else { + offset = i->immediate-s.value; + if (!getauto(&s, offset-4, CPARAM, &s)) + return 0; + reg = "(FP)"; + } + if (store) + bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg); + else + bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt); + return 1; +} + +static void +lw(Opcode *o, Instr *i, char r) +{ + char *m; + + if (r == 'F') { + if (i->size == 2) + m = "MOVD"; + else + m = "MOVF"; + } + else + m = o->mnemonic; + if (i->rs == 29 && plocal(i, m, r, 0)) + return; + + if (i->rs == 30 && mach->sb) { + bprint(i, "%s\t", m); + i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); + bprint(i, "(SB),%c%d", r, i->rt); + return; + } + if (r == 'F') + format(m, i, "%l,F%t"); + else + format(m, i, o->ken); +} + +static void +load(Opcode *o, Instr *i) +{ + lw(o, i, 'R'); +} + +static void +lwc1(Opcode *o, Instr *i) +{ + lw(o, i, 'F'); +} + +static void +sw(Opcode *o, Instr *i, char r) +{ + char *m; + + if (r == 'F') { + if (i->size == 2) + m = "MOVD"; + else + m = "MOVF"; + } + else + m = o->mnemonic; + if (i->rs == 29 && plocal(i, m, r, 1)) + return; + + if (i->rs == 30 && mach->sb) { + bprint(i, "%s\t%c%d,", m, r, i->rt); + i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY); + bprint(i, "(SB)"); + return; + } + if (r == 'F') + format(m, i, "F%t,%l"); + else + format(m, i, o->ken); +} + +static void +store(Opcode *o, Instr *i) +{ + sw(o, i, 'R'); +} + +static void +swc1(Opcode *o, Instr *i) +{ + sw(o, i, 'F'); +} + +static void +sll(Opcode *o, Instr *i) +{ + if (i->w0 == 0) + bprint(i, "NOOP"); + else if (i->rd == i->rt) + format(o->mnemonic, i, "$%a,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sl32(Opcode *o, Instr *i) +{ + i->sa += 32; + if (i->rd == i->rt) + format(o->mnemonic, i, "$%a,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sllv(Opcode *o, Instr *i) +{ + if (i->rd == i->rt) + format(o->mnemonic, i, "R%s,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +jal(Opcode *o, Instr *i) +{ + if (i->rd == 31) + format("JAL", i, "(R%s)"); + else + format(o->mnemonic, i, o->ken); +} + +static void +add(Opcode *o, Instr *i) +{ + if (i->rd == i->rs) + format(o->mnemonic, i, "R%t,R%d"); + else if (i->rd == i->rt) + format(o->mnemonic, i, "R%s,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +sub(Opcode *o, Instr *i) +{ + if (i->rd == i->rs) + format(o->mnemonic, i, "R%t,R%d"); + else + format(o->mnemonic, i, o->ken); +} + +static void +or(Opcode *o, Instr *i) +{ + if (i->rs == 0 && i->rt == 0) + format("MOVW", i, "$0,R%d"); + else if (i->rs == 0) + format("MOVW", i, "R%t,R%d"); + else if (i->rt == 0) + format("MOVW", i, "R%s,R%d"); + else + add(o, i); +} + +static void +nor(Opcode *o, Instr *i) +{ + if (i->rs == 0 && i->rt == 0 && i->rd == 0) + format("NOP", i, 0); + else + add(o, i); +} + +static char mipscoload[] = "r%t,%l"; +static char mipsload[] = "%l,R%t"; +static char mipsstore[] = "R%t,%l"; +static char mipsalui[] = "%i,R%s,R%t"; +static char mipsalu3op[] = "R%t,R%s,R%d"; +static char mipsrtrs[] = "R%t,R%s"; +static char mipscorsrt[] = "r%s,r%t"; +static char mipscorsi[] = "r%s,%i"; +static char mipscoxxx[] = "%w"; +static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */ +static char mipsfp3[] = "F%t,F%d,F%a"; +static char mipscofp2[] = "f%a,f%d"; /* fd,fs */ +static char mipsfp2[] = "F%d,F%a"; +static char mipscofpc[] = "f%d,f%t"; /* fs,ft */ +static char mipsfpc[] = "F%t,F%d"; + +static Opcode opcodes[64] = { + 0, 0, 0, + 0, 0, 0, + "JMP", 0, "%j", + "JAL", 0, "%j", + "BEQ", branch, 0, + "BNE", branch, 0, + "BLEZ", branch, 0, + "BGTZ", branch, 0, + "ADD", addi, mipsalui, + "ADDU", addi, mipsalui, + "SGT", 0, mipsalui, + "SGTU", 0, mipsalui, + "AND", andi, mipsalui, + "OR", andi, mipsalui, + "XOR", andi, mipsalui, + "MOVW", 0, "$%u,R%t", + "cop0", 0, 0, + "cop1", 0, 0, + "cop2", 0, 0, + "cop3", 0, 0, + "BEQL", branch, 0, + "BNEL", branch, 0, + "BLEZL", branch, 0, + "BGTZL", branch, 0, + "instr18", 0, mipscoxxx, + "instr19", 0, mipscoxxx, + "MOVVL", load, mipsload, + "MOVVR", load, mipsload, + "instr1C", 0, mipscoxxx, + "instr1D", 0, mipscoxxx, + "instr1E", 0, mipscoxxx, + "instr1F", 0, mipscoxxx, + "MOVB", load, mipsload, + "MOVH", load, mipsload, + "lwl", 0, mipscoload, + "MOVW", load, mipsload, + "MOVBU", load, mipsload, + "MOVHU", load, mipsload, + "lwr", 0, mipscoload, + "instr27", 0, mipscoxxx, + "MOVB", store, mipsstore, + "MOVH", store, mipsstore, + "swl", 0, mipscoload, + "MOVW", store, mipsstore, + "MOVVL", store, mipsstore, + "MOVVR", store, mipsstore, + "swr", 0, mipscoload, + "CACHE", 0, "%C,%l", + "ll", 0, mipscoload, + "MOVW", lwc1, mipscoload, + "lwc2", 0, mipscoload, + "lwc3", 0, mipscoload, + "instr34", 0, mipscoxxx, + "ldc1", 0, mipscoload, + "ldc2", 0, mipscoload, + "MOVV", load, mipsload, + "sc", 0, mipscoload, + "swc1", swc1, mipscoload, + "swc2", 0, mipscoload, + "swc3", 0, mipscoload, + "instr3C", 0, mipscoxxx, + "sdc1", 0, mipscoload, + "sdc2", 0, mipscoload, + "MOVV", store, mipsstore, +}; + +static Opcode sopcodes[64] = { + "SLL", sll, "$%a,R%t,R%d", + "special01", 0, mipscoxxx, + "SRL", sll, "$%a,R%t,R%d", + "SRA", sll, "$%a,R%t,R%d", + "SLL", sllv, "R%s,R%t,R%d", + "special05", 0, mipscoxxx, + "SRL", sllv, "R%s,R%t,R%d", + "SRA", sllv, "R%s,R%t,R%d", + "JMP", 0, "(R%s)", + "jal", jal, "r%d,r%s", + "special0A", 0, mipscoxxx, + "special0B", 0, mipscoxxx, + "SYSCALL", 0, 0, + "BREAK", 0, 0, + "special0E", 0, mipscoxxx, + "SYNC", 0, 0, + "MOVW", 0, "HI,R%d", + "MOVW", 0, "R%s,HI", + "MOVW", 0, "LO,R%d", + "MOVW", 0, "R%s,LO", + "SLLV", sllv, "R%s,R%t,R%d", + "special15", 0, mipscoxxx, + "SRLV", sllv, "R%s,R%t,R%d", + "SRAV", sllv, "R%s,R%t,R%d", + "MUL", 0, mipsrtrs, + "MULU", 0, mipsrtrs, + "DIV", 0, mipsrtrs, + "DIVU", 0, mipsrtrs, + "special1C", 0, mipscoxxx, + "special1D", 0, mipscoxxx, + "DDIV", 0, "R%s,R%t", + "special1F", 0, mipscoxxx, + "ADD", add, mipsalu3op, + "ADDU", add, mipsalu3op, + "SUB", sub, mipsalu3op, + "SUBU", sub, mipsalu3op, + "AND", add, mipsalu3op, + "OR", or, mipsalu3op, + "XOR", add, mipsalu3op, + "NOR", nor, mipsalu3op, + "special28", 0, mipscoxxx, + "special29", 0, mipscoxxx, + "SGT", 0, mipsalu3op, + "SGTU", 0, mipsalu3op, + "special2C", 0, mipscoxxx, + "special2D", 0, mipscoxxx, + "special2E", 0, mipscoxxx, + "DSUBU", 0, "R%s,R%t,R%d", + "tge", 0, mipscorsrt, + "tgeu", 0, mipscorsrt, + "tlt", 0, mipscorsrt, + "tltu", 0, mipscorsrt, + "teq", 0, mipscorsrt, + "special35", 0, mipscoxxx, + "tne", 0, mipscorsrt, + "special37", 0, mipscoxxx, + "SLLV", sll, "$%a,R%t,R%d", + "special39", 0, mipscoxxx, + "SRLV", sll, "$%a,R%t,R%d", + "SRAV", sll, "$%a,R%t,R%d", + "SLLV", sl32, "$%a,R%t,R%d", + "special3D", 0, mipscoxxx, + "SRLV", sl32, "$%a,R%t,R%d", + "SRAV", sl32, "$%a,R%t,R%d", +}; + +static Opcode ropcodes[32] = { + "BLTZ", branch, 0, + "BGEZ", branch, 0, + "BLTZL", branch, 0, + "BGEZL", branch, 0, + "regimm04", 0, mipscoxxx, + "regimm05", 0, mipscoxxx, + "regimm06", 0, mipscoxxx, + "regimm07", 0, mipscoxxx, + "tgei", 0, mipscorsi, + "tgeiu", 0, mipscorsi, + "tlti", 0, mipscorsi, + "tltiu", 0, mipscorsi, + "teqi", 0, mipscorsi, + "regimm0D", 0, mipscoxxx, + "tnei", 0, mipscorsi, + "regimm0F", 0, mipscoxxx, + "BLTZAL", branch, 0, + "BGEZAL", branch, 0, + "BLTZALL", branch, 0, + "BGEZALL", branch, 0, + "regimm14", 0, mipscoxxx, + "regimm15", 0, mipscoxxx, + "regimm16", 0, mipscoxxx, + "regimm17", 0, mipscoxxx, + "regimm18", 0, mipscoxxx, + "regimm19", 0, mipscoxxx, + "regimm1A", 0, mipscoxxx, + "regimm1B", 0, mipscoxxx, + "regimm1C", 0, mipscoxxx, + "regimm1D", 0, mipscoxxx, + "regimm1E", 0, mipscoxxx, + "regimm1F", 0, mipscoxxx, +}; + +static Opcode fopcodes[64] = { + "ADD%f", 0, mipsfp3, + "SUB%f", 0, mipsfp3, + "MUL%f", 0, mipsfp3, + "DIV%f", 0, mipsfp3, + "sqrt.%f", 0, mipscofp2, + "ABS%f", 0, mipsfp2, + "MOV%f", 0, mipsfp2, + "NEG%f", 0, mipsfp2, + "finstr08", 0, mipscoxxx, + "finstr09", 0, mipscoxxx, + "finstr0A", 0, mipscoxxx, + "finstr0B", 0, mipscoxxx, + "round.w.%f", 0, mipscofp2, + "trunc.w%f", 0, mipscofp2, + "ceil.w%f", 0, mipscofp2, + "floor.w%f", 0, mipscofp2, + "finstr10", 0, mipscoxxx, + "finstr11", 0, mipscoxxx, + "finstr12", 0, mipscoxxx, + "finstr13", 0, mipscoxxx, + "finstr14", 0, mipscoxxx, + "finstr15", 0, mipscoxxx, + "finstr16", 0, mipscoxxx, + "finstr17", 0, mipscoxxx, + "finstr18", 0, mipscoxxx, + "finstr19", 0, mipscoxxx, + "finstr1A", 0, mipscoxxx, + "finstr1B", 0, mipscoxxx, + "finstr1C", 0, mipscoxxx, + "finstr1D", 0, mipscoxxx, + "finstr1E", 0, mipscoxxx, + "finstr1F", 0, mipscoxxx, + "cvt.s.%f", 0, mipscofp2, + "cvt.d.%f", 0, mipscofp2, + "cvt.e.%f", 0, mipscofp2, + "cvt.q.%f", 0, mipscofp2, + "cvt.w.%f", 0, mipscofp2, + "finstr25", 0, mipscoxxx, + "finstr26", 0, mipscoxxx, + "finstr27", 0, mipscoxxx, + "finstr28", 0, mipscoxxx, + "finstr29", 0, mipscoxxx, + "finstr2A", 0, mipscoxxx, + "finstr2B", 0, mipscoxxx, + "finstr2C", 0, mipscoxxx, + "finstr2D", 0, mipscoxxx, + "finstr2E", 0, mipscoxxx, + "finstr2F", 0, mipscoxxx, + "c.f.%f", 0, mipscofpc, + "c.un.%f", 0, mipscofpc, + "CMPEQ%f", 0, mipsfpc, + "c.ueq.%f", 0, mipscofpc, + "c.olt.%f", 0, mipscofpc, + "c.ult.%f", 0, mipscofpc, + "c.ole.%f", 0, mipscofpc, + "c.ule.%f", 0, mipscofpc, + "c.sf.%f", 0, mipscofpc, + "c.ngle.%f", 0, mipscofpc, + "c.seq.%f", 0, mipscofpc, + "c.ngl.%f", 0, mipscofpc, + "CMPGT%f", 0, mipsfpc, + "c.nge.%f", 0, mipscofpc, + "CMPGE%f", 0, mipsfpc, + "c.ngt.%f", 0, mipscofpc, +}; + +static char *cop0regs[32] = { + "INDEX", "RANDOM", "TLBPHYS", "EntryLo0", + "CONTEXT", "PageMask", "Wired", "Error", + "BADVADDR", "Count", "TLBVIRT", "Compare", + "STATUS", "CAUSE", "EPC", "PRID", + "Config", "LLadr", "WatchLo", "WatchHi", + "20", "21", "22", "23", + "24", "25", "26", "CacheErr", + "TagLo", "TagHi", "ErrorEPC", "31" +}; + +static char fsub[16] = { + 'F', 'D', 'e', 'q', 'W', '?', '?', '?', + '?', '?', '?', '?', '?', '?', '?', '?' +}; + +static char *cacheps[] = { + "I", "D", "SI", "SD" +}; + +static char *cacheop[] = { + "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV" +}; + +static void +format(char *mnemonic, Instr *i, char *f) +{ + if (mnemonic) + format(0, i, mnemonic); + if (f == 0) + return; + if (mnemonic) + if (i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if (*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 's': + bprint(i, "%d", i->rs); + break; + + case 't': + bprint(i, "%d", i->rt); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'a': + bprint(i, "%d", i->sa); + break; + + case 'l': + bprint(i, "%lx(R%d)",i->immediate, i->rs); + break; + + case 'i': + bprint(i, "$%lx", i->immediate); + break; + + case 'u': + i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY); + bprint(i, "(SB)"); + break; + + case 'j': + i->curr += symoff(i->curr, i->end-i->curr, + (i->target<<2)|(i->addr & 0xF0000000), CANY); + bprint(i, "(SB)"); + break; + + case 'b': + i->curr += symoff(i->curr, i->end-i->curr, + (i->immediate<<2)+i->addr+4, CANY); + break; + + case 'c': + bprint(i, "$%lx", i->cofun); + break; + + case 'w': + bprint(i, "[%lux]", i->w0); + break; + + case 'm': + bprint(i, "M(%s)", cop0regs[i->rd]); + break; + + case 'f': + *i->curr++ = fsub[i->rs & 0x0F]; + break; + + case 'C': + bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]); + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +static void +copz(int cop, Instr *i) +{ + char *f, *m, buf[16]; + + m = buf; + f = "%t,%d"; + switch (i->rs) { + + case 0: + sprint(buf, "mfc%d", cop); + break; + + case 2: + sprint(buf, "cfc%d", cop); + break; + + case 4: + sprint(buf, "mtc%d", cop); + break; + + case 6: + sprint(buf, "ctc%d", cop); + break; + + case 8: + f = "%b"; + switch (i->rt) { + + case 0: + sprint(buf, "bc%df", cop); + break; + + case 1: + sprint(buf, "bc%dt", cop); + break; + + case 2: + sprint(buf, "bc%dfl", cop); + break; + + case 3: + sprint(buf, "bc%dtl", cop); + break; + + default: + sprint(buf, "cop%d", cop); + f = mipscoxxx; + break; + } + break; + + default: + sprint(buf, "cop%d", cop); + if (i->rs & 0x10) + f = "function %c"; + else + f = mipscoxxx; + break; + } + format(m, i, f); +} + +static void +cop0(Instr *i) +{ + char *m = 0; + + if (i->rs < 8) { + switch (i->rs) { + + case 0: + case 1: + format("MOVW", i, "%m,R%t"); + return; + + case 4: + case 5: + format("MOVW", i, "R%t,%m"); + return; + } + } + else if (i->rs >= 0x10) { + switch (i->cofun) { + + case 1: + m = "TLBR"; + break; + + case 2: + m = "TLBWI"; + break; + + case 6: + m = "TLBWR"; + break; + + case 8: + m = "TLBP"; + break; + + case 16: + m = "RFE"; + break; + + case 32: + m = "ERET"; + break; + } + if (m) { + format(m, i, 0); + return; + } + } + copz(0, i); +} + +static void +cop1(Instr *i) +{ + char *m = "MOVW"; + + switch (i->rs) { + + case 0: + format(m, i, "F%d,R%t"); + return; + + case 2: + format(m, i, "FCR%d,R%t"); + return; + + case 4: + format(m, i, "R%t,F%d"); + return; + + case 6: + format(m, i, "R%t,FCR%d"); + return; + + case 8: + switch (i->rt) { + + case 0: + format("BFPF", i, "%b"); + return; + + case 1: + format("BFPT", i, "%b"); + return; + } + break; + } + copz(1, i); +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + Opcode *o; + uchar op; + + i.curr = buf; + i.end = buf+n-1; + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + switch (i.op) { + + case 0x00: /* SPECIAL */ + o = sopcodes; + op = i.function; + break; + + case 0x01: /* REGIMM */ + o = ropcodes; + op = i.rt; + break; + + case 0x10: /* COP0 */ + cop0(&i); + return i.size*4; + + case 0x11: /* COP1 */ + if (i.rs & 0x10) { + o = fopcodes; + op = i.function; + break; + } + cop1(&i); + return i.size*4; + + case 0x12: /* COP2 */ + case 0x13: /* COP3 */ + copz(i.op-0x10, &i); + return i.size*4; + + default: + o = opcodes; + op = i.op; + break; + } + if (o[op].f) + (*o[op].f)(&o[op], &i); + else + format(o[op].mnemonic, &i, o[op].ken); + return i.size*4; +} + +extern int _mipscoinst(Map *, ulong, char*, int); + + /* modifier 'I' toggles the default disassembler type */ +int +mipsinst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + if ((asstype == AMIPSCO && modifier == 'i') + || (asstype == AMIPS && modifier == 'I')) + return _mipscoinst(map, pc, buf, n); + else + return printins(map, pc, buf, n); +} + +int +mipsdas(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + if (i.end-i.curr > 8) + i.curr = _hexify(buf, i.w0, 7); + if (i.size == 2 && i.end-i.curr > 9) { + *i.curr++ = ' '; + i.curr = _hexify(i.curr, i.w1, 7); + } + *i.curr = 0; + return i.size*4; +} + +int +mipsinstlen(Map *map, ulong pc) +{ + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + return i.size*4; +} + +int +mipsfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + ulong w, l; + char buf[8]; + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + w = i.w0; + if((w&0xF3600000) == 0x41000000){ /* branch on coprocessor */ + Conditional: + foll[0] = pc+8; + l = ((w&0xFFFF)<<2); + if(w & 0x8000) + l |= 0xFFFC0000; + foll[1] = pc+4 + l; + return 2; + } + + l = (w&0xFC000000)>>26; + switch(l){ + case 0: /* SPECIAL */ + if((w&0x3E) == 0x08){ /* JR, JALR */ + sprint(buf, "R%ld", (w>>21)&0x1F); + foll[0] = (*rget)(map, buf); + return 1; + } + foll[0] = pc+i.size*4; + return 1; + case 0x30: /* Load-Linked followed by NOP, STC */ + foll[0] = pc+12; + return 1; + case 1: /* BCOND */ + case 4: /* BEQ */ + case 20: /* BEQL */ + case 5: /* BNE */ + case 21: /* BNEL */ + case 6: /* BLEZ */ + case 22: /* BLEZL */ + case 7: /* BGTZ */ + case 23: /* BGTZL */ + goto Conditional; + case 2: /* J */ + case 3: /* JAL */ + foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2); + return 1; + } + + foll[0] = pc+i.size*4; + return 1; +} diff --git a/utils/libmach/vobj.c b/utils/libmach/vobj.c new file mode 100644 index 00000000..f676d219 --- /dev/null +++ b/utils/libmach/vobj.c @@ -0,0 +1,129 @@ +/* + * vobj.c - identify and parse a mips object file + */ +#include <lib9.h> +#include <bio.h> +#include "vc/v.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_isv(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + +int +_readv(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 5); /* reg(1), lineno(4) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: case D_REG: case D_FREG: case D_MREG: + case D_FCREG: case D_LO: case D_HI: + break; + case D_OREG: + case D_CONST: + case D_BRANCH: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libregexp/NOTICE b/utils/libregexp/NOTICE new file mode 100644 index 00000000..50e574e2 --- /dev/null +++ b/utils/libregexp/NOTICE @@ -0,0 +1,28 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 1994-1999 Lucent Technologies Inc. + Revisions Copyright © 2000-2003 Vita Nuova Holdings Limited (www.vitanuova.com). + +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. diff --git a/utils/libregexp/mkfile b/utils/libregexp/mkfile new file mode 100644 index 00000000..3f6bc47a --- /dev/null +++ b/utils/libregexp/mkfile @@ -0,0 +1,22 @@ +<../../mkconfig + +#XXX +<$ROOT/mkfiles/mkhost-$SYSHOST # variables appropriate for host system +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE # variables used to build target object type + +LIB=libregexp.a +CFLAGS= $CFLAGS -I../include + +OFILES=\ + regcomp.$O\ + regerror.$O\ + regexec.$O\ + regsub.$O\ + regaux.$O\ + rregexec.$O\ + rregsub.$O\ + +HFILES= ../include/regexp.h\ + regcomp.h\ + +<$ROOT/mkfiles/mksyslib-$SHELLTYPE diff --git a/utils/libregexp/regaux.c b/utils/libregexp/regaux.c new file mode 100644 index 00000000..90298ddc --- /dev/null +++ b/utils/libregexp/regaux.c @@ -0,0 +1,98 @@ +#include <lib9.h> +#include "regexp.h" +#include "regcomp.h" + + +/* + * save a new match in mp + */ +extern void +_renewmatch(Resub *mp, int ms, Resublist *sp) +{ + int i; + + if(mp==0 || ms<=0) + return; + if(mp[0].s.sp==0 || sp->m[0].s.sp<mp[0].s.sp || + (sp->m[0].s.sp==mp[0].s.sp && sp->m[0].e.ep>mp[0].e.ep)){ + for(i=0; i<ms && i<NSUBEXP; i++) + mp[i] = sp->m[i]; + for(; i<ms; i++) + mp[i].s.sp = mp[i].e.ep = 0; + } +} + +/* + * Note optimization in _renewthread: + * *lp must be pending when _renewthread called; if *l has been looked + * at already, the optimization is a bug. + */ +extern Relist* +_renewthread(Relist *lp, /* _relist to add to */ + Reinst *ip, /* instruction to add */ + Resublist *sep) /* pointers to subexpressions */ +{ + Relist *p; + + for(p=lp; p->inst; p++){ + if(p->inst == ip){ + if((sep)->m[0].s.sp < p->se.m[0].s.sp) + p->se = *sep; + return 0; + } + } + p->inst = ip; + p->se = *sep; + (++p)->inst = 0; + return p; +} + +/* + * same as renewthread, but called with + * initial empty start pointer. + */ +extern Relist* +_renewemptythread(Relist *lp, /* _relist to add to */ + Reinst *ip, /* instruction to add */ + char *sp) /* pointers to subexpressions */ +{ + Relist *p; + + for(p=lp; p->inst; p++){ + if(p->inst == ip){ + if(sp < p->se.m[0].s.sp) { + memset((void *)&p->se, 0, sizeof(p->se)); + p->se.m[0].s.sp = sp; + } + return 0; + } + } + p->inst = ip; + memset((void *)&p->se, 0, sizeof(p->se)); + p->se.m[0].s.sp = sp; + (++p)->inst = 0; + return p; +} + +extern Relist* +_rrenewemptythread(Relist *lp, /* _relist to add to */ + Reinst *ip, /* instruction to add */ + Rune *rsp) /* pointers to subexpressions */ +{ + Relist *p; + + for(p=lp; p->inst; p++){ + if(p->inst == ip){ + if(rsp < p->se.m[0].s.rsp) { + memset((void *)&p->se, 0, sizeof(p->se)); + p->se.m[0].s.rsp = rsp; + } + return 0; + } + } + p->inst = ip; + memset((void *)&p->se, 0, sizeof(p->se)); + p->se.m[0].s.rsp = rsp; + (++p)->inst = 0; + return p; +} diff --git a/utils/libregexp/regcomp.c b/utils/libregexp/regcomp.c new file mode 100644 index 00000000..da677046 --- /dev/null +++ b/utils/libregexp/regcomp.c @@ -0,0 +1,557 @@ +#include <lib9.h> +#include "regexp.h" +#include "regcomp.h" + +#define TRUE 1 +#define FALSE 0 + +/* + * Parser Information + */ +typedef +struct Node +{ + Reinst* first; + Reinst* last; +}Node; + +Reprog RePrOg; + +#define NSTACK 20 +static Node andstack[NSTACK]; +static Node *andp; +static int atorstack[NSTACK]; +static int* atorp; +static int cursubid; /* id of current subexpression */ +static int subidstack[NSTACK]; /* parallel to atorstack */ +static int* subidp; +static int lastwasand; /* Last token was operand */ +static int nbra; +static char* exprp; /* pointer to next character in source expression */ +static int lexdone; +static int nclass; +static Reclass*classp; +static Reinst* freep; +static int errors; +static Rune yyrune; /* last lex'd rune */ +static Reclass*yyclassp; /* last lex'd class */ + +/* predeclared crap */ +static void operator(int); +static void pushand(Reinst*, Reinst*); +static void pushator(int); +static void evaluntil(int); +static int bldcclass(void); + +static jmp_buf regkaboom; + +static void +rcerror(char *s) +{ + errors++; + regerror(s); + longjmp(regkaboom, 1); +} + +static Reinst* +newinst(int t) +{ + freep->type = t; + freep->u2.left = 0; + freep->u1.right = 0; + return freep++; +} + +static void +operand(int t) +{ + Reinst *i; + + if(lastwasand) + operator(CAT); /* catenate is implicit */ + i = newinst(t); + + if(t == CCLASS || t == NCCLASS) + i->u1.cp = yyclassp; + if(t == RUNE) + i->u1.r = yyrune; + + pushand(i, i); + lastwasand = TRUE; +} + +static void +operator(int t) +{ + if(t==RBRA && --nbra<0) + rcerror("unmatched right paren"); + if(t==LBRA){ + if(++cursubid >= NSUBEXP) + rcerror ("too many subexpressions"); + nbra++; + if(lastwasand) + operator(CAT); + } else + evaluntil(t); + if(t != RBRA) + pushator(t); + lastwasand = FALSE; + if(t==STAR || t==QUEST || t==PLUS || t==RBRA) + lastwasand = TRUE; /* these look like operands */ +} + +static void +regerr2(char *s, int c) +{ + char buf[100]; + char *cp = buf; + while(*s) + *cp++ = *s++; + *cp++ = c; + *cp = '\0'; + rcerror(buf); +} + +static void +cant(char *s) +{ + char buf[100]; + strcpy(buf, "can't happen: "); + strcat(buf, s); + rcerror(buf); +} + +static void +pushand(Reinst *f, Reinst *l) +{ + if(andp >= &andstack[NSTACK]) + cant("operand stack overflow"); + andp->first = f; + andp->last = l; + andp++; +} + +static void +pushator(int t) +{ + if(atorp >= &atorstack[NSTACK]) + cant("operator stack overflow"); + *atorp++ = t; + *subidp++ = cursubid; +} + +static Node* +popand(int op) +{ + Reinst *inst; + + if(andp <= &andstack[0]){ + regerr2("missing operand for ", op); + inst = newinst(NOP); + pushand(inst,inst); + } + return --andp; +} + +static int +popator(void) +{ + if(atorp <= &atorstack[0]) + cant("operator stack underflow"); + --subidp; + return *--atorp; +} + +static void +evaluntil(int pri) +{ + Node *op1, *op2; + Reinst *inst1, *inst2; + + while(pri==RBRA || atorp[-1]>=pri){ + switch(popator()){ + default: + rcerror("unknown operator in evaluntil"); + break; + case LBRA: /* must have been RBRA */ + op1 = popand('('); + inst2 = newinst(RBRA); + inst2->u1.subid = *subidp; + op1->last->u2.next = inst2; + inst1 = newinst(LBRA); + inst1->u1.subid = *subidp; + inst1->u2.next = op1->first; + pushand(inst1, inst2); + return; + case OR: + op2 = popand('|'); + op1 = popand('|'); + inst2 = newinst(NOP); + op2->last->u2.next = inst2; + op1->last->u2.next = inst2; + inst1 = newinst(OR); + inst1->u1.right = op1->first; + inst1->u2.left = op2->first; + pushand(inst1, inst2); + break; + case CAT: + op2 = popand(0); + op1 = popand(0); + op1->last->u2.next = op2->first; + pushand(op1->first, op2->last); + break; + case STAR: + op2 = popand('*'); + inst1 = newinst(OR); + op2->last->u2.next = inst1; + inst1->u1.right = op2->first; + pushand(inst1, inst1); + break; + case PLUS: + op2 = popand('+'); + inst1 = newinst(OR); + op2->last->u2.next = inst1; + inst1->u1.right = op2->first; + pushand(op2->first, inst1); + break; + case QUEST: + op2 = popand('?'); + inst1 = newinst(OR); + inst2 = newinst(NOP); + inst1->u2.left = inst2; + inst1->u1.right = op2->first; + op2->last->u2.next = inst2; + pushand(inst1, inst2); + break; + } + } +} + +static Reprog* +optimize(Reprog *pp) +{ + Reinst *inst, *target; + int size; + Reprog *npp; + Reclass *cl; + int diff; + + /* + * get rid of NOOP chains + */ + for(inst=pp->firstinst; inst->type!=END; inst++){ + target = inst->u2.next; + while(target->type == NOP) + target = target->u2.next; + inst->u2.next = target; + } + + /* + * The original allocation is for an area larger than + * necessary. Reallocate to the actual space used + * and then relocate the code. + */ + size = sizeof(Reprog) + (freep - pp->firstinst)*sizeof(Reinst); + npp = (Reprog *)realloc(pp, size); + if(npp==0 || npp==pp) + return pp; + diff = (char *)npp - (char *)pp; + freep = (Reinst *)((char *)freep + diff); + for(inst=npp->firstinst; inst<freep; inst++){ + switch(inst->type){ + case OR: + case STAR: + case PLUS: + case QUEST: + *(char **)&inst->u1.right += diff; + break; + case CCLASS: + case NCCLASS: + *(char **)&inst->u1.right += diff; + cl = inst->u1.cp; + *(char **)&cl->end += diff; + break; + } + *(char **)&inst->u2.left += diff; + } + *(char **)&npp->startinst += diff; + return npp; +} + +#ifdef DEBUG +static void +dumpstack(void){ + Node *stk; + int *ip; + + print("operators\n"); + for(ip=atorstack; ip<atorp; ip++) + print("0%o\n", *ip); + print("operands\n"); + for(stk=andstack; stk<andp; stk++) + print("0%o\t0%o\n", stk->first->type, stk->last->type); +} + +static void +dump(Reprog *pp) +{ + Reinst *l; + Rune *p; + + l = pp->firstinst; + do{ + print("%d:\t0%o\t%d\t%d", l-pp->firstinst, l->type, + l->u2.left-pp->firstinst, l->u1.right-pp->firstinst); + if(l->type == RUNE) + print("\t%C\n", l->r); + else if(l->type == CCLASS || l->type == NCCLASS){ + print("\t["); + if(l->type == NCCLASS) + print("^"); + for(p = l->cp->spans; p < l->cp->end; p += 2) + if(p[0] == p[1]) + print("%C", p[0]); + else + print("%C-%C", p[0], p[1]); + print("]\n"); + } else + print("\n"); + }while(l++->type); +} +#endif + +static Reclass* +newclass(void) +{ + if(nclass >= NCLASS) + regerr2("too many character classes; limit", NCLASS+'0'); + return &(classp[nclass++]); +} + +static int +nextc(Rune *rp) +{ + if(lexdone){ + *rp = 0; + return 1; + } + exprp += chartorune(rp, exprp); + if(*rp == L'\\'){ + exprp += chartorune(rp, exprp); + return 1; + } + if(*rp == 0) + lexdone = 1; + return 0; +} + +static int +lex(int literal, int dot_type) +{ + int quoted; + + quoted = nextc(&yyrune); + if(literal || quoted){ + if(yyrune == 0) + return END; + return RUNE; + } + + switch(yyrune){ + case 0: + return END; + case L'*': + return STAR; + case L'?': + return QUEST; + case L'+': + return PLUS; + case L'|': + return OR; + case L'.': + return dot_type; + case L'(': + return LBRA; + case L')': + return RBRA; + case L'^': + return BOL; + case L'$': + return EOL; + case L'[': + return bldcclass(); + } + return RUNE; +} + +static int +bldcclass(void) +{ + int type; + Rune r[NCCRUNE]; + Rune *p, *ep, *np; + Rune rune; + int quoted; + + /* we have already seen the '[' */ + type = CCLASS; + yyclassp = newclass(); + + /* look ahead for negation */ + /* SPECIAL CASE!!! negated classes don't match \n */ + ep = r; + quoted = nextc(&rune); + if(!quoted && rune == L'^'){ + type = NCCLASS; + quoted = nextc(&rune); + *ep++ = L'\n'; + *ep++ = L'\n'; + } + + /* parse class into a set of spans */ + for(; ep<&r[NCCRUNE];){ + if(rune == 0){ + rcerror("malformed '[]'"); + return 0; + } + if(!quoted && rune == L']') + break; + if(!quoted && rune == L'-'){ + if(ep == r){ + rcerror("malformed '[]'"); + return 0; + } + quoted = nextc(&rune); + if((!quoted && rune == L']') || rune == 0){ + rcerror("malformed '[]'"); + return 0; + } + *(ep-1) = rune; + } else { + *ep++ = rune; + *ep++ = rune; + } + quoted = nextc(&rune); + } + + /* sort on span start */ + for(p = r; p < ep; p += 2){ + for(np = p; np < ep; np += 2) + if(*np < *p){ + rune = np[0]; + np[0] = p[0]; + p[0] = rune; + rune = np[1]; + np[1] = p[1]; + p[1] = rune; + } + } + + /* merge spans */ + np = yyclassp->spans; + p = r; + if(r == ep) + yyclassp->end = np; + else { + np[0] = *p++; + np[1] = *p++; + for(; p < ep; p += 2) + if(p[0] <= np[1]){ + if(p[1] > np[1]) + np[1] = p[1]; + } else { + np += 2; + np[0] = p[0]; + np[1] = p[1]; + } + yyclassp->end = np+2; + } + + return type; +} + +static Reprog* +regcomp1(char *s, int literal, int dot_type) +{ + int token; + Reprog *pp; + + /* get memory for the program */ + pp = (Reprog *)malloc(sizeof(Reprog) + 6*sizeof(Reinst)*strlen(s)); + if(pp == 0){ + regerror("out of memory"); + return 0; + } + freep = pp->firstinst; + classp = pp->class; + errors = 0; + + if(setjmp(regkaboom)) + goto out; + + /* go compile the sucker */ + lexdone = 0; + exprp = s; + nclass = 0; + nbra = 0; + atorp = atorstack; + andp = andstack; + subidp = subidstack; + lastwasand = FALSE; + cursubid = 0; + + /* Start with a low priority operator to prime parser */ + pushator(START-1); + while((token = lex(literal, dot_type)) != END){ + if((token&0300) == OPERATOR) + operator(token); + else + operand(token); + } + + /* Close with a low priority operator */ + evaluntil(START); + + /* Force END */ + operand(END); + evaluntil(START); +#ifdef DEBUG + dumpstack(); +#endif + if(nbra) + rcerror("unmatched left paren"); + --andp; /* points to first and only operand */ + pp->startinst = andp->first; +#ifdef DEBUG + dump(pp); +#endif + pp = optimize(pp); +#ifdef DEBUG + print("start: %d\n", andp->first-pp->firstinst); + dump(pp); +#endif +out: + if(errors){ + free(pp); + pp = 0; + } + return pp; +} + +extern Reprog* +regcomp(char *s) +{ + return regcomp1(s, 0, ANY); +} + +extern Reprog* +regcomplit(char *s) +{ + return regcomp1(s, 1, ANY); +} + +extern Reprog* +regcompnl(char *s) +{ + return regcomp1(s, 0, ANYNL); +} diff --git a/utils/libregexp/regcomp.h b/utils/libregexp/regcomp.h new file mode 100644 index 00000000..1261b051 --- /dev/null +++ b/utils/libregexp/regcomp.h @@ -0,0 +1,70 @@ +/* + * substitution list + */ +#define NSUBEXP 32 +typedef struct Resublist Resublist; +struct Resublist +{ + Resub m[NSUBEXP]; +}; + +/* max character classes per program */ +extern Reprog RePrOg; +#define NCLASS (sizeof(RePrOg.class)/sizeof(Reclass)) + +/* max rune ranges per character class */ +#define NCCRUNE (sizeof(Reclass)/sizeof(Rune)) + +/* + * Actions and Tokens (Reinst types) + * + * 02xx are operators, value == precedence + * 03xx are tokens, i.e. operands for operators + */ +#define RUNE 0177 +#define OPERATOR 0200 /* Bitmask of all operators */ +#define START 0200 /* Start, used for marker on stack */ +#define RBRA 0201 /* Right bracket, ) */ +#define LBRA 0202 /* Left bracket, ( */ +#define OR 0203 /* Alternation, | */ +#define CAT 0204 /* Concatentation, implicit operator */ +#define STAR 0205 /* Closure, * */ +#define PLUS 0206 /* a+ == aa* */ +#define QUEST 0207 /* a? == a|nothing, i.e. 0 or 1 a's */ +#define ANY 0300 /* Any character except newline, . */ +#define ANYNL 0301 /* Any character including newline, . */ +#define NOP 0302 /* No operation, internal use only */ +#define BOL 0303 /* Beginning of line, ^ */ +#define EOL 0304 /* End of line, $ */ +#define CCLASS 0305 /* Character class, [] */ +#define NCCLASS 0306 /* Negated character class, [] */ +#define END 0377 /* Terminate: match found */ + +/* + * regexec execution lists + */ +#define LISTSIZE 10 +#define BIGLISTSIZE (10*LISTSIZE) +typedef struct Relist Relist; +struct Relist +{ + Reinst* inst; /* Reinstruction of the thread */ + Resublist se; /* matched subexpressions in this thread */ +}; +typedef struct Reljunk Reljunk; +struct Reljunk +{ + Relist* relist[2]; + Relist* reliste[2]; + int starttype; + Rune startchar; + char* starts; + char* eol; + Rune* rstarts; + Rune* reol; +}; + +extern Relist* _renewthread(Relist*, Reinst*, Resublist*); +extern void _renewmatch(Resub*, int, Resublist*); +extern Relist* _renewemptythread(Relist*, Reinst*, char*); +extern Relist* _rrenewemptythread(Relist*, Reinst*, Rune*); diff --git a/utils/libregexp/regerror.c b/utils/libregexp/regerror.c new file mode 100644 index 00000000..09b0b994 --- /dev/null +++ b/utils/libregexp/regerror.c @@ -0,0 +1,14 @@ +#include <lib9.h> +#include "regexp.h" + +void +regerror(char *s) +{ + char buf[132]; + + strcpy(buf, "regerror: "); + strcat(buf, s); + strcat(buf, "\n"); + write(2, buf, strlen(buf)); + exits("regerr"); +} diff --git a/utils/libregexp/regexec.c b/utils/libregexp/regexec.c new file mode 100644 index 00000000..ccb96f58 --- /dev/null +++ b/utils/libregexp/regexec.c @@ -0,0 +1,219 @@ +#include <lib9.h> +#include "regexp.h" +#include "regcomp.h" + + +/* + * return 0 if no match + * >0 if a match + * <0 if we ran out of _relist space + */ +static int +regexec1(Reprog *progp, /* program to run */ + char *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms, /* number of elements at mp */ + Reljunk *j +) +{ + int flag=0; + Reinst *inst; + Relist *tlp; + char *s; + int i, checkstart; + Rune r, *rp, *ep; + int n; + Relist* tl; /* This list, next list */ + Relist* nl; + Relist* tle; /* ends of this and next list */ + Relist* nle; + int match; + char *p; + + match = 0; + checkstart = j->starttype; + if(mp) + for(i=0; i<ms; i++) { + mp[i].s.sp = 0; + mp[i].e.ep = 0; + } + j->relist[0][0].inst = 0; + j->relist[1][0].inst = 0; + + /* Execute machine once for each character, including terminal NUL */ + s = j->starts; + do{ + /* fast check for first char */ + if(checkstart) { + switch(j->starttype) { + case RUNE: + p = utfrune(s, j->startchar); + if(p == 0 || s == j->eol) + return match; + s = p; + break; + case BOL: + if(s == bol) + break; + p = utfrune(s, '\n'); + if(p == 0 || s == j->eol) + return match; + s = p; + break; + } + } + r = *(uchar*)s; + if(r < (Rune)Runeself) + n = 1; + else + n = chartorune(&r, s); + + /* switch run lists */ + tl = j->relist[flag]; + tle = j->reliste[flag]; + nl = j->relist[flag^=1]; + nle = j->reliste[flag]; + nl->inst = 0; + + /* Add first instruction to current list */ + if(match == 0) + _renewemptythread(tl, progp->startinst, s); + + /* Execute machine until current list is empty */ + for(tlp=tl; tlp->inst; tlp++){ /* assignment = */ + for(inst = tlp->inst; ; inst = inst->u2.next){ + switch(inst->type){ + case RUNE: /* regular character */ + if(inst->u1.r == r){ + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + } + break; + case LBRA: + tlp->se.m[inst->u1.subid].s.sp = s; + continue; + case RBRA: + tlp->se.m[inst->u1.subid].e.ep = s; + continue; + case ANY: + if(r != '\n') + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case ANYNL: + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case BOL: + if(s == bol || *(s-1) == '\n') + continue; + break; + case EOL: + if(s == j->eol || r == 0 || r == '\n') + continue; + break; + case CCLASS: + ep = inst->u1.cp->end; + for(rp = inst->u1.cp->spans; rp < ep; rp += 2) + if(r >= rp[0] && r <= rp[1]){ + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + } + break; + case NCCLASS: + ep = inst->u1.cp->end; + for(rp = inst->u1.cp->spans; rp < ep; rp += 2) + if(r >= rp[0] && r <= rp[1]) + break; + if(rp == ep) + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case OR: + /* evaluate right choice later */ + if(_renewthread(tlp, inst->u1.right, &tlp->se) == tle) + return -1; + /* efficiency: advance and re-evaluate */ + continue; + case END: /* Match! */ + match = 1; + tlp->se.m[0].e.ep = s; + if(mp != 0) + _renewmatch(mp, ms, &tlp->se); + break; + } + break; + } + } + if(s == j->eol) + break; + checkstart = j->starttype && nl->inst==0; + s += n; + }while(r); + return match; +} + +static int +regexec2(Reprog *progp, /* program to run */ + char *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms, /* number of elements at mp */ + Reljunk *j +) +{ + Relist relist0[BIGLISTSIZE], relist1[BIGLISTSIZE]; + + /* mark space */ + j->relist[0] = relist0; + j->relist[1] = relist1; + j->reliste[0] = relist0 + nelem(relist0) - 2; + j->reliste[1] = relist1 + nelem(relist1) - 2; + + return regexec1(progp, bol, mp, ms, j); +} + +extern int +regexec(Reprog *progp, /* program to run */ + char *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms) /* number of elements at mp */ +{ + Reljunk j; + Relist relist0[LISTSIZE], relist1[LISTSIZE]; + int rv; + + /* + * use user-specified starting/ending location if specified + */ + j.starts = bol; + j.eol = 0; + if(mp && ms>0){ + if(mp->s.sp) + j.starts = mp->s.sp; + if(mp->e.ep) + j.eol = mp->e.ep; + } + j.starttype = 0; + j.startchar = 0; + if(progp->startinst->type == RUNE && progp->startinst->u1.r < (Rune)Runeself) { + j.starttype = RUNE; + j.startchar = progp->startinst->u1.r; + } + if(progp->startinst->type == BOL) + j.starttype = BOL; + + /* mark space */ + j.relist[0] = relist0; + j.relist[1] = relist1; + j.reliste[0] = relist0 + nelem(relist0) - 2; + j.reliste[1] = relist1 + nelem(relist1) - 2; + + rv = regexec1(progp, bol, mp, ms, &j); + if(rv >= 0) + return rv; + rv = regexec2(progp, bol, mp, ms, &j); + if(rv >= 0) + return rv; + return -1; +} diff --git a/utils/libregexp/regsub.c b/utils/libregexp/regsub.c new file mode 100644 index 00000000..f789dd97 --- /dev/null +++ b/utils/libregexp/regsub.c @@ -0,0 +1,55 @@ +#include <lib9.h> +#include "regexp.h" + +/* substitute into one string using the matches from the last regexec() */ +extern void +regsub(char *sp, /* source string */ + char *dp, /* destination string */ + Resub *mp, /* subexpression elements */ + int ms) /* number of elements pointed to by mp */ +{ + char *ssp; + int i; + + while(*sp != '\0'){ + if(*sp == '\\'){ + switch(*++sp){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i = *sp-'0'; + if(mp[i].s.sp != 0 && mp!=0 && ms>i) + for(ssp = mp[i].s.sp; + ssp < mp[i].e.ep; + ssp++) + *dp++ = *ssp; + break; + case '\\': + *dp++ = '\\'; + break; + case '\0': + sp--; + break; + default: + *dp++ = *sp; + break; + } + }else if(*sp == '&'){ + if(mp[0].s.sp != 0 && mp!=0 && ms>0) + if(mp[0].s.sp != 0) + for(ssp = mp[0].s.sp; + ssp < mp[0].e.ep; ssp++) + *dp++ = *ssp; + }else + *dp++ = *sp; + sp++; + } + *dp = '\0'; +} diff --git a/utils/libregexp/rregexec.c b/utils/libregexp/rregexec.c new file mode 100644 index 00000000..6a4f85e2 --- /dev/null +++ b/utils/libregexp/rregexec.c @@ -0,0 +1,213 @@ +#include <lib9.h> +#include "regexp.h" +#include "regcomp.h" + +/* + * return 0 if no match + * >0 if a match + * <0 if we ran out of _relist space + */ +static int +rregexec1(Reprog *progp, /* program to run */ + Rune *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms, /* number of elements at mp */ + Reljunk *j) +{ + int flag=0; + Reinst *inst; + Relist *tlp; + Rune *s; + int i, checkstart; + Rune r, *rp, *ep; + Relist* tl; /* This list, next list */ + Relist* nl; + Relist* tle; /* ends of this and next list */ + Relist* nle; + int match; + + match = 0; + checkstart = j->startchar; + if(mp) + for(i=0; i<ms; i++) { + mp[i].s.rsp = 0; + mp[i].e.rep = 0; + } + j->relist[0][0].inst = 0; + j->relist[1][0].inst = 0; + + /* Execute machine once for each character, including terminal NUL */ + s = j->rstarts; + do{ + + /* fast check for first char */ + if(checkstart) { + switch(j->starttype) { + case RUNE: + while(*s != j->startchar) { + if(*s == 0 || s == j->reol) + return match; + s++; + } + break; + case BOL: + if(s == bol) + break; + while(*s != '\n') { + if(*s == 0 || s == j->reol) + return match; + s++; + } + break; + } + } + + r = *s; + + /* switch run lists */ + tl = j->relist[flag]; + tle = j->reliste[flag]; + nl = j->relist[flag^=1]; + nle = j->reliste[flag]; + nl->inst = 0; + + /* Add first instruction to current list */ + _rrenewemptythread(tl, progp->startinst, s); + + /* Execute machine until current list is empty */ + for(tlp=tl; tlp->inst; tlp++){ + for(inst=tlp->inst; ; inst = inst->u2.next){ + switch(inst->type){ + case RUNE: /* regular character */ + if(inst->u1.r == r) + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case LBRA: + tlp->se.m[inst->u1.subid].s.rsp = s; + continue; + case RBRA: + tlp->se.m[inst->u1.subid].e.rep = s; + continue; + case ANY: + if(r != '\n') + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case ANYNL: + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case BOL: + if(s == bol || *(s-1) == '\n') + continue; + break; + case EOL: + if(s == j->reol || r == 0 || r == '\n') + continue; + break; + case CCLASS: + ep = inst->u1.cp->end; + for(rp = inst->u1.cp->spans; rp < ep; rp += 2) + if(r >= rp[0] && r <= rp[1]){ + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + } + break; + case NCCLASS: + ep = inst->u1.cp->end; + for(rp = inst->u1.cp->spans; rp < ep; rp += 2) + if(r >= rp[0] && r <= rp[1]) + break; + if(rp == ep) + if(_renewthread(nl, inst->u2.next, &tlp->se)==nle) + return -1; + break; + case OR: + /* evaluate right choice later */ + if(_renewthread(tlp, inst->u1.right, &tlp->se) == tle) + return -1; + /* efficiency: advance and re-evaluate */ + continue; + case END: /* Match! */ + match = 1; + tlp->se.m[0].e.rep = s; + if(mp != 0) + _renewmatch(mp, ms, &tlp->se); + break; + } + break; + } + } + if(s == j->reol) + break; + checkstart = j->startchar && nl->inst==0; + s++; + }while(r); + return match; +} + +static int +rregexec2(Reprog *progp, /* program to run */ + Rune *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms, /* number of elements at mp */ + Reljunk *j +) +{ + Relist relist0[5*LISTSIZE], relist1[5*LISTSIZE]; + + /* mark space */ + j->relist[0] = relist0; + j->relist[1] = relist1; + j->reliste[0] = relist0 + nelem(relist0) - 2; + j->reliste[1] = relist1 + nelem(relist1) - 2; + + return rregexec1(progp, bol, mp, ms, j); +} + +extern int +rregexec(Reprog *progp, /* program to run */ + Rune *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms) /* number of elements at mp */ +{ + Reljunk j; + Relist relist0[LISTSIZE], relist1[LISTSIZE]; + int rv; + + /* + * use user-specified starting/ending location if specified + */ + j.rstarts = bol; + j.reol = 0; + if(mp && ms>0){ + if(mp->s.sp) + j.rstarts = mp->s.rsp; + if(mp->e.ep) + j.reol = mp->e.rep; + } + j.starttype = 0; + j.startchar = 0; + if(progp->startinst->type == RUNE && progp->startinst->u1.r < (Rune)Runeself) { + j.starttype = RUNE; + j.startchar = progp->startinst->u1.r; + } + if(progp->startinst->type == BOL) + j.starttype = BOL; + + /* mark space */ + j.relist[0] = relist0; + j.relist[1] = relist1; + j.reliste[0] = relist0 + nelem(relist0) - 2; + j.reliste[1] = relist1 + nelem(relist1) - 2; + + rv = rregexec1(progp, bol, mp, ms, &j); + if(rv >= 0) + return rv; + rv = rregexec2(progp, bol, mp, ms, &j); + if(rv >= 0) + return rv; + return -1; +} diff --git a/utils/libregexp/rregsub.c b/utils/libregexp/rregsub.c new file mode 100644 index 00000000..d6251a14 --- /dev/null +++ b/utils/libregexp/rregsub.c @@ -0,0 +1,55 @@ +#include <lib9.h> +#include "regexp.h" + +/* substitute into one string using the matches from the last regexec() */ +extern void +rregsub(Rune *sp, /* source string */ + Rune *dp, /* destination string */ + Resub *mp, /* subexpression elements */ + int ms) /* number of elements pointed to by mp */ +{ + Rune *ssp; + int i; + + while(*sp != '\0'){ + if(*sp == '\\'){ + switch(*++sp){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i = *sp-'0'; + if(mp[i].s.rsp != 0 && mp!=0 && ms>i) + for(ssp = mp[i].s.rsp; + ssp < mp[i].e.rep; + ssp++) + *dp++ = *ssp; + break; + case '\\': + *dp++ = '\\'; + break; + case '\0': + sp--; + break; + default: + *dp++ = *sp; + break; + } + }else if(*sp == '&'){ + if(mp[0].s.rsp != 0 && mp!=0 && ms>0) + if(mp[0].s.rsp != 0) + for(ssp = mp[0].s.rsp; + ssp < mp[0].e.rep; ssp++) + *dp++ = *ssp; + }else + *dp++ = *sp; + sp++; + } + *dp = '\0'; +} diff --git a/utils/libregexp/test.c b/utils/libregexp/test.c new file mode 100644 index 00000000..49afd9bb --- /dev/null +++ b/utils/libregexp/test.c @@ -0,0 +1,46 @@ +#include <lib9.h> +#include <regexp.h> + +struct x +{ + char *re; + char *s; + Reprog *p; +}; + +struct x t[] = { + { "^[^!@]+$", "/bin/upas/aliasmail '&'", 0 }, + { "^local!(.*)$", "/mail/box/\\1/mbox", 0 }, + { "^plan9!(.*)$", "\\1", 0 }, + { "^helix!(.*)$", "\\1", 0 }, + { "^([^!]+)@([^!@]+)$", "\\2!\\1", 0 }, + { "^(uk\\.[^!]*)(!.*)$", "/bin/upas/uk2uk '\\1' '\\2'", 0 }, + { "^[^!]*\\.[^!]*!.*$", "inet!&", 0 }, + { "^(coma|research|pipe|pyxis|inet|hunny|gauss)!(.*)$", "/mail/lib/qmail '\s' 'net!\\1' '\\2'", 0 }, + { "^.*$", "/mail/lib/qmail '\s' 'net!research' '&'", 0 }, + { 0, 0, 0 }, +}; + + + +main(int ac, char **av) +{ + Resub rs[10]; + char dst[128]; + int n; + struct x *tp; + + for(tp = t; tp->re; tp++) + tp->p = regcomp(tp->re); + + + for(tp = t; tp->re; tp++){ + print("%s VIA %s", av[1], tp->re); + if(regexec(tp->p, av[1], rs, 10)){ + regsub(tp->s, dst, rs, 10); + print(" sub %s -> %s", tp->s, dst); + } + print("\n"); + } + exits(0); +} diff --git a/utils/libregexp/test2.c b/utils/libregexp/test2.c new file mode 100644 index 00000000..e6ec8aa5 --- /dev/null +++ b/utils/libregexp/test2.c @@ -0,0 +1,20 @@ +#include <lib9.h> +#include <regexp.h> + + +main(int ac, char **av) +{ + Resub rs[10]; + Reprog *p; + char *s; + int i; + + p = regcomp("[^a-z]"); + s = "\n"; + if(regexec(p, s, rs, 10)) + print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep); + s = "0"; + if(regexec(p, s, rs, 10)) + print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep); + exits(0); +} diff --git a/utils/md5sum/md5sum.c b/utils/md5sum/md5sum.c new file mode 100644 index 00000000..11c373d9 --- /dev/null +++ b/utils/md5sum/md5sum.c @@ -0,0 +1,61 @@ +#include <lib9.h> +#include <libsec.h> + +#pragma varargck type "M" uchar* + +static int +digestfmt(Fmt *fmt) +{ + char buf[MD5dlen*2+1]; + uchar *p; + int i; + + p = va_arg(fmt->args, uchar*); + for(i=0; i<MD5dlen; i++) + sprint(buf+2*i, "%.2ux", p[i]); + return fmtstrcpy(fmt, buf); +} + +static void +sum(int fd, char *name) +{ + int n; + uchar buf[8192], digest[MD5dlen]; + DigestState *s; + + s = md5(nil, 0, nil, nil); + while((n = read(fd, buf, sizeof buf)) > 0) + md5(buf, n, nil, s); + md5(nil, 0, digest, s); + if(name == nil) + print("%M\n", digest); + else + print("%M\t%s\n", digest, name); +} + +void +main(int argc, char *argv[]) +{ + int i, fd; + + ARGBEGIN{ + default: + fprint(2, "usage: md5sum [file...]\n"); + exits("usage"); + }ARGEND + + fmtinstall('M', digestfmt); + + if(argc == 0) + sum(0, nil); + else for(i = 0; i < argc; i++){ + fd = open(argv[i], OREAD); + if(fd < 0){ + fprint(2, "md5sum: can't open %s: %r\n", argv[i]); + continue; + } + sum(fd, argv[i]); + close(fd); + } + exits(nil); +} diff --git a/utils/md5sum/mkfile b/utils/md5sum/mkfile new file mode 100644 index 00000000..462a91ee --- /dev/null +++ b/utils/md5sum/mkfile @@ -0,0 +1,19 @@ +<../../mkconfig + +# +# the md5sum command is needed for the test suite +# + +TARG=md5sum + +OFILES= md5sum.$O\ + + +HFILES= + +LIBS=9 sec + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + diff --git a/utils/mk/Nt.c b/utils/mk/Nt.c new file mode 100644 index 00000000..002807bb --- /dev/null +++ b/utils/mk/Nt.c @@ -0,0 +1,442 @@ +#include "mk.h" +#include <signal.h> +#include <sys/utime.h> + +#define Arc My_Arc /* avoid name conflicts */ +#undef DELETE + +#include <windows.h> + +enum { + Nchild = 100, +}; + +char *rootdir = "c:\\users\\inferno"; +char *shell = "Nt\\386\\bin\\rcsh.exe"; /* Path relative to root */ + +typedef struct Child Child; + +struct Child { + int pid; + HANDLE handle; +}; + +static Child child[Nchild]; + +extern char **environ; + +DWORD WINAPI writecmd(LPVOID a); + +void +readenv(void) +{ + char **p, *s; + Word *w; + + for(p = environ; *p; p++){ + s = shname(*p); + if(*s == '=') { + *s = 0; + w = newword(s+1); + } else + w = newword(""); + if (symlook(*p, S_INTERNAL, 0)) + continue; + s = strdup(*p); + setvar(s, (void *)w); + symlook(s, S_EXPORTED, (void *)"")->value = ""; + } +} + +char * +exportenv(Envy *e) +{ + int i, n; + char *buf, *v; + + buf = 0; + n = 0; + for(i = 0; e->name; e++, i++) { + /* word separator is shell-dependent */ + if(e->values) + v = wtos(e->values, IWS); + else + v = ""; + buf = Realloc(buf, n+strlen(e->name)+1+strlen(v)+1); + + n += sprint(buf+n, "%s=%s", e->name, v); + n++; /* skip over null */ + if(e->values) + free(v); + } + /* final null */ + buf = Realloc(buf, n+1); + buf[n] = 0; + + return buf; +} + +int +waitfor(char *msg) +{ + int pid, n, i, r, code; + HANDLE tab[Nchild]; + + for(i=0,n=0; i<Nchild; i++) + if(child[i].handle != 0) + tab[n++] = child[i].handle; + + if(n == 0) + return -1; + + r = WaitForMultipleObjects(n, tab, 0, INFINITE); + + r -= WAIT_OBJECT_0; + if(r<0 || r>=n) { + perror("wait failed"); + exits("wait failed"); + } + + for(i=0; i<Nchild; i++) + if(child[i].handle == tab[r]) + break; + if(i == Nchild){ + snprint(msg, ERRMAX, "unknown child (%lux)", tab[r]); + return -1; + } + + if(msg) { + *msg = 0; + if(GetExitCodeProcess(child[i].handle, &code) == FALSE) + snprint(msg, ERRMAX, "unknown exit code"); + else if(code != 0) + snprint(msg, ERRMAX, "exit(%d)", code); + } + + CloseHandle(child[i].handle); + child[i].handle = 0; + pid = child[i].pid; + child[i].pid = 0; + + return pid; +} + +void +expunge(int pid, char *msg) +{ +/* + if(strcmp(msg, "interrupt")) + kill(pid, SIGINT); + else + kill(pid, SIGHUP); +*/ +} + +HANDLE +duphandle(HANDLE h) +{ + HANDLE r; + + if(DuplicateHandle(GetCurrentProcess(), h, + GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS, + 1, DUPLICATE_SAME_ACCESS) == FALSE) { + perror("dup handle"); + Exit(); + } + + return r; +} + +void +childadd(HANDLE h, int pid) +{ + int i; + + for(i=0; i<Nchild; i++) { + if(child[i].handle == 0) { + child[i].handle = h; + child[i].pid = pid; + return; + } + } + perror("child table full"); + Exit(); +} + +static DWORD WINAPI +spinoff(HANDLE in, HANDLE out, char *args, char *cmd, Envy *e) +{ + char args2[4096], path[MAX_PATH], *s, *eb; + STARTUPINFO si; + PROCESS_INFORMATION pi; + Symtab *sym; + + + /* set up the full path of the shell */ + sym = symlook("MKSH", S_VAR, 0); + if(sym){ + strncpy(path, ((Word*)(sym->value))->s, sizeof(path)); + path[MAX_PATH-1] = 0; + }else{ + sym = symlook("ROOT", S_VAR, 0); + if(sym) + rootdir = ((Word*)(sym->value))->s; + snprint(path, sizeof(path), "%s\\%s", rootdir, shell); + } + /* convert to backslash notation */ + for(s = strchr(path,'/'); s; s = strchr(s+1, '/')) + *s = '\\'; + + s = args2; + s += snprint(args2, sizeof(args2)-1, "%s", path); + if(shflags) + s += snprint(s, args2+sizeof(args2)-s-1, " %s", shflags); + if(args) + s += snprint(s, args2+sizeof(args2)-s-1, " %s", args); + if(cmd) + s += snprint(s, args2+sizeof(args2)-s-1, " \"%s\"", cmd); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; + si.wShowWindow = SW_SHOW; + + if (e) + eb = exportenv(e); + else + eb = 0; + si.hStdInput = duphandle(in); + si.hStdOutput = duphandle(out); + si.hStdError = duphandle(GetStdHandle(STD_ERROR_HANDLE)); + if(CreateProcess(path, args2, 0, 0, 1, 0, eb, 0, &si, &pi) == FALSE) { + perror("can't find shell"); + Exit(); + } + + free(eb); + + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + childadd(pi.hProcess, pi.dwProcessId); + return pi.dwProcessId; +} + +int +execsh(char *args, char *cmd, Bufblock *buf, Envy *e) +{ + int tot, n, tid, pid; + HANDLE outin, outout, inout, inin; + struct { char *cmd; HANDLE handle; } *arg; + + if(buf == 0) + outout = GetStdHandle(STD_OUTPUT_HANDLE); + else + if(CreatePipe(&outin, &outout, 0, 0) == FALSE){ + perror("pipe"); + Exit(); + } + + if(CreatePipe(&inin, &inout, 0, 0) == FALSE){ + perror("pipe"); + Exit(); + } + + arg = malloc(sizeof(*arg)); + arg->cmd = strdup(cmd); + arg->handle = inout; + if(CreateThread(0, 0, writecmd, arg, 0, &tid) == FALSE) { + perror("spawn writecmd"); + Exit(); + } + + pid = spinoff(inin, outout, args, 0, e); + CloseHandle(inin); + + if(DEBUG(D_EXEC)) + fprint(1, "starting: %s\n", cmd); + + if(buf){ + CloseHandle(outout); + tot = 0; + for(;;){ + if (buf->current >= buf->end) + growbuf(buf); + if(ReadFile(outin, buf->current, buf->end-buf->current, &n, 0) == FALSE) + break; + buf->current += n; + tot += n; + } + if (tot && buf->current[-1] == '\n') + buf->current--; + CloseHandle(outin); + } + + return pid; +} + +static DWORD WINAPI +writecmd(LPVOID a) +{ + struct {char *cmd; HANDLE handle;} *arg; + char *cmd, *p; + int n; + + arg = a; + cmd = arg->cmd; + p = cmd+strlen(cmd); + while(cmd < p){ + if(WriteFile(arg->handle, cmd, p-cmd, &n, 0) == FALSE) + break; + cmd += n; + } + + free(arg->cmd); + CloseHandle(arg->handle); + free(arg); + ExitThread(0); + return 0; +} + +int +pipecmd(char *cmd, Envy *e, int *fd) +{ + int pid; + HANDLE pipein, pipeout; + + if(fd){ + if(CreatePipe(&pipein, &pipeout, 0, 0) == FALSE){ + perror("pipe"); + Exit(); + } + } else + pipeout = GetStdHandle(STD_OUTPUT_HANDLE); + + + pid = spinoff(GetStdHandle(STD_INPUT_HANDLE), pipeout, "-c", cmd, e); + + if(fd){ + CloseHandle(pipeout); + *fd = _open_osfhandle((long)pipein, 0); + } + return pid; +} + +void +Exit(void) +{ + while(waitfor(0) != -1) + ; + exits("error"); +} + +void +catchnotes() +{ +} + +char* +maketmp(void) +{ + static char temp[] = "mkargXXX.XXX"; + + mktemp(temp); + return temp; +} + +Dir* +mkdirstat(char *name) +{ + int c, n, ret; + Dir *buf; + + n = strlen(name)-1; + c = name[n]; + if(c == '/' || c == '\\') + name[n] = 0; + buf = dirstat(name); + name[n] = c; + return buf; +} + +int +chgtime(char *name) +{ + Dir *sbuf; + struct utimbuf u; + + if((sbuf = mkdirstat(name)) != nil){ + u.actime = sbuf->atime; + u.modtime = time(0); + free(sbuf); + return utime(name, &u); + } + return close(create(name, OWRITE, 0666)); +} + +void +rcopy(char **to, Resub *match, int n) +{ + int c; + char *p; + + *to = match->s.sp; /* stem0 matches complete target */ + for(to++, match++; --n > 0; to++, match++){ + if(match->s.sp && match->e.ep){ + p = match->e.ep; + c = *p; + *p = 0; + *to = strdup(match->s.sp); + *p = c; + } else + *to = 0; + } +} + +ulong +mkmtime(char *name) +{ + Dir *buf; + ulong t; + int n; + char *s; + + n = strlen(name)-1; + if(n >= 0 && (name[n] == '/' || name[n] == '\\')){ + s = strdup(name); + s[n] = 0; + }else + s = name; + buf = dirstat(s); + if(buf == nil){ + if(s != name) + free(s); + return 0; + } + t = buf->mtime; + free(buf); + if(s != name) + free(s); + return t; +} + +char *stab; + +char * +membername(char *s, int fd, char *sz) +{ + long t; + + if(s[0] == '/' && s[1] == '\0'){ /* long file name string table */ + t = atol(sz); + if(t&01) t++; + stab = malloc(t); + read(fd, stab, t); + return nil; + } + else if(s[0] == '/' && stab != nil) /* index into string table */ + return stab+atol(s+1); + else + return s; +} diff --git a/utils/mk/Plan9.c b/utils/mk/Plan9.c new file mode 100644 index 00000000..66c4d925 --- /dev/null +++ b/utils/mk/Plan9.c @@ -0,0 +1,363 @@ +#include "mk.h" + +char *shell = "/bin/rc"; +char *shellname = "rc"; + +static Word *encodenulls(char*, int); + +void +readenv(void) +{ + char *p; + int envf, f; + Dir *e; + char nam[1024]; + int i, n, len; + Word *w; + + rfork(RFENVG); /* use copy of the current environment variables */ + + envf = open("/env", OREAD); + if(envf < 0) + return; + while((n = dirread(envf, &e)) > 0){ + for(i = 0; i < n; i++){ + len = e[i].length; + /* don't import funny names, NULL values, + * or internal mk variables + */ + if(len <= 0 || *shname(e[i].name) != '\0') + continue; + if (symlook(e[i].name, S_INTERNAL, 0)) + continue; + sprint(nam, "/env/%s", e[i].name); + f = open(nam, OREAD); + if(f < 0) + continue; + p = Malloc(len+1); + if(read(f, p, len) != len){ + perror(nam); + close(f); + continue; + } + close(f); + if (p[len-1] == 0) + len--; + else + p[len] = 0; + w = encodenulls(p, len); + free(p); + p = strdup(e[i].name); + setvar(p, (void *) w); + symlook(p, S_EXPORTED, (void*)"")->value = (void*)""; + } + free(e); + } + close(envf); +} + +/* break string of values into words at 01's or nulls*/ +static Word * +encodenulls(char *s, int n) +{ + Word *w, *head; + char *cp; + + head = w = 0; + while (n-- > 0) { + for (cp = s; *cp && *cp != '\0'; cp++) + n--; + *cp = 0; + if (w) { + w->next = newword(s); + w = w->next; + } else + head = w = newword(s); + s = cp+1; + } + if (!head) + head = newword(""); + return head; +} + +/* as well as 01's, change blanks to nulls, so that rc will + * treat the words as separate arguments + */ +void +exportenv(Envy *e) +{ + int f, n, hasvalue, first; + Word *w; + Symtab *sy; + char nam[256]; + + for(;e->name; e++){ + sy = symlook(e->name, S_VAR, 0); + if (e->values == 0 || e->values->s == 0 || e->values->s[0] == 0) + hasvalue = 0; + else + hasvalue = 1; + if(sy == 0 && !hasvalue) /* non-existant null symbol */ + continue; + sprint(nam, "/env/%s", e->name); + if (sy != 0 && !hasvalue) { /* Remove from environment */ + /* we could remove it from the symbol table + * too, but we're in the child copy, and it + * would still remain in the parent's table. + */ + remove(nam); + delword(e->values); + e->values = 0; /* memory leak */ + continue; + } + + f = create(nam, OWRITE, 0666L); + if(f < 0) { + fprint(2, "can't create %s, f=%d\n", nam, f); + perror(nam); + continue; + } + first = 1; + for (w = e->values; w; w = w->next) { + n = strlen(w->s); + if (n) { + if(first) + first = 0; + else{ + if (write (f, "\0", 1) != 1) + perror(nam); + } + if (write(f, w->s, n) != n) + perror(nam); + } + } + close(f); + } +} + +int +waitfor(char *msg) +{ + Waitmsg *w; + int pid; + + if((w=wait()) == nil) + return -1; + strecpy(msg, msg+ERRMAX, w->msg); + pid = w->pid; + free(w); + return pid; +} + +void +expunge(int pid, char *msg) +{ + postnote(PNPROC, pid, msg); +} + +int +execsh(char *args, char *cmd, Bufblock *buf, Envy *e) +{ + char *p; + int tot, n, pid, in[2], out[2]; + + if(buf && pipe(out) < 0){ + perror("pipe"); + Exit(); + } + pid = rfork(RFPROC|RFFDG|RFENVG); + if(pid < 0){ + perror("mk rfork"); + Exit(); + } + if(pid == 0){ + if(buf) + close(out[0]); + if(pipe(in) < 0){ + perror("pipe"); + Exit(); + } + pid = fork(); + if(pid < 0){ + perror("mk fork"); + Exit(); + } + if(pid != 0){ + dup(in[0], 0); + if(buf){ + dup(out[1], 1); + close(out[1]); + } + close(in[0]); + close(in[1]); + if (e) + exportenv(e); + if(shflags) + execl(shell, shellname, shflags, args, nil); + else + execl(shell, shellname, args, nil); + perror(shell); + _exits("exec"); + } + close(out[1]); + close(in[0]); + p = cmd+strlen(cmd); + while(cmd < p){ + n = write(in[1], cmd, p-cmd); + if(n < 0) + break; + cmd += n; + } + close(in[1]); + _exits(0); + } + if(buf){ + close(out[1]); + tot = 0; + for(;;){ + if (buf->current >= buf->end) + growbuf(buf); + n = read(out[0], buf->current, buf->end-buf->current); + if(n <= 0) + break; + buf->current += n; + tot += n; + } + if (tot && buf->current[-1] == '\n') + buf->current--; + close(out[0]); + } + return pid; +} + +int +pipecmd(char *cmd, Envy *e, int *fd) +{ + int pid, pfd[2]; + + if(DEBUG(D_EXEC)) + fprint(1, "pipecmd='%s'\n", cmd);/**/ + + if(fd && pipe(pfd) < 0){ + perror("pipe"); + Exit(); + } + pid = rfork(RFPROC|RFFDG|RFENVG); + if(pid < 0){ + perror("mk fork"); + Exit(); + } + if(pid == 0){ + if(fd){ + close(pfd[0]); + dup(pfd[1], 1); + close(pfd[1]); + } + if(e) + exportenv(e); + if(shflags) + execl(shell, shellname, shflags, "-c", cmd, nil); + else + execl(shell, shellname, "-c", cmd, nil); + perror(shell); + _exits("exec"); + } + if(fd){ + close(pfd[1]); + *fd = pfd[0]; + } + return pid; +} + +void +Exit(void) +{ + while(waitpid() >= 0) + ; + exits("error"); +} + +int +notifyf(void *a, char *msg) +{ + static int nnote; + + USED(a); + if(++nnote > 100){ /* until andrew fixes his program */ + fprint(2, "mk: too many notes\n"); + notify(0); + abort(); + } + if(strcmp(msg, "interrupt")!=0 && strcmp(msg, "hangup")!=0) + return 0; + killchildren(msg); + return -1; +} + +void +catchnotes() +{ + atnotify(notifyf, 1); +} + +char* +maketmp(void) +{ + static char temp[] = "/tmp/mkargXXXXXX"; + + mktemp(temp); + return temp; +} + +int +chgtime(char *name) +{ + Dir sbuf; + + if(access(name, AEXIST) >= 0) { + nulldir(&sbuf); + sbuf.mtime = time((long *)0); + return dirwstat(name, &sbuf); + } + return close(create(name, OWRITE, 0666)); +} + +void +rcopy(char **to, Resub *match, int n) +{ + int c; + char *p; + + *to = match->s.sp; /* stem0 matches complete target */ + for(to++, match++; --n > 0; to++, match++){ + if(match->s.sp && match->e.ep){ + p = match->e.ep; + c = *p; + *p = 0; + *to = strdup(match->s.sp); + *p = c; + } + else + *to = 0; + } +} + +ulong +mkmtime(char *name) +{ + Dir *buf; + ulong t; + + buf = dirstat(name); + if(buf == nil) + return 0; + t = buf->mtime; + free(buf); + return t; +} + +char * +membername(char *s, int, char*) +{ + return s; +} diff --git a/utils/mk/Posix.c b/utils/mk/Posix.c new file mode 100644 index 00000000..63ad17f5 --- /dev/null +++ b/utils/mk/Posix.c @@ -0,0 +1,331 @@ +#include "mk.h" +#include <dirent.h> +#include <signal.h> +#include <sys/wait.h> +#include <utime.h> +#include <stdio.h> + +char *shell = "/bin/sh"; +char *shellname = "sh"; + +extern char **environ; + +void +readenv(void) +{ + char **p, *s; + Word *w; + + for(p = environ; *p; p++){ + s = shname(*p); + if(*s == '=') { + *s = 0; + w = newword(s+1); + } else + w = newword(""); + if (symlook(*p, S_INTERNAL, 0)) + continue; + s = strdup(*p); + setvar(s, (void *)w); + symlook(s, S_EXPORTED, (void*)"")->value = (void*)""; + } +} + +/* + * done on child side of fork, so parent's env is not affected + * and we don't care about freeing memory because we're going + * to exec immediately after this. + */ +void +exportenv(Envy *e) +{ + int i; + char **p; + char *values; + + p = 0; + for(i = 0; e->name; e++, i++) { + p = (char**) Realloc(p, (i+2)*sizeof(char*)); + if (e->values) + values = wtos(e->values, IWS); + else + values = ""; + p[i] = malloc(strlen(e->name) + strlen(values) + 2); + sprint(p[i], "%s=%s", e->name, values); + } + p[i] = 0; + environ = p; +} + +int +waitfor(char *msg) +{ + int status; + int pid; + + *msg = 0; + pid = wait(&status); + if(pid > 0) { + if(status&0x7f) { + if(status&0x80) + snprint(msg, ERRMAX, "signal %d, core dumped", status&0x7f); + else + snprint(msg, ERRMAX, "signal %d", status&0x7f); + } else if(status&0xff00) + snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff); + } + return pid; +} + +void +expunge(int pid, char *msg) +{ + if(strcmp(msg, "interrupt")) + kill(pid, SIGINT); + else + kill(pid, SIGHUP); +} + +int +execsh(char *args, char *cmd, Bufblock *buf, Envy *e) +{ + char *p; + int tot, n, pid, in[2], out[2]; + + if(buf && pipe(out) < 0){ + perror("pipe"); + Exit(); + } + pid = fork(); + if(pid < 0){ + perror("mk fork"); + Exit(); + } + if(pid == 0){ + if(buf) + close(out[0]); + if(pipe(in) < 0){ + perror("pipe"); + Exit(); + } + pid = fork(); + if(pid < 0){ + perror("mk fork"); + Exit(); + } + if(pid != 0){ + dup2(in[0], 0); + if(buf){ + dup2(out[1], 1); + close(out[1]); + } + close(in[0]); + close(in[1]); + if (e) + exportenv(e); + if(shflags) + execl(shell, shellname, shflags, args, nil); + else + execl(shell, shellname, args, nil); + perror(shell); + _exits("exec"); + } + close(out[1]); + close(in[0]); + if(DEBUG(D_EXEC)) + fprint(1, "starting: %s\n", cmd); + p = cmd+strlen(cmd); + while(cmd < p){ + n = write(in[1], cmd, p-cmd); + if(n < 0) + break; + cmd += n; + } + close(in[1]); + _exits(0); + } + if(buf){ + close(out[1]); + tot = 0; + for(;;){ + if (buf->current >= buf->end) + growbuf(buf); + n = read(out[0], buf->current, buf->end-buf->current); + if(n <= 0) + break; + buf->current += n; + tot += n; + } + if (tot && buf->current[-1] == '\n') + buf->current--; + close(out[0]); + } + return pid; +} + +int +pipecmd(char *cmd, Envy *e, int *fd) +{ + int pid, pfd[2]; + + if(DEBUG(D_EXEC)) + fprint(1, "pipecmd='%s'\n", cmd);/**/ + + if(fd && pipe(pfd) < 0){ + perror("pipe"); + Exit(); + } + pid = fork(); + if(pid < 0){ + perror("mk fork"); + Exit(); + } + if(pid == 0){ + if(fd){ + close(pfd[0]); + dup2(pfd[1], 1); + close(pfd[1]); + } + if(e) + exportenv(e); + if(shflags) + execl(shell, shellname, shflags, "-c", cmd, nil); + else + execl(shell, shellname, "-c", cmd, nil); + perror(shell); + _exits("exec"); + } + if(fd){ + close(pfd[1]); + *fd = pfd[0]; + } + return pid; +} + +void +Exit(void) +{ + while(wait(0) >= 0) + ; + exits("error"); +} + +static struct +{ + int sig; + char *msg; +} sigmsgs[] = +{ + SIGALRM, "alarm", + SIGFPE, "sys: fp: fptrap", + SIGPIPE, "sys: write on closed pipe", + SIGILL, "sys: trap: illegal instruction", + SIGSEGV, "sys: segmentation violation", + 0, 0 +}; + +static void +notifyf(int sig) +{ + int i; + + for(i = 0; sigmsgs[i].msg; i++) + if(sigmsgs[i].sig == sig) + killchildren(sigmsgs[i].msg); + + /* should never happen */ + signal(sig, SIG_DFL); + kill(getpid(), sig); +} + +void +catchnotes() +{ + int i; + + for(i = 0; sigmsgs[i].msg; i++) + signal(sigmsgs[i].sig, notifyf); +} + +char* +maketmp(void) +{ + static char temp[L_tmpnam]; + + return tmpnam(temp); +} + +int +chgtime(char *name) +{ + Dir *sbuf; + struct utimbuf u; + + if((sbuf = dirstat(name)) != nil) { + u.actime = sbuf->atime; + free(sbuf); + u.modtime = time(0); + return utime(name, &u); + } + return close(create(name, OWRITE, 0666)); +} + +void +rcopy(char **to, Resub *match, int n) +{ + int c; + char *p; + + *to = match->s.sp; /* stem0 matches complete target */ + for(to++, match++; --n > 0; to++, match++){ + if(match->s.sp && match->e.ep){ + p = match->e.ep; + c = *p; + *p = 0; + *to = strdup(match->s.sp); + *p = c; + } + else + *to = 0; + } +} + +ulong +mkmtime(char *name) +{ + Dir *buf; + ulong t; + + buf = dirstat(name); + if(buf == nil) + return 0; + t = buf->mtime; + free(buf); + return t; +} + + +char *stab; + +char * +membername(char *s, int fd, char *sz) +{ + long t; + char *p, *q; + + if(s[0] == '/' && s[1] == '\0'){ /* long file name string table */ + t = atol(sz); + if(t&01) t++; + stab = malloc(t); + read(fd, stab, t); + return nil; + } + else if(s[0] == '/' && stab != nil) { /* index into string table */ + p = stab+atol(s+1); + q = strchr(p, '/'); + if (q) + *q = 0; /* terminate string here */ + return p; + }else + return s; +} diff --git a/utils/mk/README b/utils/mk/README new file mode 100644 index 00000000..092c96a4 --- /dev/null +++ b/utils/mk/README @@ -0,0 +1,26 @@ +Using the delivered mk to rebuild mk. + +You should be able to use the delivered executable of mk to +build a new executable. This may be of particular interest +on Windows NT/Win95 where the path of the shell program +can be hard-coded by changing the variable named "shell" +near the beginning of source file Nt.c. + +Mk uses the regular expression library, so build +the program as follows: + +1. ensure that ../../mkconfig contains the proper system definitions + +2. ensure that the system libraries lib9, libbio, and libregexp have + been built. you can do this by hand by changing to ../lib9, + ../libbio, and ../libregexp and doing "mk nuke" and a "mk install" + in each. + +3. in this directory + mk nuke + mk install + +4. on NT/Win95 the executable must be installed by hand because the current + executable is locked down while it is executing: + + mv obj.out ../../Nt/386/bin/mk.exe diff --git a/utils/mk/arc.c b/utils/mk/arc.c new file mode 100644 index 00000000..521ef7a7 --- /dev/null +++ b/utils/mk/arc.c @@ -0,0 +1,52 @@ +#include "mk.h" + +Arc * +newarc(Node *n, Rule *r, char *stem, Resub *match) +{ + Arc *a; + + a = (Arc *)Malloc(sizeof(Arc)); + a->n = n; + a->r = r; + a->stem = strdup(stem); + rcopy(a->match, match, NREGEXP); + a->next = 0; + a->flag = 0; + a->prog = r->prog; + return(a); +} + +void +dumpa(char *s, Arc *a) +{ + char buf[1024]; + + Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'", + s, a, a->n, a->r, a->flag, a->stem); + if(a->prog) + Bprint(&bout, " prog='%s'", a->prog); + Bprint(&bout, "\n"); + + if(a->n){ + snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:""); + dumpn(buf, a->n); + } +} + +void +nrep(void) +{ + Symtab *sym; + Word *w; + + sym = symlook("NREP", S_VAR, 0); + if(sym){ + w = (Word *) sym->value; + if (w && w->s && *w->s) + nreps = atoi(w->s); + } + if(nreps < 1) + nreps = 1; + if(DEBUG(D_GRAPH)) + Bprint(&bout, "nreps = %d\n", nreps); +} diff --git a/utils/mk/archive.c b/utils/mk/archive.c new file mode 100644 index 00000000..92ed947c --- /dev/null +++ b/utils/mk/archive.c @@ -0,0 +1,169 @@ +#include "mk.h" +#include <ar.h> + +static int dolong; + +static void atimes(char *); +static char *split(char*, char**); + +long +atimeof(int force, char *name) +{ + Symtab *sym; + long t; + char *archive, *member, buf[512]; + + archive = split(name, &member); + if(archive == 0) + Exit(); + + t = mtime(archive); + sym = symlook(archive, S_AGG, 0); + if(sym){ + if(force || (t > (long)sym->value)){ + atimes(archive); + sym->value = (void *)t; + } + } + else{ + atimes(archive); + /* mark the aggegate as having been done */ + symlook(strdup(archive), S_AGG, "")->value = (void *)t; + } + /* truncate long member name to sizeof of name field in archive header */ + if(dolong) + snprint(buf, sizeof(buf), "%s(%s)", archive, member); + else + snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member); + sym = symlook(buf, S_TIME, 0); + if (sym) + return (long)sym->value; /* uggh */ + return 0; +} + +void +atouch(char *name) +{ + char *archive, *member; + int fd, i; + struct ar_hdr h; + long t; + + archive = split(name, &member); + if(archive == 0) + Exit(); + + fd = open(archive, ORDWR); + if(fd < 0){ + fd = create(archive, OWRITE, 0666); + if(fd < 0){ + perror(archive); + Exit(); + } + write(fd, ARMAG, SARMAG); + } + if(symlook(name, S_TIME, 0)){ + /* hoon off and change it in situ */ + LSEEK(fd, SARMAG, 0); + while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){ + for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--) + ; + h.name[i+1]=0; + if(strcmp(member, h.name) == 0){ + t = SARNAME-sizeof(h); /* ughgghh */ + LSEEK(fd, t, 1); + fprint(fd, "%-12ld", time(0)); + break; + } + t = atol(h.size); + if(t&01) t++; + LSEEK(fd, t, 1); + } + } + close(fd); +} + +static void +atimes(char *ar) +{ + struct ar_hdr h; + long t; + int fd, i; + char buf[BIGBLOCK]; + char *n, name[sizeof(h.name)+1]; + + fd = open(ar, OREAD); + if(fd < 0) + return; + + if(read(fd, buf, SARMAG) != SARMAG){ + close(fd); + return; + } + while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){ + t = atol(h.date); + if(t == 0) /* as it sometimes happens; thanks ken */ + t = 1; + strncpy(name, h.name, sizeof(h.name)); + for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--) + ; + if(name[i] == '/') /* system V bug */ + i--; + name[i+1]=0; + n = membername(name, fd, h.size); + if(n == nil){ + dolong = 1; + continue; + } + sprint(buf, "%s(%s)", ar, n); + symlook(strdup(buf), S_TIME, (void *)t)->value = (void *)t; + t = atol(h.size); + if(t&01) t++; + LSEEK(fd, t, 1); + } + close(fd); +} + +static int +type(char *file) +{ + int fd; + char buf[SARMAG]; + + fd = open(file, OREAD); + if(fd < 0){ + if(symlook(file, S_BITCH, 0) == 0){ + Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file); + symlook(file, S_BITCH, (void *)file); + } + return 1; + } + if(read(fd, buf, SARMAG) != SARMAG){ + close(fd); + return 0; + } + close(fd); + return !strncmp(ARMAG, buf, SARMAG); +} + +static char* +split(char *name, char **member) +{ + char *p, *q; + + p = strdup(name); + q = utfrune(p, '('); + if(q){ + *q++ = 0; + if(member) + *member = q; + q = utfrune(q, ')'); + if (q) + *q = 0; + if(type(p)) + return p; + free(p); + fprint(2, "mk: '%s' is not an archive\n", name); + } + return 0; +} diff --git a/utils/mk/bufblock.c b/utils/mk/bufblock.c new file mode 100644 index 00000000..979403bc --- /dev/null +++ b/utils/mk/bufblock.c @@ -0,0 +1,88 @@ +#include "mk.h" + +static Bufblock *freelist; +#define QUANTA 4096 + +Bufblock * +newbuf(void) +{ + Bufblock *p; + + if (freelist) { + p = freelist; + freelist = freelist->next; + } else { + p = (Bufblock *) Malloc(sizeof(Bufblock)); + p->start = Malloc(QUANTA*sizeof(*p->start)); + p->end = p->start+QUANTA; + } + p->current = p->start; + *p->start = 0; + p->next = 0; + return p; +} + +void +freebuf(Bufblock *p) +{ + p->next = freelist; + freelist = p; +} + +void +growbuf(Bufblock *p) +{ + int n; + Bufblock *f; + char *cp; + + n = p->end-p->start+QUANTA; + /* search the free list for a big buffer */ + for (f = freelist; f; f = f->next) { + if (f->end-f->start >= n) { + memcpy(f->start, p->start, p->end-p->start); + cp = f->start; + f->start = p->start; + p->start = cp; + cp = f->end; + f->end = p->end; + p->end = cp; + f->current = f->start; + break; + } + } + if (!f) { /* not found - grow it */ + p->start = Realloc(p->start, n); + p->end = p->start+n; + } + p->current = p->start+n-QUANTA; +} + +void +bufcpy(Bufblock *buf, char *cp, int n) +{ + + while (n--) + insert(buf, *cp++); +} + +void +insert(Bufblock *buf, int c) +{ + + if (buf->current >= buf->end) + growbuf(buf); + *buf->current++ = c; +} + +void +rinsert(Bufblock *buf, Rune r) +{ + int n; + + n = runelen(r); + if (buf->current+n > buf->end) + growbuf(buf); + runetochar(buf->current, &r); + buf->current += n; +} diff --git a/utils/mk/env.c b/utils/mk/env.c new file mode 100644 index 00000000..c040db58 --- /dev/null +++ b/utils/mk/env.c @@ -0,0 +1,149 @@ +#include "mk.h" + +enum { + ENVQUANTA=10 +}; + +Envy *envy; +static int nextv; + +static char *myenv[] = +{ + "target", + "stem", + "prereq", + "pid", + "nproc", + "newprereq", + "alltarget", + "newmember", + "stem0", /* must be in order from here */ + "stem1", + "stem2", + "stem3", + "stem4", + "stem5", + "stem6", + "stem7", + "stem8", + "stem9", + 0, +}; + +void +initenv(void) +{ + char **p; + + for(p = myenv; *p; p++) + symlook(*p, S_INTERNAL, (void *)""); + readenv(); /* o.s. dependent */ +} + +static void +envinsert(char *name, Word *value) +{ + static int envsize; + + if (nextv >= envsize) { + envsize += ENVQUANTA; + envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy)); + } + envy[nextv].name = name; + envy[nextv++].values = value; +} + +static void +envupd(char *name, Word *value) +{ + Envy *e; + + for(e = envy; e->name; e++) + if(strcmp(name, e->name) == 0){ + delword(e->values); + e->values = value; + return; + } + e->name = name; + e->values = value; + envinsert(0,0); +} + +static void +ecopy(Symtab *s) +{ + char **p; + + if(symlook(s->name, S_NOEXPORT, 0)) + return; + for(p = myenv; *p; p++) + if(strcmp(*p, s->name) == 0) + return; + envinsert(s->name, (Word *) s->value); +} + +void +execinit(void) +{ + char **p; + + nextv = 0; + for(p = myenv; *p; p++) + envinsert(*p, stow("")); + + symtraverse(S_VAR, ecopy); + envinsert(0, 0); +} + +Envy* +buildenv(Job *j, int slot) +{ + char **p, *cp, *qp; + Word *w, *v, **l; + int i; + char buf[256]; + + envupd("target", wdup(j->t)); + if(j->r->attr®EXP) + envupd("stem",newword("")); + else + envupd("stem", newword(j->stem)); + envupd("prereq", wdup(j->p)); + sprint(buf, "%d", getpid()); + envupd("pid", newword(buf)); + sprint(buf, "%d", slot); + envupd("nproc", newword(buf)); + envupd("newprereq", wdup(j->np)); + envupd("alltarget", wdup(j->at)); + l = &v; + v = w = wdup(j->np); + while(w){ + cp = strchr(w->s, '('); + if(cp){ + qp = strchr(cp+1, ')'); + if(qp){ + *qp = 0; + strcpy(w->s, cp+1); + l = &w->next; + w = w->next; + continue; + } + } + *l = w->next; + free(w->s); + free(w); + w = *l; + } + envupd("newmember", v); + /* update stem0 -> stem9 */ + for(p = myenv; *p; p++) + if(strcmp(*p, "stem0") == 0) + break; + for(i = 0; *p; i++, p++){ + if((j->r->attr®EXP) && j->match[i]) + envupd(*p, newword(j->match[i])); + else + envupd(*p, newword("")); + } + return envy; +} diff --git a/utils/mk/file.c b/utils/mk/file.c new file mode 100644 index 00000000..1ff6623e --- /dev/null +++ b/utils/mk/file.c @@ -0,0 +1,90 @@ +#include "mk.h" + +/* table-driven version in bootes dump of 12/31/96 */ + +long +mtime(char *name) +{ + return mkmtime(name); +} + +long +timeof(char *name, int force) +{ + Symtab *sym; + long t; + + if(utfrune(name, '(')) + return atimeof(force, name); /* archive */ + + if(force) + return mtime(name); + + + sym = symlook(name, S_TIME, 0); + if (sym) + return (long) sym->value; /* uggh */ + + t = mtime(name); + if(t == 0) + return 0; + + symlook(name, S_TIME, (void*)t); /* install time in cache */ + return t; +} + +void +touch(char *name) +{ + Bprint(&bout, "touch(%s)\n", name); + if(nflag) + return; + + if(utfrune(name, '(')) + atouch(name); /* archive */ + else if(chgtime(name) < 0) { + perror(name); + Exit(); + } +} + +void +delete(char *name) +{ + if(utfrune(name, '(') == 0) { /* file */ + if(remove(name) < 0) + perror(name); + } else + fprint(2, "hoon off; mk can'tdelete archive members\n"); +} + +void +timeinit(char *s) +{ + long t; + char *cp; + Rune r; + int c, n; + + t = time(0); + while (*s) { + cp = s; + do{ + n = chartorune(&r, s); + if (r == ' ' || r == ',' || r == '\n') + break; + s += n; + } while(*s); + c = *s; + *s = 0; + symlook(strdup(cp), S_TIME, (void *)t)->value = (void *)t; + if (c) + *s++ = c; + while(*s){ + n = chartorune(&r, s); + if(r != ' ' && r != ',' && r != '\n') + break; + s += n; + } + } +} diff --git a/utils/mk/fns.h b/utils/mk/fns.h new file mode 100644 index 00000000..01ee98a1 --- /dev/null +++ b/utils/mk/fns.h @@ -0,0 +1,84 @@ +void addrule(char*, Word*, char*, Word*, int, int, char*); +void addrules(Word*, Word*, char*, int, int, char*); +void addw(Word*, char*); +void assert(char*, int); +int assline(Biobuf *, Bufblock *); +long atimeof(int,char*); +void atouch(char*); +void bufcpy(Bufblock *, char *, int); +Envy *buildenv(Job*, int); +void catchnotes(void); +char *charin(char *, char *); +int chgtime(char*); +void clrmade(Node*); +char *copyq(char*, Rune, Bufblock*); +void delete(char*); +void delword(Word*); +int dorecipe(Node*); +void dumpa(char*, Arc*); +void dumpj(char*, Job*, int); +void dumpn(char*, Node*); +void dumpr(char*, Rule*); +void dumpv(char*); +void dumpw(char*, Word*); +int escapetoken(Biobuf*, Bufblock*, int, int); +void execinit(void); +int execsh(char*, char*, Bufblock*, Envy*); +void Exit(void); +char *expandquote(char*, Rune, Bufblock*); +void expunge(int, char*); +void freebuf(Bufblock*); +void front(char*); +Node *graph(char*); +void growbuf(Bufblock *); +void initenv(void); +void insert(Bufblock *, int); +void ipop(void); +void ipush(void); +void killchildren(char*); +void *Malloc(int); +char *maketmp(void); +int match(char*, char*, char*); +char *membername(char*, int, char*); +void mk(char*); +ulong mkmtime(char*); +long mtime(char*); +Arc *newarc(Node*, Rule*, char*, Resub*); +Bufblock *newbuf(void); +Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*); +Word *newword(char*); +int nextrune(Biobuf*, int); +int nextslot(void); +void nproc(void); +void nrep(void); +int outofdate(Node*, Arc*, int); +void parse(char*, int, int); +int pipecmd(char*, Envy*, int*); +void prusage(void); +void rcopy(char**, Resub*, int); +void readenv(void); +void *Realloc(void*, int); +void rinsert(Bufblock *, Rune); +char *rulecnt(void); +void run(Job*); +void setvar(char*, void*); +char *shname(char*); +void shprint(char*, Envy*, Bufblock*); +Word *stow(char*); +void subst(char*, char*, char*); +void symdel(char*, int); +void syminit(void); +Symtab *symlook(char*, int, void*); +void symstat(void); +void symtraverse(int, void(*)(Symtab*)); +void timeinit(char*); +long timeof(char*, int); +void touch(char*); +void update(int, Node*); +void usage(void); +Word *varsub(char**); +int waitfor(char*); +int waitup(int, int*); +Word *wdup(Word*); +int work(Node*, Node*, Arc*); +char *wtos(Word*, int); diff --git a/utils/mk/graph.c b/utils/mk/graph.c new file mode 100644 index 00000000..018e4aea --- /dev/null +++ b/utils/mk/graph.c @@ -0,0 +1,279 @@ +#include "mk.h" + +static Node *applyrules(char *, char *); +static void togo(Node *); +static int vacuous(Node *); +static Node *newnode(char *); +static void trace(char *, Arc *); +static void cyclechk(Node *); +static void ambiguous(Node *); +static void attribute(Node *); + +Node * +graph(char *target) +{ + Node *node; + char *cnt; + + cnt = rulecnt(); + node = applyrules(target, cnt); + free(cnt); + cyclechk(node); + node->flags |= PROBABLE; /* make sure it doesn't get deleted */ + vacuous(node); + ambiguous(node); + attribute(node); + return(node); +} + +static Node * +applyrules(char *target, char *cnt) +{ + Symtab *sym; + Node *node; + Rule *r; + Arc head, *a = &head; + Word *w; + char stem[NAMEBLOCK], buf[NAMEBLOCK]; + Resub rmatch[NREGEXP]; + +/* print("applyrules(%lux='%s')\n", target, target);/**/ + sym = symlook(target, S_NODE, 0); + if(sym) + return (Node *)(sym->value); + target = strdup(target); + node = newnode(target); + head.n = 0; + head.next = 0; + sym = symlook(target, S_TARGET, 0); + memset((char*)rmatch, 0, sizeof(rmatch)); + for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){ + if(r->attr&META) continue; + if(strcmp(target, r->target)) continue; + if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */ + if(cnt[r->rule] >= nreps) continue; + cnt[r->rule]++; + node->flags |= PROBABLE; + +/* if(r->attr&VIR) + * node->flags |= VIRTUAL; + * if(r->attr&NOREC) + * node->flags |= NORECIPE; + * if(r->attr&DEL) + * node->flags |= DELETE; + */ + if(!r->tail || !r->tail->s || !*r->tail->s) { + a->next = newarc((Node *)0, r, "", rmatch); + a = a->next; + } else + for(w = r->tail; w; w = w->next){ + a->next = newarc(applyrules(w->s, cnt), r, "", rmatch); + a = a->next; + } + cnt[r->rule]--; + head.n = node; + } + for(r = metarules; r; r = r->next){ + if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */ + if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR)) + continue; + if(r->attr®EXP){ + stem[0] = 0; + patrule = r; + memset((char*)rmatch, 0, sizeof(rmatch)); + if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0) + continue; + } else { + if(!match(node->name, r->target, stem)) continue; + } + if(cnt[r->rule] >= nreps) continue; + cnt[r->rule]++; + +/* if(r->attr&VIR) + * node->flags |= VIRTUAL; + * if(r->attr&NOREC) + * node->flags |= NORECIPE; + * if(r->attr&DEL) + * node->flags |= DELETE; + */ + + if(!r->tail || !r->tail->s || !*r->tail->s) { + a->next = newarc((Node *)0, r, stem, rmatch); + a = a->next; + } else + for(w = r->tail; w; w = w->next){ + if(r->attr®EXP) + regsub(w->s, buf, rmatch, NREGEXP); + else + subst(stem, w->s, buf); + a->next = newarc(applyrules(buf, cnt), r, stem, rmatch); + a = a->next; + } + cnt[r->rule]--; + } + a->next = node->prereqs; + node->prereqs = head.next; + return(node); +} + +static void +togo(Node *node) +{ + Arc *la, *a; + + /* delete them now */ + la = 0; + for(a = node->prereqs; a; la = a, a = a->next) + if(a->flag&TOGO){ + if(a == node->prereqs) + node->prereqs = a->next; + else + la->next = a->next, a = la; + } +} + +static +vacuous(Node *node) +{ + Arc *la, *a; + int vac = !(node->flags&PROBABLE); + + if(node->flags&READY) + return(node->flags&VACUOUS); + node->flags |= READY; + for(a = node->prereqs; a; a = a->next) + if(a->n && vacuous(a->n) && (a->r->attr&META)) + a->flag |= TOGO; + else + vac = 0; + /* if a rule generated arcs that DON'T go; no others from that rule go */ + for(a = node->prereqs; a; a = a->next) + if((a->flag&TOGO) == 0) + for(la = node->prereqs; la; la = la->next) + if((la->flag&TOGO) && (la->r == a->r)){ + la->flag &= ~TOGO; + } + togo(node); + if(vac) + node->flags |= VACUOUS; + return(vac); +} + +static Node * +newnode(char *name) +{ + register Node *node; + + node = (Node *)Malloc(sizeof(Node)); + symlook(name, S_NODE, (void *)node); + node->name = name; + node->time = timeof(name, 0); + node->prereqs = 0; + node->flags = node->time? PROBABLE : 0; + node->next = 0; + return(node); +} + +void +dumpn(char *s, Node *n) +{ + char buf[1024]; + Arc *a; + + sprint(buf, "%s ", (*s == ' ')? s:""); + Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n", + s, n->name, n, n->time, n->flags, n->next); + for(a = n->prereqs; a; a = a->next) + dumpa(buf, a); +} + +static void +trace(char *s, Arc *a) +{ + fprint(2, "\t%s", s); + while(a){ + fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line, + a->n? a->n->name:""); + if(a->n){ + for(a = a->n->prereqs; a; a = a->next) + if(*a->r->recipe) break; + } else + a = 0; + } + fprint(2, "\n"); +} + +static void +cyclechk(Node *n) +{ + Arc *a; + + if((n->flags&CYCLE) && n->prereqs){ + fprint(2, "mk: cycle in graph detected at target %s\n", n->name); + Exit(); + } + n->flags |= CYCLE; + for(a = n->prereqs; a; a = a->next) + if(a->n) + cyclechk(a->n); + n->flags &= ~CYCLE; +} + +static void +ambiguous(Node *n) +{ + Arc *a; + Rule *r = 0; + Arc *la; + int bad = 0; + + la = 0; + for(a = n->prereqs; a; a = a->next){ + if(a->n) + ambiguous(a->n); + if(*a->r->recipe == 0) continue; + if(r == 0) + r = a->r, la = a; + else{ + if(r->recipe != a->r->recipe){ + if((r->attr&META) && !(a->r->attr&META)){ + la->flag |= TOGO; + r = a->r, la = a; + } else if(!(r->attr&META) && (a->r->attr&META)){ + a->flag |= TOGO; + continue; + } + } + if(r->recipe != a->r->recipe){ + if(bad == 0){ + fprint(2, "mk: ambiguous recipes for %s:\n", n->name); + bad = 1; + trace(n->name, la); + } + trace(n->name, a); + } + } + } + if(bad) + Exit(); + togo(n); +} + +static void +attribute(Node *n) +{ + register Arc *a; + + for(a = n->prereqs; a; a = a->next){ + if(a->r->attr&VIR) + n->flags |= VIRTUAL; + if(a->r->attr&NOREC) + n->flags |= NORECIPE; + if(a->r->attr&DEL) + n->flags |= DELETE; + if(a->n) + attribute(a->n); + } + if(n->flags&VIRTUAL) + n->time = 0; +} diff --git a/utils/mk/job.c b/utils/mk/job.c new file mode 100644 index 00000000..cee93760 --- /dev/null +++ b/utils/mk/job.c @@ -0,0 +1,33 @@ +#include "mk.h" + +Job * +newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar) +{ + register Job *j; + + j = (Job *)Malloc(sizeof(Job)); + j->r = r; + j->n = nlist; + j->stem = stem; + j->match = match; + j->p = pre; + j->np = npre; + j->t = tar; + j->at = atar; + j->nproc = -1; + j->next = 0; + return(j); +} + +void +dumpj(char *s, Job *j, int all) +{ + Bprint(&bout, "%s\n", s); + while(j){ + Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n", + j, j->r, j->n, j->stem, j->nproc); + Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n", + wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' ')); + j = all? j->next : 0; + } +} diff --git a/utils/mk/lex.c b/utils/mk/lex.c new file mode 100644 index 00000000..3ee244f1 --- /dev/null +++ b/utils/mk/lex.c @@ -0,0 +1,147 @@ +#include "mk.h" + +static int bquote(Biobuf*, Bufblock*); + +/* + * Assemble a line skipping blank lines, comments, and eliding + * escaped newlines + */ +int +assline(Biobuf *bp, Bufblock *buf) +{ + int c; + int lastc; + + buf->current=buf->start; + while ((c = nextrune(bp, 1)) >= 0){ + switch(c) + { + case '\r': /* consumes CRs for Win95 */ + continue; + case '\n': + if (buf->current != buf->start) { + insert(buf, 0); + return 1; + } + break; /* skip empty lines */ + case '\\': + case '\'': + case '"': + rinsert(buf, c); + if (escapetoken(bp, buf, 1, c) == 0) + Exit(); + break; + case '`': + if (bquote(bp, buf) == 0) + Exit(); + break; + case '#': + lastc = '#'; + while ((c = Bgetc(bp)) != '\n') { + if (c < 0) + goto eof; + if(c != '\r') + lastc = c; + } + mkinline++; + if (lastc == '\\') + break; /* propagate escaped newlines??*/ + if (buf->current != buf->start) { + insert(buf, 0); + return 1; + } + break; + default: + rinsert(buf, c); + break; + } + } +eof: + insert(buf, 0); + return *buf->start != 0; +} + +/* + * assemble a back-quoted shell command into a buffer + */ +static int +bquote(Biobuf *bp, Bufblock *buf) +{ + int c, line, term; + int start; + + line = mkinline; + while((c = Bgetrune(bp)) == ' ' || c == '\t') + ; + if(c == '{'){ + term = '}'; /* rc style */ + while((c = Bgetrune(bp)) == ' ' || c == '\t') + ; + } else + term = '`'; /* sh style */ + + start = buf->current-buf->start; + for(;c > 0; c = nextrune(bp, 0)){ + if(c == term){ + insert(buf, '\n'); + insert(buf,0); + buf->current = buf->start+start; + execinit(); + execsh(0, buf->current, buf, envy); + return 1; + } + if(c == '\n') + break; + if(c == '\'' || c == '"' || c == '\\'){ + insert(buf, c); + if(!escapetoken(bp, buf, 1, c)) + return 0; + continue; + } + rinsert(buf, c); + } + SYNERR(line); + fprint(2, "missing closing %c after `\n", term); + return 0; +} + +/* + * get next character stripping escaped newlines + * the flag specifies whether escaped newlines are to be elided or + * replaced with a blank. + */ +int +nextrune(Biobuf *bp, int elide) +{ + int c, c2; + static int savec; + + if(savec){ + c = savec; + savec = 0; + return c; + } + + for (;;) { + c = Bgetrune(bp); + if (c == '\\') { + c2 = Bgetrune(bp); + if(c2 == '\r'){ + savec = c2; + c2 = Bgetrune(bp); + } + if (c2 == '\n') { + savec = 0; + mkinline++; + if (elide) + continue; + return ' '; + } + Bungetrune(bp); + } + if (c == '\n') + mkinline++; + return c; + } + return 0; +} diff --git a/utils/mk/main.c b/utils/mk/main.c new file mode 100644 index 00000000..43e34559 --- /dev/null +++ b/utils/mk/main.c @@ -0,0 +1,291 @@ +#include "mk.h" + +#define MKFILE "mkfile" + +static char *version = "@(#)mk general release 4 (plan 9)"; +int debug; +Rule *rules, *metarules; +int nflag = 0; +int tflag = 0; +int iflag = 0; +int kflag = 0; +int aflag = 0; +int uflag = 0; +char *explain = 0; +Word *target1; +int nreps = 1; +Job *jobs; +Biobuf bout; +Rule *patrule; +void badusage(void); +#ifdef PROF +short buf[10000]; +#endif + +void +main(int argc, char **argv) +{ + Word *w; + char *s, *temp; + char *files[256], **f = files, **ff; + int sflag = 0; + int i; + int tfd = -1; + Biobuf tb; + Bufblock *buf; + Bufblock *whatif; + + /* + * start with a copy of the current environment variables + * instead of sharing them + */ + + Binit(&bout, 1, OWRITE); + buf = newbuf(); + whatif = 0; + USED(argc); + for(argv++; *argv && (**argv == '-'); argv++) + { + bufcpy(buf, argv[0], strlen(argv[0])); + insert(buf, ' '); + switch(argv[0][1]) + { + case 'a': + aflag = 1; + break; + case 'd': + if(*(s = &argv[0][2])) + while(*s) switch(*s++) + { + case 'p': debug |= D_PARSE; break; + case 'g': debug |= D_GRAPH; break; + case 'e': debug |= D_EXEC; break; + } + else + debug = 0xFFFF; + break; + case 'e': + explain = &argv[0][2]; + break; + case 'f': + if(*++argv == 0) + badusage(); + *f++ = *argv; + bufcpy(buf, argv[0], strlen(argv[0])); + insert(buf, ' '); + break; + case 'i': + iflag = 1; + break; + case 'k': + kflag = 1; + break; + case 'n': + nflag = 1; + break; + case 's': + sflag = 1; + break; + case 't': + tflag = 1; + break; + case 'u': + uflag = 1; + break; + case 'w': + if(whatif == 0) + whatif = newbuf(); + else + insert(whatif, ' '); + if(argv[0][2]) + bufcpy(whatif, &argv[0][2], strlen(&argv[0][2])); + else { + if(*++argv == 0) + badusage(); + bufcpy(whatif, &argv[0][0], strlen(&argv[0][0])); + } + break; + default: + badusage(); + } + } +#ifdef PROF + { + extern etext(); + monitor(main, etext, buf, sizeof buf, 300); + } +#endif + + if(aflag) + iflag = 1; + usage(); + syminit(); + initenv(); + usage(); + + /* + assignment args become null strings + */ + temp = 0; + for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){ + bufcpy(buf, argv[i], strlen(argv[i])); + insert(buf, ' '); + if(tfd < 0){ + temp = maketmp(); + if(temp == 0) { + perror("temp file"); + Exit(); + } + close(create(temp, OWRITE, 0600)); + if((tfd = open(temp, 2)) < 0){ + perror(temp); + Exit(); + } + Binit(&tb, tfd, OWRITE); + } + Bprint(&tb, "%s\n", argv[i]); + *argv[i] = 0; + } + if(tfd >= 0){ + Bflush(&tb); + LSEEK(tfd, 0L, 0); + parse("command line args", tfd, 1); + remove(temp); + } + + if (buf->current != buf->start) { + buf->current--; + insert(buf, 0); + } + symlook("MKFLAGS", S_VAR, (void *) stow(buf->start)); + buf->current = buf->start; + for(i = 0; argv[i]; i++){ + if(*argv[i] == 0) continue; + if(i) + insert(buf, ' '); + bufcpy(buf, argv[i], strlen(argv[i])); + } + insert(buf, 0); + symlook("MKARGS", S_VAR, (void *) stow(buf->start)); + freebuf(buf); + + if(f == files){ + if(access(MKFILE, 4) == 0) + parse(MKFILE, open(MKFILE, 0), 0); + } else + for(ff = files; ff < f; ff++) + parse(*ff, open(*ff, 0), 0); + if(DEBUG(D_PARSE)){ + dumpw("default targets", target1); + dumpr("rules", rules); + dumpr("metarules", metarules); + dumpv("variables"); + } + if(whatif){ + insert(whatif, 0); + timeinit(whatif->start); + freebuf(whatif); + } + execinit(); + /* skip assignment args */ + while(*argv && (**argv == 0)) + argv++; + + catchnotes(); + if(*argv == 0){ + if(target1) + for(w = target1; w; w = w->next) + mk(w->s); + else { + fprint(2, "mk: nothing to mk\n"); + Exit(); + } + } else { + if(sflag){ + for(; *argv; argv++) + if(**argv) + mk(*argv); + } else { + Word *head, *tail, *t; + + /* fake a new rule with all the args as prereqs */ + tail = 0; + t = 0; + for(; *argv; argv++) + if(**argv){ + if(tail == 0) + tail = t = newword(*argv); + else { + t->next = newword(*argv); + t = t->next; + } + } + if(tail->next == 0) + mk(tail->s); + else { + head = newword("command line arguments"); + addrules(head, tail, strdup(""), VIR, mkinline, 0); + mk(head->s); + } + } + } + if(uflag) + prusage(); + exits(0); +} + +void +badusage(void) +{ + + fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n"); + Exit(); +} + +void * +Malloc(int n) +{ + register void *s; + + s = malloc(n); + if(!s) { + fprint(2, "mk: cannot alloc %d bytes\n", n); + Exit(); + } + return(s); +} + +void * +Realloc(void *s, int n) +{ + if(s) + s = realloc(s, n); + else + s = malloc(n); + if(!s) { + fprint(2, "mk: cannot alloc %d bytes\n", n); + Exit(); + } + return(s); +} + +void +assert(char *s, int n) +{ + if(!n){ + fprint(2, "mk: Assertion ``%s'' failed.\n", s); + Exit(); + } +} + +void +regerror(char *s) +{ + if(patrule) + fprint(2, "mk: %s:%d: regular expression error; %s\n", + patrule->file, patrule->line, s); + else + fprint(2, "mk: %s:%d: regular expression error; %s\n", + infile, mkinline, s); + Exit(); +} diff --git a/utils/mk/match.c b/utils/mk/match.c new file mode 100644 index 00000000..2a96394a --- /dev/null +++ b/utils/mk/match.c @@ -0,0 +1,49 @@ +#include "mk.h" + +int +match(char *name, char *template, char *stem) +{ + Rune r; + int n; + + while(*name && *template){ + n = chartorune(&r, template); + if (PERCENT(r)) + break; + while (n--) + if(*name++ != *template++) + return 0; + } + if(!PERCENT(*template)) + return 0; + n = strlen(name)-strlen(template+1); + if (n < 0) + return 0; + if (strcmp(template+1, name+n)) + return 0; + strncpy(stem, name, n); + stem[n] = 0; + if(*template == '&') + return !charin(stem, "./"); + return 1; +} + +void +subst(char *stem, char *template, char *dest) +{ + Rune r; + char *s; + int n; + + while(*template){ + n = chartorune(&r, template); + if (PERCENT(r)) { + template += n; + for (s = stem; *s; s++) + *dest++ = *s; + } else + while (n--) + *dest++ = *template++; + } + *dest = 0; +} diff --git a/utils/mk/mk.c b/utils/mk/mk.c new file mode 100644 index 00000000..98d76623 --- /dev/null +++ b/utils/mk/mk.c @@ -0,0 +1,226 @@ +#include "mk.h" + +int runerrs; + +void +mk(char *target) +{ + Node *node; + int did = 0; + + nproc(); /* it can be updated dynamically */ + nrep(); /* it can be updated dynamically */ + runerrs = 0; + node = graph(target); + if(DEBUG(D_GRAPH)){ + dumpn("new target\n", node); + Bflush(&bout); + } + clrmade(node); + while(node->flags&NOTMADE){ + if(work(node, (Node *)0, (Arc *)0)) + did = 1; /* found something to do */ + else { + if(waitup(1, (int *)0) > 0){ + if(node->flags&(NOTMADE|BEINGMADE)){ + assert("must be run errors", runerrs); + break; /* nothing more waiting */ + } + } + } + } + if(node->flags&BEINGMADE) + waitup(-1, (int *)0); + while(jobs) + waitup(-2, (int *)0); + assert("target didn't get done", runerrs || (node->flags&MADE)); + if(did == 0) + Bprint(&bout, "mk: '%s' is up to date\n", node->name); +} + +void +clrmade(Node *n) +{ + Arc *a; + + n->flags &= ~(CANPRETEND|PRETENDING); + if(strchr(n->name, '(') ==0 || n->time) + n->flags |= CANPRETEND; + MADESET(n, NOTMADE); + for(a = n->prereqs; a; a = a->next) + if(a->n) + clrmade(a->n); +} + +static void +unpretend(Node *n) +{ + MADESET(n, NOTMADE); + n->flags &= ~(CANPRETEND|PRETENDING); + n->time = 0; +} + +int +work(Node *node, Node *p, Arc *parc) +{ + Arc *a, *ra; + int weoutofdate; + int ready; + int did = 0; + + /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, node->time);/**/ + if(node->flags&BEINGMADE) + return(did); + if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){ + if(explain) + fprint(1, "unpretending %s(%ld) because %s is out of date(%ld)\n", + node->name, node->time, p->name, p->time); + unpretend(node); + } + /* + have a look if we are pretending in case + someone has been unpretended out from underneath us + */ + if(node->flags&MADE){ + if(node->flags&PRETENDING){ + node->time = 0; + }else + return(did); + } + /* consider no prerequsite case */ + if(node->prereqs == 0){ + if(node->time == 0){ + fprint(2, "mk: don't know how to make '%s'\n", node->name); + if(kflag){ + node->flags |= BEINGMADE; + runerrs++; + } else + Exit(); + } else + MADESET(node, MADE); + return(did); + } + /* + now see if we are out of date or what + */ + ready = 1; + weoutofdate = aflag; + ra = 0; + for(a = node->prereqs; a; a = a->next) + if(a->n){ + did = work(a->n, node, a) || did; + if(a->n->flags&(NOTMADE|BEINGMADE)) + ready = 0; + if(outofdate(node, a, 0)){ + weoutofdate = 1; + if((ra == 0) || (ra->n == 0) + || (ra->n->time < a->n->time)) + ra = a; + } + } else { + if(node->time == 0){ + if(ra == 0) + ra = a; + weoutofdate = 1; + } + } + if(ready == 0) /* can't do anything now */ + return(did); + if(weoutofdate == 0){ + MADESET(node, MADE); + return(did); + } + /* + can we pretend to be made? + */ + if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND)) + && p && ra->n && !outofdate(p, ra, 0)){ + node->flags &= ~CANPRETEND; + MADESET(node, MADE); + if(explain && ((node->flags&PRETENDING) == 0)) + fprint(1, "pretending %s has time %ld\n", node->name, node->time); + node->flags |= PRETENDING; + return(did); + } + /* + node is out of date and we REALLY do have to do something. + quickly rescan for pretenders + */ + for(a = node->prereqs; a; a = a->next) + if(a->n && (a->n->flags&PRETENDING)){ + if(explain) + Bprint(&bout, "unpretending %s because of %s because of %s\n", + a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites"); + + unpretend(a->n); + did = work(a->n, node, a) || did; + ready = 0; + } + if(ready == 0) /* try later unless nothing has happened for -k's sake */ + return(did || work(node, p, parc)); + did = dorecipe(node) || did; + return(did); +} + +void +update(int fake, Node *node) +{ + Arc *a; + + MADESET(node, fake? BEINGMADE : MADE); + if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){ + node->time = timeof(node->name, 1); + node->flags &= ~(CANPRETEND|PRETENDING); + for(a = node->prereqs; a; a = a->next) + if(a->prog) + outofdate(node, a, 1); + } else { + node->time = 1; + for(a = node->prereqs; a; a = a->next) + if(a->n && outofdate(node, a, 1)) + node->time = a->n->time; + } +/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, node->flags);/**/ +} + +static +pcmp(char *prog, char *p, char *q) +{ + char buf[3*NAMEBLOCK]; + int pid; + + Bflush(&bout); + sprint(buf, "%s '%s' '%s'\n", prog, p, q); + pid = pipecmd(buf, 0, 0); + while(waitup(-3, &pid) >= 0) + ; + return(pid? 2:1); +} + +int +outofdate(Node *node, Arc *arc, int eval) +{ + char buf[3*NAMEBLOCK], *str; + Symtab *sym; + int ret; + + str = 0; + if(arc->prog){ + sprint(buf, "%s%c%s", node->name, 0377, arc->n->name); + sym = symlook(buf, S_OUTOFDATE, 0); + if(sym == 0 || eval){ + if(sym == 0) + str = strdup(buf); + ret = pcmp(arc->prog, node->name, arc->n->name); + if(sym) + sym->value = (void *)ret; + else + symlook(str, S_OUTOFDATE, (void *)ret); + } else + ret = (int)sym->value; + return(ret-1); + } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing archive member */ + return 1; + else + return node->time <= arc->n->time; +} diff --git a/utils/mk/mk.h b/utils/mk/mk.h new file mode 100644 index 00000000..40618648 --- /dev/null +++ b/utils/mk/mk.h @@ -0,0 +1,171 @@ +#include <lib9.h> +#include <bio.h> +#include <regexp.h> + +#undef assert +#define assert mkassert +extern Biobuf bout; + +typedef struct Bufblock +{ + struct Bufblock *next; + char *start; + char *end; + char *current; +} Bufblock; + +typedef struct Word +{ + char *s; + struct Word *next; +} Word; + +typedef struct Envy +{ + char *name; + Word *values; +} Envy; + +extern Envy *envy; + +typedef struct Rule +{ + char *target; /* one target */ + Word *tail; /* constituents of targets */ + char *recipe; /* do it ! */ + short attr; /* attributes */ + short line; /* source line */ + char *file; /* source file */ + Word *alltargets; /* all the targets */ + int rule; /* rule number */ + Reprog *pat; /* reg exp goo */ + char *prog; /* to use in out of date */ + struct Rule *chain; /* hashed per target */ + struct Rule *next; +} Rule; + +extern Rule *rules, *metarules, *patrule; + +/* Rule.attr */ +#define META 0x0001 +#define UNUSED 0x0002 +#define UPD 0x0004 +#define QUIET 0x0008 +#define VIR 0x0010 +#define REGEXP 0x0020 +#define NOREC 0x0040 +#define DEL 0x0080 +#define NOVIRT 0x0100 + +#define NREGEXP 10 + +typedef struct Arc +{ + short flag; + struct Node *n; + Rule *r; + char *stem; + char *prog; + char *match[NREGEXP]; + struct Arc *next; +} Arc; + + /* Arc.flag */ +#define TOGO 1 + +typedef struct Node +{ + char *name; + long time; + unsigned short flags; + Arc *prereqs; + struct Node *next; /* list for a rule */ +} Node; + + /* Node.flags */ +#define VIRTUAL 0x0001 +#define CYCLE 0x0002 +#define READY 0x0004 +#define CANPRETEND 0x0008 +#define PRETENDING 0x0010 +#define NOTMADE 0x0020 +#define BEINGMADE 0x0040 +#define MADE 0x0080 +#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEINGMADE|MADE))|(m) +#define PROBABLE 0x0100 +#define VACUOUS 0x0200 +#define NORECIPE 0x0400 +#define DELETE 0x0800 +#define NOMINUSE 0x1000 + +typedef struct Job +{ + Rule *r; /* master rule for job */ + Node *n; /* list of node targets */ + char *stem; + char **match; + Word *p; /* prerequistes */ + Word *np; /* new prerequistes */ + Word *t; /* targets */ + Word *at; /* all targets */ + int nproc; /* slot number */ + struct Job *next; +} Job; +extern Job *jobs; + +typedef struct Symtab +{ + short space; + char *name; + void *value; + struct Symtab *next; +} Symtab; + +enum { + S_VAR, /* variable -> value */ + S_TARGET, /* target -> rule */ + S_TIME, /* file -> time */ + S_PID, /* pid -> products */ + S_NODE, /* target name -> node */ + S_AGG, /* aggregate -> time */ + S_BITCH, /* bitched about aggregate not there */ + S_NOEXPORT, /* var -> noexport */ + S_OVERRIDE, /* can't override */ + S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */ + S_MAKEFILE, /* target -> node */ + S_MAKEVAR, /* dumpable mk variable */ + S_EXPORTED, /* var -> current exported value */ + S_WESET, /* variable; we set in the mkfile */ + S_INTERNAL /* an internal mk variable (e.g., stem, target) */ +}; + +extern int debug; +extern int nflag, tflag, iflag, kflag, aflag, mflag; +extern int mkinline; +extern char *infile; +extern int nreps; +extern char *explain; +extern char *termchars; +extern int IWS; +extern char *shell; +extern char *shellname; +extern char *shflags; + +#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline)) +#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line)) +#define NAMEBLOCK 1000 +#define BIGBLOCK 20000 + +#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n')) +#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", (r))) + +#define DEBUG(x) (debug&(x)) +#define D_PARSE 0x01 +#define D_GRAPH 0x02 +#define D_EXEC 0x04 + +#define LSEEK(f,o,p) seek(f,o,p) + +#define PERCENT(ch) (((ch) == '%') || ((ch) == '&')) + +#include "fns.h" diff --git a/utils/mk/mkfile b/utils/mk/mkfile new file mode 100644 index 00000000..74ddb579 --- /dev/null +++ b/utils/mk/mkfile @@ -0,0 +1,40 @@ +<../../mkconfig + +TARG=mk + +OFILES= arc.$O\ + archive.$O\ + bufblock.$O\ + env.$O\ + file.$O\ + graph.$O\ + job.$O\ + lex.$O\ + main.$O\ + match.$O\ + mk.$O\ + parse.$O\ + $TARGMODEL.$O\ + recipe.$O\ + rule.$O\ + run.$O\ + $TARGSHTYPE.$O\ + shprint.$O\ + symtab.$O\ + var.$O\ + varsub.$O\ + word.$O\ + +HFILES= fns.h\ + ../include/ar.h\ + mk.h\ + +LIBS= regexp bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS=$CFLAGS -I../include + +<mkfile-$HOSTMODEL diff --git a/utils/mk/mkfile-Nt b/utils/mk/mkfile-Nt new file mode 100644 index 00000000..95556e34 --- /dev/null +++ b/utils/mk/mkfile-Nt @@ -0,0 +1,12 @@ +# +# install rule for NT & windows 95 +# +# since we can't reliably copy the new executable +# onto the already executing copy, we make the user +# do it manually + +$BIN/%:Q: $O.out + echo 'mk must be installed manually on Windows systems' + echo use: cp $O.out $target + cp $O.out $target + diff --git a/utils/mk/mkfile-Plan9 b/utils/mk/mkfile-Plan9 new file mode 100644 index 00000000..9d85eca5 --- /dev/null +++ b/utils/mk/mkfile-Plan9 @@ -0,0 +1,3 @@ +# +# install rule for Inferno/Plan9 - use the default +# diff --git a/utils/mk/mkfile-Posix b/utils/mk/mkfile-Posix new file mode 100644 index 00000000..5948b453 --- /dev/null +++ b/utils/mk/mkfile-Posix @@ -0,0 +1,7 @@ +# +# install rule for Posix systems +# + +$BIN/%: $O.out + test -x $target && mv $target $BIN/mk.save #because we are executing it + cp $O.out $target diff --git a/utils/mk/parse.c b/utils/mk/parse.c new file mode 100644 index 00000000..52642ce6 --- /dev/null +++ b/utils/mk/parse.c @@ -0,0 +1,309 @@ +#include "mk.h" + +char *infile; +int mkinline; +static int rhead(char *, Word **, Word **, int *, char **); +static char *rbody(Biobuf*); +extern Word *target1; + +void +parse(char *f, int fd, int varoverride) +{ + int hline; + char *body; + Word *head, *tail; + int attr, set, pid; + char *prog, *p; + int newfd; + Biobuf in; + Bufblock *buf; + + if(fd < 0){ + perror(f); + Exit(); + } + ipush(); + infile = strdup(f); + mkinline = 1; + Binit(&in, fd, OREAD); + buf = newbuf(); + while(assline(&in, buf)){ + hline = mkinline; + switch(rhead(buf->start, &head, &tail, &attr, &prog)) + { + case '<': + p = wtos(tail, ' '); + if(*p == 0){ + SYNERR(-1); + fprint(2, "missing include file name\n"); + Exit(); + } + newfd = open(p, OREAD); + if(newfd < 0){ + fprint(2, "warning: skipping missing include file: "); + perror(p); + } else + parse(p, newfd, 0); + break; + case '|': + p = wtos(tail, ' '); + if(*p == 0){ + SYNERR(-1); + fprint(2, "missing include program name\n"); + Exit(); + } + execinit(); + pid=pipecmd(p, envy, &newfd); + if(newfd < 0){ + fprint(2, "warning: skipping missing program file: "); + perror(p); + } else + parse(p, newfd, 0); + while(waitup(-3, &pid) >= 0) + ; + if(pid != 0){ + fprint(2, "bad include program status\n"); + Exit(); + } + break; + case ':': + body = rbody(&in); + addrules(head, tail, body, attr, hline, prog); + break; + case '=': + if(head->next){ + SYNERR(-1); + fprint(2, "multiple vars on left side of assignment\n"); + Exit(); + } + if(symlook(head->s, S_OVERRIDE, 0)){ + set = varoverride; + } else { + set = 1; + if(varoverride) + symlook(head->s, S_OVERRIDE, (void *)""); + } + if(set){ +/* +char *cp; +dumpw("tail", tail); +cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp); +*/ + setvar(head->s, (void *) tail); + symlook(head->s, S_WESET, (void *)""); + } + if(attr) + symlook(head->s, S_NOEXPORT, (void *)""); + break; + default: + SYNERR(hline); + fprint(2, "expected one of :<=\n"); + Exit(); + break; + } + } + close(fd); + freebuf(buf); + ipop(); +} + +void +addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog) +{ + Word *w; + + assert("addrules args", head && body); + /* tuck away first non-meta rule as default target*/ + if(target1 == 0 && !(attr®EXP)){ + for(w = head; w; w = w->next) + if(charin(w->s, "%&")) + break; + if(w == 0) + target1 = wdup(head); + } + for(w = head; w; w = w->next) + addrule(w->s, tail, body, head, attr, hline, prog); +} + +static int +rhead(char *line, Word **h, Word **t, int *attr, char **prog) +{ + char *p; + char *pp; + int sep; + Rune r; + int n; + Word *w; + + p = charin(line,":=<"); + if(p == 0) + return('?'); + sep = *p; + *p++ = 0; + if(sep == '<' && *p == '|'){ + sep = '|'; + p++; + } + *attr = 0; + *prog = 0; + if(sep == '='){ + pp = charin(p, termchars); /* termchars is shell-dependent */ + if (pp && *pp == '=') { + while (p != pp) { + n = chartorune(&r, p); + switch(r) + { + default: + SYNERR(-1); + fprint(2, "unknown attribute '%c'\n",*p); + Exit(); + case 'U': + *attr = 1; + break; + } + p += n; + } + p++; /* skip trailing '=' */ + } + } + if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){ + while (*p) { + n = chartorune(&r, p); + if (r == ':') + break; + p += n; + switch(r) + { + default: + SYNERR(-1); + fprint(2, "unknown attribute '%c'\n", p[-1]); + Exit(); + case 'D': + *attr |= DEL; + break; + case 'E': + *attr |= NOMINUSE; + break; + case 'n': + *attr |= NOVIRT; + break; + case 'N': + *attr |= NOREC; + break; + case 'P': + pp = utfrune(p, ':'); + if (pp == 0 || *pp == 0) + goto eos; + *pp = 0; + *prog = strdup(p); + *pp = ':'; + p = pp; + break; + case 'Q': + *attr |= QUIET; + break; + case 'R': + *attr |= REGEXP; + break; + case 'U': + *attr |= UPD; + break; + case 'V': + *attr |= VIR; + break; + } + } + if (*p++ != ':') { + eos: + SYNERR(-1); + fprint(2, "missing trailing :\n"); + Exit(); + } + } + *h = w = stow(line); + if(*w->s == 0 && sep != '<' && sep != '|') { + SYNERR(mkinline-1); + fprint(2, "no var on left side of assignment/rule\n"); + Exit(); + } + *t = stow(p); + return(sep); +} + +static char * +rbody(Biobuf *in) +{ + Bufblock *buf; + int r, lastr; + char *p; + + lastr = '\n'; + buf = newbuf(); + for(;;){ + r = Bgetrune(in); + if (r < 0) + break; + if (lastr == '\n') { + if (r == '#') + rinsert(buf, r); + else if (r != ' ' && r != '\t') { + Bungetrune(in); + break; + } + } else + rinsert(buf, r); + lastr = r; + if (r == '\n') + mkinline++; + } + insert(buf, 0); + p = strdup(buf->start); + freebuf(buf); + return p; +} + +struct input +{ + char *file; + int line; + struct input *next; +}; +static struct input *inputs = 0; + +void +ipush(void) +{ + struct input *in, *me; + + me = (struct input *)Malloc(sizeof(*me)); + me->file = infile; + me->line = mkinline; + me->next = 0; + if(inputs == 0) + inputs = me; + else { + for(in = inputs; in->next; ) + in = in->next; + in->next = me; + } +} + +void +ipop(void) +{ + struct input *in, *me; + + assert("pop input list", inputs != 0); + if(inputs->next == 0){ + me = inputs; + inputs = 0; + } else { + for(in = inputs; in->next->next; ) + in = in->next; + me = in->next; + in->next = 0; + } + infile = me->file; + mkinline = me->line; + free((char *)me); +} diff --git a/utils/mk/rc.c b/utils/mk/rc.c new file mode 100644 index 00000000..657ddf27 --- /dev/null +++ b/utils/mk/rc.c @@ -0,0 +1,175 @@ +#include "mk.h" + +char *termchars = "'= \t"; /*used in parse.c to isolate assignment attribute*/ +char *shflags = "-I"; /* rc flag to force non-interactive mode */ +int IWS = '\1'; /* inter-word separator in env - not used in plan 9 */ + +/* + * This file contains functions that depend on rc's syntax. Most + * of the routines extract strings observing rc's escape conventions + */ + + +/* + * skip a token in single quotes. + */ +static char * +squote(char *cp) +{ + Rune r; + int n; + + while(*cp){ + n = chartorune(&r, cp); + if(r == '\'') { + n += chartorune(&r, cp+n); + if(r != '\'') + return(cp); + } + cp += n; + } + SYNERR(-1); /* should never occur */ + fprint(2, "missing closing '\n"); + return 0; +} + +/* + * search a string for characters in a pattern set + * characters in quotes and variable generators are escaped + */ +char * +charin(char *cp, char *pat) +{ + Rune r; + int n, vargen; + + vargen = 0; + while(*cp){ + n = chartorune(&r, cp); + switch(r){ + case '\'': /* skip quoted string */ + cp = squote(cp+1); /* n must = 1 */ + if(!cp) + return 0; + break; + case '$': + if(*(cp+1) == '{') + vargen = 1; + break; + case '}': + if(vargen) + vargen = 0; + else if(utfrune(pat, r)) + return cp; + break; + default: + if(vargen == 0 && utfrune(pat, r)) + return cp; + break; + } + cp += n; + } + if(vargen){ + SYNERR(-1); + fprint(2, "missing closing } in pattern generator\n"); + } + return 0; +} + +/* + * extract an escaped token. Possible escape chars are single-quote, + * double-quote,and backslash. Only the first is valid for rc. the + * others are just inserted into the receiving buffer. + */ +char* +expandquote(char *s, Rune r, Bufblock *b) +{ + if (r != '\'') { + rinsert(b, r); + return s; + } + + while(*s){ + s += chartorune(&r, s); + if(r == '\'') { + if(*s == '\'') + s++; + else + return s; + } + rinsert(b, r); + } + return 0; +} + +/* + * Input an escaped token. Possible escape chars are single-quote, + * double-quote and backslash. Only the first is a valid escape for + * rc; the others are just inserted into the receiving buffer. + */ +int +escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) +{ + int c, line; + + if(esc != '\'') + return 1; + + line = mkinline; + while((c = nextrune(bp, 0)) > 0){ + if(c == '\''){ + if(preserve) + rinsert(buf, c); + c = Bgetrune(bp); + if (c < 0) + break; + if(c != '\''){ + Bungetrune(bp); + return 1; + } + } + rinsert(buf, c); + } + SYNERR(line); fprint(2, "missing closing %c\n", esc); + return 0; +} + +/* + * copy a single-quoted string; s points to char after opening quote + */ +static char * +copysingle(char *s, Bufblock *buf) +{ + Rune r; + + while(*s){ + s += chartorune(&r, s); + rinsert(buf, r); + if(r == '\'') + break; + } + return s; +} +/* + * check for quoted strings. backquotes are handled here; single quotes above. + * s points to char after opening quote, q. + */ +char * +copyq(char *s, Rune q, Bufblock *buf) +{ + if(q == '\'') /* copy quoted string */ + return copysingle(s, buf); + + if(q != '`') /* not quoted */ + return s; + + while(*s){ /* copy backquoted string */ + s += chartorune(&q, s); + rinsert(buf, q); + if(q == '}') + break; + if(q == '\'') + s = copysingle(s, buf); /* copy quoted string */ + } + return s; +} diff --git a/utils/mk/recipe.c b/utils/mk/recipe.c new file mode 100644 index 00000000..973bac17 --- /dev/null +++ b/utils/mk/recipe.c @@ -0,0 +1,117 @@ +#include "mk.h" + +int +dorecipe(Node *node) +{ + char buf[BIGBLOCK]; + register Node *n; + Rule *r = 0; + Arc *a, *aa; + Word head, ahead, lp, ln, *w, *ww, *aw; + Symtab *s; + int did = 0; + + aa = 0; + /* + pick up the rule + */ + for(a = node->prereqs; a; a = a->next) + if(*a->r->recipe) + r = (aa = a)->r; + /* + no recipe? go to buggery! + */ + if(r == 0){ + if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){ + fprint(2, "mk: no recipe to make '%s'\n", node->name); + Exit(); + } + if(strchr(node->name, '(') && node->time == 0) + MADESET(node, MADE); + else + update(0, node); + if(tflag){ + if(!(node->flags&VIRTUAL)) + touch(node->name); + else if(explain) + Bprint(&bout, "no touch of virtual '%s'\n", node->name); + } + return(did); + } + /* + build the node list + */ + node->next = 0; + head.next = 0; + ww = &head; + ahead.next = 0; + aw = &ahead; + if(r->attr®EXP){ + ww->next = newword(node->name); + aw->next = newword(node->name); + } else { + for(w = r->alltargets; w; w = w->next){ + if(r->attr&META) + subst(aa->stem, w->s, buf); + else + strcpy(buf, w->s); + aw->next = newword(buf); + aw = aw->next; + if((s = symlook(buf, S_NODE, 0)) == 0) + continue; /* not a node we are interested in */ + n = (Node *)s->value; + if(aflag == 0 && n->time) { + for(a = n->prereqs; a; a = a->next) + if(a->n && outofdate(n, a, 0)) + break; + if(a == 0) + continue; + } + ww->next = newword(buf); + ww = ww->next; + if(n == node) continue; + n->next = node->next; + node->next = n; + } + } + for(n = node; n; n = n->next) + if((n->flags&READY) == 0) + return(did); + /* + gather the params for the job + */ + lp.next = ln.next = 0; + for(n = node; n; n = n->next){ + for(a = n->prereqs; a; a = a->next){ + if(a->n){ + addw(&lp, a->n->name); + if(outofdate(n, a, 0)){ + addw(&ln, a->n->name); + if(explain) + fprint(1, "%s(%ld) < %s(%ld)\n", + n->name, n->time, a->n->name, a->n->time); + } + } else { + if(explain) + fprint(1, "%s has no prerequisites\n", + n->name); + } + } + MADESET(n, BEINGMADE); + } + /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),wtos(lp.next, ' '));/**/ + run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, ahead.next)); + return(1); +} + +void +addw(Word *w, char *s) +{ + Word *lw; + + for(lw = w; w = w->next; lw = w){ + if(strcmp(s, w->s) == 0) + return; + } + lw->next = newword(s); +} diff --git a/utils/mk/rule.c b/utils/mk/rule.c new file mode 100644 index 00000000..662f067f --- /dev/null +++ b/utils/mk/rule.c @@ -0,0 +1,107 @@ +#include "mk.h" + +static Rule *lr, *lmr; +static int rcmp(Rule *r, char *target, Word *tail); +static int nrules = 0; + +void +addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, char *prog) +{ + Rule *r; + Rule *rr; + Symtab *sym; + int reuse; + + r = 0; + reuse = 0; + if(sym = symlook(head, S_TARGET, 0)){ + for(r = (Rule *)sym->value; r; r = r->chain) + if(rcmp(r, head, tail) == 0){ + reuse = 1; + break; + } + } + if(r == 0) + r = (Rule *)Malloc(sizeof(Rule)); + r->target = head; + r->tail = tail; + r->recipe = body; + r->line = hline; + r->file = infile; + r->attr = attr; + r->alltargets = ahead; + r->prog = prog; + r->rule = nrules++; + if(!reuse){ + rr = (Rule *)symlook(head, S_TARGET, (void *)r)->value; + if(rr != r){ + r->chain = rr->chain; + rr->chain = r; + } else + r->chain = 0; + } + if(!reuse) + r->next = 0; + if((attr®EXP) || charin(head, "%&")){ + r->attr |= META; + if(reuse) + return; + if(attr®EXP){ + patrule = r; + r->pat = regcomp(head); + } + if(metarules == 0) + metarules = lmr = r; + else { + lmr->next = r; + lmr = r; + } + } else { + if(reuse) + return; + r->pat = 0; + if(rules == 0) + rules = lr = r; + else { + lr->next = r; + lr = r; + } + } +} + +void +dumpr(char *s, Rule *r) +{ + Bprint(&bout, "%s: start=%ld\n", s, r); + for(; r; r = r->next){ + Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld alltarget='%s'", + r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' ')); + if(r->prog) + Bprint(&bout, " prog='%s'", r->prog); + Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, ' ')); + Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe); + } +} + +static int +rcmp(Rule *r, char *target, Word *tail) +{ + Word *w; + + if(strcmp(r->target, target)) + return 1; + for(w = r->tail; w && tail; w = w->next, tail = tail->next) + if(strcmp(w->s, tail->s)) + return 1; + return(w || tail); +} + +char * +rulecnt(void) +{ + char *s; + + s = Malloc(nrules); + memset(s, 0, nrules); + return(s); +} diff --git a/utils/mk/run.c b/utils/mk/run.c new file mode 100644 index 00000000..4ef4221a --- /dev/null +++ b/utils/mk/run.c @@ -0,0 +1,297 @@ +#include "mk.h" + +typedef struct Event +{ + int pid; + Job *job; +} Event; +static Event *events; +static int nevents, nrunning, nproclimit; + +typedef struct Process +{ + int pid; + int status; + struct Process *b, *f; +} Process; +static Process *phead, *pfree; +static void sched(void); +static void pnew(int, int), pdelete(Process *); + +int pidslot(int); + +void +run(Job *j) +{ + Job *jj; + + if(jobs){ + for(jj = jobs; jj->next; jj = jj->next) + ; + jj->next = j; + } else + jobs = j; + j->next = 0; + /* this code also in waitup after parse redirect */ + if(nrunning < nproclimit) + sched(); +} + +static void +sched(void) +{ + char *flags; + Job *j; + Bufblock *buf; + int slot; + Node *n; + Envy *e; + + if(jobs == 0){ + usage(); + return; + } + j = jobs; + jobs = j->next; + if(DEBUG(D_EXEC)) + fprint(1, "firing up job for target %s\n", wtos(j->t, ' ')); + slot = nextslot(); + events[slot].job = j; + buf = newbuf(); + e = buildenv(j, slot); + shprint(j->r->recipe, e, buf); + if(!tflag && (nflag || !(j->r->attr&QUIET))) + Bwrite(&bout, buf->start, (long)strlen(buf->start)); + freebuf(buf); + if(nflag||tflag){ + for(n = j->n; n; n = n->next){ + if(tflag){ + if(!(n->flags&VIRTUAL)) + touch(n->name); + else if(explain) + Bprint(&bout, "no touch of virtual '%s'\n", n->name); + } + n->time = time((long *)0); + MADESET(n, MADE); + } + } else { + if(DEBUG(D_EXEC)) + fprint(1, "recipe='%s'", j->r->recipe);/**/ + Bflush(&bout); + if(j->r->attr&NOMINUSE) + flags = 0; + else + flags = "-e"; + events[slot].pid = execsh(flags, j->r->recipe, 0, e); + usage(); + nrunning++; + if(DEBUG(D_EXEC)) + fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid); + } +} + +int +waitup(int echildok, int *retstatus) +{ + Envy *e; + int pid; + int slot; + Symtab *s; + Word *w; + Job *j; + char buf[ERRMAX]; + Bufblock *bp; + int uarg = 0; + int done; + Node *n; + Process *p; + extern int runerrs; + + /* first check against the proces slist */ + if(retstatus) + for(p = phead; p; p = p->f) + if(p->pid == *retstatus){ + *retstatus = p->status; + pdelete(p); + return(-1); + } +again: /* rogue processes */ + pid = waitfor(buf); + if(pid == -1){ + if(echildok > 0) + return(1); + else { + fprint(2, "mk: (waitup %d) ", echildok); + perror("mk wait"); + Exit(); + } + } + if(DEBUG(D_EXEC)) + fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf); + if(retstatus && pid == *retstatus){ + *retstatus = buf[0]? 1:0; + return(-1); + } + slot = pidslot(pid); + if(slot < 0){ + if(DEBUG(D_EXEC)) + fprint(2, "mk: wait returned unexpected process %d\n", pid); + pnew(pid, buf[0]? 1:0); + goto again; + } + j = events[slot].job; + usage(); + nrunning--; + events[slot].pid = -1; + if(buf[0]){ + e = buildenv(j, slot); + bp = newbuf(); + shprint(j->r->recipe, e, bp); + front(bp->start); + fprint(2, "mk: %s: exit status=%s", bp->start, buf); + freebuf(bp); + for(n = j->n, done = 0; n; n = n->next) + if(n->flags&DELETE){ + if(done++ == 0) + fprint(2, ", deleting"); + fprint(2, " '%s'", n->name); + delete(n->name); + } + fprint(2, "\n"); + if(kflag){ + runerrs++; + uarg = 1; + } else { + jobs = 0; + Exit(); + } + } + for(w = j->t; w; w = w->next){ + if((s = symlook(w->s, S_NODE, 0)) == 0) + continue; /* not interested in this node */ + update(uarg, (Node *)s->value); + } + if(nrunning < nproclimit) + sched(); + return(0); +} + +void +nproc(void) +{ + Symtab *sym; + Word *w; + + if(sym = symlook("NPROC", S_VAR, 0)) { + w = (Word *) sym->value; + if (w && w->s && w->s[0]) + nproclimit = atoi(w->s); + } + if(nproclimit < 1) + nproclimit = 1; + if(DEBUG(D_EXEC)) + fprint(1, "nprocs = %d\n", nproclimit); + if(nproclimit > nevents){ + if(nevents) + events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event)); + else + events = (Event *)Malloc(nproclimit*sizeof(Event)); + while(nevents < nproclimit) + events[nevents++].pid = 0; + } +} + +int +nextslot(void) +{ + int i; + + for(i = 0; i < nproclimit; i++) + if(events[i].pid <= 0) return i; + assert("out of slots!!", 0); + return 0; /* cyntax */ +} + +int +pidslot(int pid) +{ + int i; + + for(i = 0; i < nevents; i++) + if(events[i].pid == pid) return(i); + if(DEBUG(D_EXEC)) + fprint(2, "mk: wait returned unexpected process %d\n", pid); + return(-1); +} + + +static void +pnew(int pid, int status) +{ + Process *p; + + if(pfree){ + p = pfree; + pfree = p->f; + } else + p = (Process *)Malloc(sizeof(Process)); + p->pid = pid; + p->status = status; + p->f = phead; + phead = p; + if(p->f) + p->f->b = p; + p->b = 0; +} + +static void +pdelete(Process *p) +{ + if(p->f) + p->f->b = p->b; + if(p->b) + p->b->f = p->f; + else + phead = p->f; + p->f = pfree; + pfree = p; +} + +void +killchildren(char *msg) +{ + Process *p; + + kflag = 1; /* to make sure waitup doesn't exit */ + jobs = 0; /* make sure no more get scheduled */ + for(p = phead; p; p = p->f) + expunge(p->pid, msg); + while(waitup(1, (int *)0) == 0) + ; + Bprint(&bout, "mk: %s\n", msg); + Exit(); +} + +static long tslot[1000]; +static long tick; + +void +usage(void) +{ + long t; + + time(&t); + if(tick) + tslot[nrunning] += (t-tick); + tick = t; +} + +void +prusage(void) +{ + int i; + + usage(); + for(i = 0; i <= nevents; i++) + fprint(1, "%d: %ld\n", i, tslot[i]); +} diff --git a/utils/mk/sh.c b/utils/mk/sh.c new file mode 100644 index 00000000..524167a5 --- /dev/null +++ b/utils/mk/sh.c @@ -0,0 +1,189 @@ +#include "mk.h" + +char *termchars = "\"'= \t"; /*used in parse.c to isolate assignment attribute*/ +char *shflags = 0; +int IWS = ' '; /* inter-word separator in env */ + +/* + * This file contains functions that depend on the shell's syntax. Most + * of the routines extract strings observing the shell's escape conventions. + */ + + +/* + * skip a token in quotes. + */ +static char * +squote(char *cp, int c) +{ + Rune r; + int n; + + while(*cp){ + n = chartorune(&r, cp); + if(r == c) + return cp; + if(r == '\\') + n += chartorune(&r, cp+n); + cp += n; + } + SYNERR(-1); /* should never occur */ + fprint(2, "missing closing '\n"); + return 0; +} +/* + * search a string for unescaped characters in a pattern set + */ +char * +charin(char *cp, char *pat) +{ + Rune r; + int n, vargen; + + vargen = 0; + while(*cp){ + n = chartorune(&r, cp); + switch(r){ + case '\\': /* skip escaped char */ + cp += n; + n = chartorune(&r, cp); + break; + case '\'': /* skip quoted string */ + case '"': + cp = squote(cp+1, r); /* n must = 1 */ + if(!cp) + return 0; + break; + case '$': + if(*(cp+1) == '{') + vargen = 1; + break; + case '}': + if(vargen) + vargen = 0; + else if(utfrune(pat, r)) + return cp; + break; + default: + if(vargen == 0 && utfrune(pat, r)) + return cp; + break; + } + cp += n; + } + if(vargen){ + SYNERR(-1); + fprint(2, "missing closing } in pattern generator\n"); + } + return 0; +} + +/* + * extract an escaped token. Possible escape chars are single-quote, + * double-quote,and backslash. + */ +char* +expandquote(char *s, Rune esc, Bufblock *b) +{ + Rune r; + + if (esc == '\\') { + s += chartorune(&r, s); + rinsert(b, r); + return s; + } + + while(*s){ + s += chartorune(&r, s); + if(r == esc) + return s; + if (r == '\\') { + rinsert(b, r); + s += chartorune(&r, s); + } + rinsert(b, r); + } + return 0; +} + +/* + * Input an escaped token. Possible escape chars are single-quote, + * double-quote and backslash. + */ +int +escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) +{ + int c, line; + + if(esc == '\\') { + c = Bgetrune(bp); + if(c == '\r') + c = Bgetrune(bp); + if (c == '\n') + mkinline++; + rinsert(buf, c); + return 1; + } + + line = mkinline; + while((c = nextrune(bp, 0)) >= 0){ + if(c == esc){ + if(preserve) + rinsert(buf, c); + return 1; + } + if(c == '\\') { + rinsert(buf, c); + c = Bgetrune(bp); + if(c == '\r') + c = Bgetrune(bp); + if (c < 0) + break; + if (c == '\n') + mkinline++; + } + rinsert(buf, c); + } + SYNERR(line); fprint(2, "missing closing %c\n", esc); + return 0; +} + +/* + * copy a quoted string; s points to char after opening quote + */ +static char * +copysingle(char *s, Rune q, Bufblock *buf) +{ + Rune r; + + while(*s){ + s += chartorune(&r, s); + rinsert(buf, r); + if(r == q) + break; + } + return s; +} +/* + * check for quoted strings. backquotes are handled here; single quotes above. + * s points to char after opening quote, q. + */ +char * +copyq(char *s, Rune q, Bufblock *buf) +{ + if(q == '\'' || q == '"') /* copy quoted string */ + return copysingle(s, q, buf); + + if(q != '`') /* not quoted */ + return s; + + while(*s){ /* copy backquoted string */ + s += chartorune(&q, s); + rinsert(buf, q); + if(q == '`') + break; + if(q == '\'' || q == '"') + s = copysingle(s, q, buf); /* copy quoted string */ + } + return s; +} diff --git a/utils/mk/shprint.c b/utils/mk/shprint.c new file mode 100644 index 00000000..a3de277d --- /dev/null +++ b/utils/mk/shprint.c @@ -0,0 +1,90 @@ +#include "mk.h" + +static char *vexpand(char*, Envy*, Bufblock*); +static char *shquote(char*, Rune, Bufblock*); +static char *shbquote(char*, Bufblock*); + +void +shprint(char *s, Envy *env, Bufblock *buf) +{ + int n; + Rune r; + + while(*s) { + n = chartorune(&r, s); + if (r == '$') + s = vexpand(s, env, buf); + else { + rinsert(buf, r); + s += n; + s = copyq(s, r, buf); /*handle quoted strings*/ + } + } + insert(buf, 0); +} + +static char * +mygetenv(char *name, Envy *env) +{ + if (!env) + return 0; + if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == 0) + return 0; + /* only resolve internal variables and variables we've set */ + for(; env->name; env++){ + if (strcmp(env->name, name) == 0) + return wtos(env->values, ' '); + } + return 0; +} + +static char * +vexpand(char *w, Envy *env, Bufblock *buf) +{ + char *s, carry, *p, *q; + + assert("vexpand no $", *w == '$'); + p = w+1; /* skip dollar sign */ + if(*p == '{') { + p++; + q = utfrune(p, '}'); + if (!q) + q = strchr(p, 0); + } else + q = shname(p); + carry = *q; + *q = 0; + s = mygetenv(p, env); + *q = carry; + if (carry == '}') + q++; + if (s) { + bufcpy(buf, s, strlen(s)); + free(s); + } else /* copy name intact*/ + bufcpy(buf, w, q-w); + return(q); +} + +void +front(char *s) +{ + char *t, *q; + int i, j; + char *flds[512]; + + q = strdup(s); + i = getfields(q, flds, 512, 0, " \t\n"); + if(i > 5){ + flds[4] = flds[i-1]; + flds[3] = "..."; + i = 5; + } + t = s; + for(j = 0; j < i; j++){ + for(s = flds[j]; *s; *t++ = *s++); + *t++ = ' '; + } + *t = 0; + free(q); +} diff --git a/utils/mk/symtab.c b/utils/mk/symtab.c new file mode 100644 index 00000000..06a4d146 --- /dev/null +++ b/utils/mk/symtab.c @@ -0,0 +1,97 @@ +#include "mk.h" + +#define NHASH 4099 +#define HASHMUL 79L /* this is a good value */ +static Symtab *hash[NHASH]; + +void +syminit(void) +{ + Symtab **s, *ss, *next; + + for(s = hash; s < &hash[NHASH]; s++){ + for(ss = *s; ss; ss = next){ + next = ss->next; + free((char *)ss); + } + *s = 0; + } +} + +Symtab * +symlook(char *sym, int space, void *install) +{ + long h; + char *p; + Symtab *s; + + for(p = sym, h = space; *p; h += *p++) + h *= HASHMUL; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s; s = s->next) + if((s->space == space) && (strcmp(s->name, sym) == 0)) + return(s); + if(install == 0) + return(0); + s = (Symtab *)Malloc(sizeof(Symtab)); + s->space = space; + s->name = sym; + s->value = install; + s->next = hash[h]; + hash[h] = s; + return(s); +} + +void +symdel(char *sym, int space) +{ + long h; + char *p; + Symtab *s, *ls; + + /* multiple memory leaks */ + + for(p = sym, h = space; *p; h += *p++) + h *= HASHMUL; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h], ls = 0; s; ls = s, s = s->next) + if((s->space == space) && (strcmp(s->name, sym) == 0)){ + if(ls) + ls->next = s->next; + else + hash[h] = s->next; + free((char *)s); + } +} + +void +symtraverse(int space, void (*fn)(Symtab*)) +{ + Symtab **s, *ss; + + for(s = hash; s < &hash[NHASH]; s++) + for(ss = *s; ss; ss = ss->next) + if(ss->space == space) + (*fn)(ss); +} + +void +symstat(void) +{ + Symtab **s, *ss; + int n; + int l[1000]; + + memset((char *)l, 0, sizeof(l)); + for(s = hash; s < &hash[NHASH]; s++){ + for(ss = *s, n = 0; ss; ss = ss->next) + n++; + l[n]++; + } + for(n = 0; n < 1000; n++) + if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n); +} diff --git a/utils/mk/var.c b/utils/mk/var.c new file mode 100644 index 00000000..8429918d --- /dev/null +++ b/utils/mk/var.c @@ -0,0 +1,41 @@ +#include "mk.h" + +void +setvar(char *name, void *value) +{ + symlook(name, S_VAR, value)->value = value; + symlook(name, S_MAKEVAR, (void*)""); +} + +static void +print1(Symtab *s) +{ + Word *w; + + Bprint(&bout, "\t%s=", s->name); + for (w = (Word *) s->value; w; w = w->next) + Bprint(&bout, "'%s'", w->s); + Bprint(&bout, "\n"); +} + +void +dumpv(char *s) +{ + Bprint(&bout, "%s:\n", s); + symtraverse(S_VAR, print1); +} + +char * +shname(char *a) +{ + Rune r; + int n; + + while (*a) { + n = chartorune(&r, a); + if (!WORDCHR(r)) + break; + a += n; + } + return a; +} diff --git a/utils/mk/varsub.c b/utils/mk/varsub.c new file mode 100644 index 00000000..2a9ad987 --- /dev/null +++ b/utils/mk/varsub.c @@ -0,0 +1,256 @@ +#include "mk.h" + +static Word *subsub(Word*, char*, char*); +static Word *expandvar(char**); +static Bufblock *varname(char**); +static Word *extractpat(char*, char**, char*, char*); +static int submatch(char*, Word*, Word*, int*, char**); +static Word *varmatch(char *, char**); + +Word * +varsub(char **s) +{ + Bufblock *b; + Word *w; + + if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/ + return expandvar(s); + + b = varname(s); + if(b == 0) + return 0; + + w = varmatch(b->start, s); + freebuf(b); + return w; +} + +/* + * extract a variable name + */ +static Bufblock* +varname(char **s) +{ + Bufblock *b; + char *cp; + Rune r; + int n; + + b = newbuf(); + cp = *s; + for(;;){ + n = chartorune(&r, cp); + if (!WORDCHR(r)) + break; + rinsert(b, r); + cp += n; + } + if (b->current == b->start){ + SYNERR(-1); + fprint(2, "missing variable name <%s>\n", *s); + freebuf(b); + return 0; + } + *s = cp; + insert(b, 0); + return b; +} + +static Word* +varmatch(char *name, char **s) +{ + Word *w; + Symtab *sym; + char *cp; + + sym = symlook(name, S_VAR, 0); + if(sym){ + /* check for at least one non-NULL value */ + for (w = (Word*)sym->value; w; w = w->next) + if(w->s && *w->s) + return wdup(w); + } + for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */ + ; + *s = cp; + return 0; +} + +static Word* +expandvar(char **s) +{ + Word *w; + Bufblock *buf; + Symtab *sym; + char *cp, *begin, *end; + + begin = *s; + (*s)++; /* skip the '{' */ + buf = varname(s); + if (buf == 0) + return 0; + cp = *s; + if (*cp == '}') { /* ${name} variant*/ + (*s)++; /* skip the '}' */ + w = varmatch(buf->start, s); + freebuf(buf); + return w; + } + if (*cp != ':') { + SYNERR(-1); + fprint(2, "bad variable name <%s>\n", buf->start); + freebuf(buf); + return 0; + } + cp++; + end = charin(cp , "}"); + if(end == 0){ + SYNERR(-1); + fprint(2, "missing '}': %s\n", begin); + Exit(); + } + *end = 0; + *s = end+1; + + sym = symlook(buf->start, S_VAR, 0); + if(sym == 0 || sym->value == 0) + w = newword(buf->start); + else + w = subsub((Word*) sym->value, cp, end); + freebuf(buf); + return w; +} + +static Word* +extractpat(char *s, char **r, char *term, char *end) +{ + int save; + char *cp; + Word *w; + + cp = charin(s, term); + if(cp){ + *r = cp; + if(cp == s) + return 0; + save = *cp; + *cp = 0; + w = stow(s); + *cp = save; + } else { + *r = end; + w = stow(s); + } + return w; +} + +static Word* +subsub(Word *v, char *s, char *end) +{ + int nmid; + Word *head, *tail, *w, *h; + Word *a, *b, *c, *d; + Bufblock *buf; + char *cp, *enda; + + a = extractpat(s, &cp, "=%&", end); + b = c = d = 0; + if(PERCENT(*cp)) + b = extractpat(cp+1, &cp, "=", end); + if(*cp == '=') + c = extractpat(cp+1, &cp, "&%", end); + if(PERCENT(*cp)) + d = stow(cp+1); + else if(*cp) + d = stow(cp); + + head = tail = 0; + buf = newbuf(); + for(; v; v = v->next){ + h = w = 0; + if(submatch(v->s, a, b, &nmid, &enda)){ + /* enda points to end of A match in source; + * nmid = number of chars between end of A and start of B + */ + if(c){ + h = w = wdup(c); + while(w->next) + w = w->next; + } + if(PERCENT(*cp) && nmid > 0){ + if(w){ + bufcpy(buf, w->s, strlen(w->s)); + bufcpy(buf, enda, nmid); + insert(buf, 0); + free(w->s); + w->s = strdup(buf->start); + } else { + bufcpy(buf, enda, nmid); + insert(buf, 0); + h = w = newword(buf->start); + } + buf->current = buf->start; + } + if(d && *d->s){ + if(w){ + + bufcpy(buf, w->s, strlen(w->s)); + bufcpy(buf, d->s, strlen(d->s)); + insert(buf, 0); + free(w->s); + w->s = strdup(buf->start); + w->next = wdup(d->next); + while(w->next) + w = w->next; + buf->current = buf->start; + } else + h = w = wdup(d); + } + } + if(w == 0) + h = w = newword(v->s); + + if(head == 0) + head = h; + else + tail->next = h; + tail = w; + } + freebuf(buf); + delword(a); + delword(b); + delword(c); + delword(d); + return head; +} + +static int +submatch(char *s, Word *a, Word *b, int *nmid, char **enda) +{ + Word *w; + int n; + char *end; + + n = 0; + for(w = a; w; w = w->next){ + n = strlen(w->s); + if(strncmp(s, w->s, n) == 0) + break; + } + if(a && w == 0) /* a == NULL matches everything*/ + return 0; + + *enda = s+n; /* pointer to end a A part match */ + *nmid = strlen(s)-n; /* size of remainder of source */ + end = *enda+*nmid; + for(w = b; w; w = w->next){ + n = strlen(w->s); + if(strcmp(w->s, end-n) == 0){ + *nmid -= n; + break; + } + } + if(b && w == 0) /* b == NULL matches everything */ + return 0; + return 1; +} diff --git a/utils/mk/word.c b/utils/mk/word.c new file mode 100644 index 00000000..ac34c47b --- /dev/null +++ b/utils/mk/word.c @@ -0,0 +1,180 @@ +#include "mk.h" + +static Word *nextword(char**); + +Word* +newword(char *s) +{ + Word *w; + + w = (Word *)Malloc(sizeof(Word)); + w->s = strdup(s); + w->next = 0; + return(w); +} + +Word * +stow(char *s) +{ + Word *head, *w, *new; + + w = head = 0; + while(*s){ + new = nextword(&s); + if(new == 0) + break; + if (w) + w->next = new; + else + head = w = new; + while(w->next) + w = w->next; + + } + if (!head) + head = newword(""); + return(head); +} + +char * +wtos(Word *w, int sep) +{ + Bufblock *buf; + char *cp; + + buf = newbuf(); + for(; w; w = w->next){ + for(cp = w->s; *cp; cp++) + insert(buf, *cp); + if(w->next) + insert(buf, sep); + } + insert(buf, 0); + cp = strdup(buf->start); + freebuf(buf); + return(cp); +} + +Word* +wdup(Word *w) +{ + Word *v, *new, *base; + + v = base = 0; + while(w){ + new = newword(w->s); + if(v) + v->next = new; + else + base = new; + v = new; + w = w->next; + } + return base; +} + +void +delword(Word *w) +{ + Word *v; + + while(v = w){ + w = w->next; + if(v->s) + free(v->s); + free(v); + } +} + +/* + * break out a word from a string handling quotes, executions, + * and variable expansions. + */ +static Word* +nextword(char **s) +{ + Bufblock *b; + Word *head, *tail, *w; + Rune r; + char *cp; + + cp = *s; + b = newbuf(); + head = tail = 0; + while(*cp == ' ' || *cp == '\t') /* leading white space */ + cp++; + while(*cp){ + cp += chartorune(&r, cp); + switch(r) + { + case ' ': + case '\t': + case '\n': + goto out; + case '\\': + case '\'': + case '"': + cp = expandquote(cp, r, b); + if(cp == 0){ + fprint(2, "missing closing quote: %s\n", *s); + Exit(); + } + break; + case '$': + w = varsub(&cp); + if(w == 0) + break; + if(b->current != b->start){ + bufcpy(b, w->s, strlen(w->s)); + insert(b, 0); + free(w->s); + w->s = strdup(b->start); + b->current = b->start; + } + if(head){ + bufcpy(b, tail->s, strlen(tail->s)); + bufcpy(b, w->s, strlen(w->s)); + insert(b, 0); + free(tail->s); + tail->s = strdup(b->start); + tail->next = w->next; + free(w->s); + free(w); + b->current = b->start; + } else + tail = head = w; + while(tail->next) + tail = tail->next; + break; + default: + rinsert(b, r); + break; + } + } +out: + *s = cp; + if(b->current != b->start){ + if(head){ + cp = b->current; + bufcpy(b, tail->s, strlen(tail->s)); + bufcpy(b, b->start, cp-b->start); + insert(b, 0); + free(tail->s); + tail->s = strdup(cp); + } else { + insert(b, 0); + head = newword(b->start); + } + } + freebuf(b); + return head; +} + +void +dumpw(char *s, Word *w) +{ + Bprint(&bout, "%s", s); + for(; w; w = w->next) + Bprint(&bout, " '%s'", w->s); + Bputc(&bout, '\n'); +} diff --git a/utils/mkdir/mkdir.c b/utils/mkdir/mkdir.c new file mode 100644 index 00000000..5bdf53c0 --- /dev/null +++ b/utils/mkdir/mkdir.c @@ -0,0 +1,18 @@ +#include <lib9.h> + +void +main(int argc, char **argv) +{ + for(argv++; *argv; argv++){ + if(access(*argv, 0) == 0){ + fprint(2, "mkdir: %s already exists\n", *argv); + exits("exists"); + } + if(mkdir(*argv) < 0){ + fprint(2, "mkdir: can't create %s\n", *argv); + perror(0); + exits("error"); + } + } + exits(0); +} diff --git a/utils/mkdir/mkfile b/utils/mkdir/mkfile new file mode 100644 index 00000000..af0eb499 --- /dev/null +++ b/utils/mkdir/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=mkdir + +OFILES= mkdir.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/mkext/mkext.c b/utils/mkext/mkext.c new file mode 100644 index 00000000..3361a23b --- /dev/null +++ b/utils/mkext/mkext.c @@ -0,0 +1,313 @@ +#include <lib9.h> +#include <bio.h> + +#define dirfwstat(b,d) 0 /* lib9 doesn't implement it */ +#define mkdir extmkdir + +enum{ + LEN = 8*1024, + NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */ +}; + +int selected(char*, int, char*[]); +void mkdirs(char*, char*); +void mkdir(char*, ulong, ulong, char*, char*); +void extract(char*, ulong, ulong, char*, char*, ulong); +void seekpast(ulong); +void error(char*, ...); +void warn(char*, ...); +void usage(void); +#pragma varargck argpos warn 1 +#pragma varargck argpos error 1 + +Biobuf bin; +uchar binbuf[2*LEN]; +char linebuf[LEN]; +int uflag; +int hflag; +int vflag; +int Tflag; + +void +main(int argc, char **argv) +{ + Biobuf bout; + char *fields[NFLDS], name[2*LEN], *p, *namep; + char *uid, *gid; + ulong mode, bytes, mtime; + + setbinmode(); + quotefmtinstall(); + namep = name; + ARGBEGIN{ + case 'd': + p = ARGF(); + if(strlen(p) >= LEN) + error("destination fs name too long\n"); + strcpy(name, p); + namep = name + strlen(name); + break; + case 'h': + hflag = 1; + Binit(&bout, 1, OWRITE); + break; + case 'u': + uflag = 1; + Tflag = 1; + break; + case 'T': + Tflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + usage(); + }ARGEND + + Binits(&bin, 0, OREAD, binbuf, sizeof binbuf); + while(p = Brdline(&bin, '\n')){ + p[Blinelen(&bin)-1] = '\0'; + strcpy(linebuf, p); + p = linebuf; + if(strcmp(p, "end of archive") == 0){ + Bterm(&bout); + fprint(2, "done\n"); + exits(0); + } + if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){ + warn("too few fields in file header"); + continue; + } + strcpy(namep, fields[0]); + mode = strtoul(fields[1], 0, 8); + uid = fields[2]; + gid = fields[3]; + mtime = strtoul(fields[4], 0, 10); + bytes = strtoul(fields[5], 0, 10); + if(argc){ + if(!selected(namep, argc, argv)){ + if(bytes) + seekpast(bytes); + continue; + } + mkdirs(name, namep); + } + if(hflag){ + Bprint(&bout, "%q %luo %q %q %lud %lud\n", + name, mode, uid, gid, mtime, bytes); + if(bytes) + seekpast(bytes); + continue; + } + if(mode & DMDIR) + mkdir(name, mode, mtime, uid, gid); + else + extract(name, mode, mtime, uid, gid, bytes); + } + fprint(2, "premature end of archive\n"); + exits("premature end of archive"); +} + +int +fileprefix(char *prefix, char *s) +{ + while(*prefix) + if(*prefix++ != *s++) + return 0; + if(*s && *s != '/') + return 0; + return 1; +} + +int +selected(char *s, int argc, char *argv[]) +{ + int i; + + for(i=0; i<argc; i++) + if(fileprefix(argv[i], s)) + return 1; + return 0; +} + +void +mkdirs(char *name, char *namep) +{ + char buf[2*LEN], *p; + int fd; + + strcpy(buf, name); + for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){ + if(p[1] == '\0') + return; + *p = 0; + fd = create(buf, OREAD, 0775|DMDIR); + close(fd); + *p = '/'; + } +} + +void +mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid) +{ + Dir *d, xd; + int fd; + char *p; + char olderr[256]; + + fd = create(name, OREAD, mode); + if(fd < 0){ + rerrstr(olderr, sizeof(olderr)); + if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){ + free(d); + warn("can't make directory %q, mode %luo: %s", name, mode, olderr); + return; + } + free(d); + } + close(fd); + + d = &xd; + nulldir(d); + p = utfrrune(name, L'/'); + if(p) + p++; + else + p = name; + d->name = p; + if(uflag){ + d->uid = uid; + d->gid = gid; + } + if(Tflag) + d->mtime = mtime; + d->mode = mode; + if(dirwstat(name, d) < 0) + warn("can't set modes for %q: %r", name); + + if(uflag||Tflag){ + if((d = dirstat(name)) == nil){ + warn("can't reread modes for %q: %r", name); + return; + } + if(Tflag && d->mtime != mtime) + warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime); + if(uflag && strcmp(uid, d->uid)) + warn("%q: uid mismatch %q %q", name, uid, d->uid); + if(uflag && strcmp(gid, d->gid)) + warn("%q: gid mismatch %q %q", name, gid, d->gid); + } +} + +void +extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes) +{ + Dir d, *nd; + Biobuf *b; + char buf[LEN]; + char *p; + ulong n, tot; + + if(vflag) + print("x %q %lud bytes\n", name, bytes); + + b = Bopen(name, OWRITE); + if(!b){ + warn("can't make file %q: %r", name); + seekpast(bytes); + return; + } + for(tot = 0; tot < bytes; tot += n){ + n = sizeof buf; + if(tot + n > bytes) + n = bytes - tot; + n = Bread(&bin, buf, n); + if(n <= 0) + error("premature eof reading %q", name); + if(Bwrite(b, buf, n) != n) + warn("error writing %q: %r", name); + } + + nulldir(&d); + p = utfrrune(name, '/'); + if(p) + p++; + else + p = name; + d.name = p; + if(uflag){ + d.uid = uid; + d.gid = gid; + } + if(Tflag) + d.mtime = mtime; + d.mode = mode; + Bflush(b); + if(dirfwstat(Bfildes(b), &d) < 0) + warn("can't set modes for %q: %r", name); + if(uflag||Tflag){ + if((nd = dirfstat(Bfildes(b))) == nil) + warn("can't reread modes for %q: %r", name); + else{ + if(Tflag && nd->mtime != mtime) + warn("%q: time mismatch %lud %lud\n", name, mtime, nd->mtime); + if(uflag && strcmp(uid, nd->uid)) + warn("%q: uid mismatch %q %q", name, uid, nd->uid); + if(uflag && strcmp(gid, nd->gid)) + warn("%q: gid mismatch %q %q", name, gid, nd->gid); + free(nd); + } + } + Bterm(b); +} + +void +seekpast(ulong bytes) +{ + char buf[LEN]; + ulong tot, n; + + for(tot = 0; tot < bytes; tot += n){ + n = sizeof buf; + if(tot + n > bytes) + n = bytes - tot; + n = Bread(&bin, buf, n); + if(n < 0) + error("premature eof"); + } +} + +void +error(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + sprint(buf, "%q: ", argv0); + va_start(arg, fmt); + vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s\n", buf); + exits(0); +} + +void +warn(char *fmt, ...) +{ + char buf[1024]; + va_list arg; + + sprint(buf, "%q: ", argv0); + va_start(arg, fmt); + vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s\n", buf); +} + +void +usage(void) +{ + fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n"); + exits("usage"); +} diff --git a/utils/mkext/mkfile b/utils/mkext/mkfile new file mode 100644 index 00000000..a8b4caad --- /dev/null +++ b/utils/mkext/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=mkext + +OFILES= mkext.$O\ + +HFILES= + +LIBS=bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/mkfile b/utils/mkfile new file mode 100644 index 00000000..c70e52d4 --- /dev/null +++ b/utils/mkfile @@ -0,0 +1,112 @@ +<../mkconfig + +# +# Utils we build everywhere, because the Plan 9 versions don't yet +# contain our changes (or they don't exist on Plan 9). +# Fairly soon the Plan 9 compilers will be updated to match. +# +ALWAYS=\ + libmach\ + libregexp\ + iar\ + cc\ + 0a\ + 0c\ + 0l\ + 1a\ + 1c\ + 1l\ + 2a\ + 2c\ + 2l\ + 5a\ + 5c\ + 5l\ +# 5i\ + 5coff\ + 5cv\ + ka\ + kc\ + kl\ + qa\ + qc\ + ql\ + sqz\ + tc\ + acid\ + srclist\ + ftl\ + ms2\ + data2c\ + data2s\ + idea\ + kprof\ + c2l\ + mkppcimage\ + nm\ + +# +# Utils we build on Posix and Nt, which already exist on Plan 9. +# +NOTPLAN9=\ + yacc\ + 8a\ + 8c\ + 8l\ + va\ + vc\ + vl\ + mk\ + ksize\ + kstrip\ + md5sum\ + mkext\ + ndate\ + +# +# Utils we build on Nt, for build environment compatibility. +# +NTONLY=\ + cp\ + echo\ + format\ + mkdir\ + mv\ + ntsrv\ + rcsh\ + rm\ + sed\ + test\ + tr\ + +all:QV: all-$TARGMODEL +clean:QV: clean-$TARGMODEL +install:QV: install-$TARGMODEL +installall:QV: installall-$TARGMODEL +nuke:QV: nuke-$TARGMODEL + +%-Plan9:QV: + for (j in $ALWAYS) + { + test -d $j && { + echo '@{cd' $j '; mk $MKFLAGS $stem}' + @{cd $j; mk $MKFLAGS $stem } + } || test ! -e $j + } + +%-Posix:QV: + for j in $ALWAYS $NOTPLAN9 + do + test -d $j || continue + echo "(cd $j; mk $MKFLAGS $stem)" + (cd $j; mk $MKFLAGS $stem) + done + +%-Nt:QV: + for (j in $ALWAYS $NTONLY $NOTPLAN9) + { + test -d $j && { + echo.exe '@{cd' $j '; mk $MKFLAGS $stem}' + @{cd $j; mk $MKFLAGS $stem } + } || test ! -e $j + } diff --git a/utils/mkppcimage/mkfile b/utils/mkppcimage/mkfile new file mode 100644 index 00000000..b0a95dff --- /dev/null +++ b/utils/mkppcimage/mkfile @@ -0,0 +1,18 @@ +<../../mkconfig + +TARG=mkppcimage + +OFILES= mkppcimage.$O\ + +HFILES=\ + a.out.h\ + bio.h\ + mach.h\ + +LIBS=mach bio 9 # order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/mkppcimage/mkppcimage.c b/utils/mkppcimage/mkppcimage.c new file mode 100644 index 00000000..4dc243e3 --- /dev/null +++ b/utils/mkppcimage/mkppcimage.c @@ -0,0 +1,261 @@ +/* + * generate the special header needed by DENX's ppcboot + */ + +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +/* + * the following values are all determined by PPCBOOT + */ +enum { + /* OS code */ + IH_OS_NCR = 12, /* we'll use this for the time being; there isn't a general purpose one */ + + /* CPU code */ + IH_CPU_ARM = 2, + IH_CPU_PPC = 7, + + /* image type */ + IH_TYPE_KERNEL = 2, /* OS kernel */ + + /* compression type */ + IH_COMP_NONE = 0, /* none: if i need one, i'll use sqz internally, much faster */ + + IH_MAGIC = 0x27051956, /* Image Magic Number */ + + IH_NMLEN = 32 /* image name length */ +}; + +typedef struct Imagehdr Imagehdr; +struct Imagehdr +{ + ulong magic; /* image header magic number */ + ulong hcrc; /* image header crc */ + ulong time; /* image creation timestamp */ + ulong size; /* image data size */ + ulong load; /* data load address */ + ulong entry; /* entry point address */ + ulong dcrc; /* image data crc */ + uchar os; /* operating system */ + uchar arch; /* cpu type */ + uchar type; /* image type */ + uchar comp; /* compression type */ + char name[IH_NMLEN]; /* image name */ +}; + + +static Imagehdr ih; +static char *fname; + +static ulong crc32(ulong, uchar*, unsigned int); +static long Read(int, void*, long); +static void Write(int, void*, long); + +/* + * data is big endian + */ +static ulong +swal(ulong l) +{ + return beswal(l); +} + +void +usage(void) +{ + fprint(2, "usage: mkppcimage [-l loadaddr] q.out ppcboot.out\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int fd, ofd; + long len; + uchar *data; + ulong load, entry; + Exec ex; + int arch; + + load = ~0; + entry = ~0; + ARGBEGIN{ + case 'l': + load = strtoul(EARGF(usage()), nil, 0); + entry = load + sizeof(Exec); + break; + }ARGEND + if(*argv == nil || argv[1] == nil) + usage(); + fname = *argv; + fd = open(*argv, OREAD); + if(fd < 0){ + fprint(2, "mkppcimage: can't open %s: %r\n", *argv); + exits("image"); + } + Read(fd, &ex, sizeof(Exec)); + switch(beswal(ex.magic)){ + case Q_MAGIC: /* powerpc */ + arch = IH_CPU_PPC; + break; + case E_MAGIC: /* arm */ + arch = IH_CPU_ARM; + break; + default: + arch = 0; + fprint(2, "mkppcboot: unknown magic: %8.8lux\n", beswal(ex.magic)); + exits("bad magic"); + } + len = beswal(ex.text); + len += beswal(ex.data); + if(load == ~0){ + entry = beswal(ex.entry); + entry &= ~0xFF000000; /* physical address */ + load = entry - sizeof(Exec); + } + data = malloc(len+sizeof(Exec)); + if(data == nil){ + fprint(2, "mkppcimage: can't allocate data: %r\n"); + exits("mem"); + } + memmove(data, &ex, sizeof(Exec)); + Read(fd, data+sizeof(Exec), len); + len += sizeof(Exec); + ih.magic = swal(IH_MAGIC); + ih.hcrc = 0; + ih.time = swal(time(0)); + ih.size = swal(len); + ih.load = swal(load); + ih.entry = swal(entry); + ih.dcrc = swal(crc32(0, data, len)); + ih.os = IH_OS_NCR; /* why not */ + ih.arch = arch; + ih.type = IH_TYPE_KERNEL; + ih.comp = IH_COMP_NONE; + strcpy(ih.name, "Himmel!"); + ih.hcrc = swal(crc32(0, (uchar*)&ih, sizeof(ih))); + ofd = create(argv[1], OWRITE, 0666); + if(ofd < 0){ + fprint(2, "mkppcimage: can't create %s: %r\n", argv[1]); + exits("image"); + } + Write(ofd, &ih, sizeof(ih)); + Write(ofd, data, len); + exits(nil); +} + +static long +Read(int fd, void *buf, long nb) +{ + long n; + + n = readn(fd, buf, nb); + if(n < 0){ + fprint(2, "mkppcimage: %s: read error: %r\n", fname); + exits("read"); + } + if(n < nb){ + fprint(2, "mkppcimage: %s: unexpected end-of-file\n", fname); + exits("read"); + } + return n; +} + +static void +Write(int fd, void *buf, long nb) +{ + if(write(fd, buf, nb) != nb){ + fprint(2, "mkppcboot: write error: %r\n"); + exits("write err"); + } +} + +/* + * The remainder of this file is derived from crc32.c from the zlib-1.1.3 distribution + * by Jean-loup Gailly and Mark Adler. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static ulong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +static ulong +crc32(ulong crc, uchar *buf, unsigned len) +{ + crc = ~crc; + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return ~crc; +} diff --git a/utils/ms2/mkfile b/utils/ms2/mkfile new file mode 100644 index 00000000..7850753e --- /dev/null +++ b/utils/ms2/mkfile @@ -0,0 +1,16 @@ +<../../mkconfig +CFLAGS=$CFLAGS -I../include + +TARG=ms2 + +OFILES= ms2.$O\ + +HFILES= \ + $ROOT/include/bio.h\ + ../include/mach.h\ + +LIBS=mach bio 9 #order matters + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/ms2/ms2.c b/utils/ms2/ms2.c new file mode 100644 index 00000000..e36307db --- /dev/null +++ b/utils/ms2/ms2.c @@ -0,0 +1,186 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +void record(uchar*, int); +void usage(void); +void dosegment(long, int); +void trailer(ulong); +void header(void); + +enum +{ + Recordsize = 32 +}; + +int dsegonly; +int supressend; +int binary; +ulong addr; +ulong psize = 4096; +ulong startaddr = 0x030000; +Biobuf bout; +Biobuf bio; + +void +main(int argc, char **argv) +{ + Dir *dir; + Fhdr f; + int fd; + + ARGBEGIN{ + case 'd': + dsegonly++; + break; + case 's': + supressend++; + break; + case 'a': + case 'T': + addr = strtoul(ARGF(), 0, 0); + break; + case 'p': + case 'R': + psize = strtoul(ARGF(), 0, 0); + break; + case 'b': + binary++; + break; + case 'S': + startaddr = strtoul(ARGF(), 0, 0); + break; + default: + usage(); + }ARGEND + + if(argc != 1) + usage(); + + Binit(&bout, 1, OWRITE); + + fd = open(argv[0], OREAD); + if(fd < 0) { + fprint(2, "ms2: open %s: %r\n", argv[0]); + exits("open"); + } + + if(binary) { + if((dir = dirfstat(fd)) == nil) { + fprint(2, "ms2: stat failed %r"); + exits("dirfstat"); + } + Binit(&bio, fd, OREAD); + header(); + dosegment(0, dir->length); + if(supressend == 0) + trailer(startaddr); + Bterm(&bout); + Bterm(&bio); + free(dir); + exits(0); + } + + if(crackhdr(fd, &f) == 0){ + fprint(2, "ms2: bad magic: %r\n"); + exits("magic"); + } + seek(fd, 0, 0); + + Binit(&bio, fd, OREAD); + + header(); + if(dsegonly) + dosegment(f.datoff, f.datsz); + else { + dosegment(f.txtoff, f.txtsz); + addr = (addr+(psize-1))&~(psize-1); + dosegment(f.datoff, f.datsz); + } + + if(supressend == 0) + trailer(startaddr); + + Bterm(&bout); + Bterm(&bio); + exits(0); +} + +void +dosegment(long foff, int len) +{ + int l, n; + uchar buf[2*Recordsize]; + + Bseek(&bio, foff, 0); + for(;;) { + l = len; + if(l > Recordsize) + l = Recordsize; + n = Bread(&bio, buf, l); + if(n == 0) + break; + if(n < 0) { + fprint(2, "ms2: read error: %r\n"); + exits("read"); + } + record(buf, l); + len -= l; + } +} + +void +record(uchar *s, int l) +{ + int i; + ulong cksum; + + if(addr & (0xFF<<24)){ + Bprint(&bout, "S3%.2X%.8X", l+5, addr); + cksum = l+5; + cksum += (addr>>24)&0xff; + }else{ + Bprint(&bout, "S2%.2X%.6X", l+4, addr); + cksum = l+4; + } + cksum += addr&0xff; + cksum += (addr>>8)&0xff; + cksum += (addr>>16)&0xff; + + for(i = 0; i < l; i++) { + cksum += *s; + Bprint(&bout, "%.2X", *s++); + } + Bprint(&bout, "%.2X\n", (~cksum)&0xff); + addr += l; +} + +void +header(void) +{ + Bprint(&bout, "S0030000FC\n"); +} + +void +trailer(ulong a) +{ + ulong cksum; + + cksum = 0; + if(a & (0xFF<<24)){ + Bprint(&bout, "S7%.8X", a); + cksum += (a>>24)&0xff; + }else + Bprint(&bout, "S9%.6X", a); + cksum += a&0xff; + cksum += (a>>8)&0xff; + cksum += (a>>16)&0xff; + Bprint(&bout, "%.2X\n", (~cksum)&0xff); +} + +void +usage(void) +{ + fprint(2, "usage: ms2 [-dsb] [-T address] [-R pagesize] [-S startaddress] ?.out\n"); + exits("usage"); +} diff --git a/utils/mv/mkfile b/utils/mv/mkfile new file mode 100644 index 00000000..c04450e6 --- /dev/null +++ b/utils/mv/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=mv + +OFILES= mv.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/mv/mv.c b/utils/mv/mv.c new file mode 100644 index 00000000..f8a9893f --- /dev/null +++ b/utils/mv/mv.c @@ -0,0 +1,210 @@ +#include <lib9.h> + +void split(char *, char **, char **); +int samefile(char *, char *); +int mv(char *from, char *todir, char *toelem); +int copy1(int fdf, int fdt, char *from, char *to); +void hardremove(char *); + +void +main(int argc, char *argv[]) +{ + int i; + int failed; + Dir *dirto, *dirfrom; + char *todir, *toelem; + + if(argc<3){ + fprint(2, "usage: mv fromfile tofile\n"); + fprint(2, " mv fromfile ... todir\n"); + exits("bad usage"); + } + if((dirto = dirstat(argv[argc-1])) != nil && (dirto->mode&DMDIR)){ + if(argc == 3 + && (dirfrom = dirstat(argv[1])) !=nil + && (dirfrom->mode & DMDIR)) + split(argv[argc-1], &todir, &toelem); + else{ + todir = argv[argc-1]; + toelem = 0; /* toelem will be fromelem */ + } + }else + split(argv[argc-1], &todir, &toelem); + if(argc>3 && toelem != 0){ + fprint(2, "mv: %s not a directory\n", argv[argc-1]); + exits("bad usage"); + } + failed = 0; + for(i=1; i < argc-1; i++) + if (mv(argv[i], todir, toelem) < 0) + failed++; + if(failed) + exits("failure"); + exits(0); +} + +int +mv(char *from, char *todir, char *toelem) +{ + Dir *dirb, *dirt, null; + char toname[4096], fromname[4096]; + int fdf, fdt, i, j; + int stat; + char *fromdir, *fromelem; + + dirb = dirstat(from); + if(dirb == nil){ + fprint(2, "mv: can't stat %s: %r\n", from); + return -1; + } + strncpy(fromname, from, sizeof fromname); + split(from, &fromdir, &fromelem); + if(toelem == 0) + toelem = fromelem; + i = strlen(toelem); + if(i==0){ + fprint(2, "mv: null last name element moving %s\n", fromname); + return -1; + } + j = strlen(todir); + if(i + j + 2 > sizeof toname){ + fprint(2, "mv: path too big (max %d): %s/%s\n", sizeof toname, todir, toelem); + return -1; + } + memmove(toname, todir, j); + toname[j] = '/'; + memmove(toname+j+1, toelem, i); + toname[i+j+1] = 0; + if(samefile(fromdir, todir)){ + if(samefile(fromname, toname)){ + fprint(2, "mv: %s and %s are the same\n", fromname, toname); + return -1; + } + dirt = dirstat(toname); + if(dirt != nil){ + free(dirt); + hardremove(toname); + } + nulldir(&null); + null.name = toelem; + if(dirwstat(fromname, &null) >= 0) + return 0; + if(dirb->mode & DMDIR){ + fprint(2, "mv: can't rename directory %s: %r\n", fromname); + return -1; + } + } + /* + * Renaming won't work --- must copy + */ + if(dirb->mode & DMDIR){ + fprint(2, "mv: %s is a directory, not copied to %s\n", fromname, toname); + return -1; + } + fdf = open(fromname, OREAD); + if(fdf < 0){ + fprint(2, "mv: can't open %s: %r\n", fromname); + return -1; + } + dirt = dirstat(toname); + if(dirt != nil && (dirt->mode & DMAPPEND)) + hardremove(toname); /* because create() won't truncate file */ + free(dirt); + fdt = create(toname, OWRITE, dirb->mode); + if(fdt < 0){ + fprint(2, "mv: can't create %s: %r\n", toname); + close(fdf); + return -1; + } + if ((stat = copy1(fdf, fdt, fromname, toname)) != -1) { + nulldir(&null); + null.mtime = dirb->mtime; + null.mode = dirb->mode; + dirfwstat(fdt, &null); /* ignore errors; e.g. user none always fails */ + close(fdf); + close(fdt); + if (remove(fromname) < 0) { + fprint(2, "mv: can't remove %s: %r\n", fromname); + return -1; + } + } + close(fdf); + close(fdt); + return stat; +} + +int +copy1(int fdf, int fdt, char *from, char *to) +{ + char buf[8192]; + long n, n1; + + for(;;) { + n = read(fdf, buf, sizeof buf); + if(n >= 0) { + if(n == 0) + break; + n1 = write(fdt, buf, n); + if(n1 != n) { + fprint(2, "mv: error writing %s: %r\n", to); + return -1; + } + } + } + if(n < 0) { + fprint(2, "mv: error reading %s: %r\n", from); + return -1; + } + return 0; +} + +void +split(char *name, char **pdir, char **pelem) +{ + char *s; + + s = utfrrune(name, '/'); + if(s){ + *s = 0; + *pelem = s+1; + *pdir = name; + }else if(strcmp(name, "..") == 0){ + *pdir = ".."; + *pelem = "."; + }else{ + *pdir = "."; + *pelem = name; + } +} + +int +samefile(char *a, char *b) +{ + Dir *da, *db; + int ret; + + if(strcmp(a, b) == 0) + return 1; + da = dirstat(a); + db = dirstat(b); + ret = (da !=nil ) && + (db != nil) && + (da->qid.type==db->qid.type) && + (da->qid.path==db->qid.path) && + (da->qid.vers==db->qid.vers) && + (da->dev==db->dev) && + da->type==db->type; + free(da); + free(db); + return ret; +} + +void +hardremove(char *a) +{ + if(remove(a) == -1){ + fprint(2, "mv: can't remove %s: %r\n", a); + exits("mv"); + } + do; while(remove(a) != -1); +} diff --git a/utils/na/mkfile b/utils/na/mkfile new file mode 100644 index 00000000..d28ee1c5 --- /dev/null +++ b/utils/na/mkfile @@ -0,0 +1,18 @@ +<../../mkconfig + +TARG=na +HFILES=\ + na.h\ + +OFILES=\ + y.tab.$O\ + +YFILES=na.y\ + +LIBS=9 + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/na/na.h b/utils/na/na.h new file mode 100755 index 00000000..ef8bc3cd --- /dev/null +++ b/utils/na/na.h @@ -0,0 +1,13 @@ +#ifndef NA_H +#define NA_H + +struct na_patch { + unsigned lwoff; + unsigned char type; +}; + +int na_fixup(unsigned long *script, unsigned long pa_script, unsigned long pa_reg, + struct na_patch *patch, int patches, + int (*externval)(int x, unsigned long *v)); + +#endif diff --git a/utils/na/na.man b/utils/na/na.man new file mode 100644 index 00000000..eb0a111e --- /dev/null +++ b/utils/na/na.man @@ -0,0 +1,33 @@ +.TH NA 8 +.SH NAME +na \- assembler for the Symbios Logic PCI-SCSI I/O Processors +.SH SYNOPSIS +.B aux/na file +.SH DESCRIPTION +The SYM53C8XX series of PCI-SCSI I/O Processors contain +loadable microcode to control their operation. +The microcode is written in a language called SCRIPTS. +.I Aux/na +is an assembler for the SCRIPTS programming language. +It assembles SCRIPTS code in +.I file +into an array of assembled SCRIPTS +instructions, patches, defines and enums +that can be included in a C device driver. +.SH SOURCE +.TF /sys/src/cmd/aux/na +.TP +.B /sys/src/cmd/aux/na +.SH "SEE ALSO" +Symbios Logic, +``PCI-SCSI I/O Processors Programming Guide Version 2.1'' +.br +.TF /sys/src/9/*/sd53c8xx.c +.TP +.B /sys/src/9/*/sd53c8xx.n +SCRIPTS source code +.TP +.B /sys/src/9/*/sd53c8xx.c +driver for the SYM53C8XX series of PCI-SCSI controllers +.SH AUTHOR +Nigel Roles (ngr@9fs.org) diff --git a/utils/na/na.y b/utils/na/na.y new file mode 100755 index 00000000..4021cb43 --- /dev/null +++ b/utils/na/na.y @@ -0,0 +1,1231 @@ +/* NCR53c8xx assembler */ +%{ +#include <lib9.h> +#include <stdio.h> +#include <ctype.h> + +#include "na.h" + +#define COND_WAIT (1L << 16) +#define COND_TRUE (1L << 19) +#define COND_INTFLY (1L << 20) +#define COND_CARRY (1L << 21) +#define COND_REL (1L << 23) +#define COND_PHASE (1L << 17) +#define COND_DATA (1L << 18) + +#define IO_REL (1L << 26) + +#define MOVE_MODE (1L << 27) + +int yylex(void); +int yyparse(void); +void assemble(void); +void yyerror(char *, ...); +void yywarn(char *, ...); +void p2error(int line, char *); + +struct addr { + int type; /* 0 - direct, 1 - indirect 2 - table indirect */ + unsigned long offset; +}; + +typedef enum Type { Const, Addr, Table, Extern, Reg, Unknown, Error } Type; + +struct sym { + char *name; + int set; + Type t; + long value; + struct sym *next; +}; + +struct sym *findsym(char *name); +struct sym *symlist; + +void newsym(struct sym *s, Type t, long v); + +struct binary { + char len; + unsigned long data[3]; + unsigned char patch[3]; +}; + +#define MAXCPPOPTS 30 +#define MAX_PATCHES 1000 +struct na_patch patch[MAX_PATCHES]; +int patches; + +struct binary out; + +struct expval { + Type t; + long value; +}; + +struct expval eval(struct expval a, struct expval b, char op); + +int patchtype(Type t); +void fixup(void); + +unsigned dot; +unsigned externs; +int errors, warnings; +struct sym *externp[100]; + +void regmove(unsigned char src_reg, unsigned char op, + unsigned char dst_reg, struct expval *imm); + +void preprocess(char *in, FILE *out); + +int mk24bitssigned(long *l); +long mkreladdr(long value, int len); +long chkreladdr(int d, struct expval *e, int len, long relrv); +int pass2; +FILE *in_f; + +int yyline = 0; +char yyfilename[200]; +char line[500]; +char *cppopts[MAXCPPOPTS]; +int ncppopts; +int wflag; +%} + +%union { + long n; + struct sym *s; + struct expval e; +} + +%token NUM MOVE WHEN SYMBOL SELECT WAIT DISCONNECT RESELECT SET CLEAR +%token DATA_OUT DATA_IN COMMAND STATUS RESERVED_OUT RESERVED_IN MESSAGE_OUT +%token MESSAGE_IN WITH ATN FAIL CARRY TARGET ACK COMMENT TO +%token SCNTL0 SCNTL1 SCNTL2 SCNTL3 SCID SXFER SDID GPREG +%token SFBR SOCL SSID SBCL DSTAT SSTAT0 SSTAT1 SSTAT2 +%token ISTAT CTEST0 CTEST1 CTEST2 CTEST3 TEMP DFIFO CTEST4 CTEST5 CTEST6 +%token DBC DCMD DNAD DSP DSPS DMODE DIEN DWT DCNTL ADDER +%token SIEN0 SIEN1 SIST0 SIST1 SLPAR MACNTL GPCNTL STIME0 STIME1 RESPID +%token STEST0 STEST1 STEST2 STEST3 SIDL SODL SBDL +%token SHL SHR AND OR XOR ADD ADDC +%token JUMP CALL RETURN INT INTFLY NOT ABSOLUTE MASK IF REL PTR +%token TABLE FROM MEMORY NOP EXTERN +%token SCRATCHA0 SCRATCHA1 SCRATCHA2 SCRATCHA3 +%token SCRATCHB0 SCRATCHB1 SCRATCHB2 SCRATCHB3 +%token SCRATCHC0 SCRATCHC1 SCRATCHC2 SCRATCHC3 +%token DSA0 DSA1 DSA2 DSA3 +%token DEFW + +%left '-' '+' +%left '*' '/' +%left NEG /* negation--unary minus */ +%right '^' /* exponentiation */ +%type <n> NUM phase .atn set_list set_bit regA reg +%type <n> set_cmd .cond condsfbr condphase +%type <n> jump_or_call .ptr +%type <s> SYMBOL +%type <e> exp byteexp regexp + +/* Grammar follows */ +%% +input: /* empty string */ + | input line +; + +line: .label .opcode .comment '\n' + { + if (pass2) { + int x; + for (x = 0; x < out.len; x++) { + printf("/* %.4x */ 0x%.8lxL,", + dot, out.data[x]); + if (x == 0) { + printf(" /*\t"); + fwrite(line, + strlen(line) - 1, 1, stdout); + printf(" */"); + } + printf("\n"); + if (out.patch[x]) { + patch[patches].lwoff = dot / 4; + patch[patches].type = out.patch[x]; + patches++; + } + dot += 4; + } + } + else + dot += 4 * out.len; + } + | ABSOLUTE SYMBOL '=' exp .comment '\n' + { + setsym($2, $4.t, $4.value); + if (pass2) { + printf("\t\t\t/*\t"); + fwrite(line, strlen(line) - 1, 1, stdout); + printf(" */\n"); + } + } + | SYMBOL '=' exp .comment '\n' + { + setsym($1, $3.t, $3.value); + if (pass2) { + printf("\t\t\t/*\t"); + fwrite(line, strlen(line) - 1, 1, stdout); + printf(" */\n"); + } + } + | EXTERN SYMBOL { + if (pass2) { + printf("\t\t\t/*\t"); + fwrite(line, strlen(line) - 1, 1, stdout); + printf(" */\n"); + } + else { + if (!pass2) + externp[externs] = $2; + setsym($2, Extern, externs++); + } + } + ; + +.comment: COMMENT + | /* nothing */ + ; + +.label: SYMBOL ':' { + if ($1->t != Unknown) + { + if (!pass2) + yyerror("multiply defined symbol"); + } + else { + $1->t = Addr; + $1->value = dot; + } + } + | /* nothing */ + ; + +set_cmd: SET { $$ = 3; } + | CLEAR { $$ = 4; } + ; + +set_bit: CARRY { $$ = 0x400; } + | TARGET { $$ = 0x200; } + | ACK { $$ = 0x40; } + | ATN { $$ = 0x8; } + ; + +set_list: set_list ',' set_bit { $$ = $1 | $3; } + | set_list AND set_bit { $$ = $1 | $3; } + | set_bit { $$ = $1; } + ; + +opcode: set_cmd set_list { + out.len = 2; + out.data[0] = (1L << 30) | ((long)$1 << 27) | $2; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | DISCONNECT + { + out.len = 2; + out.data[0] = 0x48020000L; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | INT exp .cond { + out.len = 2; + out.data[0] = $3 | 0x98000000L; + out.data[1] = $2.value; + out.patch[0] = out.patch[1] = 0; + } + | INTFLY exp .cond { + out.len = 2; + out.data[0] = $3 | 0x98000000L | COND_INTFLY; + out.data[1] = $2.value; + out.patch[0] = out.patch[1] = 0; + } + | jump_or_call exp .cond { + out.len = 2; + out.data[0] = $1 | $3 | chkreladdr(1, &$2, 2, COND_REL); + out.patch[0] = 0; + } + | jump_or_call REL '(' exp ')' .cond { + out.len = 2; + out.data[0] = $1 | $6 | COND_REL; + out.data[1] = mkreladdr($4.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | MOVE exp ',' .ptr regexp ',' with_or_when phase { + out.len = 2; + out.data[0] = ($8 << 24) | $2.value | ($4 << 29) | MOVE_MODE; + out.data[1] = $5.value; + out.patch[0] = 0; + out.patch[1] = patchtype($5.t); + } + | MOVE FROM exp ',' with_or_when phase { + out.len = 2; + out.data[0] = ($6 << 24) | (1L << 28) | MOVE_MODE; + out.data[1] = $3.value; + out.patch[0] = 0; + out.patch[1] = patchtype($3.t); + } + | MOVE MEMORY exp ',' regexp ',' regexp { + out.len = 3; + out.data[0] = 0xc0000000L | $3.value; + out.data[1] = $5.value; + out.data[2] = $7.value; + out.patch[0] = 0; + out.patch[1] = patchtype($5.t); + out.patch[2] = patchtype($7.t); + } + | MOVE regA TO regA { regmove($2, 2, $4, 0); } /* do reg to sfbr moves using or 0 */ + | MOVE exp TO regA { regmove($4, 0, $4, &$2); } + | MOVE regA '|' exp TO regA { regmove($2, 2, $6, &$4); } + | MOVE regA '&' exp TO regA { regmove($2, 4, $6, &$4); } + | MOVE regA '+' exp TO regA { regmove($2, 6, $6, &$4); } + | MOVE regA '-' exp TO regA { regmove($2, 6, $6, &$4); } + | MOVE regA '+' exp TO regA WITH CARRY { + regmove($2, 7, $6, &$4); + } + | MOVE regA '-' exp TO regA WITH CARRY { + $4.value = -$4.value; + regmove($2, 7, $6, &$4); + } + | MOVE regA SHL TO regA { regmove($2, 1, $5, 0); } + | MOVE regA SHR TO regA { regmove($2, 5, $5, 0); } + | MOVE regA XOR exp TO regA { regmove($2, 3, $6, &$4); } + | NOP { + out.len = 2; + out.data[0] = 0x80000000L; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | RESELECT exp ',' exp { + out.len = 2; + out.data[0] = 0x40000000L | ((long)$2.value << 16) | (1L << 9) | chkreladdr(1, &$4, 2, IO_REL); + out.patch[0] = 0; + } + | RESELECT exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | IO_REL + | ((long)$2.value << 16) | (1L << 9); + out.data[1] = mkreladdr($6.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | RESELECT FROM exp ',' exp { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | $3.value | chkreladdr(1, &$5, 2, IO_REL); + out.patch[0] = 5; + } + | RESELECT FROM exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | IO_REL | $3.value; + out.patch[0] = 5; + out.data[1] = mkreladdr($7.value, 2); + out.patch[1] = 0; + } + | RETURN .cond { + + out.len = 2; + out.data[0] = 0x90000000L | $2; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | SELECT .atn exp ',' exp { + out.len = 2; + out.data[0] = + 0x40000000L | ((long)$3.value << 16) | (1L << 9) | $2 | chkreladdr(1, &$5, 2, IO_REL); + out.patch[0] = 0; + } + | SELECT .atn exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 26) + | ((long)$3.value << 16) | (1L << 9) | $2; + out.data[1] = mkreladdr($7.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | SELECT .atn FROM exp ',' exp { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | $4.value | $2 | chkreladdr(1, &$6, 2, IO_REL); + out.patch[0] = 5; + } + | SELECT .atn FROM exp ',' REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 25) | IO_REL | $4.value | $2; + out.patch[0] = 5; + out.data[1] = mkreladdr($8.value, 2); + out.patch[1] = 0; + } + | WAIT DISCONNECT { + out.len = 2; + out.data[0] = 0x48000000L; + out.data[1] = 0; + out.patch[0] = out.patch[1] = 0; + } + | WAIT RESELECT exp { + out.len = 2; + out.data[0] = 0x50000000L | chkreladdr(1, &$3, 2, IO_REL); + out.patch[0] = 0; + } + | WAIT RESELECT REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x50000000L | (1L << 26); + out.data[1] = mkreladdr($5.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | WAIT SELECT exp { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 9) | chkreladdr(1, &$3, 2, IO_REL); + out.patch[0] = 0; + } + | WAIT SELECT REL '(' exp ')' { + out.len = 2; + out.data[0] = 0x40000000L | (1L << 26) | (1L << 9); + out.data[1] = mkreladdr($5.value, 2); + out.patch[0] = out.patch[1] = 0; + } + | DEFW exp { + out.len = 1; + out.data[0] = $2.value; + out.patch[0] = patchtype($2.t); + } + ; + +.ptr: PTR { $$ = 1; } + | { $$ = 0; } + ; + +with_or_when: WITH + | WHEN + ; + +jump_or_call: JUMP { $$ = 0x80000000L; } + | CALL { $$ = 0x88000000L; } + ; + +condsfbr: byteexp { $$ = $1.value | COND_DATA; } + | byteexp AND MASK byteexp { $$ = ($4.value << 8) | $1.value | COND_DATA; } + ; + +condphase: phase { $$ = ($1 << 24) | COND_PHASE; } + +.cond: ',' IF ATN { $$ = COND_TRUE; } + | ',' IF condphase { $$ = $3 | COND_TRUE; } + | ',' IF CARRY { $$ = COND_CARRY | COND_TRUE; } + | ',' IF condsfbr { $$ = $3 | COND_TRUE; } + | ',' IF ATN AND condsfbr { $$ = $5 | COND_TRUE; } + | ',' IF condphase AND condsfbr { $$ = $3 | $5 | COND_TRUE; } + | ',' WHEN condphase { $$ = $3 | COND_WAIT | COND_TRUE; } + | ',' WHEN CARRY { $$ = COND_CARRY | COND_WAIT | COND_TRUE; } + | ',' WHEN condsfbr { $$ = $3 | COND_WAIT | COND_TRUE; } + | ',' WHEN condphase AND condsfbr { $$ = $3 | $5 | COND_WAIT | COND_TRUE; } + | ',' IF NOT ATN { $$ = 0; } + | ',' IF NOT condphase { $$ = $4; } + | ',' IF NOT CARRY { $$ = COND_CARRY; } + | ',' IF NOT condsfbr { $$ = $4; } + | ',' IF NOT ATN OR condsfbr { $$ = $6; } + | ',' IF NOT condphase OR condsfbr { $$ = $4 | $6; } + | ',' WHEN NOT condphase { $$ = $4 | COND_WAIT; } + | ',' WHEN NOT CARRY { $$ = COND_CARRY | COND_WAIT; } + | ',' WHEN NOT condsfbr { $$ = $4 | COND_WAIT; } + | ',' WHEN NOT condphase OR condsfbr { $$ = $4 | $6 | COND_WAIT; } + | { $$ = COND_TRUE; } + ; + +.opcode: opcode + | { out.len = 0; } + ; + +regA: reg + | SFBR { $$ = 8; } + ; + +reg: SCNTL0 { $$ = 0; } + | SCNTL1 { $$ = 1; } + | SCNTL2 { $$ = 2; } + | SCNTL3 { $$ = 3; } + | SCID { $$ = 4; } + | SXFER { $$ = 5; } + | SDID { $$ = 6; } + | GPREG { $$ = 7; } + | SOCL { $$ = 9; } + | SSID { $$ = 0xa; } + | SBCL { $$ = 0xb; } + | DSTAT { $$ = 0xc; } + | SSTAT0 { $$ = 0xd; } + | SSTAT1 { $$ = 0xe; } + | SSTAT2 { $$ = 0xf; } + | DSA0 { $$ = 0x10; } + | DSA1 { $$ = 0x11; } + | DSA2 { $$ = 0x12; } + | DSA3 { $$ = 0x13; } + | ISTAT { $$ = 0x14; } + | CTEST0 { $$ = 0x18; } + | CTEST1 { $$ = 0x19; } + | CTEST2 { $$ = 0x1a; } + | CTEST3 { $$ = 0x1b; } + | TEMP { $$ = 0x1c; } + | DFIFO { $$ = 0x20; } + | CTEST4 { $$ = 0x21; } + | CTEST5 { $$ = 0x22; } + | CTEST6 { $$ = 0x23; } + | DBC { $$ = 0x24; } + | DCMD { $$ = 0x27; } + | DNAD { $$ = 0x28; } + | DSP { $$ = 0x2c; } + | DSPS { $$ = 0x30; } + | SCRATCHA0 { $$ = 0x34; } + | SCRATCHA1 { $$ = 0x35; } + | SCRATCHA2 { $$ = 0x36; } + | SCRATCHA3 { $$ = 0x37; } + | DMODE { $$ = 0x38; } + | DIEN { $$ = 0x39; } + | DWT { $$ = 0x3a; } + | DCNTL { $$ = 0x3b; } + | ADDER { $$ = 0x3c; } + | SIEN0 { $$ = 0x40; } + | SIEN1 { $$ = 0x41; } + | SIST0 { $$ = 0x42; } + | SIST1 { $$ = 0x43; } + | SLPAR { $$ = 0x44; } + | MACNTL { $$ = 0x46; } + | GPCNTL { $$ = 0x47; } + | STIME0 { $$ = 0x48; } + | STIME1 { $$ = 0x49; } + | RESPID { $$ = 0x4a; } + | STEST0 { $$ = 0x4c; } + | STEST1 { $$ = 0x4d; } + | STEST2 { $$ = 0x4e; } + | STEST3 { $$ = 0x4f; } + | SIDL { $$ = 0x50; } + | SODL { $$ = 0x54; } + | SBDL { $$ = 0x58; } + | SCRATCHB0 { $$ = 0x5c; } + | SCRATCHB1 { $$ = 0x5d; } + | SCRATCHB2 { $$ = 0x5e; } + | SCRATCHB3 { $$ = 0x5f; } + | SCRATCHC0 { $$ = 0x60; } + | SCRATCHC1 { $$ = 0x61; } + | SCRATCHC2 { $$ = 0x62; } + | SCRATCHC3 { $$ = 0x63; } + ; + +.atn: ATN { $$ = (1 << 24); } + | /* nothing */ { $$ = 0; } +; + +phase: DATA_OUT { $$ = 0; } + | DATA_IN { $$ = 1; } + | COMMAND { $$ = 2; } + | STATUS { $$ = 3; } + | RESERVED_OUT { $$ = 4; } + | RESERVED_IN { $$ = 5; } + | MESSAGE_OUT { $$ = 6; } + | MESSAGE_IN { $$ = 7; } +; + +byteexp: exp + { + if (pass2 && ($1.value < 0 || $1.value > 255)) { + if (wflag) + yywarn("conversion causes truncation"); + $$.value = $1.value & 0xff; + } + else + $$.value = $1.value; + } + ; + +regexp: exp + | regA { $$.t = Reg; $$.value = $1; } + ; + +exp: NUM { $$.t = Const; $$.value = $1; } + | SYMBOL { + $$.t = $1->t; $$.value = $1->value; + if (pass2 && $1->t == Unknown) + { + yyerror("Undefined symbol %s", $1->name); + $1->t = Error; + $1->value = 0; + $$.t = Error; + $$.value = 0; + } + } + | exp '+' exp { $$ = eval($1, $3, '+'); } + | exp '-' exp { $$ = eval($1, $3, '-'); } + | exp '*' exp { $$ = eval($1, $3, '*'); } + | exp '/' exp { $$ = eval($1, $3, '/'); } + | '-' exp %prec NEG { $$ = eval($2, $2, '_'); } + | '(' exp ')' { $$ = $2; } + | '~' exp %prec NEG { $$ = eval($2, $2, '~'); } + ; +%% + +struct { + char *name; + int tok; +} toktab[] = +{ + { "when", WHEN }, + { "data_out", DATA_OUT }, + { "data_in", DATA_IN }, + { "msg_out", MESSAGE_OUT }, + { "msg_in", MESSAGE_IN }, + { "cmd", COMMAND }, + { "command", COMMAND }, + { "status", STATUS }, + { "move", MOVE }, + { "select", SELECT }, + { "reselect", RESELECT }, + { "disconnect", DISCONNECT }, + { "wait", WAIT }, + { "set", SET }, + { "clear", CLEAR }, + { "with", WITH }, + { "atn", ATN }, + { "fail", FAIL }, + { "carry", CARRY }, + { "target", TARGET }, + { "ack", ACK }, + { "scntl0", SCNTL0 }, + { "scntl1", SCNTL1 }, + { "scntl2", SCNTL2 }, + { "scntl3", SCNTL3 }, + { "scid", SCID }, + { "sxfer", SXFER }, + { "sdid", SDID }, + { "gpreg", GPREG }, + { "sfbr", SFBR }, + { "socl", SOCL }, + { "ssid", SSID }, + { "sbcl", SBCL }, + { "dstat", DSTAT }, + { "sstat0", SSTAT0 }, + { "sstat1", SSTAT1 }, + { "sstat2", SSTAT2 }, + { "dsa", DSA0 }, + { "dsa0", DSA0 }, + { "dsa1", DSA1 }, + { "dsa2", DSA2 }, + { "dsa3", DSA3 }, + { "istat", ISTAT }, + { "ctest0", CTEST0 }, + { "ctest1", CTEST1 }, + { "ctest2", CTEST2 }, + { "ctest3", CTEST3 }, + { "temp", TEMP }, + { "dfifo", DFIFO }, + { "ctest4", CTEST4 }, + { "ctest5", CTEST5 }, + { "ctest6", CTEST6 }, + { "dbc", DBC }, + { "dcmd", DCMD }, + { "dnad", DNAD }, + { "dsp", DSP }, + { "dsps", DSPS }, + { "scratcha", SCRATCHA0 }, + { "scratcha0", SCRATCHA0 }, + { "scratcha1", SCRATCHA1 }, + { "scratcha2", SCRATCHA2 }, + { "scratcha3", SCRATCHA3 }, + { "dmode", DMODE }, + { "dien", DIEN }, + { "dwt", DWT }, + { "dcntl", DCNTL }, + { "adder", ADDER }, + { "sien0", SIEN0 }, + { "sien1", SIEN1 }, + { "sist0", SIST0 }, + { "sist1", SIST1 }, + { "slpar", SLPAR }, + { "macntl", MACNTL }, + { "gpcntl", GPCNTL }, + { "stime0", STIME0 }, + { "stime1", STIME1 }, + { "respid", RESPID }, + { "stest0", STEST0 }, + { "stest1", STEST1 }, + { "stest2", STEST2 }, + { "stest3", STEST3 }, + { "sidl", SIDL }, + { "sodl", SODL }, + { "sbdl", SBDL }, + { "scratchb", SCRATCHB0 }, + { "scratchb0", SCRATCHB0 }, + { "scratchb1", SCRATCHB1 }, + { "scratchb2", SCRATCHB2 }, + { "scratchb3", SCRATCHB3 }, + { "scratchc", SCRATCHC0 }, + { "scratchc0", SCRATCHC0 }, + { "scratchc1", SCRATCHC1 }, + { "scratchc2", SCRATCHC2 }, + { "scratchc3", SCRATCHC3 }, + { "add", ADD }, + { "addc", ADDC }, + { "and", AND }, + { "or", OR }, + { "xor", XOR }, + { "shl", SHL }, + { "shr", SHR }, + { "jump", JUMP }, + { "call", CALL }, + { "return", RETURN }, + { "int", INT }, + { "intfly", INTFLY }, + { "not", NOT }, + { "absolute", ABSOLUTE }, + { "mask", MASK }, + { "if", IF }, + { "rel", REL }, + { "ptr", PTR }, + { "table", TABLE }, + { "from", FROM }, + { "memory", MEMORY }, + { "to", TO }, + { "nop", NOP }, + { "extern", EXTERN }, + { "defw", DEFW }, +}; + +#define TOKS (sizeof(toktab)/sizeof(toktab[0])) + +int lc; +int ll; + +void +yyrewind(void) +{ + rewind(in_f); + ll = lc = 0; + yyline = 0; + dot = 0; +} + +int +yygetc(void) +{ + if (lc == ll) + { + next: + if (fgets(line, 500, in_f) == 0) + return EOF; + /* do nasty check for #line directives */ + if (strncmp(line, "#line", 5) == 0) { + /* #line n "filename" */ + sscanf(line, "#line %d \"%[^\"]", &yyline, yyfilename); + yyline--; + goto next; + } + yyline++; + ll = strlen(line); + lc = 0; + } + return line[lc++]; +} + +void +yyungetc(void) +{ + if (lc <= 0) + exits("ungetc"); + lc--; +} + +int +yylex(void) +{ + char token[100]; + int tl = 0; + int c; + + while ((c = yygetc()) != EOF && (c == ' ' || c == '\t')) + ; + if (c == EOF) + return 0; + if(c == '/'){ + int x; + x = yygetc(); + if(x != '/') + yyungetc(); + else{ + lc -= 2; + while(lc >= 0 && (line[lc-1]==' ' || line[lc-1]=='\t')) + lc--; + line[lc++] = '\n'; + line[lc] = 0; + ll = lc; + return '\n'; + } + } + if (isalpha(c) || c == '_') + { + int x; + do { + token[tl++] = c; + } while ((c = yygetc()) != EOF && (isalnum(c) || c == '_')); + if (c == EOF) + return 0; + yyungetc(); + token[tl] = 0; + for (x = 0; x < TOKS; x++) + if (strcmp(toktab[x].name, token) == 0) + return toktab[x].tok; + /* must be a symbol */ + yylval.s = findsym(token); + return SYMBOL; + } + else if (isdigit(c)) + { + /* accept 0x<digits> or 0b<digits> 0<digits> or <digits> */ + int prefix = c == '0'; + unsigned long n = c - '0'; + int base = 10; + for (;;) + { + c = yygetc(); + if (c == EOF) + return 0; + if (prefix) + { + prefix = 0; + if (c == 'x') { + base = 16; + continue; + } + else if (c == 'b') + { + base = 2; + continue; + } + else + base = 8; + } + if (isdigit(c)) + c -= '0'; + else if (isalpha(c) && base > 10) + { + if (isupper(c)) + c = tolower(c); + c = c - 'a' + 10; + } + else { + yyungetc(); + yylval.n = n; + return NUM; + } + if (c >= base) + yyerror("illegal format number"); + n = n * base + c; + } + } + else if (c == ';') { + /* skip to end of line */ + while ((c = yygetc()) != EOF && c != '\n') + ; + if (c != EOF) + yyungetc(); + return COMMENT; + } + return c; +} + +void +yyerror(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(stderr, "%s: %d: ", yyfilename, yyline); + vfprintf(stderr, s, ap); + if (putc('\n', stderr) < 0) + exits("io"); + errors++; + va_end(ap); +} + +void +yywarn(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(stderr, "%s: %d: warning: ", yyfilename, yyline); + vfprintf(stderr, s, ap); + if (putc('\n', stderr) < 0) + exits("io"); + warnings++; + va_end(ap); +} + +void +p2error(int line, char *s) +{ + USED(line); + printf("/*\t%s */\n", s); +} + +void +main(int argc, char *argv[]) +{ + int a; + for (a = 1; a < argc; a++) + { + if (argv[a][0] == '-') + switch (argv[a][1]) { + case 'D': + /* #defines for cpp */ + if (ncppopts >= MAXCPPOPTS) { + fprintf(stderr, "too many cpp options\n"); + exits("options"); + } + cppopts[ncppopts++] = argv[a]; + break; + default: + fprintf(stderr, "unrecognised option %s\n", + argv[a]); + exits("options"); + } + else + break; + } + if (a != argc - 1) + { + fprintf(stderr, "usage: na [options] file\n"); + exits("options"); + } + if (access(argv[a], 4) < 0) { + fprintf(stderr, "can't read %s\n", argv[a]); + exits(""); + } + in_f = tmpfile(); + preprocess(argv[a], in_f); + rewind(in_f); + strcpy(yyfilename, argv[a]); + yyparse(); + if (errors) + exits("pass1"); + pass2 = 1; + printf("unsigned long na_script[] = {\n"); + yyrewind(); + yyparse(); + printf("};\n"); + printf("\n"); + printf("#define NA_SCRIPT_SIZE %d\n", dot / 4); + printf("\n"); + fixup(); +/* + assemble(); +*/ + exits(errors ? "pass2" : ""); +} + +void +preprocess(char *in, FILE *out) +{ +#ifdef USECPP + Waitmsg *w; + char **argv; + + if (fork() == 0) { + /* child */ + dup(fileno(out), 1); + argv = (char **)malloc(sizeof(char *) * (ncppopts + 5)); + argv[0] = "cpp"; + memcpy(&argv[1], cppopts, sizeof(char *) * ncppopts); + argv[ncppopts + 1] = "-+"; + argv[ncppopts + 2] = "-N"; + argv[ncppopts + 3] = in; + argv[ncppopts + 4] = 0; + if (exec("/bin/cpp", argv) < 0) { + fprintf(stderr, "failed to exec cpp (%R)\n"); + exits("exec"); + } + exits(""); + } + w = wait(); + free(w); +#else + FILE *fi; + int c; + + + fi = fopen(in, "r"); + if(fi == NULL){ + fprintf(stderr, "na: can't open %s\n", in); + exits("open"); + } + while((c = fgetc(fi)) != EOF) + fputc(c, out); + fclose(fi); +#endif +} + +struct sym * +findsym(char *name) +{ + struct sym *s; + for (s = symlist; s; s = s->next) + if (strcmp(name, s->name) == 0) + return s; + s = (struct sym *)malloc(sizeof(*s)); + s->name = strdup(name); + s->t = Unknown; + s->set = 0; + s->next = symlist; + symlist = s; + return s; +} + +void +setsym(struct sym *s, Type t, long v) +{ + if (pass2) { + if (t == Unknown || t == Error) + yyerror("can't resolve symbol"); + else { + s->t = t; + s->value = v; + } + } + else { + if (s->set) + yyerror("multiply defined symbol"); + s->set = 1; + s->t = t; + s->value = v; + } +} + +int +mk24bitssigned(long *l) +{ + if (*l < 0) { + if ((*l & 0xff800000L) != 0xff800000L) { + *l = 0; + return 0; + } + else + *l = (*l) & 0xffffffL; + } + else if (*l > 0xffffffL) { + *l = 0; + return 0; + } + return 1; +} + +static Type addresult[5][5] = { +/* Const Addr Table Extern Reg */ +/* Const */ Const, Addr, Table, Error, Reg, +/* Addr */ Addr, Error, Error, Error, Error, +/* Table */ Table, Error, Error, Error, Error, +/* Extern */ Error, Error, Error, Error, Error, +/* Reg */ Reg, Error, Error, Error, Error, +}; + +static Type subresult[5][5] = { +/* Const Addr Table Extern Reg */ +/* Const */ Const, Error, Error, Error, Error, +/* Addr */ Addr, Const, Error, Error, Error, +/* Table */ Table, Error, Const, Error, Error, +/* Extern */ Error, Error, Error, Const, Error, +/* Reg */ Error, Error, Error, Error, Error, +}; + +static Type muldivresult[5][5] = { +/* Const Addr Table Extern */ +/* Const */ Const, Error, Error, Error, Error, +/* Addr */ Error, Error, Error, Error, Error, +/* Table */ Error, Error, Error, Error, Error, +/* Extern */ Error, Error, Error, Error, Error, +/* Reg */ Error, Error, Error, Error, Error, +}; + +static Type negresult[] = { +/* Const */ Const, +/* Addr */ Error, +/* Table */ Error, +/* Extern */ Error, +/* Reg */ Error, +}; + +int +patchtype(Type t) +{ + switch (t) { + case Addr: + return 1; + case Reg: + return 2; + case Extern: + return 4; + default: + return 0; + } +} + +struct expval +eval(struct expval a, struct expval b, char op) +{ + struct expval c; + + if (a.t == Unknown || b.t == Unknown) { + c.t = Unknown; + c.value = 0; + } + else if (a.t == Error || b.t == Error) { + c.t = Error; + c.value = 0; + } + else { + switch (op) { + case '+': + c.t = addresult[a.t][b.t]; + break; + case '-': + c.t = subresult[a.t][b.t]; + break; + case '*': + case '/': + c.t = muldivresult[a.t][b.t]; + break; + case '_': + case '~': + c.t = negresult[a.t]; + break; + default: + c.t = Error; + break; + } + if (c.t == Error) { + if (pass2) + yyerror("type clash in evaluation"); + c.value = 0; + } + else { + switch (op) { + case '+': + c.value = a.value + b.value; + break; + case '-': + c.value = a.value - b.value; + break; + case '*': + c.value = a.value * b.value; + break; + case '/': + c.value = a.value / b.value; + break; + case '_': + c.value = -a.value; + break; + case '~': + c.value = ~a.value; + break; + } + } + } + return c; +} + +void +regmove(unsigned char src_reg, unsigned char op, + unsigned char dst_reg, struct expval *imm) +{ + unsigned char func, reg; + int immdata; + out.len = 2; + if (src_reg == 8) { + func = 5; + reg = dst_reg; + } + else if (dst_reg == 8) { + func = 6; + reg = src_reg; + } + else { + if (pass2 && src_reg != dst_reg) + yyerror("Registers must be the same"); + func = 7; + reg = src_reg; + } + immdata = imm ? (imm->value & 0xff) : 0; + out.data[0] = 0x40000000L + | ((long)func << 27) + | ((long)op << 24) + | ((long)reg << 16) + | ((long)(immdata) << 8); + out.data[1] = 0; + out.patch[0] = (imm && imm->t == Extern) ? 3 : 0; + out.patch[1] = 0; +} + +long +mkreladdr(long addr, int len) +{ + long rel; + rel = addr - (dot + 4 * len); + mk24bitssigned(&rel); + return rel; +} + +long +chkreladdr(int d, struct expval *e, int len, long relrv) +{ + if (e->t == Addr) { + out.data[d] = mkreladdr(e->value, len); + out.patch[d] = 0; + return relrv; + } else { + out.data[d] = e->value; + out.patch[d] = patchtype(e->t); + return 0; + } +} + +void +fixup(void) +{ + struct sym *s; + int p; + printf("struct na_patch na_patches[] = {\n"); + for (p = 0; p < patches; p++) { + printf("\t{ 0x%.4x, %d }, /* %.8lx */\n", + patch[p].lwoff, patch[p].type, patch[p].lwoff * 4L); + } + if (patches == 0) { + printf("\t{ 0, 0 },\n"); + } + printf("};\n"); + printf("#define NA_PATCHES %d\n", patches); + printf("\n"); + if (externs) { + printf("enum na_external {\n"); + for (p = 0; p < externs; p++) { + printf("\tX_%s,\n", externp[p]->name); + } + printf("};\n"); + } + /* dump all labels (symbols of type Addr) as E_<Name> */ + for (s = symlist; s; s = s->next) + if (s->t == Addr) + break; + if (s) { + printf("\nenum {\n"); + while (s) { + if (s->t == Addr) + printf("\tE_%s = %ld,\n", s->name, s->value); + s = s->next; + } + printf("};\n"); + } + /* dump all Consts as #define A_<Name> value */ + for (s = symlist; s; s = s->next) + if (s->t == Const) + printf("#define A_%s %ld\n", s->name, s->value); +} + diff --git a/utils/ndate/mkfile b/utils/ndate/mkfile new file mode 100644 index 00000000..01565f8d --- /dev/null +++ b/utils/ndate/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=ndate + +OFILES= ndate.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/ndate/ndate.c b/utils/ndate/ndate.c new file mode 100644 index 00000000..0cbc3574 --- /dev/null +++ b/utils/ndate/ndate.c @@ -0,0 +1,11 @@ +#include <lib9.h> + +void +main(void) +{ + ulong t; + + t = time(0); + print("%lud\n", t); + exits(0); +} diff --git a/utils/nm/mkfile b/utils/nm/mkfile new file mode 100644 index 00000000..983f0f52 --- /dev/null +++ b/utils/nm/mkfile @@ -0,0 +1,14 @@ +<../../mkconfig + +TARG=inm # inferno nm + +OFILES=\ + nm.$O\ + +LIBS=mach bio 9 # order is important. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I. -I../include diff --git a/utils/nm/nm.c b/utils/nm/nm.c new file mode 100644 index 00000000..cf36ad10 --- /dev/null +++ b/utils/nm/nm.c @@ -0,0 +1,287 @@ +/* + * nm.c -- drive nm + */ +#include <lib9.h> +#include <ar.h> +#include <bio.h> +#include <mach.h> + +enum{ + CHUNK = 256 /* must be power of 2 */ +}; + +char *errs; /* exit status */ +char *filename; /* current file */ +char symname[]="__.SYMDEF"; /* table of contents file name */ +int multifile; /* processing multiple files */ +int aflag; +int gflag; +int hflag; +int nflag; +int sflag; +int uflag; + +Sym **fnames; /* file path translation table */ +Sym **symptr; +int nsym; +Biobuf bout; +char* argv0; + +void error(char*, ...); +void execsyms(int); +void psym(Sym*, void*); +void printsyms(Sym**, long); +void doar(Biobuf*); +void dofile(Biobuf*); +void zenter(Sym*); + +void +main(int argc, char *argv[]) +{ + int i; + Biobuf *bin; + + Binit(&bout, 1, OWRITE); + argv0 = argv[0]; + ARGBEGIN { + case 'a': aflag = 1; break; + case 'g': gflag = 1; break; + case 'h': hflag = 1; break; + case 'n': nflag = 1; break; + case 's': sflag = 1; break; + case 'u': uflag = 1; break; + } ARGEND + if (argc > 1) + multifile++; + for(i=0; i<argc; i++){ + filename = argv[i]; + bin = Bopen(filename, OREAD); + if(bin == 0){ + error("cannot open %s", filename); + continue; + } + if (isar(bin)) + doar(bin); + else{ + Bseek(bin, 0, 0); + dofile(bin); + } + Bterm(bin); + } + exits(errs); +} + +/* + * read an archive file, + * processing the symbols for each intermediate file in it. + */ +void +doar(Biobuf *bp) +{ + int offset, size, obj; + char membername[SARNAME]; + + multifile = 1; + for (offset = Boffset(bp);;offset += size) { + size = nextar(bp, offset, membername); + if (size < 0) { + error("phase error on ar header %ld", offset); + return; + } + if (size == 0) + return; + if (strcmp(membername, symname) == 0) + continue; + obj = objtype(bp, 0); + if (obj < 0) { + error("inconsistent file %s in %s", + membername, filename); + return; + } + if (!readar(bp, obj, offset+size, 1)) { + error("invalid symbol reference in file %s", + membername); + return; + } + filename = membername; + nsym=0; + objtraverse(psym, 0); + printsyms(symptr, nsym); + } +} + +/* + * process symbols in a file + */ +void +dofile(Biobuf *bp) +{ + int obj; + + obj = objtype(bp, 0); + if (obj < 0) + execsyms(Bfildes(bp)); + else + if (readobj(bp, obj)) { + nsym = 0; + objtraverse(psym, 0); + printsyms(symptr, nsym); + } +} + +/* + * comparison routine for sorting the symbol table + * this screws up on 'z' records when aflag == 1 + */ +int +cmp(const void *vs, const void *vt) +{ + Sym **s, **t; + + s = (Sym**)vs; + t = (Sym**)vt; + if(nflag) + if((ulong)(*s)->value < (ulong)(*t)->value) + return -1; + else + return (ulong)(*s)->value > (ulong)(*t)->value; + return strcmp((*s)->name, (*t)->name); +} +/* + * enter a symbol in the table of filename elements + */ +void +zenter(Sym *s) +{ + static int maxf = 0; + + if (s->value > maxf) { + maxf = (s->value+CHUNK-1) &~ (CHUNK-1); + fnames = realloc(fnames, maxf*sizeof(*fnames)); + if(fnames == 0) { + error("out of memory", argv0); + exits("memory"); + } + } + fnames[s->value] = s; +} + +/* + * get the symbol table from an executable file, if it has one + */ +void +execsyms(int fd) +{ + Fhdr f; + Sym *s; + long n; + + seek(fd, 0, 0); + if (crackhdr(fd, &f) == 0) { + error("Can't read header for %s", filename); + return; + } + if (syminit(fd, &f) < 0) + return; + s = symbase(&n); + nsym = 0; + while(n--) + psym(s++, 0); + + printsyms(symptr, nsym); +} + +void +psym(Sym *s, void* p) +{ + USED(p); + switch(s->type) { + case 'T': + case 'L': + case 'D': + case 'B': + if (uflag) + return; + if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) + return; + break; + case 'b': + case 'd': + case 'l': + case 't': + if (uflag || gflag) + return; + if (!aflag && ((s->name[0] == '.' || s->name[0] == '$'))) + return; + break; + case 'U': + if (gflag) + return; + break; + case 'Z': + if (!aflag) + return; + break; + case 'm': + case 'f': /* we only see a 'z' when the following is true*/ + if(!aflag || uflag || gflag) + return; + if (strcmp(s->name, ".frame")) + zenter(s); + break; + case 'a': + case 'p': + case 'z': + default: + if(!aflag || uflag || gflag) + return; + break; + } + symptr = realloc(symptr, (nsym+1)*sizeof(Sym*)); + if (symptr == 0) { + error("out of memory"); + exits("memory"); + } + symptr[nsym++] = s; +} + +void +printsyms(Sym **symptr, long nsym) +{ + Sym *s; + char *cp; + char path[512]; + + if(!sflag) + qsort(symptr, nsym, sizeof(*symptr), cmp); + while (nsym-- > 0) { + s = *symptr++; + if (multifile && !hflag) + Bprint(&bout, "%s:", filename); + if (s->type == 'z') { + fileelem(fnames, (uchar *) s->name, path, 512); + cp = path; + } else + cp = s->name; + if (s->value || s->type == 'a' || s->type == 'p') + Bprint(&bout, "%8lux %c %s\n", s->value, s->type, cp); + else + Bprint(&bout, " %c %s\n", s->type, cp); + } +} + +void +error(char *fmt, ...) +{ + char buf[4096], *s; + va_list arg; + + s = buf; + s += sprint(s, "%s: ", argv0); + va_start(arg, fmt); + s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg); + va_end(arg); + *s++ = '\n'; + write(2, buf, s - buf); + errs = "errors"; +} diff --git a/utils/ntsrv/domk b/utils/ntsrv/domk new file mode 100644 index 00000000..544ad331 --- /dev/null +++ b/utils/ntsrv/domk @@ -0,0 +1,2 @@ +os -d $emuroot\utils\ntsrv mk | sed 's/\(([0-9]*)\)/:\1/ +s/
//' diff --git a/utils/ntsrv/mkfile b/utils/ntsrv/mkfile new file mode 100755 index 00000000..8d15bec8 --- /dev/null +++ b/utils/ntsrv/mkfile @@ -0,0 +1,25 @@ +#uncomment following line for full Microsoft debug symbols +#LDEBUG=-debug -debugtype:cv -pdb:none +<../../mkconfig +SYSTARG=Nt +SYSHOST=Nt +OBJTYPE=386 +OBJDIR=$SYSTARG/$OBJTYPE +<$ROOT/mkfiles/mkhost-$SYSHOST +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE + +TARG=ntsrv + +OFILES= ntsrv.$O\ + +HFILES= + +LIBS=9 + +CFLAGS=$CFLAGS -I. + +BIN=$ROOT/$OBJDIR/bin + +SYSLIBS= $SYSLIBS wsock32.lib user32.lib gdi32.lib advapi32.lib winmm.lib mpr.lib + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/ntsrv/ntsrv.c b/utils/ntsrv/ntsrv.c new file mode 100644 index 00000000..881a0c3f --- /dev/null +++ b/utils/ntsrv/ntsrv.c @@ -0,0 +1,573 @@ +#ifndef ForNT4 +/* only for XP, 2000 and above - JobObject only available on these*/ +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include "lib9.h" +#include <windows.h> +#include <winsvc.h> +#include <stdarg.h> + +#ifdef JOB_OBJECT_TERMINATE +#define Jobs +#endif + +#ifdef ForNT4 +#undef Jobs +#endif + +/* + * ntsrv add Name Inferno-root Cmds + * ntsrv del Name + * ntsrv run Name Inferno-root Cmds + * + * 'add' registers service: Name with args "run Name Inferno-root Cmds" + * 'del' unregisters service Name + * 'run' - only given by NT service manager when starting the service (see 'add') + * + * Cmds are cat'd (with space separator) and requoted for CreateProcess() + * + * There must be an ntsrv.exe in Inferno-root/Nt/386/bin + */ + + +SERVICE_STATUS status = { + SERVICE_WIN32_OWN_PROCESS, /* dwServiceType */ + 0, /* dwCurrentState */ + SERVICE_ACCEPT_STOP /* dwControlsAccepted */ +}; + +typedef struct Emu Emu; +struct Emu { + HANDLE proc; /* NULL if error */ + HANDLE job; /* job for all children */ + HANDLE stdin; /* stdio pipes */ + HANDLE stdout; + DWORD notepg; /* process group ID (in case we lack Jobs) */ +}; + +typedef struct Copyargs Copyargs; +struct Copyargs { + HANDLE in; + HANDLE out; +}; + +#ifdef Jobs +static char *myname = "ntsrv.exe"; +#else +static char *myname = "ntsrv4.exe"; +#endif +#define LOGFILE "grid\\slave\\svclog" +static char *name; +static char *root; +static char *cmds; +static SERVICE_STATUS_HANDLE statush; +static HANDLE emujob; /* win32 job object for emu session */ +static DWORD emugroup; /* process group ID for emu session */ +static HANDLE emuin; /* stdin pipe of emu */ +static HANDLE logf; + +HANDLE openlog(char*); +void logmsg(char*, ...); +void WINAPI infmain(ulong, LPTSTR[]); +void WINAPI infctl(ulong); +Emu runemu(char*); +HANDLE exporthandle(HANDLE, int); +DWORD WINAPI copy(LPVOID); +int shuttingdown = 0; +int nice = 0; + +static void +usage() +{ + fprint(2, "usage: ntsrv [-n] add name root cmds | del name\n"); +} + +/* (from rcsh) + * windows quoting rules - I think + * Words are seperated by space or tab + * Words containing a space or tab can be quoted using " + * 2N backslashes + " ==> N backslashes and end quote + * 2N+1 backslashes + " ==> N backslashes + literal " + * N backslashes not followed by " ==> N backslashes + */ +static char * +dblquote(char *cmd, char *s) +{ + int nb; + char *p; + + for(p=s; *p; p++) + if(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '"') + break; + + if(*p == 0){ /* easy case */ + strcpy(cmd, s); + return cmd+(p-s); + } + + *cmd++ = '"'; + for(;;) { + for(nb=0; *s=='\\'; nb++) + *cmd++ = *s++; + + if(*s == 0) { /* trailing backslashes -> 2N */ + while(nb-- > 0) + *cmd++ = '\\'; + break; + } + + if(*s == '"') { /* literal quote -> 2N+1 backslashes */ + while(nb-- > 0) + *cmd++ = '\\'; + *cmd++ = '\\'; /* escape the quote */ + } + *cmd++ = *s++; + } + + *cmd++ = '"'; + *cmd = 0; + + return cmd; +} + +static char * +proccmd(char **argv) +{ + int i, n; + char *cmd, *p; + + /* conservatively calculate length of command; + * backslash expansion can cause growth in dblquote(). + */ + for(i=0,n=0; argv[i]; i++) { + n += 2*strlen(argv[i]); + } + n++; + + cmd = malloc(n); + for(i=0,p=cmd; argv[i]; i++) { + p = dblquote(p, argv[i]); + *p++ = ' '; + } + if(p != cmd) + p--; + *p = 0; + + return cmd; +} + +int +installnewemu() +{ + LPCTSTR currpath, newpath; + currpath = smprint("%s\\Nt\\386\\bin\\emu.exe", root); + newpath = smprint("%s\\Nt\\386\\bin\\newemu.exe", root); + if(GetFileAttributes(newpath) == 0xffffffff) // INVALID_FILE_ATTRIBUTES is not defined + return 0; + DeleteFile(currpath); // ignore error message - it might not be there. + if(MoveFile(newpath, currpath) == 0){ + logmsg("cannot rename %s to %s: %r", newpath, currpath); + return -1; + } + return 0; +} + +void WINAPI +infmain(ulong argc, char *argv[]) +{ + HANDLE cpt; + Emu emu; + Copyargs cp; + DWORD tid; + char *cmd; + + argc--; + argv++; + cmd = smprint("%s\\%s", root, LOGFILE); + logf = openlog(cmd); + free(cmd); + statush = RegisterServiceCtrlHandler(name, infctl); + if (statush == 0) + return; + + status.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(statush, &status); + + while(installnewemu() != -1){ + /* start the service */ + cmd = smprint("%s\\Nt\\386\\bin\\emu.exe -r%s %s", root, root, cmds); + logmsg("starting %s", cmd); + emu = runemu(cmd); + free(cmd); + if (emu.proc == NULL) { + logmsg("runemu failed: %r"); + status.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(statush, &status); + return; + } + + cp.in = emu.stdout; + cp.out = logf; + cpt = CreateThread(NULL, 0, copy, (void*)&cp, 0, &tid); + if (cpt == NULL) { + logmsg("failed to create copy thread: %r"); + CloseHandle(emu.stdout); + } + + logmsg("infmain blocking on emu proc"); + emujob = emu.job; + emugroup = emu.notepg; + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(statush, &status); + WaitForSingleObject(emu.proc, INFINITE); + logmsg("infmain emu proc terminated"); + emujob = NULL; + emugroup = 0; +#ifdef Jobs + logmsg("terminating job"); + TerminateJobObject(emu.job, 0); +#else + logmsg("notepg (%d)", emu.notepg); + if(emu.notepg) + GenerateConsoleCtrlEvent(CTRL_C_EVENT, emu.notepg); +#endif + if (cpt) { + /* copy() sees eof on emu.stdout and exits */ + WaitForSingleObject(cpt, INFINITE); + CloseHandle(cpt); + CloseHandle(emu.stdout); + } + CloseHandle(emu.proc); + if(emu.job != NULL) + CloseHandle(emu.job); + CloseHandle(emu.stdin); + // XXX should check to see that we're not starting up again too quickly, as + // it's quite possible to get into an infinite loop here. + // but what are good criteria? 5 times? 100 times? + // 10 times within a minute? + // for the moment, just sleep for a while before restarting... + if(shuttingdown) + break; + SleepEx(10000, FALSE); + } + logmsg("infmain done"); + if (logf) + CloseHandle(logf); + status.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(statush, &status); + return; +} + +void WINAPI +infctl(ulong op) +{ + if (op != SERVICE_CONTROL_STOP) + return; + + /* stop the service (status set by infmain() + * + * NOTE: there is a race for emujob - may have been closed + * after test, but before TerminateJobObject() + * MSDN is unclear as to whether TerminatJobObject() handles + * NULL job ptr - should probably use a mutex + */ + shuttingdown = 1; +#ifdef Jobs + logmsg("svc stop: stopping job"); + if (emujob) + TerminateJobObject(emujob, 0); +#else + logmsg("svc stop: interrupting emu"); + if (emugroup) + GenerateConsoleCtrlEvent(CTRL_C_EVENT, emugroup); +#endif +} + +void +printerror(char *s) +{ + char *msg; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| + FORMAT_MESSAGE_FROM_SYSTEM| + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&msg, + 0, + NULL); + fprint(2, "%s: %s\n", s, msg); + LocalFree(msg); +} + +int +add(char *name, char *root, char *cmds) +{ + char *path; + int r; + SC_HANDLE scm, scs; + char *nopt; + + nopt = nice ? " -n" : ""; + path = smprint("%s\\Nt\\386\\bin\\%s%s run %s %s %s", root, myname, nopt, name, root, cmds); + r = 0; + scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (scm == NULL) { + printerror("cannot open service control manager"); + return -1; + } + scs = CreateService(scm, + name, + name, + SERVICE_START|SERVICE_STOP, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_IGNORE, + path, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (scs == NULL) { + printerror("cannot create service"); + r = -1; + } else { + CloseServiceHandle(scs); + } + CloseServiceHandle(scm); + return r; +} + +int +del(char *name) +{ + SC_HANDLE scm, scs; + + scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (scm == NULL) { + printerror("cannot open service control manager"); + return -1; + } + + scs = OpenService(scm, name, DELETE); + if (scs == NULL) { + printerror("cannot open service"); + CloseServiceHandle(scm); + return -1; + } + if (!DeleteService(scs)) { + printerror("cannot delete Iservice"); + CloseServiceHandle(scs); + CloseServiceHandle(scm); + return -1; + } + CloseServiceHandle(scs); + CloseServiceHandle(scm); + return 0; +} + +HANDLE +openlog(char *p) +{ + HANDLE h; + h = CreateFile(p, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return NULL; + SetFilePointer(h, 0, NULL, FILE_END); + return h; +} + +void +logmsg(char *fmt, ...) +{ + int n; + char *p; + va_list args; + if(logf == 0) + return; + va_start(args, fmt); + p = vsmprint(fmt, args); + va_end(args); + n = strlen(p); + if (n) + WriteFile(logf, p, n, &n, NULL); + WriteFile(logf, "\n", 1, &n, NULL); +} + +Emu +runemu(char *cmd) +{ + Emu r = {NULL, NULL, NULL}; + STARTUPINFO si; + PROCESS_INFORMATION pinfo; + HANDLE job, emu, emut, stdin, stdout, stderr, emui, emuo; + SECURITY_ATTRIBUTES sec; + DWORD flags; + + job = emu = emut = stdin = stdout = stderr = emui = emuo = NULL; +#ifdef Jobs + job = CreateJobObject(NULL, NULL); + if (job == NULL) { + logmsg("cannot create job object: %r"); + goto error; + } +#endif + + /* set up pipes */ + sec.nLength = sizeof(sec); + sec.lpSecurityDescriptor = 0; + sec.bInheritHandle = 0; + if (!CreatePipe(&stdin, &emui, &sec, 0)) { + logmsg("cannot create stdin pipe: %r"); + goto error; + } + if (!CreatePipe(&emuo, &stdout, &sec, 0)) { + logmsg("cannot create stdout pipe: %r"); + goto error; + } + stdin = exporthandle(stdin, 1); + stdout = exporthandle(stdout, 1); + stderr = exporthandle(stdout, 0); + + /* create emu process (suspended) */ + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = stdin; + si.hStdOutput = stdout; + si.hStdError = stderr; + + flags = CREATE_NEW_PROCESS_GROUP|CREATE_DEFAULT_ERROR_MODE|CREATE_SUSPENDED; + if(nice) + flags |= IDLE_PRIORITY_CLASS; + if(!CreateProcess(0, cmd, 0, 0, 1, flags, 0, 0, &si, &pinfo)) { + logmsg("cannot create process: %r"); + goto error; + } + emu = pinfo.hProcess; + emut = pinfo.hThread; + CloseHandle(stdin); + stdin = NULL; + CloseHandle(stdout); + stdout = NULL; + CloseHandle(stderr); + stderr = NULL; + +#ifdef Jobs + if(!AssignProcessToJobObject(job, emu)) { + logmsg("failed to assign emu to job: %r"); + goto error; + } +#endif + ResumeThread(emut); + CloseHandle(emut); + + r.proc = emu; + r.notepg = pinfo.dwProcessId; + r.job = job; /* will be NULL if not implemented (NT4) */ + r.stdin = emui; + r.stdout = emuo; + return r; + +error: + if (stdin) + CloseHandle(stdin); + if (stdout) + CloseHandle(stdout); + if (stderr) + CloseHandle(stderr); + if (emui) + CloseHandle(emuin); + if (emuo) + CloseHandle(emuo); + if (emut) + CloseHandle(emut); + if (emu) { + TerminateProcess(emu, 0); + CloseHandle(emu); + } + if (job) + CloseHandle(job); + return r; +} + +HANDLE +exporthandle(HANDLE h, int close) +{ + HANDLE cp, dh; + DWORD flags = DUPLICATE_SAME_ACCESS; + if (close) + flags |= DUPLICATE_CLOSE_SOURCE; + cp = GetCurrentProcess(); + if (!DuplicateHandle(cp, h, cp, &dh, DUPLICATE_SAME_ACCESS, 1, flags)) + return nil; + return dh; +} + +DWORD WINAPI +copy(void *arg) +{ + Copyargs *cp = (Copyargs*)arg; + char buf[1024]; + DWORD n; + + while (ReadFile(cp->in, buf, sizeof(buf), &n, NULL)) { + if (n && cp->out) + WriteFile(cp->out, buf, n, &n, NULL); + } + return 0; +} + +void +main(int argc, char *argv[]) +{ + char *verb; + SERVICE_TABLE_ENTRY services[2]; + + memset(services, 0, sizeof(services)); + + ARGBEGIN{ + case 'n': + nice = 1; + break; + default: + usage(); + }ARGEND + + if (argc < 2) { + usage(); + return; + } + + verb = argv[0]; + name = argv[1]; + if (argc > 2) + root = argv[2]; + if (argc > 3) + cmds = proccmd(argv+3); + + if (strcmp(verb, "del") == 0) + exit(del(name)); + if (strcmp(verb, "add") == 0) { + if (root == NULL || cmds == NULL) { + usage(); + return; + } + exit(add(name, root, cmds)); + } + if (strcmp(verb, "run") == 0) { + if (root == NULL || cmds == NULL || *cmds == '\0') { + usage(); + return; + } + services[0].lpServiceName = name; + services[0].lpServiceProc = infmain; + StartServiceCtrlDispatcher(services); + exit(0); + } + usage(); +} diff --git a/utils/qa/Ins b/utils/qa/Ins new file mode 100644 index 00000000..d113e845 --- /dev/null +++ b/utils/qa/Ins @@ -0,0 +1,203 @@ +a OR XO(31,10) +abs OR XO(31,360) +ae OR XO(31,138) +ai 0 D(12) + + +ai. 0 D(13) +ame OR XO(31,234) +and R X(31,28) +andc R X(31,60) + +andil. 0 D(28,0) +andiu. 0 D(29,0) +aze OR XO(31,202) +cal 0 D(14) + +cau 0 D(15) +cax OR XO(31,266) +cmp 0 X(31,0) +cmpi 0 D(11) + +cmpl 0 X(31,32) +cmpli 0 D(10) +cntlz R X(31,26) +crand 0 XL(19,257) + +crandc 0 XL(19,129) +creqv 0 XL(19,289) +crnand 0 XL(19,225) +crnor 0 XL(19,33) + +cror 0 XL(19,449) +crorc 0 XL(19,417) +crxor 0 XL(19,193) +div OR XO(31,331) + +divs OR XO(31,331) +doz OR XO(31,264) +dozi 0 D(9) + +eqv R X(31,284) +exts R X(31,922) +fa R A(63,21) +fabs R X(63,264) +fcmpo 0 X(63,32) + +fcmpu 0 X(63,0) +fd R A(63,8) +fm R A(63,5) +fma R A(63,29) + +fmr R X(63,72) +fms R A(63,28) +fnabs R X(63,136) +fneg R X(63,40) + +fnma R A(63,31) +fnms R A(63,30) +frsp R X(63,12) +fs R A(63,20) + +l 0 D(32) +lbrx 0 X(31,534) +lbz 0 D(34) +lbzu 0 D(35) + +lbzux 0 X(31,119) +lbzx 0 X(31,87) +lfd 0 D(50) +lfdu 0 D(51) + +lfdux 0 X(31,631) +lfdx 0 X(31,599) +lfs 0 D(48) +lfsu 0 D(49) + +lfsux 0 X(31,567) +lfsx 0 X(31,535) +lha 0 D(42) +lhau 0 D(43) + +lhaux 0 X(31,375) +lhax 0 X(31,343) +lhbrx 0 X(31,790) +lhz 0 D(40) + +lhzu 0 D(41) +lhzux 0 X(31,311) +lhzx 0 X(31,279) +lm 0 D(46) + +lscbx R X(31,277) +lsi 0 X(31,597) +lsx 0 X(31,533) +lu 0 D(33) + +lux 0 X(31,55) +lx 0 X(31,23) +maskg R X(31,29) +maskir R X(31,541) + +mcrf 0 XL(19,0) +mcrfs 0 X(63,64) +mcrxr 0 X(31,512) +mfcr 0 X(31,19) + +mffs R X(63,583) +mfmsr 0 X(31,83) +mfspr 0 X(31,339) +mtcrf 0 XFX(31,144) + +mtfsb0 R X(63,70) +mtfsb1 R X(63,38) +mtfsf R XFL(63,711) +mtfsfi R X(63,134) + +mtspr 0 X(31,467) +mul OR XO(31,107) +muli 0 D(7) +muls OR XO(31,235) + +nabs OR XO(31,488) +nand R X(31,476) +neg OR XO(31,104) + +nor R X(31,124) +or R X(31,444) +orc R X(31,412) +oril 0 D(24) + +oriu 0 D(25) +rlmi R M(20) +rlinm R M(21) +rlmi R M(22) + +rlnm R M(23) +rrib R X(31,537) +sf OR XO(31,8) +sfe OR XO(31,36) + +sfi 0 D(8) +sfme OR XO(31,232) +sfze OR XO(31,200) +sl R X(31,24) + +sle R X(31,153) +sleq R X(31,217) +sliq R X(31,184) +slliq R X(31,248) + +sllq R X(31,216) +slq R X(31,152) +sr R X(31,536) +sra R X(31,792) + +srai R X(31,824) +sraiq R X(31,952) +sraq R X(31,920) +sre R X(31,665) + +srea R X(31,921) +sreq R X(31,729) +sriq R X(31,696) +srliq R X(31,760) +srlq R X(31,728) + +srq R X(31,664) +st 0 D(36) +stb 0 D(38) +stbrx 0 X(31,662) + +stbu 0 D(39) +stbux 0 X(31,247) +stbx 0 X(31,215) +stfd 0 D(54) + +stfdu 0 D(55) +stfdux 0 X(31,759) +stfdx 0 X(31,727) +stfs 0 D(52) + +stfsu 0 D(53) +stfsux 0 X(31,695) +stfsx 0 X(31,663) +sth 0 D(44) + +sthbrx 0 X(31,918) +sthu 0 D(45) +sthux 0 X(31,439) +sthx 0 X(3,407) + +stm 0 D(47) +stsi 0 X(31,725) +stsx 0 X(31,661) +stu 0 D(37) + +stux 0 X(31,183) +stx 0 X(31,151) +svc 0 SC(17) +t 0 X(31,4) +ti 0 D(3) +xor R X(31,316) +xoril 0 D(26) +xoriu 0 D(27) diff --git a/utils/qa/a.h b/utils/qa/a.h new file mode 100644 index 00000000..f7fce238 --- /dev/null +++ b/utils/qa/a.h @@ -0,0 +1,199 @@ +#include <lib9.h> +#include <bio.h> +#include "../qc/q.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#define MAXALIGN 7 +#define FPCHIP 1 +#define NSYMB 8192 +#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 + +#define ALLOC(lhs, type)\ + while(nhunk < sizeof(type))\ + gethunk();\ + lhs = (type*)hunk;\ + nhunk -= sizeof(type);\ + hunk += sizeof(type); + +#define ALLOCN(lhs, len, n)\ + if(lhs+len != hunk || nhunk < n) {\ + while(nhunk <= len)\ + gethunk();\ + memmove(hunk, lhs, len);\ + lhs = hunk;\ + hunk += len;\ + nhunk -= len;\ + }\ + hunk += n;\ + nhunk -= n; + +struct Sym +{ + Sym* link; + char* macro; + long value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym* sym; + long offset; + short type; + short reg; + short xreg; + short name; + ushort mask; + double dval; + char sval[8]; +}; + +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 nosched; +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 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 pinit(char*); +void cclean(void); +void outcode(int, Gen*, int, Gen*); +void outgcode(int, Gen*, int, Gen*, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, 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 outhist(void); +void linehist(char*, int); +void gethunk(void); +void yyerror(char*, ...); +int yyparse(void); +void setinclude(char*); +int assemble(char*); + +/* + * system-dependent stuff from ../cc/compat.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); diff --git a/utils/qa/a.y b/utils/qa/a.y new file mode 100644 index 00000000..3474ea0d --- /dev/null +++ b/utils/qa/a.y @@ -0,0 +1,974 @@ +%{ +#include "a.h" +%} +%union +{ + Sym *sym; + long lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP +%token <lval> LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW +%token <lval> LNOP LEND LRETT LWORD LTEXT LDATA LRETRN +%token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH +%token <lval> LREG LFREG LR LCR LF LFPSCR +%token <lval> LLR LCTR LSPR LSPREG LSEG LMSR +%token <lval> LSCHED LXLD LXST LXOP LXMV +%token <lval> LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr pointer offset sreg +%type <gen> addr rreg regaddr name creg freg xlreg lr ctr +%type <gen> imm ximm fimm rel psr lcr cbit fpscr fpscrf seg msr mask +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| LSCHED ';' + { + nosched = $1; + } +| ';' +| inst ';' +| error ';' + +inst: +/* + * load ints and bytes + */ + LMOVW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW regaddr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB regaddr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * load floats + */ +| LFMOV addr ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV regaddr ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV fimm ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV freg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LFMOV freg ',' regaddr + { + outcode($1, &$2, NREG, &$4); + } +/* + * store ints and bytes + */ +| LMOVW rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' regaddr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVB rreg ',' regaddr + { + outcode($1, &$2, NREG, &$4); + } +/* + * store floats + */ +| LMOVW freg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW freg ',' regaddr + { + outcode($1, &$2, NREG, &$4); + } +/* + * floating point status + */ +| LMOVW fpscr ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW freg ',' fpscr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW freg ',' imm ',' fpscr + { + outgcode($1, &$2, NREG, &$4, &$6); + } +| LMOVW fpscr ',' creg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW imm ',' fpscrf + { + outcode($1, &$2, NREG, &$4); + } +| LMTFSB imm ',' con + { + outcode($1, &$2, $4, &nullgen); + } +/* + * field moves (mtcrf) + */ +| LMOVW rreg ',' imm ',' lcr + { + outgcode($1, &$2, NREG, &$4, &$6); + } +| LMOVW rreg ',' creg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' lcr + { + outcode($1, &$2, NREG, &$4); + } +/* + * integer operations + * logical instructions + * shift instructions + * unary instructions + */ +| LADDW rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LADDW imm ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LADDW rreg ',' imm ',' rreg + { + outgcode($1, &$2, NREG, &$4, &$6); + } +| LADDW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LADDW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LLOGW rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LLOGW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LSHW rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LSHW rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LSHW imm ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +| LSHW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LABS rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LABS rreg + { + outcode($1, &$2, NREG, &$2); + } +/* + * multiply-accumulate + */ +| LMA rreg ',' sreg ',' rreg + { + outcode($1, &$2, $4, &$6); + } +/* + * move immediate: macro for cau+or, addi, addis, and other combinations + */ +| LMOVW imm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW ximm ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +/* + * condition register operations + */ +| LCROP cbit ',' cbit + { + outcode($1, &$2, $4.reg, &$4); + } +| LCROP cbit ',' con ',' cbit + { + outcode($1, &$2, $4, &$6); + } +/* + * condition register moves + * move from machine state register + */ +| LMOVW creg ',' creg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW psr ',' creg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW lcr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW psr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW seg ',' rreg + { + int r; + r = $2.offset; + $2.offset = 0; + outcode($1, &$2, r, &$4); + } +| LMOVW rreg ',' seg + { + int r; + r = $4.offset; + $4.offset = 0; + outcode($1, &$2, r, &$4); + } +| LMOVW xlreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' xlreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW creg ',' psr + { + outcode($1, &$2, NREG, &$4); + } +| LMOVW rreg ',' psr + { + outcode($1, &$2, NREG, &$4); + } +/* + * branch, branch conditional + * branch conditional register + * branch conditional to count register + */ +| LBRA rel + { + outcode($1, &nullgen, NREG, &$2); + } +| LBRA addr + { + outcode($1, &nullgen, NREG, &$2); + } +| LBRA '(' xlreg ')' + { + outcode($1, &nullgen, NREG, &$3); + } +| LBRA ',' rel + { + outcode($1, &nullgen, NREG, &$3); + } +| LBRA ',' addr + { + outcode($1, &nullgen, NREG, &$3); + } +| LBRA ',' '(' xlreg ')' + { + outcode($1, &nullgen, NREG, &$4); + } +| LBRA creg ',' rel + { + outcode($1, &$2, NREG, &$4); + } +| LBRA creg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +| LBRA creg ',' '(' xlreg ')' + { + outcode($1, &$2, NREG, &$5); + } +| LBRA con ',' rel + { + outcode($1, &nullgen, $2, &$4); + } +| LBRA con ',' addr + { + outcode($1, &nullgen, $2, &$4); + } +| LBRA con ',' '(' xlreg ')' + { + outcode($1, &nullgen, $2, &$5); + } +| LBRA con ',' con ',' rel + { + Gen g; + g = nullgen; + g.type = D_CONST; + g.offset = $2; + outcode($1, &g, $4, &$6); + } +| LBRA con ',' con ',' addr + { + Gen g; + g = nullgen; + g.type = D_CONST; + g.offset = $2; + outcode($1, &g, $4, &$6); + } +| LBRA con ',' con ',' '(' xlreg ')' + { + Gen g; + g = nullgen; + g.type = D_CONST; + g.offset = $2; + outcode($1, &g, $4, &$7); + } +/* + * conditional trap + */ +| LTRAP rreg ',' sreg + { + outcode($1, &$2, $4, &nullgen); + } +| LTRAP imm ',' sreg + { + outcode($1, &$2, $4, &nullgen); + } +| LTRAP rreg comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LTRAP comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +/* + * floating point operate + */ +| LFCONV freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFADD freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFADD freg ',' freg ',' freg + { + outcode($1, &$2, $4.reg, &$6); + } +| LFMA freg ',' freg ',' freg ',' freg + { + outgcode($1, &$2, $4.reg, &$6, &$8); + } +| LFCMP freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LFCMP freg ',' freg ',' creg + { + outcode($1, &$2, $6.reg, &$4); + } +/* + * CMP + */ +| LCMP rreg ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LCMP rreg ',' imm + { + outcode($1, &$2, NREG, &$4); + } +| LCMP rreg ',' rreg ',' creg + { + outcode($1, &$2, $6.reg, &$4); + } +| LCMP rreg ',' imm ',' creg + { + outcode($1, &$2, $6.reg, &$4); + } +/* + * rotate and mask + */ +| LRLWM imm ',' rreg ',' imm ',' rreg + { + outgcode($1, &$2, $4.reg, &$6, &$8); + } +| LRLWM imm ',' rreg ',' mask ',' rreg + { + outgcode($1, &$2, $4.reg, &$6, &$8); + } +| LRLWM rreg ',' rreg ',' imm ',' rreg + { + outgcode($1, &$2, $4.reg, &$6, &$8); + } +| LRLWM rreg ',' rreg ',' mask ',' rreg + { + outgcode($1, &$2, $4.reg, &$6, &$8); + } +/* + * load/store multiple + */ +| LMOVMW addr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LMOVMW rreg ',' addr + { + outcode($1, &$2, NREG, &$4); + } +/* + * various indexed load/store + * indexed unary (eg, cache clear) + */ +| LXLD regaddr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LXLD regaddr ',' imm ',' rreg + { + outgcode($1, &$2, NREG, &$4, &$6); + } +| LXST rreg ',' regaddr + { + outcode($1, &$2, NREG, &$4); + } +| LXST rreg ',' imm ',' regaddr + { + outgcode($1, &$2, NREG, &$4, &$6); + } +| LXMV regaddr ',' rreg + { + outcode($1, &$2, NREG, &$4); + } +| LXMV rreg ',' regaddr + { + outcode($1, &$2, NREG, &$4); + } +| LXOP regaddr + { + outcode($1, &$2, NREG, &nullgen); + } +/* + * NOP + */ +| LNOP comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LNOP rreg comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LNOP freg comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LNOP ',' rreg + { + outcode($1, &nullgen, NREG, &$3); + } +| LNOP ',' freg + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * word + */ +| LWORD imm comma + { + outcode($1, &$2, NREG, &nullgen); + } +| LWORD ximm comma + { + outcode($1, &$2, NREG, &nullgen); + } +/* + * END + */ +| LEND comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +/* + * TEXT/GLOBL + */ +| LTEXT name ',' imm + { + outcode($1, &$2, NREG, &$4); + } +| LTEXT name ',' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +| LTEXT name ',' imm ':' imm + { + outgcode($1, &$2, NREG, &$6, &$4); + } +| LTEXT name ',' con ',' imm ':' imm + { + outgcode($1, &$2, $4, &$8, &$6); + } +/* + * DATA + */ +| LDATA name '/' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +| LDATA name '/' con ',' ximm + { + outcode($1, &$2, $4, &$6); + } +| LDATA name '/' con ',' fimm + { + outcode($1, &$2, $4, &$6); + } +/* + * RETURN + */ +| LRETRN comma + { + outcode($1, &nullgen, NREG, &nullgen); + } + +rel: + con '(' LPC ')' + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.offset = $1 + pc; + } +| LNAME offset + { + $$ = nullgen; + if(pass == 2) + yyerror("undefined label: %s", $1->name); + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $2; + } +| LLAB offset + { + $$ = nullgen; + $$.type = D_BRANCH; + $$.sym = $1; + $$.offset = $1->value + $2; + } + +rreg: + sreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +xlreg: + lr +| ctr + +lr: + LLR + { + $$ = nullgen; + $$.type = D_SPR; + $$.offset = $1; + } + +lcr: + LCR + { + $$ = nullgen; + $$.type = D_CREG; + $$.reg = NREG; /* whole register */ + } + +ctr: + LCTR + { + $$ = nullgen; + $$.type = D_SPR; + $$.offset = $1; + } + +msr: + LMSR + { + $$ = nullgen; + $$.type = D_MSR; + } + +psr: + LSPREG + { + $$ = nullgen; + $$.type = D_SPR; + $$.offset = $1; + } +| LSPR '(' con ')' + { + $$ = nullgen; + $$.type = $1; + $$.offset = $3; + } +| msr + +seg: + LSEG '(' con ')' + { + if($3 < 0 || $3 > 15) + yyerror("segment register number out of range"); + $$ = nullgen; + $$.type = D_SREG; + $$.reg = $3; + $$.offset = NREG; + } +| LSEG '(' sreg ')' + { + $$ = nullgen; + $$.type = D_SREG; + $$.reg = NREG; + $$.offset = $3; + } + +fpscr: + LFPSCR + { + $$ = nullgen; + $$.type = D_FPSCR; + $$.reg = NREG; + } + +fpscrf: + LFPSCR '(' con ')' + { + $$ = nullgen; + $$.type = D_FPSCR; + $$.reg = $3; + } + +freg: + LFREG + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } +| LF '(' con ')' + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $3; + } + +creg: + LCREG + { + $$ = nullgen; + $$.type = D_CREG; + $$.reg = $1; + } +| LCR '(' con ')' + { + $$ = nullgen; + $$.type = D_CREG; + $$.reg = $3; + } + + +cbit: con + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +mask: + con ',' con + { + int mb, me; + ulong v; + + $$ = nullgen; + $$.type = D_CONST; + mb = $1; + me = $3; + if(mb < 0 || mb > 31 || me < 0 || me > 31){ + yyerror("illegal mask start/end value(s)"); + mb = me = 0; + } + if(mb <= me) + v = ((ulong)~0L>>mb) & (~0L<<(31-me)); + else + v = ~(((ulong)~0L>>(me+1)) & (~0L<<(31-(mb-1)))); + $$.offset = v; + } + +ximm: + '$' addr + { + $$ = $2; + $$.type = D_CONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } + +fimm: + '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +imm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } + +sreg: + LREG +| LR '(' con ')' + { + if($$ < 0 || $$ >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +regaddr: + '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } +| '(' sreg '+' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.xreg = $4; + $$.offset = 0; + } + +addr: + name +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +comma: +| ',' + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/qa/branch b/utils/qa/branch new file mode 100644 index 00000000..8092a2c5 --- /dev/null +++ b/utils/qa/branch @@ -0,0 +1,37 @@ +BO operand encodings + +0+y 0000y decrement CTR, then branch if CTR != 0 && condition is false +2+y 0001y decrement CTR, then branch if CTR == 0 && condition is false +4+y 0010y branch if condition is false +8+y 0100y decrement CTR, then branch if CTR != 0 && condition is true +10+y 0101y decrement CTR, then branch if CTR == 0 && condition is true +12+y 0110y branch if condition is true +16+y 1000y decrement CTR, then branch if CTR != 0 +18+y 1001y decrement CTR, then branch if CTR == 0 +20 10100 branch always + +y=0: + BCx with negative displacement: branch probably taken + all other cases: branch not taken + +y=1: + reverse prediction + +predict to be taken if + ((BO[0] & BO[2]) | sign(displacement)) xor y + +CR field bit: + +lt 0 +gt 1 +eq 2 +so 3 +un 3 (after fp comparison) + +CR fields: + +cr0 0 +cr1 4 +cr2 8 +... +cr7 28 diff --git a/utils/qa/lex.c b/utils/qa/lex.c new file mode 100644 index 00000000..228ec4e1 --- /dev/null +++ b/utils/qa/lex.c @@ -0,0 +1,856 @@ +#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 = 'q'; + thestring = "power"; + 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) { + 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); + if(p = strrchr(ofile, pathchar())) { + include[0] = ofile; + *p++ = 0; + } else + p = ofile; + if(outfile == 0) { + outfile = p; + if(p = strrchr(outfile, '.')) + if(p[1] == 's' && p[2] == 0) + p[0] = 0; + p = strrchr(outfile, 0); + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } + 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; + nosched = 0; + pinit(file); + for(i=0; i<nDlist; i++) + dodefine(Dlist[i]); + yyparse(); + if(nerrors) { + cclean(); + return nerrors; + } + + pass = 2; + nosched = 0; + 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, + + "LR", LLR, D_LR, + "CTR", LCTR, D_CTR, + + "XER", LSPREG, D_XER, + "MSR", LMSR, D_MSR, + "FPSCR", LFPSCR, D_FPSCR, + "SPR", LSPR, D_SPR, + "DCR", LSPR, D_DCR, + + "SEG", LSEG, D_SREG, + + "CR", LCR, 0, + "CR0", LCREG, 0, + "CR1", LCREG, 1, + "CR2", LCREG, 2, + "CR3", LCREG, 3, + "CR4", LCREG, 4, + "CR5", LCREG, 5, + "CR6", LCREG, 6, + "CR7", LCREG, 7, + + "R", LR, 0, + "R0", LREG, 0, + "R1", LREG, 1, + "R2", LREG, 2, + "R3", LREG, 3, + "R4", LREG, 4, + "R5", LREG, 5, + "R6", LREG, 6, + "R7", LREG, 7, + "R8", LREG, 8, + "R9", LREG, 9, + "R10", LREG, 10, + "R11", LREG, 11, + "R12", LREG, 12, + "R13", LREG, 13, + "R14", LREG, 14, + "R15", LREG, 15, + "R16", LREG, 16, + "R17", LREG, 17, + "R18", LREG, 18, + "R19", LREG, 19, + "R20", LREG, 20, + "R21", LREG, 21, + "R22", LREG, 22, + "R23", LREG, 23, + "R24", LREG, 24, + "R25", LREG, 25, + "R26", LREG, 26, + "R27", LREG, 27, + "R28", LREG, 28, + "R29", LREG, 29, + "R30", LREG, 30, + "R31", LREG, 31, + + "F", LF, 0, + "F0", LFREG, 0, + "F1", LFREG, 1, + "F2", LFREG, 2, + "F3", LFREG, 3, + "F4", LFREG, 4, + "F5", LFREG, 5, + "F6", LFREG, 6, + "F7", LFREG, 7, + "F8", LFREG, 8, + "F9", LFREG, 9, + "F10", LFREG, 10, + "F11", LFREG, 11, + "F12", LFREG, 12, + "F13", LFREG, 13, + "F14", LFREG, 14, + "F15", LFREG, 15, + "F16", LFREG, 16, + "F17", LFREG, 17, + "F18", LFREG, 18, + "F19", LFREG, 19, + "F20", LFREG, 20, + "F21", LFREG, 21, + "F22", LFREG, 22, + "F23", LFREG, 23, + "F24", LFREG, 24, + "F25", LFREG, 25, + "F26", LFREG, 26, + "F27", LFREG, 27, + "F28", LFREG, 28, + "F29", LFREG, 29, + "F30", LFREG, 30, + "F31", LFREG, 31, + + "CREQV", LCROP, ACREQV, + "CRXOR", LCROP, ACRXOR, + "CRAND", LCROP, ACRAND, + "CROR", LCROP, ACROR, + "CRANDN", LCROP, ACRANDN, + "CRORN", LCROP, ACRORN, + "CRNAND", LCROP, ACRNAND, + "CRNOR", LCROP, ACRNOR, + + "ADD", LADDW, AADD, + "ADDV", LADDW, AADDV, + "ADDCC", LADDW, AADDCC, + "ADDVCC", LADDW, AADDVCC, + "ADDC", LADDW, AADDC, + "ADDCV", LADDW, AADDCV, + "ADDCCC", LADDW, AADDCCC, + "ADDCVCC", LADDW, AADDCVCC, + "ADDE", LLOGW, AADDE, + "ADDEV", LLOGW, AADDEV, + "ADDECC", LLOGW, AADDECC, + "ADDEVCC", LLOGW, AADDEVCC, + + "ADDME", LABS, AADDME, + "ADDMEV", LABS, AADDMEV, + "ADDMECC", LABS, AADDMECC, + "ADDMEVCC", LABS, AADDMEVCC, + "ADDZE", LABS, AADDZE, + "ADDZEV", LABS, AADDZEV, + "ADDZECC", LABS, AADDZECC, + "ADDZEVCC", LABS, AADDZEVCC, + + "SUB", LADDW, ASUB, + "SUBV", LADDW, ASUBV, + "SUBCC", LADDW, ASUBCC, + "SUBVCC", LADDW, ASUBVCC, + "SUBE", LLOGW, ASUBE, + "SUBECC", LLOGW, ASUBECC, + "SUBEV", LLOGW, ASUBEV, + "SUBEVCC", LLOGW, ASUBEVCC, + "SUBC", LADDW, ASUBC, + "SUBCCC", LADDW, ASUBCCC, + "SUBCV", LADDW, ASUBCV, + "SUBCVCC", LADDW, ASUBCVCC, + + "SUBME", LABS, ASUBME, + "SUBMEV", LABS, ASUBMEV, + "SUBMECC", LABS, ASUBMECC, + "SUBMEVCC", LABS, ASUBMEVCC, + "SUBZE", LABS, ASUBZE, + "SUBZEV", LABS, ASUBZEV, + "SUBZECC", LABS, ASUBZECC, + "SUBZEVCC", LABS, ASUBZEVCC, + + "AND", LADDW, AAND, + "ANDCC", LADDW, AANDCC, /* includes andil & andiu */ + "ANDN", LLOGW, AANDN, + "ANDNCC", LLOGW, AANDNCC, + "EQV", LLOGW, AEQV, + "EQVCC", LLOGW, AEQVCC, + "NAND", LLOGW, ANAND, + "NANDCC", LLOGW, ANANDCC, + "NOR", LLOGW, ANOR, + "NORCC", LLOGW, ANORCC, + "OR", LADDW, AOR, /* includes oril & oriu */ + "ORCC", LADDW, AORCC, + "ORN", LLOGW, AORN, + "ORNCC", LLOGW, AORNCC, + "XOR", LADDW, AXOR, /* includes xoril & xoriu */ + "XORCC", LLOGW, AXORCC, + + "EXTSB", LABS, AEXTSB, + "EXTSBCC", LABS, AEXTSBCC, + "EXTSH", LABS, AEXTSH, + "EXTSHCC", LABS, AEXTSHCC, + + "CNTLZW", LABS, ACNTLZW, + "CNTLZWCC", LABS, ACNTLZWCC, + + "RLWMI", LRLWM, ARLWMI, + "RLWMICC", LRLWM, ARLWMICC, + "RLWNM", LRLWM, ARLWNM, + "RLWNMCC", LRLWM, ARLWNMCC, + + "SLW", LSHW, ASLW, + "SLWCC", LSHW, ASLWCC, + "SRW", LSHW, ASRW, + "SRWCC", LSHW, ASRWCC, + "SRAW", LSHW, ASRAW, + "SRAWCC", LSHW, ASRAWCC, + + "BR", LBRA, ABR, + "BC", LBRA, ABC, + "BCL", LBRA, ABC, + "BL", LBRA, ABL, + "BEQ", LBRA, ABEQ, + "BNE", LBRA, ABNE, + "BGT", LBRA, ABGT, + "BGE", LBRA, ABGE, + "BLT", LBRA, ABLT, + "BLE", LBRA, ABLE, + "BVC", LBRA, ABVC, + "BVS", LBRA, ABVS, + + "CMP", LCMP, ACMP, + "CMPU", LCMP, ACMPU, + + "DIVW", LLOGW, ADIVW, + "DIVWV", LLOGW, ADIVWV, + "DIVWCC", LLOGW, ADIVWCC, + "DIVWVCC", LLOGW, ADIVWVCC, + "DIVWU", LLOGW, ADIVWU, + "DIVWUV", LLOGW, ADIVWUV, + "DIVWUCC", LLOGW, ADIVWUCC, + "DIVWUVCC", LLOGW, ADIVWUVCC, + + "FABS", LFCONV, AFABS, + "FABSCC", LFCONV, AFABSCC, + "FNEG", LFCONV, AFNEG, + "FNEGCC", LFCONV, AFNEGCC, + "FNABS", LFCONV, AFNABS, + "FNABSCC", LFCONV, AFNABSCC, + + "FADD", LFADD, AFADD, + "FADDCC", LFADD, AFADDCC, + "FSUB", LFADD, AFSUB, + "FSUBCC", LFADD, AFSUBCC, + "FMUL", LFADD, AFMUL, + "FMULCC", LFADD, AFMULCC, + "FDIV", LFADD, AFDIV, + "FDIVCC", LFADD, AFDIVCC, + "FRSP", LFCONV, AFRSP, + "FRSPCC", LFCONV, AFRSPCC, + + "FMADD", LFMA, AFMADD, + "FMADDCC", LFMA, AFMADDCC, + "FMSUB", LFMA, AFMSUB, + "FMSUBCC", LFMA, AFMSUBCC, + "FNMADD", LFMA, AFNMADD, + "FNMADDCC", LFMA, AFNMADDCC, + "FNMSUB", LFMA, AFNMSUB, + "FNMSUBCC", LFMA, AFNMSUBCC, + "FMADDS", LFMA, AFMADDS, + "FMADDSCC", LFMA, AFMADDSCC, + "FMSUBS", LFMA, AFMSUBS, + "FMSUBSCC", LFMA, AFMSUBSCC, + "FNMADDS", LFMA, AFNMADDS, + "FNMADDSCC", LFMA, AFNMADDSCC, + "FNMSUBS", LFMA, AFNMSUBS, + "FNMSUBSCC", LFMA, AFNMSUBSCC, + + "FCMPU", LFCMP, AFCMPU, + "FCMPO", LFCMP, AFCMPO, + "MTFSB0", LMTFSB, AMTFSB0, + "MTFSB1", LMTFSB, AMTFSB1, + + "FMOVD", LFMOV, AFMOVD, + "FMOVS", LFMOV, AFMOVS, + "FMOVDCC", LFCONV, AFMOVDCC, /* fmr. */ + + "GLOBL", LTEXT, AGLOBL, + + "MOVB", LMOVB, AMOVB, + "MOVBZ", LMOVB, AMOVBZ, + "MOVBU", LMOVB, AMOVBU, + "MOVBZU", LMOVB, AMOVBZU, + "MOVH", LMOVB, AMOVH, + "MOVHZ", LMOVB, AMOVHZ, + "MOVHU", LMOVB, AMOVHU, + "MOVHZU", LMOVB, AMOVHZU, + "MOVHBR", LXMV, AMOVHBR, + "MOVWBR", LXMV, AMOVWBR, + "MOVW", LMOVW, AMOVW, + "MOVWU", LMOVW, AMOVWU, + "MOVMW", LMOVMW, AMOVMW, + "MOVFL", LMOVW, AMOVFL, + + "MULLW", LADDW, AMULLW, /* includes multiply immediate 10-139 */ + "MULLWV", LLOGW, AMULLWV, + "MULLWCC", LLOGW, AMULLWCC, + "MULLWVCC", LLOGW, AMULLWVCC, + + "MULHW", LLOGW, AMULHW, + "MULHWCC", LLOGW, AMULHWCC, + "MULHWU", LLOGW, AMULHWU, + "MULHWUCC", LLOGW, AMULHWUCC, + + "NEG", LABS, ANEG, + "NEGV", LABS, ANEGV, + "NEGCC", LABS, ANEGCC, + "NEGVCC", LABS, ANEGVCC, + + "NOP", LNOP, ANOP, /* ori 0,0,0 */ + "SYSCALL", LNOP, ASYSCALL, + + "RETURN", LRETRN, ARETURN, + "RFI", LRETRN, ARFI, + "RFCI", LRETRN, ARFCI, + + "DATA", LDATA, ADATA, + "END", LEND, AEND, + "TEXT", LTEXT, ATEXT, + + /* IBM powerpc embedded */ + "MACCHW", LMA, AMACCHW, + "MACCHWCC", LMA, AMACCHWCC, + "MACCHWS", LMA, AMACCHWS, + "MACCHWSCC", LMA, AMACCHWSCC, + "MACCHWSU", LMA, AMACCHWSU, + "MACCHWSUCC", LMA, AMACCHWSUCC, + "MACCHWSUV", LMA, AMACCHWSUV, + "MACCHWSUVCC", LMA, AMACCHWSUVCC, + "MACCHWSV", LMA, AMACCHWSV, + "MACCHWSVCC", LMA, AMACCHWSVCC, + "MACCHWU", LMA, AMACCHWU, + "MACCHWUCC", LMA, AMACCHWUCC, + "MACCHWUV", LMA, AMACCHWUV, + "MACCHWUVCC", LMA, AMACCHWUVCC, + "MACCHWV", LMA, AMACCHWV, + "MACCHWVCC", LMA, AMACCHWVCC, + "MACHHW", LMA, AMACHHW, + "MACHHWCC", LMA, AMACHHWCC, + "MACHHWS", LMA, AMACHHWS, + "MACHHWSCC", LMA, AMACHHWSCC, + "MACHHWSU", LMA, AMACHHWSU, + "MACHHWSUCC", LMA, AMACHHWSUCC, + "MACHHWSUV", LMA, AMACHHWSUV, + "MACHHWSUVCC", LMA, AMACHHWSUVCC, + "MACHHWSV", LMA, AMACHHWSV, + "MACHHWSVCC", LMA, AMACHHWSVCC, + "MACHHWU", LMA, AMACHHWU, + "MACHHWUCC", LMA, AMACHHWUCC, + "MACHHWUV", LMA, AMACHHWUV, + "MACHHWUVCC", LMA, AMACHHWUVCC, + "MACHHWV", LMA, AMACHHWV, + "MACHHWVCC", LMA, AMACHHWVCC, + "MACLHW", LMA, AMACLHW, + "MACLHWCC", LMA, AMACLHWCC, + "MACLHWS", LMA, AMACLHWS, + "MACLHWSCC", LMA, AMACLHWSCC, + "MACLHWSU", LMA, AMACLHWSU, + "MACLHWSUCC", LMA, AMACLHWSUCC, + "MACLHWSUV", LMA, AMACLHWSUV, + "MACLHWSUVCC", LMA, AMACLHWSUVCC, + "MACLHWSV", LMA, AMACLHWSV, + "MACLHWSVCC", LMA, AMACLHWSVCC, + "MACLHWU", LMA, AMACLHWU, + "MACLHWUCC", LMA, AMACLHWUCC, + "MACLHWUV", LMA, AMACLHWUV, + "MACLHWUVCC", LMA, AMACLHWUVCC, + "MACLHWV", LMA, AMACLHWV, + "MACLHWVCC", LMA, AMACLHWVCC, + "MULCHW", LLOGW, AMULCHW, + "MULCHWCC", LLOGW, AMULCHWCC, + "MULCHWU", LLOGW, AMULCHWU, + "MULCHWUCC", LLOGW, AMULCHWUCC, + "MULHHW", LLOGW, AMULHHW, + "MULHHWCC", LLOGW, AMULHHWCC, + "MULHHWU", LLOGW, AMULHHWU, + "MULHHWUCC", LLOGW, AMULHHWUCC, + "MULLHW", LLOGW, AMULLHW, + "MULLHWCC", LLOGW, AMULLHWCC, + "MULLHWU", LLOGW, AMULLHWU, + "MULLHWUCC", LLOGW, AMULLHWUCC, + "NMACCHW", LMA, ANMACCHW, + "NMACCHWCC", LMA, ANMACCHWCC, + "NMACCHWS", LMA, ANMACCHWS, + "NMACCHWSCC", LMA, ANMACCHWSCC, + "NMACCHWSV", LMA, ANMACCHWSV, + "NMACCHWSVCC", LMA, ANMACCHWSVCC, + "NMACCHWV", LMA, ANMACCHWV, + "NMACCHWVCC", LMA, ANMACCHWVCC, + "NMACHHW", LMA, ANMACHHW, + "NMACHHWCC", LMA, ANMACHHWCC, + "NMACHHWS", LMA, ANMACHHWS, + "NMACHHWSCC", LMA, ANMACHHWSCC, + "NMACHHWSV", LMA, ANMACHHWSV, + "NMACHHWSVCC", LMA, ANMACHHWSVCC, + "NMACHHWV", LMA, ANMACHHWV, + "NMACHHWVCC", LMA, ANMACHHWVCC, + "NMACLHW", LMA, ANMACLHW, + "NMACLHWCC", LMA, ANMACLHWCC, + "NMACLHWS", LMA, ANMACLHWS, + "NMACLHWSCC", LMA, ANMACLHWSCC, + "NMACLHWSV", LMA, ANMACLHWSV, + "NMACLHWSVCC", LMA, ANMACLHWSVCC, + "NMACLHWV", LMA, ANMACLHWV, + "NMACLHWVCC", LMA, ANMACLHWVCC, + +/* special instructions */ + "DCBF", LXOP, ADCBF, + "DCBI", LXOP, ADCBI, + "DCBST", LXOP, ADCBST, + "DCBT", LXOP, ADCBT, + "DCBTST", LXOP, ADCBTST, + "DCBZ", LXOP, ADCBZ, + "ICBI", LXOP, AICBI, + + "ECIWX", LXLD, AECIWX, + "ECOWX", LXST, AECOWX, + "LWAR", LXLD, ALWAR, + "STWCCC", LXST, ASTWCCC, + "EIEIO", LRETRN, AEIEIO, + "TLBIE", LNOP, ATLBIE, + "LSW", LXLD, ALSW, + "STSW", LXST, ASTSW, + + "ISYNC", LRETRN, AISYNC, + "SYNC", LRETRN, ASYNC, +/* "TW", LADDW, ATW,*/ + + "WORD", LWORD, AWORD, + "SCHED", LSCHED, 0, + "NOSCHED", LSCHED, 0x80, + + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.sym = S; + nullgen.offset = 0; + nullgen.type = D_NONE; + nullgen.name = D_NONE; + nullgen.reg = NREG; + nullgen.xreg = NREG; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 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); + s->type = itab[i].type; + s->value = itab[i].value; + } + ALLOCN(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + ALLOCN(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } +} + +void +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +void +cclean(void) +{ + + outcode(AEND, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + 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; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + case D_CREG: + case D_FPSCR: + case D_MSR: + case D_SREG: + case D_OPT: + break; + + case D_SPR: + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(&obuf, *n); + n++; + } + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +int +outsim(Gen *g) +{ + Sym *s; + int sno, t; + + s = g->sym; + if(s == S) + return 0; + sno = s->sym; + if(sno < 0 || sno >= NSYM) + sno = 0; + t = g->name; + if(h[sno].type == t && h[sno].sym == s) + return sno; + zname(s->name, t, sym); + s->sym = sym; + h[sym].sym = s; + h[sym].type = t; + sno = sym; + sym++; + if(sym >= NSYM) + sym = 1; + return sno; +} + +void +outcode(int a, Gen *g1, int reg, Gen *g2) +{ + int sf, st; + + if(a != AGLOBL && a != ADATA) + pc++; + if(pass == 1) + return; + if(g1->xreg != NREG) { + if(reg != NREG || g2->xreg != NREG) + yyerror("bad addressing modes"); + reg = g1->xreg; + } else + if(g2->xreg != NREG) { + if(reg != NREG) + yyerror("bad addressing modes"); + reg = g2->xreg; + } + do { + sf = outsim(g1); + st = outsim(g2); + } while(sf != 0 && st == sf); + Bputc(&obuf, a); + Bputc(&obuf, reg|nosched); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, sf); + zaddr(g2, st); +} + +void +outgcode(int a, Gen *g1, int reg, Gen *g2, Gen *g3) +{ + int s1, s2, s3, flag; + + if(a != AGLOBL && a != ADATA) + pc++; + if(pass == 1) + return; + do { + s1 = outsim(g1); + s2 = outsim(g2); + s3 = outsim(g3); + } while(s1 && (s2 && s1 == s2 || s3 && s1 == s3) || s2 && (s3 && s2 == s3)); + flag = 0; + if(g2->type != D_NONE) + flag = 0x40; /* flags extra operand */ + Bputc(&obuf, a); + Bputc(&obuf, reg | nosched | flag); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, s1); + if(flag) + zaddr(g2, s2); + zaddr(g3, s3); +} + +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, 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, 0); + 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" diff --git a/utils/qa/mkfile b/utils/qa/mkfile new file mode 100644 index 00000000..255701f8 --- /dev/null +++ b/utils/qa/mkfile @@ -0,0 +1,29 @@ +<../../mkconfig + +TARG=qa +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../qc/q.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/qc/cgen.c b/utils/qc/cgen.c new file mode 100644 index 00000000..8323466c --- /dev/null +++ b/utils/qc/cgen.c @@ -0,0 +1,1091 @@ +#include "gc.h" + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o; + long v, curs; + + 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(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED) { + if(nn != Z || r->addable < INDEXED) { + regalloc(&nod, r, nn); + cgen(r, &nod); + gmove(&nod, l); + regfree(&nod); + } else + gmove(r, l); + break; + } + if(l->complex >= r->complex) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OXOR: + if(nn != Z) + if(r->op == OCONST && r->vconst == -1){ + cgen(l, nn); + gopcode(OCOM, nn, Z, nn); + break; + } + + case OADD: + case OSUB: + case OAND: + case OOR: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(l, nn); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OMUL: + case OLMUL: + case OLDIV: + case OLMOD: + case ODIV: + case OMOD: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + if(debug['M']) + print("%L multiply\n", n->lineno); + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, &nod1, Z, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(r->op == OCONST) + if(!typefd[r->type->etype]) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, n, nn); + cgen(r, &nod); + } else { + regalloc(&nod, n, nn); + cgen(r, &nod); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + regalloc(&nod1, n, Z); + gopcode(OAS, &nod2, Z, &nod1); + gopcode(o, &nod, &nod1, &nod); + gopcode(OAS, &nod, Z, &nod2); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + asbitop: + regalloc(&nod4, n, nn); + regalloc(&nod3, r, Z); + if(l->complex >= r->complex) { + bitload(l, &nod, &nod1, &nod2, &nod4); + cgen(r, &nod3); + } else { + cgen(r, &nod3); + bitload(l, &nod, &nod1, &nod2, &nod4); + } + gmove(&nod, &nod4); + gopcode(n->op, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + break; + + case OIND: + if(nn == Z) { + cgen(l, nn); + break; + } + regialloc(&nod, n, nn); + r = l; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { + /* both null, gen l->nn */ + cgen(l, nn); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (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(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + 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; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + 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(n->op == OCONST) { + o = vconst(n); + if(!true) + o = !o; + gbranch(OGOTO); + if(o) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + } + regalloc(&nod, n, nn); + cgen(n, &nod); + o = ONE; + if(true) + o = comrel[relindex(o)]; + if(typefd[n->type->etype]) { + nodreg(&nod1, n, NREG+FREGZERO); + gopcode(o, &nod, Z, &nod1); + } else + gopcode(o, &nod, Z, nodconst(0)); + regfree(&nod); + goto com; + + case OCOMMA: + cgen(l, Z); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(sconst(r)) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod, Z, r); + regfree(&nod); + goto com; + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + gopcode(o, &nod1, Z, &nod); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1L), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0L), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + nod1.xoffset += SZ_LONG; + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + + regfree(&nod1); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no side effects + */ + if(nn != Z && side(nn)) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regalloc(&nod2, &nod1, Z); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + /* prtree(&nod0, "hand craft"); /* */ + cgen(&nod0, Z); + } + break; + + case OAS: + if(nn == Z) { + if(n->addable < INDEXED) + sugen(n->right, n->left, w); + break; + } + /* BOTCH -- functions can clobber rathole */ + sugen(n->right, nodrat, w); + warn(n, "non-interruptable temporary"); + sugen(nodrat, n->left, w); + sugen(nodrat, nn, w); + break; + + case OFUNC: + if(nn == Z) { + sugen(n, nodrat, w); + break; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + } + + w /= SZ_LONG; + if(w <= 5) { + layout(&nod1, &nod2, w, 0, Z); + goto out; + } + + /* + * minimize space for unrolling loop + * 3,4,5 times. (6 or more is never minimum) + * if small structure, try 2 also. + */ + c = 0; /* set */ + m = 100; + i = 3; + if(w <= 15) + i = 2; + for(; i<=5; i++) + if(i + w%i <= m) { + c = i; + m = c + w%c; + } + + regalloc(&nod3, ®node, Z); + layout(&nod1, &nod2, w%c, w/c, &nod3); + + pc1 = pc; + layout(&nod1, &nod2, c, 0, Z); + + gopcode(OSUB, nodconst(1L), Z, &nod3); + nod1.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1); + nod2.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2); + + gopcode(OGT, &nod3, Z, nodconst(0)); + patch(p, pc1); + + regfree(&nod3); +out: + regfree(&nod1); + regfree(&nod2); +} + +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, ®node, Z); + regalloc(&t2, ®node, Z); + if(c > 0) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(cn != Z) + gopcode(OAS, nodconst(cv), Z, cn); + if(c > 1) { + gopcode(OAS, f, Z, &t2); + f->xoffset += SZ_LONG; + } + if(c > 0) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(c > 1) { + gopcode(OAS, &t2, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + regfree(&t1); + regfree(&t2); +} diff --git a/utils/qc/enam.c b/utils/qc/enam.c new file mode 100644 index 00000000..70535f8a --- /dev/null +++ b/utils/qc/enam.c @@ -0,0 +1,327 @@ +char *anames[] = +{ + "XXX", + "ADD", + "ADDCC", + "ADDV", + "ADDVCC", + "ADDC", + "ADDCCC", + "ADDCV", + "ADDCVCC", + "ADDME", + "ADDMECC", + "ADDMEVCC", + "ADDMEV", + "ADDE", + "ADDECC", + "ADDEVCC", + "ADDEV", + "ADDZE", + "ADDZECC", + "ADDZEVCC", + "ADDZEV", + "AND", + "ANDCC", + "ANDN", + "ANDNCC", + "BC", + "BCL", + "BEQ", + "BGE", + "BGT", + "BL", + "BLE", + "BLT", + "BNE", + "BR", + "BVC", + "BVS", + "CMP", + "CMPU", + "CNTLZW", + "CNTLZWCC", + "CRAND", + "CRANDN", + "CREQV", + "CRNAND", + "CRNOR", + "CROR", + "CRORN", + "CRXOR", + "DIVW", + "DIVWCC", + "DIVWVCC", + "DIVWV", + "DIVWU", + "DIVWUCC", + "DIVWUVCC", + "DIVWUV", + "EQV", + "EQVCC", + "EXTSB", + "EXTSBCC", + "EXTSH", + "EXTSHCC", + "FABS", + "FABSCC", + "FADD", + "FADDCC", + "FADDS", + "FADDSCC", + "FCMPO", + "FCMPU", + "FCTIW", + "FCTIWCC", + "FCTIWZ", + "FCTIWZCC", + "FDIV", + "FDIVCC", + "FDIVS", + "FDIVSCC", + "FMADD", + "FMADDCC", + "FMADDS", + "FMADDSCC", + "FMOVD", + "FMOVDCC", + "FMOVDU", + "FMOVS", + "FMOVSU", + "FMSUB", + "FMSUBCC", + "FMSUBS", + "FMSUBSCC", + "FMUL", + "FMULCC", + "FMULS", + "FMULSCC", + "FNABS", + "FNABSCC", + "FNEG", + "FNEGCC", + "FNMADD", + "FNMADDCC", + "FNMADDS", + "FNMADDSCC", + "FNMSUB", + "FNMSUBCC", + "FNMSUBS", + "FNMSUBSCC", + "FRSP", + "FRSPCC", + "FSUB", + "FSUBCC", + "FSUBS", + "FSUBSCC", + "MOVMW", + "LSW", + "LWAR", + "MOVWBR", + "MOVB", + "MOVBU", + "MOVBZ", + "MOVBZU", + "MOVH", + "MOVHBR", + "MOVHU", + "MOVHZ", + "MOVHZU", + "MOVW", + "MOVWU", + "MOVFL", + "MOVCRFXXX", + "MOVCRFS", + "MOVCRXRXXX", + "MOVFCRXXX", + "MFFSXXX", + "MFFSCCXXX", + "MTCRFXXX", + "MTFSB0", + "MTFSB0CC", + "MTFSB1", + "MTFSB1CC", + "MTFSFXXX", + "MTFSFCCXXX", + "MTFSFIXXX", + "MTFSFIXXXCC", + "MULHW", + "MULHWCC", + "MULHWU", + "MULHWUCC", + "MULLW", + "MULLWCC", + "MULLWVCC", + "MULLWV", + "NAND", + "NANDCC", + "NEG", + "NEGCC", + "NEGVCC", + "NEGV", + "NOR", + "NORCC", + "OR", + "ORCC", + "ORN", + "ORNCC", + "REM", + "REMCC", + "REMV", + "REMVCC", + "REMU", + "REMUCC", + "REMUV", + "REMUVCC", + "RFI", + "RLWMI", + "RLWMICC", + "RLWNM", + "RLWNMCC", + "SLW", + "SLWCC", + "SRW", + "SRAW", + "SRAWCC", + "SRWCC", + "ILLXXX1", + "STSW", + "STWBRXXX", + "STWCCC", + "SUB", + "SUBCC", + "SUBVCC", + "SUBC", + "SUBCCC", + "SUBCV", + "SUBCVCC", + "SUBME", + "SUBMECC", + "SUBMEVCC", + "SUBMEV", + "SUBV", + "SUBE", + "SUBECC", + "SUBEV", + "SUBEVCC", + "SUBZE", + "SUBZECC", + "SUBZEVCC", + "SUBZEV", + "SYNC", + "XOR", + "XORCC", + "DCBF", + "DCBI", + "DCBST", + "DCBT", + "DCBTST", + "DCBZ", + "ECIWX", + "ECOWX", + "EIEIO", + "ICBI", + "ISYNC", + "TLBIE", + "TW", + "SYSCALL", + "DATA", + "GLOBL", + "GOK", + "HISTORY", + "NAME", + "NOP", + "RETURN", + "TEXT", + "WORD", + "END", + "DYNT", + "INIT", + "SIGNAME", + "MACCHW", + "MACCHWCC", + "MACCHWS", + "MACCHWSCC", + "MACCHWSU", + "MACCHWSUCC", + "MACCHWSUV", + "MACCHWSUVCC", + "MACCHWSV", + "MACCHWSVCC", + "MACCHWU", + "MACCHWUCC", + "MACCHWUV", + "MACCHWUVCC", + "MACCHWV", + "MACCHWVCC", + "MACHHW", + "MACHHWCC", + "MACHHWV", + "MACHHWVCC", + "MACHHWS", + "MACHHWSCC", + "MACHHWSV", + "MACHHWSVCC", + "MACHHWSU", + "MACHHWSUCC", + "MACHHWSUV", + "MACHHWSUVCC", + "MACHHWU", + "MACHHWUCC", + "MACHHWUV", + "MACHHWUVCC", + "MACLHW", + "MACLHWCC", + "MACLHWS", + "MACLHWSCC", + "MACLHWSU", + "MACLHWSUCC", + "MACLHWSUV", + "MACLHWSUVCC", + "MACLHWSV", + "MACLHWSVCC", + "MACLHWU", + "MACLHWUCC", + "MACLHWUV", + "MACLHWUVCC", + "MACLHWV", + "MACLHWVCC", + "MULCHW", + "MULCHWCC", + "MULCHWU", + "MULCHWUCC", + "MULHHW", + "MULHHWCC", + "MULHHWU", + "MULHHWUCC", + "MULLHW", + "MULLHWCC", + "MULLHWU", + "MULLHWUCC", + "NMACCHW", + "NMACCHWCC", + "NMACCHWS", + "NMACCHWSCC", + "NMACCHWSV", + "NMACCHWSVCC", + "NMACCHWV", + "NMACCHWVCC", + "NMACHHW", + "NMACHHWCC", + "NMACHHWS", + "NMACHHWSCC", + "NMACHHWSV", + "NMACHHWSVCC", + "NMACHHWV", + "NMACHHWVCC", + "NMACLHW", + "NMACLHWCC", + "NMACLHWS", + "NMACLHWSCC", + "NMACLHWSV", + "NMACLHWSVCC", + "NMACLHWV", + "NMACLHWVCC", + "RFCI", + "LAST", +}; diff --git a/utils/qc/gc.h b/utils/qc/gc.h new file mode 100644 index 00000000..bf4e9091 --- /dev/null +++ b/utils/qc/gc.h @@ -0,0 +1,343 @@ +#include "../cc/cc.h" +#include "../qc/q.out.h" + +/* + * qc/power + * powerpc + */ +#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 Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr from3; /* third argument for fmadd, fmsub, ... */ + Adr to; + Prog* link; + long lineno; + short as; + char reg; +}; +#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 Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +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; + int active; + + Reg* p1; + Reg* p2; + Reg* p2link; + Reg* s1; + Reg* s2; + Reg* link; + Prog* prog; +}; +#define R ((Reg*)0) + +#define NRGN 600 +struct Rgn +{ + Reg* enter; + short cost; + short varno; + short regno; +}; + +EXTERN 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 int hintabsize; +EXTERN long maxargsafe; +EXTERN Multab multab[20]; +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 char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[NREG+NREG]; +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; + +#define R0ISZERO (debug['0']==0) + +extern char* anames[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void usedset(Node*, int); +void noretval(int); +void xcom(Node*); +int bcomplex(Node*, Node*); + +/* + * cgen.c + */ +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nod32const(vlong); +Node* nodfconst(double); +void nodreg(Node*, 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 raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int sval(long); +int uconst(Node*); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(void*, void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(Node*, long); +int mulcon1(Node*, long, Node*); +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 Nconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(void*, void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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 regzer(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 copyau1(Prog*, 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); + +/* + * com64.c + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/qc/list.c b/utils/qc/list.c new file mode 100644 index 00000000..3538c621 --- /dev/null +++ b/utils/qc/list.c @@ -0,0 +1,229 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('D', Dconv); + fmtinstall('B', Bconv); +} + +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; + int a; + + p = va_arg(fp->args, Prog*); + a = p->as; + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a <= AEND) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(F%d)(REG)", a, a->reg); + break; + + case D_CREG: + sprint(str, "C%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(C%d)(REG)", a, a->reg); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<NSNAME; i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/qc/mkenam b/utils/qc/mkenam new file mode 100644 index 00000000..6250da92 --- /dev/null +++ b/utils/qc/mkenam @@ -0,0 +1,18 @@ +ed - ../qc/q.out.h <<'!' +v/^ A/d +g/^ AEND/s//&,/ +g/^ ALAST/s//&,/ +g/[ ]*=.*,/s//,/ +v/,/p +,s/^ A/ "/ +,s/,.*$/",/ +1i +char *anames[] = +{ +. +,a +}; +. +w enam.c +Q +! diff --git a/utils/qc/mkfile b/utils/qc/mkfile new file mode 100644 index 00000000..21933876 --- /dev/null +++ b/utils/qc/mkfile @@ -0,0 +1,29 @@ +<../../mkconfig + +TARG=qc +OFILES=\ + cgen.$O\ + reg.$O\ + txt.$O\ + peep.$O\ + swt.$O\ + sgen.$O\ + list.$O\ + enam.$O\ + mul.$O\ + +HFILES=\ + gc.h\ + q.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/qc/mul.c b/utils/qc/mul.c new file mode 100644 index 00000000..6918c1fe --- /dev/null +++ b/utils/qc/mul.c @@ -0,0 +1,609 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ +}; + +Multab* +mulcon0(Node *n, long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; g<nelem(multab); g++) { + if(m->val == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("%L: multiply table failure %ld\n", n->lineno, v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=6; g++) { + if(g >= 6 && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("%L: multiply table failure (g=%d h=%s) %ld\n", + n->lineno, g, hint, v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(n, v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<<c, r1)) + goto out; + break; + case 1: + if(docode(hp, cp, r1<<c, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r0, r0<<c)) + goto out; + break; + case 3: + if(docode(hp, cp, r0, r1<<c)) + goto out; + break; + } + } + break; + + case '+': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0+r1, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0+r1)) + goto out; + break; + } + } + break; + + case '-': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0-r1, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r1-r0, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0-r1)) + goto out; + break; + case 6: + if(docode(hp, cp, r0, r1-r0)) + goto out; + break; + } + } + break; + + case 0: + if(r0 == mulval) + return 1; + } + return 0; + +out: + cp[-1] = i+'0'; + return 1; +} + +static int +gen1(int len) +{ + int i; + + for(shmax=1; shmax<30; shmax++) { + valmax = 1<<shmax; + if(valmax >= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<<i)) { + *--mulcp = 'a'+i; + return 1; + } + return 0; +} + +static int +gen2(int len, long r1) +{ + int i; + + if(len <= 0) { + if(r1 == mulval) + return 1; + return 0; + } + + len--; + if(len == 0) + goto calcr0; + + if(gen3(len, r1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, r1-1, r1, UR0)) { + i = '-'; + goto out; + } + if(gen3(len, 1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, 1, r1-1, UR1)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + if(mulval == r1+1) { + i = '+'; + goto out; + } + if(mulval == r1-1) { + i = '-'; + goto out; + } + return 0; + +out: + *--mulcp = i; + return 1; +} + +static int +gen3(int len, long r0, long r1, int flag) +{ + int i, f1, f2; + long x; + + if(r0 <= 0 || + r0 >= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x >= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/qc/peep.c b/utils/qc/peep.c new file mode 100644 index 00000000..bb9a2b4f --- /dev/null +++ b/utils/qc/peep.c @@ -0,0 +1,891 @@ +#include "gc.h" + +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; + } + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVW || p->as == AFMOVS || p->as == AFMOVD) + if(regtyp(&p->to)) { + if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + if(regzer(&p->from)) + if(p->to.type == D_REG) { + p->from.type = D_REG; + p->from.reg = REGZERO; + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AMOVH: + case AMOVHZ: + case AMOVB: + case AMOVBZ: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } + + if(debug['Q'] > 1) + return; /* allow following code improvement to be suppressed */ + + /* + * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R + * when OP can set condition codes correctly + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case ACMP: + if(!regzer(&p->to)) + continue; + r1 = r->s1; + if(r1 == R) + continue; + switch(r1->prog->as) { + default: + continue; + case ABCL: + case ABC: + /* the conditions can be complex and these are currently little used */ + continue; + case ABEQ: + case ABGE: + case ABGT: + case ABLE: + case ABLT: + case ABNE: + case ABVC: + case ABVS: + break; + } + r1 = r; + do + r1 = uniqp(r1); + while (r1 != R && r1->prog->as == ANOP); + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->to.type != D_REG || p1->to.reg != p->from.reg) + continue; + switch(p1->as) { + case ASUB: + case AADD: + case AXOR: + case AOR: + /* irregular instructions */ + if(p1->from.type == D_CONST) + continue; + break; + } + switch(p1->as) { + default: + continue; + case AMOVW: + if(p1->from.type != D_REG) + continue; + continue; + case AANDCC: + case AANDNCC: + case AORCC: + case AORNCC: + case AXORCC: + case ASUBCC: + case AADDCC: + t = p1->as; + break; + /* don't deal with floating point instructions for now */ +/* + case AFABS: t = AFABSCC; break; + case AFADD: t = AFADDCC; break; + case AFADDS: t = AFADDSCC; break; + case AFCTIW: t = AFCTIWCC; break; + case AFCTIWZ: t = AFCTIWZCC; break; + case AFDIV: t = AFDIVCC; break; + case AFDIVS: t = AFDIVSCC; break; + case AFMADD: t = AFMADDCC; break; + case AFMADDS: t = AFMADDSCC; break; + case AFMOVD: t = AFMOVDCC; break; + case AFMSUB: t = AFMSUBCC; break; + case AFMSUBS: t = AFMSUBSCC; break; + case AFMUL: t = AFMULCC; break; + case AFMULS: t = AFMULSCC; break; + case AFNABS: t = AFNABSCC; break; + case AFNEG: t = AFNEGCC; break; + case AFNMADD: t = AFNMADDCC; break; + case AFNMADDS: t = AFNMADDSCC; break; + case AFNMSUB: t = AFNMSUBCC; break; + case AFNMSUBS: t = AFNMSUBSCC; break; + case AFRSP: t = AFRSPCC; break; + case AFSUB: t = AFSUBCC; break; + case AFSUBS: t = AFSUBSCC; break; + case ACNTLZW: t = ACNTLZWCC; break; + case AMTFSB0: t = AMTFSB0CC; break; + case AMTFSB1: t = AMTFSB1CC; break; +*/ + case AADD: t = AADDCC; break; + case AADDV: t = AADDVCC; break; + case AADDC: t = AADDCCC; break; + case AADDCV: t = AADDCVCC; break; + case AADDME: t = AADDMECC; break; + case AADDMEV: t = AADDMEVCC; break; + case AADDE: t = AADDECC; break; + case AADDEV: t = AADDEVCC; break; + case AADDZE: t = AADDZECC; break; + case AADDZEV: t = AADDZEVCC; break; + case AAND: t = AANDCC; break; + case AANDN: t = AANDNCC; break; + case ADIVW: t = ADIVWCC; break; + case ADIVWV: t = ADIVWVCC; break; + case ADIVWU: t = ADIVWUCC; break; + case ADIVWUV: t = ADIVWUVCC; break; + case AEQV: t = AEQVCC; break; + case AEXTSB: t = AEXTSBCC; break; + case AEXTSH: t = AEXTSHCC; break; + case AMULHW: t = AMULHWCC; break; + case AMULHWU: t = AMULHWUCC; break; + case AMULLW: t = AMULLWCC; break; + case AMULLWV: t = AMULLWVCC; break; + case ANAND: t = ANANDCC; break; + case ANEG: t = ANEGCC; break; + case ANEGV: t = ANEGVCC; break; + case ANOR: t = ANORCC; break; + case AOR: t = AORCC; break; + case AORN: t = AORNCC; break; + case AREM: t = AREMCC; break; + case AREMV: t = AREMVCC; break; + case AREMU: t = AREMUCC; break; + case AREMUV: t = AREMUVCC; break; + case ARLWMI: t = ARLWMICC; break; + case ARLWNM: t = ARLWNMCC; break; + case ASLW: t = ASLWCC; break; + case ASRAW: t = ASRAWCC; break; + case ASRW: t = ASRWCC; break; + case ASUB: t = ASUBCC; break; + case ASUBV: t = ASUBVCC; break; + case ASUBC: t = ASUBCCC; break; + case ASUBCV: t = ASUBCVCC; break; + case ASUBME: t = ASUBMECC; break; + case ASUBMEV: t = ASUBMEVCC; break; + case ASUBE: t = ASUBECC; break; + case ASUBEV: t = ASUBEVCC; break; + case ASUBZE: t = ASUBZECC; break; + case ASUBZEV: t = ASUBZEVCC; break; + case AXOR: t = AXORCC; break; + break; + } + if(debug['Q']) + print("cmp %P; %P -> ", p1, p); + p1->as = t; + if(debug['Q']) + print("%P\n", p1); + excise(r); + continue; + } + } +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +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; +} + +/* + * if the system forces R0 to be zero, + * convert references to $0 to references to R0. + */ +regzer(Adr *a) +{ + if(R0ISZERO) { + if(a->type == D_CONST) + if(a->sym == S) + if(a->offset == 0) + return 1; + if(a->type == D_REG) + if(a->reg == REGZERO) + return 1; + } + return 0; +} + +regtyp(Adr *a) +{ + + if(a->type == D_REG) { + if(!R0ISZERO || a->reg != REGZERO) + return 1; + return 0; + } + if(a->type == D_FREG) + 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 ABL: + return 0; + + case AADD: + case ASUB: + case ASLW: + case ASRW: + case ASRAW: + case AOR: + case AORCC: + case AORN: + case AORNCC: + case AAND: + case AANDCC: + case AANDN: + case AANDNCC: + case ANAND: + case ANANDCC: + case ANOR: + case ANORCC: + case AXOR: + case AXORCC: + case AMULLW: + case ADIVW: + case ADIVWU: + case AREM: + case AREMU: + case ANEG: + case ANEGCC: + + case AFADD: + case AFADDS: + case AFSUB: + case AFSUBS: + case AFMUL: + case AFMULS: + case AFDIV: + case AFDIVS: + case AFNEG: + case AFNEGCC: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AFMOVS: + case AFMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +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); +} + +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("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * 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(" (???)"); + return 2; + + + case ANOP: /* read, write */ + case AMOVW: + case AMOVH: + case AMOVHZ: + case AMOVB: + case AMOVBZ: + + case ANEG: + case ANEGCC: + + case AFCTIW: + case AFCTIWZ: + case AFMOVS: + case AFMOVD: + case AFRSP: + case AFNEG: + case AFNEGCC: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case AADD: /* read read write */ + case ASUB: + case ASLW: + case ASRW: + case ASRAW: + case AOR: + case AORCC: + case AORN: + case AORNCC: + case AAND: + case AANDCC: + case AANDN: + case AANDNCC: + case ANAND: + case ANANDCC: + case ANOR: + case ANORCC: + case AXOR: + case AMULLW: + case ADIVW: + case ADIVWU: + case AREM: + case AREMU: + + case AFADDS: + case AFADD: + case AFSUBS: + case AFSUB: + case AFMULS: + case AFMUL: + case AFDIVS: + case AFDIV: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: + case ABGT: + case ABGE: + case ABLT: + case ABLE: + case ABNE: + case ABVC: + case ABVS: + break; + + case ACMP: /* read read */ + case ACMPU: + case AFCMPO: + case AFCMPU: + 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 ABR: /* 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 ARETURN: /* funny */ + if(v->type == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case ABL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) { + if(v->reg <= FREGEXT && v->reg > exfregoffset) + 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; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } + return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + case AADD: + case AADDCC: + case ASUB: + case ASUBCC: + case ASLW: + case ASLWCC: + case ASRW: + case ASRWCC: + case ASRAW: + case ASRAWCC: + case AOR: + case AORCC: + case AORN: + case AORNCC: + case AAND: + case AANDCC: + case AANDN: + case AANDNCC: + case AXOR: + case AXORCC: + case ANEG: + case ANEGCC: + case AMULLW: + case AMULLWCC: + case ADIVW: + case ADIVWCC: + case ADIVWU: + case ADIVWUCC: + case AREM: + case AREMCC: + case AREMU: + case AREMUCC: + case ANAND: + case ANANDCC: + case ANOR: + case ANORCC: + return D_REG; + + case AFADDS: + case AFADDSCC: + case AFADD: + case AFADDCC: + case AFSUBS: + case AFSUBSCC: + case AFSUB: + case AFSUBCC: + case AFMULS: + case AFMULSCC: + case AFMUL: + case AFMULCC: + case AFDIVS: + case AFDIVSCC: + case AFDIV: + case AFDIVCC: + case AFNEG: + case AFNEGCC: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) + if(a->type == D_OREG) + if(v->reg == a->reg) + return 1; + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) + if(p->from.type == v->type || p->to.type == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) + a->reg = s->reg; + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} diff --git a/utils/qc/q.out.h b/utils/qc/q.out.h new file mode 100644 index 00000000..795da7f7 --- /dev/null +++ b/utils/qc/q.out.h @@ -0,0 +1,426 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 32 + +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +enum +{ + REGZERO = 0, /* set to zero */ + REGSP = 1, + REGSB = 2, + REGRET = 3, + REGARG = 3, + REGMIN = 7, /* register variables allocated from here to REGMAX */ + REGMAX = 27, + REGEXT = 30, /* external registers allocated from here down */ + REGTMP = 31, /* used by the linker */ + + FREGRET = 0, + FREGMIN = 17, /* first register variable */ + FREGEXT = 26, /* first external register */ + FREGCVI = 27, /* floating conversion constant */ + FREGZERO = 28, /* both float and double */ + FREGHALF = 29, /* double */ + FREGONE = 30, /* double */ + FREGTWO = 31 /* double */ +/* + * GENERAL: + * + * compiler allocates R3 up as temps + * compiler allocates register variables R7-R27 + * compiler allocates external registers R30 down + * + * compiler allocates register variables F17-F26 + * compiler allocates external registers F26 down + */ +}; + +enum as +{ + AXXX = 0, + AADD, + AADDCC, + AADDV, + AADDVCC, + AADDC, + AADDCCC, + AADDCV, + AADDCVCC, + AADDME, + AADDMECC, + AADDMEVCC, + AADDMEV, + AADDE, + AADDECC, + AADDEVCC, + AADDEV, + AADDZE, + AADDZECC, + AADDZEVCC, + AADDZEV, + AAND, + AANDCC, + AANDN, + AANDNCC, + ABC, + ABCL, + ABEQ, + ABGE, + ABGT, + ABL, + ABLE, + ABLT, + ABNE, + ABR, + ABVC, + ABVS, + ACMP, + ACMPU, + ACNTLZW, + ACNTLZWCC, + ACRAND, + ACRANDN, + ACREQV, + ACRNAND, + ACRNOR, + ACROR, + ACRORN, + ACRXOR, + ADIVW, + ADIVWCC, + ADIVWVCC, + ADIVWV, + ADIVWU, + ADIVWUCC, + ADIVWUVCC, + ADIVWUV, + AEQV, + AEQVCC, + AEXTSB, + AEXTSBCC, + AEXTSH, + AEXTSHCC, + AFABS, + AFABSCC, + AFADD, + AFADDCC, + AFADDS, + AFADDSCC, + AFCMPO, + AFCMPU, + AFCTIW, + AFCTIWCC, + AFCTIWZ, + AFCTIWZCC, + AFDIV, + AFDIVCC, + AFDIVS, + AFDIVSCC, + AFMADD, + AFMADDCC, + AFMADDS, + AFMADDSCC, + AFMOVD, + AFMOVDCC, + AFMOVDU, + AFMOVS, + AFMOVSU, + AFMSUB, + AFMSUBCC, + AFMSUBS, + AFMSUBSCC, + AFMUL, + AFMULCC, + AFMULS, + AFMULSCC, + AFNABS, + AFNABSCC, + AFNEG, + AFNEGCC, + AFNMADD, + AFNMADDCC, + AFNMADDS, + AFNMADDSCC, + AFNMSUB, + AFNMSUBCC, + AFNMSUBS, + AFNMSUBSCC, + AFRSP, + AFRSPCC, + AFSUB, + AFSUBCC, + AFSUBS, + AFSUBSCC, + AMOVMW, + ALSW, + ALWAR, + AMOVWBR, + AMOVB, + AMOVBU, + AMOVBZ, + AMOVBZU, + AMOVH, + AMOVHBR, + AMOVHU, + AMOVHZ, + AMOVHZU, + AMOVW, + AMOVWU, + AMOVFL, + AMOVCRFXXX, + AMOVCRFS, + AMOVCRXRXXX, + AMOVFCRXXX, + AMFFSXXX, + AMFFSCCXXX, + AMTCRFXXX, + AMTFSB0, + AMTFSB0CC, + AMTFSB1, + AMTFSB1CC, + AMTFSFXXX, + AMTFSFCCXXX, + AMTFSFIXXX, + AMTFSFIXXXCC, + AMULHW, + AMULHWCC, + AMULHWU, + AMULHWUCC, + AMULLW, + AMULLWCC, + AMULLWVCC, + AMULLWV, + ANAND, + ANANDCC, + ANEG, + ANEGCC, + ANEGVCC, + ANEGV, + ANOR, + ANORCC, + AOR, + AORCC, + AORN, + AORNCC, + AREM, + AREMCC, + AREMV, + AREMVCC, + AREMU, + AREMUCC, + AREMUV, + AREMUVCC, + ARFI, + ARLWMI, + ARLWMICC, + ARLWNM, + ARLWNMCC, + ASLW, + ASLWCC, + ASRW, + ASRAW, + ASRAWCC, + ASRWCC, + AILLXXX1, + ASTSW, + ASTWBRXXX, + ASTWCCC, + ASUB, + ASUBCC, + ASUBVCC, + ASUBC, + ASUBCCC, + ASUBCV, + ASUBCVCC, + ASUBME, + ASUBMECC, + ASUBMEVCC, + ASUBMEV, + ASUBV, + ASUBE, + ASUBECC, + ASUBEV, + ASUBEVCC, + ASUBZE, + ASUBZECC, + ASUBZEVCC, + ASUBZEV, + ASYNC, + AXOR, + AXORCC, + + ADCBF, + ADCBI, + ADCBST, + ADCBT, + ADCBTST, + ADCBZ, + AECIWX, + AECOWX, + AEIEIO, + AICBI, + AISYNC, + ATLBIE, + ATW, + + ASYSCALL, + ADATA, + AGLOBL, + AGOK, + AHISTORY, + ANAME, + ANOP, + ARETURN, + ATEXT, + AWORD, + AEND, + ADYNT, + AINIT, + ASIGNAME, + + /* IBM powerpc embedded; not portable */ + AMACCHW, + AMACCHWCC, + AMACCHWS, + AMACCHWSCC, + AMACCHWSU, + AMACCHWSUCC, + AMACCHWSUV, + AMACCHWSUVCC, + AMACCHWSV, + AMACCHWSVCC, + AMACCHWU, + AMACCHWUCC, + AMACCHWUV, + AMACCHWUVCC, + AMACCHWV, + AMACCHWVCC, + AMACHHW, + AMACHHWCC, + AMACHHWV, + AMACHHWVCC, + AMACHHWS, + AMACHHWSCC, + AMACHHWSV, + AMACHHWSVCC, + AMACHHWSU, + AMACHHWSUCC, + AMACHHWSUV, + AMACHHWSUVCC, + AMACHHWU, + AMACHHWUCC, + AMACHHWUV, + AMACHHWUVCC, + AMACLHW, + AMACLHWCC, + AMACLHWS, + AMACLHWSCC, + AMACLHWSU, + AMACLHWSUCC, + AMACLHWSUV, + AMACLHWSUVCC, + AMACLHWSV, + AMACLHWSVCC, + AMACLHWU, + AMACLHWUCC, + AMACLHWUV, + AMACLHWUVCC, + AMACLHWV, + AMACLHWVCC, + AMULCHW, + AMULCHWCC, + AMULCHWU, + AMULCHWUCC, + AMULHHW, + AMULHHWCC, + AMULHHWU, + AMULHHWUCC, + AMULLHW, + AMULLHWCC, + AMULLHWU, + AMULLHWUCC, + ANMACCHW, + ANMACCHWCC, + ANMACCHWS, + ANMACCHWSCC, + ANMACCHWSV, + ANMACCHWSVCC, + ANMACCHWV, + ANMACCHWVCC, + ANMACHHW, + ANMACHHWCC, + ANMACHHWS, + ANMACHHWSCC, + ANMACHHWSV, + ANMACHHWSVCC, + ANMACHHWV, + ANMACHHWVCC, + ANMACLHW, + ANMACLHWCC, + ANMACLHWS, + ANMACLHWSCC, + ANMACLHWSV, + ANMACLHWSVCC, + ANMACLHWV, + ANMACLHWVCC, + + ARFCI, + + ALAST +}; + +/* type/name */ +enum +{ + D_GOK = 0, + D_NONE, + +/* name */ + D_EXTERN, + D_STATIC, + D_AUTO, + D_PARAM, + +/* type */ + D_BRANCH, + D_OREG, + D_CONST, + D_FCONST, + D_SCONST, + D_REG, + D_FPSCR, + D_MSR, + D_FREG, + D_CREG, + D_SPR, + D_SREG, /* segment register */ + D_OPT, /* branch/trap option */ + D_FILE, + D_FILE1, + D_DCR, /* device control register */ + +/* reg names iff type is D_SPR */ + D_XER = 1, + D_LR = 8, + D_CTR = 9 + /* and many supervisor level registers */ +}; + +/* + * 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 */ +}; diff --git a/utils/qc/reg.c b/utils/qc/reg.c new file mode 100644 index 00000000..c1a900b0 --- /dev/null +++ b/utils/qc/reg.c @@ -0,0 +1,1122 @@ +#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(void *a1, void *a2) +{ + Rgn *p1, *p2; + int c1, c2; + + p1 = a1; + p2 = 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 = 0; + 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 ARETURN: + case ABR: + case ARFI: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW); + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVBZ: + case AMOVBZU: + case AMOVH: + case AMOVHBR: + case AMOVHU: + case AMOVHZ: + case AMOVHZU: + case AMOVW: + case AMOVWU: + case AFMOVD: + case AFMOVDCC: + case AFMOVDU: + case AFMOVS: + case AFMOVSU: + case AFRSP: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case ABL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + 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 == ARETURN) + 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\n set = %B; rah = %B; cal = %B\n", + r->prog, r->set, r->refahead, r->calahead); + 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 an 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']) { + if(rgp->regno >= NREG) + print("%L$%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L$%d R%d: %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->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TFLOAT) + p1->as = AFMOVS; + if(v->etype == TDOUBLE) + p1->as = AFMOVD; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBZ; + if(v->etype == TUSHORT) + p1->as = AMOVHZ; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + n = a->name; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = et; + v->name = n; + 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]; + if(t == D_CONST) { + if(s == S) { + for(z=0; z<BITS; z++) + consts.b[z] |= bit.b[z]; + return bit; + } + if(et != TARRAY) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + return bit; + } + if(t == D_OREG) + 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 ABL: + 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 ARETURN: + 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 TVLONG: + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i && r->cost > 0) { + r->regno = i+NREG; + return FtoB(i); + } + 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->to.type == D_FREG && p->as == AMOVW) + change = -CINF; /* cant go Rreg to Freg */ + 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->from.type == D_FREG && p->as == AMOVW) + change = -CINF; /* cant go Rreg to Freg */ + 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(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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + 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->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * track register variables including external registers: + * bit reg + * 0 R7 + * 1 R8 + * ... ... + * 21 R28 + */ +long +RtoB(int r) +{ + + if(r >= REGMIN && r <= REGMAX) + return 1L << (r-REGMIN); + return 0; +} + +int +BtoR(long b) +{ + b &= 0x001fffffL; + if(b == 0) + return 0; + return bitno(b) + REGMIN; +} + +/* + * bit reg + * 22 F17 + * 23 F18 + * ... ... + * 31 F26 + */ +long +FtoB(int f) +{ + if(f < FREGMIN || f > FREGEXT) + return 0; + return 1L << (f - FREGMIN + 22); +} + +int +BtoF(long b) +{ + + b &= 0xffc00000L; + if(b == 0) + return 0; + return bitno(b) - 22 + FREGMIN; +} diff --git a/utils/qc/sgen.c b/utils/qc/sgen.c new file mode 100644 index 00000000..d557d375 --- /dev/null +++ b/utils/qc/sgen.c @@ -0,0 +1,640 @@ +#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)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typesuv[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gopcode(OAS, &nod, Z, &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); + gopcode(OAS, &nod, Z, &nod1); + } + } + + 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); + 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 o, f; + +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); + 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 = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int v; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASASHL; + r->vconst = v; + r->type = types[TINT]; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASHL; + r->vconst = v; + r->type = types[TINT]; + } + v = vlog(l); + if(v >= 0) { + n->op = OASHL; + n->left = r; + n->right = l; + r = l; + l = n->left; + r->vconst = v; + r->type = types[TINT]; + simplifyshift(n); + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASLSHR; + r->vconst = v; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OLSHR; + r->vconst = v; + r->type = types[TINT]; + simplifyshift(n); + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + v = vlog(r); + if(v >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + xcom(l); + xcom(r); + simplifyshift(n); + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + + case OFUNC: + n->complex = FNX; + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + } +} + +int +bcomplex(Node *n, Node *c) +{ + + 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; + bool64(n); + boolgen(n, 1, Z); + } else + gbranch(OGOTO); + return 0; +} diff --git a/utils/qc/swt.c b/utils/qc/swt.c new file mode 100644 index 00000000..9bf0e58e --- /dev/null +++ b/utils/qc/swt.c @@ -0,0 +1,722 @@ +#include "gc.h" + +int +swcmp(void *a1, void *a2) +{ + C1 *p1, *p2; + + p1 = a1; + p2 = 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; + Node tn; + + 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(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); + regalloc(&tn, ®node, Z); + swit1(iq, nc, def, n, &tn); + regfree(&tn); +} + +void +swit1(C1 *q, int nc, long def, Node *n, Node *tn) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; i<nc; i++) { + if(sval(q->val)) { + gopcode(OEQ, n, Z, nodconst(q->val)); + } else { + gopcode(OSUB, nodconst(q->val), n, tn); + gopcode(OEQ, tn, Z, nodconst(0)); + } + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); + return; + } + i = nc / 2; + r = q+i; + if(sval(r->val)) { + gopcode(OGT, n, Z, nodconst(r->val)); + sp = p; + } else { + gopcode(OSUB, nodconst(r->val), n, tn); + gopcode(OGT, tn, Z, nodconst(0)); + sp = p; + } + gbranch(OGOTO); + p->as = ABEQ; + patch(p, r->label); + swit1(q, i, def, n, tn); + + patch(sp, pc); + swit1(r+1, nc-i-1, def, n, tn); +} + +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); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +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->reg = 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; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(n, v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + if(v < 0) + gopcode(ONEG, &nod1, Z, &nod1); + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +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(0)); + p->from.offset += o+e; + p->reg = 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]) { + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + else + gpseudo(ADATA, s, nod32const(a->vconst)); + p->from.offset += o; + p->reg = 4; + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst)); + else + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + 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++; + } + } + outhist(&outbuf); + 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.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, 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.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + firstp = P; + lastp = P; +} + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + long l; + + bf[0] = p->as; + bf[1] = p->reg; + l = p->lineno; + bf[2] = l; + bf[3] = l>>8; + bf[4] = l>>16; + bf[5] = l>>24; + bp = zaddr(bf+6, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +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, 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; + + zwrite(b, &pg, 0, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n, bf[7]; + ulong sig; + + n = s->name; + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); + s->sig = SIGDONE; + } + else{ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); + } + Bwrite(b, n, strlen(n)+1); +} + +char* +zaddr(char *bp, Adr *a, int s) +{ + long l; + Ieee e; + + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_CREG: + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + } + return bp; +} + +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; + } + o += SZ_LONG - w; /* big endian adjustment */ + w = 1; + 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; +} diff --git a/utils/qc/txt.c b/utils/qc/txt.c new file mode 100644 index 00000000..c14386ac --- /dev/null +++ b/utils/qc/txt.c @@ -0,0 +1,1282 @@ +#include "gc.h" + +static int resvreg[nelem(reg)]; + + +void +ginit(void) +{ + Type *t; + + thechar = 'q'; + thestring = "power"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + 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.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = 0; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + 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(); + + memset(reg, 0, sizeof(reg)); + reg[REGZERO] = 1; /* don't use */ + reg[REGTMP] = 1; + reg[FREGCVI+NREG] = 1; + reg[FREGZERO+NREG] = 1; + reg[FREGHALF+NREG] = 1; + reg[FREGONE+NREG] = 1; + reg[FREGTWO+NREG] = 1; + memmove(resvreg, reg, sizeof(reg)); +} + +void +gclean(void) +{ + int i; + Sym *s; + + for(i=0; i<NREG; i++) + if(reg[i] && !resvreg[i]) + diag(Z, "reg %d left allocated", i); + for(i=NREG; i<NREG+NREG; i++) + if(reg[i] && !resvreg[i]) + diag(Z, "freg %d left allocated", i-NREG); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + 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; +} + +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(typesuv[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 && typechlp[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + if(vconst(n) == 0) { + regaalloc(tn2, n); + gopcode(OAS, n, Z, tn2); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nod32const(vlong v) +{ + constnode.vconst = v & MASK(32); + return &constnode; +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i, j; + static int lasti; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i > 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<NREG; i++) { + if(j >= NREG) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NREG) + goto out; + } + j = lasti + NREG; + for(i=NREG; i<NREG+NREG; i++) { + if(j >= NREG+NREG) + j = NREG; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of float registers"); + goto err; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + i = 0; +out: + if(i) + reg[i]++; + lasti++; + if(lasti >= 5) + lasti = 0; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + 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 + SZ_LONG; + 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 +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(R0ISZERO && a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = REGZERO; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: <null>"); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +fop(int as, int f1, int f2, Node *t) +{ + Node nod1, nod2, nod3; + + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod, fxc0, fxc1, fxc2, fxrat; + Prog *p1; + double d; + + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + d = f->fconst; + if(d == 0.0) { + a = FREGZERO; + goto ffreg; + } + if(d == 0.5) { + a = FREGHALF; + goto ffreg; + } + if(d == 1.0) { + a = FREGONE; + goto ffreg; + } + if(d == 2.0) { + a = FREGTWO; + goto ffreg; + } + if(d == -.5) { + fop(OSUB, FREGHALF, FREGZERO, t); + return; + } + if(d == -1.0) { + fop(OSUB, FREGONE, FREGZERO, t); + return; + } + if(d == -2.0) { + fop(OSUB, FREGTWO, FREGZERO, t); + return; + } + if(d == 1.5) { + fop(OADD, FREGONE, FREGHALF, t); + return; + } + if(d == 2.5) { + fop(OADD, FREGTWO, FREGHALF, t); + return; + } + if(d == 3.0) { + fop(OADD, FREGTWO, FREGONE, t); + return; + } + } + if(ft == TFLOAT && f->op == OCONST) { + d = f->fconst; + if(d == 0) { + a = FREGZERO; + ffreg: + nodreg(&nod, f, NREG+a); + gmove(&nod, t); + return; + } + } + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + a = AMOVW; + break; + case TFLOAT: + a = AFMOVS; + break; + case TDOUBLE: + a = AFMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBZ; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHZ; + break; + } + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + a = AMOVBZ; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHZ; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AFMOVS; + break; + case TDOUBLE: + a = AFMOVD; + break; + } + if(R0ISZERO && !typefd[ft] && vconst(f) == 0) { + gins(a, f, t); + return; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TFLOAT: + switch(tt) { + case TDOUBLE: + a = AFMOVD; + if(ft == TFLOAT) + a = AFMOVS; /* AFMOVSD */ + break; + case TFLOAT: + a = AFRSP; + if(ft == TFLOAT) + a = AFMOVS; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + /* BUG: not right for unsigned long */ + regalloc(&nod, f, Z); /* should be type float */ + regsalloc(&fxrat, f); + gins(AFCTIWZ, f, &nod); + gins(AFMOVD, &nod, &fxrat); + regfree(&nod); + fxrat.type = nodrat->type; + fxrat.etype = nodrat->etype; + fxrat.xoffset += 4; + gins(AMOVW, &fxrat, t); + gmove(t, t); + return; + } + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + switch(tt) { + case TDOUBLE: + case TFLOAT: + goto fxtofl; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TSHORT: + switch(tt) { + case TDOUBLE: + case TFLOAT: + goto fxtofl; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + case TFLOAT: + goto fxtofl; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVHZ; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + case TFLOAT: + goto fxtofl; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + case TFLOAT: + fxtofl: + /* + * rat[0] = 0x43300000; rat[1] = f^0x80000000; + * t = *(double*)rat - FREGCVI; + * is-unsigned(t) => if(t<0) t += 2^32; + * could be streamlined for int-to-float + */ + regalloc(&fxc0, f, Z); + regalloc(&fxc2, f, Z); + regsalloc(&fxrat, t); /* should be type float */ + gins(AMOVW, nodconst(0x43300000L), &fxc0); + gins(AMOVW, f, &fxc2); + gins(AMOVW, &fxc0, &fxrat); + gins(AXOR, nodconst(0x80000000L), &fxc2); + fxc1 = fxrat; + fxc1.type = nodrat->type; + fxc1.etype = nodrat->etype; + fxc1.xoffset += SZ_LONG; + gins(AMOVW, &fxc2, &fxc1); + regfree(&fxc2); + regfree(&fxc0); + regalloc(&nod, t, t); /* should be type float */ + gins(AFMOVD, &fxrat, &nod); + nodreg(&fxc1, t, NREG+FREGCVI); + gins(AFSUB, &fxc1, &nod); + a = AFMOVD; + if(tt == TFLOAT) + a = AFRSP; + gins(a, &nod, t); + regfree(&nod); + if(ft == TULONG) { + regalloc(&nod, t, Z); + if(tt == TFLOAT) { + gins(AFCMPU, t, Z); + p->to.type = D_FREG; + p->to.reg = FREGZERO; + gins(ABGE, Z, Z); + p1 = p; + gins(AFMOVS, nodfconst(4294967296.), &nod); + gins(AFADDS, &nod, t); + } else { + gins(AFCMPU, t, Z); + p->to.type = D_FREG; + p->to.reg = FREGZERO; + gins(ABGE, Z, Z); + p1 = p; + gins(AFMOVD, nodfconst(4294967296.), &nod); + gins(AFADD, &nod, t); + } + patch(p1, pc); + regfree(&nod); + } + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBZ; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AFMOVS || a == AFMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, et; + Adr ta; + int uns; + + uns = 0; + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = AADD; + if(et == TFLOAT) + a = AFADDS; + else + if(et == TDOUBLE) + a = AFADD; + break; + + case OASSUB: + case OSUB: + a = ASUB; + if(et == TFLOAT) + a = AFSUBS; + else + if(et == TDOUBLE) + a = AFSUB; + break; + + case OASOR: + case OOR: + a = AOR; + break; + + case OASAND: + case OAND: + a = AAND; + if(f1->op == OCONST) + a = AANDCC; + break; + + case OASXOR: + case OXOR: + a = AXOR; + break; + + case OASLSHR: + case OLSHR: + a = ASRW; + break; + + case OASASHR: + case OASHR: + a = ASRAW; + break; + + case OASASHL: + case OASHL: + a = ASLW; /* BUG? */ + break; + + case OFUNC: + a = ABL; + break; + + case OASLMUL: + case OLMUL: + case OASMUL: + case OMUL: + if(et == TFLOAT) { + a = AFMULS; + break; + } else + if(et == TDOUBLE) { + a = AFMUL; + break; + } + a = AMULLW; + break; + + case OASDIV: + case ODIV: + if(et == TFLOAT) { + a = AFDIVS; + break; + } else + if(et == TDOUBLE) { + a = AFDIV; + break; + } + a = ADIVW; + break; + + case OASMOD: + case OMOD: + a = AREM; + break; + + case OASLMOD: + case OLMOD: + a = AREMU; + break; + + case OASLDIV: + case OLDIV: + a = ADIVWU; + break; + + case OCOM: + a = ANOR; + break; + + case ONEG: + a = ANEG; + if(et == TFLOAT || et == TDOUBLE) + a = AFNEG; + break; + + case OEQ: + a = ABEQ; + goto cmp; + + case ONE: + a = ABNE; + goto cmp; + + case OLT: + a = ABLT; + goto cmp; + + case OLE: + a = ABLE; + goto cmp; + + case OGE: + a = ABGE; + goto cmp; + + case OGT: + a = ABGT; + goto cmp; + + case OLO: + a = ABLT; + goto cmpu; + + case OLS: + a = ABLE; + goto cmpu; + + case OHS: + a = ABGE; + goto cmpu; + + case OHI: + a = ABGT; + goto cmpu; + + cmpu: + uns = 1; + cmp: + nextpc(); + p->as = uns? ACMPU: ACMP; + if(et == TFLOAT) + p->as = AFCMPU; + else + if(et == TDOUBLE) + p->as = AFCMPU; + if(f1 != Z) + naddr(f1, &p->from); + if(t != Z) + naddr(t, &p->to); + if(f1 == Z || t == Z || f2 != Z) + diag(Z, "bad cmp in gopcode %O", o); + if(debug['g']) + print("%P\n", p); + f1 = Z; + f2 = Z; + t = Z; + break; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + if(ta.type == D_CONST && ta.offset == 0) { + if(R0ISZERO) + p->reg = REGZERO; + else + diag(Z, "REGZERO in gopcode %O", o); + } + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +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 = ARETURN; + break; + case OGOTO: + a = ABR; + break; + } + nextpc(); + if(a == AGOK) { + diag(Z, "bad in gbranch %O", o); + nextpc(); + } + p->as = a; +} + +void +patch(Prog *op, 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_OREG; + p->from.sym = s; + if(a == ATEXT) + p->reg = (profileflg ? 0 : NOPROF); + p->from.name = D_EXTERN; + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sval(long v) +{ + + if(v >= -(1<<15) && v < (1<<15)) + return 1; + return 0; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15)) + return 1; + } + } + return 0; +} + +int +uconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= 0 && vv < (((vlong)1)<<16)) + return 1; + } + } + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= 3) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 16) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; +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] */ +}; diff --git a/utils/ql/Ins b/utils/ql/Ins new file mode 100644 index 00000000..d113e845 --- /dev/null +++ b/utils/ql/Ins @@ -0,0 +1,203 @@ +a OR XO(31,10) +abs OR XO(31,360) +ae OR XO(31,138) +ai 0 D(12) + + +ai. 0 D(13) +ame OR XO(31,234) +and R X(31,28) +andc R X(31,60) + +andil. 0 D(28,0) +andiu. 0 D(29,0) +aze OR XO(31,202) +cal 0 D(14) + +cau 0 D(15) +cax OR XO(31,266) +cmp 0 X(31,0) +cmpi 0 D(11) + +cmpl 0 X(31,32) +cmpli 0 D(10) +cntlz R X(31,26) +crand 0 XL(19,257) + +crandc 0 XL(19,129) +creqv 0 XL(19,289) +crnand 0 XL(19,225) +crnor 0 XL(19,33) + +cror 0 XL(19,449) +crorc 0 XL(19,417) +crxor 0 XL(19,193) +div OR XO(31,331) + +divs OR XO(31,331) +doz OR XO(31,264) +dozi 0 D(9) + +eqv R X(31,284) +exts R X(31,922) +fa R A(63,21) +fabs R X(63,264) +fcmpo 0 X(63,32) + +fcmpu 0 X(63,0) +fd R A(63,8) +fm R A(63,5) +fma R A(63,29) + +fmr R X(63,72) +fms R A(63,28) +fnabs R X(63,136) +fneg R X(63,40) + +fnma R A(63,31) +fnms R A(63,30) +frsp R X(63,12) +fs R A(63,20) + +l 0 D(32) +lbrx 0 X(31,534) +lbz 0 D(34) +lbzu 0 D(35) + +lbzux 0 X(31,119) +lbzx 0 X(31,87) +lfd 0 D(50) +lfdu 0 D(51) + +lfdux 0 X(31,631) +lfdx 0 X(31,599) +lfs 0 D(48) +lfsu 0 D(49) + +lfsux 0 X(31,567) +lfsx 0 X(31,535) +lha 0 D(42) +lhau 0 D(43) + +lhaux 0 X(31,375) +lhax 0 X(31,343) +lhbrx 0 X(31,790) +lhz 0 D(40) + +lhzu 0 D(41) +lhzux 0 X(31,311) +lhzx 0 X(31,279) +lm 0 D(46) + +lscbx R X(31,277) +lsi 0 X(31,597) +lsx 0 X(31,533) +lu 0 D(33) + +lux 0 X(31,55) +lx 0 X(31,23) +maskg R X(31,29) +maskir R X(31,541) + +mcrf 0 XL(19,0) +mcrfs 0 X(63,64) +mcrxr 0 X(31,512) +mfcr 0 X(31,19) + +mffs R X(63,583) +mfmsr 0 X(31,83) +mfspr 0 X(31,339) +mtcrf 0 XFX(31,144) + +mtfsb0 R X(63,70) +mtfsb1 R X(63,38) +mtfsf R XFL(63,711) +mtfsfi R X(63,134) + +mtspr 0 X(31,467) +mul OR XO(31,107) +muli 0 D(7) +muls OR XO(31,235) + +nabs OR XO(31,488) +nand R X(31,476) +neg OR XO(31,104) + +nor R X(31,124) +or R X(31,444) +orc R X(31,412) +oril 0 D(24) + +oriu 0 D(25) +rlmi R M(20) +rlinm R M(21) +rlmi R M(22) + +rlnm R M(23) +rrib R X(31,537) +sf OR XO(31,8) +sfe OR XO(31,36) + +sfi 0 D(8) +sfme OR XO(31,232) +sfze OR XO(31,200) +sl R X(31,24) + +sle R X(31,153) +sleq R X(31,217) +sliq R X(31,184) +slliq R X(31,248) + +sllq R X(31,216) +slq R X(31,152) +sr R X(31,536) +sra R X(31,792) + +srai R X(31,824) +sraiq R X(31,952) +sraq R X(31,920) +sre R X(31,665) + +srea R X(31,921) +sreq R X(31,729) +sriq R X(31,696) +srliq R X(31,760) +srlq R X(31,728) + +srq R X(31,664) +st 0 D(36) +stb 0 D(38) +stbrx 0 X(31,662) + +stbu 0 D(39) +stbux 0 X(31,247) +stbx 0 X(31,215) +stfd 0 D(54) + +stfdu 0 D(55) +stfdux 0 X(31,759) +stfdx 0 X(31,727) +stfs 0 D(52) + +stfsu 0 D(53) +stfsux 0 X(31,695) +stfsx 0 X(31,663) +sth 0 D(44) + +sthbrx 0 X(31,918) +sthu 0 D(45) +sthux 0 X(31,439) +sthx 0 X(3,407) + +stm 0 D(47) +stsi 0 X(31,725) +stsx 0 X(31,661) +stu 0 D(37) + +stux 0 X(31,183) +stx 0 X(31,151) +svc 0 SC(17) +t 0 X(31,4) +ti 0 D(3) +xor R X(31,316) +xoril 0 D(26) +xoriu 0 D(27) diff --git a/utils/ql/Notes b/utils/ql/Notes new file mode 100644 index 00000000..1620b508 --- /dev/null +++ b/utils/ql/Notes @@ -0,0 +1,21 @@ +possible input transformations + adde $-1,X => addme X + adde $0,X => addze X + subw $s,X => addw $-s,X + orn $v,X => or $~v,X + +qa: + subc r1,$s,r2 => subc $s,r1,r2 + movw sreg(Rn),Rm => movw sreg(NREG),Rn,Rm [and v.v.] + +others? + andn $m => and $~m + slw $sh,s,a => rliwnm + srw $sh,s,a => rliwnm + +support for C_LCON needed since addresses are literals? + +- moves +- branch distance + +- could rewrite movwu x,d(r) as movw $d,tmp; movwu x,(tmp+d) when d is large? diff --git a/utils/ql/Nt.c b/utils/ql/Nt.c new file mode 100644 index 00000000..c6748abd --- /dev/null +++ b/utils/ql/Nt.c @@ -0,0 +1,88 @@ +#include <windows.h> + +/* + * We can't include l.h, because Windoze wants to use some names + * like FLOAT and ABC which we declare. Define what we need here. + */ +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; + +extern char *hunk; +extern long nhunk; + +void gethunk(void); + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/ql/Plan9.c b/utils/ql/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/ql/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/ql/Posix.c b/utils/ql/Posix.c new file mode 100644 index 00000000..0da0ee0c --- /dev/null +++ b/utils/ql/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fails if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} diff --git a/utils/ql/asm.c b/utils/ql/asm.c new file mode 100644 index 00000000..6887a12b --- /dev/null +++ b/utils/ql/asm.c @@ -0,0 +1,687 @@ +#include "l.h" + +#define KMASK 0xF0000000 + +#define LPUT(c)\ + {\ + cbp[0] = (c)>>24;\ + cbp[1] = (c)>>16;\ + cbp[2] = (c)>>8;\ + cbp[3] = (c);\ + cbp += 4;\ + cbc -= 4;\ + if(cbc <= 0)\ + cflush();\ + } + +#define CPUT(c)\ + {\ + cbp[0] = (c);\ + cbp++;\ + cbc--;\ + if(cbc <= 0)\ + cflush();\ + } + +void strnput(char*, int); + +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; + if(dlm && s->type == SDATA) + return s->value+INITDAT; + if(s->type != STEXT && s->type != SLEAF) + diag("entry not text: %s", s->name); + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long t; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f asm\n", cputime()); + Bflush(&bso); + seek(cout, HEADR, 0); + pc = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from3.type == D_CONST) { + for(; pc < p->pc; pc++) + CPUT(0); + } + } + if(p->pc != pc) { + diag("phase error %lux sb %lux", + p->pc, pc); + if(!debug['a']) + prasm(curp); + pc = p->pc; + } + curp = p; + o = oplook(p); /* could probably avoid this call */ + if(asmout(p, o, 0)) { + p = p->link; + pc += 4; + } + pc += o->size; + } + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + + curtext = P; + switch(HEADTYPE) { + case 0: + case 1: + case 2: + case 5: + seek(cout, HEADR+textsize, 0); + break; + case 3: + seek(cout, rnd(HEADR+textsize, 4), 0); + break; + case 4: + seek(cout, rnd(HEADR+textsize, 4096), 0); + break; + } + + if(dlm){ + char buf[8]; + + write(cout, buf, INITDAT-textsize); + textsize = INITDAT; + } + + for(t = 0; t < datsize; t += sizeof(buf)-100) { + if(datsize-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100); + else + datblk(t, datsize-t); + } + + symsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + case 0: + case 1: + case 2: + case 5: + seek(cout, HEADR+textsize+datsize, 0); + break; + case 3: + seek(cout, rnd(HEADR+textsize, 4)+datsize, 0); + break; + case 4: + seek(cout, rnd(HEADR+textsize, 4096)+datsize, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f sp\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + if(dlm) + asmdyn(); + if(HEADTYPE == 0 || HEADTYPE == 1) /* round up file length for boot image */ + if((symsize+lcsize) & 1) + CPUT(0); + cflush(); + } + else if(dlm){ + asmdyn(); + cflush(); + } + + seek(cout, 0L, 0); + switch(HEADTYPE) { + case 0: + lput(0x1030107); /* magic and sections */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 1: + lput(0x4a6f7921); /* Joy! */ + lput(0x70656666); /* peff */ + lput(0x70777063); /* pwpc */ + lput(1); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0x30002); /*YY*/ + lput(0); + lput(~0); + lput(0); + lput(textsize+datsize); + lput(textsize+datsize); + lput(textsize+datsize); + lput(0xd0); /* header size */ + lput(0x10400); + lput(~0); + lput(0); + lput(0xc); + lput(0xc); + lput(0xc); + lput(0xc0); + lput(0x01010400); + lput(~0); + lput(0); + lput(0x38); + lput(0x38); + lput(0x38); + lput(0x80); + lput(0x04040400); + lput(0); + lput(1); + lput(0); + lput(~0); + lput(0); + lput(~0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0); + lput(0x3100); /* load address */ + lput(0); + lput(0); + lput(0); /* whew! */ + break; + case 2: + if(dlm) + lput(0x80000000 | (4*21*21+7)); /* magic */ + else + lput(4*21*21+7); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 3: + break; + case 4: + lput((0x1DFL<<16)|3L); /* magic and sections */ + lput(time(0)); /* time and date */ + lput(rnd(HEADR+textsize, 4096)+datsize); + lput(symsize); /* nsyms */ + lput((0x48L<<16)|15L); /* size of optional hdr and flags */ + + lput((0413<<16)|01L); /* magic and version */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(entryvalue()); /* va of entry */ + lput(INITTEXT); /* va of base of text */ + lput(INITDAT); /* va of base of data */ + lput(INITDAT); /* address of TOC */ + lput((1L<<16)|1); /* sn(entry) | sn(text) */ + lput((2L<<16)|1); /* sn(data) | sn(toc) */ + lput((0L<<16)|3); /* sn(loader) | sn(bss) */ + lput((3L<<16)|3); /* maxalign(text) | maxalign(data) */ + lput(('1'<<24)|('L'<<16)|0); /* type field, and reserved */ + lput(0); /* max stack allowed */ + lput(0); /* max data allowed */ + lput(0); lput(0); lput(0); /* reserved */ + + strnput(".text", 8); /* text segment */ + lput(INITTEXT); /* address */ + lput(INITTEXT); + lput(textsize); + lput(HEADR); + lput(0L); + lput(HEADR+textsize+datsize+symsize); + lput(lcsize); /* line number size */ + lput(0x20L); /* flags */ + + strnput(".data", 8); /* data segment */ + lput(INITDAT); /* address */ + lput(INITDAT); + lput(datsize); + lput(rnd(HEADR+textsize, 4096)); /* sizes */ + lput(0L); + lput(0L); + lput(0L); + lput(0x40L); /* flags */ + + strnput(".bss", 8); /* bss segment */ + lput(INITDAT+datsize); /* address */ + lput(INITDAT+datsize); + lput(bsssize); + lput(0L); + lput(0L); + lput(0L); + lput(0L); + lput(0x80L); /* flags */ + break; + case 5: + strnput("\177ELF", 4); /* e_ident */ + CPUT(1); /* class = 32 bit */ + CPUT(2); /* data = MSB */ + CPUT(1); /* version = CURRENT */ + strnput("", 9); + lput((2L<<16)|20L); /* type = EXEC; machine = PowerPC */ + lput(1L); /* version = CURRENT */ + lput(entryvalue() & ~KMASK); /* entry vaddr */ + lput(52L); /* offset to first phdr */ + lput(0L); /* offset to first shdr */ + lput(0L); /* flags = PPC */ + lput((52L<<16)|32L); /* Ehdr & Phdr sizes*/ + lput((3L<<16)|0L); /* # Phdrs & Shdr size */ + lput((0L<<16)|0L); /* # Shdrs & shdr string size */ + + lput(1L); /* text - type = PT_LOAD */ + lput(HEADR); /* file offset */ + lput(INITTEXT & ~KMASK); /* vaddr */ + lput(INITTEXT); /* paddr */ + lput(textsize); /* file size */ + lput(textsize); /* memory size */ + lput(0x05L); /* protections = RX */ + lput(0x10000L); /* alignment code?? */ + + lput(1L); /* data - type = PT_LOAD */ + lput(HEADR+textsize); /* file offset */ + lput(INITDAT & ~KMASK); /* vaddr */ + lput(INITDAT); /* paddr */ + lput(datsize); /* file size */ + lput(datsize); /* memory size */ + lput(0x07L); /* protections = RWX */ + lput(0x10000L); /* alignment code?? */ + + lput(0L); /* data - type = PT_NULL */ + lput(HEADR+textsize+datsize); /* file offset */ + lput(0L); + lput(0L); + lput(symsize); /* symbol table size */ + lput(lcsize); /* line number size */ + lput(0x04L); /* protections = R */ + lput(0x04L); /* alignment code?? */ + break; + } + cflush(); +} + +void +strnput(char *s, int n) +{ + for(; *s; s++){ + CPUT(*s); + n--; + } + for(; n > 0; n--) + CPUT(0); +} + +void +cput(long l) +{ + CPUT(l); +} + +void +wput(long l) +{ + cbp[0] = l>>8; + cbp[1] = l; + cbp += 2; + cbc -= 2; + if(cbc <= 0) + cflush(); +} + +void +lput(long l) +{ + + LPUT(l); +} + +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 +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->cond) { + s = p->from.sym; + if(s->type != STEXT && s->type != SLEAF) + continue; + + /* filenames first */ + for(a=p->to.autom; a; a=a->link) + if(a->type == D_FILE) + putsymb(a->sym->name, 'z', a->aoffset, 0); + else + if(a->type == D_FILE1) + putsymb(a->sym->name, 'Z', a->aoffset, 0); + + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + else + putsymb(s->name, 'L', 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->sym->name, 'a', -a->aoffset, 0); + else + if(a->type == D_PARAM) + putsymb(a->sym->name, 'p', a->aoffset, 0); + } + if(debug['v'] || debug['n']) + Bprint(&bso, "symsize = %lud\n", symsize); + Bflush(&bso); +} + +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); + } +} + +#define MINLC 4 +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); +} + +void +datblk(long s, long n) +{ + Prog *p; + char *cast; + long l, fl, j, d; + int i, c; + + memset(buf.dbuf, 0, n+100); + for(p = datap; p != P; p = p->link) { + curp = p; + l = p->from.sym->value + p->from.offset - s; + c = p->reg; + 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) { + default: + diag("unknown mode in initialization\n%P", p); + break; + + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(&p->to.ieee); + cast = (char*)&fl; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i+4]]; + l++; + } + break; + case 8: + cast = (char*)&p->to.ieee; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + for(; i<c; i++) { + buf.dbuf[l] = p->to.sval[i]; + l++; + } + break; + + case D_CONST: + d = p->to.offset; + if(p->to.sym) { + if(p->to.sym->type == SUNDEF){ + ckoff(p->to.sym, d); + d += p->to.sym->value; + } + if(p->to.sym->type == STEXT || + p->to.sym->type == SLEAF) + d += p->to.sym->value; + if(p->to.sym->type == SDATA) + d += p->to.sym->value + INITDAT; + if(p->to.sym->type == SBSS) + d += p->to.sym->value + INITDAT; + if(dlm) + dynreloc(p->to.sym, l+s+INITDAT, 1, 0, 0); + } + cast = (char*)&d; + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + break; + case 1: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} diff --git a/utils/ql/asmout.c b/utils/ql/asmout.c new file mode 100644 index 00000000..e3d96694 --- /dev/null +++ b/utils/ql/asmout.c @@ -0,0 +1,1293 @@ +#include "l.h" + +#define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1)) +#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc)) +#define OP(o,xo) OPVCC((o),(xo),0,0) + +/* the order is dest, a/s, b/imm for both arithmetic and logical operations */ +#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11)) +#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF)) +#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11)) +#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF)) +#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1)) +#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1)) +#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)) +#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\ + (((mb)&31L)<<6)|(((me)&31L)<<1)) + +#define OP_ADD OPVCC(31,266,0,0) +#define OP_ADDI OPVCC(14,0,0,0) +#define OP_ADDIS OPVCC(15,0,0,0) +#define OP_ANDI OPVCC(28,0,0,0) +#define OP_EXTSB OPVCC(31,954,0,0) +#define OP_EXTSH OPVCC(31,922,0,0) +#define OP_MCRF OPVCC(19,0,0,0) +#define OP_MCRFS OPVCC(63,64,0,0) +#define OP_MCRXR OPVCC(31,512,0,0) +#define OP_MFCR OPVCC(31,19,0,0) +#define OP_MFFS OPVCC(63,583,0,0) +#define OP_MFMSR OPVCC(31,83,0,0) +#define OP_MFSPR OPVCC(31,339,0,0) +#define OP_MFSR OPVCC(31,595,0,0) +#define OP_MFSRIN OPVCC(31,659,0,0) +#define OP_MTCRF OPVCC(31,144,0,0) +#define OP_MTFSF OPVCC(63,711,0,0) +#define OP_MTFSFI OPVCC(63,134,0,0) +#define OP_MTMSR OPVCC(31,146,0,0) +#define OP_MTSPR OPVCC(31,467,0,0) +#define OP_MTSR OPVCC(31,210,0,0) +#define OP_MTSRIN OPVCC(31,242,0,0) +#define OP_MULLW OPVCC(31,235,0,0) +#define OP_OR OPVCC(31,444,0,0) +#define OP_ORI OPVCC(24,0,0,0) +#define OP_RLWINM OPVCC(21,0,0,0) +#define OP_SUBF OPVCC(31,40,0,0) + +#define oclass(v) ((v).class-1) + +long oprrr(int), opirr(int), opload(int), opstore(int), oploadx(int), opstorex(int); + +int +getmask(uchar *m, ulong v) +{ + int i; + + m[0] = m[1] = 0; + if(v != ~0L && v & (1<<31) && v & 1){ /* MB > ME */ + if(getmask(m, ~v)){ + i = m[0]; m[0] = m[1]+1; m[1] = i-1; + return 1; + } + return 0; + } + for(i=0; i<32; i++) + if(v & (1<<(31-i))){ + m[0] = i; + do { + m[1] = i; + } while(++i<32 && (v & (1<<(31-i))) != 0); + for(; i<32; i++) + if(v & (1<<(31-i))) + return 0; + return 1; + } + return 0; +} + +void +maskgen(Prog *p, uchar *m, ulong v) +{ + if(!getmask(m, v)) + diag("cannot generate mask #%lux\n%P", v, p); +} + +static void +reloc(Adr *a, long pc, int sext) +{ + if(a->name == D_EXTERN || a->name == D_STATIC) + dynreloc(a->sym, pc, 1, 1, sext); +} + +int +asmout(Prog *p, Optab *o, int aflag) +{ + long o1, o2, o3, o4, o5, v, t; + Prog *ct; + int r, a; + uchar mask[2]; + + o1 = 0; + o2 = 0; + o3 = 0; + o4 = 0; + o5 = 0; + switch(o->type) { + default: + if(aflag) + return 0; + diag("unknown type %d", o->type); + if(!debug['a']) + prasm(p); + break; + + case 0: /* pseudo ops */ + if(aflag) { + if(p->link) { + if(p->as == ATEXT) { + ct = curtext; + o2 = autosize; + curtext = p; + autosize = p->to.offset + 4; + o1 = asmout(p->link, oplook(p->link), aflag); + curtext = ct; + autosize = o2; + } else + o1 = asmout(p->link, oplook(p->link), aflag); + } + return o1; + } + break; + + case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */ + if(p->to.reg == REGZERO && p->from.type == D_CONST) { + v = regoff(&p->from); + if(r0iszero && v != 0) { + nerrors--; + diag("literal operation on R0\n%P", p); + } + o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v); + break; + } + o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg); + break; + + case 2: /* int/cr/fp op Rb,[Ra],Rd */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); + break; + + case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + a = OP_ADDI; + if(o->a1 == C_UCON) { + a = OP_ADDIS; + v >>= 16; + } + if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0)) + diag("literal operation on R0\n%P", p); + o1 = AOP_IRR(a, p->to.reg, r, v); + break; + + case 4: /* add/mul $scon,[r1],r2 */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + if(r0iszero && p->to.reg == 0) + diag("literal operation on R0\n%P", p); + o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v); + break; + + case 5: /* syscall */ + if(aflag) + return 0; + o1 = oprrr(p->as); + break; + + case 6: /* logical op Rb,[Rs,]Ra; no literal */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); + break; + + case 7: /* mov r, soreg ==> stw o(r) */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + if(p->to.type == D_OREG && p->reg != NREG) { + if(v) + diag("illegal indexed instruction\n%P", p); + o1 = AOP_RRR(opstorex(p->as), p->from.reg, p->reg, r); + } else + o1 = AOP_IRR(opstore(p->as), p->from.reg, r, v); + break; + + case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + if(p->from.type == D_OREG && p->reg != NREG) { + if(v) + diag("illegal indexed instruction\n%P", p); + o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r); + } else + o1 = AOP_IRR(opload(p->as), p->to.reg, r, v); + break; + + case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + if(p->from.type == D_OREG && p->reg != NREG) { + if(v) + diag("illegal indexed instruction\n%P", p); + o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r); + } else + o1 = AOP_IRR(opload(p->as), p->to.reg, r, v); + o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0); + break; + + case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, r); + break; + + case 11: /* br/bl lbra */ + if(aflag) + return 0; + v = 0; + if(p->cond == UP){ + if(p->to.sym->type != SUNDEF) + diag("bad branch sym type"); + v = (ulong)p->to.sym->value >> (Roffset-2); + dynreloc(p->to.sym, p->pc, 0, 0, 0); + } + else if(p->cond) + v = p->cond->pc - p->pc; + if(v & 03) { + diag("odd branch target address\n%P", p); + v &= ~03; + } + if(v < -(1L<<25) || v >= (1L<<25)) + diag("branch too far\n%P", p); + o1 = OP_BR(opirr(p->as), v, 0); + break; + + case 12: /* movb r,r (signed); extsb is on PowerPC but not POWER */ + o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0); + break; + + case 13: /* mov[bh]z r,r; uses rlwinm not andi. to avoid changing CC */ + if(p->as == AMOVBZ) + o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31); + else if(p->as == AMOVH) + o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0); + else if(p->as == AMOVHZ) + o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31); + else + diag("internal: bad mov[bh]z\n%P", p); + break; + +/*14 */ + + case 17: /* bc bo,bi,lbra (same for now) */ + case 16: /* bc bo,bi,sbra */ + if(aflag) + return 0; + a = 0; + if(p->from.type == D_CONST) + a = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = 0; + v = 0; + if(p->cond) + v = p->cond->pc - p->pc; + if(v & 03) { + diag("odd branch target address\n%P", p); + v &= ~03; + } + if(v < -(1L<<16) || v >= (1L<<16)) + diag("branch too far\n%P", p); + o1 = OP_BC(opirr(p->as), a, r, v, 0); + break; + + case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */ + if(aflag) + return 0; + if(p->as == ABC || p->as == ABCL) + v = regoff(&p->to)&31L; + else + v = 20; /* unconditional */ + r = p->reg; + if(r == NREG) + r = 0; + o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11); + o2 = OPVCC(19, 16, 0, 0); + if(p->as == ABL || p->as == ABCL) + o2 |= 1; + o2 = OP_BCR(o2, v, r); + break; + + case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */ + if(aflag) + return 0; + if(p->as == ABC || p->as == ABCL) + v = regoff(&p->from)&31L; + else + v = 20; /* unconditional */ + r = p->reg; + if(r == NREG) + r = 0; + switch(oclass(p->to)) { + case C_CTR: + o1 = OPVCC(19, 528, 0, 0); + break; + case C_LR: + o1 = OPVCC(19, 16, 0, 0); + break; + default: + diag("bad optab entry (18): %d\n%P", p->to.class, p); + v = 0; + } + if(p->as == ABL || p->as == ABCL) + o1 |= 1; + o1 = OP_BCR(o1, v, r); + break; + + case 19: /* mov $lcon,r ==> cau+or */ + v = regoff(&p->from); + o1 = AOP_IRR(OP_ADDIS, p->to.reg, REGZERO, v>>16); + o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, v); + if(dlm) + reloc(&p->from, p->pc, 0); + break; + + case 20: /* add $ucon,,r */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0)) + diag("literal operation on R0\n%P", p); + o1 = AOP_IRR(opirr(p->as+AEND), p->to.reg, r, v>>16); + break; + + case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */ + v = regoff(&p->from); + if(p->to.reg == REGTMP || p->reg == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); + o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o3 = AOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r); + if(dlm) + reloc(&p->from, p->pc, 0); + break; + + case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */ + v = regoff(&p->from); + if(p->to.reg == REGTMP || p->reg == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); + o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o3 = LOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r); + if(dlm) + reloc(&p->from, p->pc, 0); + break; +/*24*/ + + case 26: /* mov $lsext/auto/oreg,,r2 ==> cau+add */ + v = regoff(&p->from); + if(v & 0x8000L) + v += 0x10000L; + if(p->to.reg == REGTMP) + diag("can't synthesize large constant\n%P", p); + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v); + break; + + case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */ + v = regoff(&p->from3); + r = p->from.reg; + o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v); + break; + + case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */ + v = regoff(&p->from3); + if(p->to.reg == REGTMP || p->from.reg == REGTMP) + diag("can't synthesize large constant\n%P", p); + o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); + o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v); + o3 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, REGTMP); + if(dlm) + reloc(&p->from3, p->pc, 0); + break; + +/*29, 30, 31 */ + + case 32: /* fmul frc,fra,frd */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6); + break; + + case 33: /* fabs [frb,]frd; fmr. frb,frd */ + r = p->from.reg; + if(oclass(p->from) == C_NONE) + r = p->to.reg; + o1 = AOP_RRR(oprrr(p->as), p->to.reg, 0, r); + break; + + case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c) */ + o1 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, p->reg)|((p->from3.reg&31L)<<6); + break; + + case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */ + v = regoff(&p->to); + if(v & 0x8000L) + v += 0x10000L; + r = p->to.reg; + if(r == NREG) + r = o->param; + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o2 = AOP_IRR(opstore(p->as), p->from.reg, REGTMP, v); + break; + + case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */ + v = regoff(&p->from); + if(v & 0x8000L) + v += 0x10000L; + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v); + break; + + case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */ + v = regoff(&p->from); + if(v & 0x8000L) + v += 0x10000L; + r = p->from.reg; + if(r == NREG) + r = o->param; + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v); + o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0); + break; + + case 40: /* word */ + if(aflag) + return 0; + o1 = regoff(&p->from); + break; + + case 41: /* stswi */ + o1 = AOP_RRR(opirr(p->as), p->from.reg, p->to.reg, 0) | ((regoff(&p->from3)&0x7F)<<11); + break; + + case 42: /* lswi */ + o1 = AOP_RRR(opirr(p->as), p->to.reg, p->from.reg, 0) | ((regoff(&p->from3)&0x7F)<<11); + break; + + case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */ + r = p->reg; + if(r == NREG) + r = 0; + o1 = AOP_RRR(oprrr(p->as), 0, r, p->from.reg); + break; + + case 44: /* indexed store */ + r = p->reg; + if(r == NREG) + r = 0; + o1 = AOP_RRR(opstorex(p->as), p->from.reg, r, p->to.reg); + break; + case 45: /* indexed load */ + r = p->reg; + if(r == NREG) + r = 0; + o1 = AOP_RRR(oploadx(p->as), p->to.reg, r, p->from.reg); + break; + + case 46: /* plain op */ + o1 = oprrr(p->as); + break; + + case 47: /* op Ra, Rd; also op [Ra,] Rd */ + r = p->from.reg; + if(r == NREG) + r = p->to.reg; + o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, 0); + break; + + case 48: /* op Rs, Ra */ + r = p->from.reg; + if(r == NREG) + r = p->to.reg; + o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, 0); + break; + + case 49: /* op Rb */ + o1 = AOP_RRR(oprrr(p->as), 0, 0, p->from.reg); + break; + +/*50*/ + + case 51: /* rem[u] r1[,r2],r3 */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + v = oprrr(p->as); + t = v & ((1<<10)|1); /* OE|Rc */ + o1 = AOP_RRR(v&~t, REGTMP, r, p->from.reg); + o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, p->from.reg); + o3 = AOP_RRR(OP_SUBF|t, p->to.reg, REGTMP, r); + break; + + case 52: /* mtfsbNx cr(n) */ + v = regoff(&p->from)&31L; + o1 = AOP_RRR(oprrr(p->as), v, 0, 0); + break; + + case 53: /* mffsX ,fr1 */ + o1 = AOP_RRR(OP_MFFS, p->to.reg, 0, 0); + break; + + case 54: /* mov msr,r1; mov r1, msr*/ + if(oclass(p->from) == C_REG) + o1 = AOP_RRR(OP_MTMSR, p->from.reg, 0, 0); + else + o1 = AOP_RRR(OP_MFMSR, p->to.reg, 0, 0); + break; + + case 55: /* mov sreg,r1; mov r1,sreg */ + v = 0; + if(p->from.type == D_SREG) { + r = p->from.reg; + o1 = OP_MFSR; + if(r == NREG && p->reg != NREG) { + r = 0; + v = p->reg; + o1 = OP_MFSRIN; + } + o1 = AOP_RRR(o1, p->to.reg, r&15L, v); + } else { + r = p->to.reg; + o1 = OP_MTSR; + if(r == NREG && p->reg != NREG) { + r = 0; + v = p->reg; + o1 = OP_MTSRIN; + } + o1 = AOP_RRR(o1, p->from.reg, r&15L, v); + } + if(r == NREG) + diag("illegal move indirect to/from segment register\n%P", p); + break; + + case 56: /* sra $sh,[s,]a */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = AOP_RRR(opirr(p->as), r, p->to.reg, v&31L); + break; + + case 57: /* slw $sh,[s,]a -> rlwinm ... */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + /* + * Let user (gs) shoot himself in the foot. + * qc has already complained. + * + if(v < 0 || v > 31) + diag("illegal shift %ld\n%P", v, p); + */ + if(v < 0) + v = 0; + else if(v > 32) + v = 32; + if(p->as == ASRW || p->as == ASRWCC) { /* shift right */ + mask[0] = v; + mask[1] = 31; + v = 32-v; + } else { + mask[0] = 0; + mask[1] = 31-v; + } + o1 = OP_RLW(OP_RLWINM, p->to.reg, r, v, mask[0], mask[1]); + if(p->as == ASLWCC || p->as == ASRWCC) + o1 |= 1; /* Rc */ + break; + + case 58: /* logical $andcon,[s],a */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = LOP_IRR(opirr(p->as), p->to.reg, r, v); + break; + + case 59: /* or/and $ucon,,r */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = LOP_IRR(opirr(p->as+AEND), p->to.reg, r, v>>16); /* oris, xoris, andis */ + break; + + case 60: /* tw to,a,b */ + r = regoff(&p->from)&31L; + o1 = AOP_RRR(oprrr(p->as), r, p->reg, p->to.reg); + break; + + case 61: /* tw to,a,$simm */ + r = regoff(&p->from)&31L; + v = regoff(&p->to); + o1 = AOP_IRR(opirr(p->as), r, p->reg, v); + break; + + case 62: /* rlwmi $sh,s,$mask,a */ + v = regoff(&p->from); + maskgen(p, mask, regoff(&p->from3)); + o1 = AOP_RRR(opirr(p->as), p->reg, p->to.reg, v); + o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1); + break; + + case 63: /* rlwmi b,s,$mask,a */ + maskgen(p, mask, regoff(&p->from3)); + o1 = AOP_RRR(opirr(p->as), p->reg, p->to.reg, p->from.reg); + o1 |= ((mask[0]&31L)<<6)|((mask[1]&31L)<<1); + break; + + case 64: /* mtfsf fr[, $m] {,fpcsr} */ + if(p->from3.type != D_NONE) + v = regoff(&p->from3)&255L; + else + v = 255; + o1 = OP_MTFSF | (v<<17) | (p->from.reg<<11); + break; + + case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */ + if(p->to.reg == NREG) + diag("must specify FPSCR(n)\n%P", p); + o1 = OP_MTFSFI | ((p->to.reg&15L)<<23) | ((regoff(&p->from)&31L)<<12); + break; + + case 66: /* mov spr,r1; mov r1,spr, also dcr */ + if(p->from.type == D_REG) { + r = p->from.reg; + v = p->to.offset; + if(p->to.type == D_DCR) + o1 = OPVCC(31,451,0,0); /* mtdcr */ + else + o1 = OPVCC(31,467,0,0); /* mtspr */ + } else { + r = p->to.reg; + v = p->from.offset; + if(p->from.type == D_DCR) + o1 = OPVCC(31,323,0,0); /* mfdcr */ + else + o1 = OPVCC(31,339,0,0); /* mfspr */ + } + o1 = AOP_RRR(o1, r, 0, 0) | ((v&0x1f)<<16) | (((v>>5)&0x1f)<<11); + break; + + case 67: /* mcrf crfD,crfS */ + if(p->from.type != D_CREG || p->from.reg == NREG || + p->to.type != D_CREG || p->to.reg == NREG) + diag("illegal CR field number\n%P", p); + o1 = AOP_RRR(OP_MCRF, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0); + break; + + case 68: /* mfcr rD */ + if(p->from.type == D_CREG && p->from.reg != NREG) + diag("must move whole CR to register\n%P", p); + o1 = AOP_RRR(OP_MFCR, p->to.reg, 0, 0); + break; + + case 69: /* mtcrf CRM,rS */ + if(p->from3.type != D_NONE) { + if(p->to.reg != NREG) + diag("can't use both mask and CR(n)\n%P", p); + v = regoff(&p->from3) & 0xff; + } else { + if(p->to.reg == NREG) + v = 0xff; /* CR */ + else + v = 1<<(7-(p->to.reg&7)); /* CR(n) */ + } + o1 = AOP_RRR(OP_MTCRF, p->from.reg, 0, 0) | (v<<12); + break; + + case 70: /* [f]cmp r,r,cr*/ + if(p->reg == NREG) + r = 0; + else + r = (p->reg&7)<<2; + o1 = AOP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg); + break; + + case 71: /* cmp[l] r,i,cr*/ + if(p->reg == NREG) + r = 0; + else + r = (p->reg&7)<<2; + o1 = AOP_RRR(opirr(p->as), r, p->from.reg, 0) | (regoff(&p->to)&0xffff); + break; + + case 72: /* mcrxr crfD */ + if(p->to.reg == NREG) + diag("must move XER to CR(n)\n%P", p); + o1 = AOP_RRR(OP_MCRXR, ((p->to.reg&7L)<<2), 0, 0); + break; + + case 73: /* mcrfs crfD,crfS */ + if(p->from.type != D_FPSCR || p->from.reg == NREG || + p->to.type != D_CREG || p->to.reg == NREG) + diag("illegal FPSCR/CR field number\n%P", p); + o1 = AOP_RRR(OP_MCRFS, ((p->to.reg&7L)<<2), ((p->from.reg&7)<<2), 0); + break; + + /* relocation operations */ + + case 74: + v = regoff(&p->to); + o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); + o2 = AOP_IRR(opstore(p->as), p->from.reg, REGTMP, v); + if(dlm) + reloc(&p->to, p->pc, 1); + break; + + case 75: + v = regoff(&p->from); + o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); + o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v); + if(dlm) + reloc(&p->from, p->pc, 1); + break; + + case 76: + v = regoff(&p->from); + o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); + o2 = AOP_IRR(opload(p->as), p->to.reg, REGTMP, v); + o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0); + if(dlm) + reloc(&p->from, p->pc, 1); + break; + + } + if(aflag) + return o1; + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + lput(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + lput(o1); + lput(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + lput(o1); + lput(o2); + lput(o3); + break; + case 16: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, p); + lput(o1); + lput(o2); + lput(o3); + lput(o4); + break; + case 20: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, p); + lput(o1); + lput(o2); + lput(o3); + lput(o4); + lput(o5); + break; + } + return 0; +} + +long +oprrr(int a) +{ + switch(a) { + case AADD: return OPVCC(31,266,0,0); + case AADDCC: return OPVCC(31,266,0,1); + case AADDV: return OPVCC(31,266,1,0); + case AADDVCC: return OPVCC(31,266,1,1); + case AADDC: return OPVCC(31,10,0,0); + case AADDCCC: return OPVCC(31,10,0,1); + case AADDCV: return OPVCC(31,10,1,0); + case AADDCVCC: return OPVCC(31,10,1,1); + case AADDE: return OPVCC(31,138,0,0); + case AADDECC: return OPVCC(31,138,0,1); + case AADDEV: return OPVCC(31,138,1,0); + case AADDEVCC: return OPVCC(31,138,1,1); + case AADDME: return OPVCC(31,234,0,0); + case AADDMECC: return OPVCC(31,234,0,1); + case AADDMEV: return OPVCC(31,234,1,0); + case AADDMEVCC: return OPVCC(31,234,1,1); + case AADDZE: return OPVCC(31,202,0,0); + case AADDZECC: return OPVCC(31,202,0,1); + case AADDZEV: return OPVCC(31,202,1,0); + case AADDZEVCC: return OPVCC(31,202,1,1); + + case AAND: return OPVCC(31,28,0,0); + case AANDCC: return OPVCC(31,28,0,1); + case AANDN: return OPVCC(31,60,0,0); + case AANDNCC: return OPVCC(31,60,0,1); + + case ACMP: return OPVCC(31,0,0,0); + case ACMPU: return OPVCC(31,32,0,0); + + case ACNTLZW: return OPVCC(31,26,0,0); + case ACNTLZWCC: return OPVCC(31,26,0,1); + + case ACRAND: return OPVCC(19,257,0,0); + case ACRANDN: return OPVCC(19,129,0,0); + case ACREQV: return OPVCC(19,289,0,0); + case ACRNAND: return OPVCC(19,225,0,0); + case ACRNOR: return OPVCC(19,33,0,0); + case ACROR: return OPVCC(19,449,0,0); + case ACRORN: return OPVCC(19,417,0,0); + case ACRXOR: return OPVCC(19,193,0,0); + + case ADCBF: return OPVCC(31,86,0,0); + case ADCBI: return OPVCC(31,470,0,0); + case ADCBST: return OPVCC(31,54,0,0); + case ADCBT: return OPVCC(31,278,0,0); + case ADCBTST: return OPVCC(31,246,0,0); + case ADCBZ: return OPVCC(31,1014,0,0); + + case AREM: + case ADIVW: return OPVCC(31,491,0,0); + case AREMCC: + case ADIVWCC: return OPVCC(31,491,0,1); + case AREMV: + case ADIVWV: return OPVCC(31,491,1,0); + case AREMVCC: + case ADIVWVCC: return OPVCC(31,491,1,1); + case AREMU: + case ADIVWU: return OPVCC(31,459,0,0); + case AREMUCC: + case ADIVWUCC: return OPVCC(31,459,0,1); + case AREMUV: + case ADIVWUV: return OPVCC(31,459,1,0); + case AREMUVCC: + case ADIVWUVCC: return OPVCC(31,459,1,1); + + case AEIEIO: return OPVCC(31,854,0,0); + + case AEQV: return OPVCC(31,284,0,0); + case AEQVCC: return OPVCC(31,284,0,1); + + case AEXTSB: return OPVCC(31,954,0,0); + case AEXTSBCC: return OPVCC(31,954,0,1); + case AEXTSH: return OPVCC(31,922,0,0); + case AEXTSHCC: return OPVCC(31,922,0,1); + + case AFABS: return OPVCC(63,264,0,0); + case AFABSCC: return OPVCC(63,264,0,1); + case AFADD: return OPVCC(63,21,0,0); + case AFADDCC: return OPVCC(63,21,0,1); + case AFADDS: return OPVCC(59,21,0,0); + case AFADDSCC: return OPVCC(59,21,0,1); + case AFCMPO: return OPVCC(63,32,0,0); + case AFCMPU: return OPVCC(63,0,0,0); + case AFCTIW: return OPVCC(63,14,0,0); + case AFCTIWCC: return OPVCC(63,14,0,1); + case AFCTIWZ: return OPVCC(63,15,0,0); + case AFCTIWZCC: return OPVCC(63,15,0,1); + case AFDIV: return OPVCC(63,18,0,0); + case AFDIVCC: return OPVCC(63,18,0,1); + case AFDIVS: return OPVCC(59,18,0,0); + case AFDIVSCC: return OPVCC(59,18,0,1); + case AFMADD: return OPVCC(63,29,0,0); + case AFMADDCC: return OPVCC(63,29,0,1); + case AFMADDS: return OPVCC(59,29,0,0); + case AFMADDSCC: return OPVCC(59,29,0,1); + case AFMOVS: + case AFMOVD: return OPVCC(63,72,0,0); /* load */ + case AFMOVDCC: return OPVCC(63,72,0,1); + case AFMSUB: return OPVCC(63,28,0,0); + case AFMSUBCC: return OPVCC(63,28,0,1); + case AFMSUBS: return OPVCC(59,28,0,0); + case AFMSUBSCC: return OPVCC(59,28,0,1); + case AFMUL: return OPVCC(63,25,0,0); + case AFMULCC: return OPVCC(63,25,0,1); + case AFMULS: return OPVCC(59,25,0,0); + case AFMULSCC: return OPVCC(59,25,0,1); + case AFNABS: return OPVCC(63,136,0,0); + case AFNABSCC: return OPVCC(63,136,0,1); + case AFNEG: return OPVCC(63,40,0,0); + case AFNEGCC: return OPVCC(63,40,0,1); + case AFNMADD: return OPVCC(63,31,0,0); + case AFNMADDCC: return OPVCC(63,31,0,1); + case AFNMADDS: return OPVCC(59,31,0,0); + case AFNMADDSCC: return OPVCC(59,31,0,1); + case AFNMSUB: return OPVCC(63,30,0,0); + case AFNMSUBCC: return OPVCC(63,30,0,1); + case AFNMSUBS: return OPVCC(59,30,0,0); + case AFNMSUBSCC: return OPVCC(59,30,0,1); + case AFRSP: return OPVCC(63,12,0,0); + case AFRSPCC: return OPVCC(63,12,0,1); + case AFSUB: return OPVCC(63,20,0,0); + case AFSUBCC: return OPVCC(63,20,0,1); + case AFSUBS: return OPVCC(59,20,0,0); + case AFSUBSCC: return OPVCC(59,20,0,1); + + case AICBI: return OPVCC(31,982,0,0); + case AISYNC: return OPVCC(19,150,0,0); + + /* lscb etc are not PowerPC instructions */ + + case AMTFSB0: return OPVCC(63,70,0,0); + case AMTFSB0CC: return OPVCC(63,70,0,1); + case AMTFSB1: return OPVCC(63,38,0,0); + case AMTFSB1CC: return OPVCC(63,38,0,1); + + case AMULHW: return OPVCC(31,75,0,0); + case AMULHWCC: return OPVCC(31,75,0,1); + case AMULHWU: return OPVCC(31,11,0,0); + case AMULHWUCC: return OPVCC(31,11,0,1); + case AMULLW: return OPVCC(31,235,0,0); + case AMULLWCC: return OPVCC(31,235,0,1); + case AMULLWV: return OPVCC(31,235,1,0); + case AMULLWVCC: return OPVCC(31,235,1,1); + + /* the following group is only available on IBM embedded powerpc */ + case AMACCHW: return OPVCC(4,172,0,0); + case AMACCHWCC: return OPVCC(4,172,0,1); + case AMACCHWS: return OPVCC(4,236,0,0); + case AMACCHWSCC: return OPVCC(4,236,0,1); + case AMACCHWSU: return OPVCC(4,204,0,0); + case AMACCHWSUCC: return OPVCC(4,204,0,1); + case AMACCHWSUV: return OPVCC(4,204,1,0); + case AMACCHWSUVCC: return OPVCC(4,204,1,1); + case AMACCHWSV: return OPVCC(4,236,1,0); + case AMACCHWSVCC: return OPVCC(4,236,1,1); + case AMACCHWU: return OPVCC(4,140,0,0); + case AMACCHWUCC: return OPVCC(4,140,0,1); + case AMACCHWUV: return OPVCC(4,140,1,0); + case AMACCHWUVCC: return OPVCC(4,140,1,1); + case AMACCHWV: return OPVCC(4,172,1,0); + case AMACCHWVCC: return OPVCC(4,172,1,1); + case AMACHHW: return OPVCC(4,44,0,0); + case AMACHHWCC: return OPVCC(4,44,0,1); + case AMACHHWS: return OPVCC(4,108,0,0); + case AMACHHWSCC: return OPVCC(4,108,0,1); + case AMACHHWSU: return OPVCC(4,76,0,0); + case AMACHHWSUCC: return OPVCC(4,76,0,1); + case AMACHHWSUV: return OPVCC(4,76,1,0); + case AMACHHWSUVCC: return OPVCC(4,76,1,1); + case AMACHHWSV: return OPVCC(4,108,1,0); + case AMACHHWSVCC: return OPVCC(4,108,1,1); + case AMACHHWU: return OPVCC(4,12,0,0); + case AMACHHWUCC: return OPVCC(4,12,0,1); + case AMACHHWUV: return OPVCC(4,12,1,0); + case AMACHHWUVCC: return OPVCC(4,12,1,1); + case AMACHHWV: return OPVCC(4,44,1,0); + case AMACHHWVCC: return OPVCC(4,44,1,1); + case AMACLHW: return OPVCC(4,428,0,0); + case AMACLHWCC: return OPVCC(4,428,0,1); + case AMACLHWS: return OPVCC(4,492,0,0); + case AMACLHWSCC: return OPVCC(4,492,0,1); + case AMACLHWSU: return OPVCC(4,460,0,0); + case AMACLHWSUCC: return OPVCC(4,460,0,1); + case AMACLHWSUV: return OPVCC(4,460,1,0); + case AMACLHWSUVCC: return OPVCC(4,460,1,1); + case AMACLHWSV: return OPVCC(4,492,1,0); + case AMACLHWSVCC: return OPVCC(4,492,1,1); + case AMACLHWU: return OPVCC(4,396,0,0); + case AMACLHWUCC: return OPVCC(4,396,0,1); + case AMACLHWUV: return OPVCC(4,396,1,0); + case AMACLHWUVCC: return OPVCC(4,396,1,1); + case AMACLHWV: return OPVCC(4,428,1,0); + case AMACLHWVCC: return OPVCC(4,428,1,1); + case AMULCHW: return OPVCC(4,168,0,0); + case AMULCHWCC: return OPVCC(4,168,0,1); + case AMULCHWU: return OPVCC(4,136,0,0); + case AMULCHWUCC: return OPVCC(4,136,0,1); + case AMULHHW: return OPVCC(4,40,0,0); + case AMULHHWCC: return OPVCC(4,40,0,1); + case AMULHHWU: return OPVCC(4,8,0,0); + case AMULHHWUCC: return OPVCC(4,8,0,1); + case AMULLHW: return OPVCC(4,424,0,0); + case AMULLHWCC: return OPVCC(4,424,0,1); + case AMULLHWU: return OPVCC(4,392,0,0); + case AMULLHWUCC: return OPVCC(4,392,0,1); + case ANMACCHW: return OPVCC(4,174,0,0); + case ANMACCHWCC: return OPVCC(4,174,0,1); + case ANMACCHWS: return OPVCC(4,238,0,0); + case ANMACCHWSCC: return OPVCC(4,238,0,1); + case ANMACCHWSV: return OPVCC(4,238,1,0); + case ANMACCHWSVCC: return OPVCC(4,238,1,1); + case ANMACCHWV: return OPVCC(4,174,1,0); + case ANMACCHWVCC: return OPVCC(4,174,1,1); + case ANMACHHW: return OPVCC(4,46,0,0); + case ANMACHHWCC: return OPVCC(4,46,0,1); + case ANMACHHWS: return OPVCC(4,110,0,0); + case ANMACHHWSCC: return OPVCC(4,110,0,1); + case ANMACHHWSV: return OPVCC(4,110,1,0); + case ANMACHHWSVCC: return OPVCC(4,110,1,1); + case ANMACHHWV: return OPVCC(4,46,1,0); + case ANMACHHWVCC: return OPVCC(4,46,1,1); + case ANMACLHW: return OPVCC(4,430,0,0); + case ANMACLHWCC: return OPVCC(4,430,0,1); + case ANMACLHWS: return OPVCC(4,494,0,0); + case ANMACLHWSCC: return OPVCC(4,494,0,1); + case ANMACLHWSV: return OPVCC(4,494,1,0); + case ANMACLHWSVCC: return OPVCC(4,494,1,1); + case ANMACLHWV: return OPVCC(4,430,1,0); + case ANMACLHWVCC: return OPVCC(4,430,1,1); + + case ANAND: return OPVCC(31,476,0,0); + case ANANDCC: return OPVCC(31,476,0,1); + case ANEG: return OPVCC(31,104,0,0); + case ANEGCC: return OPVCC(31,104,0,1); + case ANEGV: return OPVCC(31,104,1,0); + case ANEGVCC: return OPVCC(31,104,1,1); + case ANOR: return OPVCC(31,124,0,0); + case ANORCC: return OPVCC(31,124,0,1); + case AOR: return OPVCC(31,444,0,0); + case AORCC: return OPVCC(31,444,0,1); + case AORN: return OPVCC(31,412,0,0); + case AORNCC: return OPVCC(31,412,0,1); + + case ARFI: return OPVCC(19,50,0,0); + case ARFCI: return OPVCC(19,51,0,0); + + case ARLWMI: return OPVCC(20,0,0,0); + case ARLWMICC: return OPVCC(20,0,0,1); + case ARLWNM: return OPVCC(23,0,0,0); + case ARLWNMCC: return OPVCC(23,0,0,1); + + case ASYSCALL: return OPVCC(17,1,0,0); + + case ASLW: return OPVCC(31,24,0,0); + case ASLWCC: return OPVCC(31,24,0,1); + + case ASRAW: return OPVCC(31,792,0,0); + case ASRAWCC: return OPVCC(31,792,0,1); + + case ASRW: return OPVCC(31,536,0,0); + case ASRWCC: return OPVCC(31,536,0,1); + + case ASUB: return OPVCC(31,40,0,0); + case ASUBCC: return OPVCC(31,40,0,1); + case ASUBV: return OPVCC(31,40,1,0); + case ASUBVCC: return OPVCC(31,40,1,1); + case ASUBC: return OPVCC(31,8,0,0); + case ASUBCCC: return OPVCC(31,8,0,1); + case ASUBCV: return OPVCC(31,8,1,0); + case ASUBCVCC: return OPVCC(31,8,1,1); + case ASUBE: return OPVCC(31,136,0,0); + case ASUBECC: return OPVCC(31,136,0,1); + case ASUBEV: return OPVCC(31,136,1,0); + case ASUBEVCC: return OPVCC(31,136,1,1); + case ASUBME: return OPVCC(31,232,0,0); + case ASUBMECC: return OPVCC(31,232,0,1); + case ASUBMEV: return OPVCC(31,232,1,0); + case ASUBMEVCC: return OPVCC(31,232,1,1); + case ASUBZE: return OPVCC(31,200,0,0); + case ASUBZECC: return OPVCC(31,200,0,1); + case ASUBZEV: return OPVCC(31,200,1,0); + case ASUBZEVCC: return OPVCC(31,200,1,1); + + case ASYNC: return OPVCC(31,598,0,0); + case ATLBIE: return OPVCC(31,306,0,0); + case ATW: return OPVCC(31,4,0,0); + + case AXOR: return OPVCC(31,316,0,0); + case AXORCC: return OPVCC(31,316,0,1); + } + diag("bad r/r opcode %A", a); + return 0; +} + +long +opirr(int a) +{ + switch(a) { + case AADD: return OPVCC(14,0,0,0); + case AADDC: return OPVCC(12,0,0,0); + case AADDCCC: return OPVCC(13,0,0,0); + case AADD+AEND: return OPVCC(15,0,0,0); /* ADDIS/CAU */ + + case AANDCC: return OPVCC(28,0,0,0); + case AANDCC+AEND: return OPVCC(29,0,0,0); /* ANDIS./ANDIU. */ + + case ABR: return OPVCC(18,0,0,0); + case ABL: return OPVCC(18,0,0,0) | 1; + case ABC: return OPVCC(16,0,0,0); + case ABCL: return OPVCC(16,0,0,0) | 1; + + case ABEQ: return AOP_RRR(16<<26,12,2,0); + case ABGE: return AOP_RRR(16<<26,4,0,0); + case ABGT: return AOP_RRR(16<<26,12,1,0); + case ABLE: return AOP_RRR(16<<26,4,1,0); + case ABLT: return AOP_RRR(16<<26,12,0,0); + case ABNE: return AOP_RRR(16<<26,4,2,0); + case ABVC: return AOP_RRR(16<<26,4,3,0); + case ABVS: return AOP_RRR(16<<26,12,3,0); + + case ACMP: return OPVCC(11,0,0,0); + case ACMPU: return OPVCC(10,0,0,0); + case ALSW: return OPVCC(31,597,0,0); + + case AMULLW: return OPVCC(7,0,0,0); + + case AOR: return OPVCC(24,0,0,0); + case AOR+AEND: return OPVCC(25,0,0,0); /* ORIS/ORIU */ + + case ARLWMI: return OPVCC(20,0,0,0); /* rlwimi */ + case ARLWMICC: return OPVCC(20,0,0,1); + + case ARLWNM: return OPVCC(21,0,0,0); /* rlwinm */ + case ARLWNMCC: return OPVCC(21,0,0,1); + + case ASRAW: return OPVCC(31,824,0,0); + case ASRAWCC: return OPVCC(31,824,0,1); + + case ASTSW: return OPVCC(31,725,0,0); + + case ASUBC: return OPVCC(8,0,0,0); + + case ATW: return OPVCC(3,0,0,0); + + case AXOR: return OPVCC(26,0,0,0); /* XORIL */ + case AXOR+AEND: return OPVCC(27,0,0,0); /* XORIU */ + } + diag("bad opcode i/r %A", a); + return 0; +} + +/* + * load o(a),d + */ +long +opload(int a) +{ + switch(a) { + case AMOVW: return OPVCC(32,0,0,0); /* lwz */ + case AMOVWU: return OPVCC(33,0,0,0); /* lwzu */ + case AMOVB: + case AMOVBZ: return OPVCC(34,0,0,0); /* load */ + case AMOVBU: + case AMOVBZU: return OPVCC(35,0,0,0); + case AFMOVD: return OPVCC(50,0,0,0); + case AFMOVDU: return OPVCC(51,0,0,0); + case AFMOVS: return OPVCC(48,0,0,0); + case AFMOVSU: return OPVCC(49,0,0,0); + case AMOVH: return OPVCC(42,0,0,0); + case AMOVHU: return OPVCC(43,0,0,0); + case AMOVHZ: return OPVCC(40,0,0,0); + case AMOVHZU: return OPVCC(41,0,0,0); + case AMOVMW: return OPVCC(46,0,0,0); /* lmw */ + } + diag("bad load opcode %A", a); + return 0; +} + +/* + * indexed load a(b),d + */ +long +oploadx(int a) +{ + switch(a) { + case AMOVW: return OPVCC(31,23,0,0); /* lwzx */ + case AMOVWU: return OPVCC(31,55,0,0); /* lwzux */ + case AMOVB: + case AMOVBZ: return OPVCC(31,87,0,0); /* lbzx */ + case AMOVBU: + case AMOVBZU: return OPVCC(31,119,0,0); /* lbzux */ + case AFMOVD: return OPVCC(31,599,0,0); /* lfdx */ + case AFMOVDU: return OPVCC(31,631,0,0); /* lfdux */ + case AFMOVS: return OPVCC(31,535,0,0); /* lfsx */ + case AFMOVSU: return OPVCC(31,567,0,0); /* lfsux */ + case AMOVH: return OPVCC(31,343,0,0); /* lhax */ + case AMOVHU: return OPVCC(31,375,0,0); /* lhaux */ + case AMOVHBR: return OPVCC(31,790,0,0); /* lhbrx */ + case AMOVWBR: return OPVCC(31,534,0,0); /* lwbrx */ + case AMOVHZ: return OPVCC(31,279,0,0); /* lhzx */ + case AMOVHZU: return OPVCC(31,311,0,0); /* lhzux */ + case AECIWX: return OPVCC(31,310,0,0); /* eciwx */ + case ALWAR: return OPVCC(31,20,0,0); /* lwarx */ + case ALSW: return OPVCC(31,533,0,0); /* lswx */ + } + diag("bad loadx opcode %A", a); + return 0; +} + +/* + * store s,o(d) + */ +long +opstore(int a) +{ + switch(a) { + case AMOVB: + case AMOVBZ: return OPVCC(38,0,0,0); /* stb */ + case AMOVBU: + case AMOVBZU: return OPVCC(39,0,0,0); /* stbu */ + case AFMOVD: return OPVCC(54,0,0,0); /* stfd */ + case AFMOVDU: return OPVCC(55,0,0,0); /* stfdu */ + case AFMOVS: return OPVCC(52,0,0,0); /* stfs */ + case AFMOVSU: return OPVCC(53,0,0,0); /* stfsu */ + case AMOVHZ: + case AMOVH: return OPVCC(44,0,0,0); /* sth */ + case AMOVHZU: + case AMOVHU: return OPVCC(45,0,0,0); /* sthu */ + case AMOVMW: return OPVCC(47,0,0,0); /* stmw */ + case ASTSW: return OPVCC(31,725,0,0); /* stswi */ + case AMOVW: return OPVCC(36,0,0,0); /* stw */ + case AMOVWU: return OPVCC(37,0,0,0); /* stwu */ + } + diag("unknown store opcode %A", a); + return 0; +} + +/* + * indexed store s,a(b) + */ +long +opstorex(int a) +{ + switch(a) { + case AMOVB: + case AMOVBZ: return OPVCC(31,215,0,0); /* stbx */ + case AMOVBU: + case AMOVBZU: return OPVCC(31,247,0,0); /* stbux */ + case AFMOVD: return OPVCC(31,727,0,0); /* stfdx */ + case AFMOVDU: return OPVCC(31,759,0,0); /* stfdux */ + case AFMOVS: return OPVCC(31,663,0,0); /* stfsx */ + case AFMOVSU: return OPVCC(31,695,0,0); /* stfsux */ + case AMOVHZ: + case AMOVH: return OPVCC(31,407,0,0); /* sthx */ + case AMOVHBR: return OPVCC(31,918,0,0); /* sthbrx */ + case AMOVHZU: + case AMOVHU: return OPVCC(31,439,0,0); /* sthux */ + case AMOVW: return OPVCC(31,151,0,0); /* stwx */ + case AMOVWU: return OPVCC(31,183,0,0); /* stwux */ + case ASTSW: return OPVCC(31,661,0,0); /* stswx */ + case AMOVWBR: return OPVCC(31,662,0,0); /* stwbrx */ + case ASTWCCC: return OPVCC(31,150,0,1); /* stwcx. */ + case AECOWX: return OPVCC(31,438,0,0); /* ecowx */ + } + diag("unknown storex opcode %A", a); + return 0; +} diff --git a/utils/ql/cnam.c b/utils/ql/cnam.c new file mode 100644 index 00000000..bc6d8c2b --- /dev/null +++ b/utils/ql/cnam.c @@ -0,0 +1,37 @@ +char *cnames[] = +{ + "NONE", + "REG", + "FREG", + "CREG", + "SPR", + "SREG", + "ZCON", + "SCON", + "UCON", + "ADDCON", + "ANDCON", + "LCON", + "SACON", + "SECON", + "LACON", + "LECON", + "SBRA", + "LBRA", + "SAUTO", + "LAUTO", + "SEXT", + "LEXT", + "ZOREG", + "SOREG", + "LOREG", + "FPSCR", + "MSR", + "XER", + "LR", + "CTR", + "ANY", + "GOK", + "ADDR", + "NCLASS", +}; diff --git a/utils/ql/l.h b/utils/ql/l.h new file mode 100644 index 00000000..7ec4aa60 --- /dev/null +++ b/utils/ql/l.h @@ -0,0 +1,335 @@ +#include <lib9.h> +#include <bio.h> +#include "../qc/q.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Adr Adr; +typedef struct Sym Sym; +typedef struct Autom Auto; +typedef struct Prog Prog; +typedef struct Optab Optab; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Adr +{ + union + { + long u0offset; + char u0sval[NSNAME]; + Ieee u0ieee; + }u0; + Sym *sym; + Auto *autom; + char type; + uchar reg; + char name; + char class; +}; + +#define offset u0.u0offset +#define sval u0.u0sval +#define ieee u0.u0ieee + +struct Prog +{ + Adr from; + Adr from3; /* fma and rlwm */ + Adr to; + Prog *forwd; + Prog *cond; + Prog *link; + long pc; + long regused; + short line; + short mark; + short optab; /* could be uchar */ + uchar as; + char reg; +}; +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + uchar subtype; + ushort file; + long value; + long sig; + Sym *link; +}; +struct Autom +{ + Sym *sym; + Auto *link; + long aoffset; + short type; +}; +struct Optab +{ + uchar as; + char a1; + char a2; + char a3; + char a4; + char type; + char size; + char param; +}; +struct +{ + Optab* start; + Optab* stop; +} oprange[ALAST]; + +enum +{ + FPCHIP = 1, + BIG = 32768-8, + STRINGSZ = 200, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ + DATBLK = 1024, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 64, + NENT = 100, + NSCHED = 20, + +/* mark flags */ + LABEL = 1<<0, + LEAF = 1<<1, + FLOAT = 1<<2, + BRANCH = 1<<3, + LOAD = 1<<4, + FCMP = 1<<5, + SYNC = 1<<6, + LIST = 1<<7, + FOLL = 1<<8, + NOSCHED = 1<<9, + + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SLEAF, + SFILE, + SCONST, + SUNDEF, + + SIMPORT, + SEXPORT, + + C_NONE = 0, + C_REG, + C_FREG, + C_CREG, + C_SPR, /* special processor register */ + C_SREG, /* segment register (32 bit implementations only) */ + C_ZCON, + C_SCON, /* 16 bit signed */ + C_UCON, /* low 16 bits 0 */ + C_ADDCON, /* -0x8000 <= v < 0 */ + C_ANDCON, /* 0 < v <= 0xFFFF */ + C_LCON, /* other */ + C_SACON, + C_SECON, + C_LACON, + C_LECON, + C_SBRA, + C_LBRA, + C_SAUTO, + C_LAUTO, + C_SEXT, + C_LEXT, + C_ZOREG, + C_SOREG, + C_LOREG, + C_FPSCR, + C_MSR, + C_XER, + C_LR, + C_CTR, + C_ANY, + C_GOK, + C_ADDR, + + C_NCLASS, + + Roffset = 22, /* no. bits for offset in relocation address */ + Rindex = 10 /* no. bits for index in relocation address */ +}; + +EXTERN union +{ + struct + { + uchar obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +EXTERN long HEADR; /* length of header */ +EXTERN int HEADTYPE; /* type of header */ +EXTERN long INITDAT; /* data location */ +EXTERN long INITRND; /* data round above text location */ +EXTERN long INITTEXT; /* text location */ +EXTERN char* INITENTRY; /* entry point */ +EXTERN long autosize; +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN Prog* prog_movsw; +EXTERN Prog* prog_movdw; +EXTERN Prog* prog_movws; +EXTERN Prog* prog_movwd; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* firstp; +EXTERN char fnuxi8[8]; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN char literal[32]; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN char* noname; +EXTERN long instoffset; +EXTERN char* outfile; +EXTERN long pc; +EXTERN int r0iszero; +EXTERN long symsize; +EXTERN long staticgen; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long tothunk; +EXTERN char xcmp[C_NCLASS][C_NCLASS]; +EXTERN int version; +EXTERN Prog zprg; +EXTERN int dtype; + +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[]; +extern char* cnames[]; + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Nconv(Fmt*); +int Pconv(Fmt*); +int Sconv(Fmt*); +int Rconv(Fmt*); +int aclass(Adr*); +void addhist(long, int); +void histtoauto(void); +void addnop(Prog*); +void append(Prog*, Prog*); +void asmb(void); +void asmdyn(void); +void asmlc(void); +int asmout(Prog*, Optab*, int); +void asmsym(void); +long atolwhex(char*); +Prog* brloop(Prog*); +void buildop(void); +void cflush(void); +void ckoff(Sym*, long); +int cmp(int, int); +void cput(long); +int compound(Prog*); +double cputime(void); +void datblk(long, long); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +void dynreloc(Sym*, long, int, int, int); +long entryvalue(void); +void errorexit(void); +void exchange(Prog*); +void export(void); +int find1(long, int); +void follow(void); +void gethunk(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +void import(void); +int isnop(Prog*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +void initmuldiv(void); +Sym* lookup(char*, int); +void lput(long); +void mkfwd(void); +void* mysbrk(ulong); +void names(void); +void nocache(Prog*); +void noops(void); +void nuxiinit(void); +void objfile(char*); +int ocmp(void*, void*); +long opcode(int); +Optab* oplook(Prog*); +void patch(void); +void prasm(Prog*); +void prepend(Prog*, Prog*); +Prog* prg(void); +int pseudo(Prog*); +void putsymb(char*, int, long, int); +void readundefs(char*, int); +long regoff(Adr*); +int relinv(int); +long rnd(long, long); +void sched(Prog*, Prog*); +void span(void); +void undef(void); +void undefsym(Sym*); +void wput(long); +void xdefine(char*, int, long); +void xfol(Prog*); +void zerosig(char*); + +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "A" int +#pragma varargck type "S" char* diff --git a/utils/ql/list.c b/utils/ql/list.c new file mode 100644 index 00000000..28578779 --- /dev/null +++ b/utils/ql/list.c @@ -0,0 +1,311 @@ +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('R', Rconv); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], *s; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + curp = p; + a = p->as; + if(a == ADATA || a == AINIT || a == ADYNT) + sprint(str, "(%d) %A %D/%d,%D", p->line, a, &p->from, p->reg, &p->to); + else { + s = str; + if(p->mark & NOSCHED) + s += sprint(s, "*"); + if(p->reg == NREG && p->from3.type == D_NONE) + sprint(s, "(%d) %A %D,%D", p->line, a, &p->from, &p->to); + else + if(a != ATEXT && p->from.type == D_OREG) { + sprint(s, "(%d) %A %ld(R%d+R%d),%D", p->line, a, + p->from.offset, p->from.reg, p->reg, &p->to); + } else + if(p->to.type == D_OREG) { + sprint(s, "(%d) %A %D,%ld(R%d+R%d)", p->line, a, + &p->from, p->to.offset, p->to.reg, p->reg); + } else { + s += sprint(s, "(%d) %A %D", p->line, a, &p->from); + if(p->reg != NREG) + s += sprint(s, ",%c%d", p->from.type==D_FREG?'F':'R', p->reg); + if(p->from3.type != D_NONE) + s += sprint(s, ",%D", &p->from3); + sprint(s, ",%D", &p->to); + } + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + long v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(F%d)(REG)", a, a->reg); + break; + + case D_CREG: + if(a->reg == NREG) + strcpy(str, "CR"); + else + sprint(str, "CR%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(C%d)(REG)", a, a->reg); + break; + + case D_SPR: + if(a->name == D_NONE && a->sym == S) { + switch(a->offset) { + case D_XER: sprint(str, "XER"); break; + case D_LR: sprint(str, "LR"); break; + case D_CTR: sprint(str, "CTR"); break; + default: sprint(str, "SPR(%ld)", a->offset); break; + } + break; + } + sprint(str, "SPR-GOK(%d)", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(SPR-GOK%d)(REG)", a, a->reg); + break; + + case D_DCR: + if(a->name == D_NONE && a->sym == S) { + sprint(str, "DCR(%ld)", a->offset); + break; + } + sprint(str, "DCR-GOK(%d)", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(DCR-GOK%d)(REG)", a, a->reg); + break; + + case D_OPT: + sprint(str, "OPT(%d)", a->reg); + break; + + case D_FPSCR: + if(a->reg == NREG) + strcpy(str, "FPSCR"); + else + sprint(str, "FPSCR(%d)", a->reg); + break; + + case D_MSR: + sprint(str, "MSR"); + break; + + case D_SREG: + sprint(str, "SREG(%d)", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(SREG%d)(REG)", a, a->reg); + break; + + case D_BRANCH: + if(curp->cond != P) { + v = curp->cond->pc; + if(v >= INITTEXT) + v -= INITTEXT-HEADR; + if(a->sym != S) + sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + else + sprint(str, "%.5lux(BRANCH)", v); + } else + if(a->sym != S) + sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + else + sprint(str, "%ld(APC)", a->offset); + break; + + case D_FCONST: + sprint(str, "$%lux-%lux", a->ieee.h, a->ieee.l); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "C_??"; + if(a >= C_NONE && a <= C_NCLASS) + s = cnames[a]; + return fmtstrcpy(fp, s); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(long); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/ql/mkcname b/utils/ql/mkcname new file mode 100644 index 00000000..cc93d9db --- /dev/null +++ b/utils/ql/mkcname @@ -0,0 +1,17 @@ +ed - ../ql/l.h <<'!' +v/^ C_/d +g/^ C_NCLASS/s//&,/ +g/[ ]*=.*,/s//,/ +v/,/p +,s/^ C_/ "/ +,s/,.*$/",/ +1i +char *cnames[] = +{ +. +,a +}; +. +w cnam.c +Q +! diff --git a/utils/ql/mkfile b/utils/ql/mkfile new file mode 100644 index 00000000..19391282 --- /dev/null +++ b/utils/ql/mkfile @@ -0,0 +1,33 @@ +<../../mkconfig + +TARG=ql + +OFILES=\ + asm.$O\ + list.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + enam.$O\ + noop.$O\ + asmout.$O\ + cnam.$O\ + sched.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../qc/q.out.h\ + ../include/ar.h\ + +LIBS=bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +enam.$O: ../qc/enam.c + $CC $CFLAGS ../qc/enam.c diff --git a/utils/ql/noop.c b/utils/ql/noop.c new file mode 100644 index 00000000..abb35057 --- /dev/null +++ b/utils/ql/noop.c @@ -0,0 +1,513 @@ +#include "l.h" + +void +noops(void) +{ + Prog *p, *p1, *q, *q1; + int o, mov, aoffset, curframe, curbecome, maxbecome; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + q = P; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + if(p->to.offset > curframe) + curframe = p->to.offset; + + switch(p->as) { + /* too hard, just leave alone */ + 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; + + q = p; + p->mark |= LABEL|LEAF|SYNC; + if(p->link) + p->link->mark |= LABEL; + curtext = p; + break; + + case ANOR: + q = p; + if(p->to.type == D_REG) + if(p->to.reg == REGZERO) + p->mark |= LABEL|SYNC; + break; + + case ALWAR: + case ASTWCCC: + case AECIWX: + case AECOWX: + case AEIEIO: + case AICBI: + case AISYNC: + case ATLBIE: + case ADCBF: + case ADCBI: + case ADCBST: + case ADCBT: + case ADCBTST: + case ADCBZ: + case ASYNC: + case ATW: + case AWORD: + case ARFI: + case ARFCI: + q = p; + p->mark |= LABEL|SYNC; + continue; + + case AMOVW: + q = p; + switch(p->from.type) { + case D_MSR: + case D_SREG: + case D_SPR: + case D_FPSCR: + case D_CREG: + case D_DCR: + p->mark |= LABEL|SYNC; + } + switch(p->to.type) { + case D_MSR: + case D_SREG: + case D_SPR: + case D_FPSCR: + case D_CREG: + case D_DCR: + p->mark |= LABEL|SYNC; + } + continue; + + case AFABS: + case AFABSCC: + case AFADD: + case AFADDCC: + case AFCTIW: + case AFCTIWCC: + case AFCTIWZ: + case AFCTIWZCC: + case AFDIV: + case AFDIVCC: + case AFMADD: + case AFMADDCC: + case AFMOVD: + case AFMOVDU: + /* case AFMOVDS: */ + case AFMOVS: + case AFMOVSU: + /* case AFMOVSD: */ + case AFMSUB: + case AFMSUBCC: + case AFMUL: + case AFMULCC: + case AFNABS: + case AFNABSCC: + case AFNEG: + case AFNEGCC: + case AFNMADD: + case AFNMADDCC: + case AFNMSUB: + case AFNMSUBCC: + case AFRSP: + case AFRSPCC: + case AFSUB: + case AFSUBCC: + q = p; + p->mark |= FLOAT; + continue; + + case ABL: + case ABCL: + if(curtext != P) + curtext->mark &= ~LEAF; + + case ABC: + case ABEQ: + case ABGE: + case ABGT: + case ABLE: + case ABLT: + case ABNE: + case ABR: + case ABVC: + case ABVS: + + p->mark |= BRANCH; + q = p; + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + if(!(q1->mark & LEAF)) + q1->mark |= LABEL; + } else + p->mark |= LABEL; + q1 = p->link; + if(q1 != P) + q1->mark |= LABEL; + continue; + + case AFCMPO: + case AFCMPU: + q = p; + p->mark |= FCMP|FLOAT; + continue; + + case ARETURN: + /* special form of RETURN is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + + q = p; + if(p->link != P) + p->link->mark |= LABEL; + continue; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + default: + q = p; + continue; + } + } + 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 ABL: /* ABCL? */ + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + curtext = P; + for(p = firstp; p != P; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + mov = AMOVW; + aoffset = 0; + curtext = p; + autosize = p->to.offset + 4; + if((p->mark & LEAF) && autosize <= 4) + autosize = 0; + else + if(autosize & 4) + autosize += 4; + p->to.offset = autosize - 4; + + q = p; + if(autosize) { + /* use MOVWU to adjust R1 when saving R31, if autosize is small */ + if(!(curtext->mark & LEAF) && autosize >= -BIG && autosize <= BIG) { + mov = AMOVWU; + aoffset = -autosize; + } else { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = -autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + } else + if(!(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + curtext->mark |= LEAF; + } + + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; + break; + } + + q1 = prg(); + q1->as = mov; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGTMP; + q1->to.type = D_OREG; + q1->to.offset = aoffset; + q1->to.reg = REGSP; + + q1->link = q->link; + q->link = q1; + + q1 = prg(); + q1->as = AMOVW; + q1->line = p->line; + q1->from.type = D_SPR; + q1->from.offset = D_LR; + q1->to.type = D_REG; + q1->to.reg = REGTMP; + + q1->link = q->link; + q->link = q1; + break; + + case ARETURN: + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + p->as = ABR; + p->from = zprg.from; + p->to.type = D_SPR; + p->to.offset = D_LR; + p->mark |= BRANCH; + break; + } + + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + + q = prg(); + q->as = ABR; + q->line = p->line; + q->to.type = D_SPR; + q->to.offset = D_LR; + q->mark |= BRANCH; + + q->link = p->link; + p->link = q; + break; + } + + p->as = AMOVW; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGTMP; + q->to.type = D_SPR; + q->to.offset = D_LR; + + q->link = p->link; + p->link = q; + p = q; + + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + + q1 = prg(); + q1->as = ABR; + q1->line = p->line; + q1->to.type = D_SPR; + q1->to.offset = D_LR; + q1->mark |= BRANCH; + + q1->link = q->link; + q->link = q1; + break; + + become: + if(curtext->mark & LEAF) { + + q = prg(); + q->line = p->line; + q->as = ABR; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; + } + q = prg(); + q->line = p->line; + q->as = ABR; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->mark |= BRANCH; + q->link = p->link; + p->link = q; + + q = prg(); + q->line = p->line; + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + + q = prg(); + q->line = p->line; + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGTMP; + q->to.type = D_SPR; + q->to.offset = D_LR; + q->link = p->link; + p->link = q; + + p->as = AMOVW; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGTMP; + + break; + } + } + + if(debug['Q'] == 0) + return; + + curtext = P; + q = P; /* p - 1 */ + q1 = firstp; /* top of block */ + o = 0; /* count of instructions */ + for(p = firstp; p != P; p = p1) { + p1 = p->link; + o++; + if(p->mark & NOSCHED){ + if(q1 != p){ + sched(q1, q); + } + for(; p != P; p = p->link){ + if(!(p->mark & NOSCHED)) + break; + q = p; + } + p1 = p; + q1 = p; + o = 0; + continue; + } + if(p->mark & (LABEL|SYNC)) { + if(q1 != p) + sched(q1, q); + q1 = p; + o = 1; + } + if(p->mark & (BRANCH|SYNC)) { + sched(q1, p); + q1 = p1; + o = 0; + } + if(o >= NSCHED) { + sched(q1, p); + q1 = p1; + o = 0; + } + q = p; + } +} + +void +addnop(Prog *p) +{ + Prog *q; + + q = prg(); + q->as = ANOR; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGZERO; + q->to.type = D_REG; + q->to.reg = REGZERO; + + q->link = p->link; + p->link = q; +} diff --git a/utils/ql/obj.c b/utils/ql/obj.c new file mode 100644 index 00000000..a4e76c1c --- /dev/null +++ b/utils/ql/obj.c @@ -0,0 +1,1465 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = 'q'; +char *thestring = "power"; + +/* + * -H0 -T0x200000 -R0 is boot + * -H1 -T0x100000 -R4 is Be boot + * -H2 -T4128 -R4096 is plan9 format + * -H3 -T0x02010000 -D0x00001000 is raw + * -H4 -T0x1000200 -D0x20000e00 -R4 is aix xcoff executable + * -H5 -T0x80010000 -t0x10000 ELF, phys = 10000, vaddr = 0x8001... + */ + +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 c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + outfile = 0; + nerrors = 0; + curtext = P; + 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': + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = 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 'H': + a = ARGF(); + if(a) + HEADTYPE = 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; + if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) + readundefs(ARGF(), SIMPORT); + break; + } ARGEND + USED(argc); + if(*argv == 0) { + diag("usage: ql [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + r0iszero = debug['0'] == 0; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 0; + if(debug['B']) + HEADTYPE = 1; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + + case 0: /* boot */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 0x200000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096L; + break; + case 1: /* Be boot format (PEF) */ + HEADR = 208L; + if(INITTEXT == -1) + INITTEXT = 0x100000; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* raw */ + HEADR = 0; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) { + INITDAT = 0; + INITRND = 4; + } + if(INITRND == -1) + INITRND = 0; + break; + case 4: /* aix unix xcoff executable */ + HEADR = 20L+72L+3*40L; + if(INITTEXT == -1) + INITTEXT = 0x1000000L+HEADR; + if(INITDAT == -1) + INITDAT = 0x20000000; + if(INITRND == -1) + INITRND = 0; + break; + case 5: /* elf executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0x00400000L+HEADR; + if(INITDAT == -1) + INITDAT = 0x10000000; + if(INITRND == -1) + INITRND = 0; + 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%x -T0x%lux -D0x%lux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + zprg.as = AGOK; + zprg.reg = NREG; + zprg.from.name = D_NONE; + zprg.from.type = D_NONE; + zprg.from.reg = NREG; + zprg.from3 = zprg.from; + zprg.to = zprg.from; + buildop(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + dtype = 4; + if(outfile == 0) + outfile = "q.out"; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("%s: cannot create", outfile); + errorexit(); + } + nuxiinit(); + 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) + goto out; + 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(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + dodata(); + follow(); + if(firstp == P) + goto out; + noops(); + span(); + asmb(); + undef(); + +out: + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%ld memory used\n", tothunk); + Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + } + 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) +{ + + Bflush(&bso); + 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 i, c; + long l; + Sym *s; + Auto *u; + + c = p[2]; + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + p[0] = AEND+1; + return 0; + } + a->type = p[0]; + a->reg = p[1]; + a->sym = h[c]; + a->name = p[3]; + c = 4; + + if(a->reg > NREG) { + print("register out of range %d\n", a->reg); + p[0] = AEND+1; + return 0; /* force real diagnostic */ + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + p[0] = AEND+1; + return 0; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + case D_CREG: + case D_FPSCR: + case D_MSR: + case D_SREG: + case D_OPT: + break; + + case D_SPR: + case D_DCR: + case D_BRANCH: + case D_OREG: + case D_CONST: + a->offset = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + c += 4; + break; + + case D_SCONST: + memmove(a->sval, p+4, NSNAME); + c += NSNAME; + break; + + case D_FCONST: + a->ieee.l = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + a->ieee.h = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + } + s = a->sym; + if(s == S) + goto out; + i = a->name; + if(i != D_AUTO && i != D_PARAM) + goto out; + + l = a->offset; + for(u=curauto; u; u=u->link) + if(u->sym == s) + if(u->type == i) { + if(u->aoffset > l) + u->aoffset = l; + goto out; + } + + u = malloc(sizeof(Auto)); + + u->link = curauto; + curauto = u; + u->sym = s; + u->aoffset = l; + u->type = i; +out: + 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->sym = 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) +{ + Prog *p, *t; + Sym *h[NSYM], *s, *di; + int v, o, r, skip; + long ipc; + uchar *bloc, *bsize, *stop; + 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)); + histfrogp = 0; + version++; + 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]; /* as */ + if(o <= 0 || o >= ALAST) { + diag("%s: opcode out of range %d", pn, o); + print(" probably not a .q file\n"); + errorexit(); + } + if(o == ANAME || o == ASIGNAME) { + sig = 0; + if(o == ASIGNAME) { + sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24); + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[1]; /* type */ + o = bloc[2]; /* sym */ + bloc += 3; + c -= 3; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 1; + 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; + } + + if(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->reg = bloc[1] & 0x3f; + if(bloc[1] & 0x80) + p->mark = NOSCHED; + p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + r = zaddr(bloc+6, &p->from, h) + 6; + if(bloc[1] & 0x40) + r += zaddr(bloc+r, &p->from3, h); + else + p->from3 = zprg.from3; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(p->reg < 0 || p->reg > NREG) + diag("register out of range %d", p->reg); + + p->link = P; + p->cond = P; + + if(debug['W']) + print("%P\n", p); + + switch(o) { + 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 == S) { + diag("GLOBL must have a name\n%P", p); + errorexit(); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("redefinition: %s\n%P", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + break; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->reg = 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_CONST; + p->link = datap; + datap = p; + break; + + 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; + p->link = datap; + datap = p; + break; + + case ADATA: + p->link = datap; + datap = p; + break; + + case AGOK: + diag("unknown opcode\n%P", p); + p->pc = pc; + pc++; + break; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + curtext = p; + autosize = (p->to.offset+3L) & ~3L; + p->to.offset = autosize; + autosize += 4; + s = p->from.sym; + if(s == S) { + diag("TEXT must have a name\n%P", p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->reg & DUPOK) { + skip = 1; + goto casedef; + } + diag("redefinition: %s\n%P", s->name, p); + } + s->type = STEXT; + s->value = pc; + if(textp != P) { + for(t = textp; t->cond != P; t = t->cond) + ; + t->cond = p; + } else + textp = p; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + + case AFMOVS: + if(skip) + goto casedef; + + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 4; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AFMOVD: + if(skip) + goto casedef; + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case ASUBC: + if(p->from.type == D_CONST) { + p->from.offset = -p->from.offset; + p->as = AADDC; + } + goto casedef; + + case ASUBCCC: + if(p->from.type == D_CONST) { + p->from.offset = -p->from.offset; + p->as = AADDCCC; + } + goto casedef; + + case ASUB: + if(p->from.type == D_CONST) { + p->from.offset = -p->from.offset; + p->as = AADD; + } + goto casedef; + + default: + casedef: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + 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; + return s; +} + +Prog* +prg(void) +{ + Prog *p; + int n; + + n = (sizeof(Prog) + 3) & ~3; + while(nhunk < n) + gethunk(); + + p = (Prog*)hunk; + nhunk -= n; + hunk += n; + + *p = zprg; + return p; +} + +void +gethunk(void) +{ + char *h; + long nh; + + nh = NHUNK; + if(tothunk >= 5L*NHUNK) { + nh = 5L*NHUNK; + if(tothunk >= 25L*NHUNK) + nh = 25L*NHUNK; + } + h = mysbrk(nh); + if(h == (char *)-1) { + diag("out of memory"); + errorexit(); + } + + hunk = h; + nhunk = nh; + tothunk += 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_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 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 = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_OREG; + p->to.name = 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_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 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->reg = 1; + ps2 = p; + } + if(p->from.sym == s4) { + p->reg = 1; + ps4 = p; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + + if(p->reg & NOPROF) { /* dont profile */ + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * BL profin + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = ABL; + p->to.type = D_BRANCH; + p->cond = ps2; + p->to.sym = s2; + + continue; + } + if(p->as == ARETURN) { + + /* + * RETURN + */ + q = prg(); + q->as = ARETURN; + q->from = p->from; + q->to = p->to; + q->link = p->link; + p->link = q; + + /* + * BL profout + */ + p->as = ABL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x01020304L, i+1); + if(i >= 2) + inuxi2[i-2] = c; + if(i >= 3) + inuxi1[i-3] = c; + inuxi4[i] = c; + + fnuxi8[i] = c+4; + fnuxi8[i+4] = c; + } + 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<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; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->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 |= ieeep->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); +} diff --git a/utils/ql/optab.c b/utils/ql/optab.c new file mode 100644 index 00000000..8a9de1bb --- /dev/null +++ b/utils/ql/optab.c @@ -0,0 +1,289 @@ +#include "l.h" + +Optab optab[] = +{ + { ATEXT, C_LEXT, C_NONE, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_NONE, C_LCON, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_LCON, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_NONE, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_REG, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_NONE, C_LCON, C_LCON, 0, 0, 0 }, + { ATEXT, C_ADDR, C_REG, C_LCON, C_LCON, 0, 0, 0 }, + + { AMOVW, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0 }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0 }, + + { AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 }, + { AADD, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 }, + { AADD, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 }, + { AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0 }, + { AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0 }, + { AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 }, + { AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 }, + + { AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 }, + { AADDC, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 }, + { AADDC, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 }, + { AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0 }, + { AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0 }, + + { AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, no literal */ + { AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 }, + { AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, + { AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 }, + + { AANDCC, C_ANDCON,C_NONE, C_NONE, C_REG, 58, 4, 0 }, + { AANDCC, C_ANDCON,C_REG, C_NONE, C_REG, 58, 4, 0 }, + { AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 }, + { AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 }, + { AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 }, + { AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 }, + + { AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 }, + { AMULLW, C_ADDCON,C_REG, C_NONE, C_REG, 4, 4, 0 }, + { AMULLW, C_ADDCON,C_NONE, C_NONE, C_REG, 4, 4, 0 }, + { AMULLW, C_ANDCON,C_REG, C_NONE, C_REG, 4, 4, 0 }, + { AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0 }, + { AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0}, + { AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0}, + + { ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 }, + { ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 }, + { ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0 }, + { ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0}, + + { AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, /* logical, literal not cc (or/xor) */ + { AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 }, + { AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0 }, + { AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0 }, + { AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0 }, + { AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0 }, + { AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0 }, + { AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0 }, + + { ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op r1[,r2],r3 */ + { ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0 }, + { ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0 }, /* op r2[,r1],r3 */ + { ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0 }, + + { ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 }, + { ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, + { ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0 }, + { ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0 }, + + { ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0 }, + { ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0 }, + { ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0 }, + { ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0 }, + + { ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0 }, + { ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0 }, + + { AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0 }, + { AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0 }, + { AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 }, + { AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0 }, + { AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0 }, + + { AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0 }, + { AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0 }, + { AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0 }, + + { AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO }, + { AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO }, + { AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO }, + { AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO }, + { AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO }, + { AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO }, + + { AMOVW, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVBZ, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVBZU, C_ZOREG,C_REG, C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVB, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO }, + { AMOVBU, C_ZOREG,C_REG, C_NONE, C_REG, 9, 8, REGZERO }, + { AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB }, + { AMOVW, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP }, + { AMOVBZ, C_SAUTO,C_NONE, C_NONE, C_REG, 8, 4, REGSP }, + { AMOVB, C_SAUTO,C_NONE, C_NONE, C_REG, 9, 8, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVBZ, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVBZU, C_SOREG,C_NONE, C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVB, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO }, + { AMOVBU, C_SOREG,C_NONE, C_NONE, C_REG, 9, 8, REGZERO }, + + { AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB }, + { AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB }, + { AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP }, + { AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP }, + { AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO }, + { AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO }, + { AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 }, + { AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 }, + { AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 }, + + { AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB }, + { AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB }, + { AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB }, + { AMOVW, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP }, + { AMOVBZ, C_LAUTO,C_NONE, C_NONE, C_REG, 36, 8, REGSP }, + { AMOVB, C_LAUTO,C_NONE, C_NONE, C_REG, 37, 12, REGSP }, + { AMOVW, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO }, + { AMOVBZ, C_LOREG,C_NONE, C_NONE, C_REG, 36, 8, REGZERO }, + { AMOVB, C_LOREG,C_NONE, C_NONE, C_REG, 37, 12, REGZERO }, + { AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 }, + { AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0 }, + { AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0 }, + + { AMOVW, C_SECON,C_NONE, C_NONE, C_REG, 3, 4, REGSB }, + { AMOVW, C_SACON,C_NONE, C_NONE, C_REG, 3, 4, REGSP }, + { AMOVW, C_LECON,C_NONE, C_NONE, C_REG, 26, 8, REGSB }, + { AMOVW, C_LACON,C_NONE, C_NONE, C_REG, 26, 8, REGSP }, + { AMOVW, C_ADDCON,C_NONE, C_NONE, C_REG, 3, 4, REGZERO }, + + { AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO }, + { AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0 }, + + { AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 }, + { AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 }, + { AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 }, + { AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 }, + + { ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0 }, + + { ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0 }, + { ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0 }, + + { ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, + + { ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0 }, + { ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0 }, + + { ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0 }, + { ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0 }, + { ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 }, + + { ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0 }, + { ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0 }, + { ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0 }, + { ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0 }, + { ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0 }, + + { AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB }, + { AFMOVD, C_SAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP }, + { AFMOVD, C_SOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO }, + + { AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB }, + { AFMOVD, C_LAUTO,C_NONE, C_NONE, C_FREG, 8, 4, REGSP }, + { AFMOVD, C_LOREG,C_NONE, C_NONE, C_FREG, 8, 4, REGZERO }, + { AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0 }, + + { AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB }, + { AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO }, + + { AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 7, 4, REGSB }, + { AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 7, 4, REGSP }, + { AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 7, 4, REGZERO }, + { AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0 }, + + { ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 }, + { AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0 }, + + { AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 }, + + { AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0 }, + { AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0 }, + + { ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0 }, + { ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0 }, + + { AREM, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0 }, + { AREM, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0 }, + + { AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0 }, + { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0 }, + { AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0 }, + { AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0 }, + { AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0 }, + { AMOVW, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0 }, + + { AMOVW, C_SREG, C_NONE, C_NONE, C_REG, 55, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_NONE, C_SREG, 55, 4, 0 }, + { AMOVW, C_SREG, C_REG, C_NONE, C_REG, 55, 4, 0 }, /* MOVW SR(Rn), Rm and v.v.*/ + { AMOVW, C_REG, C_REG, C_NONE, C_SREG, 55, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0 }, + { AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0 }, + { AMOVW, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0 }, + { AMOVW, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0 }, + { AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0 }, + + { AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0 }, + { AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0 }, + { AMOVW, C_XER, C_NONE, C_NONE, C_CREG, 72, 4, 0 }, + { AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0 }, + { AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0 }, + { AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0 }, + + { ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 }, + { ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 }, + { ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0 }, + { ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0 }, + + { ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0 }, + { ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0 }, + { ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0 }, + { ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0 }, + + { AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0 }, + { AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0 }, + + { ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0 }, + { ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0 }, + + { ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0 }, + { ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0 }, + + { AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0 }, + { AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0 }, + { AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 }, + { AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 }, + + { AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0 }, + { ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0 }, + + { ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0 }, + { ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0 }, + { ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0 }, + { ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0 }, + + { AMACCHW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0 }, /* op rb,ra,rt */ + + { AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, +}; diff --git a/utils/ql/pass.c b/utils/ql/pass.c new file mode 100644 index 00000000..1a4fc7b0 --- /dev/null +++ b/utils/ql/pass.c @@ -0,0 +1,667 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p, *p1; + long orig, orig1, v; + + 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); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%ld): %s\n%P", + s->value, s->name, p); + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rational is that data segment is more easily + * addressed through offset on REGSB) + */ + orig = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + while(v & 3) + v++; + s->value = v; + if(v > MINSIZ) + continue; + if(v >= 8) + while(orig & 7) + orig++; + s->value = orig; + orig += v; + s->type = SDATA1; + } + orig1 = orig; + + /* + * pass 2 + * assign 'data' variables to data segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + if(v >= 8) + while(orig & 7) + orig++; + s->value = orig; + orig += v; + s->type = SDATA1; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + v = s->value; + if(v >= 8) + while(orig & 7) + orig++; + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + /* + * pass 4 + * add literals to all large values. + * at this time: + * small data is allocated DATA + * large data is allocated DATA1 + * large bss is allocated BSS + * the new literals are loaded between + * small data and large data. + */ + orig = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as != AMOVW) + continue; + if(p->from.type != D_CONST) + continue; + if(s = p->from.sym) { + t = s->type; + if(t != SDATA && t != SDATA1 && t != SBSS) + continue; + t = p->from.name; + if(t != D_EXTERN && t != D_STATIC) + continue; + v = s->value + p->from.offset; + if(v >= 0 && v <= 0xffff) + continue; + if(!strcmp(s->name, "setSB")) + continue; + /* size should be 19 max */ + if(strlen(s->name) >= 10) /* has loader address */ + sprint(literal, "$%p.%lux", s, p->from.offset); + else + sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset); + } else { + if(p->from.name != D_NONE) + continue; + if(p->from.reg != NREG) + continue; + v = p->from.offset; + if(v >= -0x7fff-1 && v <= 0x7fff) + continue; + if(!(v & 0xffff)) + continue; + if(v) + continue; /* quicker to build it than load it */ + /* size should be 9 max */ + sprint(literal, "$%lux", v); + } + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + s->value = orig1+orig; + orig += 4; + p1 = prg(); + p1->as = ADATA; + p1->line = p->line; + p1->from.type = D_OREG; + p1->from.sym = s; + p1->from.name = D_EXTERN; + p1->reg = 4; + p1->to = p->from; + p1->link = datap; + datap = p1; + } + if(s->type != SDATA) + diag("literal not data: %s", s->name); + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + continue; + } + while(orig & 7) + orig++; + /* + * pass 5 + * re-adjust offsets + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t == SBSS) { + s->value += orig; + continue; + } + if(t == SDATA1) { + s->type = SDATA; + s->value += orig; + continue; + } + } + datsize += orig; + xdefine("setSB", SDATA, 0L+BIG); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +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); +} + +int +relinv(int a) +{ + + switch(a) { + case ABEQ: return ABNE; + case ABNE: return ABEQ; + + case ABGE: return ABLT; + case ABLT: return ABGE; + + case ABGT: return ABLE; + case ABLE: return ABGT; + + case ABVC: return ABVS; + case ABVS: return ABVC; + } + return 0; +} + +void +follow(void) +{ + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, b, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(a == ABR) { + q = p->cond; + if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){ + p->mark |= FOLL; + lastp->link = p; + lastp = p; + p = p->link; + xfol(p); + p = q; + if(p && !(p->mark & FOLL)) + goto loop; + return; + } + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp || (q->mark&NOSCHED)) + break; + b = 0; /* set */ + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI) + goto copy; + if(!q->cond || (q->cond->mark&FOLL)) + continue; + b = relinv(a); + if(!b) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI) + return; + r->as = b; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + + a = ABR; + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI){ + if(p->mark & NOSCHED){ + p = p->link; + goto loop; + } + return; + } + if(p->cond != P) + if(a != ABL && p->link != P) { + xfol(p->link); + p = p->cond; + if(p == P || (p->mark&FOLL)) + return; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((a == ABL || a == ARETURN) && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT && s->type != SUNDEF) { + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + } + if(s->type == SUNDEF){ + p->to.offset = 0; + p->cond = UP; + } + else + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH || p->cond == 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 %ld\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + p->mark = 0; /* initialization for follow */ + if(p->cond != P && p->cond != UP) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + 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) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(p->as != ABR || (p->mark&NOSCHED)) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +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; +} + +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; +} + +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)){ + undefsym(s); + Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value); + } +} + +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(); + p->link = datap; + datap = p; + p->as = ADATA; + p->reg = w; + p->from.type = D_OREG; + p->from.name = t; + p->from.sym = s; + p->from.offset = o; + p->to.type = D_CONST; + p->to.name = D_NONE; + 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]; + 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.name = 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.sval, buf, NSNAME); + nb = 0; + } + if(*t++ == 0) + break; + } + + /* name */ + p = newdata(et, off, sizeof(long), D_EXTERN); + off += sizeof(long); + p->to.name = 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.sval, 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); +} diff --git a/utils/ql/sched.c b/utils/ql/sched.c new file mode 100644 index 00000000..ea6c99af --- /dev/null +++ b/utils/ql/sched.c @@ -0,0 +1,801 @@ +#include "l.h" + +enum +{ + E_ICC = 1<<0, + E_FCC = 1<<1, + E_MEM = 1<<2, + E_MEMSP = 1<<3, /* uses offset and size */ + E_MEMSB = 1<<4, /* uses offset and size */ + E_LR = 1<<5, + E_CR = 1<<6, + E_CTR = 1<<7, + E_XER = 1<<8, + + E_CR0 = 0xF<<0, + E_CR1 = 0xF<<4, + + ANYMEM = E_MEM|E_MEMSP|E_MEMSB, + ALL = ~0, +}; + +typedef struct Sch Sch; +typedef struct Dep Dep; + +struct Dep +{ + ulong ireg; + ulong freg; + ulong cc; + ulong cr; +}; +struct Sch +{ + Prog p; + Dep set; + Dep used; + long soffset; + char size; + char comp; +}; + +void regused(Sch*, Prog*); +int depend(Sch*, Sch*); +int conflict(Sch*, Sch*); +int offoverlap(Sch*, Sch*); +void dumpbits(Sch*, Dep*); + +void +sched(Prog *p0, Prog *pe) +{ + Prog *p, *q; + Sch sch[NSCHED], *s, *t, *u, *se, stmp; + + if(!debug['Q']) + return; + /* + * build side structure + */ + s = sch; + for(p=p0;; p=p->link) { + memset(s, 0, sizeof(*s)); + s->p = *p; + regused(s, p); + if(debug['X']) { + Bprint(&bso, "%P\tset", &s->p); + dumpbits(s, &s->set); + Bprint(&bso, "; used"); + dumpbits(s, &s->used); + if(s->comp) + Bprint(&bso, "; compound"); + if(s->p.mark & LOAD) + Bprint(&bso, "; load"); + if(s->p.mark & BRANCH) + Bprint(&bso, "; branch"); + if(s->p.mark & FCMP) + Bprint(&bso, "; fcmp"); + Bprint(&bso, "\n"); + } + s++; + if(p == pe) + break; + } + se = s; + + for(s=se-1; s>=sch; s--) { + + /* + * load delay. interlocked. + */ + if(s->p.mark & LOAD) { + if(s >= se-1) + continue; + if(!conflict(s, (s+1))) + continue; + /* + * s is load, s+1 is immediate use of result + * t is the trial instruction to insert between s and s+1 + */ + for(t=s-1; t>=sch; t--) { + if(t->p.mark & BRANCH) + goto no2; + if(t->p.mark & FCMP) + if((s+1)->p.mark & BRANCH) + goto no2; + if(t->p.mark & LOAD) + if(conflict(t, (s+1))) + goto no2; + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no2; + goto out2; + no2:; + } + if(debug['X']) + Bprint(&bso, "?l%P\n", &s->p); + continue; + out2: + if(debug['X']) { + Bprint(&bso, "!l%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + continue; + } + + /* + * fop2 delay. + */ + if(s->p.mark & FCMP) { + if(s >= se-1) + continue; + if(!((s+1)->p.mark & BRANCH)) + continue; + /* t is the trial instruction to use */ + for(t=s-1; t>=sch; t--) { + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no3; + goto out3; + no3:; + } + if(debug['X']) + Bprint(&bso, "?f%P\n", &s->p); + continue; + out3: + if(debug['X']) { + Bprint(&bso, "!f%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + continue; + } + } + + /* + * put it all back + */ + for(s=sch, p=p0; s<se; s++, p=q) { + q = p->link; + if(q != s->p.link) { + *p = s->p; + p->link = q; + } + } + if(debug['X']) + Bprint(&bso, "\n"); +} + +void +regused(Sch *s, Prog *realp) +{ + int c, ar, ad, ld, sz, nr, upd; + ulong m; + Prog *p; + + p = &s->p; + s->comp = compound(p); + if(s->comp) { + s->set.ireg |= 1<<REGTMP; + s->used.ireg |= 1<<REGTMP; + } + ar = 0; /* dest is really reference */ + ad = 0; /* source/dest is really address */ + ld = 0; /* opcode is load instruction */ + sz = 32*4; /* size of load/store for overlap computation */ + nr = 0; /* source/dest is not really reg */ + upd = 0; /* move with update; changes reg */ + +/* + * flags based on opcode + */ + switch(p->as) { + case ATEXT: + curtext = realp; + autosize = p->to.offset + 4; + ad = 1; + break; + case ABL: + s->set.cc |= E_LR; + ar = 1; + ad = 1; + break; + case ABR: + ar = 1; + ad = 1; + break; + case ACMP: + s->set.cc |= E_ICC; + if(p->reg == 0) + s->set.cr |= E_CR0; + else + s->set.cr |= (0xF<<((p->reg&7)*4)); + ar = 1; + break; + case AFCMPO: + case AFCMPU: + s->set.cc |= E_FCC; + if(p->reg == 0) + s->set.cr |= E_CR0; + else + s->set.cr |= (0xF<<((p->reg&7)*4)); + ar = 1; + break; + case ACRAND: + case ACRANDN: + case ACREQV: + case ACRNAND: + case ACRNOR: + case ACROR: + case ACRORN: + case ACRXOR: + s->used.cr |= 1<<p->from.reg; + s->set.cr |= 1<<p->to.reg; + nr = 1; + break; + case ABCL: /* tricky */ + s->used.cc |= E_FCC|E_ICC; + s->used.cr = ALL; + s->set.cc |= E_LR; + ar = 1; + break; + case ABC: /* tricky */ + s->used.cc |= E_FCC|E_ICC; + s->used.cr = ALL; + ar = 1; + break; + case ABEQ: + case ABGE: + case ABGT: + case ABLE: + case ABLT: + case ABNE: + case ABVC: + case ABVS: + s->used.cc |= E_ICC; + s->used.cr |= E_CR0; + ar = 1; + break; + case ALSW: + case AMOVMW: + /* could do better */ + sz = 32*4; + ld = 1; + break; + case AMOVBU: + case AMOVBZU: + upd = 1; + sz = 1; + ld = 1; + break; + case AMOVB: + case AMOVBZ: + sz = 1; + ld = 1; + break; + case AMOVHU: + case AMOVHZU: + upd = 1; + sz = 2; + ld = 1; + break; + case AMOVH: + case AMOVHBR: + case AMOVHZ: + sz = 2; + ld = 1; + break; + case AFMOVSU: + case AMOVWU: + upd = 1; + sz = 4; + ld = 1; + break; + case AFMOVS: + case AMOVW: + case AMOVWBR: + case ALWAR: + sz = 4; + ld = 1; + break; + case AFMOVDU: + upd = 1; + sz = 8; + ld = 1; + break; + case AFMOVD: + sz = 8; + ld = 1; + break; + case AFMOVDCC: + sz = 8; + ld = 1; + s->set.cc |= E_FCC; + s->set.cr |= E_CR1; + break; + case AMOVFL: + case AMOVCRFS: + case AMTFSB0: + case AMTFSB0CC: + case AMTFSB1: + case AMTFSB1CC: + s->set.ireg = ALL; + s->set.freg = ALL; + s->set.cc = ALL; + s->set.cr = ALL; + break; + case AADDCC: + case AADDVCC: + case AADDCCC: + case AADDCVCC: + case AADDMECC: + case AADDMEVCC: + case AADDECC: + case AADDEVCC: + case AADDZECC: + case AADDZEVCC: + case AANDCC: + case AANDNCC: + case ACNTLZWCC: + case ADIVWCC: + case ADIVWVCC: + case ADIVWUCC: + case ADIVWUVCC: + case AEQVCC: + case AEXTSBCC: + case AEXTSHCC: + case AMULHWCC: + case AMULHWUCC: + case AMULLWCC: + case AMULLWVCC: + case ANANDCC: + case ANEGCC: + case ANEGVCC: + case ANORCC: + case AORCC: + case AORNCC: + case AREMCC: + case AREMVCC: + case AREMUCC: + case AREMUVCC: + case ARLWMICC: + case ARLWNMCC: + case ASLWCC: + case ASRAWCC: + case ASRWCC: + case ASTWCCC: + case ASUBCC: + case ASUBVCC: + case ASUBCCC: + case ASUBCVCC: + case ASUBMECC: + case ASUBMEVCC: + case ASUBECC: + case ASUBEVCC: + case ASUBZECC: + case ASUBZEVCC: + case AXORCC: + s->set.cc |= E_ICC; + s->set.cr |= E_CR0; + break; + case AFABSCC: + case AFADDCC: + case AFADDSCC: + case AFCTIWCC: + case AFCTIWZCC: + case AFDIVCC: + case AFDIVSCC: + case AFMADDCC: + case AFMADDSCC: + case AFMSUBCC: + case AFMSUBSCC: + case AFMULCC: + case AFMULSCC: + case AFNABSCC: + case AFNEGCC: + case AFNMADDCC: + case AFNMADDSCC: + case AFNMSUBCC: + case AFNMSUBSCC: + case AFRSPCC: + case AFSUBCC: + case AFSUBSCC: + s->set.cc |= E_FCC; + s->set.cr |= E_CR1; + break; + } + +/* + * flags based on 'to' field + */ + c = p->to.class; + if(c == 0) { + c = aclass(&p->to) + 1; + p->to.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->to); + + case C_NONE: + case C_ZCON: + case C_SCON: + case C_UCON: + case C_LCON: + case C_ADDCON: + case C_ANDCON: + case C_SBRA: + case C_LBRA: + break; + case C_CREG: + c = p->to.reg; + if(c == NREG) + s->set.cr = ALL; + else + s->set.cr |= (0xF << ((p->from.reg&7)*4)); + s->set.cc = ALL; + break; + case C_SPR: + case C_SREG: + case C_FPSCR: + case C_MSR: + case C_XER: + s->set.ireg = ALL; + s->set.freg = ALL; + s->set.cc = ALL; + s->set.cr = ALL; + break; + case C_LR: + s->set.cc |= E_LR; + break; + case C_CTR: + s->set.cc |= E_CTR; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + c = p->to.reg; + s->used.ireg |= 1<<c; + if(upd) + s->set.ireg |= 1<<c; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + if(ar) + s->used.cc |= m; + else + s->set.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + if(upd) + s->set.ireg |= 1<<c; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + if(upd) + s->set.ireg |= 1<<c; + break; + case C_REG: + if(nr) + break; + if(ar) + s->used.ireg |= 1<<p->to.reg; + else + s->set.ireg |= 1<<p->to.reg; + break; + case C_FREG: + if(ar) + s->used.freg |= 1<<p->to.reg; + else + s->set.freg |= 1<<p->to.reg; + break; + case C_SAUTO: + case C_LAUTO: + s->used.ireg |= 1<<REGSP; + if(upd) + s->set.ireg |= 1<<c; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSP; + else + s->set.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + s->used.ireg |= 1<<REGSB; + if(upd) + s->set.ireg |= 1<<c; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSB; + else + s->set.cc |= E_MEMSB; + break; + } + +/* + * flags based on 'from' field + */ + c = p->from.class; + if(c == 0) { + c = aclass(&p->from) + 1; + p->from.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->from); + + case C_NONE: + case C_ZCON: + case C_SCON: + case C_UCON: + case C_LCON: + case C_ADDCON: + case C_ANDCON: + case C_SBRA: + case C_LBRA: + c = p->from.reg; + if(c != NREG) + s->used.ireg |= 1<<c; + break; + case C_CREG: + c = p->from.reg; + if(c == NREG) + s->used.cr = ALL; + else + s->used.cr |= (0xF << ((p->from.reg&7)*4)); + s->used.cc = ALL; + break; + case C_SPR: + case C_SREG: + case C_FPSCR: + case C_MSR: + case C_XER: + s->set.ireg = ALL; + s->set.freg = ALL; + s->set.cc = ALL; + s->set.cr = ALL; + break; + case C_LR: + s->used.cc |= E_LR; + break; + case C_CTR: + s->used.cc |= E_CTR; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + c = p->from.reg; + s->used.ireg |= 1<<c; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + s->used.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + if(nr) + break; + s->used.ireg |= 1<<p->from.reg; + break; + case C_FREG: + s->used.freg |= 1<<p->from.reg; + break; + case C_SAUTO: + case C_LAUTO: + s->used.ireg |= 1<<REGSP; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + s->used.ireg |= 1<<REGSB; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSB; + break; + } + + c = p->reg; + if(c != NREG) { + if(p->from.type == D_FREG || p->to.type == D_FREG) + s->used.freg |= 1<<c; + else + s->used.ireg |= 1<<c; + } +} + +/* + * test to see if 2 instrictions can be + * interchanged without changing semantics + */ +int +depend(Sch *sa, Sch *sb) +{ + ulong x; + + if(sa->set.ireg & (sb->set.ireg|sb->used.ireg)) + return 1; + if(sb->set.ireg & sa->used.ireg) + return 1; + + if(sa->set.freg & (sb->set.freg|sb->used.freg)) + return 1; + if(sb->set.freg & sa->used.freg) + return 1; + + if(sa->set.cr & (sb->set.cr|sb->used.cr)) + return 1; + if(sb->set.cr & sa->used.cr) + return 1; + + + x = (sa->set.cc & (sb->set.cc|sb->used.cc)) | + (sb->set.cc & sa->used.cc); + if(x) { + /* + * allow SB and SP to pass each other. + * allow SB to pass SB iff doffsets are ok + * anything else conflicts + */ + if(x != E_MEMSP && x != E_MEMSB) + return 1; + x = sa->set.cc | sb->set.cc | + sa->used.cc | sb->used.cc; + if(x & E_MEM) + return 1; + if(offoverlap(sa, sb)) + return 1; + } + + return 0; +} + +int +offoverlap(Sch *sa, Sch *sb) +{ + + if(sa->soffset < sb->soffset) { + if(sa->soffset+sa->size > sb->soffset) + return 1; + return 0; + } + if(sb->soffset+sb->size > sa->soffset) + return 1; + return 0; +} + +/* + * test 2 adjacent instructions + * and find out if inserted instructions + * are desired to prevent stalls. + * first instruction is a load instruction. + */ +int +conflict(Sch *sa, Sch *sb) +{ + + if(sa->set.ireg & sb->used.ireg) + return 1; + if(sa->set.freg & sb->used.freg) + return 1; + if(sa->set.cr & sb->used.cr) + return 1; + return 0; +} + +int +compound(Prog *p) +{ + Optab *o; + + o = oplook(p); + if(o->size != 4) + return 1; + if(p->to.type == D_REG && p->to.reg == REGSB) + return 1; + return 0; +} + +void +dumpbits(Sch *s, Dep *d) +{ + int i; + + for(i=0; i<32; i++) + if(d->ireg & (1<<i)) + Bprint(&bso, " R%d", i); + for(i=0; i<32; i++) + if(d->freg & (1<<i)) + Bprint(&bso, " F%d", i); + for(i=0; i<32; i++) + if(d->cr & (1<<i)) + Bprint(&bso, " C%d", i); + for(i=0; i<32; i++) + switch(d->cc & (1<<i)) { + default: + break; + case E_ICC: + Bprint(&bso, " ICC"); + break; + case E_FCC: + Bprint(&bso, " FCC"); + break; + case E_LR: + Bprint(&bso, " LR"); + break; + case E_CR: + Bprint(&bso, " CR"); + break; + case E_CTR: + Bprint(&bso, " CTR"); + break; + case E_XER: + Bprint(&bso, " XER"); + break; + case E_MEM: + Bprint(&bso, " MEM%d", s->size); + break; + case E_MEMSB: + Bprint(&bso, " SB%d", s->size); + break; + case E_MEMSP: + Bprint(&bso, " SP%d", s->size); + break; + } +} diff --git a/utils/ql/span.c b/utils/ql/span.c new file mode 100644 index 00000000..b3ae1dd4 --- /dev/null +++ b/utils/ql/span.c @@ -0,0 +1,928 @@ +#include "l.h" +#define r0iszero 1 + +void +span(void) +{ + Prog *p; + Sym *setext; + Optab *o; + int m; + long c; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + p->pc = c; + o = oplook(p); + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from3.type == D_CONST) { + if(p->from3.offset & 3) + diag("illegal origin\n%P", p); + if(c > p->from3.offset) + diag("passed origin (#%lux)\n%P", c, p); + else + c = p->from3.offset; + p->pc = c; + } + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + if(p->as != ANOP) + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + c = rnd(c, 4); + + setext = lookup("etext", 0); + if(setext != S) { + setext->value = c; + textsize = c - INITTEXT; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(debug['v']) + Bprint(&bso, "tsize = %lux\n", textsize); + Bflush(&bso); +} + +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; + } +} + +long +regoff(Adr *a) +{ + + instoffset = 0; + aclass(a); + return instoffset; +} + +int +aclass(Adr *a) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_FREG: + return C_FREG; + + case D_CREG: + return C_CREG; + + case D_SPR: + if(a->offset == D_LR) + return C_LR; + if(a->offset == D_XER) + return C_XER; + if(a->offset == D_CTR) + return C_CTR; + return C_SPR; + + case D_DCR: + return C_SPR; + + case D_SREG: + return C_SREG; + + case D_FPSCR: + return C_FPSCR; + + case D_MSR: + return C_MSR; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == S) + break; + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + if(dlm){ + instoffset = a->sym->value + a->offset; + switch(a->sym->type){ + case STEXT: + case SLEAF: + case SCONST: + case SUNDEF: + break; + default: + instoffset += INITDAT; + } + return C_ADDR; + } + instoffset = a->sym->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SEXT; + return C_LEXT; + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + case D_NONE: + instoffset = a->offset; + if(instoffset == 0) + return C_ZOREG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SOREG; + return C_LOREG; + } + return C_GOK; + + case D_OPT: + instoffset = a->offset & 31L; + if(a->name == D_NONE) + return C_SCON; + return C_GOK; + + case D_CONST: + switch(a->name) { + + case D_NONE: + instoffset = a->offset; + consize: + if(instoffset >= 0) { + if(r0iszero && instoffset == 0) + return C_ZCON; + if(instoffset <= 0x7fff) + return C_SCON; + if(instoffset <= 0xffff) + return C_ANDCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + } + if(instoffset >= -0x8000) + return C_ADDCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == S) + break; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + } + if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) { + instoffset = s->value + a->offset; + return C_LCON; + } + if(s->type == SCONST) { + instoffset = s->value + a->offset; + if(dlm) + return C_LCON; + goto consize; + } + if(!dlm){ + instoffset = s->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG && instoffset != 0) + return C_SECON; + } + instoffset = s->value + a->offset + INITDAT; + if(dlm) + return C_LCON; +/* not sure why this barfs */ +return C_LCON; + if(instoffset == 0) + return C_ZCON; + if(instoffset >= -0x8000 && instoffset <= 0xffff) + return C_SCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +Optab* +oplook(Prog *p) +{ + int a1, a2, a3, a4, r; + char *c1, *c3, *c4; + Optab *o, *e; + + a1 = p->optab; + if(a1) + return optab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + a1 = aclass(&p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->from3.class; + if(a3 == 0) { + a3 = aclass(&p->from3) + 1; + p->from3.class = a3; + } + a3--; + a4 = p->to.class; + if(a4 == 0) { + a4 = aclass(&p->to) + 1; + p->to.class = a4; + } + a4--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = oprange[r].start; + if(o == 0) + o = oprange[r].stop; /* just generate an error */ + e = oprange[r].stop; + c1 = xcmp[a1]; + c3 = xcmp[a3]; + c4 = xcmp[a4]; + for(; o<e; o++) + if(o->a2 == a2) + if(c1[o->a1]) + if(c3[o->a3]) + if(c4[o->a4]) { + p->optab = (o-optab)+1; + return o; + } + diag("illegal combination %A %R %R %R %R", + p->as, a1, a2, a3, a4); + if(1||!debug['a']) + prasm(p); + if(o == 0) + errorexit(); + return o; +} + +int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON) + return 1; + break; + case C_ADDCON: + if(b == C_ZCON || b == C_SCON) + return 1; + break; + case C_ANDCON: + if(b == C_ZCON || b == C_SCON) + return 1; + break; + case C_SPR: + if(b == C_LR || b == C_XER || b == C_CTR) + return 1; + break; + case C_UCON: + if(b == C_ZCON) + return 1; + break; + case C_SCON: + if(b == C_ZCON) + return 1; + break; + case C_LACON: + if(b == C_SACON) + return 1; + break; + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + case C_LEXT: + if(b == C_SEXT) + return 1; + break; + case C_LAUTO: + if(b == C_SAUTO) + return 1; + break; + case C_REG: + if(r0iszero && b == C_ZCON) + return 1; + break; + case C_LOREG: + if(b == C_ZOREG || b == C_SOREG) + return 1; + break; + case C_SOREG: + if(b == C_ZOREG) + return 1; + break; + + case C_ANY: + return 1; + } + return 0; +} + +int +ocmp(void *a1, void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = a1; + p2 = a2; + n = p1->as - p2->as; + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a2 - p2->a2; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + n = p1->a4 - p2->a4; + if(n) + return n; + return 0; +} + +void +buildop(void) +{ + int i, n, r; + + for(i=0; i<C_NCLASS; i++) + for(n=0; n<C_NCLASS; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) + ; + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + diag("unknown op in build: %A", r); + errorexit(); + case ADCBF: /* unary indexed: op (b+a); op (b) */ + oprange[ADCBI] = oprange[r]; + oprange[ADCBST] = oprange[r]; + oprange[ADCBT] = oprange[r]; + oprange[ADCBTST] = oprange[r]; + oprange[ADCBZ] = oprange[r]; + oprange[AICBI] = oprange[r]; + break; + case AECOWX: /* indexed store: op s,(b+a); op s,(b) */ + oprange[ASTWCCC] = oprange[r]; + break; + case AREM: /* macro */ + oprange[AREMCC] = oprange[r]; + oprange[AREMV] = oprange[r]; + oprange[AREMVCC] = oprange[r]; + oprange[AREMU] = oprange[r]; + oprange[AREMUCC] = oprange[r]; + oprange[AREMUV] = oprange[r]; + oprange[AREMUVCC] = oprange[r]; + break; + case ADIVW: /* op Rb[,Ra],Rd */ + oprange[AMULHW] = oprange[r]; + oprange[AMULHWCC] = oprange[r]; + oprange[AMULHWU] = oprange[r]; + oprange[AMULHWUCC] = oprange[r]; + oprange[AMULLWCC] = oprange[r]; + oprange[AMULLWVCC] = oprange[r]; + oprange[AMULLWV] = oprange[r]; + oprange[ADIVWCC] = oprange[r]; + oprange[ADIVWV] = oprange[r]; + oprange[ADIVWVCC] = oprange[r]; + oprange[ADIVWU] = oprange[r]; + oprange[ADIVWUCC] = oprange[r]; + oprange[ADIVWUV] = oprange[r]; + oprange[ADIVWUVCC] = oprange[r]; + oprange[AADDCC] = oprange[r]; + oprange[AADDCV] = oprange[r]; + oprange[AADDCVCC] = oprange[r]; + oprange[AADDV] = oprange[r]; + oprange[AADDVCC] = oprange[r]; + oprange[AADDE] = oprange[r]; + oprange[AADDECC] = oprange[r]; + oprange[AADDEV] = oprange[r]; + oprange[AADDEVCC] = oprange[r]; + oprange[ACRAND] = oprange[r]; + oprange[ACRANDN] = oprange[r]; + oprange[ACREQV] = oprange[r]; + oprange[ACRNAND] = oprange[r]; + oprange[ACRNOR] = oprange[r]; + oprange[ACROR] = oprange[r]; + oprange[ACRORN] = oprange[r]; + oprange[ACRXOR] = oprange[r]; + oprange[AMULCHW] = oprange[r]; + oprange[AMULCHWCC] = oprange[r]; + oprange[AMULCHWU] = oprange[r]; + oprange[AMULCHWUCC] = oprange[r]; + oprange[AMULHHW] = oprange[r]; + oprange[AMULHHWCC] = oprange[r]; + oprange[AMULHHWU] = oprange[r]; + oprange[AMULHHWUCC] = oprange[r]; + oprange[AMULLHW] = oprange[r]; + oprange[AMULLHWCC] = oprange[r]; + oprange[AMULLHWU] = oprange[r]; + oprange[AMULLHWUCC] = oprange[r]; + break; + case AMACCHW: /* strictly 3 registers */ + oprange[AMACCHWCC] = oprange[r]; + oprange[AMACCHWS] = oprange[r]; + oprange[AMACCHWSCC] = oprange[r]; + oprange[AMACCHWSU] = oprange[r]; + oprange[AMACCHWSUCC] = oprange[r]; + oprange[AMACCHWSUV] = oprange[r]; + oprange[AMACCHWSUVCC] = oprange[r]; + oprange[AMACCHWSV] = oprange[r]; + oprange[AMACCHWSVCC] = oprange[r]; + oprange[AMACCHWU] = oprange[r]; + oprange[AMACCHWUCC] = oprange[r]; + oprange[AMACCHWUV] = oprange[r]; + oprange[AMACCHWUVCC] = oprange[r]; + oprange[AMACCHWV] = oprange[r]; + oprange[AMACCHWVCC] = oprange[r]; + oprange[AMACHHW] = oprange[r]; + oprange[AMACHHWCC] = oprange[r]; + oprange[AMACHHWS] = oprange[r]; + oprange[AMACHHWSCC] = oprange[r]; + oprange[AMACHHWSU] = oprange[r]; + oprange[AMACHHWSUCC] = oprange[r]; + oprange[AMACHHWSUV] = oprange[r]; + oprange[AMACHHWSUVCC] = oprange[r]; + oprange[AMACHHWSV] = oprange[r]; + oprange[AMACHHWSVCC] = oprange[r]; + oprange[AMACHHWU] = oprange[r]; + oprange[AMACHHWUCC] = oprange[r]; + oprange[AMACHHWUV] = oprange[r]; + oprange[AMACHHWUVCC] = oprange[r]; + oprange[AMACHHWV] = oprange[r]; + oprange[AMACHHWVCC] = oprange[r]; + oprange[AMACLHW] = oprange[r]; + oprange[AMACLHWCC] = oprange[r]; + oprange[AMACLHWS] = oprange[r]; + oprange[AMACLHWSCC] = oprange[r]; + oprange[AMACLHWSU] = oprange[r]; + oprange[AMACLHWSUCC] = oprange[r]; + oprange[AMACLHWSUV] = oprange[r]; + oprange[AMACLHWSUVCC] = oprange[r]; + oprange[AMACLHWSV] = oprange[r]; + oprange[AMACLHWSVCC] = oprange[r]; + oprange[AMACLHWU] = oprange[r]; + oprange[AMACLHWUCC] = oprange[r]; + oprange[AMACLHWUV] = oprange[r]; + oprange[AMACLHWUVCC] = oprange[r]; + oprange[AMACLHWV] = oprange[r]; + oprange[AMACLHWVCC] = oprange[r]; + oprange[ANMACCHW] = oprange[r]; + oprange[ANMACCHWCC] = oprange[r]; + oprange[ANMACCHWS] = oprange[r]; + oprange[ANMACCHWSCC] = oprange[r]; + oprange[ANMACCHWSV] = oprange[r]; + oprange[ANMACCHWSVCC] = oprange[r]; + oprange[ANMACCHWV] = oprange[r]; + oprange[ANMACCHWVCC] = oprange[r]; + oprange[ANMACHHW] = oprange[r]; + oprange[ANMACHHWCC] = oprange[r]; + oprange[ANMACHHWS] = oprange[r]; + oprange[ANMACHHWSCC] = oprange[r]; + oprange[ANMACHHWSV] = oprange[r]; + oprange[ANMACHHWSVCC] = oprange[r]; + oprange[ANMACHHWV] = oprange[r]; + oprange[ANMACHHWVCC] = oprange[r]; + oprange[ANMACLHW] = oprange[r]; + oprange[ANMACLHWCC] = oprange[r]; + oprange[ANMACLHWS] = oprange[r]; + oprange[ANMACLHWSCC] = oprange[r]; + oprange[ANMACLHWSV] = oprange[r]; + oprange[ANMACLHWSVCC] = oprange[r]; + oprange[ANMACLHWV] = oprange[r]; + oprange[ANMACLHWVCC] = oprange[r]; + break; +/* floating point move *//* + oprange[AFMR] = oprange[r]; + oprange[AFMRCC] = oprange[r]; +*/ +/**/ + case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */ + oprange[AMOVH] = oprange[r]; + oprange[AMOVHZ] = oprange[r]; + break; + case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x */ + oprange[AMOVHU] = oprange[r]; + oprange[AMOVHZU] = oprange[r]; + oprange[AMOVWU] = oprange[r]; + oprange[AMOVMW] = oprange[r]; + break; + case AAND: /* logical op Rb,Rs,Ra; no literal */ + oprange[AANDN] = oprange[r]; + oprange[AANDNCC] = oprange[r]; + oprange[AEQV] = oprange[r]; + oprange[AEQVCC] = oprange[r]; + oprange[ANAND] = oprange[r]; + oprange[ANANDCC] = oprange[r]; + oprange[ANOR] = oprange[r]; + oprange[ANORCC] = oprange[r]; + oprange[AORCC] = oprange[r]; + oprange[AORN] = oprange[r]; + oprange[AORNCC] = oprange[r]; + oprange[AXORCC] = oprange[r]; + break; + case AADDME: /* op Ra, Rd */ + oprange[AADDMECC] = oprange[r]; + oprange[AADDMEV] = oprange[r]; + oprange[AADDMEVCC] = oprange[r]; + oprange[AADDZE] = oprange[r]; + oprange[AADDZECC] = oprange[r]; + oprange[AADDZEV] = oprange[r]; + oprange[AADDZEVCC] = oprange[r]; + oprange[ASUBME] = oprange[r]; + oprange[ASUBMECC] = oprange[r]; + oprange[ASUBMEV] = oprange[r]; + oprange[ASUBMEVCC] = oprange[r]; + oprange[ASUBZE] = oprange[r]; + oprange[ASUBZECC] = oprange[r]; + oprange[ASUBZEV] = oprange[r]; + oprange[ASUBZEVCC] = oprange[r]; + break; + case AADDC: + oprange[AADDCCC] = oprange[r]; + break; + case ABEQ: + oprange[ABGE] = oprange[r]; + oprange[ABGT] = oprange[r]; + oprange[ABLE] = oprange[r]; + oprange[ABLT] = oprange[r]; + oprange[ABNE] = oprange[r]; + oprange[ABVC] = oprange[r]; + oprange[ABVS] = oprange[r]; + break; + case ABR: + oprange[ABL] = oprange[r]; + break; + case ABC: + oprange[ABCL] = oprange[r]; + break; + case AEXTSB: /* op Rs, Ra */ + oprange[AEXTSBCC] = oprange[r]; + oprange[AEXTSH] = oprange[r]; + oprange[AEXTSHCC] = oprange[r]; + oprange[ACNTLZW] = oprange[r]; + oprange[ACNTLZWCC] = oprange[r]; + break; + case AFABS: /* fop [s,]d */ + oprange[AFABSCC] = oprange[r]; + oprange[AFNABS] = oprange[r]; + oprange[AFNABSCC] = oprange[r]; + oprange[AFNEG] = oprange[r]; + oprange[AFNEGCC] = oprange[r]; + oprange[AFRSP] = oprange[r]; + oprange[AFRSPCC] = oprange[r]; + oprange[AFCTIW] = oprange[r]; + oprange[AFCTIWCC] = oprange[r]; + oprange[AFCTIWZ] = oprange[r]; + oprange[AFCTIWZCC] = oprange[r]; + break; + case AFADD: + oprange[AFADDS] = oprange[r]; + oprange[AFADDCC] = oprange[r]; + oprange[AFADDSCC] = oprange[r]; + oprange[AFDIV] = oprange[r]; + oprange[AFDIVS] = oprange[r]; + oprange[AFDIVCC] = oprange[r]; + oprange[AFDIVSCC] = oprange[r]; + oprange[AFSUB] = oprange[r]; + oprange[AFSUBS] = oprange[r]; + oprange[AFSUBCC] = oprange[r]; + oprange[AFSUBSCC] = oprange[r]; + break; + case AFMADD: + oprange[AFMADDCC] = oprange[r]; + oprange[AFMADDS] = oprange[r]; + oprange[AFMADDSCC] = oprange[r]; + oprange[AFMSUB] = oprange[r]; + oprange[AFMSUBCC] = oprange[r]; + oprange[AFMSUBS] = oprange[r]; + oprange[AFMSUBSCC] = oprange[r]; + oprange[AFNMADD] = oprange[r]; + oprange[AFNMADDCC] = oprange[r]; + oprange[AFNMADDS] = oprange[r]; + oprange[AFNMADDSCC] = oprange[r]; + oprange[AFNMSUB] = oprange[r]; + oprange[AFNMSUBCC] = oprange[r]; + oprange[AFNMSUBS] = oprange[r]; + oprange[AFNMSUBSCC] = oprange[r]; + break; + case AFMUL: + oprange[AFMULS] = oprange[r]; + oprange[AFMULCC] = oprange[r]; + oprange[AFMULSCC] = oprange[r]; + break; + case AFCMPO: + oprange[AFCMPU] = oprange[r]; + break; + case AMTFSB0: + oprange[AMTFSB0CC] = oprange[r]; + oprange[AMTFSB1] = oprange[r]; + oprange[AMTFSB1CC] = oprange[r]; + break; + case ANEG: /* op [Ra,] Rd */ + oprange[ANEGCC] = oprange[r]; + oprange[ANEGV] = oprange[r]; + oprange[ANEGVCC] = oprange[r]; + break; + case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */ + oprange[AXOR] = oprange[r]; + break; + case ASLW: + oprange[ASLWCC] = oprange[r]; + oprange[ASRW] = oprange[r]; + oprange[ASRWCC] = oprange[r]; + break; + case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */ + oprange[ASRAWCC] = oprange[r]; + break; + case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */ + oprange[ASUB] = oprange[r]; + oprange[ASUBCC] = oprange[r]; + oprange[ASUBV] = oprange[r]; + oprange[ASUBVCC] = oprange[r]; + oprange[ASUBCCC] = oprange[r]; + oprange[ASUBCV] = oprange[r]; + oprange[ASUBCVCC] = oprange[r]; + oprange[ASUBE] = oprange[r]; + oprange[ASUBECC] = oprange[r]; + oprange[ASUBEV] = oprange[r]; + oprange[ASUBEVCC] = oprange[r]; + break; + case ASYNC: + oprange[AISYNC] = oprange[r]; + break; + case ARLWMI: + oprange[ARLWMICC] = oprange[r]; + oprange[ARLWNM] = oprange[r]; + oprange[ARLWNMCC] = oprange[r]; + break; + case AFMOVD: + oprange[AFMOVDCC] = oprange[r]; + oprange[AFMOVDU] = oprange[r]; + oprange[AFMOVS] = oprange[r]; + oprange[AFMOVSU] = oprange[r]; + break; + case AECIWX: + oprange[ALWAR] = oprange[r]; + break; + case ASYSCALL: /* just the op; flow of control */ + oprange[ARFI] = oprange[r]; + oprange[ARFCI] = oprange[r]; + break; + case AMOVHBR: + oprange[AMOVWBR] = oprange[r]; + break; + case AADD: + case AANDCC: /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */ + case ACMP: + case ACMPU: + case AEIEIO: + case ALSW: + case AMOVB: /* macro: move byte with sign extension */ + case AMOVBU: /* macro: move byte with sign extension & update */ + case AMOVW: + case AMOVFL: + case AMULLW: /* op $s[,r2],r3; op r1[,r2],r3; no cc/v */ + case ASUBC: /* op r1,$s,r3; op r1[,r2],r3 */ + case ASTSW: + case ATLBIE: + case ATW: + case AWORD: + case ANOP: + case ATEXT: + break; + } + } +} + +enum{ + ABSD = 0, + ABSU = 1, + RELD = 2, + RELU = 3, +}; + +int modemap[8] = { 0, 1, -1, 2, 3, 4, 5, 6}; + +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, long v, int abs, int split, int sext) +{ + int i, k, n; + uchar *m; + ulong *a; + Reloc *r; + + if(v&3) + diag("bad relocation address"); + v >>= 2; + if(s->type == SUNDEF) + k = abs ? ABSU : RELU; + else + k = abs ? ABSD : RELD; + if(split) + k += 4; + if(sext) + k += 2; + /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, 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){ + wput(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); + } +} diff --git a/utils/rcsh/Nt.c b/utils/rcsh/Nt.c new file mode 100644 index 00000000..dc6ad8a9 --- /dev/null +++ b/utils/rcsh/Nt.c @@ -0,0 +1,549 @@ +#include "rc.h" +#include <windows.h> + +enum { + Nchild = 100, +}; + +typedef struct Child Child; + +struct Child { + int pid; + HANDLE handle; +}; + +static Child child[Nchild]; + +static void +winerror(void) +{ + int e, r; + char buf[100], *p, *q; + + e = GetLastError(); + + r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + 0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, sizeof(buf), 0); + + if(r == 0) + snprint(buf, sizeof(buf), "windows error %d", e); + + for(p=q=buf; *p; p++) { + if(*p == '\r') + continue; + if(*p == '\n') + *q++ = ' '; + else + *q++ = *p; + } + *q = 0; + errstr(buf, sizeof buf); +} + +static int +badentry(char *filename) +{ + if(*filename == 0) + return 1; + if(filename[0] == '.'){ + if(filename[1] == 0) + return 1; + if(filename[1] == '.' && filename[2] == 0) + return 1; + } + return 0; +} + +Direntry* +readdirect(char *path) +{ + long n; + HANDLE h; + Direntry *d; + char fullpath[MAX_PATH]; + WIN32_FIND_DATA data; + + snprint(fullpath, MAX_PATH, "%s\\*.*", path); + + h = FindFirstFile(fullpath, &data); + if(h == INVALID_HANDLE_VALUE) + return 0; + + n = 0; + d = 0; + for(;;){ + if(!badentry(data.cFileName)){ + d = realloc(d, (n+2)*sizeof(Direntry)); + if(d == 0){ + werrstr("memory allocation"); + return 0; + } + d[n].name = malloc(strlen(data.cFileName)+1); + if(d[n].name == 0){ + werrstr("memory allocation"); + return 0; + } + strcpy(d[n].name, data.cFileName); + if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + d[n].isdir = 1; + else + d[n].isdir = 0; + n++; + } + if(FindNextFile(h, &data) == 0) + break; + } + FindClose(h); + if(d){ + d[n].name = 0; + d[n].isdir = 0; + } + return d; +} + +void +fatal(char *fmt, ...) +{ + char buf[512]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + + fprint(2, "rc: %s\n", buf); + _exits(buf); +} + +static int +tas(int *p) +{ + int v; + + _asm { + mov eax, p + mov ebx, 1 + xchg ebx, [eax] + mov v, ebx + } + + return v; +} + +static void +lock(Lock *lk) +{ + int i; + + /* easy case */ + if(!tas(&lk->val)) + return; + + /* for muli processor machines */ + for(i=0; i<100; i++) + if(!tas(&lk->val)) + return; + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); + for(;;) { + for(i=0; i<10000; i++) { + Sleep(0); + if(!tas(&lk->val)) { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + return; + } + } + } +} + +static void +unlock(Lock *lk) +{ + lk->val = 0; +} + +int +refinc(Ref *r) +{ + int i; + + lock(&r->lk); + i = r->ref; + r->ref++; + unlock(&r->lk); + return i; +} + +int +refdec(Ref *r) +{ + int i; + + lock(&r->lk); + r->ref--; + i = r->ref; + unlock(&r->lk); + + return i; +} + +/* + * windows quoting rules - I think + * Words are seperated by space or tab + * Words containing a space or tab can be quoted using " + * 2N backslashes + " ==> N backslashes and end quote + * 2N+1 backslashes + " ==> N backslashes + literal " + * N backslashes not followed by " ==> N backslashes + */ +static char * +dblquote(char *cmd, char *s) +{ + int nb; + char *p; + + for(p=s; *p; p++) + if(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '"') + break; + + if(*p == 0){ /* easy case */ + strcpy(cmd, s); + return cmd+(p-s); + } + + *cmd++ = '"'; + for(;;) { + for(nb=0; *s=='\\'; nb++) + *cmd++ = *s++; + + if(*s == 0) { /* trailing backslashes -> 2N */ + while(nb-- > 0) + *cmd++ = '\\'; + break; + } + + if(*s == '"') { /* literal quote -> 2N+1 backslashes */ + while(nb-- > 0) + *cmd++ = '\\'; + *cmd++ = '\\'; /* escape the quote */ + } + *cmd++ = *s++; + } + + *cmd++ = '"'; + *cmd = 0; + + return cmd; +} + +static char * +proccmd(char **argv) +{ + int i, n; + char *cmd, *p; + + /* conservatively calculate length of command; + * backslash expansion can cause growth in dblquote(). + */ + for(i=0,n=0; argv[i]; i++) { + n += 2*strlen(argv[i]); + } + n++; + + cmd = malloc(n); + for(i=0,p=cmd; argv[i]; i++) { + p = dblquote(p, argv[i]); + *p++ = ' '; + } + if(p != cmd) + p--; + *p = 0; + + return cmd; +} + +static char * +exportenv(char **e) +{ + int i, j, n; + char *buf; + + if(e == 0 || *e == 0) + return 0; + + buf = 0; + n = 0; + for(i = 0; *e; e++, i++) { + j = strlen(*e)+1; + buf = realloc(buf, n+j); + strcpy(buf+n, *e); + n += j; + } + /* final null */ + buf = realloc(buf, n+1); + buf[n] = 0; + + return buf; +} + +static int +setpath(char *path, char *file) +{ + char *p, *last, tmp[MAX_PATH+1]; + int n; + + if(strlen(file) >= MAX_PATH){ + werrstr("file name too long"); + return -1; + } + strcpy(tmp, file); + + for(p=tmp; *p; p++) { + if(*p == '/') + *p = '\\'; + } + + if(tmp[0] != 0 && tmp[1] == ':') { + if(tmp[2] == 0) { + tmp[2] = '\\'; + tmp[3] = 0; + } else if(tmp[2] != '\\') { + /* don't allow c:foo - only c:\foo */ + werrstr("illegal file name"); + return -1; + } + } + + path[0] = 0; + n = GetFullPathName(tmp, MAX_PATH, path, &last); + if(n >= MAX_PATH) { + werrstr("file name too long"); + return -1; + } + if(n == 0 && tmp[0] == '\\' && tmp[1] == '\\' && tmp[2] != 0) { + strcpy(path, tmp); + return -1; + } + + if(n == 0) { + werrstr("bad file name"); + return -1; + } + + for(p=path; *p; p++) { + if(*p < 32 || *p == '*' || *p == '?') { + werrstr("file not found"); + return -1; + } + } + + /* get rid of trailling \ */ + if(path[n-1] == '\\') { + if(n <= 2) { + werrstr("illegal file name"); + return -1; + } + path[n-1] = 0; + n--; + } + + if(path[1] == ':' && path[2] == 0) { + path[2] = '\\'; + path[3] = '.'; + path[4] = 0; + return -1; + } + + if(path[0] != '\\' || path[1] != '\\') + return 0; + + for(p=path+2,n=0; *p; p++) + if(*p == '\\') + n++; + if(n == 0) + return -1; + if(n == 1) + return -1; + return 0; +} + + +static int +execpath(char *path, char *file) +{ + int n; + + if(setpath(path, file) < 0) + return 0; + + n = strlen(path)-4; + if(path[n] == '.') { + if(GetFileAttributes(path) != -1) + return 1; + } + strncat(path, ".exe", MAX_PATH); + path[MAX_PATH-1] = 0; + if(GetFileAttributes(path) != -1) + return 1; + return 0; +} + +static HANDLE +fdexport(int fd) +{ + HANDLE h, r; + + if(fd < 0) + return INVALID_HANDLE_VALUE; + + h = (HANDLE)_get_osfhandle(fd); + if(h < 0) + return INVALID_HANDLE_VALUE; + + if(!DuplicateHandle(GetCurrentProcess(), h, + GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS, + 1, DUPLICATE_SAME_ACCESS)) + return INVALID_HANDLE_VALUE; + return r; +} + +static int +addchild(int pid, HANDLE handle) +{ + int i; + + for(i=0; i<Nchild; i++) { + if(child[i].handle == 0) { + child[i].handle = handle; + child[i].pid = pid; + return 1; + } + } + werrstr("child table full"); + return 0; +} + +int +procwait(uint pid) +{ + HANDLE h; + int i, exit; + + if(pid == 0) + return 0; + + h = 0; + for(i = 0; i < Nchild; i++){ + if(child[i].pid == pid){ + h = child[i].handle; + child[i].pid = 0; + child[i].handle = 0; + break; + } + } + + if(h == 0){ /* we don't know about this one - let the system try to find it */ + h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); + if(h == 0) + return 0; /* can't find it */ + } + + if(WaitForSingleObject(h, INFINITE) == WAIT_FAILED) { + winerror(); + fatal("procwait: "); + } + + if(!GetExitCodeProcess(h, &exit)) { + winerror(); + exit = 1; + } + + CloseHandle(h); + return exit; +} + +uint +proc(char **argv, int stdin, int stdout, int stderr) +{ + char *p, *arg0, *q, buf[MAX_PATH], path[MAX_PATH], *cmd, *eb; + STARTUPINFO si; + PROCESS_INFORMATION pi; + int r, found, full; + extern char **_environ; + Word *w; + + arg0 = argv[0]; + if(arg0 == 0) { + werrstr("null argv[0]"); + return 0; + } + + full = arg0[0] == '\\' || arg0[0] == '/' || arg0[0] == '.'; + found = execpath(path, arg0); + + if(!found && !full) { + w = vlook("path")->val; + if(w) + p = w->word; + else + p = getenv("path"); + for(; p && *p; p = q){ + q = strchr(p, ';'); + if(q) + *q = 0; + snprint(buf, sizeof(buf), "%s/%s", p, arg0); + if(q) + *q++ = ';'; + found = execpath(path, buf); + if(found) + break; + } + } + + if(!found) { + werrstr("file not found"); + return 0; + } + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; + si.wShowWindow = SW_SHOW; + si.hStdInput = fdexport(stdin); + si.hStdOutput = fdexport(stdout); + si.hStdError = fdexport(stderr); + + eb = exportenv(_environ); + + cmd = proccmd(argv); + + r = CreateProcess(path, cmd, 0, 0, 1, 0, eb, 0, &si, &pi); + + /* allow child to run */ + Sleep(0); + + free(cmd); + free(eb); + + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + if(!r) { + winerror(); + return 0; + } + + CloseHandle(pi.hThread); + + if(addchild(pi.dwProcessId, pi.hProcess) == 0) + return 0; + + return pi.dwProcessId; +} + +int +pipe(int *fd) +{ + return _pipe(fd, 0, _O_BINARY); +} diff --git a/utils/rcsh/code.c b/utils/rcsh/code.c new file mode 100644 index 00000000..06aea6ff --- /dev/null +++ b/utils/rcsh/code.c @@ -0,0 +1,486 @@ +#include "rc.h" +#include "y.tab.h" + +#define c0 t->child[0] +#define c1 t->child[1] +#define c2 t->child[2] +#define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f=(x), codep++) +#define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i=(x), codep++) +#define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s=(x), codep++) + +void stuffdot(int); +char *fnstr(Tree*); +void outcode(Tree*, int); +void codeswitch(Tree*, int); +int iscase(Tree*); +Code *codecopy(Code*); +void codefree(Code*); + +int codep, ncode; +Code *codebuf; + +int +morecode(void) +{ + ncode+=100; + codebuf=realloc(codebuf, ncode*sizeof codebuf[0]); + if(codebuf==0) + panic("Can't realloc %d bytes in morecode!", + ncode*sizeof codebuf[0]); + return 0; /* not used */ +} + +void +stuffdot(int a) +{ + if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a); + codebuf[a].i=codep; +} + +int +compile(Tree *t) +{ + ncode=100; + codebuf=malloc(ncode*sizeof codebuf[0]); + codep=0; + emiti(0); /* reference count */ + outcode(t, flag['e']?1:0); + if(nerror){ + free(codebuf); + return 0; + } +/* readhere(); */ + emitf(Xreturn); + emitf(0); + return 1; +} + +void +cleanhere(char *f) +{ + emitf(Xdelhere); + emits(strdup(f)); +} + +char * +fnstr(Tree *t) +{ + Io *f=openstr(); + char *v; + extern char nl; + char svnl=nl; + + nl=';'; + pfmt(f, "%t", t); + nl=svnl; + v=f->strp; + f->strp=0; + closeio(f); + return v; +} + +void +outcode(Tree *t, int eflag) +{ + int p, q; + Tree *tt; + + if(t==0) + return; + if(t->type != NOT && t->type != ';') + runq->iflast=0; + switch(t->type){ + default: + pfmt(err, "bad type %d in outcode\n", t->type); + break; + case '$': + emitf(Xmark); + outcode(c0, eflag); + emitf(Xdol); + break; + case '"': + emitf(Xmark); + outcode(c0, eflag); + emitf(Xqdol); + break; + case SUB: + emitf(Xmark); + outcode(c0, eflag); + emitf(Xmark); + outcode(c1, eflag); + emitf(Xsub); + break; + case '&': + emitf(Xasync); + emits(fnstr(c0)); +/* + p=emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); +*/ + break; + case ';': + outcode(c0, eflag); + outcode(c1, eflag); + break; + case '^': + emitf(Xmark); + outcode(c1, eflag); + emitf(Xmark); + outcode(c0, eflag); + emitf(Xconc); + break; + case '`': + emitf(Xbackq); + emits(fnstr(c0)); +/* + p=emiti(0); + outcode(c0, 0); + emitf(Xexit); + stuffdot(p); +*/ + break; + case ANDAND: + outcode(c0, 0); + emitf(Xtrue); + p=emiti(0); + outcode(c1, eflag); + stuffdot(p); + break; + case ARGLIST: + outcode(c1, eflag); + outcode(c0, eflag); + break; + case BANG: + outcode(c0, eflag); + emitf(Xbang); + break; + case PCMD: + case BRACE: + outcode(c0, eflag); + break; + case COUNT: + emitf(Xmark); + outcode(c0, eflag); + emitf(Xcount); + break; + case FN: + emitf(Xmark); + outcode(c0, eflag); + if(c1){ + emitf(Xfn); + p=emiti(0); + emits(fnstr(c1)); + outcode(c1, eflag); + emitf(Xunlocal); /* get rid of $* */ + emitf(Xreturn); + stuffdot(p); + } + else + emitf(Xdelfn); + break; + case IF: + outcode(c0, 0); + emitf(Xif); + p=emiti(0); + outcode(c1, eflag); + emitf(Xwastrue); + stuffdot(p); + break; + case NOT: + if(!runq->iflast) yyerror("`if not' does not follow `if(...)'"); + emitf(Xifnot); + p=emiti(0); + outcode(c0, eflag); + stuffdot(p); + break; + case OROR: + outcode(c0, 0); + emitf(Xfalse); + p=emiti(0); + outcode(c1, eflag); + stuffdot(p); + break; + case PAREN: + outcode(c0, eflag); + break; + case SIMPLE: + emitf(Xmark); + outcode(c0, eflag); + emitf(Xsimple); + if(eflag) emitf(Xeflag); + break; + case SUBSHELL: + emitf(Xsubshell); + emits(fnstr(c0)); +/* + p=emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); +*/ + if(eflag) emitf(Xeflag); + break; + case SWITCH: + codeswitch(t, eflag); + break; + case TWIDDLE: + emitf(Xmark); + outcode(c1, eflag); + emitf(Xmark); + outcode(c0, eflag); + emitf(Xmatch); + if(eflag) emitf(Xeflag); + break; + case WHILE: + q=codep; + emitf(Xsettrue); + outcode(c0, 0); + emitf(Xtrue); + p=emiti(0); + outcode(c1, eflag); + emitf(Xjump); + emiti(q); + stuffdot(p); + break; + case WORDS: + outcode(c1, eflag); + outcode(c0, eflag); + break; + case FOR: + emitf(Xmark); + if(c1){ + outcode(c1, eflag); + emitf(Xglob); + } + else{ + emitf(Xmark); + emitf(Xword); + emits(strdup("*")); + emitf(Xdol); + } + emitf(Xmark); /* dummy value for Xlocal */ + emitf(Xmark); + outcode(c0, eflag); + emitf(Xlocal); + p=emitf(Xfor); + q=emiti(0); + outcode(c2, eflag); + emitf(Xjump); + emiti(p); + stuffdot(q); + emitf(Xunlocal); + break; + case WORD: + emitf(Xword); + emits(strdup(t->str)); + break; + case DUP: + if(t->rtype==DUPFD) { + emitf(Xdup); + emiti(t->fd0); + emiti(t->fd1); + } else { /* t->rtype == CLOSE */ + emitf(Xclose); + emiti(t->fd0); + } + outcode(c1, eflag); + emitf(Xpopredir); + break; +/* + case PIPEFD: + emitf(Xpipefd); + emiti(t->rtype); + p=emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); + break; +*/ + case REDIR: + emitf(Xmark); + outcode(c0, eflag); + emitf(Xglob); + switch(t->rtype){ + case APPEND: + emitf(Xappend); + break; + case WRITE: + emitf(Xwrite); + break; + case READ: + case HERE: + emitf(Xread); + break; + } + emiti(t->fd0); + outcode(c1, eflag); + emitf(Xpopredir); + break; + case '=': + tt=t; + for(;t && t->type=='=';t=c2) + ; + if(t){ + for(t=tt;t->type=='=';t=c2){ + emitf(Xmark); + outcode(c1, eflag); + emitf(Xmark); + outcode(c0, eflag); + emitf(Xlocal); + } + t=tt; + outcode(c2, eflag); + for(;t->type=='=';t=c2) + emitf(Xunlocal); + } + else{ + for(t=tt;t;t=c2){ + emitf(Xmark); + outcode(c1, eflag); + emitf(Xmark); + outcode(c0, eflag); + emitf(Xassign); + } + } + t=tt; /* so tests below will work */ + break; + case PIPE: + emitf(Xpipe); + emiti(t->fd0); + emiti(t->fd1); + emits(fnstr(c0)); + q=emiti(0); +/* + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); +*/ + outcode(c1, eflag); + emitf(Xreturn); + stuffdot(q); + emitf(Xpipewait); + break; + } + if(t->type!=NOT && t->type!=';') + runq->iflast=t->type==IF; + else if(c0) runq->iflast=c0->type==IF; +} + +/* + * switch code looks like this: + * Xmark + * (get switch value) + * Xjump 1f + * out: Xjump leave + * 1: Xmark + * (get case values) + * Xcase 1f + * (commands) + * Xjump out + * 1: Xmark + * (get case values) + * Xcase 1f + * (commands) + * Xjump out + * 1: + * leave: + * Xpopm + */ +void +codeswitch(Tree *t, int eflag) +{ + int leave; /* patch jump address to leave switch */ + int out; /* jump here to leave switch */ + int nextcase; /* patch jump address to next case */ + Tree *tt; + if(c1->child[0]->type!=';' + || !iscase(c1->child[0]->child[0])){ + yyerror("case missing in switch"); + return; + } + emitf(Xmark); + outcode(c0, eflag); + emitf(Xjump); + nextcase=emiti(0); + out=emitf(Xjump); + leave=emiti(0); + stuffdot(nextcase); + t=c1->child[0]; + while(t->type==';'){ + tt=c1; + emitf(Xmark); + for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag); + emitf(Xcase); + nextcase=emiti(0); + t=tt; + for(;;){ + if(t->type==';'){ + if(iscase(c0)) break; + outcode(c0, eflag); + t=c1; + } + else{ + outcode(t, eflag); + break; + } + } + emitf(Xjump); + emiti(out); + stuffdot(nextcase); + } + stuffdot(leave); + emitf(Xpopm); +} + +int +iscase(Tree *t) +{ + if(t->type!=SIMPLE) + return 0; + do + t=c0; + while(t->type==ARGLIST); + + return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0; +} + +Code * +codecopy(Code *cp) +{ + cp[0].i++; + return cp; +} + +void +codefree(Code *cp) +{ + Code *p; + + if(--cp[0].i!=0) + return; + + for(p=cp+1;p->f;){ + if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite + || p->f==Xasync || p->f==Xcase || p->f==Xfalse + || p->f==Xfor || p->f==Xjump + || p->f==Xsubshell || p->f==Xtrue) + p+=2; + else if(p->f==Xdup || p->f==Xpipefd) + p+=3; + else if(p->f==Xpipe) { + free(p[3].s); + p+=5; + } else if(p->f==Xword || p->f==Xdelhere || p->f==Xbackq) { + free(p[1].s); + p+=2; + } else if(p->f==Xfn){ + free(p[2].s); + p+=3; + } else + p++; + } + + free(cp); +} diff --git a/utils/rcsh/exec.c b/utils/rcsh/exec.c new file mode 100644 index 00000000..66112d80 --- /dev/null +++ b/utils/rcsh/exec.c @@ -0,0 +1,802 @@ +#include "rc.h" + +extern char *argv0; + +int ifnot; +int eflagok; + +/* + * Opcode routines + * Arguments on stack (...) + * Arguments in line [...] + * Code in line with jump around {...} + * + * Xappend(file)[fd] open file to append + * Xassign(name, val) assign val to name + * Xasync{... Xexit} make thread for {}, no wait + * Xbackq{... Xreturn} make thread for {}, push stdout + * Xbang complement condition + * Xcase(pat, value){...} exec code on match, leave (value) on + * stack + * Xclose[i] close file descriptor + * Xconc(left, right) concatenate, push results + * Xcount(name) push var count + * Xdelfn(name) delete function definition + * Xdeltraps(names) delete named traps + * Xdol(name) get variable value + * Xqdol(name) concatenate variable components + * Xdup[i j] dup file descriptor + * Xexit rc exits with status + * Xfalse{...} execute {} if false + * Xfn(name){... Xreturn} define function + * Xfor(var, list){... Xreturn} for loop + * Xjump[addr] goto + * Xlocal(name, val) create local variable, assign value + * Xmark mark stack + * Xmatch(pat, str) match pattern, set status + * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads, + * wait for both + * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output, + * depending on type), push /dev/fd/?? + * Xpopm(value) pop value from stack + * Xread(file)[fd] open file to read + * Xsettraps(names){... Xreturn} define trap functions + * Xshowtraps print trap list + * Xsimple(args) run command and wait + * Xreturn kill thread + * Xsubshell{... Xexit} execute {} in a subshell and wait + * Xtrue{...} execute {} if true + * Xunlocal delete local variable + * Xword[string] push string + * Xwrite(file)[fd] open file to write + */ + +static char ** +rcargv(char *s) +{ + char *flags; + + if(flag['e']) + flags = "-Se"; + else + flags = "-S"; + return procargv(argv0, flags, "-c", s, vlook("*")->val); +} + +void +Xappend(void) +{ + char *file; + int f; + + switch(count(runq->argv->words)){ + default: Xerror(">> requires singleton"); return; + case 0: Xerror(">> requires file"); return; + case 1: break; + } + file=runq->argv->words->word; + if((f=open(file, 1))<0 && (f=create(file, 1, 0666))<0){ + Xperror(file); + return; + } + seek(f, 0L, 2); + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +void +Xassign(void) +{ + Var *v; + + if(count(runq->argv->words)!=1){ + Xerror("variable name not singleton!"); + return; + } + deglob(runq->argv->words->word); + v=vlook(runq->argv->words->word); + poplist(); + globlist(); + freewords(v->val); + v->val=runq->argv->words; + v->changed=1; + runq->argv->words=0; + poplist(); +} + +void +Xasync(void) +{ + uint pid; + char buf[20], **argv; + + updenv(); + + argv = rcargv(runq->code[runq->pc].s); + pid = proc(argv, -1, 1, 2); + free(argv); + + if(pid == 0) { + Xerror("proc failed"); + return; + } + + runq->pc++; + sprint(buf, "%d", pid); + setvar("apid", newword(buf, (Word *)0)); +} + +void +Xbackq(void) +{ + char wd[8193], **argv; + int c; + char *s, *ewd=&wd[8192], *stop; + Io *f; + Var *ifs=vlook("ifs"); + Word *v, *nextv; + int pfd[2]; + int pid; + + stop = ifs->val?ifs->val->word:""; + if(pipe(pfd)<0){ + Xerror("can't make pipe"); + return; + } + + updenv(); + + argv = rcargv(runq->code[runq->pc].s); + pid = proc(argv, -1, pfd[1], 2); + free(argv); + + close(pfd[1]); + + if(pid == 0) { + Xerror("proc failed"); + close(pfd[0]); + return; + } + + f = openfd(pfd[0]); + s = wd; + v = 0; + while((c=rchr(f))!=EOF){ + if(strchr(stop, c) || s==ewd){ + if(s!=wd){ + *s='\0'; + v=newword(wd, v); + s=wd; + } + } + else *s++=c; + } + if(s!=wd){ + *s='\0'; + v=newword(wd, v); + } + closeio(f); + waitfor(pid); + /* v points to reversed arglist -- reverse it onto argv */ + while(v){ + nextv=v->next; + v->next=runq->argv->words; + runq->argv->words=v; + v=nextv; + } + runq->pc++; +} + +void +Xbang(void) +{ + setstatus(truestatus()?"false":""); +} + +void +Xcase(void) +{ + Word *p; + char *s; + int ok=0; + + s=list2str(runq->argv->next->words); + for(p=runq->argv->words;p;p=p->next){ + if(match(s, p->word, '\0')){ + ok=1; + break; + } + } + free(s); + if(ok) + runq->pc++; + else + runq->pc=runq->code[runq->pc].i; + poplist(); +} + +void +Xclose(void) +{ + pushredir(RCLOSE, runq->code[runq->pc].i, 0); + runq->pc++; +} + +void +Xconc(void) +{ + Word *lp=runq->argv->words; + Word *rp=runq->argv->next->words; + Word *vp=runq->argv->next->next->words; + int lc=count(lp), rc=count(rp); + + if(lc!=0 || rc!=0){ + if(lc==0 || rc==0){ + Xerror("null list in concatenation"); + return; + } + if(lc!=1 && rc!=1 && lc!=rc){ + Xerror("mismatched list lengths in concatenation"); + return; + } + vp=conclist(lp, rp, vp); + } + poplist(); + poplist(); + runq->argv->words=vp; +} + +void +Xcount(void) +{ + Word *a; + char *s, *t; + int n; + char num[12]; + + if(count(runq->argv->words)!=1){ + Xerror("variable name not singleton!"); + return; + } + s=runq->argv->words->word; + deglob(s); + n=0; + for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; + if(n==0 || *t){ + a=vlook(s)->val; + sprint(num, "%d", count(a)); + } + else{ + a=vlook("*")->val; + sprint(num, "%d", a && 1<=n && n<=count(a)?1:0); + } + poplist(); + pushword(num); +} + +void +Xdelfn(void) +{ + Var *v; + Word *a; + + for(a=runq->argv->words;a;a=a->next){ + v=gvlook(a->word); + if(v->fn) + codefree(v->fn); + v->fn=0; + v->fnchanged=1; + } + poplist(); +} + +void +Xdelhere(void) +{ + Var *v; + Word *a; + + for(a=runq->argv->words;a;a=a->next){ + v=gvlook(a->word); + if(v->fn) codefree(v->fn); + v->fn=0; + v->fnchanged=1; + } + poplist(); +} + +void +Xdol(void) +{ + Word *a, *star; + char *s, *t; + int n; + + if(count(runq->argv->words)!=1){ + Xerror("variable name not singleton!"); + return; + } + s=runq->argv->words->word; + deglob(s); + n=0; + for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; + a=runq->argv->next->words; + if(n==0 || *t) + a=copywords(vlook(s)->val, a); + else{ + star=vlook("*")->val; + if(star && 1<=n && n<=count(star)){ + while(--n) star=star->next; + a=newword(star->word, a); + } + } + poplist(); + runq->argv->words=a; +} + +void +Xdup(void) +{ + pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); + runq->pc+=2; +} + +void +Xeflag(void) +{ + if(eflagok && !truestatus()) + Xexit(); +} + +void +Xexit(void) +{ + Var *trapreq; + Word *starval; + char *c; + static int beenhere=0; + + if(truestatus()) + c = ""; + else + c = getstatus(); + + if(flag['S'] || beenhere) + exits(c); + + trapreq=vlook("sigexit"); + if(trapreq->fn){ + beenhere=1; + --runq->pc; + starval=vlook("*")->val; + start(trapreq->fn, trapreq->pc, (Var*)0); + runq->local=newvar(strdup("*"), runq->local); + runq->local->val=copywords(starval, (Word*)0); + runq->local->changed=1; + runq->redir=runq->startredir=0; + } + + exits(c); +} + +void +Xfalse(void) +{ + if(truestatus()) + runq->pc=runq->code[runq->pc].i; + else + runq->pc++; +} + +void +Xfor(void) +{ + if(runq->argv->words==0) { + poplist(); + runq->pc=runq->code[runq->pc].i; + } else { + freelist(runq->local->val); + runq->local->val=runq->argv->words; + runq->local->changed=1; + runq->argv->words=runq->argv->words->next; + runq->local->val->next=0; + runq->pc++; + } +} + +void +Xfn(void) +{ + Var *v; + Word *a; + int end; + + end=runq->code[runq->pc].i; + for(a=runq->argv->words;a;a=a->next){ + v=gvlook(a->word); + if(v->fn) + codefree(v->fn); + v->fn=codecopy(runq->code); + v->pc=runq->pc+2; + v->fnchanged=1; + } + runq->pc=end; + poplist(); +} + +void +Xglob(void) +{ + globlist(); +} + +void +Xif(void) +{ + ifnot=1; + if(truestatus()) runq->pc++; + else runq->pc=runq->code[runq->pc].i; +} + +void +Xifnot(void) +{ + if(ifnot) + runq->pc++; + else + runq->pc=runq->code[runq->pc].i; +} + +void +Xjump(void) +{ + runq->pc=runq->code[runq->pc].i; +} + + +void +Xlocal(void) +{ + if(count(runq->argv->words)!=1){ + Xerror("variable name must be singleton\n"); + return; + } + deglob(runq->argv->words->word); + runq->local=newvar(strdup(runq->argv->words->word), runq->local); + runq->local->val=copywords(runq->argv->next->words, 0); + runq->local->changed=1; + poplist(); + poplist(); +} + + +void +Xmark(void) +{ + pushlist(); +} + +void +Xmatch(void) +{ + Word *p; + char *subject; + + subject=list2str(runq->argv->words); + setstatus("no match"); + for(p=runq->argv->next->words;p;p=p->next) { + if(match(subject, p->word, '\0')){ + setstatus(""); + break; + } + } + free(subject); + poplist(); + poplist(); +} + +void +Xpipe(void) +{ + Thread *p=runq; + int pc=p->pc, pid; + int lfd=p->code[pc].i; + int rfd=p->code[pc+1].i; + int pfd[2]; + char **argv; + + if(pipe(pfd)<0){ + Xperror("can't get pipe"); + return; + } + + updenv(); + + argv = rcargv(runq->code[pc+2].s); + pid = proc(argv, 0, pfd[1], 2); + free(argv); + close(pfd[1]); + + if(pid == 0) { + Xerror("proc failed"); + close(pfd[0]); + return; + } + + start(p->code, pc+4, runq->local); + pushredir(ROPEN, pfd[0], rfd); + p->pc=p->code[pc+3].i; + p->pid=pid; +} + +void +Xpipefd(void) +{ + fatal("Xpipefd"); +} + +void +Xpipewait(void) +{ + char status[NSTATUS+1]; + if(runq->pid==-1) + setstatus(concstatus(runq->status, getstatus())); + else{ + strncpy(status, getstatus(), NSTATUS); + status[NSTATUS]='\0'; + waitfor(runq->pid); + runq->pid=-1; + setstatus(concstatus(getstatus(), status)); + } +} + +void +Xpopm(void) +{ + poplist(); +} + +void +Xpopredir(void) +{ + Redir *rp=runq->redir; + + if(rp==0) + panic("turfredir null!", 0); + runq->redir=rp->next; + if(rp->type==ROPEN) + close(rp->from); + free((char *)rp); +} + +void +Xqdol(void) +{ + Word *a, *p; + char *s; + int n; + + if(count(runq->argv->words)!=1){ + Xerror("variable name not singleton!"); + return; + } + s=runq->argv->words->word; + deglob(s); + a=vlook(s)->val; + poplist(); + n=count(a); + if(n==0){ + pushword(""); + return; + } + for(p=a;p;p=p->next) n+=strlen(p->word); + s=malloc(n); + if(a){ + strcpy(s, a->word); + for(p=a->next;p;p=p->next){ + strcat(s, " "); + strcat(s, p->word); + } + } + else + s[0]='\0'; + pushword(s); + free(s); +} + +void +Xrdcmds(void) +{ + Thread *p=runq; + Word *prompt; + + flush(err); + nerror=0; + if(flag['s'] && !truestatus()) + pfmt(err, "status=%v\n", vlook("status")->val); + if(runq->iflag){ + prompt=vlook("prompt")->val; + if(prompt) + promptstr=prompt->word; + else + promptstr="% "; + } + interrupted=0; + if(yyparse()) { + if(!p->iflag || p->eof /* && !Eintr() */) { + if(p->cmdfile) + free(p->cmdfile); + closeio(p->cmdfd); + Xreturn(); /* should this be omitted? */ + } else { + if(interrupted){ + pchr(err, '\n'); + p->eof=0; + } + --p->pc; /* go back for next command */ + } + } else { + --p->pc; /* re-execute Xrdcmds after codebuf runs */ + start(codebuf, 1, runq->local); + } + freenodes(); +} + +void +Xread(void) +{ + char *file; + int f; + + switch(count(runq->argv->words)){ + default: Xerror("< requires singleton\n"); return; + case 0: Xerror("< requires file\n"); return; + case 1: break; + } + file=runq->argv->words->word; + if((f=open(file, 0))<0){ + Xperror(file); + return; + } + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +void +Xreturn(void) +{ + Thread *p=runq; + + turfredir(); + while(p->argv) + poplist(); + codefree(p->code); + runq=p->ret; + free(p); + if(runq==0) + exits(truestatus()?"":getstatus()); +} + +void +Xsettrue(void) +{ + setstatus(""); +} + + +void +Xsub(void) +{ + Word *a, *v; + char *s; + if(count(runq->argv->next->words)!=1){ + Xerror("variable name not singleton!"); + return; + } + s=runq->argv->next->words->word; + deglob(s); + a=runq->argv->next->next->words; + v=vlook(s)->val; + a=subwords(v, count(v), runq->argv->words, a); + poplist(); + poplist(); + runq->argv->words=a; +} + +void +Xsubshell(void) +{ + char **argv; + uint pid; + + updenv(); + + argv = rcargv(runq->code[runq->pc].s); + pid = proc(argv, -1, 1, 2); + free(argv); + + if(pid == 0) { + Xerror("proc failed"); + return; + } + + waitfor(pid); + runq->pc++; +} + +void +Xtrue(void) +{ + if(truestatus()) + runq->pc++; + else + runq->pc=runq->code[runq->pc].i; +} + +void +Xunlocal(void) +{ + Var *v=runq->local, *hid; + + if(v==0) + panic("Xunlocal: no locals!", 0); + runq->local=v->next; + hid=vlook(v->name); + hid->changed=1; + free(v->name); + freewords(v->val); + free(v); +} + +void +Xwastrue(void) +{ + ifnot=0; +} + +void +Xwrite(void) +{ + char *file; + int f; + + switch(count(runq->argv->words)){ + default: Xerror("> requires singleton\n"); return; + case 0: Xerror("> requires file\n"); return; + case 1: break; + } + file=runq->argv->words->word; + if((f = create(file, 1, 0666))<0){ + Xperror(file); + return; + } + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +void +Xword(void) +{ + pushword(runq->code[runq->pc++].s); +} + +void +Xerror(char *s) +{ + pfmt(err, "rcsh: %s\n", s); + flush(err); + while(!runq->iflag) + Xreturn(); +} + +void +Xperror(char *s) +{ + pfmt(err, "rcsh: %s: %r\n", s); + flush(err); + while(!runq->iflag) + Xreturn(); +} diff --git a/utils/rcsh/glob.c b/utils/rcsh/glob.c new file mode 100644 index 00000000..7640eeb1 --- /dev/null +++ b/utils/rcsh/glob.c @@ -0,0 +1,286 @@ +#include "rc.h" + +char *globname; +Word *globv; + +int matchfn(char *s, char *p); +int globsize(char *p); + +/* + * delete all the GLOB marks from s, in place + */ +void +deglob(char *s) +{ + char *t=s; + do{ + if(*t==GLOB) t++; + *s++=*t; + }while(*t++); +} + +int +globcmp(const void *s, const void *t) +{ + return strcmp(*(char**)s, *(char**)t); +} + +void +globsort(Word *left, Word *right) +{ + char **list; + Word *a; + int n=0; + for(a=left;a!=right;a=a->next) n++; + list=(char **)malloc(n*sizeof(char *)); + for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word; + qsort((void*)list, (size_t)n, sizeof(char*), globcmp); + for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n]; + free(list); +} + +/* + * Push names prefixed by globname and suffixed by a match of p onto the astack. + * namep points to the end of the prefix in globname. + */ +void +globdir(char *p, char *namep) +{ + char *t, *q, *newp; + Direntry *dp, *dq; + Dir *dir; + + /* scan the pattern looking for a component with a metacharacter in it */ + if(*p=='\0'){ + globv=newword(globname, globv); + return; + } + t=namep; + newp=p; + while(*newp){ + if(*newp==GLOB) + break; + *t=*newp++; + if(*t++=='/'){ + namep=t; + p=newp; + } + } + /* If we ran out of pattern, append the name if accessible */ + if(*newp=='\0'){ + *t='\0'; + if(access(globname, 0)==0) + globv=newword(globname, globv); + return; + } + /* read the directory and recur for any entry that matches */ + *namep='\0'; + t = globname; + if(*t == 0) + t = "."; + q = strdup(t); + if (q[strlen(q)-1] == '/') + q[strlen(q)-1] = 0; + if((dir=dirstat(q)) == nil || !(dir->mode&0x80000000)){ + free(dir); + return; + } + free(dir); + dq = readdirect(q); + if(dq == 0){ + fprint(2, "could not open %s: %r\n", q); + return; + } + while(*newp!='/' && *newp!='\0') + newp++; + for(dp = dq;dp->name; dp++){ + strcpy(namep, dp->name); + if(matchfn(namep, p)) + globdir(newp, namep+strlen(namep)); + free(dp->name); + } + free(dq); +} + +/* + * Push all file names matched by p on the current thread's stack. + * If there are no matches, the list consists of p. + */ +void +glob(char *p) +{ + Word *svglobv=globv; + int globlen=globsize(p); + + if(globlen == 0){ + deglob(p); + globv=newword(p, globv); + return; + } + globname=malloc(globlen); + globname[0]='\0'; + globdir(p, globname); + free(globname); + if(svglobv==globv){ + deglob(p); + globv=newword(p, globv); + } + else + globsort(globv, svglobv); +} + + +/* + * Do p and q point at equal utf codes + */ +int +equtf(char *p, char *q) +{ + if(*p!=*q) + return 0; + if(twobyte(*p)) return p[1]==q[1]; + if(threebyte(*p)){ + if(p[1]!=q[1]) return 0; + if(p[1]=='\0') return 1; /* broken code at end of string! */ + return p[2]==q[2]; + } + return 1; +} + +/* + * Return a pointer to the next utf code in the string, + * not jumping past nuls in broken utf codes! + */ +char * +nextutf(char *p) +{ + if(twobyte(*p)) + return p[1]=='\0'?p+1:p+2; + if(threebyte(*p)) + return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; + return p+1; +} + +/* + * Convert the utf code at *p to a unicode value + */ +int +unicode(char *p) +{ + int u=*p&0xff; + if(twobyte(u)) + return ((u&0x1f)<<6)|(p[1]&0x3f); + if(threebyte(u)) + return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); + return u; +} + +/* + * Does the string s match the pattern p + * . and .. are only matched by patterns starting with . + * * matches any sequence of characters + * ? matches any single character + * [...] matches the enclosed list of characters + */ +int +matchfn(char *s, char *p) +{ + if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') + return 0; + return match(s, p, '/'); +} + +int +match(char *s, char *p, int stop) +{ + int compl, hit, lo, hi, t, c; + + for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)) { + if(*p!=GLOB){ + if(!equtf(p, s)) return 0; + } + else switch(*++p){ + case GLOB: + if(*s!=GLOB) return 0; + break; + case '*': + for(;;){ + if(match(s, nextutf(p), stop)) return 1; + if(!*s) break; + s=nextutf(s); + } + return 0; + case '?': + if(*s=='\0') return 0; + break; + case '[': + if(*s=='\0') return 0; + c=unicode(s); + p++; + compl=*p=='~'; + if(compl) p++; + hit=0; + while(*p!=']'){ + if(*p=='\0') return 0; /* syntax error */ + lo=unicode(p); + p=nextutf(p); + if(*p!='-') hi=lo; + else{ + p++; + if(*p=='\0') return 0; /* syntax error */ + hi=unicode(p); + p=nextutf(p); + if(hi<lo){ t=lo; lo=hi; hi=t; } + } + if(lo<=c && c<=hi) hit=1; + } + if(compl) hit=!hit; + if(!hit) return 0; + break; + } + } + return *s=='\0'; +} + +void +globlist1(Word *gl) +{ + if(gl){ + globlist1(gl->next); + glob(gl->word); + } +} + +void +globlist(void) +{ + Word *a; + + globv=0; + globlist1(runq->argv->words); + poplist(); + pushlist(); + if(globv){ + for(a=globv;a->next;a=a->next); + a->next=runq->argv->words; + runq->argv->words=globv; + } +} + +#define NDIR 128 +int +globsize(char *p) +{ + ulong isglob=0, globlen=NDIR+1; + + for(;*p;p++){ + if(*p==GLOB){ + p++; + if(*p!=GLOB) isglob++; + globlen+=*p=='*'?NDIR:1; + } + else + globlen++; + } + return isglob?globlen:0; +} diff --git a/utils/rcsh/here.c b/utils/rcsh/here.c new file mode 100644 index 00000000..bd1f79cc --- /dev/null +++ b/utils/rcsh/here.c @@ -0,0 +1,145 @@ +#include "rc.h" +#include "y.tab.h" + +Here *here, **ehere; +int ser; + +char tmp[]="/tmp/here0000.0000"; +char hex[]="0123456789abcdef"; + +void psubst(Io*, char*); +void pstrs(Io*, Word*); + +void hexnum(char *p, int n) +{ + *p++=hex[(n>>12)&0xF]; + *p++=hex[(n>>8)&0xF]; + *p++=hex[(n>>4)&0xF]; + *p=hex[n&0xF]; +} + +Tree * +heredoc(Tree *tag) +{ + Here *h=new(Here); + + if(tag->type!=WORD) + yyerror("Bad here tag"); + h->next=0; + if(here) + *ehere=h; + else + here=h; + ehere=&h->next; + h->tag=tag; + hexnum(&tmp[9], getpid()); + hexnum(&tmp[14], ser++); + h->name=strdup(tmp); + return token(tmp, WORD); +} +/* + * bug: lines longer than NLINE get split -- this can cause spurious + * missubstitution, or a misrecognized EOF marker. + */ +#define NLINE 4096 +void +readhere(void) +{ + Here *h, *nexth; + Io *f; + char *s, *tag; + int c, subst; + char line[NLINE+1]; + + for(h=here;h;h=nexth){ + subst=!h->tag->quoted; + tag=h->tag->str; + c=create(h->name, 1, 0666); + if(c<0) yyerror("can't create here document"); + f=openfd(c); + s=line; + pprompt(); + while((c=rchr(runq->cmdfd))!=EOF){ + if(c=='\n' || s==&line[NLINE]){ + *s='\0'; + if(strcmp(line, tag)==0) break; + if(subst) psubst(f, line); + else pstr(f, line); + s=line; + if(c=='\n'){ + pprompt(); + pchr(f, c); + } + else *s++=c; + } + else *s++=c; + } + flush(f); + closeio(f); + cleanhere(h->name); + nexth=h->next; + free(h); + } + here=0; + doprompt=1; +} + +void +psubst(Io *f, char *s) +{ + char *t, *u; + int savec, n; + Word *star; + + while(*s){ + if(*s!='$'){ + if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){ + pchr(f, *s++); + if(*s=='\0') break; + } + else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){ + pchr(f, *s++); + if(*s=='\0') break; + pchr(f, *s++); + if(*s=='\0') break; + } + pchr(f, *s++); + } + else{ + t=++s; + if(*t=='$') pchr(f, *t++); + else{ + while(*t && idchr(*t)) t++; + savec=*t; + *t='\0'; + n=0; + for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*u-'0'; + if(n && *u=='\0'){ + star=vlook("*")->val; + if(star && 1<=n && n<=count(star)){ + while(--n) star=star->next; + pstr(f, star->word); + } + } + else + pstrs(f, vlook(s)->val); + *t=savec; + if(savec=='^') t++; + } + s=t; + } + } +} + +void +pstrs(Io *f, Word *a) +{ + if(a){ + while(a->next && a->next->word){ + pstr(f, a->word); + pchr(f, ' '); + a=a->next; + } + pstr(f, a->word); + } +} diff --git a/utils/rcsh/io.c b/utils/rcsh/io.c new file mode 100644 index 00000000..6ac2555e --- /dev/null +++ b/utils/rcsh/io.c @@ -0,0 +1,238 @@ +#include "rc.h" + +int pfmtnest=0; + +void pdec(Io*, long); +void poct(Io*, ulong); +void phex(Io*, long); +void pquo(Io*, char*); +void pwrd(Io*, char*); +void pcmd(Io*, Tree*); +void pval(Io*, Word*); + +void +pfmt(Io *f, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pfmtnest++; + for(;*fmt;fmt++) { + if(*fmt!='%') pchr(f, *fmt); + else switch(*++fmt){ + case '\0': va_end(ap); return; + case 'c': pchr(f, va_arg(ap, int)); break; + case 'd': pdec(f, va_arg(ap, int)); break; + case 'o': poct(f, va_arg(ap, unsigned)); break; + case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/ + case 'Q': pquo(f, va_arg(ap, char *)); break; + case 'q': pwrd(f, va_arg(ap, char *)); break; + case 'r': perr(f); break; + case 's': pstr(f, va_arg(ap, char *)); break; + case 't': pcmd(f, va_arg(ap, Tree *)); break; + case 'v': pval(f, va_arg(ap, Word *)); break; + default: pchr(f, *fmt); break; + } + } + va_end(ap); + if(--pfmtnest==0) flush(f); +} + +void +perr(Io *f) +{ + char err[ERRMAX]; + + err[0] = 0; + errstr(err, sizeof err); + pstr(f, err); + errstr(err, sizeof err); +} + +void +pquo(Io *f, char *s) +{ + pchr(f, '\''); + for(;*s;s++) + if(*s=='\'') pfmt(f, "''"); + else pchr(f, *s); + pchr(f, '\''); +} + +void +pwrd(Io *f, char *s) +{ + char *t; + for(t=s;*t;t++) + if(!wordchr(*t)) + break; + if(t==s || *t) + pquo(f, s); + else + pstr(f, s); +} + +void +phex(Io *f, long p) +{ + int n; + for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); +} + +void +pstr(Io *f, char *s) +{ + if(s==0) + s="(null)"; + while(*s) + pchr(f, *s++); +} + +void +pdec(Io *f, long n) +{ + if(n<0){ + n=-n; + if(n>=0){ + pchr(f, '-'); + pdec(f, n); + return; + } + /* n is two's complement minimum integer */ + n=1-n; + pchr(f, '-'); + pdec(f, n/10); + pchr(f, n%10+'1'); + return; + } + if(n>9) pdec(f, n/10); + pchr(f, n%10+'0'); +} + +void +poct(Io *f, ulong n) +{ + if(n>7) poct(f, n>>3); + pchr(f, (n&7)+'0'); +} + +void +pval(Io *f, Word *a) +{ + if(a){ + while(a->next && a->next->word){ + pwrd(f, a->word); + pchr(f, ' '); + a=a->next; + } + pwrd(f, a->word); + } +} + +int +fullbuf(Io *f, int c) +{ + flush(f); + return *f->bufp++=c; +} + +void +flush(Io *f) +{ + int n; + char *s; + if(f->strp){ + n=f->ebuf-f->strp; + f->strp=realloc(f->strp, n+101); + if(f->strp==0) + panic("Can't realloc %d bytes in flush!", n+101); + f->bufp=f->strp+n; + f->ebuf=f->bufp+100; + for(s=f->bufp;s<=f->ebuf;s++) *s='\0'; + } + else{ + n=f->bufp-f->buf; + if(n && write(f->fd, f->buf, n) < 0){ +/* write(3, "Write error\n", 12); + if(ntrap.ref) + dotrap(); +*/ + } + f->bufp=f->buf; + f->ebuf=f->buf+NBUF; + } +} + +Io * +openfd(int fd) +{ + Io *f = new(Io); + f->fd = fd; + f->bufp = f->ebuf = f->buf; + f->strp = 0; + return f; +} + +Io * +openstr(void) +{ + Io *f=new(struct Io); + char *s; + f->fd=-1; + f->bufp=f->strp=malloc(101); + f->ebuf=f->bufp+100; + for(s=f->bufp;s<=f->ebuf;s++) + *s='\0'; + return f; +} + +/* + * Open a corebuffer to read. EOF occurs after reading len + * characters from buf. + */ +Io * +opencore(char *s, int len) +{ + Io *f; + char *buf; + + f = new(Io); + buf = malloc(len); + f->fd = -1; + f->bufp = f->strp=buf; + f->ebuf = buf+len; + memmove(buf, s, len); + + return f; +} + +void +rewind(Io *io) +{ + if(io->fd==-1) { + io->bufp = io->strp; + } else { + io->bufp = io->ebuf = io->buf; + seek(io->fd, 0L, 0); + } +} + +void +closeio(Io *io) +{ + if(io->fd>=0) + close(io->fd); + if(io->strp) + free(io->strp); + free(io); +} + +int +emptybuf(Io *f) +{ + int n; + if(f->fd==-1 || (n=read(f->fd, f->buf, NBUF))<=0) return EOF; + f->bufp=f->buf; + f->ebuf=f->buf+n; + return *f->bufp++&0xff; +} diff --git a/utils/rcsh/lex.c b/utils/rcsh/lex.c new file mode 100644 index 00000000..d31a94d8 --- /dev/null +++ b/utils/rcsh/lex.c @@ -0,0 +1,398 @@ +#include "rc.h" +#include "y.tab.h" + +#define NTOK 8192 + +int getnext(void); + +int future=EOF; +int doprompt=1; +int inquote; +int nerror; +char *promptstr; + +char tok[NTOK]; + +int lastdol; /* was the last token read '$' or '$#' or '"'? */ +int lastword; /* was the last token read a word or compound word terminator? */ +int lastc; + +void +kinit(void) +{ + kenter(FOR, "for"); + kenter(IN, "in"); + kenter(WHILE, "while"); + kenter(IF, "if"); + kenter(NOT, "not"); + kenter(TWIDDLE, "~"); + kenter(BANG, "!"); + kenter(SUBSHELL, "@"); + kenter(SWITCH, "switch"); + kenter(FN, "fn"); +} + +int +wordchr(int c) +{ + return !strchr("\n \t\r#;&|^$=`'{}()<>", c) && c!=EOF; +} + +int +idchr(int c) +{ + /* + * Formerly: + * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9' + * || c=='_' || c=='*'; + */ + return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); +} + +/* + * Look ahead in the input stream + */ +int +nextc(void) +{ + if(future==EOF) + future=getnext(); + return future; +} + +/* + * Consume the lookahead character. + */ +int +advance(void) +{ + int c=nextc(); + lastc=future; + future=EOF; + return c; +} + +/* + * read a character from the input stream + */ +int +getnext(void) +{ + register int c; + static peekc=EOF; + if(peekc!=EOF){ + c=peekc; + peekc=EOF; + return c; + } + if(runq->eof) return EOF; + if(doprompt) + pprompt(); + c=rchr(runq->cmdfd); + if(!inquote && c=='\\'){ + c=rchr(runq->cmdfd); + if(c=='\n'){ + doprompt=1; + c=' '; + } + else{ + peekc=c; + c='\\'; + } + } + doprompt=doprompt || c=='\n' || c==EOF; + if(c==EOF) runq->eof++; + else if(flag['V'] || ndot>=2 && flag['v']) + pchr(err, c); + return c; +} + +void +pprompt(void) +{ + Var *prompt; + + if(runq->iflag){ + pstr(err, promptstr); + flush(err); + prompt=vlook("prompt"); + if(prompt->val && prompt->val->next) + promptstr=prompt->val->next->word; + else + promptstr="\t"; + } + runq->lineno++; + doprompt=0; +} + +void +skipwhite(void) +{ + int c; + for(;;){ + c=nextc(); + if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */ + for(;;){ + c=nextc(); + if(c=='\n' || c==EOF) break; + advance(); + } + } + if(c==' ' || c=='\t' || c=='\r') advance(); + else return; + } +} + +void +skipnl(void) +{ + int c; + for(;;){ + skipwhite(); + c=nextc(); + if(c!='\n') return; + advance(); + } +} + +int +nextis(int c) +{ + if(nextc()==c){ + advance(); + return 1; + } + return 0; +} + +char * +addtok(char *p, int val) +{ + if(p==0) return 0; + if(p==&tok[NTOK]){ + *p=0; + yyerror("token buffer too short"); + return 0; + } + *p++=val; + return p; +} + +char * +addutf(char *p, int c) +{ + p=addtok(p, c); + if(twobyte(c)) /* 2-byte escape */ + return addtok(p, advance()); + if(threebyte(c)){ /* 3-byte escape */ + p=addtok(p, advance()); + return addtok(p, advance()); + } + return p; +} + +int +yylex(void) +{ + int c, d=nextc(); + char *w=tok; + Tree *t; + + yylval.tree=0; + /* + * Embarassing sneakiness: if the last token read was a quoted or unquoted + * WORD then we alter the meaning of what follows. If the next character + * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise, + * if the next character is the first character of a simple or compound word, + * we insert a `^' before it. + */ + if(lastword){ + lastword=0; + if(d=='('){ + advance(); + strcpy(tok, "( [SUB]"); + return SUB; + } + if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){ + strcpy(tok, "^"); + return '^'; + } + } + inquote=0; + skipwhite(); + switch(c=advance()){ + case EOF: + lastdol=0; + strcpy(tok, "EOF"); + return EOF; + case '$': + lastdol=1; + if(nextis('#')){ + strcpy(tok, "$#"); + return COUNT; + } + if(nextis('"')){ + strcpy(tok, "$\""); + return '"'; + } + strcpy(tok, "$"); + return '$'; + case '&': + lastdol=0; + if(nextis('&')){ + skipnl(); + strcpy(tok, "&&"); + return ANDAND; + } + strcpy(tok, "&"); + return '&'; + case '|': + lastdol=0; + if(nextis(c)){ + skipnl(); + strcpy(tok, "||"); + return OROR; + } + case '<': + case '>': + lastdol=0; + /* + * funny redirection tokens: + * redir: arrow | arrow '[' fd ']' + * arrow: '<' | '<<' | '>' | '>>' | '|' + * fd: digit | digit '=' | digit '=' digit + * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' + * some possibilities are nonsensical and get a message. + */ + *w++=c; + t=newtree(); + switch(c){ + case '|': + t->type=PIPE; + t->fd0=1; + t->fd1=0; + break; + case '>': + t->type=REDIR; + if(nextis(c)){ + t->rtype=APPEND; + *w++=c; + } + else t->rtype=WRITE; + t->fd0=1; + break; + case '<': + t->type=REDIR; + if(nextis(c)){ + t->rtype=HERE; + *w++=c; + } + else t->rtype=READ; + t->fd0=0; + break; + } + if(nextis('[')){ + *w++='['; + c=advance(); + *w++=c; + if(c<'0' || '9'<c){ + RedirErr: + *w=0; + yyerror(t->type==PIPE?"pipe syntax" + :"redirection syntax"); + return EOF; + } + t->fd0=0; + do{ + t->fd0=t->fd0*10+c-'0'; + *w++=c; + c=advance(); + }while('0'<=c && c<='9'); + if(c=='='){ + *w++='='; + if(t->type==REDIR) + t->type=DUP; + c=advance(); + if('0'<=c && c<='9'){ + t->rtype=DUPFD; + t->fd1=t->fd0; + t->fd0=0; + do{ + t->fd0=t->fd0*10+c-'0'; + *w++=c; + c=advance(); + }while('0'<=c && c<='9'); + } + else{ + if(t->type==PIPE) goto RedirErr; + t->rtype=CLOSE; + } + } + if(c!=']' || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) + goto RedirErr; + *w++=']'; + } + *w='\0'; + yylval.tree=t; + if(t->type==PIPE) skipnl(); + return t->type; + case '\'': + lastdol=0; + lastword=1; + inquote=1; + for(;;){ + c=advance(); + if(c==EOF) break; + if(c=='\''){ + if(nextc()!='\'') + break; + advance(); + } + w=addutf(w, c); + } + if(w!=0) *w='\0'; + t=token(tok, WORD); + t->quoted=1; + yylval.tree=t; + return t->type; + } + if(!wordchr(c)){ + lastdol=0; + tok[0]=c; + tok[1]='\0'; + return c; + } + for(;;){ + /* next line should have (char)c==GLOB, but ken's compiler is broken */ + if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) + w=addtok(w, GLOB); + w=addutf(w, c); + c=nextc(); + if(lastdol?!idchr(c):!wordchr(c)) break; + advance(); + } +Out: + lastword=1; + lastdol=0; + if(w!=0) *w='\0'; + t=klook(tok); + if(t->type!=WORD) lastword=0; + t->quoted=0; + yylval.tree=t; + return t->type; +} + +void +yyerror(char *m) +{ + pfmt(err, "rc: "); + if(runq->cmdfile) pfmt(err, "file %s: ", runq->cmdfile); + if(!runq->iflag) pfmt(err, "line %d: ", runq->lineno); + if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok); + pfmt(err, "%s\n", m); + flush(err); + lastword=0; + lastdol=0; + while(lastc!='\n' && lastc!=EOF) advance(); + nerror++; +} diff --git a/utils/rcsh/main.c b/utils/rcsh/main.c new file mode 100644 index 00000000..93cd2951 --- /dev/null +++ b/utils/rcsh/main.c @@ -0,0 +1,228 @@ +#include "rc.h" + +int flag[256]; +Io *err; +char *argv0; + +Thread *runq; +int ndot; + + +void +main(int argc, char *argv[]) +{ + int i; + Code bootstrap[17]; + char *cflag, *cp; + char rcmain[200]; + Var *infroot; + char **p; + + cflag = 0; + + /* default to interactive mode */ + flag['i']++; + + /* hack for DOS-style options, when rcsh started from MS-land */ + for (p = argv+1; *p && **p == '/'; p++) + **p = '-'; + + argv0 = *argv; + ARGBEGIN{ + default: + fprint(2, "usage: %s: [-seiIlvxr] [-c string] [file [args]]\n", argv0); + exits("usage"); + case 'e': flag['e']++; break; + case 'c': cflag = ARGF(); break; + case 'i': flag['i']++; break; + case 'I': flag['i'] = 0; break; + case 'l': flag['l']++; break; + case 'r': flag['r']++; break; + case 's': flag['s']++; break; + case 'S': flag['S']++; break; /* sub shell */ + case 'v': flag['v']++; break; + case 'V': flag['V']++; break; + case 'x': flag['x']++; break; + }ARGEND + + err = openfd(2); + + kinit(); + vinit(); + + cp = ROOT; + if(0 && strlen(argv0)) + sprint(rcmain, "%s/../lib/rcmain", argv0); + else{ + infroot = vlook("ROOT"); + if(infroot->val) + cp = infroot->val->word; + } + sprint(rcmain, "%s/utils/lib/rcmain", cp); + + setvar("rcname", newword(argv0, 0)); + if(cflag) + setvar("cflag", newword(cflag, 0)); + else + setvar("cflag", 0); + + /* bootstrap == . rcmain $* */ + i=0; + bootstrap[i++].i=1; + bootstrap[i++].f=Xmark; + bootstrap[i++].f=Xword; + bootstrap[i++].s="*"; + bootstrap[i++].f=Xassign; + bootstrap[i++].f=Xmark; + bootstrap[i++].f=Xmark; + bootstrap[i++].f=Xword; + bootstrap[i++].s="*"; + bootstrap[i++].f=Xdol; + bootstrap[i++].f=Xword; + bootstrap[i++].s=rcmain; + bootstrap[i++].f=Xword; + bootstrap[i++].s="."; + bootstrap[i++].f=Xsimple; + bootstrap[i++].f=Xexit; + bootstrap[i].i=0; + start(bootstrap, 1, 0); + pushlist(); + for(i=argc-1;i>=0;i--) + pushword(argv[i]); + + for(;;){ + if(flag['r']) pfnc(err, runq); + runq->pc++; + (*runq->code[runq->pc-1].f)(); + if(ntrap.ref) + dotrap(); + } +} + +void +panic(char *s, int n) +{ + pfmt(err, "rc: "); + pfmt(err, s, n); + pchr(err, '\n'); + flush(err); + pfmt(err, "aborting\n"); + flush(err); + exits("aborting"); +} + +void +setstatus(char *s) +{ + setvar("status", newword(s, 0)); +} + +char * +getstatus(void) +{ + Var *status=vlook("status"); + + return status->val?status->val->word:""; +} + +int +truestatus(void) +{ + char *s; + for(s=getstatus();*s;s++) + if(*s!='|' && *s!='0') return 0; + return 1; +} + +char * +concstatus(char *s, char *t) +{ + static char v[NSTATUS+1]; + int n=strlen(s); + strncpy(v, s, NSTATUS); + if(n<NSTATUS){ + v[n]='|'; + strncpy(v+n+1, t, NSTATUS-n-1); + } + v[NSTATUS]='\0'; + return v; +} + +/* + * Start executing the given code at the given pc with the given redirection + */ +void +start(Code *c, int pc, Var *local) +{ + Thread *p = new(Thread); + + memset(p, 0, sizeof(Thread)); + p->code = codecopy(c); + p->pc = pc; + if(runq) { + p->redir = runq->redir; + p->startredir = runq->redir; + } + p->local = local; + p->lineno = 1; + p->ret = runq; + runq=p; +} + +void +execcmds(Io *f) +{ + static Code rdcmds[4]; + static int first=1; + + if(first){ + rdcmds[0].i=1; + rdcmds[1].f=Xrdcmds; + rdcmds[2].f=Xreturn; + first=0; + } + start(rdcmds, 1, runq->local); + runq->cmdfd=f; + runq->iflast=0; +} + +void +waitfor(uint pid) +{ + int e; + char estr[64]; + + e = procwait(pid); + if(e != 0) { + sprint(estr, "error code %d", e); + setstatus(estr); + } else + setstatus(""); +} + +char ** +procargv(char *s0, char *s1, char *s2, char *s3, Word *w) +{ + int n, i; + Word *p; + char **argv; + + for(p=w,n=5; p; p=p->next,n++); + ; + + argv = malloc(n*sizeof(char*)); + i = 0; + if(s0) + argv[i++] = s0; + if(s1) + argv[i++] = s1; + if(s2) + argv[i++] = s2; + if(s3) + argv[i++] = s3; + for(p=w; p; p=p->next) + argv[i++] = p->word; + argv[i] = 0; + return argv; +} + diff --git a/utils/rcsh/mkfile b/utils/rcsh/mkfile new file mode 100644 index 00000000..b4c818cf --- /dev/null +++ b/utils/rcsh/mkfile @@ -0,0 +1,53 @@ +<../../mkconfig + +# +# this directory contains a stripped-down version of rc +# it is only build for Windows Nt and Windows 95 + +TARG=rcsh + +OFILES= code.$O\ + exec.$O\ + glob.$O\ + here.$O\ + io.$O\ + lex.$O\ + main.$O\ + $TARGMODEL.$O\ + pcmd.$O\ + pfnc.$O\ + simple.$O\ + trap.$O\ + tree.$O\ + var.$O\ + word.$O\ + y.tab.$O\ + +HFILES= rc.h\ + y.tab.h\ + +YFILES= syn.y + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS '-DROOT="'$ROOT'"' + +$BIN/%:Q: $O.out + echo $TARG must be installed manually on Windows systems + echo use: cp $O.out $target + cp $O.out $target + +install:V: $ROOT/utils/lib/rcmain + +$ROOT/utils/lib/rcmain:Q: rcmain + echo $prereq must be installed manually on Windows systems + echo use: cp $prereq $target + cp $prereq $target + +Posix.c Inferno.c:QV: + echo $TARG is only built on Windows NT or Windows 95 + exit 1 diff --git a/utils/rcsh/pcmd.c b/utils/rcsh/pcmd.c new file mode 100644 index 00000000..9c5eb8a6 --- /dev/null +++ b/utils/rcsh/pcmd.c @@ -0,0 +1,110 @@ +#include "rc.h" +#include "y.tab.h" + +char nl='\n'; /* change to semicolon for bourne-proofing */ + +#define c0 t->child[0] +#define c1 t->child[1] +#define c2 t->child[2] + +void +pdeglob(Io *f, char *s) +{ + while(*s){ + if(*s==GLOB) s++; + pchr(f, *s++); + } +} + +void +pcmd(Io *f, Tree *t) +{ + if(t==0) + return; + + switch(t->type){ + default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break; + case '$': pfmt(f, "$%t", c0); break; + case '"': pfmt(f, "$\"%t", c0); break; + case '&': pfmt(f, "%t&", c0); break; + case '^': pfmt(f, "%t^%t", c0, c1); break; + case '`': pfmt(f, "`%t", c0); break; + case ANDAND: pfmt(f, "%t && %t", c0, c1); break; + case ARGLIST: pfmt(f, "%t %t", c0, c1); break; + case BANG: pfmt(f, "! %t", c0); break; + case BRACE: pfmt(f, "{%t}", c0); break; + case COUNT: pfmt(f, "$#%t", c0); break; + case FN: pfmt(f, "fn %t %t", c0, c1); break; + case IF: pfmt(f, "if%t%t", c0, c1); break; + case NOT: pfmt(f, "if not %t", c0); break; + case OROR: pfmt(f, "%t || %t", c0, c1); break; + case PCMD: + case PAREN: pfmt(f, "(%t)", c0); break; + case SUB: pfmt(f, "$%t(%t)", c0, c1); break; + case SIMPLE: pfmt(f, "%t", c0); break; + case SUBSHELL: pfmt(f, "@ %t", c0); break; + case SWITCH: pfmt(f, "switch %t %t", c0, c1); break; + case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); break; + case WHILE: pfmt(f, "while %t%t", c0, c1); break; + case ';': + if(c0){ + if(c1) pfmt(f, "%t%c%t", c0, nl, c1); + else pfmt(f, "%t", c0); + } + else pfmt(f, "%t", c1); + break; + case WORDS: + if(c0) pfmt(f, "%t ", c0); + pfmt(f, "%t", c1); + break; + case FOR: + pfmt(f, "for(%t", c0); + if(c1) pfmt(f, " in %t", c1); + pfmt(f, ")%t", c2); + break; + case WORD: + if(t->quoted) pfmt(f, "%Q", t->str); + else pdeglob(f, t->str); + break; + case DUP: + pfmt(f, ">[%d=", t->fd0); + if(t->rtype==DUPFD) + pfmt(f, "%d", t->fd1); + /* else t->rtype == CLOSE */ + pchr(f, ']'); + break; + case PIPEFD: + case REDIR: + switch(t->rtype){ + case HERE: + pchr(f, '<'); + case READ: + pchr(f, '<'); + if(t->fd0!=0) + pfmt(f, "[%d]", t->fd0); + break; + case APPEND: + pchr(f, '>'); + case WRITE: + pchr(f, '>'); + if(t->fd0!=1) + pfmt(f, "[%d]", t->fd0); + break; + } + pfmt(f, "%t", c0); + if(c1) pfmt(f, " %t", c1); + break; + case '=': + pfmt(f, "%t=%t", c0, c1); + if(c2) pfmt(f, " %t", c2); + break; + case PIPE: + pfmt(f, "%t|", c0); + if(t->fd1==0){ + if(t->fd0!=1) pfmt(f, "[%d]", t->fd0); + } + else pfmt(f, "[%d=%d]", t->fd0, t->fd1); + pfmt(f, "%t", c1); + break; + } +} diff --git a/utils/rcsh/pfnc.c b/utils/rcsh/pfnc.c new file mode 100644 index 00000000..4116b087 --- /dev/null +++ b/utils/rcsh/pfnc.c @@ -0,0 +1,70 @@ +#include "rc.h" + +struct{ + void (*f)(void); + char *name; +}fname[]={ + Xappend, "Xappend", + Xasync, "Xasync", + Xbang, "Xbang", + Xclose, "Xclose", + Xdup, "Xdup", + Xeflag, "Xeflag", + Xexit, "Xexit", + Xfalse, "Xfalse", + Xifnot, "Xifnot", + Xjump, "Xjump", + Xmark, "Xmark", + Xpopm, "Xpopm", + Xread, "Xread", + Xreturn, "Xreturn", + Xtrue, "Xtrue", + Xif, "Xif", + Xwastrue, "Xwastrue", + Xword, "Xword", + Xwrite, "Xwrite", + Xmatch, "Xmatch", + Xcase, "Xcase", + Xconc, "Xconc", + Xassign, "Xassign", + Xdol, "Xdol", + Xcount, "Xcount", + Xlocal, "Xlocal", + Xunlocal, "Xunlocal", + Xfn, "Xfn", + Xdelfn, "Xdelfn", + Xpipe, "Xpipe", + Xpipewait, "Xpipewait", + Xrdcmds, "Xrdcmds", + Xbackq, "Xbackq", + Xpipefd, "Xpipefd", + Xsubshell, "Xsubshell", + Xdelhere, "Xdelhere", + Xfor, "Xfor", + Xglob, "Xglob", + Xsimple, "Xsimple", + Xqdol, "Xqdol", + 0 +}; + +void +pfnc(Io *fd, Thread *t) +{ + int i; + void (*fn)(void)=t->code[t->pc].f; + List *a; + + pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc); + for(i=0;fname[i].f;i++) { + if(fname[i].f==fn) { + pstr(fd, fname[i].name); + break; + } + } + if(!fname[i].f) + pfmt(fd, "%p", fn); + for(a=t->argv;a;a=a->next) + pfmt(fd, " (%v)", a->words); + pchr(fd, '\n'); + flush(fd); +} diff --git a/utils/rcsh/rc.h b/utils/rcsh/rc.h new file mode 100644 index 00000000..f7d56746 --- /dev/null +++ b/utils/rcsh/rc.h @@ -0,0 +1,295 @@ +#include <lib9.h> + +#define Lock Rclock +#define Ref Rcref + +typedef union Code Code; +typedef struct Tree Tree; +typedef struct Thread Thread; +typedef struct Word Word; +typedef struct Var Var; +typedef struct List List; +typedef struct Redir Redir; +typedef struct Io Io; +typedef struct Here Here; +typedef struct Ref Ref; +typedef struct Lock Lock; +typedef struct Direntry Direntry; + +#define EOF (-1) +#define NBUF 512 + +/* values for Tree->rtype */ +#define APPEND 1 +#define WRITE 2 +#define READ 3 +#define HERE 4 +#define DUPFD 5 +#define CLOSE 6 + +/* + * redir types + */ +#define ROPEN 1 /* dup2(from, to); close(from); */ +#define RDUP 2 /* dup2(from, to); */ +#define RCLOSE 3 /* close(from); */ + +#define NSTATUS 64 /* length of status (from plan 9) */ + +#define IWS 0x01 /* inter word seperator when word lists are stored in env variables */ + +/* + * Glob character escape in strings: + * In a string, GLOB must be followed by *?[ or GLOB. + * GLOB* matches any string + * GLOB? matches any single character + * GLOB[...] matches anything in the brackets + * GLOBGLOB matches GLOB + */ +#define GLOB ((char)0x02) + +/* + * The first word of any code vector is a reference count. + * Always create a new reference to a code vector by calling codecopy(.). + * Always call codefree(.) when deleting a reference. + */ +union Code { + void (*f)(void); + int i; + char *s; +}; + + +struct Tree +{ + int type; + int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */ + char *str; + int quoted; + int iskw; + Tree *child[3]; + Tree *next; +}; + +struct Thread +{ + Code *code; /* code for this thread */ + int pc; /* code[pc] is the next instruction */ + List *argv; /* argument stack */ + Redir *redir; /* redirection stack */ + Redir *startredir; /* redir inheritance point */ + Var *local; /* list of local variables */ + char *cmdfile; /* file name in Xrdcmd */ + Io *cmdfd; /* file descriptor for Xrdcmd */ + int iflast; /* static `if not' checking */ + int eof; /* is cmdfd at eof? */ + int iflag; /* interactive? */ + int lineno; /* linenumber */ + int pid; /* process for Xpipewait to wait for */ + char status[NSTATUS]; /* status for Xpipewait */ + Tree *treenodes; /* tree nodes created by this process */ + Thread *ret; /* who continues when this finishes */ +}; + +struct Io +{ + int fd; + char *bufp; + char *ebuf; + char *strp; + char buf[NBUF]; +}; + +struct Var +{ + char *name; /* ascii name */ + Word *val; /* value */ + int changed; + Code *fn; /* pointer to function's code vector */ + int fnchanged; + int pc; /* pc of start of function */ + Var *next; /* next on hash or local list */ +}; + +struct Word +{ + char *word; + Word *next; +}; + +struct List +{ + Word *words; + List *next; +}; + +struct Redir +{ + char type; /* what to do */ + short from, to; /* what to do it to */ + Redir *next; /* what else to do (reverse order) */ +}; + +struct Here{ + Tree *tag; + char *name; + Here *next; +}; + +struct Lock { + int val; +}; + +struct Ref +{ + Lock lk; + int ref; +}; + +struct Direntry +{ + int isdir; + char *name; +}; + +/* main.c */ +void start(Code *c, int pc, Var *local); + +/* lex.c */ +void yyerror(char*); +int yylex(void); +int yyparse(void); +int wordchr(int); +int idchr(int); + +/* code.c */ +int compile(Tree*); +Code *codecopy(Code*); +void codefree(Code*); +void cleanhere(char *f); + +void skipnl(void); + +void panic(char*, int); + +/* var.c */ +void kinit(void); +void vinit(void); +Var *vlook(char*); +Var *gvlook(char*); +Var *newvar(char*, Var*); +void setvar(char*, Word*); +void updenv(void); +void kenter(int type, char *name); + +/* glob.c */ +void deglob(char*); +void globlist(void); +int match(char *s, char *p, int stop); + +/* main.c */ +void setstatus(char *s); +char *getstatus(void); +int truestatus(void); +void execcmds(Io*); +char *concstatus(char *s, char *t); +char **procargv(char*, char*, char*, char*, Word *w); + +void freewords(Word*); + +/* tree.c */ +Tree *newtree(void); +Tree *token(char*, int), *klook(char*), *tree1(int, Tree*); +Tree *tree2(int, Tree*, Tree*), *tree3(int, Tree*, Tree*, Tree*); +Tree *mung1(Tree*, Tree*), *mung2(Tree*, Tree*, Tree*); +Tree *mung3(Tree*, Tree*, Tree*, Tree*), *epimung(Tree*, Tree*); +Tree *simplemung(Tree*), *heredoc(Tree*); +void freetree(Tree*); +void freenodes(void); + +/* here.c */ +Tree *heredoc(Tree *tag); + +/* exec.c */ +extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void); +extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void); +extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void); +extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void); +extern void Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); +extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); +extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void); +extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void); +extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void); +extern void Xerror(char*), Xperror(char*); + +/* word.c */ +Word *newword(char*, Word*); +void pushlist(void); +void poplist(void); +void pushword(char*); +void popword(void); +int count(Word*); +Word *copywords(Word*, Word*); +void pushredir(int, int, int); +void turfredir(void); +char *list2str(Word*); +void freelist(Word*); +Word *conclist(Word*, Word*, Word*); +Word *subwords(Word*, int, Word*, Word*); + +/* io.c */ +#define pchr(b, c) if((b)->bufp==(b)->ebuf)fullbuf((b), (c));else (*(b)->bufp++=(c)) +#define rchr(b) ((b)->bufp==(b)->ebuf?emptybuf(b):(*(b)->bufp++&0xff)) + +Io *openfd(int), *openstr(void), *opencore(char*, int); +int emptybuf(Io*); +void closeio(Io*); +void flush(Io*); +int fullbuf(Io*, int); + +void pfmt(Io*, char*, ...); +void perr(Io*); +void pstr(Io*, char*); +void pfnc(Io*, Thread*); + +void pprompt(void); + +/* trap.c */ +void dotrap(void); +void dointr(void); + +void waitfor(uint); + +/* nt.c */ + +Direntry* readdirect(char*); +void fatal(char*, ...); +uint proc(char**, int, int, int); +int procwait(uint); +int refinc(Ref*); +int refdec(Ref*); +int pipe(int*); + +/* + * onebyte(c), twobyte(c), threebyte(c) + * Is c the first character of a one- two- or three-byte utf sequence? + */ +#define onebyte(c) ((c&0x80)==0x00) +#define twobyte(c) ((c&0xe0)==0xc0) +#define threebyte(c) ((c&0xf0)==0xe0) + +#define new(type) ((type *)malloc(sizeof(type))) + + +extern Tree *cmdtree; +extern Thread *runq; +extern Io *err; +extern int flag[256]; +extern int doprompt; +extern char *promptstr; +extern int ndot; +extern int nerror; +extern Code *codebuf; +extern int eflagok; +extern int interrupted; +extern Ref ntrap; diff --git a/utils/rcsh/rcmain b/utils/rcsh/rcmain new file mode 100644 index 00000000..f74190ca --- /dev/null +++ b/utils/rcsh/rcmain @@ -0,0 +1,29 @@ +# rcmain: 9pm version +if(~ $#home 0) home=/ +if(~ $#ifs 0) ifs=' +' +switch($#prompt){ +case 0 +case 1 + prompt=('% ' ' ') +} +if(~ $rcname v.out) prompt=('broken! ' ' ') +if(! ~ $#cflag 0){ + if(flag l && test -r $home/lib/profile) . $home/lib/profile + status='' + eval $cflag +} +if not if(flag i){ + if(flag l && test -r $home/lib/profile) . $home/lib/profile + status='' + if(! ~ $#* 0) . $* + if not . -i 'stdin$' +} +if not { + if(~ $#* 0) . 'stdin$' + if not{ + status='' + . $* + } +} +exit $status diff --git a/utils/rcsh/rcpath b/utils/rcsh/rcpath new file mode 100644 index 00000000..cb19ff4f --- /dev/null +++ b/utils/rcsh/rcpath @@ -0,0 +1,13 @@ +# rcmain: 9pm version +PF='Program Files' +MVS='Microsoft Visual Studio' +PATH=D:/Users/Inferno/Nt/386/bin +PATH=$PATH';'D:/apps/mks/mksnt +PATH=$PATH';'C:/WINNT/system32 +PATH=$PATH';'C:/WINNT +PATH=$PATH';'D:/$PF/$MVS/Common/Tools/WinNT +PATH=$PATH';'D:/$PF/$MVS/Common/MSDev98/Bin +PATH=$PATH';'D:/$PF/$MVS/Common/Tools +PATH=$PATH';'D:/$PF/$MVS/VC98/bin +PATH=$PATH';'D:/MSSQL7/BINN +PATH=$PATH';'D:/$PF/Mts diff --git a/utils/rcsh/simple.c b/utils/rcsh/simple.c new file mode 100644 index 00000000..1c3a89b3 --- /dev/null +++ b/utils/rcsh/simple.c @@ -0,0 +1,528 @@ +#include "rc.h" + +typedef struct Builtin Builtin; + +struct Builtin +{ + char *name; + void (*fnc)(void); +}; + +int exitnext(void); +void execexec(void); +void execfunc(Var *func); +void execcd(void); +void execwhatis(void); +void execeval(void); +void execexit(void); +void execshift(void); +void execwait(void); +void execdot(void); +void execflag(void); + +Builtin builtin[]={ + "cd", execcd, + "whatis", execwhatis, + "eval", execeval, + "exec", execexec, /* but with popword first */ + "exit", execexit, + "shift", execshift, + "wait", execwait, + ".", execdot, + "flag", execflag, + 0 +}; + +int mapfd(int fd); + +void +Xsimple(void) +{ + Word *a; + Thread *p=runq; + Var *v; + Builtin *bp; + uint pid; + char **argv; + + globlist(); + a=runq->argv->words; + if(a==0){ + Xerror("empty argument list"); + return; + } + if(flag['x']) + pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ + + v=gvlook(a->word); + if(v->fn) + execfunc(v); + else{ + if(strcmp(a->word, "builtin")==0){ + if(count(a)==1){ + pfmt(err, "builtin: empty argument list\n"); + setstatus("empty arg list"); + poplist(); + return; + } + a=a->next; + popword(); + } + for(bp=builtin;bp->name;bp++) { + if(strcmp(a->word, bp->name)==0){ + (*bp->fnc)(); + return; + } + } + + updenv(); + argv = procargv(0, 0, 0, 0, runq->argv->words); + pid = proc(argv, mapfd(0), mapfd(1), mapfd(2)); + free(argv); + + if(pid == 0) + pfmt(err, "%s: %r\n", runq->argv->words->word); + else + waitfor(pid); + poplist(); +#ifdef XXX + if(exitnext()){ + /* fork and wait is redundant */ + pushword("exec"); + execexec(); + Xexit(); + } + else{ + flush(err); + updenv(); + switch(pid=fork()){ + case -1: + Xperror("try again"); + return; + case 0: + pushword("exec"); + execexec(); + Exit("can't exec"); + default: + poplist(); + /* interrupts don't get us out */ + while(Waitfor(pid, 1) < 0) + ; + } + } +#endif + } +} + +Word nullpath={ "", 0}; + +Word * +searchpath(char *w) +{ + Word *path; + + return &nullpath; + + if(strncmp(w, "/", 1) == 0 + || strncmp(w, "#", 1) == 0 + || *w && w[1] == ':' + || strncmp(w, "./", 2) == 0 + || strncmp(w, "../", 3) == 0 + || (path=vlook("path")->val) == 0) + path=&nullpath; + return path; +} + +/* + * Search through the following code to see if we're just going to exit. + */ +int +exitnext(void) +{ + Code *c=&runq->code[runq->pc]; + + while(c->f==Xpopredir) + c++; + return c->f==Xexit; +} + +#ifdef XXX + +void +doredir(Redir *rp) +{ + if(rp){ + doredir(rp->next); + switch(rp->type){ + case ROPEN: + if(rp->from!=rp->to){ + Dup(rp->from, rp->to); + close(rp->from); + } + break; + case RDUP: Dup(rp->from, rp->to); break; + case RCLOSE: close(rp->from); break; + } + } +} + + +#endif + +void +execexec(void) +{ + popword(); /* "exec" */ + if(runq->argv->words==0){ + Xerror("empty argument list"); + return; + } + fatal("execexec not done yet"); +/* + doredir(runq->redir); + Execute(runq->argv->words, searchpath(runq->argv->words->word)); +*/ + + poplist(); +} + +void +execfunc(Var *func) +{ + Word *starval; + + popword(); + starval=runq->argv->words; + runq->argv->words=0; + poplist(); + start(func->fn, func->pc, 0); + runq->local=newvar(strdup("*"), runq->local); + runq->local->val=starval; + runq->local->changed=1; +} + +void +execcd(void) +{ + Word *a=runq->argv->words; + Word *cdpath; + char dir[512]; + + setstatus("can't cd"); + cdpath=vlook("cdpath")->val; + switch(count(a)){ + default: + pfmt(err, "Usage: cd [directory]\n"); + break; + case 2: + if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; + for(;cdpath;cdpath=cdpath->next){ + strcpy(dir, cdpath->word); + if(dir[0]) strcat(dir, "/"); + strcat(dir, a->next->word); + if(chdir(dir)>=0){ + if(strlen(cdpath->word) + && strcmp(cdpath->word, ".")!=0) + pfmt(err, "%s\n", dir); + setstatus(""); + break; + } + } + if(cdpath==0) pfmt(err, "Can't cd %s\n", a->next->word); + break; + case 1: + a=vlook("home")->val; + if(count(a)>=1){ + if(chdir(a->word)>=0) + setstatus(""); + else + pfmt(err, "Can't cd %s\n", a->word); + } + else + pfmt(err, "Can't cd -- $home empty\n"); + break; + } + poplist(); +} + +void +execexit(void) +{ + switch(count(runq->argv->words)){ + default: pfmt(err, "Usage: exit [status]\nExiting anyway\n"); + case 2: setstatus(runq->argv->words->next->word); + case 1: Xexit(); + } +} + +void +execflag(void) +{ + char *letter, *val; + switch(count(runq->argv->words)){ + case 2: + setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set"); + break; + case 3: + letter=runq->argv->words->next->word; + val=runq->argv->words->next->next->word; + if(strlen(letter)==1){ + if(strcmp(val, "+")==0){ + flag[letter[0]]=1; + break; + } + if(strcmp(val, "-")==0){ + flag[letter[0]]=0; + break; + } + } + default: + Xerror("Usage: flag [letter] [+-]"); + return; + } + poplist(); +} + +void +execshift(void) +{ + int n; + Word *a; + Var *star; + switch(count(runq->argv->words)){ + default: + pfmt(err, "Usage: shift [n]\n"); + setstatus("shift usage"); + poplist(); + return; + case 2: n=atoi(runq->argv->words->next->word); break; + case 1: n=1; break; + } + star=vlook("*"); + for(;n && star->val;--n){ + a=star->val->next; + free(star->val->word); + free(star->val); + star->val=a; + star->changed=1; + } + setstatus(""); + poplist(); +} + +int +octal(char *s) +{ + int n=0; + while(*s==' ' || *s=='\t' || *s=='\n') s++; + while('0'<=*s && *s<='7') n=n*8+*s++-'0'; + return n; +} + +void +execeval(void) +{ + char *cmdline, *s, *t; + int len=0; + Word *ap; + + if(count(runq->argv->words)<=1){ + Xerror("Usage: eval cmd ..."); + return; + } + eflagok=1; + for(ap=runq->argv->words->next;ap;ap=ap->next) + len+=1+strlen(ap->word); + cmdline=malloc(len); + s=cmdline; + for(ap=runq->argv->words->next;ap;ap=ap->next){ + for(t=ap->word;*t;) *s++=*t++; + *s++=' '; + } + s[-1]='\n'; + poplist(); + execcmds(opencore(cmdline, len)); + free(cmdline); +} + +void +execdot(void) +{ + int iflag=0; + int fd; + List *av; + Thread *p=runq; + char *zero; + char file[512]; + Word *path; + static int first=1; + static Code dotcmds[14]; + + if(first) { + dotcmds[0].i=1; + dotcmds[1].f=Xmark; + dotcmds[2].f=Xword; + dotcmds[3].s="0"; + dotcmds[4].f=Xlocal; + dotcmds[5].f=Xmark; + dotcmds[6].f=Xword; + dotcmds[7].s="*"; + dotcmds[8].f=Xlocal; + dotcmds[9].f=Xrdcmds; + dotcmds[10].f=Xunlocal; + dotcmds[11].f=Xunlocal; + dotcmds[12].f=Xreturn; + first=0; + } else + eflagok=1; + popword(); + if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ + iflag=1; + popword(); + } + /* get input file */ + if(p->argv->words==0){ + Xerror("Usage: . [-i] file [arg ...]"); + return; + } + zero=strdup(p->argv->words->word); + popword(); + strcpy(file, "**No file name**"); + fd = -1; + if(strcmp(zero, "stdin$") == 0) + fd = dup(0); + else{ + for(path=searchpath(zero);path;path=path->next){ + strcpy(file, path->word); + if(file[0]) + strcat(file, "/"); + strcat(file, zero); + if((fd=open(file, 0))>=0) + break; + } + } + if(fd<0){ + Xperror(file); + return; + } + /* set up for a new command loop */ + start(dotcmds, 1, 0); + pushredir(RCLOSE, fd, 0); + runq->cmdfile=zero; + runq->cmdfd=openfd(fd); + runq->iflag=iflag; + runq->iflast=0; + /* push $* value */ + pushlist(); + runq->argv->words=p->argv->words; + /* free caller's copy of $* */ + av=p->argv; + p->argv=av->next; + free(av); + /* push $0 value */ + pushlist(); + pushword(zero); + ndot++; +} + +void +execwhatis(void) +{ /* mildly wrong -- should fork before writing */ + Word *a, *b, *path; + Var *v; + Builtin *bp; + char file[512]; + Io out[1]; + int found, sep; + + a=runq->argv->words->next; + if(a==0){ + Xerror("Usage: whatis name ..."); + return; + } + setstatus(""); + out->fd=mapfd(1); + out->bufp=out->buf; + out->ebuf=&out->buf[NBUF]; + out->strp=0; + for(;a;a=a->next){ + v=vlook(a->word); + if(v->val){ + pfmt(out, "%s=", a->word); + if(v->val->next==0) + pfmt(out, "%q\n", v->val->word); + else{ + sep='('; + for(b=v->val;b && b->word;b=b->next){ + pfmt(out, "%c%q", sep, b->word); + sep=' '; + } + pfmt(out, ")\n"); + } + found=1; + } + else + found=0; + v=gvlook(a->word); + if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); + else{ + for(bp=builtin;bp->name;bp++) + if(strcmp(a->word, bp->name)==0){ + pfmt(out, "builtin %s\n", a->word); + break; + } + if(!bp->name){ + for(path=searchpath(a->word);path;path=path->next){ + strcpy(file, path->word); + if(file[0]) strcat(file, "/"); + strcat(file, a->word); +#ifdef XXX + if(Executable(file)){ + pfmt(out, "%s\n", file); + break; + } +#endif + } + if(!path && !found){ + pfmt(err, "%s: not found\n", a->word); + setstatus("not found"); + } + } + } + } + poplist(); + flush(err); +} + +void +execwait(void) +{ + fprint(2, "wait: not done yet"); + +#ifdef XXX + switch(count(runq->argv->words)){ + default: Xerror("Usage: wait [pid]"); return; + case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break; + case 1: Waitfor(-1, 0); break; + } + poplist(); +#endif +} + +int +mapfd(int fd) +{ + Redir *rp; + for(rp=runq->redir;rp;rp=rp->next){ + switch(rp->type){ + case RCLOSE: + if(rp->from==fd) fd=-1; + break; + case RDUP: + case ROPEN: + if(rp->to==fd) fd=rp->from; + break; + } + } + return fd; +} diff --git a/utils/rcsh/syn.y b/utils/rcsh/syn.y new file mode 100644 index 00000000..b0201ef0 --- /dev/null +++ b/utils/rcsh/syn.y @@ -0,0 +1,90 @@ +%{ +#include "rc.h" +%} + +/* operator priorities -- lowest first */ +%left IF WHILE FOR SWITCH ')' NOT +%left ANDAND OROR +%left BANG SUBSHELL +%left PIPE +%left '^' +%right '$' COUNT '"' +%left SUB + +%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN +%term WORD REDIR DUP PIPE SUB +%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */ + + +%union{ + Tree *tree; +}; + +%type<tree> line paren brace body cmdsa cmdsan assign epilog redir +%type<tree> cmd simple first word comword keyword words +%type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN +%type<tree> WORD REDIR DUP PIPE + +%% + +rc: { return 1;} +| line '\n' {return !compile($1);} +line: cmd +| cmdsa line {$$=tree2(';', $1, $2);} +body: cmd +| cmdsan body {$$=tree2(';', $1, $2);} +cmdsa: cmd ';' +| cmd '&' {$$=tree1('&', $1);} +cmdsan: cmdsa +| cmd '\n' +brace: '{' body '}' {$$=tree1(BRACE, $2);} +paren: '(' body ')' {$$=tree1(PCMD, $2);} +assign: first '=' word {$$=tree2('=', $1, $3);} +epilog: {$$=0;} +| redir epilog {$$=mung2($1, $1->child[0], $2);} +redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} +| DUP +cmd: {$$=0;} +| brace epilog {$$=epimung($1, $2);} +| IF paren {skipnl();} cmd + {$$=mung2($1, $2, $4);} +| IF NOT {skipnl();} cmd {$$=mung1($2, $4);} +| FOR '(' word IN words ')' {skipnl();} cmd + {$$=mung3($1, $3, tree1(PAREN, $5), $8);} +| FOR '(' word ')' {skipnl();} cmd + {$$=mung3($1, $3, 0, $6);} +| WHILE paren {skipnl();} cmd + {$$=mung2($1, $2, $4);} +| SWITCH word {skipnl();} brace + {$$=tree2(SWITCH, $2, $4);} +| simple {$$=simplemung($1);} +| TWIDDLE word words {$$=mung2($1, $2, $3);} +| cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);} +| cmd OROR cmd {$$=tree2(OROR, $1, $3);} +| cmd PIPE cmd {$$=mung2($2, $1, $3);} +| redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);} +| assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);} +| BANG cmd {$$=mung1($1, $2);} +| SUBSHELL cmd {$$=mung1($1, $2);} +| FN words brace {$$=tree2(FN, $2, $3);} +| FN words {$$=tree1(FN, $2);} +simple: first +| simple word {$$=tree2(ARGLIST, $1, $2);} +| simple redir {$$=tree2(ARGLIST, $1, $2);} +first: comword +| first '^' word {$$=tree2('^', $1, $3);} +word: keyword {$1->type=WORD;} +| comword +| word '^' word {$$=tree2('^', $1, $3);} +comword: '$' word {$$=tree1('$', $2);} +| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);} +| '"' word {$$=tree1('"', $2);} +| COUNT word {$$=tree1(COUNT, $2);} +| WORD +| '`' brace {$$=tree1('`', $2);} +| '(' words ')' {$$=tree1(PAREN, $2);} +/* | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;} */ + +keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN +words: {$$=0;} +| words word {$$=tree2(WORDS, $1, $2);} diff --git a/utils/rcsh/trap.c b/utils/rcsh/trap.c new file mode 100644 index 00000000..7bae2cbc --- /dev/null +++ b/utils/rcsh/trap.c @@ -0,0 +1,42 @@ +#include "rc.h" + +int interrupted; +Ref ntrap; + +/* runs in a different thread */ +void +dointr(void) +{ + refinc(&ntrap); + interrupted = 1; +} + +void +dotrap(void) +{ + Var *trapreq; + Word *starval; + + while(refdec(&ntrap) >= 0) { + if(flag['S']) + exits(truestatus()?"":getstatus()); + starval=vlook("*")->val; + trapreq=vlook("sysint"); + if(trapreq->fn){ + start(trapreq->fn, trapreq->pc, (Var*)0); + runq->local=newvar(strdup("*"), runq->local); + runq->local->val=copywords(starval, (Word*)0); + runq->local->changed=1; + runq->redir=runq->startredir=0; + } else { + /* + * run the stack down until we uncover the + * command reading loop. Xreturn will exit + * if there is none (i.e. if this is not + * an interactive rc.) + */ + while(!runq->iflag) + Xreturn(); + } + } +} diff --git a/utils/rcsh/tree.c b/utils/rcsh/tree.c new file mode 100644 index 00000000..145f9c77 --- /dev/null +++ b/utils/rcsh/tree.c @@ -0,0 +1,140 @@ +#include "rc.h" +#include "y.tab.h" + +Tree *Treenodes; + +/* + * create and clear a new Tree node, and add it + * to the node list. + */ +Tree * +newtree(void) +{ + Tree *t=new(Tree); + t->iskw=0; + t->str=0; + t->child[0]=t->child[1]=t->child[2]=0; + t->next=Treenodes; + Treenodes=t; + return t; +} + +void +freenodes(void) +{ + Tree *t, *u; + for(t=Treenodes;t;t=u){ + u=t->next; + if(t->str) + free(t->str); + free(t); + } + Treenodes=0; +} + +Tree * +tree1(int type, Tree *c0) +{ + return tree3(type, c0, 0, 0); +} + +Tree * +tree2(int type, Tree *c0, Tree *c1) +{ + return tree3(type, c0, c1, 0); +} + +Tree * +tree3(int type, Tree *c0, Tree *c1, Tree *c2) +{ + Tree *t; + if(type==';'){ + if(c0==0) return c1; + if(c1==0) return c0; + } + t=newtree(); + t->type=type; + t->child[0]=c0; + t->child[1]=c1; + t->child[2]=c2; + return t; +} + +Tree * +mung1(Tree *t, Tree *c0) +{ + t->child[0]=c0; + return t; +} + +Tree * +mung2(Tree *t, Tree *c0, Tree *c1) +{ + t->child[0]=c0; + t->child[1]=c1; + return t; +} + +Tree * +mung3(Tree *t, Tree *c0, Tree *c1, Tree *c2) +{ + t->child[0]=c0; + t->child[1]=c1; + t->child[2]=c2; + return t; +} + +Tree * +epimung(Tree *comp, Tree *epi) +{ + Tree *p; + if(epi==0) return comp; + for(p=epi;p->child[1];p=p->child[1]); + p->child[1]=comp; + return epi; +} + +/* + * Add a SIMPLE node at the root of t and percolate all the redirections + * up to the root. + */ +Tree * +simplemung(Tree *t) +{ + Tree *u; + Io *s; + t=tree1(SIMPLE, t); + s=openstr(); + pfmt(s, "%t", t); + t->str=strdup(s->strp); + closeio(s); + for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){ + if(u->child[1]->type==DUP + || u->child[1]->type==REDIR){ + u->child[1]->child[1]=t; + t=u->child[1]; + u->child[1]=0; + } + } + return t; +} + +Tree * +token(char *str, int type) +{ + Tree *t=newtree(); + t->type=type; + t->str=strdup(str); + return t; +} + +void +freetree(Tree *p) +{ + if(p==0) return; + freetree(p->child[0]); + freetree(p->child[1]); + freetree(p->child[2]); + if(p->str) free(p->str); + free((char *)p); +} diff --git a/utils/rcsh/var.c b/utils/rcsh/var.c new file mode 100644 index 00000000..cee8adf5 --- /dev/null +++ b/utils/rcsh/var.c @@ -0,0 +1,240 @@ +#include "rc.h" +#include "y.tab.h" + +extern char **_environ; + +typedef struct Kw Kw; + +#define NKW 30 +#define NVAR 521 + +struct Kw{ + char *name; + int type; + Kw *next; +}; + +void updenvlocal(Var *v); +void addenv(Var *v); + +Kw *kw[NKW]; +Var *gvar[NVAR]; + +int +hash(char *s, int n) +{ + int h=0, i=1; + + while(*s) + h+=*s++*i++; + h%=n; + return h<0?h+n:h; +} + +void +kenter(int type, char *name) +{ + int h=hash(name, NKW); + Kw *p=new(Kw); + p->type=type; + p->name=name; + p->next=kw[h]; + kw[h]=p; +} + +void +vinit(void) +{ + char **env, *name, *val, *p; + int i; + Word *w; + Io *f; + int n; + Var *v; + + env = _environ; + for(i=0; env[i]; free(name), i++) { + name = strdup(env[i]); + p = strchr(name, '='); + if(p == 0 || p == name) + continue; + *p = 0; + val = p+1; + n = strlen(val); + if(n == 0) + continue; + + if(strncmp(name, "fn#", 3)!=0) { + /* variable */ + w = 0; + p = val+n-1; + while(*p) { + if(*p == IWS) + *p-- = 0; + for(; *p && *p != IWS; p--) + ; + w=newword(p+1, w); + } + setvar(name, w); + vlook(name)->changed=0; + } else { + /* function */ + f = opencore(val, n); + execcmds(f); + } + } + v = vlook("path"); + p = getenv("path"); + if(v->val == 0 && p) + v->val = newword(p, 0); +} + + +Tree * +klook(char *name) +{ + Kw *p; + Tree *t=token(name, WORD); + for(p=kw[hash(name, NKW)];p;p=p->next) { + if(strcmp(p->name, name)==0){ + t->type=p->type; + t->iskw=1; + break; + } + } + return t; +} + +Var * +gvlook(char *name) +{ + int h=hash(name, NVAR); + Var *v; + for(v=gvar[h]; v; v=v->next) + if(strcmp(v->name, name)==0) + return v; + + return gvar[h]=newvar(strdup(name), gvar[h]); +} + +Var * +vlook(char *name) +{ + Var *v; + if(runq) + for(v=runq->local; v; v=v->next) + if(strcmp(v->name, name)==0) + return v; + return gvlook(name); +} + +void +setvar(char *name, Word *val) +{ + Var *v=vlook(name); + freewords(v->val); + v->val=val; + v->changed=1; +} + +Var * +newvar(char *name, Var *next) +{ + Var *v=new(Var); + v->name=name; + v->val=0; + v->fn=0; + v->changed=0; + v->fnchanged=0; + v->next=next; + return v; +} + + +void +execfinit(void) +{ +} + +void +updenv(void) +{ + Var *v, **h; + + for(h=gvar;h!=&gvar[NVAR];h++) + for(v=*h;v;v=v->next) + addenv(v); + + if(runq) + updenvlocal(runq->local); +} + +static void +envput(char *var, char *val) +{ + int i, n; + char *e; + char buf[256]; + + snprint(buf, sizeof(buf), "%s=%s", var, val); + n = strlen(var); + for(i = 0;;i++){ + e = environ[i]; + if(e == 0) + break; + if(strncmp(e, var, n) == 0){ + free(e); + environ[i] = strdup(buf); + return; + } + } + environ = realloc(environ, (i+2)*sizeof(char*)); + environ[i++] = strdup(buf); + environ[i] = 0; +} + +void +addenv(Var *v) +{ + char buf[100], *p; + Io *f; + Word *w; + int i, n; + + if(v->changed){ + v->changed=0; + p = 0; + n = 0; + if(v->val) { + for(w=v->val; w; w=w->next) { + i = strlen(w->word); + p = realloc(p, n+i+1); + memmove(p+n, w->word, i); + n+=i; + p[n++] = IWS; + } + p[n-1] = 0; + envput(v->name, p); + } else + envput(v->name, ""); + free(p); + } + + if(v->fnchanged){ + v->fnchanged=0; + snprint(buf, sizeof(buf), "fn#%s", v->name); + f = openstr(); + pfmt(f, "fn %s %s\n", v->name, v->fn[v->pc-1].s); + envput(buf, f->strp); + closeio(f); + } +} + +void +updenvlocal(Var *v) +{ + if(v){ + updenvlocal(v->next); + addenv(v); + } +} diff --git a/utils/rcsh/word.c b/utils/rcsh/word.c new file mode 100644 index 00000000..7cbab88e --- /dev/null +++ b/utils/rcsh/word.c @@ -0,0 +1,173 @@ +#include "rc.h" + +Word * +newword(char *wd, Word *next) +{ + Word *p=new(Word); + p->word=strdup(wd); + p->next=next; + return p; +} + +void +pushword(char *wd) +{ + if(runq->argv==0) + panic("pushword but no argv!", 0); + runq->argv->words=newword(wd, runq->argv->words); +} + +void +popword(void) +{ + Word *p; + + if(runq->argv==0) + panic("popword but no argv!", 0); + p=runq->argv->words; + if(p==0) + panic("popword but no word!", 0); + runq->argv->words=p->next; + free(p->word); + free(p); +} + +void +freewords(Word *w) +{ + Word *nw; + while(w){ + free(w->word); + nw=w->next; + free(w); + w=nw; + } +} + +void +freelist(Word *w) +{ + Word *nw; + while(w){ + nw=w->next; + free(w->word); + free(w); + w=nw; + } +} + +void +pushlist(void) +{ + List *p=new(List); + p->next=runq->argv; + p->words=0; + runq->argv=p; +} + +void +poplist(void) +{ + List *p=runq->argv; + if(p==0) + panic("poplist but no argv", 0); + freelist(p->words); + runq->argv=p->next; + free(p); +} + +int +count(Word *w) +{ + int n; + for(n=0;w;n++) + w=w->next; + return n; +} + +/* + * copy arglist a, adding the copy to the front of tail + */ +Word * +copywords(Word *a, Word *tail) +{ + Word *v=0, **end; + for(end=&v;a;a=a->next,end=&(*end)->next) + *end=newword(a->word, 0); + *end=tail; + return v; +} + +char * +list2str(Word *words) +{ + char *value, *s, *t; + int len=0; + Word *ap; + + for(ap=words;ap;ap=ap->next) + len+=1+strlen(ap->word); + value=malloc(len+1); + s=value; + for(ap=words;ap;ap=ap->next){ + for(t=ap->word;*t;) *s++=*t++; + *s++=' '; + } + if(s==value) + *s='\0'; + else + s[-1]='\0'; + return value; +} + +Word * +subwords(Word *val, int len, Word *sub, Word *a) +{ + int n; + char *s; + + if(!sub) return a; + a=subwords(val, len, sub->next, a); + s=sub->word; + deglob(s); + n=0; + while('0'<=*s && *s<='9') n=n*10+ *s++ -'0'; + if(n<1 || len<n) return a; + for(;n!=1;--n) val=val->next; + return newword(val->word, a); +} + + +void +pushredir(int type, int from, int to) +{ + Redir *rp=new(Redir); + rp->type=type; + rp->from=from; + rp->to=to; + rp->next=runq->redir; + runq->redir=rp; +} + +void +turfredir(void) +{ + while(runq->redir!=runq->startredir) + Xpopredir(); +} + +Word* +conclist(Word *lp, Word *rp, Word *tail) +{ + char *buf; + Word *v; + if(lp->next || rp->next) + tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next, + tail); + buf=malloc(strlen(lp->word)+strlen(rp->word)+1); + strcpy(buf, lp->word); + strcat(buf, rp->word); + v=newword(buf, tail); + free(buf); + return v; +} diff --git a/utils/rm/mkfile b/utils/rm/mkfile new file mode 100644 index 00000000..0051452b --- /dev/null +++ b/utils/rm/mkfile @@ -0,0 +1,24 @@ +<../../mkconfig + +# +# the rm command is only needed on Windows NT and Windows 95 +# + +TARG=rm + +OFILES= rm-$TARGMODEL.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +rm-Posix.c rm-Inferno.c:QV: + echo 'rm is only built on Windows NT or Windows 95' + exit 1 + +$BIN/rm.exe: $O.out + rm -f $target && cp $prereq $target diff --git a/utils/rm/rm-Nt.c b/utils/rm/rm-Nt.c new file mode 100644 index 00000000..9c666213 --- /dev/null +++ b/utils/rm/rm-Nt.c @@ -0,0 +1,151 @@ +#include <lib9.h> +#include <windows.h> + +typedef struct Direntry +{ + int isdir; + char *name; +} Direntry; + +char errbuf[ERRMAX]; +long ndirbuf = 0; +int ignerr = 0; + +void +err(char *f) +{ + if(!ignerr){ + errstr(errbuf, sizeof errbuf); + fprint(2, "rm: %s: %s\n", f, errbuf); + } +} + +int +badentry(char *filename) +{ + if(*filename == 0) + return 1; + if(filename[0] == '.'){ + if(filename[1] == 0) + return 1; + if(filename[1] == '.' && filename[2] == 0) + return 1; + } + return 0; +} + +/* + * Read a whole directory before removing anything as the holes formed + * by removing affect the read offset. + */ +Direntry* +readdirect(char *path) +{ + long n; + HANDLE h; + Direntry *d; + char fullpath[MAX_PATH]; + WIN32_FIND_DATA data; + + snprint(fullpath, MAX_PATH, "%s\\*.*", path); + h = FindFirstFile(fullpath, &data); + if(h == INVALID_HANDLE_VALUE) + err(path); + + n = 0; + d = 0; + for(;;){ + if(!badentry(data.cFileName)){ + d = realloc(d, (n+2)*sizeof(Direntry)); + if(d == 0){ + err("memory allocation"); + exits(errbuf); + } + d[n].name = malloc(strlen(data.cFileName)+1); + if(d[n].name == 0){ + err("memory allocation"); + exits(errbuf); + } + strcpy(d[n].name, data.cFileName); + if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + d[n].isdir = 1; + else + d[n].isdir = 0; + n++; + } + if(FindNextFile(h, &data) == 0) + break; + } + FindClose(h); + if(d){ + d[n].name = 0; + d[n].isdir = 0; + } + return d; +} + +/* + * f is a non-empty directory. Remove its contents and then it. + */ +void +Ntrmdir(char *f) +{ + Direntry *dp, *dq; + char name[MAX_PATH]; + + dq = readdirect(f); + + if(dq == 0) + return; + + for(dp = dq; dp->name; dp++){ + snprint(name, MAX_PATH, "%s/%s", f, dp->name); + if(remove(name) == -1){ + if(dp->isdir == 0) + err(name); + else + if(RemoveDirectory(name) == 0) + Ntrmdir(name); + } + free(dp->name); + } + if(RemoveDirectory(f) == 0) + err(f); + free(dq); +} + +void +main(int argc, char *argv[]) +{ + int i; + int recurse; + char *f; + Dir *db; + + ignerr = 0; + recurse = 0; + ARGBEGIN{ + case 'r': + recurse = 1; + break; + case 'f': + ignerr = 1; + break; + default: + fprint(2, "usage: rm [-fr] file ...\n"); + exits("usage"); + }ARGEND + for(i=0; i<argc; i++){ + f = argv[i]; + if(remove(f) != -1) + continue; + if((db = dirstat(f)) == nil || (db->qid.type&QTDIR) ==0) + err(f); + else if(RemoveDirectory(f) == 0) + if(recurse) + Ntrmdir(f); + else + err(f); + } + exits(errbuf); +} diff --git a/utils/sed/mkfile b/utils/sed/mkfile new file mode 100644 index 00000000..f56a797b --- /dev/null +++ b/utils/sed/mkfile @@ -0,0 +1,16 @@ +<../../mkconfig + +TARG=sed + +OFILES= sed.$O\ + +HFILES= $ROOT/include/bio.h\ + ../include/regexp.h\ + +LIBS=regexp bio 9 # libbio.a uses lib9.a so order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/sed/sed.c b/utils/sed/sed.c new file mode 100644 index 00000000..e275b8f4 --- /dev/null +++ b/utils/sed/sed.c @@ -0,0 +1,1428 @@ +/* + * sed -- stream editor + * + * + */ +#include <lib9.h> +#include <bio.h> +#include <regexp.h> + +enum { + DEPTH = 20, /* max nesting depth of {} */ + MAXCMDS = 512, /* max sed commands */ + ADDSIZE = 10000, /* size of add & read buffer */ + MAXADDS = 20, /* max pending adds and reads */ + LBSIZE = 8192, /* input line size */ + LABSIZE = 50, /* max label name size */ + MAXSUB = 10, /* max number of sub reg exp */ + MAXFILES = 120, /* max output files */ +}; + /* An address is a line #, a R.E., "$", a reference to the last + * R.E., or nothing. + */ +typedef struct { + enum { + A_NONE, + A_DOL, + A_LINE, + A_RE, + A_LAST, + }type; + union { + long line; /* Line # */ + Reprog *rp; /* Compiled R.E. */ + }; +} Addr; + +typedef struct SEDCOM { + Addr ad1; /* optional start address */ + Addr ad2; /* optional end address */ + union { + Reprog *re1; /* compiled R.E. */ + Rune *text; /* added text or file name */ + struct SEDCOM *lb1; /* destination command of branch */ + }; + Rune *rhs; /* Right-hand side of substitution */ + Biobuf* fcode; /* File ID for read and write */ + char command; /* command code -see below */ + char gfl; /* 'Global' flag for substitutions */ + char pfl; /* 'print' flag for substitutions */ + char active; /* 1 => data between start and end */ + char negfl; /* negation flag */ +} SedCom; + + /* Command Codes for field SedCom.command */ +#define ACOM 01 +#define BCOM 020 +#define CCOM 02 +#define CDCOM 025 +#define CNCOM 022 +#define COCOM 017 +#define CPCOM 023 +#define DCOM 03 +#define ECOM 015 +#define EQCOM 013 +#define FCOM 016 +#define GCOM 027 +#define CGCOM 030 +#define HCOM 031 +#define CHCOM 032 +#define ICOM 04 +#define LCOM 05 +#define NCOM 012 +#define PCOM 010 +#define QCOM 011 +#define RCOM 06 +#define SCOM 07 +#define TCOM 021 +#define WCOM 014 +#define CWCOM 024 +#define YCOM 026 +#define XCOM 033 + + +typedef struct label { /* Label symbol table */ + Rune asc[9]; /* Label name */ + SedCom *chain; + SedCom *address; /* Command associated with label */ +} Label; + +typedef struct FILE_CACHE { /* Data file control block */ + struct FILE_CACHE *next; /* Forward Link */ + char *name; /* Name of file */ +} FileCache; + +SedCom pspace[MAXCMDS]; /* Command storage */ +SedCom *pend = pspace+MAXCMDS; /* End of command storage */ +SedCom *rep = pspace; /* Current fill point */ + +Reprog *lastre = 0; /* Last regular expression */ +Resub subexp[MAXSUB]; /* sub-patterns of pattern match*/ + +Rune addspace[ADDSIZE]; /* Buffer for a, c, & i commands */ +Rune *addend = addspace+ADDSIZE; + +SedCom *abuf[MAXADDS]; /* Queue of pending adds & reads */ +SedCom **aptr = abuf; + +struct { /* Sed program input control block */ + enum PTYPE /* Either on command line or in file */ + { P_ARG, + P_FILE + } type; + union PCTL { /* Pointer to data */ + Biobuf *bp; + char *curr; + }; +} prog; + +Rune genbuf[LBSIZE]; /* Miscellaneous buffer */ + +FileCache *fhead = 0; /* Head of File Cache Chain */ +FileCache *ftail = 0; /* Tail of File Cache Chain */ + +Rune *loc1; /* Start of pattern match */ +Rune *loc2; /* End of pattern match */ +Rune seof; /* Pattern delimiter char */ + +Rune linebuf[LBSIZE+1]; /* Input data buffer */ +Rune *lbend = linebuf+LBSIZE; /* End of buffer */ +Rune *spend = linebuf; /* End of input data */ +Rune *cp; /* Current scan point in linebuf */ + +Rune holdsp[LBSIZE+1]; /* Hold buffer */ +Rune *hend = holdsp+LBSIZE; /* End of hold buffer */ +Rune *hspend = holdsp; /* End of hold data */ + +int nflag; /* Command line flags */ +int gflag; + +int dolflag; /* Set when at true EOF */ +int sflag; /* Set when substitution done */ +int jflag; /* Set when jump required */ +int delflag; /* Delete current line when set */ + +long lnum = 0; /* Input line count */ + +char fname[MAXFILES][40]; /* File name cache */ +Biobuf *fcode[MAXFILES]; /* File ID cache */ +int nfiles = 0; /* Cache fill point */ + +Biobuf fout; /* Output stream */ +Biobuf stdin; /* Default input */ +Biobuf* f = 0; /* Input data */ + +Label ltab[LABSIZE]; /* Label name symbol table */ +Label *labend = ltab+LABSIZE; /* End of label table */ +Label *lab = ltab+1; /* Current Fill point */ + +int depth = 0; /* {} stack pointer */ + +Rune bad; /* Dummy err ptr reference */ +Rune *badp = &bad; + + +char CGMES[] = "Command garbled: %S"; +char TMMES[] = "Too much text: %S"; +char LTL[] = "Label too long: %S"; +char AD0MES[] = "No addresses allowed: %S"; +char AD1MES[] = "Only one address allowed: %S"; + +void address(Addr *); +void arout(void); +int cmp(char *, char *); +int rcmp(Rune *, Rune *); +void command(SedCom *); +Reprog *compile(void); +Rune *compsub(Rune *, Rune *); +void dechain(void); +void dosub(Rune *); +int ecmp(Rune *, Rune *, int); +void enroll(char *); +void errexit(void); +int executable(SedCom *); +void execute(void); +void fcomp(void); +long getrune(void); +Rune *gline(Rune *); +int match(Reprog *, Rune *); +void newfile(enum PTYPE, char *); +int opendata(void); +Biobuf *open_file(char *); +Rune *place(Rune *, Rune *, Rune *); +void quit(char *, char *); +int rline(Rune *, Rune *); +Label *search(Label *); +int substitute(SedCom *); +char *text(char *); +Rune *stext(Rune *, Rune *); +int ycomp(SedCom *); +char * trans(int c); +void putline(Biobuf *bp, Rune *buf, int n); + +void +main(int argc, char **argv) +{ + int compfl; + + lnum = 0; + Binit(&fout, 1, OWRITE); + fcode[nfiles++] = &fout; + compfl = 0; + + if(argc == 1) + exits(0); + ARGBEGIN{ + case 'n': + nflag++; + continue; + case 'f': + if(argc <= 1) + quit("no pattern-file", 0); + newfile(P_FILE, ARGF()); + fcomp(); + compfl = 1; + continue; + case 'e': + if (argc <= 1) + quit("missing pattern", 0); + newfile(P_ARG, ARGF()); + fcomp(); + compfl = 1; + continue; + case 'g': + gflag++; + continue; + default: + fprint(2, "sed: Unknown flag: %c\n", ARGC()); + continue; + } ARGEND + + if(compfl == 0) { + if (--argc < 0) + quit("missing pattern", 0); + newfile(P_ARG, *argv++); + fcomp(); + } + + if(depth) + quit("Too many {'s", 0); + + ltab[0].address = rep; + + dechain(); + + if(argc <= 0) + enroll(0); /* Add stdin to cache */ + else while(--argc >= 0) { + enroll(*argv++); + } + execute(); + exits(0); +} +void +fcomp(void) +{ + Rune *tp; + SedCom *pt, *pt1; + int i; + Label *lpt; + + static Rune *p = addspace; + static SedCom **cmpend[DEPTH]; /* stack of {} operations */ + + while (rline(linebuf, lbend) >= 0) { + cp = linebuf; +comploop: + while(*cp == ' ' || *cp == '\t') + cp++; + if(*cp == '\0' || *cp == '#') + continue; + if(*cp == ';') { + cp++; + goto comploop; + } + + address(&rep->ad1); + if (rep->ad1.type != A_NONE) { + if (rep->ad1.type == A_LAST) { + if (!lastre) + quit("First RE may not be null", 0); + rep->ad1.type = A_RE; + rep->ad1.rp = lastre; + } + if(*cp == ',' || *cp == ';') { + cp++; + address(&rep->ad2); + if (rep->ad2.type == A_LAST) { + rep->ad1.type = A_RE; + rep->ad2.rp = lastre; + } + } else + rep->ad2.type = A_NONE; + } + while(*cp == ' ' || *cp == '\t') + cp++; + +swit: + switch(*cp++) { + + default: + quit("Unrecognized command: %S", (char *)linebuf); + + case '!': + rep->negfl = 1; + goto swit; + + case '{': + rep->command = BCOM; + rep->negfl = !(rep->negfl); + cmpend[depth++] = &rep->lb1; + if(++rep >= pend) + quit("Too many commands: %S", (char *) linebuf); + if(*cp == '\0') continue; + goto comploop; + + case '}': + if(rep->ad1.type != A_NONE) + quit(AD0MES, (char *) linebuf); + if(--depth < 0) + quit("Too many }'s", 0); + *cmpend[depth] = rep; + if(*cp == 0) continue; + goto comploop; + + case '=': + rep->command = EQCOM; + if(rep->ad2.type != A_NONE) + quit(AD1MES, (char *) linebuf); + break; + + case ':': + if(rep->ad1.type != A_NONE) + quit(AD0MES, (char *) linebuf); + + while(*cp == ' ') + cp++; + tp = lab->asc; + while (*cp && *cp != ';' && *cp != ' ' && *cp != '\t' && *cp != '#') { + *tp++ = *cp++; + if(tp >= &(lab->asc[8])) + quit(LTL, (char *) linebuf); + } + *tp = '\0'; + + if(lpt = search(lab)) { + if(lpt->address) + quit("Duplicate labels: %S", (char *) linebuf); + } else { + lab->chain = 0; + lpt = lab; + if(++lab >= labend) + quit("Too many labels: %S", (char *) linebuf); + } + lpt->address = rep; + if (*cp == '#') + continue; + rep--; /* reuse this slot */ + break; + + case 'a': + rep->command = ACOM; + if(rep->ad2.type != A_NONE) + quit(AD1MES, (char *) linebuf); + if(*cp == '\\') cp++; + if(*cp++ != '\n') + quit(CGMES, (char *) linebuf); + rep->text = p; + p = stext(p, addend); + break; + case 'c': + rep->command = CCOM; + if(*cp == '\\') cp++; + if(*cp++ != '\n') + quit(CGMES, (char *) linebuf); + rep->text = p; + p = stext(p, addend); + break; + case 'i': + rep->command = ICOM; + if(rep->ad2.type != A_NONE) + quit(AD1MES, (char *) linebuf); + if(*cp == '\\') cp++; + if(*cp++ != '\n') + quit(CGMES, (char *) linebuf); + rep->text = p; + p = stext(p, addend); + break; + + case 'g': + rep->command = GCOM; + break; + + case 'G': + rep->command = CGCOM; + break; + + case 'h': + rep->command = HCOM; + break; + + case 'H': + rep->command = CHCOM; + break; + + case 't': + rep->command = TCOM; + goto jtcommon; + + case 'b': + rep->command = BCOM; +jtcommon: + while(*cp == ' ')cp++; + if(*cp == '\0') { + if(pt = ltab[0].chain) { + while(pt1 = pt->lb1) + pt = pt1; + pt->lb1 = rep; + } else + ltab[0].chain = rep; + break; + } + tp = lab->asc; + while((*tp++ = *cp++)) + if(tp >= &(lab->asc[8])) + quit(LTL, (char *) linebuf); + cp--; + tp[-1] = '\0'; + + if(lpt = search(lab)) { + if(lpt->address) { + rep->lb1 = lpt->address; + } else { + pt = lpt->chain; + while(pt1 = pt->lb1) + pt = pt1; + pt->lb1 = rep; + } + } else { + lab->chain = rep; + lab->address = 0; + if(++lab >= labend) + quit("Too many labels: %S", + (char *) linebuf); + } + break; + + case 'n': + rep->command = NCOM; + break; + + case 'N': + rep->command = CNCOM; + break; + + case 'p': + rep->command = PCOM; + break; + + case 'P': + rep->command = CPCOM; + break; + + case 'r': + rep->command = RCOM; + if(rep->ad2.type != A_NONE) + quit(AD1MES, (char *) linebuf); + if(*cp++ != ' ') + quit(CGMES, (char *) linebuf); + rep->text = p; + p = stext(p, addend); + break; + + case 'd': + rep->command = DCOM; + break; + + case 'D': + rep->command = CDCOM; + rep->lb1 = pspace; + break; + + case 'q': + rep->command = QCOM; + if(rep->ad2.type != A_NONE) + quit(AD1MES, (char *) linebuf); + break; + + case 'l': + rep->command = LCOM; + break; + + case 's': + rep->command = SCOM; + seof = *cp++; + if ((rep->re1 = compile()) == 0) { + if(!lastre) + quit("First RE may not be null.", 0); + rep->re1 = lastre; + } + rep->rhs = p; + if((p = compsub(p, addend)) == 0) + quit(CGMES, (char *) linebuf); + if(*cp == 'g') { + cp++; + rep->gfl++; + } else if(gflag) + rep->gfl++; + + if(*cp == 'p') { + cp++; + rep->pfl = 1; + } + + if(*cp == 'P') { + cp++; + rep->pfl = 2; + } + + if(*cp == 'w') { + cp++; + if(*cp++ != ' ') + quit(CGMES, (char *) linebuf); + text(fname[nfiles]); + for(i = nfiles - 1; i >= 0; i--) + if(cmp(fname[nfiles],fname[i]) == 0) { + rep->fcode = fcode[i]; + goto done; + } + if(nfiles >= MAXFILES) + quit("Too many files in w commands 1", 0); + rep->fcode = open_file(fname[nfiles]); + } + break; + + case 'w': + rep->command = WCOM; + if(*cp++ != ' ') + quit(CGMES, (char *) linebuf); + text(fname[nfiles]); + for(i = nfiles - 1; i >= 0; i--) + if(cmp(fname[nfiles], fname[i]) == 0) { + rep->fcode = fcode[i]; + goto done; + } + if(nfiles >= MAXFILES){ + fprint(2, "sed: Too many files in w commands 2 \n"); + fprint(2, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES); + errexit(); + } + rep->fcode = open_file(fname[nfiles]); + break; + + case 'x': + rep->command = XCOM; + break; + + case 'y': + rep->command = YCOM; + seof = *cp++; + if (ycomp(rep) == 0) + quit(CGMES, (char *) linebuf); + break; + + } +done: + if(++rep >= pend) + quit("Too many commands, last: %S", (char *) linebuf); + + if(*cp++ != '\0') { + if(cp[-1] == ';') + goto comploop; + quit(CGMES, (char *) linebuf); + } + + } +} + +Biobuf * +open_file(char *name) +{ + Biobuf *bp; + int fd; + + if ((bp = malloc(sizeof(Biobuf))) == 0) + quit("Out of memory", 0); + if ((fd = open(name, OWRITE)) < 0 && + (fd = create(name, OWRITE, 0666)) < 0) + quit("Cannot create %s", name); + Binit(bp, fd, OWRITE); + Bseek(bp, 0, 2); + fcode[nfiles++] = bp; + return bp; +} + +Rune * +compsub(Rune *rhs, Rune *end) +{ + Rune r; + + while ((r = *cp++) != '\0') { + if(r == '\\') { + if (rhs < end) + *rhs++ = 0xFFFF; + else + return 0; + r = *cp++; + if(r == 'n') + r = '\n'; + } else { + if(r == seof) { + if (rhs < end) + *rhs++ = '\0'; + else + return 0; + return rhs; + } + } + if (rhs < end) + *rhs++ = r; + else + return 0; + + } + return 0; +} + +Reprog * +compile(void) +{ + Rune c; + char *ep; + char expbuf[512]; + + if((c = *cp++) == seof) /* '//' */ + return 0; + ep = expbuf; + do { + if (c == 0 || c == '\n') + quit(TMMES, (char *) linebuf); + if (c == '\\') { + if (ep >= expbuf+sizeof(expbuf)) + quit(TMMES, (char *) linebuf); + ep += runetochar(ep, &c); + if ((c = *cp++) == 'n') + c = '\n'; + } + if (ep >= expbuf+sizeof(expbuf)) + quit(TMMES, (char *) linebuf); + ep += runetochar(ep, &c); + } while ((c = *cp++) != seof); + *ep = 0; + return lastre = regcomp(expbuf); +} + +void +regerror(char *s) +{ + USED(s); + quit(CGMES, (char *) linebuf); +} + +void +newfile(enum PTYPE type, char *name) +{ + if (type == P_ARG) + prog.curr = name; + else if ((prog.bp = Bopen(name, OREAD)) == 0) + quit("Cannot open pattern-file: %s\n", name); + prog.type = type; +} + +int +rline(Rune *buf, Rune *end) +{ + long c; + Rune r; + + while ((c = getrune()) >= 0) { + if(c == '\r') /* consume CRs on win95 */ + continue; + r = c; + if (r == '\\') { + if (buf <= end) + *buf++ = r; + c = getrune(); + if (c == '\r') + c = getrune(); + if (c < 0) + break; + r = c; + } else if (r == '\n') { + *buf = '\0'; + return(1); + } + if (buf <= end) + *buf++ = r; + } + *buf = '\0'; + return(-1); +} + +long +getrune(void) +{ + char *p; + long c; + Rune r; + + if (prog.type == P_ARG) { + if ((p = prog.curr) != 0) { + if (*p) { + prog.curr += chartorune(&r, p); + c = r; + } else { + c = '\n'; /* fake an end-of-line */ + prog.curr = 0; + } + } else + c = -1; + } else if ((c = Bgetrune(prog.bp)) < 0) + Bterm(prog.bp); + return c; +} + +void +address(Addr *ap) +{ + int c; + long lno; + + if((c = *cp++) == '$') + ap->type = A_DOL; + else if(c == '/') { + seof = c; + if (ap->rp = compile()) + ap->type = A_RE; + else + ap->type = A_LAST; + } + else if (c >= '0' && c <= '9') { + lno = c-'0'; + while ((c = *cp) >= '0' && c <= '9') + lno = lno*10 + *cp++-'0'; + if(!lno) + quit("line number 0 is illegal",0); + ap->type = A_LINE; + ap->line = lno; + } + else { + cp--; + ap->type = A_NONE; + } +} + +cmp(char *a, char *b) /* compare characters */ +{ + while(*a == *b++) + if (*a == '\0') + return(0); + else a++; + return(1); +} +rcmp(Rune *a, Rune *b) /* compare runes */ +{ + while(*a == *b++) + if (*a == '\0') + return(0); + else a++; + return(1); +} + +char * +text(char *p) /* extract character string */ +{ + Rune r; + + while(*cp == '\t' || *cp == ' ') + cp++; + while (*cp) { + if ((r = *cp++) == '\\') + if ((r = *cp++) == 0) + break;; + if (r == '\n') + while (*cp == '\t' || *cp == ' ') + cp++; + p += runetochar(p, &r); + } + *p++ = '\0'; + return p; +} + +Rune * +stext(Rune *p, Rune *end) /* extract rune string */ +{ + while(*cp == '\t' || *cp == ' ') + cp++; + while (*cp) { + if (*cp == '\\') + if (*++cp == 0) + break; + if (p >= end-1) + quit(TMMES, (char *) linebuf); + if ((*p++ = *cp++) == '\n') + while(*cp == '\t' || *cp == ' ') + cp++; + } + *p++ = 0; + return p; +} + + +Label * +search (Label *ptr) +{ + Label *rp; + + for (rp = ltab; rp < ptr; rp++) + if(rcmp(rp->asc, ptr->asc) == 0) + return(rp); + return(0); +} + +void +dechain(void) +{ + Label *lptr; + SedCom *rptr, *trptr; + + for(lptr = ltab; lptr < lab; lptr++) { + + if(lptr->address == 0) + quit("Undefined label: %S", (char *) lptr->asc); + + if(lptr->chain) { + rptr = lptr->chain; + while(trptr = rptr->lb1) { + rptr->lb1 = lptr->address; + rptr = trptr; + } + rptr->lb1 = lptr->address; + } + } +} + +int +ycomp(SedCom *r) +{ + int i; + Rune *rp; + Rune c, *tsp, highc; + Rune *sp; + + highc = 0; + for(tsp = cp; *tsp != seof; tsp++) { + if(*tsp == '\\') + tsp++; + if(*tsp == '\n' || *tsp == '\0') + return(0); + if (*tsp > highc) highc = *tsp; + } + tsp++; + if ((rp = r->text = (Rune *) malloc(sizeof(Rune)*(highc+2))) == 0) + quit("Out of memory", 0); + *rp++ = highc; /* save upper bound */ + for (i = 0; i <= highc; i++) + rp[i] = i; + sp = cp; + while((c = *sp++) != seof) { + if(c == '\\' && *sp == 'n') { + sp++; + c = '\n'; + } + if((rp[c] = *tsp++) == '\\' && *tsp == 'n') { + rp[c] = '\n'; + tsp++; + } + if(rp[c] == seof || rp[c] == '\0') { + free(r->re1); + r->re1 = 0; + return(0); + } + } + if(*tsp != seof) { + free(r->re1); + r->re1 = 0; + return(0); + } + cp = tsp+1; + return(1); +} + +void +execute(void) +{ + SedCom *ipc; + + while (spend = gline(linebuf)){ + for(ipc = pspace; ipc->command; ) { + if (!executable(ipc)) { + ipc++; + continue; + } + command(ipc); + + if(delflag) + break; + + if(jflag) { + jflag = 0; + if((ipc = ipc->lb1) == 0) + break; + } else + ipc++; + + } + if(!nflag && !delflag) + putline(&fout, linebuf, spend-linebuf); + if(aptr > abuf) { + arout(); + } + delflag = 0; + } +} + /* determine if a statement should be applied to an input line */ +int +executable(SedCom *ipc) +{ + if (ipc->active) { /* Addr1 satisfied - accept until Addr2 */ + if (ipc->active == 1) /* Second line */ + ipc->active = 2; + switch(ipc->ad2.type) { + case A_NONE: /* No second addr; use first */ + ipc->active = 0; + break; + case A_DOL: /* Accept everything */ + return !ipc->negfl; + case A_LINE: /* Line at end of range? */ + if (lnum <= ipc->ad2.line) { + if (ipc->ad2.line == lnum) + ipc->active = 0; + return !ipc->negfl; + } + ipc->active = 0; /* out of range */ + return ipc->negfl; + case A_RE: /* Check for matching R.E. */ + if (match(ipc->ad2.rp, linebuf)) + ipc->active = 0; + return !ipc->negfl; + default: /* internal error */ + quit("Internal error", 0); + } + } + switch (ipc->ad1.type) { /* Check first address */ + case A_NONE: /* Everything matches */ + return !ipc->negfl; + case A_DOL: /* Only last line */ + if (dolflag) + return !ipc->negfl; + break; + case A_LINE: /* Check line number */ + if (ipc->ad1.line == lnum) { + ipc->active = 1; /* In range */ + return !ipc->negfl; + } + break; + case A_RE: /* Check R.E. */ + if (match(ipc->ad1.rp, linebuf)) { + ipc->active = 1; /* In range */ + return !ipc->negfl; + } + break; + default: + quit("Internal error", 0); + } + return ipc->negfl; +} +match(Reprog *pattern, Rune *buf) +{ + if (!pattern) + return 0; + subexp[0].s.rsp = buf; + subexp[0].e.ep = 0; + if (rregexec(pattern, linebuf, subexp, MAXSUB)) { + loc1 = subexp[0].s.rsp; + loc2 = subexp[0].e.rep; + return 1; + } + loc1 = loc2 = 0; + return 0; +} +substitute(SedCom *ipc) +{ + if(match(ipc->re1, linebuf)) { + sflag = 1; + dosub(ipc->rhs); + if(!ipc->gfl) + return 1; + while (match(ipc->re1, loc2)) { + if (loc2-loc1 == 0){ /* NULL R.E. match */ + if (*loc2++ == 0) + break; + } else { + dosub(ipc->rhs); + if(*loc2 == 0) + break; + } + } + return 1; + } + return 0; +} + +void +dosub(Rune *rhsbuf) +{ + Rune *lp, *sp; + Rune *rp; + int c, n; + + lp = linebuf; + sp = genbuf; + rp = rhsbuf; + while (lp < loc1) + *sp++ = *lp++; + while(c = *rp++) { + if (c == '&') { + sp = place(sp, loc1, loc2); + continue; + } + if (c == 0xFFFF && (c = *rp++) >= '1' && c <= MAXSUB+'0') { + n = c-'0'; + if (subexp[n].s.rsp && subexp[n].e.rep) { + sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep); + continue; + } + else { + fprint(2, "sed: Invalid back reference \\%d\n",n); + errexit(); + } + } + *sp++ = c; + if (sp >= &genbuf[LBSIZE]) + fprint(2, "sed: Output line too long.\n"); + } + lp = loc2; + loc2 = sp - genbuf + linebuf; + while (*sp++ = *lp++) + if (sp >= &genbuf[LBSIZE]) + fprint(2, "sed: Output line too long.\n"); + lp = linebuf; + sp = genbuf; + while (*lp++ = *sp++) + ; + spend = lp-1; +} + +Rune * +place(Rune *sp, Rune *l1, Rune *l2) +{ + while (l1 < l2) { + *sp++ = *l1++; + if (sp >= &genbuf[LBSIZE]) + fprint(2, "sed: Output line too long.\n"); + } + return(sp); +} + +char * +trans(int c) +{ + static char buf[] = "\\x0000"; + static char hex[] = "0123456789abcdef"; + + switch(c) { + case '\b': + return "\\b"; + case '\n': + return "\\n"; + case '\r': + return "\\r"; + case '\t': + return "\\t"; + case '\\': + return "\\\\"; + } + buf[2] = hex[(c>>12)&0xF]; + buf[3] = hex[(c>>8)&0xF]; + buf[4] = hex[(c>>4)&0xF]; + buf[5] = hex[c&0xF]; + return buf; +} + +void +command(SedCom *ipc) +{ + int i, c; + Rune *p1, *p2; + char *ucp; + Rune *rp; + Rune *execp; + + switch(ipc->command) { + + case ACOM: + *aptr++ = ipc; + if(aptr >= abuf+MAXADDS) { + quit("sed: Too many appends after line %ld\n", + (char *) lnum); + } + *aptr = 0; + break; + case CCOM: + delflag = 1; + if(ipc->active == 1) { + for(rp = ipc->text; *rp; rp++) + Bputrune(&fout, *rp); + Bputc(&fout, '\n'); + } + break; + case DCOM: + delflag++; + break; + case CDCOM: + p1 = p2 = linebuf; + while(*p1 != '\n') { + if(*p1++ == 0) { + delflag++; + return; + } + } + p1++; + while(*p2++ = *p1++) + ; + spend = p2-1; + jflag++; + break; + case EQCOM: + Bprint(&fout, "%ld\n", lnum); + break; + case GCOM: + p1 = linebuf; + p2 = holdsp; + while(*p1++ = *p2++) + ; + spend = p1-1; + break; + case CGCOM: + *spend++ = '\n'; + p1 = spend; + p2 = holdsp; + while(*p1++ = *p2++) + if(p1 >= lbend) + break; + spend = p1-1; + break; + case HCOM: + p1 = holdsp; + p2 = linebuf; + while(*p1++ = *p2++); + hspend = p1-1; + break; + case CHCOM: + *hspend++ = '\n'; + p1 = hspend; + p2 = linebuf; + while(*p1++ = *p2++) + if(p1 >= hend) + break; + hspend = p1-1; + break; + case ICOM: + for(rp = ipc->text; *rp; rp++) + Bputrune(&fout, *rp); + Bputc(&fout, '\n'); + break; + case BCOM: + jflag = 1; + break; + case LCOM: + c = 0; + for (i = 0, rp = linebuf; *rp; rp++) { + c = *rp; + if(c >= 0x20 && c < 0x7F && c != '\\') { + Bputc(&fout, c); + if(i++ > 71) { + Bprint(&fout, "\\\n"); + i = 0; + } + } else { + for (ucp = trans(*rp); *ucp; ucp++){ + c = *ucp; + Bputc(&fout, c); + if(i++ > 71) { + Bprint(&fout, "\\\n"); + i = 0; + } + } + } + } + if(c == ' ') + Bprint(&fout, "\\n"); + Bputc(&fout, '\n'); + break; + case NCOM: + if(!nflag) + putline(&fout, linebuf, spend-linebuf); + + if(aptr > abuf) + arout(); + if((execp = gline(linebuf)) == 0) { + delflag = 1; + break; + } + spend = execp; + break; + case CNCOM: + if(aptr > abuf) + arout(); + *spend++ = '\n'; + if((execp = gline(spend)) == 0) { + delflag = 1; + break; + } + spend = execp; + break; + case PCOM: + putline(&fout, linebuf, spend-linebuf); + break; + case CPCOM: + cpcom: + for(rp = linebuf; *rp && *rp != '\n'; rp++) + Bputc(&fout, *rp); + Bputc(&fout, '\n'); + break; + case QCOM: + if(!nflag) + putline(&fout, linebuf, spend-linebuf); + if(aptr > abuf) + arout(); + exits(0); + case RCOM: + *aptr++ = ipc; + if(aptr >= &abuf[MAXADDS]) + quit("sed: Too many reads after line %ld\n", + (char *) lnum); + *aptr = 0; + break; + case SCOM: + i = substitute(ipc); + if(i && ipc->pfl) + if(ipc->pfl == 1) + putline(&fout, linebuf, spend-linebuf); + else + goto cpcom; + if(i && ipc->fcode) + goto wcom; + break; + + case TCOM: + if(sflag == 0) break; + sflag = 0; + jflag = 1; + break; + + wcom: + case WCOM: + putline(ipc->fcode,linebuf, spend-linebuf); + break; + case XCOM: + p1 = linebuf; + p2 = genbuf; + while(*p2++ = *p1++); + p1 = holdsp; + p2 = linebuf; + while(*p2++ = *p1++); + spend = p2 - 1; + p1 = genbuf; + p2 = holdsp; + while(*p2++ = *p1++); + hspend = p2 - 1; + break; + case YCOM: + p1 = linebuf; + p2 = ipc->text; + for (i = *p2++; *p1; p1++){ + if (*p1 <= i) *p1 = p2[*p1]; + } + break; + } + +} + +void +putline(Biobuf *bp, Rune *buf, int n) +{ + while (n--) + Bputrune(bp, *buf++); + Bputc(bp, '\n'); +} +ecmp(Rune *a, Rune *b, int count) +{ + while(count--) + if(*a++ != *b++) return(0); + return(1); +} + +void +arout(void) +{ + Rune *p1; + Biobuf *fi; + int c; + char *s; + char buf[128]; + + for (aptr = abuf; *aptr; aptr++) { + if((*aptr)->command == ACOM) { + for(p1 = (*aptr)->text; *p1; p1++ ) + Bputrune(&fout, *p1); + Bputc(&fout, '\n'); + } else { + for(s = buf, p1= (*aptr)->text; *p1; p1++) + s += runetochar(s, p1); + *s = '\0'; + if((fi = Bopen(buf, OREAD)) == 0) + continue; + while((c = Bgetc(fi)) >= 0) + Bputc(&fout, c); + Bterm(fi); + } + } + aptr = abuf; + *aptr = 0; +} + +void +errexit(void) +{ + exits("error"); +} + +void +quit (char *msg, char *arg) +{ + fprint(2, "sed: "); + fprint(2, msg, arg); + fprint(2, "\n"); + errexit(); +} + +Rune * +gline(Rune *addr) +{ + long c; + Rune *p; + + static long peekc = 0; + + if (f == 0 && opendata() < 0) + return 0; + sflag = 0; + lnum++; +/* Bflush(&fout);********* dumped 4/30/92 - bobf****/ + do { + p = addr; + for (c = (peekc ? peekc : Bgetrune(f)); c >= 0; c = Bgetrune(f)) { + if (c == '\n') { + if ((peekc = Bgetrune(f)) < 0) { + Bterm(f); + if (fhead == 0) + dolflag = 1; + } + *p = '\0'; + return p; + } + if (c && p < lbend) + *p++ = c; + } + peekc = 0; + } while (opendata() > 0); /* Switch to next stream */ + f = 0; + return 0; +} + + /* Data file input section - the intent is to transparently + * catenate all data input streams. + */ +void +enroll(char *filename) /* Add a file to the input file cache */ +{ + FileCache *fp; + + if ((fp = (FileCache *) malloc(sizeof (FileCache))) == 0) + quit("Out of memory", 0); + if (ftail == 0) + fhead = fp; + else + ftail->next = fp; + ftail = fp; + fp->next = 0; + fp->name = filename; /* 0 => stdin */ +} + +int +opendata(void) +{ + if (fhead == 0) + return -1; + if (fhead->name) { + if ((f = Bopen(fhead->name, OREAD)) == 0) + quit("Can't open %s", fhead->name); + } else { + Binit(&stdin, 0, OREAD); + f = &stdin; + } + fhead = fhead->next; + return 1; +} diff --git a/utils/sqz/NOTICE b/utils/sqz/NOTICE new file mode 100644 index 00000000..724003a1 --- /dev/null +++ b/utils/sqz/NOTICE @@ -0,0 +1,27 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 1998 C H Forsyth (forsyth@terzarima.net). + +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. diff --git a/utils/sqz/mkfile b/utils/sqz/mkfile new file mode 100644 index 00000000..430bbce5 --- /dev/null +++ b/utils/sqz/mkfile @@ -0,0 +1,19 @@ +<../../mkconfig +CFLAGS=$CFLAGS -I../include + +TARG=sqz + +OFILES= sqz.$O\ + +HFILES= \ + squeeze.h\ + ../include/a.out.h\ + ../include/mach.h\ + +LIBS= mach bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/sqz/squeeze.h b/utils/sqz/squeeze.h new file mode 100644 index 00000000..b06c1b79 --- /dev/null +++ b/utils/sqz/squeeze.h @@ -0,0 +1,34 @@ + +/* + * squeezed file format: + * Sqhdr + * original Exec header + * two Squeeze tables + * squeezed segment + * unsqueezed segment, if any + */ +#define SQMAGIC (ulong)0xFEEF0F1E + +typedef struct Sqhdr Sqhdr; +struct Sqhdr { + uchar magic[4]; /* SQMAGIC */ + uchar text[4]; /* squeezed length of text (excluding tables) */ + uchar data[4]; /* squeezed length of data (excluding tables) */ + uchar asis[4]; /* length of unsqueezed segment */ + uchar toptxt[4]; /* value for 0 encoding in text */ + uchar topdat[4]; /* value for 0 encoding in data */ + uchar sum[4]; /* simple checksum of unsqueezed data */ + uchar flags[4]; +}; +#define SQHDRLEN (8*4) + +/* + * certain power instruction types are rearranged by sqz + * so as to move the variable part of the instruction word to the + * low order bits. note that the mapping is its own inverse. + */ +#define QREMAP(X)\ + switch((X)>>26){\ + case 19: case 31: case 59: case 63:\ + (X) = (((X) & 0xFC00F801) | (((X)>>15)&0x7FE) | (((X)&0x7FE)<<15));\ + } diff --git a/utils/sqz/sqz.c b/utils/sqz/sqz.c new file mode 100644 index 00000000..cf399e45 --- /dev/null +++ b/utils/sqz/sqz.c @@ -0,0 +1,528 @@ +#include <lib9.h> +#include <a.out.h> +#include "squeeze.h" + +/* + * forsyth@vitanuova.com + */ + +typedef struct Word Word; +struct Word { + ulong v; + ushort freq; + ushort code; + Word* next; +}; + +typedef struct Squeeze Squeeze; +struct Squeeze { + int n; + /*union {*/ + ulong tab[7*256]; + Word* rep[7*256]; + /*};*/ +}; + +enum { + HMASK = 0xFFFF, + HSIZE = HMASK+1, + + Codebufsize = 3*1024*1024 +}; + +#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) +#define GET4L(p) (((((((p)[3]<<8)|(p)[2])<<8)|(p)[1])<<8)|(p)[0]) +#define PUT4(p,v) (((p)[0]=(v)>>24),((p)[1]=(v)>>16),((p)[2]=(v)>>8),((p)[3]=(v))) + +static uchar prog[Codebufsize]; +static uchar outbuf[Codebufsize]; +static Word* hash1[HSIZE]; +static Word* hash2[HSIZE]; +static Sqhdr sqhdr; +static ulong chksum; + +static int aflag; /* all: both text (squeezed) and data (not) */ +static int dflag; /* squeeze data, not text */ +static int tflag; /* squeeze text, leave data as-is */ +static int qflag = 1; /* enable powerpc option */ +static int wflag; /* write output */ +static int zflag; /* use top==0 for data segment */ +static int islittle; /* object code uses little-endian byte order */ +static int debug; +static char* fname; + +static void analyse(ulong*, int, Squeeze*, Squeeze*, Word**); +static Word** collate(Word**, int); +static void dumpsq(Squeeze*, int); +static void freehash(Word**); +static long Read(int, void*, long); +static void remap(Squeeze*); +static int squeeze(ulong*, int, uchar*, ulong); +static int squeezetab(int, int, Squeeze*, Word**, int); +static void squirt(int, Squeeze*); +static void Write(int, void*, long); + +static void +usage(void) +{ + fprint(2, "Usage: sqz [-w] [-t] [-d] [-q] q.out\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int fd, n, ns, nst, nsd; + long txtlen, datlen, asis; + ulong topdat, toptxt; + Exec ex; + Squeeze sq3, sq4, sq5, sq6; + Word *top; + + setbinmode(); +/* fmtinstall('f', gfltconv); */ + ARGBEGIN{ + case 'D': + debug++; + break; + case 'd': + dflag++; + break; + case 'q': + qflag = 0; + break; + case 't': + tflag++; + break; + case 'w': + wflag++; + break; + default: + usage(); + }ARGEND + fname = *argv; + if(fname == nil) + usage(); + fd = open(fname, OREAD); + if(fd < 0){ + fprint(2, "sqz: can't open %s: %r\n", fname); + exits("open"); + } + Read(fd, &ex, sizeof(Exec)); + txtlen = GET4((uchar*)&ex.text); + datlen = GET4((uchar*)&ex.data); + switch(GET4((uchar*)&ex.magic)){ + case Q_MAGIC: /* powerpc */ + islittle = 0; + break; + case E_MAGIC: /* arm */ + islittle = 1; + qflag = 0; + break; + case 0xA0E1: /* arm AIF */ + islittle = 1; + qflag = 0; + txtlen = GET4L((uchar*)&ex+(5*4))-sizeof(Exec); + datlen = GET4L((uchar*)&ex+(6*4)); + break; + default: + fprint(2, "sqz: unknown magic for sqz: %8.8ux\n", GET4((uchar*)&ex.magic)); + exits("bad magic"); + } + if(qflag) + fprint(2, "PowerPC rules\n"); + if(islittle) + fprint(2, "Little endian\n"); + if(txtlen > sizeof(prog) || datlen > sizeof(prog) || txtlen+datlen > sizeof(prog)){ + fprint(2, "sqz: executable too big: %lud+%lud; increase Codebufsize in sqz.c\n", txtlen, datlen); + exits("size"); + } + if(dflag){ + seek(fd, txtlen, 1); + Read(fd, prog, datlen); + }else{ + Read(fd, prog, txtlen); + Read(fd, prog+txtlen, datlen); + } + close(fd); + asis = 0; + if(dflag) + n = datlen; + else if(tflag){ + n = txtlen; + asis = datlen; + }else + n = txtlen+datlen; + if(dflag || tflag){ + analyse((ulong*)prog, n/4, &sq3, &sq4, &top); + nst = squeeze((ulong*)prog, n/4, outbuf, top->v); + if(nst < 0) + exits("sqz"); + nsd = 0; + remap(&sq3); + remap(&sq4); + toptxt = topdat = top->v; + }else{ + analyse((ulong*)prog, txtlen/4, &sq3, &sq4, &top); + nst = squeeze((ulong*)prog, txtlen/4, outbuf, top->v); + if(nst < 0) + exits("sqz"); + toptxt = top->v; + remap(&sq3); + remap(&sq4); + if(datlen/4){ + freehash(hash1); + freehash(hash2); + analyse((ulong*)(prog+txtlen), datlen/4, &sq5, &sq6, &top); + nsd = squeeze((ulong*)(prog+txtlen), datlen/4, outbuf+nst, top->v); + if(nsd < 0) + exits("sqz"); + topdat = top->v; + remap(&sq5); + remap(&sq6); + }else{ + nsd = 0; + topdat = 0; + } + } + ns = nst+nsd; + fprint(2, "%d/%d bytes\n", ns, n); + fprint(2, "%8.8lux csum\n", chksum); + if(!wflag) + exits(0); + PUT4(sqhdr.magic, SQMAGIC); + PUT4(sqhdr.toptxt, toptxt); + PUT4(sqhdr.sum, chksum); + PUT4(sqhdr.text, nst); + PUT4(sqhdr.topdat, topdat); + PUT4(sqhdr.data, nsd); + PUT4(sqhdr.asis, asis); + PUT4(sqhdr.flags, 0); + Write(1, &sqhdr, SQHDRLEN); + Write(1, &ex, sizeof(Exec)); + squirt(1, &sq3); + squirt(1, &sq4); + Write(1, outbuf, nst); + if(nsd){ + squirt(1, &sq5); + squirt(1, &sq6); + Write(1, outbuf+nst, nsd); + } + if(asis) + Write(1, prog+txtlen, asis); + exits(0); +} + +static void +analyse(ulong *prog, int nw, Squeeze *sq3, Squeeze *sq4, Word **top) +{ + Word *w, **hp, **sorts, **resorts; + ulong *rp, *ep; + ulong v; + int i, nv1, nv2, nv, nz; + + rp = prog; + ep = prog+nw; + nv = 0; + nz = 0; + while(rp < ep){ + if(islittle){ + v = GET4L((uchar*)rp); + }else{ + v = GET4((uchar*)rp); + } + rp++; + chksum += v; + if(v == 0){ + nz++; + if(0) + continue; + } + if(qflag){ + QREMAP(v); + } + for(hp = &hash1[v&HMASK]; (w = *hp) != nil; hp = &w->next) + if(w->v == v) + break; + if(w == nil){ + w = (Word*)malloc(sizeof(*w)); + w->v = v; + w->freq = 0; + w->code = 0; + w->next = nil; + *hp = w; + nv++; + } + w->freq++; + } + sorts = collate(hash1, nv); + fprint(2, "phase 1: %d/%d words (%d zero), %d top (%8.8lux)\n", nv, nw, nz, sorts[0]->freq, sorts[0]->v); + *top = sorts[0]; + nv1 = squeezetab(1, 0x900, sq3, sorts+1, nv-1)+1; + nv2 = 0; + for(i=nv1; i<nv; i++){ + v = sorts[i]->v >> 8; + for(hp = &hash2[v&HMASK]; (w = *hp) != nil; hp = &w->next) + if(w->v == v) + break; + if(w == nil){ + w = (Word*)malloc(sizeof(*w)); + w->v = v; + w->freq = 0; + w->code = 0; + w->next = nil; + *hp = w; + nv2++; + } + w->freq++; + } + free(sorts); + resorts = collate(hash2, nv2); + fprint(2, "phase 2: %d/%d\n", nv2, nv-nv1); + squeezetab(2, 0x200, sq4, resorts, nv2); + free(resorts); + fprint(2, "phase 3: 1 4-code, %d 12-codes, %d 20-codes, %d uncoded\n", + sq3->n, sq4->n, nv-(sq3->n+sq4->n+1)); +} + +static int +wdcmp(const void *a, const void *b) +{ + return (*(Word**)b)->freq - (*(Word**)a)->freq; +} + +static Word ** +collate(Word **tab, int nv) +{ + Word *w, **hp, **sorts; + int i; + + sorts = (Word**)malloc(nv*sizeof(Word**)); + i = 0; + for(hp = &tab[0]; hp < &tab[HSIZE]; hp++) + for(w = *hp; w != nil; w = w->next) + sorts[i++] = w; + qsort(sorts, nv, sizeof(*sorts), wdcmp); + if(debug > 1) + for(i=0; i<nv; i++) + fprint(2, "%d\t%d\t%8.8lux\n", i, sorts[i]->freq, sorts[i]->v); + return sorts; +} + +static int +tabcmp(const void *a, const void *b) +{ + ulong av, bv; + + av = (*(Word**)a)->v; + bv = (*(Word**)b)->v; + if(av > bv) + return 1; + if(av < bv) + return -1; + return 0; +} + +static int +squeezetab(int tabno, int base, Squeeze *sq, Word **sorts, int nv) +{ + int i; + + if(nv >= 7*256) + nv = 7*256; + memset(sq, 0, sizeof(*sq)); + for(i=0; i<nv; i++) + sq->rep[sq->n++] = sorts[i]; + qsort(sq->rep, sq->n, sizeof(*sq->rep), tabcmp); + for(i=0; i<sq->n; i++) + sq->rep[i]->code = base + i; + if(debug) + dumpsq(sq, tabno); + return sq->n; +} + +static void +dumpsq(Squeeze *sq, int n) +{ + int i; + + fprint(2, "table %d: %d entries\n", n, sq->n); + for(i=0; i<sq->n; i++) + fprint(2, "%.3x\t%8.8lux\t%lux\n", sq->rep[i]->code, sq->rep[i]->v, i? sq->rep[i]->v - sq->rep[i-1]->v: 0); +} + +static void +remap(Squeeze *sq) +{ + int i; + ulong v; + + if(sq->n){ + v = 0; + for(i=0; i<sq->n; i++){ + sq->tab[i] = sq->rep[i]->v - v; + v += sq->tab[i]; + } + } +} + +static Word * +squash(Word **tab, ulong v) +{ + Word *w, **hp; + + for(hp = &tab[v&0xFFFF]; (w = *hp) != nil; hp = &w->next) + if(w->v == v) + return w; + return nil; +} + +static void +freehash(Word **tab) +{ + Word *w, **hp; + + for(hp = &tab[0]; hp < &tab[HSIZE]; hp++) + while((w = *hp) != nil){ + *hp = w->next; + free(w); + } +} + +static int +squeeze(ulong *prog, int nw, uchar *out, ulong top) +{ + ulong *rp, *ep; + ulong v, bits; + ulong e1, e2, e3, e4; + Word *w; + uchar bytes[8], *bp, *wp; + int ctl, n; + + rp = prog; + ep = prog+nw; + bits = 0; + e1 = e2 = e3 = e4 = 0; + wp = out; + n = 0; + ctl = 0; + bp = bytes; + for(;;){ + if(n == 2){ + *wp++ = ctl; + if(0) + fprint(2, "%x\n", ctl); + memmove(wp, bytes, bp-bytes); + wp += bp-bytes; + bp = bytes; + ctl = 0; + n = 0; + } + ctl <<= 4; + n++; + if(rp >= ep){ + if(n == 1) + break; + continue; + } + if(islittle){ + v = GET4L((uchar*)rp); + }else{ + v = GET4((uchar*)rp); + } + rp++; + if(qflag){ + QREMAP(v); + } + if(v == top){ + e1++; + bits += 4; + ctl |= 0; + continue; + } + w = squash(hash1, v); + if(w && w->code){ + e2++; + bits += 4+8; + ctl |= w->code>>8; + *bp++ = w->code; + continue; + } + w = squash(hash2, v>>8); + if(w && w->code){ + e3++; + bits += 4+8+8; + ctl |= w->code>>8; + *bp++ = w->code; + *bp++ = v & 0xFF; + if(debug > 2) + fprint(2, "%x %8.8lux %8.8lux\n", w->code, w->v, v); + continue; + } + e4++; + bits += 4+32; + ctl |= 0x1; + bp[0] = v; + bp[1] = v>>8; + bp[2] = v>>16; + bp[3] = v>>24; + bp += 4; + } + fprint(2, "enc: %lud 4-bits, %lud 12-bits %lud 20-bits %lud 36-bits -- %ld bytes\n", + e1, e2, e3, e4, wp-out); + return wp-out; +} + +static void +squirt(int fd, Squeeze *sq) +{ + uchar b[7*256*5 + 2], rep[5], *p, *q; + ulong v; + int i; + + p = b+2; + for(i=0; i<sq->n; i++){ + v = sq->tab[i]; + q = rep; + do { + *q++ = v & 0x7F; + }while((v >>= 7) != 0); + do { + *p++ = *--q | 0x80; + }while(q != rep); + p[-1] &= ~0x80; + } + if(p > b+sizeof(b)) + abort(); + i = p-b; + b[0] = i>>8; + b[1] = i; + Write(fd, b, i); + fprint(2, "table: %d/%d\n", i, (sq->n+1)*4); +} + +static long +Read(int fd, void *buf, long nb) +{ + long n; + + n = read(fd, buf, nb); + if(n < 0){ + fprint(2, "sqz: %s: read error: %r\n", fname); + exits("read"); + } + if(n < nb){ + fprint(2, "sqz: %s: unexpected end-of-file\n", fname); + exits("read"); + } + return n; +} + +static void +Write(int fd, void *buf, long nb) +{ + if(write(fd, buf, nb) != nb){ + fprint(2, "sqz: write error: %r\n"); + exits("write err"); + } +} diff --git a/utils/sqz/zqs.c b/utils/sqz/zqs.c new file mode 100644 index 00000000..b9b2a163 --- /dev/null +++ b/utils/sqz/zqs.c @@ -0,0 +1,243 @@ +#include <lib9.h> +#include <a.out.h> +#include "squeeze.h" + +/* + * forsyth@vitanuova.com + */ + +/* + * for details of `unsqueeze' see: + * + * %A Mark Taunton + * %T Compressed Executables: An Exercise in Thinking Small + * %P 385-404 + * %I USENIX + * %B USENIX Conference Proceedings + * %D Summer 1991 + * %C Nashville, TN + * + * several of the unimplemented improvements described in the paper + * have been implemented here + * + * there is a further transformation on the powerpc (QFLAG!=0) to shuffle bits + * in certain instructions so as to push the fixed bits to the top of the word. + */ + +typedef struct Squeeze Squeeze; +struct Squeeze { + int n; + ulong tab[7*256]; +}; + +enum { + CHECK = 1 /* check precise bounds in Squeeze array */ +}; + +#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) + +static uchar out[3*1024*1024]; +static uchar bigb[1024*1024]; +static ulong top; +static int qflag = 1; +static int islittle = 0; +static ulong chksum, oldsum; +static int rdtab(int, Squeeze*, int); +static long unsqueezefd(int, void*); +static uchar* unsqueeze(uchar*, uchar*, uchar*, Squeeze*, Squeeze*, ulong); +static uchar* unsqzseg(int, uchar*, long, ulong); + +void +main(int argc, char **argv) +{ + int fd; + long n; + + if(argc < 2) + exits("args"); + fd = open(argv[1], OREAD); + if(fd < 0) + exits("open"); + n = unsqueezefd(fd, out); + if(n < 0){ + fprint(2, "zqs: can't unsqueeze\n"); + exits("err"); + } + if(write(1, out, n) != n){ + fprint(2, "zqs: write error: %r\n"); + exits("err"); + } + fprint(2, "%ld bytes, %8.8lux csum\n", n, chksum); + exits(0); +} + +static long +unsqueezefd(int fd, void *v) +{ + uchar *wp, *out; + ulong toptxt, topdat; + long asis, nst, nsd; + Sqhdr sqh; + Exec ex; + + out = (uchar*)v; + if(read(fd, &sqh, SQHDRLEN) != SQHDRLEN) + return -1; + if(GET4(sqh.magic) != SQMAGIC) + return -1; + if(read(fd, &ex, sizeof(Exec)) != sizeof(Exec)) + return -1; + toptxt = GET4(sqh.toptxt); + topdat = GET4(sqh.topdat); + oldsum = GET4(sqh.sum); + asis = GET4(sqh.asis); + if(asis < 0) + asis = 0; + nst = GET4(sqh.text); + nsd = GET4(sqh.data); + switch(GET4((uchar*)&ex.magic)){ + case Q_MAGIC: + if(qflag) + fprint(2, "PowerPC mode\n"); + islittle = 0; + break; + case E_MAGIC: + case 0xA0E1: /* arm AIF */ + islittle = 1; + qflag = 0; + break; + default: + fprint(2, "Unknown magic: %8.8ux\n", GET4((uchar*)&ex.magic)); + qflag = 0; + break; + } + memmove(out, &ex, sizeof(ex)); + wp = unsqzseg(fd, out + sizeof(ex), nst, toptxt); + if(wp == nil) + return -1; + wp = unsqzseg(fd, wp, nsd, topdat); + if(wp == nil) + return -1; + if(asis){ + if(read(fd, wp, asis) != asis) + return -1; + wp += asis; + } + return wp-out; +} + +static uchar* +unsqzseg(int fd, uchar *wp, long ns, ulong top) +{ + Squeeze sq3, sq4; + + if(ns == 0) + return wp; + if(rdtab(fd, &sq3, 0) < 0) + return nil; + if(rdtab(fd, &sq4, 8) < 0) + return nil; + fprint(2, "tables: %d %d\n", sq3.n, sq4.n); + if(read(fd, bigb, ns) != ns) + return nil; + return unsqueeze(wp, bigb, bigb+ns, &sq3, &sq4, top); +} + +static uchar* +unsqueeze(uchar *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top) +{ + ulong nx; + int code, n; + + if(qflag){ + QREMAP(top); /* adjust top just once, outside the loop */ + } + while(rp < ep){ + code = *rp++; + n = 0; + nx = code>>4; + do{ + if(nx == 0){ + nx = top; + }else{ + if(nx==1){ + if(rp+3 >= ep) + return nil; + nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0]; + rp += 4; + }else if(nx <= 8){ /* 2 to 8 */ + if(rp+1 >= ep) + return nil; + nx = ((nx-2)<<8) | rp[0]; + if(CHECK && nx >= sq4->n) + return nil; /* corrupted file */ + nx = sq4->tab[nx] | rp[1]; + rp += 2; + }else{ /* 9 to 15 */ + if(rp >= ep) + return nil; /* corrupted file */ + nx = ((nx-9)<<8) | rp[0]; + if(CHECK && nx >= sq3->n) + return nil; /* corrupted file */ + nx = sq3->tab[nx]; + rp++; + } + if(rp > ep) + return nil; /* corrupted file */ + if(qflag){ + QREMAP(nx); + } + } + if(islittle){ + wp[0] = nx; + wp[1] = nx>>8; + wp[2] = nx>>16; + wp[3] = nx>>24; + }else{ + wp[0] = nx>>24; + wp[1] = nx>>16; + wp[2] = nx>>8; + wp[3] = nx; + } + wp += 4; + chksum += nx; + nx = code & 0xF; + }while(++n == 1); + } + return wp; +} + +static int +rdtab(int fd, Squeeze *sq, int shift) +{ + uchar b[7*256*5], *p, *ep; + ulong v, w; + int i; + + if(read(fd, b, 2) != 2) + return -1; + i = (b[0]<<8) | b[1]; + if(1) + fprint(2, "table: %d\n", i); + if((i -= 2) > 0){ + if(read(fd, b, i) != i) + return -1; + } + sq->n = 0; + p = b; + ep = b+i; + v = 0; + while(p < ep){ + w = 0; + do{ + if(p >= ep) + return -1; + w = (w<<7) | (*p & 0x7F); + }while(*p++ & 0x80); + v += w; + if(0) + fprint(2, "%d %8.8lux %8.8lux\n", sq->n, v, w); + sq->tab[sq->n++] = v << shift; + } + return 0; +} diff --git a/utils/srclist/Nt.c b/utils/srclist/Nt.c new file mode 100644 index 00000000..b86b930d --- /dev/null +++ b/utils/srclist/Nt.c @@ -0,0 +1,8 @@ +#include <windows.h> +#include "lib9.h" + +char* +mygetwd(char *path, int len) +{ + return getcwd(path, len); +} diff --git a/utils/srclist/Plan9.c b/utils/srclist/Plan9.c new file mode 100644 index 00000000..31838bd4 --- /dev/null +++ b/utils/srclist/Plan9.c @@ -0,0 +1,7 @@ +#include "lib9.h" + +char* +mygetwd(char *path, int len) +{ + return getwd(path, len); +} diff --git a/utils/srclist/Posix.c b/utils/srclist/Posix.c new file mode 100644 index 00000000..ea5c842a --- /dev/null +++ b/utils/srclist/Posix.c @@ -0,0 +1,10 @@ +#include "lib9.h" +#undef getwd +#undef getwd +#include <unistd.h> + +char* +mygetwd(char *path, int len) +{ + return getcwd(path, len); +} diff --git a/utils/srclist/mkfile b/utils/srclist/mkfile new file mode 100644 index 00000000..a8c2a4d6 --- /dev/null +++ b/utils/srclist/mkfile @@ -0,0 +1,19 @@ +<../../mkconfig + +TARG=srclist + +OFILES= srclist.$O\ + $TARGMODEL.$O\ + +HFILES=\ + a.out.h\ + bio.h\ + mach.h\ + +LIBS=mach bio 9 # order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/srclist/srclist.c b/utils/srclist/srclist.c new file mode 100644 index 00000000..83b0f0ed --- /dev/null +++ b/utils/srclist/srclist.c @@ -0,0 +1,144 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +int conly; +int exists; + +enum { + Maxroot = 10, +}; + +int nroot; +char *root[Maxroot]; +int rootlen[Maxroot]; + +void usage(void); +void error(char *); +void addroot(char *); +void addroots(char *); +void chomp(char *); + +extern char *mygetwd(char*, int); + +void +main(int argc, char **argv) +{ + char buf[1024], *cwd; + + cwd = mygetwd(buf, sizeof(buf)); + ARGBEGIN { + case 'c': + conly = 1; + break; + case 'e': + exists = 1; + break; + case 'r': + addroots(EARGF(usage())); + break; + default: + usage(); + } ARGEND + + if(argc != 1) + usage(); + + if(cwd != nil) + chdir(cwd); + setbinmode(); + chomp(argv[0]); + + exits(0); +} + +void +addroot(char *x) +{ + if(nroot >= Maxroot){ + fprint(2, "srclist: too many root directories\n"); + exits("usage"); + } + root[nroot] = x; + rootlen[nroot] = strlen(x); + nroot++; +} + +void +addrootnt(char *r) +{ + addroot(r); + if(r[1] != ':') + return; /* phew! */ + if(*r >= 'a' && *r <= 'z' || *r >= 'A' && *r <= 'Z') + addroot(r+2); +} + +void +addroots(char *r) +{ + char buf[1024], *r2; + + addrootnt(r); + if(chdir(r) < 0) + return; + r2 = mygetwd(buf, sizeof(buf)); + if(r2 && strcmp(r2, r) != 0) + addrootnt(r2); +} + +void +chomp(char *file) +{ + int fd, i, j, len; + Fhdr fhdr; + Dir *td; + char fname[1024]; + + fd = open(file, OREAD); + if(fd < 0) + error("open"); + + if(crackhdr(fd, &fhdr) == 0) + error("crackhdr"); + + if(syminit(fd, &fhdr) < 0) + error("syminit"); + + for(i = 0; i < 1000; i++) + if(filesym(i, fname, sizeof(fname)-1)){ + cleanname(fname); + if(conly){ + len = strlen(fname); + if(len < 2 || strcmp(fname+len-2, ".c") != 0) + continue; + } + if(exists){ + if((td = dirstat(fname)) == nil) + continue; + free(td); + } + if(nroot){ + for(j = 0; j < nroot; j++) + if(strncmp(fname, root[j], rootlen[j]) == 0) + break; + if(j == nroot) + continue; + } + print("%s\n", fname); + } +} + +void +usage(void) +{ + fprint(2, "usage: srclist [-ce] [-r root] <objfile>\n"); + exits("usage"); +} + +void +error(char *s) +{ + fprint(2, "srclist: %s: %r\n", s); + exits(s); +} diff --git a/utils/tc/5.out.h b/utils/tc/5.out.h new file mode 100644 index 00000000..59aebab6 --- /dev/null +++ b/utils/tc/5.out.h @@ -0,0 +1,192 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 16 + +#define NOPROF (1<<0) +#define DUPOK (1<<1) +#define ALLTHUMBS (1<<2) + +#define REGRET 0 +#define REGARG 0 +/* compiler allocates R1 up as temps */ +/* compiler allocates register variables R3 up */ +#define REGEXT 6 +/* compiler allocates external registers R5 down */ +#define REGTMPT 7 /* used by the loader - thumb */ +#define REGTMP 11 /* used by the loader - arm */ +#define REGSB 12 +#define REGSP 13 +#define REGLINK 14 +#define REGPC 15 + +#define NFREG 8 +#define FREGRET 0 +#define FREGEXT 7 +/* compiler allocates register variables F0 up */ +/* compiler allocates external registers F7 down */ + +enum as +{ + + AXXX, + + AAND, + AEOR, + ASUB, + ARSB, // not used + AADD, + AADC, + ASBC, + ARSC, // not used + ATST, + ATEQ, // not used + ACMP, + ACMN, + AORR, + ABIC, + + AMVN, + + AB, + ABL, + + /* + * Do not reorder or fragment the conditional branch + * opcodes, or the predication code will break + */ + + ABEQ, + ABNE, + ABCS, + ABHS, + ABCC, + ABLO, + ABMI, + ABPL, + ABVS, + ABVC, + ABHI, + ABLS, + ABGE, + ABLT, + ABGT, + ABLE, + + AMOVWD, + AMOVWF, + AMOVDW, + AMOVFW, + AMOVFD, + AMOVDF, + AMOVF, + AMOVD, + + ACMPF, + ACMPD, + AADDF, + AADDD, + ASUBF, + ASUBD, + AMULF, + AMULD, + ADIVF, + ADIVD, + + ASRL, // right logical + ASRA, // right arithmetic + ASLL, // left logical = left arithmetic + AMULU, + ADIVU, + AMUL, + ADIV, + AMOD, + AMODU, + + AMOVB, + AMOVBU, + AMOVH, + AMOVHU, + AMOVW, + AMOVM, + ASWPBU, // not used + ASWPW, // not used + + ANOP, + ARFE, + ASWI, + AMULA, // not used + + ADATA, + AGLOBL, + AGOK, + AHISTORY, + ANAME, + ARET, // fn return + ATEXT, // fn start + AWORD, + ADYNT, // not used + AINIT, // not used + ABCASE, // not used + ACASE, // not used + + AEND, + + AMULL, + AMULAL, + AMULLU, + AMULALU, + + ABX, + ABXRET, + + ADWORD, + + ASIGNAME, + + ALAST, + +}; + +/* type/name */ +#define D_GOK 0 +#define D_NONE 1 + +/* type */ +#define D_BRANCH (D_NONE+1) +#define D_OREG (D_NONE+2) +#define D_CONST (D_NONE+7) +#define D_FCONST (D_NONE+8) +#define D_SCONST (D_NONE+9) +#define D_PSR (D_NONE+10) +#define D_REG (D_NONE+12) +#define D_FREG (D_NONE+13) +#define D_FILE (D_NONE+16) +#define D_OCONST (D_NONE+17) +#define D_FILE1 (D_NONE+18) + +#define D_SHIFT (D_NONE+19) /* not used */ +#define D_FPCR (D_NONE+20) +#define D_REGREG (D_NONE+21) + +/* name */ +#define D_EXTERN (D_NONE+3) +#define D_STATIC (D_NONE+4) +#define D_AUTO (D_NONE+5) +#define D_PARAM (D_NONE+6) + +/* + * 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 */ +}; diff --git a/utils/tc/cgen.c b/utils/tc/cgen.c new file mode 100644 index 00000000..1c1525c4 --- /dev/null +++ b/utils/tc/cgen.c @@ -0,0 +1,1234 @@ +#include "gc.h" + +static int +commutes(int o) +{ + switch(o){ + case OAND: + case OOR: + case OXOR: + case OLMUL: + case OMUL: + case OADD: + return 1; + } + return 0; +} + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o, t; + long v, curs; + + if(debug['g'] && nn == Z) { + // 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(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED && l->complex < FNX) { + 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) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case ODIV: + case OMOD: + if(nn != Z) + if((t = vlog(r)) >= 0 && t <= 8) { + /* signed div/mod by constant power of 2 */ + cgen(l, nn); + gopcode(OGE, nodconst(0), nn, Z); + p1 = p; + if(o == ODIV) { + gopcode(OADD, nodconst((1<<t)-1), Z, nn); + patch(p1, pc); + gopcode(OASHR, nodconst(t), Z, nn); + } else { + gopcode(OSUB, nn, nodconst(0), nn); + regalloc(&nod, l, Z); + gopcode(OAS, nodconst((1<<t)-1), Z, &nod); + gopcode(OAND, &nod, Z, nn); + regfree(&nod); + // gopcode(OAND, nodconst((1<<t)-1), Z, nn); + gopcode(OSUB, nn, nodconst(0), nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + regalloc(&nod, l, Z); + gopcode(OAS, nodconst((1<<t)-1), Z, &nod); + gopcode(OAND, &nod, Z, nn); + regfree(&nod); + // gopcode(OAND, nodconst((1<<t)-1), Z, nn); + patch(p1, pc); + } + break; + } + goto muldiv; + + case OADD: + case OSUB: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(sconst(r)) + if(o == OADD || o == OSUB || r->vconst < (vlong)32) { + // if(r->op == OCONST) + // if(!typefd[n->type->etype]) { + cgen(l, nn); + if(r->vconst == 0) + break; + gopcode(o, r, Z, nn); + break; + } + + case OAND: + case OOR: + case OXOR: + case OLMUL: + case OLDIV: + case OLMOD: + case OMUL: + muldiv: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, &nod1, Z, &nod); + } else { + if(o == OADD || o == OSUB) { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); + } + else { + if(commutes(o)){ + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod1, Z, &nod); + } + else{ + regalloc(&nod1, r, Z); + cgen(r, &nod1); + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod1, Z, &nod); + } + } + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + +/* + case ONEG: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod, Z, &nod); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; +*/ + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASADD: + case OASSUB: + if(l->op == OBIT) + goto asbitop; + if(sconst(r)) + if(o == OASADD || o == OASSUB || r->vconst < (vlong)32) { + // if(r->op == OCONST) + // if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASAND: + case OASXOR: + case OASOR: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } else { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + + regalloc(&nod, n, nn); + gmove(&nod2, &nod); + gopcode(o, &nod1, Z, &nod); + gmove(&nod, &nod2); + if(nn != Z) + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + 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); + gopcode(o, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + if(REGARG >= 0) + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG >= 0) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + 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+nod.xoffset) >= 0 && v < 32*r->type->width/SZ_LONG) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type)) { + if(nocast(n->type, nn->type)) { + cgen(l, nn); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (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(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else { + if (v > 0 && v < 8) + gopcode(OADD, nodconst(v), &nod, &nod1); + else if (v < 0 && v > -8) + gopcode(OSUB, nodconst(-v), &nod, &nod1); + else { + regalloc(&nod3, l, Z); + gopcode(OAS, nodconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + regfree(&nod3); + } + } + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else { + if (v > 0 && v < 256) + gopcode(OADD, nodconst(v), Z, &nod); + else if (v < 0 && v > -256) + gopcode(OSUB, nodconst(-v), Z, &nod); + else { + regalloc(&nod3, l, Z); + gopcode(OAS, nodconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod); + regfree(&nod3); + } + } + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + if (v > 0 && v < 256) + gopcode(OADD, nodconst(v), Z, &nod); + else if (v < 0 && v > -256) + gopcode(OSUB, nodconst(-v), Z, &nod); + else { + regalloc(&nod3, l, Z); + gopcode(OAS, nodconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod); + regfree(&nod3); + } + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + if (v > 0 && v < 256) + gopcode(OADD, nodconst(v), Z, &nod); + else if (v < 0 && v > -256) + gopcode(OSUB, nodconst(-v), Z, &nod); + else { + regalloc(&nod3, l, Z); + gopcode(OAS, nodconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod); + regfree(&nod3); + } + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; + return; +} + +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+t->xoffset) >= 0 && v < 32*n->type->width/SZ_LONG) { + v = r->vconst; + r->vconst = 0; + lcgen(n, t); + t->xoffset += v; + r->vconst = v; + regind(t, n); + return; + } + } else if(n->op == OINDREG) { + if((v = n->xoffset) >= 0 && v < (n->reg == REGSP ? 256 : 32)*n->type->width/SZ_LONG) { + n->op = OREGISTER; + cgen(n, t); + t->xoffset += v; + n->op = OINDREG; + regind(t, n); + return; + } + } + lcgen(n, t); + regind(t, n); +} + +void +reglpcgen(Node *n, Node *nn, int f) +{ + Type *t; + + t = nn->type; + nn->type = types[TLONG]; + if(f) + reglcgen(n, nn, Z); + else { + regialloc(n, nn, Z); + lcgen(nn, n); + regind(n, nn); + } + nn->type = t; +} + +void +lcgen(Node *n, Node *nn) +{ + Prog *p1; + Node nod; + + if(debug['g']) { + prtree(nn, "lcgen lhs"); + prtree(n, "lcgen"); + } + if(n == Z || n->type == T) + return; + if(nn == Z) { + nn = &nod; + regalloc(&nod, n, Z); + } + switch(n->op) { + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, "boolgen"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + regalloc(&nod, n, nn); + cgen(n, &nod); + o = ONE; + if(true) + o = comrel[relindex(o)]; + if(typefd[n->type->etype]) { + gopcode(o, nodfconst(0), &nod, Z); + } else + gopcode(o, nodconst(0), &nod, Z); + 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(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(sconst(l)) { + regalloc(&nod, r, nn); + cgen(r, &nod); + o = invrel[relindex(o)]; + gopcode(o, l, &nod, Z); + regfree(&nod); + goto com; + } + if(sconst(r)) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, r, &nod, Z); + regfree(&nod); + goto com; + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + gopcode(o, &nod, &nod1, Z); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + nod1.xoffset += SZ_LONG; + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + + regfree(&nod1); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && nn->complex >= FNX) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + 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; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + w /= SZ_LONG; + if(w <= 2) { + if(n->complex > nn->complex) { + reglpcgen(&nod1, n, 1); + reglpcgen(&nod2, nn, 1); + } else { + reglpcgen(&nod2, nn, 1); + reglpcgen(&nod1, n, 1); + } + regalloc(&nod3, ®node, Z); + regalloc(&nod4, ®node, Z); + nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg)); + if(w == 2 && nod1.xoffset == 0) + gmovm(&nod1, &nod0); + else { + gmove(&nod1, &nod3); + if(w == 2) { + nod1.xoffset += SZ_LONG; + gmove(&nod1, &nod4); + } + } + if(w == 2 && nod2.xoffset == 0) + gmovm(&nod0, &nod2); + else { + gmove(&nod3, &nod2); + if(w == 2) { + nod2.xoffset += SZ_LONG; + gmove(&nod4, &nod2); + } + } + regfree(&nod1); + regfree(&nod2); + regfree(&nod3); + regfree(&nod4); + return; + } + + if(n->complex > nn->complex) { + reglpcgen(&nod1, n, 0); + reglpcgen(&nod2, nn, 0); + } else { + reglpcgen(&nod2, nn, 0); + reglpcgen(&nod1, n, 0); + } + + m = 0; + for(c = 0; c < w && c < 3; c++) { + i = tmpreg(); + if (i == 0) + break; + reg[i]++; + m |= 1<<i; + } + nod4 = *(nodconst(m)); + if(w < 3*c) { + for (; w>c; w-=c) { + gmovm(&nod1, &nod4); + gmovm(&nod4, &nod2); + } + goto out; + } + + regalloc(&nod3, ®node, Z); + gopcode(OAS, nodconst(w/c), Z, &nod3); + w %= c; + + pc1 = pc; + gmovm(&nod1, &nod4); + gmovm(&nod4, &nod2); + + gopcode(OSUB, nodconst(1), Z, &nod3); + gopcode(OEQ, nodconst(0), &nod3, Z); + p->as = ABGT; + patch(p, pc1); + regfree(&nod3); + +out: + if (w) { + i = 0; + while (c>w) { + while ((m&(1<<i)) == 0) + i++; + m &= ~(1<<i); + reg[i] = 0; + c--; + i++; + } + nod4.vconst = m; + gmovm(&nod1, &nod4); + gmovm(&nod4, &nod2); + } + i = 0; + do { + while ((m&(1<<i)) == 0) + i++; + reg[i] = 0; + c--; + i++; + } while (c>0); + regfree(&nod1); + regfree(&nod2); +} diff --git a/utils/tc/enam.c b/utils/tc/enam.c new file mode 100644 index 00000000..b4a5fbe6 --- /dev/null +++ b/utils/tc/enam.c @@ -0,0 +1,98 @@ +char* anames[] = +{ + "XXX", + "AND", + "EOR", + "SUB", + "RSB", + "ADD", + "ADC", + "SBC", + "RSC", + "TST", + "TEQ", + "CMP", + "CMN", + "ORR", + "BIC", + "MVN", + "B", + "BL", + "BEQ", + "BNE", + "BCS", + "BHS", + "BCC", + "BLO", + "BMI", + "BPL", + "BVS", + "BVC", + "BHI", + "BLS", + "BGE", + "BLT", + "BGT", + "BLE", + "MOVWD", + "MOVWF", + "MOVDW", + "MOVFW", + "MOVFD", + "MOVDF", + "MOVF", + "MOVD", + "CMPF", + "CMPD", + "ADDF", + "ADDD", + "SUBF", + "SUBD", + "MULF", + "MULD", + "DIVF", + "DIVD", + "SRL", + "SRA", + "SLL", + "MULU", + "DIVU", + "MUL", + "DIV", + "MOD", + "MODU", + "MOVB", + "MOVBU", + "MOVH", + "MOVHU", + "MOVW", + "MOVM", + "SWPBU", + "SWPW", + "NOP", + "RFE", + "SWI", + "MULA", + "DATA", + "GLOBL", + "GOK", + "HISTORY", + "NAME", + "RET", + "TEXT", + "WORD", + "DYNT", + "INIT", + "ABCASE", + "ACASE", + "END", + "MULL", + "MULAL", + "MULLU", + "MULALU", + "BX", + "BX", + "DWORD", + "SIGNAME", + "LAST", +}; diff --git a/utils/tc/gc.h b/utils/tc/gc.h new file mode 100644 index 00000000..e61a1967 --- /dev/null +++ b/utils/tc/gc.h @@ -0,0 +1,349 @@ +#include "../cc/cc.h" +#include "../tc/5.out.h" + +/* + * 5ct/Thumb + * Arm 7500 + * Thumb + */ +#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 Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + + +#define R0ISZERO 0 + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + Ieee ieee; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + char as; + char reg; + uchar scond; /* not used in 5ct */ +}; +#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 Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +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) + +#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 Multab multab[20]; +EXTERN int retok; +EXTERN int hintabsize; +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 char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN char reg[NREG+NFREG]; +EXTERN long exregoffset; +EXTERN long exfregoffset; +EXTERN int suppress; + +#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 4 +#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 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[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void usedset(Node*, int); +void xcom(Node*); +int bcomplex(Node*, Node*); + +/* + * cgen.c + */ +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nod32const(vlong); +Node* nodfconst(double); +void nodreg(Node*, Node*, int); +void regret(Node*, Node*); +int tmpreg(void); +void regalloc(Node*, Node*, Node*); +void regfree(Node*); +void regialloc(Node*, Node*, Node*); +void regsalloc(Node*, Node*); +void regaalloc1(Node*, Node*); +void regaalloc(Node*, Node*); +void regind(Node*, Node*); +void gprep(Node*, Node*); +void raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmovm(Node*, Node*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +void gopcode2(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int sval(long); +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); +int mulcon(Node*, Node*); +Multab* mulcon0(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 Nconv(Fmt*); +int Bconv(Fmt*); +int Rconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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 regzer(Adr*); +int anyvar(Adr*); +int subprop(Reg*); +int copyprop(Reg*); +void constprop(Adr*, Adr*, Reg*); +int copy1(Adr*, Adr*, Reg*, int); +int copyu(Prog*, Adr*, Adr*); + +int copyas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copyau1(Prog*, 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); + +void predicate(void); +int isbranch(Prog *); +int predicable(Prog *p); +int modifiescpsr(Prog *p); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "R" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/tc/list.c b/utils/tc/list.c new file mode 100644 index 00000000..1078423e --- /dev/null +++ b/utils/tc/list.c @@ -0,0 +1,276 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('B', Bconv); + 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; + int a; + + p = va_arg(fp->args, Prog*); + a = p->as; + if(a == AMOVM) { + if(p->from.type == D_CONST) + sprint(str, " %A %R,%D", a, &p->from, &p->to); + else + if(p->to.type == D_CONST) + sprint(str, " %A %D,%R", a, &p->from, &p->to); + else + sprint(str, " %A %D,%D", a, &p->from, &p->to); + } else + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_EXTERN: + case D_STATIC: + sprint(str, "%N", a); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_PSR: + sprint(str, "PSR"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(PSR)(REG)", a); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Rconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + int i, v; + + a = va_arg(fp->args, Adr*); + sprint(str, "GOK-reglist"); + switch(a->type) { + case D_CONST: + if(a->reg != NREG) + break; + if(a->sym != S) + break; + v = a->offset; + strcpy(str, ""); + for(i=0; i<NREG; i++) { + if(v & (1<<i)) { + if(str[0] == 0) + strcat(str, "[R"); + else + strcat(str, ",R"); + sprint(strchr(str, 0), "%d", i); + } + } + strcat(str, "]"); + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<NSNAME; i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/tc/mkenam b/utils/tc/mkenam new file mode 100644 index 00000000..7cd23551 --- /dev/null +++ b/utils/tc/mkenam @@ -0,0 +1,15 @@ +ed - ../5ct/5.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/utils/tc/mkfile b/utils/tc/mkfile new file mode 100644 index 00000000..60863925 --- /dev/null +++ b/utils/tc/mkfile @@ -0,0 +1,28 @@ +<../../mkconfig + +TARG=tc + +OFILES= cgen.$O\ + enam.$O\ + list.$O\ + mul.$O\ + peep.$O\ + reg.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + +HFILES= gc.h\ + 5.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/tc/mul.c b/utils/tc/mul.c new file mode 100644 index 00000000..67370a62 --- /dev/null +++ b/utils/tc/mul.c @@ -0,0 +1,609 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int maxmulops = 3; /* max # of ops to replace mul with */ +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ +}; + +Multab* +mulcon0(long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; g<nelem(multab); g++) { + if(m->val == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=maxmulops; g++) { + if(g >= maxmulops && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<<c, r1)) + goto out; + break; + case 1: + if(docode(hp, cp, r1<<c, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r0, r0<<c)) + goto out; + break; + case 3: + if(docode(hp, cp, r0, r1<<c)) + goto out; + break; + } + } + break; + + case '+': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0+r1, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0+r1)) + goto out; + break; + } + } + break; + + case '-': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0-r1, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r1-r0, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0-r1)) + goto out; + break; + case 6: + if(docode(hp, cp, r0, r1-r0)) + goto out; + break; + } + } + break; + + case 0: + if(r0 == mulval) + return 1; + } + return 0; + +out: + cp[-1] = i+'0'; + return 1; +} + +static int +gen1(int len) +{ + int i; + + for(shmax=1; shmax<30; shmax++) { + valmax = 1<<shmax; + if(valmax >= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<<i)) { + *--mulcp = 'a'+i; + return 1; + } + return 0; +} + +static int +gen2(int len, long r1) +{ + int i; + + if(len <= 0) { + if(r1 == mulval) + return 1; + return 0; + } + + len--; + if(len == 0) + goto calcr0; + + if(gen3(len, r1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, r1-1, r1, UR0)) { + i = '-'; + goto out; + } + if(gen3(len, 1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, 1, r1-1, UR1)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + if(mulval == r1+1) { + i = '+'; + goto out; + } + if(mulval == r1-1) { + i = '-'; + goto out; + } + return 0; + +out: + *--mulcp = i; + return 1; +} + +static int +gen3(int len, long r0, long r1, int flag) +{ + int i, f1, f2; + long x; + + if(r0 <= 0 || + r0 >= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x >= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/tc/peep.c b/utils/tc/peep.c new file mode 100644 index 00000000..2842b3e3 --- /dev/null +++ b/utils/tc/peep.c @@ -0,0 +1,759 @@ +#include "gc.h" + +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; + } + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) + if(regtyp(&p->to)) { + if(p->from.type == D_CONST) + constprop(&p->from, &p->to, r->s1); + else if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AEOR: + /* + * EOR -1,x,y => MVN x,y + */ + if(p->from.type == D_CONST && p->from.offset == -1) { + p->as = AMVN; + p->from.type = D_REG; + if(p->reg != NREG) + p->from.reg = p->reg; + else + p->from.reg = p->to.reg; + p->reg = NREG; + } + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +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) +{ + + if(a->type == D_REG) + return 1; + if(a->type == D_FREG) + 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 ABL: + case ABX: + return 0; + + // case ACMP: + // case ACMN: + case AADD: + case ASUB: + // case ASLL: + // case ASRL: + // case ASRA: + // case AORR: + // case AAND: + // case AEOR: + // case AMUL: + // case ADIV: + // case ADIVU: + + // case ACMPF: + // case ACMPD: + // case AADDD: + // case AADDF: + // case ASUBD: + // case ASUBF: + // case AMULD: + // case AMULF: + // case ADIVD: + // case ADIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AMOVF: + case AMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + + case AMOVM: + t = 1<<v2->reg; + if((p->from.type == D_CONST && (p->from.offset&t)) || + (p->to.type == D_CONST && (p->to.offset&t))) + return 0; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +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("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * The idea is to remove redundant constants. + * $c1->v1 + * ($c1->v2 s/$c1/v1)* + * set v1 return + * The v1->v2 should be eliminated by copy propagation. + */ +void +constprop(Adr *c1, Adr *v1, Reg *r) +{ + Prog *p; + + if(debug['C']) + print("constprop %D->%D\n", c1, v1); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['C']) + print("%P", p); + if(uniqp(r) == R) { + if(debug['C']) + print("; merge; return\n"); + return; + } + if(p->as == AMOVW && copyas(&p->from, c1)) { + if(debug['C']) + print("; sub%D/%D", &p->from, v1); + p->from = *v1; + } else if(copyu(p, v1, A) > 1) { + if(debug['C']) + print("; %Dset; return\n", v1); + return; + } + if(debug['C']) + print("\n"); + if(r->s2) + constprop(c1, v1, r->s2); + } +} + +/* + * 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(" (???)"); + return 2; + + case AMOVM: + if(v->type != D_REG) + return 0; + if(p->from.type == D_CONST) { /* read reglist, read/rar */ + if(s != A) { + if(p->from.offset&(1<<v->reg)) + return 1; + if(copysub(&p->to, v, s, 1)) + diag(Z, "movm dst being replaced"); // was return 1; + return 0; + } + if(copyau(&p->to, v)) + return 2; // register updated in thumb // was return 1; + if(p->from.offset&(1<<v->reg)) + return 1; + } else { /* read/rar, write reglist */ + if(s != A) { + if(p->to.offset&(1<<v->reg)) + return 1; + if(copysub(&p->from, v, s, 1)) + diag(Z, "movm src being replaced"); // was return 1; + return 0; + } + if(copyau(&p->from, v)) { + // if(p->to.offset&(1<<v->reg)) + // return 4; + return 2; // register updated in thumb // was return 1; + } + if(p->to.offset&(1<<v->reg)) + return 3; + } + return 0; + + case ANOP: /* read, write */ + case AMOVW: + case AMOVF: + case AMOVD: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + case AMOVDW: + case AMOVWD: + case AMOVFD: + case AMOVDF: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + case ACMPF: + case ACMPD: + case ACMP: + case ACMN: + if(copyas(&p->to, v)) + return 2; + /*FALLTHROUGH*/ + + case AADD: /* read, read, write */ + case ASUB: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: /* read, read */ + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub1(p, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + return 0; + + case AB: /* funny */ + if(s != 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 == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case ABL: /* funny */ + case ABX: + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) + if(v->reg <= FREGEXT && v->reg > exfregoffset) + 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; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } + return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + + case ACMP: + case ACMN: + + case AADD: + case ASUB: + case ASLL: + case ASRL: + case ASRA: + case AORR: + case AAND: + case AEOR: + case AMUL: + case ADIV: + case ADIVU: + return D_REG; + + case ACMPF: + case ACMPD: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) { + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + } else if(v->type == D_CONST) { /* for constprop */ + if(a->type == v->type) + if(a->name == v->name) + if(a->sym == v->sym) + if(a->reg == v->reg) + if(a->offset == v->offset) + return 1; + } + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) { + if(a->type == D_OREG) { + if(v->reg == a->reg) + return 1; + } + } + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) { + if(a2type(p) == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) { + a->reg = s->reg; + } + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} diff --git a/utils/tc/reg.c b/utils/tc/reg.c new file mode 100644 index 00000000..54bc76a7 --- /dev/null +++ b/utils/tc/reg.c @@ -0,0 +1,1161 @@ +#include "gc.h" + +void addsplits(void); + +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 = 0; + 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 AB: + case ARFE: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW); + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + case AMOVW: + case AMOVF: + case AMOVD: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case ABL: + case ABX: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + break; + } + + if(p->as == AMOVM) { + if(p->from.type == D_CONST) + z = p->from.offset; + else + z = p->to.offset; + for(i=0; z; i++) { + if(z&1) + regbits |= RtoB(i); + z >>= 1; + } + } + } + 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); + + /* + * 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; + + addsplits(); + + if(debug['R'] && debug['v']) { + print("\nprop 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->set.b[z] | + r->refahead.b[z] | r->calahead.b[z] | + r->refbehind.b[z] | r->calbehind.b[z] | + r->use1.b[z] | r->use2.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); + if(bany(&r->refahead)) + print(" ra=%B", r->refahead); + if(bany(&r->calahead)) + print(" ca=%B", r->calahead); + if(bany(&r->refbehind)) + print(" rb=%B", r->refbehind); + if(bany(&r->calbehind)) + print(" cb=%B", r->calbehind); + } + print("\n"); + } + } + + /* + * 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); + } + } + + for(r = firstr; r != R; r = r->link) + r->act = zbits; + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + 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']) { + if(rgp->regno >= NREG) + print("%L $%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L $%d R%d: %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; + } +} + +void +addsplits(void) +{ + Reg *r, *r1; + int z, i; + Bits bit; + + for(r = firstr; r != R; r = r->link) { + if(r->loop > 1) + continue; + if(r->prog->as == ABL || r->prog->as == ABX) + continue; + for(r1 = r->p2; r1 != R; r1 = r1->p2link) { + if(r1->loop <= 1) + continue; + for(z=0; z<BITS; z++) + bit.b[z] = r1->calbehind.b[z] & + (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & + ~(r->calahead.b[z] & addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + } + } + } +} + +/* + * 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->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TFLOAT) + p1->as = AMOVF; + if(v->etype == TDOUBLE) + p1->as = AMOVD; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBU; + if(v->etype == TUSHORT) + p1->as = AMOVHU; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + + n = a->name; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = et; + v->name = n; + 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]; + if(t == D_CONST) { + if(s == S) { + for(z=0; z<BITS; z++) + consts.b[z] |= bit.b[z]; + return bit; + } + if(et != TARRAY) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + return bit; + } + if(t == D_OREG) + 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 ABL: + case ABX: + 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 TVLONG: + case TDOUBLE: + case TFLOAT: + i = BtoF(~b); + if(i && r->cost >= 0) { + r->regno = i+NREG; + return FtoB(i); + } + 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(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(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(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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + 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->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * bit reg + * 0 R0 + * 1 R1 + * ... ... + * 10 R10 + */ +long +RtoB(int r) +{ + + if(r < 2 || r >= REGTMPT) + return 0; + return 1L << r; +} + +int +BtoR(long b) +{ + + b &= 0x7cL; // r2-r6 + if(b == 0) + return 0; + return bitno(b); +} + +/* + * bit reg + * 18 F2 + * 19 F3 + * ... ... + * 23 F7 + */ +long +FtoB(int f) +{ + + if(f < 2 || f > NFREG-1) + return 0; + return 1L << (f + 16); +} + +int +BtoF(long b) +{ + + b &= 0xfc0000L; + if(b == 0) + return 0; + return bitno(b) - 16; +} diff --git a/utils/tc/sgen.c b/utils/tc/sgen.c new file mode 100644 index 00000000..d76de7de --- /dev/null +++ b/utils/tc/sgen.c @@ -0,0 +1,667 @@ +#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)); + sp = p; + sp->reg |= ALLTHUMBS; /* denotes thumb code */ + + /* + * isolate first argument + */ + if(REGARG >= 0) { + if(typesuv[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gopcode(OAS, &nod, Z, &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); + gopcode(OAS, &nod, Z, &nod1); + } + } + + 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); + 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 o, f; + +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); + 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->pc = 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->pc) { + patch(p, n->pc); + 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 = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int t; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + +/* + case OSUB: + xcom(l); + xcom(r); + if(typefd[n->type->etype] || typev[n->type->etype]) + break; + if(vconst(l) == 0) + n->op = ONEG; + n->left = l; + n->right = Z; + } + break; +*/ + + case OASHL: + case OASHR: + case OLSHR: + case OASASHL: + case OASASHR: + case OASLSHR: + xcom(l); + xcom(r); + if(sconst(r) && r->vconst < 0){ + r->vconst = -r->vconst; + switch(n->op){ + case OASHL: n->op = OASHR; break; + case OASHR: n->op = OASHL; break; + case OLSHR: n->op = OASHL; break; + case OASASHL: n->op = OASASHR; break; + case OASASHR: n->op = OASASHL; break; + case OASLSHR: n->op = OASASHL; break; + } + } + break; + + case OASLMUL: + case OASMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASASHL; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASHL; + r->vconst = t; + r->type = types[TINT]; + } + t = vlog(l); + if(t >= 0) { + n->op = OASHL; + n->left = r; + n->right = l; + r = l; + l = n->left; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + case OFUNC: + n->complex = FNX; + break; + + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + case OEQ: + case ONE: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + } +} + +int +bcomplex(Node *n, Node *c) +{ + + 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; + bool64(n); + boolgen(n, 1, Z); + } else + gbranch(OGOTO); + return 0; +} diff --git a/utils/tc/swt.c b/utils/tc/swt.c new file mode 100644 index 00000000..1ded1e5c --- /dev/null +++ b/utils/tc/swt.c @@ -0,0 +1,717 @@ +#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, nodconst(q->val), n, Z); + 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, nodconst(r->val), n, Z); + sp = p; + gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */ + 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); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode2(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode2(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode2(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, 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->reg = 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; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v, vs; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + if(debug['M'] && debug['v']) + print("%L multiply: %ld\n", n->lineno, v); + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + vs = v; + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + if(vs < 0) { + gopcode(OAS, &nod1, Z, &nod1); + gopcode(OSUB, &nod1, nodconst(0), nn); + } else + gopcode(OAS, &nod1, Z, nn); +/* + if(vs < 0) + gopcode(ONEG, &nod1, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); +*/ + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +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(0)); + p->from.offset += o+e; + p->reg = 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, nod32const(a->vconst>>32)); + p->from.offset += o; + p->reg = 4; + gpseudo(ADATA, s, nod32const(a->vconst)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + + bf[0] = p->as; + bf[1] = 14; + bf[2] = p->reg; + bf[3] = p->lineno; + bf[4] = p->lineno>>8; + bf[5] = p->lineno>>16; + bf[6] = p->lineno>>24; + bp = zaddr(bf+7, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + 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++; + } + } + outhist(&outbuf); + 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.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, 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.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + 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, 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; + + zwrite(b, &pg, 0, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n, bf[7]; + ulong sig; + + n = s->name; + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); + s->sig = SIGDONE; + } + else{ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); + } + Bwrite(b, n, strlen(n)+1); +} + +char* +zaddr(char *bp, Adr *a, int s) +{ + long l; + Ieee e; + + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_PSR: + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + } + return bp; +} + +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; + 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; + 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, Ael2); + o = align(o, t, Ael1); + w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ + 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 = round(v, SZ_LONG); + if(v > max) + return v; + return max; +} diff --git a/utils/tc/txt.c b/utils/tc/txt.c new file mode 100644 index 00000000..7f186bd4 --- /dev/null +++ b/utils/tc/txt.c @@ -0,0 +1,1199 @@ +#include "gc.h" + +void +ginit(void) +{ + Type *t; + + thechar = 't'; + thestring = "arm"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + 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.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMPT; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + 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(); + + memset(reg, 0, sizeof(reg)); + // reg[REGTMPT] = 1; +} + +void +gclean(void) +{ + int i; + Sym *s; + + for(i=0; i<NREG; i++) + if(reg[i]) + diag(Z, "reg %d left allocated", i); + for(i=NREG; i<NREG+NFREG; i++) + if(reg[i]) + diag(Z, "freg %d left allocated", i-NREG); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + 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; +} + +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(typesuv[n->type->etype]) { + regaalloc(tn2, n); + if(n->complex >= FNX) { + sugen(*fnxp, tn2, n->type->width); + (*fnxp)++; + } else + sugen(n, tn2, n->type->width); + return; + } + if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nod32const(vlong v) +{ + constnode.vconst = v & MASK(32); + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +int +tmpreg(void) +{ + int i; + + for(i=REGRET+1; i<NREG; i++) + if(reg[i] == 0) + return i; + diag(Z, "out of fixed tmp registers"); + return 0; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i, j; + static int lasti; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<REGTMPT; i++) { + if(j >= REGTMPT) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + case TVLONG: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NFREG) + goto out; + } + j = 0*2 + NREG; + for(i=NREG; i<NREG+NFREG; i++) { + if(j >= NREG+NFREG) + j = NREG; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of float registers"); + goto err; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + nodreg(n, tn, 0); + return; +out: + reg[i]++; +/* lasti++; *** StrongARM does register forwarding */ +/* + if(lasti >= 5) + lasti = 0; +*/ + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + 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 + SZ_LONG; + 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 +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(R0ISZERO && a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: <null>"); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +gmovm(Node *f, Node *t) +{ + gins(AMOVM, f, t); // always sets base register now +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod; + +// prtree(f, "gmove src"); +// prtree(t, "gmove dst"); + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + } + if(ft == TFLOAT && f->op == OCONST) { + } + + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + a = AMOVW; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + } + if(typechlp[ft] && typeilp[tt]) + regalloc(&nod, t, t); + else + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + a = AMOVBU; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHU; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AMOVF; + break; + case TVLONG: + case TDOUBLE: + a = AMOVD; + break; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + switch(tt) { + case TDOUBLE: + case TVLONG: + a = AMOVD; + if(ft == TFLOAT) + a = AMOVFD; + break; + case TFLOAT: + a = AMOVDF; + if(ft == TFLOAT) + a = AMOVF; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVDW; + if(ft == TFLOAT) + a = AMOVFW; + break; + } + break; + case TUINT: + case TINT: + case TULONG: + case TLONG: + case TIND: + switch(tt) { + case TDOUBLE: + case TVLONG: + gins(AMOVWD, f, t); + if(ft == TULONG) { + } + return; + case TFLOAT: + gins(AMOVWF, f, t); + if(ft == TULONG) { + } + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TUINT: + case TINT: + case TULONG: + case TLONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWD, &nod, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVWF, &nod, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AMOVF || a == AMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, et; + Adr ta; + + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = AADD; + if(et == TFLOAT) + a = AADDF; + else + if(et == TDOUBLE || et == TVLONG) + a = AADDD; + break; + + case OASSUB: + case OSUB: + a = ASUB; + if(et == TFLOAT) + a = ASUBF; + else + if(et == TDOUBLE || et == TVLONG) + a = ASUBD; + break; + + case OASOR: + case OOR: + a = AORR; + break; + + case OASAND: + case OAND: + a = AAND; + break; + + case OASXOR: + case OXOR: + a = AEOR; + break; + + case OASLSHR: + case OLSHR: + a = ASRL; + break; + + case OASASHR: + case OASHR: + a = ASRA; + break; + + case OASASHL: + case OASHL: + a = ASLL; + break; + + case OFUNC: + a = ABL; + break; + + case OASMUL: + case OMUL: + a = AMUL; + if(et == TFLOAT) + a = AMULF; + else + if(et == TDOUBLE || et == TVLONG) + a = AMULD; + break; + + case OASDIV: + case ODIV: + a = ADIV; + if(et == TFLOAT) + a = ADIVF; + else + if(et == TDOUBLE || et == TVLONG) + a = ADIVD; + break; + + case OASMOD: + case OMOD: + a = AMOD; + break; + + case OASLMUL: + case OLMUL: + a = AMULU; + break; + + case OASLMOD: + case OLMOD: + a = AMODU; + break; + + case OASLDIV: + case OLDIV: + a = ADIVU; + break; + + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + case OLO: + case OLS: + case OHS: + case OHI: + a = ACMP; + if(et == TFLOAT) + a = ACMPF; + else + if(et == TDOUBLE || et == TVLONG) + a = ACMPD; + nextpc(); + p->as = a; + naddr(f1, &p->from); +/* + if(a == ACMP && f1->op == OCONST && p->from.offset < 0) { + p->as = ACMN; + p->from.offset = -p->from.offset; + } +*/ + raddr(f2, p); // expects it to be a register + switch(o) { + case OEQ: + a = ABEQ; + break; + case ONE: + a = ABNE; + break; + case OLT: + a = ABLT; + break; + case OLE: + a = ABLE; + break; + case OGE: + a = ABGE; + break; + case OGT: + a = ABGT; + break; + case OLO: + a = ABLO; + break; + case OLS: + a = ABLS; + break; + case OHS: + a = ABHS; + break; + case OHI: + a = ABHI; + break; + } + f1 = Z; + f2 = Z; + break; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +/* put f1 in a register first */ +void +gopcode2(int o, Node *f1, Node *f2, Node *t) +{ + Node nod; + + if(f2 != Z) + diag(Z, "bad parameter in gopcode2"); + // regalloc(&nod, t, Z); + nodreg(&nod, t, REGTMPT); + gopcode(OAS, f1, Z, &nod); + gopcode(o, &nod, Z, t); + // regfree(&nod); +} + +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 = AB; + 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_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + if(a == ATEXT) + p->reg = (profileflg ? 0 : NOPROF); + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= (vlong)0 && vv < (vlong)256) + return 1; + /* + * should be specialised for constant values which will + * fit in different instructionsl; for now, let 5l + * sort it out + */ + return 1; + } + } + return 0; +} + +int +sval(long v) +{ + if(v >= -32768 && v < 32768) + return 1; + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= NREG-1) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= NFREG-1) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; + +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] */ +}; diff --git a/utils/test/mkfile b/utils/test/mkfile new file mode 100644 index 00000000..4bd74e15 --- /dev/null +++ b/utils/test/mkfile @@ -0,0 +1,21 @@ +<../../mkconfig + +# +# the test command is only needed on Windows NT and Windows 95 +# + +TARG=test + +OFILES= test-$TARGMODEL.$O\ + +HFILES= + +LIBS=9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +test-Posix.c test-Inferno.c:QV: + echo 'test is only built on Windows NT or Windows 95' + exit 1 diff --git a/utils/test/test-Nt.c b/utils/test/test-Nt.c new file mode 100644 index 00000000..7d2a9fa7 --- /dev/null +++ b/utils/test/test-Nt.c @@ -0,0 +1,278 @@ +/* + * POSIX standard + * test expression + * [ expression ] + */ + +#include <lib9.h> +#include <windows.h> + +#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0)) + +int ap; +int ac; +char **av; +char *tmp; + +void synbad(char *, char *); +int length(char *); +int fsizep(char *); +int isdir(char *); +int isreg(char *); +int Ntisatty(int); +int isint(char *, int *); +int tio(char *, int); +int e(void), e1(void), e2(void), e3(void); + +void +main(int argc, char *argv[]) +{ + + ac = argc; av = argv; ap = 1; + if(EQ(argv[0],"[")) { + if(!EQ(argv[--ac],"]")) + synbad("] missing",""); + } + argv[ac] = 0; + if (ac<=1) exits("usage"); + exits(e()?0:"false"); +} + +char * +nxtarg(int mt) +{ + if(ap>=ac){ + if(mt){ + ap++; + return(0); + } + synbad("argument expected",""); + } + return(av[ap++]); +} + +int +nxtintarg(int *pans) +{ + if(ap<ac && isint(av[ap], pans)){ + ap++; + return 1; + } + return 0; +} + +int +e(void) { + int p1; + + p1 = e1(); + if (EQ(nxtarg(1), "-o")) return(p1 || e()); + ap--; + return(p1); +} + +int +e1(void) { + int p1; + + p1 = e2(); + if (EQ(nxtarg(1), "-a")) return (p1 && e1()); + ap--; + return(p1); +} + +int +e2(void) { + if (EQ(nxtarg(0), "!")) + return(!e2()); + ap--; + return(e3()); +} + +int +e3(void) { + int p1; + char *a; + char *p2; + int int1, int2; + + a = nxtarg(0); + if(EQ(a, "(")) { + p1 = e(); + if(!EQ(nxtarg(0), ")")) synbad(") expected",""); + return(p1); + } + + if(EQ(a, "-f")) + return(isreg(nxtarg(0))); + + if(EQ(a, "-d")) + return(isdir(nxtarg(0))); + + if(EQ(a, "-r")) + return(tio(nxtarg(0), 4)); + + if(EQ(a, "-w")) + return(tio(nxtarg(0), 2)); + + if(EQ(a, "-x")) + return(tio(nxtarg(0), 1)); + + if(EQ(a, "-e")) + return(tio(nxtarg(0), 0)); + + if(EQ(a, "-c")) + return(0); + + if(EQ(a, "-b")) + return(0); + + if(EQ(a, "-u")) + return(0); + + if(EQ(a, "-g")) + return(0); + + if(EQ(a, "-s")) + return(fsizep(nxtarg(0))); + + if(EQ(a, "-t")) + if(ap>=ac || !nxtintarg(&int1)) + return(Ntisatty(1)); + else + return(Ntisatty(int1)); + + if(EQ(a, "-n")) + return(!EQ(nxtarg(0), "")); + if(EQ(a, "-z")) + return(EQ(nxtarg(0), "")); + + p2 = nxtarg(1); + if (p2==0) + return(!EQ(a,"")); + if(EQ(p2, "=")) + return(EQ(nxtarg(0), a)); + + if(EQ(p2, "!=")) + return(!EQ(nxtarg(0), a)); + + if(!isint(a, &int1)) + return(!EQ(a,"")); + + if(nxtintarg(&int2)){ + if(EQ(p2, "-eq")) + return(int1==int2); + if(EQ(p2, "-ne")) + return(int1!=int2); + if(EQ(p2, "-gt")) + return(int1>int2); + if(EQ(p2, "-lt")) + return(int1<int2); + if(EQ(p2, "-ge")) + return(int1>=int2); + if(EQ(p2, "-le")) + return(int1<=int2); + } + + synbad("unknown operator ",p2); + return 0; /* to shut ken up */ +} + +int +tio(char *a, int f) +{ + return access (a, f) >= 0; +} + +/* + * dirstat fails for: + * [drivename]: + * [drivename]:/ + * <dirname>/ + * [drivename]:<dirname>/ + */ +int +isdir(char *f) +{ + Dir *dir; + int len; + + len = strlen(f); + if (f[(len-1)] == '/') { + /* zap trailing '/' */ + f[(len-1)] = '\0'; + } + if (len == 2) { + if (f[1] == ':') { + return DMDIR; + } + } + if((dir = dirstat(f))==nil) + return(0); + return(dir->mode&DMDIR); +} + +int +isreg(char *f) +{ + Dir *dir; + + if((dir = dirstat(f))==nil) + return(0); + return(!(dir->mode&DMDIR)); +} + +int +Ntisatty(int fd) +{ + HANDLE h; + + if(fd < 0) + return 0; + + h = (HANDLE)_get_osfhandle(fd); + if(h < 0) + return 0; + return _isatty((int)h); +} + +int +fsizep(char *f) +{ + Dir *dir; + + if((dir = dirstat(f))==nil) + return(0); + return(dir->length>0); +} + +void +synbad(char *s1, char *s2) +{ + int len; + + write(2, "test: ", 6); + if ((len = strlen(s1)) != 0) + write(2, s1, len); + if ((len = strlen(s2)) != 0) + write(2, s2, len); + write(2, "\n", 1); + exits("bad syntax"); +} + +int +length(char *s) +{ + char *es=s; + while(*es++); + return(es-s-1); +} + +int +isint(char *s, int *pans) +{ + char *ep; + + *pans = strtol(s, &ep, 0); + return (*ep == 0); +} diff --git a/utils/tr/mkfile b/utils/tr/mkfile new file mode 100644 index 00000000..410f7a3a --- /dev/null +++ b/utils/tr/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=tr + +OFILES= tr.$O\ + +HFILES= + +LIBS=9 # libbio.a uses lib9.a so order matters. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE diff --git a/utils/tr/tr.c b/utils/tr/tr.c new file mode 100644 index 00000000..65243103 --- /dev/null +++ b/utils/tr/tr.c @@ -0,0 +1,355 @@ +#include <lib9.h> + +typedef struct PCB /* Control block controlling specification parse */ +{ + char *base; /* start of specification */ + char *current; /* current parse point */ + long last; /* last Rune returned */ + long final; /* final Rune in a span */ +} Pcb; + +uchar bits[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +#define SETBIT(a, c) ((a)[(c)/8] |= bits[(c)&07]) +#define CLEARBIT(a,c) ((a)[(c)/8] &= ~bits[(c)&07]) +#define BITSET(a,c) ((a)[(c)/8] & bits[(c)&07]) + +#define MAXRUNE 0xFFFF + +uchar f[(MAXRUNE+1)/8]; +uchar t[(MAXRUNE+1)/8]; +char wbuf[4096]; +char *wptr; + +Pcb pfrom, pto; + +int cflag; +int dflag; +int sflag; + +void complement(void); +void delete(void); +void squeeze(void); +void translit(void); +void error(char*); +long canon(Pcb*); +char *getrune(char*, Rune*); +void Pinit(Pcb*, char*); +void Prewind(Pcb *p); +int readrune(int, long*); +void wflush(int); +void writerune(int, Rune); + +void +main(int argc, char **argv) +{ + ARGBEGIN{ + case 's': sflag++; break; + case 'd': dflag++; break; + case 'c': cflag++; break; + default: error("bad option"); + }ARGEND + if(argc>0) + Pinit(&pfrom, argv[0]); + if(argc>1) + Pinit(&pto, argv[1]); + if(argc>2) + error("arg count"); + if(dflag) { + if ((sflag && argc != 2) || (!sflag && argc != 1)) + error("arg count"); + delete(); + } else { + if (argc != 2) + error("arg count"); + if (cflag) + complement(); + else translit(); + } + exits(0); +} + +void +delete(void) +{ + long c, last; + + if (cflag) { + memset((char *) f, 0xff, sizeof f); + while ((c = canon(&pfrom)) >= 0) + CLEARBIT(f, c); + } else { + while ((c = canon(&pfrom)) >= 0) + SETBIT(f, c); + } + if (sflag) { + while ((c = canon(&pto)) >= 0) + SETBIT(t, c); + } + + last = 0x10000; + while (readrune(0, &c) > 0) { + if(!BITSET(f, c) && (c != last || !BITSET(t,c))) { + last = c; + writerune(1, (Rune) c); + } + } + wflush(1); +} + +void +complement(void) +{ + Rune *p; + int i; + long from, to, lastc, high; + + lastc = 0; + high = 0; + while ((from = canon(&pfrom)) >= 0) { + if (from > high) high = from; + SETBIT(f, from); + } + while ((to = canon(&pto)) > 0) { + if (to > high) high = to; + SETBIT(t,to); + } + Prewind(&pto); + if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0) + error("can't allocate memory"); + for (i = 0; i <= high; i++){ + if (!BITSET(f,i)) { + if ((to = canon(&pto)) < 0) + to = lastc; + else lastc = to; + p[i] = to; + } + else p[i] = i; + } + if (sflag){ + lastc = 0x10000; + while (readrune(0, &from) > 0) { + if (from > high) + from = to; + else + from = p[from]; + if (from != lastc || !BITSET(t,from)) { + lastc = from; + writerune(1, (Rune) from); + } + } + + } else { + while (readrune(0, &from) > 0){ + if (from > high) + from = to; + else + from = p[from]; + writerune(1, (Rune) from); + } + } + wflush(1); +} + +void +translit(void) +{ + Rune *p; + int i; + long from, to, lastc, high; + + lastc = 0; + high = 0; + while ((from = canon(&pfrom)) >= 0) + if (from > high) high = from; + Prewind(&pfrom); + if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0) + error("can't allocate memory"); + for (i = 0; i <= high; i++) + p[i] = i; + while ((from = canon(&pfrom)) >= 0) { + if ((to = canon(&pto)) < 0) + to = lastc; + else lastc = to; + if (BITSET(f,from) && p[from] != to) + error("ambiguous translation"); + SETBIT(f,from); + p[from] = to; + SETBIT(t,to); + } + while ((to = canon(&pto)) >= 0) { + SETBIT(t,to); + } + if (sflag){ + lastc = 0x10000; + while (readrune(0, &from) > 0) { + if (from <= high) + from = p[from]; + if (from != lastc || !BITSET(t,from)) { + lastc = from; + writerune(1, (Rune) from); + } + } + + } else { + while (readrune(0, &from) > 0) { + if (from <= high) + from = p[from]; + writerune(1, (Rune) from); + } + } + wflush(1); +} + +int +readrune(int fd, long *rp) +{ + Rune r; + int j; + static int i, n; + static char buf[4096]; + + j = i; + for (;;) { + if (i >= n) { + wflush(1); + if (j != i) + memcpy(buf, buf+j, n-j); + i = n-j; + n = read(fd, &buf[i], sizeof(buf)-i); + if (n < 0) + error("read error"); + if (n == 0) + return 0; + j = 0; + n += i; + } + i++; + if (fullrune(&buf[j], i-j)) + break; + } + chartorune(&r, &buf[j]); + *rp = r; + return 1; +} + +void +writerune(int fd, Rune r) +{ + char buf[UTFmax]; + int n; + + if (!wptr) + wptr = wbuf; + n = runetochar(buf, (Rune*)&r); + if (wptr+n >= wbuf+sizeof(wbuf)) + wflush(fd); + memcpy(wptr, buf, n); + wptr += n; +} + +void +wflush(int fd) +{ + if (wptr && wptr > wbuf) + if (write(fd, wbuf, wptr-wbuf) != wptr-wbuf) + error("write error"); + wptr = wbuf; +} + +char * +getrune(char *s, Rune *rp) +{ + Rune r; + char *save; + int i, n; + + s += chartorune(rp, s); + if((r = *rp) == '\\' && *s){ + n = 0; + if (*s == 'x') { + s++; + for (i = 0; i < 4; i++) { + save = s; + s += chartorune(&r, s); + if ('0' <= r && r <= '9') + n = 16*n + r - '0'; + else if ('a' <= r && r <= 'f') + n = 16*n + r - 'a' + 10; + else if ('A' <= r && r <= 'F') + n = 16*n + r - 'A' + 10; + else { + if (i == 0) + *rp = 'x'; + else *rp = n; + return save; + } + } + } else { + for(i = 0; i < 3; i++) { + save = s; + s += chartorune(&r, s); + if('0' <= r && r <= '7') + n = 8*n + r - '0'; + else { + if (i == 0) + { + *rp = r; + return s; + } + *rp = n; + return save; + } + } + if(n > 0377) + error("char>0377"); + } + *rp = n; + } + return s; +} + +long +canon(Pcb *p) +{ + Rune r; + + if (p->final >= 0) { + if (p->last < p->final) + return ++p->last; + p->final = -1; + } + if (*p->current == '\0') + return -1; + if(*p->current == '-' && p->last >= 0 && p->current[1]){ + p->current = getrune(p->current+1, &r); + if (r < p->last) + error ("Invalid range specification"); + if (r > p->last) { + p->final = r; + return ++p->last; + } + } + p->current = getrune(p->current, &r); + p->last = r; + return p->last; +} + +void +Pinit(Pcb *p, char *cp) +{ + p->current = p->base = cp; + p->last = p->final = -1; +} +void +Prewind(Pcb *p) +{ + p->current = p->base; + p->last = p->final = -1; +} +void +error(char *s) +{ + fprint(2, "tr: %s\n", s); + exits(s); +} diff --git a/utils/va/a.h b/utils/va/a.h new file mode 100644 index 00000000..92199a08 --- /dev/null +++ b/utils/va/a.h @@ -0,0 +1,181 @@ +#include <lib9.h> +#include <bio.h> +#include "../vc/v.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Sym Sym; +typedef struct Gen Gen; +typedef struct Io Io; +typedef struct Hist Hist; + +#define MAXALIGN 7 +#define FPCHIP 1 +#define NSYMB 8192 +#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; + char* macro; + long value; + ushort type; + char *name; + char sym; +}; +#define S ((Sym*)0) + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char b[BUFSIZ]; + char* p; + short c; + short f; +}; +#define I ((Io*)0) + +EXTERN struct +{ + Sym* sym; + short type; +} h[NSYM]; + +struct Gen +{ + Sym* sym; + long offset; + short type; + short reg; + short name; + double dval; + char sval[8]; +}; + +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 nosched; +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* alloc(long); +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 pinit(char*); +void cclean(void); +int isreg(Gen*); +void outcode(int, Gen*, int, Gen*); +void zname(char*, int, int); +void zaddr(Gen*, 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 maclin(void); +void macprag(void); +void macif(int); +void macend(void); +void outhist(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*); + +/* + * system-dependent stuff from ../cc/compat.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); diff --git a/utils/va/a.y b/utils/va/a.y new file mode 100644 index 00000000..cbc07fd7 --- /dev/null +++ b/utils/va/a.y @@ -0,0 +1,588 @@ +%{ +#include "a.h" +%} +%union +{ + Sym *sym; + long lval; + double dval; + char sval[8]; + Gen gen; +} +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' +%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 +%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA +%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF +%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK +%token <lval> LCONST LSP LSB LFP LPC LHI LLO LMREG +%token <lval> LTYPEX LREG LFREG LFCREG LR LM LF +%token <lval> LFCR LSCHED +%token <dval> LFCONST +%token <sval> LSCONST +%token <sym> LNAME LLAB LVAR +%type <lval> con expr pointer offset sreg +%type <gen> gen vgen lgen vlgen rel reg freg mreg fcreg +%type <gen> imm ximm ireg name oreg imr nireg fgen +%% +prog: +| prog line + +line: + LLAB ':' + { + if($1->value != pc) + yyerror("redeclaration of %s", $1->name); + $1->value = pc; + } + line +| LNAME ':' + { + $1->type = LLAB; + $1->value = pc; + } + line +| LNAME '=' expr ';' + { + $1->type = LVAR; + $1->value = $3; + } +| LVAR '=' expr ';' + { + if($1->value != $3) + yyerror("redeclaration of %s", $1->name); + $1->value = $3; + } +| LSCHED ';' + { + nosched = $1; + } +| ';' +| inst ';' +| error ';' + +inst: +/* + * Immed-type + */ + LTYPE1 imr ',' sreg ',' reg + { + outcode($1, &$2, $4, &$6); + } +| LTYPE1 imr ',' reg + { + outcode($1, &$2, NREG, &$4); + } +/* + * NOR + */ +| LTYPE2 imr ',' sreg ',' imr + { + outcode($1, &$2, $4, &$6); + } +| LTYPE2 imr ',' imr + { + outcode($1, &$2, NREG, &$4); + } +/* + * LOAD/STORE, but not MOVW + */ +| LTYPE3 lgen ',' gen + { + if(!isreg(&$2) && !isreg(&$4)) + print("one side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +/* + * SPECIAL + */ +| LTYPE4 comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +/* + * MOVW + */ +| LTYPE5 vlgen ',' vgen + { + if(!isreg(&$2) && !isreg(&$4)) + print("one side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +/* + * MUL/DIV + */ +| LTYPE6 reg ',' sreg comma + { + outcode($1, &$2, $4, &nullgen); + } +| LTYPE6 reg ',' sreg ',' reg + { + outcode($1, &$2, $4, &$6); + } +/* + * JMP/JAL + */ +| LTYPE7 comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE7 comma nireg + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE8 comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE8 comma nireg + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPE8 sreg ',' nireg + { + outcode($1, &nullgen, $2, &$4); + } +/* + * BEQ/BNE + */ +| LTYPE9 gen ',' rel + { + if(!isreg(&$2)) + print("left side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +| LTYPE9 gen ',' sreg ',' rel + { + if(!isreg(&$2)) + print("left side must be register\n"); + outcode($1, &$2, $4, &$6); + } +/* + * B-other + */ +| LTYPEA gen ',' rel + { + if(!isreg(&$2)) + print("left side must be register\n"); + outcode($1, &$2, NREG, &$4); + } +/* + * TEXT/GLOBL + */ +| LTYPEB name ',' imm + { + outcode($1, &$2, NREG, &$4); + } +| LTYPEB name ',' con ',' imm + { + outcode($1, &$2, $4, &$6); + } +/* + * DATA + */ +| LTYPEC name '/' con ',' ximm + { + outcode($1, &$2, $4, &$6); + } +/* + * floating-type + */ +| LTYPED freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LTYPEE freg ',' freg + { + outcode($1, &$2, NREG, &$4); + } +| LTYPEE freg ',' LFREG ',' freg + { + outcode($1, &$2, $4, &$6); + } +| LTYPEF freg ',' LFREG comma + { + outcode($1, &$2, $4, &nullgen); + } +/* + * coprocessor branch + */ +| LTYPEG comma rel + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * word + */ +| LTYPEH comma ximm + { + outcode($1, &nullgen, NREG, &$3); + } +/* + * NOP + */ +| LTYPEI comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LTYPEI ',' vgen + { + outcode($1, &nullgen, NREG, &$3); + } +| LTYPEI vgen comma + { + outcode($1, &$2, NREG, &nullgen); + } +/* + * BREAK -- overloaded with CACHE opcode + */ +| LTYPEJ comma + { + outcode($1, &nullgen, NREG, &nullgen); + } +| LTYPEJ vgen ',' vgen + { + outcode($1, &$2, NREG, &$4); + } + +comma: +| ',' + +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; + } + +vlgen: + lgen +| fgen +| mreg +| fcreg +| LHI + { + $$ = nullgen; + $$.type = D_HI; + } +| LLO + { + $$ = nullgen; + $$.type = D_LO; + } + +vgen: + gen +| fgen +| mreg +| fcreg +| LHI + { + $$ = nullgen; + $$.type = D_HI; + } +| LLO + { + $$ = nullgen; + $$.type = D_LO; + } + +lgen: + gen +| ximm + +fgen: + freg + +mreg: + LMREG + { + $$ = nullgen; + $$.type = D_MREG; + $$.reg = $1; + } +| LM '(' con ')' + { + $$ = nullgen; + $$.type = D_MREG; + $$.reg = $3; + } + +fcreg: + LFCREG + { + $$ = nullgen; + $$.type = D_FCREG; + $$.reg = $1; + } +| LFCR '(' con ')' + { + $$ = nullgen; + $$.type = D_FCREG; + $$.reg = $3; + } + +freg: + LFREG + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $1; + } +| LF '(' con ')' + { + $$ = nullgen; + $$.type = D_FREG; + $$.reg = $3; + } + +ximm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } +| '$' oreg + { + $$ = $2; + $$.type = D_CONST; + } +| '$' '*' '$' oreg + { + $$ = $4; + $$.type = D_OCONST; + } +| '$' LSCONST + { + $$ = nullgen; + $$.type = D_SCONST; + memcpy($$.sval, $2, sizeof($$.sval)); + } +| '$' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = $2; + } +| '$' '-' LFCONST + { + $$ = nullgen; + $$.type = D_FCONST; + $$.dval = -$3; + } + +nireg: + ireg +| con ireg + { + if($1 != 0) + yyerror("offset must be zero"); + $$ = $2; + } +| name + { + $$ = $1; + if($1.name != D_EXTERN && $1.name != D_STATIC) { + } + } + +ireg: + '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } + +gen: + reg +| con + { + $$ = nullgen; + $$.type = D_OREG; + $$.offset = $1; + } +| oreg + +oreg: + name +| name '(' sreg ')' + { + $$ = $1; + $$.type = D_OREG; + $$.reg = $3; + } +| '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $2; + $$.offset = 0; + } +| con '(' sreg ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.reg = $3; + $$.offset = $1; + } + +imr: + reg +| imm + +imm: '$' con + { + $$ = nullgen; + $$.type = D_CONST; + $$.offset = $2; + } + +reg: + sreg + { + $$ = nullgen; + $$.type = D_REG; + $$.reg = $1; + } + +sreg: + LREG +| LR '(' con ')' + { + if($$ < 0 || $$ >= NREG) + print("register value out of range\n"); + $$ = $3; + } + +name: + con '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $3; + $$.sym = S; + $$.offset = $1; + } +| LNAME offset '(' pointer ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = $4; + $$.sym = $1; + $$.offset = $2; + } +| LNAME '<' '>' offset '(' LSB ')' + { + $$ = nullgen; + $$.type = D_OREG; + $$.name = D_STATIC; + $$.sym = $1; + $$.offset = $4; + } + +offset: + { + $$ = 0; + } +| '+' con + { + $$ = $2; + } +| '-' con + { + $$ = -$2; + } + +pointer: + LSB +| LSP +| LFP + +con: + LCONST +| LVAR + { + $$ = $1->value; + } +| '-' con + { + $$ = -$2; + } +| '+' con + { + $$ = $2; + } +| '~' con + { + $$ = ~$2; + } +| '(' expr ')' + { + $$ = $2; + } + +expr: + con +| expr '+' expr + { + $$ = $1 + $3; + } +| expr '-' expr + { + $$ = $1 - $3; + } +| expr '*' expr + { + $$ = $1 * $3; + } +| expr '/' expr + { + $$ = $1 / $3; + } +| expr '%' expr + { + $$ = $1 % $3; + } +| expr '<' '<' expr + { + $$ = $1 << $4; + } +| expr '>' '>' expr + { + $$ = $1 >> $4; + } +| expr '&' expr + { + $$ = $1 & $3; + } +| expr '^' expr + { + $$ = $1 ^ $3; + } +| expr '|' expr + { + $$ = $1 | $3; + } diff --git a/utils/va/l.s b/utils/va/l.s new file mode 100644 index 00000000..2f8e6341 --- /dev/null +++ b/utils/va/l.s @@ -0,0 +1,703 @@ +/* + * 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 MAXMACH 4 /* max # cpus system can run */ + +/* + * Time + */ +#define MS2HZ 50 /* millisec per clock tick */ +#define TK2SEC(t) ((t)/20) /* ticks to seconds */ +#define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */ +#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */ + +/* + * CP0 registers + */ + +#define INDEX 0 +#define RANDOM 1 +#define TLBPHYS 2 +#define CONTEXT 4 +#define BADVADDR 8 +#define TLBVIRT 10 +#define STATUS 12 +#define CAUSE 13 +#define EPC 14 +#define PRID 15 + +/* + * M(STATUS) bits + */ +#define IEC 0x00000001 +#define KUC 0x00000002 +#define IEP 0x00000004 +#define KUP 0x00000008 +#define INTMASK 0x0000ff00 +#define SW0 0x00000100 +#define SW1 0x00000200 +#define INTR0 0x00000400 +#define INTR1 0x00000800 +#define INTR2 0x00001000 +#define INTR3 0x00002000 +#define INTR4 0x00004000 +#define INTR5 0x00008000 +#define ISC 0x00010000 +#define SWC 0x00020000 +#define CU1 0x20000000 + +/* + * Traps + */ + +#define UTLBMISS (KSEG0+0x00) +#define EXCEPTION (KSEG0+0x80) + +/* + * Magic registers + */ + +#define MACH 25 /* R25 is m-> */ +#define USER 24 /* R24 is u-> */ +#define MPID 0xBF000000 /* long; low 3 bits identify mp bus slot */ +#define WBFLUSH 0xBC000000 /* D-CACHE data; used for write buffer flush */ + +/* + * Fundamental addresses + */ + +#define MACHADDR 0x80014000 +#define USERADDR 0xC0000000 +#define UREGADDR (USERADDR+BY2PG-4-0xA0) +/* + * MMU + */ + +#define KUSEG 0x00000000 +#define KSEG0 0x80000000 +#define KSEG1 0xA0000000 +#define KSEG2 0xC0000000 +#define KSEGM 0xE0000000 /* mask to check which seg */ + +#define PTEGLOBL (1<<8) +#define PTEVALID (1<<9) +#define PTEWRITE (1<<10) +#define PTEPID(n) ((n)<<6) + +#define NTLBPID 64 /* number of pids */ +#define NTLB 64 /* number of entries */ +#define TLBROFF 8 /* offset of first randomly indexed entry */ + +/* + * Address spaces + */ + +#define UZERO KUSEG /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define USTKTOP KZERO /* byte just beyond user stack */ +#define TSTKTOP (USERADDR+100*BY2PG) /* top of temporary stack */ +#define KZERO KSEG0 /* base of kernel address space */ +#define KTZERO (KSEG0+0x20000) /* first address in kernel text */ +#define USTACKSIZE (4*1024*1024) /* size of user stack */ +/* + * Exception codes + */ +#define CINT 0 /* external interrupt */ +#define CTLBM 1 /* TLB modification */ +#define CTLBL 2 /* TLB miss (load or fetch) */ +#define CTLBS 3 /* TLB miss (store) */ +#define CADREL 4 /* address error (load or fetch) */ +#define CADRES 5 /* address error (store) */ +#define CBUSI 6 /* bus error (fetch) */ +#define CBUSD 7 /* bus error (data load or store) */ +#define CSYS 8 /* system call */ +#define CBRK 9 /* breakpoint */ +#define CRES 10 /* reserved instruction */ +#define CCPU 11 /* coprocessor unusable */ +#define COVF 12 /* arithmetic overflow */ +#define CUNK13 13 /* undefined 13 */ +#define CUNK14 14 /* undefined 14 */ +#define CUNK15 15 /* undefined 15 */ + +#define NSEG 5 + +#define SP R29 + +#define PROM (KSEG1+0x1FC00000) +#define NOOP NOR R0,R0 +#define WAIT NOOP; NOOP + +/* + * Boot first processor + * - why is the processor number loaded from R0 ????? + */ +TEXT start(SB), $-4 + + MOVW $setR30(SB), R30 + MOVW $(CU1|INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 + MOVW R1, M(STATUS) + WAIT + + MOVW $(0x1C<<7), R1 + MOVW R1, FCR31 /* permit only inexact and underflow */ + NOOP + MOVD $0.5, F26 + SUBD F26, F26, F24 + ADDD F26, F26, F28 + ADDD F28, F28, F30 + + MOVD F24, F0 + MOVD F24, F2 + MOVD F24, F4 + MOVD F24, F6 + MOVD F24, F8 + MOVD F24, F10 + MOVD F24, F12 + MOVD F24, F14 + MOVD F24, F16 + MOVD F24, F18 + MOVD F24, F20 + MOVD F24, F22 + + MOVW $MACHADDR, R(MACH) + ADDU $(BY2PG-4), R(MACH), SP + MOVW $0, R(USER) + MOVW R0, 0(R(MACH)) + + MOVW $edata(SB), R1 + MOVW $end(SB), R2 + +clrbss: + MOVB $0, (R1) + ADDU $1, R1 + BNE R1, R2, clrbss + + MOVW R4, _argc(SB) + MOVW R5, _argv(SB) + MOVW R6, _env(SB) + JAL main(SB) + JMP (R0) + +/* + * Take first processor into user mode + * - argument is stack pointer to user + */ + +TEXT touser(SB), $-4 + + MOVW M(STATUS), R1 + OR $(KUP|IEP), R1 + MOVW R1, M(STATUS) + NOOP + MOVW 0(FP), SP + MOVW $(UTZERO+32), R26 /* header appears in text */ + RFE (R26) + +/* + * Bring subsequent processors on line + */ +TEXT newstart(SB), $0 + + MOVW $setR30(SB), R30 + MOVW $(INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 + MOVW R1, M(STATUS) + NOOP + MOVW $MACHADDR, R(MACH) + MOVB (MPID+3), R1 + AND $7, R1 + SLL $PGSHIFT, R1, R2 + ADDU R2, R(MACH) + ADDU $(BY2PG-4), R(MACH), SP + MOVW $0, R(USER) + MOVW R1, 0(R(MACH)) + JAL online(SB) + JMP (R0) + +TEXT firmware(SB), $0 + + MOVW $(PROM+0x18), R1 /**/ +/* MOVW $(PROM+0x00), R1 /**/ + JMP (R1) + +TEXT splhi(SB), $0 + + MOVW M(STATUS), R1 + AND $~IEC, R1, R2 + MOVW R2, M(STATUS) + NOOP + RET + +TEXT spllo(SB), $0 + + MOVW M(STATUS), R1 + OR $IEC, R1, R2 + MOVW R2, M(STATUS) + NOOP + RET + +TEXT splx(SB), $0 + + MOVW 0(FP), R1 + MOVW M(STATUS), R2 + AND $IEC, R1 + AND $~IEC, R2 + OR R2, R1 + MOVW R1, M(STATUS) + NOOP + RET + +TEXT wbflush(SB), $-4 + + MOVW $WBFLUSH, R1 + MOVW 0(R1), R1 + RET + +TEXT setlabel(SB), $0 + + MOVW 0(FP), R2 + MOVW $0, R1 + MOVW R31, 0(R2) + MOVW R29, 4(R2) + RET + +TEXT gotolabel(SB), $0 + + MOVW 0(FP), R2 + MOVW $1, R1 + MOVW 0(R2), R31 + MOVW 4(R2), R29 + RET + +TEXT gotopc(SB), $8 + + MOVW 0(FP), R7 /* save arguments for later */ + MOVW _argc(SB), R4 + MOVW _argv(SB), R5 + MOVW _env(SB), R6 + MOVW R0, 4(SP) + MOVW $(64*1024), R1 + MOVW R1, 8(SP) + JAL icflush(SB) + JMP (R7) + +TEXT puttlb(SB), $4 + + JAL splhi(SB) + MOVW 0(FP), R2 + MOVW 4(FP), R3 + MOVW R1, 4(SP) + MOVW R2, M(TLBVIRT) + MOVW R3, M(TLBPHYS) + NOOP + TLBP + NOOP + MOVW M(INDEX), R4 + BGEZ R4, index + TLBWR + NOOP + JAL splx(SB) + RET +index: + TLBWI + NOOP + JAL splx(SB) + RET + +TEXT puttlbx(SB), $0 + + MOVW 0(FP), R4 + MOVW 4(FP), R2 + MOVW 8(FP), R3 + SLL $8, R4 + MOVW R2, M(TLBVIRT) + MOVW R3, M(TLBPHYS) + MOVW R4, M(INDEX) + NOOP + TLBWI + NOOP + RET + +TEXT tlbp(SB), $0 + TLBP + NOOP + MOVW M(INDEX), R1 + RET + +TEXT tlbvirt(SB), $0 + TLBP + NOOP + MOVW M(TLBVIRT), R1 + RET + + +TEXT gettlb(SB), $0 + + MOVW 0(FP), R3 + MOVW 4(FP), R4 + SLL $8, R3 + MOVW R3, M(INDEX) + NOOP + TLBR + NOOP + MOVW M(TLBVIRT), R1 + MOVW M(TLBPHYS), R2 + NOOP + MOVW R1, 0(R4) + MOVW R2, 4(R4) + RET + +TEXT gettlbvirt(SB), $0 + + MOVW 0(FP), R3 + SLL $8, R3 + MOVW R3, M(INDEX) + NOOP + TLBR + NOOP + MOVW M(TLBVIRT), R1 + NOOP + RET + +TEXT vector80(SB), $-4 + + MOVW $exception(SB), R26 + JMP (R26) + +TEXT exception(SB), $-4 + + MOVW M(STATUS), R26 + AND $KUP, R26 + BEQ R26, waskernel + +wasuser: + MOVW SP, R26 + /* + * set kernel sp: ureg - ureg* - pc + * done in 2 steps because R30 is not set + * and the loader will make a literal + */ + MOVW $((UREGADDR-2*BY2WD) & 0xffff0000), SP + OR $((UREGADDR-2*BY2WD) & 0xffff), SP + MOVW R26, 0x10(SP) /* user SP */ + MOVW R31, 0x28(SP) + MOVW R30, 0x2C(SP) + MOVW M(CAUSE), R26 + MOVW R(MACH), 0x3C(SP) + MOVW R(USER), 0x40(SP) + AND $(0xF<<2), R26 + SUB $(CSYS<<2), R26 + + JAL saveregs(SB) + + MOVW $setR30(SB), R30 + SUBU $(UREGADDR-2*BY2WD-USERADDR), SP, R(USER) + MOVW $MPID, R1 + MOVB 3(R1), R1 + MOVW $MACHADDR, R(MACH) /* locn of mach 0 */ + AND $7, R1 + SLL $PGSHIFT, R1 + ADDU R1, R(MACH) /* add offset for mach # */ + + BNE R26, notsys + + JAL syscall(SB) + + MOVW 0x28(SP), R31 + MOVW 0x08(SP), R26 + MOVW 0x2C(SP), R30 + MOVW R26, M(STATUS) + NOOP + MOVW 0x0C(SP), R26 /* old pc */ + MOVW 0x10(SP), SP + RFE (R26) + +notsys: + JAL trap(SB) + +restore: + JAL restregs(SB) + MOVW 0x28(SP), R31 + MOVW 0x2C(SP), R30 + MOVW 0x3C(SP), R(MACH) + MOVW 0x40(SP), R(USER) + MOVW 0x10(SP), SP + RFE (R26) + +waskernel: + MOVW $1, R26 /* not sys call */ + MOVW SP, -0x90(SP) /* drop this if possible */ + SUB $0xA0, SP + MOVW R31, 0x28(SP) + JAL saveregs(SB) + JAL trap(SB) + JAL restregs(SB) + MOVW 0x28(SP), R31 + ADD $0xA0, SP + RFE (R26) + +TEXT saveregs(SB), $-4 + MOVW R1, 0x9C(SP) + MOVW R2, 0x98(SP) + ADDU $8, SP, R1 + MOVW R1, 0x04(SP) /* arg to base of regs */ + MOVW M(STATUS), R1 + MOVW M(EPC), R2 + MOVW R1, 0x08(SP) + MOVW R2, 0x0C(SP) + + BEQ R26, return /* sys call, don't save */ + + MOVW M(CAUSE), R1 + MOVW M(BADVADDR), R2 + MOVW R1, 0x14(SP) + MOVW M(TLBVIRT), R1 + MOVW R2, 0x18(SP) + MOVW R1, 0x1C(SP) + MOVW HI, R1 + MOVW LO, R2 + MOVW R1, 0x20(SP) + MOVW R2, 0x24(SP) + /* LINK,SB,SP missing */ + MOVW R28, 0x30(SP) + /* R27, R26 not saved */ + /* R25, R24 missing */ + MOVW R23, 0x44(SP) + MOVW R22, 0x48(SP) + MOVW R21, 0x4C(SP) + MOVW R20, 0x50(SP) + MOVW R19, 0x54(SP) + MOVW R18, 0x58(SP) + MOVW R17, 0x5C(SP) + MOVW R16, 0x60(SP) + MOVW R15, 0x64(SP) + MOVW R14, 0x68(SP) + MOVW R13, 0x6C(SP) + MOVW R12, 0x70(SP) + MOVW R11, 0x74(SP) + MOVW R10, 0x78(SP) + MOVW R9, 0x7C(SP) + MOVW R8, 0x80(SP) + MOVW R7, 0x84(SP) + MOVW R6, 0x88(SP) + MOVW R5, 0x8C(SP) + MOVW R4, 0x90(SP) + MOVW R3, 0x94(SP) +return: + RET + +TEXT restregs(SB), $-4 + /* LINK,SB,SP missing */ + MOVW 0x30(SP), R28 + /* R27, R26 not saved */ + /* R25, R24 missing */ + MOVW 0x44(SP), R23 + MOVW 0x48(SP), R22 + MOVW 0x4C(SP), R21 + MOVW 0x50(SP), R20 + MOVW 0x54(SP), R19 + MOVW 0x58(SP), R18 + MOVW 0x5C(SP), R17 + MOVW 0x60(SP), R16 + MOVW 0x64(SP), R15 + MOVW 0x68(SP), R14 + MOVW 0x6C(SP), R13 + MOVW 0x70(SP), R12 + MOVW 0x74(SP), R11 + MOVW 0x78(SP), R10 + MOVW 0x7C(SP), R9 + MOVW 0x80(SP), R8 + MOVW 0x84(SP), R7 + MOVW 0x88(SP), R6 + MOVW 0x8C(SP), R5 + MOVW 0x90(SP), R4 + MOVW 0x94(SP), R3 + MOVW 0x24(SP), R2 + MOVW 0x20(SP), R1 + MOVW R2, LO + MOVW R1, HI + MOVW 0x08(SP), R1 + MOVW 0x98(SP), R2 + MOVW R1, M(STATUS) + NOOP + MOVW 0x9C(SP), R1 + MOVW 0x0C(SP), R26 /* old pc */ + RET + +TEXT rfnote(SB), $0 + MOVW 0(FP), R26 /* 1st arg is &uregpointer */ + SUBU $(BY2WD), R26, SP /* pc hole */ + BNE R26, restore + + +TEXT clrfpintr(SB), $0 + MOVW FCR31, R1 + MOVW R1, R2 + AND $~(0x3F<<12), R2 + MOVW R2, FCR31 + RET + +TEXT savefpregs(SB), $0 + MOVW M(STATUS), R3 + MOVW 0(FP), R1 + MOVW FCR31, R2 + + MOVD F0, 0x00(R1) + MOVD F2, 0x08(R1) + MOVD F4, 0x10(R1) + MOVD F6, 0x18(R1) + MOVD F8, 0x20(R1) + MOVD F10, 0x28(R1) + MOVD F12, 0x30(R1) + MOVD F14, 0x38(R1) + MOVD F16, 0x40(R1) + MOVD F18, 0x48(R1) + MOVD F20, 0x50(R1) + MOVD F22, 0x58(R1) + MOVD F24, 0x60(R1) + MOVD F26, 0x68(R1) + MOVD F28, 0x70(R1) + MOVD F30, 0x78(R1) + + MOVW R2, 0x80(R1) + AND $~CU1, R3 + MOVW R3, M(STATUS) + RET + +TEXT restfpregs(SB), $0 + + MOVW M(STATUS), R3 + MOVW 0(FP), R1 + OR $CU1, R3 + MOVW R3, M(STATUS) + MOVW 0x80(R1), R2 + + MOVD 0x00(R1), F0 + MOVD 0x08(R1), F2 + MOVD 0x10(R1), F4 + MOVD 0x18(R1), F6 + MOVD 0x20(R1), F8 + MOVD 0x28(R1), F10 + MOVD 0x30(R1), F12 + MOVD 0x38(R1), F14 + MOVD 0x40(R1), F16 + MOVD 0x48(R1), F18 + MOVD 0x50(R1), F20 + MOVD 0x58(R1), F22 + MOVD 0x60(R1), F24 + MOVD 0x68(R1), F26 + MOVD 0x70(R1), F28 + MOVD 0x78(R1), F30 + + MOVW R2, FCR31 + AND $~CU1, R3 + MOVW R3, M(STATUS) + RET + +/* + * we avoid using R4, R5, R6, and R7 so gotopc can call us without saving them + */ +TEXT icflush(SB), $-4 /* icflush(physaddr, nbytes) */ + + MOVW M(STATUS), R10 + MOVW 0(FP), R8 + MOVW 4(FP), R9 + MOVW $KSEG0, R3 + OR R3, R8 + MOVW $0, M(STATUS) + MOVW $WBFLUSH, R1 /* wbflush */ + MOVW 0(R1), R1 + NOOP + MOVW $KSEG1, R3 + MOVW $icflush0(SB), R2 /* make sure PC is in uncached address space */ + MOVW $(SWC|ISC), R1 + OR R3, R2 + JMP (R2) + +TEXT icflush0(SB), $-4 + + MOVW R1, M(STATUS) /* swap and isolate cache, splhi */ + MOVW $icflush1(SB), R2 + JMP (R2) + +TEXT icflush1(SB), $-4 + +_icflush1: + MOVBU R0, 0x00(R8) + MOVBU R0, 0x04(R8) + MOVBU R0, 0x08(R8) + MOVBU R0, 0x0C(R8) + MOVBU R0, 0x10(R8) + MOVBU R0, 0x14(R8) + MOVBU R0, 0x18(R8) + MOVBU R0, 0x1C(R8) + MOVBU R0, 0x20(R8) + MOVBU R0, 0x24(R8) + MOVBU R0, 0x28(R8) + MOVBU R0, 0x2C(R8) + MOVBU R0, 0x30(R8) + MOVBU R0, 0x34(R8) + MOVBU R0, 0x38(R8) + MOVBU R0, 0x3C(R8) + SUB $0x40, R9 + ADD $0x40, R8 + BGTZ R9, _icflush1 + MOVW $icflush2(SB), R2 /* make sure PC is in uncached address space */ + OR R3, R2 + JMP (R2) + +TEXT icflush2(SB), $-4 + + MOVW $0, M(STATUS) /* swap back caches, de-isolate them, and stay splhi */ + NOOP /* +++ */ + MOVW R10, M(STATUS) + RET + +TEXT dcflush(SB), $-4 /* dcflush(physaddr, nbytes) */ + + MOVW M(STATUS), R6 + MOVW 0(FP), R4 + MOVW 4(FP), R5 + MOVW $KSEG0, R3 + OR R3, R4 + MOVW $0, M(STATUS) + MOVW $WBFLUSH, R1 + MOVW 0(R1), R1 + NOOP + MOVW $ISC, R1 + MOVW R1, M(STATUS) +_dcflush0: + MOVBU R0, 0x00(R4) + MOVBU R0, 0x04(R4) + MOVBU R0, 0x08(R4) + MOVBU R0, 0x0C(R4) + MOVBU R0, 0x10(R4) + MOVBU R0, 0x14(R4) + MOVBU R0, 0x18(R4) + MOVBU R0, 0x1C(R4) + MOVBU R0, 0x20(R4) + MOVBU R0, 0x24(R4) + MOVBU R0, 0x28(R4) + MOVBU R0, 0x2C(R4) + MOVBU R0, 0x30(R4) + MOVBU R0, 0x34(R4) + MOVBU R0, 0x38(R4) + MOVBU R0, 0x3C(R4) + SUB $0x40, R5 + ADD $0x40, R4 + BGTZ R5, _dcflush0 + MOVW $0, M(STATUS) + NOOP /* +++ */ + MOVW R6, M(STATUS) + RET diff --git a/utils/va/lex.c b/utils/va/lex.c new file mode 100644 index 00000000..fee14c2f --- /dev/null +++ b/utils/va/lex.c @@ -0,0 +1,697 @@ +#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 = 'v'; + thestring = "mips"; + 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, + "HI", LHI, D_HI, + "LO", LLO, D_LO, + + "R", LR, 0, + "R0", LREG, 0, + "R1", LREG, 1, + "R2", LREG, 2, + "R3", LREG, 3, + "R4", LREG, 4, + "R5", LREG, 5, + "R6", LREG, 6, + "R7", LREG, 7, + "R8", LREG, 8, + "R9", LREG, 9, + "R10", LREG, 10, + "R11", LREG, 11, + "R12", LREG, 12, + "R13", LREG, 13, + "R14", LREG, 14, + "R15", LREG, 15, + "R16", LREG, 16, + "R17", LREG, 17, + "R18", LREG, 18, + "R19", LREG, 19, + "R20", LREG, 20, + "R21", LREG, 21, + "R22", LREG, 22, + "R23", LREG, 23, + "R24", LREG, 24, + "R25", LREG, 25, + "R26", LREG, 26, + "R27", LREG, 27, + "R28", LREG, 28, + "R29", LREG, 29, + "R30", LREG, 30, + "R31", LREG, 31, + + "M", LM, 0, + "M0", LMREG, 0, + "M1", LMREG, 1, + "M2", LMREG, 2, + "M3", LMREG, 3, + "M4", LMREG, 4, + "M5", LMREG, 5, + "M6", LMREG, 6, + "M7", LMREG, 7, + "M8", LMREG, 8, + "M9", LMREG, 9, + "M10", LMREG, 10, + "M11", LMREG, 11, + "M12", LMREG, 12, + "M13", LMREG, 13, + "M14", LMREG, 14, + "M15", LMREG, 15, + "M16", LMREG, 16, + "M17", LMREG, 17, + "M18", LMREG, 18, + "M19", LMREG, 19, + "M20", LMREG, 20, + "M21", LMREG, 21, + "M22", LMREG, 22, + "M23", LMREG, 23, + "M24", LMREG, 24, + "M25", LMREG, 25, + "M26", LMREG, 26, + "M27", LMREG, 27, + "M28", LMREG, 28, + "M29", LMREG, 29, + "M30", LMREG, 30, + "M31", LMREG, 31, + + "F", LF, 0, + + "F0", LFREG, 0, + "F1", LFREG, 1, + "F2", LFREG, 2, + "F3", LFREG, 3, + "F4", LFREG, 4, + "F5", LFREG, 5, + "F6", LFREG, 6, + "F7", LFREG, 7, + "F8", LFREG, 8, + "F9", LFREG, 9, + "F10", LFREG, 10, + "F11", LFREG, 11, + "F12", LFREG, 12, + "F13", LFREG, 13, + "F14", LFREG, 14, + "F15", LFREG, 15, + "F16", LFREG, 16, + "F17", LFREG, 17, + "F18", LFREG, 18, + "F19", LFREG, 19, + "F20", LFREG, 20, + "F21", LFREG, 21, + "F22", LFREG, 22, + "F23", LFREG, 23, + "F24", LFREG, 24, + "F25", LFREG, 25, + "F26", LFREG, 26, + "F27", LFREG, 27, + "F28", LFREG, 28, + "F29", LFREG, 29, + "F30", LFREG, 30, + "F31", LFREG, 31, + + "FCR", LFCR, 0, + "FCR0", LFCREG, 0, + "FCR1", LFCREG, 1, + "FCR2", LFCREG, 2, + "FCR3", LFCREG, 3, + "FCR4", LFCREG, 4, + "FCR5", LFCREG, 5, + "FCR6", LFCREG, 6, + "FCR7", LFCREG, 7, + "FCR8", LFCREG, 8, + "FCR9", LFCREG, 9, + "FCR10", LFCREG, 10, + "FCR11", LFCREG, 11, + "FCR12", LFCREG, 12, + "FCR13", LFCREG, 13, + "FCR14", LFCREG, 14, + "FCR15", LFCREG, 15, + "FCR16", LFCREG, 16, + "FCR17", LFCREG, 17, + "FCR18", LFCREG, 18, + "FCR19", LFCREG, 19, + "FCR20", LFCREG, 20, + "FCR21", LFCREG, 21, + "FCR22", LFCREG, 22, + "FCR23", LFCREG, 23, + "FCR24", LFCREG, 24, + "FCR25", LFCREG, 25, + "FCR26", LFCREG, 26, + "FCR27", LFCREG, 27, + "FCR28", LFCREG, 28, + "FCR29", LFCREG, 29, + "FCR30", LFCREG, 30, + "FCR31", LFCREG, 31, + + "ADD", LTYPE1, AADD, + "ADDU", LTYPE1, AADDU, + "SUB", LTYPE1, ASUB, /* converted to ADD(-) in loader */ + "SUBU", LTYPE1, ASUBU, + "SGT", LTYPE1, ASGT, + "SGTU", LTYPE1, ASGTU, + "AND", LTYPE1, AAND, + "OR", LTYPE1, AOR, + "XOR", LTYPE1, AXOR, + "SLL", LTYPE1, ASLL, + "SRL", LTYPE1, ASRL, + "SRA", LTYPE1, ASRA, + + "ADDV", LTYPE1, AADDV, + "ADDVU", LTYPE1, AADDVU, + "SUBV", LTYPE1, ASUBV, /* converted to ADD(-) in loader */ + "SUBVU", LTYPE1, ASUBVU, + "SLLV", LTYPE1, ASLLV, + "SRLV", LTYPE1, ASRLV, + "SRAV", LTYPE1, ASRAV, + + "NOR", LTYPE2, ANOR, + + "MOVB", LTYPE3, AMOVB, + "MOVBU", LTYPE3, AMOVBU, + "MOVH", LTYPE3, AMOVH, + "MOVHU", LTYPE3, AMOVHU, + "MOVWL", LTYPE3, AMOVWL, + "MOVWR", LTYPE3, AMOVWR, + "MOVVL", LTYPE3, AMOVVL, + "MOVVR", LTYPE3, AMOVVR, + + "BREAK", LTYPEJ, ABREAK, /* overloaded CACHE opcode */ + "END", LTYPE4, AEND, + "REM", LTYPE6, AREM, + "REMU", LTYPE6, AREMU, + "RET", LTYPE4, ARET, + "SYSCALL", LTYPE4, ASYSCALL, + "TLBP", LTYPE4, ATLBP, + "TLBR", LTYPE4, ATLBR, + "TLBWI", LTYPE4, ATLBWI, + "TLBWR", LTYPE4, ATLBWR, + + "MOVW", LTYPE5, AMOVW, + "MOVV", LTYPE5, AMOVV, + "MOVD", LTYPE5, AMOVD, + "MOVF", LTYPE5, AMOVF, + + "DIV", LTYPE6, ADIV, + "DIVU", LTYPE6, ADIVU, + "MUL", LTYPE6, AMUL, + "MULU", LTYPE6, AMULU, + "DIVV", LTYPE6, ADIVV, + "DIVVU", LTYPE6, ADIVVU, + "MULV", LTYPE6, AMULV, + "MULVU", LTYPE6, AMULVU, + + "RFE", LTYPE7, ARFE, + "JMP", LTYPE7, AJMP, + + "JAL", LTYPE8, AJAL, + + "BEQ", LTYPE9, ABEQ, + "BNE", LTYPE9, ABNE, + + "BGEZ", LTYPEA, ABGEZ, + "BGEZAL", LTYPEA, ABGEZAL, + "BGTZ", LTYPEA, ABGTZ, + "BLEZ", LTYPEA, ABLEZ, + "BLTZ", LTYPEA, ABLTZ, + "BLTZAL", LTYPEA, ABLTZAL, + + "TEXT", LTYPEB, ATEXT, + "GLOBL", LTYPEB, AGLOBL, + + "DATA", LTYPEC, ADATA, + + "MOVDF", LTYPE5, AMOVDF, + "MOVDW", LTYPE5, AMOVDW, + "MOVFD", LTYPE5, AMOVFD, + "MOVFW", LTYPE5, AMOVFW, + "MOVWD", LTYPE5, AMOVWD, + "MOVWF", LTYPE5, AMOVWF, + + "ABSD", LTYPED, AABSD, + "ABSF", LTYPED, AABSF, + "ABSW", LTYPED, AABSW, + "NEGD", LTYPED, ANEGD, + "NEGF", LTYPED, ANEGF, + "NEGW", LTYPED, ANEGW, + + "CMPEQD", LTYPEF, ACMPEQD, + "CMPEQF", LTYPEF, ACMPEQF, + "CMPGED", LTYPEF, ACMPGED, + "CMPGEF", LTYPEF, ACMPGEF, + "CMPGTD", LTYPEF, ACMPGTD, + "CMPGTF", LTYPEF, ACMPGTF, + + "ADDD", LTYPEE, AADDD, + "ADDF", LTYPEE, AADDF, + "ADDW", LTYPEE, AADDW, + "DIVD", LTYPEE, ADIVD, + "DIVF", LTYPEE, ADIVF, + "DIVW", LTYPEE, ADIVW, + "MULD", LTYPEE, AMULD, + "MULF", LTYPEE, AMULF, + "MULW", LTYPEE, AMULW, + "SUBD", LTYPEE, ASUBD, + "SUBF", LTYPEE, ASUBF, + "SUBW", LTYPEE, ASUBW, + + "BFPT", LTYPEG, ABFPT, + "BFPF", LTYPEG, ABFPF, + + "WORD", LTYPEH, AWORD, + "NOP", LTYPEI, ANOP, + "SCHED", LSCHED, 0, + "NOSCHED", LSCHED, 0x80, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + + nullgen.sym = S; + nullgen.offset = 0; + nullgen.type = D_NONE; + nullgen.name = D_NONE; + nullgen.reg = NREG; + if(FPCHIP) + nullgen.dval = 0; + for(i=0; i<sizeof(nullgen.sval); i++) + nullgen.sval[i] = 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); + 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 +syminit(Sym *s) +{ + + s->type = LNAME; + s->value = 0; +} + +int +isreg(Gen *g) +{ + + USED(g); + return 1; +} + +void +cclean(void) +{ + + outcode(AEND, &nullgen, NREG, &nullgen); + Bflush(&obuf); +} + +void +zname(char *n, int t, int s) +{ + + Bputc(&obuf, ANAME); + 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; + char *n; + Ieee e; + + Bputc(&obuf, a->type); + Bputc(&obuf, a->reg); + Bputc(&obuf, s); + Bputc(&obuf, a->name); + switch(a->type) { + default: + print("unknown type %d\n", a->type); + exits("arg"); + + case D_NONE: + case D_REG: + case D_FREG: + case D_MREG: + case D_FCREG: + case D_LO: + case D_HI: + break; + + case D_OREG: + case D_CONST: + case D_OCONST: + case D_BRANCH: + l = a->offset; + Bputc(&obuf, l); + Bputc(&obuf, l>>8); + Bputc(&obuf, l>>16); + Bputc(&obuf, l>>24); + break; + + case D_SCONST: + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(&obuf, *n); + n++; + } + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + Bputc(&obuf, e.l); + Bputc(&obuf, e.l>>8); + Bputc(&obuf, e.l>>16); + Bputc(&obuf, e.l>>24); + Bputc(&obuf, e.h); + Bputc(&obuf, e.h>>8); + Bputc(&obuf, e.h>>16); + Bputc(&obuf, e.h>>24); + break; + } +} + +void +outcode(int a, Gen *g1, int reg, Gen *g2) +{ + int sf, st, t; + Sym *s; + + if(pass == 1) + goto out; +jackpot: + sf = 0; + s = g1->sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = g1->name; + 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->sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = g2->name; + 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, reg|nosched); + Bputc(&obuf, lineno); + Bputc(&obuf, lineno>>8); + Bputc(&obuf, lineno>>16); + Bputc(&obuf, lineno>>24); + zaddr(g1, sf); + zaddr(g2, 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, 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, 0); + 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" diff --git a/utils/va/mkfile b/utils/va/mkfile new file mode 100644 index 00000000..73604984 --- /dev/null +++ b/utils/va/mkfile @@ -0,0 +1,30 @@ +<../../mkconfig + +TARG=va + +OFILES=\ + y.tab.$O\ + lex.$O\ + +HFILES=\ + ../vc/v.out.h\ + y.tab.h\ + a.h\ + +YFILES=a.y\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +YFLAGS=-D1 -d +CFLAGS= $CFLAGS -I../include + +lex.$O: ../cc/macbody ../cc/lexbody + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/va/note b/utils/va/note new file mode 100644 index 00000000..f68e464f --- /dev/null +++ b/utils/va/note @@ -0,0 +1,51 @@ +gen address + +$con + type = D_CONST + offset = con + +$name+con(P) + type = D_CONST + offset = con + name = P + +$"xxx" + type = D_SCONST + +$1.0 + type = D_FCONST + +con + type = D_OREG + offset = con + +name+con(P) + type = D_OREG + offset = con + name = P + +con(R1) + type = D_OREG + offset = con + reg = 1 + +name+con(P)(R1) + type = D_OREG + offset = con + name = P + reg = 1 + +R1 + type = D_REG + reg = 1 + +MOVB[U] + LB[U], SB +MOVH[U] + LH[U], SB +MOVW[LR] + LW[LR], SW[LR] +MOVW + LW, SW, LUI, M[FT]HI, M[FT]LO +BREAK is synonym for CACHE. +operands make the difference. diff --git a/utils/vc/cgen.c b/utils/vc/cgen.c new file mode 100644 index 00000000..5d5262db --- /dev/null +++ b/utils/vc/cgen.c @@ -0,0 +1,1184 @@ +#include "gc.h" + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o; + long v, curs; + + 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(n->complex >= FNX) + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + switch(o) { + default: + diag(n, "unknown op in cgen: %O", o); + break; + + case OAS: + if(l->op == OBIT) + goto bitas; + if(l->addable >= INDEXED && l->complex < FNX) { + 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) { + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gopcode(OAS, &nod1, Z, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OADD: + case OSUB: + case OAND: + case OOR: + case OXOR: + case OLSHR: + case OASHL: + case OASHR: + /* + * immediate operands + */ + if(nn != Z) + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + cgen(l, nn); + if(r->vconst == 0) + if(o != OAND) + break; + if(nn != Z) + gopcode(o, r, Z, nn); + break; + } + + case OLMUL: + case OLDIV: + case OLMOD: + case OMUL: + case ODIV: + case OMOD: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(o == OMUL || o == OLMUL) { + if(mulcon(n, nn)) + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, &nod1, Z, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + gopcode(o, &nod, &nod1, &nod); + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + if(l->op == OBIT) + goto asbitop; + if(r->op == OCONST) + if(!typefd[r->type->etype]) + if(!typefd[n->type->etype]) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, r, nn); + gopcode(OAS, &nod2, Z, &nod); + gopcode(o, r, Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + } + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(l->complex >= r->complex) { + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } else { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + } + + regalloc(&nod, n, nn); + gmove(&nod2, &nod); + gopcode(o, &nod1, Z, &nod); + gmove(&nod, &nod2); + if(nn != Z) + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + 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); + gopcode(o, &nod3, Z, &nod4); + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + o = reg[REGARG]; + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gopcode(OFUNC, Z, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, Z, Z, l); + if(REGARG) + if(o != reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + } + 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); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type)) { + if(nocast(n->type, nn->type)) { + cgen(l, nn); + break; + } + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gopcode(OAS, &nod, Z, &nod1); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (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(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + regalloc(&nod1, l, Z); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, &nod, &nod1); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, &nod, &nod1); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), &nod, &nod1); + gopcode(OAS, &nod1, Z, &nod2); + + regfree(&nod); + regfree(&nod1); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(l->addable < INDEXED) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + + regalloc(&nod, l, nn); + gopcode(OAS, &nod2, Z, &nod); + if(typefd[l->type->etype]) { + regalloc(&nod3, l, Z); + if(v < 0) { + gopcode(OAS, nodfconst(-v), Z, &nod3); + gopcode(OSUB, &nod3, Z, &nod); + } else { + gopcode(OAS, nodfconst(v), Z, &nod3); + gopcode(OADD, &nod3, Z, &nod); + } + regfree(&nod3); + } else + gopcode(OADD, nodconst(v), Z, &nod); + gopcode(OAS, &nod, Z, &nod2); + + regfree(&nod); + if(l->addable < INDEXED) + regfree(&nod2); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gopcode(OAS, &nod, Z, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, nodconst(v), Z, &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + 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; + } + nod = *n; + nod.op = OADDR; + nod.left = n; + nod.right = Z; + nod.type = types[TIND]; + gopcode(OAS, &nod, Z, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, "boolgen"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + regalloc(&nod, n, nn); + cgen(n, &nod); + if(nn == Z || typefd[n->type->etype]) { + o = ONE; + if(true) + o = comrel[relindex(o)]; + if(typefd[n->type->etype]) { + nodreg(&nod1, n, NREG+FREGZERO); + gopcode(o, &nod, &nod1, Z); + } else + gopcode(o, &nod, Z, Z); + regfree(&nod); + goto com; + } + if(true) + gopcode(OCOND, &nod, nodconst(0), &nod); + else + gopcode(OCOND, nodconst(1), &nod, &nod); + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + break; + + 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(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gopcode(OAS, &nod, Z, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(nn != Z && !typefd[l->type->etype]) { + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + switch(o) { + case OEQ: + gopcode(OSUB, &nod1, &nod, &nod); + gopcode(OCOND, &nod, nodconst(0), &nod); + break; + case ONE: + gopcode(OSUB, &nod1, &nod, &nod); + gopcode(OCOND, nodconst(1), &nod, &nod); + break; + case OLE: + gopcode(OCOMMA, &nod1, &nod, &nod); + break; + case OGT: + gopcode(OCOMMA, &nod1, &nod, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OLT: + gopcode(OCOMMA, &nod, &nod1, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OGE: + gopcode(OCOMMA, &nod, &nod1, &nod); + break; + case OLS: + gopcode(OCOND, &nod1, &nod, &nod); + break; + case OHI: + gopcode(OCOND, &nod1, &nod, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OLO: + gopcode(OCOND, &nod, &nod1, &nod); + gopcode(OXOR, nodconst(1), &nod, &nod); + break; + case OHS: + gopcode(OCOND, &nod, &nod1, &nod); + break; + } + gopcode(OAS, &nod, Z, nn); + regfree(&nod); + regfree(&nod1); + break; + } + if(sconst(l)) { + switch(o) { + default: + if(l->vconst != 0) + break; + + case OGT: + case OHI: + case OLE: + case OLS: + regalloc(&nod, r, nn); + cgen(r, &nod); + gopcode(o, l, &nod, Z); + regfree(&nod); + goto com; + } + } + if(sconst(r)) { + switch(o) { + default: + if(r->vconst != 0) + break; + + case OGE: + case OHS: + case OLT: + case OLO: + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, &nod, r, Z); + regfree(&nod); + goto com; + } + } + if(l->complex >= r->complex) { + regalloc(&nod1, l, nn); + cgen(l, &nod1); + regalloc(&nod, r, Z); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l, Z); + cgen(l, &nod1); + } + gopcode(o, &nod1, &nod, Z); + regfree(&nod); + regfree(&nod1); + + com: + if(nn != Z) { + p1 = p; + gopcode(OAS, nodconst(1), Z, nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gopcode(OAS, nodconst(0), Z, nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *l, *r; + Type *t; + long pc1; + int i, m, c; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + nod1.xoffset += SZ_LONG; + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gopcode(OAS, nod32const(n->vconst), Z, &nod1); + else + gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); + + regfree(&nod1); + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn != Z) { + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + } + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && nn->complex >= FNX) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + gopcode(OAS, &nod2, Z, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = l; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + + 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; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) + return; + if(n->complex >= FNX && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gopcode(OAS, &nod1, Z, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + } else { + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = t; + + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod1, n, Z); + n->type = t; + } + + w /= SZ_LONG; + if(w <= 5) { + layout(&nod1, &nod2, w, 0, Z); + goto out; + } + + /* + * minimize space for unrolling loop + * 3,4,5 times. (6 or more is never minimum) + * if small structure, try 2 also. + */ + c = 0; /* set */ + m = 100; + i = 3; + if(w <= 15) + i = 2; + for(; i<=5; i++) + if(i + w%i <= m) { + c = i; + m = c + w%c; + } + + regalloc(&nod3, ®node, Z); + layout(&nod1, &nod2, w%c, w/c, &nod3); + + pc1 = pc; + layout(&nod1, &nod2, c, 0, Z); + + gopcode(OSUB, nodconst(1), Z, &nod3); + nod1.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1); + nod2.op = OREGISTER; + gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2); + + gopcode(OEQ, &nod3, Z, Z); + p->as = ABGTZ; + patch(p, pc1); + + regfree(&nod3); +out: + regfree(&nod1); + regfree(&nod2); +} + +void +layout(Node *f, Node *t, int c, int cv, Node *cn) +{ + Node t1, t2; + + while(c > 3) { + layout(f, t, 2, 0, Z); + c -= 2; + } + + regalloc(&t1, ®node, Z); + regalloc(&t2, ®node, Z); + t1.type = types[TLONG]; + t2.type = types[TLONG]; + if(c > 0) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(cn != Z) + gopcode(OAS, nodconst(cv), Z, cn); + if(c > 1) { + gopcode(OAS, f, Z, &t2); + f->xoffset += SZ_LONG; + } + if(c > 0) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, f, Z, &t1); + f->xoffset += SZ_LONG; + } + if(c > 1) { + gopcode(OAS, &t2, Z, t); + t->xoffset += SZ_LONG; + } + if(c > 2) { + gopcode(OAS, &t1, Z, t); + t->xoffset += SZ_LONG; + } + regfree(&t1); + regfree(&t2); +} diff --git a/utils/vc/enam.c b/utils/vc/enam.c new file mode 100644 index 00000000..f9c94f7f --- /dev/null +++ b/utils/vc/enam.c @@ -0,0 +1,118 @@ +char* anames[] = +{ + "XXX", + "ABSD", + "ABSF", + "ABSW", + "ADD", + "ADDD", + "ADDF", + "ADDU", + "ADDW", + "AND", + "BEQ", + "BFPF", + "BFPT", + "BGEZ", + "BGEZAL", + "BGTZ", + "BLEZ", + "BLTZ", + "BLTZAL", + "BNE", + "BREAK", + "CMPEQD", + "CMPEQF", + "CMPGED", + "CMPGEF", + "CMPGTD", + "CMPGTF", + "DATA", + "DIV", + "DIVD", + "DIVF", + "DIVU", + "DIVW", + "GLOBL", + "GOK", + "HISTORY", + "JAL", + "JMP", + "MOVB", + "MOVBU", + "MOVD", + "MOVDF", + "MOVDW", + "MOVF", + "MOVFD", + "MOVFW", + "MOVH", + "MOVHU", + "MOVW", + "MOVWD", + "MOVWF", + "MOVWL", + "MOVWR", + "MUL", + "MULD", + "MULF", + "MULU", + "MULW", + "NAME", + "NEGD", + "NEGF", + "NEGW", + "NOP", + "NOR", + "OR", + "REM", + "REMU", + "RET", + "RFE", + "SGT", + "SGTU", + "SLL", + "SRA", + "SRL", + "SUB", + "SUBD", + "SUBF", + "SUBU", + "SUBW", + "SYSCALL", + "TEXT", + "TLBP", + "TLBR", + "TLBWI", + "TLBWR", + "WORD", + "XOR", + "END", + "MOVV", + "MOVVL", + "MOVVR", + "SLLV", + "SRAV", + "SRLV", + "DIVV", + "DIVVU", + "REMV", + "REMVU", + "MULV", + "MULVU", + "ADDV", + "ADDVU", + "SUBV", + "SUBVU", + "DYNT", + "INIT", + "BCASE", + "CASE", + "TRUNCFV", + "TRUNCDV", + "TRUNCFW", + "TRUNCDW", + "MOVWU", + "SIGNAME", + "LAST", +}; diff --git a/utils/vc/gc.h b/utils/vc/gc.h new file mode 100644 index 00000000..c090af40 --- /dev/null +++ b/utils/vc/gc.h @@ -0,0 +1,331 @@ +#include "../cc/cc.h" +#include "../vc/v.out.h" + +/* + * vc/mips + * Mips 3000 + */ +#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 Multab Multab; +typedef struct Hintab Hintab; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + Ieee ieee; + + Sym* sym; + char type; + char reg; + char name; + char etype; +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + char as; + char reg; +}; +#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 Multab +{ + long val; + char code[20]; +}; + +struct Hintab +{ + ushort val; + char hint[10]; +}; + +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) + +#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 Multab multab[20]; +EXTERN int retok; +EXTERN int hintabsize; +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 char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[NREG+NREG]; +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 4 +#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 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[]; +extern Hintab hintab[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void xcom(Node*); +void bcomplex(Node*); +void usedset(Node*, int); + +/* + * cgen.c + */ +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +void layout(Node*, Node*, int, int, Node*); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nod32const(vlong); +Node* nodfconst(double); +void nodreg(Node*, 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 raddr(Node*, Prog*); +void naddr(Node*, Adr*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void gopcode(int, Node*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +int sval(long); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +int mulcon(Node*, Node*); +Multab* mulcon0(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 Nconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Adr*, int); +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 regzer(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 copyau1(Prog*, 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); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* diff --git a/utils/vc/list.c b/utils/vc/list.c new file mode 100644 index 00000000..f89b17ca --- /dev/null +++ b/utils/vc/list.c @@ -0,0 +1,244 @@ +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + fmtinstall('A', Aconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); + fmtinstall('B', Bconv); + fmtinstall('D', Dconv); +} + +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; + int a; + + p = va_arg(fp->args, Prog*); + a = p->as; + if(a == ADATA) + sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to); + else + if(p->reg == NREG) + sprint(str, " %A %D,%D", a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to); + else + sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + if(a->reg != NREG) + sprint(str, "$%N(R%d)", a, a->reg); + else + sprint(str, "$%N", a); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FCREG: + sprint(str, "FCR%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_LO: + sprint(str, "LO"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(LO)(REG)", a); + break; + + case D_HI: + sprint(str, "HI"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(HI)(REG)", a); + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_FCONST: + sprint(str, "$%.17e", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<NSNAME; i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + case '\r': + *p++ = 'r'; + continue; + case '\f': + *p++ = 'f'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + if(s == S) { + sprint(str, "%ld", a->offset); + goto out; + } + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } +out: + return fmtstrcpy(fp, str); +} diff --git a/utils/vc/mkenam b/utils/vc/mkenam new file mode 100644 index 00000000..f09ef75d --- /dev/null +++ b/utils/vc/mkenam @@ -0,0 +1,15 @@ +ed - ../vc/v.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/utils/vc/mkfile b/utils/vc/mkfile new file mode 100644 index 00000000..f17af88d --- /dev/null +++ b/utils/vc/mkfile @@ -0,0 +1,32 @@ +<../../mkconfig + +TARG=vc + +OFILES=\ + cgen.$O\ + enam.$O\ + list.$O\ + peep.$O\ + reg.$O\ + sgen.$O\ + swt.$O\ + txt.$O\ + mul.$O\ + +HFILES=\ + gc.h\ + v.out.h\ + ../cc/cc.h\ + +LIBS=cc bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +$ROOT/$OBJDIR/lib/libcc.a: + cd ../cc + mk $MKFLAGS install + mk $MKFLAGS clean diff --git a/utils/vc/mul.c b/utils/vc/mul.c new file mode 100644 index 00000000..3ef56cd5 --- /dev/null +++ b/utils/vc/mul.c @@ -0,0 +1,608 @@ +#include "gc.h" + +/* + * code sequences for multiply by constant. + * [a-l][0-3] + * lsl $(A-'a'),r0,r1 + * [+][0-7] + * add r0,r1,r2 + * [-][0-7] + * sub r0,r1,r2 + */ + +static int multabp; +static long mulval; +static char* mulcp; +static long valmax; +static int shmax; + +static int docode(char *hp, char *cp, int r0, int r1); +static int gen1(int len); +static int gen2(int len, long r1); +static int gen3(int len, long r0, long r1, int flag); +enum +{ + SR1 = 1<<0, /* r1 has been shifted */ + SR0 = 1<<1, /* r0 has been shifted */ + UR1 = 1<<2, /* r1 has not been used */ + UR0 = 1<<3, /* r0 has not been used */ +}; + +Multab* +mulcon0(long v) +{ + int a1, a2, g; + Multab *m, *m1; + char hint[10]; + + if(v < 0) + v = -v; + + /* + * look in cache + */ + m = multab; + for(g=0; g<nelem(multab); g++) { + if(m->val == v) { + if(m->code[0] == 0) + return 0; + return m; + } + m++; + } + + /* + * select a spot in cache to overwrite + */ + multabp++; + if(multabp < 0 || multabp >= nelem(multab)) + multabp = 0; + m = multab+multabp; + m->val = v; + mulval = v; + + /* + * look in execption hint table + */ + a1 = 0; + a2 = hintabsize; + for(;;) { + if(a1 >= a2) + goto no; + g = (a2 + a1)/2; + if(v < hintab[g].val) { + a2 = g; + continue; + } + if(v > hintab[g].val) { + a1 = g+1; + continue; + } + break; + } + + if(docode(hintab[g].hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + m->code[0] = 0; + return 0; + +no: + /* + * try to search + */ + hint[0] = 0; + for(g=1; g<=6; g++) { + if(g >= 6 && v >= 65535) + break; + mulcp = hint+g; + *mulcp = 0; + if(gen1(g)) { + if(docode(hint, m->code, 1, 0)) + return m; + print("multiply table failure %ld\n", v); + break; + } + } + + /* + * try a recur followed by a shift + */ + g = 0; + while(!(v & 1)) { + g++; + v >>= 1; + } + if(g) { + m1 = mulcon0(v); + if(m1) { + strcpy(m->code, m1->code); + sprint(strchr(m->code, 0), "%c0", g+'a'); + return m; + } + } + m->code[0] = 0; + return 0; +} + +static int +docode(char *hp, char *cp, int r0, int r1) +{ + int c, i; + + c = *hp++; + *cp = c; + cp += 2; + switch(c) { + default: + c -= 'a'; + if(c < 1 || c >= 30) + break; + for(i=0; i<4; i++) { + switch(i) { + case 0: + if(docode(hp, cp, r0<<c, r1)) + goto out; + break; + case 1: + if(docode(hp, cp, r1<<c, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r0, r0<<c)) + goto out; + break; + case 3: + if(docode(hp, cp, r0, r1<<c)) + goto out; + break; + } + } + break; + + case '+': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0+r1, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0+r1)) + goto out; + break; + } + } + break; + + case '-': + for(i=0; i<8; i++) { + cp[-1] = i+'0'; + switch(i) { + case 1: + if(docode(hp, cp, r0-r1, r1)) + goto out; + break; + case 2: + if(docode(hp, cp, r1-r0, r1)) + goto out; + break; + case 5: + if(docode(hp, cp, r0, r0-r1)) + goto out; + break; + case 6: + if(docode(hp, cp, r0, r1-r0)) + goto out; + break; + } + } + break; + + case 0: + if(r0 == mulval) + return 1; + } + return 0; + +out: + cp[-1] = i+'0'; + return 1; +} + +static int +gen1(int len) +{ + int i; + + for(shmax=1; shmax<30; shmax++) { + valmax = 1<<shmax; + if(valmax >= mulval) + break; + } + if(mulval == 1) + return 1; + + len--; + for(i=1; i<=shmax; i++) + if(gen2(len, 1<<i)) { + *--mulcp = 'a'+i; + return 1; + } + return 0; +} + +static int +gen2(int len, long r1) +{ + int i; + + if(len <= 0) { + if(r1 == mulval) + return 1; + return 0; + } + + len--; + if(len == 0) + goto calcr0; + + if(gen3(len, r1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, r1-1, r1, UR0)) { + i = '-'; + goto out; + } + if(gen3(len, 1, r1+1, UR1)) { + i = '+'; + goto out; + } + if(gen3(len, 1, r1-1, UR1)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + if(mulval == r1+1) { + i = '+'; + goto out; + } + if(mulval == r1-1) { + i = '-'; + goto out; + } + return 0; + +out: + *--mulcp = i; + return 1; +} + +static int +gen3(int len, long r0, long r1, int flag) +{ + int i, f1, f2; + long x; + + if(r0 <= 0 || + r0 >= r1 || + r1 > valmax) + return 0; + + len--; + if(len == 0) + goto calcr0; + + if(!(flag & UR1)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & UR0)) { + f1 = UR1|SR1; + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r1, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR1)) { + f1 = UR1|SR1|(flag&UR0); + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x > valmax) + break; + if(gen3(len, r0, x, f1)) { + i += 'a'; + goto out; + } + } + } + + if(!(flag & SR0)) { + f1 = UR0|SR0|(flag&(SR1|UR1)); + + f2 = UR1|SR1; + if(flag & UR1) + f2 |= UR0; + if(flag & SR1) + f2 |= SR0; + + for(i=1; i<=shmax; i++) { + x = r0<<i; + if(x > valmax) + break; + if(x > r1) { + if(gen3(len, r1, x, f2)) { + i += 'a'; + goto out; + } + } else + if(gen3(len, x, r1, f1)) { + i += 'a'; + goto out; + } + } + } + + x = r1+r0; + if(gen3(len, r0, x, UR1)) { + i = '+'; + goto out; + } + + if(gen3(len, r1, x, UR1)) { + i = '+'; + goto out; + } + + x = r1-r0; + if(gen3(len, x, r1, UR0)) { + i = '-'; + goto out; + } + + if(x > r0) { + if(gen3(len, r0, x, UR1)) { + i = '-'; + goto out; + } + } else + if(gen3(len, x, r0, UR0)) { + i = '-'; + goto out; + } + + return 0; + +calcr0: + f1 = flag & (UR0|UR1); + if(f1 == UR1) { + for(i=1; i<=shmax; i++) { + x = r1<<i; + if(x >= mulval) { + if(x == mulval) { + i += 'a'; + goto out; + } + break; + } + } + } + + if(mulval == r1+r0) { + i = '+'; + goto out; + } + if(mulval == r1-r0) { + i = '-'; + goto out; + } + + return 0; + +out: + *--mulcp = i; + return 1; +} + +/* + * hint table has numbers that + * the search algorithm fails on. + * <1000: + * all numbers + * <5000: + * ÷ by 5 + * <10000: + * ÷ by 50 + * <65536: + * ÷ by 250 + */ +Hintab hintab[] = +{ + 683, "b++d+e+", + 687, "b+e++e-", + 691, "b++d+e+", + 731, "b++d+e+", + 811, "b++d+i+", + 821, "b++e+e+", + 843, "b+d++e+", + 851, "b+f-+e-", + 853, "b++e+e+", + 877, "c++++g-", + 933, "b+c++g-", + 981, "c-+e-d+", + 1375, "b+c+b+h-", + 1675, "d+b++h+", + 2425, "c++f-e+", + 2675, "c+d++f-", + 2750, "b+d-b+h-", + 2775, "c-+g-e-", + 3125, "b++e+g+", + 3275, "b+c+g+e+", + 3350, "c++++i+", + 3475, "c-+e-f-", + 3525, "c-+d+g-", + 3625, "c-+e-j+", + 3675, "b+d+d+e+", + 3725, "b+d-+h+", + 3925, "b+d+f-d-", + 4275, "b+g++e+", + 4325, "b+h-+d+", + 4425, "b+b+g-j-", + 4525, "b+d-d+f+", + 4675, "c++d-g+", + 4775, "b+d+b+g-", + 4825, "c+c-+i-", + 4850, "c++++i-", + 4925, "b++e-g-", + 4975, "c+f++e-", + 5500, "b+g-c+d+", + 6700, "d+b++i+", + 9700, "d++++j-", + 11000, "b+f-c-h-", + 11750, "b+d+g+j-", + 12500, "b+c+e-k+", + 13250, "b+d+e-f+", + 13750, "b+h-c-d+", + 14250, "b+g-c+e-", + 14500, "c+f+j-d-", + 14750, "d-g--f+", + 16750, "b+e-d-n+", + 17750, "c+h-b+e+", + 18250, "d+b+h-d+", + 18750, "b+g-++f+", + 19250, "b+e+b+h+", + 19750, "b++h--f-", + 20250, "b+e-l-c+", + 20750, "c++bi+e-", + 21250, "b+i+l+c+", + 22000, "b+e+d-g-", + 22250, "b+d-h+k-", + 22750, "b+d-e-g+", + 23250, "b+c+h+e-", + 23500, "b+g-c-g-", + 23750, "b+g-b+h-", + 24250, "c++g+m-", + 24750, "b+e+e+j-", + 25000, "b++dh+g+", + 25250, "b+e+d-g-", + 25750, "b+e+b+j+", + 26250, "b+h+c+e+", + 26500, "b+h+c+g+", + 26750, "b+d+e+g-", + 27250, "b+e+e+f+", + 27500, "c-i-c-d+", + 27750, "b+bd++j+", + 28250, "d-d-++i-", + 28500, "c+c-h-e-", + 29000, "b+g-d-f+", + 29500, "c+h+++e-", + 29750, "b+g+f-c+", + 30250, "b+f-g-c+", + 33500, "c-f-d-n+", + 33750, "b+d-b+j-", + 34250, "c+e+++i+", + 35250, "e+b+d+k+", + 35500, "c+e+d-g-", + 35750, "c+i-++e+", + 36250, "b+bh-d+e+", + 36500, "c+c-h-e-", + 36750, "d+e--i+", + 37250, "b+g+g+b+", + 37500, "b+h-b+f+", + 37750, "c+be++j-", + 38500, "b+e+b+i+", + 38750, "d+i-b+d+", + 39250, "b+g-l-+d+", + 39500, "b+g-c+g-", + 39750, "b+bh-c+f-", + 40250, "b+bf+d+g-", + 40500, "b+g-c+g+", + 40750, "c+b+i-e+", + 41250, "d++bf+h+", + 41500, "b+j+c+d-", + 41750, "c+f+b+h-", + 42500, "c+h++g+", + 42750, "b+g+d-f-", + 43250, "b+l-e+d-", + 43750, "c+bd+h+f-", + 44000, "b+f+g-d-", + 44250, "b+d-g--f+", + 44500, "c+e+c+h+", + 44750, "b+e+d-h-", + 45250, "b++g+j-g+", + 45500, "c+d+e-g+", + 45750, "b+d-h-e-", + 46250, "c+bd++j+", + 46500, "b+d-c-j-", + 46750, "e-e-b+g-", + 47000, "b+c+d-j-", + 47250, "b+e+e-g-", + 47500, "b+g-c-h-", + 47750, "b+f-c+h-", + 48250, "d--h+n-", + 48500, "b+c-g+m-", + 48750, "b+e+e-g+", + 49500, "c-f+e+j-", + 49750, "c+c+g++f-", + 50000, "b+e+e+k+", + 50250, "b++i++g+", + 50500, "c+g+f-i+", + 50750, "b+e+d+k-", + 51500, "b+i+c-f+", + 51750, "b+bd+g-e-", + 52250, "b+d+g-j+", + 52500, "c+c+f+g+", + 52750, "b+c+e+i+", + 53000, "b+i+c+g+", + 53500, "c+g+g-n+", + 53750, "b+j+d-c+", + 54250, "b+d-g-j-", + 54500, "c-f+e+f+", + 54750, "b+f-+c+g+", + 55000, "b+g-d-g-", + 55250, "b+e+e+g+", + 55500, "b+cd++j+", + 55750, "b+bh-d-f-", + 56250, "c+d-b+j-", + 56500, "c+d+c+i+", + 56750, "b+e+d++h-", + 57000, "b+d+g-f+", + 57250, "b+f-m+d-", + 57750, "b+i+c+e-", + 58000, "b+e+d+h+", + 58250, "c+b+g+g+", + 58750, "d-e-j--e+", + 59000, "d-i-+e+", + 59250, "e--h-m+", + 59500, "c+c-h+f-", + 59750, "b+bh-e+i-", + 60250, "b+bh-e-e-", + 60500, "c+c-g-g-", + 60750, "b+e-l-e-", + 61250, "b+g-g-c+", + 61750, "b+g-c+g+", + 62250, "f--+c-i-", + 62750, "e+f--+g+", + 64750, "b+f+d+p-", +}; +int hintabsize = nelem(hintab); diff --git a/utils/vc/peep.c b/utils/vc/peep.c new file mode 100644 index 00000000..a9a43da4 --- /dev/null +++ b/utils/vc/peep.c @@ -0,0 +1,694 @@ +#include "gc.h" + +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; + } + } + +loop1: + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) + if(regtyp(&p->to)) { + if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + if(regzer(&p->from)) + if(p->to.type == D_REG) { + p->from.type = D_REG; + p->from.reg = 0; + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + /* + * look for MOVB x,R; MOVB R,R + */ + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == R) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; + p->reg = zprog.reg; /**/ +} + +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 +regzer(Adr *a) +{ + + if(a->type == D_CONST) + if(a->sym == S) + if(a->offset == 0) + return 1; + if(a->type == D_REG) + if(a->reg == 0) + return 1; + return 0; +} + +int +regtyp(Adr *a) +{ + + if(a->type == D_REG) { + if(a->reg != 0) + return 1; + return 0; + } + if(a->type == D_FREG) + 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 AJAL: + return 0; + + case ASGT: + case ASGTU: + + case AADD: + case AADDU: + case ASUB: + case ASUBU: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case AMULU: + case ADIV: + case ADIVU: + + case AADDD: + case AADDF: + case ASUBD: + case ASUBF: + case AMULD: + case AMULF: + case ADIVD: + case ADIVF: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) { + if(p->reg == NREG) + p->reg = p->to.reg; + goto gotit; + } + break; + + case AMOVF: + case AMOVD: + case AMOVW: + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +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("; %Drar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %Dset; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %Dused+set and f=%d; return 0\n", v2, f); + else + print("; %Dused and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub%D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %Dused+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %Dset and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * 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) + */ +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print(" (???)"); + return 2; + + + case ANOP: /* read, write */ + case AMOVW: + case AMOVF: + case AMOVD: + case AMOVH: + case AMOVHU: + case AMOVB: + case AMOVBU: + case AMOVDW: + case AMOVWD: + case AMOVFD: + case AMOVDF: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ASGT: /* read, read, write */ + case ASGTU: + + case AADD: + case AADDU: + case ASUB: + case ASUBU: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case ANOR: + case AAND: + case AXOR: + case AMUL: + case AMULU: + case ADIV: + case ADIVU: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: /* read, read */ + case ABNE: + case ABGTZ: + case ABGEZ: + case ABLTZ: + case ABLEZ: + + case ACMPEQD: + case ACMPEQF: + case ACMPGED: + case ACMPGEF: + case ACMPGTD: + case ACMPGTF: + case ABFPF: + case ABFPT: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub1(p, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + return 0; + + case 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 == D_REG) + if(v->reg == REGRET) + return 2; + if(v->type == D_FREG) + if(v->reg == FREGRET) + return 2; + + case AJAL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(REGARG && v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) + if(v->reg <= FREGEXT && v->reg > exfregoffset) + 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; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + } + return 0; +} + +int +a2type(Prog *p) +{ + + switch(p->as) { + case ABEQ: + case ABNE: + case ABGTZ: + case ABGEZ: + case ABLTZ: + case ABLEZ: + + case ASGT: + case ASGTU: + + case AADD: + case AADDU: + case ASUB: + case ASUBU: + case ASLL: + case ASRL: + case ASRA: + case AOR: + case AAND: + case AXOR: + case AMUL: + case AMULU: + case ADIV: + case ADIVU: + return D_REG; + + case ACMPEQD: + case ACMPEQF: + case ACMPGED: + case ACMPGEF: + case ACMPGTD: + case ACMPGTF: + + case AADDF: + case AADDD: + case ASUBF: + case ASUBD: + case AMULF: + case AMULD: + case ADIVF: + case ADIVD: + return D_FREG; + } + return D_NONE; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + + if(regtyp(v)) + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(v->type == D_REG) + if(a->type == D_OREG) + if(v->reg == a->reg) + return 1; + return 0; +} + +int +copyau1(Prog *p, Adr *v) +{ + + if(regtyp(v)) + if(p->from.type == v->type || p->to.type == v->type) + if(p->reg == v->reg) { + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau(a, v)) + a->reg = s->reg; + return 0; +} + +int +copysub1(Prog *p1, Adr *v, Adr *s, int f) +{ + + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} diff --git a/utils/vc/reg.c b/utils/vc/reg.c new file mode 100644 index 00000000..c0d294c9 --- /dev/null +++ b/utils/vc/reg.c @@ -0,0 +1,1148 @@ +#include "gc.h" + +void addsplits(void); + +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 = 0; + 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 ARFE: + r->p1 = R; + r1->s1 = R; + } + + /* + * left side always read + */ + bit = mkvar(&p->from, p->as==AMOVW); + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + + /* + * right side depends on opcode + */ + bit = mkvar(&p->to, 0); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown asop: %A", p->as); + break; + + /* + * right side write + */ + case ANOP: + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + case AMOVW: + case AMOVF: + case AMOVD: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case AJAL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + 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); + + /* + * 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; + + addsplits(); + + if(debug['R'] && debug['v']) { + print("\nprop 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->set.b[z] | + r->refahead.b[z] | r->calahead.b[z] | + r->refbehind.b[z] | r->calbehind.b[z] | + r->use1.b[z] | r->use2.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); + if(bany(&r->refahead)) + print(" ra=%B", r->refahead); + if(bany(&r->calahead)) + print(" ca=%B", r->calahead); + if(bany(&r->refbehind)) + print(" rb=%B", r->refbehind); + if(bany(&r->calbehind)) + print(" cb=%B", r->calbehind); + if(bany(&r->regdiff)) + print(" rd=%B", r->regdiff); + } + print("\n"); + } + } + + /* + * 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); + } + } + + for(r = firstr; r != R; r = r->link) + r->act = zbits; + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + 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']) { + if(rgp->regno >= NREG) + print("%L $%d F%d: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno-NREG, + bit); + else + print("%L $%d R%d: %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; + } +} + +void +addsplits(void) +{ + Reg *r, *r1; + int z, i; + Bits bit; + + for(r = firstr; r != R; r = r->link) { + if(r->loop > 1) + continue; + if(r->prog->as == AJAL) + continue; + for(r1 = r->p2; r1 != R; r1 = r1->p2link) { + if(r1->loop <= 1) + continue; + for(z=0; z<BITS; z++) + bit.b[z] = r1->calbehind.b[z] & + (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) & + ~(r->calahead.b[z] & addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + bit.b[i/32] &= ~(1L << (i%32)); + } + } + } +} + +/* + * 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->name = v->name; + a->offset = v->offset; + a->etype = v->etype; + a->type = D_OREG; + if(a->etype == TARRAY || a->sym == S) + a->type = D_CONST; + + p1->as = AMOVW; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVH; + if(v->etype == TFLOAT) + p1->as = AMOVF; + if(v->etype == TDOUBLE) + p1->as = AMOVD; + + p1->from.type = D_REG; + p1->from.reg = rn; + if(rn >= NREG) { + p1->from.type = D_FREG; + p1->from.reg = rn-NREG; + } + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } + if(v->etype == TUCHAR) + p1->as = AMOVBU; + if(v->etype == TUSHORT) + p1->as = AMOVHU; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +Bits +mkvar(Adr *a, int docon) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + t = a->type; + if(t == D_REG && a->reg != NREG) + regbits |= RtoB(a->reg); + if(t == D_FREG && a->reg != NREG) + regbits |= FtoB(a->reg); + s = a->sym; + o = a->offset; + et = a->etype; + if(s == S) { + if(t != D_CONST || !docon || a->reg != NREG) + goto none; + et = TLONG; + } + if(t == D_CONST) { + if(s == S && sval(o)) + goto none; + } + + n = a->name; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(s) + if(s->name[0] == '.') + goto none; + 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->etype = et; + v->name = n; + 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]; + if(t == D_CONST) { + if(s == S) { + for(z=0; z<BITS; z++) + consts.b[z] |= bit.b[z]; + return bit; + } + if(et != TARRAY) + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + return bit; + } + if(t == D_OREG) + 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 AJAL: + 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: + i = BtoF(~b); + if(i && r->cost >= 0) { + r->regno = i+NREG; + return FtoB(i); + } + 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(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(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(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 +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg; + + 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; + } + 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->name = D_NONE; + a->type = D_REG; + a->reg = rn; + if(rn >= NREG) { + a->type = D_FREG; + a->reg = rn-NREG; + } +} + +/* + * bit reg + * 0 R3 + * 1 R4 + * ... ... + * 19 R22 + * 20 R23 + */ +long +RtoB(int r) +{ + + if(r < 3 || r > 23) + return 0; + return 1L << (r-3); +} + +BtoR(long b) +{ + + b &= 0x001fffffL; + if(b == 0) + return 0; + return bitno(b) + 3; +} + +/* + * bit reg + * 22 F4 + * 23 F6 + * ... ... + * 31 F22 + */ +long +FtoB(int f) +{ + + if(f < 4 || f > 22 || (f&1)) + return 0; + return 1L << (f/2 + 20); +} + +int +BtoF(long b) +{ + + b &= 0xffc00000L; + if(b == 0) + return 0; + return bitno(b)*2 - 40; +} diff --git a/utils/vc/sgen.c b/utils/vc/sgen.c new file mode 100644 index 00000000..e4aa65e0 --- /dev/null +++ b/utils/vc/sgen.c @@ -0,0 +1,580 @@ +#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)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typesuv[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gopcode(OAS, &nod, Z, &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); + gopcode(OAS, &nod, Z, &nod1); + } + } + + 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); + gbranch(ORETURN); + + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); + + sp->to.offset += maxargsafe; +} + +void +gen(Node *n) +{ + Node *l, nod; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int 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); + 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->pc = 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; + } + gbranch(OGOTO); + if(n->pc) { + patch(p, n->pc); + 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); /* 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); + 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; + bcomplex(l); + 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 = D_REG; + p->to.reg = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = D_FREG; + p->to.reg = FREGRET; + } +} + +/* + * calculate addressability as follows + * CONST ==> 20 $value + * NAME ==> 10 name + * REGISTER ==> 11 register + * INDREG ==> 12 *[(reg)+offset] + * &10 ==> 2 $name + * ADD(2, 20) ==> 2 $name+offset + * ADD(3, 20) ==> 3 $(reg)+offset + * &12 ==> 3 $(reg)+offset + * *11 ==> 11 ?? + * *2 ==> 10 name + * *3 ==> 12 *(reg)+offset + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int t; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->addable = 0; + n->complex = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + return; + + case OREGISTER: + n->addable = 11; + return; + + case OINDREG: + n->addable = 12; + return; + + case ONAME: + n->addable = 10; + return; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 2; + if(l->addable == 12) + n->addable = 3; + break; + + case OIND: + xcom(l); + if(l->addable == 11) + n->addable = 12; + if(l->addable == 3) + n->addable = 12; + if(l->addable == 2) + n->addable = 10; + break; + + case OADD: + xcom(l); + xcom(r); + if(l->addable == 20) { + if(r->addable == 2) + n->addable = 2; + if(r->addable == 3) + n->addable = 3; + } + if(r->addable == 20) { + if(l->addable == 2) + n->addable = 2; + if(l->addable == 3) + n->addable = 3; + } + break; + + case OASLMUL: + case OASMUL: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASASHL; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + t = vlog(l); + if(t >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + } + t = vlog(r); + if(t >= 0) { + n->op = OASHL; + r->vconst = t; + r->type = types[TINT]; + simplifyshift(n); + } + break; + + case OASLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASLSHR; + r->vconst = t; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OLSHR; + r->vconst = t; + r->type = types[TINT]; + simplifyshift(n); + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + t = vlog(r); + if(t >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + xcom(l); + xcom(r); + simplifyshift(n); + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } + if(n->addable >= 10) + return; + + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + case OFUNC: + n->complex = FNX; + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + case OEQ: + case ONE: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + } +} + +void +bcomplex(Node *n) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type != T) { + bool64(n); + boolgen(n, 1, Z); + } else + gbranch(OGOTO); +} diff --git a/utils/vc/swt.c b/utils/vc/swt.c new file mode 100644 index 00000000..0ec09b39 --- /dev/null +++ b/utils/vc/swt.c @@ -0,0 +1,717 @@ +#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; + Node tn; + + 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); + regalloc(&tn, ®node, Z); + swit1(iq, nc, def, n, &tn); + regfree(&tn); +} + +void +swit1(C1 *q, int nc, long def, Node *n, Node *tn) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; i<nc; i++) { + if(debug['W']) + print("case = %.8lux\n", q->val); + gmove(nodconst(q->val), tn); + gopcode(OEQ, n, tn, Z); + 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); + gmove(nodconst(r->val), tn); + gopcode(OLT, tn, n, Z); + sp = p; + gopcode(OEQ, n, tn, Z); + patch(p, r->label); + swit1(q, i, def, n, tn); + + if(debug['W']) + print("case < %.8lux\n", r->val); + patch(sp, pc); + swit1(r+1, nc-i-1, def, n, tn); +} + +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); + gopcode(OAS, n2, Z, n3); + gopcode(OAS, n3, Z, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, nodconst(sh), Z, n1); + else + gopcode(OASHR, nodconst(sh), Z, n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod, *l; + int sh; + + /* + * n1 has adjusted/masked value + * n2 has address of cell + * n3 has contents of cell + */ + l = b->left; + regalloc(&nod, l, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, nodconst(v), Z, n1); + gopcode(OAS, n1, Z, &nod); + if(nn != Z) + gopcode(OAS, n1, Z, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, nodconst(sh), Z, &nod); + v <<= sh; + gopcode(OAND, nodconst(~v), Z, n3); + gopcode(OOR, n3, Z, &nod); + gopcode(OAS, &nod, Z, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, nodconst(0L)); + p->from.offset += nstring - NSNAME; + p->reg = NSNAME; + p->to.type = D_SCONST; + memmove(p->to.sval, string, NSNAME); + mnstring = 0; + } + n--; + } + return r; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + 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; +} + +int +mulcon(Node *n, Node *nn) +{ + Node *l, *r, nod1, nod2; + Multab *m; + long v; + int o; + char code[sizeof(m->code)+2], *p; + + if(typefd[n->type->etype]) + return 0; + l = n->left; + r = n->right; + if(l->op == OCONST) { + l = r; + r = n->left; + } + if(r->op != OCONST) + return 0; + v = convvtox(r->vconst, n->type->etype); + if(v != r->vconst) { + if(debug['M']) + print("%L multiply conv: %lld\n", n->lineno, r->vconst); + return 0; + } + m = mulcon0(v); + if(!m) { + if(debug['M']) + print("%L multiply table: %lld\n", n->lineno, r->vconst); + return 0; + } + if(debug['M'] && debug['v']) + print("%L multiply: %ld\n", n->lineno, v); + + memmove(code, m->code, sizeof(m->code)); + code[sizeof(m->code)] = 0; + + p = code; + if(p[1] == 'i') + p += 2; + regalloc(&nod1, n, nn); + cgen(l, &nod1); + if(v < 0) + gopcode(OSUB, &nod1, nodconst(0), &nod1); + regalloc(&nod2, n, Z); + +loop: + switch(*p) { + case 0: + regfree(&nod2); + gopcode(OAS, &nod1, Z, nn); + regfree(&nod1); + return 1; + case '+': + o = OADD; + goto addsub; + case '-': + o = OSUB; + addsub: /* number is r,n,l */ + v = p[1] - '0'; + r = &nod1; + if(v&4) + r = &nod2; + n = &nod1; + if(v&2) + n = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + gopcode(o, l, n, r); + break; + default: /* op is shiftcount, number is r,l */ + v = p[1] - '0'; + r = &nod1; + if(v&2) + r = &nod2; + l = &nod1; + if(v&1) + l = &nod2; + v = *p - 'a'; + if(v < 0 || v >= 32) { + diag(n, "mulcon unknown op: %c%c", p[0], p[1]); + break; + } + gopcode(OASHL, nodconst(v), l, r); + break; + } + p += 2; + goto loop; +} + +void +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(0)); + p->from.offset += o+e; + p->reg = 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]) { + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + else + gpseudo(ADATA, s, nod32const(a->vconst)); + p->from.offset += o; + p->reg = 4; + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + gpseudo(ADATA, s, nod32const(a->vconst)); + else + gpseudo(ADATA, s, nod32const(a->vconst>>32)); + p->from.offset += o + 4; + p->reg = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->reg = w; + if(p->to.type == D_OREG) + p->to.type = D_CONST; +} + +void zname(Biobuf*, Sym*, int); +char* zaddr(char*, Adr*, int); +void zwrite(Biobuf*, Prog*, int, int); +void outhist(Biobuf*); + +void +zwrite(Biobuf *b, Prog *p, int sf, int st) +{ + char bf[100], *bp; + + bf[0] = p->as; + bf[1] = p->reg; + bf[2] = p->lineno; + bf[3] = p->lineno>>8; + bf[4] = p->lineno>>16; + bf[5] = p->lineno>>24; + bp = zaddr(bf+6, &p->from, sf); + bp = zaddr(bp, &p->to, st); + Bwrite(b, bf, bp-bf); +} + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int sf, st, t, sym; + + 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++; + } + } + outhist(&outbuf); + 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.name; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&outbuf, 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.name; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&outbuf, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + zwrite(&outbuf, p, sf, st); + } + 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, 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; + + zwrite(b, &pg, 0, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n, bf[7]; + ulong sig; + + n = s->name; + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + bf[0] = ASIGNAME; + bf[1] = sig; + bf[2] = sig>>8; + bf[3] = sig>>16; + bf[4] = sig>>24; + bf[5] = t; + bf[6] = s->sym; + Bwrite(b, bf, 7); + s->sig = SIGDONE; + } + else{ + bf[0] = ANAME; + bf[1] = t; /* type */ + bf[2] = s->sym; /* sym */ + Bwrite(b, bf, 3); + } + Bwrite(b, n, strlen(n)+1); +} + +char* +zaddr(char *bp, Adr *a, int s) +{ + long l; + Ieee e; + + bp[0] = a->type; + bp[1] = a->reg; + bp[2] = s; + bp[3] = a->name; + bp += 4; + switch(a->type) { + default: + diag(Z, "unknown type %d in zaddr", a->type); + + case D_NONE: + case D_REG: + case D_FREG: + case D_MREG: + case D_FCREG: + case D_LO: + case D_HI: + break; + + case D_OREG: + case D_CONST: + case D_BRANCH: + l = a->offset; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + + case D_SCONST: + memmove(bp, a->sval, NSNAME); + bp += NSNAME; + break; + + case D_FCONST: + ieeedtod(&e, a->dval); + l = e.l; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + l = e.h; + bp[0] = l; + bp[1] = l>>8; + bp[2] = l>>16; + bp[3] = l>>24; + bp += 4; + break; + } + return bp; +} + +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; + 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; + 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; + } + o += SZ_LONG - w; /* big endian adjustment */ + w = 1; + 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; +} diff --git a/utils/vc/txt.c b/utils/vc/txt.c new file mode 100644 index 00000000..3ff08b93 --- /dev/null +++ b/utils/vc/txt.c @@ -0,0 +1,1440 @@ +#include "gc.h" + +void +ginit(void) +{ + int i; + Type *t; + + thechar = 'v'; + thestring = "mips"; + exregoffset = REGEXT; + exfregoffset = FREGEXT; + 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.reg = NREG; + zprog.from.type = D_NONE; + zprog.from.name = D_NONE; + zprog.from.reg = NREG; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMP; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + 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] = 0; + if(i == REGZERO || + (i >= NREG && ((i-NREG)&1))) + reg[i] = 1; + } +} + +void +gclean(void) +{ + int i; + Sym *s; + + for(i=0; i<NREG; i++) + if(i != REGZERO) + if(reg[i]) + diag(Z, "reg %d left allocated", i); + for(i=NREG; i<NREG+NREG; i+=2) + if(reg[i]) + diag(Z, "freg %d left allocated", i-NREG); + while(mnstring) + outstring("", 1L); + symstring->type->width = nstring; + symrathole->type->width = nrathole; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type == T) + continue; + if(s->type->width == 0) + continue; + if(s->class != CGLOBL && s->class != CSTATIC) + continue; + if(s->type == types[TENUM]) + continue; + gpseudo(AGLOBL, s, nodconst(s->type->width)); + } + nextpc(); + p->as = AEND; + outcode(); +} + +void +nextpc(void) +{ + + 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; +} + +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(typesuv[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 && typechlp[n->type->etype]) { + regaalloc1(tn1, n); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + return; + } + if(vconst(n) == 0) { + regaalloc(tn2, n); + gopcode(OAS, n, Z, tn2); + return; + } + regalloc(tn1, n, Z); + if(n->complex >= FNX) { + cgen(*fnxp, tn1); + (*fnxp)++; + } else + cgen(n, tn1); + regaalloc(tn2, n); + gopcode(OAS, tn1, Z, tn2); + regfree(tn1); +} + +Node* +nodconst(long v) +{ + constnode.vconst = v; + return &constnode; +} + +Node* +nod32const(vlong v) +{ + constnode.vconst = v & MASK(32); + return &constnode; +} + +Node* +nodfconst(double d) +{ + fconstnode.fconst = d; + return &fconstnode; +} + +void +nodreg(Node *n, Node *nn, int reg) +{ + *n = regnode; + n->reg = reg; + n->type = nn->type; + n->lineno = nn->lineno; +} + +void +regret(Node *n, Node *nn) +{ + int r; + + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; +} + +int +tmpreg(void) +{ + int i; + + for(i=REGRET+1; i<NREG; i++) + if(reg[i] == 0) + return i; + diag(Z, "out of fixed registers"); + return 0; +} + +void +regalloc(Node *n, Node *tn, Node *o) +{ + int i, j; + static int lasti; + + switch(tn->type->etype) { + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i > 0 && i < NREG) + goto out; + } + j = lasti + REGRET+1; + for(i=REGRET+1; i<NREG; i++) { + if(j >= NREG) + j = REGRET+1; + if(reg[j] == 0) { + i = j; + goto out; + } + j++; + } + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + case TVLONG: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= NREG && i < NREG+NREG) + goto out; + } + j = 0*2 + NREG; + for(i=NREG; i<NREG+NREG; i+=2) { + if(j >= NREG+NREG) + j = NREG; + if(reg[j] == 0) { + i = j; + goto out; + } + j += 2; + } + diag(tn, "out of float registers"); + goto err; + } + diag(tn, "unknown type in regalloc: %T", tn->type); +err: + nodreg(n, tn, 0); + return; +out: + reg[i]++; + lasti++; + if(lasti >= 5) + lasti = 0; + nodreg(n, tn, i); +} + +void +regialloc(Node *n, Node *tn, Node *o) +{ + Node nod; + + nod = *tn; + nod.type = types[TIND]; + regalloc(n, &nod, o); +} + +void +regfree(Node *n) +{ + int i; + + i = 0; + if(n->op != OREGISTER && n->op != OINDREG) + goto err; + i = n->reg; + if(i < 0 || i >= sizeof(reg)) + goto err; + if(reg[i] <= 0) + goto err; + reg[i]--; + return; +err: + diag(n, "error in regfree: %d", i); +} + +void +regsalloc(Node *n, Node *nn) +{ + cursafe = align(cursafe, nn->type, Aaut3); + 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 + SZ_LONG; + 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 +raddr(Node *n, Prog *p) +{ + Adr a; + + naddr(n, &a); + if(a.type == D_CONST && a.offset == 0) { + a.type = D_REG; + a.reg = 0; + } + if(a.type != D_REG && a.type != D_FREG) { + if(n) + diag(n, "bad in raddr: %O", n->op); + else + diag(n, "bad in raddr: <null>"); + p->reg = NREG; + } else + p->reg = a.reg; +} + +void +naddr(Node *n, Adr *a) +{ + long v; + + a->type = D_NONE; + if(n == Z) + return; + switch(n->op) { + default: + bad: + diag(n, "bad in naddr: %O", n->op); + break; + + case OREGISTER: + a->type = D_REG; + a->sym = S; + a->reg = n->reg; + if(a->reg >= NREG) { + a->type = D_FREG; + a->reg -= NREG; + } + break; + + case OIND: + naddr(n->left, a); + if(a->type == D_REG) { + a->type = D_OREG; + break; + } + if(a->type == D_CONST) { + a->type = D_OREG; + break; + } + goto bad; + + case OINDREG: + a->type = D_OREG; + a->sym = S; + a->offset = n->xoffset; + a->reg = n->reg; + break; + + case ONAME: + a->etype = n->etype; + a->type = D_OREG; + a->name = D_STATIC; + a->sym = n->sym; + a->offset = n->xoffset; + if(n->class == CSTATIC) + break; + if(n->class == CEXTERN || n->class == CGLOBL) { + a->name = D_EXTERN; + break; + } + if(n->class == CAUTO) { + a->name = D_AUTO; + break; + } + if(n->class == CPARAM) { + a->name = D_PARAM; + break; + } + goto bad; + + case OCONST: + a->sym = S; + a->reg = NREG; + if(typefd[n->type->etype]) { + a->type = D_FCONST; + a->dval = n->fconst; + } else { + a->type = D_CONST; + a->offset = n->vconst; + } + break; + + case OADDR: + naddr(n->left, a); + if(a->type == D_OREG) { + a->type = D_CONST; + break; + } + goto bad; + + case OADD: + if(n->left->op == OCONST) { + naddr(n->left, a); + v = a->offset; + naddr(n->right, a); + } else { + naddr(n->right, a); + v = a->offset; + naddr(n->left, a); + } + a->offset += v; + break; + + } +} + +void +fop(int as, int f1, int f2, Node *t) +{ + Node nod1, nod2, nod3; + + nodreg(&nod1, t, NREG+f1); + nodreg(&nod2, t, NREG+f2); + regalloc(&nod3, t, t); + gopcode(as, &nod1, &nod2, &nod3); + gmove(&nod3, t); + regfree(&nod3); +} + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod, nod1, nod2; + Prog *p1; + double d; + + ft = f->type->etype; + tt = t->type->etype; + + if(ft == TDOUBLE && f->op == OCONST) { + d = f->fconst; + if(d == 0.0) { + a = FREGZERO; + goto ffreg; + } + if(d == 0.5) { + a = FREGHALF; + goto ffreg; + } + if(d == 1.0) { + a = FREGONE; + goto ffreg; + } + if(d == 2.0) { + a = FREGTWO; + goto ffreg; + } + if(d == -.5) { + fop(OSUB, FREGHALF, FREGZERO, t); + return; + } + if(d == -1.0) { + fop(OSUB, FREGONE, FREGZERO, t); + return; + } + if(d == -2.0) { + fop(OSUB, FREGTWO, FREGZERO, t); + return; + } + if(d == 1.5) { + fop(OADD, FREGONE, FREGHALF, t); + return; + } + if(d == 2.5) { + fop(OADD, FREGTWO, FREGHALF, t); + return; + } + if(d == 3.0) { + fop(OADD, FREGTWO, FREGONE, t); + return; + } + } + if(ft == TFLOAT && f->op == OCONST) { + d = f->fconst; + if(d == 0) { + a = FREGZERO; + ffreg: + nodreg(&nod, f, NREG+a); + gmove(&nod, t); + return; + } + } + /* + * a load -- + * put it into a register then + * worry what to do with it. + */ + if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { + switch(ft) { + default: + if(typefd[tt]) { + /* special case can load mem to Freg */ + regalloc(&nod, t, t); + gins(AMOVW, f, &nod); + a = AMOVWD; + if(tt == TFLOAT) + a = AMOVWF; + gins(a, &nod, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + a = AMOVW; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + case TCHAR: + a = AMOVB; + break; + case TUCHAR: + a = AMOVBU; + break; + case TSHORT: + a = AMOVH; + break; + case TUSHORT: + a = AMOVHU; + break; + } + if(typechlp[ft] && typeilp[tt]) + regalloc(&nod, t, t); + else + regalloc(&nod, f, t); + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + } + + /* + * a store -- + * put it into a register then + * store it. + */ + if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { + switch(tt) { + default: + a = AMOVW; + break; + case TUCHAR: + a = AMOVBU; + break; + case TCHAR: + a = AMOVB; + break; + case TUSHORT: + a = AMOVHU; + break; + case TSHORT: + a = AMOVH; + break; + case TFLOAT: + a = AMOVF; + break; + case TDOUBLE: + a = AMOVD; + break; + } + if(!typefd[ft] && vconst(f) == 0) { + gins(a, f, t); + return; + } + if(ft == tt) + regalloc(&nod, t, f); + else + regalloc(&nod, t, Z); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + } + + /* + * type x type cross table + */ + a = AGOK; + switch(ft) { + case TDOUBLE: + case TVLONG: + case TFLOAT: + switch(tt) { + case TDOUBLE: + case TVLONG: + a = AMOVD; + if(ft == TFLOAT) + a = AMOVFD; + break; + case TFLOAT: + a = AMOVDF; + if(ft == TFLOAT) + a = AMOVF; + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + if(fproundflg) { + /* convert f, t */ + regalloc(&nod, f, Z); + gins(AMOVDW, f, &nod); + if(ft == TFLOAT) + p->as = AMOVFW; + gins(AMOVW, &nod, t); + regfree(&nod); + gins(AMOVW, t, t); + return; + } + regalloc(&nod1, ®node, Z); + regalloc(&nod2, ®node, Z); + + /* movw fcr, rx */ + gins(AMOVW, Z, &nod1); + p->from.type = D_FCREG; + p->from.reg = 31; + + /* nop */ + gins(ANOR, nodconst(0), nodconst(0)); + p->to.type = D_REG; + p->to.reg = 0; + + /* nop */ + gins(ANOR, nodconst(0), nodconst(0)); + p->to.type = D_REG; + p->to.reg = 0; + + /* or $3, rx, ry */ + gins(AOR, nodconst(3), &nod2); + p->reg = nod1.reg; + + /* xor $2, ry */ + gins(AXOR, nodconst(2), &nod2); + + /* movw ry, fcr */ + gins(AMOVW, &nod2, Z); + p->to.type = D_FCREG; + p->to.reg = 31; + + /* nop */ + gins(ANOR, nodconst(0), nodconst(0)); + p->to.type = D_REG; + p->to.reg = 0; + + /* nop */ + gins(ANOR, nodconst(0), nodconst(0)); + p->to.type = D_REG; + p->to.reg = 0; + + /* convert f, t */ + regalloc(&nod, f, Z); + gins(AMOVDW, f, &nod); + if(ft == TFLOAT) + p->as = AMOVFW; + gins(AMOVW, &nod, t); + regfree(&nod); + gins(AMOVW, t, t); + + /* movw rx, fcr */ + gins(AMOVW, &nod1, Z); + p->to.type = D_FCREG; + p->to.reg = 31; + + /* nop */ + gins(ANOR, nodconst(0), nodconst(0)); + p->to.type = D_REG; + p->to.reg = 0; + + /* nop */ + gins(ANOR, nodconst(0), nodconst(0)); + p->to.type = D_REG; + p->to.reg = 0; + + regfree(&nod1); + regfree(&nod2); + return; + } + break; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + switch(tt) { + case TDOUBLE: + case TVLONG: + gins(AMOVW, f, t); + gins(AMOVWD, t, t); + if(ft == TULONG || ft == TUINT) { + regalloc(&nod, t, Z); + gins(ACMPGED, t, Z); + p->reg = FREGZERO; + gins(ABFPT, Z, Z); + p1 = p; + gins(AMOVD, nodfconst(4294967296.), &nod); + gins(AADDD, &nod, t); + patch(p1, pc); + regfree(&nod); + } + return; + case TFLOAT: + gins(AMOVW, f, t); + gins(AMOVWF, t, t); + if(ft == TULONG || ft == TUINT) { + regalloc(&nod, t, Z); + gins(ACMPGEF, t, Z); + p->reg = FREGZERO; + gins(ABFPT, Z, Z); + p1 = p; + gins(AMOVF, nodfconst(4294967296.), &nod); + gins(AADDF, &nod, t); + patch(p1, pc); + regfree(&nod); + } + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVH, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVH; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUSHORT: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVHU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + a = AMOVHU; + break; + case TSHORT: + case TUSHORT: + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVB, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVB; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + case TUCHAR: + switch(tt) { + case TDOUBLE: + case TVLONG: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWD, t, t); + regfree(&nod); + return; + case TFLOAT: + regalloc(&nod, f, Z); + gins(AMOVBU, f, &nod); + gins(AMOVW, &nod, t); + gins(AMOVWF, t, t); + regfree(&nod); + return; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TSHORT: + case TUSHORT: + a = AMOVBU; + break; + case TCHAR: + case TUCHAR: + a = AMOVW; + break; + } + break; + } + if(a == AGOK) + diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); + if(a == AMOVW || a == AMOVF || a == AMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +gins(int a, Node *f, Node *t) +{ + + nextpc(); + p->as = a; + if(f != Z) + naddr(f, &p->from); + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +void +gopcode(int o, Node *f1, Node *f2, Node *t) +{ + int a, et; + Adr ta; + + et = TLONG; + if(f1 != Z && f1->type != T) + et = f1->type->etype; + a = AGOK; + switch(o) { + case OAS: + gmove(f1, t); + return; + + case OASADD: + case OADD: + a = AADDU; + if(et == TFLOAT) + a = AADDF; + else + if(et == TDOUBLE || et == TVLONG) + a = AADDD; + break; + + case OASSUB: + case OSUB: + a = ASUBU; + if(et == TFLOAT) + a = ASUBF; + else + if(et == TDOUBLE || et == TVLONG) + a = ASUBD; + break; + + case OASOR: + case OOR: + a = AOR; + break; + + case OASAND: + case OAND: + a = AAND; + break; + + case OASXOR: + case OXOR: + a = AXOR; + break; + + case OASLSHR: + case OLSHR: + a = ASRL; + break; + + case OASASHR: + case OASHR: + a = ASRA; + break; + + case OASASHL: + case OASHL: + a = ASLL; + break; + + case OFUNC: + a = AJAL; + break; + + case OCOND: + a = ASGTU; + break; + + case OCOMMA: + a = ASGT; + break; + + case OASMUL: + case OMUL: + if(et == TFLOAT) { + a = AMULF; + break; + } else + if(et == TDOUBLE || et == TVLONG) { + a = AMULD; + break; + } + a = AMUL; + goto muldiv; + + case OASDIV: + case ODIV: + if(et == TFLOAT) { + a = ADIVF; + break; + } else + if(et == TDOUBLE || et == TVLONG) { + a = ADIVD; + break; + } + a = ADIV; + goto muldiv; + + case OASMOD: + case OMOD: + a = ADIV; + o = OMOD; + goto muldiv; + + case OASLMUL: + case OLMUL: + a = AMULU; + goto muldiv; + + case OASLMOD: + case OLMOD: + a = ADIVU; + o = OMOD; + goto muldiv; + + case OASLDIV: + case OLDIV: + a = ADIVU; + goto muldiv; + + muldiv: + nextpc(); + naddr(f1, &p->from); + if(f2 == Z) + raddr(t, p); + else + raddr(f2, p); + p->as = a; + if(debug['g']) + print("%P\n", p); + + nextpc(); + p->as = AMOVW; + a = D_LO; + if(o == OMOD) + a = D_HI; + p->from.type = a; + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); + return; + + case OEQ: + if(!typefd[et]) { + a = ABEQ; + break; + } + + case ONE: + if(!typefd[et]) { + a = ABNE; + break; + } + + case OLT: + case OLE: + case OGE: + case OGT: + if(typefd[et]) { + nextpc(); + if(et == TFLOAT) { + a = ACMPGTF; + if(o == OEQ || o == ONE) + a = ACMPEQF; + else + if(o == OLT || o == OGE) + a = ACMPGEF; + } else { + a = ACMPGTD; + if(o == OEQ || o == ONE) + a = ACMPEQD; + else + if(o == OLT || o == OGE) + a = ACMPGED; + } + p->as = a; + naddr(f1, &p->from); + raddr(f2, p); + if(debug['g']) + print("%P\n", p); + nextpc(); + a = ABFPF; + if(o == OEQ || o == OGE || o == OGT) + a = ABFPT; + p->as = a; + if(debug['g']) + print("%P\n", p); + return; + } + if(vconst(f1) == 0 || vconst(f2) == 0) { + if(vconst(f1) == 0) { + o = invrel[relindex(o)]; + f1 = f2; + } + switch(o) { + case OLT: + a = ABLTZ; + break; + case OLE: + a = ABLEZ; + break; + case OGE: + a = ABGEZ; + break; + case OGT: + a = ABGTZ; + break; + } + f2 = Z; + break; + } + + case OLO: + case OLS: + case OHS: + case OHI: + nextpc(); + if(o == OLE || o == OGT || o == OLS || o == OHI) { + naddr(f1, &p->from); + raddr(f2, p); + } else { + naddr(f2, &p->from); + raddr(f1, p); + } + naddr(®node, &p->to); + p->to.reg = tmpreg(); + a = ASGT; + if(o == OLO || o == OLS || o == OHS || o == OHI) + a = ASGTU; + p->as = a; + if(debug['g']) + print("%P\n", p); + + nextpc(); + naddr(®node, &p->from); + p->from.reg = tmpreg(); + a = ABEQ; + if(o == OLT || o == OGT || o == OLO || o == OHI) + a = ABNE; + p->as = a; + if(debug['g']) + print("%P\n", p); + return; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + nextpc(); + p->as = a; + if(f1 != Z) + naddr(f1, &p->from); + if(f2 != Z) { + naddr(f2, &ta); + p->reg = ta.reg; + if(ta.type == D_CONST && ta.offset == 0) + p->reg = REGZERO; + } + if(t != Z) + naddr(t, &p->to); + if(debug['g']) + print("%P\n", p); +} + +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_OREG; + p->from.sym = s; + if(a == ATEXT) + p->reg = (profileflg ? 0 : NOPROF); + p->from.name = D_EXTERN; + if(s->class == CSTATIC) + p->from.name = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + vlong vv; + + if(n->op == OCONST) { + if(!typefd[n->type->etype]) { + vv = n->vconst; + if(vv >= (vlong)(-32766) && vv < (vlong)32766) + return 1; + } + } + return 0; +} + +int +sval(long v) +{ + if(v >= -32766L && v < 32766L) + return 1; + return 0; +} + +long +exreg(Type *t) +{ + long o; + + if(typechlp[t->etype]) { + if(exregoffset <= 16) + return 0; + o = exregoffset; + exregoffset--; + return o; + } + if(typefd[t->etype]) { + if(exfregoffset <= 16) + return 0; + o = exfregoffset + NREG; + exfregoffset--; + return o; + } + return 0; +} + +schar ewidth[NTYPE] = +{ + -1, /* [TXXX] */ + SZ_CHAR, /* [TCHAR] */ + SZ_CHAR, /* [TUCHAR] */ + SZ_SHORT, /* [TSHORT] */ + SZ_SHORT, /* [TUSHORT] */ + SZ_INT, /* [TINT] */ + SZ_INT, /* [TUINT] */ + SZ_LONG, /* [TLONG] */ + SZ_LONG, /* [TULONG] */ + SZ_VLONG, /* [TVLONG] */ + SZ_VLONG, /* [TUVLONG] */ + SZ_FLOAT, /* [TFLOAT] */ + SZ_DOUBLE, /* [TDOUBLE] */ + SZ_IND, /* [TIND] */ + 0, /* [TFUNC] */ + -1, /* [TARRAY] */ + 0, /* [TVOID] */ + -1, /* [TSTRUCT] */ + -1, /* [TUNION] */ + SZ_INT, /* [TENUM] */ +}; + +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] */ +}; diff --git a/utils/vc/v.out.h b/utils/vc/v.out.h new file mode 100644 index 00000000..2fec2893 --- /dev/null +++ b/utils/vc/v.out.h @@ -0,0 +1,201 @@ +#define NSNAME 8 +#define NSYM 50 +#define NREG 32 + +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +#define REGZERO 0 +#define REGRET 1 +#define REGARG 1 +/* compiler allocates R1 up as temps */ +/* compiler allocates register variables R3-R23 */ +#define REGEXT 25 +/* compiler allocates external registers R25 down */ +/* dont use R26 R27 */ +#define REGTMP 28 +#define REGSP 29 +#define REGSB 30 +#define REGLINK 31 + +#define FREGRET 0 +/* compiler allocates register variables F4-F22 */ +/* compiler allocates external registers F22 down */ +#define FREGEXT 22 +#define FREGZERO 24 /* both float and double */ +#define FREGHALF 26 /* double */ +#define FREGONE 28 /* double */ +#define FREGTWO 30 /* double */ + +enum as +{ + AXXX, + + AABSD, + AABSF, + AABSW, + AADD, + AADDD, + AADDF, + AADDU, + AADDW, + AAND, + ABEQ, + ABFPF, + ABFPT, + ABGEZ, + ABGEZAL, + ABGTZ, + ABLEZ, + ABLTZ, + ABLTZAL, + ABNE, + ABREAK, + ACMPEQD, + ACMPEQF, + ACMPGED, + ACMPGEF, + ACMPGTD, + ACMPGTF, + ADATA, + ADIV, + ADIVD, + ADIVF, + ADIVU, + ADIVW, + AGLOBL, + AGOK, + AHISTORY, + AJAL, + AJMP, + AMOVB, + AMOVBU, + AMOVD, + AMOVDF, + AMOVDW, + AMOVF, + AMOVFD, + AMOVFW, + AMOVH, + AMOVHU, + AMOVW, + AMOVWD, + AMOVWF, + AMOVWL, + AMOVWR, + AMUL, + AMULD, + AMULF, + AMULU, + AMULW, + ANAME, + ANEGD, + ANEGF, + ANEGW, + ANOP, + ANOR, + AOR, + AREM, + AREMU, + ARET, + ARFE, + ASGT, + ASGTU, + ASLL, + ASRA, + ASRL, + ASUB, + ASUBD, + ASUBF, + ASUBU, + ASUBW, + ASYSCALL, + ATEXT, + ATLBP, + ATLBR, + ATLBWI, + ATLBWR, + AWORD, + AXOR, + + AEND, + + AMOVV, + AMOVVL, + AMOVVR, + ASLLV, + ASRAV, + ASRLV, + ADIVV, + ADIVVU, + AREMV, + AREMVU, + AMULV, + AMULVU, + AADDV, + AADDVU, + ASUBV, + ASUBVU, + + ADYNT, + AINIT, + + ABCASE, + ACASE, + + ATRUNCFV, + ATRUNCDV, + ATRUNCFW, + ATRUNCDW, + AMOVWU, + AMOVFV, + AMOVDV, + AMOVVF, + AMOVVD, + + ASIGNAME, + + ALAST, +}; + +/* type/name */ +#define D_GOK 0 +#define D_NONE 1 + +/* type */ +#define D_BRANCH (D_NONE+1) +#define D_OREG (D_NONE+2) +#define D_EXTERN (D_NONE+3) /* name */ +#define D_STATIC (D_NONE+4) /* name */ +#define D_AUTO (D_NONE+5) /* name */ +#define D_PARAM (D_NONE+6) /* name */ +#define D_CONST (D_NONE+7) +#define D_FCONST (D_NONE+8) +#define D_SCONST (D_NONE+9) +#define D_HI (D_NONE+10) +#define D_LO (D_NONE+11) +#define D_REG (D_NONE+12) +#define D_FREG (D_NONE+13) +#define D_FCREG (D_NONE+14) +#define D_MREG (D_NONE+15) +#define D_FILE (D_NONE+16) +#define D_OCONST (D_NONE+17) +#define D_FILE1 (D_NONE+18) +#define D_VCONST (D_NONE+19) + +/* + * 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 */ +}; diff --git a/utils/vl/Nt.c b/utils/vl/Nt.c new file mode 100644 index 00000000..73c6f795 --- /dev/null +++ b/utils/vl/Nt.c @@ -0,0 +1,77 @@ +#include <windows.h> +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(uint n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(uint m, uint n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, uint n) +{ + void *new; + + new = malloc(n); + if(new && p) + memmove(new, p, n); + return new; +} + +#define Chunk (1*1024*1024) + +void* +mysbrk(ulong size) +{ + void *v; + static int chunk; + static uchar *brk; + + if(chunk < size) { + chunk = Chunk; + if(chunk < size) + chunk = Chunk + size; + brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(brk == 0) + return (void*)-1; + } + v = brk; + chunk -= size; + brk += size; + return v; +} + +double +cputime(void) +{ + return ((double)0); +} diff --git a/utils/vl/Plan9.c b/utils/vl/Plan9.c new file mode 100644 index 00000000..f4cf23f4 --- /dev/null +++ b/utils/vl/Plan9.c @@ -0,0 +1,57 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(ulong n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(ulong m, ulong n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, ulong n) +{ + USED(p); + USED(n); + fprint(2, "realloc called\n"); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} + +void +setmalloctag(void*, ulong) +{ +} diff --git a/utils/vl/Posix.c b/utils/vl/Posix.c new file mode 100644 index 00000000..7c3a661f --- /dev/null +++ b/utils/vl/Posix.c @@ -0,0 +1,80 @@ +#include "l.h" +#include <sys/types.h> +#include <sys/times.h> +#undef getwd +#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ + +/* + * fake malloc + */ +void* +malloc(size_t n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(size_t m, size_t n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, size_t n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return (void*)sbrk(size); +} + +double +cputime(void) +{ + + struct tms tmbuf; + double ret_val; + + /* + * times() only fials if &tmbuf is invalid. + */ + (void)times(&tmbuf); + /* + * Return the total time (in system clock ticks) + * spent in user code and system + * calls by both the calling process and its children. + */ + ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + + tmbuf.tms_cutime + tmbuf.tms_cstime); + /* + * Convert to seconds. + */ + ret_val *= sysconf(_SC_CLK_TCK); + return ret_val; + +} diff --git a/utils/vl/asm.c b/utils/vl/asm.c new file mode 100644 index 00000000..28ec1a89 --- /dev/null +++ b/utils/vl/asm.c @@ -0,0 +1,1403 @@ +#include "l.h" + +long OFFSET; +/* +long BADOFFSET = -1; + + if(OFFSET <= BADOFFSET && OFFSET+4 > BADOFFSET)\ + abort();\ + OFFSET += 4;\ + + if(OFFSET == BADOFFSET)\ + abort();\ + OFFSET++;\ +*/ + +#define LPUT(c)\ + {\ + cbp[0] = (c)>>24;\ + cbp[1] = (c)>>16;\ + cbp[2] = (c)>>8;\ + cbp[3] = (c);\ + cbp += 4;\ + cbc -= 4;\ + if(cbc <= 0)\ + cflush();\ + } + +#define CPUT(c)\ + {\ + cbp[0] = (c);\ + cbp++;\ + cbc--;\ + if(cbc <= 0)\ + cflush();\ + } + +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; + if(s->type != STEXT && s->type != SLEAF) + diag("entry not text: %s", s->name); + return s->value; +} + +void +asmb(void) +{ + Prog *p; + long t, etext; + Optab *o; + + if(debug['v']) + Bprint(&bso, "%5.2f asm\n", cputime()); + Bflush(&bso); + OFFSET = HEADR; + seek(cout, OFFSET, 0); + pc = INITTEXT; + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + } + if(p->pc != pc) { + diag("phase error %lux sb %lux", + p->pc, pc); + if(!debug['a']) + prasm(curp); + pc = p->pc; + } + curp = p; + o = oplook(p); /* could probably avoid this call */ + if(asmout(p, o, 0)) { + p = p->link; + pc += 4; + } + pc += o->size; + } + if(debug['a']) + Bprint(&bso, "\n"); + Bflush(&bso); + cflush(); + + etext = INITTEXT + textsize; + for(t = pc; t < etext; t += sizeof(buf)-100) { + if(etext-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100, 1); + else + datblk(t, etext-t, 1); + } + + Bflush(&bso); + cflush(); + + curtext = P; + switch(HEADTYPE) { + case 0: + case 4: + OFFSET = rnd(HEADR+textsize, 4096); + seek(cout, OFFSET, 0); + break; + case 1: + case 2: + case 3: + case 5: + OFFSET = HEADR+textsize; + seek(cout, OFFSET, 0); + break; + } + for(t = 0; t < datsize; t += sizeof(buf)-100) { + if(datsize-t > sizeof(buf)-100) + datblk(t, sizeof(buf)-100, 0); + else + datblk(t, datsize-t, 0); + } + + symsize = 0; + lcsize = 0; + if(!debug['s']) { + if(debug['v']) + Bprint(&bso, "%5.2f sym\n", cputime()); + Bflush(&bso); + switch(HEADTYPE) { + case 0: + case 4: + OFFSET = rnd(HEADR+textsize, 4096)+datsize; + seek(cout, OFFSET, 0); + break; + case 3: + case 2: + case 1: + case 5: + OFFSET = HEADR+textsize+datsize; + seek(cout, OFFSET, 0); + break; + } + if(!debug['s']) + asmsym(); + if(debug['v']) + Bprint(&bso, "%5.2f pc\n", cputime()); + Bflush(&bso); + if(!debug['s']) + asmlc(); + cflush(); + } + + if(debug['v']) + Bprint(&bso, "%5.2f header\n", cputime()); + Bflush(&bso); + OFFSET = 0; + seek(cout, OFFSET, 0); + switch(HEADTYPE) { + case 0: + 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; + case 1: + lput(0x160L<<16); /* magic and sections */ + lput(0L); /* time and date */ + lput(HEADR+textsize+datsize); + lput(symsize); /* nsyms */ + lput((0x38L<<16)|7L); /* size of optional hdr and flags */ + + lput((0407<<16)|0437L); /* magic and version */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(entryvalue()); /* va of entry */ + lput(INITTEXT); /* 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(lcsize); + lput(0L); + lput(0L); + lput(0L); + lput(~0L); /* gp value ?? */ + lput(0L); /* complete mystery */ + break; + case 2: + lput(0x407); /* magic */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(symsize); /* nsyms */ + lput(entryvalue()); /* va of entry */ + lput(0L); + lput(lcsize); + break; + case 3: + lput((0x160L<<16)|3L); /* magic and sections */ + lput(time(0)); /* time and date */ + lput(HEADR+textsize+datsize); + lput(symsize); /* nsyms */ + lput((0x38L<<16)|7L); /* size of optional hdr and flags */ + + lput((0407<<16)|0437L); /* magic and version */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(entryvalue()); /* va of entry */ + lput(INITTEXT); /* 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(lcsize); + lput(0L); + lput(0L); + lput(0L); + lput(~0L); /* gp value ?? */ + + strnput(".text", 8); /* text segment */ + lput(INITTEXT); /* address */ + lput(INITTEXT); + lput(textsize); + lput(HEADR); + lput(0L); + lput(HEADR+textsize+datsize+symsize); + lput(lcsize); /* line number size */ + lput(0x20L); /* flags */ + + strnput(".data", 8); /* data segment */ + lput(INITDAT); /* address */ + lput(INITDAT); + lput(datsize); + lput(HEADR+textsize); + lput(0L); + lput(0L); + lput(0L); + lput(0x40L); /* flags */ + + strnput(".bss", 8); /* bss segment */ + lput(INITDAT+datsize); /* address */ + lput(INITDAT+datsize); + lput(bsssize); + lput(0L); + lput(0L); + lput(0L); + lput(0L); + lput(0x80L); /* flags */ + break; + case 4: + + lput((0x160L<<16)|3L); /* magic and sections */ + lput(time(0)); /* 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)|01012L); /* magic and version */ + lput(textsize); /* sizes */ + lput(datsize); + lput(bsssize); + lput(entryvalue()); /* va of entry */ + lput(INITTEXT); /* 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(lcsize); + lput(0L); + lput(0L); + lput(0L); + lput(~0L); /* gp value ?? */ + + strnput(".text", 8); /* text segment */ + lput(INITTEXT); /* address */ + lput(INITTEXT); + lput(textsize); + lput(HEADR); + lput(0L); + lput(HEADR+textsize+datsize+symsize); + lput(lcsize); /* line number size */ + lput(0x20L); /* flags */ + + strnput(".data", 8); /* data segment */ + lput(INITDAT); /* address */ + lput(INITDAT); + lput(datsize); + lput(rnd(HEADR+textsize, 4096)); /* sizes */ + lput(0L); + lput(0L); + lput(0L); + lput(0x40L); /* flags */ + + strnput(".bss", 8); /* bss segment */ + lput(INITDAT+datsize); /* address */ + lput(INITDAT+datsize); + lput(bsssize); + lput(0L); + lput(0L); + lput(0L); + lput(0L); + lput(0x80L); /* flags */ + break; + case 5: + strnput("\177ELF", 4); /* e_ident */ + CPUT(1); /* class = 32 bit */ + CPUT(2); /* data = MSB */ + CPUT(1); /* version = CURRENT */ + strnput("", 9); + lput((2L<<16)|8L); /* type = EXEC; machine = MIPS */ + lput(1L); /* version = CURRENT */ + lput(entryvalue()); /* entry vaddr */ + lput(52L); /* offset to first phdr */ + lput(0L); /* offset to first shdr */ + lput(0L); /* flags = MIPS */ + lput((52L<<16)|32L); /* Ehdr & Phdr sizes*/ + lput((3L<<16)|0L); /* # Phdrs & Shdr size */ + lput((0L<<16)|0L); /* # Shdrs & shdr string size */ + + lput(1L); /* text - type = PT_LOAD */ + lput(0L); /* file offset */ + lput(INITTEXT-HEADR); /* vaddr */ + lput(INITTEXT-HEADR); /* paddr */ + lput(HEADR+textsize); /* file size */ + lput(HEADR+textsize); /* memory size */ + lput(0x05L); /* protections = RX */ + lput(0x10000L); /* alignment code?? */ + + lput(1L); /* data - type = PT_LOAD */ + lput(HEADR+textsize); /* file offset */ + lput(INITDAT); /* vaddr */ + lput(INITDAT); /* paddr */ + lput(datsize); /* file size */ + lput(datsize+bsssize); /* memory size */ + lput(0x06L); /* protections = RW */ + lput(0x10000L); /* alignment code?? */ + + lput(0L); /* data - type = PT_NULL */ + lput(HEADR+textsize+datsize); /* file offset */ + lput(0L); + lput(0L); + lput(symsize); /* symbol table size */ + lput(lcsize); /* line number size */ + lput(0x04L); /* protections = R */ + lput(0x04L); /* alignment code?? */ + } + cflush(); +} + +void +strnput(char *s, int n) +{ + for(; *s; s++){ + CPUT(*s); + n--; + } + for(; n > 0; n--) + CPUT(0); +} + +void +lput(long l) +{ + + LPUT(l); +} + +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 +nopstat(char *f, Count *c) +{ + if(c->outof) + Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f, + c->outof - c->count, c->outof, + (double)(c->outof - c->count)/c->outof); +} + +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 SSTRING: + putsymb(s->name, 'T', 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->cond) { + s = p->from.sym; + if(s->type != STEXT && s->type != SLEAF) + 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); + + if(s->type == STEXT) + putsymb(s->name, 'T', s->value, s->version); + else + putsymb(s->name, 'L', 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 +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); + } +} + +#define MINLC 4 +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); +} + +void +datblk(long s, long n, int str) +{ + Prog *p; + char *cast; + long l, fl, j, d; + int i, c; + + memset(buf.dbuf, 0, n+100); + for(p = datap; p != P; p = p->link) { + curp = p; + if(str != (p->from.sym->type == SSTRING)) + continue; + l = p->from.sym->value + p->from.offset - s; + c = p->reg; + 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) { + default: + diag("unknown mode in initialization\n%P", p); + break; + + case D_FCONST: + switch(c) { + default: + case 4: + fl = ieeedtof(p->to.ieee); + cast = (char*)&fl; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i+4]]; + l++; + } + break; + case 8: + cast = (char*)p->to.ieee; + for(; i<c; i++) { + buf.dbuf[l] = cast[fnuxi8[i]]; + l++; + } + break; + } + break; + + case D_SCONST: + for(; i<c; i++) { + buf.dbuf[l] = p->to.sval[i]; + l++; + } + break; + + case D_CONST: + d = p->to.offset; + if(p->to.sym) { + switch(p->to.sym->type) { + case STEXT: + case SLEAF: + case SSTRING: + d += p->to.sym->value; + break; + case SDATA: + case SBSS: + d += p->to.sym->value + INITDAT; + break; + } + } + cast = (char*)&d; + switch(c) { + default: + diag("bad nuxi %d %d\n%P", c, i, curp); + break; + case 1: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi1[i]]; + l++; + } + break; + case 2: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi2[i]]; + l++; + } + break; + case 4: + for(; i<c; i++) { + buf.dbuf[l] = cast[inuxi4[i]]; + l++; + } + break; + } + break; + } + } + write(cout, buf.dbuf, n); +} + +#define OP_RRR(op,r1,r2,r3)\ + (op|(((r1)&31L)<<16)|(((r2)&31L)<<21)|(((r3)&31L)<<11)) +#define OP_IRR(op,i,r2,r3)\ + (op|((i)&0xffffL)|(((r2)&31L)<<21)|(((r3)&31L)<<16)) +#define OP_SRR(op,s,r2,r3)\ + (op|(((s)&31L)<<6)|(((r2)&31L)<<16)|(((r3)&31L)<<11)) +#define OP_FRRR(op,r1,r2,r3)\ + (op|(((r1)&31L)<<16)|(((r2)&31L)<<11)|(((r3)&31L)<<6)) +#define OP_JMP(op,i)\ + ((op)|((i)&0x3ffffffL)) + +#define OP(x,y)\ + (((x)<<3)|((y)<<0)) +#define SP(x,y)\ + (((x)<<29)|((y)<<26)) +#define BCOND(x,y)\ + (((x)<<19)|((y)<<16)) +#define MMU(x,y)\ + (SP(2,0)|(16<<21)|((x)<<3)|((y)<<0)) +#define FPF(x,y)\ + (SP(2,1)|(16<<21)|((x)<<3)|((y)<<0)) +#define FPD(x,y)\ + (SP(2,1)|(17<<21)|((x)<<3)|((y)<<0)) +#define FPW(x,y)\ + (SP(2,1)|(20<<21)|((x)<<3)|((y)<<0)) + +int vshift(int); + +int +asmout(Prog *p, Optab *o, int aflag) +{ + long o1, o2, o3, o4, o5, o6, o7, v; + Prog *ct; + int r, a; + + o1 = 0; + o2 = 0; + o3 = 0; + o4 = 0; + o5 = 0; + o6 = 0; + o7 = 0; + switch(o->type) { + default: + diag("unknown type %d", o->type); + if(!debug['a']) + prasm(p); + break; + + case 0: /* pseudo ops */ + if(aflag) { + if(p->link) { + if(p->as == ATEXT) { + ct = curtext; + o2 = autosize; + curtext = p; + autosize = p->to.offset + 4; + o1 = asmout(p->link, oplook(p->link), aflag); + curtext = ct; + autosize = o2; + } else + o1 = asmout(p->link, oplook(p->link), aflag); + } + return o1; + } + break; + + case 1: /* mov[v] r1,r2 ==> OR r1,r0,r2 */ + o1 = OP_RRR(oprrr(AOR), p->from.reg, REGZERO, p->to.reg); + break; + + case 2: /* add/sub r1,[r2],r3 */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg); + break; + + case 3: /* mov $soreg, r ==> or/add $i,o,r */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + a = AADDU; + if(o->a1 == C_ANDCON) + a = AOR; + o1 = OP_IRR(opirr(a), v, r, p->to.reg); + break; + + case 4: /* add $scon,[r1],r2 */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_IRR(opirr(p->as), v, r, p->to.reg); + break; + + case 5: /* syscall */ + if(aflag) + return 0; + o1 = oprrr(p->as); + break; + + case 6: /* beq r1,[r2],sbra */ + if(aflag) + return 0; + if(p->cond == P) + v = -4 >> 2; + else + v = (p->cond->pc - pc-4) >> 2; + if(((v << 16) >> 16) != v) + diag("short branch too far: %d\n%P", v, p); + o1 = OP_IRR(opirr(p->as), v, p->from.reg, p->reg); + break; + + case 7: /* mov r, soreg ==> sw o(r) */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + o1 = OP_IRR(opirr(p->as), v, r, p->from.reg); + break; + + case 8: /* mov soreg, r ==> lw o(r) */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + o1 = OP_IRR(opirr(p->as+ALAST), v, r, p->to.reg); + break; + + case 9: /* asl r1,[r2],r3 */ + r = p->reg; + if(r == NREG) + r = p->to.reg; + o1 = OP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg); + break; + + case 10: /* add $con,[r1],r2 ==> mov $con,t; add t,[r1],r2 */ + v = regoff(&p->from); + r = AOR; + if(v < 0) + r = AADDU; + o1 = OP_IRR(opirr(r), v, 0, REGTMP); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); + break; + + case 11: /* jmp lbra */ + if(aflag) + return 0; + if(p->cond == P) + v = p->pc >> 2; + else + v = p->cond->pc >> 2; + o1 = OP_JMP(opirr(p->as), v); + if(!debug['Y'] && p->link && p->cond && isnop(p->link)) { + nop.branch.count--; + nop.branch.outof--; + nop.jump.outof++; + o2 = asmout(p->cond, oplook(p->cond), 1); + if(o2) { + o1 += 1; + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", + p->pc, o1, o2, p); + LPUT(o1); + LPUT(o2); + return 1; + } + } + break; + + case 12: /* movbs r,r */ + v = 16; + if(p->as == AMOVB) + v = 24; + o1 = OP_SRR(opirr(ASLL), v, p->from.reg, p->to.reg); + o2 = OP_SRR(opirr(ASRA), v, p->to.reg, p->to.reg); + break; + + case 13: /* movbu r,r */ + if(p->as == AMOVBU) + o1 = OP_IRR(opirr(AAND), 0xffL, p->from.reg, p->to.reg); + else + o1 = OP_IRR(opirr(AAND), 0xffffL, p->from.reg, p->to.reg); + break; + + case 16: /* sll $c,[r1],r2 */ + v = regoff(&p->from); + r = p->reg; + if(r == NREG) + r = p->to.reg; + + /* OP_SRR will use only the low 5 bits of the shift value */ + if(v >= 32 && vshift(p->as)) + o1 = OP_SRR(opirr(p->as+ALAST), v-32, r, p->to.reg); + else + o1 = OP_SRR(opirr(p->as), v, r, p->to.reg); + break; + + case 18: /* jmp [r1],0(r2) */ + if(aflag) + return 0; + r = p->reg; + if(r == NREG) + r = o->param; + o1 = OP_RRR(oprrr(p->as), 0, p->to.reg, r); + break; + + case 19: /* mov $lcon,r ==> lu+or */ + v = regoff(&p->from); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg); + o2 = OP_IRR(opirr(AOR), v, p->to.reg, p->to.reg); + break; + + case 20: /* mov lohi,r */ + r = OP(2,0); /* mfhi */ + if(p->from.type == D_LO) + r = OP(2,2); /* mflo */ + o1 = OP_RRR(r, REGZERO, REGZERO, p->to.reg); + break; + + case 21: /* mov r,lohi */ + r = OP(2,1); /* mthi */ + if(p->to.type == D_LO) + r = OP(2,3); /* mtlo */ + o1 = OP_RRR(r, REGZERO, p->from.reg, REGZERO); + break; + + case 22: /* mul r1,r2 */ + o1 = OP_RRR(oprrr(p->as), p->from.reg, p->reg, REGZERO); + break; + + case 23: /* add $lcon,r1,r2 ==> lu+or+add */ + v = regoff(&p->from); + if(p->to.reg == REGTMP || p->reg == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o3 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); + break; + + case 24: /* mov $ucon,,r ==> lu r */ + v = regoff(&p->from); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, p->to.reg); + break; + + case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */ + v = regoff(&p->from); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + r = p->reg; + if(r == NREG) + r = p->to.reg; + o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg); + break; + + case 26: /* mov $lsext/auto/oreg,,r2 ==> lu+or+add */ + v = regoff(&p->from); + if(p->to.reg == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + r = p->from.reg; + if(r == NREG) + r = o->param; + o3 = OP_RRR(oprrr(AADDU), REGTMP, r, p->to.reg); + break; + + case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */ + r = p->from.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->from); + switch(o->size) { + case 20: + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(AMOVF+ALAST), 0, REGTMP, p->to.reg+1); + o5 = OP_IRR(opirr(AMOVF+ALAST), 4, REGTMP, p->to.reg); + break; + case 16: + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(AMOVF+ALAST), 0, REGTMP, p->to.reg); + break; + case 8: + o1 = OP_IRR(opirr(AMOVF+ALAST), v, r, p->to.reg+1); + o2 = OP_IRR(opirr(AMOVF+ALAST), v+4, r, p->to.reg); + break; + case 4: + o1 = OP_IRR(opirr(AMOVF+ALAST), v, r, p->to.reg); + break; + } + break; + + case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */ + r = p->to.reg; + if(r == NREG) + r = o->param; + v = regoff(&p->to); + switch(o->size) { + case 20: + if(r == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(AMOVF), 0, REGTMP, p->from.reg+1); + o5 = OP_IRR(opirr(AMOVF), 4, REGTMP, p->from.reg); + break; + case 16: + if(r == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(AMOVF), 0, REGTMP, p->from.reg); + break; + case 8: + o1 = OP_IRR(opirr(AMOVF), v, r, p->from.reg+1); + o2 = OP_IRR(opirr(AMOVF), v+4, r, p->from.reg); + break; + case 4: + o1 = OP_IRR(opirr(AMOVF), v, r, p->from.reg); + break; + } + break; + + case 30: /* movw r,fr */ + r = SP(2,1)|(4<<21); /* mtc1 */ + o1 = OP_RRR(r, p->from.reg, 0, p->to.reg); + break; + + case 31: /* movw fr,r */ + r = SP(2,1)|(0<<21); /* mfc1 */ + o1 = OP_RRR(r, p->to.reg, 0, p->from.reg); + break; + + case 32: /* fadd fr1,[fr2],fr3 */ + r = p->reg; + if(r == NREG) + o1 = OP_FRRR(oprrr(p->as), p->from.reg, p->to.reg, p->to.reg); + else + o1 = OP_FRRR(oprrr(p->as), p->from.reg, r, p->to.reg); + break; + + case 33: /* fabs fr1,fr3 */ + o1 = OP_FRRR(oprrr(p->as), 0, p->from.reg, p->to.reg); + break; + + case 34: /* mov $con,fr ==> or/add $i,r,r2 */ + v = regoff(&p->from); + r = AADDU; + if(o->a1 == C_ANDCON) + r = AOR; + o1 = OP_IRR(opirr(r), v, 0, REGTMP); + o2 = OP_RRR(SP(2,1)|(4<<21), REGTMP, 0, p->to.reg); /* mtc1 */ + break; + + case 35: /* mov r,lext/luto/oreg ==> sw o(r) */ + /* + * the lowbits of the constant cannot + * be moved into the offset of the load + * because the mips 4000 in 64-bit mode + * does a 64-bit add and it will screw up. + */ + v = regoff(&p->to); + r = p->to.reg; + if(r == NREG) + r = o->param; + if(r == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(p->as), 0, REGTMP, p->from.reg); + break; + + case 36: /* mov lext/lauto/lreg,r ==> lw o(r30) */ + v = regoff(&p->from); + r = p->from.reg; + if(r == NREG) + r = o->param; + if(r == REGTMP) + diag("cant synthesize large constant\n%P", p); + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_IRR(opirr(AOR), v, REGTMP, REGTMP); + o3 = OP_RRR(oprrr(AADDU), r, REGTMP, REGTMP); + o4 = OP_IRR(opirr(p->as+ALAST), 0, REGTMP, p->to.reg); + break; + + case 37: /* movw r,mr */ + r = SP(2,0)|(4<<21); /* mtc0 */ + if(p->as == AMOVV) + r = SP(2,0)|(5<<21); /* dmtc0 */ + o1 = OP_RRR(r, p->from.reg, 0, p->to.reg); + break; + + case 38: /* movw mr,r */ + r = SP(2,0)|(0<<21); /* mfc0 */ + if(p->as == AMOVV) + r = SP(2,0)|(1<<21); /* dmfc0 */ + o1 = OP_RRR(r, p->to.reg, 0, p->from.reg); + break; + + case 39: /* rfe ==> jmp+rfe */ + if(aflag) + return 0; + o1 = OP_RRR(oprrr(AJMP), 0, p->to.reg, REGZERO); + o2 = oprrr(p->as); + break; + + case 40: /* word */ + if(aflag) + return 0; + o1 = regoff(&p->to); + break; + + case 41: /* movw r,fcr */ + o1 = OP_RRR(SP(2,1)|(2<<21), REGZERO, 0, p->to.reg); /* mfcc1 */ + o2 = OP_RRR(SP(2,1)|(6<<21), p->from.reg, 0, p->to.reg);/* mtcc1 */ + break; + + case 42: /* movw fcr,r */ + o1 = OP_RRR(SP(2,1)|(2<<21), p->to.reg, 0, p->from.reg);/* mfcc1 */ + break; + + case 45: /* case r */ + if(p->link == P) + v = p->pc+28; + else + v = p->link->pc; + if(v & (1<<15)) + o1 = OP_IRR(opirr(ALAST), (v>>16)+1, REGZERO, REGTMP); + else + o1 = OP_IRR(opirr(ALAST), v>>16, REGZERO, REGTMP); + o2 = OP_SRR(opirr(ASLL), 2, p->from.reg, p->from.reg); + o3 = OP_RRR(oprrr(AADD), p->from.reg, REGTMP, REGTMP); + o4 = OP_IRR(opirr(AMOVW+ALAST), v, REGTMP, REGTMP); + o5 = OP_RRR(oprrr(ANOR), REGZERO, REGZERO, REGZERO); + o6 = OP_RRR(oprrr(AJMP), 0, REGTMP, REGZERO); + o7 = OP_RRR(oprrr(ANOR), REGZERO, REGZERO, REGZERO); + break; + + case 46: /* bcase $con,lbra */ + if(p->cond == P) + v = p->pc; + else + v = p->cond->pc; + o1 = v; + break; + } + if(aflag) + return o1; + v = p->pc; + switch(o->size) { + default: + if(debug['a']) + Bprint(&bso, " %.8lux:\t\t%P\n", v, p); + break; + case 4: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); + LPUT(o1); + break; + case 8: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p); + LPUT(o1); + LPUT(o2); + break; + case 12: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + break; + case 16: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + LPUT(o4); + break; + case 20: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + LPUT(o4); + LPUT(o5); + break; + + case 28: + if(debug['a']) + Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n", + v, o1, o2, o3, o4, o5, o6, o7, p); + LPUT(o1); + LPUT(o2); + LPUT(o3); + LPUT(o4); + LPUT(o5); + LPUT(o6); + LPUT(o7); + break; + } + return 0; +} + +int +isnop(Prog *p) +{ + if(p->as != ANOR) + return 0; + if(p->reg != REGZERO && p->reg != NREG) + return 0; + if(p->from.type != D_REG || p->from.reg != REGZERO) + return 0; + if(p->to.type != D_REG || p->to.reg != REGZERO) + return 0; + return 1; +} + +long +oprrr(int a) +{ + switch(a) { + case AADD: return OP(4,0); + case AADDU: return OP(4,1); + case ASGT: return OP(5,2); + case ASGTU: return OP(5,3); + case AAND: return OP(4,4); + case AOR: return OP(4,5); + case AXOR: return OP(4,6); + case ASUB: return OP(4,2); + case ASUBU: return OP(4,3); + case ANOR: return OP(4,7); + case ASLL: return OP(0,4); + case ASRL: return OP(0,6); + case ASRA: return OP(0,7); + + case AREM: + case ADIV: return OP(3,2); + case AREMU: + case ADIVU: return OP(3,3); + case AMUL: return OP(3,0); + case AMULU: return OP(3,1); + + case AJMP: return OP(1,0); + case AJAL: return OP(1,1); + + case ABREAK: return OP(1,5); + case ASYSCALL: return OP(1,4); + case ATLBP: return MMU(1,0); + case ATLBR: return MMU(0,1); + case ATLBWI: return MMU(0,2); + case ATLBWR: return MMU(0,6); + case ARFE: return MMU(2,0); + + case ADIVF: return FPF(0,3); + case ADIVD: return FPD(0,3); + case AMULF: return FPF(0,2); + case AMULD: return FPD(0,2); + case ASUBF: return FPF(0,1); + case ASUBD: return FPD(0,1); + case AADDF: return FPF(0,0); + case AADDD: return FPD(0,0); + + case AMOVFW: return FPF(4,4); + case AMOVDW: return FPD(4,4); + case AMOVWF: return FPW(4,0); + case AMOVDF: return FPD(4,0); + case AMOVWD: return FPW(4,1); + case AMOVFD: return FPF(4,1); + case AABSF: return FPF(0,5); + case AABSD: return FPD(0,5); + case AMOVF: return FPF(0,6); + case AMOVD: return FPD(0,6); + case ANEGF: return FPF(0,7); + case ANEGD: return FPD(0,7); + + case ACMPEQF: return FPF(6,2); + case ACMPEQD: return FPD(6,2); + case ACMPGTF: return FPF(7,4); + case ACMPGTD: return FPD(7,4); + case ACMPGEF: return FPF(7,6); + case ACMPGED: return FPD(7,6); + + case ADIVV: return OP(3,6); + case ADIVVU: return OP(3,7); + case AADDV: return OP(5,4); + case AADDVU: return OP(5,5); + } + diag("bad rrr %d", a); + return 0; +} + +long +opirr(int a) +{ + switch(a) { + case AADD: return SP(1,0); + case AADDU: return SP(1,1); + case ASGT: return SP(1,2); + case ASGTU: return SP(1,3); + case AAND: return SP(1,4); + case AOR: return SP(1,5); + case AXOR: return SP(1,6); + case ALAST: return SP(1,7); + case ASLL: return OP(0,0); + case ASRL: return OP(0,2); + case ASRA: return OP(0,3); + + case AJMP: return SP(0,2); + case AJAL: return SP(0,3); + case ABEQ: return SP(0,4); + case ABNE: return SP(0,5); + + case ABGEZ: return SP(0,1)|BCOND(0,1); + case ABGEZAL: return SP(0,1)|BCOND(2,1); + case ABGTZ: return SP(0,7); + case ABLEZ: return SP(0,6); + case ABLTZ: return SP(0,1)|BCOND(0,0); + case ABLTZAL: return SP(0,1)|BCOND(2,0); + + case ABFPT: return SP(2,1)|(257<<16); + case ABFPF: return SP(2,1)|(256<<16); + + case AMOVB: + case AMOVBU: return SP(5,0); + case AMOVH: + case AMOVHU: return SP(5,1); + case AMOVW: return SP(5,3); + case AMOVV: return SP(7,7); + case AMOVF: return SP(7,1); + case AMOVWL: return SP(5,2); + case AMOVWR: return SP(5,6); + case AMOVVL: return SP(5,4); + case AMOVVR: return SP(5,5); + + case ABREAK: return SP(5,7); + + case AMOVWL+ALAST: return SP(4,2); + case AMOVWR+ALAST: return SP(4,6); + case AMOVVL+ALAST: return SP(3,2); + case AMOVVR+ALAST: return SP(3,3); + case AMOVB+ALAST: return SP(4,0); + case AMOVBU+ALAST: return SP(4,4); + case AMOVH+ALAST: return SP(4,1); + case AMOVHU+ALAST: return SP(4,5); + case AMOVW+ALAST: return SP(4,3); + case AMOVV+ALAST: return SP(6,7); + case AMOVF+ALAST: return SP(6,1); + + case ASLLV: return OP(7,0); + case ASRLV: return OP(7,2); + case ASRAV: return OP(7,3); + case ASLLV+ALAST: return OP(7,4); + case ASRLV+ALAST: return OP(7,6); + case ASRAV+ALAST: return OP(7,7); + + case AADDV: return SP(3,0); + case AADDVU: return SP(3,1); + } + diag("bad irr %d", a); +abort(); + return 0; +} + +int +vshift(int a) +{ + switch(a){ + case ASLLV: return 1; + case ASRLV: return 1; + case ASRAV: return 1; + } + return 0; +} diff --git a/utils/vl/compat.c b/utils/vl/compat.c new file mode 100644 index 00000000..5e676913 --- /dev/null +++ b/utils/vl/compat.c @@ -0,0 +1,50 @@ +#include "l.h" + +/* + * fake malloc + */ +void* +malloc(long n) +{ + void *p; + + while(n & 7) + n++; + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void +free(void *p) +{ + USED(p); +} + +void* +calloc(long m, long n) +{ + void *p; + + n *= m; + p = malloc(n); + memset(p, 0, n); + return p; +} + +void* +realloc(void *p, long n) +{ + fprint(2, "realloc called\n", p, n); + abort(); + return 0; +} + +void* +mysbrk(ulong size) +{ + return sbrk(size); +} diff --git a/utils/vl/l.h b/utils/vl/l.h new file mode 100644 index 00000000..1cac8768 --- /dev/null +++ b/utils/vl/l.h @@ -0,0 +1,327 @@ +#include <lib9.h> +#include <bio.h> +#include "../vc/v.out.h" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Adr Adr; +typedef struct Sym Sym; +typedef struct Autom Auto; +typedef struct Prog Prog; +typedef struct Optab Optab; +typedef struct Oprang Oprang; +typedef uchar Opcross[32][2][32]; +typedef struct Count Count; + +#define P ((Prog*)0) +#define S ((Sym*)0) +#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) + +struct Adr +{ + union + { + long u0offset; + char* u0sval; + Ieee* u0ieee; + } u0; + union + { + Auto* u1autom; + Sym* u1sym; + } u1; + char type; + char reg; + char name; + char class; +}; + +#define offset u0.u0offset +#define sval u0.u0sval +#define ieee u0.u0ieee + +#define autom u1.u1autom +#define sym u1.u1sym + +struct Prog +{ + Adr from; + Adr to; + union + { + long u0regused; + Prog* u0forwd; + } u0; + Prog* cond; + Prog* link; + long pc; + long line; + uchar mark; + uchar optab; + char as; + char reg; +}; +#define regused u0.u0regused +#define forwd u0.u0forwd + +struct Sym +{ + char *name; + short type; + short version; + short become; + short frame; + long value; + Sym* link; +}; +struct Autom +{ + Sym* asym; + Auto* link; + long aoffset; + short type; +}; +struct Optab +{ + char as; + char a1; + char a2; + char a3; + char type; + char size; + char param; +}; +struct Oprang +{ + Optab* start; + Optab* stop; +}; +struct Count +{ + long count; + long outof; +}; + +enum +{ + STEXT = 1, + SDATA, + SBSS, + SDATA1, + SXREF, + SLEAF, + SFILE, + SCONST, + SSTRING, + + C_NONE = 0, + C_REG, + C_FREG, + C_FCREG, + C_MREG, + C_HI, + C_LO, + C_ZCON, + C_SCON, + C_ADD0CON, + C_AND0CON, + C_ADDCON, + C_ANDCON, + C_UCON, + C_LCON, + C_SACON, + C_SECON, + C_LACON, + C_LECON, + C_SBRA, + C_LBRA, + C_SAUTO, + C_SEXT, + C_LAUTO, + C_LEXT, + C_ZOREG, + C_SOREG, + C_LOREG, + C_GOK, + + NSCHED = 20, + +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + SYNC = 1<<3, + BRANCH = 1<<4, + LOAD = 1<<5, + FCMP = 1<<6, + NOSCHED = 1<<7, + + BIG = 32766, + STRINGSZ = 200, + NHASH = 10007, + NHUNK = 100000, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 20, /* limit of path elements for history symbols */ +}; + +EXTERN union +{ + struct + { + uchar obuf[MAXIO]; /* output buffer */ + uchar ibuf[MAXIO]; /* input buffer */ + } u; + char dbuf[1]; +} buf; + +#define cbuf u.obuf +#define xbuf u.ibuf + +EXTERN long HEADR; /* length of header */ +EXTERN int HEADTYPE; /* type of header */ +EXTERN long INITDAT; /* data location */ +EXTERN long INITRND; /* data round above text location */ +EXTERN long INITTEXT; /* text location */ +EXTERN char* INITENTRY; /* entry point */ +EXTERN long autosize; +EXTERN Biobuf bso; +EXTERN long bsssize; +EXTERN int cbc; +EXTERN uchar* cbp; +EXTERN int cout; +EXTERN Auto* curauto; +EXTERN Auto* curhist; +EXTERN Prog* curp; +EXTERN Prog* curtext; +EXTERN Prog* datap; +EXTERN long datsize; +EXTERN char debug[128]; +EXTERN Prog* etextp; +EXTERN Prog* firstp; +EXTERN char fnuxi4[4]; /* for 3l [sic] */ +EXTERN char fnuxi8[8]; +EXTERN char* noname; +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 Prog* lastp; +EXTERN long lcsize; +EXTERN char literal[32]; +EXTERN int nerrors; +EXTERN long nhunk; +EXTERN long instoffset; +EXTERN Opcross opcross[10]; +EXTERN Oprang oprange[ALAST]; +EXTERN char* outfile; +EXTERN long pc; +EXTERN uchar repop[ALAST]; +EXTERN long symsize; +EXTERN Prog* textp; +EXTERN long textsize; +EXTERN long thunk; +EXTERN int version; +EXTERN char xcmp[32][32]; +EXTERN Prog zprg; +EXTERN int dtype; + +EXTERN struct +{ + Count branch; + Count fcmp; + Count load; + Count mfrom; + Count page; + Count jump; +} nop; + +extern char* anames[]; +extern Optab optab[]; + +#pragma varargck type "A" int +#pragma varargck type "D" Adr* +#pragma varargck type "N" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "S" char* + +int Aconv(Fmt*); +int Dconv(Fmt*); +int Nconv(Fmt*); +int Pconv(Fmt*); +int Sconv(Fmt*); +int aclass(Adr*); +void addhist(long, int); +void addnop(Prog*); +void append(Prog*, Prog*); +void asmb(void); +void asmlc(void); +int asmout(Prog*, Optab*, int); +void asmsym(void); +long atolwhex(char*); +Prog* brloop(Prog*); +void buildop(void); +void buildrep(int, int); +void cflush(void); +int cmp(int, int); +int compound(Prog*); +double cputime(void); +void datblk(long, long, int); +void diag(char*, ...); +void dodata(void); +void doprof1(void); +void doprof2(void); +long entryvalue(void); +void errorexit(void); +void exchange(Prog*); +int find1(long, int); +void follow(void); +void gethunk(void); +void histtoauto(void); +double ieeedtod(Ieee*); +long ieeedtof(Ieee*); +int isnop(Prog*); +void ldobj(int, long, char*); +void loadlib(void); +void listinit(void); +Sym* lookup(char*, int); +void lput(long); +void mkfwd(void); +void* mysbrk(ulong); +void names(void); +void nocache(Prog*); +void noops(void); +void nuxiinit(void); +void objfile(char*); +int ocmp(const void*, const void*); +long opirr(int); +Optab* oplook(Prog*); +long oprrr(int); +void patch(void); +void prasm(Prog*); +void prepend(Prog*, Prog*); +Prog* prg(void); +int pseudo(Prog*); +void putsymb(char*, int, long, int); +long regoff(Adr*); +int relinv(int); +long rnd(long, long); +void sched(Prog*, Prog*); +void span(void); +void strnput(char*, int); +void undef(void); +void xdefine(char*, int, long); +void xfol(Prog*); +void xfol(Prog*); +void nopstat(char*, Count*); diff --git a/utils/vl/list.c b/utils/vl/list.c new file mode 100644 index 00000000..9261bc8e --- /dev/null +++ b/utils/vl/list.c @@ -0,0 +1,277 @@ +#include "l.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('D', Dconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('N', Nconv); +} + +void +prasm(Prog *p) +{ + print("%P\n", p); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ], *s; + Prog *p; + int a; + + p = va_arg(fp->args, Prog*); + curp = p; + a = p->as; + if(a == ADATA || a == ADYNT || a == AINIT) + sprint(str, "(%ld) %A %D/%d,%D", + p->line, a, &p->from, p->reg, &p->to); + else{ + s = str; + s += sprint(s, "(%ld)", p->line); + if(p->mark & NOSCHED) + s += sprint(s, "*"); + if(p->reg == NREG) + sprint(s, " %A %D,%D", + a, &p->from, &p->to); + else + if(p->from.type != D_FREG) + sprint(s, " %A %D,R%d,%D", + a, &p->from, p->reg, &p->to); + else + sprint(s, " %A %D,F%d,%D", + a, &p->from, p->reg, &p->to); + } + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + char *s; + int a; + + a = va_arg(fp->args, int); + s = "???"; + if(a >= AXXX && a < ALAST) + s = anames[a]; + return fmtstrcpy(fp, s); +} + +int +Dconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + long v; + + a = va_arg(fp->args, Adr*); + switch(a->type) { + + default: + sprint(str, "GOK-type(%d)", a->type); + break; + + case D_NONE: + str[0] = 0; + if(a->name != D_NONE || a->reg != NREG || a->sym != S) + sprint(str, "%N(R%d)(NONE)", a, a->reg); + break; + + case D_CONST: + sprint(str, "$%N", a); + if(a->reg != NREG) + sprint(str, "%N(R%d)(CONST)", a, a->reg); + break; + + case D_OCONST: + sprint(str, "$*$%N", a); + if(a->reg != NREG) + sprint(str, "%N(R%d)(CONST)", a, a->reg); + break; + + case D_OREG: + if(a->reg != NREG) + sprint(str, "%N(R%d)", a, a->reg); + else + sprint(str, "%N", a); + break; + + case D_REG: + sprint(str, "R%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_MREG: + sprint(str, "M%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FREG: + sprint(str, "F%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_FCREG: + sprint(str, "FC%d", a->reg); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(R%d)(REG)", a, a->reg); + break; + + case D_LO: + sprint(str, "LO"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(LO)(REG)", a); + break; + + case D_HI: + sprint(str, "HI"); + if(a->name != D_NONE || a->sym != S) + sprint(str, "%N(HI)(REG)", a); + break; + + case D_BRANCH: /* botch */ + if(curp->cond != P) { + v = curp->cond->pc; + if(v >= INITTEXT) + v -= INITTEXT-HEADR; + if(a->sym != S) + sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v); + else + sprint(str, "%.5lux(BRANCH)", v); + } else + if(a->sym != S) + sprint(str, "%s+%ld(APC)", a->sym->name, a->offset); + else + sprint(str, "%ld(APC)", a->offset); + break; + + case D_FCONST: + sprint(str, "$%e", ieeedtod(a->ieee)); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + } + return fmtstrcpy(fp, str); +} + +int +Nconv(Fmt *fp) +{ + char str[STRINGSZ]; + Adr *a; + Sym *s; + + a = va_arg(fp->args, Adr*); + s = a->sym; + switch(a->name) { + default: + sprint(str, "GOK-name(%d)", a->name); + break; + + case D_NONE: + sprint(str, "%ld", a->offset); + break; + + case D_EXTERN: + if(s == S) + sprint(str, "%ld(SB)", a->offset); + else + sprint(str, "%s+%ld(SB)", s->name, a->offset); + break; + + case D_STATIC: + if(s == S) + sprint(str, "<>+%ld(SB)", a->offset); + else + sprint(str, "%s<>+%ld(SB)", s->name, a->offset); + break; + + case D_AUTO: + if(s == S) + sprint(str, "%ld(SP)", a->offset); + else + sprint(str, "%s-%ld(SP)", s->name, -a->offset); + break; + + case D_PARAM: + if(s == S) + sprint(str, "%ld(FP)", a->offset); + else + sprint(str, "%s+%ld(FP)", s->name, a->offset); + break; + } + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[STRINGSZ], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(long); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == ' ' || c == '%') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + 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 > 10) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/utils/vl/mkfile b/utils/vl/mkfile new file mode 100644 index 00000000..b84163a6 --- /dev/null +++ b/utils/vl/mkfile @@ -0,0 +1,31 @@ +<../../mkconfig + +TARG=vl + +OFILES=\ + asm.$O\ + list.$O\ + noop.$O\ + sched.$O\ + obj.$O\ + optab.$O\ + pass.$O\ + span.$O\ + enam.$O\ + $TARGMODEL.$O\ + +HFILES=\ + l.h\ + ../vc/v.out.h\ + ../include/ar.h\ + +LIBS=bio 9 # order is important + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include + +enam.$O: ../vc/enam.c + $CC $CFLAGS ../vc/enam.c diff --git a/utils/vl/noop.c b/utils/vl/noop.c new file mode 100644 index 00000000..337e947d --- /dev/null +++ b/utils/vl/noop.c @@ -0,0 +1,416 @@ +#include "l.h" + +void +noops(void) +{ + Prog *p, *p1, *q, *q1; + int o, curframe, curbecome, maxbecome; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + + q = P; + for(p = firstp; p != P; p = p->link) { + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + 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; + + p->mark |= LABEL|LEAF|SYNC; + if(p->link) + p->link->mark |= LABEL; + curtext = p; + break; + + /* too hard, just leave alone */ + case AMOVW: + if(p->to.type == D_FCREG || + p->to.type == D_MREG) { + p->mark |= LABEL|SYNC; + break; + } + if(p->from.type == D_FCREG || + p->from.type == D_MREG) { + p->mark |= LABEL|SYNC; + addnop(p); + addnop(p); + nop.mfrom.count += 2; + nop.mfrom.outof += 2; + break; + } + break; + + /* too hard, just leave alone */ + case ACASE: + case ASYSCALL: + case AWORD: + case ATLBWR: + case ATLBWI: + case ATLBP: + case ATLBR: + p->mark |= LABEL|SYNC; + break; + + case ANOR: + if(p->to.type == D_REG && p->to.reg == REGZERO) + p->mark |= LABEL|SYNC; + break; + + case ARET: + /* special form of RET is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + + if(p->link != P) + p->link->mark |= LABEL; + break; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + case ABCASE: + p->mark |= LABEL|SYNC; + goto dstlab; + + case ABGEZAL: + case ABLTZAL: + case AJAL: + if(curtext != P) + curtext->mark &= ~LEAF; + + case AJMP: + case ABEQ: + case ABGEZ: + case ABGTZ: + case ABLEZ: + case ABLTZ: + case ABNE: + case ABFPT: + case ABFPF: + p->mark |= BRANCH; + + dstlab: + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + if(!(q1->mark & LEAF)) + q1->mark |= LABEL; + } else + p->mark |= LABEL; + q1 = p->link; + if(q1 != P) + q1->mark |= LABEL; + break; + } + q = p; + } + + 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 AJAL: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + for(p = firstp; p != P; p = p->link) { + o = p->as; + switch(o) { + case ATEXT: + curtext = p; + autosize = p->to.offset + 4; + if(autosize <= 4) + if(curtext->mark & LEAF) { + p->to.offset = -4; + autosize = 0; + } + + q = p; + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = -autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } else + if(!(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + Bflush(&bso); + curtext->mark |= LEAF; + } + + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; + break; + } + + q1 = prg(); + q1->as = AMOVW; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->from.offset = 0; + q1->to.reg = REGSP; + + q1->link = q->link; + q->link = q1; + break; + + case ARET: + nocache(p); + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + p->as = AJMP; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + p->mark |= BRANCH; + break; + } + + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + + q = prg(); + q->as = AJMP; + q->line = p->line; + q->to.type = D_OREG; + q->to.offset = 0; + q->to.reg = REGLINK; + q->mark |= BRANCH; + + q->link = p->link; + p->link = q; + break; + } + p->as = AMOVW; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = 2; + + q = p; + if(autosize) { + q = prg(); + q->as = AADD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + + q1 = prg(); + q1->as = AJMP; + q1->line = p->line; + q1->to.type = D_OREG; + q1->to.offset = 0; + q1->to.reg = 2; + q1->mark |= BRANCH; + + q1->link = q->link; + q->link = q1; + break; + + become: + if(curtext->mark & LEAF) { + + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; + } + q = prg(); + q->line = p->line; + q->as = AJMP; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + q->mark |= BRANCH; + p->link = q; + + q = prg(); + q->line = p->line; + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + + p->as = AMOVW; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = 0; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGLINK; + + break; + } + } + + curtext = P; + q = P; /* p - 1 */ + q1 = firstp; /* top of block */ + o = 0; /* count of instructions */ + for(p = firstp; p != P; p = p1) { + p1 = p->link; + o++; + if(p->mark & NOSCHED){ + if(q1 != p){ + sched(q1, q); + } + for(; p != P; p = p->link){ + if(!(p->mark & NOSCHED)) + break; + q = p; + } + p1 = p; + q1 = p; + o = 0; + continue; + } + if(p->mark & (LABEL|SYNC)) { + if(q1 != p) + sched(q1, q); + q1 = p; + o = 1; + } + if(p->mark & (BRANCH|SYNC)) { + sched(q1, p); + q1 = p1; + o = 0; + } + if(o >= NSCHED) { + sched(q1, p); + q1 = p1; + o = 0; + } + q = p; + } +} + +void +addnop(Prog *p) +{ + Prog *q; + + q = prg(); + q->as = ANOR; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGZERO; + q->to.type = D_REG; + q->to.reg = REGZERO; + + q->link = p->link; + p->link = q; +} + +void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} diff --git a/utils/vl/obj.c b/utils/vl/obj.c new file mode 100644 index 00000000..26c80683 --- /dev/null +++ b/utils/vl/obj.c @@ -0,0 +1,1332 @@ +#define EXTERN +#include "l.h" +#include <ar.h> + +#ifndef DEFAULT +#define DEFAULT '9' +#endif + +char *noname = "<none>"; +char symname[] = SYMDEF; +char thechar = 'v'; +char *thestring = "mips"; + +/* + * -H0 -T0x40004C -D0x10000000 is abbrev unix + * -H1 -T0x80020000 -R4 is bootp() format for 3k + * -H2 -T4128 -R4096 is plan9 format + * -H3 -T0x80020000 -R8 is bootp() format for 4k + * -H4 -T0x400000 -R4 is sgi unix coff executable + * -H5 -T0x4000A0 -R4 is sgi unix elf executable + */ + +void +main(int argc, char *argv[]) +{ + int c; + char *a; + + Binit(&bso, 1, OWRITE); + cout = -1; + listinit(); + outfile = 0; + nerrors = 0; + curtext = P; + 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': + outfile = ARGF(); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = 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 'H': + a = ARGF(); + if(a) + HEADTYPE = atolwhex(a); + /* do something about setting INITTEXT */ + break; + } ARGEND + + USED(argc); + + if(*argv == 0) { + diag("usage: vl [-options] objects"); + errorexit(); + } + if(!debug['9'] && !debug['U'] && !debug['B']) + debug[DEFAULT] = 1; + if(HEADTYPE == -1) { + if(debug['U']) + HEADTYPE = 0; + if(debug['B']) + HEADTYPE = 1; + if(debug['9']) + HEADTYPE = 2; + } + switch(HEADTYPE) { + default: + diag("unknown -H option"); + errorexit(); + + case 0: /* unix simple */ + HEADR = 20L+56L; + if(INITTEXT == -1) + INITTEXT = 0x40004CL; + if(INITDAT == -1) + INITDAT = 0x10000000L; + if(INITRND == -1) + INITRND = 0; + break; + case 1: /* boot for 3k */ + HEADR = 20L+60L; + if(INITTEXT == -1) + INITTEXT = 0x80020000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; + case 2: /* plan 9 */ + HEADR = 32L; + if(INITTEXT == -1) + INITTEXT = 4128; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4096; + break; + case 3: /* boot for 4k */ + HEADR = 20L+56L+3*40L; + if(INITTEXT == -1) + INITTEXT = 0x80020000L; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 8; + break; + case 4: /* sgi unix coff executable */ + HEADR = 20L+56L+3*40L; + if(INITTEXT == -1) + INITTEXT = 0x00400000L+HEADR; + if(INITDAT == -1) + INITDAT = 0x10000000; + if(INITRND == -1) + INITRND = 0; + break; + case 5: /* sgi unix elf executable */ + HEADR = rnd(52L+3*32L, 16); + if(INITTEXT == -1) + INITTEXT = 0x00400000L+HEADR; + if(INITDAT == -1) + INITDAT = 0x10000000; + if(INITRND == -1) + INITRND = 0; + 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%d -T0x%lux -D0x%lux -R0x%lux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + zprg.as = AGOK; + zprg.reg = NREG; + zprg.from.name = D_NONE; + zprg.from.type = D_NONE; + zprg.from.reg = NREG; + zprg.to = zprg.from; + buildop(); + histgen = 0; + textp = P; + datap = P; + pc = 0; + dtype = 4; + if(outfile == 0) + outfile = "v.out"; + cout = create(outfile, 1, 0775); + if(cout < 0) { + diag("%s: cannot create", outfile); + errorexit(); + } + nuxiinit(); + + 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) + goto out; + patch(); + if(debug['p']) + if(debug['1']) + doprof1(); + else + doprof2(); + dodata(); + follow(); + if(firstp == P) + goto out; + noops(); + span(); + asmb(); + undef(); + +out: + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + 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; + } + + if(debug['v']) + Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file); + 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 i, c; + long l; + Sym *s; + Auto *u; + + c = p[2]; + if(c < 0 || c > NSYM){ + print("sym out of range: %d\n", c); + p[0] = ALAST+1; + return 0; + } + a->type = p[0]; + a->reg = p[1]; + a->sym = h[c]; + a->name = p[3]; + c = 4; + + if(a->reg < 0 || a->reg > NREG) { + print("register out of range %d\n", a->reg); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + } + + switch(a->type) { + default: + print("unknown type %d\n", a->type); + p[0] = ALAST+1; + return 0; /* force real diagnostic */ + + case D_NONE: + case D_REG: + case D_FREG: + case D_MREG: + case D_FCREG: + case D_LO: + case D_HI: + break; + + case D_BRANCH: + case D_OREG: + case D_CONST: + case D_OCONST: + a->offset = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + c += 4; + break; + + case D_SCONST: + while(nhunk < NSNAME) + gethunk(); + a->sval = (char*)hunk; + nhunk -= NSNAME; + hunk += NSNAME; + + memmove(a->sval, p+4, NSNAME); + c += NSNAME; + break; + + case D_FCONST: + while(nhunk < sizeof(Ieee)) + gethunk(); + a->ieee = (Ieee*)hunk; + nhunk -= NSNAME; + hunk += NSNAME; + + a->ieee->l = p[4] | (p[5]<<8) | + (p[6]<<16) | (p[7]<<24); + a->ieee->h = p[8] | (p[9]<<8) | + (p[10]<<16) | (p[11]<<24); + c += 8; + break; + } + s = a->sym; + if(s == S) + return c; + i = a->name; + if(i != D_AUTO && i != D_PARAM) + return c; + + l = a->offset; + for(u=curauto; u; u=u->link) + if(u->asym == s) + if(u->type == i) { + 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 = i; + 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; + Sym *h[NSYM], *s, *di; + int v, o, r, skip; + + 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]; /* as */ + if(o <= AXXX || o >= ALAST) { + diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o); + print(" probably not a .v file\n"); + errorexit(); + } + if(o == ANAME || o == ASIGNAME) { + if(o == ASIGNAME) { + bloc += 4; + c -= 4; + } + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + bsize = readsome(f, buf.xbuf, bloc, bsize, c); + if(bsize == 0) + goto eof; + bloc = buf.xbuf; + stop = memchr(&bloc[3], 0, bsize-&bloc[3]); + if(stop == 0){ + fprint(2, "%s: name too long\n", pn); + errorexit(); + } + } + v = bloc[1]; /* type */ + o = bloc[2]; /* sym */ + bloc += 3; + c -= 3; + + r = 0; + if(v == D_STATIC) + r = version; + s = lookup((char*)bloc, r); + c -= &stop[1] - bloc; + bloc = stop + 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; + } + + if(nhunk < sizeof(Prog)) + gethunk(); + p = (Prog*)hunk; + nhunk -= sizeof(Prog); + hunk += sizeof(Prog); + + p->as = o; + p->reg = bloc[1] & 0x7f; + if(bloc[1] & 0x80) + p->mark = NOSCHED; + p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24); + + r = zaddr(bloc+6, &p->from, h) + 6; + r += zaddr(bloc+r, &p->to, h); + bloc += r; + c -= r; + + if(p->reg < 0 || p->reg > NREG) + diag("register out of range %d", p->reg); + + p->link = P; + p->cond = P; + + if(debug['W']) + print("%P\n", p); + + switch(o) { + 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 == S) { + diag("GLOBL must have a name\n%P", p); + errorexit(); + } + if(s->type == 0 || s->type == SXREF) { + s->type = SBSS; + s->value = 0; + } + if(s->type != SBSS) { + diag("redefinition: %s\n%P", s->name, p); + s->type = SBSS; + s->value = 0; + } + if(p->to.offset > s->value) + s->value = p->to.offset; + break; + + case ADYNT: + if(p->to.sym == S) { + diag("DYNT without a sym\n%P", p); + break; + } + di = p->to.sym; + p->reg = 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_CONST; + p->link = datap; + datap = p; + break; + + 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; + p->link = datap; + datap = p; + break; + + case ADATA: + if(p->from.sym == S) { + diag("DATA without a sym\n%P", p); + break; + } + p->link = datap; + datap = p; + break; + + case AGOK: + diag("unknown opcode\n%P", p); + p->pc = pc; + pc++; + break; + + case ATEXT: + if(curtext != P) { + histtoauto(); + curtext->to.autom = curauto; + curauto = 0; + } + skip = 0; + curtext = p; + autosize = (p->to.offset+3L) & ~3L; + p->to.offset = autosize; + autosize += 4; + s = p->from.sym; + if(s == S) { + diag("TEXT must have a name\n%P", p); + errorexit(); + } + if(s->type != 0 && s->type != SXREF) { + if(p->reg & DUPOK) { + skip = 1; + goto casedef; + } + diag("redefinition: %s\n%P", 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->cond = p; + etextp = p; + break; + + case ASUB: + case ASUBU: + if(p->from.type == D_CONST) + if(p->from.name == D_NONE) { + p->from.offset = -p->from.offset; + if(p->as == ASUB) + p->as = AADD; + else + p->as = AADDU; + } + goto casedef; + + case AMOVF: + if(skip) + goto casedef; + + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 4; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + case AMOVD: + if(skip) + goto casedef; + + 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_OREG; + t->from.sym = s; + t->from.name = D_EXTERN; + t->reg = 8; + t->to = p->from; + t->link = datap; + datap = t; + } + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + } + goto casedef; + + default: + casedef: + if(skip) + nopout(p); + + if(p->to.type == D_BRANCH) + p->to.offset += ipc; + lastp->link = p; + lastp = p; + p->pc = pc; + pc++; + break; + } + goto loop; + +eof: + diag("truncated object file: %s", pn); +} + +Sym* +lookup(char *symb, int v) +{ + Sym *s; + char *p; + long h; + int c, l; + + 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); + memmove(s->name, symb, l); + + s->link = hash[h]; + s->type = 0; + s->version = v; + s->value = 0; + hash[h] = s; + 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; +} + +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_OREG; + q->from.name = D_EXTERN; + q->from.offset = n*4; + q->from.sym = s; + q->reg = 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 = AMOVW; + p->from.type = D_OREG; + p->from.name = D_EXTERN; + p->from.sym = s; + p->from.offset = n*4 + 4; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AADDU; + p->from.type = D_CONST; + p->from.offset = 1; + p->to.type = D_REG; + p->to.reg = REGTMP; + + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_OREG; + p->to.name = 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_OREG; + q->from.name = D_EXTERN; + q->from.sym = s; + q->reg = 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) { + ps2 = p; + p->reg = 1; + } + if(p->from.sym == s4) { + ps4 = p; + p->reg = 1; + } + } + } + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) { + if(p->reg & NOPROF) { + for(;;) { + q = p->link; + if(q == P) + break; + if(q->as == ATEXT) + break; + p = q; + } + continue; + } + + /* + * JAL profin, R2 + */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + p->as = AJAL; + p->to.type = D_BRANCH; + p->cond = 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 = AJAL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + + p = q; + + continue; + } + } +} + +void +nuxiinit(void) +{ + int i, c; + + for(i=0; i<4; i++) { + c = find1(0x01020304L, i+1); + if(i >= 2) + inuxi2[i-2] = c; + if(i >= 3) + inuxi1[i-3] = c; + inuxi4[i] = c; + + fnuxi8[i] = c+4; + fnuxi8[i+4] = c; + } + 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<8; i++) + Bprint(&bso, "%d", fnuxi8[i]); + Bprint(&bso, "\n"); + } + Bflush(&bso); +} + +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; +} + +long +ieeedtof(Ieee *ieeep) +{ + int exp; + long v; + + if(ieeep->h == 0) + return 0; + exp = (ieeep->h>>20) & ((1L<<11)-1L); + exp -= (1L<<10) - 2L; + v = (ieeep->h & 0xfffffL) << 3; + v |= (ieeep->l >> 29) & 0x7L; + if((ieeep->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 |= ieeep->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); +} diff --git a/utils/vl/optab.c b/utils/vl/optab.c new file mode 100644 index 00000000..858ecacc --- /dev/null +++ b/utils/vl/optab.c @@ -0,0 +1,232 @@ +#include "l.h" + +/* note: not finished + * movd fr,mem + * movd mem,fr + * addv + * addvu + * subv + * subvu + * mulv + * mulvu + * divv + * divvu + * remv + * remvu + */ + +#define X 99 + +Optab optab[] = +{ + { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, + { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, + + { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0 }, + { AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0 }, + { AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0 }, + + { ASUB, C_REG, C_REG, C_REG, 2, 4, 0 }, + { AADD, C_REG, C_REG, C_REG, 2, 4, 0 }, + { AAND, C_REG, C_REG, C_REG, 2, 4, 0 }, + { ASUB, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AADD, C_REG, C_NONE, C_REG, 2, 4, 0 }, + { AAND, C_REG, C_NONE, C_REG, 2, 4, 0 }, + + { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, + { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, + + { AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0 }, + { AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0 }, + { ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0 }, + { AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0 }, + { AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0 }, + { AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, + { AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + + { AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB }, + { AMOVW, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVV, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVB, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVBU, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVWL, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVV, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVB, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVBU, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + { AMOVWL, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO }, + + { AMOVW, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVV, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVB, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVBU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB }, + { AMOVW, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVV, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVB, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP }, + { AMOVW, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + { AMOVV, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + { AMOVB, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + { AMOVBU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO }, + + { AMOVW, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVV, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVB, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVBU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB }, + { AMOVW, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVV, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVB, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVBU, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP }, + { AMOVW, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + { AMOVV, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + { AMOVB, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + { AMOVBU, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO }, + + { AMOVW, C_SECON,C_NONE, C_REG, 3, 4, REGSB }, + { AMOVW, C_SACON,C_NONE, C_REG, 3, 4, REGSP }, + { AMOVW, C_LECON,C_NONE, C_REG, 26, 12, REGSB }, + { AMOVW, C_LACON,C_NONE, C_REG, 26, 12, REGSP }, + { AMOVW, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO }, + { AMOVW, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO }, + + { AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0 }, + { AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0 }, + + { AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0 }, + { AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0 }, + { AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0 }, + { AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0 }, + { AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0 }, + + { AMUL, C_REG, C_REG, C_NONE, 22, 4, 0 }, + + { AADD, C_ADD0CON,C_REG,C_REG, 4, 4, 0 }, + { AADD, C_ADD0CON,C_NONE,C_REG, 4, 4, 0 }, + { AADD, C_ANDCON,C_REG, C_REG, 10, 8, 0 }, + { AADD, C_ANDCON,C_NONE,C_REG, 10, 8, 0 }, + + { AAND, C_AND0CON,C_REG,C_REG, 4, 4, 0 }, + { AAND, C_AND0CON,C_NONE,C_REG, 4, 4, 0 }, + { AAND, C_ADDCON,C_REG, C_REG, 10, 8, 0 }, + { AAND, C_ADDCON,C_NONE,C_REG, 10, 8, 0 }, + + { AADD, C_UCON, C_REG, C_REG, 25, 8, 0 }, + { AADD, C_UCON, C_NONE, C_REG, 25, 8, 0 }, + { AAND, C_UCON, C_REG, C_REG, 25, 8, 0 }, + { AAND, C_UCON, C_NONE, C_REG, 25, 8, 0 }, + + { AADD, C_LCON, C_NONE, C_REG, 23, 12, 0 }, + { AAND, C_LCON, C_NONE, C_REG, 23, 12, 0 }, + { AADD, C_LCON, C_REG, C_REG, 23, 12, 0 }, + { AAND, C_LCON, C_REG, C_REG, 23, 12, 0 }, + + { ASLL, C_SCON, C_REG, C_REG, 16, 4, 0 }, + { ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0 }, + + { ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0 }, + + { ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0 }, + { ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0 }, + { ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0 }, + { ABFPT, C_NONE, C_NONE, C_SBRA, 6, 4, 0 }, + + { AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, + { AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0 }, + + { AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO }, + { AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK }, + + { AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB }, + { AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB }, + { AMOVD, C_SEXT, C_NONE, C_FREG, 27, 8, REGSB }, + { AMOVW, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP }, + { AMOVF, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP }, + { AMOVD, C_SAUTO,C_NONE, C_FREG, 27, 8, REGSP }, + { AMOVW, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO }, + { AMOVF, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO }, + { AMOVD, C_SOREG,C_NONE, C_FREG, 27, 8, REGZERO }, + + { AMOVW, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB }, + { AMOVF, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB }, + { AMOVD, C_LEXT, C_NONE, C_FREG, 27, 20, REGSB }, + { AMOVW, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP }, + { AMOVF, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP }, + { AMOVD, C_LAUTO,C_NONE, C_FREG, 27, 20, REGSP }, + { AMOVW, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO }, + { AMOVF, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO }, + { AMOVD, C_LOREG,C_NONE, C_FREG, 27, 20, REGZERO }, + + { AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB }, + { AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB }, + { AMOVD, C_FREG, C_NONE, C_SEXT, 28, 8, REGSB }, + { AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP }, + { AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP }, + { AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 8, REGSP }, + { AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO }, + { AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO }, + { AMOVD, C_FREG, C_NONE, C_SOREG, 28, 8, REGZERO }, + + { AMOVW, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB }, + { AMOVF, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB }, + { AMOVD, C_FREG, C_NONE, C_LEXT, 28, 20, REGSB }, + { AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP }, + { AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP }, + { AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 20, REGSP }, + { AMOVW, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO }, + { AMOVF, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO }, + { AMOVD, C_FREG, C_NONE, C_LOREG, 28, 20, REGZERO }, + + { AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0 }, + { AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0 }, + + { AMOVW, C_ADDCON,C_NONE,C_FREG, 34, 8, 0 }, + { AMOVW, C_ANDCON,C_NONE,C_FREG, 34, 8, 0 }, + { AMOVW, C_UCON, C_NONE, C_FREG, 35, 8, 0 }, + { AMOVW, C_LCON, C_NONE, C_FREG, 36, 12, 0 }, + + { AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0 }, + { AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0 }, + { AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0 }, + { AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0 }, + + { ARFE, C_NONE, C_NONE, C_ZOREG, 39, 8, 0 }, + { AWORD, C_NONE, C_NONE, C_LCON, 40, 4, 0 }, + + { AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0 }, + { AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0 }, + { AMOVW, C_FCREG,C_NONE, C_REG, 42, 4, 0 }, + { AMOVV, C_FCREG,C_NONE, C_REG, 42, 4, 0 }, + + { ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, /* really CACHE instruction */ + { ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP }, + { ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO }, + { ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0 }, + + { ACASE, C_REG, C_NONE, C_NONE, 45, 28, 0 }, + { ABCASE, C_LCON, C_NONE, C_LBRA, 46, 4, 0 }, + + { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, +}; diff --git a/utils/vl/pass.c b/utils/vl/pass.c new file mode 100644 index 00000000..7dc2e5dd --- /dev/null +++ b/utils/vl/pass.c @@ -0,0 +1,505 @@ +#include "l.h" + +void +dodata(void) +{ + int i, t; + Sym *s; + Prog *p, *p1; + long orig, orig1, v; + + 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); + v = p->from.offset + p->reg; + if(v > s->value) + diag("initialize bounds (%ld): %s\n%P", + s->value, s->name, p); + } + + if(debug['t']) { + /* + * pull out string constants + */ + for(p = datap; p != P; p = p->link) { + s = p->from.sym; + if(p->to.type == D_SCONST) + s->type = SSTRING; + } + } + + /* + * pass 1 + * assign 'small' variables to data segment + * (rational is that data segment is more easily + * addressed through offset on R30) + */ + orig = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA && t != SBSS) + continue; + v = s->value; + if(v == 0) { + diag("%s: no size", s->name); + v = 1; + } + while(v & 3) + v++; + s->value = v; + if(v > MINSIZ) + continue; + s->value = orig; + orig += v; + s->type = SDATA1; + } + orig1 = orig; + + /* + * pass 2 + * assign 'data' variables to data segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t != SDATA) { + if(t == SDATA1) + s->type = SDATA; + continue; + } + v = s->value; + s->value = orig; + orig += v; + s->type = SDATA1; + } + + while(orig & 7) + orig++; + datsize = orig; + + /* + * pass 3 + * everything else to bss segment + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SBSS) + continue; + v = s->value; + s->value = orig; + orig += v; + } + while(orig & 7) + orig++; + bsssize = orig-datsize; + + /* + * pass 4 + * add literals to all large values. + * at this time: + * small data is allocated DATA + * large data is allocated DATA1 + * large bss is allocated BSS + * the new literals are loaded between + * small data and large data. + */ + orig = 0; + for(p = firstp; p != P; p = p->link) { + if(p->as != AMOVW) + continue; + if(p->from.type != D_CONST) + continue; + if(s = p->from.sym) { + t = s->type; + if(t != SDATA && t != SDATA1 && t != SBSS) + continue; + t = p->from.name; + if(t != D_EXTERN && t != D_STATIC) + continue; + v = s->value + p->from.offset; + if(v >= 0 && v <= 0xffff) + continue; + if(!strcmp(s->name, "setR30")) + continue; + /* size should be 19 max */ + if(strlen(s->name) >= 10) /* has loader address */ + sprint(literal, "$%lux.%lux", (long)s, p->from.offset); + else + sprint(literal, "$%s.%d.%lux", s->name, s->version, p->from.offset); + } else { + if(p->from.name != D_NONE) + continue; + if(p->from.reg != NREG) + continue; + v = p->from.offset; + if(v >= -0x7fff && v <= 0xffff) + continue; + if(!(v & 0xffff)) + continue; + /* size should be 9 max */ + sprint(literal, "$%lux", v); + } + s = lookup(literal, 0); + if(s->type == 0) { + s->type = SDATA; + s->value = orig1+orig; + orig += 4; + p1 = prg(); + p1->line = p->line; + p1->as = ADATA; + p1->from.type = D_OREG; + p1->from.sym = s; + p1->from.name = D_EXTERN; + p1->reg = 4; + p1->to = p->from; + p1->link = datap; + datap = p1; + } + if(s->type != SDATA) + diag("literal not data: %s", s->name); + p->from.type = D_OREG; + p->from.sym = s; + p->from.name = D_EXTERN; + p->from.offset = 0; + nocache(p); + continue; + } + while(orig & 7) + orig++; + /* + * pass 5 + * re-adjust offsets + */ + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + t = s->type; + if(t == SBSS) { + s->value += orig; + continue; + } + if(t == SDATA1) { + s->type = SDATA; + s->value += orig; + continue; + } + } + datsize += orig; + xdefine("setR30", SDATA, 0L+BIG); + xdefine("bdata", SDATA, 0L); + xdefine("edata", SDATA, datsize); + xdefine("end", SBSS, datsize+bsssize); + xdefine("etext", STEXT, 0L); +} + +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 +follow(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + firstp = prg(); + lastp = firstp; + xfol(textp); + + firstp = firstp->link; + lastp->link = P; +} + +void +xfol(Prog *p) +{ + Prog *q, *r; + int a, i; + +loop: + if(p == P) + return; + a = p->as; + if(a == ATEXT) + curtext = p; + if(a == AJMP) { + q = p->cond; + if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){ + p->mark |= FOLL; + lastp->link = p; + lastp = p; + p = p->link; + xfol(p); + p = q; + if(p && !(p->mark & FOLL)) + goto loop; + return; + } + if(q != P) { + p->mark |= FOLL; + p = q; + if(!(p->mark & FOLL)) + goto loop; + } + } + if(p->mark & FOLL) { + for(i=0,q=p; i<4; i++,q=q->link) { + if(q == lastp || (q->mark&NOSCHED)) + break; + a = q->as; + if(a == ANOP) { + i--; + continue; + } + if(a == AJMP || a == ARET || a == ARFE) + goto copy; + if(!q->cond || (q->cond->mark&FOLL)) + continue; + if(a != ABEQ && a != ABNE) + continue; + copy: + for(;;) { + r = prg(); + *r = *p; + if(!(r->mark&FOLL)) + print("cant happen 1\n"); + r->mark |= FOLL; + if(p != q) { + p = p->link; + lastp->link = r; + lastp = r; + continue; + } + lastp->link = r; + lastp = r; + if(a == AJMP || a == ARET || a == ARFE) + return; + r->as = ABNE; + if(a == ABNE) + r->as = ABEQ; + r->cond = p->link; + r->link = p->cond; + if(!(r->link->mark&FOLL)) + xfol(r->link); + if(!(r->cond->mark&FOLL)) + print("cant happen 2\n"); + return; + } + } + a = AJMP; + q = prg(); + q->as = a; + q->line = p->line; + q->to.type = D_BRANCH; + q->to.offset = p->pc; + q->cond = p; + p = q; + } + p->mark |= FOLL; + lastp->link = p; + lastp = p; + if(a == AJMP || a == ARET || a == ARFE){ + if(p->mark & NOSCHED){ + p = p->link; + goto loop; + } + return; + } + if(p->cond != P) + if(a != AJAL && p->link != P) { + xfol(p->link); + p = p->cond; + if(p == P || (p->mark&FOLL)) + return; + goto loop; + } + p = p->link; + goto loop; +} + +void +patch(void) +{ + long c, vexit; + Prog *p, *q; + Sym *s; + int a; + + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + mkfwd(); + s = lookup("exit", 0); + vexit = s->value; + for(p = firstp; p != P; p = p->link) { + a = p->as; + if(a == ATEXT) + curtext = p; + if((a == AJAL || a == AJMP || a == ARET) && + p->to.type != D_BRANCH && p->to.sym != S) { + s = p->to.sym; + if(s->type != STEXT) { + diag("undefined: %s\n%P", s->name, p); + s->type = STEXT; + s->value = vexit; + } + p->to.offset = s->value; + p->to.type = D_BRANCH; + } + if(p->to.type != D_BRANCH) + 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 %ld\n%P", c, p); + p->to.type = D_NONE; + } + p->cond = q; + } + + for(p = firstp; p != P; p = p->link) { + if(p->as == ATEXT) + curtext = p; + if(p->cond != P) { + p->cond = brloop(p->cond); + if(p->cond != P) + if(p->to.type == D_BRANCH) + p->to.offset = p->cond->pc; + } + } +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + long dwn[LOG], cnt[LOG], i; + 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) +{ + Prog *q; + int c; + + for(c=0; p!=P;) { + if(p->as != AJMP || (p->mark&NOSCHED)) + return p; + q = p->cond; + if(q <= p) { + c++; + if(q == p || c > 5000) + break; + } + p = q; + } + return P; +} + +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; +} + +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; +} diff --git a/utils/vl/sched.c b/utils/vl/sched.c new file mode 100644 index 00000000..efa88a75 --- /dev/null +++ b/utils/vl/sched.c @@ -0,0 +1,695 @@ +#include "l.h" + +enum +{ + E_HILO = 1<<0, + E_FCR = 1<<1, + E_MCR = 1<<2, + E_MEM = 1<<3, + E_MEMSP = 1<<4, /* uses offset and size */ + E_MEMSB = 1<<5, /* uses offset and size */ + ANYMEM = E_MEM|E_MEMSP|E_MEMSB, + DELAY = BRANCH|LOAD|FCMP, +}; + +typedef struct Sch Sch; +typedef struct Dep Dep; + +struct Dep +{ + ulong ireg; + ulong freg; + ulong cc; +}; +struct Sch +{ + Prog p; + Dep set; + Dep used; + long soffset; + char size; + char nop; + char comp; +}; + +void regsused(Sch*, Prog*); +int depend(Sch*, Sch*); +int conflict(Sch*, Sch*); +int offoverlap(Sch*, Sch*); +void dumpbits(Sch*, Dep*); + +void +sched(Prog *p0, Prog *pe) +{ + Prog *p, *q; + Sch sch[NSCHED], *s, *t, *u, *se, stmp; + + /* + * build side structure + */ + s = sch; + for(p=p0;; p=p->link) { + memset(s, 0, sizeof(*s)); + s->p = *p; + regsused(s, p); + if(debug['X']) { + Bprint(&bso, "%P\t\tset", &s->p); + dumpbits(s, &s->set); + Bprint(&bso, "; used"); + dumpbits(s, &s->used); + if(s->comp) + Bprint(&bso, "; compound"); + if(s->p.mark & LOAD) + Bprint(&bso, "; load"); + if(s->p.mark & BRANCH) + Bprint(&bso, "; branch"); + if(s->p.mark & FCMP) + Bprint(&bso, "; fcmp"); + Bprint(&bso, "\n"); + } + if(p == pe) + break; + s++; + } + se = s; + + /* + * prepass to move things around + * does nothing, but tries to make + * the actual scheduler work better + */ + for(s=sch; s<=se; s++) { + if(!(s->p.mark & LOAD)) + continue; + /* always good to put nonconflict loads together */ + for(t=s+1; t<=se; t++) { + if(!(t->p.mark & LOAD)) + continue; + if(t->p.mark & BRANCH) + break; + if(conflict(s, t)) + break; + for(u=t-1; u>s; u--) + if(depend(u, t)) + goto no11; + u = s+1; + stmp = *t; + memmove(s+2, u, (uchar*)t - (uchar*)u); + *u = stmp; + break; + } + no11: + + /* put schedule fodder above load */ + for(t=s+1; t<=se; t++) { + if(t->p.mark & BRANCH) + break; + if(s > sch && conflict(s-1, t)) + continue; + for(u=t-1; u>=s; u--) + if(depend(t, u)) + goto no1; + stmp = *t; + memmove(s+1, s, (uchar*)t - (uchar*)s); + *s = stmp; + if(!(s->p.mark & LOAD)) + break; + no1:; + } + } + + for(s=se; s>=sch; s--) { + if(!(s->p.mark & DELAY)) + continue; + if(s < se) + if(!conflict(s, s+1)) + goto out3; + /* + * s is load, s+1 is immediate use of result or end of block + * t is the trial instruction to insert between s and s+1 + */ + if(!debug['Y']) + for(t=s-1; t>=sch; t--) { + if(t->comp) + if(s->p.mark & BRANCH) + goto no2; + if(t->p.mark & DELAY) + if(s >= se || conflict(t, s+1)) + goto no2; + for(u=t+1; u<=s; u++) + if(depend(u, t)) + goto no2; + goto out2; + no2:; + } + if(debug['X']) + Bprint(&bso, "?l%P\n", &s->p); + s->nop = 1; + if(debug['v']) { + if(s->p.mark & LOAD) { + nop.load.count++; + nop.load.outof++; + } + if(s->p.mark & BRANCH) { + nop.branch.count++; + nop.branch.outof++; + } + if(s->p.mark & FCMP) { + nop.fcmp.count++; + nop.fcmp.outof++; + } + } + continue; + + out2: + if(debug['X']) { + Bprint(&bso, "!l%P\n", &t->p); + Bprint(&bso, "%P\n", &s->p); + } + stmp = *t; + memmove(t, t+1, (uchar*)s - (uchar*)t); + *s = stmp; + s--; + + out3: + if(debug['v']) { + if(s->p.mark & LOAD) + nop.load.outof++; + if(s->p.mark & BRANCH) + nop.branch.outof++; + if(s->p.mark & FCMP) + nop.fcmp.outof++; + } + } + + /* Avoid HI/LO use->set */ + t = sch+1; + for(s=sch; s<se-1; s++, t++) { + if((s->used.cc & E_HILO) == 0) + continue; + if(t->set.cc & E_HILO) + s->nop = 2; + } + + /* + * put it all back + */ + for(s=sch, p=p0; s<=se; s++, p=q) { + q = p->link; + if(q != s->p.link) { + *p = s->p; + p->link = q; + } + while(s->nop--) + addnop(p); + } + if(debug['X']) { + Bprint(&bso, "\n"); + Bflush(&bso); + } +} + +void +regsused(Sch *s, Prog *realp) +{ + int c, ar, ad, ld, sz; + ulong m; + Prog *p; + + p = &s->p; + s->comp = compound(p); + s->nop = 0; + if(s->comp) { + s->set.ireg |= 1<<REGTMP; + s->used.ireg |= 1<<REGTMP; + } + + ar = 0; /* dest is really reference */ + ad = 0; /* source/dest is really address */ + ld = 0; /* opcode is load instruction */ + sz = 20; /* size of load/store for overlap computation */ + +/* + * flags based on opcode + */ + switch(p->as) { + case ATEXT: + curtext = realp; + autosize = p->to.offset + 4; + ad = 1; + break; + case AJAL: + c = p->reg; + if(c == NREG) + c = REGLINK; + s->set.ireg |= 1<<c; + ar = 1; + ad = 1; + break; + case ABGEZAL: + case ABLTZAL: + s->set.ireg |= 1<<REGLINK; + case ABEQ: + case ABGEZ: + case ABGTZ: + case ABLEZ: + case ABLTZ: + case ABNE: + ar = 1; + ad = 1; + break; + case ABFPT: + case ABFPF: + ad = 1; + s->used.cc |= E_FCR; + break; + case ACMPEQD: + case ACMPEQF: + case ACMPGED: + case ACMPGEF: + case ACMPGTD: + case ACMPGTF: + ar = 1; + s->set.cc |= E_FCR; + p->mark |= FCMP; + break; + case AJMP: + ar = 1; + ad = 1; + break; + case AMOVB: + case AMOVBU: + sz = 1; + ld = 1; + break; + case AMOVH: + case AMOVHU: + sz = 2; + ld = 1; + break; + case AMOVF: + case AMOVW: + case AMOVWL: + case AMOVWR: + sz = 4; + ld = 1; + break; + case AMOVD: + case AMOVV: + case AMOVVL: + case AMOVVR: + sz = 8; + ld = 1; + break; + case ADIV: + case ADIVU: + case AMUL: + case AMULU: + case AREM: + case AREMU: + s->set.cc = E_HILO; + case AADD: + case AADDU: + case AAND: + case ANOR: + case AOR: + case ASGT: + case ASGTU: + case ASLL: + case ASRA: + case ASRL: + case ASUB: + case ASUBU: + case AXOR: + + case AADDD: + case AADDF: + case AADDW: + case ASUBD: + case ASUBF: + case ASUBW: + case AMULF: + case AMULD: + case AMULW: + case ADIVF: + case ADIVD: + case ADIVW: + if(p->reg == NREG) { + if(p->to.type == D_REG || p->to.type == D_FREG) + p->reg = p->to.reg; + if(p->reg == NREG) + print("botch %P\n", p); + } + break; + } + +/* + * flags based on 'to' field + */ + c = p->to.class; + if(c == 0) { + c = aclass(&p->to) + 1; + p->to.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->to); + + case C_ZCON: + case C_SCON: + case C_ADD0CON: + case C_AND0CON: + case C_ADDCON: + case C_ANDCON: + case C_UCON: + case C_LCON: + case C_NONE: + case C_SBRA: + case C_LBRA: + break; + + case C_HI: + case C_LO: + s->set.cc |= E_HILO; + break; + case C_FCREG: + s->set.cc |= E_FCR; + break; + case C_MREG: + s->set.cc |= E_MCR; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + c = p->to.reg; + s->used.ireg |= 1<<c; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + if(ar) + s->used.cc |= m; + else + s->set.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + if(ar) + s->used.ireg |= 1<<p->to.reg; + else + s->set.ireg |= 1<<p->to.reg; + break; + case C_FREG: + /* do better -- determine double prec */ + if(ar) { + s->used.freg |= 1<<p->to.reg; + s->used.freg |= 1<<(p->to.reg|1); + } else { + s->set.freg |= 1<<p->to.reg; + s->set.freg |= 1<<(p->to.reg|1); + } + if(ld && p->from.type == D_REG) + p->mark |= LOAD; + break; + case C_SAUTO: + case C_LAUTO: + s->used.ireg |= 1<<REGSP; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSP; + else + s->set.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + s->used.ireg |= 1<<REGSB; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->to); + + if(ar) + s->used.cc |= E_MEMSB; + else + s->set.cc |= E_MEMSB; + break; + } + +/* + * flags based on 'from' field + */ + c = p->from.class; + if(c == 0) { + c = aclass(&p->from) + 1; + p->from.class = c; + } + c--; + switch(c) { + default: + print("unknown class %d %D\n", c, &p->from); + + case C_ZCON: + case C_SCON: + case C_ADD0CON: + case C_AND0CON: + case C_ADDCON: + case C_ANDCON: + case C_UCON: + case C_LCON: + case C_NONE: + case C_SBRA: + case C_LBRA: + break; + case C_HI: + case C_LO: + s->used.cc |= E_HILO; + break; + case C_FCREG: + s->used.cc |= E_FCR; + break; + case C_MREG: + s->used.cc |= E_MCR; + break; + case C_ZOREG: + case C_SOREG: + case C_LOREG: + c = p->from.reg; + s->used.ireg |= 1<<c; + if(ld) + p->mark |= LOAD; + s->size = sz; + s->soffset = regoff(&p->from); + + m = ANYMEM; + if(c == REGSB) + m = E_MEMSB; + if(c == REGSP) + m = E_MEMSP; + + s->used.cc |= m; + break; + case C_SACON: + case C_LACON: + s->used.ireg |= 1<<REGSP; + break; + case C_SECON: + case C_LECON: + s->used.ireg |= 1<<REGSB; + break; + case C_REG: + s->used.ireg |= 1<<p->from.reg; + break; + case C_FREG: + /* do better -- determine double prec */ + s->used.freg |= 1<<p->from.reg; + s->used.freg |= 1<<(p->from.reg|1); + if(ld && p->to.type == D_REG) + p->mark |= LOAD; + break; + case C_SAUTO: + case C_LAUTO: + s->used.ireg |= 1<<REGSP; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSP; + break; + case C_SEXT: + case C_LEXT: + s->used.ireg |= 1<<REGSB; + if(ld) + p->mark |= LOAD; + if(ad) + break; + s->size = sz; + s->soffset = regoff(&p->from); + + s->used.cc |= E_MEMSB; + break; + } + + c = p->reg; + if(c != NREG) { + if(p->from.type == D_FREG || p->to.type == D_FREG) { + s->used.freg |= 1<<c; + s->used.freg |= 1<<(c|1); + } else + s->used.ireg |= 1<<c; + } + s->set.ireg &= ~(1<<REGZERO); /* R0 cant be set */ +} + +/* + * test to see if 2 instrictions can be + * interchanged without changing semantics + */ +int +depend(Sch *sa, Sch *sb) +{ + ulong x; + + if(sa->set.ireg & (sb->set.ireg|sb->used.ireg)) + return 1; + if(sb->set.ireg & sa->used.ireg) + return 1; + + if(sa->set.freg & (sb->set.freg|sb->used.freg)) + return 1; + if(sb->set.freg & sa->used.freg) + return 1; + + /* + * special case. + * loads from same address cannot pass. + * this is for hardware fifo's and the like + */ + if(sa->used.cc & sb->used.cc & E_MEM) + if(sa->p.reg == sb->p.reg) + if(regoff(&sa->p.from) == regoff(&sb->p.from)) + return 1; + + x = (sa->set.cc & (sb->set.cc|sb->used.cc)) | + (sb->set.cc & sa->used.cc); + if(x) { + /* + * allow SB and SP to pass each other. + * allow SB to pass SB iff doffsets are ok + * anything else conflicts + */ + if(x != E_MEMSP && x != E_MEMSB) + return 1; + x = sa->set.cc | sb->set.cc | + sa->used.cc | sb->used.cc; + if(x & E_MEM) + return 1; + if(offoverlap(sa, sb)) + return 1; + } + + return 0; +} + +int +offoverlap(Sch *sa, Sch *sb) +{ + + if(sa->soffset < sb->soffset) { + if(sa->soffset+sa->size > sb->soffset) + return 1; + return 0; + } + if(sb->soffset+sb->size > sa->soffset) + return 1; + return 0; +} + +/* + * test 2 adjacent instructions + * and find out if inserted instructions + * are desired to prevent stalls. + */ +int +conflict(Sch *sa, Sch *sb) +{ + + if(sa->set.ireg & sb->used.ireg) + return 1; + if(sa->set.freg & sb->used.freg) + return 1; + if(sa->set.cc & sb->used.cc) + return 1; + + return 0; +} + +int +compound(Prog *p) +{ + Optab *o; + + o = oplook(p); + if(o->size != 4) + return 1; + if(p->to.type == D_REG && p->to.reg == REGSB) + return 1; + return 0; +} + +void +dumpbits(Sch *s, Dep *d) +{ + int i; + + for(i=0; i<32; i++) + if(d->ireg & (1<<i)) + Bprint(&bso, " R%d", i); + for(i=0; i<32; i++) + if(d->freg & (1<<i)) + Bprint(&bso, " F%d", i); + for(i=0; i<32; i++) + switch(d->cc & (1<<i)) { + default: + break; + case E_HILO: + Bprint(&bso, " HILO"); + break; + case E_FCR: + Bprint(&bso, " FCR"); + break; + case E_MCR: + Bprint(&bso, " MCR"); + break; + case E_MEM: + Bprint(&bso, " MEM%d", s->size); + break; + case E_MEMSB: + Bprint(&bso, " SB%d", s->size); + break; + case E_MEMSP: + Bprint(&bso, " SP%d", s->size); + break; + } +} diff --git a/utils/vl/span.c b/utils/vl/span.c new file mode 100644 index 00000000..706d8b0e --- /dev/null +++ b/utils/vl/span.c @@ -0,0 +1,662 @@ +#include "l.h" + +void +pagebug(Prog *p) +{ + Prog *q; + + switch(p->as) { + case ABGEZAL: + case ABLTZAL: + case AJAL: + case ABEQ: + case ABGEZ: + case ABGTZ: + case ABLEZ: + case ABLTZ: + case ABNE: + case ABFPT: + case ABFPF: + case AJMP: + q = prg(); + *q = *p; + p->link = q; + p->as = ANOR; + p->optab = 0; + p->from = zprg.from; + p->from.type = D_REG; + p->from.reg = REGZERO; + p->to = p->from; + } +} + +void +span(void) +{ + Prog *p, *q; + Sym *setext, *s; + Optab *o; + int m, bflag, i; + long c, otxt, v; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + Bflush(&bso); + + bflag = 0; + c = INITTEXT; + otxt = c; + for(p = firstp; p != P; p = p->link) { + /* bug in early 4000 chips delayslot on page boundary */ + if((c&(0x1000-1)) == 0xffc) + pagebug(p); + p->pc = c; + o = oplook(p); + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + /* need passes to resolve branches */ + if(c-otxt >= 1L<<17) + bflag = 1; + otxt = c; + continue; + } + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + while(bflag) { + if(debug['v']) + Bprint(&bso, "%5.2f span1\n", cputime()); + bflag = 0; + c = INITTEXT; + for(p = firstp; p != P; p = p->link) { + /* bug in early 4000 chips delayslot on page boundary */ + if((c&(0x1000-1)) == 0xffc) + pagebug(p); + p->pc = c; + o = oplook(p); + if(o->type == 6 && p->cond) { + otxt = p->cond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = prg(); + q->link = p->link; + p->link = q; + q->as = AJMP; + q->to.type = D_BRANCH; + q->cond = p->cond; + p->cond = q; + q = prg(); + q->link = p->link; + p->link = q; + q->as = AJMP; + q->to.type = D_BRANCH; + q->cond = q->link->link; + addnop(p->link); + addnop(p); + bflag = 1; + } + } + m = o->size; + if(m == 0) { + if(p->as == ATEXT) { + curtext = p; + autosize = p->to.offset + 4; + if(p->from.sym != S) + p->from.sym->value = c; + continue; + } + diag("zero-width instruction\n%P", p); + continue; + } + c += m; + } + } + + if(debug['t']) { + /* + * add strings to text segment + */ + c = rnd(c, 8); + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) { + if(s->type != SSTRING) + continue; + v = s->value; + while(v & 3) + v++; + s->value = c; + c += v; + } + } + + c = rnd(c, 8); + + setext = lookup("etext", 0); + if(setext != S) { + setext->value = c; + textsize = c - INITTEXT; + } + if(INITRND) + INITDAT = rnd(c, INITRND); + if(debug['v']) + Bprint(&bso, "tsize = %lux\n", textsize); + Bflush(&bso); +} + +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; + } +} + +long +regoff(Adr *a) +{ + + instoffset = 0; + aclass(a); + return instoffset; +} + +aclass(Adr *a) +{ + Sym *s; + int t; + + switch(a->type) { + case D_NONE: + return C_NONE; + + case D_REG: + return C_REG; + + case D_FREG: + return C_FREG; + + case D_FCREG: + return C_FCREG; + + case D_MREG: + return C_MREG; + + case D_OREG: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + if(a->sym == 0 || a->sym->name == 0) { + print("null sym external\n"); + print("%D\n", a); + return C_GOK; + } + t = a->sym->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + a->sym->name, TNAME); + a->sym->type = SDATA; + } + instoffset = a->sym->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SEXT; + return C_LEXT; + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SAUTO; + return C_LAUTO; + case D_NONE: + instoffset = a->offset; + if(instoffset == 0) + return C_ZOREG; + if(instoffset >= -BIG && instoffset < BIG) + return C_SOREG; + return C_LOREG; + } + return C_GOK; + + case D_HI: + return C_LO; + case D_LO: + return C_HI; + + case D_OCONST: + switch(a->name) { + case D_EXTERN: + case D_STATIC: + s = a->sym; + t = s->type; + if(t == 0 || t == SXREF) { + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + } + instoffset = s->value + a->offset + INITDAT; + if(s->type == STEXT || s->type == SLEAF) + instoffset = s->value + a->offset; + return C_LCON; + } + return C_GOK; + + case D_CONST: + switch(a->name) { + + case D_NONE: + instoffset = a->offset; + consize: + if(instoffset > 0) { + if(instoffset <= 0x7fff) + return C_SCON; + if(instoffset <= 0xffff) + return C_ANDCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + } + if(instoffset == 0) + return C_ZCON; + if(instoffset >= -0x8000) + return C_ADDCON; + if((instoffset & 0xffff) == 0) + return C_UCON; + return C_LCON; + + case D_EXTERN: + case D_STATIC: + s = a->sym; + if(s == S) + break; + t = s->type; + switch(t) { + case 0: + case SXREF: + diag("undefined external: %s in %s", + s->name, TNAME); + s->type = SDATA; + break; + case SCONST: + instoffset = s->value + a->offset; + goto consize; + case STEXT: + case SLEAF: + case SSTRING: + instoffset = s->value + a->offset; + return C_LCON; + } + instoffset = s->value + a->offset - BIG; + if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L) + return C_SECON; + instoffset = s->value + a->offset + INITDAT; + return C_LCON; + + case D_AUTO: + instoffset = autosize + a->offset; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + + case D_PARAM: + instoffset = autosize + a->offset + 4L; + if(instoffset >= -BIG && instoffset < BIG) + return C_SACON; + return C_LACON; + } + return C_GOK; + + case D_BRANCH: + return C_SBRA; + } + return C_GOK; +} + +Optab* +oplook(Prog *p) +{ + int a1, a2, a3, r; + char *c1, *c3; + Optab *o, *e; + + a1 = p->optab; + if(a1) + return optab+(a1-1); + a1 = p->from.class; + if(a1 == 0) { + a1 = aclass(&p->from) + 1; + p->from.class = a1; + } + a1--; + a3 = p->to.class; + if(a3 == 0) { + a3 = aclass(&p->to) + 1; + p->to.class = a3; + } + a3--; + a2 = C_NONE; + if(p->reg != NREG) + a2 = C_REG; + r = p->as; + o = oprange[r].start; + if(o == 0) { + a1 = opcross[repop[r]][a1][a2][a3]; + if(a1) { + p->optab = a1+1; + return optab+a1; + } + o = oprange[r].stop; /* just generate an error */ + } + e = oprange[r].stop; + c1 = xcmp[a1]; + c3 = xcmp[a3]; + for(; o<e; o++) + if(o->a2 == a2) + if(c1[o->a1]) + if(c3[o->a3]) { + p->optab = (o-optab)+1; + return o; + } + diag("illegal combination %A %d %d %d", + p->as, a1, a2, a3); + if(!debug['a']) + prasm(p); + o = optab; + p->optab = (o-optab)+1; + return o; +} + +int +cmp(int a, int b) +{ + + if(a == b) + return 1; + switch(a) { + case C_LCON: + if(b == C_ZCON || b == C_SCON || b == C_UCON || + b == C_ADDCON || b == C_ANDCON) + return 1; + break; + case C_ADD0CON: + if(b == C_ADDCON) + return 1; + case C_ADDCON: + if(b == C_ZCON || b == C_SCON) + return 1; + break; + case C_AND0CON: + if(b == C_ANDCON) + return 1; + case C_ANDCON: + if(b == C_ZCON || b == C_SCON) + return 1; + break; + case C_UCON: + if(b == C_ZCON) + return 1; + break; + case C_SCON: + if(b == C_ZCON) + return 1; + break; + case C_LACON: + if(b == C_SACON) + return 1; + break; + case C_LBRA: + if(b == C_SBRA) + return 1; + break; + case C_LEXT: + if(b == C_SEXT) + return 1; + break; + case C_LAUTO: + if(b == C_SAUTO) + return 1; + break; + case C_REG: + if(b == C_ZCON) + return 1; + break; + case C_LOREG: + if(b == C_ZOREG || b == C_SOREG) + return 1; + break; + case C_SOREG: + if(b == C_ZOREG) + return 1; + break; + } + return 0; +} + +int +ocmp(const void *a1, const void *a2) +{ + Optab *p1, *p2; + int n; + + p1 = (Optab*)a1; + p2 = (Optab*)a2; + n = p1->as - p2->as; + if(n) + return n; + n = p1->a1 - p2->a1; + if(n) + return n; + n = p1->a2 - p2->a2; + if(n) + return n; + n = p1->a3 - p2->a3; + if(n) + return n; + return 0; +} + +void +buildop(void) +{ + int i, n, r; + + for(i=0; i<32; i++) + for(n=0; n<32; n++) + xcmp[i][n] = cmp(n, i); + for(n=0; optab[n].as != AXXX; n++) + ; + qsort(optab, n, sizeof(optab[0]), ocmp); + for(i=0; i<n; i++) { + r = optab[i].as; + oprange[r].start = optab+i; + while(optab[i].as == r) + i++; + oprange[r].stop = optab+i; + i--; + + switch(r) + { + default: + diag("unknown op in build: %A", r); + errorexit(); + case AABSF: + oprange[AMOVFD] = oprange[r]; + oprange[AMOVDF] = oprange[r]; + oprange[AMOVWF] = oprange[r]; + oprange[AMOVFW] = oprange[r]; + oprange[AMOVWD] = oprange[r]; + oprange[AMOVDW] = oprange[r]; + oprange[ANEGF] = oprange[r]; + oprange[ANEGD] = oprange[r]; + oprange[AABSD] = oprange[r]; + break; + case AADD: + buildrep(1, AADD); + oprange[ASGT] = oprange[r]; + repop[ASGT] = 1; + oprange[ASGTU] = oprange[r]; + repop[ASGTU] = 1; + oprange[AADDU] = oprange[r]; + repop[AADDU] = 1; + oprange[AADDVU] = oprange[r]; + repop[AADDVU] = 1; + break; + case AADDF: + oprange[ADIVF] = oprange[r]; + oprange[ADIVD] = oprange[r]; + oprange[AMULF] = oprange[r]; + oprange[AMULD] = oprange[r]; + oprange[ASUBF] = oprange[r]; + oprange[ASUBD] = oprange[r]; + oprange[AADDD] = oprange[r]; + break; + case AAND: + buildrep(2, AAND); + oprange[AXOR] = oprange[r]; + repop[AXOR] = 2; + oprange[AOR] = oprange[r]; + repop[AOR] = 2; + break; + case ABEQ: + oprange[ABNE] = oprange[r]; + break; + case ABLEZ: + oprange[ABGEZ] = oprange[r]; + oprange[ABGEZAL] = oprange[r]; + oprange[ABLTZ] = oprange[r]; + oprange[ABLTZAL] = oprange[r]; + oprange[ABGTZ] = oprange[r]; + break; + case AMOVB: + buildrep(3, AMOVB); + oprange[AMOVH] = oprange[r]; + repop[AMOVH] = 3; + break; + case AMOVBU: + buildrep(4, AMOVBU); + oprange[AMOVHU] = oprange[r]; + repop[AMOVHU] = 4; + break; + case AMUL: + oprange[AREM] = oprange[r]; + oprange[AREMU] = oprange[r]; + oprange[ADIVU] = oprange[r]; + oprange[AMULU] = oprange[r]; + oprange[ADIV] = oprange[r]; + oprange[ADIVVU] = oprange[r]; + oprange[ADIVV] = oprange[r]; + break; + case ASLL: + oprange[ASRL] = oprange[r]; + oprange[ASRA] = oprange[r]; + oprange[ASLLV] = oprange[r]; + oprange[ASRAV] = oprange[r]; + oprange[ASRLV] = oprange[r]; + break; + case ASUB: + oprange[ASUBU] = oprange[r]; + oprange[ANOR] = oprange[r]; + break; + case ASYSCALL: + oprange[ATLBP] = oprange[r]; + oprange[ATLBR] = oprange[r]; + oprange[ATLBWI] = oprange[r]; + oprange[ATLBWR] = oprange[r]; + break; + case ACMPEQF: + oprange[ACMPGTF] = oprange[r]; + oprange[ACMPGTD] = oprange[r]; + oprange[ACMPGEF] = oprange[r]; + oprange[ACMPGED] = oprange[r]; + oprange[ACMPEQD] = oprange[r]; + break; + case ABFPT: + oprange[ABFPF] = oprange[r]; + break; + case AMOVWL: + oprange[AMOVWR] = oprange[r]; + oprange[AMOVVR] = oprange[r]; + oprange[AMOVVL] = oprange[r]; + break; + case AMOVW: + buildrep(5, AMOVW); + break; + case AMOVD: + buildrep(6, AMOVD); + break; + case AMOVF: + buildrep(7, AMOVF); + break; + case AMOVV: + buildrep(8, AMOVV); + break; + case ABREAK: + case AWORD: + case ARFE: + case AJAL: + case AJMP: + case ATEXT: + case ACASE: + case ABCASE: + break; + } + } +} + +void +buildrep(int x, int as) +{ + Opcross *p; + Optab *e, *s, *o; + int a1, a2, a3, n; + + if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) { + diag("assumptions fail in buildrep"); + errorexit(); + } + repop[as] = x; + p = (opcross + x); + s = oprange[as].start; + e = oprange[as].stop; + for(o=e-1; o>=s; o--) { + n = o-optab; + for(a2=0; a2<2; a2++) { + if(a2) { + if(o->a2 == C_NONE) + continue; + } else + if(o->a2 != C_NONE) + continue; + for(a1=0; a1<32; a1++) { + if(!xcmp[a1][o->a1]) + continue; + for(a3=0; a3<32; a3++) + if(xcmp[a3][o->a3]) + (*p)[a1][a2][a3] = n; + } + } + } + oprange[as].start = 0; +} diff --git a/utils/yacc/mkfile b/utils/yacc/mkfile new file mode 100644 index 00000000..05e2709e --- /dev/null +++ b/utils/yacc/mkfile @@ -0,0 +1,20 @@ +<../../mkconfig + +TARG=yacc + +OFILES= yacc.$O\ + +HFILES= ../../include/bio.h\ + +LIBS=bio 9 # libbio.a uses lib9.a so order matters. + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include '-DROOT="'$ROOT'"' '-DPARSER="yaccpar"' '-DPARSERS="yaccpar"' + +install:V: $ROOT/utils/lib/yaccpar + +$ROOT/utils/lib/yaccpar: yaccpar + rm -f $target && cp $prereq $target diff --git a/utils/yacc/yacc.c b/utils/yacc/yacc.c new file mode 100644 index 00000000..0a6fdda0 --- /dev/null +++ b/utils/yacc/yacc.c @@ -0,0 +1,2933 @@ +#include <lib9.h> +#include <bio.h> +#include <ctype.h> + +#define Bungetrune Bungetc /* ok for now. */ + +/* + * all these are 32 bit + */ +#define TBITSET ((32+NTERMS)/32) /* BOTCH?? +31 */ +#define BIT(a,i) ((a)[(i)>>5] & (1<<((i)&037))) +#define SETBIT(a,i) ((a)[(i)>>5] |= (1<<((i)&037))) +#define NWORDS(n) (((n)+32)/32) + +#ifndef PARSER +#define PARSER "yaccpar" +#define PARSERS "yaccpars" +#endif +#define TEMPNAME "y.tmp.XXXXXX" +#define ACTNAME "y.acts.XXXXXX" +#define OFILE "tab.c" +#define FILEU "output" +#define FILED "tab.h" +#define FILEDEBUG "debug" + +enum +{ +/* + * the following are adjustable + * according to memory size + */ + ACTSIZE = 30000, + MEMSIZE = 30000, + NSTATES = 2000, + NTERMS = 255, + NPROD = 800, + NNONTERM = 300, + TEMPSIZE = 2000, + CNAMSZ = 5000, + LSETSIZE = 2400, + WSETSIZE = 350, + + NAMESIZE = 50, + NTYPES = 63, + ISIZE = 400, + + PRIVATE = 0xE000, /* unicode private use */ + + /* relationships which must hold: + TBITSET ints must hold NTERMS+1 bits... + WSETSIZE >= NNONTERM + LSETSIZE >= NNONTERM + TEMPSIZE >= NTERMS + NNONTERM + 1 + TEMPSIZE >= NSTATES + */ + + NTBASE = 010000, + ERRCODE = 8190, + ACCEPTCODE = 8191, + + NOASC = 0, /* no assoc. */ + LASC = 1, /* left assoc. */ + RASC = 2, /* right assoc. */ + BASC = 3, /* binary assoc. */ + + /* flags for state generation */ + + DONE = 0, + MUSTDO = 1, + MUSTLOOKAHEAD = 2, + + /* flags for a rule having an action, and being reduced */ + + ACTFLAG = 04, + REDFLAG = 010, + + /* output parser flags */ + YYFLAG1 = -1000, + + /* parse tokens */ + IDENTIFIER = PRIVATE, + MARK, + TERM, + LEFT, + RIGHT, + BINARY, + PREC, + LCURLY, + IDENTCOLON, + NUMBER, + START, + TYPEDEF, + TYPENAME, + UNION, + + ENDFILE = 0, + + EMPTY = 1, + WHOKNOWS = 0, + OK = 1, + NOMORE = -1000, +}; + + /* macros for getting associativity and precedence levels */ + +#define ASSOC(i) ((i)&03) +#define PLEVEL(i) (((i)>>4)&077) +#define TYPE(i) (((i)>>10)&077) + + /* macros for setting associativity and precedence levels */ + +#define SETASC(i,j) i |= j +#define SETPLEV(i,j) i |= (j<<4) +#define SETTYPE(i,j) i |= (j<<10) + + /* looping macros */ + +#define TLOOP(i) for(i=1; i<=ntokens; i++) +#define NTLOOP(i) for(i=0; i<=nnonter; i++) +#define PLOOP(s,i) for(i=s; i<nprod; i++) +#define SLOOP(i) for(i=0; i<nstate; i++) +#define WSBUMP(x) x++ +#define WSLOOP(s,j) for(j=s; j<cwp; j++) +#define ITMLOOP(i,p,q) for(q=pstate[i+1], p=pstate[i]; p<q; p++) +#define SETLOOP(i) for(i=0; i<tbitset; i++) + + /* command to clobber tempfiles after use */ + +#define ZAPFILE(x) if(x) remove(x) + + /* I/O descriptors */ + +Biobuf* faction; /* file for saving actions */ +Biobuf* fdefine; /* file for #defines */ +Biobuf* fdebug; /* y.debug for strings for debugging */ +Biobuf* ftable; /* y.tab.c file */ +Biobuf* ftemp; /* tempfile to pass 2 */ +Biobuf* finput; /* input file */ +Biobuf* foutput; /* y.output file */ + + /* communication variables between various I/O routines */ + +char* infile; /* input file name */ +int numbval; /* value of an input number */ +char tokname[NAMESIZE+4]; /* input token name, slop for runes and 0 */ + + /* structure declarations */ + +typedef +struct +{ + int lset[TBITSET]; +} Lkset; + +typedef +struct +{ + int* pitem; + Lkset* look; +} Item; + +typedef +struct +{ + char* name; + int value; +} Symb; + +typedef +struct +{ + int* pitem; + int flag; + Lkset ws; +} Wset; + + /* storage of names */ + +char cnames[CNAMSZ]; /* place where token and nonterminal names are stored */ +int cnamsz = CNAMSZ; /* size of cnames */ +char* cnamp = cnames; /* place where next name is to be put in */ +int ndefout = 4; /* number of defined symbols output */ +char* tempname; +char* actname; +char ttempname[] = TEMPNAME; +char tactname[] = ACTNAME; +char* parser = PARSER; +char* yydebug; +char par[256]; /* full path of parser */ + + /* storage of types */ +int ntypes; /* number of types defined */ +char* typeset[NTYPES]; /* pointers to type tags */ + + /* token information */ + +int ntokens = 0 ; /* number of tokens */ +Symb tokset[NTERMS]; +int toklev[NTERMS]; /* vector with the precedence of the terminals */ + + /* nonterminal information */ + +int nnonter = -1; /* the number of nonterminals */ +Symb nontrst[NNONTERM]; +int start; /* start symbol */ + + /* assigned token type values */ +int extval = 0; + +char* ytabc = OFILE; /* name of y.tab.c */ + + /* grammar rule information */ + +int mem0[MEMSIZE] ; /* production storage */ +int* mem = mem0; +int nprod = 1; /* number of productions */ +int* prdptr[NPROD]; /* pointers to descriptions of productions */ +int levprd[NPROD]; /* precedence levels for the productions */ +int rlines[NPROD]; /* line number for this rule */ + + /* state information */ + +int nstate = 0; /* number of states */ +Item* pstate[NSTATES+2]; /* pointers to the descriptions of the states */ +int tystate[NSTATES]; /* contains type information about the states */ +int defact[NSTATES]; /* the default actions of states */ +int tstates[NTERMS]; /* states generated by terminal gotos */ +int ntstates[NNONTERM]; /* states generated by nonterminal gotos */ +int mstates[NSTATES]; /* chain of overflows of term/nonterm generation lists */ +int lastred; /* the number of the last reduction of a state */ + + /* lookahead set information */ + +Lkset lkst[LSETSIZE]; +int nolook; /* flag to turn off lookahead computations */ +int tbitset; /* size of lookahead sets */ +int nlset = 0; /* next lookahead set index */ +int nolook = 0; /* flag to suppress lookahead computations */ +Lkset clset; /* temporary storage for lookahead computations */ + + /* working set information */ + +Wset wsets[WSETSIZE]; +Wset* cwp; + + /* storage for action table */ + +int amem[ACTSIZE]; /* action table storage */ +int* memp = amem; /* next free action table position */ +int indgo[NSTATES]; /* index to the stored goto table */ + + /* temporary vector, indexable by states, terms, or ntokens */ + +int temp1[TEMPSIZE]; /* temporary storage, indexed by terms + ntokens or states */ +int lineno = 1; /* current input line number */ +int fatfl = 1; /* if on, error is fatal */ +int nerrors = 0; /* number of errors */ + + /* statistics collection variables */ + +int zzgoent; +int zzgobest; +int zzacent; +int zzexcp; +int zzclose; +int zzrrconf; +int zzsrconf; + +int* ggreed = lkst[0].lset; +int* pgo = wsets[0].ws.lset; +int* yypgo = &nontrst[0].value; + +int maxspr = 0; /* maximum spread of any entry */ +int maxoff = 0; /* maximum offset into a array */ +int* pmem = mem0; +int* maxa; +int nxdb = 0; +int adb = 0; + + + /* storage for information about the nonterminals */ + +int** pres[NNONTERM+2]; /* vector of pointers to productions yielding each nonterminal */ +Lkset* pfirst[NNONTERM+2]; /* vector of pointers to first sets for each nonterminal */ +int pempty[NNONTERM+1]; /* vector of nonterminals nontrivially deriving e */ + + /* random stuff picked out from between functions */ + +int indebug = 0; +Wset* zzcwp = wsets; +int zzgoent = 0; +int zzgobest = 0; +int zzacent = 0; +int zzexcp = 0; +int zzclose = 0; +int zzsrconf = 0; +int* zzmemsz = mem0; +int zzrrconf = 0; +int pidebug = 0; /* debugging flag for putitem */ +int gsdebug = 0; +int cldebug = 0; /* debugging flag for closure */ +int pkdebug = 0; +int g2debug = 0; + +struct +{ + char* name; + long value; +} resrv[] = +{ + "binary", BINARY, + "left", LEFT, + "nonassoc", BINARY, + "prec", PREC, + "right", RIGHT, + "start", START, + "term", TERM, + "token", TERM, + "type", TYPEDEF, + "union", UNION, + 0, +}; + + /* define functions */ + +void main(int, char**); +void others(void); +char* chcopy(char*, char*); +char* writem(int*); +char* symnam(int); +void summary(void); +void error(char*, ...); +void aryfil(int*, int, int); +int setunion(int*, int*); +void prlook(Lkset*); +void cpres(void); +void cpfir(void); +int state(int); +void putitem(int*, Lkset*); +void cempty(void); +void stagen(void); +void closure(int); +Lkset* flset(Lkset*); +void cleantmp(void); +void intr(void); +void setup(int, char**); +void finact(void); +int defin(int, char*); +void defout(int); +char* cstash(char*); +long gettok(void); +int fdtype(int); +int chfind(int, char*); +void cpyunion(void); +void cpycode(void); +int skipcom(void); +void cpyact(int); +void openup(char*, int, int, int, char*); +void output(void); +int apack(int*, int); +void go2out(void); +void go2gen(int); +void precftn(int, int, int); +void wract(int); +void wrstate(int); +void warray(char*, int*, int); +void hideprod(void); +void callopt(void); +void gin(int); +void stin(int); +int nxti(void); +void osummary(void); +void aoutput(void); +void arout(char*, int*, int); +int gtnm(void); + +void +main(int argc, char *argv[]) +{ + + setup(argc, argv); /* initialize and read productions */ + tbitset = NWORDS(ntokens); + cpres(); /* make table of which productions yield a given nonterminal */ + cempty(); /* make a table of which nonterminals can match the empty string */ + cpfir(); /* make a table of firsts of nonterminals */ + stagen(); /* generate the states */ + output(); /* write the states and the tables */ + go2out(); + hideprod(); + summary(); + callopt(); + others(); + exits(0); +} + +/* + * put out other arrays, copy the parsers + */ +void +others(void) +{ + int c, i, j; + + finput = Bopen(parser, OREAD); + if(finput == 0) + error("cannot find parser %s", parser); + warray("yyr1", levprd, nprod); + aryfil(temp1, nprod, 0); + PLOOP(1, i) + temp1[i] = prdptr[i+1]-prdptr[i]-2; + warray("yyr2", temp1, nprod); + + aryfil(temp1, nstate, -1000); + TLOOP(i) + for(j=tstates[i]; j!=0; j=mstates[j]) + temp1[j] = i; + NTLOOP(i) + for(j=ntstates[i]; j!=0; j=mstates[j]) + temp1[j] = -i; + warray("yychk", temp1, nstate); + warray("yydef", defact, nstate); + + /* put out token translation tables */ + /* table 1 has 0-256 */ + aryfil(temp1, 256, 0); + c = 0; + TLOOP(i) { + j = tokset[i].value; + if(j >= 0 && j < 256) { + if(temp1[j]) { + print("yacc bug -- cant have 2 different Ts with same value\n"); + print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name); + nerrors++; + } + temp1[j] = i; + if(j > c) + c = j; + } + } + warray("yytok1", temp1, c+1); + + /* table 2 has PRIVATE-PRIVATE+256 */ + aryfil(temp1, 256, 0); + c = 0; + TLOOP(i) { + j = tokset[i].value - PRIVATE; + if(j >= 0 && j < 256) { + if(temp1[j]) { + print("yacc bug -- cant have 2 different Ts with same value\n"); + print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name); + nerrors++; + } + temp1[j] = i; + if(j > c) + c = j; + } + } + warray("yytok2", temp1, c+1); + + /* table 3 has everything else */ + Bprint(ftable, "long yytok3[] =\n{\n"); + c = 0; + TLOOP(i) { + j = tokset[i].value; + if(j >= 0 && j < 256) + continue; + if(j >= PRIVATE && j < 256+PRIVATE) + continue; + + Bprint(ftable, "%4d,%4d,", j, i); + c++; + if(c%5 == 0) + Bprint(ftable, "\n"); + } + Bprint(ftable, "%4d\n};\n", 0); + + /* copy parser text */ + while((c=Bgetrune(finput)) != Beof) { + if(c == '$') { + if((c = Bgetrune(finput)) != 'A') + Bputrune(ftable, '$'); + else { /* copy actions */ + faction = Bopen(actname, OREAD); + if(faction == 0) + error("cannot reopen action tempfile"); + while((c=Bgetrune(faction)) != Beof) + Bputrune(ftable, c); + Bterm(faction); + ZAPFILE(actname); + c = Bgetrune(finput); + } + } + Bputrune(ftable, c); + } + Bterm(ftable); +} + +/* + * copies string q into p, returning next free char ptr + */ +char* +chcopy(char* p, char* q) +{ + int c; + + while(c = *q) { + if(c == '"') + *p++ = '\\'; + *p++ = c; + q++; + } + *p = 0; + return p; +} + +/* + * creates output string for item pointed to by pp + */ +char* +writem(int *pp) +{ + int i,*p; + static char sarr[ISIZE]; + char* q; + + for(p=pp; *p>0; p++) + ; + p = prdptr[-*p]; + q = chcopy(sarr, nontrst[*p-NTBASE].name); + q = chcopy(q, ": "); + for(;;) { + *q = ' '; + p++; + if(p == pp) + *q = '.'; + q++; + *q = '\0'; + i = *p; + if(i <= 0) + break; + q = chcopy(q, symnam(i)); + if(q > &sarr[ISIZE-30]) + error("item too big"); + } + + /* an item calling for a reduction */ + i = *pp; + if(i < 0 ) { + q = chcopy(q, " ("); + sprint(q, "%d)", -i); + } + return sarr; +} + +/* + * return a pointer to the name of symbol i + */ +char* +symnam(int i) +{ + char* cp; + + cp = (i >= NTBASE)? nontrst[i-NTBASE].name: tokset[i].name; + if(*cp == ' ') + cp++; + return cp; +} + +/* + * output the summary on y.output + */ +void +summary(void) +{ + + if(foutput != 0) { + Bprint(foutput, "\n%d/%d terminals, %d/%d nonterminals\n", + ntokens, NTERMS, nnonter, NNONTERM); + Bprint(foutput, "%d/%d grammar rules, %d/%d states\n", + nprod, NPROD, nstate, NSTATES); + Bprint(foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n", + zzsrconf, zzrrconf); + Bprint(foutput, "%d/%d working sets used\n", + (int)(zzcwp-wsets), WSETSIZE); + Bprint(foutput, "memory: states,etc. %d/%d, parser %d/%d\n", + (int)(zzmemsz-mem0), MEMSIZE, (int)(memp-amem), ACTSIZE); + Bprint(foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE); + Bprint(foutput, "%d extra closures\n", zzclose - 2*nstate); + Bprint(foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp); + Bprint(foutput, "%d goto entries\n", zzgoent); + Bprint(foutput, "%d entries saved by goto default\n", zzgobest); + } + if(zzsrconf != 0 || zzrrconf != 0) { + print("\nconflicts: "); + if(zzsrconf) + print("%d shift/reduce", zzsrconf); + if(zzsrconf && zzrrconf) + print(", "); + if(zzrrconf) + print("%d reduce/reduce", zzrrconf); + print("\n"); + } + if(ftemp != 0) { + Bterm(ftemp); + ftemp = 0; + } + if(fdefine != 0) { + Bterm(fdefine); + fdefine = 0; + } +} + +/* + * write out error comment -- NEEDS WORK + */ +void +error(char *s, ...) +{ + + nerrors++; + fprint(2, "\n fatal error:"); + fprint(2, s, (&s)[1]); + fprint(2, ", %s:%d\n", infile, lineno); + if(!fatfl) + return; + summary(); + cleantmp(); + exits("error"); +} + +/* + * set elements 0 through n-1 to c + */ +void +aryfil(int *v, int n, int c) +{ + int i; + + for(i=0; i<n; i++) + v[i] = c; +} + +/* + * set a to the union of a and b + * return 1 if b is not a subset of a, 0 otherwise + */ +int +setunion(int *a, int *b) +{ + int i, x, sub; + + sub = 0; + SETLOOP(i) { + x = *a; + *a |= *b; + if(*a != x) + sub = 1; + a++; + b++; + } + return sub; +} + +void +prlook(Lkset* p) +{ + int j, *pp; + + pp = p->lset; + if(pp == 0) + Bprint(foutput, "\tNULL"); + else { + Bprint(foutput, " { "); + TLOOP(j) + if(BIT(pp,j)) + Bprint(foutput, "%s ", symnam(j)); + Bprint(foutput, "}"); + } +} + +/* + * compute an array with the beginnings of productions yielding given nonterminals + * The array pres points to these lists + * the array pyield has the lists: the total size is only NPROD+1 + */ +void +cpres(void) +{ + int c, j, i, **pmem; + static int *pyield[NPROD]; + + pmem = pyield; + NTLOOP(i) { + c = i+NTBASE; + pres[i] = pmem; + fatfl = 0; /* make undefined symbols nonfatal */ + PLOOP(0, j) + if(*prdptr[j] == c) + *pmem++ = prdptr[j]+1; + if(pres[i] == pmem) + error("nonterminal %s not defined!", nontrst[i].name); + } + pres[i] = pmem; + fatfl = 1; + if(nerrors) { + summary(); + cleantmp(); + exits("error"); + } + if(pmem != &pyield[nprod]) + error("internal Yacc error: pyield %d", pmem-&pyield[nprod]); +} + +/* + * compute an array with the first of nonterminals + */ +void +cpfir(void) +{ + int *p, **s, i, **t, ch, changes; + + zzcwp = &wsets[nnonter]; + NTLOOP(i) { + aryfil(wsets[i].ws.lset, tbitset, 0); + t = pres[i+1]; + /* initially fill the sets */ + for(s=pres[i]; s<t; ++s) + for(p = *s; (ch = *p) > 0; ++p) { + if(ch < NTBASE) { + SETBIT(wsets[i].ws.lset, ch); + break; + } + if(!pempty[ch-NTBASE]) + break; + } + } + + /* now, reflect transitivity */ + changes = 1; + while(changes) { + changes = 0; + NTLOOP(i) { + t = pres[i+1]; + for(s = pres[i]; s < t; ++s) + for(p = *s; (ch = (*p-NTBASE)) >= 0; ++p) { + changes |= setunion(wsets[i].ws.lset, wsets[ch].ws.lset); + if(!pempty[ch]) + break; + } + } + } + + NTLOOP(i) + pfirst[i] = flset(&wsets[i].ws); + if(!indebug) + return; + if(foutput != 0) + NTLOOP(i) { + Bprint(foutput, "\n%s: ", nontrst[i].name); + prlook(pfirst[i]); + Bprint(foutput, " %d\n", pempty[i]); + } +} + +/* + * sorts last state,and sees if it equals earlier ones. returns state number + */ +int +state(int c) +{ + Item *p1, *p2, *k, *l, *q1, *q2; + int size1, size2, i; + + p1 = pstate[nstate]; + p2 = pstate[nstate+1]; + if(p1 == p2) + return 0; /* null state */ + /* sort the items */ + for(k = p2-1; k > p1; k--) /* make k the biggest */ + for(l = k-1; l >= p1; --l) + if(l->pitem > k->pitem) { + int *s; + Lkset *ss; + + s = k->pitem; + k->pitem = l->pitem; + l->pitem = s; + ss = k->look; + k->look = l->look; + l->look = ss; + } + size1 = p2 - p1; /* size of state */ + + for(i = (c>=NTBASE)? ntstates[c-NTBASE]: tstates[c]; i != 0; i = mstates[i]) { + /* get ith state */ + q1 = pstate[i]; + q2 = pstate[i+1]; + size2 = q2 - q1; + if(size1 != size2) + continue; + k = p1; + for(l = q1; l < q2; l++) { + if(l->pitem != k->pitem) + break; + k++; + } + if(l != q2) + continue; + /* found it */ + pstate[nstate+1] = pstate[nstate]; /* delete last state */ + /* fix up lookaheads */ + if(nolook) + return i; + for(l = q1, k = p1; l < q2; ++l, ++k ) { + int s; + + SETLOOP(s) + clset.lset[s] = l->look->lset[s]; + if(setunion(clset.lset, k->look->lset)) { + tystate[i] = MUSTDO; + /* register the new set */ + l->look = flset( &clset ); + } + } + return i; + } + /* state is new */ + if(nolook) + error("yacc state/nolook error"); + pstate[nstate+2] = p2; + if(nstate+1 >= NSTATES) + error("too many states"); + if(c >= NTBASE) { + mstates[nstate] = ntstates[c-NTBASE]; + ntstates[c-NTBASE] = nstate; + } else { + mstates[nstate] = tstates[c]; + tstates[c] = nstate; + } + tystate[nstate] = MUSTDO; + return nstate++; +} + +void +putitem(int *ptr, Lkset *lptr) +{ + Item *j; + + if(pidebug && foutput != 0) + Bprint(foutput, "putitem(%s), state %d\n", writem(ptr), nstate); + j = pstate[nstate+1]; + j->pitem = ptr; + if(!nolook) + j->look = flset(lptr); + pstate[nstate+1] = ++j; + if((int*)j > zzmemsz) { + zzmemsz = (int*)j; + if(zzmemsz >= &mem0[MEMSIZE]) + error("out of state space"); + } +} + +/* + * mark nonterminals which derive the empty string + * also, look for nonterminals which don't derive any token strings + */ +void +cempty(void) +{ + + int i, *p; + + /* first, use the array pempty to detect productions that can never be reduced */ + /* set pempty to WHONOWS */ + aryfil(pempty, nnonter+1, WHOKNOWS); + + /* now, look at productions, marking nonterminals which derive something */ +more: + PLOOP(0, i) { + if(pempty[*prdptr[i] - NTBASE]) + continue; + for(p = prdptr[i]+1; *p >= 0; ++p) + if(*p >= NTBASE && pempty[*p-NTBASE] == WHOKNOWS) + break; + /* production can be derived */ + if(*p < 0) { + pempty[*prdptr[i]-NTBASE] = OK; + goto more; + } + } + + /* now, look at the nonterminals, to see if they are all OK */ + NTLOOP(i) { + /* the added production rises or falls as the start symbol ... */ + if(i == 0) + continue; + if(pempty[i] != OK) { + fatfl = 0; + error("nonterminal %s never derives any token string", nontrst[i].name); + } + } + + if(nerrors) { + summary(); + cleantmp(); + exits("error"); + } + + /* now, compute the pempty array, to see which nonterminals derive the empty string */ + /* set pempty to WHOKNOWS */ + aryfil( pempty, nnonter+1, WHOKNOWS); + + /* loop as long as we keep finding empty nonterminals */ + +again: + PLOOP(1, i) { + /* not known to be empty */ + if(pempty[*prdptr[i]-NTBASE] == WHOKNOWS) { + for(p = prdptr[i]+1; *p >= NTBASE && pempty[*p-NTBASE] == EMPTY ; ++p) + ; + /* we have a nontrivially empty nonterminal */ + if(*p < 0) { + pempty[*prdptr[i]-NTBASE] = EMPTY; + /* got one ... try for another */ + goto again; + } + } + } +} + +/* + * generate the states + */ +void +stagen(void) +{ + + int c, i, j, more; + Wset *p, *q; + + /* initialize */ + nstate = 0; + + /* THIS IS FUNNY from the standpoint of portability + * it represents the magic moment when the mem0 array, which has + * been holding the productions, starts to hold item pointers, of a + * different type... + * someday, alloc should be used to allocate all this stuff... for now, we + * accept that if pointers don't fit in integers, there is a problem... + */ + + pstate[0] = pstate[1] = (Item*)mem; + aryfil(clset.lset, tbitset, 0); + putitem(prdptr[0]+1, &clset); + tystate[0] = MUSTDO; + nstate = 1; + pstate[2] = pstate[1]; + + aryfil(amem, ACTSIZE, 0); + + /* now, the main state generation loop */ + for(more=1; more;) { + more = 0; + SLOOP(i) { + if(tystate[i] != MUSTDO) + continue; + tystate[i] = DONE; + aryfil(temp1, nnonter+1, 0); + /* take state i, close it, and do gotos */ + closure(i); + /* generate goto's */ + WSLOOP(wsets, p) { + if(p->flag) + continue; + p->flag = 1; + c = *(p->pitem); + if(c <= 1) { + if(pstate[i+1]-pstate[i] <= p-wsets) + tystate[i] = MUSTLOOKAHEAD; + continue; + } + /* do a goto on c */ + WSLOOP(p, q) + /* this item contributes to the goto */ + if(c == *(q->pitem)) { + putitem(q->pitem+1, &q->ws); + q->flag = 1; + } + if(c < NTBASE) + state(c); /* register new state */ + else + temp1[c-NTBASE] = state(c); + } + if(gsdebug && foutput != 0) { + Bprint(foutput, "%d: ", i); + NTLOOP(j) + if(temp1[j]) + Bprint(foutput, "%s %d, ", + nontrst[j].name, temp1[j]); + Bprint(foutput, "\n"); + } + indgo[i] = apack(&temp1[1], nnonter-1) - 1; + /* do some more */ + more = 1; + } + } +} + +/* + * generate the closure of state i + */ +void +closure(int i) +{ + + Wset *u, *v; + Item *p, *q; + int c, ch, work, k, *pi, **s, **t; + + zzclose++; + + /* first, copy kernel of state i to wsets */ + cwp = wsets; + ITMLOOP(i, p, q) { + cwp->pitem = p->pitem; + cwp->flag = 1; /* this item must get closed */ + SETLOOP(k) + cwp->ws.lset[k] = p->look->lset[k]; + WSBUMP(cwp); + } + + /* now, go through the loop, closing each item */ + work = 1; + while(work) { + work = 0; + WSLOOP(wsets, u) { + if(u->flag == 0) + continue; + /* dot is before c */ + c = *(u->pitem); + if(c < NTBASE) { + u->flag = 0; + /* only interesting case is where . is before nonterminal */ + continue; + } + + /* compute the lookahead */ + aryfil(clset.lset, tbitset, 0); + + /* find items involving c */ + WSLOOP(u, v) + if(v->flag == 1 && *(pi=v->pitem) == c) { + v->flag = 0; + if(nolook) + continue; + while((ch = *++pi) > 0) { + /* terminal symbol */ + if(ch < NTBASE) { + SETBIT(clset.lset, ch); + break; + } + /* nonterminal symbol */ + setunion(clset.lset, pfirst[ch-NTBASE]->lset); + if(!pempty[ch-NTBASE]) + break; + } + if(ch <= 0) + setunion(clset.lset, v->ws.lset); + } + + /* + * now loop over productions derived from c + * c is now nonterminal number + */ + c -= NTBASE; + t = pres[c+1]; + for(s = pres[c]; s < t; ++s) { + /* + * put these items into the closure + * is the item there + */ + WSLOOP(wsets, v) + /* yes, it is there */ + if(v->pitem == *s) { + if(nolook) + goto nexts; + if(setunion(v->ws.lset, clset.lset)) + v->flag = work = 1; + goto nexts; + } + + /* not there; make a new entry */ + if(cwp-wsets+1 >= WSETSIZE) + error( "working set overflow"); + cwp->pitem = *s; + cwp->flag = 1; + if(!nolook) { + work = 1; + SETLOOP(k) cwp->ws.lset[k] = clset.lset[k]; + } + WSBUMP(cwp); + + nexts:; + } + } + } + + /* have computed closure; flags are reset; return */ + if(cwp > zzcwp) + zzcwp = cwp; + if(cldebug && foutput != 0) { + Bprint(foutput, "\nState %d, nolook = %d\n", i, nolook); + WSLOOP(wsets, u) { + if(u->flag) + Bprint(foutput, "flag set!\n"); + u->flag = 0; + Bprint(foutput, "\t%s", writem(u->pitem)); + prlook(&u->ws); + Bprint(foutput, "\n"); + } + } +} + +/* + * decide if the lookahead set pointed to by p is known + * return pointer to a perminent location for the set + */ +Lkset* +flset(Lkset *p) +{ + Lkset *q; + int *u, *v, *w, j; + + for(q = &lkst[nlset]; q-- > lkst;) { + u = p->lset; + v = q->lset; + w = &v[tbitset]; + while(v < w) + if(*u++ != *v++) + goto more; + /* we have matched */ + return q; + more:; + } + /* add a new one */ + q = &lkst[nlset++]; + if(nlset >= LSETSIZE) + error("too many lookahead sets"); + SETLOOP(j) + q->lset[j] = p->lset[j]; + return q; +} + +void +cleantmp(void) +{ + ZAPFILE(actname); + ZAPFILE(tempname); +} + +void +intr(void) +{ + cleantmp(); + exits("interrupted"); +} + +void +setup(int argc, char *argv[]) +{ + long c, t; + int i, j, lev, ty, ytab, *p; + int vflag, dflag, stem; + char actnm[8], *stemc, *cp; + + ytab = 0; + vflag = 0; + dflag = 0; + stem = 0; + stemc = "y"; + foutput = 0; + fdefine = 0; + fdebug = 0; + ARGBEGIN{ + case 'v': + case 'V': + vflag++; + break; + case 'D': + yydebug = ARGF(); + break; + case 'd': + dflag++; + break; + case 'o': + ytab++; + ytabc = ARGF(); + break; + case 's': + stem++; + stemc = ARGF(); + break; + case 'S': + parser = PARSERS; + break; + default: + error("illegal option: %c", ARGC()); + }ARGEND + + cp = getenv("ROOT"); + if(cp == 0) + cp = ROOT; + snprint(par, sizeof(par), "%s/utils/lib/%s", cp, parser); + parser = par; + + openup(stemc, dflag, vflag, ytab, ytabc); + + ftemp = Bopen(tempname = mktemp(ttempname), OWRITE); + faction = Bopen(actname = mktemp(tactname), OWRITE); + if(ftemp == 0 || faction == 0) + error("cannot open temp file"); + if(argc < 1) + error("no input file"); + infile = argv[0]; + finput = Bopen(infile, OREAD); + if(finput == 0) + error("cannot open '%s'", argv[0]); + cnamp = cnames; + + defin(0, "$end"); + extval = PRIVATE; /* tokens start in unicode 'private use' */ + defin(0, "error"); + defin(1, "$accept"); + defin(0, "$unk"); + mem = mem0; + i = 0; + + for(t = gettok(); t != MARK && t != ENDFILE;) + switch(t) { + case ';': + t = gettok(); + break; + + case START: + if(gettok() != IDENTIFIER) + error("bad %%start construction"); + start = chfind(1, tokname); + t = gettok(); + continue; + + case TYPEDEF: + if(gettok() != TYPENAME) + error("bad syntax in %%type"); + ty = numbval; + for(;;) { + t = gettok(); + switch(t) { + case IDENTIFIER: + if((t=chfind(1, tokname)) < NTBASE) { + j = TYPE(toklev[t]); + if(j != 0 && j != ty) + error("type redeclaration of token %s", + tokset[t].name); + else + SETTYPE(toklev[t], ty); + } else { + j = nontrst[t-NTBASE].value; + if(j != 0 && j != ty) + error("type redeclaration of nonterminal %s", + nontrst[t-NTBASE].name ); + else + nontrst[t-NTBASE].value = ty; + } + case ',': + continue; + case ';': + t = gettok(); + default: + break; + } + break; + } + continue; + + case UNION: + /* copy the union declaration to the output */ + cpyunion(); + t = gettok(); + continue; + + case LEFT: + case BINARY: + case RIGHT: + i++; + + case TERM: + /* nonzero means new prec. and assoc. */ + lev = t-TERM; + ty = 0; + + /* get identifiers so defined */ + t = gettok(); + + /* there is a type defined */ + if(t == TYPENAME) { + ty = numbval; + t = gettok(); + } + for(;;) { + switch(t) { + case ',': + t = gettok(); + continue; + + case ';': + break; + + case IDENTIFIER: + j = chfind(0, tokname); + if(j >= NTBASE) + error("%s defined earlier as nonterminal", tokname); + if(lev) { + if(ASSOC(toklev[j])) + error("redeclaration of precedence of %s", tokname); + SETASC(toklev[j], lev); + SETPLEV(toklev[j], i); + } + if(ty) { + if(TYPE(toklev[j])) + error("redeclaration of type of %s", tokname); + SETTYPE(toklev[j],ty); + } + t = gettok(); + if(t == NUMBER) { + tokset[j].value = numbval; + if(j < ndefout && j > 3) + error("please define type number of %s earlier", + tokset[j].name); + t = gettok(); + } + continue; + } + break; + } + continue; + + case LCURLY: + defout(0); + cpycode(); + t = gettok(); + continue; + + default: + error("syntax error"); + } + if(t == ENDFILE) + error("unexpected EOF before %%"); + + /* t is MARK */ + Bprint(ftable, "extern int yyerrflag;\n"); + Bprint(ftable, "#ifndef YYMAXDEPTH\n"); + Bprint(ftable, "#define YYMAXDEPTH 150\n"); + Bprint(ftable, "#endif\n" ); + if(!ntypes) { + Bprint(ftable, "#ifndef YYSTYPE\n"); + Bprint(ftable, "#define YYSTYPE int\n"); + Bprint(ftable, "#endif\n"); + } + Bprint(ftable, "YYSTYPE yylval;\n"); + Bprint(ftable, "YYSTYPE yyval;\n"); + + prdptr[0] = mem; + + /* added production */ + *mem++ = NTBASE; + + /* if start is 0, we will overwrite with the lhs of the first rule */ + *mem++ = start; + *mem++ = 1; + *mem++ = 0; + prdptr[1] = mem; + while((t=gettok()) == LCURLY) + cpycode(); + if(t != IDENTCOLON) + error("bad syntax on first rule"); + + if(!start) + prdptr[0][1] = chfind(1, tokname); + + /* read rules */ + while(t != MARK && t != ENDFILE) { + /* process a rule */ + rlines[nprod] = lineno; + if(t == '|') + *mem++ = *prdptr[nprod-1]; + else + if(t == IDENTCOLON) { + *mem = chfind(1, tokname); + if(*mem < NTBASE) + error("token illegal on LHS of grammar rule"); + mem++; + } else + error("illegal rule: missing semicolon or | ?"); + /* read rule body */ + t = gettok(); + + more_rule: + while(t == IDENTIFIER) { + *mem = chfind(1, tokname); + if(*mem < NTBASE) + levprd[nprod] = toklev[*mem]; + mem++; + t = gettok(); + } + if(t == PREC) { + if(gettok() != IDENTIFIER) + error("illegal %%prec syntax"); + j = chfind(2, tokname); + if(j >= NTBASE) + error("nonterminal %s illegal after %%prec", + nontrst[j-NTBASE].name); + levprd[nprod] = toklev[j]; + t = gettok(); + } + if(t == '=') { + levprd[nprod] |= ACTFLAG; + Bprint(faction, "\ncase %d:", nprod); + cpyact(mem-prdptr[nprod]-1); + Bprint(faction, " break;"); + if((t=gettok()) == IDENTIFIER) { + + /* action within rule... */ + sprint(actnm, "$$%d", nprod); + + /* make it a nonterminal */ + j = chfind(1, actnm); + + /* + * the current rule will become rule number nprod+1 + * move the contents down, and make room for the null + */ + for(p = mem; p >= prdptr[nprod]; --p) + p[2] = *p; + mem += 2; + + /* enter null production for action */ + p = prdptr[nprod]; + *p++ = j; + *p++ = -nprod; + + /* update the production information */ + levprd[nprod+1] = levprd[nprod] & ~ACTFLAG; + levprd[nprod] = ACTFLAG; + if(++nprod >= NPROD) + error("more than %d rules", NPROD); + prdptr[nprod] = p; + + /* make the action appear in the original rule */ + *mem++ = j; + + /* get some more of the rule */ + goto more_rule; + } + } + + while(t == ';') + t = gettok(); + *mem++ = -nprod; + + /* check that default action is reasonable */ + if(ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].value) { + + /* no explicit action, LHS has value */ + int tempty; + + tempty = prdptr[nprod][1]; + if(tempty < 0) + error("must return a value, since LHS has a type"); + else + if(tempty >= NTBASE) + tempty = nontrst[tempty-NTBASE].value; + else + tempty = TYPE(toklev[tempty]); + if(tempty != nontrst[*prdptr[nprod]-NTBASE].value) + error("default action causes potential type clash"); + } + nprod++; + if(nprod >= NPROD) + error("more than %d rules", NPROD); + prdptr[nprod] = mem; + levprd[nprod] = 0; + } + + /* end of all rules */ + defout(1); + + finact(); + if(t == MARK) { + Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile); + while((c=Bgetrune(finput)) != Beof) + Bputrune(ftable, c); + } + Bterm(finput); +} + +/* + * finish action routine + */ +void +finact(void) +{ + + Bterm(faction); + Bprint(ftable, "#define YYEOFCODE %d\n", 1); + Bprint(ftable, "#define YYERRCODE %d\n", 2); +} + +/* + * define s to be a terminal if t=0 + * or a nonterminal if t=1 + */ +int +defin(int nt, char *s) +{ + int val; + Rune rune; + + val = 0; + if(nt) { + nnonter++; + if(nnonter >= NNONTERM) + error("too many nonterminals, limit %d",NNONTERM); + nontrst[nnonter].name = cstash(s); + return NTBASE + nnonter; + } + + /* must be a token */ + ntokens++; + if(ntokens >= NTERMS) + error("too many terminals, limit %d", NTERMS); + tokset[ntokens].name = cstash(s); + + /* establish value for token */ + /* single character literal */ + if(s[0] == ' ') { + val = chartorune(&rune, &s[1]); + if(s[val+1] == 0) { + val = rune; + goto out; + } + } + + /* escape sequence */ + if(s[0] == ' ' && s[1] == '\\') { + if(s[3] == 0) { + /* single character escape sequence */ + switch(s[2]) { + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 'b': val = '\b'; break; + case 't': val = '\t'; break; + case 'f': val = '\f'; break; + case '\'': val = '\''; break; + case '"': val = '"'; break; + case '\\': val = '\\'; break; + default: error("invalid escape"); + } + goto out; + } + + /* \nnn sequence */ + if(s[2] >= '0' && s[2] <= '7') { + if(s[3] < '0' || + s[3] > '7' || + s[4] < '0' || + s[4] > '7' || + s[5] != 0) + error("illegal \\nnn construction"); + val = 64*s[2] + 8*s[3] + s[4] - 73*'0'; + if(val == 0) + error("'\\000' is illegal"); + goto out; + } + error("unknown escape"); + } + val = extval++; + +out: + tokset[ntokens].value = val; + toklev[ntokens] = 0; + return ntokens; +} + +/* + * write out the defines (at the end of the declaration section) + */ +void +defout(int last) +{ + int i, c; + char sar[NAMESIZE+10]; + + for(i=ndefout; i<=ntokens; i++) { + /* non-literals */ + c = tokset[i].name[0]; + if(c != ' ' && c != '$') { + Bprint(ftable, "#define %s %d\n", + tokset[i].name, tokset[i].value); + if(fdefine) + Bprint(fdefine, "#define\t%s\t%d\n", + tokset[i].name, tokset[i].value); + } + } + ndefout = ntokens+1; + if(last && fdebug) { + Bprint(fdebug, "char* yytoknames[] =\n{\n"); + TLOOP(i) { + if(tokset[i].name) { + chcopy(sar, tokset[i].name); + Bprint(fdebug, "\t\"%s\",\n", sar); + continue; + } + Bprint(fdebug, "\t0,\n"); + } + Bprint(fdebug, "};\n"); + } +} + +char* +cstash(char *s) +{ + char *temp; + + temp = cnamp; + do { + if(cnamp >= &cnames[cnamsz]) + error("too many characters in id's and literals"); + else + *cnamp++ = *s; + } while(*s++); + return temp; +} + +long +gettok(void) +{ + long c; + Rune rune; + int i, base, match, reserve; + static int peekline; + +begin: + reserve = 0; + lineno += peekline; + peekline = 0; + c = Bgetrune(finput); + while(c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r') { + if(c == '\n') + lineno++; + c = Bgetrune(finput); + } + + /* skip comment */ + if(c == '/') { + lineno += skipcom(); + goto begin; + } + switch(c) { + case Beof: + return ENDFILE; + + case '{': + Bungetrune(finput); + return '='; + + case '<': + /* get, and look up, a type name (union member name) */ + i = 0; + while((c=Bgetrune(finput)) != '>' && c >= 0 && c != '\n' && c != '\r') { + rune = c; + c = runetochar(&tokname[i], &rune); + if(i < NAMESIZE) + i += c; + } + if(c != '>') + error("unterminated < ... > clause"); + tokname[i] = 0; + for(i=1; i<=ntypes; i++) + if(!strcmp(typeset[i], tokname)) { + numbval = i; + return TYPENAME; + } + ntypes++; + numbval = ntypes; + typeset[numbval] = cstash(tokname); + return TYPENAME; + + case '"': + case '\'': + match = c; + tokname[0] = ' '; + i = 1; + for(;;) { + c = Bgetrune(finput); + if(c == '\n' || c == '\r' || c <= 0) + error("illegal or missing ' or \"" ); + if(c == '\\') { + tokname[i] = '\\'; + if(i < NAMESIZE) + i++; + c = Bgetrune(finput); + } else + if(c == match) + break; + rune = c; + c = runetochar(&tokname[i], &rune); + if(i < NAMESIZE) + i += c; + } + break; + + case '%': + case '\\': + switch(c = Bgetrune(finput)) { + case '0': return TERM; + case '<': return LEFT; + case '2': return BINARY; + case '>': return RIGHT; + case '%': + case '\\': return MARK; + case '=': return PREC; + case '{': return LCURLY; + default: reserve = 1; + } + + default: + /* number */ + if(isdigit(c)) { + numbval = c-'0'; + base = (c=='0')? 8: 10; + for(c = Bgetrune(finput); isdigit(c); c = Bgetrune(finput)) + numbval = numbval*base + (c-'0'); + Bungetrune(finput); + return NUMBER; + } + if(islower(c) || isupper(c) || c=='_' || c=='.' || c=='$') { + i = 0; + while(islower(c) || isupper(c) || isdigit(c) || + c == '-' || c=='_' || c=='.' || c=='$') { + if(reserve && isupper(c)) + c += 'a'-'A'; + rune = c; + c = runetochar(&tokname[i], &rune); + if(i < NAMESIZE) + i += c; + c = Bgetrune(finput); + } + } else + return c; + Bungetrune(finput); + } + tokname[i] = 0; + + /* find a reserved word */ + if(reserve) { + for(c=0; resrv[c].name; c++) + if(strcmp(tokname, resrv[c].name) == 0) + return resrv[c].value; + error("invalid escape, or illegal reserved word: %s", tokname); + } + + /* look ahead to distinguish IDENTIFIER from IDENTCOLON */ + c = Bgetrune(finput); + while(c == ' ' || c == '\t'|| c == '\n' || c == '\r' || c == '\f' || c == '/') { + if(c == '\n') + peekline++; + /* look for comments */ + if(c == '/') + peekline += skipcom(); + c = Bgetrune(finput); + } + if(c == ':') + return IDENTCOLON; + Bungetrune(finput); + return IDENTIFIER; +} + +/* + * determine the type of a symbol + */ +int +fdtype(int t) +{ + int v; + + if(t >= NTBASE) + v = nontrst[t-NTBASE].value; + else + v = TYPE(toklev[t]); + if(v <= 0) + error("must specify type for %s", (t>=NTBASE)? + nontrst[t-NTBASE].name: tokset[t].name); + return v; +} + +int +chfind(int t, char *s) +{ + int i; + + if(s[0] == ' ') + t = 0; + TLOOP(i) + if(!strcmp(s, tokset[i].name)) + return i; + NTLOOP(i) + if(!strcmp(s, nontrst[i].name)) + return NTBASE+i; + + /* cannot find name */ + if(t > 1) + error("%s should have been defined earlier", s); + return defin(t, s); +} + +/* + * copy the union declaration to the output, and the define file if present + */ +void +cpyunion(void) +{ + long c; + int level; + + Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile); + Bprint(ftable, "typedef union "); + if(fdefine != 0) + Bprint(fdefine, "\ntypedef union "); + + level = 0; + for(;;) { + if((c=Bgetrune(finput)) == Beof) + error("EOF encountered while processing %%union"); + Bputrune(ftable, c); + if(fdefine != 0) + Bputrune(fdefine, c); + switch(c) { + case '\n': + lineno++; + break; + case '{': + level++; + break; + case '}': + level--; + + /* we are finished copying */ + if(level == 0) { + Bprint(ftable, " YYSTYPE;\n"); + if(fdefine != 0) + Bprint(fdefine, "\tYYSTYPE;\nextern\tYYSTYPE\tyylval;\n"); + return; + } + } + } +} + +/* + * copies code between \{ and \} + */ +void +cpycode(void) +{ + + long c; + + c = Bgetrune(finput); + if(c == '\n') { + c = Bgetrune(finput); + lineno++; + } + Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile); + while(c != Beof) { + if(c == '\\') { + if((c=Bgetrune(finput)) == '}') + return; + Bputc(ftable, '\\'); + } + if(c == '%') { + if((c=Bgetrune(finput)) == '}') + return; + Bputc(ftable, '%'); + } + Bputrune(ftable, c); + if(c == '\n') + lineno++; + c = Bgetrune(finput); + } + error("eof before %%}"); +} + +/* + * skip over comments + * skipcom is called after reading a '/' + */ +int +skipcom(void) +{ + long c; + int i; + + /* i is the number of lines skipped */ + i = 0; + if(Bgetrune(finput) != '*') + error("illegal comment"); + c = Bgetrune(finput); + while(c != Beof) { + while(c == '*') + if((c=Bgetrune(finput)) == '/') + return i; + if(c == '\n') + i++; + c = Bgetrune(finput); + } + error("EOF inside comment"); + return 0; +} + +/* + * copy C action to the next ; or closing } + */ +void +cpyact(int offset) +{ + long c; + int brac, match, j, s, fnd, tok; + + Bprint(faction, "\n#line\t%d\t\"%s\"\n", lineno, infile); + brac = 0; + +loop: + c = Bgetrune(finput); +swt: + switch(c) { + case ';': + if(brac == 0) { + Bputrune(faction, c); + return; + } + goto lcopy; + + case '{': + brac++; + goto lcopy; + + case '$': + s = 1; + tok = -1; + c = Bgetrune(finput); + + /* type description */ + if(c == '<') { + Bungetrune(finput); + if(gettok() != TYPENAME) + error("bad syntax on $<ident> clause"); + tok = numbval; + c = Bgetrune(finput); + } + if(c == '$') { + Bprint(faction, "yyval"); + + /* put out the proper tag... */ + if(ntypes) { + if(tok < 0) + tok = fdtype(*prdptr[nprod]); + Bprint(faction, ".%s", typeset[tok]); + } + goto loop; + } + if(c == '-') { + s = -s; + c = Bgetrune(finput); + } + if(isdigit(c)) { + j = 0; + while(isdigit(c)) { + j = j*10 + (c-'0'); + c = Bgetrune(finput); + } + Bungetrune(finput); + j = j*s - offset; + if(j > 0) + error("Illegal use of $%d", j+offset); + + dollar: + Bprint(faction, "yypt[-%d].yyv", -j); + + /* put out the proper tag */ + if(ntypes) { + if(j+offset <= 0 && tok < 0) + error("must specify type of $%d", j+offset); + if(tok < 0) + tok = fdtype(prdptr[nprod][j+offset]); + Bprint(faction, ".%s", typeset[tok]); + } + goto loop; + } + if(isupper(c) || islower(c) || c == '_' || c == '.') { + int tok; /* tok used oustide for type info */ + + /* look for $name */ + Bungetrune(finput); + if(gettok() != IDENTIFIER) + error("$ must be followed by an identifier"); + tok = chfind(2, tokname); + if((c = Bgetrune(finput)) != '#') { + Bungetrune(finput); + fnd = -1; + } else + if(gettok() != NUMBER) { + error("# must be followed by number"); + fnd = -1; + } else + fnd = numbval; + for(j=1; j<=offset; ++j) + if(tok == prdptr[nprod][j]) { + if(--fnd <= 0) { + j -= offset; + goto dollar; + } + } + error("$name or $name#number not found"); + } + Bputc(faction, '$'); + if(s < 0 ) + Bputc(faction, '-'); + goto swt; + + case '}': + brac--; + if(brac) + goto lcopy; + Bputrune(faction, c); + return; + + case '/': + /* look for comments */ + Bputrune(faction, c); + c = Bgetrune(finput); + if(c != '*') + goto swt; + + /* it really is a comment */ + Bputrune(faction, c); + c = Bgetrune(finput); + while(c >= 0) { + while(c == '*') { + Bputrune(faction, c); + if((c=Bgetrune(finput)) == '/') + goto lcopy; + } + Bputrune(faction, c); + if(c == '\n') + lineno++; + c = Bgetrune(finput); + } + error("EOF inside comment"); + + case '\'': + /* character constant */ + match = '\''; + goto string; + + case '"': + /* character string */ + match = '"'; + + string: + Bputrune(faction, c); + while(c = Bgetrune(finput)) { + if(c == '\\') { + Bputrune(faction, c); + c = Bgetrune(finput); + if(c == '\n') + lineno++; + } else + if(c == match) + goto lcopy; + if(c == '\n') + error("newline in string or char. const."); + Bputrune(faction, c); + } + error("EOF in string or character constant"); + + case Beof: + error("action does not terminate"); + + case '\n': + lineno++; + goto lcopy; + } + +lcopy: + Bputrune(faction, c); + goto loop; +} + +void +openup(char *stem, int dflag, int vflag, int ytab, char *ytabc) +{ + char buf[256]; + + if(vflag) { + sprint(buf, "%s.%s", stem, FILEU); + foutput = Bopen(buf, OWRITE); + if(foutput == 0) + error("cannot open %s", buf); + } + if(yydebug) { + sprint(buf, "%s.%s", stem, FILEDEBUG); + if((fdebug = Bopen(buf, OWRITE)) == 0) + error("can't open %s", buf); + } + if(dflag) { + sprint(buf, "%s.%s", stem, FILED); + fdefine = Bopen(buf, OWRITE); + if(fdefine == 0) + error("can't create %s", buf); + } + if(ytab == 0) + sprint(buf, "%s.%s", stem, OFILE); + else + strcpy(buf, ytabc); + ftable = Bopen(buf, OWRITE); + if(ftable == 0) + error("cannot open table file %s", buf); +} + +/* + * print the output for the states + */ +void +output(void) +{ + int i, k, c; + Wset *u, *v; + + Bprint(ftable, "short yyexca[] =\n{"); + if(fdebug) + Bprint(fdebug, "char* yystates[] =\n{\n"); + + /* output the stuff for state i */ + SLOOP(i) { + nolook = tystate[i]!=MUSTLOOKAHEAD; + closure(i); + + /* output actions */ + nolook = 1; + aryfil(temp1, ntokens+nnonter+1, 0); + WSLOOP(wsets, u) { + c = *(u->pitem); + if(c > 1 && c < NTBASE && temp1[c] == 0) { + WSLOOP(u, v) + if(c == *(v->pitem)) + putitem(v->pitem+1, (Lkset*)0); + temp1[c] = state(c); + } else + if(c > NTBASE && temp1[(c -= NTBASE) + ntokens] == 0) + temp1[c+ntokens] = amem[indgo[i]+c]; + } + if(i == 1) + temp1[1] = ACCEPTCODE; + + /* now, we have the shifts; look at the reductions */ + lastred = 0; + WSLOOP(wsets, u) { + c = *u->pitem; + + /* reduction */ + if(c <= 0) { + lastred = -c; + TLOOP(k) + if(BIT(u->ws.lset, k)) { + if(temp1[k] == 0) + temp1[k] = c; + else + if(temp1[k] < 0) { /* reduce/reduce conflict */ + if(foutput) + Bprint(foutput, + "\n%d: reduce/reduce conflict" + " (red'ns %d and %d ) on %s", + i, -temp1[k], lastred, + symnam(k)); + if(-temp1[k] > lastred) + temp1[k] = -lastred; + zzrrconf++; + } else + /* potential shift/reduce conflict */ + precftn( lastred, k, i ); + } + } + } + wract(i); + } + + if(fdebug) + Bprint(fdebug, "};\n"); + Bprint(ftable, "};\n"); + Bprint(ftable, "#define YYNPROD %d\n", nprod); + Bprint(ftable, "#define YYPRIVATE %d\n", PRIVATE); + if(yydebug) + Bprint(ftable, "#define yydebug %s\n", yydebug); +} + +/* + * pack state i from temp1 into amem + */ +int +apack(int *p, int n) +{ + int *pp, *qq, *rr, off, *q, *r; + + /* we don't need to worry about checking because + * we will only look at entries known to be there... + * eliminate leading and trailing 0's + */ + + q = p+n; + for(pp = p, off = 0; *pp == 0 && pp <= q; ++pp, --off) + ; + /* no actions */ + if(pp > q) + return 0; + p = pp; + + /* now, find a place for the elements from p to q, inclusive */ + r = &amem[ACTSIZE-1]; + for(rr = amem; rr <= r; rr++, off++) { + for(qq = rr, pp = p; pp <= q; pp++, qq++) + if(*pp != 0) + if(*pp != *qq && *qq != 0) + goto nextk; + + /* we have found an acceptable k */ + if(pkdebug && foutput != 0) + Bprint(foutput, "off = %d, k = %d\n", off, (int)(rr-amem)); + for(qq = rr, pp = p; pp <= q; pp++, qq++) + if(*pp) { + if(qq > r) + error("action table overflow"); + if(qq > memp) + memp = qq; + *qq = *pp; + } + if(pkdebug && foutput != 0) + for(pp = amem; pp <= memp; pp += 10) { + Bprint(foutput, "\t"); + for(qq = pp; qq <= pp+9; qq++) + Bprint(foutput, "%d ", *qq); + Bprint(foutput, "\n"); + } + return(off); + nextk:; + } + error("no space in action table"); + return 0; +} + +/* + * output the gotos for the nontermninals + */ +void +go2out(void) +{ + int i, j, k, best, count, cbest, times; + + /* mark begining of gotos */ + Bprint(ftemp, "$\n"); + for(i = 1; i <= nnonter; i++) { + go2gen(i); + + /* find the best one to make default */ + best = -1; + times = 0; + + /* is j the most frequent */ + for(j = 0; j <= nstate; j++) { + if(tystate[j] == 0) + continue; + if(tystate[j] == best) + continue; + + /* is tystate[j] the most frequent */ + count = 0; + cbest = tystate[j]; + for(k = j; k <= nstate; k++) + if(tystate[k] == cbest) + count++; + if(count > times) { + best = cbest; + times = count; + } + } + + /* best is now the default entry */ + zzgobest += times-1; + for(j = 0; j <= nstate; j++) + if(tystate[j] != 0 && tystate[j] != best) { + Bprint(ftemp, "%d,%d,", j, tystate[j]); + zzgoent++; + } + + /* now, the default */ + if(best == -1) + best = 0; + zzgoent++; + Bprint(ftemp, "%d\n", best); + } +} + +/* + * output the gotos for nonterminal c + */ +void +go2gen(int c) +{ + int i, work, cc; + Item *p, *q; + + + /* first, find nonterminals with gotos on c */ + aryfil(temp1, nnonter+1, 0); + temp1[c] = 1; + work = 1; + while(work) { + work = 0; + PLOOP(0, i) + + /* cc is a nonterminal */ + if((cc=prdptr[i][1]-NTBASE) >= 0) + /* cc has a goto on c */ + if(temp1[cc] != 0) { + + /* thus, the left side of production i does too */ + cc = *prdptr[i]-NTBASE; + if(temp1[cc] == 0) { + work = 1; + temp1[cc] = 1; + } + } + } + + /* now, we have temp1[c] = 1 if a goto on c in closure of cc */ + if(g2debug && foutput != 0) { + Bprint(foutput, "%s: gotos on ", nontrst[c].name); + NTLOOP(i) + if(temp1[i]) + Bprint(foutput, "%s ", nontrst[i].name); + Bprint(foutput, "\n"); + } + + /* now, go through and put gotos into tystate */ + aryfil(tystate, nstate, 0); + SLOOP(i) + ITMLOOP(i, p, q) + if((cc = *p->pitem) >= NTBASE) + /* goto on c is possible */ + if(temp1[cc-NTBASE]) { + tystate[i] = amem[indgo[i]+c]; + break; + } +} + +/* + * decide a shift/reduce conflict by precedence. + * r is a rule number, t a token number + * the conflict is in state s + * temp1[t] is changed to reflect the action + */ +void +precftn(int r, int t, int s) +{ + int lp, lt, action; + + lp = levprd[r]; + lt = toklev[t]; + if(PLEVEL(lt) == 0 || PLEVEL(lp) == 0) { + + /* conflict */ + if(foutput != 0) + Bprint(foutput, + "\n%d: shift/reduce conflict (shift %d(%d), red'n %d(%d)) on %s", + s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t)); + zzsrconf++; + return; + } + if(PLEVEL(lt) == PLEVEL(lp)) + action = ASSOC(lt); + else + if(PLEVEL(lt) > PLEVEL(lp)) + action = RASC; /* shift */ + else + action = LASC; /* reduce */ + switch(action) { + case BASC: /* error action */ + temp1[t] = ERRCODE; + break; + case LASC: /* reduce */ + temp1[t] = -r; + break; + } +} + +/* + * output state i + * temp1 has the actions, lastred the default + */ +void +wract(int i) +{ + int p, p0, p1, ntimes, tred, count, j, flag; + + /* find the best choice for lastred */ + lastred = 0; + ntimes = 0; + TLOOP(j) { + if(temp1[j] >= 0) + continue; + if(temp1[j]+lastred == 0) + continue; + /* count the number of appearances of temp1[j] */ + count = 0; + tred = -temp1[j]; + levprd[tred] |= REDFLAG; + TLOOP(p) + if(temp1[p]+tred == 0) + count++; + if(count > ntimes) { + lastred = tred; + ntimes = count; + } + } + + /* + * for error recovery, arrange that, if there is a shift on the + * error recovery token, `error', that the default be the error action + */ + if(temp1[2] > 0) + lastred = 0; + + /* clear out entries in temp1 which equal lastred */ + TLOOP(p) + if(temp1[p]+lastred == 0) + temp1[p] = 0; + + wrstate(i); + defact[i] = lastred; + flag = 0; + TLOOP(p0) + if((p1=temp1[p0]) != 0) { + if(p1 < 0) { + p1 = -p1; + goto exc; + } + if(p1 == ACCEPTCODE) { + p1 = -1; + goto exc; + } + if(p1 == ERRCODE) { + p1 = 0; + exc: + if(flag++ == 0) + Bprint(ftable, "-1, %d,\n", i); + Bprint(ftable, "\t%d, %d,\n", p0, p1); + zzexcp++; + continue; + } + Bprint(ftemp, "%d,%d,", p0, p1); + zzacent++; + } + if(flag) { + defact[i] = -2; + Bprint(ftable, "\t-2, %d,\n", lastred); + } + Bprint(ftemp, "\n"); +} + +/* + * writes state i + */ +void +wrstate(int i) +{ + int j0, j1; + Item *pp, *qq; + Wset *u; + + if(fdebug) { + if(lastred) { + Bprint(fdebug, " 0, /*%d*/\n", i); + } else { + Bprint(fdebug, " \""); + ITMLOOP(i, pp, qq) + Bprint(fdebug, "%s\\n", writem(pp->pitem)); + if(tystate[i] == MUSTLOOKAHEAD) + WSLOOP(wsets + (pstate[i+1] - pstate[i]), u) + if(*u->pitem < 0) + Bprint(fdebug, "%s\\n", writem(u->pitem)); + Bprint(fdebug, "\", /*%d*/\n", i); + } + } + if(foutput == 0) + return; + Bprint(foutput, "\nstate %d\n", i); + ITMLOOP(i, pp, qq) + Bprint(foutput, "\t%s\n", writem(pp->pitem)); + if(tystate[i] == MUSTLOOKAHEAD) + /* print out empty productions in closure */ + WSLOOP(wsets+(pstate[i+1]-pstate[i]), u) + if(*u->pitem < 0) + Bprint(foutput, "\t%s\n", writem(u->pitem)); + + /* check for state equal to another */ + TLOOP(j0) + if((j1=temp1[j0]) != 0) { + Bprint(foutput, "\n\t%s ", symnam(j0)); + /* shift, error, or accept */ + if(j1 > 0) { + if(j1 == ACCEPTCODE) + Bprint(foutput, "accept"); + else + if(j1 == ERRCODE) + Bprint(foutput, "error"); + else + Bprint(foutput, "shift %d", j1); + } else + Bprint(foutput, "reduce %d (src line %d)", -j1, rlines[-j1]); + } + + /* output the final production */ + if(lastred) + Bprint(foutput, "\n\t. reduce %d (src line %d)\n\n", + lastred, rlines[lastred]); + else + Bprint(foutput, "\n\t. error\n\n"); + + /* now, output nonterminal actions */ + j1 = ntokens; + for(j0 = 1; j0 <= nnonter; j0++) { + j1++; + if(temp1[j1]) + Bprint(foutput, "\t%s goto %d\n", symnam(j0+NTBASE), temp1[j1]); + } +} + +void +warray(char *s, int *v, int n) +{ + int i; + + Bprint(ftable, "short %s[] =\n{", s); + for(i=0;;) { + if(i%10 == 0) + Bprint(ftable, "\n"); + Bprint(ftable, "%4d", v[i]); + i++; + if(i >= n) { + Bprint(ftable, "\n};\n"); + break; + } + Bprint(ftable, ","); + } +} + +/* + * in order to free up the mem and amem arrays for the optimizer, + * and still be able to output yyr1, etc., after the sizes of + * the action array is known, we hide the nonterminals + * derived by productions in levprd. + */ + +void +hideprod(void) +{ + int i, j; + + j = 0; + levprd[0] = 0; + PLOOP(1, i) { + if(!(levprd[i] & REDFLAG)) { + j++; + if(foutput != 0) + Bprint(foutput, "Rule not reduced: %s\n", writem(prdptr[i])); + } + levprd[i] = *prdptr[i] - NTBASE; + } + if(j) + print("%d rules never reduced\n", j); +} + +void +callopt(void) +{ + int i, *p, j, k, *q; + + /* read the arrays from tempfile and set parameters */ + finput = Bopen(tempname, OREAD); + if(finput == 0) + error("optimizer cannot open tempfile"); + pgo[0] = 0; + temp1[0] = 0; + nstate = 0; + nnonter = 0; + for(;;) { + switch(gtnm()) { + case '\n': + nstate++; + pmem--; + temp1[nstate] = pmem - mem0; + case ',': + continue; + case '$': + break; + default: + error("bad tempfile"); + } + break; + } + + pmem--; + temp1[nstate] = yypgo[0] = pmem - mem0; + for(;;) { + switch(gtnm()) { + case '\n': + nnonter++; + yypgo[nnonter] = pmem-mem0; + case ',': + continue; + case -1: + break; + default: + error("bad tempfile"); + } + break; + } + pmem--; + yypgo[nnonter--] = pmem - mem0; + for(i = 0; i < nstate; i++) { + k = 32000; + j = 0; + q = mem0 + temp1[i+1]; + for(p = mem0 + temp1[i]; p < q ; p += 2) { + if(*p > j) + j = *p; + if(*p < k) + k = *p; + } + /* nontrivial situation */ + if(k <= j) { + /* j is now the range */ +/* j -= k; /* call scj */ + if(k > maxoff) + maxoff = k; + } + tystate[i] = (temp1[i+1]-temp1[i]) + 2*j; + if(j > maxspr) + maxspr = j; + } + + /* initialize ggreed table */ + for(i = 1; i <= nnonter; i++) { + ggreed[i] = 1; + j = 0; + + /* minimum entry index is always 0 */ + q = mem0 + yypgo[i+1] - 1; + for(p = mem0+yypgo[i]; p < q ; p += 2) { + ggreed[i] += 2; + if(*p > j) + j = *p; + } + ggreed[i] = ggreed[i] + 2*j; + if(j > maxoff) + maxoff = j; + } + + /* now, prepare to put the shift actions into the amem array */ + for(i = 0; i < ACTSIZE; i++) + amem[i] = 0; + maxa = amem; + for(i = 0; i < nstate; i++) { + if(tystate[i] == 0 && adb > 1) + Bprint(ftable, "State %d: null\n", i); + indgo[i] = YYFLAG1; + } + while((i = nxti()) != NOMORE) + if(i >= 0) + stin(i); + else + gin(-i); + + /* print amem array */ + if(adb > 2 ) + for(p = amem; p <= maxa; p += 10) { + Bprint(ftable, "%4d ", (int)(p-amem)); + for(i = 0; i < 10; ++i) + Bprint(ftable, "%4d ", p[i]); + Bprint(ftable, "\n"); + } + + /* write out the output appropriate to the language */ + aoutput(); + osummary(); + Bterm(finput); + ZAPFILE(tempname); +} + +void +gin(int i) +{ + int *p, *r, *s, *q1, *q2; + + /* enter gotos on nonterminal i into array amem */ + ggreed[i] = 0; + + q2 = mem0+ yypgo[i+1] - 1; + q1 = mem0 + yypgo[i]; + + /* now, find amem place for it */ + for(p = amem; p < &amem[ACTSIZE]; p++) { + if(*p) + continue; + for(r = q1; r < q2; r += 2) { + s = p + *r + 1; + if(*s) + goto nextgp; + if(s > maxa) + if((maxa = s) > &amem[ACTSIZE]) + error("a array overflow"); + } + /* we have found amem spot */ + *p = *q2; + if(p > maxa) + if((maxa = p) > &amem[ACTSIZE]) + error("a array overflow"); + for(r = q1; r < q2; r += 2) { + s = p + *r + 1; + *s = r[1]; + } + pgo[i] = p-amem; + if(adb > 1) + Bprint(ftable, "Nonterminal %d, entry at %d\n", i, pgo[i]); + return; + + nextgp:; + } + error("cannot place goto %d\n", i); +} + +void +stin(int i) +{ + int *r, *s, n, flag, j, *q1, *q2; + + tystate[i] = 0; + + /* enter state i into the amem array */ + q2 = mem0+temp1[i+1]; + q1 = mem0+temp1[i]; + /* find an acceptable place */ + for(n = -maxoff; n < ACTSIZE; n++) { + flag = 0; + for(r = q1; r < q2; r += 2) { + if((s = *r + n + amem) < amem) + goto nextn; + if(*s == 0) + flag++; + else + if(*s != r[1]) + goto nextn; + } + + /* check that the position equals another only if the states are identical */ + for(j=0; j<nstate; j++) { + if(indgo[j] == n) { + + /* we have some disagreement */ + if(flag) + goto nextn; + if(temp1[j+1]+temp1[i] == temp1[j]+temp1[i+1]) { + + /* states are equal */ + indgo[i] = n; + if(adb > 1) + Bprint(ftable, + "State %d: entry at %d equals state %d\n", + i, n, j); + return; + } + + /* we have some disagreement */ + goto nextn; + } + } + + for(r = q1; r < q2; r += 2) { + if((s = *r+n+amem) >= &amem[ACTSIZE]) + error("out of space in optimizer a array"); + if(s > maxa) + maxa = s; + if(*s != 0 && *s != r[1]) + error("clobber of a array, pos'n %d, by %d", s-amem, r[1]); + *s = r[1]; + } + indgo[i] = n; + if(adb > 1) + Bprint(ftable, "State %d: entry at %d\n", i, indgo[i]); + return; + nextn:; + } + error("Error; failure to place state %d\n", i); +} + +/* + * finds the next i + */ +int +nxti(void) +{ + int i, max, maxi; + + max = 0; + maxi = 0; + for(i = 1; i <= nnonter; i++) + if(ggreed[i] >= max) { + max = ggreed[i]; + maxi = -i; + } + for(i = 0; i < nstate; ++i) + if(tystate[i] >= max) { + max = tystate[i]; + maxi = i; + } + if(nxdb) + Bprint(ftable, "nxti = %d, max = %d\n", maxi, max); + if(max == 0) + return NOMORE; + return maxi; +} + +/* + * write summary + */ +void +osummary(void) +{ + + int i, *p; + + if(foutput == 0) + return; + i = 0; + for(p = maxa; p >= amem; p--) + if(*p == 0) + i++; + + Bprint(foutput, "Optimizer space used: input %d/%d, output %d/%d\n", + (int)(pmem-mem0+1), MEMSIZE, (int)(maxa-amem+1), ACTSIZE); + Bprint(foutput, "%d table entries, %d zero\n", (int)(maxa-amem+1), i); + Bprint(foutput, "maximum spread: %d, maximum offset: %d\n", maxspr, maxoff); +} + +/* + * this version is for C + * write out the optimized parser + */ +void +aoutput(void) +{ + Bprint(ftable, "#define\tYYLAST\t%d\n", (int)(maxa-amem+1)); + arout("yyact", amem, (maxa-amem)+1); + arout("yypact", indgo, nstate); + arout("yypgo", pgo, nnonter+1); +} + +void +arout(char *s, int *v, int n) +{ + int i; + + Bprint(ftable, "short %s[] =\n{", s); + for(i = 0; i < n;) { + if(i%10 == 0) + Bprint(ftable, "\n"); + Bprint(ftable, "%4d", v[i]); + i++; + if(i == n) + Bprint(ftable, "\n};\n"); + else + Bprint(ftable, ","); + } +} + +/* + * read and convert an integer from the standard input + * return the terminating character + * blanks, tabs, and newlines are ignored + */ +int +gtnm(void) +{ + int sign, val, c; + + sign = 0; + val = 0; + while((c=Bgetrune(finput)) != Beof) { + if(isdigit(c)) { + val = val*10 + c-'0'; + continue; + } + if(c == '-') { + sign = 1; + continue; + } + break; + } + if(sign) + val = -val; + *pmem++ = val; + if(pmem >= &mem0[MEMSIZE]) + error("out of space"); + return c; +} diff --git a/utils/yacc/yaccpar b/utils/yacc/yaccpar new file mode 100644 index 00000000..efc1da06 --- /dev/null +++ b/utils/yacc/yaccpar @@ -0,0 +1,241 @@ +#define YYFLAG -1000 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 + +#ifdef yydebug +#include "y.debug" +#else +#define yydebug 0 +char* yytoknames[1]; /* for debugging */ +char* yystates[1]; /* for debugging */ +#endif + +/* parser for yacc output */ + +int yynerrs = 0; /* number of errors */ +int yyerrflag = 0; /* error recovery flag */ + +extern int fprint(int, char*, ...); +extern int sprint(char*, char*, ...); + +char* +yytokname(int yyc) +{ + static char x[10]; + + if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0])) + if(yytoknames[yyc-1]) + return yytoknames[yyc-1]; + sprint(x, "<%d>", yyc); + return x; +} + +char* +yystatname(int yys) +{ + static char x[10]; + + if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0])) + if(yystates[yys]) + return yystates[yys]; + sprint(x, "<%d>\n", yys); + return x; +} + +long +yylex1(void) +{ + long yychar; + long *t3p; + int c; + + yychar = yylex(); + if(yychar <= 0) { + c = yytok1[0]; + goto out; + } + if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) { + c = yytok1[yychar]; + goto out; + } + if(yychar >= YYPRIVATE) + if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) { + c = yytok2[yychar-YYPRIVATE]; + goto out; + } + for(t3p=yytok3;; t3p+=2) { + c = t3p[0]; + if(c == yychar) { + c = t3p[1]; + goto out; + } + if(c == 0) + break; + } + c = 0; + +out: + if(c == 0) + c = yytok2[1]; /* unknown char */ + if(yydebug >= 3) + fprint(2, "lex %.4lux %s\n", yychar, yytokname(c)); + return c; +} + +int +yyparse(void) +{ + struct + { + YYSTYPE yyv; + int yys; + } yys[YYMAXDEPTH], *yyp, *yypt; + short *yyxi; + int yyj, yym, yystate, yyn, yyg; + long yychar; + YYSTYPE save1, save2; + int save3, save4; + + save1 = yylval; + save2 = yyval; + save3 = yynerrs; + save4 = yyerrflag; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyp = &yys[-1]; + goto yystack; + +ret0: + yyn = 0; + goto ret; + +ret1: + yyn = 1; + goto ret; + +ret: + yylval = save1; + yyval = save2; + yynerrs = save3; + yyerrflag = save4; + return yyn; + +yystack: + /* put a state and value onto the stack */ + if(yydebug >= 4) + fprint(2, "char %s in %s", yytokname(yychar), yystatname(yystate)); + + yyp++; + if(yyp >= &yys[YYMAXDEPTH]) { + yyerror("yacc stack overflow"); + goto ret1; + } + yyp->yys = yystate; + yyp->yyv = yyval; + +yynewstate: + yyn = yypact[yystate]; + if(yyn <= YYFLAG) + goto yydefault; /* simple state */ + if(yychar < 0) + yychar = yylex1(); + yyn += yychar; + if(yyn < 0 || yyn >= YYLAST) + goto yydefault; + yyn = yyact[yyn]; + if(yychk[yyn] == yychar) { /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if(yyerrflag > 0) + yyerrflag--; + goto yystack; + } + +yydefault: + /* default state action */ + yyn = yydef[yystate]; + if(yyn == -2) { + if(yychar < 0) + yychar = yylex1(); + + /* look through exception table */ + for(yyxi=yyexca;; yyxi+=2) + if(yyxi[0] == -1 && yyxi[1] == yystate) + break; + for(yyxi += 2;; yyxi += 2) { + yyn = yyxi[0]; + if(yyn < 0 || yyn == yychar) + break; + } + yyn = yyxi[1]; + if(yyn < 0) + goto ret0; + } + if(yyn == 0) { + /* error ... attempt to resume parsing */ + switch(yyerrflag) { + case 0: /* brand new error */ + yyerror("syntax error"); + yynerrs++; + if(yydebug >= 1) { + fprint(2, "%s", yystatname(yystate)); + fprint(2, "saw %s\n", yytokname(yychar)); + } + + case 1: + case 2: /* incompletely recovered error ... try again */ + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + while(yyp >= yys) { + yyn = yypact[yyp->yys] + YYERRCODE; + if(yyn >= 0 && yyn < YYLAST) { + yystate = yyact[yyn]; /* simulate a shift of "error" */ + if(yychk[yystate] == YYERRCODE) + goto yystack; + } + + /* the current yyp has no shift onn "error", pop stack */ + if(yydebug >= 2) + fprint(2, "error recovery pops state %d, uncovers %d\n", + yyp->yys, (yyp-1)->yys ); + yyp--; + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1; + + case 3: /* no shift yet; clobber input char */ + if(yydebug >= 2) + fprint(2, "error recovery discards %s\n", yytokname(yychar)); + if(yychar == YYEOFCODE) + goto ret1; + yychar = -1; + goto yynewstate; /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if(yydebug >= 2) + fprint(2, "reduce %d in:\n\t%s", yyn, yystatname(yystate)); + + yypt = yyp; + yyp -= yyr2[yyn]; + yyval = (yyp+1)->yyv; + yym = yyn; + + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyg = yypgo[yyn]; + yyj = yyg + yyp->yys + 1; + + if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) + yystate = yyact[yyg]; + switch(yym) { + $A + } + goto yystack; /* stack new state and value */ +} |
