From 3c5d933b181a92de2b0fe4eb287e5c20c495d5c1 Mon Sep 17 00:00:00 2001 From: "Stephen C. Johnson" Date: Wed, 10 Jan 1979 15:10:46 -0500 Subject: [PATCH] Research V7 development Work on file usr/src/cmd/mip/INDEX Work on file usr/src/cmd/mip/cgram.y Work on file usr/src/cmd/mip/comm1.c Work on file usr/src/cmd/mip/common Work on file usr/src/cmd/mip/fcomm2.c Work on file usr/src/cmd/mip/convert Work on file usr/src/cmd/mip/fallo.c Work on file usr/src/cmd/mip/flocal2.c Work on file usr/src/cmd/mip/fconvert Work on file usr/src/cmd/mip/forder.c Work on file usr/src/cmd/mip/fmatch.c Work on file usr/src/cmd/mip/freader.c Work on file usr/src/cmd/mip/fort.c Work on file usr/src/cmd/mip/ftable.c Work on file usr/src/cmd/mip/g Work on file usr/src/cmd/mip/manifest Work on file usr/src/cmd/mip/makefile Work on file usr/src/cmd/mip/mfile1 Work on file usr/src/cmd/mip/optim.c Work on file usr/src/cmd/mip/pftn.c Work on file usr/src/cmd/mip/reader.c Work on file usr/src/cmd/mip/trees.c Work on file usr/src/cmd/mip/xdefs.c Work on file usr/src/cmd/pcc/INDEX Work on file usr/src/cmd/pcc/code.c Work on file usr/src/cmd/pcc/local.c Work on file usr/src/cmd/pcc/local2.c Work on file usr/src/cmd/pcc/mac2defs Work on file usr/src/cmd/pcc/macdefs Work on file usr/src/cmd/pcc/order.c Work on file usr/src/cmd/pcc/table.c Synthesized-from: v7 --- usr/src/cmd/mip/INDEX | 12 + usr/src/cmd/mip/cgram.y | 924 ++++++++++++++++++++ usr/src/cmd/mip/comm1.c | 4 + usr/src/cmd/mip/common | 250 ++++++ usr/src/cmd/mip/convert | 83 ++ usr/src/cmd/mip/fallo.c | 2 + usr/src/cmd/mip/fcomm2.c | 3 + usr/src/cmd/mip/fconvert | 27 + usr/src/cmd/mip/flocal2.c | 2 + usr/src/cmd/mip/fmatch.c | 2 + usr/src/cmd/mip/forder.c | 2 + usr/src/cmd/mip/fort.c | 256 ++++++ usr/src/cmd/mip/freader.c | 3 + usr/src/cmd/mip/ftable.c | 2 + usr/src/cmd/mip/g | 2 + usr/src/cmd/mip/makefile | 71 ++ usr/src/cmd/mip/manifest | 318 +++++++ usr/src/cmd/mip/mfile1 | 237 ++++++ usr/src/cmd/mip/optim.c | 181 ++++ usr/src/cmd/mip/pftn.c | 1673 +++++++++++++++++++++++++++++++++++++ usr/src/cmd/mip/reader.c | 1253 +++++++++++++++++++++++++++ usr/src/cmd/mip/trees.c | 1388 ++++++++++++++++++++++++++++++ usr/src/cmd/mip/xdefs.c | 99 +++ usr/src/cmd/pcc/INDEX | 4 + usr/src/cmd/pcc/code.c | 341 ++++++++ usr/src/cmd/pcc/local.c | 337 ++++++++ usr/src/cmd/pcc/local2.c | 918 ++++++++++++++++++++ usr/src/cmd/pcc/mac2defs | 51 ++ usr/src/cmd/pcc/macdefs | 67 ++ usr/src/cmd/pcc/order.c | 725 ++++++++++++++++ usr/src/cmd/pcc/table.c | 854 +++++++++++++++++++ 31 files changed, 10091 insertions(+) create mode 100644 usr/src/cmd/mip/INDEX create mode 100644 usr/src/cmd/mip/cgram.y create mode 100644 usr/src/cmd/mip/comm1.c create mode 100644 usr/src/cmd/mip/common create mode 100644 usr/src/cmd/mip/convert create mode 100644 usr/src/cmd/mip/fallo.c create mode 100644 usr/src/cmd/mip/fcomm2.c create mode 100644 usr/src/cmd/mip/fconvert create mode 100644 usr/src/cmd/mip/flocal2.c create mode 100644 usr/src/cmd/mip/fmatch.c create mode 100644 usr/src/cmd/mip/forder.c create mode 100644 usr/src/cmd/mip/fort.c create mode 100644 usr/src/cmd/mip/freader.c create mode 100644 usr/src/cmd/mip/ftable.c create mode 100755 usr/src/cmd/mip/g create mode 100644 usr/src/cmd/mip/makefile create mode 100644 usr/src/cmd/mip/manifest create mode 100644 usr/src/cmd/mip/mfile1 create mode 100644 usr/src/cmd/mip/optim.c create mode 100644 usr/src/cmd/mip/pftn.c create mode 100644 usr/src/cmd/mip/reader.c create mode 100644 usr/src/cmd/mip/trees.c create mode 100644 usr/src/cmd/mip/xdefs.c create mode 100644 usr/src/cmd/pcc/INDEX create mode 100644 usr/src/cmd/pcc/code.c create mode 100644 usr/src/cmd/pcc/local.c create mode 100644 usr/src/cmd/pcc/local2.c create mode 100644 usr/src/cmd/pcc/mac2defs create mode 100644 usr/src/cmd/pcc/macdefs create mode 100644 usr/src/cmd/pcc/order.c create mode 100644 usr/src/cmd/pcc/table.c diff --git a/usr/src/cmd/mip/INDEX b/usr/src/cmd/mip/INDEX new file mode 100644 index 0000000000..858f8ac7cc --- /dev/null +++ b/usr/src/cmd/mip/INDEX @@ -0,0 +1,12 @@ +This directory contains the machine independent parts of the +portable C compiler. For more explanation of how these files +are used, see the "Tour through the Portable C Compiler" +in Volume 2 of the UNIX(TM) documentation. + +The makefile in this directory is useful when makeing a compiler; +create a directory, copy the makefile into it, write the +machine dependent files, and you are off and running. The file g +is a useful aid for finding out when things are used. + +The pcc command (see the pcc source) uses this makefile and +the files in this directory. Lint also uses the files. diff --git a/usr/src/cmd/mip/cgram.y b/usr/src/cmd/mip/cgram.y new file mode 100644 index 0000000000..94d634899d --- /dev/null +++ b/usr/src/cmd/mip/cgram.y @@ -0,0 +1,924 @@ +%term NAME 2 +%term STRING 3 +%term ICON 4 +%term FCON 5 +%term PLUS 6 +%term MINUS 8 +%term MUL 11 +%term AND 14 +%term OR 17 +%term ER 19 +%term QUEST 21 +%term COLON 22 +%term ANDAND 23 +%term OROR 24 + +/* special interfaces for yacc alone */ +/* These serve as abbreviations of 2 or more ops: + ASOP =, = ops + RELOP LE,LT,GE,GT + EQUOP EQ,NE + DIVOP DIV,MOD + SHIFTOP LS,RS + ICOP ICR,DECR + UNOP NOT,COMPL + STROP DOT,STREF + + */ +%term ASOP 25 +%term RELOP 26 +%term EQUOP 27 +%term DIVOP 28 +%term SHIFTOP 29 +%term INCOP 30 +%term UNOP 31 +%term STROP 32 + +/* reserved words, etc */ +%term TYPE 33 +%term CLASS 34 +%term STRUCT 35 +%term RETURN 36 +%term GOTO 37 +%term IF 38 +%term ELSE 39 +%term SWITCH 40 +%term BREAK 41 +%term CONTINUE 42 +%term WHILE 43 +%term DO 44 +%term FOR 45 +%term DEFAULT 46 +%term CASE 47 +%term SIZEOF 48 +%term ENUM 49 + + +/* little symbols, etc. */ +/* namely, + + LP ( + RP ) + + LC { + RC } + + LB [ + RB ] + + CM , + SM ; + + */ + +%term LP 50 +%term RP 51 +%term LC 52 +%term RC 53 +%term LB 54 +%term RB 55 +%term CM 56 +%term SM 57 +%term ASSIGN 58 + +/* at last count, there were 7 shift/reduce, 1 reduce/reduce conflicts +/* these involved: + if/else + recognizing functions in various contexts, including declarations + error recovery + */ + +%left CM +%right ASOP ASSIGN +%right QUEST COLON +%left OROR +%left ANDAND +%left OR +%left ER +%left AND +%left EQUOP +%left RELOP +%left SHIFTOP +%left PLUS MINUS +%left MUL DIVOP +%right UNOP +%right INCOP SIZEOF +%left LB LP STROP +%{ +# include "mfile1" +%} + + /* define types */ +%start ext_def_list + +%type con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart + enum_head str_head name_lp +%type e .e term attributes oattributes type enum_dcl struct_dcl + cast_type null_decl funct_idn declarator fdeclarator nfdeclarator + elist + +%token CLASS NAME STRUCT RELOP CM DIVOP PLUS MINUS SHIFTOP MUL AND OR ER ANDAND OROR + ASSIGN STROP INCOP UNOP ICON +%token TYPE + +%% + +%{ + static int fake = 0; + static char fakename[NCHNAM+1]; +%} + +ext_def_list: ext_def_list external_def + | + =ftnend(); + ; +external_def: data_def + ={ curclass = SNULL; blevel = 0; } + | error + ={ curclass = SNULL; blevel = 0; } + ; +data_def: + oattributes SM + ={ $1->op = FREE; } + | oattributes init_dcl_list SM + ={ $1->op = FREE; } + | oattributes fdeclarator { + defid( tymerge($1,$2), curclass==STATIC?STATIC:EXTDEF ); + } function_body + ={ + if( blevel ) cerror( "function level error" ); + if( reached ) retstat |= NRETVAL; + $1->op = FREE; + ftnend(); + } + ; + +function_body: arg_dcl_list compoundstmt + ; +arg_dcl_list: arg_dcl_list declaration + | ={ blevel = 1; } + ; + +stmt_list: stmt_list statement + | /* empty */ + ={ bccode(); + locctr(PROG); + } + ; + +dcl_stat_list : dcl_stat_list attributes SM + ={ $2->op = FREE; } + | dcl_stat_list attributes init_dcl_list SM + ={ $2->op = FREE; } + | /* empty */ + ; +declaration: attributes declarator_list SM + ={ curclass = SNULL; $1->op = FREE; } + | attributes SM + ={ curclass = SNULL; $1->op = FREE; } + | error SM + ={ curclass = SNULL; } + ; +oattributes: attributes + | /* VOID */ + ={ $$ = mkty(INT,0,INT); curclass = SNULL; } + ; +attributes: class type + ={ $$ = $2; } + | type class + | class + ={ $$ = mkty(INT,0,INT); } + | type + ={ curclass = SNULL ; } + ; + + +class: CLASS + ={ curclass = $1; } + ; + +type: TYPE + | TYPE TYPE + ={ $1->type = types( $1->type, $2->type, UNDEF ); + $2->op = FREE; + } + | TYPE TYPE TYPE + ={ $1->type = types( $1->type, $2->type, $3->type ); + $2->op = $3->op = FREE; + } + | struct_dcl + | enum_dcl + ; + +enum_dcl: enum_head LC moe_list optcomma RC + ={ $$ = dclstruct($1); } + | ENUM NAME + ={ $$ = rstruct($2,0); stwart = instruct; } + ; + +enum_head: ENUM + ={ $$ = bstruct(-1,0); } + | ENUM NAME + ={ $$ = bstruct($2,0); } + ; + +moe_list: moe + | moe_list CM moe + ; + +moe: NAME + ={ moedef( $1 ); } + | NAME ASSIGN con_e + ={ strucoff = $3; moedef( $1 ); } + ; + +struct_dcl: str_head LC type_dcl_list optsemi RC + ={ $$ = dclstruct($1); } + | STRUCT NAME + ={ $$ = rstruct($2,$1); } + ; + +str_head: STRUCT + ={ $$ = bstruct(-1,$1); stwart=0; } + | STRUCT NAME + ={ $$ = bstruct($2,$1); stwart=0; } + ; + +type_dcl_list: type_declaration + | type_dcl_list SM type_declaration + ; + +type_declaration: type declarator_list + ={ curclass = SNULL; stwart=0; $1->op = FREE; } + | type + ={ if( curclass != MOU ){ + curclass = SNULL; + } + else { + sprintf( fakename, "$%dFAKE", fake++ ); + defid( tymerge($1, bdty(NAME,NIL,lookup( fakename, SMOS ))), curclass ); + } + stwart = 0; + $1->op = FREE; + } + ; + + +declarator_list: declarator + ={ defid( tymerge($0,$1), curclass); stwart = instruct; } + | declarator_list CM {$$=$0;} declarator + ={ defid( tymerge($0,$4), curclass); stwart = instruct; } + ; +declarator: fdeclarator + | nfdeclarator + | nfdeclarator COLON con_e + %prec CM + ={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" ); + if( $3<0 || $3 >= FIELD ){ + uerror( "illegal field size" ); + $3 = 1; + } + defid( tymerge($0,$1), FIELD|$3 ); + $$ = NIL; + } + | COLON con_e + %prec CM + ={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" ); + falloc( stab, $2, -1, $0 ); /* alignment or hole */ + $$ = NIL; + } + | error + ={ $$ = NIL; } + ; + + /* int (a)(); is not a function --- sorry! */ +nfdeclarator: MUL nfdeclarator + ={ umul: + $$ = bdty( UNARY MUL, $2, 0 ); } + | nfdeclarator LP RP + ={ uftn: + $$ = bdty( UNARY CALL, $1, 0 ); } + | nfdeclarator LB RB + ={ uary: + $$ = bdty( LB, $1, 0 ); } + | nfdeclarator LB con_e RB + ={ bary: + if( (int)$3 <= 0 ) werror( "zero or negative subscript" ); + $$ = bdty( LB, $1, $3 ); } + | NAME + ={ $$ = bdty( NAME, NIL, $1 ); } + | LP nfdeclarator RP + ={ $$=$2; } + ; +fdeclarator: MUL fdeclarator + ={ goto umul; } + | fdeclarator LP RP + ={ goto uftn; } + | fdeclarator LB RB + ={ goto uary; } + | fdeclarator LB con_e RB + ={ goto bary; } + | LP fdeclarator RP + ={ $$ = $2; } + | name_lp name_list RP + ={ + if( blevel!=0 ) uerror("function declaration in bad context"); + $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 ); + stwart = 0; + } + | name_lp RP + ={ + $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 ); + stwart = 0; + } + ; + +name_lp: NAME LP + ={ + /* turn off typedefs for argument names */ + stwart = SEENAME; + } + ; + +name_list: NAME + ={ ftnarg( $1 ); stwart = SEENAME; } + | name_list CM NAME + ={ ftnarg( $3 ); stwart = SEENAME; } + ; + /* always preceeded by attributes: thus the $0's */ +init_dcl_list: init_declarator + %prec CM + | init_dcl_list CM {$$=$0;} init_declarator + ; + /* always preceeded by attributes */ +xnfdeclarator: nfdeclarator + ={ defid( $1 = tymerge($0,$1), curclass); + beginit($1->rval); + } + | error + ; + /* always preceeded by attributes */ +init_declarator: nfdeclarator + ={ nidcl( tymerge($0,$1) ); } + | fdeclarator + ={ defid( tymerge($0,$1), uclass(curclass) ); + } + | xnfdeclarator optasgn e + %prec CM + ={ doinit( $3 ); + endinit(); } + | xnfdeclarator optasgn LC init_list optcomma RC + ={ endinit(); } + ; + +init_list: initializer + %prec CM + | init_list CM initializer + ; +initializer: e + %prec CM + ={ doinit( $1 ); } + | ibrace init_list optcomma RC + ={ irbrace(); } + ; + +optcomma : /* VOID */ + | CM + ; + +optsemi : /* VOID */ + | SM + ; + +optasgn : /* VOID */ + ={ werror( "old-fashioned initialization: use =" ); } + | ASSIGN + ; + +ibrace : LC + ={ ilbrace(); } + ; + +/* STATEMENTS */ + +compoundstmt: begin dcl_stat_list stmt_list RC + ={ --blevel; + if( blevel == 1 ) blevel = 0; + clearst( blevel ); + checkst( blevel ); + autooff = *--psavbc; + regvar = *--psavbc; + } + ; + +begin: LC + ={ if( blevel == 1 ) dclargs(); + ++blevel; + if( psavbc > &asavbc[BCSZ-2] ) cerror( "nesting too deep" ); + *psavbc++ = regvar; + *psavbc++ = autooff; + } + ; + +statement: e SM + ={ ecomp( $1 ); } + | compoundstmt + | ifprefix statement + ={ deflab($1); + reached = 1; + } + | ifelprefix statement + ={ if( $1 != NOLAB ){ + deflab( $1 ); + reached = 1; + } + } + | whprefix statement + ={ branch( contlab ); + deflab( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1; + else reached = 0; + resetbc(0); + } + | doprefix statement WHILE LP e RP SM + ={ deflab( contlab ); + if( flostat & FCONT ) reached = 1; + ecomp( buildtree( CBRANCH, buildtree( NOT, $5, NIL ), bcon( $1 ) ) ); + deflab( brklab ); + reached = 1; + resetbc(0); + } + | forprefix .e RP statement + ={ deflab( contlab ); + if( flostat&FCONT ) reached = 1; + if( $2 ) ecomp( $2 ); + branch( $1 ); + deflab( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; + else reached = 0; + resetbc(0); + } + | switchpart statement + ={ if( reached ) branch( brklab ); + deflab( $1 ); + swend(); + deflab(brklab); + if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; + resetbc(FCONT); + } + | BREAK SM + ={ if( brklab == NOLAB ) uerror( "illegal break"); + else if(reached) branch( brklab ); + flostat |= FBRK; + if( brkflag ) goto rch; + reached = 0; + } + | CONTINUE SM + ={ if( contlab == NOLAB ) uerror( "illegal continue"); + else branch( contlab ); + flostat |= FCONT; + goto rch; + } + | RETURN SM + ={ retstat |= NRETVAL; + branch( retlab ); + rch: + if( !reached ) werror( "statement not reached"); + reached = 0; + } + | RETURN e SM + ={ register NODE *temp; + idname = curftn; + temp = buildtree( NAME, NIL, NIL ); + temp->type = DECREF( temp->type ); + temp = buildtree( RETURN, temp, $2 ); + /* now, we have the type of the RHS correct */ + temp->left->op = FREE; + temp->op = FREE; + ecomp( buildtree( FORCE, temp->right, NIL ) ); + retstat |= RETVAL; + branch( retlab ); + reached = 0; + } + | GOTO NAME SM + ={ register NODE *q; + q = block( FREE, NIL, NIL, INT|ARY, 0, INT ); + q->rval = idname = $2; + defid( q, ULABEL ); + stab[idname].suse = -lineno; + branch( stab[idname].offset ); + goto rch; + } + | SM + | error SM + | error RC + | label statement + ; +label: NAME COLON + ={ register NODE *q; + q = block( FREE, NIL, NIL, INT|ARY, 0, LABEL ); + q->rval = $1; + defid( q, LABEL ); + reached = 1; + } + | CASE e COLON + ={ addcase($2); + reached = 1; + } + | DEFAULT COLON + ={ reached = 1; + adddef(); + flostat |= FDEF; + } + ; +doprefix: DO + ={ savebc(); + if( !reached ) werror( "loop not entered at top"); + brklab = getlab(); + contlab = getlab(); + deflab( $$ = getlab() ); + reached = 1; + } + ; +ifprefix: IF LP e RP + ={ ecomp( buildtree( CBRANCH, $3, bcon( $$=getlab()) ) ) ; + reached = 1; + } + ; +ifelprefix: ifprefix statement ELSE + ={ if( reached ) branch( $$ = getlab() ); + else $$ = NOLAB; + deflab( $1 ); + reached = 1; + } + ; + +whprefix: WHILE LP e RP + ={ savebc(); + if( !reached ) werror( "loop not entered at top"); + if( $3->op == ICON && $3->lval != 0 ) flostat = FLOOP; + deflab( contlab = getlab() ); + reached = 1; + brklab = getlab(); + if( flostat == FLOOP ) tfree( $3 ); + else ecomp( buildtree( CBRANCH, $3, bcon( brklab) ) ); + } + ; +forprefix: FOR LP .e SM .e SM + ={ if( $3 ) ecomp( $3 ); + else if( !reached ) werror( "loop not entered at top"); + savebc(); + contlab = getlab(); + brklab = getlab(); + deflab( $$ = getlab() ); + reached = 1; + if( $5 ) ecomp( buildtree( CBRANCH, $5, bcon( brklab) ) ); + else flostat |= FLOOP; + } + ; +switchpart: SWITCH LP e RP + ={ savebc(); + brklab = getlab(); + ecomp( buildtree( FORCE, $3, NIL ) ); + branch( $$ = getlab() ); + swstart(); + reached = 0; + } + ; +/* EXPRESSIONS */ +con_e: { $$=instruct; stwart=instruct=0; } e + %prec CM + ={ $$ = icons( $2 ); instruct=$1; } + ; +.e: e + | + ={ $$=0; } + ; +elist: e + %prec CM + | elist CM e + ={ goto bop; } + ; + +e: e RELOP e + ={ + preconf: + if( yychar==RELOP||yychar==EQUOP||yychar==AND||yychar==OR||yychar==ER ){ + precplaint: + if( hflag ) werror( "precedence confusion possible: parenthesize!" ); + } + bop: + $$ = buildtree( $2, $1, $3 ); + } + | e CM e + ={ $2 = COMOP; + goto bop; + } + | e DIVOP e + ={ goto bop; } + | e PLUS e + ={ if(yychar==SHIFTOP) goto precplaint; else goto bop; } + | e MINUS e + ={ if(yychar==SHIFTOP ) goto precplaint; else goto bop; } + | e SHIFTOP e + ={ if(yychar==PLUS||yychar==MINUS) goto precplaint; else goto bop; } + | e MUL e + ={ goto bop; } + | e EQUOP e + ={ goto preconf; } + | e AND e + ={ if( yychar==RELOP||yychar==EQUOP ) goto preconf; else goto bop; } + | e OR e + ={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; } + | e ER e + ={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; } + | e ANDAND e + ={ goto bop; } + | e OROR e + ={ goto bop; } + | e MUL ASSIGN e + ={ abop: + $$ = buildtree( ASG $2, $1, $4 ); + } + | e DIVOP ASSIGN e + ={ goto abop; } + | e PLUS ASSIGN e + ={ goto abop; } + | e MINUS ASSIGN e + ={ goto abop; } + | e SHIFTOP ASSIGN e + ={ goto abop; } + | e AND ASSIGN e + ={ goto abop; } + | e OR ASSIGN e + ={ goto abop; } + | e ER ASSIGN e + ={ goto abop; } + | e QUEST e COLON e + ={ $$=buildtree(QUEST, $1, buildtree( COLON, $3, $5 ) ); + } + | e ASOP e + ={ werror( "old-fashioned assignment operator" ); goto bop; } + | e ASSIGN e + ={ goto bop; } + | term + ; +term: term INCOP + ={ $$ = buildtree( $2, $1, bcon(1) ); } + | MUL term + ={ ubop: + $$ = buildtree( UNARY $1, $2, NIL ); + } + | AND term + ={ if( ISFTN($2->type) || ISARY($2->type) ){ + werror( "& before array or function: ignored" ); + $$ = $2; + } + else goto ubop; + } + | MINUS term + ={ goto ubop; } + | UNOP term + ={ + $$ = buildtree( $1, $2, NIL ); + } + | INCOP term + ={ $$ = buildtree( $1==INCR ? ASG PLUS : ASG MINUS, + $2, + bcon(1) ); + } + | SIZEOF term + ={ $$ = doszof( $2 ); } + | LP cast_type RP term %prec INCOP + ={ $$ = buildtree( CAST, $2, $4 ); + $$->left->op = FREE; + $$->op = FREE; + $$ = $$->right; + } + | SIZEOF LP cast_type RP %prec SIZEOF + ={ $$ = doszof( $3 ); } + | term LB e RB + ={ $$ = buildtree( UNARY MUL, buildtree( PLUS, $1, $3 ), NIL ); } + | funct_idn RP + ={ $$=buildtree(UNARY CALL,$1,NIL); } + | funct_idn elist RP + ={ $$=buildtree(CALL,$1,$2); } + | term STROP NAME + ={ if( $2 == DOT ){ + $1 = buildtree( UNARY AND, $1, NIL ); + } + idname = $3; + $$ = buildtree( STREF, $1, buildtree( NAME, NIL, NIL ) ); + } + | NAME + ={ idname = $1; + /* recognize identifiers in initializations */ + if( blevel==0 && stab[idname].stype == UNDEF ) { + register NODE *q; + werror( "undeclared initializer name %.8s", stab[idname].sname ); + q = block( FREE, NIL, NIL, INT, 0, INT ); + q->rval = idname; + defid( q, EXTERN ); + } + $$=buildtree(NAME,NIL,NIL); + stab[$1].suse = -lineno; + } + | ICON + ={ $$=bcon(0); + $$->lval = lastcon; + $$->rval = NONAME; + if( $1 ) $$->csiz = $$->type = ctype(LONG); + } + | FCON + ={ $$=buildtree(FCON,NIL,NIL); + $$->dval = dcon; + } + | STRING + ={ $$ = getstr(); /* get string contents */ } + | LP e RP + ={ $$=$2; } + ; + +cast_type: type null_decl + ={ + $$ = tymerge( $1, $2 ); + $$->op = NAME; + $1->op = FREE; + } + ; + +null_decl: /* empty */ + ={ $$ = bdty( NAME, NIL, -1 ); } + | LP RP + ={ $$ = bdty( UNARY CALL, bdty(NAME,NIL,-1),0); } + | LP null_decl RP LP RP + ={ $$ = bdty( UNARY CALL, $2, 0 ); } + | MUL null_decl + ={ goto umul; } + | null_decl LB RB + ={ goto uary; } + | null_decl LB con_e RB + ={ goto bary; } + | LP null_decl RP + ={ $$ = $2; } + ; + +funct_idn: NAME LP + ={ if( stab[$1].stype == UNDEF ){ + register NODE *q; + q = block( FREE, NIL, NIL, FTN|INT, 0, INT ); + q->rval = $1; + defid( q, EXTERN ); + } + idname = $1; + $$=buildtree(NAME,NIL,NIL); + stab[idname].suse = -lineno; + } + | term LP + ; +%% + +NODE * +mkty( t, d, s ) unsigned t; { + return( block( TYPE, NIL, NIL, t, d, s ) ); + } + +NODE * +bdty( op, p, v ) NODE *p; { + register NODE *q; + + q = block( op, p, NIL, INT, 0, INT ); + + switch( op ){ + + case UNARY MUL: + case UNARY CALL: + break; + + case LB: + q->right = bcon(v); + break; + + case NAME: + q->rval = v; + break; + + default: + cerror( "bad bdty" ); + } + + return( q ); + } + +dstash( n ){ /* put n into the dimension table */ + if( curdim >= DIMTABSZ-1 ){ + cerror( "dimension table overflow"); + } + dimtab[ curdim++ ] = n; + } + +savebc() { + if( psavbc > & asavbc[BCSZ-4 ] ){ + cerror( "whiles, fors, etc. too deeply nested"); + } + *psavbc++ = brklab; + *psavbc++ = contlab; + *psavbc++ = flostat; + *psavbc++ = swx; + flostat = 0; + } + +resetbc(mask){ + + swx = *--psavbc; + flostat = *--psavbc | (flostat&mask); + contlab = *--psavbc; + brklab = *--psavbc; + + } + +addcase(p) NODE *p; { /* add case to switch */ + + p = optim( p ); /* change enum to ints */ + if( p->op != ICON ){ + uerror( "non-constant case expression"); + return; + } + if( swp == swtab ){ + uerror( "case not in switch"); + return; + } + if( swp >= &swtab[SWITSZ] ){ + cerror( "switch table overflow"); + } + swp->sval = p->lval; + deflab( swp->slab = getlab() ); + ++swp; + tfree(p); + } + +adddef(){ /* add default case to switch */ + if( swtab[swx].slab >= 0 ){ + uerror( "duplicate default in switch"); + return; + } + if( swp == swtab ){ + uerror( "default not inside switch"); + return; + } + deflab( swtab[swx].slab = getlab() ); + } + +swstart(){ + /* begin a switch block */ + if( swp >= &swtab[SWITSZ] ){ + cerror( "switch table overflow"); + } + swx = swp - swtab; + swp->slab = -1; + ++swp; + } + +swend(){ /* end a switch block */ + + register struct sw *swbeg, *p, *q, *r, *r1; + CONSZ temp; + int tempi; + + swbeg = &swtab[swx+1]; + + /* sort */ + + r1 = swbeg; + r = swp-1; + + while( swbeg < r ){ + /* bubble largest to end */ + for( q=swbeg; qsval > (q+1)->sval ){ + /* swap */ + r1 = q+1; + temp = q->sval; + q->sval = r1->sval; + r1->sval = temp; + tempi = q->slab; + q->slab = r1->slab; + r1->slab = tempi; + } + } + r = r1; + r1 = swbeg; + } + + /* it is now sorted */ + + for( p = swbeg+1; psval == (p-1)->sval ){ + uerror( "duplicate case in switch, %d", tempi=p->sval ); + return; + } + } + + genswitch( swbeg-1, swp-swbeg ); + swp = swbeg-1; + } diff --git a/usr/src/cmd/mip/comm1.c b/usr/src/cmd/mip/comm1.c new file mode 100644 index 0000000000..ed05ba5205 --- /dev/null +++ b/usr/src/cmd/mip/comm1.c @@ -0,0 +1,4 @@ +# include "mfile1" + +# include "common" + diff --git a/usr/src/cmd/mip/common b/usr/src/cmd/mip/common new file mode 100644 index 0000000000..cd6cb4b2a2 --- /dev/null +++ b/usr/src/cmd/mip/common @@ -0,0 +1,250 @@ +# ifndef EXIT +# define EXIT exit +# endif + +int nerrors = 0; /* number of errors */ + +NODE *NIL; /* pointer which always has 0 in it */ + +NODE *lastfree; /* pointer to last free node; (for allocator) */ + + /* VARARGS1 */ +uerror( s, a ) char *s; { /* nonfatal error message */ + /* the routine where is different for pass 1 and pass 2; + /* it tells where the error took place */ + + ++nerrors; + where('u'); + fprintf( stderr, s, a ); + fprintf( stderr, "\n" ); + if( nerrors > 30 ) cerror( "too many errors"); + } + + /* VARARGS1 */ +cerror( s, a, b, c ) char *s; { /* compiler error: die */ + where('c'); + if( nerrors && nerrors <= 30 ){ /* give the compiler the benefit of the doubt */ + fprintf( stderr, "cannot recover from earlier errors: goodbye!\n" ); + } + else { + fprintf( stderr, "compiler error: " ); + fprintf( stderr, s, a, b, c ); + fprintf( stderr, "\n" ); + } + EXIT(1); + } + + /* VARARGS1 */ +werror( s, a, b ) char *s; { /* warning */ + where('w'); + fprintf( stderr, "warning: " ); + fprintf( stderr, s, a, b ); + fprintf( stderr, "\n" ); + } + +tinit(){ /* initialize expression tree search */ + + NODE *p; + + for( p=node; p<= &node[TREESZ-1]; ++p ) p->op = FREE; + lastfree = node; + + } + +# define TNEXT(p) (p== &node[TREESZ-1]?node:p+1) + +NODE * +talloc(){ + NODE *p, *q; + + q = lastfree; + for( p = TNEXT(q); p!=q; p= TNEXT(p)) + if( p->op ==FREE ) return(lastfree=p); + + cerror( "out of tree space; simplify expression"); + /* NOTREACHED */ + } + +tcheck(){ /* ensure that all nodes have been freed */ + + NODE *p; + + if( !nerrors ) + for( p=node; p<= &node[TREESZ-1]; ++p ) + if( p->op != FREE ) cerror( "wasted space: %o", p ); + tinit(); + } +tfree( p ) NODE *p; { + /* free the tree p */ + extern tfree1(); + + if( p->op != FREE ) walkf( p, tfree1 ); + + } + +tfree1(p) NODE *p; { + if( p == 0 ) cerror( "freeing blank tree!"); + else p->op = FREE; + } + +fwalk( t, f, down ) register NODE *t; int (*f)(); { + + int down1, down2; + + more: + down1 = down2 = 0; + + (*f)( t, down, &down1, &down2 ); + + switch( optype( t->op ) ){ + + case BITYPE: + fwalk( t->left, f, down1 ); + t = t->right; + down = down2; + goto more; + + case UTYPE: + t = t->left; + down = down1; + goto more; + + } + } + +walkf( t, f ) register NODE *t; int (*f)(); { + register opty; + + opty = optype(t->op); + + if( opty != LTYPE ) walkf( t->left, f ); + if( opty == BITYPE ) walkf( t->right, f ); + (*f)( t ); + } + + + +int dope[ DSIZE ]; +char *opst[DSIZE]; + +struct dopest { int dopeop; char opst[8]; int dopeval; } indope[] = { + + NAME, "NAME", LTYPE, + STRING, "STRING", LTYPE, + REG, "REG", LTYPE, + OREG, "OREG", LTYPE, + ICON, "ICON", LTYPE, + FCON, "FCON", LTYPE, + CCODES, "CCODES", LTYPE, + UNARY MINUS, "U-", UTYPE, + UNARY MUL, "U*", UTYPE, + UNARY AND, "U&", UTYPE, + UNARY CALL, "UCALL", UTYPE|CALLFLG, + UNARY FORTCALL, "UFCALL", UTYPE|CALLFLG, + NOT, "!", UTYPE|LOGFLG, + COMPL, "~", UTYPE, + FORCE, "FORCE", UTYPE, + INIT, "INIT", UTYPE, + SCONV, "SCONV", UTYPE, + PCONV, "PCONV", UTYPE, + PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, + ASG PLUS, "+=", BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG, + MINUS, "-", BITYPE|FLOFLG|SIMPFLG, + ASG MINUS, "-=", BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG, + MUL, "*", BITYPE|FLOFLG|MULFLG, + ASG MUL, "*=", BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG, + AND, "&", BITYPE|SIMPFLG|COMMFLG, + ASG AND, "&=", BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG, + QUEST, "?", BITYPE, + COLON, ":", BITYPE, + ANDAND, "&&", BITYPE|LOGFLG, + OROR, "||", BITYPE|LOGFLG, + CM, ",", BITYPE, + COMOP, ",OP", BITYPE, + ASSIGN, "=", BITYPE|ASGFLG, + DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG, + ASG DIV, "/=", BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG, + MOD, "%", BITYPE|DIVFLG, + ASG MOD, "%=", BITYPE|DIVFLG|ASGFLG|ASGOPFLG, + LS, "<<", BITYPE|SHFFLG, + ASG LS, "<<=", BITYPE|SHFFLG|ASGFLG|ASGOPFLG, + RS, ">>", BITYPE|SHFFLG, + ASG RS, ">>=", BITYPE|SHFFLG|ASGFLG|ASGOPFLG, + OR, "|", BITYPE|COMMFLG|SIMPFLG, + ASG OR, "|=", BITYPE|COMMFLG|SIMPFLG|ASGFLG|ASGOPFLG, + ER, "^", BITYPE|COMMFLG|SIMPFLG, + ASG ER, "^=", BITYPE|COMMFLG|SIMPFLG|ASGFLG|ASGOPFLG, + INCR, "++", BITYPE|ASGFLG, + DECR, "--", BITYPE|ASGFLG, + STREF, "->", BITYPE, + CALL, "CALL", BITYPE|CALLFLG, + FORTCALL, "FCALL", BITYPE|CALLFLG, + EQ, "==", BITYPE|LOGFLG, + NE, "!=", BITYPE|LOGFLG, + LE, "<=", BITYPE|LOGFLG, + LT, "<", BITYPE|LOGFLG, + GE, ">", BITYPE|LOGFLG, + GT, ">", BITYPE|LOGFLG, + UGT, "UGT", BITYPE|LOGFLG, + UGE, "UGE", BITYPE|LOGFLG, + ULT, "ULT", BITYPE|LOGFLG, + ULE, "ULE", BITYPE|LOGFLG, + ARS, "A>>", BITYPE, + TYPE, "TYPE", LTYPE, + LB, "[", BITYPE, + CBRANCH, "CBRANCH", BITYPE, + FLD, "FLD", UTYPE, + PMCONV, "PMCONV", BITYPE, + PVCONV, "PVCONV", BITYPE, + RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG, + CAST, "CAST", BITYPE|ASGFLG|ASGOPFLG, + GOTO, "GOTO", UTYPE, + STASG, "STASG", BITYPE|ASGFLG, + STARG, "STARG", UTYPE, + STCALL, "STCALL", BITYPE|CALLFLG, + UNARY STCALL, "USTCALL", UTYPE|CALLFLG, + +-1, 0 +}; + +mkdope(){ + register struct dopest *q; + + for( q = indope; q->dopeop >= 0; ++q ){ + dope[q->dopeop] = q->dopeval; + opst[q->dopeop] = q->opst; + } + } +tprint( t ) TWORD t; { /* output a nice description of the type of t */ + + static char * tnames[] = { + "undef", + "farg", + "char", + "short", + "int", + "long", + "float", + "double", + "strty", + "unionty", + "enumty", + "moety", + "uchar", + "ushort", + "unsigned", + "ulong", + "?", "?" + }; + + for(;; t = DECREF(t) ){ + + if( ISPTR(t) ) printf( "PTR " ); + else if( ISFTN(t) ) printf( "FTN " ); + else if( ISARY(t) ) printf( "ARY " ); + else { + printf( "%s", tnames[t] ); + return; + } + } + } diff --git a/usr/src/cmd/mip/convert b/usr/src/cmd/mip/convert new file mode 100644 index 0000000000..179bea1338 --- /dev/null +++ b/usr/src/cmd/mip/convert @@ -0,0 +1,83 @@ +To convert two pass to 1 pass operation: +(I suggest that you use a subdirectory, since +it is hard to repair some of this damage once done) + +I assume that you have new copies of the machine-independent +files. The file cl is no longer used, and there is no +use of lex at all. The file scan.c contains the new +lexical analyzer. Moreover, the file comm2.c is no longer +used when the passes are loaded together. +These changes may affect local procedures for searching, printing, +diffing, etc. the compiler. + +I suggest that you take the makefile in /usr/n as well, to help you +along. + +The conversion process, as well as I understand it is as follows. + +1. Make a subdirectory, and put in it the old machine dependent files +macdefs, mac2defs, local.c, order.c, code.c, local2.c, and table.c. +Put in all the new machine independent stuff, including the new makefile + +2. Insert the line # define ONEPASS into macdefs +Change LABFMT by deleting the \n. + +3. In all the machine dependent source files local.c, +code.c, order.c, local2.c, and table.c, remove the includes of +manifest and macdefs; these are now included by mfile1 and mfile2. + +4. The main routine for pass 2 (probably on local2.c) +should be deleted; it probably only does a call to mainp2. +If it does anything else of interest, +let me know. + +5. On the file local.c, in the routine `ecode', +replace the lines + printf( ".%d\t%s\n", lineno, ftitle ); + prtree( p ); +by + p2tree( p ); + p2compile( p ); + +6. In code.c, in the function bccode, replace the line + printf( "[\t%d\t%d\t%d\t\n", ftnno, XXXX, YYYY ); +by + p2bbeg( XXXX, YYYY ); +Also, in efcode, replace the line which prints out the "]..." +with + p2bend(); + +7. In code.c and local.c, look at all remaining printfs. Lines +which go onto the intermediate file all had ")" at the head. +All of these must be clobbered. Thus, a line which read + printf( ") xxx yyy\n) zzz www\n" ); +must be changed to read + printf( " xxx yyy\n zzz www\n" ); +This is tedious, although a few cleverly chosen ed commands +will probably do the trick. + +8. Say make, and stand back. The result is a +single program called comp. +You may experience loading errors as a result of having used the +same external names in the first and second pass. Look at the +beginning of mfile2 to get a hint about one way to deal with +this problem (add stuff to mac2defs to change the names). +The other way to deal with it is just fix it... + +9. As a side-effect of other changes, the meaning of the arguments +to match has changed slightly; ASG OPANY, as it always +did, matches any assignment op except ++, --, and = itself. +OPANY, on the other hand, matches only ops which are not assignment +ops. In table.c, there must be explicit rewriting rule entries for +++, --, and =. In most cases with which I am familiar, this should +be true already, and no change is needed. + +10. Usage is /lib/cpp x.c | comp +which produces assembler output on the std. output. +research!/usr/bin/ncc gives the interdata compiler, with many +bells and whistles, as a Bourne shell script. +regression tests, and checks that this compiler +produces the same output as the earlier one, are +both wise. + +Good Luck! diff --git a/usr/src/cmd/mip/fallo.c b/usr/src/cmd/mip/fallo.c new file mode 100644 index 0000000000..4bed17b727 --- /dev/null +++ b/usr/src/cmd/mip/fallo.c @@ -0,0 +1,2 @@ +# define FORT +# include "allo.c" diff --git a/usr/src/cmd/mip/fcomm2.c b/usr/src/cmd/mip/fcomm2.c new file mode 100644 index 0000000000..65154394db --- /dev/null +++ b/usr/src/cmd/mip/fcomm2.c @@ -0,0 +1,3 @@ +# define FORT +# include "mfile2" +# include "common" diff --git a/usr/src/cmd/mip/fconvert b/usr/src/cmd/mip/fconvert new file mode 100644 index 0000000000..6a0a02ba5f --- /dev/null +++ b/usr/src/cmd/mip/fconvert @@ -0,0 +1,27 @@ +In an attempt to speed up the Fortran 77 +compiler, we have provided a new interface between +the fortran compiler and the portable C compiler. +The intermediate file is binary, and the result is +to speed up the execution of Fortran considerably. +The changes necessary to make this work are as follows: + +*** The ONEPASS flag should be off for Fortran; + the simplest way of making this happen is to take + the line # define ONEPASS on macdefs, and put a + # ifndef FORT ... # endif around it. + +*** The function label from pass 1 must be put in + a file, fort.h. Also, a simple function, tlabel, + must be written to copy names and make labels. + +*** The function `where' must be defined, as well as the + function main (which was once on local2.c). + They can be defined on fort.h, or on local2.c + (surrounded by # ifnded ONEPASS and # endif) + +*** Other things from pass one may have crept into the pass 2 + code: they must be also done, either on fort.h or + on local2.c surrounded by ifdefs. + +*** make fort then creates the fortran interface... + diff --git a/usr/src/cmd/mip/flocal2.c b/usr/src/cmd/mip/flocal2.c new file mode 100644 index 0000000000..a36e77bf2b --- /dev/null +++ b/usr/src/cmd/mip/flocal2.c @@ -0,0 +1,2 @@ +# define FORT +# include "local2.c" diff --git a/usr/src/cmd/mip/fmatch.c b/usr/src/cmd/mip/fmatch.c new file mode 100644 index 0000000000..76ff408d5d --- /dev/null +++ b/usr/src/cmd/mip/fmatch.c @@ -0,0 +1,2 @@ +# define FORT +# include "match.c" diff --git a/usr/src/cmd/mip/forder.c b/usr/src/cmd/mip/forder.c new file mode 100644 index 0000000000..0853117450 --- /dev/null +++ b/usr/src/cmd/mip/forder.c @@ -0,0 +1,2 @@ +# define FORT +# include "order.c" diff --git a/usr/src/cmd/mip/fort.c b/usr/src/cmd/mip/fort.c new file mode 100644 index 0000000000..ad2d56c540 --- /dev/null +++ b/usr/src/cmd/mip/fort.c @@ -0,0 +1,256 @@ +# define FORT +/* this forces larger trees, etc. */ +# include "mfile2" +# include "fort.h" + +/* masks for unpacking longs */ + +# ifndef FOP +# define FOP(x) (int)((x)&0377) +# endif + +# ifndef VAL +# define VAL(x) (int)(((x)>>8)&0377) +# endif + +# ifndef REST +# define REST(x) (((x)>>16)&0177777) +# endif + +FILE * lrd; /* for default reading routines */ +# ifndef NOLREAD +long lread(){ + static long x; + if( fread( (char *) &x, 4, 1, lrd ) <= 0 ) cerror( "intermediate file read error" ); + return( x ); + } +# endif + +# ifndef NOLOPEN +lopen( s ) char *s; { + /* if null, opens the standard input */ + if( *s ){ + lrd = fopen( s, "r" ); + if( lrd == NULL ) cerror( "cannot open intermediate file %s", s ); + } + else lrd = stdin; + } +# endif + +# ifndef NOLCREAD +lcread( cp, n ) char *cp; { + if( n > 0 ){ + if( fread( cp, 4, n, lrd ) != n ) cerror( "intermediate file read error" ); + } + } +# endif + +# ifndef NOLCCOPY +lccopy( n ) register n; { + register i; + static char fbuf[128]; + if( n > 0 ){ + if( n > 32 ) cerror( "lccopy asked to copy too much" ); + if( fread( fbuf, 4, n, lrd ) != n ) cerror( "intermediate file read error" ); + for( i=4*n; fbuf[i-1] == '\0' && i>0; --i ) { /* VOID */ } + if( i ) { + if( fwrite( fbuf, 1, i, stdout ) != i ) cerror( "output file error" ); + } + } + } +# endif + +/* new opcode definitions */ + +# define FORTOPS 200 +# define FTEXT 200 +# define FEXPR 201 +# define FSWITCH 202 +# define FLBRAC 203 +# define FRBRAC 204 +# define FEOF 205 +# define FARIF 206 +# define LABEL 207 + +/* stack for reading nodes in postfix form */ + +# define NSTACKSZ 250 + +NODE * fstack[NSTACKSZ]; +NODE ** fsp; /* points to next free position on the stack */ + +mainp2( argc, argv ) char *argv[]; { + int files; + register long x; + register NODE *p; + + files = p2init( argc, argv ); + tinit(); + + + if( files ){ + while( files < argc && argv[files][0] == '-' ) { + ++files; + } + if( files > argc ) return( nerrors ); + lopen( argv[files] ); + } + else lopen( "" ); + + fsp = fstack; + + for(;;){ + /* read nodes, and go to work... */ + x = lread(); + + if( xdebug ) fprintf( stderr, "op=%d, val = %d, rest = 0%o\n", FOP(x), VAL(x), (int)REST(x) ); + switch( (int)FOP(x) ){ /* switch on opcode */ + + case 0: + fprintf( stderr, "null opcode ignored\n" ); + continue; + case FTEXT: + lccopy( VAL(x) ); + printf( "\n" ); + continue; + + case FLBRAC: + tmpoff = baseoff = lread(); + maxtreg = VAL(x); + if( ftnno != REST(x) ){ + /* beginning of function */ + maxoff = baseoff; + ftnno = REST(x); + maxtemp = 0; + } + else { + if( baseoff > maxoff ) maxoff = baseoff; + /* maxoff at end of ftn is max of autos and temps + over all blocks in the function */ + } + setregs(); + continue; + + case FRBRAC: + SETOFF( maxoff, ALSTACK ); + eobl2(); + continue; + + case FEOF: + return( nerrors ); + + case FSWITCH: + uerror( "switch not yet done" ); + for( x=VAL(x); x>0; --x ) lread(); + continue; + + case ICON: + p = talloc(); + p->op = ICON; + p->type = REST(x); + p->rval = 0; + p->lval = lread(); + if( VAL(x) ){ + lcread( p->name, 2 ); + } + else p->name[0] = '\0'; + + bump: + p->su = 0; + p->rall = NOPREF; + *fsp++ = p; + if( fsp >= &fstack[NSTACKSZ] ) uerror( "expression depth exceeded" ); + continue; + + case NAME: + p = talloc(); + p->op = NAME; + p->type = REST(x); + p->rval = 0; + if( VAL(x) ) p->lval = lread(); + else p->lval = 0; + lcread( p->name, 2 ); + goto bump; + + case OREG: + p = talloc(); + p->op = OREG; + p->type = REST(x); + p->rval = VAL(x); + p->lval = lread(); + lcread( p->name, 2 ); + goto bump; + + case REG: + p = talloc(); + p->op = REG; + p->type = REST(x); + p->rval = VAL(x); + rbusy( p->rval, p->type ); + p->lval = 0; + p->name[0] = '\0'; + goto bump; + + case FEXPR: + lineno = REST(x); + if( VAL(x) ) lcread( filename, VAL(x) ); + if( fsp == fstack ) continue; /* filename only */ + if( --fsp != fstack ) uerror( "expression poorly formed" ); + if( lflag ) lineid( lineno, filename ); + tmpoff = baseoff; + p = fstack[0]; + if( edebug ) fwalk( p, eprint, 0 ); +# ifdef MYREADER + MYREADER(p); +# endif + + nrecur = 0; + delay( p ); + reclaim( p, RNULL, 0 ); + + allchk(); + tcheck(); + continue; + + case LABEL: + if( VAL(x) ){ + tlabel(); + } + else { + label( (int) REST(x) ); + } + continue; + + case GOTO: + if( VAL(x) ) { + cbgen( 0, (int) REST(x), 'I' ); /* unconditional branch */ + continue; + } + /* otherwise, treat as unary */ + goto def; + + default: + def: + p = talloc(); + p->op = FOP(x); + p->type = REST(x); + + switch( optype( p->op ) ){ + + case BITYPE: + p->right = *--fsp; + p->left = *--fsp; + goto bump; + + case UTYPE: + p->left = *--fsp; + p->rval = 0; + goto bump; + + case LTYPE: + uerror( "illegal leaf node: %d", p->op ); + exit( 1 ); + } + } + } + } diff --git a/usr/src/cmd/mip/freader.c b/usr/src/cmd/mip/freader.c new file mode 100644 index 0000000000..205b14bf3c --- /dev/null +++ b/usr/src/cmd/mip/freader.c @@ -0,0 +1,3 @@ +# define FORT +# define NOMAIN +# include "reader.c" diff --git a/usr/src/cmd/mip/ftable.c b/usr/src/cmd/mip/ftable.c new file mode 100644 index 0000000000..95809a56e3 --- /dev/null +++ b/usr/src/cmd/mip/ftable.c @@ -0,0 +1,2 @@ +# define FORT +# include "table.c" diff --git a/usr/src/cmd/mip/g b/usr/src/cmd/mip/g new file mode 100755 index 0000000000..1f7fa9d85a --- /dev/null +++ b/usr/src/cmd/mip/g @@ -0,0 +1,2 @@ +grep -n "$1" macdefs code.c local.c mac2defs local2.c order.c table.c +cd /usr/src/cmd/mip;grep -n "$1" manifest mfile1 cgram.y comm1.c scan.c xdefs.c pftn.c trees.c mfile2 reader.c allo.c match.c common optim.c diff --git a/usr/src/cmd/mip/makefile b/usr/src/cmd/mip/makefile new file mode 100644 index 0000000000..f33460bf97 --- /dev/null +++ b/usr/src/cmd/mip/makefile @@ -0,0 +1,71 @@ +INSTALL=./ccom +M=/usr/src/cmd/mip +CFLAGS=-O +head: comp ; + +all cp cmp: + @echo "This makefile is just a prototype for a portable" + @echo "C compiler-- it isn't used for an existing command" + +comp: cgram.o xdefs.o scan.o pftn.o trees.o optim.o code.o local.o reader.o local2.o order.o match.o allo.o comm1.o table.o + cc $(CFLAGS) -i cgram.o xdefs.o scan.o pftn.o trees.o optim.o code.o local.o reader.o local2.o order.o match.o allo.o comm1.o table.o + mv a.out comp +trees.o: $M/manifest macdefs $M/mfile1 $M/trees.c + cc -c $(CFLAGS) -I$M -I. $M/trees.c +optim.o: $M/manifest macdefs $M/mfile1 $M/optim.c + cc -c $(CFLAGS) -I$M -I. $M/optim.c +pftn.o: $M/manifest macdefs $M/mfile1 $M/pftn.c + cc -c $(CFLAGS) -I$M -I. $M/pftn.c +code.o: $M/manifest macdefs $M/mfile1 + cc -c $(CFLAGS) -I$M -I. code.c +local.o: $M/manifest macdefs $M/mfile1 + cc -c $(CFLAGS) -I$M -I. local.c +scan.o: $M/manifest macdefs $M/mfile1 $M/scan.c + cc -c $(CFLAGS) -I$M -I. $M/scan.c +xdefs.o: $M/manifest $M/mfile1 macdefs $M/xdefs.c + cc -c $(CFLAGS) -I$M -I. $M/xdefs.c +cgram.o: $M/manifest $M/mfile1 macdefs $M/cgram.c + cc -c $(CFLAGS) -I$M -I. $M/cgram.c +$M/cgram.c: $M/cgram.y + yacc $M/cgram.y + mv y.tab.c $M/cgram.c +comm1.o: $M/manifest $M/mfile1 $M/common macdefs $M/comm1.c + cc -c $(CFLAGS) -I. -I$M $M/comm1.c +table.o: $M/manifest $M/mfile2 mac2defs macdefs table.c + cc -c $(CFLAGS) -I$M -I. table.c +reader.o: $M/manifest $M/mfile2 mac2defs macdefs $M/reader.c + cc -c $(CFLAGS) -I$M -I. $M/reader.c +local2.o: $M/manifest $M/mfile2 mac2defs macdefs + cc -c $(CFLAGS) -I$M -I. local2.c +order.o: $M/manifest $M/mfile2 mac2defs macdefs + cc -c $(CFLAGS) -I$M -I. order.c +match.o: $M/manifest $M/mfile2 mac2defs macdefs $M/match.c + cc -c $(CFLAGS) -I$M -I. $M/match.c +allo.o: $M/manifest $M/mfile2 mac2defs macdefs $M/allo.c + cc -c $(CFLAGS) -I$M -I. $M/allo.c +shrink: + rm *.o comp +lintall: + lint -hpv -I. -I$M $M/cgram.c $M/xdefs.c $M/scan.c $M/pftn.c $M/trees.c $M/optim.c code.c local.c $M/reader.c local2.c order.c $M/match.c $M/allo.c $M/comm1.c table.c +fort: comp fort.o freader.o fallo.o fmatch.o ftable.o forder.o flocal2.o fcomm2.o + cc -i $(CFLAGS) fort.o freader.o fallo.o fmatch.o ftable.o forder.o flocal2.o fcomm2.o + mv a.out fort +fort.o: fort.h $M/fort.c + cc -c $(CFLAGS) -I$M -I. $M/fort.c +freader.o: reader.o + cc -c $(CFLAGS) -I$M -I. $M/freader.c +fallo.o: allo.o + cc -c $(CFLAGS) -I$M -I. $M/fallo.c +fmatch.o: match.o + cc -c $(CFLAGS) -I$M -I. $M/fmatch.c +ftable.o: table.o + cc -c $(CFLAGS) -I$M -I. $M/ftable.c +forder.o: order.o + cc -c $(CFLAGS) -I$M -I. $M/forder.c +flocal2.o: local2.o + cc -c $(CFLAGS) -I$M -I. $M/flocal2.c +fcomm2.o: $M/common + cc -c $(CFLAGS) -I$M -I. $M/fcomm2.c +fort.o freader.o fallo.o fmatch.o ftable.o forder.o flocal2.o fcomm2.o: $M/mfile2 $M/manifest macdefs mac2defs +install: + cp comp $(INSTALL) diff --git a/usr/src/cmd/mip/manifest b/usr/src/cmd/mip/manifest new file mode 100644 index 0000000000..7711a29c65 --- /dev/null +++ b/usr/src/cmd/mip/manifest @@ -0,0 +1,318 @@ + +# include +/* manifest constant file for the lex/yacc interface */ + +# define ERROR 1 +# define NAME 2 +# define STRING 3 +# define ICON 4 +# define FCON 5 +# define PLUS 6 +# define MINUS 8 +# define MUL 11 +# define AND 14 +# define OR 17 +# define ER 19 +# define QUEST 21 +# define COLON 22 +# define ANDAND 23 +# define OROR 24 + +/* special interfaces for yacc alone */ +/* These serve as abbreviations of 2 or more ops: + ASOP =, = ops + RELOP LE,LT,GE,GT + EQUOP EQ,NE + DIVOP DIV,MOD + SHIFTOP LS,RS + ICOP ICR,DECR + UNOP NOT,COMPL + STROP DOT,STREF + + */ +# define ASOP 25 +# define RELOP 26 +# define EQUOP 27 +# define DIVOP 28 +# define SHIFTOP 29 +# define INCOP 30 +# define UNOP 31 +# define STROP 32 + +/* reserved words, etc */ +# define TYPE 33 +# define CLASS 34 +# define STRUCT 35 +# define RETURN 36 +# define GOTO 37 +# define IF 38 +# define ELSE 39 +# define SWITCH 40 +# define BREAK 41 +# define CONTINUE 42 +# define WHILE 43 +# define DO 44 +# define FOR 45 +# define DEFAULT 46 +# define CASE 47 +# define SIZEOF 48 +# define ENUM 49 + + +/* little symbols, etc. */ +/* namely, + + LP ( + RP ) + + LC { + RC } + + LB [ + RB ] + + CM , + SM ; + + */ + +# define LP 50 +# define RP 51 +# define LC 52 +# define RC 53 +# define LB 54 +# define RB 55 +# define CM 56 +# define SM 57 +# define ASSIGN 58 + +/* END OF YACC */ + +/* left over tree building operators */ +# define COMOP 59 +# define DIV 60 +# define MOD 62 +# define LS 64 +# define RS 66 +# define DOT 68 +# define STREF 69 +# define CALL 70 +# define FORTCALL 73 +# define NOT 76 +# define COMPL 77 +# define INCR 78 +# define DECR 79 +# define EQ 80 +# define NE 81 +# define LE 82 +# define LT 83 +# define GE 84 +# define GT 85 +# define ULE 86 +# define ULT 87 +# define UGE 88 +# define UGT 89 +# define SETBIT 90 +# define TESTBIT 91 +# define RESETBIT 92 +# define ARS 93 +# define REG 94 +# define OREG 95 +# define CCODES 96 +# define FREE 97 +# define STASG 98 +# define STARG 99 +# define STCALL 100 + +/* some conversion operators */ +# define FLD 103 +# define SCONV 104 +# define PCONV 105 +# define PMCONV 106 +# define PVCONV 107 + +/* special node operators, used for special contexts */ +# define FORCE 108 +# define CBRANCH 109 +# define INIT 110 +# define CAST 111 + +/* node types */ +# define LTYPE 02 +# define UTYPE 04 +# define BITYPE 010 + + /* DSIZE is the size of the dope array */ +# define DSIZE CAST+1 + +/* type names, used in symbol table building */ +# define TNULL PTR /* pointer to UNDEF */ +# define UNDEF 0 +# define FARG 1 +# define CHAR 2 +# define SHORT 3 +# define INT 4 +# define LONG 5 +# define FLOAT 6 +# define DOUBLE 7 +# define STRTY 8 +# define UNIONTY 9 +# define ENUMTY 10 +# define MOETY 11 +# define UCHAR 12 +# define USHORT 13 +# define UNSIGNED 14 +# define ULONG 15 + +# define ASG 1+ +# define UNARY 2+ +# define NOASG (-1)+ +# define NOUNARY (-2)+ + +/* various flags */ +# define NOLAB (-1) + +/* type modifiers */ + +# define PTR 020 +# define FTN 040 +# define ARY 060 + +/* type packing constants */ + +# define TMASK 060 +# define TMASK1 0300 +# define TMASK2 0360 +# define BTMASK 017 +# define BTSHIFT 4 +# define TSHIFT 2 + +/* macros */ + +# define MODTYPE(x,y) x = (x&(~BTMASK))|y /* set basic type of x to y */ +# define BTYPE(x) (x&BTMASK) /* basic type of x */ +# define ISUNSIGNED(x) ((x)<=ULONG&&(x)>=UCHAR) +# define UNSIGNABLE(x) ((x)<=LONG&&(x)>=CHAR) +# define ENUNSIGN(x) ((x)+(UNSIGNED-INT)) +# define DEUNSIGN(x) ((x)+(INT-UNSIGNED)) +# define ISPTR(x) ((x&TMASK)==PTR) +# define ISFTN(x) ((x&TMASK)==FTN) /* is x a function type */ +# define ISARY(x) ((x&TMASK)==ARY) /* is x an array type */ +# define INCREF(x) (((x&~BTMASK)<>TSHIFT)&~BTMASK)|(x&BTMASK)) +# define SETOFF(x,y) if( x%y != 0 ) x = ( (x/y + 1) * y) + /* advance x to a multiple of y */ +# define NOFIT(x,y,z) ( (x%z + y) > z ) + /* can y bits be added to x without overflowing z */ + /* pack and unpack field descriptors (size and offset) */ +# define PKFIELD(s,o) ((o<<6)|s) +# define UPKFSZ(v) (v&077) +# define UPKFOFF(v) (v>>6) + +/* operator information */ + +# define TYFLG 016 +# define ASGFLG 01 +# define LOGFLG 020 + +# define SIMPFLG 040 +# define COMMFLG 0100 +# define DIVFLG 0200 +# define FLOFLG 0400 +# define LTYFLG 01000 +# define CALLFLG 02000 +# define MULFLG 04000 +# define SHFFLG 010000 +# define ASGOPFLG 020000 + +# define SPFLG 040000 + +#define optype(o) (dope[o]&TYFLG) +#define asgop(o) (dope[o]&ASGFLG) +#define logop(o) (dope[o]&LOGFLG) +#define callop(o) (dope[o]&CALLFLG) + +/* table sizes */ + +# define BCSZ 100 /* size of the table to save break and continue labels */ +# define SYMTSZ 450 /* size of the symbol table */ +# define DIMTABSZ 750 /* size of the dimension/size table */ +# define PARAMSZ 150 /* size of the parameter stack */ +# ifndef FORT +# define TREESZ 350 /* space for building parse tree */ +# else +# define TREESZ 1000 +# endif +# define SWITSZ 250 /* size of switch table */ + +# define NCHNAM 8 /* number of characters in a name */ + +/* common defined variables */ + +extern int nerrors; /* number of errors seen so far */ + +typedef union ndu NODE; +typedef unsigned int TWORD; +extern NODE *NIL; /* a pointer which will always have 0 in it */ +extern int dope[]; /* a vector containing operator information */ +extern char *opst[]; /* a vector containing names for ops */ + +# ifdef ONEPASS + /* in one-pass operation, define the tree nodes */ + +union ndu { + + struct { + int op; + int rall; + TWORD type; + int su; + char name[NCHNAM]; + NODE *left; + NODE *right; + }; + + struct { + int op; + int rall; + TWORD type; + int su; + char name[NCHNAM]; + CONSZ lval; + int rval; + }; + + struct { + int op, rall; + TWORD type; + int su; + int label; /* for use with branching */ + }; + + struct { + int op, rall; + TWORD type; + int su; + int stsize; /* sizes of structure objects */ + int stalign; /* alignment of structure objects */ + }; + + struct { + int op; + int cdim; + TWORD type; + int csiz; + }; + + struct { + /* this structure is used when a floating point constant + is being computed */ + int op; + int cdim; + TWORD type; + int csiz; + double dval; + }; + + }; +# endif diff --git a/usr/src/cmd/mip/mfile1 b/usr/src/cmd/mip/mfile1 new file mode 100644 index 0000000000..141a46f690 --- /dev/null +++ b/usr/src/cmd/mip/mfile1 @@ -0,0 +1,237 @@ + +# include "macdefs" +# include "manifest" + +/* storage classes */ +# define SNULL 0 +# define AUTO 1 +# define EXTERN 2 +# define STATIC 3 +# define REGISTER 4 +# define EXTDEF 5 +# define LABEL 6 +# define ULABEL 7 +# define MOS 8 +# define PARAM 9 +# define STNAME 10 +# define MOU 11 +# define UNAME 12 +# define TYPEDEF 13 +# define FORTRAN 14 +# define ENAME 15 +# define MOE 16 +# define UFORTRAN 17 +# define USTATIC 18 + /* field size is ORed in */ +# define FIELD 0100 +# define FLDSIZ 077 +extern char *scnames(); + +/* location counters */ +# define PROG 0 +# define DATA 1 +# define ADATA 2 +# define STRNG 3 +# define ISTRNG 4 +# define STAB 5 + + +/* symbol table flags */ +# define SMOS 01 +# define SHIDDEN 02 +# define SHIDES 04 +# define SSET 010 +# define SREF 020 + +# ifndef FIXDEF +# define FIXDEF(p) +#endif + + /* alignment of initialized quantities */ +# ifndef AL_INIT +# define AL_INIT ALINT +# endif + +struct symtab { + char sname[NCHNAM]; + TWORD stype; /* type word */ + + char sclass; /* storage class */ + char slevel; /* scope level */ + char sflags; /* flags for set, use, hidden, mos, etc. */ + int offset; /* offset or value */ + short dimoff; /* offset into the dimension table */ + short sizoff; /* offset into the size table */ + short suse; /* line number of last use of the variable */ + }; + + +# ifdef ONEPASS +/* NOPREF must be defined for use in first pass tree machine */ +# define NOPREF 020000 /* no preference for register assignment */ +#else + +union ndu { + struct { + int op; + TWORD type; + int cdim, csiz; + NODE *left; + NODE * right; + }; + + struct { + /* this structure is the same as above, + but is used when a value, rather than + address, is kept in +left */ + int op; + TWORD type; + int cdim, csiz; + CONSZ lval; + int rval; + }; + + struct { + /* this structure is used when a floating point constant + is being computed */ + int op; + TWORD type; + int cdim, csiz; + double dval; + }; + + }; +# endif + +struct sw { + CONSZ sval; + int slab; + }; + +extern struct sw swtab[]; +extern struct sw *swp; +extern int swx; + +extern int ftnno; +extern int blevel; +extern int instruct, stwart; + +extern int lineno, nerrors; +typedef union { + int intval; + NODE * nodep; + } YYSTYPE; +extern YYSTYPE yylval; + +extern CONSZ lastcon; +extern double dcon; + +extern char ftitle[]; +extern struct symtab stab[]; +extern int curftn; +extern int curclass; +extern int curdim; +extern int dimtab[]; +extern int paramstk[]; +extern int paramno; +extern int autooff, argoff, strucoff; +extern int regvar; +extern int minrvar; +extern int brkflag; +extern char yytext[]; + +extern int strflg; + +extern OFFSZ inoff; + +extern int reached; + +/* tunnel to buildtree for name id's */ + +extern int idname; + +extern NODE node[]; +extern NODE *lastfree; + +extern int cflag, hflag, pflag; + +/* various labels */ +extern int brklab; +extern int contlab; +extern int flostat; +extern int retlab; +extern int retstat; +extern int asavbc[], *psavbc; + +/* flags used in structures/unions */ + +# define SEENAME 01 +# define INSTRUCT 02 +# define INUNION 04 +# define FUNNYNAME 010 + +/* flags used in the (elementary) flow analysis ... */ + +# define FBRK 02 +# define FCONT 04 +# define FDEF 010 +# define FLOOP 020 + +/* flags used for return status */ + +# define RETVAL 1 +# define NRETVAL 2 + +/* used to mark a constant with no name field */ + +# define NONAME 040000 + + /* mark an offset which is undefined */ + +# define NOOFFSET (-10201) + +/* declarations of various functions */ + +extern NODE + *buildtree(), + *bdty(), + *mkty(), + *rstruct(), + *dclstruct(), + *getstr(), + *tymerge(), + *stref(), + *offcon(), + *bcon(), + *bpsize(), + *convert(), + *pconvert(), + *oconvert(), + *ptmatch(), + *tymatch(), + *makety(), + *block(), + *doszof(), + *talloc(), + *optim(), + *strargs(), + *clocal(); + +OFFSZ tsize(), + psize(); + +TWORD types(); + + +double atof(); + +char *exname(), *exdcon(); + +# define checkst(x) + +# ifndef CHARCAST +/* to make character constants into character connstants */ +/* this is a macro to defend against cross-compilers, etc. */ +# define CHARCAST(x) (char)(x) +# endif + diff --git a/usr/src/cmd/mip/optim.c b/usr/src/cmd/mip/optim.c new file mode 100644 index 0000000000..7beaa7d9fb --- /dev/null +++ b/usr/src/cmd/mip/optim.c @@ -0,0 +1,181 @@ +# include "mfile1" + +# define SWAP(p,q) {sp=p; p=q; q=sp;} +# define RCON(p) (p->right->op==ICON) +# define RO(p) p->right->op +# define RV(p) p->right->lval +# define LCON(p) (p->left->op==ICON) +# define LO(p) p->left->op +# define LV(p) p->left->lval + +int oflag = 0; + +NODE * +fortarg( p ) NODE *p; { + /* fortran function arguments */ + + if( p->op == CM ){ + p->left = fortarg( p->left ); + p->right = fortarg( p->right ); + return(p); + } + + while( ISPTR(p->type) ){ + p = buildtree( UNARY MUL, p, NIL ); + } + return( optim(p) ); + } + + /* mapping relationals when the sides are reversed */ +short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; +NODE * +optim(p) register NODE *p; { + /* local optimizations, most of which are probably machine independent */ + + register o, ty; + NODE *sp; + int i; + TWORD t; + + if( (t=BTYPE(p->type))==ENUMTY || t==MOETY ) econvert(p); + if( oflag ) return(p); + ty = optype( o=p->op); + if( ty == LTYPE ) return(p); + + if( ty == BITYPE ) p->right = optim(p->right); + p->left = optim(p->left); + + /* collect constants */ + + switch(o){ + + case SCONV: + case PCONV: + return( clocal(p) ); + + case FORTCALL: + p->right = fortarg( p->right ); + break; + + case UNARY AND: + if( LO(p) != NAME ) cerror( "& error" ); + + if( !andable(p->left) ) return(p); + + LO(p) = ICON; + + setuleft: + /* paint over the type of the left hand side with the type of the top */ + p->left->type = p->type; + p->left->cdim = p->cdim; + p->left->csiz = p->csiz; + p->op = FREE; + return( p->left ); + + case UNARY MUL: + if( LO(p) != ICON ) break; + LO(p) = NAME; + goto setuleft; + + case MINUS: + if( !nncon(p->right) ) break; + RV(p) = -RV(p); + o = p->op = PLUS; + + case MUL: + case PLUS: + case AND: + case OR: + case ER: + /* commutative ops; for now, just collect constants */ + /* someday, do it right */ + if( nncon(p->left) || ( LCON(p) && !RCON(p) ) ) SWAP( p->left, p->right ); + /* make ops tower to the left, not the right */ + if( RO(p) == o ){ + NODE *t1, *t2, *t3; + t1 = p->left; + sp = p->right; + t2 = sp->left; + t3 = sp->right; + /* now, put together again */ + p->left = sp; + sp->left = t1; + sp->right = t2; + p->right = t3; + } + if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->left) && + conval(p->right, MINUS, p->left->right)){ + zapleft: + RO(p->left) = FREE; + LO(p) = FREE; + p->left = p->left->left; + } + if( RCON(p) && LO(p)==o && RCON(p->left) && conval( p->right, o, p->left->right ) ){ + goto zapleft; + } + else if( LCON(p) && RCON(p) && conval( p->left, o, p->right ) ){ + zapright: + RO(p) = FREE; + p->left = makety( p->left, p->type, p->cdim, p->csiz ); + p->op = FREE; + return( clocal( p->left ) ); + } + + /* change muls to shifts */ + + if( o==MUL && nncon(p->right) && (i=ispow2(RV(p)))>=0){ + if( i == 0 ){ /* multiplication by 1 */ + goto zapright; + } + o = p->op = LS; + p->right->type = p->right->csiz = INT; + RV(p) = i; + } + + /* change +'s of negative consts back to - */ + if( o==PLUS && nncon(p->right) && RV(p)<0 ){ + RV(p) = -RV(p); + o = p->op = MINUS; + } + break; + + case DIV: + if( nncon( p->right ) && p->right->lval == 1 ) goto zapright; + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + case ULT: + case ULE: + case UGT: + case UGE: + if( !LCON(p) ) break; + + /* exchange operands */ + + sp = p->left; + p->left = p->right; + p->right = sp; + p->op = revrel[p->op - EQ ]; + break; + + } + + return(p); + } + +ispow2( c ) CONSZ c; { + register i; + if( c <= 0 || (c&(c-1)) ) return(-1); + for( i=0; c>1; ++i) c >>= 1; + return(i); + } + +nncon( p ) NODE *p; { + /* is p a constant without a name */ + return( p->op == ICON && p->rval == NONAME ); + } diff --git a/usr/src/cmd/mip/pftn.c b/usr/src/cmd/mip/pftn.c new file mode 100644 index 0000000000..0a2dbc7929 --- /dev/null +++ b/usr/src/cmd/mip/pftn.c @@ -0,0 +1,1673 @@ +# include "mfile1" + +struct instk { + int in_sz; /* size of array element */ + int in_x; /* current index for structure member in structure initializations */ + int in_n; /* number of initializations seen */ + int in_s; /* sizoff */ + int in_d; /* dimoff */ + TWORD in_t; /* type */ + int in_id; /* stab index */ + int in_fl; /* flag which says if this level is controlled by {} */ + OFFSZ in_off; /* offset of the beginning of this level */ + } +instack[10], +*pstk; + + /* defines used for getting things off of the initialization stack */ + + +struct symtab *relook(); + + +int ddebug = 0; + +defid( q, class ) NODE *q; { + register struct symtab *p; + int idp; + TWORD type; + TWORD stp; + int scl; + int dsym, ddef; + int slev, temp; + + if( q == NIL ) return; /* an error was detected */ + + if( q < node || q >= &node[TREESZ] ) cerror( "defid call" ); + + idp = q->rval; + + if( idp < 0 ) cerror( "tyreduce" ); + p = &stab[idp]; + + if( ddebug ){ + printf( "defid( %.8s (%d), ", p->sname, idp ); + tprint( q->type ); + printf( ", %s, (%d,%d) ), level %d\n", scnames(class), q->cdim, q->csiz, blevel ); + } + + fixtype( q, class ); + + type = q->type; + class = fixclass( class, type ); + + stp = p->stype; + slev = p->slevel; + + if( ddebug ){ + printf( " modified to " ); + tprint( type ); + printf( ", %s\n", scnames(class) ); + printf( " previous def'n: " ); + tprint( stp ); + printf( ", %s, (%d,%d) ), level %d\n", scnames(p->sclass), p->dimoff, p->sizoff, slev ); + } + + if( stp == UNDEF|| stp == FARG ){ + if( blevel==1 && stp!=FARG ) switch( class ){ + + default: + if(!(class&FIELD)) uerror( "declared argument %.8s is missing", p->sname ); + case MOS: + case STNAME: + case MOU: + case UNAME: + case MOE: + case ENAME: + case TYPEDEF: + ; + } + goto enter; + } + if( type != stp ) goto mismatch; + /* test (and possibly adjust) dimensions */ + dsym = p->dimoff; + ddef = q->cdim; + for( temp=type; temp&TMASK; temp = DECREF(temp) ){ + if( ISARY(temp) ){ + if( dimtab[dsym] == 0 ) dimtab[dsym] = dimtab[ddef]; + else if( dimtab[ddef]!=0 && dimtab[dsym] != dimtab[ddef] ){ + goto mismatch; + } + ++dsym; + ++ddef; + } + } + + /* check that redeclarations are to the same structure */ + if( (temp==STRTY||temp==UNIONTY||temp==ENUMTY) && p->sizoff != q->csiz && (type&TMASK) ) { + goto mismatch; + } + + scl = ( p->sclass ); + + if( ddebug ){ + printf( " previous class: %s\n", scnames(scl) ); + } + + if( class&FIELD ){ + /* redefinition */ + if( !falloc( p, class&FLDSIZ, 1, NIL ) ) { + /* successful allocation */ + psave( idp ); + return; + } + /* blew it: resume at end of switch... */ + } + + else switch( class ){ + + case EXTERN: + switch( scl ){ + case STATIC: + case USTATIC: + if( slev==0 ) return; + break; + case EXTDEF: + case EXTERN: + case FORTRAN: + case UFORTRAN: + return; + } + break; + + case STATIC: + if( scl==USTATIC || (scl==EXTERN && blevel==0) ){ + p->sclass = STATIC; + if( ISFTN(type) ) curftn = idp; + return; + } + break; + + case USTATIC: + if( scl==STATIC || scl==USTATIC ) return; + break; + + case LABEL: + if( scl == ULABEL ){ + p->sclass = LABEL; + deflab( p->offset ); + return; + } + break; + + case TYPEDEF: + if( scl == class ) return; + break; + + case UFORTRAN: + if( scl == UFORTRAN || scl == FORTRAN ) return; + break; + + case FORTRAN: + if( scl == UFORTRAN ){ + p->sclass = FORTRAN; + if( ISFTN(type) ) curftn = idp; + return; + } + break; + + case MOU: + case MOS: + if( scl == class ) { + if( oalloc( p, &strucoff ) ) break; + if( class == MOU ) strucoff = 0; + psave( idp ); + return; + } + break; + + case MOE: + if( scl == class ){ + if( p->offset!= strucoff++ ) break; + psave( idp ); + } + break; + + case EXTDEF: + if( scl == EXTERN ) { + p->sclass = EXTDEF; + if( ISFTN(type) ) curftn = idp; + return; + } + break; + + case STNAME: + case UNAME: + case ENAME: + if( scl != class ) break; + if( dimtab[p->sizoff] == 0 ) return; /* previous entry just a mention */ + break; + + case ULABEL: + if( scl == LABEL || scl == ULABEL ) return; + case PARAM: + case AUTO: + case REGISTER: + ; /* mismatch.. */ + + } + + mismatch: + if( blevel > slev && class != EXTERN && class != FORTRAN && + class != UFORTRAN && !( class == LABEL && slev >= 2 ) ){ + q->rval = idp = hide( p ); + p = &stab[idp]; + goto enter; + } + uerror( "redeclaration of %.8s", p->sname ); + if( class==EXTDEF && ISFTN(type) ) curftn = idp; + return; + + enter: /* make a new entry */ + + if( ddebug ) printf( " new entry made\n" ); + p->stype = type; + p->sclass = class; + p->slevel = blevel; + p->offset = NOOFFSET; + p->suse = lineno; + if( class == STNAME || class == UNAME || class == ENAME ) { + p->sizoff = curdim; + dstash( 0 ); /* size */ + dstash( -1 ); /* index to members of str or union */ + dstash( ALSTRUCT ); /* alignment */ + } + else { + switch( BTYPE(type) ){ + case STRTY: + case UNIONTY: + case ENUMTY: + p->sizoff = q->csiz; + break; + default: + p->sizoff = BTYPE(type); + } + } + + /* copy dimensions */ + + p->dimoff = q->cdim; + + /* allocate offsets */ + if( class&FIELD ){ + falloc( p, class&FLDSIZ, 0, NIL ); /* new entry */ + psave( idp ); + } + else switch( class ){ + + case AUTO: + oalloc( p, &autooff ); + break; + case STATIC: + case EXTDEF: + p->offset = getlab(); + if( ISFTN(type) ) curftn = idp; + break; + case ULABEL: + case LABEL: + p->offset = getlab(); + p->slevel = 2; + if( class == LABEL ){ + locctr( PROG ); + deflab( p->offset ); + } + break; + + case EXTERN: + case UFORTRAN: + case FORTRAN: + p->offset = getlab(); + p->slevel = 0; + break; + case MOU: + case MOS: + oalloc( p, &strucoff ); + if( class == MOU ) strucoff = 0; + psave( idp ); + break; + + case MOE: + p->offset = strucoff++; + psave( idp ); + break; + case REGISTER: + p->offset = regvar--; + if( blevel == 1 ) p->sflags |= SSET; + if( regvar < minrvar ) minrvar = regvar; + break; + } + + /* user-supplied routine to fix up new definitions */ + + FIXDEF(p); + + if( ddebug ) printf( " dimoff, sizoff, offset: %d, %d, %d\n", p->dimoff, p->sizoff, p->offset ); + + } + +psave( i ){ + if( paramno >= PARAMSZ ){ + cerror( "parameter stack overflow"); + } + paramstk[ paramno++ ] = i; + } + +ftnend(){ /* end of function */ + if( retlab != NOLAB ){ /* inside a real function */ + efcode(); + } + checkst(0); + retstat = 0; + tcheck(); + curclass = SNULL; + brklab = contlab = retlab = NOLAB; + flostat = 0; + if( nerrors == 0 ){ + if( psavbc != & asavbc[0] ) cerror("bcsave error"); + if( paramno != 0 ) cerror("parameter reset error"); + if( swx != 0 ) cerror( "switch error"); + } + psavbc = &asavbc[0]; + paramno = 0; + autooff = AUTOINIT; + minrvar = regvar = MAXRVAR; + reached = 1; + swx = 0; + swp = swtab; + locctr(DATA); + } + +dclargs(){ + register i, j; + register struct symtab *p; + register NODE *q; + argoff = ARGINIT; + for( i=0; istype == FARG ) { + q = block(FREE,NIL,NIL,INT,0,INT); + q->rval = j; + defid( q, PARAM ); + } + oalloc( p, &argoff ); /* always set aside space, even for register arguments */ + } + cendarg(); + locctr(PROG); + defalign(ALINT); + ++ftnno; + bfcode( paramstk, paramno ); + paramno = 0; + } + +NODE * +rstruct( idn, soru ){ /* reference to a structure or union, with no definition */ + register struct symtab *p; + register NODE *q; + p = &stab[idn]; + switch( p->stype ){ + + case UNDEF: + def: + q = block( FREE, NIL, NIL, 0, 0, 0 ); + q->rval = idn; + q->type = (soru&INSTRUCT) ? STRTY : ( (soru&INUNION) ? UNIONTY : ENUMTY ); + defid( q, (soru&INSTRUCT) ? STNAME : ( (soru&INUNION) ? UNAME : ENAME ) ); + break; + + case STRTY: + if( soru & INSTRUCT ) break; + goto def; + + case UNIONTY: + if( soru & INUNION ) break; + goto def; + + case ENUMTY: + if( !(soru&(INUNION|INSTRUCT)) ) break; + goto def; + + } + stwart = instruct; + return( mkty( p->stype, 0, p->sizoff ) ); + } + +moedef( idn ){ + register NODE *q; + + q = block( FREE, NIL, NIL, MOETY, 0, 0 ); + q -> rval = idn; + if( idn>=0 ) defid( q, MOE ); + } + +bstruct( idn, soru ){ /* begining of structure or union declaration */ + register NODE *q; + + psave( instruct ); + psave( curclass ); + psave( strucoff ); + strucoff = 0; + instruct = soru; + q = block( FREE, NIL, NIL, 0, 0, 0 ); + q->rval = idn; + if( instruct==INSTRUCT ){ + curclass = MOS; + q->type = STRTY; + if( idn >= 0 ) defid( q, STNAME ); + } + else if( instruct == INUNION ) { + curclass = MOU; + q->type = UNIONTY; + if( idn >= 0 ) defid( q, UNAME ); + } + else { /* enum */ + curclass = MOE; + q->type = ENUMTY; + if( idn >= 0 ) defid( q, ENAME ); + } + psave( q->rval ); + return( paramno-4 ); + } + +NODE * +dclstruct( oparam ){ + register struct symtab *p; + register i, al, sa, j, sz, szindex; + register TWORD temp; + register high, low; + + /* paramstack contains: + paramstack[ oparam ] = previous instruct + paramstack[ oparam+1 ] = previous class + paramstk[ oparam+2 ] = previous strucoff + paramstk[ oparam+3 ] = structure name + + paramstk[ oparam+4, ... ] = member stab indices + + */ + + + if( (i=paramstk[oparam+3]) < 0 ){ + szindex = curdim; + dstash( 0 ); /* size */ + dstash( -1 ); /* index to member names */ + dstash( ALSTRUCT ); /* alignment */ + } + else { + szindex = stab[i].sizoff; + } + + if( ddebug ){ + printf( "dclstruct( %.8s ), szindex = %d\n", (i>=0)? stab[i].sname : "??", szindex ); + } + temp = (instruct&INSTRUCT)?STRTY:((instruct&INUNION)?UNIONTY:ENUMTY); + stwart = instruct = paramstk[ oparam ]; + curclass = paramstk[ oparam+1 ]; + dimtab[ szindex+1 ] = curdim; + al = ALSTRUCT; + + high = low = 0; + + for( i = oparam+4; i< paramno; ++i ){ + dstash( j=paramstk[i] ); + if( j<0 || j>= SYMTSZ ) cerror( "gummy structure member" ); + p = &stab[j]; + if( temp == ENUMTY ){ + if( p->offset < low ) low = p->offset; + if( p->offset > high ) high = p->offset; + p->sizoff = szindex; + continue; + } + sa = talign( p->stype, p->sizoff ); + if( p->sclass & FIELD ){ + sz = p->sclass&FLDSIZ; + } + else { + sz = tsize( p->stype, p->dimoff, p->sizoff ); + } + if( sz == 0 ){ + uerror( "illegal zero sized structure member: %.8s", p->sname ); + } + if( sz > strucoff ) strucoff = sz; /* for use with unions */ + SETOFF( al, sa ); + /* set al, the alignment, to the lcm of the alignments of the members */ + } + dstash( -1 ); /* endmarker */ + SETOFF( strucoff, al ); + + if( temp == ENUMTY ){ + register TWORD ty; + +# ifdef ENUMSIZE + ty = ENUMSIZE(high,low); +# else + if( (char)high == high && (char)low == low ) ty = ctype( CHAR ); + else if( (short)high == high && (short)low == low ) ty = ctype( SHORT ); + else ty = ctype(INT); +#endif + strucoff = tsize( ty, 0, (int)ty ); + dimtab[ szindex+2 ] = al = talign( ty, (int)ty ); + } + + if( strucoff == 0 ) uerror( "zero sized structure" ); + dimtab[ szindex ] = strucoff; + dimtab[ szindex+2 ] = al; + + if( ddebug>1 ){ + printf( "\tdimtab[%d,%d,%d] = %d,%d,%d\n", szindex,szindex+1,szindex+2, + dimtab[szindex],dimtab[szindex+1],dimtab[szindex+2] ); + for( i = dimtab[szindex+1]; dimtab[i] >= 0; ++i ){ + printf( "\tmember %.8s(%d)\n", stab[dimtab[i]].sname, dimtab[i] ); + } + } + + strucoff = paramstk[ oparam+2 ]; + paramno = oparam; + + return( mkty( temp, 0, szindex ) ); + } + + /* VARARGS */ +yyerror( s ) char *s; { /* error printing routine in parser */ + + uerror( s ); + + } + +yyaccpt(){ + ftnend(); + } + +ftnarg( idn ) { + if( stab[idn].stype != UNDEF ){ + idn = hide( &stab[idn]); + } + stab[idn].stype = FARG; + stab[idn].sclass = PARAM; + psave( idn ); + } + +talign( ty, s) register unsigned ty; register s; { + /* compute the alignment of an object with type ty, sizeoff index s */ + + register i; + if( s<0 && ty!=INT && ty!=CHAR && ty!=SHORT && ty!=UNSIGNED && ty!=UCHAR && ty!=USHORT +#ifdef LONGFIELDS + && ty!=LONG && ty!=ULONG +#endif + ){ + return( fldal( ty ) ); + } + + for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){ + switch( (ty>>i)&TMASK ){ + + case FTN: + cerror( "compiler takes alignment of function"); + case PTR: + return( ALPOINT ); + case ARY: + continue; + case 0: + break; + } + } + + switch( BTYPE(ty) ){ + + case UNIONTY: + case ENUMTY: + case STRTY: + return( dimtab[ s+2 ] ); + case CHAR: + case UCHAR: + return( ALCHAR ); + case FLOAT: + return( ALFLOAT ); + case DOUBLE: + return( ALDOUBLE ); + case LONG: + case ULONG: + return( ALLONG ); + case SHORT: + case USHORT: + return( ALSHORT ); + default: + return( ALINT ); + } + } + +OFFSZ +tsize( ty, d, s ) TWORD ty; { + /* compute the size associated with type ty, + dimoff d, and sizoff s */ + /* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ + + int i; + OFFSZ mult; + + mult = 1; + + for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){ + switch( (ty>>i)&TMASK ){ + + case FTN: + cerror( "compiler takes size of function"); + case PTR: + return( SZPOINT * mult ); + case ARY: + mult *= dimtab[ d++ ]; + continue; + case 0: + break; + + } + } + + if( dimtab[s]==0 ) { + uerror( "unknown size"); + return( SZINT ); + } + return( dimtab[ s ] * mult ); + } + +inforce( n ) OFFSZ n; { /* force inoff to have the value n */ + /* inoff is updated to have the value n */ + OFFSZ wb; + register rest; + /* rest is used to do a lot of conversion to ints... */ + + if( inoff == n ) return; + if( inoff > n ) { + cerror( "initialization alignment error"); + } + + wb = inoff; + SETOFF( wb, SZINT ); + + /* wb now has the next higher word boundary */ + + if( wb >= n ){ /* in the same word */ + rest = n - inoff; + vfdzero( rest ); + return; + } + + /* otherwise, extend inoff to be word aligned */ + + rest = wb - inoff; + vfdzero( rest ); + + /* now, skip full words until near to n */ + + rest = (n-inoff)/SZINT; + zecode( rest ); + + /* now, the remainder of the last word */ + + rest = n-inoff; + vfdzero( rest ); + if( inoff != n ) cerror( "inoff error"); + + } + +vfdalign( n ){ /* make inoff have the offset the next alignment of n */ + OFFSZ m; + + m = inoff; + SETOFF( m, n ); + inforce( m ); + } + + +int idebug = 0; + +int ibseen = 0; /* the number of } constructions which have been filled */ + +int iclass; /* storage class of thing being initialized */ + +int ilocctr = 0; /* location counter for current initialization */ + +beginit(curid){ + /* beginning of initilization; set location ctr and set type */ + register struct symtab *p; + + if( idebug >= 3 ) printf( "beginit(), curid = %d\n", curid ); + + p = &stab[curid]; + + iclass = p->sclass; + if( curclass == EXTERN || curclass == FORTRAN ) iclass = EXTERN; + switch( iclass ){ + + case UNAME: + case EXTERN: + return; + case AUTO: + case REGISTER: + break; + case EXTDEF: + case STATIC: + ilocctr = ISARY(p->stype)?ADATA:DATA; + locctr( ilocctr ); + defalign( talign( p->stype, p->sizoff ) ); + defnam( p ); + + } + + inoff = 0; + ibseen = 0; + + pstk = 0; + + instk( curid, p->stype, p->dimoff, p->sizoff, inoff ); + + } + +instk( id, t, d, s, off ) OFFSZ off; TWORD t; { + /* make a new entry on the parameter stack to initialize id */ + + register struct symtab *p; + + for(;;){ + if( idebug ) printf( "instk((%d, %o,%d,%d, %d)\n", id, t, d, s, off ); + + /* save information on the stack */ + + if( !pstk ) pstk = instack; + else ++pstk; + + pstk->in_fl = 0; /* { flag */ + pstk->in_id = id ; + pstk->in_t = t ; + pstk->in_d = d ; + pstk->in_s = s ; + pstk->in_n = 0; /* number seen */ + pstk->in_x = t==STRTY ?dimtab[s+1] : 0 ; + pstk->in_off = off; /* offset at the beginning of this element */ + /* if t is an array, DECREF(t) can't be a field */ + /* INS_sz has size of array elements, and -size for fields */ + if( ISARY(t) ){ + pstk->in_sz = tsize( DECREF(t), d+1, s ); + } + else if( stab[id].sclass & FIELD ){ + pstk->in_sz = - ( stab[id].sclass & FLDSIZ ); + } + else { + pstk->in_sz = 0; + } + + if( (iclass==AUTO || iclass == REGISTER ) && + (ISARY(t) || t==STRTY) ) uerror( "no automatic aggregate initialization" ); + + /* now, if this is not a scalar, put on another element */ + + if( ISARY(t) ){ + t = DECREF(t); + ++d; + continue; + } + else if( t == STRTY ){ + id = dimtab[pstk->in_x]; + p = &stab[id]; + if( p->sclass != MOS && !(p->sclass&FIELD) ) cerror( "insane structure member list" ); + t = p->stype; + d = p->dimoff; + s = p->sizoff; + off += p->offset; + continue; + } + else return; + } + } + +NODE * +getstr(){ /* decide if the string is external or an initializer, and get the contents accordingly */ + + register l, temp; + register NODE *p; + + if( (iclass==EXTDEF||iclass==STATIC) && (pstk->in_t == CHAR || pstk->in_t == UCHAR) && + pstk!=instack && ISARY( pstk[-1].in_t ) ){ + /* treat "abc" as { 'a', 'b', 'c', 0 } */ + strflg = 1; + ilbrace(); /* simulate { */ + inforce( pstk->in_off ); + /* if the array is inflexible (not top level), pass in the size and + be prepared to throw away unwanted initializers */ + lxstr((pstk-1)!=instack?dimtab[(pstk-1)->in_d]:0); /* get the contents */ + irbrace(); /* simulate } */ + return( NIL ); + } + else { /* make a label, and get the contents and stash them away */ + if( iclass != SNULL ){ /* initializing */ + /* fill out previous word, to permit pointer */ + vfdalign( ALPOINT ); + } + temp = locctr( blevel==0?ISTRNG:STRNG ); /* set up location counter */ + deflab( l = getlab() ); + strflg = 0; + lxstr(0); /* get the contents */ + locctr( blevel==0?ilocctr:temp ); + p = buildtree( STRING, NIL, NIL ); + p->rval = -l; + return(p); + } + } + +putbyte( v ){ /* simulate byte v appearing in a list of integer values */ + register NODE *p; + p = bcon(v); + incode( p, SZCHAR ); + tfree( p ); + gotscal(); + } + +endinit(){ + register TWORD t; + register d, s, n, d1; + + if( idebug ) printf( "endinit(), inoff = %d\n", inoff ); + + switch( iclass ){ + + case EXTERN: + case AUTO: + case REGISTER: + return; + } + + pstk = instack; + + t = pstk->in_t; + d = pstk->in_d; + s = pstk->in_s; + n = pstk->in_n; + + if( ISARY(t) ){ + d1 = dimtab[d]; + + vfdalign( pstk->in_sz ); /* fill out part of the last element, if needed */ + n = inoff/pstk->in_sz; /* real number of initializers */ + if( d1 >= n ){ + /* once again, t is an array, so no fields */ + inforce( tsize( t, d, s ) ); + n = d1; + } + if( d1!=0 && d1!=n ) uerror( "too many initializers"); + if( n==0 ) werror( "empty array declaration"); + dimtab[d] = n; + } + + else if( t == STRTY || t == UNIONTY ){ + /* clearly not fields either */ + inforce( tsize( t, d, s ) ); + } + else if( n > 1 ) uerror( "bad scalar initialization"); + /* this will never be called with a field element... */ + else inforce( tsize(t,d,s) ); + + paramno = 0; + vfdalign( AL_INIT ); + inoff = 0; + iclass = SNULL; + + } + +doinit( p ) register NODE *p; { + + /* take care of generating a value for the initializer p */ + /* inoff has the current offset (last bit written) + in the current word being generated */ + + register sz, d, s; + register TWORD t; + + /* note: size of an individual initializer is assumed to fit into an int */ + + if( iclass < 0 ) goto leave; + if( iclass == EXTERN || iclass == UNAME ){ + uerror( "cannot initialize extern or union" ); + iclass = -1; + goto leave; + } + + if( iclass == AUTO || iclass == REGISTER ){ + /* do the initialization and get out, without regard + for filing out the variable with zeros, etc. */ + bccode(); + idname = pstk->in_id; + p = buildtree( ASSIGN, buildtree( NAME, NIL, NIL ), p ); + ecomp(p); + return; + } + + if( p == NIL ) return; /* for throwing away strings that have been turned into lists */ + + if( ibseen ){ + uerror( "} expected"); + goto leave; + } + + if( idebug > 1 ) printf( "doinit(%o)\n", p ); + + t = pstk->in_t; /* type required */ + d = pstk->in_d; + s = pstk->in_s; + if( pstk->in_sz < 0 ){ /* bit field */ + sz = -pstk->in_sz; + } + else { + sz = tsize( t, d, s ); + } + + inforce( pstk->in_off ); + + p = buildtree( ASSIGN, block( NAME, NIL,NIL, t, d, s ), p ); + p->left->op = FREE; + p->left = p->right; + p->right = NIL; + p->left = optim( p->left ); + if( p->left->op == UNARY AND ){ + p->left->op = FREE; + p->left = p->left->left; + } + p->op = INIT; + + if( sz < SZINT ){ /* special case: bit fields, etc. */ + if( p->left->op != ICON ) uerror( "illegal initialization" ); + else incode( p->left, sz ); + } + else if( p->left->op == FCON ){ + fincode( p->left->dval, sz ); + } + else { + cinit( optim(p), sz ); + } + + gotscal(); + + leave: + tfree(p); + } + +gotscal(){ + register t, ix; + register n, id; + struct symtab *p; + OFFSZ temp; + + for( ; pstk > instack; ) { + + if( pstk->in_fl ) ++ibseen; + + --pstk; + + t = pstk->in_t; + + if( t == STRTY ){ + ix = ++pstk->in_x; + if( (id=dimtab[ix]) < 0 ) continue; + + /* otherwise, put next element on the stack */ + + p = &stab[id]; + instk( id, p->stype, p->dimoff, p->sizoff, p->offset+pstk->in_off ); + return; + } + else if( ISARY(t) ){ + n = ++pstk->in_n; + if( n >= dimtab[pstk->in_d] && pstk > instack ) continue; + + /* put the new element onto the stack */ + + temp = pstk->in_sz; + instk( pstk->in_id, (TWORD)DECREF(pstk->in_t), pstk->in_d+1, pstk->in_s, + pstk->in_off+n*temp ); + return; + } + + } + + } + +ilbrace(){ /* process an initializer's left brace */ + register t; + struct instk *temp; + + temp = pstk; + + for( ; pstk > instack; --pstk ){ + + t = pstk->in_t; + if( t != STRTY && !ISARY(t) ) continue; /* not an aggregate */ + if( pstk->in_fl ){ /* already associated with a { */ + if( pstk->in_n ) uerror( "illegal {"); + continue; + } + + /* we have one ... */ + pstk->in_fl = 1; + break; + } + + /* cannot find one */ + /* ignore such right braces */ + + pstk = temp; + } + +irbrace(){ + /* called when a '}' is seen */ + + if( idebug ) printf( "irbrace(): paramno = %d on entry\n", paramno ); + + if( ibseen ) { + --ibseen; + return; + } + + for( ; pstk > instack; --pstk ){ + if( !pstk->in_fl ) continue; + + /* we have one now */ + + pstk->in_fl = 0; /* cancel { */ + gotscal(); /* take it away... */ + return; + } + + /* these right braces match ignored left braces: throw out */ + + } + +upoff( size, alignment, poff ) register alignment, *poff; { + /* update the offset pointed to by poff; return the + /* offset of a value of size `size', alignment `alignment', + /* given that off is increasing */ + + register off; + + off = *poff; + SETOFF( off, alignment ); + *poff = off+size; + return( off ); + } + +oalloc( p, poff ) register struct symtab *p; register *poff; { + /* allocate p with offset *poff, and update *poff */ + register al, off, tsz; + int noff; + + al = talign( p->stype, p->sizoff ); + noff = off = *poff; + tsz = tsize( p->stype, p->dimoff, p->sizoff ); +#ifdef BACKAUTO + if( p->sclass == AUTO ){ + noff = off + tsz; + SETOFF( noff, al ); + off = -noff; + } + else +#endif + if( p->sclass == PARAM && (p->stype==CHAR||p->stype==UCHAR||p->stype==SHORT|| + p->stype==USHORT) ){ + off = upoff( SZINT, ALINT, &noff ); +# ifndef RTOLBYTES + off = noff - tsz; +#endif + } + else + { + off = upoff( tsz, al, &noff ); + } + + if( p->sclass != REGISTER ){ /* in case we are allocating stack space for register arguments */ + if( p->offset == NOOFFSET ) p->offset = off; + else if( off != p->offset ) return(1); + } + + *poff = noff; + return(0); + } + +falloc( p, w, new, pty ) register struct symtab *p; NODE *pty; { + /* allocate a field of width w */ + /* new is 0 if new entry, 1 if redefinition, -1 if alignment */ + + register al,sz,type; + + type = (new<0)? pty->type : p->stype; + + /* this must be fixed to use the current type in alignments */ + switch( new<0?pty->type:p->stype ){ + + case ENUMTY: + { + int s; + s = new<0 ? pty->csiz : p->sizoff; + al = dimtab[s+2]; + sz = dimtab[s]; + break; + } + + case CHAR: + case UCHAR: + al = ALCHAR; + sz = SZCHAR; + break; + + case SHORT: + case USHORT: + al = ALSHORT; + sz = SZSHORT; + break; + + case INT: + case UNSIGNED: + al = ALINT; + sz = SZINT; + break; +#ifdef LONGFIELDS + + case LONG: + case ULONG: + al = ALLONG; + sz = SZLONG; + break; +#endif + + default: + if( new < 0 ) { + uerror( "illegal field type" ); + al = ALINT; + } + else { + al = fldal( p->stype ); + sz =SZINT; + } + } + + if( w > sz ) { + uerror( "field too big"); + w = sz; + } + + if( w == 0 ){ /* align only */ + SETOFF( strucoff, al ); + if( new >= 0 ) uerror( "zero size field"); + return(0); + } + + if( strucoff%al + w > sz ) SETOFF( strucoff, al ); + if( new < 0 ) { + strucoff += w; /* we know it will fit */ + return(0); + } + + /* establish the field */ + + if( new == 1 ) { /* previous definition */ + if( p->offset != strucoff || p->sclass != (FIELD|w) ) return(1); + } + p->offset = strucoff; + strucoff += w; + p->stype = type; + fldty( p ); + return(0); + } + +nidcl( p ) NODE *p; { /* handle unitialized declarations */ + /* assumed to be not functions */ + register class; + register commflag; /* flag for labelled common declarations */ + + commflag = 0; + + /* compute class */ + if( (class=curclass) == SNULL ){ + if( blevel > 1 ) class = AUTO; + else if( blevel != 0 || instruct ) cerror( "nidcl error" ); + else { /* blevel = 0 */ + class = noinit(); + if( class == EXTERN ) commflag = 1; + } + } + + defid( p, class ); + + if( class==EXTDEF || class==STATIC ){ + /* simulate initialization by 0 */ + beginit(p->rval); + endinit(); + } + if( commflag ) commdec( p->rval ); + } + +TWORD +types( t1, t2, t3 ) TWORD t1, t2, t3; { + /* return a basic type from basic types t1, t2, and t3 */ + + TWORD t[3], noun, adj, unsg; + register i; + + t[0] = t1; + t[1] = t2; + t[2] = t3; + + unsg = INT; /* INT or UNSIGNED */ + noun = UNDEF; /* INT, CHAR, or FLOAT */ + adj = INT; /* INT, LONG, or SHORT */ + + for( i=0; i<3; ++i ){ + switch( t[i] ){ + + default: + bad: + uerror( "illegal type combination" ); + return( INT ); + + case UNDEF: + continue; + + case UNSIGNED: + if( unsg != INT ) goto bad; + unsg = UNSIGNED; + continue; + + case LONG: + case SHORT: + if( adj != INT ) goto bad; + adj = t[i]; + continue; + + case INT: + case CHAR: + case FLOAT: + if( noun != UNDEF ) goto bad; + noun = t[i]; + continue; + } + } + + /* now, construct final type */ + if( noun == UNDEF ) noun = INT; + else if( noun == FLOAT ){ + if( unsg != INT || adj == SHORT ) goto bad; + return( adj==LONG ? DOUBLE : FLOAT ); + } + else if( noun == CHAR && adj != INT ) goto bad; + + /* now, noun is INT or CHAR */ + if( adj != INT ) noun = adj; + if( unsg == UNSIGNED ) return( noun + (UNSIGNED-INT) ); + else return( noun ); + } + +NODE * +tymerge( typ, idp ) NODE *typ, *idp; { + /* merge type typ with identifier idp */ + + register unsigned t; + register i; + extern int eprint(); + + if( typ->op != TYPE ) cerror( "tymerge: arg 1" ); + if(idp == NIL ) return( NIL ); + + if( ddebug > 2 ) fwalk( idp, eprint, 0 ); + + idp->type = typ->type; + idp->cdim = curdim; + tyreduce( idp ); + idp->csiz = typ->csiz; + + for( t=typ->type, i=typ->cdim; t&TMASK; t = DECREF(t) ){ + if( ISARY(t) ) dstash( dimtab[i++] ); + } + + /* now idp is a single node: fix up type */ + + idp->type = ctype( idp->type ); + + if( (t = BTYPE(idp->type)) != STRTY && t != UNIONTY && t != ENUMTY ){ + idp->csiz = t; /* in case ctype has rewritten things */ + } + + return( idp ); + } + +tyreduce( p ) register NODE *p; { + + /* build a type, and stash away dimensions, from a parse tree of the declaration */ + /* the type is build top down, the dimensions bottom up */ + register o, temp; + register unsigned t; + + o = p->op; + p->op = FREE; + + if( o == NAME ) return; + + t = INCREF( p->type ); + if( o == UNARY CALL ) t += (FTN-PTR); + else if( o == LB ){ + t += (ARY-PTR); + temp = p->right->lval; + p->right->op = FREE; + } + + p->left->type = t; + tyreduce( p->left ); + + if( o == LB ) dstash( temp ); + + p->rval = p->left->rval; + p->type = p->left->type; + + } + +fixtype( p, class ) register NODE *p; { + register unsigned t, type; + register mod1, mod2; + /* fix up the types, and check for legality */ + + if( (type = p->type) == UNDEF ) return; + if( mod2 = (type&TMASK) ){ + t = DECREF(type); + while( mod1=mod2, mod2 = (t&TMASK) ){ + if( mod1 == ARY && mod2 == FTN ){ + uerror( "array of functions is illegal" ); + type = 0; + } + else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ + uerror( "function returns illegal type" ); + type = 0; + } + t = DECREF(t); + } + } + + /* detect function arguments, watching out for structure declarations */ + + if( class==SNULL && blevel==1 && !(instruct&(INSTRUCT|INUNION)) ) class = PARAM; + if( class == PARAM || ( class==REGISTER && blevel==1 ) ){ + if( type == FLOAT ) type = DOUBLE; + else if( ISARY(type) ){ + ++p->cdim; + type += (PTR-ARY); + } + else if( ISFTN(type) ) type = INCREF(type); + + } + + if( instruct && ISFTN(type) ){ + uerror( "function illegal in structure or union" ); + type = INCREF(type); + } + p->type = type; + } + +uclass( class ) register class; { + /* give undefined version of class */ + if( class == SNULL ) return( EXTERN ); + else if( class == STATIC ) return( USTATIC ); + else if( class == FORTRAN ) return( UFORTRAN ); + else return( class ); + } + +fixclass( class, type ) TWORD type; { + + /* first, fix null class */ + + if( class == SNULL ){ + if( instruct&INSTRUCT ) class = MOS; + else if( instruct&INUNION ) class = MOU; + else if( blevel == 0 ) class = EXTDEF; + else if( blevel == 1 ) class = PARAM; + else class = AUTO; + + } + + /* now, do general checking */ + + if( ISFTN( type ) ){ + switch( class ) { + default: + uerror( "function has illegal storage class" ); + case AUTO: + class = EXTERN; + case EXTERN: + case EXTDEF: + case FORTRAN: + case TYPEDEF: + case STATIC: + case UFORTRAN: + case USTATIC: + ; + } + } + + if( class&FIELD ){ + if( !(instruct&INSTRUCT) ) uerror( "illegal use of field" ); + return( class ); + } + + switch( class ){ + + case MOU: + if( !(instruct&INUNION) ) uerror( "illegal class" ); + return( class ); + + case MOS: + if( !(instruct&INSTRUCT) ) uerror( "illegal class" ); + return( class ); + + case MOE: + if( instruct & (INSTRUCT|INUNION) ) uerror( "illegal class" ); + return( class ); + + case REGISTER: + if( blevel == 0 ) uerror( "illegal register declaration" ); + else if( regvar >= MINRVAR && cisreg( type ) ) return( class ); + if( blevel == 1 ) return( PARAM ); + else return( AUTO ); + + case AUTO: + case LABEL: + case ULABEL: + if( blevel < 2 ) uerror( "illegal class" ); + return( class ); + + case PARAM: + if( blevel != 1 ) uerror( "illegal class" ); + return( class ); + + case UFORTRAN: + case FORTRAN: +# ifdef NOFORTRAN + NOFORTRAN; /* a condition which can regulate the FORTRAN usage */ +# endif + if( !ISFTN(type) ) uerror( "fortran declaration must apply to function" ); + else { + type = DECREF(type); + if( ISFTN(type) || ISARY(type) || ISPTR(type) ) { + uerror( "fortran function has wrong type" ); + } + } + case STNAME: + case UNAME: + case ENAME: + case EXTERN: + case STATIC: + case EXTDEF: + case TYPEDEF: + case USTATIC: + return( class ); + + default: + cerror( "illegal class: %d", class ); + /* NOTREACHED */ + + } + } + +lookup( name, s) char *name; { + /* look up name: must agree with s w.r.t. SMOS and SHIDDEN */ + + register char *p, *q; + int i, j, ii; + register struct symtab *sp; + + /* compute initial hash index */ + if( ddebug > 2 ){ + printf( "lookup( %s, %d ), stwart=%d, instruct=%d\n", name, s, stwart, instruct ); + } + + i = 0; + for( p=name, j=0; *p != '\0'; ++p ){ + i += *p; + if( ++j >= NCHNAM ) break; + } + i = i%SYMTSZ; + sp = &stab[ii=i]; + + for(;;){ /* look for name */ + + if( sp->stype == TNULL ){ /* empty slot */ + p = sp->sname; + sp->sflags = s; /* set SMOS if needed, turn off all others */ + for( j=0; jstype = UNDEF; + sp->sclass = SNULL; + return( i ); + } + if( (sp->sflags & (SMOS|SHIDDEN)) != s ) goto next; + p = sp->sname; + q = name; + for( j=0; j= SYMTSZ ){ + i = 0; + sp = stab; + } + else ++sp; + if( i == ii ) cerror( "symbol table full" ); + } + } + +#ifndef checkst +/* if not debugging, make checkst a macro */ +checkst(lev){ + register int s, i, j; + register struct symtab *p, *q; + + for( i=0, p=stab; istype == TNULL ) continue; + j = lookup( p->sname, p->sflags&SMOS ); + if( j != i ){ + q = &stab[j]; + if( q->stype == UNDEF || + q->slevel <= p->slevel ){ + cerror( "check error: %.8s", q->sname ); + } + } + else if( p->slevel > lev ) cerror( "%.8s check at level %d", p->sname, lev ); + } + } +#endif + +struct symtab * +relook(p) register struct symtab *p; { /* look up p again, and see where it lies */ + + register struct symtab *q; + + /* I'm not sure that this handles towers of several hidden definitions in all cases */ + q = &stab[lookup( p->sname, p->sflags&(SMOS|SHIDDEN) )]; + /* make relook always point to either p or an empty cell */ + if( q->stype == UNDEF ){ + q->stype = TNULL; + return(q); + } + while( q != p ){ + if( q->stype == TNULL ) break; + if( ++q >= &stab[SYMTSZ] ) q=stab; + } + return(q); + } + +clearst( lev ){ /* clear entries of internal scope from the symbol table */ + register struct symtab *p, *q, *r; + register int temp, rehash; + + temp = lineno; + aobeg(); + + /* first, find an empty slot to prevent newly hashed entries from + being slopped into... */ + + for( q=stab; q< &stab[SYMTSZ]; ++q ){ + if( q->stype == TNULL )goto search; + } + + cerror( "symbol table full"); + + search: + p = q; + + for(;;){ + if( p->stype == TNULL ) { + rehash = 0; + goto next; + } + lineno = p->suse; + if( lineno < 0 ) lineno = - lineno; + if( p->slevel>lev ){ /* must clobber */ + if( p->stype == UNDEF || ( p->sclass == ULABEL && lev < 2 ) ){ + lineno = temp; + uerror( "%.8s undefined", p->sname ); + } + else aocode(p); + if (ddebug) printf("removing %8s from stab[ %d], flags %o level %d\n", + p->sname,p-stab,p->sflags,p->slevel); + if( p->sflags & SHIDES ) unhide(p); + p->stype = TNULL; + rehash = 1; + goto next; + } + if( rehash ){ + if( (r=relook(p)) != p ){ + movestab( r, p ); + p->stype = TNULL; + } + } + next: + if( ++p >= &stab[SYMTSZ] ) p = stab; + if( p == q ) break; + } + lineno = temp; + aoend(); + } + +movestab( p, q ) register struct symtab *p, *q; { + int k; + /* structure assignment: *p = *q; */ + p->stype = q->stype; + p->sclass = q->sclass; + p->slevel = q->slevel; + p->offset = q->offset; + p->sflags = q->sflags; + p->dimoff = q->dimoff; + p->sizoff = q->sizoff; + p->suse = q->suse; + for( k=0; ksname[k] = q->sname[k]; + } + } + +hide( p ) register struct symtab *p; { + register struct symtab *q; + for( q=p+1; ; ++q ){ + if( q >= &stab[SYMTSZ] ) q = stab; + if( q == p ) cerror( "symbol table full" ); + if( q->stype == TNULL ) break; + } + movestab( q, p ); + p->sflags |= SHIDDEN; + q->sflags = (p->sflags&SMOS) | SHIDES; + if( hflag ) werror( "%.8s redefinition hides earlier one", p->sname ); + if( ddebug ) printf( " %d hidden in %d\n", p-stab, q-stab ); + return( idname = q-stab ); + } + +unhide( p ) register struct symtab *p; { + register struct symtab *q; + register s, j; + + s = p->sflags & SMOS; + q = p; + + for(;;){ + + if( q == stab ) q = &stab[SYMTSZ-1]; + else --q; + + if( q == p ) break; + + if( (q->sflags&SMOS) == s ){ + for( j =0; jsname[j] != q->sname[j] ) break; + if( j == NCHNAM ){ /* found the name */ + q->sflags &= ~SHIDDEN; + if( ddebug ) printf( "unhide uncovered %d from %d\n", q-stab,p-stab); + return; + } + } + + } + cerror( "unhide fails" ); + } diff --git a/usr/src/cmd/mip/reader.c b/usr/src/cmd/mip/reader.c new file mode 100644 index 0000000000..c1dec2f5e7 --- /dev/null +++ b/usr/src/cmd/mip/reader.c @@ -0,0 +1,1253 @@ +# include "mfile2" + +/* some storage declarations */ + +# ifndef ONEPASS +NODE node[TREESZ]; +char filename[100] = ""; /* the name of the file */ +int ftnno; /* number of current function */ +int lineno; +# else +# define NOMAIN +#endif + +int nrecur; +int lflag; +int edebug = 0; +int xdebug = 0; +int udebug = 0; + +OFFSZ tmpoff; /* offset for first temporary, in bits for current block */ +OFFSZ maxoff; /* maximum temporary offset over all blocks in current ftn, in bits */ +int maxtreg; + +NODE *stotree; +int stocook; + +OFFSZ baseoff = 0; +OFFSZ maxtemp = 0; + +p2init( argc, argv ) char *argv[];{ + /* set the values of the pass 2 arguments */ + + register int c; + register char *cp; + register files; + + allo0(); /* free all regs */ + files = 0; + + for( c=1; c argc ) return( nerrors ); + freopen( argv[files], "r", stdin ); + } + while( (c=getchar()) > 0 ) switch( c ){ + case ')': + /* copy line unchanged */ + while( (c=getchar()) > 0 ){ + PUTCHAR(c); + if( c == '\n' ) break; + } + continue; + + case '[': + /* beginning of a block */ + temp = rdin(10); /* ftnno */ + tmpoff = baseoff = rdin(10); /* autooff for block gives max offset of autos in block */ + maxtreg = rdin(10); + if( getchar() != '\n' ) cerror( "intermediate file format error"); + + if( temp != ftnno ){ /* beginning of function */ + maxoff = baseoff; + ftnno = temp; + maxtemp = 0; + } + else { + if( baseoff > maxoff ) maxoff = baseoff; + /* maxoff at end of ftn is max of autos and temps + over all blocks in the function */ + } + setregs(); + continue; + + case ']': /* end of block */ + SETOFF( maxoff, ALSTACK ); + eobl2(); + while( (c=getchar()) != '\n' ){ + if( c <= 0 ) cerror( "intermediate file format eof" ); + } + continue; + + case '.': + /* compile code for an expression */ + lineno = rdin( 10 ); + for( cp=filename; (*cp=getchar()) != '\n'; ++cp ) ; /* VOID, reads filename */ + *cp = '\0'; + if( lflag ) lineid( lineno, filename ); + + tmpoff = baseoff; /* expression at top level reuses temps */ + p = eread(); + + if( edebug ) fwalk( p, eprint, 0 ); + +# ifdef MYREADER + MYREADER(p); /* do your own laundering of the input */ +# endif + + nrecur = 0; + delay( p ); /* expression statement throws out results */ + reclaim( p, RNULL, 0 ); + + allchk(); + tcheck(); + continue; + + default: + cerror( "intermediate file format error" ); + + } + + /* EOF */ + if( files ) goto reread; + return(nerrors); + + } + +# endif + +# ifdef ONEPASS + +p2compile( p ) NODE *p; { + + if( lflag ) lineid( lineno, filename ); + tmpoff = baseoff; /* expression at top level reuses temps */ + /* generate code for the tree p */ + if( edebug ) fwalk( p, eprint, 0 ); + +# ifdef MYREADER + MYREADER(p); /* do your own laundering of the input */ +# endif + nrecur = 0; + delay( p ); /* do the code generation */ + reclaim( p, RNULL, 0 ); + allchk(); + /* can't do tcheck here; some stuff (e.g., attributes) may be around from first pass */ + /* first pass will do it... */ + } + +p2bbeg( aoff, myreg ) { + static int myftn = -1; + tmpoff = baseoff = aoff; + maxtreg = myreg; + if( myftn != ftnno ){ /* beginning of function */ + maxoff = baseoff; + myftn = ftnno; + maxtemp = 0; + } + else { + if( baseoff > maxoff ) maxoff = baseoff; + /* maxoff at end of ftn is max of autos and temps over all blocks */ + } + setregs(); + } + +p2bend(){ + SETOFF( maxoff, ALSTACK ); + eobl2(); + } + +# endif + +NODE *deltrees[DELAYS]; +int deli; + +delay( p ) register NODE *p; { + /* look in all legal places for COMOP's and ++ and -- ops to delay */ + /* note; don't delay ++ and -- within calls or things like + /* getchar (in their macro forms) will start behaving strangely */ + register i; + + /* look for visible COMOPS, and rewrite repeatedly */ + + while( delay1( p ) ) { /* VOID */ } + + /* look for visible, delayable ++ and -- */ + + deli = 0; + delay2( p ); + codgen( p, FOREFF ); /* do what is left */ + for( i = 0; iop; + ty = optype( o ); + if( ty == LTYPE ) return( 0 ); + else if( ty == UTYPE ) return( delay1( p->left ) ); + + switch( o ){ + + case QUEST: + case ANDAND: + case OROR: + /* don't look on RHS */ + return( delay1(p->left ) ); + + case COMOP: /* the meat of the routine */ + delay( p->left ); /* completely evaluate the LHS */ + /* rewrite the COMOP */ + { register NODE *q; + q = p->right; + ncopy( p, p->right ); + q->op = FREE; + } + return( 1 ); + } + + return( delay1(p->left) || delay1(p->right ) ); + } + +delay2( p ) register NODE *p; { + + /* look for delayable ++ and -- operators */ + + register o, ty; + o = p->op; + ty = optype( o ); + + switch( o ){ + + case NOT: + case QUEST: + case ANDAND: + case OROR: + case CALL: + case UNARY CALL: + case STCALL: + case UNARY STCALL: + case FORTCALL: + case UNARY FORTCALL: + case COMOP: + case CBRANCH: + /* for the moment, don7t delay past a conditional context, or + /* inside of a call */ + return; + + case INCR: + case DECR: + if( deltest( p ) ){ + if( deli < DELAYS ){ + register NODE *q; + deltrees[deli++] = tcopy(p); + q = p->left; + p->right->op = FREE; /* zap constant */ + ncopy( p, q ); + q->op = FREE; + return; + } + } + + } + + if( ty == BITYPE ) delay2( p->right ); + if( ty != LTYPE ) delay2( p->left ); + } + +codgen( p, cookie ) NODE *p; { + + /* generate the code for p; + order may call codgen recursively */ + /* cookie is used to describe the context */ + + for(;;){ + canon(p); /* creats OREG from * if possible and does sucomp */ + stotree = NIL; + if( edebug ){ + printf( "store called on:\n" ); + fwalk( p, eprint, 0 ); + } + store(p); + if( stotree==NIL ) break; + + /* because it's minimal, can do w.o. stores */ + + order( stotree, stocook ); + } + + order( p, cookie ); + + } + +char *cnames[] = { + "SANY", + "SAREG", + "STAREG", + "SBREG", + "STBREG", + "SCC", + "SNAME", + "SCON", + "SFLD", + "SOREG", + "STARNM", + "STARREG", + "INTEMP", + "FORARG", + "SWADD", + 0, + }; + +prcook( cookie ){ + + /* print a nice-looking description of cookie */ + + int i, flag; + + if( cookie & SPECIAL ){ + if( cookie == SZERO ) printf( "SZERO" ); + else if( cookie == SONE ) printf( "SONE" ); + else if( cookie == SMONE ) printf( "SMONE" ); + else printf( "SPECIAL+%d", cookie & ~SPECIAL ); + return; + } + + flag = 0; + for( i=0; cnames[i]; ++i ){ + if( cookie & (1<rall ); + + if( odebug ){ + printf( "order( %o, ", p ); + prcook( cookie ); + printf( " )\n" ); + fwalk( p, eprint, 0 ); + } + + o = p->op; + ty = optype(o); + + /* first of all, for most ops, see if it is in the table */ + + /* look for ops */ + + switch( m = p->op ){ + + default: + /* look for op in table */ + for(;;){ + if( (m = match( p, cookie ) ) == MDONE ) goto cleanup; + else if( m == MNOPE ){ + if( !(cookie = nextcook( p, cookie ) ) ) goto nomat; + continue; + } + else break; + } + break; + + case COMOP: + case FORCE: + case CBRANCH: + case QUEST: + case ANDAND: + case OROR: + case NOT: + case UNARY CALL: + case CALL: + case UNARY STCALL: + case STCALL: + case UNARY FORTCALL: + case FORTCALL: + /* don't even go near the table... */ + ; + + } + /* get here to do rewriting if no match or + fall through from above for hard ops */ + + p1 = p->left; + if( ty == BITYPE ) p2 = p->right; + else p2 = NIL; + + if( odebug ){ + printf( "order( %o, ", p ); + prcook( cook ); + printf( " ), cookie " ); + prcook( cookie ); + printf( ", rewrite %s\n", opst[m] ); + } + switch( m ){ + default: + nomat: + cerror( "no table entry for op %s", opst[p->op] ); + + case COMOP: + codgen( p1, FOREFF ); + p2->rall = p->rall; + codgen( p2, cookie ); + ncopy( p, p2 ); + p2->op = FREE; + goto cleanup; + + case FORCE: + /* recurse, letting the work be done by rallo */ + p = p->left; + cook = INTAREG|INTBREG; + goto again; + + case CBRANCH: + o = p2->lval; + cbranch( p1, -1, o ); + p2->op = FREE; + p->op = FREE; + return; + + case QUEST: + cbranch( p1, -1, m=getlab() ); + p2->left->rall = p->rall; + codgen( p2->left, INTAREG|INTBREG ); + /* force right to compute result into same reg used by left */ + p2->right->rall = p2->left->rval|MUSTDO; + reclaim( p2->left, RNULL, 0 ); + cbgen( 0, m1 = getlab(), 'I' ); + deflab( m ); + codgen( p2->right, INTAREG|INTBREG ); + deflab( m1 ); + p->op = REG; /* set up node describing result */ + p->lval = 0; + p->rval = p2->right->rval; + p->type = p2->right->type; + tfree( p2->right ); + p2->op = FREE; + goto cleanup; + + case ANDAND: + case OROR: + case NOT: /* logical operators */ + /* if here, must be a logical operator for 0-1 value */ + cbranch( p, -1, m=getlab() ); + p->op = CCODES; + p->label = m; + order( p, INTAREG ); + goto cleanup; + + case FLD: /* fields of funny type */ + if ( p1->op == UNARY MUL ){ + offstar( p1->left ); + goto again; + } + + case UNARY MINUS: + order( p1, INBREG|INAREG ); + goto again; + + case NAME: + /* all leaves end up here ... */ + if( o == REG ) goto nomat; + order( p, INTAREG|INTBREG ); + goto again; + + case INIT: + uerror( "illegal initialization" ); + return; + + case UNARY FORTCALL: + p->right = NIL; + case FORTCALL: + o = p->op = UNARY FORTCALL; + if( genfcall( p, cookie ) ) goto nomat; + goto cleanup; + + case UNARY CALL: + p->right = NIL; + case CALL: + o = p->op = UNARY CALL; + if( gencall( p, cookie ) ) goto nomat; + goto cleanup; + + case UNARY STCALL: + p->right = NIL; + case STCALL: + o = p->op = UNARY STCALL; + if( genscall( p, cookie ) ) goto nomat; + goto cleanup; + + /* if arguments are passed in register, care must be taken that reclaim + /* not throw away the register which now has the result... */ + + case UNARY MUL: + if( cook == FOREFF ){ + /* do nothing */ + order( p->left, FOREFF ); + p->op = FREE; + return; + } + offstar( p->left ); + goto again; + + case INCR: /* INCR and DECR */ + if( setincr(p) ) goto again; + + /* x++ becomes (x += 1) -1; */ + + if( cook & FOREFF ){ /* result not needed so inc or dec and be done with it */ + /* x++ => x += 1 */ + p->op = (p->op==INCR)?ASG PLUS:ASG MINUS; + goto again; + } + + p1 = tcopy(p); + reclaim( p->left, RNULL, 0 ); + p->left = p1; + p1->op = (p->op==INCR)?ASG PLUS:ASG MINUS; + p->op = (p->op==INCR)?MINUS:PLUS; + goto again; + + case STASG: + if( setstr( p ) ) goto again; + goto nomat; + + case ASG PLUS: /* and other assignment ops */ + if( setasop(p) ) goto again; + + /* there are assumed to be no side effects in LHS */ + + p2 = tcopy(p); + p->op = ASSIGN; + reclaim( p->right, RNULL, 0 ); + p->right = p2; + canon(p); + rallo( p, p->rall ); + + if( odebug ) fwalk( p, eprint, 0 ); + + order( p2->left, INTBREG|INTAREG ); + order( p2, INTBREG|INTAREG ); + goto again; + + case ASSIGN: + if( setasg( p ) ) goto again; + goto nomat; + + + case BITYPE: + if( setbin( p ) ) goto again; + /* try to replace binary ops by =ops */ + switch(o){ + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + case AND: + case OR: + case ER: + case LS: + case RS: + p->op = ASG o; + goto again; + } + goto nomat; + + } + + cleanup: + + /* if it is not yet in the right state, put it there */ + + if( cook & FOREFF ){ + reclaim( p, RNULL, 0 ); + return; + } + + if( p->op==FREE ) return; + + if( tshape( p, cook ) ) return; + + if( (m=match(p,cook) ) == MDONE ) return; + + /* we are in bad shape, try one last chance */ + if( lastchance( p, cook ) ) goto again; + + goto nomat; + } + +int callflag; +int fregs; + +store( p ) register NODE *p; { + + /* find a subtree of p which should be stored */ + + register o, ty; + + o = p->op; + ty = optype(o); + + if( ty == LTYPE ) return; + + switch( o ){ + + case UNARY CALL: + case UNARY FORTCALL: + case UNARY STCALL: + ++callflag; + break; + + case UNARY MUL: + if( asgop(p->left->op) ) stoasg( p->left, UNARY MUL ); + break; + + case CALL: + case FORTCALL: + case STCALL: + store( p->left ); + stoarg( p->right, o ); + ++callflag; + return; + + case COMOP: + markcall( p->right ); + if( p->right->su > fregs ) SETSTO( p, INTEMP ); + store( p->left ); + return; + + case ANDAND: + case OROR: + case QUEST: + markcall( p->right ); + if( p->right->su > fregs ) SETSTO( p, INTEMP ); + case CBRANCH: /* to prevent complicated expressions on the LHS from being stored */ + case NOT: + constore( p->left ); + return; + + } + + if( ty == UTYPE ){ + store( p->left ); + return; + } + + if( asgop( p->right->op ) ) stoasg( p->right, o ); + + if( p->su>fregs ){ /* must store */ + mkadrs( p ); /* set up stotree and stocook to subtree + that must be stored */ + } + + store( p->right ); + store( p->left ); + } + +constore( p ) register NODE *p; { + + /* store conditional expressions */ + /* the point is, avoid storing expressions in conditional + conditional context, since the evaluation order is predetermined */ + + switch( p->op ) { + + case ANDAND: + case OROR: + case QUEST: + markcall( p->right ); + case NOT: + constore( p->left ); + return; + + } + + store( p ); + } + +markcall( p ) register NODE *p; { /* mark off calls below the current node */ + + again: + switch( p->op ){ + + case UNARY CALL: + case UNARY STCALL: + case UNARY FORTCALL: + case CALL: + case STCALL: + case FORTCALL: + ++callflag; + return; + + } + + switch( optype( p->op ) ){ + + case BITYPE: + markcall( p->right ); + case UTYPE: + p = p->left; + /* eliminate recursion (aren't I clever...) */ + goto again; + case LTYPE: + return; + } + + } + +stoarg( p, calltype ) register NODE *p; { + /* arrange to store the args */ + + if( p->op == CM ){ + stoarg( p->left, calltype ); + p = p->right ; + } + if( calltype == CALL ){ + STOARG(p); + } + else if( calltype == STCALL ){ + STOSTARG(p); + } + else { + STOFARG(p); + } + callflag = 0; + store(p); +# ifndef NESTCALLS + if( callflag ){ /* prevent two calls from being active at once */ + SETSTO(p,INTEMP); + store(p); /* do again to preserve bottom up nature.... */ + } +#endif + } + +int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */ + +cbranch( p, true, false ) NODE *p; { + /* evaluate p for truth value, and branch to true or false + /* accordingly: label <0 means fall through */ + + register o, lab, flab, tlab; + + lab = -1; + + switch( o=p->op ){ + + case ULE: + case ULT: + case UGE: + case UGT: + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + if( true < 0 ){ + o = p->op = negrel[ o-EQ ]; + true = false; + false = -1; + } +#ifndef NOOPT + if( p->right->op == ICON && p->right->lval == 0 && p->right->name[0] == '\0' ){ + switch( o ){ + + case UGT: + case ULE: + o = p->op = (o==UGT)?NE:EQ; + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + if( logop(p->left->op) ){ + /* strange situation: e.g., (a!=0) == 0 */ + /* must prevent reference to p->left->lable, so get 0/1 */ + /* we could optimize, but why bother */ + codgen( p->left, INAREG|INBREG ); + } + codgen( p->left, FORCC ); + cbgen( o, true, 'I' ); + break; + + case UGE: + cbgen( 0, true, 'I' ); /* unconditional branch */ + case ULT: + ; /* do nothing for LT */ + } + } + else +#endif + { + p->label = true; + codgen( p, FORCC ); + } + if( false>=0 ) cbgen( 0, false, 'I' ); + reclaim( p, RNULL, 0 ); + return; + + case ANDAND: + lab = false<0 ? getlab() : false ; + cbranch( p->left, -1, lab ); + cbranch( p->right, true, false ); + if( false < 0 ) deflab( lab ); + p->op = FREE; + return; + + case OROR: + lab = true<0 ? getlab() : true; + cbranch( p->left, lab, -1 ); + cbranch( p->right, true, false ); + if( true < 0 ) deflab( lab ); + p->op = FREE; + return; + + case NOT: + cbranch( p->left, false, true ); + p->op = FREE; + break; + + case COMOP: + codgen( p->left, FOREFF ); + p->op = FREE; + cbranch( p->right, true, false ); + return; + + case QUEST: + flab = false<0 ? getlab() : false; + tlab = true<0 ? getlab() : true; + cbranch( p->left, -1, lab = getlab() ); + cbranch( p->right->left, tlab, flab ); + deflab( lab ); + cbranch( p->right->right, true, false ); + if( true < 0 ) deflab( tlab); + if( false < 0 ) deflab( flab ); + p->right->op = FREE; + p->op = FREE; + return; + + case ICON: + if( p->type != FLOAT && p->type != DOUBLE ){ + + if( p->lval || p->name[0] ){ + /* addresses of C objects are never 0 */ + if( true>=0 ) cbgen( 0, true, 'I' ); + } + else if( false>=0 ) cbgen( 0, false, 'I' ); + p->op = FREE; + return; + } + /* fall through to default with other strange constants */ + + default: + /* get condition codes */ + codgen( p, FORCC ); + if( true >= 0 ) cbgen( NE, true, 'I' ); + if( false >= 0 ) cbgen( true >= 0 ? 0 : EQ, false, 'I' ); + reclaim( p, RNULL, 0 ); + return; + + } + + } + +rcount(){ /* count recursions */ + if( ++nrecur > NRECUR ){ + cerror( "expression causes compiler loop: try simplifying" ); + } + + } + +eprint( p, down, a, b ) NODE *p; int *a, *b; { + + *a = *b = down+1; + while( down >= 2 ){ + printf( "\t" ); + down -= 2; + } + if( down-- ) printf( " " ); + + + printf( "%o) %s", p, opst[p->op] ); + switch( p->op ) { /* special cases */ + + case REG: + printf( " %s", rnames[p->rval] ); + break; + + case ICON: + case NAME: + case OREG: + printf( " " ); + adrput( p ); + break; + + case STCALL: + case UNARY STCALL: + case STARG: + case STASG: + printf( " size=%d", p->stsize ); + printf( " align=%d", p->stalign ); + break; + } + + printf( ", " ); + tprint( p->type ); + printf( ", " ); + if( p->rall == NOPREF ) printf( "NOPREF" ); + else { + if( p->rall & MUSTDO ) printf( "MUSTDO " ); + else printf( "PREF " ); + printf( "%s", rnames[p->rall&~MUSTDO]); + } + printf( ", SU= %d\n", p->su ); + + } + +# ifndef NOMAIN +NODE * +eread(){ + + /* call eread recursively to get subtrees, if any */ + + register NODE *p; + register i, c; + register char *pc; + register j; + + i = rdin( 10 ); + + p = talloc(); + + p->op = i; + + i = optype(i); + + if( i == LTYPE ) p->lval = rdin( 10 ); + if( i != BITYPE ) p->rval = rdin( 10 ); + + p->type = rdin(8 ); + p->rall = NOPREF; /* register allocation information */ + + if( p->op == STASG || p->op == STARG || p->op == STCALL || p->op == UNARY STCALL ){ + p->stsize = (rdin( 10 ) + (SZCHAR-1) )/SZCHAR; + p->stalign = rdin(10) / SZCHAR; + if( getchar() != '\n' ) cerror( "illegal \n" ); + } + else { /* usual case */ + if( p->op == REG ) rbusy( p->rval, p->type ); /* non usually, but sometimes justified */ + for( pc=p->name,j=0; ( c = getchar() ) != '\n'; ++j ){ + if( j < NCHNAM ) *pc++ = c; + } + if( j < NCHNAM ) *pc = '\0'; + } + + /* now, recursively read descendents, if any */ + + if( i != LTYPE ) p->left = eread(); + if( i == BITYPE ) p->right = eread(); + + return( p ); + + } + +CONSZ +rdin( base ){ + register sign, c; + CONSZ val; + + sign = 1; + val = 0; + + while( (c=getchar()) > 0 ) { + if( c == '-' ){ + if( val != 0 ) cerror( "illegal -"); + sign = -sign; + continue; + } + if( c == '\t' ) break; + if( c>='0' && c<='9' ) { + val *= base; + if( sign > 0 ) + val += c-'0'; + else + val -= c-'0'; + continue; + } + cerror( "illegal character `%c' on intermediate file", c ); + break; + } + + if( c <= 0 ) { + cerror( "unexpected EOF"); + } + return( val ); + } +# endif + +#ifndef FIELDOPS + /* do this if there is no special hardware support for fields */ + +ffld( p, down, down1, down2 ) NODE *p; int *down1, *down2; { + /* look for fields that are not in an lvalue context, and rewrite them... */ + register NODE *shp; + register s, o, v, ty; + + *down1 = asgop( p->op ); + *down2 = 0; + + if( !down && p->op == FLD ){ /* rewrite the node */ + + if( !rewfld(p) ) return; + + ty = (szty(p->type) == 2)? LONG: INT; + v = p->rval; + s = UPKFSZ(v); +# ifdef RTOLBYTES + o = UPKFOFF(v); /* amount to shift */ +# else + o = szty(p->type)*SZINT - s - UPKFOFF(v); /* amount to shift */ +#endif + + /* make & mask part */ + + p->left->type = ty; + + p->op = AND; + p->right = talloc(); + p->right->op = ICON; + p->right->rall = NOPREF; + p->right->type = ty; + p->right->lval = 1; + p->right->rval = 0; + p->right->name[0] = '\0'; + p->right->lval <<= s; + p->right->lval--; + + /* now, if a shift is needed, do it */ + + if( o != 0 ){ + shp = talloc(); + shp->op = RS; + shp->rall = NOPREF; + shp->type = ty; + shp->left = p->left; + shp->right = talloc(); + shp->right->op = ICON; + shp->right->rall = NOPREF; + shp->right->type = ty; + shp->right->rval = 0; + shp->right->lval = o; /* amount to shift */ + shp->right->name[0] = '\0'; + p->left = shp; + /* whew! */ + } + } + } +#endif + +oreg2( p ) register NODE *p; { + + /* look for situations where we can turn * into OREG */ + + NODE *q; + register i; + register r; + register char *cp; + register NODE *ql, *qr; + CONSZ temp; + + if( p->op == UNARY MUL ){ + q = p->left; + if( q->op == REG ){ + temp = q->lval; + r = q->rval; + cp = q->name; + goto ormake; + } + + if( q->op != PLUS && q->op != MINUS ) return; + ql = q->left; + qr = q->right; + +#ifdef R2REGS + + /* look for doubly indexed expressions */ + + if( q->op==PLUS && qr->op==REG && ql->op==REG && + (szty(ql->type)==1||szty(qr->type)==1) ) { + temp = 0; + cp = ql->name; + if( *cp ){ + if( *qr->name ) return; + } + else { + cp = qr->name; + } + if( szty(qr->type)>1) r = R2PACK(qr->rval,ql->rval); + else r = R2PACK(ql->rval,qr->rval); + goto ormake; + } + + if( (q->op==PLUS||q->op==MINUS) && qr->op==ICON && ql->op==PLUS && + ql->left->op==REG && + ql->right->op==REG ){ + temp = qr->lval; + cp = qr->name; + if( q->op == MINUS ){ + if( *cp ) return; + temp = -temp; + } + if( *cp ){ + if( *ql->name ) return; + } + else { + cp = ql->name; + } + r = R2PACK(ql->left->rval,ql->right->rval); + goto ormake; + } + +#endif + + if( (q->op==PLUS || q->op==MINUS) && qr->op == ICON && + ql->op==REG && szty(qr->type)==1) { + temp = qr->lval; + if( q->op == MINUS ) temp = -temp; + r = ql->rval; + temp += ql->lval; + cp = qr->name; + if( *cp && ( q->op == MINUS || *ql->name ) ) return; + if( !*cp ) cp = ql->name; + + ormake: + if( notoff( p->type, r, temp, cp ) ) return; + p->op = OREG; + p->rval = r; + p->lval = temp; + for( i=0; iname[i] = *cp++; + tfree(q); + return; + } + } + + } + +canon(p) NODE *p; { + /* put p in canonical form */ + int oreg2(), sucomp(); + +#ifndef FIELDOPS + int ffld(); + fwalk( p, ffld, 0 ); /* look for field operators */ +# endif + walkf( p, oreg2 ); /* look for and create OREG nodes */ +#ifdef MYCANON + MYCANON(p); /* your own canonicalization routine(s) */ +#endif + walkf( p, sucomp ); /* do the Sethi-Ullman computation */ + + } + diff --git a/usr/src/cmd/mip/trees.c b/usr/src/cmd/mip/trees.c new file mode 100644 index 0000000000..755d0297c4 --- /dev/null +++ b/usr/src/cmd/mip/trees.c @@ -0,0 +1,1388 @@ +# include "mfile1" + +/* some special actions, used in finding the type of nodes */ +# define NCVT 01 +# define PUN 02 +# define TYPL 04 +# define TYPR 010 +# define TYMATCH 040 +# define LVAL 0100 +# define CVTO 0200 +# define CVTL 0400 +# define CVTR 01000 +# define PTMATCH 02000 +# define OTHER 04000 +# define NCVTR 010000 + +/* node conventions: + + NAME: rval>0 is stab index for external + rval<0 is -inlabel number + lval is offset in bits + ICON: lval has the value + rval has the STAB index, or - label number, + if a name whose address is in the constant + rval = NONAME means no name + REG: rval is reg. identification cookie + + */ + +int bdebug = 0; + +NODE * +buildtree( o, l, r ) register NODE *l, *r; { + register NODE *p, *q; + register actions; + register opty; + register struct symtab *sp; + register NODE *lr, *ll; + int i; + extern int eprint(); + + if( bdebug ) printf( "buildtree( %s, %o, %o )\n", opst[o], l, r ); + opty = optype(o); + + /* check for constants */ + + if( opty == UTYPE && l->op == ICON ){ + + switch( o ){ + + case NOT: + if( hflag ) werror( "constant argument to NOT" ); + case UNARY MINUS: + case COMPL: + if( conval( l, o, l ) ) return(l); + break; + + } + } + + else if( o==UNARY MINUS && l->op==FCON ){ + l->dval = -l->dval; + return(l); + } + + else if( o==QUEST && l->op==ICON ) { + l->op = FREE; + r->op = FREE; + if( l->lval ){ + tfree( r->right ); + return( r->left ); + } + else { + tfree( r->left ); + return( r->right ); + } + } + + else if( (o==ANDAND || o==OROR) && (l->op==ICON||r->op==ICON) ) goto ccwarn; + + else if( opty == BITYPE && l->op == ICON && r->op == ICON ){ + + switch( o ){ + + case ULT: + case UGT: + case ULE: + case UGE: + case LT: + case GT: + case LE: + case GE: + case EQ: + case NE: + case ANDAND: + case OROR: + case CBRANCH: + + ccwarn: + if( hflag ) werror( "constant in conditional context" ); + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + case AND: + case OR: + case ER: + case LS: + case RS: + if( conval( l, o, r ) ) { + r->op = FREE; + return(l); + } + break; + } + } + + else if( opty == BITYPE && (l->op==FCON||l->op==ICON) && + (r->op==FCON||r->op==ICON) ){ + switch(o){ + case PLUS: + case MINUS: + case MUL: + case DIV: + if( l->op == ICON ){ + l->dval = l->lval; + } + if( r->op == ICON ){ + r->dval = r->lval; + } + l->op = FCON; + l->type = l->csiz = DOUBLE; + r->op = FREE; + switch(o){ + case PLUS: + l->dval += r->dval; + return(l); + case MINUS: + l->dval -= r->dval; + return(l); + case MUL: + l->dval *= r->dval; + return(l); + case DIV: + if( r->dval == 0 ) uerror( "division by 0." ); + else l->dval /= r->dval; + return(l); + } + } + } + + /* its real; we must make a new node */ + + p = block( o, l, r, INT, 0, INT ); + + actions = opact(p); + + if( actions&LVAL ){ /* check left descendent */ + if( notlval(p->left) ) { + uerror( "lvalue required" ); + } + } + + if( actions & NCVTR ){ + p->left = pconvert( p->left ); + } + else if( !(actions & NCVT ) ){ + switch( opty ){ + + case BITYPE: + p->right = pconvert( p->right ); + case UTYPE: + p->left = pconvert( p->left ); + + } + } + + if( (actions&PUN) && (o!=CAST||cflag) ){ + chkpun(p); + } + + if( actions & (TYPL|TYPR) ){ + + q = (actions&TYPL) ? p->left : p->right; + + p->type = q->type; + p->cdim = q->cdim; + p->csiz = q->csiz; + } + + if( actions & CVTL ) p = convert( p, CVTL ); + if( actions & CVTR ) p = convert( p, CVTR ); + if( actions & TYMATCH ) p = tymatch(p); + if( actions & PTMATCH ) p = ptmatch(p); + + if( actions & OTHER ){ + l = p->left; + r = p->right; + + switch(o){ + + case NAME: + sp = &stab[idname]; + if( sp->stype == UNDEF ){ + uerror( "%.8s undefined", sp->sname ); + /* make p look reasonable */ + p->type = p->cdim = p->csiz = INT; + p->rval = idname; + p->lval = 0; + defid( p, SNULL ); + break; + } + p->type = sp->stype; + p->cdim = sp->dimoff; + p->csiz = sp->sizoff; + p->lval = 0; + p->rval = idname; + /* special case: MOETY is really an ICON... */ + if( p->type == MOETY ){ + p->rval = NONAME; + p->lval = sp->offset; + p->cdim = 0; + p->type = ENUMTY; + p->op = ICON; + } + break; + + case ICON: + p->type = INT; + p->cdim = 0; + p->csiz = INT; + break; + + case STRING: + p->op = NAME; + p->type = CHAR+ARY; + p->lval = 0; + p->rval = NOLAB; + p->cdim = curdim; + p->csiz = CHAR; + break; + + case FCON: + p->lval = 0; + p->rval = 0; + p->type = DOUBLE; + p->cdim = 0; + p->csiz = DOUBLE; + break; + + case STREF: + /* p->x turned into *(p+offset) */ + /* rhs must be a name; check correctness */ + + i = r->rval; + if( i<0 || ((sp= &stab[i])->sclass != MOS && sp->sclass != MOU && !(sp->sclass&FIELD)) ){ + uerror( "member of structure or union required" ); + } + else { + register j; + if( l->type != PTR+STRTY && l->type != PTR+UNIONTY ){ + werror( "struct/union or struct/union pointer required" ); + } + else if( (j=l->csiz+1)<0 ) cerror( "undefined structure or union" ); + else if( !chkstr( i, dimtab[j], DECREF(l->type) ) ){ + werror( "illegal member use: %.8s", stab[i].sname ); + } + } + + p = stref( p ); + break; + + case UNARY MUL: + if( l->op == UNARY AND ){ + p->op = l->op = FREE; + p = l->left; + } + if( !ISPTR(l->type))uerror("illegal indirection"); + p->type = DECREF(l->type); + p->cdim = l->cdim; + p->csiz = l->csiz; + break; + + case UNARY AND: + switch( l->op ){ + + case UNARY MUL: + p->op = l->op = FREE; + p = l->left; + case NAME: + p->type = INCREF( l->type ); + p->cdim = l->cdim; + p->csiz = l->csiz; + break; + + case COMOP: + lr = buildtree( UNARY AND, l->right, NIL ); + p->op = l->op = FREE; + p = buildtree( COMOP, l->left, lr ); + break; + + case QUEST: + lr = buildtree( UNARY AND, l->right->right, NIL ); + ll = buildtree( UNARY AND, l->right->left, NIL ); + p->op = l->op = l->right->op = FREE; + p = buildtree( QUEST, l->left, buildtree( COLON, ll, lr ) ); + break; + + default: + uerror( "unacceptable operand of &" ); + break; + } + break; + + case LS: + case RS: + case ASG LS: + case ASG RS: + if(tsize(p->right->type, p->right->cdim, p->right->csiz) > SZINT) + p->right = makety(p->right, INT, 0, INT ); + break; + + case RETURN: + case ASSIGN: + case CAST: + /* structure assignment */ + /* take the addresses of the two sides; then make an + /* operator using STASG and + /* the addresses of left and right */ + + { + register TWORD t; + register d, s; + + if( l->csiz != r->csiz ) uerror( "assignment of different structures" ); + + r = buildtree( UNARY AND, r, NIL ); + t = r->type; + d = r->cdim; + s = r->csiz; + + l = block( STASG, l, r, t, d, s ); + + if( o == RETURN ){ + p->op = FREE; + p = l; + break; + } + + p->op = UNARY MUL; + p->left = l; + p->right = NIL; + break; + } + case COLON: + /* structure colon */ + + if( l->csiz != r->csiz ) uerror( "type clash in conditional" ); + break; + + case CALL: + p->right = r = strargs( p->right ); + case UNARY CALL: + if( !ISPTR(l->type)) uerror("illegal function"); + p->type = DECREF(l->type); + if( !ISFTN(p->type)) uerror("illegal function"); + p->type = DECREF( p->type ); + p->cdim = l->cdim; + p->csiz = l->csiz; + if( l->op == UNARY AND && l->left->op == NAME && + l->left->rval >= 0 && l->left->rval != NONAME && + ( (i=stab[l->left->rval].sclass) == FORTRAN || i==UFORTRAN ) ){ + p->op += (FORTCALL-CALL); + } + if( p->type == STRTY || p->type == UNIONTY ){ + /* function returning structure */ + /* make function really return ptr to str., with * */ + + p->op += STCALL-CALL; + p->type = INCREF( p->type ); + p = buildtree( UNARY MUL, p, NIL ); + + } + break; + + default: + cerror( "other code %d", o ); + } + + } + + if( actions & CVTO ) p = oconvert(p); + p = clocal(p); + + if( bdebug ) fwalk( p, eprint, 0 ); + + return(p); + + } + +NODE * +strargs( p ) register NODE *p; { /* rewrite structure flavored arguments */ + + if( p->op == CM ){ + p->left = strargs( p->left ); + p->right = strargs( p->right ); + return( p ); + } + + if( p->type == STRTY || p->type == UNIONTY ){ + p = block( STARG, p, NIL, p->type, p->cdim, p->csiz ); + p->left = buildtree( UNARY AND, p->left, NIL ); + p = clocal(p); + } + return( p ); + } + +chkstr( i, j, type ) TWORD type; { + /* is the MOS or MOU at stab[i] OK for strict reference by a ptr */ + /* i has been checked to contain a MOS or MOU */ + /* j is the index in dimtab of the members... */ + int k, kk; + + extern int ddebug; + + if( ddebug > 1 ) printf( "chkstr( %.8s(%d), %d )\n", stab[i].sname, i, j ); + if( (k = j) < 0 ) uerror( "undefined structure or union" ); + else { + for( ; (kk = dimtab[k] ) >= 0; ++k ){ + if( kk >= SYMTSZ ){ + cerror( "gummy structure" ); + return(1); + } + if( kk == i ) return( 1 ); + switch( stab[kk].stype ){ + + case STRTY: + case UNIONTY: + if( type == STRTY ) continue; /* no recursive looking for strs */ + if( chkstr( i, dimtab[stab[kk].sizoff+1], stab[kk].stype ) ) return(1); + } + } + } + return( 0 ); + } + +conval( p, o, q ) register NODE *p, *q; { + /* apply the op o to the lval part of p; if binary, rhs is val */ + int i, u; + CONSZ val; + + val = q->lval; + u = ISUNSIGNED(p->type) || ISUNSIGNED(q->type); + if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); + + if( p->rval != NONAME && q->rval != NONAME ) return(0); + if( q->rval != NONAME && o!=PLUS ) return(0); + if( p->rval != NONAME && o!=PLUS && o!=MINUS ) return(0); + + switch( o ){ + + case PLUS: + p->lval += val; + if( p->rval == NONAME ){ + p->rval = q->rval; + p->type = q->type; + } + break; + case MINUS: + p->lval -= val; + break; + case MUL: + p->lval *= val; + break; + case DIV: + if( val == 0 ) uerror( "division by 0" ); + else p->lval /= val; + break; + case MOD: + if( val == 0 ) uerror( "division by 0" ); + else p->lval %= val; + break; + case AND: + p->lval &= val; + break; + case OR: + p->lval |= val; + break; + case ER: + p->lval ^= val; + break; + case LS: + i = val; + p->lval = p->lval << i; + break; + case RS: + i = val; + p->lval = p->lval >> i; + break; + + case UNARY MINUS: + p->lval = - p->lval; + break; + case COMPL: + p->lval = ~p->lval; + break; + case NOT: + p->lval = !p->lval; + break; + case LT: + p->lval = p->lval < val; + break; + case LE: + p->lval = p->lval <= val; + break; + case GT: + p->lval = p->lval > val; + break; + case GE: + p->lval = p->lval >= val; + break; + case ULT: + p->lval = (p->lval-val)<0; + break; + case ULE: + p->lval = (p->lval-val)<=0; + break; + case UGE: + p->lval = (p->lval-val)>=0; + break; + case UGT: + p->lval = (p->lval-val)>0; + break; + case EQ: + p->lval = p->lval == val; + break; + case NE: + p->lval = p->lval != val; + break; + default: + return(0); + } + return(1); + } + +chkpun(p) register NODE *p; { + + /* checks p for the existance of a pun */ + + /* this is called when the op of p is ASSIGN, RETURN, CAST, COLON, or relational */ + + /* one case is when enumerations are used: this applies only to lint */ + /* in the other case, one operand is a pointer, the other integer type */ + /* we check that this integer is in fact a constant zero... */ + + /* in the case of ASSIGN, any assignment of pointer to integer is illegal */ + /* this falls out, because the LHS is never 0 */ + + register NODE *q; + register t1, t2; + register d1, d2; + + t1 = p->left->type; + t2 = p->right->type; + + if( t1==ENUMTY || t2==ENUMTY ) { /* check for enumerations */ + if( logop( p->op ) && p->op != EQ && p->op != NE ) { + uerror( "illegal comparison of enums" ); + return; + } + if( t1==ENUMTY && t2==ENUMTY && p->left->csiz==p->right->csiz ) return; + werror( "enumeration type clash, operator %s", opst[p->op] ); + return; + } + + if( ISPTR(t1) || ISARY(t1) ) q = p->right; + else q = p->left; + + if( !ISPTR(q->type) && !ISARY(q->type) ){ + if( q->op != ICON || q->lval != 0 ){ + werror( "illegal combination of pointer and integer"); + } + } + else { + d1 = p->left->cdim; + d2 = p->right->cdim; + for( ;; ){ + if( t1 == t2 ) {; + if( p->left->csiz != p->right->csiz ) { + werror( "illegal structure pointer combination" ); + } + return; + } + if( ISARY(t1) || ISPTR(t1) ){ + if( !ISARY(t2) && !ISPTR(t2) ) break; + if( ISARY(t1) && ISARY(t2) && dimtab[d1] != dimtab[d2] ){ + werror( "illegal array size combination" ); + return; + } + if( ISARY(t1) ) ++d1; + if( ISARY(t2) ) ++d2; + } + else break; + t1 = DECREF(t1); + t2 = DECREF(t2); + } + werror( "illegal pointer combination" ); + } + + } + +NODE * +stref( p ) register NODE *p; { + + TWORD t; + int d, s, dsc; + OFFSZ off; + register struct symtab *q; + + /* make p->x */ + /* this is also used to reference automatic variables */ + + q = &stab[p->right->rval]; + p->right->op = FREE; + p->op = FREE; + p = pconvert( p->left ); + + /* make p look like ptr to x */ + + if( !ISPTR(p->type)){ + p->type = PTR+UNIONTY; + } + + t = INCREF( q->stype ); + d = q->dimoff; + s = q->sizoff; + + p = makety( p, t, d, s ); + + /* compute the offset to be added */ + + off = q->offset; + dsc = q->sclass; + + if( dsc & FIELD ){ /* make fields look like ints */ + off = (off/ALINT)*ALINT; + s = INT; + } + if( off != 0 ) p = clocal( block( PLUS, p, offcon( off, t, d, s ), t, d, s ) ); + + p = buildtree( UNARY MUL, p, NIL ); + + /* if field, build field info */ + + if( dsc & FIELD ){ + p = block( FLD, p, NIL, q->stype, 0, q->sizoff ); + p->rval = PKFIELD( dsc&FLDSIZ, q->offset%ALINT ); + } + + return( clocal(p) ); + } + +notlval(p) register NODE *p; { + + /* return 0 if p an lvalue, 1 otherwise */ + + again: + + switch( p->op ){ + + case FLD: + p = p->left; + goto again; + + case NAME: + case OREG: + case UNARY MUL: + if( ISARY(p->type) || ISFTN(p->type) ) return(1); + case REG: + return(0); + + default: + return(1); + + } + + } + +NODE * +bcon( i ){ /* make a constant node with value i */ + register NODE *p; + + p = block( ICON, NIL, NIL, INT, 0, INT ); + p->lval = i; + p->rval = NONAME; + return( clocal(p) ); + } + +NODE * +bpsize(p) register NODE *p; { + return( offcon( psize(p), p->type, p->cdim, p->csiz ) ); + } + +OFFSZ +psize( p ) NODE *p; { + /* p is a node of type pointer; psize returns the + size of the thing pointed to */ + + if( !ISPTR(p->type) ){ + uerror( "pointer required"); + return( SZINT ); + } + /* note: no pointers to fields */ + return( tsize( DECREF(p->type), p->cdim, p->csiz ) ); + } + +NODE * +convert( p, f ) register NODE *p; { + /* convert an operand of p + f is either CVTL or CVTR + operand has type int, and is converted by the size of the other side + */ + + register NODE *q, *r; + + q = (f==CVTL)?p->left:p->right; + + r = block( PMCONV, + q, bpsize(f==CVTL?p->right:p->left), INT, 0, INT ); + r = clocal(r); + if( f == CVTL ) + p->left = r; + else + p->right = r; + return(p); + + } + +econvert( p ) register NODE *p; { + + /* change enums to ints, or appropriate types */ + + register TWORD ty; + + if( (ty=BTYPE(p->type)) == ENUMTY || ty == MOETY ) { + if( dimtab[ p->csiz ] == SZCHAR ) ty = CHAR; + else if( dimtab[ p->csiz ] == SZINT ) ty = INT; + else if( dimtab[ p->csiz ] == SZSHORT ) ty = SHORT; + else ty = LONG; + ty = ctype( ty ); + p->csiz = ty; + MODTYPE(p->type,ty); + if( p->op == ICON && ty != LONG ) p->type = p->csiz = INT; + } + } + +NODE * +pconvert( p ) register NODE *p; { + + /* if p should be changed into a pointer, do so */ + + if( ISARY( p->type) ){ + p->type = DECREF( p->type ); + ++p->cdim; + return( buildtree( UNARY AND, p, NIL ) ); + } + if( ISFTN( p->type) ) + return( buildtree( UNARY AND, p, NIL ) ); + + return( p ); + } + +NODE * +oconvert(p) register NODE *p; { + /* convert the result itself: used for pointer and unsigned */ + + switch(p->op) { + + case LE: + case LT: + case GE: + case GT: + if( ISUNSIGNED(p->left->type) || ISUNSIGNED(p->right->type) ) p->op += (ULE-LE); + case EQ: + case NE: + return( p ); + + case MINUS: + return( clocal( block( PVCONV, + p, bpsize(p->left), INT, 0, INT ) ) ); + } + + cerror( "illegal oconvert: %d", p->op ); + + return(p); + } + +NODE * +ptmatch(p) register NODE *p; { + + /* makes the operands of p agree; they are + either pointers or integers, by this time */ + /* with MINUS, the sizes must be the same */ + /* with COLON, the types must be the same */ + + TWORD t1, t2, t; + int o, d2, d, s2, s; + + o = p->op; + t = t1 = p->left->type; + t2 = p->right->type; + d = p->left->cdim; + d2 = p->right->cdim; + s = p->left->csiz; + s2 = p->right->csiz; + + switch( o ){ + + case ASSIGN: + case RETURN: + case CAST: + { break; } + + case MINUS: + { if( psize(p->left) != psize(p->right) ){ + uerror( "illegal pointer subtraction"); + } + break; + } + case COLON: + { if( t1 != t2 ) uerror( "illegal types in :"); + break; + } + default: /* must work harder: relationals or comparisons */ + + if( !ISPTR(t1) ){ + t = t2; + d = d2; + s = s2; + break; + } + if( !ISPTR(t2) ){ + break; + } + + /* both are pointers */ + if( talign(t2,s2) < talign(t,s) ){ + t = t2; + s = s2; + } + break; + } + + p->left = makety( p->left, t, d, s ); + p->right = makety( p->right, t, d, s ); + if( o!=MINUS && !logop(o) ){ + + p->type = t; + p->cdim = d; + p->csiz = s; + } + + return(clocal(p)); + } + +int tdebug = 0; + +NODE * +tymatch(p) register NODE *p; { + + /* satisfy the types of various arithmetic binary ops */ + + /* rules are: + if assignment, op, type of LHS + if any float or doubles, make double + if any longs, make long + otherwise, make int + if either operand is unsigned, the result is... + */ + + register TWORD t1, t2, t, tu; + register o, u; + + o = p->op; + + t1 = p->left->type; + t2 = p->right->type; + + u = 0; + if( ISUNSIGNED(t1) ){ + u = 1; + t1 = DEUNSIGN(t1); + } + if( ISUNSIGNED(t2) ){ + u = 1; + t2 = DEUNSIGN(t2); + } + + if( ( t1 == CHAR || t1 == SHORT ) && o!= RETURN ) t1 = INT; + if( t2 == CHAR || t2 == SHORT ) t2 = INT; + + if( t1==DOUBLE || t1==FLOAT || t2==DOUBLE || t2==FLOAT ) t = DOUBLE; + else if( t1==LONG || t2==LONG ) t = LONG; + else t = INT; + + if( asgop(o) ){ + tu = p->left->type; + t = t1; + } + else { + tu = (u && UNSIGNABLE(t))?ENUNSIGN(t):t; + } + + /* because expressions have values that are at least as wide + as INT or UNSIGNED, the only conversions needed + are those involving FLOAT/DOUBLE, and those + from LONG to INT and ULONG to UNSIGNED */ + + if( t != t1 ) p->left = makety( p->left, tu, 0, (int)tu ); + + if( t != t2 || o==CAST ) p->right = makety( p->right, tu, 0, (int)tu ); + + if( asgop(o) ){ + p->type = p->left->type; + p->cdim = p->left->cdim; + p->csiz = p->left->csiz; + } + else if( !logop(o) ){ + p->type = tu; + p->cdim = 0; + p->csiz = t; + } + + if( tdebug ) printf( "tymatch(%o): %o %s %o => %o\n",p,t1,opst[o],t2,tu ); + + return(p); + } + +NODE * +makety( p, t, d, s ) register NODE *p; TWORD t; { + /* make p into type t by inserting a conversion */ + + if( p->type == ENUMTY && p->op == ICON ) econvert(p); + if( t == p->type ){ + p->cdim = d; + p->csiz = s; + return( p ); + } + + if( t & TMASK ){ + /* non-simple type */ + return( block( PCONV, p, NIL, t, d, s ) ); + } + + if( p->op == ICON ){ + if( t==DOUBLE||t==FLOAT ){ + p->op = FCON; + if( ISUNSIGNED(p->type) ){ + p->dval = /* (unsigned CONSZ) */ p->lval; + } + else { + p->dval = p->lval; + } + + p->type = p->csiz = t; + return( clocal(p) ); + } + } + + return( block( SCONV, p, NIL, t, d, s ) ); + + } + +NODE * +block( o, l, r, t, d, s ) register NODE *l, *r; TWORD t; { + + register NODE *p; + + p = talloc(); + p->op = o; + p->left = l; + p->right = r; + p->type = t; + p->cdim = d; + p->csiz = s; + return(p); + } + +icons(p) register NODE *p; { + /* if p is an integer constant, return its value */ + int val; + + if( p->op != ICON ){ + uerror( "constant expected"); + val = 1; + } + else { + val = p->lval; + if( val != p->lval ) uerror( "constant too big for cross-compiler" ); + } + tfree( p ); + return(val); + } + +/* the intent of this table is to examine the + operators, and to check them for + correctness. + + The table is searched for the op and the + modified type (where this is one of the + types INT (includes char and short), LONG, + DOUBLE (includes FLOAT), and POINTER + + The default action is to make the node type integer + + The actions taken include: + PUN check for puns + CVTL convert the left operand + CVTR convert the right operand + TYPL the type is determined by the left operand + TYPR the type is determined by the right operand + TYMATCH force type of left and right to match, by inserting conversions + PTMATCH like TYMATCH, but for pointers + LVAL left operand must be lval + CVTO convert the op + NCVT do not convert the operands + OTHER handled by code + NCVTR convert the left operand, not the right... + + */ + +# define MINT 01 /* integer */ +# define MDBI 02 /* integer or double */ +# define MSTR 04 /* structure */ +# define MPTR 010 /* pointer */ +# define MPTI 020 /* pointer or integer */ +# define MENU 040 /* enumeration variable or member */ + +opact( p ) NODE *p; { + + register mt12, mt1, mt2, o; + + mt12 = 0; + + switch( optype(o=p->op) ){ + + case BITYPE: + mt12=mt2 = moditype( p->right->type ); + case UTYPE: + mt12 &= (mt1 = moditype( p->left->type )); + + } + + switch( o ){ + + case NAME : + case STRING : + case ICON : + case FCON : + case CALL : + case UNARY CALL: + case UNARY MUL: + { return( OTHER ); } + case UNARY MINUS: + if( mt1 & MDBI ) return( TYPL ); + break; + + case COMPL: + if( mt1 & MINT ) return( TYPL ); + break; + + case UNARY AND: + { return( NCVT+OTHER ); } + case INIT: + case CM: + case NOT: + case CBRANCH: + case ANDAND: + case OROR: + return( 0 ); + + case MUL: + case DIV: + if( mt12 & MDBI ) return( TYMATCH ); + break; + + case MOD: + case AND: + case OR: + case ER: + if( mt12 & MINT ) return( TYMATCH ); + break; + + case LS: + case RS: + if( mt12 & MINT ) return( TYPL+OTHER ); + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + if( (mt1&MENU)||(mt2&MENU) ) return( PTMATCH+PUN+NCVT ); + if( mt12 & MDBI ) return( TYMATCH+CVTO ); + else if( mt12 & MPTR ) return( PTMATCH+PUN ); + else if( mt12 & MPTI ) return( PTMATCH+PUN ); + else break; + + case QUEST: + case COMOP: + if( mt2&MENU ) return( TYPR+NCVTR ); + return( TYPR ); + + case STREF: + return( NCVT+OTHER ); + + case FORCE: + return( TYPL ); + + case COLON: + if( mt12 & MENU ) return( NCVT+PUN+PTMATCH ); + else if( mt12 & MDBI ) return( TYMATCH ); + else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); + else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); + else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); + break; + + case ASSIGN: + case RETURN: + if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); + case CAST: + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); + else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); + else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; + + case ASG LS: + case ASG RS: + if( mt12 & MINT ) return( TYPL+LVAL+OTHER ); + break; + + case ASG MUL: + case ASG DIV: + if( mt12 & MDBI ) return( LVAL+TYMATCH ); + break; + + case ASG MOD: + case ASG AND: + case ASG OR: + case ASG ER: + if( mt12 & MINT ) return( LVAL+TYMATCH ); + break; + + case ASG PLUS: + case ASG MINUS: + case INCR: + case DECR: + if( mt12 & MDBI ) return( TYMATCH+LVAL ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+LVAL+CVTR ); + break; + + case MINUS: + if( mt12 & MPTR ) return( CVTO+PTMATCH+PUN ); + if( mt2 & MPTR ) break; + case PLUS: + if( mt12 & MDBI ) return( TYMATCH ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+CVTR ); + else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+CVTL ); + + } + uerror( "operands of %s have incompatible types", opst[o] ); + return( NCVT ); + } + +moditype( ty ) TWORD ty; { + + switch( ty ){ + + case ENUMTY: + case MOETY: + return( MENU ); + + case STRTY: + case UNIONTY: + return( MSTR ); + + case CHAR: + case SHORT: + case UCHAR: + case USHORT: + return( MINT|MDBI ); + case UNSIGNED: + case ULONG: + case INT: + case LONG: + return( MINT|MDBI|MPTI ); + case FLOAT: + case DOUBLE: + return( MDBI ); + default: + return( MPTR|MPTI ); + + } + } + +NODE * +doszof( p ) register NODE *p; { + /* do sizeof p */ + int i; + + /* whatever is the meaning of this if it is a bitfield? */ + i = tsize( p->type, p->cdim, p->csiz )/SZCHAR; + + tfree(p); + if( i <= 0 ) werror( "sizeof returns 0" ); + return( bcon( i ) ); + } + +eprint( p, down, a, b ) register NODE *p; int *a, *b; { + register ty; + + *a = *b = down+1; + while( down > 1 ){ + printf( "\t" ); + down -= 2; + } + if( down ) printf( " " ); + + ty = optype( p->op ); + + printf("%o) %s, ", p, opst[p->op] ); + if( ty == LTYPE ){ + printf( CONFMT, p->lval ); + printf( ", %d, ", p->rval ); + } + tprint( p->type ); + printf( ", %d, %d\n", p->cdim, p->csiz ); + } + +prtdcon( p ) register NODE *p; { + int i; + + if( p->op == FCON ){ + locctr( DATA ); + defalign( ALDOUBLE ); + deflab( i = getlab() ); + fincode( p->dval, SZDOUBLE ); + p->lval = 0; + p->rval = -i; + p->type = DOUBLE; + p->op = NAME; + } + } + + +int edebug = 0; +ecomp( p ) register NODE *p; { + if( edebug ) fwalk( p, eprint, 0 ); + if( !reached ){ + werror( "statement not reached" ); + reached = 1; + } + p = optim(p); + walkf( p, prtdcon ); + locctr( PROG ); + ecode( p ); + tfree(p); + } + +# ifdef STDPRTREE +# ifndef ONEPASS + +prtree(p) register NODE *p; { + + register struct symtab *q; + register ty; + +# ifdef MYPRTREE + MYPRTREE(p); /* local action can be taken here; then return... */ +#endif + + ty = optype(p->op); + + printf( "%d\t", p->op ); + + if( ty == LTYPE ) { + printf( CONFMT, p->lval ); + printf( "\t" ); + } + if( ty != BITYPE ) { + if( p->op == NAME || p->op == ICON ) printf( "0\t" ); + else printf( "%d\t", p->rval ); + } + + printf( "%o\t", p->type ); + + /* handle special cases */ + + switch( p->op ){ + + case NAME: + case ICON: + /* print external name */ + if( p->rval == NONAME ) printf( "\n" ); + else if( p->rval >= 0 ){ + q = &stab[p->rval]; + printf( "%s\n", exname(q->sname) ); + } + else { /* label */ + printf( LABFMT, -p->rval ); + } + break; + + case STARG: + case STASG: + case STCALL: + case UNARY STCALL: + /* print out size */ + /* use lhs size, in order to avoid hassles with the structure `.' operator */ + + /* note: p->left not a field... */ + printf( CONFMT, (CONSZ) tsize( STRTY, p->left->cdim, p->left->csiz ) ); + printf( "\t%d\t\n", talign( STRTY, p->left->csiz ) ); + break; + + default: + printf( "\n" ); + } + + if( ty != LTYPE ) prtree( p->left ); + if( ty == BITYPE ) prtree( p->right ); + + } + +# else + +p2tree(p) register NODE *p; { + register ty; + +# ifdef MYP2TREE + MYP2TREE(p); /* local action can be taken here; then return... */ +# endif + + ty = optype(p->op); + + switch( p->op ){ + + case NAME: + case ICON: + if( p->rval == NONAME ) p->name[0] = '\0'; + else if( p->rval >= 0 ){ /* copy name from exname */ + register char *cp; + register i; + cp = exname( stab[p->rval].sname ); + for( i=0; iname[i] = *cp++; + } + else sprintf( p->name, LABFMT, -p->rval ); + break; + + case STARG: + case STASG: + case STCALL: + case UNARY STCALL: + /* set up size parameters */ + p->stsize = (tsize(STRTY,p->left->cdim,p->left->csiz)+SZCHAR-1)/SZCHAR; + p->stalign = talign(STRTY,p->left->csiz)/SZCHAR; + break; + + case REG: + rbusy( p->rval, p->type ); + default: + p->name[0] = '\0'; + } + + p->rall = NOPREF; + + if( ty != LTYPE ) p2tree( p->left ); + if( ty == BITYPE ) p2tree( p->right ); + } + +# endif +# endif diff --git a/usr/src/cmd/mip/xdefs.c b/usr/src/cmd/mip/xdefs.c new file mode 100644 index 0000000000..61caff7fd6 --- /dev/null +++ b/usr/src/cmd/mip/xdefs.c @@ -0,0 +1,99 @@ +# include "mfile1" + +/* communication between lexical routines */ + +char ftitle[100] = ""; /* title of the file */ +int lineno; /* line number of the input file */ + +CONSZ lastcon; /* the last constant read by the lexical analyzer */ +double dcon; /* the last double read by the lexical analyzer */ + + +/* symbol table maintainence */ + +struct symtab stab[SYMTSZ+1]; /* one extra slot for scratch */ + +int curftn; /* "current" function */ +int ftnno; /* "current" function number */ + +int curclass, /* current storage class */ + instruct, /* "in structure" flag */ + stwart, /* for accessing names which are structure members or names */ + blevel, /* block level: 0 for extern, 1 for ftn args, >=2 inside function */ + curdim; /* current offset into the dimension table */ + +int dimtab[ DIMTABSZ ]; + +int paramstk[ PARAMSZ ]; /* used in the definition of function parameters */ +int paramno; /* the number of parameters */ +int autooff, /* the next unused automatic offset */ + argoff, /* the next unused argument offset */ + strucoff; /* the next structure offset position */ +int regvar; /* the next free register for register variables */ +int minrvar; /* the smallest that regvar gets witing a function */ +OFFSZ inoff; /* offset of external element being initialized */ +int brkflag = 0; /* complain about break statements not reached */ + +struct sw swtab[SWITSZ]; /* table for cases within a switch */ +struct sw *swp; /* pointer to next free entry in swtab */ +int swx; /* index of beginning of cases for current switch */ + +/* debugging flag */ +int xdebug = 0; + +int strflg; /* if on, strings are to be treated as lists */ + +int reached; /* true if statement can be reached... */ + +int idname; /* tunnel to buildtree for name id's */ + + +NODE node[TREESZ]; + +int cflag = 0; /* do we check for funny casts */ +int hflag = 0; /* do we check for various heuristics which may indicate errors */ +int pflag = 0; /* do we check for portable constructions */ + +int brklab; +int contlab; +int flostat; +int retlab = NOLAB; +int retstat; + +/* save array for break, continue labels, and flostat */ + +int asavbc[BCSZ]; +int *psavbc = asavbc ; + +static char * +ccnames[] = { /* names of storage classes */ + "SNULL", + "AUTO", + "EXTERN", + "STATIC", + "REGISTER", + "EXTDEF", + "LABEL", + "ULABEL", + "MOS", + "PARAM", + "STNAME", + "MOU", + "UNAME", + "TYPEDEF", + "FORTRAN", + "ENAME", + "MOE", + "UFORTRAN", + "USTATIC", + }; + +char * scnames( c ) register c; { + /* return the name for storage class c */ + static char buf[12]; + if( c&FIELD ){ + sprintf( buf, "FIELD[%d]", c&FLDSIZ ); + return( buf ); + } + return( ccnames[c] ); + } diff --git a/usr/src/cmd/pcc/INDEX b/usr/src/cmd/pcc/INDEX new file mode 100644 index 0000000000..270cc0a93a --- /dev/null +++ b/usr/src/cmd/pcc/INDEX @@ -0,0 +1,4 @@ +This directory contains the machine-dependent files for the +pcc compiler, which is a PDP-11 C compiler based on the portable +C compiler. The machine-independent files are obtained +from directory /usr/src/cmd/mip. diff --git a/usr/src/cmd/pcc/code.c b/usr/src/cmd/pcc/code.c new file mode 100644 index 0000000000..e629a3763f --- /dev/null +++ b/usr/src/cmd/pcc/code.c @@ -0,0 +1,341 @@ +# include +# include + +# include "mfile1" + +int proflag; +int strftn = 0; /* is the current function one which returns a value */ +FILE *tmpfile; +FILE *outfile = stdout; + +branch( n ){ + /* output a branch to label n */ + /* exception is an ordinary function branching to retlab: then, return */ + if( n == retlab && !strftn ){ + printf( " jmp cret\n" ); + } + else printf( " jbr L%d\n", n ); + } + +int lastloc = PROG; + +defalign(n) { + /* cause the alignment to become a multiple of n */ + n /= SZCHAR; + if( lastloc != PROG && n > 1 ) printf( " .even\n" ); + } + +locctr( l ){ + register temp; + /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ + + if( l == lastloc ) return(l); + temp = lastloc; + lastloc = l; + switch( l ){ + + case PROG: + outfile = stdout; + printf( " .text\n" ); + break; + + case DATA: + case ADATA: + outfile = stdout; + if( temp != DATA && temp != ADATA ) + printf( " .data\n" ); + break; + + case STRNG: + case ISTRNG: + outfile = tmpfile; + break; + + case STAB: + cerror( "locctr: STAB unused" ); + break; + + default: + cerror( "illegal location counter" ); + } + + return( temp ); + } + +deflab( n ){ + /* output something to define the current position as label n */ + fprintf( outfile, "L%d:\n", n ); + } + +int crslab = 10; + +getlab(){ + /* return a number usable for a label */ + return( ++crslab ); + } + +efcode(){ + /* code for the end of a function */ + + if( strftn ){ /* copy output (in r0) to caller */ + register struct symtab *p; + register int stlab; + register int count; + int size; + + p = &stab[curftn]; + + deflab( retlab ); + + stlab = getlab(); + printf( " mov $L%d,r1\n", stlab ); + size = tsize( DECREF(p->stype), p->dimoff, p->sizoff ) / SZCHAR; + count = size/2; + while( count-- ) { + printf( " mov (r0)+,(r1)+\n" ); + } + printf( " mov $L%d,r0\n", stlab ); + printf( " .bss\nL%d: .=.+%d.\n .text\n", stlab, size ); + /* turn off strftn flag, so return sequence will be generated */ + strftn = 0; + } + branch( retlab ); + p2bend(); + } + +bfcode( a, n ) int a[]; { + /* code for the beginning of a function; a is an array of + indices in stab for the arguments; n is the number */ + register i; + register temp; + register struct symtab *p; + int off; + + locctr( PROG ); + p = &stab[curftn]; + defnam( p ); + temp = p->stype; + temp = DECREF(temp); + strftn = (temp==STRTY) || (temp==UNIONTY); + + retlab = getlab(); + if( proflag ){ + int plab; + plab = getlab(); + printf( " mov $L%d,r0\n", plab ); + printf( " jsr pc,mcount\n" ); + printf( " .bss\nL%d: .=.+2\n .text\n", plab ); + } + + /* routine prolog */ + + printf( " jsr r5,csv\n" ); + /* adjust stack for autos */ + printf( " sub $.F%d,sp\n", ftnno ); + + off = ARGINIT; + + for( i=0; isclass == REGISTER ){ + temp = p->offset; /* save register number */ + p->sclass = PARAM; /* forget that it is a register */ + p->offset = NOOFFSET; + oalloc( p, &off ); + printf( " mov %d.(r5),r%d\n", p->offset/SZCHAR, temp ); + p->offset = temp; /* remember register number */ + p->sclass = REGISTER; /* remember that it is a register */ + } + else { + if( oalloc( p, &off ) ) cerror( "bad argument" ); + } + + } + } + +bccode(){ /* called just before the first executable statment */ + /* by now, the automatics and register variables are allocated */ + SETOFF( autooff, SZINT ); + /* set aside store area offset */ + p2bbeg( autooff, regvar ); + } + +ejobcode( flag ){ + /* called just before final exit */ + /* flag is 1 if errors, 0 if none */ + } + +aobeg(){ + /* called before removing automatics from stab */ + } + +aocode(p) struct symtab *p; { + /* called when automatic p removed from stab */ + } + +aoend(){ + /* called after removing all automatics from stab */ + } + +defnam( p ) register struct symtab *p; { + /* define the current location as the name p->sname */ + + if( p->sclass == EXTDEF ){ + printf( " .globl %s\n", exname( p->sname ) ); + } + if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); + else printf( "%s:\n", exname( p->sname ) ); + + } + +bycode( t, i ){ + /* put byte i+1 in a string */ + + i &= 07; + if( t < 0 ){ /* end of the string */ + if( i != 0 ) fprintf( outfile, "\n" ); + } + + else { /* stash byte t into string */ + if( i == 0 ) fprintf( outfile, " .byte " ); + else fprintf( outfile, "," ); + fprintf( outfile, "%o", t ); + if( i == 07 ) fprintf( outfile, "\n" ); + } + } + +zecode( n ){ + /* n integer words of zeros */ + OFFSZ temp; + register i; + + if( n <= 0 ) return; + printf( " " ); + for( i=1; i=0 if there is a default label; + its value is the label number + The entries p[1] to p[n] are the nontrivial cases + */ + register i; + register CONSZ j, range; + register dlab, swlab; + + range = p[n].sval-p[1].sval; + + if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ + + dlab = p->slab >= 0 ? p->slab : getlab(); + + if( p[1].sval ){ + printf( " sub $" ); + printf( CONFMT, p[1].sval ); + printf( ".,r0\n" ); + } + + /* note that this is a cl; it thus checks + for numbers below range as well as out of range. + */ + printf( " cmp r0,$%ld.\n", range ); + printf( " jhi L%d\n", dlab ); + + printf( " asl r0\n" ); + printf( " jmp *L%d(r0)\n", swlab = getlab() ); + + /* output table */ + + locctr( ADATA ); + defalign( ALPOINT ); + deflab( swlab ); + + for( i=1,j=p[1].sval; i<=n; ++j ){ + + printf( " L%d\n", ( j == p[i].sval ) ? + p[i++].slab : dlab ); + } + + locctr( PROG ); + + if( p->slab< 0 ) deflab( dlab ); + return; + + } + + /* debugging code */ + + /* out for the moment + if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); + */ + + /* simple switch code */ + + for( i=1; i<=n; ++i ){ + /* already in r0 */ + + printf( " cmp r0,$" ); + printf( CONFMT, p[i].sval ); + printf( ".\n jeq L%d\n", p[i].slab ); + } + + if( p->slab>=0 ) branch( p->slab ); + } diff --git a/usr/src/cmd/pcc/local.c b/usr/src/cmd/pcc/local.c new file mode 100644 index 0000000000..c9fe72f518 --- /dev/null +++ b/usr/src/cmd/pcc/local.c @@ -0,0 +1,337 @@ +# include "mfile1" + + +/* this file contains code which is dependent on the target machine */ + +NODE * +cast( p, t ) register NODE *p; TWORD t; { + /* cast node p to type t */ + + p = buildtree( CAST, block( NAME, NIL, NIL, t, 0, (int)t ), p ); + p->left->op = FREE; + p->op = FREE; + return( p->right ); + } + +NODE * +clocal(p) NODE *p; { + + /* this is called to do local transformations on + an expression tree preparitory to its being + written out in intermediate code. + */ + + /* the major essential job is rewriting the + automatic variables and arguments in terms of + REG and OREG nodes */ + /* conversion ops which are not necessary are also clobbered here */ + /* in addition, any special features (such as rewriting + exclusive or) are easily handled here as well */ + + register struct symtab *q; + register NODE *r; + register o; + register m, ml; + + switch( o = p->op ){ + + case NAME: + if( p->rval < 0 ) { /* already processed; ignore... */ + return(p); + } + q = &stab[p->rval]; + switch( q->sclass ){ + + case AUTO: + case PARAM: + /* fake up a structure reference */ + r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 ); + r->lval = 0; + r->rval = (q->sclass==AUTO?STKREG:ARGREG); + p = stref( block( STREF, r, p, 0, 0, 0 ) ); + break; + + case ULABEL: + case LABEL: + case STATIC: + if( q->slevel == 0 ) break; + p->lval = 0; + p->rval = -q->offset; + break; + + case REGISTER: + p->op = REG; + p->lval = 0; + p->rval = q->offset; + break; + + } + break; + case LT: + case LE: + case GT: + case GE: + if( ISPTR( p->left->type ) || ISPTR( p->right->type ) ){ + p->op += (ULT-LT); + } + break; + + case PCONV: + /* do pointer conversions for char and longs */ + ml = p->left->type; + if( ( ml==CHAR || ml==UCHAR || ml==LONG || ml==ULONG ) && p->left->op != ICON ) break; + + /* pointers all have the same representation; the type is inherited */ + p->left->type = p->type; + p->left->cdim = p->cdim; + p->left->csiz = p->csiz; + p->op = FREE; + return( p->left ); + + case SCONV: + m = (p->type == FLOAT || p->type == DOUBLE ); + ml = (p->left->type == FLOAT || p->left->type == DOUBLE ); + if( m != ml ) break; + + /* now, look for conversions downwards */ + + m = p->type; + ml = p->left->type; + if( p->left->op == ICON ){ /* simulate the conversion here */ + CONSZ val; + val = p->left->lval; + switch( m ){ + case CHAR: + p->left->lval = (char) val; + break; + case UCHAR: + p->left->lval = val & 0XFF; + break; + case UNSIGNED: + p->left->lval = val & 0XFFFFL; + break; + case INT: + p->left->lval = (int)val; + break; + } + p->left->type = m; + } + else { + /* meaningful ones are conversion of int to char, int to short, + and short to char, and unsigned version of them */ + if( m==CHAR || m==UCHAR ){ + if( ml==LONG || ml==ULONG ) break; + } + else if( m==INT || m==UNSIGNED ){ + if( ml==LONG || ml==ULONG ) break; + } + else if( m==LONG || m==ULONG ){ + if( ml!=LONG && ml!= ULONG ) break; + } + } + + /* clobber conversion */ + p->op = FREE; + return( p->left ); /* conversion gets clobbered */ + + case ASSIGN: + /* get rid of SCONV for assignments + from LONG -> CHAR|INT */ + if( p->right->op == SCONV ) { + m = p->right->type; + ml = p->right->left->type; + if( ( m==LONG || m==ULONG ) && + ml!=FLOAT && ml!=DOUBLE ) { + p->right->op = FREE; + p->right = p->right->left; + } + } + break; + + case PVCONV: + case PMCONV: + if( p->right->op != ICON ) cerror( "bad conversion", 0); + p->op = FREE; + return( buildtree( o==PMCONV?MUL:DIV, p->left, p->right ) ); + + case PLUS: + case MINUS: + case LS: + case MUL: + /* optimize address calculations with long indexes */ + if( ISPTR( p->type ) || ISARY( p->type ) ) { + if( p->left->type==LONG || p->left->type==ULONG ) + p->left = cast( p->left, INT ); + if( p->right->type==LONG || p->right->type==ULONG ) + p->right = cast( p->right, INT ); + } + break; + + } + + return(p); + } + +andable( p ) NODE *p; { + return(1); /* all names can have & taken on them */ + } + +cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */ + autooff = AUTOINIT; + } + +cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */ + + if( t==INT || t==UNSIGNED || ISPTR(t) ) return(1); + return(0); + } + +NODE * +offcon( off, t, d, s ) OFFSZ off; TWORD t; { + + /* return a node, for structure references, which is suitable for + being added to a pointer of type t, in order to be off bits offset + into a structure */ + + register NODE *p; + + /* t, d, and s are the type, dimension offset, and sizeoffset */ + /* in general they are necessary for offcon, but not on H'well */ + + p = bcon(0); + p->lval = off/SZCHAR; + return(p); + + } + +static inwd /* current bit offsed in word */; +static word /* word being built from fields */; + +incode( p, sz ) register NODE *p; { + + /* generate initialization code for assigning a constant c + to a field of width sz */ + /* we assume that the proper alignment has been obtained */ + /* inoff is updated to have the proper final value */ + /* we also assume sz < SZINT */ + + if((sz+inwd) > SZINT) cerror("incode: field > int"); + word |= p->lval<sname ) ); + off = tsize( q->stype, q->dimoff, q->sizoff ); + printf( CONFMT, off/SZCHAR ); + printf( ".\n" ); + } + +isitlong( cb, ce ){ /* is lastcon to be long or short */ + /* cb is the first character of the representation, ce the last */ + + if( ce == 'l' || ce == 'L' || + lastcon >= (1L << (SZINT-1) ) ) return (1); + return(0); + } + + +isitfloat( s ) char *s; { + double atof(); + dcon = atof(s); + return( FCON ); + } + +ecode( p ) NODE *p; { + + /* walk the tree and write out the nodes.. */ + + if( nerrors ) return; + p2tree( p ); + p2compile( p ); + } + diff --git a/usr/src/cmd/pcc/local2.c b/usr/src/cmd/pcc/local2.c new file mode 100644 index 0000000000..bd5de3407d --- /dev/null +++ b/usr/src/cmd/pcc/local2.c @@ -0,0 +1,918 @@ +# include "mfile2" +/* a lot of the machine dependent parts of the second pass */ + +# define BITMASK(n) ((1L<= AUTOINIT ) spoff -= AUTOINIT; + spoff /= SZCHAR; + SETOFF(spoff,2); + printf( " .F%d = %Ld.\n", ftnno, spoff ); + if( fltused ) { + fltused = 0; + printf( " .globl fltused\n" ); + } + } + +struct hoptab { int opmask; char * opstring; } ioptab[]= { + + ASG PLUS, "add", + ASG MINUS, "sub", + ASG OR, "bis", + ASG AND, "bic", + ASG ER, "xor", + ASG MUL, "mul", + ASG DIV, "div", + ASG MOD, "div", + ASG LS, "asl", + ASG RS, "asr", + + -1, "" }; + +hopcode( f, o ){ + /* output the appropriate string from the above table */ + + register struct hoptab *q; + + for( q = ioptab; q->opmask>=0; ++q ){ + if( q->opmask == o ){ + printf( "%s", q->opstring ); + if( f == 'F' ) printf( "f" ); + return; + } + } + cerror( "no hoptab for %s", opst[o] ); + } + +char * +rnames[]= { /* keyed to register number tokens */ + + "r0", "r1", + "r2", "r3", "r4", + "r5", "sp", "pc", + + "fr0", "fr1", "fr2", "fr3", + "fr4", "fr5", /* not accumulators - used for temps */ + }; + +int rstatus[] = { + SAREG|STAREG, SAREG|STAREG, + SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, /* use as scratch if not reg var */ + SAREG, SAREG, SAREG, + + SBREG|STBREG, SBREG|STBREG, SBREG|STBREG, SBREG|STBREG, + SBREG, SBREG, + }; + +NODE *brnode; +int brcase; + +int toff = 0; /* number of stack locations used for args */ + +zzzcode( p, c ) NODE *p; { + register m; + switch( c ){ + + case 'B': /* output b if type is byte */ + if( p->type == CHAR || p->type == UCHAR ) printf( "b" ); + return; + + case 'N': /* logical ops, turned into 0-1 */ + /* use register given by register 1 */ + cbgen( 0, m=getlab(), 'I' ); + deflab( p->label ); + printf( " clr %s\n", rnames[getlr( p, '1' )->rval] ); + if( p->type == LONG || p->type == ULONG ) + printf( " clr %s\n", rnames[getlr( p, '1' )->rval + 1] ); + deflab( m ); + return; + + case 'I': + case 'F': + cbgen( p->op, p->label, c ); + return; + + case 'A': + case 'C': + /* logical operators for longs + defer comparisons until branch occurs */ + + brnode = tcopy( p ); + brcase = c; + return; + + case 'H': /* fix up unsigned shifts */ + { register NODE *q; + register r, l; + TWORD t; + + if( p->op == ASG LS ) return; + if( p->op != ASG RS ) cerror( "ZH bad" ); + if( p->left->op != REG ) cerror( "SH left bad" ); + + r = p->left->rval; + t = p->left->type; + l = (t==LONG || t == ULONG ); + + if( t != UNSIGNED && t != UCHAR && t != ULONG ) return; /* signed is ok */ + + /* there are three cases: right side is a constant, + and has the shift value; right side is + a temporary reg, and has the - shift value, + and right side is something else: A1 has the + - shift value then */ + + /* in the case where the value is known (rhs a constant), + the mask is just computed and put out... */ + + if( p->right->op == ICON ){ + int s; + s = p->right->lval; + if( l ){ + if( s >= 16 ){ + printf( " clr r%d\n", r ); + s -= 16; + ++r; + } + } + if( s >= 16 ) printf( " clr r%d\n", r ); + else { + m = 0100000; + m >>= s; /* sign extends... */ + m <<= 1; + printf( " bic $%o,r%d\n", m, r ); + } + return; + } + + /* general case */ + + if( istnode( p->right ) ) q = p->right; + else q = getlr( p, '1' ); /* where -shift is stored */ + + /* first, we store the shifted value on the stack */ + printf( " mov r%d,-(sp)\n", r ); + if( l ) printf( " mov r%d,-(sp)\n", r+1 ); + + /* now, make a mask */ + + printf( " mov $100000,r%d\n", r ); + if( l ) printf( " clr r%d\n", r+1 ); + + /* shift (arithmetically ) */ + if( l ) expand( q, RNOP, " ashc AR" ); + else expand( q, RNOP, " ash AR" ); + printf( ",r%d\n", r ); + + if( l ) printf( " ashc $1,r%d\n", r ); + else printf( " asl r%d\n", r ); + + /* now, we have a mask: use it to clear sp, and reload */ + + if( l ){ + printf( "\tbic\tr%d,(sp)\n\tmov\t(sp)+,r%d\n", r+1, r+1 ); + } + printf( "\tbic\tr%d,(sp)\n\tmov\t(sp)+,r%d\n", r, r ); + /* whew! */ + return; + } + + case 'V': + /* sign extend or not -- register is one less than the + left descendent */ + + m = p->left->rval - 1; + + if( ISUNSIGNED(p->type) ){ + printf( " clr r%d\n", m ); + } + else { + printf( " sxt r%d\n", m ); + } + return; + + /* stack management macros */ + case '-': + if( toff ++ ) printf( "-" ); + printf( "(sp)" ); + return; + + case '4': + if( toff == 0 ) ++toff; /* can't push doubles that way */ + printf( "-(sp)" ); + toff += 4; + return; + + case '~': + /* complimented CR */ + p->right->lval = ~p->right->lval; + conput( getlr( p, 'R' ) ); + p->right->lval = ~p->right->lval; + return; + + case 'M': + /* negated CR */ + p->right->lval = -p->right->lval; + conput( getlr( p, 'R' ) ); + p->right->lval = -p->right->lval; + return; + + case 'L': /* INIT for long constants */ + { + unsigned hi, lo; + lo = p->left->lval & BITMASK(SZINT); + hi = ( p->left->lval >> SZINT ) & BITMASK(SZINT); + printf( " %o; %o\n", hi, lo ); + return; + } + + case 'T': + /* Truncate longs for type conversions: + LONG|ULONG -> CHAR|UCHAR|INT|UNSIGNED + increment offset to second word */ + + m = p->type; + p = p->left; + switch( p->op ){ + case NAME: + case OREG: + p->lval += SZINT/SZCHAR; + return; + case REG: + rfree( p->rval, p->type ); + p->rval += 1; + p->type = m; + rbusy( p->rval, p->type ); + return; + default: + cerror( "Illegal ZT type conversion" ); + return; + + } + + case 'U': + /* same as AL for exp under U* */ + if( p->left->op == UNARY MUL ) { + adrput( getlr( p->left, 'L' ) ); + return; + } + cerror( "Illegal ZU" ); + /* NO RETURN */ + + case 'W': /* structure size */ + if( p->op == STASG ) + printf( "%d", p->stsize); + else cerror( "Not a structure" ); + return; + + case 'S': /* structure assignment */ + { + register NODE *l, *r; + register size, count; + + if( p->op == STASG ){ + l = p->left; + r = p->right; + } + else if( p->op == STARG ){ /* store an arg onto the stack */ + r = p->left; + } + else cerror( "STASG bad" ); + + if( r->op == ICON ) r->op = NAME; + else if( r->op == REG ) r->op = OREG; + else if( r->op != OREG ) cerror( "STASG-r" ); + + size = p->stsize; + count = size / 2; + + r->lval += size; + if( p->op == STASG ) l->lval += size; + + while( count-- ){ /* simple load/store loop */ + r->lval -= 2; + expand( r, FOREFF, " mov AR," ); + if( p->op == STASG ){ + l->lval -= 2; + expand( l, FOREFF, "AR\n" ); + } + else { + printf( "-(sp)\n" ); + } + + } + + if( r->op == NAME ) r->op = ICON; + else if( r->op == OREG ) r->op = REG; + + } + break; + + default: + cerror( "illegal zzzcode" ); + } + } + +rmove( rt, rs, t ) TWORD t; { + printf( " %s %s,%s\n", (t==FLOAT||t==DOUBLE)?"movf":"mov", rnames[rs], rnames[rt] ); + } + +struct respref +respref[] = { + INTAREG|INTBREG, INTAREG|INTBREG, + INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|SNAME|STARNM|SCON, + INTEMP, INTEMP, + FORARG, FORARG, + INTAREG, SOREG|SNAME, + 0, 0 }; + +setregs(){ /* set up temporary registers */ + register i; + + /* use any unused variable registers as scratch registers */ + fregs = maxtreg>=MINRVAR ? maxtreg + 1 : MINRVAR; + if( xdebug ){ + /* -x changes number of free regs to 2, -xx to 3, etc. */ + if( (xdebug+1) < fregs ) fregs = xdebug+1; + } + /* NOTE: for pdp11 fregs <= 4 for float regs */ + if( fregs > 4 ) fregs = 4; + for( i=MINRVAR; i<=MAXRVAR; i++ ) + rstatus[i] = itype==DOUBLE||p->type==FLOAT) ? FR0 : R0 ); + } + +shltype( o, p ) NODE *p; { + if( o == NAME|| o==REG || o == ICON || o == OREG ) return( 1 ); + return( o==UNARY MUL && shumul(p->left) ); + } + +flshape( p ) register NODE *p; { + register o = p->op; + if( o==NAME || o==REG || o==ICON || o==OREG ) return( 1 ); + return( o==UNARY MUL && shumul(p->left)==STARNM ); + } + +shtemp( p ) register NODE *p; { + if( p->op == UNARY MUL ) p = p->left; + if( p->op == REG || p->op == OREG ) return( !istreg( p->rval ) ); + return( p->op == NAME || p->op == ICON ); + } + +spsz( t, v ) TWORD t; CONSZ v; { + + /* is v the size to increment something of type t */ + + if( !ISPTR(t) ) return( 0 ); + t = DECREF(t); + + if( ISPTR(t) ) return( v == 2 ); + + switch( t ){ + + case UCHAR: + case CHAR: + return( v == 1 ); + + case INT: + case UNSIGNED: + return( v == 2 ); + + case FLOAT: + return( v == 4 ); + + case DOUBLE: + return( v == 8 ); + } + + return( 0 ); + } + +shumul( p ) register NODE *p; { + register o; + + o = p->op; + if( o == NAME || o == OREG || o == ICON ) return( STARNM ); + + if( ( o == INCR || o == ASG MINUS ) && + ( p->left->op == REG && p->right->op == ICON ) && + p->right->name[0] == '\0' && + spsz( p->left->type, p->right->lval ) ) + return( STARREG ); + + return( 0 ); + } + +adrcon( val ) CONSZ val; { + printf( CONFMT, val ); + } + +conput( p ) register NODE *p; { + switch( p->op ){ + + case ICON: + acon( p ); + return; + + case REG: + printf( "%s", rnames[p->rval] ); + return; + + default: + cerror( "illegal conput" ); + } + } + +insput( p ) NODE *p; { + cerror( "insput" ); + } + +upput( p ) NODE *p; { + /* output the address of the second word in the + pair pointed to by p (for LONGs)*/ + CONSZ save; + + if( p->op == FLD ){ + p = p->left; + } + + save = p->lval; + switch( p->op ){ + + case NAME: + p->lval += SZINT/SZCHAR; + acon( p ); + break; + + case ICON: + /* addressable value of the constant */ + p->lval &= BITMASK(SZINT); + printf( "$" ); + acon( p ); + break; + + case REG: + printf( "%s", rnames[p->rval+1] ); + break; + + case OREG: + p->lval += SZINT/SZCHAR; + if( p->rval == R5 ){ /* in the argument region */ + if( p->name[0] != '\0' ) werror( "bad arg temp" ); + } + if( p->lval != 0 || p->name[0] != '\0' ) acon( p ); + printf( "(%s)", rnames[p->rval] ); + break; + + default: + cerror( "illegal upper address" ); + break; + + } + p->lval = save; + + } + +adrput( p ) register NODE *p; { + /* output an address, with offsets, from p */ + + if( p->op == FLD ){ + p = p->left; + } + switch( p->op ){ + + case NAME: + acon( p ); + return; + + case ICON: + /* addressable value of the constant */ + if( szty( p->type ) == 2 ) { + /* print the high order value */ + CONSZ save; + save = p->lval; + p->lval = ( p->lval >> SZINT ) & BITMASK(SZINT); + printf( "$" ); + acon( p ); + p->lval = save; + return; + } + printf( "$" ); + acon( p ); + return; + + case REG: + printf( "%s", rnames[p->rval] ); + return; + + case OREG: + if( p->rval == R5 ){ /* in the argument region */ + if( p->name[0] != '\0' ) werror( "bad arg temp" ); + printf( CONFMT, p->lval ); + printf( ".(r5)" ); + return; + } + if( p->lval != 0 || p->name[0] != '\0' ) acon( p ); + printf( "(%s)", rnames[p->rval] ); + return; + + case UNARY MUL: + /* STARNM or STARREG found */ + if( tshape(p, STARNM) ) { + printf( "*" ); + adrput( p->left); + } + else { /* STARREG - really auto inc or dec */ + /* turn into OREG so replacement node will + reflect the value of the expression */ + register i; + register NODE *q, *l; + + l = p->left; + q = l->left; + p->op = OREG; + p->rall = q->rall; + p->lval = q->lval; + p->rval = q->rval; + for( i=0; iname[i] = q->name[i]; + if( l->op == INCR ) { + adrput( p ); + printf( "+" ); + p->lval -= l->right->lval; + } + else { /* l->op == ASG MINUS */ + printf( "-" ); + adrput( p ); + } + tfree( l ); + } + return; + + default: + cerror( "illegal address" ); + return; + + } + + } + +acon( p ) register NODE *p; { /* print out a constant */ + + if( p->name[0] == '\0' ){ /* constant only */ + printf( CONFMT, p->lval); + printf( "." ); + } + else if( p->lval == 0 ) { /* name only */ + printf( "%.8s", p->name ); + } + else { /* name + offset */ + printf( "%.8s+", p->name ); + printf( CONFMT, p->lval ); + printf( "." ); + } + } + +genscall( p, cookie ) register NODE *p; { + /* structure valued call */ + return( gencall( p, cookie ) ); + } + +gencall( p, cookie ) register NODE *p; { + /* generate the call given by p */ + register temp; + register m; + + if( p->right ) temp = argsize( p->right ); + else temp = 0; + + if( p->right ){ /* generate args */ + genargs( p->right ); + } + + if( !shltype( p->left->op, p->left ) ) { + order( p->left, INAREG|SOREG ); + } + + p->op = UNARY CALL; + m = match( p, INTAREG|INTBREG ); + popargs( temp ); + return(m != MDONE); + } + +popargs( size ) register size; { + /* pop arguments from stack */ + + toff -= size/2; + if( toff == 0 && size >= 2 ) size -= 2; + switch( size ) { + case 0: + break; + case 2: + printf( " tst (sp)+\n" ); + break; + case 4: + printf( " cmp (sp)+,(sp)+\n" ); + break; + default: + printf( " add $%d.,sp\n", size); + } + } + +char * +ccbranches[] = { + " jeq L%d\n", + " jne L%d\n", + " jle L%d\n", + " jlt L%d\n", + " jge L%d\n", + " jgt L%d\n", + " jlos L%d\n", + " jlo L%d\n", + " jhis L%d\n", + " jhi L%d\n", + }; + +/* long branch table + + This table, when indexed by a logical operator, + selects a set of three logical conditions required + to generate long comparisons and branches. A zero + entry indicates that no branch is required. + E.G.: The <= operator would generate: + cmp AL,AR + jlt lable / 1st entry LT -> lable + jgt 1f / 2nd entry GT -> 1f + cmp UL,UR + jlos lable / 3rd entry ULE -> lable + 1: + */ + +int lbranches[][3] = { + /*EQ*/ 0, NE, EQ, + /*NE*/ NE, 0, NE, + /*LE*/ LT, GT, ULE, + /*LT*/ LT, GT, ULT, + /*GE*/ GT, LT, UGE, + /*GT*/ GT, LT, UGT, + /*ULE*/ ULT, UGT, ULE, + /*ULT*/ ULT, UGT, ULT, + /*UGE*/ UGT, ULT, UGE, + /*UGT*/ UGT, ULT, UGT, + }; + +/* logical relations when compared in reverse order (cmp R,L) */ +extern short revrel[] ; + +cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ + register *plb; + int lab1f; + + if( o == 0 ) printf( " jbr L%d\n", lab ); + else if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] ); + else { + switch( brcase ) { + + case 'A': + case 'C': + plb = lbranches[ o-EQ ]; + lab1f = getlab(); + expand( brnode, FORCC, brcase=='C' ? "\tcmp\tAL,AR\n" : "\ttst\tAR\n" ); + if( *plb != 0 ) + printf( ccbranches[*plb-EQ], lab); + if( *++plb != 0 ) + printf( ccbranches[*plb-EQ], lab1f); + expand( brnode, FORCC, brcase=='C' ? "\tcmp\tUL,UR\n" : "\ttst\tUR\n" ); + printf( ccbranches[*++plb-EQ], lab); + deflab( lab1f ); + reclaim( brnode, RNULL, 0 ); + break; + + default: + if( mode=='F' ) o = revrel[ o-EQ ]; + printf( ccbranches[o-EQ], lab ); + break; + } + + brcase = 0; + brnode = 0; + } + } + +nextcook( p, cookie ) NODE *p; { + /* we have failed to match p with cookie; try another */ + if( cookie == FORREW ) return( 0 ); /* hopeless! */ + if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); + if( !(cookie&INTEMP) && asgop(p->op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); + return( FORREW ); + } + +lastchance( p, cook ) NODE *p; { + /* forget it! */ + return(0); + } + +struct functbl { + int fop; + TWORD ftype; + char *func; + } opfunc[] = { + MUL, LONG, "lmul", + DIV, LONG, "ldiv", + MOD, LONG, "lrem", + ASG MUL, LONG, "almul", + ASG DIV, LONG, "aldiv", + ASG MOD, LONG, "alrem", + MUL, ULONG, "lmul", + DIV, ULONG, "uldiv", + MOD, ULONG, "ulrem", + ASG MUL, ULONG, "almul", + ASG DIV, ULONG, "auldiv", + ASG MOD, ULONG, "aulrem", + 0, 0, 0 }; + +hardops(p) register NODE *p; { + /* change hard to do operators into function calls. + for pdp11 do long * / % */ + register NODE *q; + register struct functbl *f; + register o; + register TWORD t; + + o = p->op; + t = p->type; + if( t!=LONG && t!=ULONG ) return; + + for( f=opfunc; f->fop; f++ ) { + if( o==f->fop && t==f->ftype ) goto convert; + } + return; + + /* need address of left node for ASG OP */ + /* WARNING - this won't work for long in a REG */ + convert: + if( asgop( o ) ) { + switch( p->left->op ) { + + case UNARY MUL: /* convert to address */ + p->left->op = FREE; + p->left = p->left->left; + break; + + case NAME: /* convert to ICON pointer */ + p->left->op = ICON; + p->left->type = INCREF( p->left->type ); + break; + + case OREG: /* convert OREG to address */ + p->left->op = REG; + p->left->type = INCREF( p->left->type ); + if( p->left->lval != 0 ) { + q = talloc(); + q->op = PLUS; + q->rall = NOPREF; + q->type = p->left->type; + q->left = p->left; + q->right = talloc(); + + q->right->op = ICON; + q->right->rall = NOPREF; + q->right->type = INT; + q->right->name[0] = '\0'; + q->right->lval = p->left->lval; + q->right->rval = 0; + + p->left->lval = 0; + p->left = q; + } + break; + + default: + cerror( "Bad address for hard ops" ); + /* NO RETURN */ + + } + } + + /* build comma op for args to function */ + q = talloc(); + q->op = CM; + q->rall = NOPREF; + q->type = INT; + q->left = p->left; + q->right = p->right; + p->op = CALL; + p->right = q; + + /* put function name in left node of call */ + p->left = q = talloc(); + q->op = ICON; + q->rall = NOPREF; + q->type = INCREF( FTN + p->type ); + strcpy( q->name, f->func ); + q->lval = 0; + q->rval = 0; + + return; + + } + +optim2( p ) register NODE *p; { + /* do local tree transformations and optimizations */ + + register NODE *r; + + switch( p->op ) { + + case AND: + /* commute L and R to eliminate compliments and constants */ + if( p->left->op==ICON || p->left->op==COMPL ) { + r = p->left; + p->left = p->right; + p->right = r; + } + case ASG AND: + /* change meaning of AND to ~R&L - bic on pdp11 */ + r = p->right; + if( r->op==ICON ) { /* compliment constant */ + r->lval = ~r->lval; + } + else if( r->op==COMPL ) { /* ~~A => A */ + r->op = FREE; + p->right = r->left; + } + else { /* insert complement node */ + p->right = talloc(); + p->right->op = COMPL; + p->right->rall = NOPREF; + p->right->type = r->type; + p->right->left = r; + p->right->right = NULL; + } + break; + + } + } + +myreader(p) register NODE *p; { + walkf( p, hardops ); /* convert ops to function calls */ + canon( p ); /* expands r-vals for fileds */ + walkf( p, optim2 ); + toff = 0; /* stack offset swindle */ + } + +special( p, shape ) register NODE *p; { + /* special shape matching routine */ + + switch( shape ) { + + case SCCON: + if( p->op == ICON && p->name[0]=='\0' && p->lval>= -128 && p->lval <=127 ) return( 1 ); + break; + + case SICON: + if( p->op == ICON && p->name[0]=='\0' && p->lval>= 0 && p->lval <=32767 ) return( 1 ); + break; + + default: + cerror( "bad special shape" ); + + } + + return( 0 ); + } + +# ifndef ONEPASS +main( argc, argv ) char *argv[]; { + return( mainp2( argc, argv ) ); + } +# endif diff --git a/usr/src/cmd/pcc/mac2defs b/usr/src/cmd/pcc/mac2defs new file mode 100644 index 0000000000..59476ee4b7 --- /dev/null +++ b/usr/src/cmd/pcc/mac2defs @@ -0,0 +1,51 @@ +/* PDP11 Registers */ + + /* scratch registers */ +# define R0 0 +# define R1 1 + + /* register variables */ +# define R2 2 +# define R3 3 +# define R4 4 + + /* special purpose */ +# define R5 5 /* frame pointer */ +# define SP 6 /* stack pointer */ +# define PC 7 /* program counter */ + + /* floating registers */ + +# define FR0 8 +# define FR1 9 +# define FR2 10 +# define FR3 11 +# define FR4 12 +# define FR5 13 + +# define SAVEREGION 8 /* number of bytes for save area */ + +# define BYTEOFF(x) ((x)&01) +# define wdal(k) (BYTEOFF(k)==0) +# define BITOOR(x) ((x)>>3) /* bit offset to oreg offset */ + +# define REGSZ 14 + +# define TMPREG R5 + + +# define STOARG(p) /* just evaluate the arguments, and be done with it... */ +# define STOFARG(p) +# define STOSTARG(p) +# define genfcall(a,b) gencall(a,b) + + + /* shape for constants between -128 and 127 */ +# define SCCON (SPECIAL+100) + /* shape for constants between 0 and 32767 */ +# define SICON (SPECIAL+101) + +# define MYREADER(p) myreader(p) +extern int fltused; + /* calls can be nested on the PDP-11 */ +# define NESTCALLS diff --git a/usr/src/cmd/pcc/macdefs b/usr/src/cmd/pcc/macdefs new file mode 100644 index 0000000000..07289e97d3 --- /dev/null +++ b/usr/src/cmd/pcc/macdefs @@ -0,0 +1,67 @@ +# define makecc(val,i) lastcon = i ? (val<<8)|lastcon : val + +# define ARGINIT 32 +# define AUTOINIT 48 +# define SZCHAR 8 +# define SZINT 16 +# define SZFLOAT 32 +# define SZDOUBLE 64 +# define SZLONG 32 +# define SZSHORT 16 +# define SZPOINT 16 +# define ALCHAR 8 +# define ALINT 16 +# define ALFLOAT 16 +# define ALDOUBLE 16 +# define ALLONG 16 +# define ALSHORT 16 +# define ALPOINT 16 +# define ALSTRUCT 16 +# define ALSTACK 16 + +/* size in which constants are converted */ +/* should be long if feasable */ + +# define CONSZ long +# define CONFMT "%Ld" + +/* size in which offsets are kept +/* should be large enough to cover address space in bits +*/ + +# define OFFSZ long + +/* character set macro */ + +# define CCTRANS(x) x + +/* register cookie for stack poINTer */ + +# define STKREG 5 +# define ARGREG 5 + +/* maximum and minimum register variables */ + +# define MAXRVAR 4 +# define MINRVAR 2 + + /* various standard pieces of code are used */ +# define STDPRTREE +# define LABFMT "L%d" + +/* definition indicates automatics and/or temporaries + are on a negative growing stack */ + +# define BACKAUTO +# define BACKTEMP + +# define RTOLBYTES +# ifndef FORT +# define ONEPASS +# endif + +# ifndef FORT +# define EXIT dexit +# endif + +# define ENUMSIZE(high,low) INT diff --git a/usr/src/cmd/pcc/order.c b/usr/src/cmd/pcc/order.c new file mode 100644 index 0000000000..e21f334d53 --- /dev/null +++ b/usr/src/cmd/pcc/order.c @@ -0,0 +1,725 @@ +# include "mfile2" + +int fltused = 0; + +stoasg( p, o ) register NODE *p; { + /* should the assignment op p be stored, + given that it lies as the right operand of o + (or the left, if o==UNARY MUL) */ + return( shltype(p->left->op, p->left ) ); + + } + +deltest( p ) register NODE *p; { + /* should we delay the INCR or DECR operation p */ + if( p->op == INCR && p->left->op == REG && spsz( p->left->type, p->right->lval ) ){ + /* STARREG */ + return( 0 ); + } + + p = p->left; + if( p->op == UNARY MUL ) p = p->left; + return( p->op == NAME || p->op == OREG || p->op == REG ); + } + +mkadrs(p) register NODE *p; { + register o; + + o = p->op; + + if( asgop(o) ){ + if( p->left->su >= p->right->su ){ + if( p->left->op == UNARY MUL ){ + if( p->left->su > 0 ) + SETSTO( p->left->left, INTEMP ); + else { + if( p->right->su > 0 ) SETSTO( p->right, INTEMP ); + else cerror( "store finds both sides trivial" ); + } + } + else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + SETSTO( p->left->left->left, INTEMP ); + } + else { /* should be only structure assignment */ + SETSTO( p->left, INTEMP ); + } + } + else SETSTO( p->right, INTEMP ); + } + else { + if( p->left->su > p->right->su ){ + SETSTO( p->left, INTEMP ); + } + else { + SETSTO( p->right, INTEMP ); + } + } + } + +notoff( t, r, off, cp) TWORD t; CONSZ off; char *cp; { + /* is it legal to make an OREG or NAME entry which has an + /* offset of off, (from a register of r), if the + /* resulting thing had type t */ + + /* return( 1 ); /* NO */ + return(0); /* YES */ + } + +# define max(x,y) ((x)<(y)?(y):(x)) +# define min(x,y) ((x)<(y)?(x):(y)) + + +# define ZCHAR 01 +# define ZLONG 02 +# define ZFLOAT 04 + +zum( p, zap ) register NODE *p; { + /* zap Sethi-Ullman number for chars, longs, floats */ + /* in the case of longs, only STARNM's are zapped */ + /* ZCHAR, ZLONG, ZFLOAT are used to select the zapping */ + + register su; + + su = p->su; + + switch( p->type ){ + + case CHAR: + case UCHAR: + if( !(zap&ZCHAR) ) break; + if( su == 0 ) p->su = su = 1; + break; + + case LONG: + case ULONG: + if( !(zap&ZLONG) ) break; + if( p->op == UNARY MUL && su == 0 ) p->su = su = 2; + break; + + case FLOAT: + if( !(zap&ZFLOAT) ) break; + if( su == 0 ) p->su = su = 1; + + } + + return( su ); + } + +sucomp( p ) register NODE *p; { + + /* set the su field in the node to the sethi-ullman + number, or local equivalent */ + + register o, ty, sul, sur; + register nr; + + ty = optype( o=p->op); + nr = szty( p->type ); + p->su = 0; + + if( ty == LTYPE ) { + if( p->type==FLOAT ) p->su = 1; + return; + } + else if( ty == UTYPE ){ + switch( o ) { + case UNARY CALL: + case UNARY STCALL: + p->su = fregs; /* all regs needed */ + return; + + case UNARY MUL: + if( shumul( p->left ) ) return; + + default: + p->su = max( p->left->su, nr); + return; + } + } + + + /* If rhs needs n, lhs needs m, regular su computation */ + + sul = p->left->su; + sur = p->right->su; + + if( o == ASSIGN ){ + asop: /* also used for +=, etc., to memory */ + if( sul==0 ){ + /* don't need to worry about the left side */ + p->su = max( sur, nr ); + } + else { + /* right, left address, op */ + if( sur == 0 ){ + /* just get the lhs address into a register, and mov */ + /* the `nr' covers the case where value is in reg afterwards */ + p->su = max( sul, nr ); + } + else { + /* right, left address, op */ + p->su = max( sur, nr+sul ); + } + } + return; + } + + if( o == CALL || o == STCALL ){ + /* in effect, takes all free registers */ + p->su = fregs; + return; + } + + if( o == STASG ){ + /* right, then left */ + p->su = max( max( sul+nr, sur), fregs ); + return; + } + + if( logop(o) ){ + /* do the harder side, then the easier side, into registers */ + /* left then right, max(sul,sur+nr) */ + /* right then left, max(sur,sul+nr) */ + /* to hold both sides in regs: nr+nr */ + nr = szty( p->left->type ); + sul = zum( p->left, ZLONG|ZCHAR|ZFLOAT ); + sur = zum( p->right, ZLONG|ZCHAR|ZFLOAT ); + p->su = min( max(sul,sur+nr), max(sur,sul+nr) ); + return; + } + + if( asgop(o) ){ + /* computed by doing right, doing left address, doing left, op, and store */ + switch( o ) { + case INCR: + case DECR: + /* do as binary op */ + break; + + case ASG DIV: + case ASG MOD: + case ASG MUL: + if( p->type!=FLOAT && p->type!=DOUBLE ) nr = fregs; + goto gencase; + + case ASG PLUS: + case ASG MINUS: + case ASG AND: /* really bic */ + case ASG OR: + if( p->type == INT || p->type == UNSIGNED || ISPTR(p->type) ) goto asop; + + gencase: + default: + sur = zum( p->right, ZCHAR|ZLONG|ZFLOAT ); + if( sur == 0 ){ /* easy case: if addressable, + do left value, op, store */ + if( sul == 0 ) p->su = nr; + /* harder: left adr, val, op, store */ + else p->su = max( sul, nr+1 ); + } + else { /* do right, left adr, left value, op, store */ + if( sul == 0 ){ /* right, left value, op, store */ + p->su = max( sur, nr+nr ); + } + else { + p->su = max( sur, max( sul+nr, 1+nr+nr ) ); + } + } + return; + } + } + + switch( o ){ + case ANDAND: + case OROR: + case QUEST: + case COLON: + case COMOP: + p->su = max( max(sul,sur), nr); + return; + } + + if( ( o==DIV || o==MOD || o==MUL ) + && p->type!=FLOAT && p->type!=DOUBLE ) nr = fregs; + if( o==PLUS || o==MUL || o==OR || o==ER ){ + /* AND is ruined by the hardware */ + /* permute: get the harder on the left */ + + register rt, lt; + + if( istnode( p->left ) || sul > sur ) goto noswap; /* don't do it! */ + + /* look for a funny type on the left, one on the right */ + + + lt = p->left->type; + rt = p->right->type; + + if( rt == FLOAT && lt == DOUBLE ) goto swap; + + if( (rt==CHAR||rt==UCHAR) && (lt==INT||lt==UNSIGNED||ISPTR(lt)) ) goto swap; + + if( lt==LONG || lt==ULONG ){ + if( rt==LONG || rt==ULONG ){ + /* if one is a STARNM, swap */ + if( p->left->op == UNARY MUL && sul==0 ) goto noswap; + if( p->right->op == UNARY MUL && p->left->op != UNARY MUL ) goto swap; + goto noswap; + } + else if( p->left->op == UNARY MUL && sul == 0 ) goto noswap; + else goto swap; /* put long on right, unless STARNM */ + } + + /* we are finished with the type stuff now; if one is addressable, + put it on the right */ + if( sul == 0 && sur != 0 ){ + + NODE *s; + int ssu; + + swap: + ssu = sul; sul = sur; sur = ssu; + s = p->left; p->left = p->right; p->right = s; + } + } + noswap: + + sur = zum( p->right, ZCHAR|ZLONG|ZFLOAT ); + if( sur == 0 ){ + /* get left value into a register, do op */ + p->su = max( nr, sul ); + } + else { + /* do harder into a register, then easier */ + p->su = max( nr+nr, min( max( sul, nr+sur ), max( sur, nr+sul ) ) ); + } + } + +int radebug = 0; + +mkrall( p, r ) register NODE *p; { + /* insure that the use of p gets done with register r; in effect, */ + /* simulate offstar */ + + if( p->op == FLD ){ + p->left->rall = p->rall; + p = p->left; + } + + if( p->op != UNARY MUL ) return; /* no more to do */ + p = p->left; + if( p->op == UNARY MUL ){ + p->rall = r; + p = p->left; + } + if( p->op == PLUS && p->right->op == ICON ){ + p->rall = r; + p = p->left; + } + rallo( p, r ); + } + +rallo( p, down ) register NODE *p; { + /* do register allocation */ + register o, type, down1, down2, ty; + + if( radebug ) printf( "rallo( %o, %o )\n", p, down ); + + down2 = NOPREF; + p->rall = down; + down1 = ( down &= ~MUSTDO ); + + ty = optype( o = p->op ); + type = p->type; + + + if( type == DOUBLE || type == FLOAT ){ + if( o == FORCE ) down1 = FR0|MUSTDO; + ++fltused; + } + else switch( o ) { + case ASSIGN: + down1 = NOPREF; + down2 = down; + break; + + case ASG MUL: + case ASG DIV: + case ASG MOD: + /* keep the addresses out of the hair of (r0,r1) */ + if(fregs == 2 ){ + /* lhs in (r0,r1), nothing else matters */ + down1 = R1|MUSTDO; + down2 = NOPREF; + break; + } + /* at least 3 regs free */ + /* compute lhs in (r0,r1), address of left in r2 */ + p->left->rall = R1|MUSTDO; + mkrall( p->left, R2|MUSTDO ); + /* now, deal with right */ + if( fregs == 3 ) rallo( p->right, NOPREF ); + else { + /* put address of long or value here */ + p->right->rall = R3|MUSTDO; + mkrall( p->right, R3|MUSTDO ); + } + return; + + case MUL: + case DIV: + case MOD: + rallo( p->left, R1|MUSTDO ); + + if( fregs == 2 ){ + rallo( p->right, NOPREF ); + return; + } + /* compute addresses, stay away from (r0,r1) */ + + p->right->rall = (fregs==3) ? R2|MUSTDO : R3|MUSTDO ; + mkrall( p->right, R2|MUSTDO ); + return; + + case CALL: + case STASG: + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case NOT: + case ANDAND: + case OROR: + down1 = NOPREF; + break; + + case FORCE: + down1 = R0|MUSTDO; + break; + + } + + if( ty != LTYPE ) rallo( p->left, down1 ); + if( ty == BITYPE ) rallo( p->right, down2 ); + + } + +offstar( p ) register NODE *p; { + /* handle indirections */ + + if( p->op == UNARY MUL ) p = p->left; + + if( p->op == PLUS || p->op == MINUS ){ + if( p->right->op == ICON ){ + order( p->left , INTAREG|INAREG ); + return; + } + } + order( p, INTAREG|INAREG ); + } + +setincr( p ) NODE *p; { + return( 0 ); /* for the moment, don't bother */ + } + +niceuty( p ) register NODE *p; { + register TWORD t; + + return( p->op == UNARY MUL && (t=p->type)!=CHAR && + t!= UCHAR && t!= FLOAT && + shumul( p->left) != STARREG ); + } +setbin( p ) register NODE *p; { + register NODE *r, *l; + + r = p->right; + l = p->left; + + if( p->right->su == 0 ){ /* rhs is addressable */ + if( logop( p->op ) ){ + if( l->op == UNARY MUL && l->type != FLOAT && shumul( l->left ) != STARREG ) offstar( l->left ); + else order( l, INAREG|INTAREG|INBREG|INTBREG|INTEMP ); + return( 1 ); + } + if( !istnode( l ) ){ + order( l, INTAREG|INTBREG ); + return( 1 ); + } + /* rewrite */ + return( 0 ); + } + /* now, rhs is complicated: must do both sides into registers */ + /* do the harder side first */ + + if( logop( p->op ) ){ + /* relational: do both sides into regs if need be */ + + if( r->su > l->su ){ + if( niceuty(r) ){ + offstar( r->left ); + return( 1 ); + } + else if( !istnode( r ) ){ + order( r, INTAREG|INAREG|INTBREG|INBREG|INTEMP ); + return( 1 ); + } + } + if( niceuty(l) ){ + offstar( l->left ); + return( 1 ); + } + else if( niceuty(r) ){ + offstar( r->left ); + return( 1 ); + } + else if( !istnode( l ) ){ + order( l, INTAREG|INAREG|INTBREG|INBREG|INTEMP ); + return( 1 ); + } + if( !istnode( r ) ){ + order( r, INTAREG|INAREG|INTBREG|INBREG|INTEMP ); + return( 1 ); + } + cerror( "setbin can't deal with %s", opst[p->op] ); + } + + /* ordinary operator */ + + if( !istnode(r) && r->su > l->su ){ + /* if there is a chance of making it addressable, try it... */ + if( niceuty(r) ){ + offstar( r->left ); + return( 1 ); /* hopefully, it is addressable by now */ + } + order( r, INTAREG|INAREG|INTBREG|INBREG|INTEMP ); /* anything goes on rhs */ + return( 1 ); + } + else { + if( !istnode( l ) ){ + order( l, INTAREG|INTBREG ); + return( 1 ); + } + /* rewrite */ + return( 0 ); + } + } + +setstr( p ) register NODE *p; { /* structure assignment */ + if( p->right->op != REG ){ + order( p->right, INTAREG ); + return(1); + } + p = p->left; + if( p->op != NAME && p->op != OREG ){ + if( p->op != UNARY MUL ) cerror( "bad setstr" ); + order( p->left, INTAREG ); + return( 1 ); + } + return( 0 ); + } + +setasg( p ) register NODE *p; { + /* setup for assignment operator */ + + if( p->right->su != 0 && p->right->op != REG ) { + if( p->right->op == UNARY MUL ) + offstar( p->right->left ); + else + order( p->right, INAREG|INBREG|SOREG|SNAME|SCON ); + return(1); + } + if( p->right->op != REG && ( p->type == FLOAT || p->type == DOUBLE ) ) { + order( p->right, INBREG ); + return(1); + } + if( p->left->op == UNARY MUL && !tshape( p->left, STARREG|STARNM ) ){ + offstar( p->left->left ); + return(1); + } + if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + offstar( p->left->left->left ); + return(1); + } + /* if things are really strange, get rhs into a register */ + if( p->right->op != REG ){ + order( p->right, INAREG|INBREG ); + return( 1 ); + } + return(0); + } + +setasop( p ) register NODE *p; { + /* setup for =ops */ + register sul, sur; + register NODE *q, *p2; + + sul = p->left->su; + sur = p->right->su; + + switch( p->op ){ + + case ASG PLUS: + case ASG OR: + case ASG MINUS: + if( p->type != INT && p->type != UNSIGNED && !ISPTR(p->type) ) break; + if( p->right->type == CHAR || p->right->type == UCHAR ){ + order( p->right, INAREG ); + return( 1 ); + } + break; + + case ASG ER: + if( sul == 0 || p->left->op == REG ){ + if( p->left->type == CHAR || p->left->type == UCHAR ) goto rew; /* rewrite */ + order( p->right, INAREG|INBREG ); + return( 1 ); + } + goto leftadr; + } + + if( sur == 0 ){ + + leftadr: + /* easy case: if addressable, do left value, op, store */ + if( sul == 0 ) goto rew; /* rewrite */ + + /* harder; make aleft address, val, op, and store */ + + if( p->left->op == UNARY MUL ){ + offstar( p->left->left ); + return( 1 ); + } + if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + offstar( p->left->left->left ); + return( 1 ); + } + rew: /* rewrite, accounting for autoincrement and autodecrement */ + + q = p->left; + if( q->op == FLD ) q = q->left; + if( q->op != UNARY MUL || shumul(q->left) != STARREG ) return(0); /* let reader.c do it */ + + /* mimic code from reader.c */ + + p2 = tcopy( p ); + p->op = ASSIGN; + reclaim( p->right, RNULL, 0 ); + p->right = p2; + + /* now, zap INCR on right, ASG MINUS on left */ + + if( q->left->op == INCR ){ + q = p2->left; + if( q->op == FLD ) q = q->left; + if( q->left->op != INCR ) cerror( "bad incr rewrite" ); + } + else if( q->left->op != ASG MINUS ) cerror( " bad -= rewrite" ); + + q->left->right->op = FREE; + q->left->op = FREE; + q->left = q->left->left; + + /* now, resume reader.c rewriting code */ + + canon(p); + rallo( p, p->rall ); + order( p2->left, INTBREG|INTAREG ); + order( p2, INTBREG|INTAREG ); + return( 1 ); + } + + /* harder case: do right, left address, left value, op, store */ + + if( p->right->op == UNARY MUL ){ + offstar( p->right->left ); + return( 1 ); + } + /* sur> 0, since otherwise, done above */ + if( p->right->op == REG ) goto leftadr; /* make lhs addressable */ + order( p->right, INAREG|INBREG ); + return( 1 ); + } + +int crslab = 10000; + +getlab(){ + return( crslab++ ); + } + +deflab( l ){ + printf( "L%d:\n", l ); + } + +genargs( p) register NODE *p; { + register size; + + /* generate code for the arguments */ + + /* first, do the arguments on the right (last->first) */ + while( p->op == CM ){ + genargs( p->right ); + p->op = FREE; + p = p->left; + } + + if( p->op == STARG ){ /* structure valued argument */ + + size = p->stsize; + if( p->left->op == ICON ){ + /* make into a name node */ + p->op = FREE; + p= p->left; + p->op = NAME; + } + else { + /* make it look beautiful... */ + p->op = UNARY MUL; + canon( p ); /* turn it into an oreg */ + if( p->op != OREG ){ + offstar( p->left ); + canon( p ); + if( p->op != OREG ) cerror( "stuck starg" ); + } + } + + p->lval += size; /* end of structure */ + /* put on stack backwards */ + for( ; size>0; size -= 2 ){ + p->lval -= 2; + expand( p, RNOP, " mov AR,Z-\n" ); + } + reclaim( p, RNULL, 0 ); + return; + } + + /* ordinary case */ + + order( p, FORARG ); + } + +argsize( p ) register NODE *p; { + register t; + t = 0; + if( p->op == CM ){ + t = argsize( p->left ); + p = p->right; + } + if( p->type == DOUBLE || p->type == FLOAT ){ + SETOFF( t, 2 ); + return( t+8 ); + } + else if( p->type == LONG || p->type == ULONG ) { + SETOFF( t, 2); + return( t+4 ); + } + else if( p->op == STARG ){ + SETOFF( t, p->stalign ); /* alignment */ + return( t + p->stsize ); /* size */ + } + else { + SETOFF( t, 2 ); + return( t+2 ); + } + } diff --git a/usr/src/cmd/pcc/table.c b/usr/src/cmd/pcc/table.c new file mode 100644 index 0000000000..47e07c8332 --- /dev/null +++ b/usr/src/cmd/pcc/table.c @@ -0,0 +1,854 @@ +# include "mfile2" + +# define AWD SNAME|SOREG|SCON|STARNM|STARREG|SAREG +# define LWD SNAME|SOREG|SCON|SAREG + +struct optab table[] = { + +ASSIGN, INAREG|FOREFF|FORCC, + AWD, TPOINT|TINT|TUNSIGNED|TCHAR|TUCHAR, + SZERO, TANY, + 0, RLEFT|RRIGHT|RESCC, + " clrZB AL\n", + +ASSIGN, INAREG|FOREFF|FORCC, + AWD, TINT|TUNSIGNED, + AWD, TCHAR, + NAREG|NASR, RLEFT|RESC1|RESCC, + " movb AR,A1\n mov A1,AL\n", + +ASSIGN, INAREG|FOREFF|FORCC, + AWD, TINT|TUNSIGNED, + AWD, TUCHAR, + 0, RLEFT|RESCC, + " movb AR,AL\n bic $!377,AL\n", + +ASSIGN, INAREG|FOREFF|FORCC, + AWD, TPOINT|TINT|TUNSIGNED|TCHAR|TUCHAR, + AWD, TPOINT|TINT|TUNSIGNED|TCHAR|TUCHAR, + 0, RLEFT|RRIGHT|RESCC, + " movZB AR,AL\n", + +ASSIGN, INAREG|FOREFF, + LWD, TLONG|TULONG, + SZERO, TANY, + 0, RLEFT|RRIGHT, + " clr AL\n clr UL\n", + +ASSIGN, INAREG|FOREFF, + LWD, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RLEFT|RRIGHT, + " mov AR,AL\n mov UR,UL\n", + +ASSIGN, FOREFF|INAREG, + STARNM, TLONG|TULONG, + LWD, TLONG|TULONG, + NAREG|NASL, RRIGHT, + " mov ZU,A1\n mov AR,(A1)+\n mov UR,(A1)\n", + +ASSIGN, FOREFF, + STARNM, TLONG|TULONG, + AWD, TUNSIGNED|TPOINT, + NAREG|NASL, RRIGHT, + " mov ZU,A1\n clr (A1)+\n mov AR,(A1)\n", + +ASSIGN, FOREFF, + STARNM, TLONG|TULONG, + AWD, TINT, + NAREG|NASL, RRIGHT, + " mov ZU,A1\n mov AR,2(A1)\n sxt (A1)\n", + + /* PANIC! */ +ASSIGN, FOREFF|INAREG, + STARNM, TLONG|TULONG, + AWD, TUNSIGNED|TPOINT, + NAREG|NASL|NASR, RESC1, + "\tmov\tAR,-(sp)\n\tmov\tZU,A1\n\tclr\t(A1)+\n\tmov\t(sp)+,(A1)\ + \nF\tmov\t(A1),U1\nF\tclr\tA1\n", + +ASSIGN, FOREFF|INAREG, + STARNM, TLONG|TULONG, + AWD, TINT, + NAREG|NASL|NASR, RESC1, + "\tmov\tAR,-(sp)\n\tmov\tZU,A1\n\tmov\t(sp)+,2(A1)\nF\tmov\t2(A1),U1\ + \n\tsxt\t(A1)\nF\tsxt\tA1\n", + +ASSIGN, FOREFF|INAREG, + STARNM, TLONG|TULONG, + SAREG, TLONG|TULONG, + 0, RRIGHT, + " mov AR,AL\n mov ZU,AR\n mov UR,2(AR)\nF mov (AR),AR\n", + +ASSIGN, INAREG|FOREFF, + LWD, TLONG|TULONG, + AWD, TCHAR, + NAREG, RESC1, + " movb AR,U1\n mov U1,UL\n sxt AL\nF sxt A1\n", + +ASSIGN, INAREG|FOREFF, + LWD, TLONG|TULONG, + AWD, TUCHAR, + 0, RLEFT, + " movb AR,UL\n bic $!377,UL\n clr AL\n", + +ASSIGN, INAREG|FOREFF, + LWD, TLONG|TULONG, + AWD, TINT, + 0, RLEFT, + " mov AR,UL\n sxt AL\n", + +ASSIGN, INAREG|FOREFF, + LWD, TLONG|TULONG, + AWD, TUNSIGNED|TPOINT, + 0, RLEFT, + " mov AR,UL\n clr AL\n", + +ASSIGN, INBREG|INTBREG|FOREFF, + AWD, TDOUBLE, + SBREG, TDOUBLE, + 0, RRIGHT, + " movf AR,AL\n", + +ASSIGN, INBREG|INTBREG|FOREFF, + AWD, TFLOAT, + SBREG, TDOUBLE, + 0, RRIGHT, + " movfo AR,AL\n", + +ASSIGN, INAREG|FOREFF, + SFLD, TANY, + SZERO, TANY, + 0, RRIGHT, + " bic $M.,AL\n", + +ASSIGN, INTAREG|INAREG|FOREFF, + SFLD, TANY, + STAREG, TANY, + 0, RRIGHT, + "F\tmov\tAR,-(sp)\n\tash\t$H.,AR\n\tbic\t$!M.,AR\n\tbic\t$M.,AL\n\tbis\tAR,AL\nF\tmov\t(sp)+,AR\n", + +ASSIGN, INAREG|FOREFF, + SFLD, TANY, + AWD, TANY, + NAREG, RRIGHT, + "\tmov\tAR,A1\n\tash\t$H.,A1\n\tbic\t$!M.,A1\n\tbic\t$M.,AL\n\tbis\tA1,AL\n", + +ASSIGN, FOREFF, + AWD, TFLOAT, + AWD, TFLOAT, + NBREG, RESC1, + " movof AR,A1\n movfo A1,AL\n", + +/* put this here so UNARY MUL nodes match OPLTYPE when appropriate */ +UNARY MUL, INTAREG|INAREG, + SANY, TANY, + STARNM, TLONG|TULONG, + NAREG|NASR, RESC1, + " mov AL,U1\n mov (U1)+,A1\n mov (U1),U1\n", + +OPLTYPE, FOREFF, + SANY, TANY, + LWD, TANY, + 0, RRIGHT, + "", /* this entry throws away computations which don't do anything */ +OPLTYPE, INTAREG|INAREG, + SANY, TANY, + SZERO, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + NAREG|NASR, RESC1, + " clr A1\n", + +OPLTYPE, INTAREG|INAREG, + SANY, TANY, + SZERO, TLONG|TULONG, + NAREG|NASR, RESC1, + " clr A1\n clr U1\n", + +OPLTYPE, INTAREG|INAREG, + SANY, TANY, + SANY, TINT|TUNSIGNED|TPOINT|TCHAR, + NAREG|NASR, RESC1, + " movZB AR,A1\n", + +OPLTYPE, INTEMP, + SANY, TANY, + SANY, TINT|TUNSIGNED|TPOINT, + NTEMP, RESC1, + " mov AR,A1\n", + +OPLTYPE, FORCC, + SANY, TANY, + SANY, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + 0, RESCC, + " tstZB AR\n", + + +OPLTYPE, FORARG, + SANY, TANY, + SANY, TINT|TUNSIGNED|TPOINT, + 0, RNULL, + " mov AR,Z-\n", + +OPLTYPE, INTAREG|INAREG, + SANY, TANY, + AWD, TUCHAR, + NAREG|NASR, RESC1, + " movb AR,A1\n bic $!377,A1\n", + +OPLTYPE, INTAREG|INAREG, + SANY, TANY, + LWD, TLONG|TULONG, + NAREG, RESC1, + " mov UR,U1\n mov AR,A1\n", + +OPLTYPE, INTAREG|INAREG, /* for use when there are no free regs */ + SANY, TANY, + LWD, TLONG|TULONG, + NAREG|NASR, RESC1, + " mov AR,-(sp)\n mov UR,U1\n mov (sp)+,A1\n", + +OPLTYPE, INTEMP, + SANY, TANY, + LWD, TLONG|TULONG, + 2*NTEMP, RESC1, + " mov AR,A1\n mov UR,U1\n", + +OPLTYPE, FORCC, + SANY, TANY, + LWD, TLONG|TULONG, + 0, RESCC, + "ZA", + +OPLTYPE, FORARG, + SANY, TANY, + LWD, TLONG|TULONG, + 0, RNULL, + " mov UR,Z-\n mov AR,Z-\n", + +UNARY MUL, FORARG, + STARNM, TANY, + SANY, TLONG|TULONG, + NAREG|NASR, RNULL, + " mov AL,A1\n mov 2(A1),Z-\n mov (A1),Z-\n", + +OPLTYPE, FORARG, + SANY, TANY, + SBREG, TDOUBLE, + 0, RNULL, + " movf AR,Z4\n", + +OPLTYPE, INTBREG|INBREG, + SANY, TANY, + AWD, TDOUBLE, + NBREG, RESC1, + " movf AR,A1\n", + +OPLTYPE, INTEMP, + SANY, TANY, + SBREG, TDOUBLE, + 4*NTEMP, RESC1, + " movf AR,A1\n", + +OPLTYPE, FORCC, + SANY, TANY, + AWD, TDOUBLE, + 0, RESCC, + " tstf AR\n cfcc\n", + +OPLTYPE, INTBREG|INBREG, + SANY, TANY, + AWD, TFLOAT, + NBREG, RESC1, + " movof AR,A1\n", + +OPLTYPE, FORCC, + SANY, TANY, + AWD, TFLOAT, + NBREG, RESCC, + " movof AR,A1\n cfcc\n", + + +OPLOG, FORCC, + AWD, TPOINT|TINT|TUNSIGNED, + AWD, TPOINT|TINT|TUNSIGNED, + 0, RESCC, + " cmp AL,AR\nZI", + +OPLOG, FORCC, + AWD, TCHAR|TUCHAR, + AWD, TCHAR|TUCHAR, + 0, RESCC, + " cmpb AL,AR\nZI", + +OPLOG, FORCC, + AWD, TCHAR|TUCHAR, + SCCON, TINT, /* look for constants between -128 and 127 */ + 0, RESCC, + " cmpb AL,AR\nZI", + +OPLOG, FORCC, + LWD, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RESCC, + "ZCZI", + +OPLOG, FORCC, + SBREG, TDOUBLE, + AWD, TFLOAT, + NBREG, RESCC, + " movof AR,A1\n cmpf A1,AL\n cfcc\nZF", + +OPLOG, FORCC, + SBREG, TDOUBLE, + SBREG|AWD, TDOUBLE, + 0, RESCC, + " cmpf AR,AL\n cfcc\nZF", + +CCODES, INTAREG|INAREG, + SANY, TANY, + SANY, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + NAREG, RESC1, + " mov $1,A1\nZN", + +CCODES, INTAREG|INAREG, + SANY, TANY, + SANY, TLONG|TULONG, + NAREG, RESC1, + " clr A1\n mov $1,U1\nZN", + +UNARY MINUS, INTAREG|INAREG, + STAREG, TINT|TUNSIGNED, + SANY, TANY, + 0, RLEFT, + " neg AL\n", + +UNARY MINUS, INTAREG|INAREG, + STAREG, TLONG|TULONG, + SANY, TANY, + 0, RLEFT, + " neg AL\n neg UL\n sbc AL\n", + +UNARY MINUS, INTBREG|INBREG, + STBREG, TDOUBLE, + SANY, TANY, + 0, RLEFT, + " negf AL\n", + +COMPL, INTAREG|INAREG, + STAREG, TINT|TUNSIGNED, + SANY, TANY, + 0, RLEFT, + " com AL\n", + +INCR, INTAREG|INAREG|FOREFF, + AWD, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + SONE, TANY, + NAREG, RESC1, + "F movZB AL,A1\n incZB AL\n", + +DECR, INTAREG|INAREG|FOREFF, + AWD, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + SONE, TANY, + NAREG, RESC1, + "F movZB AL,A1\n decZB AL\n", + +INCR, INTAREG|INAREG|FOREFF, + AWD, TINT|TUNSIGNED|TPOINT, + SCON, TANY, + NAREG, RESC1, + "F mov AL,A1\n add AR,AL\n", + +DECR, INTAREG|INAREG|FOREFF, + AWD, TINT|TUNSIGNED|TPOINT, + SCON, TANY, + NAREG, RESC1, + "F mov AL,A1\n sub AR,AL\n", + +INCR, INTAREG|INAREG|FOREFF, + LWD, TLONG|TULONG, + SCON, TANY, + NAREG, RESC1, + "F mov AL,A1\nF mov UL,U1\n add AR,AL\n add UR,UL\n adc AL\n", + +DECR, INTAREG|INAREG|FOREFF, + LWD, TLONG|TULONG, + SCON, TANY, + NAREG, RESC1, + "F mov AL,A1\nF mov UL,U1\n sub AR,AL\n sub UR,UL\n sbc AL\n", + +COMPL, INTAREG|INAREG, + STAREG, TLONG|TULONG, + SANY, TANY, + 0, RLEFT, + " com AL\n com UL\n", + +AND, FORCC, + AWD, TINT|TUNSIGNED|TPOINT, + SCON, TANY, + 0, RESCC, + " bit AL,$Z~\n", + +ASG MUL, INAREG, + STAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + NAREG, RLEFT, + " mul AR,AL\n", + +ASG DIV, INAREG, + STAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + NAREG, RESC1, + "ZV div AR,r0\n", /* since lhs must be in r1 */ + +ASG MOD, INAREG, + STAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + NAREG, RLEFT, + "ZV div AR,r0\n", /* since lhs must be in r1 */ + +ASG PLUS, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + SONE, TINT, + 0, RLEFT|RESCC, + " incZB AL\n", + +ASG PLUS, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT|RESCC, + " add AR,AL\n", + +ASG MINUS, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + SONE, TINT, + 0, RLEFT|RESCC, + " decZB AL\n", + +ASG MINUS, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT|RESCC, + " sub AR,AL\n", + +ASG OR, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT|RESCC, + " bis AR,AL\n", + +/* AND transformed to "pdp11 bic" in first pass. */ +ASG AND, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT|RESCC, + " bic AR,AL\n", + +ASG ER, INAREG|FORCC, + AWD, TINT|TUNSIGNED|TPOINT, + SAREG, TINT|TUNSIGNED|TPOINT, + 0, RLEFT|RESCC, + " xor AR,AL\n", + +ASG OPSHFT, INAREG, + SAREG, TINT|TUNSIGNED|TPOINT, + SONE, TINT, + 0, RLEFT, + " OI AL\nZH", + +ASG LS, INAREG, + SAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT, + " ash AR,AL\n", + +ASG RS, INAREG, + SAREG, TINT|TUNSIGNED|TPOINT, + SCON, TANY, + 0, RLEFT, + " ash $ZM,AL\nZH", + +ASG RS, INAREG, + SAREG, TINT|TUNSIGNED|TPOINT, + STAREG, TINT|TUNSIGNED|TPOINT, + 0, RLEFT, + " neg AR\n ash AR,AL\nZH", + +ASG RS, INAREG, + SAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + NAREG|NASR, RLEFT, + " mov AR,A1\n neg A1\n ash A1,AL\nZH", + +ASG RS, INAREG, + SAREG, TINT, + AWD, TINT, + 0, RLEFT, + " mov AR,-(sp)\n neg (sp)\n ash (sp)+,AL\nZH", + +ASG RS, INAREG, + SAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + NTEMP, RLEFT, + " mov AR,A1\n neg A1\n ash A1,AL\nZH", + +ASG OR, INAREG|FORCC, + AWD, TCHAR|TUCHAR, + AWD, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " bisb AR,AL\n", + +/* AND transformed to "pdp11 bic" in first pass. */ +ASG AND, INAREG|FORCC, + AWD, TCHAR|TUCHAR, + AWD, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " bicb AR,AL\n", + +ASG PLUS, INAREG, + LWD, TLONG|TULONG, + SICON, TINT|TLONG|TULONG, + 0, RLEFT, + " add UR,UL\n adc AL\n", + +ASG PLUS, INAREG, + STARNM, TLONG|TULONG, + LWD, TLONG|TULONG, + NAREG, RLEFT, + " mov ZU,A1\n add AR,(A1)+\n add UR,(A1)\n adc -(A1)\n", + +ASG PLUS, INAREG, + LWD, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RLEFT, + " add AR,AL\n add UR,UL\n adc AL\n", + +ASG PLUS, INAREG, + AWD, TPOINT, + LWD, TLONG|TULONG, + 0, RLEFT, + " add UR,AL\n", + +ASG MINUS, INAREG, + LWD, TLONG|TULONG, + SICON, TINT|TLONG|TULONG, + 0, RLEFT, + " sub UR,UL\n sbc AL\n", + +ASG MINUS, INAREG, + STARNM, TLONG|TULONG, + LWD, TLONG|TULONG, + NAREG, RLEFT, + " mov ZU,A1\n sub AR,(A1)+\n sub UR,(A1)\n sbc -(A1)\n", + +ASG MINUS, INAREG, + LWD, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RLEFT, + " sub AR,AL\n sub UR,UL\n sbc AL\n", + +ASG MINUS, INAREG, + AWD, TPOINT, + LWD, TLONG|TULONG, + 0, RLEFT, + " sub UR,AL\n", + +ASG OR, INAREG, + LWD, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RLEFT, + " bis AR,AL\n bis UR,UL\n", + +/* AND transformed to "pdp11 bic" in first pass. */ +ASG AND, INAREG, + LWD, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RLEFT, + " bic AR,AL\n bic UR,UL\n", + +ASG ER, INAREG, + LWD, TLONG|TULONG, + SAREG, TLONG|TULONG, + 0, RLEFT, + " xor AR,AL\n xor UR,UL\n", + + /* table entries for ^ which correspond to the usual way of doing busingess + (rhs in a temp register */ + +ASG ER, INAREG|INTAREG, + STAREG, TLONG|TULONG, + LWD, TLONG|TULONG, + 0, RLEFT, + "\tmov\tAL,-(sp)\n\tmov\tUR,AL\n\txor\tAL,UL\n\tmov\tAR,AL\n\txor\tAL,(sp)\n\tmov\t(sp)+,AL\n", + +ASG ER, INAREG|INTAREG, + STAREG, TINT|TUNSIGNED|TPOINT, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT, + "\tmov\tAL,-(sp)\n\tmov\tAR,AL\n\txor\tAL,(sp)\n\tmov\t(sp)+,AL\n", + +ASG LS, INAREG, + SAREG, TLONG|TULONG, + AWD, TINT|TUNSIGNED|TPOINT, + 0, RLEFT, + " ashc AR,AL\n", + +ASG RS, INAREG, + SAREG, TLONG|TULONG, + SCON, TANY, + 0, RLEFT, + " ashc $ZM,AL\nZH", + +ASG RS, INAREG, + SAREG, TLONG|TULONG, + STAREG, TINT|TUNSIGNED|TPOINT, + 0, RLEFT, + " neg AR\n ashc AR,AL\nZH", + +ASG RS, INAREG, + SAREG, TLONG|TULONG, + AWD, TINT|TUNSIGNED|TPOINT, + NAREG|NASR, RLEFT, + " mov AR,A1\n neg A1\n ashc A1,AL\nZH", + +ASG RS, INAREG, + SAREG, TLONG|TULONG, + AWD, TINT|TUNSIGNED|TPOINT, + NTEMP, RLEFT, + " mov AR,A1\n neg A1\n ashc A1,AL\nZH", + +ASG OPFLOAT, INBREG|INTBREG, + STBREG, TDOUBLE, + SBREG|AWD, TDOUBLE, + 0, RLEFT|RESCC, + " OF AR,AL\n", + +ASG OPFLOAT, INBREG|INTBREG, + STBREG, TDOUBLE, + AWD, TFLOAT, + NBREG|NBSR, RLEFT|RESCC, + " movof AR,A1\n OF A1,AL\n", + +ASG OPFLOAT, FORCC, + STBREG, TDOUBLE, + SBREG|AWD, TDOUBLE, + 0, RESCC, + " OF AR,AL\n cfcc\n", + +ASG OPFLOAT, FORCC, + STBREG, TDOUBLE, + AWD, TFLOAT, + NBREG|NBSR, RESCC, + " movof AR,A1\n OF A1,AL\n cfcc\n", + +UNARY CALL, INTAREG, + SAREG|SNAME|SOREG|SCON, TANY, + SANY, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR|TLONG|TULONG, + NAREG|NASL, RESC1, /* should be register 0 */ + " jsr pc,*AL\n", + +UNARY CALL, INTBREG, + SAREG|SNAME|SOREG|SCON, TANY, + SANY, TDOUBLE|TFLOAT, + NBREG, RESC1, /* should be register FR0 */ + " jsr pc,*AL\n", + +SCONV, INTAREG, + STAREG, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + SANY, TUCHAR, + 0, RLEFT, + " bic $!377,AL\n", + +SCONV, INTAREG, + AWD, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + SANY, TCHAR|TINT, + NAREG|NASL, RESC1, + " movZB AL,A1\n", + +SCONV, INAREG|INTAREG, + LWD, TLONG|TULONG, + SANY, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + 0, RLEFT, + "ZT", + +SCONV, INTAREG, + AWD, TUCHAR, + SANY, TLONG|TULONG, + NAREG|NASL, RESC1, + " movb AL,U1\n bic $!377,U1\n clr A1\n", + +SCONV, INTAREG, + AWD, TINT, + SANY, TLONG|TULONG, + NAREG|NASL, RESC1, + " mov AL,U1\n sxt A1\n", + +SCONV, INTAREG, + AWD, TUNSIGNED|TPOINT, + SANY, TLONG|TULONG, + NAREG|NASL, RESC1, + " mov AL,U1\n clr A1\n", + +SCONV, INTAREG, + SBREG, TDOUBLE, + SANY, TINT|TUNSIGNED|TPOINT|TCHAR|TUCHAR, + NAREG, RESC1, + " movfi AL,A1\n", + +SCONV, INTAREG, + STBREG, TDOUBLE, + SANY, TLONG|TULONG, + NAREG, RESC1, + " setl\n movfi AL,-(sp)\n seti\n mov (sp)+,A1\n mov (sp)+,U1\n", + +SCONV, FORARG, + STBREG, TDOUBLE, + SANY, TLONG|TULONG, + 0, RNULL, + " setl\n movfi AL,Z4\n seti\n", + +SCONV, INTBREG, + SAREG, TLONG, + SANY, TANY, + NBREG, RESC1, + "\tmov\tUL,-(sp)\n\tmov\tAL,-(sp)\n\tsetl\n\tmovif\t(sp)+,A1\n\tseti\n", + +SCONV, INTBREG, + LWD, TLONG, + SANY, TANY, + NBREG, RESC1, + "\tsetl\n\tmovif\tAL,A1\n\tseti\n", + +SCONV, INTBREG, + AWD, TINT, + SANY, TANY, + NBREG, RESC1, + " movif AL,A1\n", + +SCONV, INTBREG, + SAREG, TULONG, + SANY, TANY, + NBREG, RESC1, + "\tmov\tUL,-(sp)\n\tmov\tAL,-(sp)\n\tsetl\n\tmovif\t(sp)+,A1\n\tseti\n\tcfcc\n\tbpl\t1f\n\taddf\t$050200,A1\n1:\n", + +SCONV, INTBREG, + LWD, TULONG, + SANY, TANY, + NBREG, RESC1, + "\tsetl\n\tmovif\tAL,A1\n\tseti\n\tcfcc\n\tbpl\t1f\n\taddf\t$050200,A1\n1:\n", + +SCONV, INTBREG, + STAREG, TUNSIGNED|TPOINT, + SANY, TANY, + NBREG, RESC1, + "\tmovif\tAL,A1\n\tcfcc\n\tbpl\t1f\n\taddf\t$044200,A1\n1:\n", + +PCONV, INTAREG, + AWD, TCHAR|TUCHAR, + SANY, TPOINT, + NAREG|NASL, RESC1, + " movb AL,A1\n", + +PCONV, INAREG|INTAREG, + LWD, TLONG|TULONG, + SANY, TPOINT, + 0, RLEFT, + "ZT", + +STARG, FORARG, + SNAME|SOREG, TANY, + SANY, TANY, + 0, RNULL, + "ZS", + +STASG, FOREFF, + SNAME|SOREG, TANY, + SCON|SAREG, TANY, + 0, RNOP, + "ZS", + +STASG, INTAREG|INAREG, + SNAME|SOREG, TANY, + STAREG, TANY, + 0, RRIGHT, + "ZS", + +STASG, INAREG|INTAREG, + SNAME|SOREG, TANY, + SCON|SAREG, TANY, + NAREG, RESC1, + "ZS mov AR,A1\n", + +INIT, FOREFF, + SCON, TANY, + SANY, TINT|TUNSIGNED|TPOINT, + 0, RNOP, + " CL\n", + +INIT, FOREFF, + SCON, TANY, + SANY, TLONG|TULONG, + 0, RNOP, + "ZL", + +INIT, FOREFF, + SCON, TANY, + SANY, TCHAR|TUCHAR, + 0, RNOP, + " .byte CL\n", + + /* for the use of fortran only */ + +GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jbr CL\n", + +GOTO, FOREFF, + SNAME, TLONG|TULONG, + SANY, TANY, + 0, RNOP, + " jmp *UL\n", + +GOTO, FOREFF, + SNAME, TINT|TUNSIGNED|TCHAR|TUCHAR|TPOINT, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", + + /* Default actions for hard trees ... */ + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +UNARY MUL, DF( UNARY MUL ), + +INCR, DF(INCR), + +DECR, DF(INCR), + +ASSIGN, DF(ASSIGN), + +STASG, DF(STASG), + +OPLEAF, DF(NAME), + +OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, BITYPE, + "", + +OPLOG, DF(NOT), + +COMOP, DF(COMOP), + +INIT, DF(INIT), + +OPUNARY, DF(UNARY MINUS), + + +ASG OPANY, DF(ASG PLUS), + +OPANY, DF(BITYPE), + +FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }; -- 2.20.1