/* Copyright (c) 1979 Regents of the University of California */
static char sccsid
[] = "@(#)fend.c 1.21 2/28/83";
* this array keeps the pxp counters associated with
* functions and procedures, so that they can be output
* when their bodies are encountered
* finish a block by generating
* the code for the statements.
* It then looks for unresolved declarations
* of labels, procedures and functions,
* and cleans up the name list.
* For the program, it checks the
* semantics of the program
funcend(fp
, bundle
, endline
)
struct entry_exit_cookie eecookie
;
line
= program
->value
[3];
* Patch the branch to the
* entry point of the function
patch4(fp
->value
[NL_ENTLOC
]);
* Put out the block entrance code and the block name.
* HDRSZE is the number of bytes of info in the static
* BEG data area exclusive of the proc name. It is
/* long framesze; /* number of bytes of local vars */
/* long nargs; /* number of bytes of arguments */
/* bool tests; /* TRUE => perform runtime tests */
/* short offset; /* offset of procedure in source file */
/* char name[1]; /* name of active procedure */
# define HDRSZE (2 * sizeof(long) + sizeof(short) + sizeof(bool))
var
= put(2, ((lenstr(fp
->symbol
,0) + HDRSZE
) << 8)
| (cbn
== 1 && opt('p') == 0 ? O_NODUMP
: O_BEG
), (long)0);
* output the number of bytes of arguments
* this is only checked on formal calls.
put(2, O_CASE4
, cbn
== 1 ? (long)0 : (long)(fp
->value
[NL_OFFS
]-DPOFF2
));
* Output the runtime test mode for the routine
put(2, sizeof(bool) == 2 ? O_CASE2
: O_CASE4
, opt('t') ? TRUE
: FALSE
);
* Output line number and routine name
put(2, O_CASE2
, bundle
[1]);
* put out the procedure entry code
if ( fp
-> class == PROG
) {
* If there is a label declaration in the main routine
* then there may be a non-local goto to it that does
* not appear in this module. We have to assume that
* such a reference may occur and generate code to
if ( parts
[ cbn
] & LPRT
) {
parts
[ cbn
] |= ( NONLOCALVAR
| NONLOCALGOTO
);
ftnno
= fp
-> value
[NL_ENTLOC
];
prog_prologue(&eecookie
);
stabfunc( "program" , fp
-> class , bundle
[1] , 0 );
ftnno
= fp
-> value
[NL_ENTLOC
];
stabfunc( fp
-> symbol
, fp
-> class , bundle
[1] , cbn
- 1 );
for ( p
= fp
-> chain
; p
!= NIL
; p
= p
-> chain
) {
stabparam( p
-> symbol
, p2type( p
-> type
)
, p
-> value
[ NL_OFFS
] , lwidth( p
-> type
) );
if ( fp
-> class == FUNC
) {
* stab the function variable
p
= fp
-> ptr
[ NL_FVAR
];
stablvar( p
-> symbol
, p2type( p
-> type
) , cbn
, p
-> value
[ NL_OFFS
] , lwidth( p
-> type
) );
* rummage down hash chain links.
for ( i
= 0 ; i
<= 077 ; i
++ ) {
for ( p
= disptab
[ i
] ; p
!= NIL
; p
= p
->nl_next
) {
if ( ( p
-> nl_block
& 037 ) != cbn
) {
* that's named variables, but not params
if ( ( p
-> symbol
!= NIL
)
&& ( p
-> value
[ NL_OFFS
] < 0 ) ) {
stablvar( p
-> symbol
, p2type( p
-> type
) , cbn
, p
-> value
[ NL_OFFS
] , lwidth( p
-> type
) );
* ask second pass to allocate known locals
putlbracket(ftnno
, &sizes
[cbn
]);
if ( fp
-> value
[ NL_CNTR
] != 0 ) {
inccnt( fp
-> value
[ NL_CNTR
] );
inccnt( bodycnts
[ fp
-> nl_block
& 037 ] );
* The glorious buffers option.
* 0 = don't buffer output
* 2 = 512 byte buffer output
put(1, O_BUFF
| opt('b') << 8);
, ADDTYPE( P2FTN
| P2INT
, P2PTR
) , "_BUFF" );
putleaf( P2ICON
, opt( 'b' ) , 0 , P2INT
, 0 );
putdot( filename
, line
);
for (p
= fp
->chain
; p
!= NIL
; p
= p
->chain
) {
if (strcmp(p
->symbol
, input
->symbol
) == 0) {
if (strcmp(p
->symbol
, output
->symbol
) == 0) {
iop
= lookup1(p
->symbol
);
if (iop
== NIL
|| bn
!= cbn
) {
error("File %s listed in program statement but not declared", p
->symbol
);
error("File %s listed in program statement but declared as a %s", p
->symbol
, classes
[iop
->class]);
if (iop
->type
->class != FILET
) {
error("File %s listed in program statement but defined as %s",
p
->symbol
, nameof(iop
->type
));
put(2, O_CON24
, text(iop
->type
) ? 0 : width(iop
->type
->type
));
put(2, O_LV
| bn
<<8+INDX
, (int)iop
->value
[NL_OFFS
]);
, ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putLV( p
-> symbol
, bn
, iop
-> value
[NL_OFFS
] ,
iop
-> extra_flags
, p2type( iop
) );
putCONG( p
-> symbol
, strlen( p
-> symbol
)
putop( P2LISTOP
, P2INT
);
putleaf( P2ICON
, strlen( p
-> symbol
)
putop( P2LISTOP
, P2INT
);
, text(iop
->type
) ? 0 : width(iop
->type
->type
)
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
* Process the prog/proc/func body
pPointer Body
= tCopy( blk
);
pDEF( PorFHeader
[ nesting
-- ] ).PorFBody
= Body
;
if (cbn
== 1 && monflg
!= 0) {
patchfil(cntpatch
- 2, (long)cnts
, 2);
patchfil(nfppatch
- 2, (long)pfcnt
, 2);
if ( fp
-> class == PROG
&& monflg
) {
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putleaf( P2ICON
, cnts
, 0 , P2INT
, 0 );
putleaf( P2ICON
, pfcnt
, 0 , P2INT
, 0 );
putop( P2LISTOP
, P2INT
);
putLV( PCPCOUNT
, 0 , 0 , NGLOBAL
, P2INT
);
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
* Clean up the symbol table displays and check for unresolves
if (fp
->class == PROG
&& inp
== 0 && (input
->nl_flags
& (NUSED
|NMOD
)) != 0) {
error("Input is used but not defined in the program statement");
if (fp
->class == PROG
&& out
== 0 && (output
->nl_flags
& (NUSED
|NMOD
)) != 0) {
error("Output is used but not defined in the program statement");
chkref
= syneflg
== errcnt
[cbn
] && opt('w') == 0;
for (i
= 0; i
<= 077; i
++) {
for (p
= disptab
[i
]; p
!= NIL
&& (p
->nl_block
& 037) == b
; p
= p
->nl_next
) {
* Check for variables defined
if (chkref
&& p
->symbol
!= NIL
)
* If the corresponding record is
* unused, we shouldn't complain about
if ((p
->nl_flags
& (NUSED
|NMOD
)) == 0) {
nerror("%s %s is neither used nor set", classes
[p
->class], p
->symbol
);
* If a var parameter is either
* modified or used that is enough.
if ((p
->nl_flags
& NUSED
) == 0) {
nerror("%s %s is never used", classes
[p
->class], p
->symbol
);
if (((p
->nl_flags
& NUSED
) == 0) && ((p
->extra_flags
& NEXTERN
) == 0)) {
nerror("%s %s is never used", classes
[p
->class], p
->symbol
);
if ((p
->nl_flags
& NMOD
) == 0) {
nerror("%s %s is used but never set", classes
[p
->class], p
->symbol
);
if (p
->chain
->ud_next
== NIL
)
if (p
->value
[NL_KINDS
] & ISUNDEF
)
nerror("%s undefined on line%s", p
->symbol
, cp
);
nerror("%s improperly used on line%s", p
->symbol
, cp
);
if ((p
->nl_flags
& NFORWD
))
nerror("Unresolved forward declaration of %s %s", classes
[p
->class], p
->symbol
);
if ((p
->nl_flags
& NFORWD
) && ((p
->extra_flags
& NEXTERN
) == 0))
nerror("Unresolved forward declaration of %s %s", classes
[p
->class], p
->symbol
);
if (p
->nl_flags
& NFORWD
)
nerror("label %s was declared but not defined", p
->symbol
);
if ((p
->nl_flags
& NMOD
) == 0)
nerror("No assignment to the function variable");
if (fp
-> class != PROG
) {
fp_formalentry(&eecookie
);
* declare pcp counters, if any
if ( monflg
&& fp
-> class == PROG
) {
putprintf( " .data" , 0 );
putprintf( " .comm " , 1 );
putprintf( PCPCOUNT
, 1 );
putprintf( ",%d" , 0 , ( cnts
+ 1 ) * sizeof (long) );
putprintf( " .text" , 0 );
dumpnl(fp
->ptr
[2], fp
->symbol
);
* save the namelist for the debugger pdx
savenl(fp
->ptr
[2], fp
->symbol
);
* the proper variable size
patchfil(var
, leven(-sizes
[cbn
].om_max
), 2);
if (inpflist(fp
->symbol
)) {
* construct the long name of a function based on it's static nesting.
* into a caller-supplied buffer (that should be about BUFSIZ big).
sextname( buffer
, name
, level
)
for ( i
= 1 ; i
< level
; i
++ ) {
sprintf( starthere
, EXTFORMAT
, enclosing
[ i
] );
starthere
+= strlen( enclosing
[ i
] ) + 1;
sprintf( starthere
, EXTFORMAT
, name
);
starthere
+= strlen( name
) + 1;
if ( starthere
>= &buffer
[ BUFSIZ
] ) {
putprintf(" .text" , 0 );
putprintf(" .align 1" , 0 );
putprintf(" .globl _main" , 0 );
putprintf("_main:" , 0 );
putprintf(" .word 0" , 0 );
putprintf(" pushl $1" , 0 );
putprintf(" pushl $0" , 0 );
putprintf(" calls $1,_PCSTART" , 0 );
putprintf(" movl 4(ap),__argc" , 0 );
putprintf(" movl 8(ap),__argv" , 0 );
putprintf(" calls $0,_program" , 0 );
putprintf(" pushl $0" , 0 );
putprintf(" calls $1,_PCEXIT" , 0 );
* prologue for the program.
* doesn't have formal entry point
struct entry_exit_cookie
*eecookiep
;
putprintf(" .text" , 0 );
putprintf(" .align 1" , 0 );
putprintf(" .globl _program" , 0 );
putprintf("_program:" , 0 );
eecookiep
-> savlabel
= getlab();
putprintf(" .word %s%d", 0, SAVE_MASK_LABEL
, eecookiep
-> savlabel
);
struct entry_exit_cookie
*eecookiep
;
int ftnno
= eecookiep
-> nlp
-> value
[NL_ENTLOC
];
sextname( eecookiep
-> extname
, eecookiep
-> nlp
-> symbol
, cbn
- 1 );
putprintf( " .text" , 0 );
putprintf( " .align 1" , 0 );
putprintf( " .globl %s%s", 0, FORMALPREFIX
, eecookiep
-> extname
);
putprintf( " .globl %s" , 0 , eecookiep
-> extname
);
putprintf( "%s:" , 0 , eecookiep
-> extname
);
eecookiep
-> savlabel
= getlab();
putprintf(" .word %s%d", 0, SAVE_MASK_LABEL
, eecookiep
-> savlabel
);
* code before any user code.
* or code that is machine dependent.
struct entry_exit_cookie
*eecookiep
;
int ftnno
= eecookiep
-> nlp
-> value
[NL_ENTLOC
];
int proflabel
= getlab();
* top of code; destination of jump from formal entry code.
eecookiep
-> toplabel
= getlab();
putlab( eecookiep
-> toplabel
);
putprintf(" subl2 $%s%d,sp" , 0 , FRAME_SIZE_LABEL
, ftnno
);
* call mcount for profiling
putprintf( " moval " , 1 );
putprintf( PREFIXFORMAT
, 1 , LABELPREFIX
, proflabel
);
putprintf( " jsb mcount" , 0 );
putprintf( " .data" , 0 );
putprintf( " .align 2" , 0 );
putprintf( " .long 0" , 0 );
putprintf( " .text" , 0 );
* if there are nested procedures that access our variables
* we must save the display.
if ( parts
[ cbn
] & NONLOCALVAR
) {
putprintf( " movq %s+%d,%d(%s)" , 0
, DISPLAYNAME
, cbn
* sizeof(struct dispsave
)
, DSAVEOFFSET
, P2FPNAME
);
* set up new display by saving AP and FP in appropriate
* slot in display structure.
putprintf( " movq %s,%s+%d" , 0
, P2APNAME
, DISPLAYNAME
, cbn
* sizeof(struct dispsave
) );
* set underflow checking if runtime tests
putprintf( " bispsw $0xe0" , 0 );
* zero local variables if checking is on
* by calling blkclr( bytes of locals , starting local address );
if ( opt( 't' ) && ( -sizes
[ cbn
].om_max
) > DPOFF1
) {
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putLV( 0 , cbn
, sizes
[ cbn
].om_max
, NLOCAL
, P2CHAR
);
putleaf( P2ICON
, ( -sizes
[ cbn
].om_max
) - DPOFF1
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
* set up goto vector if non-local goto to this frame
if ( parts
[ cbn
] & NONLOCALGOTO
) {
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putLV( 0 , cbn
, GOTOENVOFFSET
, NLOCAL
, P2PTR
|P2STRTY
);
putleaf( P2ICON
, 0 , 0 , P2INT
, 0 );
putleaf( P2ICON
, setjmp0
, 0 , P2INT
, 0 );
putop( P2CBRANCH
, P2INT
);
putdot( filename
, line
);
* on non-local goto, setjmp returns with address to
putprintf( " jmp (r0)" , 0 );
struct entry_exit_cookie
*eecookiep
;
* if there were file variables declared at this level
* call PCLOSE( ap ) to clean them up.
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putleaf( P2REG
, 0 , P2AP
, ADDTYPE( P2CHAR
, P2PTR
) , 0 );
putdot( filename
, line
);
* the function variable is the return value.
* if it's a scalar valued function, return scalar,
* else, return a pointer to the structure value.
if ( eecookiep
-> nlp
-> class == FUNC
) {
struct nl
*fvar
= eecookiep
-> nlp
-> ptr
[ NL_FVAR
];
long fvartype
= p2type( fvar
-> type
);
char labelname
[ BUFSIZ
];
switch ( classify( fvar
-> type
) ) {
putRV( fvar
-> symbol
, ( fvar
-> nl_block
) & 037 ,
fvar
-> value
[ NL_OFFS
] ,
sprintf( labelname
, PREFIXFORMAT
, LABELPREFIX
, label
);
putprintf( " .data" , 0 );
putprintf( " .lcomm %s,%d" , 0 ,
labelname
, lwidth( fvar
-> type
) );
putprintf( " .text" , 0 );
putleaf( P2NAME
, 0 , 0 , fvartype
, labelname
);
putLV( fvar
-> symbol
, ( fvar
-> nl_block
) & 037 ,
fvar
-> value
[ NL_OFFS
] ,
putstrop( P2STASG
, fvartype
, lwidth( fvar
-> type
) ,
putdot( filename
, line
);
putleaf( P2ICON
, 0 , 0 , fvartype
, labelname
);
putop( P2FORCE
, fvartype
);
putdot( filename
, line
);
* if there are nested procedures we must save the display.
if ( parts
[ cbn
] & NONLOCALVAR
) {
* restore old display entry from save area
putprintf( " movq %d(%s),%s+%d" , 0
, DISPLAYNAME
, cbn
* sizeof(struct dispsave
) );
struct entry_exit_cookie
*eecookiep
;
* set the register save mask.
putprintf(" .set %s%d,0x%x", 0,
SAVE_MASK_LABEL
, eecookiep
-> savlabel
, savmask());
fp_formalentry(eecookiep
)
struct entry_exit_cookie
*eecookiep
;
putprintf("%s%s:" , 0 , FORMALPREFIX
, eecookiep
-> extname
);
putprintf(" .word %s%d", 0, SAVE_MASK_LABEL
, eecookiep
-> savlabel
);
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
) , "_FCALL" );
eecookiep
-> nlp
-> value
[ NL_OFFS
] + sizeof( struct formalrtn
* ) ,
NPARAM
, P2PTR
| P2STRTY
);
putRV(0, cbn
, eecookiep
-> nlp
-> value
[NL_OFFS
], NPARAM
, P2PTR
|P2STRTY
);
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
putjbr( eecookiep
-> toplabel
);
putprintf(" .globl _main", 0);
putprintf(" link %s,#0", 0, P2FPNAME
);
putprintf(" jbsr _PCSTART", 0);
putprintf(" addql #4,sp", 0);
putprintf(" movl %s@(8),__argc", 0, P2FPNAME
);
putprintf(" movl %s@(12),__argv", 0, P2FPNAME
);
putprintf(" jbsr _program", 0);
putprintf(" jbsr _PCEXIT", 0);
struct entry_exit_cookie
*eecookiep
;
int ftnno
= eecookiep
-> nlp
-> value
[NL_ENTLOC
];
putprintf(" .globl _program", 0);
putprintf("_program:", 0);
putprintf(" link %s,#0", 0, P2FPNAME
);
putprintf(" addl #-%s%d,sp", 0, FRAME_SIZE_LABEL
, ftnno
);
/* touch new end of stack, to break more stack space */
putprintf(" tstb sp@(-%s%d)", 0, PAGE_BREAK_LABEL
, ftnno
);
putprintf(" moveml #%s%d,sp@", 0, SAVE_MASK_LABEL
, ftnno
);
struct entry_exit_cookie
*eecookiep
;
int ftnno
= eecookiep
-> nlp
-> value
[NL_ENTLOC
];
sextname(eecookiep
-> extname
, eecookiep
-> nlp
-> symbol
, cbn
- 1);
putprintf(" .globl %s%s", 0, FORMALPREFIX
, eecookiep
-> extname
);
putprintf(" .globl %s", 0, eecookiep
-> extname
);
putprintf("%s:", 0, eecookiep
-> extname
);
putprintf(" link %s,#0", 0, P2FPNAME
);
putprintf(" addl #-%s%d,sp", 0, FRAME_SIZE_LABEL
, ftnno
);
/* touch new end of stack, to break more stack space */
putprintf(" tstb sp@(-%s%d)", 0, PAGE_BREAK_LABEL
, ftnno
);
putprintf(" moveml #%s%d,sp@", 0, SAVE_MASK_LABEL
, ftnno
);
struct entry_exit_cookie
*eecookiep
;
int proflabel
= getlab();
* fill in the label cookie
eecookiep
-> toplabel
= getlab();
putlab(eecookiep
-> toplabel
);
* call mcount if we are profiling.
putprintf(" movl #%s%d,a0", 0, LABELPREFIX
, proflabel
);
putprintf(" jsr mcount", 0);
putprintf(" .long 0", 0);
* if there are nested procedures that access our variables
* we must save the display
if (parts
[cbn
] & NONLOCALVAR
) {
putprintf(" movl %s+%d,%s@(%d)", 0,
DISPLAYNAME
, cbn
* sizeof(struct dispsave
),
* set up the new display by saving the framepointer
* in the display structure.
putprintf(" movl %s,%s+%d", 0,
P2FPNAME
, DISPLAYNAME
, cbn
* sizeof(struct dispsave
));
* zero local variables if checking is on
* by calling blkclr( bytes of locals , starting local address );
if ( opt( 't' ) && ( -sizes
[ cbn
].om_max
) > DPOFF1
) {
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putLV( 0 , cbn
, sizes
[ cbn
].om_max
, NLOCAL
, P2CHAR
);
putleaf( P2ICON
, ( -sizes
[ cbn
].om_max
) - DPOFF1
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
* set up goto vector if non-local goto to this frame
if ( parts
[ cbn
] & NONLOCALGOTO
) {
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putLV( 0 , cbn
, GOTOENVOFFSET
, NLOCAL
, P2PTR
|P2STRTY
);
putleaf( P2ICON
, 0 , 0 , P2INT
, 0 );
putleaf( P2ICON
, setjmp0
, 0 , P2INT
, 0 );
putop( P2CBRANCH
, P2INT
);
putdot( filename
, line
);
* on non-local goto, setjmp returns with address to
putprintf(" movl d0,a0", 0);
putprintf(" jmp a0@", 0);
struct entry_exit_cookie
*eecookiep
;
* if there were file variables declared at this level
* call PCLOSE( ap ) to clean them up.
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
)
putleaf( P2REG
, 0 , P2AP
, ADDTYPE( P2CHAR
, P2PTR
) , 0 );
putdot( filename
, line
);
* the function variable is the return value.
* if it's a scalar valued function, return scalar,
* else, return a pointer to the structure value.
if ( eecookiep
-> nlp
-> class == FUNC
) {
struct nl
*fvar
= eecookiep
-> nlp
-> ptr
[ NL_FVAR
];
long fvartype
= p2type( fvar
-> type
);
char labelname
[ BUFSIZ
];
switch ( classify( fvar
-> type
) ) {
putRV( fvar
-> symbol
, ( fvar
-> nl_block
) & 037 ,
fvar
-> value
[ NL_OFFS
] ,
sprintf( labelname
, PREFIXFORMAT
, LABELPREFIX
, label
);
putprintf(" .lcomm %s,%d", 0,
labelname
, lwidth(fvar
-> type
));
putleaf( P2NAME
, 0 , 0 , fvartype
, labelname
);
putLV( fvar
-> symbol
, ( fvar
-> nl_block
) & 037 ,
fvar
-> value
[ NL_OFFS
] ,
putstrop( P2STASG
, fvartype
, lwidth( fvar
-> type
) ,
putdot( filename
, line
);
putleaf( P2ICON
, 0 , 0 , fvartype
, labelname
);
putop( P2FORCE
, fvartype
);
putdot( filename
, line
);
* if we saved a display, we must restore it.
if ( parts
[ cbn
] & NONLOCALVAR
) {
* restore old display entry from save area
putprintf(" movl %s@(%d),%s+%d", 0,
DISPLAYNAME
, cbn
* sizeof(struct dispsave
));
struct entry_exit_cookie
*eecookiep
;
* all done by the second pass.
fp_formalentry(eecookiep
)
struct entry_exit_cookie
*eecookiep
;
putprintf( "%s%s:" , 0 , FORMALPREFIX
, eecookiep
-> extname
);
putprintf(" link %s,#0", 0, P2FPNAME
);
putprintf(" addl #-%s%d,sp", 0, FRAME_SIZE_LABEL
, ftnno
);
/* touch new end of stack, to break more stack space */
putprintf(" tstb sp@(-%s%d)", 0, PAGE_BREAK_LABEL
, ftnno
);
putprintf(" moveml #%s%d,sp@", 0, SAVE_MASK_LABEL
, ftnno
);
putleaf( P2ICON
, 0 , 0 , ADDTYPE( P2FTN
| P2INT
, P2PTR
) , "_FCALL" );
eecookiep
-> nlp
-> value
[ NL_OFFS
] + sizeof( struct formalrtn
* ) ,
NPARAM
, P2PTR
| P2STRTY
);
putRV(0, cbn
, eecookiep
-> nlp
-> value
[NL_OFFS
], NPARAM
, P2PTR
|P2STRTY
);
putop( P2LISTOP
, P2INT
);
putdot( filename
, line
);
putjbr( eecookiep
-> toplabel
);