Blame | Last modification | View Log | RSS feed
/*
Crown Copyright (c) 1997
This TenDRA(r) Computer Program is subject to Copyright
owned by the United Kingdom Secretary of State for Defence
acting through the Defence Evaluation and Research Agency
(DERA). It is made available to Recipients with a
royalty-free licence for its use, reproduction, transfer
to other parties and amendment for any purpose not excluding
product development provided that any such use et cetera
shall be deemed to be acceptance of the following conditions:-
(1) Its Recipients shall ensure that this Notice is
reproduced upon any copies or amended versions of it;
(2) Any amended version of it shall be clearly marked to
show both the nature of and the organisation responsible
for the relevant amendment or amendments;
(3) Its onward transfer from a recipient to another
party shall be deemed to be that party's acceptance of
these conditions;
(4) DERA gives no warranty or assurance as to its
quality or suitability for any purpose and DERA accepts
no liability whatsoever in relation to any use to which
it may be put.
*/
/*
VERSION INFORMATION
===================
--------------------------------------------------------------------------
$Header: /u/g/release/CVSROOT/Source/src/installers/sparc/common/translat.c,v 1.2 1998/03/11 11:04:00 pwe Exp $
--------------------------------------------------------------------------
$Log: translat.c,v $
* Revision 1.2 1998/03/11 11:04:00 pwe
* DWARF optimisation info
*
* Revision 1.1.1.1 1998/01/17 15:55:55 release
* First version to be checked into rolling release.
*
* Revision 1.27 1997/12/04 19:54:30 pwe
* ANDF-DE V1.9
*
* Revision 1.26 1997/10/10 18:33:10 pwe
* prep ANDF-DE revision
*
* Revision 1.25 1997/08/23 13:54:43 pwe
* initial ANDF-DE
*
* Revision 1.24 1997/04/17 12:00:03 pwe
* dwarf2 support
*
* Revision 1.23 1997/04/04 15:23:15 pwe
* tidy re old DWARF interface
*
* Revision 1.22 1997/03/26 13:04:55 pwe
* general proc compatibility
*
* Revision 1.21 1997/03/24 17:09:40 pwe
* reorganise solaris/sunos split
*
* Revision 1.20 1997/02/18 11:48:36 pwe
* NEWDIAGS for debugging optimised code
*
* Revision 1.19 1996/09/18 12:04:04 pwe
* fixed PIC_code
*
* Revision 1.18 1996/08/27 14:09:18 pwe
* ensure all varargs are stored, and ptr is not64bit
*
* Revision 1.17 1996/08/15 15:34:57 pwe
* mod for PWE ownership
*
* Revision 1.16 1995/12/15 11:14:57 john
* Change for dynamic initialisations on SunOS
*
* Revision 1.15 1995/11/14 14:25:05 john
* Fix to dynamic initialisations
*
* Revision 1.14 1995/11/07 09:53:53 john
* Change to register allocation for general procs
*
* Revision 1.13 1995/10/25 17:13:50 john
* Fixed error in init segment
*
* Revision 1.12 1995/10/06 10:22:09 john
* Changed optimisation level for general procs (SunOS only).
*
* Revision 1.11 1995/10/04 09:01:22 john
* Added dynamic initialisation on Solaris
*
* Revision 1.10 1995/09/22 13:07:48 john
* Change for new exception handling
*
* Revision 1.9 1995/09/13 11:01:44 john
* compilation fixes
*
* Revision 1.8 1995/08/04 15:47:14 john
* Minor change
*
* Revision 1.7 1995/07/17 16:46:16 john
* Fixed error on SunOS
*
* Revision 1.6 1995/07/14 16:34:26 john
* Changes for new spec
*
* Revision 1.5 1995/06/30 08:29:50 john
* Changed size of callee area
*
* Revision 1.4 1995/06/14 15:36:38 john
* Added support for trap error treatment & stack limits. Also, some
* reformatting.
*
* Revision 1.3 1995/05/26 13:02:20 john
* Change for new spec
*
* Revision 1.2 1995/04/20 08:07:08 john
* Moved source stabs record before initial text section
*
* Revision 1.1.1.1 1995/03/13 10:19:00 john
* Entered into CVS
*
* Revision 1.4 1994/07/07 16:11:33 djch
* Jul94 tape
*
* Revision 1.3 1994/07/04 08:31:36 djch
* changes for new versioning info.
*
* Revision 1.2 1994/05/03 15:12:43 djch
* removed extract.h and the inner procs stuff, now done in the common section
*
* Revision 1.11 94/02/21 16:13:59 16:13:59 ra (Robert Andrews)
* Correct unit weight in weightsv.
*
* Revision 1.10 93/09/27 14:57:41 14:57:41 ra (Robert Andrews)
* Added support for weak linking. Added support for DWARF diagnostic
* routines.
*
* Revision 1.9 93/08/27 11:40:10 11:40:10 ra (Robert Andrews)
* A couple of lint-like changes.
*
* Revision 1.8 93/08/18 11:17:49 11:17:49 ra (Robert Andrews)
* Removed stray spaces from outs command.
*
* Revision 1.7 93/08/13 14:48:20 14:48:20 ra (Robert Andrews)
* Removed a comment.
*
* Revision 1.6 93/07/12 15:20:32 15:20:32 ra (Robert Andrews)
* The exit_translator routine now outputs any special_routines which
* have been used but are not defined in the system libraries.
*
* Revision 1.5 93/07/05 18:29:07 18:29:07 ra (Robert Andrews)
* Made distinction between the System V assembler and the System V ABI.
* Added support for PIC by setting avoid_L7 if necessary.
*
* Revision 1.4 93/06/29 14:49:03 14:49:03 ra (Robert Andrews)
* Messed up version control header. Revision 1.2 was the important one.
* It involved a minor reorganisation and reformat. The routines
* init_translator and exit_translator were introduced.
*
* Revision 1.1 93/06/24 14:59:37 14:59:37 ra (Robert Andrews)
* Initial revision
*
--------------------------------------------------------------------------
*/
#define SPARCTRANS_CODE
/*
* Translation is controlled by translate () in this module.
* Code generation follows the following phases :
*
* 1. The TDF is read in, applying bottom-up optimisations.
* 2. Top-down optimisations are performed.
* 3. Register allocation is performed, and TDF idents introduced
* so code generation can be performed with no register spills.
* 4. Code is generated for each procedure, and global declarations processed.
* 5. Currently assembler source is generated directly, and the
* assembler optimiser ( as -O ) used for delay slot filling,
* instruction scheduling and peep-hole optimisation.
*
* In a little more detail :
*
* 1 ) During the TDF reading process for tag declarations and tag
* definitions, applications of tokens are expanded as they are
* encountered, using the token definitions. Every token used must have
* been previously defined in the bitstream.
*
* The reading of the tag definitions creates a data structure in memory
* which directly represents the TDF. At present, all the tag definitions
* are read into memory in this way before any further translation is
* performed. This will shortly be changed, so that translation is
* performed in smaller units. The translator is set up already so that
* the change to translate in units of single global definitions ( or
* groups of these ) can easily be made.
*
* During the creation of the data structure bottom-up optimisations
* are performed. These are the optimisations which can be done when a
* complete sub-tree of TDF is present, and are independent of the context
* in which the sub-tree is used. They are defined in check.c and
* check_id.c. These optimisation do such things as use the commutative
* and associative laws for plus to collect together and evaluate
* constants. More ambitious examples of these bottom-up optimisations
* include all constant evaluation, elimination of inaccessible code, and
* forward propagation of assignments of constants.
*
* 2 ) After reading in the TDF various optimisations are performed which
* cannot be done until the whole context is present. For example,
* constants cannot be extracted from a loop when we just have the loop
* itself, because we cannot tell whether the variables used in it are
* aliased.
*
* These optimisations are invoked by opt_all_exps which is defined in
* indep.c. They include extraction of constants from loops, common
* expression elimination on them and strength reduction for indexing.
*
* 3 ) Allocatable registers are partitioned into two sets, the s regs
* which are preserved over calls, and the t regs which are not.
*
* The TDF is scanned introducing TDF idents so that expressions can be
* evaluated within the available t regs with no spills. These new idents
* may be later allocated to a s reg later, if the weighting algorithm
* ( below ) considers this worth while. Otherwise they will be on the stack.
*
* Information is collected to help in global register allocation. During
* a forward recursive scan of the TDF the number of accesses to each
* variable is computed ( making assumptions about the frequency of
* execution of loops ) . Then on the return scan of this recursion, for
* each declaration, the number of registers which must be free for it to
* be worthwhile to use a register is computed, and put into the TDF as
* the "break" point. The procedures to do this are defined in weights.c.
*
* Suitable idents not alive over a procedure call are allocated to a t reg,
* and others to s regs. At the same time stack space requirements are
* calculated, so this is known before code for a procedure is generated.
*
* 4 ) Finally the code is generated without register spills. The code is
* generated by make_code () in makecode.c, and make_XXX_code () in proc.c.
*
* Note that procedure inlining and loop unrolling optimisations are not
* currently implemented. Library procedures such as memcpy () and
* strcpy () are not treated specially. Integer multiply, divide and
* remainder use the standard support procedures .mul, .div, .rem and
* unsigned variants.
*/
#include "config.h"
#include "common_types.h"
#include "myassert.h"
#include "flpt.h"
#include "expmacs.h"
#include "tags.h"
#include "exptypes.h"
#include "exp.h"
#include "shapemacs.h"
#include "tempdecs.h"
#include "weights.h"
#include "proctypes.h"
#include "procrec.h"
#include "regalloc.h"
#include "codehere.h"
#include "makecode.h"
#include "eval.h"
#include "toktypes.h"
#include "flags.h"
#include "basicread.h"
#include "tags.h"
#include "bitsmacs.h"
#include "needscan.h"
#include "getregs.h"
#include "regmacs.h"
#include "labels.h"
#include "xalloc.h"
#include "comment.h"
#include "sparcdiags.h"
#include "installglob.h"
#include "externs.h"
#include "out.h"
#include "translat.h"
#include "optimise.h"
#include "proc.h"
#include "special.h"
#include "target_v.h"
#include "locate.h"
#include "sparctrans.h"
#ifdef NEWDWARF
#include "dw2_iface.h"
#include "dw2_config.h"
#endif
extern bool know_size ;
char * proc_name;
#if ADDUNDERSCORE
#define isINITproc(id) (!strncmp("___I.TDF",id,8))
#else
#define isINITproc(id) (!strncmp("__I.TDF",id,7))
#endif /* ADDUNDERSCORE */
/*
VARIABLES
*/
int sysV_abi ; /* System V version? */
int sysV_assembler ; /* System V version? */
int optim_level ; /* optimisation level */
int g_reg_max ; /* the maximum number of G registers */
int maxfix_tregs ; /* the maximum number of T registers */
FILE *as_file = NULL ; /* assembler output file */
dec **main_globals ; /* global declarations */
procrec *procrecs ; /* procedure records */
dec *diag_def = NULL ; /* diagnostics definition */
int main_globals_index = 0; /* number of globals */
int caller_offset_used = 0;
enum section current_section = no_section ;
/*
FIND THE SIZE AND ALIGNMENT OF A SHAPE
*/
ash ashof
PROTO_N ( ( s ) )
PROTO_T ( shape s ){
ash a ;
a.ashsize = shape_size ( s ) ;
a.ashalign = shape_align ( s ) ;
return ( a ) ;
}
/*
IS A SHAPE OF KNOWN SIZE?
*/
#define varsize( s ) 1
/*
OUTPUT A SECTION DIRECTIVE
*/
void insection
PROTO_N ( ( s ) )
PROTO_T ( enum section s ){
if (!sysV_assembler && s == rodata_section)
s = data_section;
if ( s == current_section ) return ;
current_section = s ;
if ( sysV_assembler ) {
switch ( s ) {
case data_section : {
if (do_prom)
failer ("prom .data");
outs ( "\t.section\t\".data\"\n" ) ;
return ;
}
case text_section : {
outs ( "\t.section\t\".text\"\n" ) ;
return ;
}
case rodata_section : {
outs ( "\t.section\t\".rodata\"\n" ) ;
return ;
}
case init_section : {
outs ("\t.section\t\".init\"\n");
return;
}
default : {
break ;
}
}
}
else {
switch ( s ) {
case data_section : {
outs ( "\t.seg\t\"data\"\n" ) ;
return ;
}
case text_section : {
outs ( "\t.seg\t\"text\"\n" ) ;
return ;
}
default : {
break ;
}
}
}
current_section = no_section ;
fail ( "bad \".section\" name" ) ;
return ;
}
/*
MARK AN EXPRESSION AS UNALIASED
*/
void mark_unaliased
PROTO_N ( ( e ) )
PROTO_T ( exp e ){
exp p = pt ( e ) ;
bool ca = 1 ;
assert ( !separate_units ) ;
while ( p != nilexp && ca ) {
exp q = bro ( p ) ;
if ( q == nilexp ) {
#ifdef NEWDIAGS
if (!isdiaginfo(p))
#endif
ca = 0 ;
}
else {
if ( !( last ( p ) && name ( q ) == cont_tag ) &&
!( !last ( p ) && last ( q ) &&
name ( bro ( q ) ) == ass_tag ) ) {
#ifdef NEWDIAGS
if (!isdiaginfo(p))
#endif
ca = 0 ;
}
}
p = pt ( p ) ;
}
if ( ca ) setcaonly ( e ) ;
return ;
}
/*
RENAMING ROUTINE
*/
void out_rename
PROTO_N ( ( oldid, newid ) )
PROTO_T ( char * oldid X char * newid ){
#if 0
outs ( "\t" ) ;
outs ( oldid ) ;
outs ( "=" ) ;
outs ( newid ) ;
outnl () ;
#endif
return ;
}
/*
LIST OF WEAK SYMBOLS
*/
weak_cell *weak_list = null ;
/*
INITIALISE TRANSLATOR
*/
void init_translator
PROTO_Z (){
/* initialise nowhere */
setregalt ( nowhere.answhere, 0 ) ;
nowhere.ashwhere.ashsize = 0 ;
nowhere.ashwhere.ashsize = 0 ;
/* mark the as output as TDF compiled */
outs ( lab_prefix ) ;
outs ( "TDF.translated:\n" ) ;
outs ( "!\tTDF->SPARC, " ) ;
outn ( target_version ) ;
outs ( " , " ) ;
outn ( target_revision ) ;
if ( sysV_assembler ) outs ( " (SysV)" ) ;
outnl () ;
/* start diagnostics if necessary */
#ifdef NEWDWARF
if (dwarf2)
init_dwarf2 ();
else
#endif
if ( diagnose ) {
#if DWARF
out_diagnose_prelude () ;
#else
init_stab () ;
#endif
}
/* start in text section */
insection ( text_section ) ;
return ;
}
/*
Return the tag with name 'tag_name'
*/
baseoff find_tag
PROTO_N ( ( tag_name ) )
PROTO_T ( char * tag_name ){
int i;
for (i=0; i<main_globals_index; ++i){
exp newtag = main_globals[i]->dec_u.dec_val.dec_exp;
char * id = main_globals[i]->dec_u.dec_val.dec_id;
if(!strcmp(id,tag_name)) return boff(newtag);
}
printf("%s\n: ",tag_name);
fail("tag not declared");
exit(1);
}
/*
EXIT TRANSLATOR
*/
void exit_translator
PROTO_Z (){
output_special_routines () ;
insection ( text_section ) ;
#ifdef NEWDWARF
if (dwarf2)
end_dwarf2 ();
else
#endif
if ( diagnose ) {
#if DWARF
out_diagnose_postlude () ;
#else
/* do nothing */
#endif
}
return ;
}
/*
TRANSLATE AN ENTIRE TDF CAPSULE
*/
void translate_capsule
PROTO_Z (){
int i ;
int r ;
dec *d ;
int procno ;
int noprocs ;
space tempregs ;
/* initialize diagnostics */
#ifdef NEWDWARF
if ( diagnose && !dwarf2 ) {
#else
if ( diagnose ) {
#endif
#if DWARF
/* do nothing */
#else
init_stab_aux () ;
#endif
}
/* apply all optimisations */
#ifdef NEWDIAGS
if ( !diag_visible ) opt_all_exps () ;
#else
if ( !diagnose ) opt_all_exps () ;
#endif
/* mark all statics as unaliased and count procedures */
noprocs = 0 ;
for ( d = top_def ; d != null ; d = d->def_next ) {
exp c = d->dec_u.dec_val.dec_exp ;
if ( son ( c ) != nilexp ) {
#ifdef NEWDIAGS
if ( !diag_visible && !separate_units && !d->dec_u.dec_val.extnamed
#else
if ( !diagnose && !separate_units && !d->dec_u.dec_val.extnamed
#endif
&& isvar ( c ) ) {
mark_unaliased ( c ) ;
}
if ( name ( son ( c ) ) == proc_tag ||
name(son(c))==general_proc_tag) noprocs++ ;
}
}
#ifdef NEWDWARF
if (dwarf2) {
dwarf2_prelude ();
}
#endif
/* output weak symbols */
while ( weak_list ) {
outs ( "\t" ) ;
outs ( weak_list->weak_id ) ;
outs ( "=" ) ;
outs ( weak_list->val_id ) ;
outnl () ;
weak_list = weak_list->next ;
}
/* allocate memory for procedures */
procrecs = ( procrec * ) xcalloc ( noprocs, sizeof ( procrec ) ) ;
/* number procedure definitions */
procno = 0 ;
for ( d = top_def ; d != null ; d = d->def_next ) {
exp c = d->dec_u.dec_val.dec_exp ;
exp s = son ( c ) ;
if ( s != nilexp && (name ( s ) == proc_tag ||
name(s) == general_proc_tag)) {
procrec *pr = &procrecs [ procno ] ;
pr->nameproc = bro ( c ) ;
no ( s ) = procno++ ;
}
}
/*
Scan to put everything in SPARC form, and calculate register
and stack space needs. First work out which t fixed point
registers (those not preserved over calls) can be used. This
needs to be done before scan () which adds identities so that
temporary register needs are within the available temporary
register set. We dynamically calculate g registers we can use
as temporaries so that we can support :
SUNOS 4 : %g1..%g7 can be used,
SYSV SPARC ABI : %g1..%g4 can be used.
*/
/* initialise register sets */
tempregs.fixed = PROC_TREGS ;
tempregs.flt = PROC_FLT_TREGS ;
/*permit use of valid g registers(%g0 is not a proper register)*/
/* ensure R_TMP not allocatable */
/* scan all the procedures, to put everything in SPARC operand form */
for ( d = top_def ; d != null ; d = d->def_next ) {
exp c = d->dec_u.dec_val.dec_exp ;
exp s = son ( c ) ;
if ( s != nilexp && (name ( s ) == proc_tag ||
name(s) == general_proc_tag)) {
exp *st = &s ;
procrec *pr = &procrecs [ no ( s ) ] ;
if (d->dec_u.dec_val.extnamed && isINITproc(d->dec_u.dec_val.dec_id))
set_proc_uses_external (s); /* for PIC_code, should be done in install_fns? */
Has_vcallees = (name(s) == general_proc_tag) &&
proc_has_vcallees(s);
for (r=R_G1; r <= R_G0 + g_reg_max ; r++ ) {
tempregs.fixed &= ~RMASK ( r ) ;
}
tempregs.fixed |= RMASK ( R_TMP ) ;
/* count the number of fixed t registers */
maxfix_tregs = 0 ;
for ( r = R_FIRST ; r <= R_LAST ; r++ ) {
if ( IS_TREG ( r ) && ( tempregs.fixed & RMASK ( r ) ) == 0 ) {
maxfix_tregs++ ;
}
}
if (name(s) == general_proc_tag) {
int any_envoff = 0;
exp a = son (s);
while (name(a) == ident_tag && isparam(a) && name(son(a)) != formal_callee_tag) {
if (isenvoff(a) && caller_offset_used)
any_envoff = 1;
else if (any_envoff) {
setvis(a);
setenvoff(a);
}
a = bro(son(a));
}
#ifdef GENCOMPAT
if ((name(a) == ident_tag && isparam(a)) || Has_vcallees) {
set_proc_may_have_callees(s);
}
#endif
}
pr->needsproc = scan ( st, &st ) ;
pr->needsproc.callee_size = (callee_size+63)&~63;
}
}
#if 0
/* apply dead variable analysis (not currently implemented) */
if ( do_deadvars ) {
init_dead () ;
dead_flag = 0 ;
for ( d = top_def ; d != null ; d = d->def_next ) {
exp c = d->dec_u.dec_val.dec_exp ;
exp s = son ( c ) ;
if ( s != nilexp && (name ( s ) == proc_tag ||
name(s) == general_proc_tag)){
deadvar ( s ) ;
}
}
}
#endif
/* calculate the break points for register allocation */
for ( d = top_def ; d != null ; d = d->def_next ) {
exp c = d->dec_u.dec_val.dec_exp ;
exp s = son ( c ) ;
if ( s != nilexp && (name ( s ) == proc_tag ||
name(s) == general_proc_tag)) {
weights w ;
spacereq forrest ;
int freefixed, freefloat ;
procrec *pr = &procrecs [ no ( s ) ] ;
avoid_L7 = ( bool )( PIC_code && proc_uses_external ( s ) ) ;
Has_vcallees = (name(s) == general_proc_tag) &&
proc_has_vcallees(s);
in_general_proc = (name(s) == general_proc_tag);
#ifdef GENCOMPAT
May_have_callees = proc_may_have_callees(s);
#endif
/* calculate number of free registers */
freefixed = ( R_L7 - R_L0 + 1 ) + ( R_I5 - R_I0 + 1 ) ;
freefloat = 0 ;
if ( avoid_L7 ) freefixed-- ;
#ifdef GENCOMPAT
if (May_have_callees) freefixed--;
#else
if(in_general_proc) freefixed--;
#endif
if(Has_vcallees) freefixed --;
/* estimate tag usage */
w = weightsv ( 1.0, bro ( son ( s ) ) ) ;
/* calculate register and stack allocation for tags */
forrest = regalloc ( bro ( son ( s ) ), freefixed, freefloat, 0 ) ;
pr->spacereqproc = forrest ;
}
}
/* set up main_globals */
i = 0 ;
for ( d = top_def ; d != null ; d = d->def_next ) i++ ;
main_globals_index = i;
if ( i ) main_globals = ( dec ** ) xcalloc ( i, sizeof ( dec * ) ) ;
i = 0 ;
for ( d = top_def ; d != null ; d = d->def_next ) {
main_globals [i] = d ;
main_globals [i]->dec_u.dec_val.sym_number = i ;
i++ ;
}
/* output global definitions */
for ( d = top_def ; d != null ; d = d->def_next ) {
exp tg = d->dec_u.dec_val.dec_exp ;
exp stg = son ( tg ) ;
char *id = d->dec_u.dec_val.dec_id ;
bool extnamed = ( bool ) d->dec_u.dec_val.extnamed ;
if ( stg != nilexp && (extnamed || no(tg)!= 0 ||
!strcmp(id,TDF_HANDLER) || !strcmp(id,TDF_STACKLIM))) {
if ( extnamed ) {
assert ( id [ 0 ] != '$' ) ;
if ( name ( stg ) != proc_tag && name(stg)!=general_proc_tag) {
if (!isvar (tg) || (d -> dec_u.dec_val.acc & f_constant) || do_prom)
insection ( rodata_section ) ;
else
insection ( data_section ) ;
}
else if (isINITproc(id) && sysV_assembler) {
/* On solaris, this is easy. Insert a call to the procedure
into the init segment */
insection (init_section);
fprintf(as_file,"\tcall %s\n",id);
outs("\tnop\n");
insection (text_section);
}
else{
insection ( text_section ) ;
}
outs ( "\t.global\t" ) ;
outs ( id ) ;
outnl () ;
}
if ( name ( stg ) != proc_tag && name(stg)!=general_proc_tag) {
/* evaluate all outer level constants */
instore is ;
long symdef = d->dec_u.dec_val.sym_number + 1 ;
diag_global *diag_props = d->dec_u.dec_val.diag_info ;
if ( isvar ( tg ) ) symdef = -symdef ;
if ( diag_props ) {
DIAG_VAL_BEGIN ( diag_props, extnamed, symdef, id, stg ) ;
}
is = evaluated ( stg, symdef,
(!isvar (tg) || (d -> dec_u.dec_val.acc & f_constant)) ) ;
if ( diag_props ) {
DIAG_VAL_END ( diag_props ) ;
}
if ( is.adval ) setvar ( tg ) ;
if ( sysV_assembler ) {
outs ( "\t.type\t" ) ;
outs ( id ) ;
outs ( ",#object\n" ) ;
if ( !know_size ) {
outs ( "\t.size\t" ) ;
outs ( id ) ;
outs ( "," ) ;
outn ( shape_size ( sh ( stg ) ) / 8 ) ;
outnl () ;
}
}
}
}
}
/* translate procedures */
for ( d = top_def ; d != null ; d = d->def_next ) {
exp tg = d->dec_u.dec_val.dec_exp ;
exp stg = son ( tg ) ;
char *id = d->dec_u.dec_val.dec_id ;
bool extnamed = ( bool ) d->dec_u.dec_val.extnamed ;
if ( stg != nilexp && shape_size (sh(stg)) == 0 && name(stg) == asm_tag) {
if (props(stg) != 0)
failer ("~asm not in ~asm_sequence");
check_asm_seq (son(stg), 1);
insection ( text_section ) ;
(void)code_here ( stg, tempregs, nowhere ) ;
outnl ();
}
if ( no ( tg ) == 0 && !extnamed ) continue ;
if ( stg != nilexp ) {
if ( name ( stg ) == proc_tag || name(stg)==general_proc_tag) {
/* translate code for procedure */
int proc_directive ;
exp c = d->dec_u.dec_val.dec_exp ;
prop p = procrecs [ no ( son ( c ) ) ].needsproc.prps ;
diag_global *diag_props = d->dec_u.dec_val.diag_info ;
insection ( text_section ) ;
if(!sysV_assembler){
#ifdef GENCOMPAT
optim_level = (proc_may_have_callees(stg))?0:2;
#else
optim_level = (name(stg) == general_proc_tag)?0:2;
#endif
}
/*
The .proc directive number tells Sun's assembler
optimiser which register are live at the end of the
procedure. We must get it right, or be conservative.
*/
if ( p & longrealresult_bit ) {
proc_directive = 7 ; /* %f0 and %f1 */
}
else if ( p & realresult_bit ) {
proc_directive = 6 ; /* %f0 */
}
else if ( p & long_result_bit ) {
proc_directive = 0 ; /* compound */
}
else if ( p & has_result_bit ) {
proc_directive = 4 ; /* %i0 or (leaf) %o0 */
}
else {
proc_directive = 0 ;
}
outs ( "\t.proc\t" ) ;
outn ( proc_directive ) ;
outnl () ;
#ifdef DO_COMMENT
if ( p & long_result_bit ) outs ( "!\tstruct result\n" ) ;
#endif
if ( diagnose ) {
DIAG_PROC_BEGIN ( diag_props, extnamed, -1, id, stg ) ;
}
if ( optim_level >= 0 ) {
/* .optim must go after .proc */
if ( ( p & long_result_bit ) || ( p & dont_optimise ) ) {
outs ( "\t.optim\t\"-O0\"\n" ) ;
}
else {
outs ( "\t.optim\t\"-O" ) ;
outn ( optim_level ) ;
outs ( "\"\n" ) ;
}
}
outs ( id ) ;
outs ( ":\n" ) ;
seed_label () ; /* reset label sequence */
settempregs ( stg ) ; /* reset getreg sequence */
/* generate code for this proc */
proc_name = id;
(void)code_here ( stg, tempregs, nowhere ) ;
if ( sysV_assembler ) {
outs ( "\t.type\t" ) ;
outs ( id ) ;
outs ( ",#function\n" ) ;
outs ( "\t.size\t" ) ;
outs ( id ) ;
outs ( ",.-" ) ;
outs ( id ) ;
outnl () ;
}
else {
#ifdef DO_COMMENT
outs ( "!\t.end\t" ) ;
outs ( id ) ;
outnl () ;
#endif
}
if ( diagnose ) {
DIAG_PROC_END ( stg ) ;
}
}
}
}
#ifdef NEWDWARF
if (dwarf2) {
dwarf2_postlude ();
}
#endif
return ;
}
/*
TRANSLATE A SINGLE TAG DEFINITION
*/
void translate_tagdef
PROTO_Z (){
/* not implemented */
return ;
}
/*
TRANSLATE A SINGLE UNIT
*/
void translate_unit
PROTO_Z (){
if ( separate_units ) {
dec *d ;
translate_capsule () ;
d = top_def ;
while ( d != null ) {
exp c = d->dec_u.dec_val.dec_exp ;
no ( c ) = 0 ;
pt ( c ) = nilexp ;
d = d->def_next ;
}
crt_repeat = nilexp ;
repeat_list = nilexp ;
}
return ;
}