X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=gcc%2Ff%2Fcom.c;fp=gcc%2Ff%2Fcom.c;h=0000000000000000000000000000000000000000;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=13de981b793ffe2db88439c53874df6c683dc34d;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/f/com.c b/gcc/f/com.c deleted file mode 100644 index 13de981b..00000000 --- a/gcc/f/com.c +++ /dev/null @@ -1,16638 +0,0 @@ -/* com.c -- Implementation File (module.c template V1.0) - Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 - Free Software Foundation, Inc. - Contributed by James Craig Burley. - -This file is part of GNU Fortran. - -GNU Fortran is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Fortran is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Fortran; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. - - Related Modules: - None - - Description: - Contains compiler-specific functions. - - Modifications: -*/ - -/* Understanding this module means understanding the interface between - the g77 front end and the gcc back end (or, perhaps, some other - back end). In here are the functions called by the front end proper - to notify whatever back end is in place about certain things, and - also the back-end-specific functions. It's a bear to deal with, so - lately I've been trying to simplify things, especially with regard - to the gcc-back-end-specific stuff. - - Building expressions generally seems quite easy, but building decls - has been challenging and is undergoing revision. gcc has several - kinds of decls: - - TYPE_DECL -- a type (int, float, struct, function, etc.) - CONST_DECL -- a constant of some type other than function - LABEL_DECL -- a variable or a constant? - PARM_DECL -- an argument to a function (a variable that is a dummy) - RESULT_DECL -- the return value of a function (a variable) - VAR_DECL -- other variable (can hold a ptr-to-function, struct, int, etc.) - FUNCTION_DECL -- a function (either the actual function or an extern ref) - FIELD_DECL -- a field in a struct or union (goes into types) - - g77 has a set of functions that somewhat parallels the gcc front end - when it comes to building decls: - - Internal Function (one we define, not just declare as extern): - if (is_nested) push_f_function_context (); - start_function (get_identifier ("function_name"), function_type, - is_nested, is_public); - // for each arg, build PARM_DECL and call push_parm_decl (decl) with it; - store_parm_decls (is_main_program); - ffecom_start_compstmt (); - // for stmts and decls inside function, do appropriate things; - ffecom_end_compstmt (); - finish_function (is_nested); - if (is_nested) pop_f_function_context (); - - Everything Else: - tree d; - tree init; - // fill in external, public, static, &c for decl, and - // set DECL_INITIAL to error_mark_node if going to initialize - // set is_top_level TRUE only if not at top level and decl - // must go in top level (i.e. not within current function decl context) - d = start_decl (decl, is_top_level); - init = ...; // if have initializer - finish_decl (d, init, is_top_level); - -*/ - -/* Include files. */ - -#include "proj.h" -#include "flags.h" -#include "rtl.h" -#include "toplev.h" -#include "tree.h" -#include "output.h" /* Must follow tree.h so TREE_CODE is defined! */ -#include "convert.h" -#include "ggc.h" -#include "diagnostic.h" -#include "intl.h" -#include "langhooks.h" -#include "langhooks-def.h" - -/* VMS-specific definitions */ -#ifdef VMS -#include -#define O_RDONLY 0 /* Open arg for Read/Only */ -#define O_WRONLY 1 /* Open arg for Write/Only */ -#define read(fd,buf,size) VMS_read (fd,buf,size) -#define write(fd,buf,size) VMS_write (fd,buf,size) -#define open(fname,mode,prot) VMS_open (fname,mode,prot) -#define fopen(fname,mode) VMS_fopen (fname,mode) -#define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile) -#define strncat(dst,src,cnt) VMS_strncat (dst,src,cnt) -#define fstat(fd,stbuf) VMS_fstat (fd,stbuf) -static int VMS_fstat (), VMS_stat (); -static char * VMS_strncat (); -static int VMS_read (); -static int VMS_write (); -static int VMS_open (); -static FILE * VMS_fopen (); -static FILE * VMS_freopen (); -static void hack_vms_include_specification (); -typedef struct { unsigned :16, :16, :16; } vms_ino_t; -#define ino_t vms_ino_t -#define INCLUDE_LEN_FUDGE 10 /* leave room for VMS syntax conversion */ -#endif /* VMS */ - -#define FFECOM_DETERMINE_TYPES 1 /* for com.h */ -#include "com.h" -#include "bad.h" -#include "bld.h" -#include "equiv.h" -#include "expr.h" -#include "implic.h" -#include "info.h" -#include "malloc.h" -#include "src.h" -#include "st.h" -#include "storag.h" -#include "symbol.h" -#include "target.h" -#include "top.h" -#include "type.h" - -/* Externals defined here. */ - -/* Stream for reading from the input file. */ -FILE *finput; - -/* These definitions parallel those in c-decl.c so that code from that - module can be used pretty much as is. Much of these defs aren't - otherwise used, i.e. by g77 code per se, except some of them are used - to build some of them that are. The ones that are global (i.e. not - "static") are those that ste.c and such might use (directly - or by using com macros that reference them in their definitions). */ - -tree string_type_node; - -/* The rest of these are inventions for g77, though there might be - similar things in the C front end. As they are found, these - inventions should be renamed to be canonical. Note that only - the ones currently required to be global are so. */ - -static tree ffecom_tree_fun_type_void; - -tree ffecom_integer_type_node; /* Abbrev for _tree_type[blah][blah]. */ -tree ffecom_integer_zero_node; /* Like *_*_* with g77's integer type. */ -tree ffecom_integer_one_node; /* " */ -tree ffecom_tree_type[FFEINFO_basictype][FFEINFO_kindtype]; - -/* _fun_type things are the f2c-specific versions. For -fno-f2c, - just use build_function_type and build_pointer_type on the - appropriate _tree_type array element. */ - -static tree ffecom_tree_fun_type[FFEINFO_basictype][FFEINFO_kindtype]; -static tree ffecom_tree_ptr_to_fun_type[FFEINFO_basictype][FFEINFO_kindtype]; -static tree ffecom_tree_subr_type; -static tree ffecom_tree_ptr_to_subr_type; -static tree ffecom_tree_blockdata_type; - -static tree ffecom_tree_xargc_; - -ffecomSymbol ffecom_symbol_null_ -= -{ - NULL_TREE, - NULL_TREE, - NULL_TREE, - NULL_TREE, - false -}; -ffeinfoKindtype ffecom_pointer_kind_ = FFEINFO_basictypeNONE; -ffeinfoKindtype ffecom_label_kind_ = FFEINFO_basictypeNONE; - -int ffecom_f2c_typecode_[FFEINFO_basictype][FFEINFO_kindtype]; -tree ffecom_f2c_integer_type_node; -tree ffecom_f2c_ptr_to_integer_type_node; -tree ffecom_f2c_address_type_node; -tree ffecom_f2c_real_type_node; -tree ffecom_f2c_ptr_to_real_type_node; -tree ffecom_f2c_doublereal_type_node; -tree ffecom_f2c_complex_type_node; -tree ffecom_f2c_doublecomplex_type_node; -tree ffecom_f2c_longint_type_node; -tree ffecom_f2c_logical_type_node; -tree ffecom_f2c_flag_type_node; -tree ffecom_f2c_ftnlen_type_node; -tree ffecom_f2c_ftnlen_zero_node; -tree ffecom_f2c_ftnlen_one_node; -tree ffecom_f2c_ftnlen_two_node; -tree ffecom_f2c_ptr_to_ftnlen_type_node; -tree ffecom_f2c_ftnint_type_node; -tree ffecom_f2c_ptr_to_ftnint_type_node; - -/* Simple definitions and enumerations. */ - -#ifndef FFECOM_sizeMAXSTACKITEM -#define FFECOM_sizeMAXSTACKITEM 32*1024 /* Keep user-declared things - larger than this # bytes - off stack if possible. */ -#endif - -/* For systems that have large enough stacks, they should define - this to 0, and here, for ease of use later on, we just undefine - it if it is 0. */ - -#if FFECOM_sizeMAXSTACKITEM == 0 -#undef FFECOM_sizeMAXSTACKITEM -#endif - -typedef enum - { - FFECOM_rttypeVOID_, - FFECOM_rttypeVOIDSTAR_, /* C's `void *' type. */ - FFECOM_rttypeFTNINT_, /* f2c's `ftnint' type. */ - FFECOM_rttypeINTEGER_, /* f2c's `integer' type. */ - FFECOM_rttypeLONGINT_, /* f2c's `longint' type. */ - FFECOM_rttypeLOGICAL_, /* f2c's `logical' type. */ - FFECOM_rttypeREAL_F2C_, /* f2c's `real' returned as `double'. */ - FFECOM_rttypeREAL_GNU_, /* `real' returned as such. */ - FFECOM_rttypeCOMPLEX_F2C_, /* f2c's `complex' returned via 1st arg. */ - FFECOM_rttypeCOMPLEX_GNU_, /* f2c's `complex' returned directly. */ - FFECOM_rttypeDOUBLE_, /* C's `double' type. */ - FFECOM_rttypeDOUBLEREAL_, /* f2c's `doublereal' type. */ - FFECOM_rttypeDBLCMPLX_F2C_, /* f2c's `doublecomplex' returned via 1st arg. */ - FFECOM_rttypeDBLCMPLX_GNU_, /* f2c's `doublecomplex' returned directly. */ - FFECOM_rttypeCHARACTER_, /* f2c `char *'/`ftnlen' pair. */ - FFECOM_rttype_ - } ffecomRttype_; - -/* Internal typedefs. */ - -typedef struct _ffecom_concat_list_ ffecomConcatList_; - -/* Private include files. */ - - -/* Internal structure definitions. */ - -struct _ffecom_concat_list_ - { - ffebld *exprs; - int count; - int max; - ffetargetCharacterSize minlen; - ffetargetCharacterSize maxlen; - }; - -/* Static functions (internal). */ - -static void ffecom_init_decl_processing PARAMS ((void)); -static tree ffecom_arglist_expr_ (const char *argstring, ffebld args); -static tree ffecom_widest_expr_type_ (ffebld list); -static bool ffecom_overlap_ (tree dest_decl, tree dest_offset, - tree dest_size, tree source_tree, - ffebld source, bool scalar_arg); -static bool ffecom_args_overlapping_ (tree dest_tree, ffebld dest, - tree args, tree callee_commons, - bool scalar_args); -static tree ffecom_build_f2c_string_ (int i, const char *s); -static tree ffecom_call_ (tree fn, ffeinfoKindtype kt, - bool is_f2c_complex, tree type, - tree args, tree dest_tree, - ffebld dest, bool *dest_used, - tree callee_commons, bool scalar_args, tree hook); -static tree ffecom_call_binop_ (tree fn, ffeinfoKindtype kt, - bool is_f2c_complex, tree type, - ffebld left, ffebld right, - tree dest_tree, ffebld dest, - bool *dest_used, tree callee_commons, - bool scalar_args, bool ref, tree hook); -static void ffecom_char_args_x_ (tree *xitem, tree *length, - ffebld expr, bool with_null); -static tree ffecom_check_size_overflow_ (ffesymbol s, tree type, bool dummy); -static tree ffecom_char_enhance_arg_ (tree *xtype, ffesymbol s); -static ffecomConcatList_ - ffecom_concat_list_gather_ (ffecomConcatList_ catlist, - ffebld expr, - ffetargetCharacterSize max); -static void ffecom_concat_list_kill_ (ffecomConcatList_ catlist); -static ffecomConcatList_ ffecom_concat_list_new_ (ffebld expr, - ffetargetCharacterSize max); -static void ffecom_debug_kludge_ (tree aggr, const char *aggr_type, - ffesymbol member, tree member_type, - ffetargetOffset offset); -static void ffecom_do_entry_ (ffesymbol fn, int entrynum); -static tree ffecom_expr_ (ffebld expr, tree dest_tree, ffebld dest, - bool *dest_used, bool assignp, bool widenp); -static tree ffecom_expr_intrinsic_ (ffebld expr, tree dest_tree, - ffebld dest, bool *dest_used); -static tree ffecom_expr_power_integer_ (ffebld expr); -static void ffecom_expr_transform_ (ffebld expr); -static void ffecom_f2c_make_type_ (tree *type, int tcode, const char *name); -static void ffecom_f2c_set_lio_code_ (ffeinfoBasictype bt, int size, - int code); -static ffeglobal ffecom_finish_global_ (ffeglobal global); -static ffesymbol ffecom_finish_symbol_transform_ (ffesymbol s); -static tree ffecom_get_appended_identifier_ (char us, const char *text); -static tree ffecom_get_external_identifier_ (ffesymbol s); -static tree ffecom_get_identifier_ (const char *text); -static tree ffecom_gen_sfuncdef_ (ffesymbol s, - ffeinfoBasictype bt, - ffeinfoKindtype kt); -static const char *ffecom_gfrt_args_ (ffecomGfrt ix); -static tree ffecom_gfrt_tree_ (ffecomGfrt ix); -static tree ffecom_init_zero_ (tree decl); -static tree ffecom_intrinsic_ichar_ (tree tree_type, ffebld arg, - tree *maybe_tree); -static tree ffecom_intrinsic_len_ (ffebld expr); -static void ffecom_let_char_ (tree dest_tree, - tree dest_length, - ffetargetCharacterSize dest_size, - ffebld source); -static void ffecom_make_gfrt_ (ffecomGfrt ix); -static void ffecom_member_phase1_ (ffestorag mst, ffestorag st); -static void ffecom_member_phase2_ (ffestorag mst, ffestorag st); -static void ffecom_prepare_let_char_ (ffetargetCharacterSize dest_size, - ffebld source); -static void ffecom_push_dummy_decls_ (ffebld dumlist, - bool stmtfunc); -static void ffecom_start_progunit_ (void); -static ffesymbol ffecom_sym_transform_ (ffesymbol s); -static ffesymbol ffecom_sym_transform_assign_ (ffesymbol s); -static void ffecom_transform_common_ (ffesymbol s); -static void ffecom_transform_equiv_ (ffestorag st); -static tree ffecom_transform_namelist_ (ffesymbol s); -static void ffecom_tree_canonize_ptr_ (tree *decl, tree *offset, - tree t); -static void ffecom_tree_canonize_ref_ (tree *decl, tree *offset, - tree *size, tree tree); -static tree ffecom_tree_divide_ (tree tree_type, tree left, tree right, - tree dest_tree, ffebld dest, - bool *dest_used, tree hook); -static tree ffecom_type_localvar_ (ffesymbol s, - ffeinfoBasictype bt, - ffeinfoKindtype kt); -static tree ffecom_type_namelist_ (void); -static tree ffecom_type_vardesc_ (void); -static tree ffecom_vardesc_ (ffebld expr); -static tree ffecom_vardesc_array_ (ffesymbol s); -static tree ffecom_vardesc_dims_ (ffesymbol s); -static tree ffecom_convert_narrow_ (tree type, tree expr); -static tree ffecom_convert_widen_ (tree type, tree expr); - -/* These are static functions that parallel those found in the C front - end and thus have the same names. */ - -static tree bison_rule_compstmt_ (void); -static void bison_rule_pushlevel_ (void); -static void delete_block (tree block); -static int duplicate_decls (tree newdecl, tree olddecl); -static void finish_decl (tree decl, tree init, bool is_top_level); -static void finish_function (int nested); -static const char *lang_printable_name (tree decl, int v); -static tree lookup_name_current_level (tree name); -static struct binding_level *make_binding_level (void); -static void pop_f_function_context (void); -static void push_f_function_context (void); -static void push_parm_decl (tree parm); -static tree pushdecl_top_level (tree decl); -static int kept_level_p (void); -static tree storedecls (tree decls); -static void store_parm_decls (int is_main_program); -static tree start_decl (tree decl, bool is_top_level); -static void start_function (tree name, tree type, int nested, int public); -static void ffecom_file_ (const char *name); -static void ffecom_close_include_ (FILE *f); -static int ffecom_decode_include_option_ (char *spec); -static FILE *ffecom_open_include_ (char *name, ffewhereLine l, - ffewhereColumn c); - -/* Static objects accessed by functions in this module. */ - -static ffesymbol ffecom_primary_entry_ = NULL; -static ffesymbol ffecom_nested_entry_ = NULL; -static ffeinfoKind ffecom_primary_entry_kind_; -static bool ffecom_primary_entry_is_proc_; -static tree ffecom_outer_function_decl_; -static tree ffecom_previous_function_decl_; -static tree ffecom_which_entrypoint_decl_; -static tree ffecom_float_zero_ = NULL_TREE; -static tree ffecom_float_half_ = NULL_TREE; -static tree ffecom_double_zero_ = NULL_TREE; -static tree ffecom_double_half_ = NULL_TREE; -static tree ffecom_func_result_;/* For functions. */ -static tree ffecom_func_length_;/* For CHARACTER fns. */ -static ffebld ffecom_list_blockdata_; -static ffebld ffecom_list_common_; -static ffebld ffecom_master_arglist_; -static ffeinfoBasictype ffecom_master_bt_; -static ffeinfoKindtype ffecom_master_kt_; -static ffetargetCharacterSize ffecom_master_size_; -static int ffecom_num_fns_ = 0; -static int ffecom_num_entrypoints_ = 0; -static bool ffecom_is_altreturning_ = FALSE; -static tree ffecom_multi_type_node_; -static tree ffecom_multi_retval_; -static tree - ffecom_multi_fields_[FFEINFO_basictype][FFEINFO_kindtype]; -static bool ffecom_member_namelisted_; /* _member_phase1_ namelisted? */ -static bool ffecom_doing_entry_ = FALSE; -static bool ffecom_transform_only_dummies_ = FALSE; -static int ffecom_typesize_pointer_; -static int ffecom_typesize_integer1_; - -/* Holds pointer-to-function expressions. */ - -static tree ffecom_gfrt_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) NULL_TREE, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* Holds the external names of the functions. */ - -static const char *const ffecom_gfrt_name_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) NAME, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* Whether the function returns. */ - -static const bool ffecom_gfrt_volatile_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) VOLATILE, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* Whether the function returns type complex. */ - -static const bool ffecom_gfrt_complex_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) COMPLEX, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* Whether the function is const - (i.e., has no side effects and only depends on its arguments). */ - -static const bool ffecom_gfrt_const_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) CONST, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* Type code for the function return value. */ - -static const ffecomRttype_ ffecom_gfrt_type_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) TYPE, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* String of codes for the function's arguments. */ - -static const char *const ffecom_gfrt_argstring_[FFECOM_gfrt] -= -{ -#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX,CONST) ARGS, -#include "com-rt.def" -#undef DEFGFRT -}; - -/* Internal macros. */ - -/* We let tm.h override the types used here, to handle trivial differences - such as the choice of unsigned int or long unsigned int for size_t. - When machines start needing nontrivial differences in the size type, - it would be best to do something here to figure out automatically - from other information what type to use. */ - -#ifndef SIZE_TYPE -#define SIZE_TYPE "long unsigned int" -#endif - -#define ffecom_concat_list_count_(catlist) ((catlist).count) -#define ffecom_concat_list_expr_(catlist,i) ((catlist).exprs[(i)]) -#define ffecom_concat_list_maxlen_(catlist) ((catlist).maxlen) -#define ffecom_concat_list_minlen_(catlist) ((catlist).minlen) - -#define ffecom_char_args_(i,l,e) ffecom_char_args_x_((i),(l),(e),FALSE) -#define ffecom_char_args_with_null_(i,l,e) ffecom_char_args_x_((i),(l),(e),TRUE) - -/* For each binding contour we allocate a binding_level structure - * which records the names defined in that contour. - * Contours include: - * 0) the global one - * 1) one for each function definition, - * where internal declarations of the parameters appear. - * - * The current meaning of a name can be found by searching the levels from - * the current one out to the global one. - */ - -/* Note that the information in the `names' component of the global contour - is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */ - -struct binding_level - { - /* A chain of _DECL nodes for all variables, constants, functions, - and typedef types. These are in the reverse of the order supplied. - */ - tree names; - - /* For each level (except not the global one), - a chain of BLOCK nodes for all the levels - that were entered and exited one level down. */ - tree blocks; - - /* The BLOCK node for this level, if one has been preallocated. - If 0, the BLOCK is allocated (if needed) when the level is popped. */ - tree this_block; - - /* The binding level which this one is contained in (inherits from). */ - struct binding_level *level_chain; - - /* 0: no ffecom_prepare_* functions called at this level yet; - 1: ffecom_prepare* functions called, except not ffecom_prepare_end; - 2: ffecom_prepare_end called. */ - int prep_state; - }; - -#define NULL_BINDING_LEVEL (struct binding_level *) NULL - -/* The binding level currently in effect. */ - -static struct binding_level *current_binding_level; - -/* A chain of binding_level structures awaiting reuse. */ - -static struct binding_level *free_binding_level; - -/* The outermost binding level, for names of file scope. - This is created when the compiler is started and exists - through the entire run. */ - -static struct binding_level *global_binding_level; - -/* Binding level structures are initialized by copying this one. */ - -static const struct binding_level clear_binding_level -= -{NULL, NULL, NULL, NULL_BINDING_LEVEL, 0}; - -/* Language-dependent contents of an identifier. */ - -struct lang_identifier - { - struct tree_identifier ignore; - tree global_value, local_value, label_value; - bool invented; - }; - -/* Macros for access to language-specific slots in an identifier. */ -/* Each of these slots contains a DECL node or null. */ - -/* This represents the value which the identifier has in the - file-scope namespace. */ -#define IDENTIFIER_GLOBAL_VALUE(NODE) \ - (((struct lang_identifier *)(NODE))->global_value) -/* This represents the value which the identifier has in the current - scope. */ -#define IDENTIFIER_LOCAL_VALUE(NODE) \ - (((struct lang_identifier *)(NODE))->local_value) -/* This represents the value which the identifier has as a label in - the current label scope. */ -#define IDENTIFIER_LABEL_VALUE(NODE) \ - (((struct lang_identifier *)(NODE))->label_value) -/* This is nonzero if the identifier was "made up" by g77 code. */ -#define IDENTIFIER_INVENTED(NODE) \ - (((struct lang_identifier *)(NODE))->invented) - -/* In identifiers, C uses the following fields in a special way: - TREE_PUBLIC to record that there was a previous local extern decl. - TREE_USED to record that such a decl was used. - TREE_ADDRESSABLE to record that the address of such a decl was used. */ - -/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function - that have names. Here so we can clear out their names' definitions - at the end of the function. */ - -static tree named_labels; - -/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ - -static tree shadowed_labels; - -/* Return the subscript expression, modified to do range-checking. - - `array' is the array to be checked against. - `element' is the subscript expression to check. - `dim' is the dimension number (starting at 0). - `total_dims' is the total number of dimensions (0 for CHARACTER substring). -*/ - -static tree -ffecom_subscript_check_ (tree array, tree element, int dim, int total_dims, - const char *array_name) -{ - tree low = TYPE_MIN_VALUE (TYPE_DOMAIN (array)); - tree high = TYPE_MAX_VALUE (TYPE_DOMAIN (array)); - tree cond; - tree die; - tree args; - - if (element == error_mark_node) - return element; - - if (TREE_TYPE (low) != TREE_TYPE (element)) - { - if (TYPE_PRECISION (TREE_TYPE (low)) - > TYPE_PRECISION (TREE_TYPE (element))) - element = convert (TREE_TYPE (low), element); - else - { - low = convert (TREE_TYPE (element), low); - if (high) - high = convert (TREE_TYPE (element), high); - } - } - - element = ffecom_save_tree (element); - if (total_dims == 0) - { - /* Special handling for substring range checks. Fortran allows the - end subscript < begin subscript, which means that expressions like - string(1:0) are valid (and yield a null string). In view of this, - enforce two simpler conditions: - 1) element<=high for end-substring; - 2) element>=low for start-substring. - Run-time character movement will enforce remaining conditions. - - More complicated checks would be better, but present structure only - provides one index element at a time, so it is not possible to - enforce a check of both i and j in string(i:j). If it were, the - complete set of rules would read, - if ( ((j ffecom_typesize_integer1_ - && ffetype_size (type) > ffecom_typesize_integer1_) - /* E.g. ARRAY(INDEX), given INTEGER*8 INDEX, on a system with 64-bit - pointers and 32-bit integers. Do the full 64-bit pointer - arithmetic, for codes using arrays for nonstandard heap-like - work. */ - flatten = 1; - } - - total_dims = i; - - need_ptr = want_ptr || flatten; - - if (! item) - { - if (need_ptr) - item = ffecom_ptr_to_expr (ffebld_left (expr)); - else - item = ffecom_expr (ffebld_left (expr)); - - if (item == error_mark_node) - return item; - - if (ffeinfo_where (ffebld_info (expr)) == FFEINFO_whereFLEETING - && ! mark_addressable (item)) - return error_mark_node; - } - - if (item == error_mark_node) - return item; - - if (need_ptr) - { - tree min; - - for (--i, array = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item))); - i >= 0; - --i, array = TYPE_MAIN_VARIANT (TREE_TYPE (array))) - { - min = TYPE_MIN_VALUE (TYPE_DOMAIN (array)); - element = ffecom_expr_ (dims[i], NULL, NULL, NULL, FALSE, TRUE); - if (flag_bounds_check) - element = ffecom_subscript_check_ (array, element, i, total_dims, - array_name); - if (element == error_mark_node) - return element; - - /* Widen integral arithmetic as desired while preserving - signedness. */ - tree_type = TREE_TYPE (element); - tree_type_x = tree_type; - if (tree_type - && GET_MODE_CLASS (TYPE_MODE (tree_type)) == MODE_INT - && TYPE_PRECISION (tree_type) < TYPE_PRECISION (sizetype)) - tree_type_x = (TREE_UNSIGNED (tree_type) ? usizetype : ssizetype); - - if (TREE_TYPE (min) != tree_type_x) - min = convert (tree_type_x, min); - if (TREE_TYPE (element) != tree_type_x) - element = convert (tree_type_x, element); - - item = ffecom_2 (PLUS_EXPR, - build_pointer_type (TREE_TYPE (array)), - item, - size_binop (MULT_EXPR, - size_in_bytes (TREE_TYPE (array)), - convert (sizetype, - fold (build (MINUS_EXPR, - tree_type_x, - element, min))))); - } - if (! want_ptr) - { - item = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item))), - item); - } - } - else - { - for (--i; - i >= 0; - --i) - { - array = TYPE_MAIN_VARIANT (TREE_TYPE (item)); - - element = ffecom_expr_ (dims[i], NULL, NULL, NULL, FALSE, TRUE); - if (flag_bounds_check) - element = ffecom_subscript_check_ (array, element, i, total_dims, - array_name); - if (element == error_mark_node) - return element; - - /* Widen integral arithmetic as desired while preserving - signedness. */ - tree_type = TREE_TYPE (element); - tree_type_x = tree_type; - if (tree_type - && GET_MODE_CLASS (TYPE_MODE (tree_type)) == MODE_INT - && TYPE_PRECISION (tree_type) < TYPE_PRECISION (sizetype)) - tree_type_x = (TREE_UNSIGNED (tree_type) ? usizetype : ssizetype); - - element = convert (tree_type_x, element); - - item = ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item))), - item, - element); - } - } - - return item; -} - -/* This is like gcc's stabilize_reference -- in fact, most of the code - comes from that -- but it handles the situation where the reference - is going to have its subparts picked at, and it shouldn't change - (or trigger extra invocations of functions in the subtrees) due to - this. save_expr is a bit overzealous, because we don't need the - entire thing calculated and saved like a temp. So, for DECLs, no - change is needed, because these are stable aggregates, and ARRAY_REF - and such might well be stable too, but for things like calculations, - we do need to calculate a snapshot of a value before picking at it. */ - -static tree -ffecom_stabilize_aggregate_ (tree ref) -{ - tree result; - enum tree_code code = TREE_CODE (ref); - - switch (code) - { - case VAR_DECL: - case PARM_DECL: - case RESULT_DECL: - /* No action is needed in this case. */ - return ref; - - case NOP_EXPR: - case CONVERT_EXPR: - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - case FIX_FLOOR_EXPR: - case FIX_ROUND_EXPR: - case FIX_CEIL_EXPR: - result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0))); - break; - - case INDIRECT_REF: - result = build_nt (INDIRECT_REF, - stabilize_reference_1 (TREE_OPERAND (ref, 0))); - break; - - case COMPONENT_REF: - result = build_nt (COMPONENT_REF, - stabilize_reference (TREE_OPERAND (ref, 0)), - TREE_OPERAND (ref, 1)); - break; - - case BIT_FIELD_REF: - result = build_nt (BIT_FIELD_REF, - stabilize_reference (TREE_OPERAND (ref, 0)), - stabilize_reference_1 (TREE_OPERAND (ref, 1)), - stabilize_reference_1 (TREE_OPERAND (ref, 2))); - break; - - case ARRAY_REF: - result = build_nt (ARRAY_REF, - stabilize_reference (TREE_OPERAND (ref, 0)), - stabilize_reference_1 (TREE_OPERAND (ref, 1))); - break; - - case COMPOUND_EXPR: - result = build_nt (COMPOUND_EXPR, - stabilize_reference_1 (TREE_OPERAND (ref, 0)), - stabilize_reference (TREE_OPERAND (ref, 1))); - break; - - case RTL_EXPR: - abort (); - - - default: - return save_expr (ref); - - case ERROR_MARK: - return error_mark_node; - } - - TREE_TYPE (result) = TREE_TYPE (ref); - TREE_READONLY (result) = TREE_READONLY (ref); - TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref); - TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref); - - return result; -} - -/* A rip-off of gcc's convert.c convert_to_complex function, - reworked to handle complex implemented as C structures - (RECORD_TYPE with two fields, real and imaginary `r' and `i'). */ - -static tree -ffecom_convert_to_complex_ (tree type, tree expr) -{ - register enum tree_code form = TREE_CODE (TREE_TYPE (expr)); - tree subtype; - - assert (TREE_CODE (type) == RECORD_TYPE); - - subtype = TREE_TYPE (TYPE_FIELDS (type)); - - if (form == REAL_TYPE || form == INTEGER_TYPE || form == ENUMERAL_TYPE) - { - expr = convert (subtype, expr); - return ffecom_2 (COMPLEX_EXPR, type, expr, - convert (subtype, integer_zero_node)); - } - - if (form == RECORD_TYPE) - { - tree elt_type = TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr))); - if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype)) - return expr; - else - { - expr = save_expr (expr); - return ffecom_2 (COMPLEX_EXPR, - type, - convert (subtype, - ffecom_1 (REALPART_EXPR, - TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr))), - expr)), - convert (subtype, - ffecom_1 (IMAGPART_EXPR, - TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr))), - expr))); - } - } - - if (form == POINTER_TYPE || form == REFERENCE_TYPE) - error ("pointer value used where a complex was expected"); - else - error ("aggregate value used where a complex was expected"); - - return ffecom_2 (COMPLEX_EXPR, type, - convert (subtype, integer_zero_node), - convert (subtype, integer_zero_node)); -} - -/* Like gcc's convert(), but crashes if widening might happen. */ - -static tree -ffecom_convert_narrow_ (type, expr) - tree type, expr; -{ - register tree e = expr; - register enum tree_code code = TREE_CODE (type); - - if (type == TREE_TYPE (e) - || TREE_CODE (e) == ERROR_MARK) - return e; - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))) - return fold (build1 (NOP_EXPR, type, e)); - if (TREE_CODE (TREE_TYPE (e)) == ERROR_MARK - || code == ERROR_MARK) - return error_mark_node; - if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE) - { - assert ("void value not ignored as it ought to be" == NULL); - return error_mark_node; - } - assert (code != VOID_TYPE); - if ((code != RECORD_TYPE) - && (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE)) - assert ("converting COMPLEX to REAL" == NULL); - assert (code != ENUMERAL_TYPE); - if (code == INTEGER_TYPE) - { - assert ((TREE_CODE (TREE_TYPE (e)) == INTEGER_TYPE - && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (e))) - || (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE - && (TYPE_PRECISION (type) - == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (e)))))); - return fold (convert_to_integer (type, e)); - } - if (code == POINTER_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE); - return fold (convert_to_pointer (type, e)); - } - if (code == REAL_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == REAL_TYPE); - assert (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (e))); - return fold (convert_to_real (type, e)); - } - if (code == COMPLEX_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE); - assert (TYPE_PRECISION (TREE_TYPE (type)) <= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (e)))); - return fold (convert_to_complex (type, e)); - } - if (code == RECORD_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE); - /* Check that at least the first field name agrees. */ - assert (DECL_NAME (TYPE_FIELDS (type)) - == DECL_NAME (TYPE_FIELDS (TREE_TYPE (e)))); - assert (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type))) - <= TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e))))); - if (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type))) - == TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e))))) - return e; - return fold (ffecom_convert_to_complex_ (type, e)); - } - - assert ("conversion to non-scalar type requested" == NULL); - return error_mark_node; -} - -/* Like gcc's convert(), but crashes if narrowing might happen. */ - -static tree -ffecom_convert_widen_ (type, expr) - tree type, expr; -{ - register tree e = expr; - register enum tree_code code = TREE_CODE (type); - - if (type == TREE_TYPE (e) - || TREE_CODE (e) == ERROR_MARK) - return e; - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))) - return fold (build1 (NOP_EXPR, type, e)); - if (TREE_CODE (TREE_TYPE (e)) == ERROR_MARK - || code == ERROR_MARK) - return error_mark_node; - if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE) - { - assert ("void value not ignored as it ought to be" == NULL); - return error_mark_node; - } - assert (code != VOID_TYPE); - if ((code != RECORD_TYPE) - && (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE)) - assert ("narrowing COMPLEX to REAL" == NULL); - assert (code != ENUMERAL_TYPE); - if (code == INTEGER_TYPE) - { - assert ((TREE_CODE (TREE_TYPE (e)) == INTEGER_TYPE - && TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (e))) - || (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE - && (TYPE_PRECISION (type) - == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (e)))))); - return fold (convert_to_integer (type, e)); - } - if (code == POINTER_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE); - return fold (convert_to_pointer (type, e)); - } - if (code == REAL_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == REAL_TYPE); - assert (TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (e))); - return fold (convert_to_real (type, e)); - } - if (code == COMPLEX_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE); - assert (TYPE_PRECISION (TREE_TYPE (type)) >= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (e)))); - return fold (convert_to_complex (type, e)); - } - if (code == RECORD_TYPE) - { - assert (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE); - /* Check that at least the first field name agrees. */ - assert (DECL_NAME (TYPE_FIELDS (type)) - == DECL_NAME (TYPE_FIELDS (TREE_TYPE (e)))); - assert (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type))) - >= TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e))))); - if (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type))) - == TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e))))) - return e; - return fold (ffecom_convert_to_complex_ (type, e)); - } - - assert ("conversion to non-scalar type requested" == NULL); - return error_mark_node; -} - -/* Handles making a COMPLEX type, either the standard - (but buggy?) gbe way, or the safer (but less elegant?) - f2c way. */ - -static tree -ffecom_make_complex_type_ (tree subtype) -{ - tree type; - tree realfield; - tree imagfield; - - if (ffe_is_emulate_complex ()) - { - type = make_node (RECORD_TYPE); - realfield = ffecom_decl_field (type, NULL_TREE, "r", subtype); - imagfield = ffecom_decl_field (type, realfield, "i", subtype); - TYPE_FIELDS (type) = realfield; - layout_type (type); - } - else - { - type = make_node (COMPLEX_TYPE); - TREE_TYPE (type) = subtype; - layout_type (type); - } - - return type; -} - -/* Chooses either the gbe or the f2c way to build a - complex constant. */ - -static tree -ffecom_build_complex_constant_ (tree type, tree realpart, tree imagpart) -{ - tree bothparts; - - if (ffe_is_emulate_complex ()) - { - bothparts = build_tree_list (TYPE_FIELDS (type), realpart); - TREE_CHAIN (bothparts) = build_tree_list (TREE_CHAIN (TYPE_FIELDS (type)), imagpart); - bothparts = build (CONSTRUCTOR, type, NULL_TREE, bothparts); - } - else - { - bothparts = build_complex (type, realpart, imagpart); - } - - return bothparts; -} - -static tree -ffecom_arglist_expr_ (const char *c, ffebld expr) -{ - tree list; - tree *plist = &list; - tree trail = NULL_TREE; /* Append char length args here. */ - tree *ptrail = &trail; - tree length; - ffebld exprh; - tree item; - bool ptr = FALSE; - tree wanted = NULL_TREE; - static const char zed[] = "0"; - - if (c == NULL) - c = &zed[0]; - - while (expr != NULL) - { - if (*c != '\0') - { - ptr = FALSE; - if (*c == '&') - { - ptr = TRUE; - ++c; - } - switch (*(c++)) - { - case '\0': - ptr = TRUE; - wanted = NULL_TREE; - break; - - case 'a': - assert (ptr); - wanted = NULL_TREE; - break; - - case 'c': - wanted = ffecom_f2c_complex_type_node; - break; - - case 'd': - wanted = ffecom_f2c_doublereal_type_node; - break; - - case 'e': - wanted = ffecom_f2c_doublecomplex_type_node; - break; - - case 'f': - wanted = ffecom_f2c_real_type_node; - break; - - case 'i': - wanted = ffecom_f2c_integer_type_node; - break; - - case 'j': - wanted = ffecom_f2c_longint_type_node; - break; - - default: - assert ("bad argstring code" == NULL); - wanted = NULL_TREE; - break; - } - } - - exprh = ffebld_head (expr); - if (exprh == NULL) - wanted = NULL_TREE; - - if ((wanted == NULL_TREE) - || (ptr - && (TYPE_MODE - (ffecom_tree_type[ffeinfo_basictype (ffebld_info (exprh))] - [ffeinfo_kindtype (ffebld_info (exprh))]) - == TYPE_MODE (wanted)))) - *plist - = build_tree_list (NULL_TREE, - ffecom_arg_ptr_to_expr (exprh, - &length)); - else - { - item = ffecom_arg_expr (exprh, &length); - item = ffecom_convert_widen_ (wanted, item); - if (ptr) - { - item = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (item)), - item); - } - *plist - = build_tree_list (NULL_TREE, - item); - } - - plist = &TREE_CHAIN (*plist); - expr = ffebld_trail (expr); - if (length != NULL_TREE) - { - *ptrail = build_tree_list (NULL_TREE, length); - ptrail = &TREE_CHAIN (*ptrail); - } - } - - /* We've run out of args in the call; if the implementation expects - more, supply null pointers for them, which the implementation can - check to see if an arg was omitted. */ - - while (*c != '\0' && *c != '0') - { - if (*c == '&') - ++c; - else - assert ("missing arg to run-time routine!" == NULL); - - switch (*(c++)) - { - case '\0': - case 'a': - case 'c': - case 'd': - case 'e': - case 'f': - case 'i': - case 'j': - break; - - default: - assert ("bad arg string code" == NULL); - break; - } - *plist - = build_tree_list (NULL_TREE, - null_pointer_node); - plist = &TREE_CHAIN (*plist); - } - - *plist = trail; - - return list; -} - -static tree -ffecom_widest_expr_type_ (ffebld list) -{ - ffebld item; - ffebld widest = NULL; - ffetype type; - ffetype widest_type = NULL; - tree t; - - for (; list != NULL; list = ffebld_trail (list)) - { - item = ffebld_head (list); - if (item == NULL) - continue; - if ((widest != NULL) - && (ffeinfo_basictype (ffebld_info (item)) - != ffeinfo_basictype (ffebld_info (widest)))) - continue; - type = ffeinfo_type (ffeinfo_basictype (ffebld_info (item)), - ffeinfo_kindtype (ffebld_info (item))); - if ((widest == FFEINFO_kindtypeNONE) - || (ffetype_size (type) - > ffetype_size (widest_type))) - { - widest = item; - widest_type = type; - } - } - - assert (widest != NULL); - t = ffecom_tree_type[ffeinfo_basictype (ffebld_info (widest))] - [ffeinfo_kindtype (ffebld_info (widest))]; - assert (t != NULL_TREE); - return t; -} - -/* Check whether a partial overlap between two expressions is possible. - - Can *starting* to write a portion of expr1 change the value - computed (perhaps already, *partially*) by expr2? - - Currently, this is a concern only for a COMPLEX expr1. But if it - isn't in COMMON or local EQUIVALENCE, since we don't support - aliasing of arguments, it isn't a concern. */ - -static bool -ffecom_possible_partial_overlap_ (ffebld expr1, ffebld expr2 ATTRIBUTE_UNUSED) -{ - ffesymbol sym; - ffestorag st; - - switch (ffebld_op (expr1)) - { - case FFEBLD_opSYMTER: - sym = ffebld_symter (expr1); - break; - - case FFEBLD_opARRAYREF: - if (ffebld_op (ffebld_left (expr1)) != FFEBLD_opSYMTER) - return FALSE; - sym = ffebld_symter (ffebld_left (expr1)); - break; - - default: - return FALSE; - } - - if (ffesymbol_where (sym) != FFEINFO_whereCOMMON - && (ffesymbol_where (sym) != FFEINFO_whereLOCAL - || ! (st = ffesymbol_storage (sym)) - || ! ffestorag_parent (st))) - return FALSE; - - /* It's in COMMON or local EQUIVALENCE. */ - - return TRUE; -} - -/* Check whether dest and source might overlap. ffebld versions of these - might or might not be passed, will be NULL if not. - - The test is really whether source_tree is modifiable and, if modified, - might overlap destination such that the value(s) in the destination might - change before it is finally modified. dest_* are the canonized - destination itself. */ - -static bool -ffecom_overlap_ (tree dest_decl, tree dest_offset, tree dest_size, - tree source_tree, ffebld source UNUSED, - bool scalar_arg) -{ - tree source_decl; - tree source_offset; - tree source_size; - tree t; - - if (source_tree == NULL_TREE) - return FALSE; - - switch (TREE_CODE (source_tree)) - { - case ERROR_MARK: - case IDENTIFIER_NODE: - case INTEGER_CST: - case REAL_CST: - case COMPLEX_CST: - case STRING_CST: - case CONST_DECL: - case VAR_DECL: - case RESULT_DECL: - case FIELD_DECL: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case FIX_TRUNC_EXPR: - case FIX_CEIL_EXPR: - case FIX_FLOOR_EXPR: - case FIX_ROUND_EXPR: - case FLOAT_EXPR: - case NEGATE_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case ABS_EXPR: - case FFS_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case BIT_ANDTC_EXPR: - case BIT_NOT_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_NOT_EXPR: - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - case COMPLEX_EXPR: - case CONJ_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - case LABEL_EXPR: - case COMPONENT_REF: - return FALSE; - - case COMPOUND_EXPR: - return ffecom_overlap_ (dest_decl, dest_offset, dest_size, - TREE_OPERAND (source_tree, 1), NULL, - scalar_arg); - - case MODIFY_EXPR: - return ffecom_overlap_ (dest_decl, dest_offset, dest_size, - TREE_OPERAND (source_tree, 0), NULL, - scalar_arg); - - case CONVERT_EXPR: - case NOP_EXPR: - case NON_LVALUE_EXPR: - case PLUS_EXPR: - if (TREE_CODE (TREE_TYPE (source_tree)) != POINTER_TYPE) - return TRUE; - - ffecom_tree_canonize_ptr_ (&source_decl, &source_offset, - source_tree); - source_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (source_tree))); - break; - - case COND_EXPR: - return - ffecom_overlap_ (dest_decl, dest_offset, dest_size, - TREE_OPERAND (source_tree, 1), NULL, - scalar_arg) - || ffecom_overlap_ (dest_decl, dest_offset, dest_size, - TREE_OPERAND (source_tree, 2), NULL, - scalar_arg); - - - case ADDR_EXPR: - ffecom_tree_canonize_ref_ (&source_decl, &source_offset, - &source_size, - TREE_OPERAND (source_tree, 0)); - break; - - case PARM_DECL: - if (TREE_CODE (TREE_TYPE (source_tree)) != POINTER_TYPE) - return TRUE; - - source_decl = source_tree; - source_offset = bitsize_zero_node; - source_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (source_tree))); - break; - - case SAVE_EXPR: - case REFERENCE_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case INDIRECT_REF: - case ARRAY_REF: - case CALL_EXPR: - default: - return TRUE; - } - - /* Come here when source_decl, source_offset, and source_size filled - in appropriately. */ - - if (source_decl == NULL_TREE) - return FALSE; /* No decl involved, so no overlap. */ - - if (source_decl != dest_decl) - return FALSE; /* Different decl, no overlap. */ - - if (TREE_CODE (dest_size) == ERROR_MARK) - return TRUE; /* Assignment into entire assumed-size - array? Shouldn't happen.... */ - - t = ffecom_2 (LE_EXPR, integer_type_node, - ffecom_2 (PLUS_EXPR, TREE_TYPE (dest_offset), - dest_offset, - convert (TREE_TYPE (dest_offset), - dest_size)), - convert (TREE_TYPE (dest_offset), - source_offset)); - - if (integer_onep (t)) - return FALSE; /* Destination precedes source. */ - - if (!scalar_arg - || (source_size == NULL_TREE) - || (TREE_CODE (source_size) == ERROR_MARK) - || integer_zerop (source_size)) - return TRUE; /* No way to tell if dest follows source. */ - - t = ffecom_2 (LE_EXPR, integer_type_node, - ffecom_2 (PLUS_EXPR, TREE_TYPE (source_offset), - source_offset, - convert (TREE_TYPE (source_offset), - source_size)), - convert (TREE_TYPE (source_offset), - dest_offset)); - - if (integer_onep (t)) - return FALSE; /* Destination follows source. */ - - return TRUE; /* Destination and source overlap. */ -} - -/* Check whether dest might overlap any of a list of arguments or is - in a COMMON area the callee might know about (and thus modify). */ - -static bool -ffecom_args_overlapping_ (tree dest_tree, ffebld dest UNUSED, - tree args, tree callee_commons, - bool scalar_args) -{ - tree arg; - tree dest_decl; - tree dest_offset; - tree dest_size; - - ffecom_tree_canonize_ref_ (&dest_decl, &dest_offset, &dest_size, - dest_tree); - - if (dest_decl == NULL_TREE) - return FALSE; /* Seems unlikely! */ - - /* If the decl cannot be determined reliably, or if its in COMMON - and the callee isn't known to not futz with COMMON via other - means, overlap might happen. */ - - if ((TREE_CODE (dest_decl) == ERROR_MARK) - || ((callee_commons != NULL_TREE) - && TREE_PUBLIC (dest_decl))) - return TRUE; - - for (; args != NULL_TREE; args = TREE_CHAIN (args)) - { - if (((arg = TREE_VALUE (args)) != NULL_TREE) - && ffecom_overlap_ (dest_decl, dest_offset, dest_size, - arg, NULL, scalar_args)) - return TRUE; - } - - return FALSE; -} - -/* Build a string for a variable name as used by NAMELIST. This means that - if we're using the f2c library, we build an uppercase string, since - f2c does this. */ - -static tree -ffecom_build_f2c_string_ (int i, const char *s) -{ - if (!ffe_is_f2c_library ()) - return build_string (i, s); - - { - char *tmp; - const char *p; - char *q; - char space[34]; - tree t; - - if (((size_t) i) > ARRAY_SIZE (space)) - tmp = malloc_new_ks (malloc_pool_image (), "f2c_string", i); - else - tmp = &space[0]; - - for (p = s, q = tmp; *p != '\0'; ++p, ++q) - *q = TOUPPER (*p); - *q = '\0'; - - t = build_string (i, tmp); - - if (((size_t) i) > ARRAY_SIZE (space)) - malloc_kill_ks (malloc_pool_image (), tmp, i); - - return t; - } -} - -/* Returns CALL_EXPR or equivalent with given type (pass NULL_TREE for - type to just get whatever the function returns), handling the - f2c value-returning convention, if required, by prepending - to the arglist a pointer to a temporary to receive the return value. */ - -static tree -ffecom_call_ (tree fn, ffeinfoKindtype kt, bool is_f2c_complex, - tree type, tree args, tree dest_tree, - ffebld dest, bool *dest_used, tree callee_commons, - bool scalar_args, tree hook) -{ - tree item; - tree tempvar; - - if (dest_used != NULL) - *dest_used = FALSE; - - if (is_f2c_complex) - { - if ((dest_used == NULL) - || (dest == NULL) - || (ffeinfo_basictype (ffebld_info (dest)) - != FFEINFO_basictypeCOMPLEX) - || (ffeinfo_kindtype (ffebld_info (dest)) != kt) - || ((type != NULL_TREE) && (TREE_TYPE (dest_tree) != type)) - || ffecom_args_overlapping_ (dest_tree, dest, args, - callee_commons, - scalar_args)) - { -#ifdef HOHO - tempvar = ffecom_make_tempvar (ffecom_tree_type - [FFEINFO_basictypeCOMPLEX][kt], - FFETARGET_charactersizeNONE, - -1); -#else - tempvar = hook; - assert (tempvar); -#endif - } - else - { - *dest_used = TRUE; - tempvar = dest_tree; - type = NULL_TREE; - } - - item - = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (tempvar)), - tempvar)); - TREE_CHAIN (item) = args; - - item = ffecom_3s (CALL_EXPR, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), fn, - item, NULL_TREE); - - if (tempvar != dest_tree) - item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), item, tempvar); - } - else - item = ffecom_3s (CALL_EXPR, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), fn, - args, NULL_TREE); - - if ((type != NULL_TREE) && (TREE_TYPE (item) != type)) - item = ffecom_convert_narrow_ (type, item); - - return item; -} - -/* Given two arguments, transform them and make a call to the given - function via ffecom_call_. */ - -static tree -ffecom_call_binop_ (tree fn, ffeinfoKindtype kt, bool is_f2c_complex, - tree type, ffebld left, ffebld right, - tree dest_tree, ffebld dest, bool *dest_used, - tree callee_commons, bool scalar_args, bool ref, tree hook) -{ - tree left_tree; - tree right_tree; - tree left_length; - tree right_length; - - if (ref) - { - /* Pass arguments by reference. */ - left_tree = ffecom_arg_ptr_to_expr (left, &left_length); - right_tree = ffecom_arg_ptr_to_expr (right, &right_length); - } - else - { - /* Pass arguments by value. */ - left_tree = ffecom_arg_expr (left, &left_length); - right_tree = ffecom_arg_expr (right, &right_length); - } - - - left_tree = build_tree_list (NULL_TREE, left_tree); - right_tree = build_tree_list (NULL_TREE, right_tree); - TREE_CHAIN (left_tree) = right_tree; - - if (left_length != NULL_TREE) - { - left_length = build_tree_list (NULL_TREE, left_length); - TREE_CHAIN (right_tree) = left_length; - } - - if (right_length != NULL_TREE) - { - right_length = build_tree_list (NULL_TREE, right_length); - if (left_length != NULL_TREE) - TREE_CHAIN (left_length) = right_length; - else - TREE_CHAIN (right_tree) = right_length; - } - - return ffecom_call_ (fn, kt, is_f2c_complex, type, left_tree, - dest_tree, dest, dest_used, callee_commons, - scalar_args, hook); -} - -/* Return ptr/length args for char subexpression - - Handles CHARACTER-type CONTER, SYMTER, SUBSTR, ARRAYREF, and FUNCREF - subexpressions by constructing the appropriate trees for the ptr-to- - character-text and length-of-character-text arguments in a calling - sequence. - - Note that if with_null is TRUE, and the expression is an opCONTER, - a null byte is appended to the string. */ - -static void -ffecom_char_args_x_ (tree *xitem, tree *length, ffebld expr, bool with_null) -{ - tree item; - tree high; - ffetargetCharacter1 val; - ffetargetCharacterSize newlen; - - switch (ffebld_op (expr)) - { - case FFEBLD_opCONTER: - val = ffebld_constant_character1 (ffebld_conter (expr)); - newlen = ffetarget_length_character1 (val); - if (with_null) - { - /* Begin FFETARGET-NULL-KLUDGE. */ - if (newlen != 0) - ++newlen; - } - *length = build_int_2 (newlen, 0); - TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node; - high = build_int_2 (newlen, 0); - TREE_TYPE (high) = ffecom_f2c_ftnlen_type_node; - item = build_string (newlen, - ffetarget_text_character1 (val)); - /* End FFETARGET-NULL-KLUDGE. */ - TREE_TYPE (item) - = build_type_variant - (build_array_type - (char_type_node, - build_range_type - (ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - high)), - 1, 0); - TREE_CONSTANT (item) = 1; - TREE_STATIC (item) = 1; - item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)), - item); - break; - - case FFEBLD_opSYMTER: - { - ffesymbol s = ffebld_symter (expr); - - item = ffesymbol_hook (s).decl_tree; - if (item == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - item = ffesymbol_hook (s).decl_tree; - } - if (ffesymbol_kind (s) == FFEINFO_kindENTITY) - { - if (ffesymbol_size (s) == FFETARGET_charactersizeNONE) - *length = ffesymbol_hook (s).length_tree; - else - { - *length = build_int_2 (ffesymbol_size (s), 0); - TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node; - } - } - else if (item == error_mark_node) - *length = error_mark_node; - else - /* FFEINFO_kindFUNCTION. */ - *length = NULL_TREE; - if (!ffesymbol_hook (s).addr - && (item != error_mark_node)) - item = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (item)), - item); - } - break; - - case FFEBLD_opARRAYREF: - { - ffecom_char_args_ (&item, length, ffebld_left (expr)); - - if (item == error_mark_node || *length == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - item = ffecom_arrayref_ (item, expr, 1); - } - break; - - case FFEBLD_opSUBSTR: - { - ffebld start; - ffebld end; - ffebld thing = ffebld_right (expr); - tree start_tree; - tree end_tree; - const char *char_name; - ffebld left_symter; - tree array; - - assert (ffebld_op (thing) == FFEBLD_opITEM); - start = ffebld_head (thing); - thing = ffebld_trail (thing); - assert (ffebld_trail (thing) == NULL); - end = ffebld_head (thing); - - /* Determine name for pretty-printing range-check errors. */ - for (left_symter = ffebld_left (expr); - left_symter && ffebld_op (left_symter) == FFEBLD_opARRAYREF; - left_symter = ffebld_left (left_symter)) - ; - if (ffebld_op (left_symter) == FFEBLD_opSYMTER) - char_name = ffesymbol_text (ffebld_symter (left_symter)); - else - char_name = "[expr?]"; - - ffecom_char_args_ (&item, length, ffebld_left (expr)); - - if (item == error_mark_node || *length == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - array = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item))); - - /* ~~~~Handle INTEGER*8 start/end, a la FFEBLD_opARRAYREF. */ - - if (start == NULL) - { - if (end == NULL) - ; - else - { - end_tree = ffecom_expr (end); - if (flag_bounds_check) - end_tree = ffecom_subscript_check_ (array, end_tree, 1, 0, - char_name); - end_tree = convert (ffecom_f2c_ftnlen_type_node, - end_tree); - - if (end_tree == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - *length = end_tree; - } - } - else - { - start_tree = ffecom_expr (start); - if (flag_bounds_check) - start_tree = ffecom_subscript_check_ (array, start_tree, 0, 0, - char_name); - start_tree = convert (ffecom_f2c_ftnlen_type_node, - start_tree); - - if (start_tree == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - start_tree = ffecom_save_tree (start_tree); - - item = ffecom_2 (PLUS_EXPR, TREE_TYPE (item), - item, - ffecom_2 (MINUS_EXPR, - TREE_TYPE (start_tree), - start_tree, - ffecom_f2c_ftnlen_one_node)); - - if (end == NULL) - { - *length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - ffecom_2 (MINUS_EXPR, - ffecom_f2c_ftnlen_type_node, - *length, - start_tree)); - } - else - { - end_tree = ffecom_expr (end); - if (flag_bounds_check) - end_tree = ffecom_subscript_check_ (array, end_tree, 1, 0, - char_name); - end_tree = convert (ffecom_f2c_ftnlen_type_node, - end_tree); - - if (end_tree == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - *length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - ffecom_2 (MINUS_EXPR, - ffecom_f2c_ftnlen_type_node, - end_tree, start_tree)); - } - } - } - break; - - case FFEBLD_opFUNCREF: - { - ffesymbol s = ffebld_symter (ffebld_left (expr)); - tree tempvar; - tree args; - ffetargetCharacterSize size = ffeinfo_size (ffebld_info (expr)); - ffecomGfrt ix; - - if (size == FFETARGET_charactersizeNONE) - /* ~~Kludge alert! This should someday be fixed. */ - size = 24; - - *length = build_int_2 (size, 0); - TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node; - - if (ffeinfo_where (ffebld_info (ffebld_left (expr))) - == FFEINFO_whereINTRINSIC) - { - if (size == 1) - { - /* Invocation of an intrinsic returning CHARACTER*1. */ - item = ffecom_expr_intrinsic_ (expr, NULL_TREE, - NULL, NULL); - break; - } - ix = ffeintrin_gfrt_direct (ffebld_symter_implementation (ffebld_left (expr))); - assert (ix != FFECOM_gfrt); - item = ffecom_gfrt_tree_ (ix); - } - else - { - ix = FFECOM_gfrt; - item = ffesymbol_hook (s).decl_tree; - if (item == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - item = ffesymbol_hook (s).decl_tree; - } - if (item == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - if (!ffesymbol_hook (s).addr) - item = ffecom_1_fn (item); - } - -#ifdef HOHO - tempvar = ffecom_push_tempvar (char_type_node, size, -1, TRUE); -#else - tempvar = ffebld_nonter_hook (expr); - assert (tempvar); -#endif - tempvar = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (tempvar)), - tempvar); - - args = build_tree_list (NULL_TREE, tempvar); - - if (ffesymbol_where (s) == FFEINFO_whereCONSTANT) /* Sfunc args by value. */ - TREE_CHAIN (args) = ffecom_list_expr (ffebld_right (expr)); - else - { - TREE_CHAIN (args) = build_tree_list (NULL_TREE, *length); - if (ffesymbol_where (s) == FFEINFO_whereINTRINSIC) - { - TREE_CHAIN (TREE_CHAIN (args)) - = ffecom_arglist_expr_ (ffecom_gfrt_args_ (ix), - ffebld_right (expr)); - } - else - { - TREE_CHAIN (TREE_CHAIN (args)) - = ffecom_list_ptr_to_expr (ffebld_right (expr)); - } - } - - item = ffecom_3s (CALL_EXPR, - TREE_TYPE (TREE_TYPE (TREE_TYPE (item))), - item, args, NULL_TREE); - item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), item, - tempvar); - } - break; - - case FFEBLD_opCONVERT: - - ffecom_char_args_ (&item, length, ffebld_left (expr)); - - if (item == error_mark_node || *length == error_mark_node) - { - item = *length = error_mark_node; - break; - } - - if ((ffebld_size_known (ffebld_left (expr)) - == FFETARGET_charactersizeNONE) - || (ffebld_size_known (ffebld_left (expr)) < (ffebld_size (expr)))) - { /* Possible blank-padding needed, copy into - temporary. */ - tree tempvar; - tree args; - tree newlen; - -#ifdef HOHO - tempvar = ffecom_make_tempvar (char_type_node, - ffebld_size (expr), -1); -#else - tempvar = ffebld_nonter_hook (expr); - assert (tempvar); -#endif - tempvar = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (tempvar)), - tempvar); - - newlen = build_int_2 (ffebld_size (expr), 0); - TREE_TYPE (newlen) = ffecom_f2c_ftnlen_type_node; - - args = build_tree_list (NULL_TREE, tempvar); - TREE_CHAIN (args) = build_tree_list (NULL_TREE, item); - TREE_CHAIN (TREE_CHAIN (args)) = build_tree_list (NULL_TREE, newlen); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (args))) - = build_tree_list (NULL_TREE, *length); - - item = ffecom_call_gfrt (FFECOM_gfrtCOPY, args, NULL_TREE); - TREE_SIDE_EFFECTS (item) = 1; - item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), fold (item), - tempvar); - *length = newlen; - } - else - { /* Just truncate the length. */ - *length = build_int_2 (ffebld_size (expr), 0); - TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node; - } - break; - - default: - assert ("bad op for single char arg expr" == NULL); - item = NULL_TREE; - break; - } - - *xitem = item; -} - -/* Check the size of the type to be sure it doesn't overflow the - "portable" capacities of the compiler back end. `dummy' types - can generally overflow the normal sizes as long as the computations - themselves don't overflow. A particular target of the back end - must still enforce its size requirements, though, and the back - end takes care of this in stor-layout.c. */ - -static tree -ffecom_check_size_overflow_ (ffesymbol s, tree type, bool dummy) -{ - if (TREE_CODE (type) == ERROR_MARK) - return type; - - if (TYPE_SIZE (type) == NULL_TREE) - return type; - - if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) - return type; - - /* An array is too large if size is negative or the type_size overflows - or its "upper half" is larger than 3 (which would make the signed - byte size and offset computations overflow). */ - - if ((tree_int_cst_sgn (TYPE_SIZE (type)) < 0) - || (!dummy && (TREE_INT_CST_HIGH (TYPE_SIZE (type)) > 3 - || TREE_OVERFLOW (TYPE_SIZE (type))))) - { - ffebad_start (FFEBAD_ARRAY_LARGE); - ffebad_string (ffesymbol_text (s)); - ffebad_here (0, ffesymbol_where_line (s), ffesymbol_where_column (s)); - ffebad_finish (); - - return error_mark_node; - } - - return type; -} - -/* Builds a length argument (PARM_DECL). Also wraps type in an array type - where the dimension info is (1:size) where is ffesymbol_size(s) if - known, length_arg if not known (FFETARGET_charactersizeNONE). */ - -static tree -ffecom_char_enhance_arg_ (tree *xtype, ffesymbol s) -{ - ffetargetCharacterSize sz = ffesymbol_size (s); - tree highval; - tree tlen; - tree type = *xtype; - - if (ffesymbol_where (s) == FFEINFO_whereCONSTANT) - tlen = NULL_TREE; /* A statement function, no length passed. */ - else - { - if (ffesymbol_where (s) == FFEINFO_whereDUMMY) - tlen = ffecom_get_invented_identifier ("__g77_length_%s", - ffesymbol_text (s)); - else - tlen = ffecom_get_invented_identifier ("__g77_%s", "length"); - tlen = build_decl (PARM_DECL, tlen, ffecom_f2c_ftnlen_type_node); - DECL_ARTIFICIAL (tlen) = 1; - } - - if (sz == FFETARGET_charactersizeNONE) - { - assert (tlen != NULL_TREE); - highval = variable_size (tlen); - } - else - { - highval = build_int_2 (sz, 0); - TREE_TYPE (highval) = ffecom_f2c_ftnlen_type_node; - } - - type = build_array_type (type, - build_range_type (ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - highval)); - - *xtype = type; - return tlen; -} - -/* ffecom_concat_list_gather_ -- Gather list of concatenated string exprs - - ffecomConcatList_ catlist; - ffebld expr; // expr of CHARACTER basictype. - ffetargetCharacterSize max; // max chars to gather or _...NONE if no max - catlist = ffecom_concat_list_gather_(catlist,expr,max); - - Scans expr for character subexpressions, updates and returns catlist - accordingly. */ - -static ffecomConcatList_ -ffecom_concat_list_gather_ (ffecomConcatList_ catlist, ffebld expr, - ffetargetCharacterSize max) -{ - ffetargetCharacterSize sz; - - recurse: - - if (expr == NULL) - return catlist; - - if ((max != FFETARGET_charactersizeNONE) && (catlist.minlen >= max)) - return catlist; /* Don't append any more items. */ - - switch (ffebld_op (expr)) - { - case FFEBLD_opCONTER: - case FFEBLD_opSYMTER: - case FFEBLD_opARRAYREF: - case FFEBLD_opFUNCREF: - case FFEBLD_opSUBSTR: - case FFEBLD_opCONVERT: /* Callers should strip this off beforehand - if they don't need to preserve it. */ - if (catlist.count == catlist.max) - { /* Make a (larger) list. */ - ffebld *newx; - int newmax; - - newmax = (catlist.max == 0) ? 8 : catlist.max * 2; - newx = malloc_new_ks (malloc_pool_image (), "catlist", - newmax * sizeof (newx[0])); - if (catlist.max != 0) - { - memcpy (newx, catlist.exprs, catlist.max * sizeof (newx[0])); - malloc_kill_ks (malloc_pool_image (), catlist.exprs, - catlist.max * sizeof (newx[0])); - } - catlist.max = newmax; - catlist.exprs = newx; - } - if ((sz = ffebld_size_known (expr)) != FFETARGET_charactersizeNONE) - catlist.minlen += sz; - else - ++catlist.minlen; /* Not true for F90; can be 0 length. */ - if ((sz = ffebld_size_max (expr)) == FFETARGET_charactersizeNONE) - catlist.maxlen = sz; - else - catlist.maxlen += sz; - if ((max != FFETARGET_charactersizeNONE) && (catlist.minlen > max)) - { /* This item overlaps (or is beyond) the end - of the destination. */ - switch (ffebld_op (expr)) - { - case FFEBLD_opCONTER: - case FFEBLD_opSYMTER: - case FFEBLD_opARRAYREF: - case FFEBLD_opFUNCREF: - case FFEBLD_opSUBSTR: - /* ~~Do useful truncations here. */ - break; - - default: - assert ("op changed or inconsistent switches!" == NULL); - break; - } - } - catlist.exprs[catlist.count++] = expr; - return catlist; - - case FFEBLD_opPAREN: - expr = ffebld_left (expr); - goto recurse; /* :::::::::::::::::::: */ - - case FFEBLD_opCONCATENATE: - catlist = ffecom_concat_list_gather_ (catlist, ffebld_left (expr), max); - expr = ffebld_right (expr); - goto recurse; /* :::::::::::::::::::: */ - -#if 0 /* Breaks passing small actual arg to larger - dummy arg of sfunc */ - case FFEBLD_opCONVERT: - expr = ffebld_left (expr); - { - ffetargetCharacterSize cmax; - - cmax = catlist.len + ffebld_size_known (expr); - - if ((max == FFETARGET_charactersizeNONE) || (max > cmax)) - max = cmax; - } - goto recurse; /* :::::::::::::::::::: */ -#endif - - case FFEBLD_opANY: - return catlist; - - default: - assert ("bad op in _gather_" == NULL); - return catlist; - } -} - -/* ffecom_concat_list_kill_ -- Kill list of concatenated string exprs - - ffecomConcatList_ catlist; - ffecom_concat_list_kill_(catlist); - - Anything allocated within the list info is deallocated. */ - -static void -ffecom_concat_list_kill_ (ffecomConcatList_ catlist) -{ - if (catlist.max != 0) - malloc_kill_ks (malloc_pool_image (), catlist.exprs, - catlist.max * sizeof (catlist.exprs[0])); -} - -/* Make list of concatenated string exprs. - - Returns a flattened list of concatenated subexpressions given a - tree of such expressions. */ - -static ffecomConcatList_ -ffecom_concat_list_new_ (ffebld expr, ffetargetCharacterSize max) -{ - ffecomConcatList_ catlist; - - catlist.maxlen = catlist.minlen = catlist.max = catlist.count = 0; - return ffecom_concat_list_gather_ (catlist, expr, max); -} - -/* Provide some kind of useful info on member of aggregate area, - since current g77/gcc technology does not provide debug info - on these members. */ - -static void -ffecom_debug_kludge_ (tree aggr, const char *aggr_type, ffesymbol member, - tree member_type UNUSED, ffetargetOffset offset) -{ - tree value; - tree decl; - int len; - char *buff; - char space[120]; -#if 0 - tree type_id; - - for (type_id = member_type; - TREE_CODE (type_id) != IDENTIFIER_NODE; - ) - { - switch (TREE_CODE (type_id)) - { - case INTEGER_TYPE: - case REAL_TYPE: - type_id = TYPE_NAME (type_id); - break; - - case ARRAY_TYPE: - case COMPLEX_TYPE: - type_id = TREE_TYPE (type_id); - break; - - default: - assert ("no IDENTIFIER_NODE for type!" == NULL); - type_id = error_mark_node; - break; - } - } -#endif - - if (ffecom_transform_only_dummies_ - || !ffe_is_debug_kludge ()) - return; /* Can't do this yet, maybe later. */ - - len = 60 - + strlen (aggr_type) - + IDENTIFIER_LENGTH (DECL_NAME (aggr)); -#if 0 - + IDENTIFIER_LENGTH (type_id); -#endif - - if (((size_t) len) >= ARRAY_SIZE (space)) - buff = malloc_new_ks (malloc_pool_image (), "debug_kludge", len + 1); - else - buff = &space[0]; - - sprintf (&buff[0], "At (%s) `%s' plus %ld bytes", - aggr_type, - IDENTIFIER_POINTER (DECL_NAME (aggr)), - (long int) offset); - - value = build_string (len, buff); - TREE_TYPE (value) - = build_type_variant (build_array_type (char_type_node, - build_range_type - (integer_type_node, - integer_one_node, - build_int_2 (strlen (buff), 0))), - 1, 0); - decl = build_decl (VAR_DECL, - ffecom_get_identifier_ (ffesymbol_text (member)), - TREE_TYPE (value)); - TREE_CONSTANT (decl) = 1; - TREE_STATIC (decl) = 1; - DECL_INITIAL (decl) = error_mark_node; - DECL_IN_SYSTEM_HEADER (decl) = 1; /* Don't let -Wunused complain. */ - decl = start_decl (decl, FALSE); - finish_decl (decl, value, FALSE); - - if (buff != &space[0]) - malloc_kill_ks (malloc_pool_image (), buff, len + 1); -} - -/* ffecom_do_entry_ -- Do compilation of a particular entrypoint - - ffesymbol fn; // the SUBROUTINE, FUNCTION, or ENTRY symbol itself - int i; // entry# for this entrypoint (used by master fn) - ffecom_do_entrypoint_(s,i); - - Makes a public entry point that calls our private master fn (already - compiled). */ - -static void -ffecom_do_entry_ (ffesymbol fn, int entrynum) -{ - ffebld item; - tree type; /* Type of function. */ - tree multi_retval; /* Var holding return value (union). */ - tree result; /* Var holding result. */ - ffeinfoBasictype bt; - ffeinfoKindtype kt; - ffeglobal g; - ffeglobalType gt; - bool charfunc; /* All entry points return same type - CHARACTER. */ - bool cmplxfunc; /* Use f2c way of returning COMPLEX. */ - bool multi; /* Master fn has multiple return types. */ - bool altreturning = FALSE; /* This entry point has alternate returns. */ - int old_lineno = lineno; - const char *old_input_filename = input_filename; - - input_filename = ffesymbol_where_filename (fn); - lineno = ffesymbol_where_filelinenum (fn); - - ffecom_doing_entry_ = TRUE; /* Don't bother with array dimensions. */ - - switch (ffecom_primary_entry_kind_) - { - case FFEINFO_kindFUNCTION: - - /* Determine actual return type for function. */ - - gt = FFEGLOBAL_typeFUNC; - bt = ffesymbol_basictype (fn); - kt = ffesymbol_kindtype (fn); - if (bt == FFEINFO_basictypeNONE) - { - ffeimplic_establish_symbol (fn); - if (ffesymbol_funcresult (fn) != NULL) - ffeimplic_establish_symbol (ffesymbol_funcresult (fn)); - bt = ffesymbol_basictype (fn); - kt = ffesymbol_kindtype (fn); - } - - if (bt == FFEINFO_basictypeCHARACTER) - charfunc = TRUE, cmplxfunc = FALSE; - else if ((bt == FFEINFO_basictypeCOMPLEX) - && ffesymbol_is_f2c (fn)) - charfunc = FALSE, cmplxfunc = TRUE; - else - charfunc = cmplxfunc = FALSE; - - if (charfunc) - type = ffecom_tree_fun_type_void; - else if (ffesymbol_is_f2c (fn)) - type = ffecom_tree_fun_type[bt][kt]; - else - type = build_function_type (ffecom_tree_type[bt][kt], NULL_TREE); - - if ((type == NULL_TREE) - || (TREE_TYPE (type) == NULL_TREE)) - type = ffecom_tree_fun_type_void; /* _sym_exec_transition. */ - - multi = (ffecom_master_bt_ == FFEINFO_basictypeNONE); - break; - - case FFEINFO_kindSUBROUTINE: - gt = FFEGLOBAL_typeSUBR; - bt = FFEINFO_basictypeNONE; - kt = FFEINFO_kindtypeNONE; - if (ffecom_is_altreturning_) - { /* Am _I_ altreturning? */ - for (item = ffesymbol_dummyargs (fn); - item != NULL; - item = ffebld_trail (item)) - { - if (ffebld_op (ffebld_head (item)) == FFEBLD_opSTAR) - { - altreturning = TRUE; - break; - } - } - if (altreturning) - type = ffecom_tree_subr_type; - else - type = ffecom_tree_fun_type_void; - } - else - type = ffecom_tree_fun_type_void; - charfunc = FALSE; - cmplxfunc = FALSE; - multi = FALSE; - break; - - default: - assert ("say what??" == NULL); - /* Fall through. */ - case FFEINFO_kindANY: - gt = FFEGLOBAL_typeANY; - bt = FFEINFO_basictypeNONE; - kt = FFEINFO_kindtypeNONE; - type = error_mark_node; - charfunc = FALSE; - cmplxfunc = FALSE; - multi = FALSE; - break; - } - - /* build_decl uses the current lineno and input_filename to set the decl - source info. So, I've putzed with ffestd and ffeste code to update that - source info to point to the appropriate statement just before calling - ffecom_do_entrypoint (which calls this fn). */ - - start_function (ffecom_get_external_identifier_ (fn), - type, - 0, /* nested/inline */ - 1); /* TREE_PUBLIC */ - - if (((g = ffesymbol_global (fn)) != NULL) - && ((ffeglobal_type (g) == gt) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))) - { - ffeglobal_set_hook (g, current_function_decl); - } - - /* Reset args in master arg list so they get retransitioned. */ - - for (item = ffecom_master_arglist_; - item != NULL; - item = ffebld_trail (item)) - { - ffebld arg; - ffesymbol s; - - arg = ffebld_head (item); - if (ffebld_op (arg) != FFEBLD_opSYMTER) - continue; /* Alternate return or some such thing. */ - s = ffebld_symter (arg); - ffesymbol_hook (s).decl_tree = NULL_TREE; - ffesymbol_hook (s).length_tree = NULL_TREE; - } - - /* Build dummy arg list for this entry point. */ - - if (charfunc || cmplxfunc) - { /* Prepend arg for where result goes. */ - tree type; - tree length; - - if (charfunc) - type = ffecom_tree_type[FFEINFO_basictypeCHARACTER][kt]; - else - type = ffecom_tree_type[FFEINFO_basictypeCOMPLEX][kt]; - - result = ffecom_get_invented_identifier ("__g77_%s", "result"); - - /* Make length arg _and_ enhance type info for CHAR arg itself. */ - - if (charfunc) - length = ffecom_char_enhance_arg_ (&type, fn); - else - length = NULL_TREE; /* Not ref'd if !charfunc. */ - - type = build_pointer_type (type); - result = build_decl (PARM_DECL, result, type); - - push_parm_decl (result); - ffecom_func_result_ = result; - - if (charfunc) - { - push_parm_decl (length); - ffecom_func_length_ = length; - } - } - else - result = DECL_RESULT (current_function_decl); - - ffecom_push_dummy_decls_ (ffesymbol_dummyargs (fn), FALSE); - - store_parm_decls (0); - - ffecom_start_compstmt (); - /* Disallow temp vars at this level. */ - current_binding_level->prep_state = 2; - - /* Make local var to hold return type for multi-type master fn. */ - - if (multi) - { - multi_retval = ffecom_get_invented_identifier ("__g77_%s", - "multi_retval"); - multi_retval = build_decl (VAR_DECL, multi_retval, - ffecom_multi_type_node_); - multi_retval = start_decl (multi_retval, FALSE); - finish_decl (multi_retval, NULL_TREE, FALSE); - } - else - multi_retval = NULL_TREE; /* Not actually ref'd if !multi. */ - - /* Here we emit the actual code for the entry point. */ - - { - ffebld list; - ffebld arg; - ffesymbol s; - tree arglist = NULL_TREE; - tree *plist = &arglist; - tree prepend; - tree call; - tree actarg; - tree master_fn; - - /* Prepare actual arg list based on master arg list. */ - - for (list = ffecom_master_arglist_; - list != NULL; - list = ffebld_trail (list)) - { - arg = ffebld_head (list); - if (ffebld_op (arg) != FFEBLD_opSYMTER) - continue; - s = ffebld_symter (arg); - if (ffesymbol_hook (s).decl_tree == NULL_TREE - || ffesymbol_hook (s).decl_tree == error_mark_node) - actarg = null_pointer_node; /* We don't have this arg. */ - else - actarg = ffesymbol_hook (s).decl_tree; - *plist = build_tree_list (NULL_TREE, actarg); - plist = &TREE_CHAIN (*plist); - } - - /* This code appends the length arguments for character - variables/arrays. */ - - for (list = ffecom_master_arglist_; - list != NULL; - list = ffebld_trail (list)) - { - arg = ffebld_head (list); - if (ffebld_op (arg) != FFEBLD_opSYMTER) - continue; - s = ffebld_symter (arg); - if (ffesymbol_basictype (s) != FFEINFO_basictypeCHARACTER) - continue; /* Only looking for CHARACTER arguments. */ - if (ffesymbol_kind (s) != FFEINFO_kindENTITY) - continue; /* Only looking for variables and arrays. */ - if (ffesymbol_hook (s).length_tree == NULL_TREE - || ffesymbol_hook (s).length_tree == error_mark_node) - actarg = ffecom_f2c_ftnlen_zero_node; /* We don't have this arg. */ - else - actarg = ffesymbol_hook (s).length_tree; - *plist = build_tree_list (NULL_TREE, actarg); - plist = &TREE_CHAIN (*plist); - } - - /* Prepend character-value return info to actual arg list. */ - - if (charfunc) - { - prepend = build_tree_list (NULL_TREE, ffecom_func_result_); - TREE_CHAIN (prepend) - = build_tree_list (NULL_TREE, ffecom_func_length_); - TREE_CHAIN (TREE_CHAIN (prepend)) = arglist; - arglist = prepend; - } - - /* Prepend multi-type return value to actual arg list. */ - - if (multi) - { - prepend - = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (multi_retval)), - multi_retval)); - TREE_CHAIN (prepend) = arglist; - arglist = prepend; - } - - /* Prepend my entry-point number to the actual arg list. */ - - prepend = build_tree_list (NULL_TREE, build_int_2 (entrynum, 0)); - TREE_CHAIN (prepend) = arglist; - arglist = prepend; - - /* Build the call to the master function. */ - - master_fn = ffecom_1_fn (ffecom_previous_function_decl_); - call = ffecom_3s (CALL_EXPR, - TREE_TYPE (TREE_TYPE (TREE_TYPE (master_fn))), - master_fn, arglist, NULL_TREE); - - /* Decide whether the master function is a function or subroutine, and - handle the return value for my entry point. */ - - if (charfunc || ((ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE) - && !altreturning)) - { - expand_expr_stmt (call); - expand_null_return (); - } - else if (multi && cmplxfunc) - { - expand_expr_stmt (call); - result - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (result))), - result); - result = ffecom_modify (NULL_TREE, result, - ffecom_2 (COMPONENT_REF, TREE_TYPE (result), - multi_retval, - ffecom_multi_fields_[bt][kt])); - expand_expr_stmt (result); - expand_null_return (); - } - else if (multi) - { - expand_expr_stmt (call); - result - = ffecom_modify (NULL_TREE, result, - convert (TREE_TYPE (result), - ffecom_2 (COMPONENT_REF, - ffecom_tree_type[bt][kt], - multi_retval, - ffecom_multi_fields_[bt][kt]))); - expand_return (result); - } - else if (cmplxfunc) - { - result - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (result))), - result); - result = ffecom_modify (NULL_TREE, result, call); - expand_expr_stmt (result); - expand_null_return (); - } - else - { - result = ffecom_modify (NULL_TREE, - result, - convert (TREE_TYPE (result), - call)); - expand_return (result); - } - } - - ffecom_end_compstmt (); - - finish_function (0); - - lineno = old_lineno; - input_filename = old_input_filename; - - ffecom_doing_entry_ = FALSE; -} - -/* Transform expr into gcc tree with possible destination - - Recursive descent on expr while making corresponding tree nodes and - attaching type info and such. If destination supplied and compatible - with temporary that would be made in certain cases, temporary isn't - made, destination used instead, and dest_used flag set TRUE. */ - -static tree -ffecom_expr_ (ffebld expr, tree dest_tree, ffebld dest, - bool *dest_used, bool assignp, bool widenp) -{ - tree item; - tree list; - tree args; - ffeinfoBasictype bt; - ffeinfoKindtype kt; - tree t; - tree dt; /* decl_tree for an ffesymbol. */ - tree tree_type, tree_type_x; - tree left, right; - ffesymbol s; - enum tree_code code; - - assert (expr != NULL); - - if (dest_used != NULL) - *dest_used = FALSE; - - bt = ffeinfo_basictype (ffebld_info (expr)); - kt = ffeinfo_kindtype (ffebld_info (expr)); - tree_type = ffecom_tree_type[bt][kt]; - - /* Widen integral arithmetic as desired while preserving signedness. */ - tree_type_x = NULL_TREE; - if (widenp && tree_type - && GET_MODE_CLASS (TYPE_MODE (tree_type)) == MODE_INT - && TYPE_PRECISION (tree_type) < TYPE_PRECISION (sizetype)) - tree_type_x = (TREE_UNSIGNED (tree_type) ? usizetype : ssizetype); - - switch (ffebld_op (expr)) - { - case FFEBLD_opACCTER: - { - ffebitCount i; - ffebit bits = ffebld_accter_bits (expr); - ffetargetOffset source_offset = 0; - ffetargetOffset dest_offset = ffebld_accter_pad (expr); - tree purpose; - - assert (dest_offset == 0 - || (bt == FFEINFO_basictypeCHARACTER - && kt == FFEINFO_kindtypeCHARACTER1)); - - list = item = NULL; - for (;;) - { - ffebldConstantUnion cu; - ffebitCount length; - bool value; - ffebldConstantArray ca = ffebld_accter (expr); - - ffebit_test (bits, source_offset, &value, &length); - if (length == 0) - break; - - if (value) - { - for (i = 0; i < length; ++i) - { - cu = ffebld_constantarray_get (ca, bt, kt, - source_offset + i); - - t = ffecom_constantunion (&cu, bt, kt, tree_type); - - if (i == 0 - && dest_offset != 0) - purpose = build_int_2 (dest_offset, 0); - else - purpose = NULL_TREE; - - if (list == NULL_TREE) - list = item = build_tree_list (purpose, t); - else - { - TREE_CHAIN (item) = build_tree_list (purpose, t); - item = TREE_CHAIN (item); - } - } - } - source_offset += length; - dest_offset += length; - } - } - - item = build_int_2 ((ffebld_accter_size (expr) - + ffebld_accter_pad (expr)) - 1, 0); - ffebit_kill (ffebld_accter_bits (expr)); - TREE_TYPE (item) = ffecom_integer_type_node; - item - = build_array_type - (tree_type, - build_range_type (ffecom_integer_type_node, - ffecom_integer_zero_node, - item)); - list = build (CONSTRUCTOR, item, NULL_TREE, list); - TREE_CONSTANT (list) = 1; - TREE_STATIC (list) = 1; - return list; - - case FFEBLD_opARRTER: - { - ffetargetOffset i; - - list = NULL_TREE; - if (ffebld_arrter_pad (expr) == 0) - item = NULL_TREE; - else - { - assert (bt == FFEINFO_basictypeCHARACTER - && kt == FFEINFO_kindtypeCHARACTER1); - - /* Becomes PURPOSE first time through loop. */ - item = build_int_2 (ffebld_arrter_pad (expr), 0); - } - - for (i = 0; i < ffebld_arrter_size (expr); ++i) - { - ffebldConstantUnion cu - = ffebld_constantarray_get (ffebld_arrter (expr), bt, kt, i); - - t = ffecom_constantunion (&cu, bt, kt, tree_type); - - if (list == NULL_TREE) - /* Assume item is PURPOSE first time through loop. */ - list = item = build_tree_list (item, t); - else - { - TREE_CHAIN (item) = build_tree_list (NULL_TREE, t); - item = TREE_CHAIN (item); - } - } - } - - item = build_int_2 ((ffebld_arrter_size (expr) - + ffebld_arrter_pad (expr)) - 1, 0); - TREE_TYPE (item) = ffecom_integer_type_node; - item - = build_array_type - (tree_type, - build_range_type (ffecom_integer_type_node, - ffecom_integer_zero_node, - item)); - list = build (CONSTRUCTOR, item, NULL_TREE, list); - TREE_CONSTANT (list) = 1; - TREE_STATIC (list) = 1; - return list; - - case FFEBLD_opCONTER: - assert (ffebld_conter_pad (expr) == 0); - item - = ffecom_constantunion (&ffebld_constant_union (ffebld_conter (expr)), - bt, kt, tree_type); - return item; - - case FFEBLD_opSYMTER: - if ((ffebld_symter_generic (expr) != FFEINTRIN_genNONE) - || (ffebld_symter_specific (expr) != FFEINTRIN_specNONE)) - return ffecom_ptr_to_expr (expr); /* Same as %REF(intrinsic). */ - s = ffebld_symter (expr); - t = ffesymbol_hook (s).decl_tree; - - if (assignp) - { /* ASSIGN'ed-label expr. */ - if (ffe_is_ugly_assign ()) - { - /* User explicitly wants ASSIGN'ed variables to be at the same - memory address as the variables when used in non-ASSIGN - contexts. That can make old, arcane, non-standard code - work, but don't try to do it when a pointer wouldn't fit - in the normal variable (take other approach, and warn, - instead). */ - - if (t == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - t = ffesymbol_hook (s).decl_tree; - assert (t != NULL_TREE); - } - - if (t == error_mark_node) - return t; - - if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t))) - >= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node)))) - { - if (ffesymbol_hook (s).addr) - t = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t))), t); - return t; - } - - if (ffesymbol_hook (s).assign_tree == NULL_TREE) - { - /* xgettext:no-c-format */ - ffebad_start_msg ("ASSIGN'ed label cannot fit into `%A' at %0 -- using wider sibling", - FFEBAD_severityWARNING); - ffebad_string (ffesymbol_text (s)); - ffebad_here (0, ffesymbol_where_line (s), - ffesymbol_where_column (s)); - ffebad_finish (); - } - } - - /* Don't use the normal variable's tree for ASSIGN, though mark - it as in the system header (housekeeping). Use an explicit, - specially created sibling that is known to be wide enough - to hold pointers to labels. */ - - if (t != NULL_TREE - && TREE_CODE (t) == VAR_DECL) - DECL_IN_SYSTEM_HEADER (t) = 1; /* Don't let -Wunused complain. */ - - t = ffesymbol_hook (s).assign_tree; - if (t == NULL_TREE) - { - s = ffecom_sym_transform_assign_ (s); - t = ffesymbol_hook (s).assign_tree; - assert (t != NULL_TREE); - } - } - else - { - if (t == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - t = ffesymbol_hook (s).decl_tree; - assert (t != NULL_TREE); - } - if (ffesymbol_hook (s).addr) - t = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t))), t); - } - return t; - - case FFEBLD_opARRAYREF: - return ffecom_arrayref_ (NULL_TREE, expr, 0); - - case FFEBLD_opUPLUS: - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - return ffecom_1 (NOP_EXPR, tree_type, left); - - case FFEBLD_opPAREN: - /* ~~~Make sure Fortran rules respected here */ - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - return ffecom_1 (NOP_EXPR, tree_type, left); - - case FFEBLD_opUMINUS: - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - if (tree_type_x) - { - tree_type = tree_type_x; - left = convert (tree_type, left); - } - return ffecom_1 (NEGATE_EXPR, tree_type, left); - - case FFEBLD_opADD: - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp); - if (tree_type_x) - { - tree_type = tree_type_x; - left = convert (tree_type, left); - right = convert (tree_type, right); - } - return ffecom_2 (PLUS_EXPR, tree_type, left, right); - - case FFEBLD_opSUBTRACT: - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp); - if (tree_type_x) - { - tree_type = tree_type_x; - left = convert (tree_type, left); - right = convert (tree_type, right); - } - return ffecom_2 (MINUS_EXPR, tree_type, left, right); - - case FFEBLD_opMULTIPLY: - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp); - if (tree_type_x) - { - tree_type = tree_type_x; - left = convert (tree_type, left); - right = convert (tree_type, right); - } - return ffecom_2 (MULT_EXPR, tree_type, left, right); - - case FFEBLD_opDIVIDE: - left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp); - right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp); - if (tree_type_x) - { - tree_type = tree_type_x; - left = convert (tree_type, left); - right = convert (tree_type, right); - } - return ffecom_tree_divide_ (tree_type, left, right, - dest_tree, dest, dest_used, - ffebld_nonter_hook (expr)); - - case FFEBLD_opPOWER: - { - ffebld left = ffebld_left (expr); - ffebld right = ffebld_right (expr); - ffecomGfrt code; - ffeinfoKindtype rtkt; - ffeinfoKindtype ltkt; - bool ref = TRUE; - - switch (ffeinfo_basictype (ffebld_info (right))) - { - - case FFEINFO_basictypeINTEGER: - if (1 || optimize) - { - item = ffecom_expr_power_integer_ (expr); - if (item != NULL_TREE) - return item; - } - - rtkt = FFEINFO_kindtypeINTEGER1; - switch (ffeinfo_basictype (ffebld_info (left))) - { - case FFEINFO_basictypeINTEGER: - if ((ffeinfo_kindtype (ffebld_info (left)) - == FFEINFO_kindtypeINTEGER4) - || (ffeinfo_kindtype (ffebld_info (right)) - == FFEINFO_kindtypeINTEGER4)) - { - code = FFECOM_gfrtPOW_QQ; - ltkt = FFEINFO_kindtypeINTEGER4; - rtkt = FFEINFO_kindtypeINTEGER4; - } - else - { - code = FFECOM_gfrtPOW_II; - ltkt = FFEINFO_kindtypeINTEGER1; - } - break; - - case FFEINFO_basictypeREAL: - if (ffeinfo_kindtype (ffebld_info (left)) - == FFEINFO_kindtypeREAL1) - { - code = FFECOM_gfrtPOW_RI; - ltkt = FFEINFO_kindtypeREAL1; - } - else - { - code = FFECOM_gfrtPOW_DI; - ltkt = FFEINFO_kindtypeREAL2; - } - break; - - case FFEINFO_basictypeCOMPLEX: - if (ffeinfo_kindtype (ffebld_info (left)) - == FFEINFO_kindtypeREAL1) - { - code = FFECOM_gfrtPOW_CI; /* Overlapping result okay. */ - ltkt = FFEINFO_kindtypeREAL1; - } - else - { - code = FFECOM_gfrtPOW_ZI; /* Overlapping result okay. */ - ltkt = FFEINFO_kindtypeREAL2; - } - break; - - default: - assert ("bad pow_*i" == NULL); - code = FFECOM_gfrtPOW_CI; /* Overlapping result okay. */ - ltkt = FFEINFO_kindtypeREAL1; - break; - } - if (ffeinfo_kindtype (ffebld_info (left)) != ltkt) - left = ffeexpr_convert (left, NULL, NULL, - ffeinfo_basictype (ffebld_info (left)), - ltkt, 0, - FFETARGET_charactersizeNONE, - FFEEXPR_contextLET); - if (ffeinfo_kindtype (ffebld_info (right)) != rtkt) - right = ffeexpr_convert (right, NULL, NULL, - FFEINFO_basictypeINTEGER, - rtkt, 0, - FFETARGET_charactersizeNONE, - FFEEXPR_contextLET); - break; - - case FFEINFO_basictypeREAL: - if (ffeinfo_kindtype (ffebld_info (left)) == FFEINFO_kindtypeREAL1) - left = ffeexpr_convert (left, NULL, NULL, FFEINFO_basictypeREAL, - FFEINFO_kindtypeREALDOUBLE, 0, - FFETARGET_charactersizeNONE, - FFEEXPR_contextLET); - if (ffeinfo_kindtype (ffebld_info (right)) - == FFEINFO_kindtypeREAL1) - right = ffeexpr_convert (right, NULL, NULL, - FFEINFO_basictypeREAL, - FFEINFO_kindtypeREALDOUBLE, 0, - FFETARGET_charactersizeNONE, - FFEEXPR_contextLET); - /* We used to call FFECOM_gfrtPOW_DD here, - which passes arguments by reference. */ - code = FFECOM_gfrtL_POW; - /* Pass arguments by value. */ - ref = FALSE; - break; - - case FFEINFO_basictypeCOMPLEX: - if (ffeinfo_kindtype (ffebld_info (left)) == FFEINFO_kindtypeREAL1) - left = ffeexpr_convert (left, NULL, NULL, - FFEINFO_basictypeCOMPLEX, - FFEINFO_kindtypeREALDOUBLE, 0, - FFETARGET_charactersizeNONE, - FFEEXPR_contextLET); - if (ffeinfo_kindtype (ffebld_info (right)) - == FFEINFO_kindtypeREAL1) - right = ffeexpr_convert (right, NULL, NULL, - FFEINFO_basictypeCOMPLEX, - FFEINFO_kindtypeREALDOUBLE, 0, - FFETARGET_charactersizeNONE, - FFEEXPR_contextLET); - code = FFECOM_gfrtPOW_ZZ; /* Overlapping result okay. */ - ref = TRUE; /* Pass arguments by reference. */ - break; - - default: - assert ("bad pow_x*" == NULL); - code = FFECOM_gfrtPOW_II; - break; - } - return ffecom_call_binop_ (ffecom_gfrt_tree_ (code), - ffecom_gfrt_kindtype (code), - (ffe_is_f2c_library () - && ffecom_gfrt_complex_[code]), - tree_type, left, right, - dest_tree, dest, dest_used, - NULL_TREE, FALSE, ref, - ffebld_nonter_hook (expr)); - } - - case FFEBLD_opNOT: - switch (bt) - { - case FFEINFO_basictypeLOGICAL: - item = ffecom_truth_value_invert (ffecom_expr (ffebld_left (expr))); - return convert (tree_type, item); - - case FFEINFO_basictypeINTEGER: - return ffecom_1 (BIT_NOT_EXPR, tree_type, - ffecom_expr (ffebld_left (expr))); - - default: - assert ("NOT bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opFUNCREF: - assert (ffeinfo_basictype (ffebld_info (expr)) - != FFEINFO_basictypeCHARACTER); - /* Fall through. */ - case FFEBLD_opSUBRREF: - if (ffeinfo_where (ffebld_info (ffebld_left (expr))) - == FFEINFO_whereINTRINSIC) - { /* Invocation of an intrinsic. */ - item = ffecom_expr_intrinsic_ (expr, dest_tree, dest, - dest_used); - return item; - } - s = ffebld_symter (ffebld_left (expr)); - dt = ffesymbol_hook (s).decl_tree; - if (dt == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - dt = ffesymbol_hook (s).decl_tree; - } - if (dt == error_mark_node) - return dt; - - if (ffesymbol_hook (s).addr) - item = dt; - else - item = ffecom_1_fn (dt); - - if (ffesymbol_where (s) == FFEINFO_whereCONSTANT) - args = ffecom_list_expr (ffebld_right (expr)); - else - args = ffecom_list_ptr_to_expr (ffebld_right (expr)); - - if (args == error_mark_node) - return error_mark_node; - - item = ffecom_call_ (item, kt, - ffesymbol_is_f2c (s) - && (bt == FFEINFO_basictypeCOMPLEX) - && (ffesymbol_where (s) - != FFEINFO_whereCONSTANT), - tree_type, - args, - dest_tree, dest, dest_used, - error_mark_node, FALSE, - ffebld_nonter_hook (expr)); - TREE_SIDE_EFFECTS (item) = 1; - return item; - - case FFEBLD_opAND: - switch (bt) - { - case FFEINFO_basictypeLOGICAL: - item - = ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node, - ffecom_truth_value (ffecom_expr (ffebld_left (expr))), - ffecom_truth_value (ffecom_expr (ffebld_right (expr)))); - return convert (tree_type, item); - - case FFEINFO_basictypeINTEGER: - return ffecom_2 (BIT_AND_EXPR, tree_type, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr))); - - default: - assert ("AND bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opOR: - switch (bt) - { - case FFEINFO_basictypeLOGICAL: - item - = ffecom_2 (TRUTH_ORIF_EXPR, integer_type_node, - ffecom_truth_value (ffecom_expr (ffebld_left (expr))), - ffecom_truth_value (ffecom_expr (ffebld_right (expr)))); - return convert (tree_type, item); - - case FFEINFO_basictypeINTEGER: - return ffecom_2 (BIT_IOR_EXPR, tree_type, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr))); - - default: - assert ("OR bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opXOR: - case FFEBLD_opNEQV: - switch (bt) - { - case FFEINFO_basictypeLOGICAL: - item - = ffecom_2 (NE_EXPR, integer_type_node, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr))); - return convert (tree_type, ffecom_truth_value (item)); - - case FFEINFO_basictypeINTEGER: - return ffecom_2 (BIT_XOR_EXPR, tree_type, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr))); - - default: - assert ("XOR/NEQV bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opEQV: - switch (bt) - { - case FFEINFO_basictypeLOGICAL: - item - = ffecom_2 (EQ_EXPR, integer_type_node, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr))); - return convert (tree_type, ffecom_truth_value (item)); - - case FFEINFO_basictypeINTEGER: - return - ffecom_1 (BIT_NOT_EXPR, tree_type, - ffecom_2 (BIT_XOR_EXPR, tree_type, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr)))); - - default: - assert ("EQV bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opCONVERT: - if (ffebld_op (ffebld_left (expr)) == FFEBLD_opANY) - return error_mark_node; - - switch (bt) - { - case FFEINFO_basictypeLOGICAL: - case FFEINFO_basictypeINTEGER: - case FFEINFO_basictypeREAL: - return convert (tree_type, ffecom_expr (ffebld_left (expr))); - - case FFEINFO_basictypeCOMPLEX: - switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr)))) - { - case FFEINFO_basictypeINTEGER: - case FFEINFO_basictypeLOGICAL: - case FFEINFO_basictypeREAL: - item = ffecom_expr (ffebld_left (expr)); - if (item == error_mark_node) - return error_mark_node; - /* convert() takes care of converting to the subtype first, - at least in gcc-2.7.2. */ - item = convert (tree_type, item); - return item; - - case FFEINFO_basictypeCOMPLEX: - return convert (tree_type, ffecom_expr (ffebld_left (expr))); - - default: - assert ("CONVERT COMPLEX bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - default: - assert ("CONVERT bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opLT: - code = LT_EXPR; - goto relational; /* :::::::::::::::::::: */ - - case FFEBLD_opLE: - code = LE_EXPR; - goto relational; /* :::::::::::::::::::: */ - - case FFEBLD_opEQ: - code = EQ_EXPR; - goto relational; /* :::::::::::::::::::: */ - - case FFEBLD_opNE: - code = NE_EXPR; - goto relational; /* :::::::::::::::::::: */ - - case FFEBLD_opGT: - code = GT_EXPR; - goto relational; /* :::::::::::::::::::: */ - - case FFEBLD_opGE: - code = GE_EXPR; - - relational: /* :::::::::::::::::::: */ - switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr)))) - { - case FFEINFO_basictypeLOGICAL: - case FFEINFO_basictypeINTEGER: - case FFEINFO_basictypeREAL: - item = ffecom_2 (code, integer_type_node, - ffecom_expr (ffebld_left (expr)), - ffecom_expr (ffebld_right (expr))); - return convert (tree_type, item); - - case FFEINFO_basictypeCOMPLEX: - assert (code == EQ_EXPR || code == NE_EXPR); - { - tree real_type; - tree arg1 = ffecom_expr (ffebld_left (expr)); - tree arg2 = ffecom_expr (ffebld_right (expr)); - - if (arg1 == error_mark_node || arg2 == error_mark_node) - return error_mark_node; - - arg1 = ffecom_save_tree (arg1); - arg2 = ffecom_save_tree (arg2); - - if (TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE) - { - real_type = TREE_TYPE (TREE_TYPE (arg1)); - assert (real_type == TREE_TYPE (TREE_TYPE (arg2))); - } - else - { - real_type = TREE_TYPE (TYPE_FIELDS (TREE_TYPE (arg1))); - assert (real_type == TREE_TYPE (TYPE_FIELDS (TREE_TYPE (arg2)))); - } - - item - = ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node, - ffecom_2 (EQ_EXPR, integer_type_node, - ffecom_1 (REALPART_EXPR, real_type, arg1), - ffecom_1 (REALPART_EXPR, real_type, arg2)), - ffecom_2 (EQ_EXPR, integer_type_node, - ffecom_1 (IMAGPART_EXPR, real_type, arg1), - ffecom_1 (IMAGPART_EXPR, real_type, - arg2))); - if (code == EQ_EXPR) - item = ffecom_truth_value (item); - else - item = ffecom_truth_value_invert (item); - return convert (tree_type, item); - } - - case FFEINFO_basictypeCHARACTER: - { - ffebld left = ffebld_left (expr); - ffebld right = ffebld_right (expr); - tree left_tree; - tree right_tree; - tree left_length; - tree right_length; - - /* f2c run-time functions do the implicit blank-padding for us, - so we don't usually have to implement blank-padding ourselves. - (The exception is when we pass an argument to a separately - compiled statement function -- if we know the arg is not the - same length as the dummy, we must truncate or extend it. If - we "inline" statement functions, that necessity goes away as - well.) - - Strip off the CONVERT operators that blank-pad. (Truncation by - CONVERT shouldn't happen here, but it can happen in - assignments.) */ - - while (ffebld_op (left) == FFEBLD_opCONVERT) - left = ffebld_left (left); - while (ffebld_op (right) == FFEBLD_opCONVERT) - right = ffebld_left (right); - - left_tree = ffecom_arg_ptr_to_expr (left, &left_length); - right_tree = ffecom_arg_ptr_to_expr (right, &right_length); - - if (left_tree == error_mark_node || left_length == error_mark_node - || right_tree == error_mark_node - || right_length == error_mark_node) - return error_mark_node; - - if ((ffebld_size_known (left) == 1) - && (ffebld_size_known (right) == 1)) - { - left_tree - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (left_tree))), - left_tree); - right_tree - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (right_tree))), - right_tree); - - item - = ffecom_2 (code, integer_type_node, - ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (left_tree))), - left_tree, - integer_one_node), - ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (right_tree))), - right_tree, - integer_one_node)); - } - else - { - item = build_tree_list (NULL_TREE, left_tree); - TREE_CHAIN (item) = build_tree_list (NULL_TREE, right_tree); - TREE_CHAIN (TREE_CHAIN (item)) = build_tree_list (NULL_TREE, - left_length); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (item))) - = build_tree_list (NULL_TREE, right_length); - item = ffecom_call_gfrt (FFECOM_gfrtCMP, item, NULL_TREE); - item = ffecom_2 (code, integer_type_node, - item, - convert (TREE_TYPE (item), - integer_zero_node)); - } - item = convert (tree_type, item); - } - - return item; - - default: - assert ("relational bad basictype" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - break; - - case FFEBLD_opPERCENT_LOC: - item = ffecom_arg_ptr_to_expr (ffebld_left (expr), &list); - return convert (tree_type, item); - - case FFEBLD_opPERCENT_VAL: - item = ffecom_arg_expr (ffebld_left (expr), &list); - return convert (tree_type, item); - - case FFEBLD_opITEM: - case FFEBLD_opSTAR: - case FFEBLD_opBOUNDS: - case FFEBLD_opREPEAT: - case FFEBLD_opLABTER: - case FFEBLD_opLABTOK: - case FFEBLD_opIMPDO: - case FFEBLD_opCONCATENATE: - case FFEBLD_opSUBSTR: - default: - assert ("bad op" == NULL); - /* Fall through. */ - case FFEBLD_opANY: - return error_mark_node; - } - -#if 1 - assert ("didn't think anything got here anymore!!" == NULL); -#else - switch (ffebld_arity (expr)) - { - case 2: - TREE_OPERAND (item, 0) = ffecom_expr (ffebld_left (expr)); - TREE_OPERAND (item, 1) = ffecom_expr (ffebld_right (expr)); - if (TREE_OPERAND (item, 0) == error_mark_node - || TREE_OPERAND (item, 1) == error_mark_node) - return error_mark_node; - break; - - case 1: - TREE_OPERAND (item, 0) = ffecom_expr (ffebld_left (expr)); - if (TREE_OPERAND (item, 0) == error_mark_node) - return error_mark_node; - break; - - default: - break; - } - - return fold (item); -#endif -} - -/* Returns the tree that does the intrinsic invocation. - - Note: this function applies only to intrinsics returning - CHARACTER*1 or non-CHARACTER results, and to intrinsic - subroutines. */ - -static tree -ffecom_expr_intrinsic_ (ffebld expr, tree dest_tree, - ffebld dest, bool *dest_used) -{ - tree expr_tree; - tree saved_expr1; /* For those who need it. */ - tree saved_expr2; /* For those who need it. */ - ffeinfoBasictype bt; - ffeinfoKindtype kt; - tree tree_type; - tree arg1_type; - tree real_type; /* REAL type corresponding to COMPLEX. */ - tree tempvar; - ffebld list = ffebld_right (expr); /* List of (some) args. */ - ffebld arg1; /* For handy reference. */ - ffebld arg2; - ffebld arg3; - ffeintrinImp codegen_imp; - ffecomGfrt gfrt; - - assert (ffebld_op (ffebld_left (expr)) == FFEBLD_opSYMTER); - - if (dest_used != NULL) - *dest_used = FALSE; - - bt = ffeinfo_basictype (ffebld_info (expr)); - kt = ffeinfo_kindtype (ffebld_info (expr)); - tree_type = ffecom_tree_type[bt][kt]; - - if (list != NULL) - { - arg1 = ffebld_head (list); - if (arg1 != NULL && ffebld_op (arg1) == FFEBLD_opANY) - return error_mark_node; - if ((list = ffebld_trail (list)) != NULL) - { - arg2 = ffebld_head (list); - if (arg2 != NULL && ffebld_op (arg2) == FFEBLD_opANY) - return error_mark_node; - if ((list = ffebld_trail (list)) != NULL) - { - arg3 = ffebld_head (list); - if (arg3 != NULL && ffebld_op (arg3) == FFEBLD_opANY) - return error_mark_node; - } - else - arg3 = NULL; - } - else - arg2 = arg3 = NULL; - } - else - arg1 = arg2 = arg3 = NULL; - - /* ends up at the opITEM of the 3rd arg, or NULL if there are < 3 - args. This is used by the MAX/MIN expansions. */ - - if (arg1 != NULL) - arg1_type = ffecom_tree_type - [ffeinfo_basictype (ffebld_info (arg1))] - [ffeinfo_kindtype (ffebld_info (arg1))]; - else - arg1_type = NULL_TREE; /* Really not needed, but might catch bugs - here. */ - - /* There are several ways for each of the cases in the following switch - statements to exit (from simplest to use to most complicated): - - break; (when expr_tree == NULL) - - A standard call is made to the specific intrinsic just as if it had been - passed in as a dummy procedure and called as any old procedure. This - method can produce slower code but in some cases it's the easiest way for - now. However, if a (presumably faster) direct call is available, - that is used, so this is the easiest way in many more cases now. - - gfrt = FFECOM_gfrtWHATEVER; - break; - - gfrt contains the gfrt index of a library function to call, passing the - argument(s) by value rather than by reference. Used when a more - careful choice of library function is needed than that provided - by the vanilla `break;'. - - return expr_tree; - - The expr_tree has been completely set up and is ready to be returned - as is. No further actions are taken. Use this when the tree is not - in the simple form for one of the arity_n labels. */ - - /* For info on how the switch statement cases were written, see the files - enclosed in comments below the switch statement. */ - - codegen_imp = ffebld_symter_implementation (ffebld_left (expr)); - gfrt = ffeintrin_gfrt_direct (codegen_imp); - if (gfrt == FFECOM_gfrt) - gfrt = ffeintrin_gfrt_indirect (codegen_imp); - - switch (codegen_imp) - { - case FFEINTRIN_impABS: - case FFEINTRIN_impCABS: - case FFEINTRIN_impCDABS: - case FFEINTRIN_impDABS: - case FFEINTRIN_impIABS: - if (ffeinfo_basictype (ffebld_info (arg1)) - == FFEINFO_basictypeCOMPLEX) - { - if (kt == FFEINFO_kindtypeREAL1) - gfrt = FFECOM_gfrtCABS; - else if (kt == FFEINFO_kindtypeREAL2) - gfrt = FFECOM_gfrtCDABS; - break; - } - return ffecom_1 (ABS_EXPR, tree_type, - convert (tree_type, ffecom_expr (arg1))); - - case FFEINTRIN_impACOS: - case FFEINTRIN_impDACOS: - break; - - case FFEINTRIN_impAIMAG: - case FFEINTRIN_impDIMAG: - case FFEINTRIN_impIMAGPART: - if (TREE_CODE (arg1_type) == COMPLEX_TYPE) - arg1_type = TREE_TYPE (arg1_type); - else - arg1_type = TREE_TYPE (TYPE_FIELDS (arg1_type)); - - return - convert (tree_type, - ffecom_1 (IMAGPART_EXPR, arg1_type, - ffecom_expr (arg1))); - - case FFEINTRIN_impAINT: - case FFEINTRIN_impDINT: -#if 0 - /* ~~Someday implement FIX_TRUNC_EXPR yielding same type as arg. */ - return ffecom_1 (FIX_TRUNC_EXPR, tree_type, ffecom_expr (arg1)); -#else /* in the meantime, must use floor to avoid range problems with ints */ - /* r__1 = r1 >= 0 ? floor(r1) : -floor(-r1); */ - saved_expr1 = ffecom_save_tree (ffecom_expr (arg1)); - return - convert (tree_type, - ffecom_3 (COND_EXPR, double_type_node, - ffecom_truth_value - (ffecom_2 (GE_EXPR, integer_type_node, - saved_expr1, - convert (arg1_type, - ffecom_float_zero_))), - ffecom_call_gfrt (FFECOM_gfrtL_FLOOR, - build_tree_list (NULL_TREE, - convert (double_type_node, - saved_expr1)), - NULL_TREE), - ffecom_1 (NEGATE_EXPR, double_type_node, - ffecom_call_gfrt (FFECOM_gfrtL_FLOOR, - build_tree_list (NULL_TREE, - convert (double_type_node, - ffecom_1 (NEGATE_EXPR, - arg1_type, - saved_expr1))), - NULL_TREE) - )) - ); -#endif - - case FFEINTRIN_impANINT: - case FFEINTRIN_impDNINT: -#if 0 /* This way of doing it won't handle real - numbers of large magnitudes. */ - saved_expr1 = ffecom_save_tree (ffecom_expr (arg1)); - expr_tree = convert (tree_type, - convert (integer_type_node, - ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (GE_EXPR, - integer_type_node, - saved_expr1, - ffecom_float_zero_)), - ffecom_2 (PLUS_EXPR, - tree_type, - saved_expr1, - ffecom_float_half_), - ffecom_2 (MINUS_EXPR, - tree_type, - saved_expr1, - ffecom_float_half_)))); - return expr_tree; -#else /* So we instead call floor. */ - /* r__1 = r1 >= 0 ? floor(r1 + .5) : -floor(.5 - r1) */ - saved_expr1 = ffecom_save_tree (ffecom_expr (arg1)); - return - convert (tree_type, - ffecom_3 (COND_EXPR, double_type_node, - ffecom_truth_value - (ffecom_2 (GE_EXPR, integer_type_node, - saved_expr1, - convert (arg1_type, - ffecom_float_zero_))), - ffecom_call_gfrt (FFECOM_gfrtL_FLOOR, - build_tree_list (NULL_TREE, - convert (double_type_node, - ffecom_2 (PLUS_EXPR, - arg1_type, - saved_expr1, - convert (arg1_type, - ffecom_float_half_)))), - NULL_TREE), - ffecom_1 (NEGATE_EXPR, double_type_node, - ffecom_call_gfrt (FFECOM_gfrtL_FLOOR, - build_tree_list (NULL_TREE, - convert (double_type_node, - ffecom_2 (MINUS_EXPR, - arg1_type, - convert (arg1_type, - ffecom_float_half_), - saved_expr1))), - NULL_TREE)) - ) - ); -#endif - - case FFEINTRIN_impASIN: - case FFEINTRIN_impDASIN: - case FFEINTRIN_impATAN: - case FFEINTRIN_impDATAN: - case FFEINTRIN_impATAN2: - case FFEINTRIN_impDATAN2: - break; - - case FFEINTRIN_impCHAR: - case FFEINTRIN_impACHAR: -#ifdef HOHO - tempvar = ffecom_make_tempvar (char_type_node, 1, -1); -#else - tempvar = ffebld_nonter_hook (expr); - assert (tempvar); -#endif - { - tree tmv = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (tempvar))); - - expr_tree = ffecom_modify (tmv, - ffecom_2 (ARRAY_REF, tmv, tempvar, - integer_one_node), - convert (tmv, ffecom_expr (arg1))); - } - expr_tree = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), - expr_tree, - tempvar); - expr_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (expr_tree)), - expr_tree); - return expr_tree; - - case FFEINTRIN_impCMPLX: - case FFEINTRIN_impDCMPLX: - if (arg2 == NULL) - return - convert (tree_type, ffecom_expr (arg1)); - - real_type = ffecom_tree_type[FFEINFO_basictypeREAL][kt]; - return - ffecom_2 (COMPLEX_EXPR, tree_type, - convert (real_type, ffecom_expr (arg1)), - convert (real_type, - ffecom_expr (arg2))); - - case FFEINTRIN_impCOMPLEX: - return - ffecom_2 (COMPLEX_EXPR, tree_type, - ffecom_expr (arg1), - ffecom_expr (arg2)); - - case FFEINTRIN_impCONJG: - case FFEINTRIN_impDCONJG: - { - tree arg1_tree; - - real_type = ffecom_tree_type[FFEINFO_basictypeREAL][kt]; - arg1_tree = ffecom_save_tree (ffecom_expr (arg1)); - return - ffecom_2 (COMPLEX_EXPR, tree_type, - ffecom_1 (REALPART_EXPR, real_type, arg1_tree), - ffecom_1 (NEGATE_EXPR, real_type, - ffecom_1 (IMAGPART_EXPR, real_type, arg1_tree))); - } - - case FFEINTRIN_impCOS: - case FFEINTRIN_impCCOS: - case FFEINTRIN_impCDCOS: - case FFEINTRIN_impDCOS: - if (bt == FFEINFO_basictypeCOMPLEX) - { - if (kt == FFEINFO_kindtypeREAL1) - gfrt = FFECOM_gfrtCCOS; /* Overlapping result okay. */ - else if (kt == FFEINFO_kindtypeREAL2) - gfrt = FFECOM_gfrtCDCOS; /* Overlapping result okay. */ - } - break; - - case FFEINTRIN_impCOSH: - case FFEINTRIN_impDCOSH: - break; - - case FFEINTRIN_impDBLE: - case FFEINTRIN_impDFLOAT: - case FFEINTRIN_impDREAL: - case FFEINTRIN_impFLOAT: - case FFEINTRIN_impIDINT: - case FFEINTRIN_impIFIX: - case FFEINTRIN_impINT2: - case FFEINTRIN_impINT8: - case FFEINTRIN_impINT: - case FFEINTRIN_impLONG: - case FFEINTRIN_impREAL: - case FFEINTRIN_impSHORT: - case FFEINTRIN_impSNGL: - return convert (tree_type, ffecom_expr (arg1)); - - case FFEINTRIN_impDIM: - case FFEINTRIN_impDDIM: - case FFEINTRIN_impIDIM: - saved_expr1 = ffecom_save_tree (convert (tree_type, - ffecom_expr (arg1))); - saved_expr2 = ffecom_save_tree (convert (tree_type, - ffecom_expr (arg2))); - return - ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (GT_EXPR, integer_type_node, - saved_expr1, - saved_expr2)), - ffecom_2 (MINUS_EXPR, tree_type, - saved_expr1, - saved_expr2), - convert (tree_type, ffecom_float_zero_)); - - case FFEINTRIN_impDPROD: - return - ffecom_2 (MULT_EXPR, tree_type, - convert (tree_type, ffecom_expr (arg1)), - convert (tree_type, ffecom_expr (arg2))); - - case FFEINTRIN_impEXP: - case FFEINTRIN_impCDEXP: - case FFEINTRIN_impCEXP: - case FFEINTRIN_impDEXP: - if (bt == FFEINFO_basictypeCOMPLEX) - { - if (kt == FFEINFO_kindtypeREAL1) - gfrt = FFECOM_gfrtCEXP; /* Overlapping result okay. */ - else if (kt == FFEINFO_kindtypeREAL2) - gfrt = FFECOM_gfrtCDEXP; /* Overlapping result okay. */ - } - break; - - case FFEINTRIN_impICHAR: - case FFEINTRIN_impIACHAR: -#if 0 /* The simple approach. */ - ffecom_char_args_ (&expr_tree, &saved_expr1 /* Ignored */ , arg1); - expr_tree - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))), - expr_tree); - expr_tree - = ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))), - expr_tree, - integer_one_node); - return convert (tree_type, expr_tree); -#else /* The more interesting (and more optimal) approach. */ - expr_tree = ffecom_intrinsic_ichar_ (tree_type, arg1, &saved_expr1); - expr_tree = ffecom_3 (COND_EXPR, tree_type, - saved_expr1, - expr_tree, - convert (tree_type, integer_zero_node)); - return expr_tree; -#endif - - case FFEINTRIN_impINDEX: - break; - - case FFEINTRIN_impLEN: -#if 0 - break; /* The simple approach. */ -#else - return ffecom_intrinsic_len_ (arg1); /* The more optimal approach. */ -#endif - - case FFEINTRIN_impLGE: - case FFEINTRIN_impLGT: - case FFEINTRIN_impLLE: - case FFEINTRIN_impLLT: - break; - - case FFEINTRIN_impLOG: - case FFEINTRIN_impALOG: - case FFEINTRIN_impCDLOG: - case FFEINTRIN_impCLOG: - case FFEINTRIN_impDLOG: - if (bt == FFEINFO_basictypeCOMPLEX) - { - if (kt == FFEINFO_kindtypeREAL1) - gfrt = FFECOM_gfrtCLOG; /* Overlapping result okay. */ - else if (kt == FFEINFO_kindtypeREAL2) - gfrt = FFECOM_gfrtCDLOG; /* Overlapping result okay. */ - } - break; - - case FFEINTRIN_impLOG10: - case FFEINTRIN_impALOG10: - case FFEINTRIN_impDLOG10: - if (gfrt != FFECOM_gfrt) - break; /* Already picked one, stick with it. */ - - if (kt == FFEINFO_kindtypeREAL1) - /* We used to call FFECOM_gfrtALOG10 here. */ - gfrt = FFECOM_gfrtL_LOG10; - else if (kt == FFEINFO_kindtypeREAL2) - /* We used to call FFECOM_gfrtDLOG10 here. */ - gfrt = FFECOM_gfrtL_LOG10; - break; - - case FFEINTRIN_impMAX: - case FFEINTRIN_impAMAX0: - case FFEINTRIN_impAMAX1: - case FFEINTRIN_impDMAX1: - case FFEINTRIN_impMAX0: - case FFEINTRIN_impMAX1: - if (bt != ffeinfo_basictype (ffebld_info (arg1))) - arg1_type = ffecom_widest_expr_type_ (ffebld_right (expr)); - else - arg1_type = tree_type; - expr_tree = ffecom_2 (MAX_EXPR, arg1_type, - convert (arg1_type, ffecom_expr (arg1)), - convert (arg1_type, ffecom_expr (arg2))); - for (; list != NULL; list = ffebld_trail (list)) - { - if ((ffebld_head (list) == NULL) - || (ffebld_op (ffebld_head (list)) == FFEBLD_opANY)) - continue; - expr_tree = ffecom_2 (MAX_EXPR, arg1_type, - expr_tree, - convert (arg1_type, - ffecom_expr (ffebld_head (list)))); - } - return convert (tree_type, expr_tree); - - case FFEINTRIN_impMIN: - case FFEINTRIN_impAMIN0: - case FFEINTRIN_impAMIN1: - case FFEINTRIN_impDMIN1: - case FFEINTRIN_impMIN0: - case FFEINTRIN_impMIN1: - if (bt != ffeinfo_basictype (ffebld_info (arg1))) - arg1_type = ffecom_widest_expr_type_ (ffebld_right (expr)); - else - arg1_type = tree_type; - expr_tree = ffecom_2 (MIN_EXPR, arg1_type, - convert (arg1_type, ffecom_expr (arg1)), - convert (arg1_type, ffecom_expr (arg2))); - for (; list != NULL; list = ffebld_trail (list)) - { - if ((ffebld_head (list) == NULL) - || (ffebld_op (ffebld_head (list)) == FFEBLD_opANY)) - continue; - expr_tree = ffecom_2 (MIN_EXPR, arg1_type, - expr_tree, - convert (arg1_type, - ffecom_expr (ffebld_head (list)))); - } - return convert (tree_type, expr_tree); - - case FFEINTRIN_impMOD: - case FFEINTRIN_impAMOD: - case FFEINTRIN_impDMOD: - if (bt != FFEINFO_basictypeREAL) - return ffecom_2 (TRUNC_MOD_EXPR, tree_type, - convert (tree_type, ffecom_expr (arg1)), - convert (tree_type, ffecom_expr (arg2))); - - if (kt == FFEINFO_kindtypeREAL1) - /* We used to call FFECOM_gfrtAMOD here. */ - gfrt = FFECOM_gfrtL_FMOD; - else if (kt == FFEINFO_kindtypeREAL2) - /* We used to call FFECOM_gfrtDMOD here. */ - gfrt = FFECOM_gfrtL_FMOD; - break; - - case FFEINTRIN_impNINT: - case FFEINTRIN_impIDNINT: -#if 0 - /* ~~Ideally FIX_ROUND_EXPR would be implemented, but it ain't yet. */ - return ffecom_1 (FIX_ROUND_EXPR, tree_type, ffecom_expr (arg1)); -#else - /* i__1 = r1 >= 0 ? floor(r1 + .5) : -floor(.5 - r1); */ - saved_expr1 = ffecom_save_tree (ffecom_expr (arg1)); - return - convert (ffecom_integer_type_node, - ffecom_3 (COND_EXPR, arg1_type, - ffecom_truth_value - (ffecom_2 (GE_EXPR, integer_type_node, - saved_expr1, - convert (arg1_type, - ffecom_float_zero_))), - ffecom_2 (PLUS_EXPR, arg1_type, - saved_expr1, - convert (arg1_type, - ffecom_float_half_)), - ffecom_2 (MINUS_EXPR, arg1_type, - saved_expr1, - convert (arg1_type, - ffecom_float_half_)))); -#endif - - case FFEINTRIN_impSIGN: - case FFEINTRIN_impDSIGN: - case FFEINTRIN_impISIGN: - { - tree arg2_tree = ffecom_expr (arg2); - - saved_expr1 - = ffecom_save_tree - (ffecom_1 (ABS_EXPR, tree_type, - convert (tree_type, - ffecom_expr (arg1)))); - expr_tree - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (GE_EXPR, integer_type_node, - arg2_tree, - convert (TREE_TYPE (arg2_tree), - integer_zero_node))), - saved_expr1, - ffecom_1 (NEGATE_EXPR, tree_type, saved_expr1)); - /* Make sure SAVE_EXPRs get referenced early enough. */ - expr_tree - = ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, saved_expr1), - expr_tree); - } - return expr_tree; - - case FFEINTRIN_impSIN: - case FFEINTRIN_impCDSIN: - case FFEINTRIN_impCSIN: - case FFEINTRIN_impDSIN: - if (bt == FFEINFO_basictypeCOMPLEX) - { - if (kt == FFEINFO_kindtypeREAL1) - gfrt = FFECOM_gfrtCSIN; /* Overlapping result okay. */ - else if (kt == FFEINFO_kindtypeREAL2) - gfrt = FFECOM_gfrtCDSIN; /* Overlapping result okay. */ - } - break; - - case FFEINTRIN_impSINH: - case FFEINTRIN_impDSINH: - break; - - case FFEINTRIN_impSQRT: - case FFEINTRIN_impCDSQRT: - case FFEINTRIN_impCSQRT: - case FFEINTRIN_impDSQRT: - if (bt == FFEINFO_basictypeCOMPLEX) - { - if (kt == FFEINFO_kindtypeREAL1) - gfrt = FFECOM_gfrtCSQRT; /* Overlapping result okay. */ - else if (kt == FFEINFO_kindtypeREAL2) - gfrt = FFECOM_gfrtCDSQRT; /* Overlapping result okay. */ - } - break; - - case FFEINTRIN_impTAN: - case FFEINTRIN_impDTAN: - case FFEINTRIN_impTANH: - case FFEINTRIN_impDTANH: - break; - - case FFEINTRIN_impREALPART: - if (TREE_CODE (arg1_type) == COMPLEX_TYPE) - arg1_type = TREE_TYPE (arg1_type); - else - arg1_type = TREE_TYPE (TYPE_FIELDS (arg1_type)); - - return - convert (tree_type, - ffecom_1 (REALPART_EXPR, arg1_type, - ffecom_expr (arg1))); - - case FFEINTRIN_impIAND: - case FFEINTRIN_impAND: - return ffecom_2 (BIT_AND_EXPR, tree_type, - convert (tree_type, - ffecom_expr (arg1)), - convert (tree_type, - ffecom_expr (arg2))); - - case FFEINTRIN_impIOR: - case FFEINTRIN_impOR: - return ffecom_2 (BIT_IOR_EXPR, tree_type, - convert (tree_type, - ffecom_expr (arg1)), - convert (tree_type, - ffecom_expr (arg2))); - - case FFEINTRIN_impIEOR: - case FFEINTRIN_impXOR: - return ffecom_2 (BIT_XOR_EXPR, tree_type, - convert (tree_type, - ffecom_expr (arg1)), - convert (tree_type, - ffecom_expr (arg2))); - - case FFEINTRIN_impLSHIFT: - return ffecom_2 (LSHIFT_EXPR, tree_type, - ffecom_expr (arg1), - convert (integer_type_node, - ffecom_expr (arg2))); - - case FFEINTRIN_impRSHIFT: - return ffecom_2 (RSHIFT_EXPR, tree_type, - ffecom_expr (arg1), - convert (integer_type_node, - ffecom_expr (arg2))); - - case FFEINTRIN_impNOT: - return ffecom_1 (BIT_NOT_EXPR, tree_type, ffecom_expr (arg1)); - - case FFEINTRIN_impBIT_SIZE: - return convert (tree_type, TYPE_SIZE (arg1_type)); - - case FFEINTRIN_impBTEST: - { - ffetargetLogical1 target_true; - ffetargetLogical1 target_false; - tree true_tree; - tree false_tree; - - ffetarget_logical1 (&target_true, TRUE); - ffetarget_logical1 (&target_false, FALSE); - if (target_true == 1) - true_tree = convert (tree_type, integer_one_node); - else - true_tree = convert (tree_type, build_int_2 (target_true, 0)); - if (target_false == 0) - false_tree = convert (tree_type, integer_zero_node); - else - false_tree = convert (tree_type, build_int_2 (target_false, 0)); - - return - ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (EQ_EXPR, integer_type_node, - ffecom_2 (BIT_AND_EXPR, arg1_type, - ffecom_expr (arg1), - ffecom_2 (LSHIFT_EXPR, arg1_type, - convert (arg1_type, - integer_one_node), - convert (integer_type_node, - ffecom_expr (arg2)))), - convert (arg1_type, - integer_zero_node))), - false_tree, - true_tree); - } - - case FFEINTRIN_impIBCLR: - return - ffecom_2 (BIT_AND_EXPR, tree_type, - ffecom_expr (arg1), - ffecom_1 (BIT_NOT_EXPR, tree_type, - ffecom_2 (LSHIFT_EXPR, tree_type, - convert (tree_type, - integer_one_node), - convert (integer_type_node, - ffecom_expr (arg2))))); - - case FFEINTRIN_impIBITS: - { - tree arg3_tree = ffecom_save_tree (convert (integer_type_node, - ffecom_expr (arg3))); - tree uns_type - = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt]; - - expr_tree - = ffecom_2 (BIT_AND_EXPR, tree_type, - ffecom_2 (RSHIFT_EXPR, tree_type, - ffecom_expr (arg1), - convert (integer_type_node, - ffecom_expr (arg2))), - convert (tree_type, - ffecom_2 (RSHIFT_EXPR, uns_type, - ffecom_1 (BIT_NOT_EXPR, - uns_type, - convert (uns_type, - integer_zero_node)), - ffecom_2 (MINUS_EXPR, - integer_type_node, - TYPE_SIZE (uns_type), - arg3_tree)))); - /* Fix up, because the RSHIFT_EXPR above can't shift over TYPE_SIZE. */ - expr_tree - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (NE_EXPR, integer_type_node, - arg3_tree, - integer_zero_node)), - expr_tree, - convert (tree_type, integer_zero_node)); - } - return expr_tree; - - case FFEINTRIN_impIBSET: - return - ffecom_2 (BIT_IOR_EXPR, tree_type, - ffecom_expr (arg1), - ffecom_2 (LSHIFT_EXPR, tree_type, - convert (tree_type, integer_one_node), - convert (integer_type_node, - ffecom_expr (arg2)))); - - case FFEINTRIN_impISHFT: - { - tree arg1_tree = ffecom_save_tree (ffecom_expr (arg1)); - tree arg2_tree = ffecom_save_tree (convert (integer_type_node, - ffecom_expr (arg2))); - tree uns_type - = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt]; - - expr_tree - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (GE_EXPR, integer_type_node, - arg2_tree, - integer_zero_node)), - ffecom_2 (LSHIFT_EXPR, tree_type, - arg1_tree, - arg2_tree), - convert (tree_type, - ffecom_2 (RSHIFT_EXPR, uns_type, - convert (uns_type, arg1_tree), - ffecom_1 (NEGATE_EXPR, - integer_type_node, - arg2_tree)))); - /* Fix up, because {L|R}SHIFT_EXPR don't go over TYPE_SIZE bounds. */ - expr_tree - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (NE_EXPR, integer_type_node, - ffecom_1 (ABS_EXPR, - integer_type_node, - arg2_tree), - TYPE_SIZE (uns_type))), - expr_tree, - convert (tree_type, integer_zero_node)); - /* Make sure SAVE_EXPRs get referenced early enough. */ - expr_tree - = ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, arg1_tree), - ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, arg2_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impISHFTC: - { - tree arg1_tree = ffecom_save_tree (ffecom_expr (arg1)); - tree arg2_tree = ffecom_save_tree (convert (integer_type_node, - ffecom_expr (arg2))); - tree arg3_tree = (arg3 == NULL) ? TYPE_SIZE (tree_type) - : ffecom_save_tree (convert (integer_type_node, ffecom_expr (arg3))); - tree shift_neg; - tree shift_pos; - tree mask_arg1; - tree masked_arg1; - tree uns_type - = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt]; - - mask_arg1 - = ffecom_2 (LSHIFT_EXPR, tree_type, - ffecom_1 (BIT_NOT_EXPR, tree_type, - convert (tree_type, integer_zero_node)), - arg3_tree); - /* Fix up, because LSHIFT_EXPR above can't shift over TYPE_SIZE. */ - mask_arg1 - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (NE_EXPR, integer_type_node, - arg3_tree, - TYPE_SIZE (uns_type))), - mask_arg1, - convert (tree_type, integer_zero_node)); - mask_arg1 = ffecom_save_tree (mask_arg1); - masked_arg1 - = ffecom_2 (BIT_AND_EXPR, tree_type, - arg1_tree, - ffecom_1 (BIT_NOT_EXPR, tree_type, - mask_arg1)); - masked_arg1 = ffecom_save_tree (masked_arg1); - shift_neg - = ffecom_2 (BIT_IOR_EXPR, tree_type, - convert (tree_type, - ffecom_2 (RSHIFT_EXPR, uns_type, - convert (uns_type, masked_arg1), - ffecom_1 (NEGATE_EXPR, - integer_type_node, - arg2_tree))), - ffecom_2 (LSHIFT_EXPR, tree_type, - arg1_tree, - ffecom_2 (PLUS_EXPR, integer_type_node, - arg2_tree, - arg3_tree))); - shift_pos - = ffecom_2 (BIT_IOR_EXPR, tree_type, - ffecom_2 (LSHIFT_EXPR, tree_type, - arg1_tree, - arg2_tree), - convert (tree_type, - ffecom_2 (RSHIFT_EXPR, uns_type, - convert (uns_type, masked_arg1), - ffecom_2 (MINUS_EXPR, - integer_type_node, - arg3_tree, - arg2_tree)))); - expr_tree - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (LT_EXPR, integer_type_node, - arg2_tree, - integer_zero_node)), - shift_neg, - shift_pos); - expr_tree - = ffecom_2 (BIT_IOR_EXPR, tree_type, - ffecom_2 (BIT_AND_EXPR, tree_type, - mask_arg1, - arg1_tree), - ffecom_2 (BIT_AND_EXPR, tree_type, - ffecom_1 (BIT_NOT_EXPR, tree_type, - mask_arg1), - expr_tree)); - expr_tree - = ffecom_3 (COND_EXPR, tree_type, - ffecom_truth_value - (ffecom_2 (TRUTH_ORIF_EXPR, integer_type_node, - ffecom_2 (EQ_EXPR, integer_type_node, - ffecom_1 (ABS_EXPR, - integer_type_node, - arg2_tree), - arg3_tree), - ffecom_2 (EQ_EXPR, integer_type_node, - arg2_tree, - integer_zero_node))), - arg1_tree, - expr_tree); - /* Make sure SAVE_EXPRs get referenced early enough. */ - expr_tree - = ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, arg1_tree), - ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, arg2_tree), - ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, - mask_arg1), - ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, - masked_arg1), - expr_tree)))); - expr_tree - = ffecom_2 (COMPOUND_EXPR, tree_type, - convert (void_type_node, - arg3_tree), - expr_tree); - } - return expr_tree; - - case FFEINTRIN_impLOC: - { - tree arg1_tree = ffecom_expr (arg1); - - expr_tree - = convert (tree_type, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree)); - } - return expr_tree; - - case FFEINTRIN_impMVBITS: - { - tree arg1_tree; - tree arg2_tree; - tree arg3_tree; - ffebld arg4 = ffebld_head (ffebld_trail (list)); - tree arg4_tree; - tree arg4_type; - ffebld arg5 = ffebld_head (ffebld_trail (ffebld_trail (list))); - tree arg5_tree; - tree prep_arg1; - tree prep_arg4; - tree arg5_plus_arg3; - - arg2_tree = convert (integer_type_node, - ffecom_expr (arg2)); - arg3_tree = ffecom_save_tree (convert (integer_type_node, - ffecom_expr (arg3))); - arg4_tree = ffecom_expr_rw (NULL_TREE, arg4); - arg4_type = TREE_TYPE (arg4_tree); - - arg1_tree = ffecom_save_tree (convert (arg4_type, - ffecom_expr (arg1))); - - arg5_tree = ffecom_save_tree (convert (integer_type_node, - ffecom_expr (arg5))); - - prep_arg1 - = ffecom_2 (LSHIFT_EXPR, arg4_type, - ffecom_2 (BIT_AND_EXPR, arg4_type, - ffecom_2 (RSHIFT_EXPR, arg4_type, - arg1_tree, - arg2_tree), - ffecom_1 (BIT_NOT_EXPR, arg4_type, - ffecom_2 (LSHIFT_EXPR, arg4_type, - ffecom_1 (BIT_NOT_EXPR, - arg4_type, - convert - (arg4_type, - integer_zero_node)), - arg3_tree))), - arg5_tree); - arg5_plus_arg3 - = ffecom_save_tree (ffecom_2 (PLUS_EXPR, arg4_type, - arg5_tree, - arg3_tree)); - prep_arg4 - = ffecom_2 (LSHIFT_EXPR, arg4_type, - ffecom_1 (BIT_NOT_EXPR, arg4_type, - convert (arg4_type, - integer_zero_node)), - arg5_plus_arg3); - /* Fix up, because LSHIFT_EXPR above can't shift over TYPE_SIZE. */ - prep_arg4 - = ffecom_3 (COND_EXPR, arg4_type, - ffecom_truth_value - (ffecom_2 (NE_EXPR, integer_type_node, - arg5_plus_arg3, - convert (TREE_TYPE (arg5_plus_arg3), - TYPE_SIZE (arg4_type)))), - prep_arg4, - convert (arg4_type, integer_zero_node)); - prep_arg4 - = ffecom_2 (BIT_AND_EXPR, arg4_type, - arg4_tree, - ffecom_2 (BIT_IOR_EXPR, arg4_type, - prep_arg4, - ffecom_1 (BIT_NOT_EXPR, arg4_type, - ffecom_2 (LSHIFT_EXPR, arg4_type, - ffecom_1 (BIT_NOT_EXPR, - arg4_type, - convert - (arg4_type, - integer_zero_node)), - arg5_tree)))); - prep_arg1 - = ffecom_2 (BIT_IOR_EXPR, arg4_type, - prep_arg1, - prep_arg4); - /* Fix up (twice), because LSHIFT_EXPR above - can't shift over TYPE_SIZE. */ - prep_arg1 - = ffecom_3 (COND_EXPR, arg4_type, - ffecom_truth_value - (ffecom_2 (NE_EXPR, integer_type_node, - arg3_tree, - convert (TREE_TYPE (arg3_tree), - integer_zero_node))), - prep_arg1, - arg4_tree); - prep_arg1 - = ffecom_3 (COND_EXPR, arg4_type, - ffecom_truth_value - (ffecom_2 (NE_EXPR, integer_type_node, - arg3_tree, - convert (TREE_TYPE (arg3_tree), - TYPE_SIZE (arg4_type)))), - prep_arg1, - arg1_tree); - expr_tree - = ffecom_2s (MODIFY_EXPR, void_type_node, - arg4_tree, - prep_arg1); - /* Make sure SAVE_EXPRs get referenced early enough. */ - expr_tree - = ffecom_2 (COMPOUND_EXPR, void_type_node, - arg1_tree, - ffecom_2 (COMPOUND_EXPR, void_type_node, - arg3_tree, - ffecom_2 (COMPOUND_EXPR, void_type_node, - arg5_tree, - ffecom_2 (COMPOUND_EXPR, void_type_node, - arg5_plus_arg3, - expr_tree)))); - expr_tree - = ffecom_2 (COMPOUND_EXPR, void_type_node, - arg4_tree, - expr_tree); - - } - return expr_tree; - - case FFEINTRIN_impDERF: - case FFEINTRIN_impERF: - case FFEINTRIN_impDERFC: - case FFEINTRIN_impERFC: - break; - - case FFEINTRIN_impIARGC: - /* extern int xargc; i__1 = xargc - 1; */ - expr_tree = ffecom_2 (MINUS_EXPR, TREE_TYPE (ffecom_tree_xargc_), - ffecom_tree_xargc_, - convert (TREE_TYPE (ffecom_tree_xargc_), - integer_one_node)); - return expr_tree; - - case FFEINTRIN_impSIGNAL_func: - case FFEINTRIN_impSIGNAL_subr: - { - tree arg1_tree; - tree arg2_tree; - tree arg3_tree; - - arg1_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg1)); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - - /* Pass procedure as a pointer to it, anything else by value. */ - if (ffeinfo_kind (ffebld_info (arg2)) == FFEINFO_kindENTITY) - arg2_tree = convert (integer_type_node, ffecom_expr (arg2)); - else - arg2_tree = ffecom_ptr_to_expr (arg2); - arg2_tree = convert (TREE_TYPE (null_pointer_node), - arg2_tree); - - if (arg3 != NULL) - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - else - arg3_tree = NULL_TREE; - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - TREE_CHAIN (arg1_tree) = arg2_tree; - - expr_tree - = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - ((codegen_imp == FFEINTRIN_impSIGNAL_subr) ? - NULL_TREE : - tree_type), - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - - if (arg3_tree != NULL_TREE) - expr_tree - = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impALARM: - { - tree arg1_tree; - tree arg2_tree; - tree arg3_tree; - - arg1_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg1)); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - - /* Pass procedure as a pointer to it, anything else by value. */ - if (ffeinfo_kind (ffebld_info (arg2)) == FFEINFO_kindENTITY) - arg2_tree = convert (integer_type_node, ffecom_expr (arg2)); - else - arg2_tree = ffecom_ptr_to_expr (arg2); - arg2_tree = convert (TREE_TYPE (null_pointer_node), - arg2_tree); - - if (arg3 != NULL) - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - else - arg3_tree = NULL_TREE; - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - TREE_CHAIN (arg1_tree) = arg2_tree; - - expr_tree - = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - - if (arg3_tree != NULL_TREE) - expr_tree - = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impCHDIR_subr: - case FFEINTRIN_impFDATE_subr: - case FFEINTRIN_impFGET_subr: - case FFEINTRIN_impFPUT_subr: - case FFEINTRIN_impGETCWD_subr: - case FFEINTRIN_impHOSTNM_subr: - case FFEINTRIN_impSYSTEM_subr: - case FFEINTRIN_impUNLINK_subr: - { - tree arg1_len = integer_zero_node; - tree arg1_tree; - tree arg2_tree; - - arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len); - - if (arg2 != NULL) - arg2_tree = ffecom_expr_w (NULL_TREE, arg2); - else - arg2_tree = NULL_TREE; - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg1_len = build_tree_list (NULL_TREE, arg1_len); - TREE_CHAIN (arg1_tree) = arg1_len; - - expr_tree - = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - - if (arg2_tree != NULL_TREE) - expr_tree - = ffecom_modify (NULL_TREE, arg2_tree, - convert (TREE_TYPE (arg2_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impEXIT: - if (arg1 != NULL) - break; - - expr_tree = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type - (ffecom_integer_type_node), - integer_zero_node)); - - return - ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - void_type_node, - expr_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - - case FFEINTRIN_impFLUSH: - if (arg1 == NULL) - gfrt = FFECOM_gfrtFLUSH; - else - gfrt = FFECOM_gfrtFLUSH1; - break; - - case FFEINTRIN_impCHMOD_subr: - case FFEINTRIN_impLINK_subr: - case FFEINTRIN_impRENAME_subr: - case FFEINTRIN_impSYMLNK_subr: - { - tree arg1_len = integer_zero_node; - tree arg1_tree; - tree arg2_len = integer_zero_node; - tree arg2_tree; - tree arg3_tree; - - arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len); - arg2_tree = ffecom_arg_ptr_to_expr (arg2, &arg2_len); - if (arg3 != NULL) - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - else - arg3_tree = NULL_TREE; - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg1_len = build_tree_list (NULL_TREE, arg1_len); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - arg2_len = build_tree_list (NULL_TREE, arg2_len); - TREE_CHAIN (arg1_tree) = arg2_tree; - TREE_CHAIN (arg2_tree) = arg1_len; - TREE_CHAIN (arg1_len) = arg2_len; - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - if (arg3_tree != NULL_TREE) - expr_tree = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impLSTAT_subr: - case FFEINTRIN_impSTAT_subr: - { - tree arg1_len = integer_zero_node; - tree arg1_tree; - tree arg2_tree; - tree arg3_tree; - - arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len); - - arg2_tree = ffecom_ptr_to_expr (arg2); - - if (arg3 != NULL) - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - else - arg3_tree = NULL_TREE; - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg1_len = build_tree_list (NULL_TREE, arg1_len); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - TREE_CHAIN (arg1_tree) = arg2_tree; - TREE_CHAIN (arg2_tree) = arg1_len; - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - if (arg3_tree != NULL_TREE) - expr_tree = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impFGETC_subr: - case FFEINTRIN_impFPUTC_subr: - { - tree arg1_tree; - tree arg2_tree; - tree arg2_len = integer_zero_node; - tree arg3_tree; - - arg1_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg1)); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - - arg2_tree = ffecom_arg_ptr_to_expr (arg2, &arg2_len); - if (arg3 != NULL) - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - else - arg3_tree = NULL_TREE; - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - arg2_len = build_tree_list (NULL_TREE, arg2_len); - TREE_CHAIN (arg1_tree) = arg2_tree; - TREE_CHAIN (arg2_tree) = arg2_len; - - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - if (arg3_tree != NULL_TREE) - expr_tree = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impFSTAT_subr: - { - tree arg1_tree; - tree arg2_tree; - tree arg3_tree; - - arg1_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg1)); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - - arg2_tree = convert (ffecom_f2c_ptr_to_integer_type_node, - ffecom_ptr_to_expr (arg2)); - - if (arg3 == NULL) - arg3_tree = NULL_TREE; - else - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - TREE_CHAIN (arg1_tree) = arg2_tree; - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - if (arg3_tree != NULL_TREE) { - expr_tree = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - } - return expr_tree; - - case FFEINTRIN_impKILL_subr: - { - tree arg1_tree; - tree arg2_tree; - tree arg3_tree; - - arg1_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg1)); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - - arg2_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg2)); - arg2_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg2_tree)), - arg2_tree); - - if (arg3 == NULL) - arg3_tree = NULL_TREE; - else - arg3_tree = ffecom_expr_w (NULL_TREE, arg3); - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - TREE_CHAIN (arg1_tree) = arg2_tree; - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - if (arg3_tree != NULL_TREE) { - expr_tree = ffecom_modify (NULL_TREE, arg3_tree, - convert (TREE_TYPE (arg3_tree), - expr_tree)); - } - } - return expr_tree; - - case FFEINTRIN_impCTIME_subr: - case FFEINTRIN_impTTYNAM_subr: - { - tree arg1_len = integer_zero_node; - tree arg1_tree; - tree arg2_tree; - - arg1_tree = ffecom_arg_ptr_to_expr (arg2, &arg1_len); - - arg2_tree = convert (((codegen_imp == FFEINTRIN_impCTIME_subr) ? - ffecom_f2c_longint_type_node : - ffecom_f2c_integer_type_node), - ffecom_expr (arg1)); - arg2_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg2_tree)), - arg2_tree); - - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - arg1_len = build_tree_list (NULL_TREE, arg1_len); - arg2_tree = build_tree_list (NULL_TREE, arg2_tree); - TREE_CHAIN (arg1_len) = arg2_tree; - TREE_CHAIN (arg1_tree) = arg1_len; - - expr_tree - = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - arg1_tree, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - TREE_SIDE_EFFECTS (expr_tree) = 1; - } - return expr_tree; - - case FFEINTRIN_impIRAND: - case FFEINTRIN_impRAND: - /* Arg defaults to 0 (normal random case) */ - { - tree arg1_tree; - - if (arg1 == NULL) - arg1_tree = ffecom_integer_zero_node; - else - arg1_tree = ffecom_expr (arg1); - arg1_tree = convert (ffecom_f2c_integer_type_node, - arg1_tree); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - arg1_tree = build_tree_list (NULL_TREE, arg1_tree); - - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - ((codegen_imp == FFEINTRIN_impIRAND) ? - ffecom_f2c_integer_type_node : - ffecom_f2c_real_type_node), - arg1_tree, - dest_tree, dest, dest_used, - NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - } - return expr_tree; - - case FFEINTRIN_impFTELL_subr: - case FFEINTRIN_impUMASK_subr: - { - tree arg1_tree; - tree arg2_tree; - - arg1_tree = convert (ffecom_f2c_integer_type_node, - ffecom_expr (arg1)); - arg1_tree = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (arg1_tree)), - arg1_tree); - - if (arg2 == NULL) - arg2_tree = NULL_TREE; - else - arg2_tree = ffecom_expr_w (NULL_TREE, arg2); - - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - build_tree_list (NULL_TREE, arg1_tree), - NULL_TREE, NULL, NULL, NULL_TREE, - TRUE, - ffebld_nonter_hook (expr)); - if (arg2_tree != NULL_TREE) { - expr_tree = ffecom_modify (NULL_TREE, arg2_tree, - convert (TREE_TYPE (arg2_tree), - expr_tree)); - } - } - return expr_tree; - - case FFEINTRIN_impCPU_TIME: - case FFEINTRIN_impSECOND_subr: - { - tree arg1_tree; - - arg1_tree = ffecom_expr_w (NULL_TREE, arg1); - - expr_tree - = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - NULL_TREE, - NULL_TREE, NULL, NULL, NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - - expr_tree - = ffecom_modify (NULL_TREE, arg1_tree, - convert (TREE_TYPE (arg1_tree), - expr_tree)); - } - return expr_tree; - - case FFEINTRIN_impDTIME_subr: - case FFEINTRIN_impETIME_subr: - { - tree arg1_tree; - tree result_tree; - - result_tree = ffecom_expr_w (NULL_TREE, arg2); - - arg1_tree = ffecom_ptr_to_expr (arg1); - - expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt), - ffecom_gfrt_kindtype (gfrt), - FALSE, - NULL_TREE, - build_tree_list (NULL_TREE, arg1_tree), - NULL_TREE, NULL, NULL, NULL_TREE, - TRUE, - ffebld_nonter_hook (expr)); - expr_tree = ffecom_modify (NULL_TREE, result_tree, - convert (TREE_TYPE (result_tree), - expr_tree)); - } - return expr_tree; - - /* Straightforward calls of libf2c routines: */ - case FFEINTRIN_impABORT: - case FFEINTRIN_impACCESS: - case FFEINTRIN_impBESJ0: - case FFEINTRIN_impBESJ1: - case FFEINTRIN_impBESJN: - case FFEINTRIN_impBESY0: - case FFEINTRIN_impBESY1: - case FFEINTRIN_impBESYN: - case FFEINTRIN_impCHDIR_func: - case FFEINTRIN_impCHMOD_func: - case FFEINTRIN_impDATE: - case FFEINTRIN_impDATE_AND_TIME: - case FFEINTRIN_impDBESJ0: - case FFEINTRIN_impDBESJ1: - case FFEINTRIN_impDBESJN: - case FFEINTRIN_impDBESY0: - case FFEINTRIN_impDBESY1: - case FFEINTRIN_impDBESYN: - case FFEINTRIN_impDTIME_func: - case FFEINTRIN_impETIME_func: - case FFEINTRIN_impFGETC_func: - case FFEINTRIN_impFGET_func: - case FFEINTRIN_impFNUM: - case FFEINTRIN_impFPUTC_func: - case FFEINTRIN_impFPUT_func: - case FFEINTRIN_impFSEEK: - case FFEINTRIN_impFSTAT_func: - case FFEINTRIN_impFTELL_func: - case FFEINTRIN_impGERROR: - case FFEINTRIN_impGETARG: - case FFEINTRIN_impGETCWD_func: - case FFEINTRIN_impGETENV: - case FFEINTRIN_impGETGID: - case FFEINTRIN_impGETLOG: - case FFEINTRIN_impGETPID: - case FFEINTRIN_impGETUID: - case FFEINTRIN_impGMTIME: - case FFEINTRIN_impHOSTNM_func: - case FFEINTRIN_impIDATE_unix: - case FFEINTRIN_impIDATE_vxt: - case FFEINTRIN_impIERRNO: - case FFEINTRIN_impISATTY: - case FFEINTRIN_impITIME: - case FFEINTRIN_impKILL_func: - case FFEINTRIN_impLINK_func: - case FFEINTRIN_impLNBLNK: - case FFEINTRIN_impLSTAT_func: - case FFEINTRIN_impLTIME: - case FFEINTRIN_impMCLOCK8: - case FFEINTRIN_impMCLOCK: - case FFEINTRIN_impPERROR: - case FFEINTRIN_impRENAME_func: - case FFEINTRIN_impSECNDS: - case FFEINTRIN_impSECOND_func: - case FFEINTRIN_impSLEEP: - case FFEINTRIN_impSRAND: - case FFEINTRIN_impSTAT_func: - case FFEINTRIN_impSYMLNK_func: - case FFEINTRIN_impSYSTEM_CLOCK: - case FFEINTRIN_impSYSTEM_func: - case FFEINTRIN_impTIME8: - case FFEINTRIN_impTIME_unix: - case FFEINTRIN_impTIME_vxt: - case FFEINTRIN_impUMASK_func: - case FFEINTRIN_impUNLINK_func: - break; - - case FFEINTRIN_impCTIME_func: /* CHARACTER functions not handled here. */ - case FFEINTRIN_impFDATE_func: /* CHARACTER functions not handled here. */ - case FFEINTRIN_impTTYNAM_func: /* CHARACTER functions not handled here. */ - case FFEINTRIN_impNONE: - case FFEINTRIN_imp: /* Hush up gcc warning. */ - fprintf (stderr, "No %s implementation.\n", - ffeintrin_name_implementation (ffebld_symter_implementation (ffebld_left (expr)))); - assert ("unimplemented intrinsic" == NULL); - return error_mark_node; - } - - assert (gfrt != FFECOM_gfrt); /* Must have an implementation! */ - - expr_tree = ffecom_arglist_expr_ (ffecom_gfrt_args_ (gfrt), - ffebld_right (expr)); - - return ffecom_call_ (ffecom_gfrt_tree_ (gfrt), ffecom_gfrt_kindtype (gfrt), - (ffe_is_f2c_library () && ffecom_gfrt_complex_[gfrt]), - tree_type, - expr_tree, dest_tree, dest, dest_used, - NULL_TREE, TRUE, - ffebld_nonter_hook (expr)); - - /* See bottom of this file for f2c transforms used to determine - many of the above implementations. The info seems to confuse - Emacs's C mode indentation, which is why it's been moved to - the bottom of this source file. */ -} - -/* For power (exponentiation) where right-hand operand is type INTEGER, - generate in-line code to do it the fast way (which, if the operand - is a constant, might just mean a series of multiplies). */ - -static tree -ffecom_expr_power_integer_ (ffebld expr) -{ - tree l = ffecom_expr (ffebld_left (expr)); - tree r = ffecom_expr (ffebld_right (expr)); - tree ltype = TREE_TYPE (l); - tree rtype = TREE_TYPE (r); - tree result = NULL_TREE; - - if (l == error_mark_node - || r == error_mark_node) - return error_mark_node; - - if (TREE_CODE (r) == INTEGER_CST) - { - int sgn = tree_int_cst_sgn (r); - - if (sgn == 0) - return convert (ltype, integer_one_node); - - if ((TREE_CODE (ltype) == INTEGER_TYPE) - && (sgn < 0)) - { - /* Reciprocal of integer is either 0, -1, or 1, so after - calculating that (which we leave to the back end to do - or not do optimally), don't bother with any multiplying. */ - - result = ffecom_tree_divide_ (ltype, - convert (ltype, integer_one_node), - l, - NULL_TREE, NULL, NULL, NULL_TREE); - r = ffecom_1 (NEGATE_EXPR, - rtype, - r); - if ((TREE_INT_CST_LOW (r) & 1) == 0) - result = ffecom_1 (ABS_EXPR, rtype, - result); - } - - /* Generate appropriate series of multiplies, preceded - by divide if the exponent is negative. */ - - l = save_expr (l); - - if (sgn < 0) - { - l = ffecom_tree_divide_ (ltype, - convert (ltype, integer_one_node), - l, - NULL_TREE, NULL, NULL, - ffebld_nonter_hook (expr)); - r = ffecom_1 (NEGATE_EXPR, rtype, r); - assert (TREE_CODE (r) == INTEGER_CST); - - if (tree_int_cst_sgn (r) < 0) - { /* The "most negative" number. */ - r = ffecom_1 (NEGATE_EXPR, rtype, - ffecom_2 (RSHIFT_EXPR, rtype, - r, - integer_one_node)); - l = save_expr (l); - l = ffecom_2 (MULT_EXPR, ltype, - l, - l); - } - } - - for (;;) - { - if (TREE_INT_CST_LOW (r) & 1) - { - if (result == NULL_TREE) - result = l; - else - result = ffecom_2 (MULT_EXPR, ltype, - result, - l); - } - - r = ffecom_2 (RSHIFT_EXPR, rtype, - r, - integer_one_node); - if (integer_zerop (r)) - break; - assert (TREE_CODE (r) == INTEGER_CST); - - l = save_expr (l); - l = ffecom_2 (MULT_EXPR, ltype, - l, - l); - } - return result; - } - - /* Though rhs isn't a constant, in-line code cannot be expanded - while transforming dummies - because the back end cannot be easily convinced to generate - stores (MODIFY_EXPR), handle temporaries, and so on before - all the appropriate rtx's have been generated for things like - dummy args referenced in rhs -- which doesn't happen until - store_parm_decls() is called (expand_function_start, I believe, - does the actual rtx-stuffing of PARM_DECLs). - - So, in this case, let the caller generate the call to the - run-time-library function to evaluate the power for us. */ - - if (ffecom_transform_only_dummies_) - return NULL_TREE; - - /* Right-hand operand not a constant, expand in-line code to figure - out how to do the multiplies, &c. - - The returned expression is expressed this way in GNU C, where l and - r are the "inputs": - - ({ typeof (r) rtmp = r; - typeof (l) ltmp = l; - typeof (l) result; - - if (rtmp == 0) - result = 1; - else - { - if ((basetypeof (l) == basetypeof (int)) - && (rtmp < 0)) - { - result = ((typeof (l)) 1) / ltmp; - if ((ltmp < 0) && (((-rtmp) & 1) == 0)) - result = -result; - } - else - { - result = 1; - if ((basetypeof (l) != basetypeof (int)) - && (rtmp < 0)) - { - ltmp = ((typeof (l)) 1) / ltmp; - rtmp = -rtmp; - if (rtmp < 0) - { - rtmp = -(rtmp >> 1); - ltmp *= ltmp; - } - } - for (;;) - { - if (rtmp & 1) - result *= ltmp; - if ((rtmp >>= 1) == 0) - break; - ltmp *= ltmp; - } - } - } - result; - }) - - Note that some of the above is compile-time collapsable, such as - the first part of the if statements that checks the base type of - l against int. The if statements are phrased that way to suggest - an easy way to generate the if/else constructs here, knowing that - the back end should (and probably does) eliminate the resulting - dead code (either the int case or the non-int case), something - it couldn't do without the redundant phrasing, requiring explicit - dead-code elimination here, which would be kind of difficult to - read. */ - - { - tree rtmp; - tree ltmp; - tree divide; - tree basetypeof_l_is_int; - tree se; - tree t; - - basetypeof_l_is_int - = build_int_2 ((TREE_CODE (ltype) == INTEGER_TYPE), 0); - - se = expand_start_stmt_expr (/*has_scope=*/1); - - ffecom_start_compstmt (); - -#ifndef HAHA - rtmp = ffecom_make_tempvar ("power_r", rtype, - FFETARGET_charactersizeNONE, -1); - ltmp = ffecom_make_tempvar ("power_l", ltype, - FFETARGET_charactersizeNONE, -1); - result = ffecom_make_tempvar ("power_res", ltype, - FFETARGET_charactersizeNONE, -1); - if (TREE_CODE (ltype) == COMPLEX_TYPE - || TREE_CODE (ltype) == RECORD_TYPE) - divide = ffecom_make_tempvar ("power_div", ltype, - FFETARGET_charactersizeNONE, -1); - else - divide = NULL_TREE; -#else /* HAHA */ - { - tree hook; - - hook = ffebld_nonter_hook (expr); - assert (hook); - assert (TREE_CODE (hook) == TREE_VEC); - assert (TREE_VEC_LENGTH (hook) == 4); - rtmp = TREE_VEC_ELT (hook, 0); - ltmp = TREE_VEC_ELT (hook, 1); - result = TREE_VEC_ELT (hook, 2); - divide = TREE_VEC_ELT (hook, 3); - if (TREE_CODE (ltype) == COMPLEX_TYPE - || TREE_CODE (ltype) == RECORD_TYPE) - assert (divide); - else - assert (! divide); - } -#endif /* HAHA */ - - expand_expr_stmt (ffecom_modify (void_type_node, - rtmp, - r)); - expand_expr_stmt (ffecom_modify (void_type_node, - ltmp, - l)); - expand_start_cond (ffecom_truth_value - (ffecom_2 (EQ_EXPR, integer_type_node, - rtmp, - convert (rtype, integer_zero_node))), - 0); - expand_expr_stmt (ffecom_modify (void_type_node, - result, - convert (ltype, integer_one_node))); - expand_start_else (); - if (! integer_zerop (basetypeof_l_is_int)) - { - expand_start_cond (ffecom_2 (LT_EXPR, integer_type_node, - rtmp, - convert (rtype, - integer_zero_node)), - 0); - expand_expr_stmt (ffecom_modify (void_type_node, - result, - ffecom_tree_divide_ - (ltype, - convert (ltype, integer_one_node), - ltmp, - NULL_TREE, NULL, NULL, - divide))); - expand_start_cond (ffecom_truth_value - (ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node, - ffecom_2 (LT_EXPR, integer_type_node, - ltmp, - convert (ltype, - integer_zero_node)), - ffecom_2 (EQ_EXPR, integer_type_node, - ffecom_2 (BIT_AND_EXPR, - rtype, - ffecom_1 (NEGATE_EXPR, - rtype, - rtmp), - convert (rtype, - integer_one_node)), - convert (rtype, - integer_zero_node)))), - 0); - expand_expr_stmt (ffecom_modify (void_type_node, - result, - ffecom_1 (NEGATE_EXPR, - ltype, - result))); - expand_end_cond (); - expand_start_else (); - } - expand_expr_stmt (ffecom_modify (void_type_node, - result, - convert (ltype, integer_one_node))); - expand_start_cond (ffecom_truth_value - (ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node, - ffecom_truth_value_invert - (basetypeof_l_is_int), - ffecom_2 (LT_EXPR, integer_type_node, - rtmp, - convert (rtype, - integer_zero_node)))), - 0); - expand_expr_stmt (ffecom_modify (void_type_node, - ltmp, - ffecom_tree_divide_ - (ltype, - convert (ltype, integer_one_node), - ltmp, - NULL_TREE, NULL, NULL, - divide))); - expand_expr_stmt (ffecom_modify (void_type_node, - rtmp, - ffecom_1 (NEGATE_EXPR, rtype, - rtmp))); - expand_start_cond (ffecom_truth_value - (ffecom_2 (LT_EXPR, integer_type_node, - rtmp, - convert (rtype, integer_zero_node))), - 0); - expand_expr_stmt (ffecom_modify (void_type_node, - rtmp, - ffecom_1 (NEGATE_EXPR, rtype, - ffecom_2 (RSHIFT_EXPR, - rtype, - rtmp, - integer_one_node)))); - expand_expr_stmt (ffecom_modify (void_type_node, - ltmp, - ffecom_2 (MULT_EXPR, ltype, - ltmp, - ltmp))); - expand_end_cond (); - expand_end_cond (); - expand_start_loop (1); - expand_start_cond (ffecom_truth_value - (ffecom_2 (BIT_AND_EXPR, rtype, - rtmp, - convert (rtype, integer_one_node))), - 0); - expand_expr_stmt (ffecom_modify (void_type_node, - result, - ffecom_2 (MULT_EXPR, ltype, - result, - ltmp))); - expand_end_cond (); - expand_exit_loop_if_false (NULL, - ffecom_truth_value - (ffecom_modify (rtype, - rtmp, - ffecom_2 (RSHIFT_EXPR, - rtype, - rtmp, - integer_one_node)))); - expand_expr_stmt (ffecom_modify (void_type_node, - ltmp, - ffecom_2 (MULT_EXPR, ltype, - ltmp, - ltmp))); - expand_end_loop (); - expand_end_cond (); - if (!integer_zerop (basetypeof_l_is_int)) - expand_end_cond (); - expand_expr_stmt (result); - - t = ffecom_end_compstmt (); - - result = expand_end_stmt_expr (se); - - /* This code comes from c-parse.in, after its expand_end_stmt_expr. */ - - if (TREE_CODE (t) == BLOCK) - { - /* Make a BIND_EXPR for the BLOCK already made. */ - result = build (BIND_EXPR, TREE_TYPE (result), - NULL_TREE, result, t); - /* Remove the block from the tree at this point. - It gets put back at the proper place - when the BIND_EXPR is expanded. */ - delete_block (t); - } - else - result = t; - } - - return result; -} - -/* ffecom_expr_transform_ -- Transform symbols in expr - - ffebld expr; // FFE expression. - ffecom_expr_transform_ (expr); - - Recursive descent on expr while transforming any untransformed SYMTERs. */ - -static void -ffecom_expr_transform_ (ffebld expr) -{ - tree t; - ffesymbol s; - - tail_recurse: - - if (expr == NULL) - return; - - switch (ffebld_op (expr)) - { - case FFEBLD_opSYMTER: - s = ffebld_symter (expr); - t = ffesymbol_hook (s).decl_tree; - if ((t == NULL_TREE) - && ((ffesymbol_kind (s) != FFEINFO_kindNONE) - || ((ffesymbol_where (s) != FFEINFO_whereNONE) - && (ffesymbol_where (s) != FFEINFO_whereINTRINSIC)))) - { - s = ffecom_sym_transform_ (s); - t = ffesymbol_hook (s).decl_tree; /* Sfunc expr non-dummy, - DIMENSION expr? */ - } - break; /* Ok if (t == NULL) here. */ - - case FFEBLD_opITEM: - ffecom_expr_transform_ (ffebld_head (expr)); - expr = ffebld_trail (expr); - goto tail_recurse; /* :::::::::::::::::::: */ - - default: - break; - } - - switch (ffebld_arity (expr)) - { - case 2: - ffecom_expr_transform_ (ffebld_left (expr)); - expr = ffebld_right (expr); - goto tail_recurse; /* :::::::::::::::::::: */ - - case 1: - expr = ffebld_left (expr); - goto tail_recurse; /* :::::::::::::::::::: */ - - default: - break; - } - - return; -} - -/* Make a type based on info in live f2c.h file. */ - -static void -ffecom_f2c_make_type_ (tree *type, int tcode, const char *name) -{ - switch (tcode) - { - case FFECOM_f2ccodeCHAR: - *type = make_signed_type (CHAR_TYPE_SIZE); - break; - - case FFECOM_f2ccodeSHORT: - *type = make_signed_type (SHORT_TYPE_SIZE); - break; - - case FFECOM_f2ccodeINT: - *type = make_signed_type (INT_TYPE_SIZE); - break; - - case FFECOM_f2ccodeLONG: - *type = make_signed_type (LONG_TYPE_SIZE); - break; - - case FFECOM_f2ccodeLONGLONG: - *type = make_signed_type (LONG_LONG_TYPE_SIZE); - break; - - case FFECOM_f2ccodeCHARPTR: - *type = build_pointer_type (DEFAULT_SIGNED_CHAR - ? signed_char_type_node - : unsigned_char_type_node); - break; - - case FFECOM_f2ccodeFLOAT: - *type = make_node (REAL_TYPE); - TYPE_PRECISION (*type) = FLOAT_TYPE_SIZE; - layout_type (*type); - break; - - case FFECOM_f2ccodeDOUBLE: - *type = make_node (REAL_TYPE); - TYPE_PRECISION (*type) = DOUBLE_TYPE_SIZE; - layout_type (*type); - break; - - case FFECOM_f2ccodeLONGDOUBLE: - *type = make_node (REAL_TYPE); - TYPE_PRECISION (*type) = LONG_DOUBLE_TYPE_SIZE; - layout_type (*type); - break; - - case FFECOM_f2ccodeTWOREALS: - *type = ffecom_make_complex_type_ (ffecom_f2c_real_type_node); - break; - - case FFECOM_f2ccodeTWODOUBLEREALS: - *type = ffecom_make_complex_type_ (ffecom_f2c_doublereal_type_node); - break; - - default: - assert ("unexpected FFECOM_f2ccodeXYZZY!" == NULL); - *type = error_mark_node; - return; - } - - pushdecl (build_decl (TYPE_DECL, - ffecom_get_invented_identifier ("__g77_f2c_%s", name), - *type)); -} - -/* Set the f2c list-directed-I/O code for whatever (integral) type has the - given size. */ - -static void -ffecom_f2c_set_lio_code_ (ffeinfoBasictype bt, int size, - int code) -{ - int j; - tree t; - - for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j) - if ((t = ffecom_tree_type[bt][j]) != NULL_TREE - && compare_tree_int (TYPE_SIZE (t), size) == 0) - { - assert (code != -1); - ffecom_f2c_typecode_[bt][j] = code; - code = -1; - } -} - -/* Finish up globals after doing all program units in file - - Need to handle only uninitialized COMMON areas. */ - -static ffeglobal -ffecom_finish_global_ (ffeglobal global) -{ - tree cbtype; - tree cbt; - tree size; - - if (ffeglobal_type (global) != FFEGLOBAL_typeCOMMON) - return global; - - if (ffeglobal_common_init (global)) - return global; - - cbt = ffeglobal_hook (global); - if ((cbt == NULL_TREE) - || !ffeglobal_common_have_size (global)) - return global; /* No need to make common, never ref'd. */ - - DECL_EXTERNAL (cbt) = 0; - - /* Give the array a size now. */ - - size = build_int_2 ((ffeglobal_common_size (global) - + ffeglobal_common_pad (global)) - 1, - 0); - - cbtype = TREE_TYPE (cbt); - TYPE_DOMAIN (cbtype) = build_range_type (integer_type_node, - integer_zero_node, - size); - if (!TREE_TYPE (size)) - TREE_TYPE (size) = TYPE_DOMAIN (cbtype); - layout_type (cbtype); - - cbt = start_decl (cbt, FALSE); - assert (cbt == ffeglobal_hook (global)); - - finish_decl (cbt, NULL_TREE, FALSE); - - return global; -} - -/* Finish up any untransformed symbols. */ - -static ffesymbol -ffecom_finish_symbol_transform_ (ffesymbol s) -{ - if ((s == NULL) || (TREE_CODE (current_function_decl) == ERROR_MARK)) - return s; - - /* It's easy to know to transform an untransformed symbol, to make sure - we put out debugging info for it. But COMMON variables, unlike - EQUIVALENCE ones, aren't given declarations in addition to the - tree expressions that specify offsets, because COMMON variables - can be referenced in the outer scope where only dummy arguments - (PARM_DECLs) should really be seen. To be safe, just don't do any - VAR_DECLs for COMMON variables when we transform them for real - use, and therefore we do all the VAR_DECL creating here. */ - - if (ffesymbol_hook (s).decl_tree == NULL_TREE) - { - if (ffesymbol_kind (s) != FFEINFO_kindNONE - || (ffesymbol_where (s) != FFEINFO_whereNONE - && ffesymbol_where (s) != FFEINFO_whereINTRINSIC - && ffesymbol_where (s) != FFEINFO_whereDUMMY)) - /* Not transformed, and not CHARACTER*(*), and not a dummy - argument, which can happen only if the entry point names - it "rides in on" are all invalidated for other reasons. */ - s = ffecom_sym_transform_ (s); - } - - if ((ffesymbol_where (s) == FFEINFO_whereCOMMON) - && (ffesymbol_hook (s).decl_tree != error_mark_node)) - { - /* This isn't working, at least for dbxout. The .s file looks - okay to me (burley), but in gdb 4.9 at least, the variables - appear to reside somewhere outside of the common area, so - it doesn't make sense to mislead anyone by generating the info - on those variables until this is fixed. NOTE: Same problem - with EQUIVALENCE, sadly...see similar #if later. */ - ffecom_member_phase2_ (ffesymbol_storage (ffesymbol_common (s)), - ffesymbol_storage (s)); - } - - return s; -} - -/* Append underscore(s) to name before calling get_identifier. "us" - is nonzero if the name already contains an underscore and thus - needs two underscores appended. */ - -static tree -ffecom_get_appended_identifier_ (char us, const char *name) -{ - int i; - char *newname; - tree id; - - newname = xmalloc ((i = strlen (name)) + 1 - + ffe_is_underscoring () - + us); - memcpy (newname, name, i); - newname[i] = '_'; - newname[i + us] = '_'; - newname[i + 1 + us] = '\0'; - id = get_identifier (newname); - - free (newname); - - return id; -} - -/* Decide whether to append underscore to name before calling - get_identifier. */ - -static tree -ffecom_get_external_identifier_ (ffesymbol s) -{ - char us; - const char *name = ffesymbol_text (s); - - /* If name is a built-in name, just return it as is. */ - - if (!ffe_is_underscoring () - || (strcmp (name, FFETARGET_nameBLANK_COMMON) == 0) -#if FFETARGET_isENFORCED_MAIN_NAME - || (strcmp (name, FFETARGET_nameENFORCED_NAME) == 0) -#else - || (strcmp (name, FFETARGET_nameUNNAMED_MAIN) == 0) -#endif - || (strcmp (name, FFETARGET_nameUNNAMED_BLOCK_DATA) == 0)) - return get_identifier (name); - - us = ffe_is_second_underscore () - ? (strchr (name, '_') != NULL) - : 0; - - return ffecom_get_appended_identifier_ (us, name); -} - -/* Decide whether to append underscore to internal name before calling - get_identifier. - - This is for non-external, top-function-context names only. Transform - identifier so it doesn't conflict with the transformed result - of using a _different_ external name. E.g. if "CALL FOO" is - transformed into "FOO_();", then the variable in "FOO_ = 3" - must be transformed into something that does not conflict, since - these two things should be independent. - - The transformation is as follows. If the name does not contain - an underscore, there is no possible conflict, so just return. - If the name does contain an underscore, then transform it just - like we transform an external identifier. */ - -static tree -ffecom_get_identifier_ (const char *name) -{ - /* If name does not contain an underscore, just return it as is. */ - - if (!ffe_is_underscoring () - || (strchr (name, '_') == NULL)) - return get_identifier (name); - - return ffecom_get_appended_identifier_ (ffe_is_second_underscore (), - name); -} - -/* ffecom_gen_sfuncdef_ -- Generate definition of statement function - - tree t; - ffesymbol s; // kindFUNCTION, whereIMMEDIATE. - t = ffecom_gen_sfuncdef_(s,ffesymbol_basictype(s), - ffesymbol_kindtype(s)); - - Call after setting up containing function and getting trees for all - other symbols. */ - -static tree -ffecom_gen_sfuncdef_ (ffesymbol s, ffeinfoBasictype bt, ffeinfoKindtype kt) -{ - ffebld expr = ffesymbol_sfexpr (s); - tree type; - tree func; - tree result; - bool charfunc = (bt == FFEINFO_basictypeCHARACTER); - static bool recurse = FALSE; - int old_lineno = lineno; - const char *old_input_filename = input_filename; - - ffecom_nested_entry_ = s; - - /* For now, we don't have a handy pointer to where the sfunc is actually - defined, though that should be easy to add to an ffesymbol. (The - token/where info available might well point to the place where the type - of the sfunc is declared, especially if that precedes the place where - the sfunc itself is defined, which is typically the case.) We should - put out a null pointer rather than point somewhere wrong, but I want to - see how it works at this point. */ - - input_filename = ffesymbol_where_filename (s); - lineno = ffesymbol_where_filelinenum (s); - - /* Pretransform the expression so any newly discovered things belong to the - outer program unit, not to the statement function. */ - - ffecom_expr_transform_ (expr); - - /* Make sure no recursive invocation of this fn (a specific case of failing - to pretransform an sfunc's expression, i.e. where its expression - references another untransformed sfunc) happens. */ - - assert (!recurse); - recurse = TRUE; - - push_f_function_context (); - - if (charfunc) - type = void_type_node; - else - { - type = ffecom_tree_type[bt][kt]; - if (type == NULL_TREE) - type = integer_type_node; /* _sym_exec_transition reports - error. */ - } - - start_function (ffecom_get_identifier_ (ffesymbol_text (s)), - build_function_type (type, NULL_TREE), - 1, /* nested/inline */ - 0); /* TREE_PUBLIC */ - - /* We don't worry about COMPLEX return values here, because this is - entirely internal to our code, and gcc has the ability to return COMPLEX - directly as a value. */ - - if (charfunc) - { /* Prepend arg for where result goes. */ - tree type; - - type = ffecom_tree_type[FFEINFO_basictypeCHARACTER][kt]; - - result = ffecom_get_invented_identifier ("__g77_%s", "result"); - - ffecom_char_enhance_arg_ (&type, s); /* Ignore returned length. */ - - type = build_pointer_type (type); - result = build_decl (PARM_DECL, result, type); - - push_parm_decl (result); - } - else - result = NULL_TREE; /* Not ref'd if !charfunc. */ - - ffecom_push_dummy_decls_ (ffesymbol_dummyargs (s), TRUE); - - store_parm_decls (0); - - ffecom_start_compstmt (); - - if (expr != NULL) - { - if (charfunc) - { - ffetargetCharacterSize sz = ffesymbol_size (s); - tree result_length; - - result_length = build_int_2 (sz, 0); - TREE_TYPE (result_length) = ffecom_f2c_ftnlen_type_node; - - ffecom_prepare_let_char_ (sz, expr); - - ffecom_prepare_end (); - - ffecom_let_char_ (result, result_length, sz, expr); - expand_null_return (); - } - else - { - ffecom_prepare_expr (expr); - - ffecom_prepare_end (); - - expand_return (ffecom_modify (NULL_TREE, - DECL_RESULT (current_function_decl), - ffecom_expr (expr))); - } - } - - ffecom_end_compstmt (); - - func = current_function_decl; - finish_function (1); - - pop_f_function_context (); - - recurse = FALSE; - - lineno = old_lineno; - input_filename = old_input_filename; - - ffecom_nested_entry_ = NULL; - - return func; -} - -static const char * -ffecom_gfrt_args_ (ffecomGfrt ix) -{ - return ffecom_gfrt_argstring_[ix]; -} - -static tree -ffecom_gfrt_tree_ (ffecomGfrt ix) -{ - if (ffecom_gfrt_[ix] == NULL_TREE) - ffecom_make_gfrt_ (ix); - - return ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (ffecom_gfrt_[ix])), - ffecom_gfrt_[ix]); -} - -/* Return initialize-to-zero expression for this VAR_DECL. */ - -/* A somewhat evil way to prevent the garbage collector - from collecting 'tree' structures. */ -#define NUM_TRACKED_CHUNK 63 -static struct tree_ggc_tracker -{ - struct tree_ggc_tracker *next; - tree trees[NUM_TRACKED_CHUNK]; -} *tracker_head = NULL; - -static void -mark_tracker_head (void *arg) -{ - struct tree_ggc_tracker *head; - int i; - - for (head = * (struct tree_ggc_tracker **) arg; - head != NULL; - head = head->next) - { - ggc_mark (head); - for (i = 0; i < NUM_TRACKED_CHUNK; i++) - ggc_mark_tree (head->trees[i]); - } -} - -void -ffecom_save_tree_forever (tree t) -{ - int i; - if (tracker_head != NULL) - for (i = 0; i < NUM_TRACKED_CHUNK; i++) - if (tracker_head->trees[i] == NULL) - { - tracker_head->trees[i] = t; - return; - } - - { - /* Need to allocate a new block. */ - struct tree_ggc_tracker *old_head = tracker_head; - - tracker_head = ggc_alloc (sizeof (*tracker_head)); - tracker_head->next = old_head; - tracker_head->trees[0] = t; - for (i = 1; i < NUM_TRACKED_CHUNK; i++) - tracker_head->trees[i] = NULL; - } -} - -static tree -ffecom_init_zero_ (tree decl) -{ - tree init; - int incremental = TREE_STATIC (decl); - tree type = TREE_TYPE (decl); - - if (incremental) - { - make_decl_rtl (decl, NULL); - assemble_variable (decl, TREE_PUBLIC (decl) ? 1 : 0, 0, 1); - } - - if ((TREE_CODE (type) != ARRAY_TYPE) - && (TREE_CODE (type) != RECORD_TYPE) - && (TREE_CODE (type) != UNION_TYPE) - && !incremental) - init = convert (type, integer_zero_node); - else if (!incremental) - { - init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); - TREE_CONSTANT (init) = 1; - TREE_STATIC (init) = 1; - } - else - { - assemble_zeros (int_size_in_bytes (type)); - init = error_mark_node; - } - - return init; -} - -static tree -ffecom_intrinsic_ichar_ (tree tree_type, ffebld arg, - tree *maybe_tree) -{ - tree expr_tree; - tree length_tree; - - switch (ffebld_op (arg)) - { - case FFEBLD_opCONTER: /* For F90, check 0-length. */ - if (ffetarget_length_character1 - (ffebld_constant_character1 - (ffebld_conter (arg))) == 0) - { - *maybe_tree = integer_zero_node; - return convert (tree_type, integer_zero_node); - } - - *maybe_tree = integer_one_node; - expr_tree = build_int_2 (*ffetarget_text_character1 - (ffebld_constant_character1 - (ffebld_conter (arg))), - 0); - TREE_TYPE (expr_tree) = tree_type; - return expr_tree; - - case FFEBLD_opSYMTER: - case FFEBLD_opARRAYREF: - case FFEBLD_opFUNCREF: - case FFEBLD_opSUBSTR: - ffecom_char_args_ (&expr_tree, &length_tree, arg); - - if ((expr_tree == error_mark_node) - || (length_tree == error_mark_node)) - { - *maybe_tree = error_mark_node; - return error_mark_node; - } - - if (integer_zerop (length_tree)) - { - *maybe_tree = integer_zero_node; - return convert (tree_type, integer_zero_node); - } - - expr_tree - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))), - expr_tree); - expr_tree - = ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))), - expr_tree, - integer_one_node); - expr_tree = convert (tree_type, expr_tree); - - if (TREE_CODE (length_tree) == INTEGER_CST) - *maybe_tree = integer_one_node; - else /* Must check length at run time. */ - *maybe_tree - = ffecom_truth_value - (ffecom_2 (GT_EXPR, integer_type_node, - length_tree, - ffecom_f2c_ftnlen_zero_node)); - return expr_tree; - - case FFEBLD_opPAREN: - case FFEBLD_opCONVERT: - if (ffeinfo_size (ffebld_info (arg)) == 0) - { - *maybe_tree = integer_zero_node; - return convert (tree_type, integer_zero_node); - } - return ffecom_intrinsic_ichar_ (tree_type, ffebld_left (arg), - maybe_tree); - - case FFEBLD_opCONCATENATE: - { - tree maybe_left; - tree maybe_right; - tree expr_left; - tree expr_right; - - expr_left = ffecom_intrinsic_ichar_ (tree_type, ffebld_left (arg), - &maybe_left); - expr_right = ffecom_intrinsic_ichar_ (tree_type, ffebld_right (arg), - &maybe_right); - *maybe_tree = ffecom_2 (TRUTH_ORIF_EXPR, integer_type_node, - maybe_left, - maybe_right); - expr_tree = ffecom_3 (COND_EXPR, tree_type, - maybe_left, - expr_left, - expr_right); - return expr_tree; - } - - default: - assert ("bad op in ICHAR" == NULL); - return error_mark_node; - } -} - -/* ffecom_intrinsic_len_ -- Return length info for char arg (LEN()) - - tree length_arg; - ffebld expr; - length_arg = ffecom_intrinsic_len_ (expr); - - Handles CHARACTER-type CONTER, SYMTER, SUBSTR, ARRAYREF, and FUNCREF - subexpressions by constructing the appropriate tree for the - length-of-character-text argument in a calling sequence. */ - -static tree -ffecom_intrinsic_len_ (ffebld expr) -{ - ffetargetCharacter1 val; - tree length; - - switch (ffebld_op (expr)) - { - case FFEBLD_opCONTER: - val = ffebld_constant_character1 (ffebld_conter (expr)); - length = build_int_2 (ffetarget_length_character1 (val), 0); - TREE_TYPE (length) = ffecom_f2c_ftnlen_type_node; - break; - - case FFEBLD_opSYMTER: - { - ffesymbol s = ffebld_symter (expr); - tree item; - - item = ffesymbol_hook (s).decl_tree; - if (item == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - item = ffesymbol_hook (s).decl_tree; - } - if (ffesymbol_kind (s) == FFEINFO_kindENTITY) - { - if (ffesymbol_size (s) == FFETARGET_charactersizeNONE) - length = ffesymbol_hook (s).length_tree; - else - { - length = build_int_2 (ffesymbol_size (s), 0); - TREE_TYPE (length) = ffecom_f2c_ftnlen_type_node; - } - } - else if (item == error_mark_node) - length = error_mark_node; - else /* FFEINFO_kindFUNCTION: */ - length = NULL_TREE; - } - break; - - case FFEBLD_opARRAYREF: - length = ffecom_intrinsic_len_ (ffebld_left (expr)); - break; - - case FFEBLD_opSUBSTR: - { - ffebld start; - ffebld end; - ffebld thing = ffebld_right (expr); - tree start_tree; - tree end_tree; - - assert (ffebld_op (thing) == FFEBLD_opITEM); - start = ffebld_head (thing); - thing = ffebld_trail (thing); - assert (ffebld_trail (thing) == NULL); - end = ffebld_head (thing); - - length = ffecom_intrinsic_len_ (ffebld_left (expr)); - - if (length == error_mark_node) - break; - - if (start == NULL) - { - if (end == NULL) - ; - else - { - length = convert (ffecom_f2c_ftnlen_type_node, - ffecom_expr (end)); - } - } - else - { - start_tree = convert (ffecom_f2c_ftnlen_type_node, - ffecom_expr (start)); - - if (start_tree == error_mark_node) - { - length = error_mark_node; - break; - } - - if (end == NULL) - { - length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - ffecom_2 (MINUS_EXPR, - ffecom_f2c_ftnlen_type_node, - length, - start_tree)); - } - else - { - end_tree = convert (ffecom_f2c_ftnlen_type_node, - ffecom_expr (end)); - - if (end_tree == error_mark_node) - { - length = error_mark_node; - break; - } - - length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - ffecom_2 (MINUS_EXPR, - ffecom_f2c_ftnlen_type_node, - end_tree, start_tree)); - } - } - } - break; - - case FFEBLD_opCONCATENATE: - length - = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - ffecom_intrinsic_len_ (ffebld_left (expr)), - ffecom_intrinsic_len_ (ffebld_right (expr))); - break; - - case FFEBLD_opFUNCREF: - case FFEBLD_opCONVERT: - length = build_int_2 (ffebld_size (expr), 0); - TREE_TYPE (length) = ffecom_f2c_ftnlen_type_node; - break; - - default: - assert ("bad op for single char arg expr" == NULL); - length = ffecom_f2c_ftnlen_zero_node; - break; - } - - assert (length != NULL_TREE); - - return length; -} - -/* Handle CHARACTER assignments. - - Generates code to do the assignment. Used by ordinary assignment - statement handler ffecom_let_stmt and by statement-function - handler to generate code for a statement function. */ - -static void -ffecom_let_char_ (tree dest_tree, tree dest_length, - ffetargetCharacterSize dest_size, ffebld source) -{ - ffecomConcatList_ catlist; - tree source_length; - tree source_tree; - tree expr_tree; - - if ((dest_tree == error_mark_node) - || (dest_length == error_mark_node)) - return; - - assert (dest_tree != NULL_TREE); - assert (dest_length != NULL_TREE); - - /* Source might be an opCONVERT, which just means it is a different size - than the destination. Since the underlying implementation here handles - that (directly or via the s_copy or s_cat run-time-library functions), - we don't need the "convenience" of an opCONVERT that tells us to - truncate or blank-pad, particularly since the resulting implementation - would probably be slower than otherwise. */ - - while (ffebld_op (source) == FFEBLD_opCONVERT) - source = ffebld_left (source); - - catlist = ffecom_concat_list_new_ (source, dest_size); - switch (ffecom_concat_list_count_ (catlist)) - { - case 0: /* Shouldn't happen, but in case it does... */ - ffecom_concat_list_kill_ (catlist); - source_tree = null_pointer_node; - source_length = ffecom_f2c_ftnlen_zero_node; - expr_tree = build_tree_list (NULL_TREE, dest_tree); - TREE_CHAIN (expr_tree) = build_tree_list (NULL_TREE, source_tree); - TREE_CHAIN (TREE_CHAIN (expr_tree)) - = build_tree_list (NULL_TREE, dest_length); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree))) - = build_tree_list (NULL_TREE, source_length); - - expr_tree = ffecom_call_gfrt (FFECOM_gfrtCOPY, expr_tree, NULL_TREE); - TREE_SIDE_EFFECTS (expr_tree) = 1; - - expand_expr_stmt (expr_tree); - - return; - - case 1: /* The (fairly) easy case. */ - ffecom_char_args_ (&source_tree, &source_length, - ffecom_concat_list_expr_ (catlist, 0)); - ffecom_concat_list_kill_ (catlist); - assert (source_tree != NULL_TREE); - assert (source_length != NULL_TREE); - - if ((source_tree == error_mark_node) - || (source_length == error_mark_node)) - return; - - if (dest_size == 1) - { - dest_tree - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE - (dest_tree))), - dest_tree); - dest_tree - = ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE - (dest_tree))), - dest_tree, - integer_one_node); - source_tree - = ffecom_1 (INDIRECT_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE - (source_tree))), - source_tree); - source_tree - = ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE - (source_tree))), - source_tree, - integer_one_node); - - expr_tree = ffecom_modify (void_type_node, dest_tree, source_tree); - - expand_expr_stmt (expr_tree); - - return; - } - - expr_tree = build_tree_list (NULL_TREE, dest_tree); - TREE_CHAIN (expr_tree) = build_tree_list (NULL_TREE, source_tree); - TREE_CHAIN (TREE_CHAIN (expr_tree)) - = build_tree_list (NULL_TREE, dest_length); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree))) - = build_tree_list (NULL_TREE, source_length); - - expr_tree = ffecom_call_gfrt (FFECOM_gfrtCOPY, expr_tree, NULL_TREE); - TREE_SIDE_EFFECTS (expr_tree) = 1; - - expand_expr_stmt (expr_tree); - - return; - - default: /* Must actually concatenate things. */ - break; - } - - /* Heavy-duty concatenation. */ - - { - int count = ffecom_concat_list_count_ (catlist); - int i; - tree lengths; - tree items; - tree length_array; - tree item_array; - tree citem; - tree clength; - -#ifdef HOHO - length_array - = lengths - = ffecom_push_tempvar (ffecom_f2c_ftnlen_type_node, - FFETARGET_charactersizeNONE, count, TRUE); - item_array = items = ffecom_push_tempvar (ffecom_f2c_address_type_node, - FFETARGET_charactersizeNONE, - count, TRUE); -#else - { - tree hook; - - hook = ffebld_nonter_hook (source); - assert (hook); - assert (TREE_CODE (hook) == TREE_VEC); - assert (TREE_VEC_LENGTH (hook) == 2); - length_array = lengths = TREE_VEC_ELT (hook, 0); - item_array = items = TREE_VEC_ELT (hook, 1); - } -#endif - - for (i = 0; i < count; ++i) - { - ffecom_char_args_ (&citem, &clength, - ffecom_concat_list_expr_ (catlist, i)); - if ((citem == error_mark_node) - || (clength == error_mark_node)) - { - ffecom_concat_list_kill_ (catlist); - return; - } - - items - = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (items), - ffecom_modify (void_type_node, - ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item_array))), - item_array, - build_int_2 (i, 0)), - citem), - items); - lengths - = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (lengths), - ffecom_modify (void_type_node, - ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (length_array))), - length_array, - build_int_2 (i, 0)), - clength), - lengths); - } - - expr_tree = build_tree_list (NULL_TREE, dest_tree); - TREE_CHAIN (expr_tree) - = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (items)), - items)); - TREE_CHAIN (TREE_CHAIN (expr_tree)) - = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (lengths)), - lengths)); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree))) - = build_tree_list - (NULL_TREE, - ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node, - convert (ffecom_f2c_ftnlen_type_node, - build_int_2 (count, 0)))); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree)))) - = build_tree_list (NULL_TREE, dest_length); - - expr_tree = ffecom_call_gfrt (FFECOM_gfrtCAT, expr_tree, NULL_TREE); - TREE_SIDE_EFFECTS (expr_tree) = 1; - - expand_expr_stmt (expr_tree); - } - - ffecom_concat_list_kill_ (catlist); -} - -/* ffecom_make_gfrt_ -- Make initial info for run-time routine - - ffecomGfrt ix; - ffecom_make_gfrt_(ix); - - Assumes gfrt_[ix] is NULL_TREE, and replaces it with the FUNCTION_DECL - for the indicated run-time routine (ix). */ - -static void -ffecom_make_gfrt_ (ffecomGfrt ix) -{ - tree t; - tree ttype; - - switch (ffecom_gfrt_type_[ix]) - { - case FFECOM_rttypeVOID_: - ttype = void_type_node; - break; - - case FFECOM_rttypeVOIDSTAR_: - ttype = TREE_TYPE (null_pointer_node); /* `void *'. */ - break; - - case FFECOM_rttypeFTNINT_: - ttype = ffecom_f2c_ftnint_type_node; - break; - - case FFECOM_rttypeINTEGER_: - ttype = ffecom_f2c_integer_type_node; - break; - - case FFECOM_rttypeLONGINT_: - ttype = ffecom_f2c_longint_type_node; - break; - - case FFECOM_rttypeLOGICAL_: - ttype = ffecom_f2c_logical_type_node; - break; - - case FFECOM_rttypeREAL_F2C_: - ttype = double_type_node; - break; - - case FFECOM_rttypeREAL_GNU_: - ttype = float_type_node; - break; - - case FFECOM_rttypeCOMPLEX_F2C_: - ttype = void_type_node; - break; - - case FFECOM_rttypeCOMPLEX_GNU_: - ttype = ffecom_f2c_complex_type_node; - break; - - case FFECOM_rttypeDOUBLE_: - ttype = double_type_node; - break; - - case FFECOM_rttypeDOUBLEREAL_: - ttype = ffecom_f2c_doublereal_type_node; - break; - - case FFECOM_rttypeDBLCMPLX_F2C_: - ttype = void_type_node; - break; - - case FFECOM_rttypeDBLCMPLX_GNU_: - ttype = ffecom_f2c_doublecomplex_type_node; - break; - - case FFECOM_rttypeCHARACTER_: - ttype = void_type_node; - break; - - default: - ttype = NULL; - assert ("bad rttype" == NULL); - break; - } - - ttype = build_function_type (ttype, NULL_TREE); - t = build_decl (FUNCTION_DECL, - get_identifier (ffecom_gfrt_name_[ix]), - ttype); - DECL_EXTERNAL (t) = 1; - TREE_READONLY (t) = ffecom_gfrt_const_[ix] ? 1 : 0; - TREE_PUBLIC (t) = 1; - TREE_THIS_VOLATILE (t) = ffecom_gfrt_volatile_[ix] ? 1 : 0; - - /* Sanity check: A function that's const cannot be volatile. */ - - assert (ffecom_gfrt_const_[ix] ? !ffecom_gfrt_volatile_[ix] : 1); - - /* Sanity check: A function that's const cannot return complex. */ - - assert (ffecom_gfrt_const_[ix] ? !ffecom_gfrt_complex_[ix] : 1); - - t = start_decl (t, TRUE); - - finish_decl (t, NULL_TREE, TRUE); - - ffecom_gfrt_[ix] = t; -} - -/* Phase 1 pass over each member of a COMMON/EQUIVALENCE group. */ - -static void -ffecom_member_phase1_ (ffestorag mst UNUSED, ffestorag st) -{ - ffesymbol s = ffestorag_symbol (st); - - if (ffesymbol_namelisted (s)) - ffecom_member_namelisted_ = TRUE; -} - -/* Phase 2 pass over each member of a COMMON/EQUIVALENCE group. Declare - the member so debugger will see it. Otherwise nobody should be - referencing the member. */ - -static void -ffecom_member_phase2_ (ffestorag mst, ffestorag st) -{ - ffesymbol s; - tree t; - tree mt; - tree type; - - if ((mst == NULL) - || ((mt = ffestorag_hook (mst)) == NULL) - || (mt == error_mark_node)) - return; - - if ((st == NULL) - || ((s = ffestorag_symbol (st)) == NULL)) - return; - - type = ffecom_type_localvar_ (s, - ffesymbol_basictype (s), - ffesymbol_kindtype (s)); - if (type == error_mark_node) - return; - - t = build_decl (VAR_DECL, - ffecom_get_identifier_ (ffesymbol_text (s)), - type); - - TREE_STATIC (t) = TREE_STATIC (mt); - DECL_INITIAL (t) = NULL_TREE; - TREE_ASM_WRITTEN (t) = 1; - TREE_USED (t) = 1; - - SET_DECL_RTL (t, - gen_rtx (MEM, TYPE_MODE (type), - plus_constant (XEXP (DECL_RTL (mt), 0), - ffestorag_modulo (mst) - + ffestorag_offset (st) - - ffestorag_offset (mst)))); - - t = start_decl (t, FALSE); - - finish_decl (t, NULL_TREE, FALSE); -} - -/* Prepare source expression for assignment into a destination perhaps known - to be of a specific size. */ - -static void -ffecom_prepare_let_char_ (ffetargetCharacterSize dest_size, ffebld source) -{ - ffecomConcatList_ catlist; - int count; - int i; - tree ltmp; - tree itmp; - tree tempvar = NULL_TREE; - - while (ffebld_op (source) == FFEBLD_opCONVERT) - source = ffebld_left (source); - - catlist = ffecom_concat_list_new_ (source, dest_size); - count = ffecom_concat_list_count_ (catlist); - - if (count >= 2) - { - ltmp - = ffecom_make_tempvar ("let_char_len", ffecom_f2c_ftnlen_type_node, - FFETARGET_charactersizeNONE, count); - itmp - = ffecom_make_tempvar ("let_char_item", ffecom_f2c_address_type_node, - FFETARGET_charactersizeNONE, count); - - tempvar = make_tree_vec (2); - TREE_VEC_ELT (tempvar, 0) = ltmp; - TREE_VEC_ELT (tempvar, 1) = itmp; - } - - for (i = 0; i < count; ++i) - ffecom_prepare_arg_ptr_to_expr (ffecom_concat_list_expr_ (catlist, i)); - - ffecom_concat_list_kill_ (catlist); - - if (tempvar) - { - ffebld_nonter_set_hook (source, tempvar); - current_binding_level->prep_state = 1; - } -} - -/* ffecom_push_dummy_decls_ -- Transform dummy args, push parm decls in order - - Ignores STAR (alternate-return) dummies. All other get exec-transitioned - (which generates their trees) and then their trees get push_parm_decl'd. - - The second arg is TRUE if the dummies are for a statement function, in - which case lengths are not pushed for character arguments (since they are - always known by both the caller and the callee, though the code allows - for someday permitting CHAR*(*) stmtfunc dummies). */ - -static void -ffecom_push_dummy_decls_ (ffebld dummy_list, bool stmtfunc) -{ - ffebld dummy; - ffebld dumlist; - ffesymbol s; - tree parm; - - ffecom_transform_only_dummies_ = TRUE; - - /* First push the parms corresponding to actual dummy "contents". */ - - for (dumlist = dummy_list; dumlist != NULL; dumlist = ffebld_trail (dumlist)) - { - dummy = ffebld_head (dumlist); - switch (ffebld_op (dummy)) - { - case FFEBLD_opSTAR: - case FFEBLD_opANY: - continue; /* Forget alternate returns. */ - - default: - break; - } - assert (ffebld_op (dummy) == FFEBLD_opSYMTER); - s = ffebld_symter (dummy); - parm = ffesymbol_hook (s).decl_tree; - if (parm == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - parm = ffesymbol_hook (s).decl_tree; - assert (parm != NULL_TREE); - } - if (parm != error_mark_node) - push_parm_decl (parm); - } - - /* Then, for CHARACTER dummies, push the parms giving their lengths. */ - - for (dumlist = dummy_list; dumlist != NULL; dumlist = ffebld_trail (dumlist)) - { - dummy = ffebld_head (dumlist); - switch (ffebld_op (dummy)) - { - case FFEBLD_opSTAR: - case FFEBLD_opANY: - continue; /* Forget alternate returns, they mean - NOTHING! */ - - default: - break; - } - s = ffebld_symter (dummy); - if (ffesymbol_basictype (s) != FFEINFO_basictypeCHARACTER) - continue; /* Only looking for CHARACTER arguments. */ - if (stmtfunc && (ffesymbol_size (s) != FFETARGET_charactersizeNONE)) - continue; /* Stmtfunc arg with known size needs no - length param. */ - if (ffesymbol_kind (s) != FFEINFO_kindENTITY) - continue; /* Only looking for variables and arrays. */ - parm = ffesymbol_hook (s).length_tree; - assert (parm != NULL_TREE); - if (parm != error_mark_node) - push_parm_decl (parm); - } - - ffecom_transform_only_dummies_ = FALSE; -} - -/* ffecom_start_progunit_ -- Beginning of program unit - - Does GNU back end stuff necessary to teach it about the start of its - equivalent of a Fortran program unit. */ - -static void -ffecom_start_progunit_ () -{ - ffesymbol fn = ffecom_primary_entry_; - ffebld arglist; - tree id; /* Identifier (name) of function. */ - tree type; /* Type of function. */ - tree result; /* Result of function. */ - ffeinfoBasictype bt; - ffeinfoKindtype kt; - ffeglobal g; - ffeglobalType gt; - ffeglobalType egt = FFEGLOBAL_type; - bool charfunc; - bool cmplxfunc; - bool altentries = (ffecom_num_entrypoints_ != 0); - bool multi - = altentries - && (ffecom_primary_entry_kind_ == FFEINFO_kindFUNCTION) - && (ffecom_master_bt_ == FFEINFO_basictypeNONE); - bool main_program = FALSE; - int old_lineno = lineno; - const char *old_input_filename = input_filename; - - assert (fn != NULL); - assert (ffesymbol_hook (fn).decl_tree == NULL_TREE); - - input_filename = ffesymbol_where_filename (fn); - lineno = ffesymbol_where_filelinenum (fn); - - switch (ffecom_primary_entry_kind_) - { - case FFEINFO_kindPROGRAM: - main_program = TRUE; - gt = FFEGLOBAL_typeMAIN; - bt = FFEINFO_basictypeNONE; - kt = FFEINFO_kindtypeNONE; - type = ffecom_tree_fun_type_void; - charfunc = FALSE; - cmplxfunc = FALSE; - break; - - case FFEINFO_kindBLOCKDATA: - gt = FFEGLOBAL_typeBDATA; - bt = FFEINFO_basictypeNONE; - kt = FFEINFO_kindtypeNONE; - type = ffecom_tree_fun_type_void; - charfunc = FALSE; - cmplxfunc = FALSE; - break; - - case FFEINFO_kindFUNCTION: - gt = FFEGLOBAL_typeFUNC; - egt = FFEGLOBAL_typeEXT; - bt = ffesymbol_basictype (fn); - kt = ffesymbol_kindtype (fn); - if (bt == FFEINFO_basictypeNONE) - { - ffeimplic_establish_symbol (fn); - if (ffesymbol_funcresult (fn) != NULL) - ffeimplic_establish_symbol (ffesymbol_funcresult (fn)); - bt = ffesymbol_basictype (fn); - kt = ffesymbol_kindtype (fn); - } - - if (multi) - charfunc = cmplxfunc = FALSE; - else if (bt == FFEINFO_basictypeCHARACTER) - charfunc = TRUE, cmplxfunc = FALSE; - else if ((bt == FFEINFO_basictypeCOMPLEX) - && ffesymbol_is_f2c (fn) - && !altentries) - charfunc = FALSE, cmplxfunc = TRUE; - else - charfunc = cmplxfunc = FALSE; - - if (multi || charfunc) - type = ffecom_tree_fun_type_void; - else if (ffesymbol_is_f2c (fn) && !altentries) - type = ffecom_tree_fun_type[bt][kt]; - else - type = build_function_type (ffecom_tree_type[bt][kt], NULL_TREE); - - if ((type == NULL_TREE) - || (TREE_TYPE (type) == NULL_TREE)) - type = ffecom_tree_fun_type_void; /* _sym_exec_transition. */ - break; - - case FFEINFO_kindSUBROUTINE: - gt = FFEGLOBAL_typeSUBR; - egt = FFEGLOBAL_typeEXT; - bt = FFEINFO_basictypeNONE; - kt = FFEINFO_kindtypeNONE; - if (ffecom_is_altreturning_) - type = ffecom_tree_subr_type; - else - type = ffecom_tree_fun_type_void; - charfunc = FALSE; - cmplxfunc = FALSE; - break; - - default: - assert ("say what??" == NULL); - /* Fall through. */ - case FFEINFO_kindANY: - gt = FFEGLOBAL_typeANY; - bt = FFEINFO_basictypeNONE; - kt = FFEINFO_kindtypeNONE; - type = error_mark_node; - charfunc = FALSE; - cmplxfunc = FALSE; - break; - } - - if (altentries) - { - id = ffecom_get_invented_identifier ("__g77_masterfun_%s", - ffesymbol_text (fn)); - } -#if FFETARGET_isENFORCED_MAIN - else if (main_program) - id = get_identifier (FFETARGET_nameENFORCED_MAIN_NAME); -#endif - else - id = ffecom_get_external_identifier_ (fn); - - start_function (id, - type, - 0, /* nested/inline */ - !altentries); /* TREE_PUBLIC */ - - TREE_USED (current_function_decl) = 1; /* Avoid spurious warning if altentries. */ - - if (!altentries - && ((g = ffesymbol_global (fn)) != NULL) - && ((ffeglobal_type (g) == gt) - || (ffeglobal_type (g) == egt))) - { - ffeglobal_set_hook (g, current_function_decl); - } - - /* Arg handling needs exec-transitioned ffesymbols to work with. But - exec-transitioning needs current_function_decl to be filled in. So we - do these things in two phases. */ - - if (altentries) - { /* 1st arg identifies which entrypoint. */ - ffecom_which_entrypoint_decl_ - = build_decl (PARM_DECL, - ffecom_get_invented_identifier ("__g77_%s", - "which_entrypoint"), - integer_type_node); - push_parm_decl (ffecom_which_entrypoint_decl_); - } - - if (charfunc - || cmplxfunc - || multi) - { /* Arg for result (return value). */ - tree type; - tree length; - - if (charfunc) - type = ffecom_tree_type[FFEINFO_basictypeCHARACTER][kt]; - else if (cmplxfunc) - type = ffecom_tree_type[FFEINFO_basictypeCOMPLEX][kt]; - else - type = ffecom_multi_type_node_; - - result = ffecom_get_invented_identifier ("__g77_%s", "result"); - - /* Make length arg _and_ enhance type info for CHAR arg itself. */ - - if (charfunc) - length = ffecom_char_enhance_arg_ (&type, fn); - else - length = NULL_TREE; /* Not ref'd if !charfunc. */ - - type = build_pointer_type (type); - result = build_decl (PARM_DECL, result, type); - - push_parm_decl (result); - if (multi) - ffecom_multi_retval_ = result; - else - ffecom_func_result_ = result; - - if (charfunc) - { - push_parm_decl (length); - ffecom_func_length_ = length; - } - } - - if (ffecom_primary_entry_is_proc_) - { - if (altentries) - arglist = ffecom_master_arglist_; - else - arglist = ffesymbol_dummyargs (fn); - ffecom_push_dummy_decls_ (arglist, FALSE); - } - - if (TREE_CODE (current_function_decl) != ERROR_MARK) - store_parm_decls (main_program ? 1 : 0); - - ffecom_start_compstmt (); - /* Disallow temp vars at this level. */ - current_binding_level->prep_state = 2; - - lineno = old_lineno; - input_filename = old_input_filename; - - /* This handles any symbols still untransformed, in case -g specified. - This used to be done in ffecom_finish_progunit, but it turns out to - be necessary to do it here so that statement functions are - expanded before code. But don't bother for BLOCK DATA. */ - - if (ffecom_primary_entry_kind_ != FFEINFO_kindBLOCKDATA) - ffesymbol_drive (ffecom_finish_symbol_transform_); -} - -/* ffecom_sym_transform_ -- Transform FFE sym into backend sym - - ffesymbol s; - ffecom_sym_transform_(s); - - The ffesymbol_hook info for s is updated with appropriate backend info - on the symbol. */ - -static ffesymbol -ffecom_sym_transform_ (ffesymbol s) -{ - tree t; /* Transformed thingy. */ - tree tlen; /* Length if CHAR*(*). */ - bool addr; /* Is t the address of the thingy? */ - ffeinfoBasictype bt; - ffeinfoKindtype kt; - ffeglobal g; - int old_lineno = lineno; - const char *old_input_filename = input_filename; - - /* Must ensure special ASSIGN variables are declared at top of outermost - block, else they'll end up in the innermost block when their first - ASSIGN is seen, which leaves them out of scope when they're the - subject of a GOTO or I/O statement. - - We make this variable even if -fugly-assign. Just let it go unused, - in case it turns out there are cases where we really want to use this - variable anyway (e.g. ASSIGN to INTEGER*2 variable). */ - - if (! ffecom_transform_only_dummies_ - && ffesymbol_assigned (s) - && ! ffesymbol_hook (s).assign_tree) - s = ffecom_sym_transform_assign_ (s); - - if (ffesymbol_sfdummyparent (s) == NULL) - { - input_filename = ffesymbol_where_filename (s); - lineno = ffesymbol_where_filelinenum (s); - } - else - { - ffesymbol sf = ffesymbol_sfdummyparent (s); - - input_filename = ffesymbol_where_filename (sf); - lineno = ffesymbol_where_filelinenum (sf); - } - - bt = ffeinfo_basictype (ffebld_info (s)); - kt = ffeinfo_kindtype (ffebld_info (s)); - - t = NULL_TREE; - tlen = NULL_TREE; - addr = FALSE; - - switch (ffesymbol_kind (s)) - { - case FFEINFO_kindNONE: - switch (ffesymbol_where (s)) - { - case FFEINFO_whereDUMMY: /* Subroutine or function. */ - assert (ffecom_transform_only_dummies_); - - /* Before 0.4, this could be ENTITY/DUMMY, but see - ffestu_sym_end_transition -- no longer true (in particular, if - it could be an ENTITY, it _will_ be made one, so that - possibility won't come through here). So we never make length - arg for CHARACTER type. */ - - t = build_decl (PARM_DECL, - ffecom_get_identifier_ (ffesymbol_text (s)), - ffecom_tree_ptr_to_subr_type); - DECL_ARTIFICIAL (t) = 1; - addr = TRUE; - break; - - case FFEINFO_whereGLOBAL: /* Subroutine or function. */ - assert (!ffecom_transform_only_dummies_); - - if (((g = ffesymbol_global (s)) != NULL) - && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR) - || (ffeglobal_type (g) == FFEGLOBAL_typeFUNC) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)) - && (ffeglobal_hook (g) != NULL_TREE) - && ffe_is_globals ()) - { - t = ffeglobal_hook (g); - break; - } - - t = build_decl (FUNCTION_DECL, - ffecom_get_external_identifier_ (s), - ffecom_tree_subr_type); /* Assume subr. */ - DECL_EXTERNAL (t) = 1; - TREE_PUBLIC (t) = 1; - - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - if ((g != NULL) - && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR) - || (ffeglobal_type (g) == FFEGLOBAL_typeFUNC) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))) - ffeglobal_set_hook (g, t); - - ffecom_save_tree_forever (t); - - break; - - default: - assert ("NONE where unexpected" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - break; - } - break; - - case FFEINFO_kindENTITY: - switch (ffeinfo_where (ffesymbol_info (s))) - { - - case FFEINFO_whereCONSTANT: - /* ~~Debugging info needed? */ - assert (!ffecom_transform_only_dummies_); - t = error_mark_node; /* Shouldn't ever see this in expr. */ - break; - - case FFEINFO_whereLOCAL: - assert (!ffecom_transform_only_dummies_); - - { - ffestorag st = ffesymbol_storage (s); - tree type; - - if ((st != NULL) - && (ffestorag_size (st) == 0)) - { - t = error_mark_node; - break; - } - - type = ffecom_type_localvar_ (s, bt, kt); - - if (type == error_mark_node) - { - t = error_mark_node; - break; - } - - if ((st != NULL) - && (ffestorag_parent (st) != NULL)) - { /* Child of EQUIVALENCE parent. */ - ffestorag est; - tree et; - ffetargetOffset offset; - - est = ffestorag_parent (st); - ffecom_transform_equiv_ (est); - - et = ffestorag_hook (est); - assert (et != NULL_TREE); - - if (! TREE_STATIC (et)) - put_var_into_stack (et); - - offset = ffestorag_modulo (est) - + ffestorag_offset (ffesymbol_storage (s)) - - ffestorag_offset (est); - - ffecom_debug_kludge_ (et, "EQUIVALENCE", s, type, offset); - - /* (t_type *) (((char *) &et) + offset) */ - - t = convert (string_type_node, /* (char *) */ - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (et)), - et)); - t = ffecom_2 (PLUS_EXPR, TREE_TYPE (t), - t, - build_int_2 (offset, 0)); - t = convert (build_pointer_type (type), - t); - TREE_CONSTANT (t) = staticp (et); - - addr = TRUE; - } - else - { - tree initexpr; - bool init = ffesymbol_is_init (s); - - t = build_decl (VAR_DECL, - ffecom_get_identifier_ (ffesymbol_text (s)), - type); - - if (init - || ffesymbol_namelisted (s) -#ifdef FFECOM_sizeMAXSTACKITEM - || ((st != NULL) - && (ffestorag_size (st) > FFECOM_sizeMAXSTACKITEM)) -#endif - || ((ffecom_primary_entry_kind_ != FFEINFO_kindPROGRAM) - && (ffecom_primary_entry_kind_ - != FFEINFO_kindBLOCKDATA) - && (ffesymbol_is_save (s) || ffe_is_saveall ()))) - TREE_STATIC (t) = !ffesymbol_attr (s, FFESYMBOL_attrADJUSTABLE); - else - TREE_STATIC (t) = 0; /* No need to make static. */ - - if (init || ffe_is_init_local_zero ()) - DECL_INITIAL (t) = error_mark_node; - - /* Keep -Wunused from complaining about var if it - is used as sfunc arg or DATA implied-DO. */ - if (ffesymbol_attrs (s) & FFESYMBOL_attrsSFARG) - DECL_IN_SYSTEM_HEADER (t) = 1; - - t = start_decl (t, FALSE); - - if (init) - { - if (ffesymbol_init (s) != NULL) - initexpr = ffecom_expr (ffesymbol_init (s)); - else - initexpr = ffecom_init_zero_ (t); - } - else if (ffe_is_init_local_zero ()) - initexpr = ffecom_init_zero_ (t); - else - initexpr = NULL_TREE; /* Not ref'd if !init. */ - - finish_decl (t, initexpr, FALSE); - - if (st != NULL && DECL_SIZE (t) != error_mark_node) - { - assert (TREE_CODE (DECL_SIZE_UNIT (t)) == INTEGER_CST); - assert (0 == compare_tree_int (DECL_SIZE_UNIT (t), - ffestorag_size (st))); - } - } - } - break; - - case FFEINFO_whereRESULT: - assert (!ffecom_transform_only_dummies_); - - if (bt == FFEINFO_basictypeCHARACTER) - { /* Result is already in list of dummies, use - it (& length). */ - t = ffecom_func_result_; - tlen = ffecom_func_length_; - addr = TRUE; - break; - } - if ((ffecom_num_entrypoints_ == 0) - && (bt == FFEINFO_basictypeCOMPLEX) - && (ffesymbol_is_f2c (ffecom_primary_entry_))) - { /* Result is already in list of dummies, use - it. */ - t = ffecom_func_result_; - addr = TRUE; - break; - } - if (ffecom_func_result_ != NULL_TREE) - { - t = ffecom_func_result_; - break; - } - if ((ffecom_num_entrypoints_ != 0) - && (ffecom_master_bt_ == FFEINFO_basictypeNONE)) - { - assert (ffecom_multi_retval_ != NULL_TREE); - t = ffecom_1 (INDIRECT_REF, ffecom_multi_type_node_, - ffecom_multi_retval_); - t = ffecom_2 (COMPONENT_REF, ffecom_tree_type[bt][kt], - t, ffecom_multi_fields_[bt][kt]); - - break; - } - - t = build_decl (VAR_DECL, - ffecom_get_identifier_ (ffesymbol_text (s)), - ffecom_tree_type[bt][kt]); - TREE_STATIC (t) = 0; /* Put result on stack. */ - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - ffecom_func_result_ = t; - - break; - - case FFEINFO_whereDUMMY: - { - tree type; - ffebld dl; - ffebld dim; - tree low; - tree high; - tree old_sizes; - bool adjustable = FALSE; /* Conditionally adjustable? */ - - type = ffecom_tree_type[bt][kt]; - if (ffesymbol_sfdummyparent (s) != NULL) - { - if (current_function_decl == ffecom_outer_function_decl_) - { /* Exec transition before sfunc - context; get it later. */ - break; - } - t = ffecom_get_identifier_ (ffesymbol_text - (ffesymbol_sfdummyparent (s))); - } - else - t = ffecom_get_identifier_ (ffesymbol_text (s)); - - assert (ffecom_transform_only_dummies_); - - old_sizes = get_pending_sizes (); - put_pending_sizes (old_sizes); - - if (bt == FFEINFO_basictypeCHARACTER) - tlen = ffecom_char_enhance_arg_ (&type, s); - type = ffecom_check_size_overflow_ (s, type, TRUE); - - for (dl = ffesymbol_dims (s); dl != NULL; dl = ffebld_trail (dl)) - { - if (type == error_mark_node) - break; - - dim = ffebld_head (dl); - assert (ffebld_op (dim) == FFEBLD_opBOUNDS); - if ((ffebld_left (dim) == NULL) || ffecom_doing_entry_) - low = ffecom_integer_one_node; - else - low = ffecom_expr (ffebld_left (dim)); - assert (ffebld_right (dim) != NULL); - if ((ffebld_op (ffebld_right (dim)) == FFEBLD_opSTAR) - || ffecom_doing_entry_) - { - /* Used to just do high=low. But for ffecom_tree_ - canonize_ref_, it probably is important to correctly - assess the size. E.g. given COMPLEX C(*),CFUNC and - C(2)=CFUNC(C), overlap can happen, while it can't - for, say, C(1)=CFUNC(C(2)). */ - /* Even more recently used to set to INT_MAX, but that - broke when some overflow checking went into the back - end. Now we just leave the upper bound unspecified. */ - high = NULL; - } - else - high = ffecom_expr (ffebld_right (dim)); - - /* Determine whether array is conditionally adjustable, - to decide whether back-end magic is needed. - - Normally the front end uses the back-end function - variable_size to wrap SAVE_EXPR's around expressions - affecting the size/shape of an array so that the - size/shape info doesn't change during execution - of the compiled code even though variables and - functions referenced in those expressions might. - - variable_size also makes sure those saved expressions - get evaluated immediately upon entry to the - compiled procedure -- the front end normally doesn't - have to worry about that. - - However, there is a problem with this that affects - g77's implementation of entry points, and that is - that it is _not_ true that each invocation of the - compiled procedure is permitted to evaluate - array size/shape info -- because it is possible - that, for some invocations, that info is invalid (in - which case it is "promised" -- i.e. a violation of - the Fortran standard -- that the compiled code - won't reference the array or its size/shape - during that particular invocation). - - To phrase this in C terms, consider this gcc function: - - void foo (int *n, float (*a)[*n]) - { - // a is "pointer to array ...", fyi. - } - - Suppose that, for some invocations, it is permitted - for a caller of foo to do this: - - foo (NULL, NULL); - - Now the _written_ code for foo can take such a call - into account by either testing explicitly for whether - (a == NULL) || (n == NULL) -- presumably it is - not permitted to reference *a in various fashions - if (n == NULL) I suppose -- or it can avoid it by - looking at other info (other arguments, static/global - data, etc.). - - However, this won't work in gcc 2.5.8 because it'll - automatically emit the code to save the "*n" - expression, which'll yield a NULL dereference for - the "foo (NULL, NULL)" call, something the code - for foo cannot prevent. - - g77 definitely needs to avoid executing such - code anytime the pointer to the adjustable array - is NULL, because even if its bounds expressions - don't have any references to possible "absent" - variables like "*n" -- say all variable references - are to COMMON variables, i.e. global (though in C, - local static could actually make sense) -- the - expressions could yield other run-time problems - for allowably "dead" values in those variables. - - For example, let's consider a more complicated - version of foo: - - extern int i; - extern int j; - - void foo (float (*a)[i/j]) - { - ... - } - - The above is (essentially) quite valid for Fortran - but, again, for a call like "foo (NULL);", it is - permitted for i and j to be undefined when the - call is made. If j happened to be zero, for - example, emitting the code to evaluate "i/j" - could result in a run-time error. - - Offhand, though I don't have my F77 or F90 - standards handy, it might even be valid for a - bounds expression to contain a function reference, - in which case I doubt it is permitted for an - implementation to invoke that function in the - Fortran case involved here (invocation of an - alternate ENTRY point that doesn't have the adjustable - array as one of its arguments). - - So, the code that the compiler would normally emit - to preevaluate the size/shape info for an - adjustable array _must not_ be executed at run time - in certain cases. Specifically, for Fortran, - the case is when the pointer to the adjustable - array == NULL. (For gnu-ish C, it might be nice - for the source code itself to specify an expression - that, if TRUE, inhibits execution of the code. Or - reverse the sense for elegance.) - - (Note that g77 could use a different test than NULL, - actually, since it happens to always pass an - integer to the called function that specifies which - entry point is being invoked. Hmm, this might - solve the next problem.) - - One way a user could, I suppose, write "foo" so - it works is to insert COND_EXPR's for the - size/shape info so the dangerous stuff isn't - actually done, as in: - - void foo (int *n, float (*a)[(a == NULL) ? 0 : *n]) - { - ... - } - - The next problem is that the front end needs to - be able to tell the back end about the array's - decl _before_ it tells it about the conditional - expression to inhibit evaluation of size/shape info, - as shown above. - - To solve this, the front end needs to be able - to give the back end the expression to inhibit - generation of the preevaluation code _after_ - it makes the decl for the adjustable array. - - Until then, the above example using the COND_EXPR - doesn't pass muster with gcc because the "(a == NULL)" - part has a reference to "a", which is still - undefined at that point. - - g77 will therefore use a different mechanism in the - meantime. */ - - if (!adjustable - && ((TREE_CODE (low) != INTEGER_CST) - || (high && TREE_CODE (high) != INTEGER_CST))) - adjustable = TRUE; - -#if 0 /* Old approach -- see below. */ - if (TREE_CODE (low) != INTEGER_CST) - low = ffecom_3 (COND_EXPR, integer_type_node, - ffecom_adjarray_passed_ (s), - low, - ffecom_integer_zero_node); - - if (high && TREE_CODE (high) != INTEGER_CST) - high = ffecom_3 (COND_EXPR, integer_type_node, - ffecom_adjarray_passed_ (s), - high, - ffecom_integer_zero_node); -#endif - - /* ~~~gcc/stor-layout.c (layout_type) should do this, - probably. Fixes 950302-1.f. */ - - if (TREE_CODE (low) != INTEGER_CST) - low = variable_size (low); - - /* ~~~Similarly, this fixes dumb0.f. The C front end - does this, which is why dumb0.c would work. */ - - if (high && TREE_CODE (high) != INTEGER_CST) - high = variable_size (high); - - type - = build_array_type - (type, - build_range_type (ffecom_integer_type_node, - low, high)); - type = ffecom_check_size_overflow_ (s, type, TRUE); - } - - if (type == error_mark_node) - { - t = error_mark_node; - break; - } - - if ((ffesymbol_sfdummyparent (s) == NULL) - || (ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER)) - { - type = build_pointer_type (type); - addr = TRUE; - } - - t = build_decl (PARM_DECL, t, type); - DECL_ARTIFICIAL (t) = 1; - - /* If this arg is present in every entry point's list of - dummy args, then we're done. */ - - if (ffesymbol_numentries (s) - == (ffecom_num_entrypoints_ + 1)) - break; - -#if 1 - - /* If variable_size in stor-layout has been called during - the above, then get_pending_sizes should have the - yet-to-be-evaluated saved expressions pending. - Make the whole lot of them get emitted, conditionally - on whether the array decl ("t" above) is not NULL. */ - - { - tree sizes = get_pending_sizes (); - tree tem; - - for (tem = sizes; - tem != old_sizes; - tem = TREE_CHAIN (tem)) - { - tree temv = TREE_VALUE (tem); - - if (sizes == tem) - sizes = temv; - else - sizes - = ffecom_2 (COMPOUND_EXPR, - TREE_TYPE (sizes), - temv, - sizes); - } - - if (sizes != tem) - { - sizes - = ffecom_3 (COND_EXPR, - TREE_TYPE (sizes), - ffecom_2 (NE_EXPR, - integer_type_node, - t, - null_pointer_node), - sizes, - convert (TREE_TYPE (sizes), - integer_zero_node)); - sizes = ffecom_save_tree (sizes); - - sizes - = tree_cons (NULL_TREE, sizes, tem); - } - - if (sizes) - put_pending_sizes (sizes); - } - -#else -#if 0 - if (adjustable - && (ffesymbol_numentries (s) - != ffecom_num_entrypoints_ + 1)) - DECL_SOMETHING (t) - = ffecom_2 (NE_EXPR, integer_type_node, - t, - null_pointer_node); -#else -#if 0 - if (adjustable - && (ffesymbol_numentries (s) - != ffecom_num_entrypoints_ + 1)) - { - ffebad_start (FFEBAD_MISSING_ADJARRAY_UNSUPPORTED); - ffebad_here (0, ffesymbol_where_line (s), - ffesymbol_where_column (s)); - ffebad_string (ffesymbol_text (s)); - ffebad_finish (); - } -#endif -#endif -#endif - } - break; - - case FFEINFO_whereCOMMON: - { - ffesymbol cs; - ffeglobal cg; - tree ct; - ffestorag st = ffesymbol_storage (s); - tree type; - - cs = ffesymbol_common (s); /* The COMMON area itself. */ - if (st != NULL) /* Else not laid out. */ - { - ffecom_transform_common_ (cs); - st = ffesymbol_storage (s); - } - - type = ffecom_type_localvar_ (s, bt, kt); - - cg = ffesymbol_global (cs); /* The global COMMON info. */ - if ((cg == NULL) - || (ffeglobal_type (cg) != FFEGLOBAL_typeCOMMON)) - ct = NULL_TREE; - else - ct = ffeglobal_hook (cg); /* The common area's tree. */ - - if ((ct == NULL_TREE) - || (st == NULL) - || (type == error_mark_node)) - t = error_mark_node; - else - { - ffetargetOffset offset; - ffestorag cst; - - cst = ffestorag_parent (st); - assert (cst == ffesymbol_storage (cs)); - - offset = ffestorag_modulo (cst) - + ffestorag_offset (st) - - ffestorag_offset (cst); - - ffecom_debug_kludge_ (ct, "COMMON", s, type, offset); - - /* (t_type *) (((char *) &ct) + offset) */ - - t = convert (string_type_node, /* (char *) */ - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (ct)), - ct)); - t = ffecom_2 (PLUS_EXPR, TREE_TYPE (t), - t, - build_int_2 (offset, 0)); - t = convert (build_pointer_type (type), - t); - TREE_CONSTANT (t) = 1; - - addr = TRUE; - } - } - break; - - case FFEINFO_whereIMMEDIATE: - case FFEINFO_whereGLOBAL: - case FFEINFO_whereFLEETING: - case FFEINFO_whereFLEETING_CADDR: - case FFEINFO_whereFLEETING_IADDR: - case FFEINFO_whereINTRINSIC: - case FFEINFO_whereCONSTANT_SUBOBJECT: - default: - assert ("ENTITY where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindFUNCTION: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: /* Me. */ - assert (!ffecom_transform_only_dummies_); - t = current_function_decl; - break; - - case FFEINFO_whereGLOBAL: - assert (!ffecom_transform_only_dummies_); - - if (((g = ffesymbol_global (s)) != NULL) - && ((ffeglobal_type (g) == FFEGLOBAL_typeFUNC) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)) - && (ffeglobal_hook (g) != NULL_TREE) - && ffe_is_globals ()) - { - t = ffeglobal_hook (g); - break; - } - - if (ffesymbol_is_f2c (s) - && (ffesymbol_where (s) != FFEINFO_whereCONSTANT)) - t = ffecom_tree_fun_type[bt][kt]; - else - t = build_function_type (ffecom_tree_type[bt][kt], NULL_TREE); - - t = build_decl (FUNCTION_DECL, - ffecom_get_external_identifier_ (s), - t); - DECL_EXTERNAL (t) = 1; - TREE_PUBLIC (t) = 1; - - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - if ((g != NULL) - && ((ffeglobal_type (g) == FFEGLOBAL_typeFUNC) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))) - ffeglobal_set_hook (g, t); - - ffecom_save_tree_forever (t); - - break; - - case FFEINFO_whereDUMMY: - assert (ffecom_transform_only_dummies_); - - if (ffesymbol_is_f2c (s) - && (ffesymbol_where (s) != FFEINFO_whereCONSTANT)) - t = ffecom_tree_ptr_to_fun_type[bt][kt]; - else - t = build_pointer_type - (build_function_type (ffecom_tree_type[bt][kt], NULL_TREE)); - - t = build_decl (PARM_DECL, - ffecom_get_identifier_ (ffesymbol_text (s)), - t); - DECL_ARTIFICIAL (t) = 1; - addr = TRUE; - break; - - case FFEINFO_whereCONSTANT: /* Statement function. */ - assert (!ffecom_transform_only_dummies_); - t = ffecom_gen_sfuncdef_ (s, bt, kt); - break; - - case FFEINFO_whereINTRINSIC: - assert (!ffecom_transform_only_dummies_); - break; /* Let actual references generate their - decls. */ - - default: - assert ("FUNCTION where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindSUBROUTINE: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: /* Me. */ - assert (!ffecom_transform_only_dummies_); - t = current_function_decl; - break; - - case FFEINFO_whereGLOBAL: - assert (!ffecom_transform_only_dummies_); - - if (((g = ffesymbol_global (s)) != NULL) - && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)) - && (ffeglobal_hook (g) != NULL_TREE) - && ffe_is_globals ()) - { - t = ffeglobal_hook (g); - break; - } - - t = build_decl (FUNCTION_DECL, - ffecom_get_external_identifier_ (s), - ffecom_tree_subr_type); - DECL_EXTERNAL (t) = 1; - TREE_PUBLIC (t) = 1; - - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - if ((g != NULL) - && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR) - || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))) - ffeglobal_set_hook (g, t); - - ffecom_save_tree_forever (t); - - break; - - case FFEINFO_whereDUMMY: - assert (ffecom_transform_only_dummies_); - - t = build_decl (PARM_DECL, - ffecom_get_identifier_ (ffesymbol_text (s)), - ffecom_tree_ptr_to_subr_type); - DECL_ARTIFICIAL (t) = 1; - addr = TRUE; - break; - - case FFEINFO_whereINTRINSIC: - assert (!ffecom_transform_only_dummies_); - break; /* Let actual references generate their - decls. */ - - default: - assert ("SUBROUTINE where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindPROGRAM: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: /* Me. */ - assert (!ffecom_transform_only_dummies_); - t = current_function_decl; - break; - - case FFEINFO_whereCOMMON: - case FFEINFO_whereDUMMY: - case FFEINFO_whereGLOBAL: - case FFEINFO_whereRESULT: - case FFEINFO_whereFLEETING: - case FFEINFO_whereFLEETING_CADDR: - case FFEINFO_whereFLEETING_IADDR: - case FFEINFO_whereIMMEDIATE: - case FFEINFO_whereINTRINSIC: - case FFEINFO_whereCONSTANT: - case FFEINFO_whereCONSTANT_SUBOBJECT: - default: - assert ("PROGRAM where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindBLOCKDATA: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: /* Me. */ - assert (!ffecom_transform_only_dummies_); - t = current_function_decl; - break; - - case FFEINFO_whereGLOBAL: - assert (!ffecom_transform_only_dummies_); - - t = build_decl (FUNCTION_DECL, - ffecom_get_external_identifier_ (s), - ffecom_tree_blockdata_type); - DECL_EXTERNAL (t) = 1; - TREE_PUBLIC (t) = 1; - - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - ffecom_save_tree_forever (t); - - break; - - case FFEINFO_whereCOMMON: - case FFEINFO_whereDUMMY: - case FFEINFO_whereRESULT: - case FFEINFO_whereFLEETING: - case FFEINFO_whereFLEETING_CADDR: - case FFEINFO_whereFLEETING_IADDR: - case FFEINFO_whereIMMEDIATE: - case FFEINFO_whereINTRINSIC: - case FFEINFO_whereCONSTANT: - case FFEINFO_whereCONSTANT_SUBOBJECT: - default: - assert ("BLOCKDATA where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindCOMMON: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: - assert (!ffecom_transform_only_dummies_); - ffecom_transform_common_ (s); - break; - - case FFEINFO_whereNONE: - case FFEINFO_whereCOMMON: - case FFEINFO_whereDUMMY: - case FFEINFO_whereGLOBAL: - case FFEINFO_whereRESULT: - case FFEINFO_whereFLEETING: - case FFEINFO_whereFLEETING_CADDR: - case FFEINFO_whereFLEETING_IADDR: - case FFEINFO_whereIMMEDIATE: - case FFEINFO_whereINTRINSIC: - case FFEINFO_whereCONSTANT: - case FFEINFO_whereCONSTANT_SUBOBJECT: - default: - assert ("COMMON where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindCONSTRUCT: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: - assert (!ffecom_transform_only_dummies_); - break; - - case FFEINFO_whereNONE: - case FFEINFO_whereCOMMON: - case FFEINFO_whereDUMMY: - case FFEINFO_whereGLOBAL: - case FFEINFO_whereRESULT: - case FFEINFO_whereFLEETING: - case FFEINFO_whereFLEETING_CADDR: - case FFEINFO_whereFLEETING_IADDR: - case FFEINFO_whereIMMEDIATE: - case FFEINFO_whereINTRINSIC: - case FFEINFO_whereCONSTANT: - case FFEINFO_whereCONSTANT_SUBOBJECT: - default: - assert ("CONSTRUCT where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - case FFEINFO_kindNAMELIST: - switch (ffeinfo_where (ffesymbol_info (s))) - { - case FFEINFO_whereLOCAL: - assert (!ffecom_transform_only_dummies_); - t = ffecom_transform_namelist_ (s); - break; - - case FFEINFO_whereNONE: - case FFEINFO_whereCOMMON: - case FFEINFO_whereDUMMY: - case FFEINFO_whereGLOBAL: - case FFEINFO_whereRESULT: - case FFEINFO_whereFLEETING: - case FFEINFO_whereFLEETING_CADDR: - case FFEINFO_whereFLEETING_IADDR: - case FFEINFO_whereIMMEDIATE: - case FFEINFO_whereINTRINSIC: - case FFEINFO_whereCONSTANT: - case FFEINFO_whereCONSTANT_SUBOBJECT: - default: - assert ("NAMELIST where unheard of" == NULL); - /* Fall through. */ - case FFEINFO_whereANY: - t = error_mark_node; - break; - } - break; - - default: - assert ("kind unheard of" == NULL); - /* Fall through. */ - case FFEINFO_kindANY: - t = error_mark_node; - break; - } - - ffesymbol_hook (s).decl_tree = t; - ffesymbol_hook (s).length_tree = tlen; - ffesymbol_hook (s).addr = addr; - - lineno = old_lineno; - input_filename = old_input_filename; - - return s; -} - -/* Transform into ASSIGNable symbol. - - Symbol has already been transformed, but for whatever reason, the - resulting decl_tree has been deemed not usable for an ASSIGN target. - (E.g. it isn't wide enough to hold a pointer.) So, here we invent - another local symbol of type void * and stuff that in the assign_tree - argument. The F77/F90 standards allow this implementation. */ - -static ffesymbol -ffecom_sym_transform_assign_ (ffesymbol s) -{ - tree t; /* Transformed thingy. */ - int old_lineno = lineno; - const char *old_input_filename = input_filename; - - if (ffesymbol_sfdummyparent (s) == NULL) - { - input_filename = ffesymbol_where_filename (s); - lineno = ffesymbol_where_filelinenum (s); - } - else - { - ffesymbol sf = ffesymbol_sfdummyparent (s); - - input_filename = ffesymbol_where_filename (sf); - lineno = ffesymbol_where_filelinenum (sf); - } - - assert (!ffecom_transform_only_dummies_); - - t = build_decl (VAR_DECL, - ffecom_get_invented_identifier ("__g77_ASSIGN_%s", - ffesymbol_text (s)), - TREE_TYPE (null_pointer_node)); - - switch (ffesymbol_where (s)) - { - case FFEINFO_whereLOCAL: - /* Unlike for regular vars, SAVE status is easy to determine for - ASSIGNed vars, since there's no initialization, there's no - effective storage association (so "SAVE J" does not apply to - K even given "EQUIVALENCE (J,K)"), there's no size issue - to worry about, etc. */ - if ((ffesymbol_is_save (s) || ffe_is_saveall ()) - && (ffecom_primary_entry_kind_ != FFEINFO_kindPROGRAM) - && (ffecom_primary_entry_kind_ != FFEINFO_kindBLOCKDATA)) - TREE_STATIC (t) = 1; /* SAVEd in proc, make static. */ - else - TREE_STATIC (t) = 0; /* No need to make static. */ - break; - - case FFEINFO_whereCOMMON: - TREE_STATIC (t) = 1; /* Assume COMMONs always SAVEd. */ - break; - - case FFEINFO_whereDUMMY: - /* Note that twinning a DUMMY means the caller won't see - the ASSIGNed value. But both F77 and F90 allow implementations - to do this, i.e. disallow Fortran code that would try and - take advantage of actually putting a label into a variable - via a dummy argument (or any other storage association, for - that matter). */ - TREE_STATIC (t) = 0; - break; - - default: - TREE_STATIC (t) = 0; - break; - } - - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - ffesymbol_hook (s).assign_tree = t; - - lineno = old_lineno; - input_filename = old_input_filename; - - return s; -} - -/* Implement COMMON area in back end. - - Because COMMON-based variables can be referenced in the dimension - expressions of dummy (adjustable) arrays, and because dummies - (in the gcc back end) need to be put in the outer binding level - of a function (which has two binding levels, the outer holding - the dummies and the inner holding the other vars), special care - must be taken to handle COMMON areas. - - The current strategy is basically to always tell the back end about - the COMMON area as a top-level external reference to just a block - of storage of the master type of that area (e.g. integer, real, - character, whatever -- not a structure). As a distinct action, - if initial values are provided, tell the back end about the area - as a top-level non-external (initialized) area and remember not to - allow further initialization or expansion of the area. Meanwhile, - if no initialization happens at all, tell the back end about - the largest size we've seen declared so the space does get reserved. - (This function doesn't handle all that stuff, but it does some - of the important things.) - - Meanwhile, for COMMON variables themselves, just keep creating - references like *((float *) (&common_area + offset)) each time - we reference the variable. In other words, don't make a VAR_DECL - or any kind of component reference (like we used to do before 0.4), - though we might do that as well just for debugging purposes (and - stuff the rtl with the appropriate offset expression). */ - -static void -ffecom_transform_common_ (ffesymbol s) -{ - ffestorag st = ffesymbol_storage (s); - ffeglobal g = ffesymbol_global (s); - tree cbt; - tree cbtype; - tree init; - tree high; - bool is_init = ffestorag_is_init (st); - - assert (st != NULL); - - if ((g == NULL) - || (ffeglobal_type (g) != FFEGLOBAL_typeCOMMON)) - return; - - /* First update the size of the area in global terms. */ - - ffeglobal_size_common (s, ffestorag_size (st)); - - if (!ffeglobal_common_init (g)) - is_init = FALSE; /* No explicit init, don't let erroneous joins init. */ - - cbt = ffeglobal_hook (g); - - /* If we already have declared this common block for a previous program - unit, and either we already initialized it or we don't have new - initialization for it, just return what we have without changing it. */ - - if ((cbt != NULL_TREE) - && (!is_init - || !DECL_EXTERNAL (cbt))) - { - if (st->hook == NULL) ffestorag_set_hook (st, cbt); - return; - } - - /* Process inits. */ - - if (is_init) - { - if (ffestorag_init (st) != NULL) - { - ffebld sexp; - - /* Set the padding for the expression, so ffecom_expr - knows to insert that many zeros. */ - switch (ffebld_op (sexp = ffestorag_init (st))) - { - case FFEBLD_opCONTER: - ffebld_conter_set_pad (sexp, ffestorag_modulo (st)); - break; - - case FFEBLD_opARRTER: - ffebld_arrter_set_pad (sexp, ffestorag_modulo (st)); - break; - - case FFEBLD_opACCTER: - ffebld_accter_set_pad (sexp, ffestorag_modulo (st)); - break; - - default: - assert ("bad op for cmn init (pad)" == NULL); - break; - } - - init = ffecom_expr (sexp); - if (init == error_mark_node) - { /* Hopefully the back end complained! */ - init = NULL_TREE; - if (cbt != NULL_TREE) - return; - } - } - else - init = error_mark_node; - } - else - init = NULL_TREE; - - /* cbtype must be permanently allocated! */ - - /* Allocate the MAX of the areas so far, seen filewide. */ - high = build_int_2 ((ffeglobal_common_size (g) - + ffeglobal_common_pad (g)) - 1, 0); - TREE_TYPE (high) = ffecom_integer_type_node; - - if (init) - cbtype = build_array_type (char_type_node, - build_range_type (integer_type_node, - integer_zero_node, - high)); - else - cbtype = build_array_type (char_type_node, NULL_TREE); - - if (cbt == NULL_TREE) - { - cbt - = build_decl (VAR_DECL, - ffecom_get_external_identifier_ (s), - cbtype); - TREE_STATIC (cbt) = 1; - TREE_PUBLIC (cbt) = 1; - } - else - { - assert (is_init); - TREE_TYPE (cbt) = cbtype; - } - DECL_EXTERNAL (cbt) = init ? 0 : 1; - DECL_INITIAL (cbt) = init ? error_mark_node : NULL_TREE; - - cbt = start_decl (cbt, TRUE); - if (ffeglobal_hook (g) != NULL) - assert (cbt == ffeglobal_hook (g)); - - assert (!init || !DECL_EXTERNAL (cbt)); - - /* Make sure that any type can live in COMMON and be referenced - without getting a bus error. We could pick the most restrictive - alignment of all entities actually placed in the COMMON, but - this seems easy enough. */ - - DECL_ALIGN (cbt) = BIGGEST_ALIGNMENT; - DECL_USER_ALIGN (cbt) = 0; - - if (is_init && (ffestorag_init (st) == NULL)) - init = ffecom_init_zero_ (cbt); - - finish_decl (cbt, init, TRUE); - - if (is_init) - ffestorag_set_init (st, ffebld_new_any ()); - - if (init) - { - assert (DECL_SIZE_UNIT (cbt) != NULL_TREE); - assert (TREE_CODE (DECL_SIZE_UNIT (cbt)) == INTEGER_CST); - assert (0 == compare_tree_int (DECL_SIZE_UNIT (cbt), - (ffeglobal_common_size (g) - + ffeglobal_common_pad (g)))); - } - - ffeglobal_set_hook (g, cbt); - - ffestorag_set_hook (st, cbt); - - ffecom_save_tree_forever (cbt); -} - -/* Make master area for local EQUIVALENCE. */ - -static void -ffecom_transform_equiv_ (ffestorag eqst) -{ - tree eqt; - tree eqtype; - tree init; - tree high; - bool is_init = ffestorag_is_init (eqst); - - assert (eqst != NULL); - - eqt = ffestorag_hook (eqst); - - if (eqt != NULL_TREE) - return; - - /* Process inits. */ - - if (is_init) - { - if (ffestorag_init (eqst) != NULL) - { - ffebld sexp; - - /* Set the padding for the expression, so ffecom_expr - knows to insert that many zeros. */ - switch (ffebld_op (sexp = ffestorag_init (eqst))) - { - case FFEBLD_opCONTER: - ffebld_conter_set_pad (sexp, ffestorag_modulo (eqst)); - break; - - case FFEBLD_opARRTER: - ffebld_arrter_set_pad (sexp, ffestorag_modulo (eqst)); - break; - - case FFEBLD_opACCTER: - ffebld_accter_set_pad (sexp, ffestorag_modulo (eqst)); - break; - - default: - assert ("bad op for eqv init (pad)" == NULL); - break; - } - - init = ffecom_expr (sexp); - if (init == error_mark_node) - init = NULL_TREE; /* Hopefully the back end complained! */ - } - else - init = error_mark_node; - } - else if (ffe_is_init_local_zero ()) - init = error_mark_node; - else - init = NULL_TREE; - - ffecom_member_namelisted_ = FALSE; - ffestorag_drive (ffestorag_list_equivs (eqst), - &ffecom_member_phase1_, - eqst); - - high = build_int_2 ((ffestorag_size (eqst) - + ffestorag_modulo (eqst)) - 1, 0); - TREE_TYPE (high) = ffecom_integer_type_node; - - eqtype = build_array_type (char_type_node, - build_range_type (ffecom_integer_type_node, - ffecom_integer_zero_node, - high)); - - eqt = build_decl (VAR_DECL, - ffecom_get_invented_identifier ("__g77_equiv_%s", - ffesymbol_text - (ffestorag_symbol (eqst))), - eqtype); - DECL_EXTERNAL (eqt) = 0; - if (is_init - || ffecom_member_namelisted_ -#ifdef FFECOM_sizeMAXSTACKITEM - || (ffestorag_size (eqst) > FFECOM_sizeMAXSTACKITEM) -#endif - || ((ffecom_primary_entry_kind_ != FFEINFO_kindPROGRAM) - && (ffecom_primary_entry_kind_ != FFEINFO_kindBLOCKDATA) - && (ffestorag_is_save (eqst) || ffe_is_saveall ()))) - TREE_STATIC (eqt) = 1; - else - TREE_STATIC (eqt) = 0; - TREE_PUBLIC (eqt) = 0; - TREE_ADDRESSABLE (eqt) = 1; /* Ensure non-register allocation */ - DECL_CONTEXT (eqt) = current_function_decl; - if (init) - DECL_INITIAL (eqt) = error_mark_node; - else - DECL_INITIAL (eqt) = NULL_TREE; - - eqt = start_decl (eqt, FALSE); - - /* Make sure that any type can live in EQUIVALENCE and be referenced - without getting a bus error. We could pick the most restrictive - alignment of all entities actually placed in the EQUIVALENCE, but - this seems easy enough. */ - - DECL_ALIGN (eqt) = BIGGEST_ALIGNMENT; - DECL_USER_ALIGN (eqt) = 0; - - if ((!is_init && ffe_is_init_local_zero ()) - || (is_init && (ffestorag_init (eqst) == NULL))) - init = ffecom_init_zero_ (eqt); - - finish_decl (eqt, init, FALSE); - - if (is_init) - ffestorag_set_init (eqst, ffebld_new_any ()); - - { - assert (TREE_CODE (DECL_SIZE_UNIT (eqt)) == INTEGER_CST); - assert (0 == compare_tree_int (DECL_SIZE_UNIT (eqt), - (ffestorag_size (eqst) - + ffestorag_modulo (eqst)))); - } - - ffestorag_set_hook (eqst, eqt); - - ffestorag_drive (ffestorag_list_equivs (eqst), - &ffecom_member_phase2_, - eqst); -} - -/* Implement NAMELIST in back end. See f2c/format.c for more info. */ - -static tree -ffecom_transform_namelist_ (ffesymbol s) -{ - tree nmlt; - tree nmltype = ffecom_type_namelist_ (); - tree nmlinits; - tree nameinit; - tree varsinit; - tree nvarsinit; - tree field; - tree high; - int i; - static int mynumber = 0; - - nmlt = build_decl (VAR_DECL, - ffecom_get_invented_identifier ("__g77_namelist_%d", - mynumber++), - nmltype); - TREE_STATIC (nmlt) = 1; - DECL_INITIAL (nmlt) = error_mark_node; - - nmlt = start_decl (nmlt, FALSE); - - /* Process inits. */ - - i = strlen (ffesymbol_text (s)); - - high = build_int_2 (i, 0); - TREE_TYPE (high) = ffecom_f2c_ftnlen_type_node; - - nameinit = ffecom_build_f2c_string_ (i + 1, - ffesymbol_text (s)); - TREE_TYPE (nameinit) - = build_type_variant - (build_array_type - (char_type_node, - build_range_type (ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - high)), - 1, 0); - TREE_CONSTANT (nameinit) = 1; - TREE_STATIC (nameinit) = 1; - nameinit = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (nameinit)), - nameinit); - - varsinit = ffecom_vardesc_array_ (s); - varsinit = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (varsinit)), - varsinit); - TREE_CONSTANT (varsinit) = 1; - TREE_STATIC (varsinit) = 1; - - { - ffebld b; - - for (i = 0, b = ffesymbol_namelist (s); b != NULL; b = ffebld_trail (b)) - ++i; - } - nvarsinit = build_int_2 (i, 0); - TREE_TYPE (nvarsinit) = integer_type_node; - TREE_CONSTANT (nvarsinit) = 1; - TREE_STATIC (nvarsinit) = 1; - - nmlinits = build_tree_list ((field = TYPE_FIELDS (nmltype)), nameinit); - TREE_CHAIN (nmlinits) = build_tree_list ((field = TREE_CHAIN (field)), - varsinit); - TREE_CHAIN (TREE_CHAIN (nmlinits)) - = build_tree_list ((field = TREE_CHAIN (field)), nvarsinit); - - nmlinits = build (CONSTRUCTOR, nmltype, NULL_TREE, nmlinits); - TREE_CONSTANT (nmlinits) = 1; - TREE_STATIC (nmlinits) = 1; - - finish_decl (nmlt, nmlinits, FALSE); - - nmlt = ffecom_1 (ADDR_EXPR, build_pointer_type (nmltype), nmlt); - - return nmlt; -} - -/* A subroutine of ffecom_tree_canonize_ref_. The incoming tree is - analyzed on the assumption it is calculating a pointer to be - indirected through. It must return the proper decl and offset, - taking into account different units of measurements for offsets. */ - -static void -ffecom_tree_canonize_ptr_ (tree *decl, tree *offset, - tree t) -{ - switch (TREE_CODE (t)) - { - case NOP_EXPR: - case CONVERT_EXPR: - case NON_LVALUE_EXPR: - ffecom_tree_canonize_ptr_ (decl, offset, TREE_OPERAND (t, 0)); - break; - - case PLUS_EXPR: - ffecom_tree_canonize_ptr_ (decl, offset, TREE_OPERAND (t, 0)); - if ((*decl == NULL_TREE) - || (*decl == error_mark_node)) - break; - - if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) - { - /* An offset into COMMON. */ - *offset = fold (build (PLUS_EXPR, TREE_TYPE (*offset), - *offset, TREE_OPERAND (t, 1))); - /* Convert offset (presumably in bytes) into canonical units - (presumably bits). */ - *offset = size_binop (MULT_EXPR, - convert (bitsizetype, *offset), - TYPE_SIZE (TREE_TYPE (TREE_TYPE (t)))); - break; - } - /* Not a COMMON reference, so an unrecognized pattern. */ - *decl = error_mark_node; - break; - - case PARM_DECL: - *decl = t; - *offset = bitsize_zero_node; - break; - - case ADDR_EXPR: - if (TREE_CODE (TREE_OPERAND (t, 0)) == VAR_DECL) - { - /* A reference to COMMON. */ - *decl = TREE_OPERAND (t, 0); - *offset = bitsize_zero_node; - break; - } - /* Fall through. */ - default: - /* Not a COMMON reference, so an unrecognized pattern. */ - *decl = error_mark_node; - break; - } -} - -/* Given a tree that is possibly intended for use as an lvalue, return - information representing a canonical view of that tree as a decl, an - offset into that decl, and a size for the lvalue. - - If there's no applicable decl, NULL_TREE is returned for the decl, - and the other fields are left undefined. - - If the tree doesn't fit the recognizable forms, an ERROR_MARK node - is returned for the decl, and the other fields are left undefined. - - Otherwise, the decl returned currently is either a VAR_DECL or a - PARM_DECL. - - The offset returned is always valid, but of course not necessarily - a constant, and not necessarily converted into the appropriate - type, leaving that up to the caller (so as to avoid that overhead - if the decls being looked at are different anyway). - - If the size cannot be determined (e.g. an adjustable array), - an ERROR_MARK node is returned for the size. Otherwise, the - size returned is valid, not necessarily a constant, and not - necessarily converted into the appropriate type as with the - offset. - - Note that the offset and size expressions are expressed in the - base storage units (usually bits) rather than in the units of - the type of the decl, because two decls with different types - might overlap but with apparently non-overlapping array offsets, - whereas converting the array offsets to consistant offsets will - reveal the overlap. */ - -static void -ffecom_tree_canonize_ref_ (tree *decl, tree *offset, - tree *size, tree t) -{ - /* The default path is to report a nonexistant decl. */ - *decl = NULL_TREE; - - if (t == NULL_TREE) - return; - - switch (TREE_CODE (t)) - { - case ERROR_MARK: - case IDENTIFIER_NODE: - case INTEGER_CST: - case REAL_CST: - case COMPLEX_CST: - case STRING_CST: - case CONST_DECL: - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case FIX_TRUNC_EXPR: - case FIX_CEIL_EXPR: - case FIX_FLOOR_EXPR: - case FIX_ROUND_EXPR: - case FLOAT_EXPR: - case NEGATE_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case ABS_EXPR: - case FFS_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case BIT_ANDTC_EXPR: - case BIT_NOT_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_NOT_EXPR: - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - case COMPLEX_EXPR: - case CONJ_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - case LABEL_EXPR: - case COMPONENT_REF: - case COMPOUND_EXPR: - case ADDR_EXPR: - return; - - case VAR_DECL: - case PARM_DECL: - *decl = t; - *offset = bitsize_zero_node; - *size = TYPE_SIZE (TREE_TYPE (t)); - return; - - case ARRAY_REF: - { - tree array = TREE_OPERAND (t, 0); - tree element = TREE_OPERAND (t, 1); - tree init_offset; - - if ((array == NULL_TREE) - || (element == NULL_TREE)) - { - *decl = error_mark_node; - return; - } - - ffecom_tree_canonize_ref_ (decl, &init_offset, size, - array); - if ((*decl == NULL_TREE) - || (*decl == error_mark_node)) - return; - - /* Calculate ((element - base) * NBBY) + init_offset. */ - *offset = fold (build (MINUS_EXPR, TREE_TYPE (element), - element, - TYPE_MIN_VALUE (TYPE_DOMAIN - (TREE_TYPE (array))))); - - *offset = size_binop (MULT_EXPR, - convert (bitsizetype, *offset), - TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))); - - *offset = size_binop (PLUS_EXPR, init_offset, *offset); - - *size = TYPE_SIZE (TREE_TYPE (t)); - return; - } - - case INDIRECT_REF: - - /* Most of this code is to handle references to COMMON. And so - far that is useful only for calling library functions, since - external (user) functions might reference common areas. But - even calling an external function, it's worthwhile to decode - COMMON references because if not storing into COMMON, we don't - want COMMON-based arguments to gratuitously force use of a - temporary. */ - - *size = TYPE_SIZE (TREE_TYPE (t)); - - ffecom_tree_canonize_ptr_ (decl, offset, - TREE_OPERAND (t, 0)); - - return; - - case CONVERT_EXPR: - case NOP_EXPR: - case MODIFY_EXPR: - case NON_LVALUE_EXPR: - case RESULT_DECL: - case FIELD_DECL: - case COND_EXPR: /* More cases than we can handle. */ - case SAVE_EXPR: - case REFERENCE_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case CALL_EXPR: - default: - *decl = error_mark_node; - return; - } -} - -/* Do divide operation appropriate to type of operands. */ - -static tree -ffecom_tree_divide_ (tree tree_type, tree left, tree right, - tree dest_tree, ffebld dest, bool *dest_used, - tree hook) -{ - if ((left == error_mark_node) - || (right == error_mark_node)) - return error_mark_node; - - switch (TREE_CODE (tree_type)) - { - case INTEGER_TYPE: - return ffecom_2 (TRUNC_DIV_EXPR, tree_type, - left, - right); - - case COMPLEX_TYPE: - if (! optimize_size) - return ffecom_2 (RDIV_EXPR, tree_type, - left, - right); - { - ffecomGfrt ix; - - if (TREE_TYPE (tree_type) - == ffecom_tree_type [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1]) - ix = FFECOM_gfrtDIV_CC; /* Overlapping result okay. */ - else - ix = FFECOM_gfrtDIV_ZZ; /* Overlapping result okay. */ - - left = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (left)), - left); - left = build_tree_list (NULL_TREE, left); - right = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (right)), - right); - right = build_tree_list (NULL_TREE, right); - TREE_CHAIN (left) = right; - - return ffecom_call_ (ffecom_gfrt_tree_ (ix), - ffecom_gfrt_kindtype (ix), - ffe_is_f2c_library (), - tree_type, - left, - dest_tree, dest, dest_used, - NULL_TREE, TRUE, hook); - } - break; - - case RECORD_TYPE: - { - ffecomGfrt ix; - - if (TREE_TYPE (TYPE_FIELDS (tree_type)) - == ffecom_tree_type [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1]) - ix = FFECOM_gfrtDIV_CC; /* Overlapping result okay. */ - else - ix = FFECOM_gfrtDIV_ZZ; /* Overlapping result okay. */ - - left = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (left)), - left); - left = build_tree_list (NULL_TREE, left); - right = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (right)), - right); - right = build_tree_list (NULL_TREE, right); - TREE_CHAIN (left) = right; - - return ffecom_call_ (ffecom_gfrt_tree_ (ix), - ffecom_gfrt_kindtype (ix), - ffe_is_f2c_library (), - tree_type, - left, - dest_tree, dest, dest_used, - NULL_TREE, TRUE, hook); - } - break; - - default: - return ffecom_2 (RDIV_EXPR, tree_type, - left, - right); - } -} - -/* Build type info for non-dummy variable. */ - -static tree -ffecom_type_localvar_ (ffesymbol s, ffeinfoBasictype bt, - ffeinfoKindtype kt) -{ - tree type; - ffebld dl; - ffebld dim; - tree lowt; - tree hight; - - type = ffecom_tree_type[bt][kt]; - if (bt == FFEINFO_basictypeCHARACTER) - { - hight = build_int_2 (ffesymbol_size (s), 0); - TREE_TYPE (hight) = ffecom_f2c_ftnlen_type_node; - - type - = build_array_type - (type, - build_range_type (ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - hight)); - type = ffecom_check_size_overflow_ (s, type, FALSE); - } - - for (dl = ffesymbol_dims (s); dl != NULL; dl = ffebld_trail (dl)) - { - if (type == error_mark_node) - break; - - dim = ffebld_head (dl); - assert (ffebld_op (dim) == FFEBLD_opBOUNDS); - - if (ffebld_left (dim) == NULL) - lowt = integer_one_node; - else - lowt = ffecom_expr (ffebld_left (dim)); - - if (TREE_CODE (lowt) != INTEGER_CST) - lowt = variable_size (lowt); - - assert (ffebld_right (dim) != NULL); - hight = ffecom_expr (ffebld_right (dim)); - - if (TREE_CODE (hight) != INTEGER_CST) - hight = variable_size (hight); - - type = build_array_type (type, - build_range_type (ffecom_integer_type_node, - lowt, hight)); - type = ffecom_check_size_overflow_ (s, type, FALSE); - } - - return type; -} - -/* Build Namelist type. */ - -static tree -ffecom_type_namelist_ () -{ - static tree type = NULL_TREE; - - if (type == NULL_TREE) - { - static tree namefield, varsfield, nvarsfield; - tree vardesctype; - - vardesctype = ffecom_type_vardesc_ (); - - type = make_node (RECORD_TYPE); - - vardesctype = build_pointer_type (build_pointer_type (vardesctype)); - - namefield = ffecom_decl_field (type, NULL_TREE, "name", - string_type_node); - varsfield = ffecom_decl_field (type, namefield, "vars", vardesctype); - nvarsfield = ffecom_decl_field (type, varsfield, "nvars", - integer_type_node); - - TYPE_FIELDS (type) = namefield; - layout_type (type); - - ggc_add_tree_root (&type, 1); - } - - return type; -} - -/* Build Vardesc type. */ - -static tree -ffecom_type_vardesc_ () -{ - static tree type = NULL_TREE; - static tree namefield, addrfield, dimsfield, typefield; - - if (type == NULL_TREE) - { - type = make_node (RECORD_TYPE); - - namefield = ffecom_decl_field (type, NULL_TREE, "name", - string_type_node); - addrfield = ffecom_decl_field (type, namefield, "addr", - string_type_node); - dimsfield = ffecom_decl_field (type, addrfield, "dims", - ffecom_f2c_ptr_to_ftnlen_type_node); - typefield = ffecom_decl_field (type, dimsfield, "type", - integer_type_node); - - TYPE_FIELDS (type) = namefield; - layout_type (type); - - ggc_add_tree_root (&type, 1); - } - - return type; -} - -static tree -ffecom_vardesc_ (ffebld expr) -{ - ffesymbol s; - - assert (ffebld_op (expr) == FFEBLD_opSYMTER); - s = ffebld_symter (expr); - - if (ffesymbol_hook (s).vardesc_tree == NULL_TREE) - { - int i; - tree vardesctype = ffecom_type_vardesc_ (); - tree var; - tree nameinit; - tree dimsinit; - tree addrinit; - tree typeinit; - tree field; - tree varinits; - static int mynumber = 0; - - var = build_decl (VAR_DECL, - ffecom_get_invented_identifier ("__g77_vardesc_%d", - mynumber++), - vardesctype); - TREE_STATIC (var) = 1; - DECL_INITIAL (var) = error_mark_node; - - var = start_decl (var, FALSE); - - /* Process inits. */ - - nameinit = ffecom_build_f2c_string_ ((i = strlen (ffesymbol_text (s))) - + 1, - ffesymbol_text (s)); - TREE_TYPE (nameinit) - = build_type_variant - (build_array_type - (char_type_node, - build_range_type (integer_type_node, - integer_one_node, - build_int_2 (i, 0))), - 1, 0); - TREE_CONSTANT (nameinit) = 1; - TREE_STATIC (nameinit) = 1; - nameinit = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (nameinit)), - nameinit); - - addrinit = ffecom_arg_ptr_to_expr (expr, &typeinit); - - dimsinit = ffecom_vardesc_dims_ (s); - - if (typeinit == NULL_TREE) - { - ffeinfoBasictype bt = ffesymbol_basictype (s); - ffeinfoKindtype kt = ffesymbol_kindtype (s); - int tc = ffecom_f2c_typecode (bt, kt); - - assert (tc != -1); - typeinit = build_int_2 (tc, (tc < 0) ? -1 : 0); - } - else - typeinit = ffecom_1 (NEGATE_EXPR, TREE_TYPE (typeinit), typeinit); - - varinits = build_tree_list ((field = TYPE_FIELDS (vardesctype)), - nameinit); - TREE_CHAIN (varinits) = build_tree_list ((field = TREE_CHAIN (field)), - addrinit); - TREE_CHAIN (TREE_CHAIN (varinits)) - = build_tree_list ((field = TREE_CHAIN (field)), dimsinit); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (varinits))) - = build_tree_list ((field = TREE_CHAIN (field)), typeinit); - - varinits = build (CONSTRUCTOR, vardesctype, NULL_TREE, varinits); - TREE_CONSTANT (varinits) = 1; - TREE_STATIC (varinits) = 1; - - finish_decl (var, varinits, FALSE); - - var = ffecom_1 (ADDR_EXPR, build_pointer_type (vardesctype), var); - - ffesymbol_hook (s).vardesc_tree = var; - } - - return ffesymbol_hook (s).vardesc_tree; -} - -static tree -ffecom_vardesc_array_ (ffesymbol s) -{ - ffebld b; - tree list; - tree item = NULL_TREE; - tree var; - int i; - static int mynumber = 0; - - for (i = 0, list = NULL_TREE, b = ffesymbol_namelist (s); - b != NULL; - b = ffebld_trail (b), ++i) - { - tree t; - - t = ffecom_vardesc_ (ffebld_head (b)); - - if (list == NULL_TREE) - list = item = build_tree_list (NULL_TREE, t); - else - { - TREE_CHAIN (item) = build_tree_list (NULL_TREE, t); - item = TREE_CHAIN (item); - } - } - - item = build_array_type (build_pointer_type (ffecom_type_vardesc_ ()), - build_range_type (integer_type_node, - integer_one_node, - build_int_2 (i, 0))); - list = build (CONSTRUCTOR, item, NULL_TREE, list); - TREE_CONSTANT (list) = 1; - TREE_STATIC (list) = 1; - - var = ffecom_get_invented_identifier ("__g77_vardesc_array_%d", mynumber++); - var = build_decl (VAR_DECL, var, item); - TREE_STATIC (var) = 1; - DECL_INITIAL (var) = error_mark_node; - var = start_decl (var, FALSE); - finish_decl (var, list, FALSE); - - return var; -} - -static tree -ffecom_vardesc_dims_ (ffesymbol s) -{ - if (ffesymbol_dims (s) == NULL) - return convert (ffecom_f2c_ptr_to_ftnlen_type_node, - integer_zero_node); - - { - ffebld b; - ffebld e; - tree list; - tree backlist; - tree item = NULL_TREE; - tree var; - tree numdim; - tree numelem; - tree baseoff = NULL_TREE; - static int mynumber = 0; - - numdim = build_int_2 ((int) ffesymbol_rank (s), 0); - TREE_TYPE (numdim) = ffecom_f2c_ftnlen_type_node; - - numelem = ffecom_expr (ffesymbol_arraysize (s)); - TREE_TYPE (numelem) = ffecom_f2c_ftnlen_type_node; - - list = NULL_TREE; - backlist = NULL_TREE; - for (b = ffesymbol_dims (s), e = ffesymbol_extents (s); - b != NULL; - b = ffebld_trail (b), e = ffebld_trail (e)) - { - tree t; - tree low; - tree back; - - if (ffebld_trail (b) == NULL) - t = NULL_TREE; - else - { - t = convert (ffecom_f2c_ftnlen_type_node, - ffecom_expr (ffebld_head (e))); - - if (list == NULL_TREE) - list = item = build_tree_list (NULL_TREE, t); - else - { - TREE_CHAIN (item) = build_tree_list (NULL_TREE, t); - item = TREE_CHAIN (item); - } - } - - if (ffebld_left (ffebld_head (b)) == NULL) - low = ffecom_integer_one_node; - else - low = ffecom_expr (ffebld_left (ffebld_head (b))); - low = convert (ffecom_f2c_ftnlen_type_node, low); - - back = build_tree_list (low, t); - TREE_CHAIN (back) = backlist; - backlist = back; - } - - for (item = backlist; item != NULL_TREE; item = TREE_CHAIN (item)) - { - if (TREE_VALUE (item) == NULL_TREE) - baseoff = TREE_PURPOSE (item); - else - baseoff = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - TREE_PURPOSE (item), - ffecom_2 (MULT_EXPR, - ffecom_f2c_ftnlen_type_node, - TREE_VALUE (item), - baseoff)); - } - - /* backlist now dead, along with all TREE_PURPOSEs on it. */ - - baseoff = build_tree_list (NULL_TREE, baseoff); - TREE_CHAIN (baseoff) = list; - - numelem = build_tree_list (NULL_TREE, numelem); - TREE_CHAIN (numelem) = baseoff; - - numdim = build_tree_list (NULL_TREE, numdim); - TREE_CHAIN (numdim) = numelem; - - item = build_array_type (ffecom_f2c_ftnlen_type_node, - build_range_type (integer_type_node, - integer_zero_node, - build_int_2 - ((int) ffesymbol_rank (s) - + 2, 0))); - list = build (CONSTRUCTOR, item, NULL_TREE, numdim); - TREE_CONSTANT (list) = 1; - TREE_STATIC (list) = 1; - - var = ffecom_get_invented_identifier ("__g77_dims_%d", mynumber++); - var = build_decl (VAR_DECL, var, item); - TREE_STATIC (var) = 1; - DECL_INITIAL (var) = error_mark_node; - var = start_decl (var, FALSE); - finish_decl (var, list, FALSE); - - var = ffecom_1 (ADDR_EXPR, build_pointer_type (item), var); - - return var; - } -} - -/* Essentially does a "fold (build1 (code, type, node))" while checking - for certain housekeeping things. - - NOTE: for building an ADDR_EXPR around a FUNCTION_DECL, use - ffecom_1_fn instead. */ - -tree -ffecom_1 (enum tree_code code, tree type, tree node) -{ - tree item; - - if ((node == error_mark_node) - || (type == error_mark_node)) - return error_mark_node; - - if (code == ADDR_EXPR) - { - if (!mark_addressable (node)) - assert ("can't mark_addressable this node!" == NULL); - } - - switch (ffe_is_emulate_complex () ? code : NOP_EXPR) - { - tree realtype; - - case REALPART_EXPR: - item = build (COMPONENT_REF, type, node, TYPE_FIELDS (TREE_TYPE (node))); - break; - - case IMAGPART_EXPR: - item = build (COMPONENT_REF, type, node, TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (node)))); - break; - - - case NEGATE_EXPR: - if (TREE_CODE (type) != RECORD_TYPE) - { - item = build1 (code, type, node); - break; - } - node = ffecom_stabilize_aggregate_ (node); - realtype = TREE_TYPE (TYPE_FIELDS (type)); - item = - ffecom_2 (COMPLEX_EXPR, type, - ffecom_1 (NEGATE_EXPR, realtype, - ffecom_1 (REALPART_EXPR, realtype, - node)), - ffecom_1 (NEGATE_EXPR, realtype, - ffecom_1 (IMAGPART_EXPR, realtype, - node))); - break; - - default: - item = build1 (code, type, node); - break; - } - - if (TREE_SIDE_EFFECTS (node)) - TREE_SIDE_EFFECTS (item) = 1; - if (code == ADDR_EXPR && staticp (node)) - TREE_CONSTANT (item) = 1; - else if (code == INDIRECT_REF) - TREE_READONLY (item) = TYPE_READONLY (type); - return fold (item); -} - -/* Like ffecom_1 (ADDR_EXPR, TREE_TYPE (node), node), except - handles TREE_CODE (node) == FUNCTION_DECL. In particular, - does not set TREE_ADDRESSABLE (because calling an inline - function does not mean the function needs to be separately - compiled). */ - -tree -ffecom_1_fn (tree node) -{ - tree item; - tree type; - - if (node == error_mark_node) - return error_mark_node; - - type = build_type_variant (TREE_TYPE (node), - TREE_READONLY (node), - TREE_THIS_VOLATILE (node)); - item = build1 (ADDR_EXPR, - build_pointer_type (type), node); - if (TREE_SIDE_EFFECTS (node)) - TREE_SIDE_EFFECTS (item) = 1; - if (staticp (node)) - TREE_CONSTANT (item) = 1; - return fold (item); -} - -/* Essentially does a "fold (build (code, type, node1, node2))" while - checking for certain housekeeping things. */ - -tree -ffecom_2 (enum tree_code code, tree type, tree node1, - tree node2) -{ - tree item; - - if ((node1 == error_mark_node) - || (node2 == error_mark_node) - || (type == error_mark_node)) - return error_mark_node; - - switch (ffe_is_emulate_complex () ? code : NOP_EXPR) - { - tree a, b, c, d, realtype; - - case CONJ_EXPR: - assert ("no CONJ_EXPR support yet" == NULL); - return error_mark_node; - - case COMPLEX_EXPR: - item = build_tree_list (TYPE_FIELDS (type), node1); - TREE_CHAIN (item) = build_tree_list (TREE_CHAIN (TYPE_FIELDS (type)), node2); - item = build (CONSTRUCTOR, type, NULL_TREE, item); - break; - - case PLUS_EXPR: - if (TREE_CODE (type) != RECORD_TYPE) - { - item = build (code, type, node1, node2); - break; - } - node1 = ffecom_stabilize_aggregate_ (node1); - node2 = ffecom_stabilize_aggregate_ (node2); - realtype = TREE_TYPE (TYPE_FIELDS (type)); - item = - ffecom_2 (COMPLEX_EXPR, type, - ffecom_2 (PLUS_EXPR, realtype, - ffecom_1 (REALPART_EXPR, realtype, - node1), - ffecom_1 (REALPART_EXPR, realtype, - node2)), - ffecom_2 (PLUS_EXPR, realtype, - ffecom_1 (IMAGPART_EXPR, realtype, - node1), - ffecom_1 (IMAGPART_EXPR, realtype, - node2))); - break; - - case MINUS_EXPR: - if (TREE_CODE (type) != RECORD_TYPE) - { - item = build (code, type, node1, node2); - break; - } - node1 = ffecom_stabilize_aggregate_ (node1); - node2 = ffecom_stabilize_aggregate_ (node2); - realtype = TREE_TYPE (TYPE_FIELDS (type)); - item = - ffecom_2 (COMPLEX_EXPR, type, - ffecom_2 (MINUS_EXPR, realtype, - ffecom_1 (REALPART_EXPR, realtype, - node1), - ffecom_1 (REALPART_EXPR, realtype, - node2)), - ffecom_2 (MINUS_EXPR, realtype, - ffecom_1 (IMAGPART_EXPR, realtype, - node1), - ffecom_1 (IMAGPART_EXPR, realtype, - node2))); - break; - - case MULT_EXPR: - if (TREE_CODE (type) != RECORD_TYPE) - { - item = build (code, type, node1, node2); - break; - } - node1 = ffecom_stabilize_aggregate_ (node1); - node2 = ffecom_stabilize_aggregate_ (node2); - realtype = TREE_TYPE (TYPE_FIELDS (type)); - a = save_expr (ffecom_1 (REALPART_EXPR, realtype, - node1)); - b = save_expr (ffecom_1 (IMAGPART_EXPR, realtype, - node1)); - c = save_expr (ffecom_1 (REALPART_EXPR, realtype, - node2)); - d = save_expr (ffecom_1 (IMAGPART_EXPR, realtype, - node2)); - item = - ffecom_2 (COMPLEX_EXPR, type, - ffecom_2 (MINUS_EXPR, realtype, - ffecom_2 (MULT_EXPR, realtype, - a, - c), - ffecom_2 (MULT_EXPR, realtype, - b, - d)), - ffecom_2 (PLUS_EXPR, realtype, - ffecom_2 (MULT_EXPR, realtype, - a, - d), - ffecom_2 (MULT_EXPR, realtype, - c, - b))); - break; - - case EQ_EXPR: - if ((TREE_CODE (node1) != RECORD_TYPE) - && (TREE_CODE (node2) != RECORD_TYPE)) - { - item = build (code, type, node1, node2); - break; - } - assert (TREE_CODE (node1) == RECORD_TYPE); - assert (TREE_CODE (node2) == RECORD_TYPE); - node1 = ffecom_stabilize_aggregate_ (node1); - node2 = ffecom_stabilize_aggregate_ (node2); - realtype = TREE_TYPE (TYPE_FIELDS (type)); - item = - ffecom_2 (TRUTH_ANDIF_EXPR, type, - ffecom_2 (code, type, - ffecom_1 (REALPART_EXPR, realtype, - node1), - ffecom_1 (REALPART_EXPR, realtype, - node2)), - ffecom_2 (code, type, - ffecom_1 (IMAGPART_EXPR, realtype, - node1), - ffecom_1 (IMAGPART_EXPR, realtype, - node2))); - break; - - case NE_EXPR: - if ((TREE_CODE (node1) != RECORD_TYPE) - && (TREE_CODE (node2) != RECORD_TYPE)) - { - item = build (code, type, node1, node2); - break; - } - assert (TREE_CODE (node1) == RECORD_TYPE); - assert (TREE_CODE (node2) == RECORD_TYPE); - node1 = ffecom_stabilize_aggregate_ (node1); - node2 = ffecom_stabilize_aggregate_ (node2); - realtype = TREE_TYPE (TYPE_FIELDS (type)); - item = - ffecom_2 (TRUTH_ORIF_EXPR, type, - ffecom_2 (code, type, - ffecom_1 (REALPART_EXPR, realtype, - node1), - ffecom_1 (REALPART_EXPR, realtype, - node2)), - ffecom_2 (code, type, - ffecom_1 (IMAGPART_EXPR, realtype, - node1), - ffecom_1 (IMAGPART_EXPR, realtype, - node2))); - break; - - default: - item = build (code, type, node1, node2); - break; - } - - if (TREE_SIDE_EFFECTS (node1) || TREE_SIDE_EFFECTS (node2)) - TREE_SIDE_EFFECTS (item) = 1; - return fold (item); -} - -/* ffecom_2pass_advise_entrypoint -- Advise that there's this entrypoint - - ffesymbol s; // the ENTRY point itself - if (ffecom_2pass_advise_entrypoint(s)) - // the ENTRY point has been accepted - - Does whatever compiler needs to do when it learns about the entrypoint, - like determine the return type of the master function, count the - number of entrypoints, etc. Returns FALSE if the return type is - not compatible with the return type(s) of other entrypoint(s). - - NOTE: for every call to this fn that returns TRUE, _do_entrypoint must - later (after _finish_progunit) be called with the same entrypoint(s) - as passed to this fn for which TRUE was returned. - - 03-Jan-92 JCB 2.0 - Return FALSE if the return type conflicts with previous entrypoints. */ - -bool -ffecom_2pass_advise_entrypoint (ffesymbol entry) -{ - ffebld list; /* opITEM. */ - ffebld mlist; /* opITEM. */ - ffebld plist; /* opITEM. */ - ffebld arg; /* ffebld_head(opITEM). */ - ffebld item; /* opITEM. */ - ffesymbol s; /* ffebld_symter(arg). */ - ffeinfoBasictype bt = ffesymbol_basictype (entry); - ffeinfoKindtype kt = ffesymbol_kindtype (entry); - ffetargetCharacterSize size = ffesymbol_size (entry); - bool ok; - - if (ffecom_num_entrypoints_ == 0) - { /* First entrypoint, make list of main - arglist's dummies. */ - assert (ffecom_primary_entry_ != NULL); - - ffecom_master_bt_ = ffesymbol_basictype (ffecom_primary_entry_); - ffecom_master_kt_ = ffesymbol_kindtype (ffecom_primary_entry_); - ffecom_master_size_ = ffesymbol_size (ffecom_primary_entry_); - - for (plist = NULL, list = ffesymbol_dummyargs (ffecom_primary_entry_); - list != NULL; - list = ffebld_trail (list)) - { - arg = ffebld_head (list); - if (ffebld_op (arg) != FFEBLD_opSYMTER) - continue; /* Alternate return or some such thing. */ - item = ffebld_new_item (arg, NULL); - if (plist == NULL) - ffecom_master_arglist_ = item; - else - ffebld_set_trail (plist, item); - plist = item; - } - } - - /* If necessary, scan entry arglist for alternate returns. Do this scan - apparently redundantly (it's done below to UNIONize the arglists) so - that we don't complain about RETURN 1 if an offending ENTRY is the only - one with an alternate return. */ - - if (!ffecom_is_altreturning_) - { - for (list = ffesymbol_dummyargs (entry); - list != NULL; - list = ffebld_trail (list)) - { - arg = ffebld_head (list); - if (ffebld_op (arg) == FFEBLD_opSTAR) - { - ffecom_is_altreturning_ = TRUE; - break; - } - } - } - - /* Now check type compatibility. */ - - switch (ffecom_master_bt_) - { - case FFEINFO_basictypeNONE: - ok = (bt != FFEINFO_basictypeCHARACTER); - break; - - case FFEINFO_basictypeCHARACTER: - ok - = (bt == FFEINFO_basictypeCHARACTER) - && (kt == ffecom_master_kt_) - && (size == ffecom_master_size_); - break; - - case FFEINFO_basictypeANY: - return FALSE; /* Just don't bother. */ - - default: - if (bt == FFEINFO_basictypeCHARACTER) - { - ok = FALSE; - break; - } - ok = TRUE; - if ((bt != ffecom_master_bt_) || (kt != ffecom_master_kt_)) - { - ffecom_master_bt_ = FFEINFO_basictypeNONE; - ffecom_master_kt_ = FFEINFO_kindtypeNONE; - } - break; - } - - if (!ok) - { - ffebad_start (FFEBAD_ENTRY_CONFLICTS); - ffest_ffebad_here_current_stmt (0); - ffebad_finish (); - return FALSE; /* Can't handle entrypoint. */ - } - - /* Entrypoint type compatible with previous types. */ - - ++ffecom_num_entrypoints_; - - /* Master-arg-list = UNION(Master-arg-list,entry-arg-list). */ - - for (list = ffesymbol_dummyargs (entry); - list != NULL; - list = ffebld_trail (list)) - { - arg = ffebld_head (list); - if (ffebld_op (arg) != FFEBLD_opSYMTER) - continue; /* Alternate return or some such thing. */ - s = ffebld_symter (arg); - for (plist = NULL, mlist = ffecom_master_arglist_; - mlist != NULL; - plist = mlist, mlist = ffebld_trail (mlist)) - { /* plist points to previous item for easy - appending of arg. */ - if (ffebld_symter (ffebld_head (mlist)) == s) - break; /* Already have this arg in the master list. */ - } - if (mlist != NULL) - continue; /* Already have this arg in the master list. */ - - /* Append this arg to the master list. */ - - item = ffebld_new_item (arg, NULL); - if (plist == NULL) - ffecom_master_arglist_ = item; - else - ffebld_set_trail (plist, item); - } - - return TRUE; -} - -/* ffecom_2pass_do_entrypoint -- Do compilation of entrypoint - - ffesymbol s; // the ENTRY point itself - ffecom_2pass_do_entrypoint(s); - - Does whatever compiler needs to do to make the entrypoint actually - happen. Must be called for each entrypoint after - ffecom_finish_progunit is called. */ - -void -ffecom_2pass_do_entrypoint (ffesymbol entry) -{ - static int mfn_num = 0; - static int ent_num; - - if (mfn_num != ffecom_num_fns_) - { /* First entrypoint for this program unit. */ - ent_num = 1; - mfn_num = ffecom_num_fns_; - ffecom_do_entry_ (ffecom_primary_entry_, 0); - } - else - ++ent_num; - - --ffecom_num_entrypoints_; - - ffecom_do_entry_ (entry, ent_num); -} - -/* Essentially does a "fold (build (code, type, node1, node2))" while - checking for certain housekeeping things. Always sets - TREE_SIDE_EFFECTS. */ - -tree -ffecom_2s (enum tree_code code, tree type, tree node1, - tree node2) -{ - tree item; - - if ((node1 == error_mark_node) - || (node2 == error_mark_node) - || (type == error_mark_node)) - return error_mark_node; - - item = build (code, type, node1, node2); - TREE_SIDE_EFFECTS (item) = 1; - return fold (item); -} - -/* Essentially does a "fold (build (code, type, node1, node2, node3))" while - checking for certain housekeeping things. */ - -tree -ffecom_3 (enum tree_code code, tree type, tree node1, - tree node2, tree node3) -{ - tree item; - - if ((node1 == error_mark_node) - || (node2 == error_mark_node) - || (node3 == error_mark_node) - || (type == error_mark_node)) - return error_mark_node; - - item = build (code, type, node1, node2, node3); - if (TREE_SIDE_EFFECTS (node1) || TREE_SIDE_EFFECTS (node2) - || (node3 != NULL_TREE && TREE_SIDE_EFFECTS (node3))) - TREE_SIDE_EFFECTS (item) = 1; - return fold (item); -} - -/* Essentially does a "fold (build (code, type, node1, node2, node3))" while - checking for certain housekeeping things. Always sets - TREE_SIDE_EFFECTS. */ - -tree -ffecom_3s (enum tree_code code, tree type, tree node1, - tree node2, tree node3) -{ - tree item; - - if ((node1 == error_mark_node) - || (node2 == error_mark_node) - || (node3 == error_mark_node) - || (type == error_mark_node)) - return error_mark_node; - - item = build (code, type, node1, node2, node3); - TREE_SIDE_EFFECTS (item) = 1; - return fold (item); -} - -/* ffecom_arg_expr -- Transform argument expr into gcc tree - - See use by ffecom_list_expr. - - If expression is NULL, returns an integer zero tree. If it is not - a CHARACTER expression, returns whatever ffecom_expr - returns and sets the length return value to NULL_TREE. Otherwise - generates code to evaluate the character expression, returns the proper - pointer to the result, but does NOT set the length return value to a tree - that specifies the length of the result. (In other words, the length - variable is always set to NULL_TREE, because a length is never passed.) - - 21-Dec-91 JCB 1.1 - Don't set returned length, since nobody needs it (yet; someday if - we allow CHARACTER*(*) dummies to statement functions, we'll need - it). */ - -tree -ffecom_arg_expr (ffebld expr, tree *length) -{ - tree ign; - - *length = NULL_TREE; - - if (expr == NULL) - return integer_zero_node; - - if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER) - return ffecom_expr (expr); - - return ffecom_arg_ptr_to_expr (expr, &ign); -} - -/* Transform expression into constant argument-pointer-to-expression tree. - - If the expression can be transformed into a argument-pointer-to-expression - tree that is constant, that is done, and the tree returned. Else - NULL_TREE is returned. - - That way, a caller can attempt to provide compile-time initialization - of a variable and, if that fails, *then* choose to start a new block - and resort to using temporaries, as appropriate. */ - -tree -ffecom_arg_ptr_to_const_expr (ffebld expr, tree *length) -{ - if (! expr) - return integer_zero_node; - - if (ffebld_op (expr) == FFEBLD_opANY) - { - if (length) - *length = error_mark_node; - return error_mark_node; - } - - if (ffebld_arity (expr) == 0 - && (ffebld_op (expr) != FFEBLD_opSYMTER - || ffebld_where (expr) == FFEINFO_whereCOMMON - || ffebld_where (expr) == FFEINFO_whereGLOBAL - || ffebld_where (expr) == FFEINFO_whereINTRINSIC)) - { - tree t; - - t = ffecom_arg_ptr_to_expr (expr, length); - assert (TREE_CONSTANT (t)); - assert (! length || TREE_CONSTANT (*length)); - return t; - } - - if (length - && ffebld_size (expr) != FFETARGET_charactersizeNONE) - *length = build_int_2 (ffebld_size (expr), 0); - else if (length) - *length = NULL_TREE; - return NULL_TREE; -} - -/* ffecom_arg_ptr_to_expr -- Transform argument expr into gcc tree - - See use by ffecom_list_ptr_to_expr. - - If expression is NULL, returns an integer zero tree. If it is not - a CHARACTER expression, returns whatever ffecom_ptr_to_expr - returns and sets the length return value to NULL_TREE. Otherwise - generates code to evaluate the character expression, returns the proper - pointer to the result, AND sets the length return value to a tree that - specifies the length of the result. - - If the length argument is NULL, this is a slightly special - case of building a FORMAT expression, that is, an expression that - will be used at run time without regard to length. For the current - implementation, which uses the libf2c library, this means it is nice - to append a null byte to the end of the expression, where feasible, - to make sure any diagnostic about the FORMAT string terminates at - some useful point. - - For now, treat %REF(char-expr) as the same as char-expr with a NULL - length argument. This might even be seen as a feature, if a null - byte can always be appended. */ - -tree -ffecom_arg_ptr_to_expr (ffebld expr, tree *length) -{ - tree item; - tree ign_length; - ffecomConcatList_ catlist; - - if (length != NULL) - *length = NULL_TREE; - - if (expr == NULL) - return integer_zero_node; - - switch (ffebld_op (expr)) - { - case FFEBLD_opPERCENT_VAL: - if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER) - return ffecom_expr (ffebld_left (expr)); - { - tree temp_exp; - tree temp_length; - - temp_exp = ffecom_arg_ptr_to_expr (ffebld_left (expr), &temp_length); - if (temp_exp == error_mark_node) - return error_mark_node; - - return ffecom_1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (temp_exp)), - temp_exp); - } - - case FFEBLD_opPERCENT_REF: - if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER) - return ffecom_ptr_to_expr (ffebld_left (expr)); - if (length != NULL) - { - ign_length = NULL_TREE; - length = &ign_length; - } - expr = ffebld_left (expr); - break; - - case FFEBLD_opPERCENT_DESCR: - switch (ffeinfo_basictype (ffebld_info (expr))) - { -#ifdef PASS_HOLLERITH_BY_DESCRIPTOR - case FFEINFO_basictypeHOLLERITH: -#endif - case FFEINFO_basictypeCHARACTER: - break; /* Passed by descriptor anyway. */ - - default: - item = ffecom_ptr_to_expr (expr); - if (item != error_mark_node) - *length = TYPE_SIZE (TREE_TYPE (TREE_TYPE (item))); - break; - } - break; - - default: - break; - } - -#ifdef PASS_HOLLERITH_BY_DESCRIPTOR - if ((ffeinfo_basictype (ffebld_info (expr)) == FFEINFO_basictypeHOLLERITH) - && (length != NULL)) - { /* Pass Hollerith by descriptor. */ - ffetargetHollerith h; - - assert (ffebld_op (expr) == FFEBLD_opCONTER); - h = ffebld_cu_val_hollerith (ffebld_constant_union - (ffebld_conter (expr))); - *length - = build_int_2 (h.length, 0); - TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node; - } -#endif - - if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER) - return ffecom_ptr_to_expr (expr); - - assert (ffeinfo_kindtype (ffebld_info (expr)) - == FFEINFO_kindtypeCHARACTER1); - - while (ffebld_op (expr) == FFEBLD_opPAREN) - expr = ffebld_left (expr); - - catlist = ffecom_concat_list_new_ (expr, FFETARGET_charactersizeNONE); - switch (ffecom_concat_list_count_ (catlist)) - { - case 0: /* Shouldn't happen, but in case it does... */ - if (length != NULL) - { - *length = ffecom_f2c_ftnlen_zero_node; - TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node; - } - ffecom_concat_list_kill_ (catlist); - return null_pointer_node; - - case 1: /* The (fairly) easy case. */ - if (length == NULL) - ffecom_char_args_with_null_ (&item, &ign_length, - ffecom_concat_list_expr_ (catlist, 0)); - else - ffecom_char_args_ (&item, length, - ffecom_concat_list_expr_ (catlist, 0)); - ffecom_concat_list_kill_ (catlist); - assert (item != NULL_TREE); - return item; - - default: /* Must actually concatenate things. */ - break; - } - - { - int count = ffecom_concat_list_count_ (catlist); - int i; - tree lengths; - tree items; - tree length_array; - tree item_array; - tree citem; - tree clength; - tree temporary; - tree num; - tree known_length; - ffetargetCharacterSize sz; - - sz = ffecom_concat_list_maxlen_ (catlist); - /* ~~Kludge! */ - assert (sz != FFETARGET_charactersizeNONE); - -#ifdef HOHO - length_array - = lengths - = ffecom_push_tempvar (ffecom_f2c_ftnlen_type_node, - FFETARGET_charactersizeNONE, count, TRUE); - item_array - = items - = ffecom_push_tempvar (ffecom_f2c_address_type_node, - FFETARGET_charactersizeNONE, count, TRUE); - temporary = ffecom_push_tempvar (char_type_node, - sz, -1, TRUE); -#else - { - tree hook; - - hook = ffebld_nonter_hook (expr); - assert (hook); - assert (TREE_CODE (hook) == TREE_VEC); - assert (TREE_VEC_LENGTH (hook) == 3); - length_array = lengths = TREE_VEC_ELT (hook, 0); - item_array = items = TREE_VEC_ELT (hook, 1); - temporary = TREE_VEC_ELT (hook, 2); - } -#endif - - known_length = ffecom_f2c_ftnlen_zero_node; - - for (i = 0; i < count; ++i) - { - if ((i == count) - && (length == NULL)) - ffecom_char_args_with_null_ (&citem, &clength, - ffecom_concat_list_expr_ (catlist, i)); - else - ffecom_char_args_ (&citem, &clength, - ffecom_concat_list_expr_ (catlist, i)); - if ((citem == error_mark_node) - || (clength == error_mark_node)) - { - ffecom_concat_list_kill_ (catlist); - *length = error_mark_node; - return error_mark_node; - } - - items - = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (items), - ffecom_modify (void_type_node, - ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item_array))), - item_array, - build_int_2 (i, 0)), - citem), - items); - clength = ffecom_save_tree (clength); - if (length != NULL) - known_length - = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node, - known_length, - clength); - lengths - = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (lengths), - ffecom_modify (void_type_node, - ffecom_2 (ARRAY_REF, - TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (length_array))), - length_array, - build_int_2 (i, 0)), - clength), - lengths); - } - - temporary = ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (temporary)), - temporary); - - item = build_tree_list (NULL_TREE, temporary); - TREE_CHAIN (item) - = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (items)), - items)); - TREE_CHAIN (TREE_CHAIN (item)) - = build_tree_list (NULL_TREE, - ffecom_1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (lengths)), - lengths)); - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (item))) - = build_tree_list - (NULL_TREE, - ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node, - convert (ffecom_f2c_ftnlen_type_node, - build_int_2 (count, 0)))); - num = build_int_2 (sz, 0); - TREE_TYPE (num) = ffecom_f2c_ftnlen_type_node; - TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (item)))) - = build_tree_list (NULL_TREE, num); - - item = ffecom_call_gfrt (FFECOM_gfrtCAT, item, NULL_TREE); - TREE_SIDE_EFFECTS (item) = 1; - item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (temporary), - item, - temporary); - - if (length != NULL) - *length = known_length; - } - - ffecom_concat_list_kill_ (catlist); - assert (item != NULL_TREE); - return item; -} - -/* Generate call to run-time function. - - The first arg is the GNU Fortran Run-Time function index, the second - arg is the list of arguments to pass to it. Returned is the expression - (WITHOUT TREE_SIDE_EFFECTS set!) that makes the call and returns the - result (which may be void). */ - -tree -ffecom_call_gfrt (ffecomGfrt ix, tree args, tree hook) -{ - return ffecom_call_ (ffecom_gfrt_tree_ (ix), - ffecom_gfrt_kindtype (ix), - ffe_is_f2c_library () && ffecom_gfrt_complex_[ix], - NULL_TREE, args, NULL_TREE, NULL, - NULL, NULL_TREE, TRUE, hook); -} - -/* Transform constant-union to tree. */ - -tree -ffecom_constantunion (ffebldConstantUnion *cu, ffeinfoBasictype bt, - ffeinfoKindtype kt, tree tree_type) -{ - tree item; - - switch (bt) - { - case FFEINFO_basictypeINTEGER: - { - int val; - - switch (kt) - { -#if FFETARGET_okINTEGER1 - case FFEINFO_kindtypeINTEGER1: - val = ffebld_cu_val_integer1 (*cu); - break; -#endif - -#if FFETARGET_okINTEGER2 - case FFEINFO_kindtypeINTEGER2: - val = ffebld_cu_val_integer2 (*cu); - break; -#endif - -#if FFETARGET_okINTEGER3 - case FFEINFO_kindtypeINTEGER3: - val = ffebld_cu_val_integer3 (*cu); - break; -#endif - -#if FFETARGET_okINTEGER4 - case FFEINFO_kindtypeINTEGER4: - val = ffebld_cu_val_integer4 (*cu); - break; -#endif - - default: - assert ("bad INTEGER constant kind type" == NULL); - /* Fall through. */ - case FFEINFO_kindtypeANY: - return error_mark_node; - } - item = build_int_2 (val, (val < 0) ? -1 : 0); - TREE_TYPE (item) = tree_type; - } - break; - - case FFEINFO_basictypeLOGICAL: - { - int val; - - switch (kt) - { -#if FFETARGET_okLOGICAL1 - case FFEINFO_kindtypeLOGICAL1: - val = ffebld_cu_val_logical1 (*cu); - break; -#endif - -#if FFETARGET_okLOGICAL2 - case FFEINFO_kindtypeLOGICAL2: - val = ffebld_cu_val_logical2 (*cu); - break; -#endif - -#if FFETARGET_okLOGICAL3 - case FFEINFO_kindtypeLOGICAL3: - val = ffebld_cu_val_logical3 (*cu); - break; -#endif - -#if FFETARGET_okLOGICAL4 - case FFEINFO_kindtypeLOGICAL4: - val = ffebld_cu_val_logical4 (*cu); - break; -#endif - - default: - assert ("bad LOGICAL constant kind type" == NULL); - /* Fall through. */ - case FFEINFO_kindtypeANY: - return error_mark_node; - } - item = build_int_2 (val, (val < 0) ? -1 : 0); - TREE_TYPE (item) = tree_type; - } - break; - - case FFEINFO_basictypeREAL: - { - REAL_VALUE_TYPE val; - - switch (kt) - { -#if FFETARGET_okREAL1 - case FFEINFO_kindtypeREAL1: - val = ffetarget_value_real1 (ffebld_cu_val_real1 (*cu)); - break; -#endif - -#if FFETARGET_okREAL2 - case FFEINFO_kindtypeREAL2: - val = ffetarget_value_real2 (ffebld_cu_val_real2 (*cu)); - break; -#endif - -#if FFETARGET_okREAL3 - case FFEINFO_kindtypeREAL3: - val = ffetarget_value_real3 (ffebld_cu_val_real3 (*cu)); - break; -#endif - -#if FFETARGET_okREAL4 - case FFEINFO_kindtypeREAL4: - val = ffetarget_value_real4 (ffebld_cu_val_real4 (*cu)); - break; -#endif - - default: - assert ("bad REAL constant kind type" == NULL); - /* Fall through. */ - case FFEINFO_kindtypeANY: - return error_mark_node; - } - item = build_real (tree_type, val); - } - break; - - case FFEINFO_basictypeCOMPLEX: - { - REAL_VALUE_TYPE real; - REAL_VALUE_TYPE imag; - tree el_type = ffecom_tree_type[FFEINFO_basictypeREAL][kt]; - - switch (kt) - { -#if FFETARGET_okCOMPLEX1 - case FFEINFO_kindtypeREAL1: - real = ffetarget_value_real1 (ffebld_cu_val_complex1 (*cu).real); - imag = ffetarget_value_real1 (ffebld_cu_val_complex1 (*cu).imaginary); - break; -#endif - -#if FFETARGET_okCOMPLEX2 - case FFEINFO_kindtypeREAL2: - real = ffetarget_value_real2 (ffebld_cu_val_complex2 (*cu).real); - imag = ffetarget_value_real2 (ffebld_cu_val_complex2 (*cu).imaginary); - break; -#endif - -#if FFETARGET_okCOMPLEX3 - case FFEINFO_kindtypeREAL3: - real = ffetarget_value_real3 (ffebld_cu_val_complex3 (*cu).real); - imag = ffetarget_value_real3 (ffebld_cu_val_complex3 (*cu).imaginary); - break; -#endif - -#if FFETARGET_okCOMPLEX4 - case FFEINFO_kindtypeREAL4: - real = ffetarget_value_real4 (ffebld_cu_val_complex4 (*cu).real); - imag = ffetarget_value_real4 (ffebld_cu_val_complex4 (*cu).imaginary); - break; -#endif - - default: - assert ("bad REAL constant kind type" == NULL); - /* Fall through. */ - case FFEINFO_kindtypeANY: - return error_mark_node; - } - item = ffecom_build_complex_constant_ (tree_type, - build_real (el_type, real), - build_real (el_type, imag)); - } - break; - - case FFEINFO_basictypeCHARACTER: - { /* Happens only in DATA and similar contexts. */ - ffetargetCharacter1 val; - - switch (kt) - { -#if FFETARGET_okCHARACTER1 - case FFEINFO_kindtypeLOGICAL1: - val = ffebld_cu_val_character1 (*cu); - break; -#endif - - default: - assert ("bad CHARACTER constant kind type" == NULL); - /* Fall through. */ - case FFEINFO_kindtypeANY: - return error_mark_node; - } - item = build_string (ffetarget_length_character1 (val), - ffetarget_text_character1 (val)); - TREE_TYPE (item) - = build_type_variant (build_array_type (char_type_node, - build_range_type - (integer_type_node, - integer_one_node, - build_int_2 - (ffetarget_length_character1 - (val), 0))), - 1, 0); - } - break; - - case FFEINFO_basictypeHOLLERITH: - { - ffetargetHollerith h; - - h = ffebld_cu_val_hollerith (*cu); - - /* If not at least as wide as default INTEGER, widen it. */ - if (h.length >= FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE) - item = build_string (h.length, h.text); - else - { - char str[FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE]; - - memcpy (str, h.text, h.length); - memset (&str[h.length], ' ', - FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE - - h.length); - item = build_string (FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE, - str); - } - TREE_TYPE (item) - = build_type_variant (build_array_type (char_type_node, - build_range_type - (integer_type_node, - integer_one_node, - build_int_2 - (h.length, 0))), - 1, 0); - } - break; - - case FFEINFO_basictypeTYPELESS: - { - ffetargetInteger1 ival; - ffetargetTypeless tless; - ffebad error; - - tless = ffebld_cu_val_typeless (*cu); - error = ffetarget_convert_integer1_typeless (&ival, tless); - assert (error == FFEBAD); - - item = build_int_2 ((int) ival, 0); - } - break; - - default: - assert ("not yet on constant type" == NULL); - /* Fall through. */ - case FFEINFO_basictypeANY: - return error_mark_node; - } - - TREE_CONSTANT (item) = 1; - - return item; -} - -/* Transform expression into constant tree. - - If the expression can be transformed into a tree that is constant, - that is done, and the tree returned. Else NULL_TREE is returned. - - That way, a caller can attempt to provide compile-time initialization - of a variable and, if that fails, *then* choose to start a new block - and resort to using temporaries, as appropriate. */ - -tree -ffecom_const_expr (ffebld expr) -{ - if (! expr) - return integer_zero_node; - - if (ffebld_op (expr) == FFEBLD_opANY) - return error_mark_node; - - if (ffebld_arity (expr) == 0 - && (ffebld_op (expr) != FFEBLD_opSYMTER -#if NEWCOMMON - /* ~~Enable once common/equivalence is handled properly? */ - || ffebld_where (expr) == FFEINFO_whereCOMMON -#endif - || ffebld_where (expr) == FFEINFO_whereGLOBAL - || ffebld_where (expr) == FFEINFO_whereINTRINSIC)) - { - tree t; - - t = ffecom_expr (expr); - assert (TREE_CONSTANT (t)); - return t; - } - - return NULL_TREE; -} - -/* Handy way to make a field in a struct/union. */ - -tree -ffecom_decl_field (tree context, tree prevfield, - const char *name, tree type) -{ - tree field; - - field = build_decl (FIELD_DECL, get_identifier (name), type); - DECL_CONTEXT (field) = context; - DECL_ALIGN (field) = 0; - DECL_USER_ALIGN (field) = 0; - if (prevfield != NULL_TREE) - TREE_CHAIN (prevfield) = field; - - return field; -} - -void -ffecom_close_include (FILE *f) -{ - ffecom_close_include_ (f); -} - -int -ffecom_decode_include_option (char *spec) -{ - return ffecom_decode_include_option_ (spec); -} - -/* End a compound statement (block). */ - -tree -ffecom_end_compstmt (void) -{ - return bison_rule_compstmt_ (); -} - -/* ffecom_end_transition -- Perform end transition on all symbols - - ffecom_end_transition(); - - Calls ffecom_sym_end_transition for each global and local symbol. */ - -void -ffecom_end_transition () -{ - ffebld item; - - if (ffe_is_ffedebug ()) - fprintf (dmpout, "; end_stmt_transition\n"); - - ffecom_list_blockdata_ = NULL; - ffecom_list_common_ = NULL; - - ffesymbol_drive (ffecom_sym_end_transition); - if (ffe_is_ffedebug ()) - { - ffestorag_report (); - } - - ffecom_start_progunit_ (); - - for (item = ffecom_list_blockdata_; - item != NULL; - item = ffebld_trail (item)) - { - ffebld callee; - ffesymbol s; - tree dt; - tree t; - tree var; - static int number = 0; - - callee = ffebld_head (item); - s = ffebld_symter (callee); - t = ffesymbol_hook (s).decl_tree; - if (t == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - t = ffesymbol_hook (s).decl_tree; - } - - dt = build_pointer_type (TREE_TYPE (t)); - - var = build_decl (VAR_DECL, - ffecom_get_invented_identifier ("__g77_forceload_%d", - number++), - dt); - DECL_EXTERNAL (var) = 0; - TREE_STATIC (var) = 1; - TREE_PUBLIC (var) = 0; - DECL_INITIAL (var) = error_mark_node; - TREE_USED (var) = 1; - - var = start_decl (var, FALSE); - - t = ffecom_1 (ADDR_EXPR, dt, t); - - finish_decl (var, t, FALSE); - } - - /* This handles any COMMON areas that weren't referenced but have, for - example, important initial data. */ - - for (item = ffecom_list_common_; - item != NULL; - item = ffebld_trail (item)) - ffecom_transform_common_ (ffebld_symter (ffebld_head (item))); - - ffecom_list_common_ = NULL; -} - -/* ffecom_exec_transition -- Perform exec transition on all symbols - - ffecom_exec_transition(); - - Calls ffecom_sym_exec_transition for each global and local symbol. - Make sure error updating not inhibited. */ - -void -ffecom_exec_transition () -{ - bool inhibited; - - if (ffe_is_ffedebug ()) - fprintf (dmpout, "; exec_stmt_transition\n"); - - inhibited = ffebad_inhibit (); - ffebad_set_inhibit (FALSE); - - ffesymbol_drive (ffecom_sym_exec_transition); /* Don't retract! */ - ffeequiv_exec_transition (); /* Handle all pending EQUIVALENCEs. */ - if (ffe_is_ffedebug ()) - { - ffestorag_report (); - } - - if (inhibited) - ffebad_set_inhibit (TRUE); -} - -/* Handle assignment statement. - - Convert dest and source using ffecom_expr, then join them - with an ASSIGN op and pass the whole thing to expand_expr_stmt. */ - -void -ffecom_expand_let_stmt (ffebld dest, ffebld source) -{ - tree dest_tree; - tree dest_length; - tree source_tree; - tree expr_tree; - - if (ffeinfo_basictype (ffebld_info (dest)) != FFEINFO_basictypeCHARACTER) - { - bool dest_used; - tree assign_temp; - - /* This attempts to replicate the test below, but must not be - true when the test below is false. (Always err on the side - of creating unused temporaries, to avoid ICEs.) */ - if (ffebld_op (dest) != FFEBLD_opSYMTER - || ((dest_tree = ffesymbol_hook (ffebld_symter (dest)).decl_tree) - && (TREE_CODE (dest_tree) != VAR_DECL - || TREE_ADDRESSABLE (dest_tree)))) - { - ffecom_prepare_expr_ (source, dest); - dest_used = TRUE; - } - else - { - ffecom_prepare_expr_ (source, NULL); - dest_used = FALSE; - } - - ffecom_prepare_expr_w (NULL_TREE, dest); - - /* For COMPLEX assignment like C1=C2, if partial overlap is possible, - create a temporary through which the assignment is to take place, - since MODIFY_EXPR doesn't handle partial overlap properly. */ - if (ffebld_basictype (dest) == FFEINFO_basictypeCOMPLEX - && ffecom_possible_partial_overlap_ (dest, source)) - { - assign_temp = ffecom_make_tempvar ("complex_let", - ffecom_tree_type - [ffebld_basictype (dest)] - [ffebld_kindtype (dest)], - FFETARGET_charactersizeNONE, - -1); - } - else - assign_temp = NULL_TREE; - - ffecom_prepare_end (); - - dest_tree = ffecom_expr_w (NULL_TREE, dest); - if (dest_tree == error_mark_node) - return; - - if ((TREE_CODE (dest_tree) != VAR_DECL) - || TREE_ADDRESSABLE (dest_tree)) - source_tree = ffecom_expr_ (source, dest_tree, dest, &dest_used, - FALSE, FALSE); - else - { - assert (! dest_used); - dest_used = FALSE; - source_tree = ffecom_expr (source); - } - if (source_tree == error_mark_node) - return; - - if (dest_used) - expr_tree = source_tree; - else if (assign_temp) - { -#ifdef MOVE_EXPR - /* The back end understands a conceptual move (evaluate source; - store into dest), so use that, in case it can determine - that it is going to use, say, two registers as temporaries - anyway. So don't use the temp (and someday avoid generating - it, once this code starts triggering regularly). */ - expr_tree = ffecom_2s (MOVE_EXPR, void_type_node, - dest_tree, - source_tree); -#else - expr_tree = ffecom_2s (MODIFY_EXPR, void_type_node, - assign_temp, - source_tree); - expand_expr_stmt (expr_tree); - expr_tree = ffecom_2s (MODIFY_EXPR, void_type_node, - dest_tree, - assign_temp); -#endif - } - else - expr_tree = ffecom_2s (MODIFY_EXPR, void_type_node, - dest_tree, - source_tree); - - expand_expr_stmt (expr_tree); - return; - } - - ffecom_prepare_let_char_ (ffebld_size_known (dest), source); - ffecom_prepare_expr_w (NULL_TREE, dest); - - ffecom_prepare_end (); - - ffecom_char_args_ (&dest_tree, &dest_length, dest); - ffecom_let_char_ (dest_tree, dest_length, ffebld_size_known (dest), - source); -} - -/* ffecom_expr -- Transform expr into gcc tree - - tree t; - ffebld expr; // FFE expression. - tree = ffecom_expr(expr); - - Recursive descent on expr while making corresponding tree nodes and - attaching type info and such. */ - -tree -ffecom_expr (ffebld expr) -{ - return ffecom_expr_ (expr, NULL_TREE, NULL, NULL, FALSE, FALSE); -} - -/* Like ffecom_expr, but return tree usable for assigned GOTO or FORMAT. */ - -tree -ffecom_expr_assign (ffebld expr) -{ - return ffecom_expr_ (expr, NULL_TREE, NULL, NULL, TRUE, FALSE); -} - -/* Like ffecom_expr_rw, but return tree usable for ASSIGN. */ - -tree -ffecom_expr_assign_w (ffebld expr) -{ - return ffecom_expr_ (expr, NULL_TREE, NULL, NULL, TRUE, FALSE); -} - -/* Transform expr for use as into read/write tree and stabilize the - reference. Not for use on CHARACTER expressions. - - Recursive descent on expr while making corresponding tree nodes and - attaching type info and such. */ - -tree -ffecom_expr_rw (tree type, ffebld expr) -{ - assert (expr != NULL); - /* Different target types not yet supported. */ - assert (type == NULL_TREE || type == ffecom_type_expr (expr)); - - return stabilize_reference (ffecom_expr (expr)); -} - -/* Transform expr for use as into write tree and stabilize the - reference. Not for use on CHARACTER expressions. - - Recursive descent on expr while making corresponding tree nodes and - attaching type info and such. */ - -tree -ffecom_expr_w (tree type, ffebld expr) -{ - assert (expr != NULL); - /* Different target types not yet supported. */ - assert (type == NULL_TREE || type == ffecom_type_expr (expr)); - - return stabilize_reference (ffecom_expr (expr)); -} - -/* Do global stuff. */ - -void -ffecom_finish_compile () -{ - assert (ffecom_outer_function_decl_ == NULL_TREE); - assert (current_function_decl == NULL_TREE); - - ffeglobal_drive (ffecom_finish_global_); -} - -/* Public entry point for front end to access finish_decl. */ - -void -ffecom_finish_decl (tree decl, tree init, bool is_top_level) -{ - assert (!is_top_level); - finish_decl (decl, init, FALSE); -} - -/* Finish a program unit. */ - -void -ffecom_finish_progunit () -{ - ffecom_end_compstmt (); - - ffecom_previous_function_decl_ = current_function_decl; - ffecom_which_entrypoint_decl_ = NULL_TREE; - - finish_function (0); -} - -/* Wrapper for get_identifier. pattern is sprintf-like. */ - -tree -ffecom_get_invented_identifier (const char *pattern, ...) -{ - tree decl; - char *nam; - va_list ap; - - va_start (ap, pattern); - if (vasprintf (&nam, pattern, ap) == 0) - abort (); - va_end (ap); - decl = get_identifier (nam); - free (nam); - IDENTIFIER_INVENTED (decl) = 1; - return decl; -} - -ffeinfoBasictype -ffecom_gfrt_basictype (ffecomGfrt gfrt) -{ - assert (gfrt < FFECOM_gfrt); - - switch (ffecom_gfrt_type_[gfrt]) - { - case FFECOM_rttypeVOID_: - case FFECOM_rttypeVOIDSTAR_: - return FFEINFO_basictypeNONE; - - case FFECOM_rttypeFTNINT_: - return FFEINFO_basictypeINTEGER; - - case FFECOM_rttypeINTEGER_: - return FFEINFO_basictypeINTEGER; - - case FFECOM_rttypeLONGINT_: - return FFEINFO_basictypeINTEGER; - - case FFECOM_rttypeLOGICAL_: - return FFEINFO_basictypeLOGICAL; - - case FFECOM_rttypeREAL_F2C_: - case FFECOM_rttypeREAL_GNU_: - return FFEINFO_basictypeREAL; - - case FFECOM_rttypeCOMPLEX_F2C_: - case FFECOM_rttypeCOMPLEX_GNU_: - return FFEINFO_basictypeCOMPLEX; - - case FFECOM_rttypeDOUBLE_: - case FFECOM_rttypeDOUBLEREAL_: - return FFEINFO_basictypeREAL; - - case FFECOM_rttypeDBLCMPLX_F2C_: - case FFECOM_rttypeDBLCMPLX_GNU_: - return FFEINFO_basictypeCOMPLEX; - - case FFECOM_rttypeCHARACTER_: - return FFEINFO_basictypeCHARACTER; - - default: - return FFEINFO_basictypeANY; - } -} - -ffeinfoKindtype -ffecom_gfrt_kindtype (ffecomGfrt gfrt) -{ - assert (gfrt < FFECOM_gfrt); - - switch (ffecom_gfrt_type_[gfrt]) - { - case FFECOM_rttypeVOID_: - case FFECOM_rttypeVOIDSTAR_: - return FFEINFO_kindtypeNONE; - - case FFECOM_rttypeFTNINT_: - return FFEINFO_kindtypeINTEGER1; - - case FFECOM_rttypeINTEGER_: - return FFEINFO_kindtypeINTEGER1; - - case FFECOM_rttypeLONGINT_: - return FFEINFO_kindtypeINTEGER4; - - case FFECOM_rttypeLOGICAL_: - return FFEINFO_kindtypeLOGICAL1; - - case FFECOM_rttypeREAL_F2C_: - case FFECOM_rttypeREAL_GNU_: - return FFEINFO_kindtypeREAL1; - - case FFECOM_rttypeCOMPLEX_F2C_: - case FFECOM_rttypeCOMPLEX_GNU_: - return FFEINFO_kindtypeREAL1; - - case FFECOM_rttypeDOUBLE_: - case FFECOM_rttypeDOUBLEREAL_: - return FFEINFO_kindtypeREAL2; - - case FFECOM_rttypeDBLCMPLX_F2C_: - case FFECOM_rttypeDBLCMPLX_GNU_: - return FFEINFO_kindtypeREAL2; - - case FFECOM_rttypeCHARACTER_: - return FFEINFO_kindtypeCHARACTER1; - - default: - return FFEINFO_kindtypeANY; - } -} - -void -ffecom_init_0 () -{ - tree endlink; - int i; - int j; - tree t; - tree field; - ffetype type; - ffetype base_type; - tree double_ftype_double; - tree float_ftype_float; - tree ldouble_ftype_ldouble; - tree ffecom_tree_ptr_to_fun_type_void; - - /* This block of code comes from the now-obsolete cktyps.c. It checks - whether the compiler environment is buggy in known ways, some of which - would, if not explicitly checked here, result in subtle bugs in g77. */ - - if (ffe_is_do_internal_checks ()) - { - static const char names[][12] - = - {"bar", "bletch", "foo", "foobar"}; - const char *name; - unsigned long ul; - double fl; - - name = bsearch ("foo", &names[0], ARRAY_SIZE (names), sizeof (names[0]), - (int (*)(const void *, const void *)) strcmp); - if (name != &names[0][2]) - { - assert ("bsearch doesn't work, #define FFEPROJ_BSEARCH 0 in proj.h" - == NULL); - abort (); - } - - ul = strtoul ("123456789", NULL, 10); - if (ul != 123456789L) - { - assert ("strtoul doesn't have enough range, #define FFEPROJ_STRTOUL 0\ - in proj.h" == NULL); - abort (); - } - - fl = atof ("56.789"); - if ((fl < 56.788) || (fl > 56.79)) - { - assert ("atof not type double, fix your #include " - == NULL); - abort (); - } - } - - ffecom_outer_function_decl_ = NULL_TREE; - current_function_decl = NULL_TREE; - named_labels = NULL_TREE; - current_binding_level = NULL_BINDING_LEVEL; - free_binding_level = NULL_BINDING_LEVEL; - /* Make the binding_level structure for global names. */ - pushlevel (0); - global_binding_level = current_binding_level; - current_binding_level->prep_state = 2; - - build_common_tree_nodes (1); - - /* Define `int' and `char' first so that dbx will output them first. */ - pushdecl (build_decl (TYPE_DECL, get_identifier ("int"), - integer_type_node)); - /* CHARACTER*1 is unsigned in ICHAR contexts. */ - char_type_node = make_unsigned_type (CHAR_TYPE_SIZE); - pushdecl (build_decl (TYPE_DECL, get_identifier ("char"), - char_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("long int"), - long_integer_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"), - unsigned_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("long unsigned int"), - long_unsigned_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"), - long_long_integer_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"), - long_long_unsigned_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"), - short_integer_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"), - short_unsigned_type_node)); - - /* Set the sizetype before we make other types. This *should* be the - first type we create. */ - - set_sizetype - (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)))); - ffecom_typesize_pointer_ - = TREE_INT_CST_LOW (TYPE_SIZE (sizetype)) / BITS_PER_UNIT; - - build_common_tree_nodes_2 (0); - - /* Define both `signed char' and `unsigned char'. */ - pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"), - signed_char_type_node)); - - pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"), - unsigned_char_type_node)); - - pushdecl (build_decl (TYPE_DECL, get_identifier ("float"), - float_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("double"), - double_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"), - long_double_type_node)); - - /* For now, override what build_common_tree_nodes has done. */ - complex_integer_type_node = ffecom_make_complex_type_ (integer_type_node); - complex_float_type_node = ffecom_make_complex_type_ (float_type_node); - complex_double_type_node = ffecom_make_complex_type_ (double_type_node); - complex_long_double_type_node - = ffecom_make_complex_type_ (long_double_type_node); - - pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"), - complex_integer_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), - complex_float_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"), - complex_double_type_node)); - pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"), - complex_long_double_type_node)); - - pushdecl (build_decl (TYPE_DECL, get_identifier ("void"), - void_type_node)); - /* We are not going to have real types in C with less than byte alignment, - so we might as well not have any types that claim to have it. */ - TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; - TYPE_USER_ALIGN (void_type_node) = 0; - - string_type_node = build_pointer_type (char_type_node); - - ffecom_tree_fun_type_void - = build_function_type (void_type_node, NULL_TREE); - - ffecom_tree_ptr_to_fun_type_void - = build_pointer_type (ffecom_tree_fun_type_void); - - endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE); - - float_ftype_float - = build_function_type (float_type_node, - tree_cons (NULL_TREE, float_type_node, endlink)); - - double_ftype_double - = build_function_type (double_type_node, - tree_cons (NULL_TREE, double_type_node, endlink)); - - ldouble_ftype_ldouble - = build_function_type (long_double_type_node, - tree_cons (NULL_TREE, long_double_type_node, - endlink)); - - for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i) - for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j) - { - ffecom_tree_type[i][j] = NULL_TREE; - ffecom_tree_fun_type[i][j] = NULL_TREE; - ffecom_tree_ptr_to_fun_type[i][j] = NULL_TREE; - ffecom_f2c_typecode_[i][j] = -1; - } - - /* Set up standard g77 types. Note that INTEGER and LOGICAL are set - to size FLOAT_TYPE_SIZE because they have to be the same size as - REAL, which also is FLOAT_TYPE_SIZE, according to the standard. - Compiler options and other such stuff that change the ways these - types are set should not affect this particular setup. */ - - ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER1] - = t = make_signed_type (FLOAT_TYPE_SIZE); - pushdecl (build_decl (TYPE_DECL, get_identifier ("integer"), - t)); - type = ffetype_new (); - base_type = type; - ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER1, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 1, type); - ffecom_typesize_integer1_ = ffetype_size (type); - assert (ffetype_size (type) == sizeof (ffetargetInteger1)); - - ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER1] - = t = make_unsigned_type (FLOAT_TYPE_SIZE); /* HOLLERITH means unsigned. */ - pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned"), - t)); - - ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER2] - = t = make_signed_type (CHAR_TYPE_SIZE); - pushdecl (build_decl (TYPE_DECL, get_identifier ("byte"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER2, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 3, type); - assert (ffetype_size (type) == sizeof (ffetargetInteger2)); - - ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER2] - = t = make_unsigned_type (CHAR_TYPE_SIZE); - pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned byte"), - t)); - - ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER3] - = t = make_signed_type (CHAR_TYPE_SIZE * 2); - pushdecl (build_decl (TYPE_DECL, get_identifier ("word"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER3, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 6, type); - assert (ffetype_size (type) == sizeof (ffetargetInteger3)); - - ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER3] - = t = make_unsigned_type (CHAR_TYPE_SIZE * 2); - pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned word"), - t)); - - ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER4] - = t = make_signed_type (FLOAT_TYPE_SIZE * 2); - pushdecl (build_decl (TYPE_DECL, get_identifier ("integer4"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER4, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 2, type); - assert (ffetype_size (type) == sizeof (ffetargetInteger4)); - - ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER4] - = t = make_unsigned_type (FLOAT_TYPE_SIZE * 2); - pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned4"), - t)); - -#if 0 - if (ffe_is_do_internal_checks () - && LONG_TYPE_SIZE != FLOAT_TYPE_SIZE - && LONG_TYPE_SIZE != CHAR_TYPE_SIZE - && LONG_TYPE_SIZE != SHORT_TYPE_SIZE - && LONG_TYPE_SIZE != LONG_LONG_TYPE_SIZE) - { - fprintf (stderr, "Sorry, no g77 support for LONG_TYPE_SIZE (%d bits) yet.\n", - LONG_TYPE_SIZE); - } -#endif - - ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL1] - = t = make_signed_type (FLOAT_TYPE_SIZE); - pushdecl (build_decl (TYPE_DECL, get_identifier ("logical"), - t)); - type = ffetype_new (); - base_type = type; - ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL1, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 1, type); - assert (ffetype_size (type) == sizeof (ffetargetLogical1)); - - ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL2] - = t = make_signed_type (CHAR_TYPE_SIZE); - pushdecl (build_decl (TYPE_DECL, get_identifier ("logical2"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL2, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 3, type); - assert (ffetype_size (type) == sizeof (ffetargetLogical2)); - - ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL3] - = t = make_signed_type (CHAR_TYPE_SIZE * 2); - pushdecl (build_decl (TYPE_DECL, get_identifier ("logical3"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL3, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 6, type); - assert (ffetype_size (type) == sizeof (ffetargetLogical3)); - - ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL4] - = t = make_signed_type (FLOAT_TYPE_SIZE * 2); - pushdecl (build_decl (TYPE_DECL, get_identifier ("logical4"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL4, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 2, type); - assert (ffetype_size (type) == sizeof (ffetargetLogical4)); - - ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1] - = t = make_node (REAL_TYPE); - TYPE_PRECISION (t) = FLOAT_TYPE_SIZE; - pushdecl (build_decl (TYPE_DECL, get_identifier ("real"), - t)); - layout_type (t); - type = ffetype_new (); - base_type = type; - ffeinfo_set_type (FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL1, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 1, type); - ffecom_f2c_typecode_[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1] - = FFETARGET_f2cTYREAL; - assert (ffetype_size (type) == sizeof (ffetargetReal1)); - - ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREALDOUBLE] - = t = make_node (REAL_TYPE); - TYPE_PRECISION (t) = FLOAT_TYPE_SIZE * 2; /* Always twice REAL. */ - pushdecl (build_decl (TYPE_DECL, get_identifier ("double precision"), - t)); - layout_type (t); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeREAL, FFEINFO_kindtypeREALDOUBLE, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 2, type); - ffecom_f2c_typecode_[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL2] - = FFETARGET_f2cTYDREAL; - assert (ffetype_size (type) == sizeof (ffetargetReal2)); - - ffecom_tree_type[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREAL1] - = t = ffecom_make_complex_type_ (ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1]); - pushdecl (build_decl (TYPE_DECL, get_identifier ("complex"), - t)); - type = ffetype_new (); - base_type = type; - ffeinfo_set_type (FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL1, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 1, type); - ffecom_f2c_typecode_[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREAL1] - = FFETARGET_f2cTYCOMPLEX; - assert (ffetype_size (type) == sizeof (ffetargetComplex1)); - - ffecom_tree_type[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREALDOUBLE] - = t = ffecom_make_complex_type_ (ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL2]); - pushdecl (build_decl (TYPE_DECL, get_identifier ("double complex"), - t)); - type = ffetype_new (); - ffeinfo_set_type (FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREALDOUBLE, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_star (base_type, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE, - type); - ffetype_set_kind (base_type, 2, - type); - ffecom_f2c_typecode_[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREAL2] - = FFETARGET_f2cTYDCOMPLEX; - assert (ffetype_size (type) == sizeof (ffetargetComplex2)); - - /* Make function and ptr-to-function types for non-CHARACTER types. */ - - for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i) - for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j) - { - if ((t = ffecom_tree_type[i][j]) != NULL_TREE) - { - if (i == FFEINFO_basictypeINTEGER) - { - /* Figure out the smallest INTEGER type that can hold - a pointer on this machine. */ - if (GET_MODE_SIZE (TYPE_MODE (t)) - >= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node)))) - { - if ((ffecom_pointer_kind_ == FFEINFO_kindtypeNONE) - || (GET_MODE_SIZE (TYPE_MODE (ffecom_tree_type[i][ffecom_pointer_kind_])) - > GET_MODE_SIZE (TYPE_MODE (t)))) - ffecom_pointer_kind_ = j; - } - } - else if (i == FFEINFO_basictypeCOMPLEX) - t = void_type_node; - /* For f2c compatibility, REAL functions are really - implemented as DOUBLE PRECISION. */ - else if ((i == FFEINFO_basictypeREAL) - && (j == FFEINFO_kindtypeREAL1)) - t = ffecom_tree_type - [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL2]; - - t = ffecom_tree_fun_type[i][j] = build_function_type (t, - NULL_TREE); - ffecom_tree_ptr_to_fun_type[i][j] = build_pointer_type (t); - } - } - - /* Set up pointer types. */ - - if (ffecom_pointer_kind_ == FFEINFO_basictypeNONE) - fatal_error ("no INTEGER type can hold a pointer on this configuration"); - else if (0 && ffe_is_do_internal_checks ()) - fprintf (stderr, "Pointer type kt=%d\n", ffecom_pointer_kind_); - ffetype_set_kind (ffeinfo_type (FFEINFO_basictypeINTEGER, - FFEINFO_kindtypeINTEGERDEFAULT), - 7, - ffeinfo_type (FFEINFO_basictypeINTEGER, - ffecom_pointer_kind_)); - - if (ffe_is_ugly_assign ()) - ffecom_label_kind_ = ffecom_pointer_kind_; /* Require ASSIGN etc to this. */ - else - ffecom_label_kind_ = FFEINFO_kindtypeINTEGERDEFAULT; - if (0 && ffe_is_do_internal_checks ()) - fprintf (stderr, "Label type kt=%d\n", ffecom_label_kind_); - - ffecom_integer_type_node - = ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER1]; - ffecom_integer_zero_node = convert (ffecom_integer_type_node, - integer_zero_node); - ffecom_integer_one_node = convert (ffecom_integer_type_node, - integer_one_node); - - /* Yes, the "FLOAT_TYPE_SIZE" references below are intentional. - Turns out that by TYLONG, runtime/libI77/lio.h really means - "whatever size an ftnint is". For consistency and sanity, - com.h and runtime/f2c.h.in agree that flag, ftnint, and ftlen - all are INTEGER, which we also make out of whatever back-end - integer type is FLOAT_TYPE_SIZE bits wide. This change, from - LONG_TYPE_SIZE, for TYLONG and TYLOGICAL, was necessary to - accommodate machines like the Alpha. Note that this suggests - f2c and libf2c are missing a distinction perhaps needed on - some machines between "int" and "long int". -- burley 0.5.5 950215 */ - - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, FLOAT_TYPE_SIZE, - FFETARGET_f2cTYLONG); - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, SHORT_TYPE_SIZE, - FFETARGET_f2cTYSHORT); - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, CHAR_TYPE_SIZE, - FFETARGET_f2cTYINT1); - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, LONG_LONG_TYPE_SIZE, - FFETARGET_f2cTYQUAD); - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, FLOAT_TYPE_SIZE, - FFETARGET_f2cTYLOGICAL); - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, SHORT_TYPE_SIZE, - FFETARGET_f2cTYLOGICAL2); - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, CHAR_TYPE_SIZE, - FFETARGET_f2cTYLOGICAL1); - /* ~~~Not really such a type in libf2c, e.g. I/O support? */ - ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, LONG_LONG_TYPE_SIZE, - FFETARGET_f2cTYQUAD); - - /* CHARACTER stuff is all special-cased, so it is not handled in the above - loop. CHARACTER items are built as arrays of unsigned char. */ - - ffecom_tree_type[FFEINFO_basictypeCHARACTER] - [FFEINFO_kindtypeCHARACTER1] = t = char_type_node; - type = ffetype_new (); - base_type = type; - ffeinfo_set_type (FFEINFO_basictypeCHARACTER, - FFEINFO_kindtypeCHARACTER1, - type); - ffetype_set_ams (type, - TYPE_ALIGN (t) / BITS_PER_UNIT, 0, - TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT); - ffetype_set_kind (base_type, 1, type); - assert (ffetype_size (type) - == sizeof (((ffetargetCharacter1) { 0, NULL }).text[0])); - - ffecom_tree_fun_type[FFEINFO_basictypeCHARACTER] - [FFEINFO_kindtypeCHARACTER1] = ffecom_tree_fun_type_void; - ffecom_tree_ptr_to_fun_type[FFEINFO_basictypeCHARACTER] - [FFEINFO_kindtypeCHARACTER1] - = ffecom_tree_ptr_to_fun_type_void; - ffecom_f2c_typecode_[FFEINFO_basictypeCHARACTER][FFEINFO_kindtypeCHARACTER1] - = FFETARGET_f2cTYCHAR; - - ffecom_f2c_typecode_[FFEINFO_basictypeANY][FFEINFO_kindtypeANY] - = 0; - - /* Make multi-return-value type and fields. */ - - ffecom_multi_type_node_ = make_node (UNION_TYPE); - - field = NULL_TREE; - - for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i) - for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j) - { - char name[30]; - - if (ffecom_tree_type[i][j] == NULL_TREE) - continue; /* Not supported. */ - sprintf (&name[0], "bt_%s_kt_%s", - ffeinfo_basictype_string ((ffeinfoBasictype) i), - ffeinfo_kindtype_string ((ffeinfoKindtype) j)); - ffecom_multi_fields_[i][j] = build_decl (FIELD_DECL, - get_identifier (name), - ffecom_tree_type[i][j]); - DECL_CONTEXT (ffecom_multi_fields_[i][j]) - = ffecom_multi_type_node_; - DECL_ALIGN (ffecom_multi_fields_[i][j]) = 0; - DECL_USER_ALIGN (ffecom_multi_fields_[i][j]) = 0; - TREE_CHAIN (ffecom_multi_fields_[i][j]) = field; - field = ffecom_multi_fields_[i][j]; - } - - TYPE_FIELDS (ffecom_multi_type_node_) = field; - layout_type (ffecom_multi_type_node_); - - /* Subroutines usually return integer because they might have alternate - returns. */ - - ffecom_tree_subr_type - = build_function_type (integer_type_node, NULL_TREE); - ffecom_tree_ptr_to_subr_type - = build_pointer_type (ffecom_tree_subr_type); - ffecom_tree_blockdata_type - = build_function_type (void_type_node, NULL_TREE); - - builtin_function ("__builtin_sqrtf", float_ftype_float, - BUILT_IN_SQRTF, BUILT_IN_NORMAL, "sqrtf"); - builtin_function ("__builtin_sqrt", double_ftype_double, - BUILT_IN_SQRT, BUILT_IN_NORMAL, "sqrt"); - builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, - BUILT_IN_SQRTL, BUILT_IN_NORMAL, "sqrtl"); - builtin_function ("__builtin_sinf", float_ftype_float, - BUILT_IN_SINF, BUILT_IN_NORMAL, "sinf"); - builtin_function ("__builtin_sin", double_ftype_double, - BUILT_IN_SIN, BUILT_IN_NORMAL, "sin"); - builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, - BUILT_IN_SINL, BUILT_IN_NORMAL, "sinl"); - builtin_function ("__builtin_cosf", float_ftype_float, - BUILT_IN_COSF, BUILT_IN_NORMAL, "cosf"); - builtin_function ("__builtin_cos", double_ftype_double, - BUILT_IN_COS, BUILT_IN_NORMAL, "cos"); - builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, - BUILT_IN_COSL, BUILT_IN_NORMAL, "cosl"); - - pedantic_lvalues = FALSE; - - ffecom_f2c_make_type_ (&ffecom_f2c_integer_type_node, - FFECOM_f2cINTEGER, - "integer"); - ffecom_f2c_make_type_ (&ffecom_f2c_address_type_node, - FFECOM_f2cADDRESS, - "address"); - ffecom_f2c_make_type_ (&ffecom_f2c_real_type_node, - FFECOM_f2cREAL, - "real"); - ffecom_f2c_make_type_ (&ffecom_f2c_doublereal_type_node, - FFECOM_f2cDOUBLEREAL, - "doublereal"); - ffecom_f2c_make_type_ (&ffecom_f2c_complex_type_node, - FFECOM_f2cCOMPLEX, - "complex"); - ffecom_f2c_make_type_ (&ffecom_f2c_doublecomplex_type_node, - FFECOM_f2cDOUBLECOMPLEX, - "doublecomplex"); - ffecom_f2c_make_type_ (&ffecom_f2c_longint_type_node, - FFECOM_f2cLONGINT, - "longint"); - ffecom_f2c_make_type_ (&ffecom_f2c_logical_type_node, - FFECOM_f2cLOGICAL, - "logical"); - ffecom_f2c_make_type_ (&ffecom_f2c_flag_type_node, - FFECOM_f2cFLAG, - "flag"); - ffecom_f2c_make_type_ (&ffecom_f2c_ftnlen_type_node, - FFECOM_f2cFTNLEN, - "ftnlen"); - ffecom_f2c_make_type_ (&ffecom_f2c_ftnint_type_node, - FFECOM_f2cFTNINT, - "ftnint"); - - ffecom_f2c_ftnlen_zero_node - = convert (ffecom_f2c_ftnlen_type_node, integer_zero_node); - - ffecom_f2c_ftnlen_one_node - = convert (ffecom_f2c_ftnlen_type_node, integer_one_node); - - ffecom_f2c_ftnlen_two_node = build_int_2 (2, 0); - TREE_TYPE (ffecom_f2c_ftnlen_two_node) = ffecom_integer_type_node; - - ffecom_f2c_ptr_to_ftnlen_type_node - = build_pointer_type (ffecom_f2c_ftnlen_type_node); - - ffecom_f2c_ptr_to_ftnint_type_node - = build_pointer_type (ffecom_f2c_ftnint_type_node); - - ffecom_f2c_ptr_to_integer_type_node - = build_pointer_type (ffecom_f2c_integer_type_node); - - ffecom_f2c_ptr_to_real_type_node - = build_pointer_type (ffecom_f2c_real_type_node); - - ffecom_float_zero_ = build_real (float_type_node, dconst0); - ffecom_double_zero_ = build_real (double_type_node, dconst0); - { - REAL_VALUE_TYPE point_5; - -#ifdef REAL_ARITHMETIC - REAL_ARITHMETIC (point_5, RDIV_EXPR, dconst1, dconst2); -#else - point_5 = .5; -#endif - ffecom_float_half_ = build_real (float_type_node, point_5); - ffecom_double_half_ = build_real (double_type_node, point_5); - } - - /* Do "extern int xargc;". */ - - ffecom_tree_xargc_ = build_decl (VAR_DECL, - get_identifier ("f__xargc"), - integer_type_node); - DECL_EXTERNAL (ffecom_tree_xargc_) = 1; - TREE_STATIC (ffecom_tree_xargc_) = 1; - TREE_PUBLIC (ffecom_tree_xargc_) = 1; - ffecom_tree_xargc_ = start_decl (ffecom_tree_xargc_, FALSE); - finish_decl (ffecom_tree_xargc_, NULL_TREE, FALSE); - -#if 0 /* This is being fixed, and seems to be working now. */ - if ((FLOAT_TYPE_SIZE != 32) - || (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (null_pointer_node))) != 32)) - { - warning ("configuration: REAL, INTEGER, and LOGICAL are %d bits wide,", - (int) FLOAT_TYPE_SIZE); - warning ("and pointers are %d bits wide, but g77 doesn't yet work", - (int) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (null_pointer_node)))); - warning ("properly unless they all are 32 bits wide"); - warning ("Please keep this in mind before you report bugs."); - } -#endif - -#if 0 /* Code in ste.c that would crash has been commented out. */ - if (TYPE_PRECISION (ffecom_f2c_ftnlen_type_node) - < TYPE_PRECISION (string_type_node)) - /* I/O will probably crash. */ - warning ("configuration: char * holds %d bits, but ftnlen only %d", - TYPE_PRECISION (string_type_node), - TYPE_PRECISION (ffecom_f2c_ftnlen_type_node)); -#endif - -#if 0 /* ASSIGN-related stuff has been changed to accommodate this. */ - if (TYPE_PRECISION (ffecom_integer_type_node) - < TYPE_PRECISION (string_type_node)) - /* ASSIGN 10 TO I will crash. */ - warning ("configuration: char * holds %d bits, but INTEGER only %d --\n\ - ASSIGN statement might fail", - TYPE_PRECISION (string_type_node), - TYPE_PRECISION (ffecom_integer_type_node)); -#endif -} - -/* ffecom_init_2 -- Initialize - - ffecom_init_2(); */ - -void -ffecom_init_2 () -{ - assert (ffecom_outer_function_decl_ == NULL_TREE); - assert (current_function_decl == NULL_TREE); - assert (ffecom_which_entrypoint_decl_ == NULL_TREE); - - ffecom_master_arglist_ = NULL; - ++ffecom_num_fns_; - ffecom_primary_entry_ = NULL; - ffecom_is_altreturning_ = FALSE; - ffecom_func_result_ = NULL_TREE; - ffecom_multi_retval_ = NULL_TREE; -} - -/* ffecom_list_expr -- Transform list of exprs into gcc tree - - tree t; - ffebld expr; // FFE opITEM list. - tree = ffecom_list_expr(expr); - - List of actual args is transformed into corresponding gcc backend list. */ - -tree -ffecom_list_expr (ffebld expr) -{ - tree list; - tree *plist = &list; - tree trail = NULL_TREE; /* Append char length args here. */ - tree *ptrail = &trail; - tree length; - - while (expr != NULL) - { - tree texpr = ffecom_arg_expr (ffebld_head (expr), &length); - - if (texpr == error_mark_node) - return error_mark_node; - - *plist = build_tree_list (NULL_TREE, texpr); - plist = &TREE_CHAIN (*plist); - expr = ffebld_trail (expr); - if (length != NULL_TREE) - { - *ptrail = build_tree_list (NULL_TREE, length); - ptrail = &TREE_CHAIN (*ptrail); - } - } - - *plist = trail; - - return list; -} - -/* ffecom_list_ptr_to_expr -- Transform list of exprs into gcc tree - - tree t; - ffebld expr; // FFE opITEM list. - tree = ffecom_list_ptr_to_expr(expr); - - List of actual args is transformed into corresponding gcc backend list for - use in calling an external procedure (vs. a statement function). */ - -tree -ffecom_list_ptr_to_expr (ffebld expr) -{ - tree list; - tree *plist = &list; - tree trail = NULL_TREE; /* Append char length args here. */ - tree *ptrail = &trail; - tree length; - - while (expr != NULL) - { - tree texpr = ffecom_arg_ptr_to_expr (ffebld_head (expr), &length); - - if (texpr == error_mark_node) - return error_mark_node; - - *plist = build_tree_list (NULL_TREE, texpr); - plist = &TREE_CHAIN (*plist); - expr = ffebld_trail (expr); - if (length != NULL_TREE) - { - *ptrail = build_tree_list (NULL_TREE, length); - ptrail = &TREE_CHAIN (*ptrail); - } - } - - *plist = trail; - - return list; -} - -/* Obtain gcc's LABEL_DECL tree for label. */ - -tree -ffecom_lookup_label (ffelab label) -{ - tree glabel; - - if (ffelab_hook (label) == NULL_TREE) - { - char labelname[16]; - - switch (ffelab_type (label)) - { - case FFELAB_typeLOOPEND: - case FFELAB_typeNOTLOOP: - case FFELAB_typeENDIF: - sprintf (labelname, "%" ffelabValue_f "u", ffelab_value (label)); - glabel = build_decl (LABEL_DECL, get_identifier (labelname), - void_type_node); - DECL_CONTEXT (glabel) = current_function_decl; - DECL_MODE (glabel) = VOIDmode; - break; - - case FFELAB_typeFORMAT: - glabel = build_decl (VAR_DECL, - ffecom_get_invented_identifier - ("__g77_format_%d", (int) ffelab_value (label)), - build_type_variant (build_array_type - (char_type_node, - NULL_TREE), - 1, 0)); - TREE_CONSTANT (glabel) = 1; - TREE_STATIC (glabel) = 1; - DECL_CONTEXT (glabel) = current_function_decl; - DECL_INITIAL (glabel) = NULL; - make_decl_rtl (glabel, NULL); - expand_decl (glabel); - - ffecom_save_tree_forever (glabel); - - break; - - case FFELAB_typeANY: - glabel = error_mark_node; - break; - - default: - assert ("bad label type" == NULL); - glabel = NULL; - break; - } - ffelab_set_hook (label, glabel); - } - else - { - glabel = ffelab_hook (label); - } - - return glabel; -} - -/* Stabilizes the arguments. Don't use this if the lhs and rhs come from - a single source specification (as in the fourth argument of MVBITS). - If the type is NULL_TREE, the type of lhs is used to make the type of - the MODIFY_EXPR. */ - -tree -ffecom_modify (tree newtype, tree lhs, - tree rhs) -{ - if (lhs == error_mark_node || rhs == error_mark_node) - return error_mark_node; - - if (newtype == NULL_TREE) - newtype = TREE_TYPE (lhs); - - if (TREE_SIDE_EFFECTS (lhs)) - lhs = stabilize_reference (lhs); - - return ffecom_2s (MODIFY_EXPR, newtype, lhs, rhs); -} - -/* Register source file name. */ - -void -ffecom_file (const char *name) -{ - ffecom_file_ (name); -} - -/* ffecom_notify_init_storage -- An aggregate storage is now fully init'ed - - ffestorag st; - ffecom_notify_init_storage(st); - - Gets called when all possible units in an aggregate storage area (a LOCAL - with equivalences or a COMMON) have been initialized. The initialization - info either is in ffestorag_init or, if that is NULL, - ffestorag_accretion: - - ffestorag_init may contain an opCONTER or opARRTER. opCONTER may occur - even for an array if the array is one element in length! - - ffestorag_accretion will contain an opACCTER. It is much like an - opARRTER except it has an ffebit object in it instead of just a size. - The back end can use the info in the ffebit object, if it wants, to - reduce the amount of actual initialization, but in any case it should - kill the ffebit object when done. Also, set accretion to NULL but - init to a non-NULL value. - - After performing initialization, DO NOT set init to NULL, because that'll - tell the front end it is ok for more initialization to happen. Instead, - set init to an opANY expression or some such thing that you can use to - tell that you've already initialized the object. - - 27-Oct-91 JCB 1.1 - Support two-pass FFE. */ - -void -ffecom_notify_init_storage (ffestorag st) -{ - ffebld init; /* The initialization expression. */ - - if (ffestorag_init (st) == NULL) - { - init = ffestorag_accretion (st); - assert (init != NULL); - ffestorag_set_accretion (st, NULL); - ffestorag_set_accretes (st, 0); - ffestorag_set_init (st, init); - } -} - -/* ffecom_notify_init_symbol -- A symbol is now fully init'ed - - ffesymbol s; - ffecom_notify_init_symbol(s); - - Gets called when all possible units in a symbol (not placed in COMMON - or involved in EQUIVALENCE, unless it as yet has no ffestorag object) - have been initialized. The initialization info either is in - ffesymbol_init or, if that is NULL, ffesymbol_accretion: - - ffesymbol_init may contain an opCONTER or opARRTER. opCONTER may occur - even for an array if the array is one element in length! - - ffesymbol_accretion will contain an opACCTER. It is much like an - opARRTER except it has an ffebit object in it instead of just a size. - The back end can use the info in the ffebit object, if it wants, to - reduce the amount of actual initialization, but in any case it should - kill the ffebit object when done. Also, set accretion to NULL but - init to a non-NULL value. - - After performing initialization, DO NOT set init to NULL, because that'll - tell the front end it is ok for more initialization to happen. Instead, - set init to an opANY expression or some such thing that you can use to - tell that you've already initialized the object. - - 27-Oct-91 JCB 1.1 - Support two-pass FFE. */ - -void -ffecom_notify_init_symbol (ffesymbol s) -{ - ffebld init; /* The initialization expression. */ - - if (ffesymbol_storage (s) == NULL) - return; /* Do nothing until COMMON/EQUIVALENCE - possibilities checked. */ - - if ((ffesymbol_init (s) == NULL) - && ((init = ffesymbol_accretion (s)) != NULL)) - { - ffesymbol_set_accretion (s, NULL); - ffesymbol_set_accretes (s, 0); - ffesymbol_set_init (s, init); - } -} - -/* ffecom_notify_primary_entry -- Learn which is the primary entry point - - ffesymbol s; - ffecom_notify_primary_entry(s); - - Gets called when implicit or explicit PROGRAM statement seen or when - FUNCTION, SUBROUTINE, or BLOCK DATA statement seen, with the primary - global symbol that serves as the entry point. */ - -void -ffecom_notify_primary_entry (ffesymbol s) -{ - ffecom_primary_entry_ = s; - ffecom_primary_entry_kind_ = ffesymbol_kind (s); - - if ((ffecom_primary_entry_kind_ == FFEINFO_kindFUNCTION) - || (ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE)) - ffecom_primary_entry_is_proc_ = TRUE; - else - ffecom_primary_entry_is_proc_ = FALSE; - - if (!ffe_is_silent ()) - { - if (ffecom_primary_entry_kind_ == FFEINFO_kindPROGRAM) - fprintf (stderr, "%s:\n", ffesymbol_text (s)); - else - fprintf (stderr, " %s:\n", ffesymbol_text (s)); - } - - if (ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE) - { - ffebld list; - ffebld arg; - - for (list = ffesymbol_dummyargs (s); - list != NULL; - list = ffebld_trail (list)) - { - arg = ffebld_head (list); - if (ffebld_op (arg) == FFEBLD_opSTAR) - { - ffecom_is_altreturning_ = TRUE; - break; - } - } - } -} - -FILE * -ffecom_open_include (char *name, ffewhereLine l, ffewhereColumn c) -{ - return ffecom_open_include_ (name, l, c); -} - -/* ffecom_ptr_to_expr -- Transform expr into gcc tree with & in front - - tree t; - ffebld expr; // FFE expression. - tree = ffecom_ptr_to_expr(expr); - - Like ffecom_expr, but sticks address-of in front of most things. */ - -tree -ffecom_ptr_to_expr (ffebld expr) -{ - tree item; - ffeinfoBasictype bt; - ffeinfoKindtype kt; - ffesymbol s; - - assert (expr != NULL); - - switch (ffebld_op (expr)) - { - case FFEBLD_opSYMTER: - s = ffebld_symter (expr); - if (ffesymbol_where (s) == FFEINFO_whereINTRINSIC) - { - ffecomGfrt ix; - - ix = ffeintrin_gfrt_indirect (ffebld_symter_implementation (expr)); - assert (ix != FFECOM_gfrt); - if ((item = ffecom_gfrt_[ix]) == NULL_TREE) - { - ffecom_make_gfrt_ (ix); - item = ffecom_gfrt_[ix]; - } - } - else - { - item = ffesymbol_hook (s).decl_tree; - if (item == NULL_TREE) - { - s = ffecom_sym_transform_ (s); - item = ffesymbol_hook (s).decl_tree; - } - } - assert (item != NULL); - if (item == error_mark_node) - return item; - if (!ffesymbol_hook (s).addr) - item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)), - item); - return item; - - case FFEBLD_opARRAYREF: - return ffecom_arrayref_ (NULL_TREE, expr, 1); - - case FFEBLD_opCONTER: - - bt = ffeinfo_basictype (ffebld_info (expr)); - kt = ffeinfo_kindtype (ffebld_info (expr)); - - item = ffecom_constantunion (&ffebld_constant_union - (ffebld_conter (expr)), bt, kt, - ffecom_tree_type[bt][kt]); - if (item == error_mark_node) - return error_mark_node; - item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)), - item); - return item; - - case FFEBLD_opANY: - return error_mark_node; - - default: - bt = ffeinfo_basictype (ffebld_info (expr)); - kt = ffeinfo_kindtype (ffebld_info (expr)); - - item = ffecom_expr (expr); - if (item == error_mark_node) - return error_mark_node; - - /* The back end currently optimizes a bit too zealously for us, in that - we fail JCB001 if the following block of code is omitted. It checks - to see if the transformed expression is a symbol or array reference, - and encloses it in a SAVE_EXPR if that is the case. */ - - STRIP_NOPS (item); - if ((TREE_CODE (item) == VAR_DECL) - || (TREE_CODE (item) == PARM_DECL) - || (TREE_CODE (item) == RESULT_DECL) - || (TREE_CODE (item) == INDIRECT_REF) - || (TREE_CODE (item) == ARRAY_REF) - || (TREE_CODE (item) == COMPONENT_REF) -#ifdef OFFSET_REF - || (TREE_CODE (item) == OFFSET_REF) -#endif - || (TREE_CODE (item) == BUFFER_REF) - || (TREE_CODE (item) == REALPART_EXPR) - || (TREE_CODE (item) == IMAGPART_EXPR)) - { - item = ffecom_save_tree (item); - } - - item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)), - item); - return item; - } - - assert ("fall-through error" == NULL); - return error_mark_node; -} - -/* Obtain a temp var with given data type. - - size is FFETARGET_charactersizeNONE for a non-CHARACTER type - or >= 0 for a CHARACTER type. - - elements is -1 for a scalar or > 0 for an array of type. */ - -tree -ffecom_make_tempvar (const char *commentary, tree type, - ffetargetCharacterSize size, int elements) -{ - tree t; - static int mynumber; - - assert (current_binding_level->prep_state < 2); - - if (type == error_mark_node) - return error_mark_node; - - if (size != FFETARGET_charactersizeNONE) - type = build_array_type (type, - build_range_type (ffecom_f2c_ftnlen_type_node, - ffecom_f2c_ftnlen_one_node, - build_int_2 (size, 0))); - if (elements != -1) - type = build_array_type (type, - build_range_type (integer_type_node, - integer_zero_node, - build_int_2 (elements - 1, - 0))); - t = build_decl (VAR_DECL, - ffecom_get_invented_identifier ("__g77_%s_%d", - commentary, - mynumber++), - type); - - t = start_decl (t, FALSE); - finish_decl (t, NULL_TREE, FALSE); - - return t; -} - -/* Prepare argument pointer to expression. - - Like ffecom_prepare_expr, except for expressions to be evaluated - via ffecom_arg_ptr_to_expr. */ - -void -ffecom_prepare_arg_ptr_to_expr (ffebld expr) -{ - /* ~~For now, it seems to be the same thing. */ - ffecom_prepare_expr (expr); - return; -} - -/* End of preparations. */ - -bool -ffecom_prepare_end (void) -{ - int prep_state = current_binding_level->prep_state; - - assert (prep_state < 2); - current_binding_level->prep_state = 2; - - return (prep_state == 1) ? TRUE : FALSE; -} - -/* Prepare expression. - - This is called before any code is generated for the current block. - It scans the expression, declares any temporaries that might be needed - during evaluation of the expression, and stores those temporaries in - the appropriate "hook" fields of the expression. `dest', if not NULL, - specifies the destination that ffecom_expr_ will see, in case that - helps avoid generating unused temporaries. - - ~~Improve to avoid allocating unused temporaries by taking `dest' - into account vis-a-vis aliasing requirements of complex/character - functions. */ - -void -ffecom_prepare_expr_ (ffebld expr, ffebld dest UNUSED) -{ - ffeinfoBasictype bt; - ffeinfoKindtype kt; - ffetargetCharacterSize sz; - tree tempvar = NULL_TREE; - - assert (current_binding_level->prep_state < 2); - - if (! expr) - return; - - bt = ffeinfo_basictype (ffebld_info (expr)); - kt = ffeinfo_kindtype (ffebld_info (expr)); - sz = ffeinfo_size (ffebld_info (expr)); - - /* Generate whatever temporaries are needed to represent the result - of the expression. */ - - if (bt == FFEINFO_basictypeCHARACTER) - { - while (ffebld_op (expr) == FFEBLD_opPAREN) - expr = ffebld_left (expr); - } - - switch (ffebld_op (expr)) - { - default: - /* Don't make temps for SYMTER, CONTER, etc. */ - if (ffebld_arity (expr) == 0) - break; - - switch (bt) - { - case FFEINFO_basictypeCOMPLEX: - if (ffebld_op (expr) == FFEBLD_opFUNCREF) - { - ffesymbol s; - - if (ffebld_op (ffebld_left (expr)) != FFEBLD_opSYMTER) - break; - - s = ffebld_symter (ffebld_left (expr)); - if (ffesymbol_where (s) == FFEINFO_whereCONSTANT - || (ffesymbol_where (s) != FFEINFO_whereINTRINSIC - && ! ffesymbol_is_f2c (s)) - || (ffesymbol_where (s) == FFEINFO_whereINTRINSIC - && ! ffe_is_f2c_library ())) - break; - } - else if (ffebld_op (expr) == FFEBLD_opPOWER) - { - /* Requires special treatment. There's no POW_CC function - in libg2c, so POW_ZZ is used, which means we always - need a double-complex temp, not a single-complex. */ - kt = FFEINFO_kindtypeREAL2; - } - else if (ffebld_op (expr) != FFEBLD_opDIVIDE) - /* The other ops don't need temps for complex operands. */ - break; - - /* ~~~Avoid making temps for some intrinsics, such as AIMAG(C), - REAL(C). See 19990325-0.f, routine `check', for cases. */ - tempvar = ffecom_make_tempvar ("complex", - ffecom_tree_type - [FFEINFO_basictypeCOMPLEX][kt], - FFETARGET_charactersizeNONE, - -1); - break; - - case FFEINFO_basictypeCHARACTER: - if (ffebld_op (expr) != FFEBLD_opFUNCREF) - break; - - if (sz == FFETARGET_charactersizeNONE) - /* ~~Kludge alert! This should someday be fixed. */ - sz = 24; - - tempvar = ffecom_make_tempvar ("char", char_type_node, sz, -1); - break; - - default: - break; - } - break; - -#ifdef HAHA - case FFEBLD_opPOWER: - { - tree rtype, ltype; - tree rtmp, ltmp, result; - - ltype = ffecom_type_expr (ffebld_left (expr)); - rtype = ffecom_type_expr (ffebld_right (expr)); - - rtmp = ffecom_make_tempvar (rtype, FFETARGET_charactersizeNONE, -1); - ltmp = ffecom_make_tempvar (ltype, FFETARGET_charactersizeNONE, -1); - result = ffecom_make_tempvar (ltype, FFETARGET_charactersizeNONE, -1); - - tempvar = make_tree_vec (3); - TREE_VEC_ELT (tempvar, 0) = rtmp; - TREE_VEC_ELT (tempvar, 1) = ltmp; - TREE_VEC_ELT (tempvar, 2) = result; - } - break; -#endif /* HAHA */ - - case FFEBLD_opCONCATENATE: - { - /* This gets special handling, because only one set of temps - is needed for a tree of these -- the tree is treated as - a flattened list of concatenations when generating code. */ - - ffecomConcatList_ catlist; - tree ltmp, itmp, result; - int count; - int i; - - catlist = ffecom_concat_list_new_ (expr, FFETARGET_charactersizeNONE); - count = ffecom_concat_list_count_ (catlist); - - if (count >= 2) - { - ltmp - = ffecom_make_tempvar ("concat_len", - ffecom_f2c_ftnlen_type_node, - FFETARGET_charactersizeNONE, count); - itmp - = ffecom_make_tempvar ("concat_item", - ffecom_f2c_address_type_node, - FFETARGET_charactersizeNONE, count); - result - = ffecom_make_tempvar ("concat_res", - char_type_node, - ffecom_concat_list_maxlen_ (catlist), - -1); - - tempvar = make_tree_vec (3); - TREE_VEC_ELT (tempvar, 0) = ltmp; - TREE_VEC_ELT (tempvar, 1) = itmp; - TREE_VEC_ELT (tempvar, 2) = result; - } - - for (i = 0; i < count; ++i) - ffecom_prepare_arg_ptr_to_expr (ffecom_concat_list_expr_ (catlist, - i)); - - ffecom_concat_list_kill_ (catlist); - - if (tempvar) - { - ffebld_nonter_set_hook (expr, tempvar); - current_binding_level->prep_state = 1; - } - } - return; - - case FFEBLD_opCONVERT: - if (bt == FFEINFO_basictypeCHARACTER - && ((ffebld_size_known (ffebld_left (expr)) - == FFETARGET_charactersizeNONE) - || (ffebld_size_known (ffebld_left (expr)) >= sz))) - tempvar = ffecom_make_tempvar ("convert", char_type_node, sz, -1); - break; - } - - if (tempvar) - { - ffebld_nonter_set_hook (expr, tempvar); - current_binding_level->prep_state = 1; - } - - /* Prepare subexpressions for this expr. */ - - switch (ffebld_op (expr)) - { - case FFEBLD_opPERCENT_LOC: - ffecom_prepare_ptr_to_expr (ffebld_left (expr)); - break; - - case FFEBLD_opPERCENT_VAL: - case FFEBLD_opPERCENT_REF: - ffecom_prepare_expr (ffebld_left (expr)); - break; - - case FFEBLD_opPERCENT_DESCR: - ffecom_prepare_arg_ptr_to_expr (ffebld_left (expr)); - break; - - case FFEBLD_opITEM: - { - ffebld item; - - for (item = expr; - item != NULL; - item = ffebld_trail (item)) - if (ffebld_head (item) != NULL) - ffecom_prepare_expr (ffebld_head (item)); - } - break; - - default: - /* Need to handle character conversion specially. */ - switch (ffebld_arity (expr)) - { - case 2: - ffecom_prepare_expr (ffebld_left (expr)); - ffecom_prepare_expr (ffebld_right (expr)); - break; - - case 1: - ffecom_prepare_expr (ffebld_left (expr)); - break; - - default: - break; - } - } - - return; -} - -/* Prepare expression for reading and writing. - - Like ffecom_prepare_expr, except for expressions to be evaluated - via ffecom_expr_rw. */ - -void -ffecom_prepare_expr_rw (tree type, ffebld expr) -{ - /* This is all we support for now. */ - assert (type == NULL_TREE || type == ffecom_type_expr (expr)); - - /* ~~For now, it seems to be the same thing. */ - ffecom_prepare_expr (expr); - return; -} - -/* Prepare expression for writing. - - Like ffecom_prepare_expr, except for expressions to be evaluated - via ffecom_expr_w. */ - -void -ffecom_prepare_expr_w (tree type, ffebld expr) -{ - /* This is all we support for now. */ - assert (type == NULL_TREE || type == ffecom_type_expr (expr)); - - /* ~~For now, it seems to be the same thing. */ - ffecom_prepare_expr (expr); - return; -} - -/* Prepare expression for returning. - - Like ffecom_prepare_expr, except for expressions to be evaluated - via ffecom_return_expr. */ - -void -ffecom_prepare_return_expr (ffebld expr) -{ - assert (current_binding_level->prep_state < 2); - - if (ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE - && ffecom_is_altreturning_ - && expr != NULL) - ffecom_prepare_expr (expr); -} - -/* Prepare pointer to expression. - - Like ffecom_prepare_expr, except for expressions to be evaluated - via ffecom_ptr_to_expr. */ - -void -ffecom_prepare_ptr_to_expr (ffebld expr) -{ - /* ~~For now, it seems to be the same thing. */ - ffecom_prepare_expr (expr); - return; -} - -/* Transform expression into constant pointer-to-expression tree. - - If the expression can be transformed into a pointer-to-expression tree - that is constant, that is done, and the tree returned. Else NULL_TREE - is returned. - - That way, a caller can attempt to provide compile-time initialization - of a variable and, if that fails, *then* choose to start a new block - and resort to using temporaries, as appropriate. */ - -tree -ffecom_ptr_to_const_expr (ffebld expr) -{ - if (! expr) - return integer_zero_node; - - if (ffebld_op (expr) == FFEBLD_opANY) - return error_mark_node; - - if (ffebld_arity (expr) == 0 - && (ffebld_op (expr) != FFEBLD_opSYMTER - || ffebld_where (expr) == FFEINFO_whereCOMMON - || ffebld_where (expr) == FFEINFO_whereGLOBAL - || ffebld_where (expr) == FFEINFO_whereINTRINSIC)) - { - tree t; - - t = ffecom_ptr_to_expr (expr); - assert (TREE_CONSTANT (t)); - return t; - } - - return NULL_TREE; -} - -/* ffecom_return_expr -- Returns return-value expr given alt return expr - - tree rtn; // NULL_TREE means use expand_null_return() - ffebld expr; // NULL if no alt return expr to RETURN stmt - rtn = ffecom_return_expr(expr); - - Based on the program unit type and other info (like return function - type, return master function type when alternate ENTRY points, - whether subroutine has any alternate RETURN points, etc), returns the - appropriate expression to be returned to the caller, or NULL_TREE - meaning no return value or the caller expects it to be returned somewhere - else (which is handled by other parts of this module). */ - -tree -ffecom_return_expr (ffebld expr) -{ - tree rtn; - - switch (ffecom_primary_entry_kind_) - { - case FFEINFO_kindPROGRAM: - case FFEINFO_kindBLOCKDATA: - rtn = NULL_TREE; - break; - - case FFEINFO_kindSUBROUTINE: - if (!ffecom_is_altreturning_) - rtn = NULL_TREE; /* No alt returns, never an expr. */ - else if (expr == NULL) - rtn = integer_zero_node; - else - rtn = ffecom_expr (expr); - break; - - case FFEINFO_kindFUNCTION: - if ((ffecom_multi_retval_ != NULL_TREE) - || (ffesymbol_basictype (ffecom_primary_entry_) - == FFEINFO_basictypeCHARACTER) - || ((ffesymbol_basictype (ffecom_primary_entry_) - == FFEINFO_basictypeCOMPLEX) - && (ffecom_num_entrypoints_ == 0) - && ffesymbol_is_f2c (ffecom_primary_entry_))) - { /* Value is returned by direct assignment - into (implicit) dummy. */ - rtn = NULL_TREE; - break; - } - rtn = ffecom_func_result_; -#if 0 - /* Spurious error if RETURN happens before first reference! So elide - this code. In particular, for debugging registry, rtn should always - be non-null after all, but TREE_USED won't be set until we encounter - a reference in the code. Perfectly okay (but weird) code that, - e.g., has "GOTO 20;10 RETURN;20 RTN=0;GOTO 10", would result in - this diagnostic for no reason. Have people use -O -Wuninitialized - and leave it to the back end to find obviously weird cases. */ - - /* Used to "assert(rtn != NULL_TREE);" here, but it's kind of a valid - situation; if the return value has never been referenced, it won't - have a tree under 2pass mode. */ - if ((rtn == NULL_TREE) - || !TREE_USED (rtn)) - { - ffebad_start (FFEBAD_RETURN_VALUE_UNSET); - ffebad_here (0, ffesymbol_where_line (ffecom_primary_entry_), - ffesymbol_where_column (ffecom_primary_entry_)); - ffebad_string (ffesymbol_text (ffesymbol_funcresult - (ffecom_primary_entry_))); - ffebad_finish (); - } -#endif - break; - - default: - assert ("bad unit kind" == NULL); - case FFEINFO_kindANY: - rtn = error_mark_node; - break; - } - - return rtn; -} - -/* Do save_expr only if tree is not error_mark_node. */ - -tree -ffecom_save_tree (tree t) -{ - return save_expr (t); -} - -/* Start a compound statement (block). */ - -void -ffecom_start_compstmt (void) -{ - bison_rule_pushlevel_ (); -} - -/* Public entry point for front end to access start_decl. */ - -tree -ffecom_start_decl (tree decl, bool is_initialized) -{ - DECL_INITIAL (decl) = is_initialized ? error_mark_node : NULL_TREE; - return start_decl (decl, FALSE); -} - -/* ffecom_sym_commit -- Symbol's state being committed to reality - - ffesymbol s; - ffecom_sym_commit(s); - - Does whatever the backend needs when a symbol is committed after having - been backtrackable for a period of time. */ - -void -ffecom_sym_commit (ffesymbol s UNUSED) -{ - assert (!ffesymbol_retractable ()); -} - -/* ffecom_sym_end_transition -- Perform end transition on all symbols - - ffecom_sym_end_transition(); - - Does backend-specific stuff and also calls ffest_sym_end_transition - to do the necessary FFE stuff. - - Backtracking is never enabled when this fn is called, so don't worry - about it. */ - -ffesymbol -ffecom_sym_end_transition (ffesymbol s) -{ - ffestorag st; - - assert (!ffesymbol_retractable ()); - - s = ffest_sym_end_transition (s); - - if ((ffesymbol_kind (s) == FFEINFO_kindBLOCKDATA) - && (ffesymbol_where (s) == FFEINFO_whereGLOBAL)) - { - ffecom_list_blockdata_ - = ffebld_new_item (ffebld_new_symter (s, FFEINTRIN_genNONE, - FFEINTRIN_specNONE, - FFEINTRIN_impNONE), - ffecom_list_blockdata_); - } - - /* This is where we finally notice that a symbol has partial initialization - and finalize it. */ - - if (ffesymbol_accretion (s) != NULL) - { - assert (ffesymbol_init (s) == NULL); - ffecom_notify_init_symbol (s); - } - else if (((st = ffesymbol_storage (s)) != NULL) - && ((st = ffestorag_parent (st)) != NULL) - && (ffestorag_accretion (st) != NULL)) - { - assert (ffestorag_init (st) == NULL); - ffecom_notify_init_storage (st); - } - - if ((ffesymbol_kind (s) == FFEINFO_kindCOMMON) - && (ffesymbol_where (s) == FFEINFO_whereLOCAL) - && (ffesymbol_storage (s) != NULL)) - { - ffecom_list_common_ - = ffebld_new_item (ffebld_new_symter (s, FFEINTRIN_genNONE, - FFEINTRIN_specNONE, - FFEINTRIN_impNONE), - ffecom_list_common_); - } - - return s; -} - -/* ffecom_sym_exec_transition -- Perform exec transition on all symbols - - ffecom_sym_exec_transition(); - - Does backend-specific stuff and also calls ffest_sym_exec_transition - to do the necessary FFE stuff. - - See the long-winded description in ffecom_sym_learned for info - on handling the situation where backtracking is inhibited. */ - -ffesymbol -ffecom_sym_exec_transition (ffesymbol s) -{ - s = ffest_sym_exec_transition (s); - - return s; -} - -/* ffecom_sym_learned -- Initial or more info gained on symbol after exec - - ffesymbol s; - s = ffecom_sym_learned(s); - - Called when a new symbol is seen after the exec transition or when more - info (perhaps) is gained for an UNCERTAIN symbol. The symbol state when - it arrives here is that all its latest info is updated already, so its - state may be UNCERTAIN or UNDERSTOOD, it might already have the hook - field filled in if its gone through here or exec_transition first, and - so on. - - The backend probably wants to check ffesymbol_retractable() to see if - backtracking is in effect. If so, the FFE's changes to the symbol may - be retracted (undone) or committed (ratified), at which time the - appropriate ffecom_sym_retract or _commit function will be called - for that function. - - If the backend has its own backtracking mechanism, great, use it so that - committal is a simple operation. Though it doesn't make much difference, - I suppose: the reason for tentative symbol evolution in the FFE is to - enable error detection in weird incorrect statements early and to disable - incorrect error detection on a correct statement. The backend is not - likely to introduce any information that'll get involved in these - considerations, so it is probably just fine that the implementation - model for this fn and for _exec_transition is to not do anything - (besides the required FFE stuff) if ffesymbol_retractable() returns TRUE - and instead wait until ffecom_sym_commit is called (which it never - will be as long as we're using ambiguity-detecting statement analysis in - the FFE, which we are initially to shake out the code, but don't depend - on this), otherwise go ahead and do whatever is needed. - - In essence, then, when this fn and _exec_transition get called while - backtracking is enabled, a general mechanism would be to flag which (or - both) of these were called (and in what order? neat question as to what - might happen that I'm too lame to think through right now) and then when - _commit is called reproduce the original calling sequence, if any, for - the two fns (at which point backtracking will, of course, be disabled). */ - -ffesymbol -ffecom_sym_learned (ffesymbol s) -{ - ffestorag_exec_layout (s); - - return s; -} - -/* ffecom_sym_retract -- Symbol's state being retracted from reality - - ffesymbol s; - ffecom_sym_retract(s); - - Does whatever the backend needs when a symbol is retracted after having - been backtrackable for a period of time. */ - -void -ffecom_sym_retract (ffesymbol s UNUSED) -{ - assert (!ffesymbol_retractable ()); - -#if 0 /* GCC doesn't commit any backtrackable sins, - so nothing needed here. */ - switch (ffesymbol_hook (s).state) - { - case 0: /* nothing happened yet. */ - break; - - case 1: /* exec transition happened. */ - break; - - case 2: /* learned happened. */ - break; - - case 3: /* learned then exec. */ - break; - - case 4: /* exec then learned. */ - break; - - default: - assert ("bad hook state" == NULL); - break; - } -#endif -} - -/* Create temporary gcc label. */ - -tree -ffecom_temp_label () -{ - tree glabel; - static int mynumber = 0; - - glabel = build_decl (LABEL_DECL, - ffecom_get_invented_identifier ("__g77_label_%d", - mynumber++), - void_type_node); - DECL_CONTEXT (glabel) = current_function_decl; - DECL_MODE (glabel) = VOIDmode; - - return glabel; -} - -/* Return an expression that is usable as an arg in a conditional context - (IF, DO WHILE, .NOT., and so on). - - Use the one provided for the back end as of >2.6.0. */ - -tree -ffecom_truth_value (tree expr) -{ - return truthvalue_conversion (expr); -} - -/* Return the inversion of a truth value (the inversion of what - ffecom_truth_value builds). - - Apparently invert_truthvalue, which is properly in the back end, is - enough for now, so just use it. */ - -tree -ffecom_truth_value_invert (tree expr) -{ - return invert_truthvalue (ffecom_truth_value (expr)); -} - -/* Return the tree that is the type of the expression, as would be - returned in TREE_TYPE(ffecom_expr(expr)), without otherwise - transforming the expression, generating temporaries, etc. */ - -tree -ffecom_type_expr (ffebld expr) -{ - ffeinfoBasictype bt; - ffeinfoKindtype kt; - tree tree_type; - - assert (expr != NULL); - - bt = ffeinfo_basictype (ffebld_info (expr)); - kt = ffeinfo_kindtype (ffebld_info (expr)); - tree_type = ffecom_tree_type[bt][kt]; - - switch (ffebld_op (expr)) - { - case FFEBLD_opCONTER: - case FFEBLD_opSYMTER: - case FFEBLD_opARRAYREF: - case FFEBLD_opUPLUS: - case FFEBLD_opPAREN: - case FFEBLD_opUMINUS: - case FFEBLD_opADD: - case FFEBLD_opSUBTRACT: - case FFEBLD_opMULTIPLY: - case FFEBLD_opDIVIDE: - case FFEBLD_opPOWER: - case FFEBLD_opNOT: - case FFEBLD_opFUNCREF: - case FFEBLD_opSUBRREF: - case FFEBLD_opAND: - case FFEBLD_opOR: - case FFEBLD_opXOR: - case FFEBLD_opNEQV: - case FFEBLD_opEQV: - case FFEBLD_opCONVERT: - case FFEBLD_opLT: - case FFEBLD_opLE: - case FFEBLD_opEQ: - case FFEBLD_opNE: - case FFEBLD_opGT: - case FFEBLD_opGE: - case FFEBLD_opPERCENT_LOC: - return tree_type; - - case FFEBLD_opACCTER: - case FFEBLD_opARRTER: - case FFEBLD_opITEM: - case FFEBLD_opSTAR: - case FFEBLD_opBOUNDS: - case FFEBLD_opREPEAT: - case FFEBLD_opLABTER: - case FFEBLD_opLABTOK: - case FFEBLD_opIMPDO: - case FFEBLD_opCONCATENATE: - case FFEBLD_opSUBSTR: - default: - assert ("bad op for ffecom_type_expr" == NULL); - /* Fall through. */ - case FFEBLD_opANY: - return error_mark_node; - } -} - -/* Return PARM_DECL for arg#1 of master fn containing alternate ENTRY points - - If the PARM_DECL already exists, return it, else create it. It's an - integer_type_node argument for the master function that implements a - subroutine or function with more than one entrypoint and is bound at - run time with the entrypoint number (0 for SUBROUTINE/FUNCTION, 1 for - first ENTRY statement, and so on). */ - -tree -ffecom_which_entrypoint_decl () -{ - assert (ffecom_which_entrypoint_decl_ != NULL_TREE); - - return ffecom_which_entrypoint_decl_; -} - -/* The following sections consists of private and public functions - that have the same names and perform roughly the same functions - as counterparts in the C front end. Changes in the C front end - might affect how things should be done here. Only functions - needed by the back end should be public here; the rest should - be private (static in the C sense). Functions needed by other - g77 front-end modules should be accessed by them via public - ffecom_* names, which should themselves call private versions - in this section so the private versions are easy to recognize - when upgrading to a new gcc and finding interesting changes - in the front end. - - Functions named after rule "foo:" in c-parse.y are named - "bison_rule_foo_" so they are easy to find. */ - -static void -bison_rule_pushlevel_ () -{ - emit_line_note (input_filename, lineno); - pushlevel (0); - clear_last_expr (); - expand_start_bindings (0); -} - -static tree -bison_rule_compstmt_ () -{ - tree t; - int keep = kept_level_p (); - - /* Make the temps go away. */ - if (! keep) - current_binding_level->names = NULL_TREE; - - emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), keep, 0); - t = poplevel (keep, 1, 0); - - return t; -} - -/* Return a definition for a builtin function named NAME and whose data type - is TYPE. TYPE should be a function type with argument types. - FUNCTION_CODE tells later passes how to compile calls to this function. - See tree.h for its possible values. - - If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, - the name to be called if we can't opencode the function. */ - -tree -builtin_function (const char *name, tree type, int function_code, - enum built_in_class class, - const char *library_name) -{ - tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); - DECL_EXTERNAL (decl) = 1; - TREE_PUBLIC (decl) = 1; - if (library_name) - SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name)); - make_decl_rtl (decl, NULL); - pushdecl (decl); - DECL_BUILT_IN_CLASS (decl) = class; - DECL_FUNCTION_CODE (decl) = function_code; - - return decl; -} - -/* Handle when a new declaration NEWDECL - has the same name as an old one OLDDECL - in the same binding contour. - Prints an error message if appropriate. - - If safely possible, alter OLDDECL to look like NEWDECL, and return 1. - Otherwise, return 0. */ - -static int -duplicate_decls (tree newdecl, tree olddecl) -{ - int types_match = 1; - int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL - && DECL_INITIAL (newdecl) != 0); - tree oldtype = TREE_TYPE (olddecl); - tree newtype = TREE_TYPE (newdecl); - - if (olddecl == newdecl) - return 1; - - if (TREE_CODE (newtype) == ERROR_MARK - || TREE_CODE (oldtype) == ERROR_MARK) - types_match = 0; - - /* New decl is completely inconsistent with the old one => - tell caller to replace the old one. - This is always an error except in the case of shadowing a builtin. */ - if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) - return 0; - - /* For real parm decl following a forward decl, - return 1 so old decl will be reused. */ - if (types_match && TREE_CODE (newdecl) == PARM_DECL - && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl)) - return 1; - - /* The new declaration is the same kind of object as the old one. - The declarations may partially match. Print warnings if they don't - match enough. Ultimately, copy most of the information from the new - decl to the old one, and keep using the old one. */ - - if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_BUILT_IN (olddecl)) - { - /* A function declaration for a built-in function. */ - if (!TREE_PUBLIC (newdecl)) - return 0; - else if (!types_match) - { - /* Accept the return type of the new declaration if same modes. */ - tree oldreturntype = TREE_TYPE (TREE_TYPE (olddecl)); - tree newreturntype = TREE_TYPE (TREE_TYPE (newdecl)); - - if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype)) - { - /* Function types may be shared, so we can't just modify - the return type of olddecl's function type. */ - tree newtype - = build_function_type (newreturntype, - TYPE_ARG_TYPES (TREE_TYPE (olddecl))); - - types_match = 1; - if (types_match) - TREE_TYPE (olddecl) = newtype; - } - } - if (!types_match) - return 0; - } - else if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_SOURCE_LINE (olddecl) == 0) - { - /* A function declaration for a predeclared function - that isn't actually built in. */ - if (!TREE_PUBLIC (newdecl)) - return 0; - else if (!types_match) - { - /* If the types don't match, preserve volatility indication. - Later on, we will discard everything else about the - default declaration. */ - TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); - } - } - - /* Copy all the DECL_... slots specified in the new decl - except for any that we copy here from the old type. - - Past this point, we don't change OLDTYPE and NEWTYPE - even if we change the types of NEWDECL and OLDDECL. */ - - if (types_match) - { - /* Merge the data types specified in the two decls. */ - if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl)) - TREE_TYPE (newdecl) - = TREE_TYPE (olddecl) - = TREE_TYPE (newdecl); - - /* Lay the type out, unless already done. */ - if (oldtype != TREE_TYPE (newdecl)) - { - if (TREE_TYPE (newdecl) != error_mark_node) - layout_type (TREE_TYPE (newdecl)); - if (TREE_CODE (newdecl) != FUNCTION_DECL - && TREE_CODE (newdecl) != TYPE_DECL - && TREE_CODE (newdecl) != CONST_DECL) - layout_decl (newdecl, 0); - } - else - { - /* Since the type is OLDDECL's, make OLDDECL's size go with. */ - DECL_SIZE (newdecl) = DECL_SIZE (olddecl); - DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); - if (TREE_CODE (olddecl) != FUNCTION_DECL) - if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) - { - DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); - DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); - } - } - - /* Keep the old rtl since we can safely use it. */ - COPY_DECL_RTL (olddecl, newdecl); - - /* Merge the type qualifiers. */ - if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl) - && !TREE_THIS_VOLATILE (newdecl)) - TREE_THIS_VOLATILE (olddecl) = 0; - if (TREE_READONLY (newdecl)) - TREE_READONLY (olddecl) = 1; - if (TREE_THIS_VOLATILE (newdecl)) - { - TREE_THIS_VOLATILE (olddecl) = 1; - if (TREE_CODE (newdecl) == VAR_DECL) - make_var_volatile (newdecl); - } - - /* Keep source location of definition rather than declaration. - Likewise, keep decl at outer scope. */ - if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0) - || (DECL_CONTEXT (newdecl) != 0 && DECL_CONTEXT (olddecl) == 0)) - { - DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); - DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl); - - if (DECL_CONTEXT (olddecl) == 0 - && TREE_CODE (newdecl) != FUNCTION_DECL) - DECL_CONTEXT (newdecl) = 0; - } - - /* Merge the unused-warning information. */ - if (DECL_IN_SYSTEM_HEADER (olddecl)) - DECL_IN_SYSTEM_HEADER (newdecl) = 1; - else if (DECL_IN_SYSTEM_HEADER (newdecl)) - DECL_IN_SYSTEM_HEADER (olddecl) = 1; - - /* Merge the initialization information. */ - if (DECL_INITIAL (newdecl) == 0) - DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - - /* Merge the section attribute. - We want to issue an error if the sections conflict but that must be - done later in decl_attributes since we are called before attributes - are assigned. */ - if (DECL_SECTION_NAME (newdecl) == NULL_TREE) - DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl); - - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl); - DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); - } - } - /* If cannot merge, then use the new type and qualifiers, - and don't preserve the old rtl. */ - else - { - TREE_TYPE (olddecl) = TREE_TYPE (newdecl); - TREE_READONLY (olddecl) = TREE_READONLY (newdecl); - TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); - TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); - } - - /* Merge the storage class information. */ - /* For functions, static overrides non-static. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL) - { - TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl); - /* This is since we don't automatically - copy the attributes of NEWDECL into OLDDECL. */ - TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); - /* If this clears `static', clear it in the identifier too. */ - if (! TREE_PUBLIC (olddecl)) - TREE_PUBLIC (DECL_NAME (olddecl)) = 0; - } - if (DECL_EXTERNAL (newdecl)) - { - TREE_STATIC (newdecl) = TREE_STATIC (olddecl); - DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl); - /* An extern decl does not override previous storage class. */ - TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); - } - else - { - TREE_STATIC (olddecl) = TREE_STATIC (newdecl); - TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); - } - - /* If either decl says `inline', this fn is inline, - unless its definition was passed already. */ - if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0) - DECL_INLINE (olddecl) = 1; - DECL_INLINE (newdecl) = DECL_INLINE (olddecl); - - /* Get rid of any built-in function if new arg types don't match it - or if we have a function definition. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL - && DECL_BUILT_IN (olddecl) - && (!types_match || new_is_definition)) - { - TREE_TYPE (olddecl) = TREE_TYPE (newdecl); - DECL_BUILT_IN_CLASS (olddecl) = NOT_BUILT_IN; - } - - /* If redeclaring a builtin function, and not a definition, - it stays built in. - Also preserve various other info from the definition. */ - if (TREE_CODE (newdecl) == FUNCTION_DECL && !new_is_definition) - { - if (DECL_BUILT_IN (olddecl)) - { - DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); - DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); - } - - DECL_RESULT (newdecl) = DECL_RESULT (olddecl); - DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); - DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); - DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); - } - - /* Copy most of the decl-specific fields of NEWDECL into OLDDECL. - But preserve olddecl's DECL_UID. */ - { - register unsigned olddecl_uid = DECL_UID (olddecl); - - memcpy ((char *) olddecl + sizeof (struct tree_common), - (char *) newdecl + sizeof (struct tree_common), - sizeof (struct tree_decl) - sizeof (struct tree_common)); - DECL_UID (olddecl) = olddecl_uid; - } - - return 1; -} - -/* Finish processing of a declaration; - install its initial value. - If the length of an array type is not known before, - it must be determined now, from the initial value, or it is an error. */ - -static void -finish_decl (tree decl, tree init, bool is_top_level) -{ - register tree type = TREE_TYPE (decl); - int was_incomplete = (DECL_SIZE (decl) == 0); - bool at_top_level = (current_binding_level == global_binding_level); - bool top_level = is_top_level || at_top_level; - - /* Caller should pass TRUE for is_top_level only if we wouldn't be at top - level anyway. */ - assert (!is_top_level || !at_top_level); - - if (TREE_CODE (decl) == PARM_DECL) - assert (init == NULL_TREE); - /* Remember that PARM_DECL doesn't have a DECL_INITIAL field per se -- it - overlaps DECL_ARG_TYPE. */ - else if (init == NULL_TREE) - assert (DECL_INITIAL (decl) == NULL_TREE); - else - assert (DECL_INITIAL (decl) == error_mark_node); - - if (init != NULL_TREE) - { - if (TREE_CODE (decl) != TYPE_DECL) - DECL_INITIAL (decl) = init; - else - { - /* typedef foo = bar; store the type of bar as the type of foo. */ - TREE_TYPE (decl) = TREE_TYPE (init); - DECL_INITIAL (decl) = init = 0; - } - } - - /* Deduce size of array from initialization, if not already known */ - - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) == 0 - && TREE_CODE (decl) != TYPE_DECL) - { - assert (top_level); - assert (was_incomplete); - - layout_decl (decl, 0); - } - - if (TREE_CODE (decl) == VAR_DECL) - { - if (DECL_SIZE (decl) == NULL_TREE - && TYPE_SIZE (TREE_TYPE (decl)) != NULL_TREE) - layout_decl (decl, 0); - - if (DECL_SIZE (decl) == NULL_TREE - && (TREE_STATIC (decl) - ? - /* A static variable with an incomplete type is an error if it is - initialized. Also if it is not file scope. Otherwise, let it - through, but if it is not `extern' then it may cause an error - message later. */ - (DECL_INITIAL (decl) != 0 || DECL_CONTEXT (decl) != 0) - : - /* An automatic variable with an incomplete type is an error. */ - !DECL_EXTERNAL (decl))) - { - assert ("storage size not known" == NULL); - abort (); - } - - if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) - && (DECL_SIZE (decl) != 0) - && (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)) - { - assert ("storage size not constant" == NULL); - abort (); - } - } - - /* Output the assembler code and/or RTL code for variables and functions, - unless the type is an undefined structure or union. If not, it will get - done when the type is completed. */ - - if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) - { - rest_of_decl_compilation (decl, NULL, - DECL_CONTEXT (decl) == 0, - 0); - - if (DECL_CONTEXT (decl) != 0) - { - /* Recompute the RTL of a local array now if it used to be an - incomplete type. */ - if (was_incomplete - && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) - { - /* If we used it already as memory, it must stay in memory. */ - TREE_ADDRESSABLE (decl) = TREE_USED (decl); - /* If it's still incomplete now, no init will save it. */ - if (DECL_SIZE (decl) == 0) - DECL_INITIAL (decl) = 0; - expand_decl (decl); - } - /* Compute and store the initial value. */ - if (TREE_CODE (decl) != FUNCTION_DECL) - expand_decl_init (decl); - } - } - else if (TREE_CODE (decl) == TYPE_DECL) - { - rest_of_decl_compilation (decl, NULL, - DECL_CONTEXT (decl) == 0, - 0); - } - - /* At the end of a declaration, throw away any variable type sizes of types - defined inside that declaration. There is no use computing them in the - following function definition. */ - if (current_binding_level == global_binding_level) - get_pending_sizes (); -} - -/* Finish up a function declaration and compile that function - all the way to assembler language output. The free the storage - for the function definition. - - This is called after parsing the body of the function definition. - - NESTED is nonzero if the function being finished is nested in another. */ - -static void -finish_function (int nested) -{ - register tree fndecl = current_function_decl; - - assert (fndecl != NULL_TREE); - if (TREE_CODE (fndecl) != ERROR_MARK) - { - if (nested) - assert (DECL_CONTEXT (fndecl) != NULL_TREE); - else - assert (DECL_CONTEXT (fndecl) == NULL_TREE); - } - -/* TREE_READONLY (fndecl) = 1; - This caused &foo to be of type ptr-to-const-function - which then got a warning when stored in a ptr-to-function variable. */ - - poplevel (1, 0, 1); - - if (TREE_CODE (fndecl) != ERROR_MARK) - { - BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; - - /* Must mark the RESULT_DECL as being in this function. */ - - DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; - - /* Obey `register' declarations if `setjmp' is called in this fn. */ - /* Generate rtl for function exit. */ - expand_function_end (input_filename, lineno, 0); - - /* If this is a nested function, protect the local variables in the stack - above us from being collected while we're compiling this function. */ - if (nested) - ggc_push_context (); - - /* Run the optimizers and output the assembler code for this function. */ - rest_of_compilation (fndecl); - - /* Undo the GC context switch. */ - if (nested) - ggc_pop_context (); - } - - if (TREE_CODE (fndecl) != ERROR_MARK - && !nested - && DECL_SAVED_INSNS (fndecl) == 0) - { - /* Stop pointing to the local nodes about to be freed. */ - /* But DECL_INITIAL must remain nonzero so we know this was an actual - function definition. */ - /* For a nested function, this is done in pop_f_function_context. */ - /* If rest_of_compilation set this to 0, leave it 0. */ - if (DECL_INITIAL (fndecl) != 0) - DECL_INITIAL (fndecl) = error_mark_node; - DECL_ARGUMENTS (fndecl) = 0; - } - - if (!nested) - { - /* Let the error reporting routines know that we're outside a function. - For a nested function, this value is used in pop_c_function_context - and then reset via pop_function_context. */ - ffecom_outer_function_decl_ = current_function_decl = NULL; - } -} - -/* Plug-in replacement for identifying the name of a decl and, for a - function, what we call it in diagnostics. For now, "program unit" - should suffice, since it's a bit of a hassle to figure out which - of several kinds of things it is. Note that it could conceivably - be a statement function, which probably isn't really a program unit - per se, but if that comes up, it should be easy to check (being a - nested function and all). */ - -static const char * -lang_printable_name (tree decl, int v) -{ - /* Just to keep GCC quiet about the unused variable. - In theory, differing values of V should produce different - output. */ - switch (v) - { - default: - if (TREE_CODE (decl) == ERROR_MARK) - return "erroneous code"; - return IDENTIFIER_POINTER (DECL_NAME (decl)); - } -} - -/* g77's function to print out name of current function that caused - an error. */ - -static void -lang_print_error_function (diagnostic_context *context __attribute__((unused)), - const char *file) -{ - static ffeglobal last_g = NULL; - static ffesymbol last_s = NULL; - ffeglobal g; - ffesymbol s; - const char *kind; - - if ((ffecom_primary_entry_ == NULL) - || (ffesymbol_global (ffecom_primary_entry_) == NULL)) - { - g = NULL; - s = NULL; - kind = NULL; - } - else - { - g = ffesymbol_global (ffecom_primary_entry_); - if (ffecom_nested_entry_ == NULL) - { - s = ffecom_primary_entry_; - kind = _(ffeinfo_kind_message (ffesymbol_kind (s))); - } - else - { - s = ffecom_nested_entry_; - kind = _("In statement function"); - } - } - - if ((last_g != g) || (last_s != s)) - { - if (file) - fprintf (stderr, "%s: ", file); - - if (s == NULL) - fprintf (stderr, _("Outside of any program unit:\n")); - else - { - const char *name = ffesymbol_text (s); - - fprintf (stderr, "%s `%s':\n", kind, name); - } - - last_g = g; - last_s = s; - } -} - -/* Similar to `lookup_name' but look only at current binding level. */ - -static tree -lookup_name_current_level (tree name) -{ - register tree t; - - if (current_binding_level == global_binding_level) - return IDENTIFIER_GLOBAL_VALUE (name); - - if (IDENTIFIER_LOCAL_VALUE (name) == 0) - return 0; - - for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) - if (DECL_NAME (t) == name) - break; - - return t; -} - -/* Create a new `struct binding_level'. */ - -static struct binding_level * -make_binding_level () -{ - /* NOSTRICT */ - return (struct binding_level *) xmalloc (sizeof (struct binding_level)); -} - -/* Save and restore the variables in this file and elsewhere - that keep track of the progress of compilation of the current function. - Used for nested functions. */ - -struct f_function -{ - struct f_function *next; - tree named_labels; - tree shadowed_labels; - struct binding_level *binding_level; -}; - -struct f_function *f_function_chain; - -/* Restore the variables used during compilation of a C function. */ - -static void -pop_f_function_context () -{ - struct f_function *p = f_function_chain; - tree link; - - /* Bring back all the labels that were shadowed. */ - for (link = shadowed_labels; link; link = TREE_CHAIN (link)) - if (DECL_NAME (TREE_VALUE (link)) != 0) - IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) - = TREE_VALUE (link); - - if (current_function_decl != error_mark_node - && DECL_SAVED_INSNS (current_function_decl) == 0) - { - /* Stop pointing to the local nodes about to be freed. */ - /* But DECL_INITIAL must remain nonzero so we know this was an actual - function definition. */ - DECL_INITIAL (current_function_decl) = error_mark_node; - DECL_ARGUMENTS (current_function_decl) = 0; - } - - pop_function_context (); - - f_function_chain = p->next; - - named_labels = p->named_labels; - shadowed_labels = p->shadowed_labels; - current_binding_level = p->binding_level; - - free (p); -} - -/* Save and reinitialize the variables - used during compilation of a C function. */ - -static void -push_f_function_context () -{ - struct f_function *p - = (struct f_function *) xmalloc (sizeof (struct f_function)); - - push_function_context (); - - p->next = f_function_chain; - f_function_chain = p; - - p->named_labels = named_labels; - p->shadowed_labels = shadowed_labels; - p->binding_level = current_binding_level; -} - -static void -push_parm_decl (tree parm) -{ - int old_immediate_size_expand = immediate_size_expand; - - /* Don't try computing parm sizes now -- wait till fn is called. */ - - immediate_size_expand = 0; - - /* Fill in arg stuff. */ - - DECL_ARG_TYPE (parm) = TREE_TYPE (parm); - DECL_ARG_TYPE_AS_WRITTEN (parm) = TREE_TYPE (parm); - TREE_READONLY (parm) = 1; /* All implementation args are read-only. */ - - parm = pushdecl (parm); - - immediate_size_expand = old_immediate_size_expand; - - finish_decl (parm, NULL_TREE, FALSE); -} - -/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */ - -static tree -pushdecl_top_level (x) - tree x; -{ - register tree t; - register struct binding_level *b = current_binding_level; - register tree f = current_function_decl; - - current_binding_level = global_binding_level; - current_function_decl = NULL_TREE; - t = pushdecl (x); - current_binding_level = b; - current_function_decl = f; - return t; -} - -/* Store the list of declarations of the current level. - This is done for the parameter declarations of a function being defined, - after they are modified in the light of any missing parameters. */ - -static tree -storedecls (decls) - tree decls; -{ - return current_binding_level->names = decls; -} - -/* Store the parameter declarations into the current function declaration. - This is called after parsing the parameter declarations, before - digesting the body of the function. - - For an old-style definition, modify the function's type - to specify at least the number of arguments. */ - -static void -store_parm_decls (int is_main_program UNUSED) -{ - register tree fndecl = current_function_decl; - - if (fndecl == error_mark_node) - return; - - /* This is a chain of PARM_DECLs from old-style parm declarations. */ - DECL_ARGUMENTS (fndecl) = storedecls (nreverse (getdecls ())); - - /* Initialize the RTL code for the function. */ - - init_function_start (fndecl, input_filename, lineno); - - /* Set up parameters and prepare for return, for the function. */ - - expand_function_start (fndecl, 0); -} - -static tree -start_decl (tree decl, bool is_top_level) -{ - register tree tem; - bool at_top_level = (current_binding_level == global_binding_level); - bool top_level = is_top_level || at_top_level; - - /* Caller should pass TRUE for is_top_level only if we wouldn't be at top - level anyway. */ - assert (!is_top_level || !at_top_level); - - if (DECL_INITIAL (decl) != NULL_TREE) - { - assert (DECL_INITIAL (decl) == error_mark_node); - assert (!DECL_EXTERNAL (decl)); - } - else if (top_level) - assert ((TREE_STATIC (decl) == 1) || DECL_EXTERNAL (decl) == 1); - - /* For Fortran, we by default put things in .common when possible. */ - DECL_COMMON (decl) = 1; - - /* Add this decl to the current binding level. TEM may equal DECL or it may - be a previous decl of the same name. */ - if (is_top_level) - tem = pushdecl_top_level (decl); - else - tem = pushdecl (decl); - - /* For a local variable, define the RTL now. */ - if (!top_level - /* But not if this is a duplicate decl and we preserved the rtl from the - previous one (which may or may not happen). */ - && !DECL_RTL_SET_P (tem)) - { - if (TYPE_SIZE (TREE_TYPE (tem)) != 0) - expand_decl (tem); - else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE - && DECL_INITIAL (tem) != 0) - expand_decl (tem); - } - - return tem; -} - -/* Create the FUNCTION_DECL for a function definition. - DECLSPECS and DECLARATOR are the parts of the declaration; - they describe the function's name and the type it returns, - but twisted together in a fashion that parallels the syntax of C. - - This function creates a binding context for the function body - as well as setting up the FUNCTION_DECL in current_function_decl. - - Returns 1 on success. If the DECLARATOR is not suitable for a function - (it defines a datum instead), we return 0, which tells - yyparse to report a parse error. - - NESTED is nonzero for a function nested within another function. */ - -static void -start_function (tree name, tree type, int nested, int public) -{ - tree decl1; - tree restype; - int old_immediate_size_expand = immediate_size_expand; - - named_labels = 0; - shadowed_labels = 0; - - /* Don't expand any sizes in the return type of the function. */ - immediate_size_expand = 0; - - if (nested) - { - assert (!public); - assert (current_function_decl != NULL_TREE); - assert (DECL_CONTEXT (current_function_decl) == NULL_TREE); - } - else - { - assert (current_function_decl == NULL_TREE); - } - - if (TREE_CODE (type) == ERROR_MARK) - decl1 = current_function_decl = error_mark_node; - else - { - decl1 = build_decl (FUNCTION_DECL, - name, - type); - TREE_PUBLIC (decl1) = public ? 1 : 0; - if (nested) - DECL_INLINE (decl1) = 1; - TREE_STATIC (decl1) = 1; - DECL_EXTERNAL (decl1) = 0; - - announce_function (decl1); - - /* Make the init_value nonzero so pushdecl knows this is not tentative. - error_mark_node is replaced below (in poplevel) with the BLOCK. */ - DECL_INITIAL (decl1) = error_mark_node; - - /* Record the decl so that the function name is defined. If we already have - a decl for this name, and it is a FUNCTION_DECL, use the old decl. */ - - current_function_decl = pushdecl (decl1); - } - - if (!nested) - ffecom_outer_function_decl_ = current_function_decl; - - pushlevel (0); - current_binding_level->prep_state = 2; - - if (TREE_CODE (current_function_decl) != ERROR_MARK) - { - make_decl_rtl (current_function_decl, NULL); - - restype = TREE_TYPE (TREE_TYPE (current_function_decl)); - DECL_RESULT (current_function_decl) - = build_decl (RESULT_DECL, NULL_TREE, restype); - } - - if (!nested && (TREE_CODE (current_function_decl) != ERROR_MARK)) - TREE_ADDRESSABLE (current_function_decl) = 1; - - immediate_size_expand = old_immediate_size_expand; -} - -/* Here are the public functions the GNU back end needs. */ - -tree -convert (type, expr) - tree type, expr; -{ - register tree e = expr; - register enum tree_code code = TREE_CODE (type); - - if (type == TREE_TYPE (e) - || TREE_CODE (e) == ERROR_MARK) - return e; - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))) - return fold (build1 (NOP_EXPR, type, e)); - if (TREE_CODE (TREE_TYPE (e)) == ERROR_MARK - || code == ERROR_MARK) - return error_mark_node; - if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE) - { - assert ("void value not ignored as it ought to be" == NULL); - return error_mark_node; - } - if (code == VOID_TYPE) - return build1 (CONVERT_EXPR, type, e); - if ((code != RECORD_TYPE) - && (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE)) - e = ffecom_1 (REALPART_EXPR, TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e))), - e); - if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) - return fold (convert_to_integer (type, e)); - if (code == POINTER_TYPE) - return fold (convert_to_pointer (type, e)); - if (code == REAL_TYPE) - return fold (convert_to_real (type, e)); - if (code == COMPLEX_TYPE) - return fold (convert_to_complex (type, e)); - if (code == RECORD_TYPE) - return fold (ffecom_convert_to_complex_ (type, e)); - - assert ("conversion to non-scalar type requested" == NULL); - return error_mark_node; -} - -/* integrate_decl_tree calls this function, but since we don't use the - DECL_LANG_SPECIFIC field, this is a no-op. */ - -void -copy_lang_decl (node) - tree node UNUSED; -{ -} - -/* Return the list of declarations of the current level. - Note that this list is in reverse order unless/until - you nreverse it; and when you do nreverse it, you must - store the result back using `storedecls' or you will lose. */ - -tree -getdecls () -{ - return current_binding_level->names; -} - -/* Nonzero if we are currently in the global binding level. */ - -int -global_bindings_p () -{ - return current_binding_level == global_binding_level; -} - -/* Print an error message for invalid use of an incomplete type. - VALUE is the expression that was used (or 0 if that isn't known) - and TYPE is the type that was invalid. */ - -void -incomplete_type_error (value, type) - tree value UNUSED; - tree type; -{ - if (TREE_CODE (type) == ERROR_MARK) - return; - - assert ("incomplete type?!?" == NULL); -} - -/* Mark ARG for GC. */ -static void -mark_binding_level (void *arg) -{ - struct binding_level *level = *(struct binding_level **) arg; - - while (level) - { - ggc_mark_tree (level->names); - ggc_mark_tree (level->blocks); - ggc_mark_tree (level->this_block); - level = level->level_chain; - } -} - -static void -ffecom_init_decl_processing () -{ - static tree *const tree_roots[] = { - ¤t_function_decl, - &string_type_node, - &ffecom_tree_fun_type_void, - &ffecom_integer_zero_node, - &ffecom_integer_one_node, - &ffecom_tree_subr_type, - &ffecom_tree_ptr_to_subr_type, - &ffecom_tree_blockdata_type, - &ffecom_tree_xargc_, - &ffecom_f2c_integer_type_node, - &ffecom_f2c_ptr_to_integer_type_node, - &ffecom_f2c_address_type_node, - &ffecom_f2c_real_type_node, - &ffecom_f2c_ptr_to_real_type_node, - &ffecom_f2c_doublereal_type_node, - &ffecom_f2c_complex_type_node, - &ffecom_f2c_doublecomplex_type_node, - &ffecom_f2c_longint_type_node, - &ffecom_f2c_logical_type_node, - &ffecom_f2c_flag_type_node, - &ffecom_f2c_ftnlen_type_node, - &ffecom_f2c_ftnlen_zero_node, - &ffecom_f2c_ftnlen_one_node, - &ffecom_f2c_ftnlen_two_node, - &ffecom_f2c_ptr_to_ftnlen_type_node, - &ffecom_f2c_ftnint_type_node, - &ffecom_f2c_ptr_to_ftnint_type_node, - &ffecom_outer_function_decl_, - &ffecom_previous_function_decl_, - &ffecom_which_entrypoint_decl_, - &ffecom_float_zero_, - &ffecom_float_half_, - &ffecom_double_zero_, - &ffecom_double_half_, - &ffecom_func_result_, - &ffecom_func_length_, - &ffecom_multi_type_node_, - &ffecom_multi_retval_, - &named_labels, - &shadowed_labels - }; - size_t i; - - malloc_init (); - - /* Record our roots. */ - for (i = 0; i < ARRAY_SIZE (tree_roots); i++) - ggc_add_tree_root (tree_roots[i], 1); - ggc_add_tree_root (&ffecom_tree_type[0][0], - FFEINFO_basictype*FFEINFO_kindtype); - ggc_add_tree_root (&ffecom_tree_fun_type[0][0], - FFEINFO_basictype*FFEINFO_kindtype); - ggc_add_tree_root (&ffecom_tree_ptr_to_fun_type[0][0], - FFEINFO_basictype*FFEINFO_kindtype); - ggc_add_tree_root (ffecom_gfrt_, FFECOM_gfrt); - ggc_add_root (¤t_binding_level, 1, sizeof current_binding_level, - mark_binding_level); - ggc_add_root (&free_binding_level, 1, sizeof current_binding_level, - mark_binding_level); - ggc_add_root (&tracker_head, 1, sizeof tracker_head, mark_tracker_head); - - ffe_init_0 (); -} - -/* Delete the node BLOCK from the current binding level. - This is used for the block inside a stmt expr ({...}) - so that the block can be reinserted where appropriate. */ - -static void -delete_block (block) - tree block; -{ - tree t; - if (current_binding_level->blocks == block) - current_binding_level->blocks = TREE_CHAIN (block); - for (t = current_binding_level->blocks; t;) - { - if (TREE_CHAIN (t) == block) - TREE_CHAIN (t) = TREE_CHAIN (block); - else - t = TREE_CHAIN (t); - } - TREE_CHAIN (block) = NULL; - /* Clear TREE_USED which is always set by poplevel. - The flag is set again if insert_block is called. */ - TREE_USED (block) = 0; -} - -void -insert_block (block) - tree block; -{ - TREE_USED (block) = 1; - current_binding_level->blocks - = chainon (current_binding_level->blocks, block); -} - -/* Each front end provides its own. */ -static const char *ffe_init PARAMS ((const char *)); -static void ffe_finish PARAMS ((void)); -static void ffe_init_options PARAMS ((void)); -static void ffe_print_identifier PARAMS ((FILE *, tree, int)); - -#undef LANG_HOOKS_NAME -#define LANG_HOOKS_NAME "GNU F77" -#undef LANG_HOOKS_INIT -#define LANG_HOOKS_INIT ffe_init -#undef LANG_HOOKS_FINISH -#define LANG_HOOKS_FINISH ffe_finish -#undef LANG_HOOKS_INIT_OPTIONS -#define LANG_HOOKS_INIT_OPTIONS ffe_init_options -#undef LANG_HOOKS_DECODE_OPTION -#define LANG_HOOKS_DECODE_OPTION ffe_decode_option -#undef LANG_HOOKS_PRINT_IDENTIFIER -#define LANG_HOOKS_PRINT_IDENTIFIER ffe_print_identifier - -/* We do not wish to use alias-set based aliasing at all. Used in the - extreme (every object with its own set, with equivalences recorded) it - might be helpful, but there are problems when it comes to inlining. We - get on ok with flag_argument_noalias, and alias-set aliasing does - currently limit how stack slots can be reused, which is a lose. */ -#undef LANG_HOOKS_GET_ALIAS_SET -#define LANG_HOOKS_GET_ALIAS_SET hook_get_alias_set_0 - -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; - -static const char * -ffe_init (filename) - const char *filename; -{ - /* Open input file. */ - if (filename == 0 || !strcmp (filename, "-")) - { - finput = stdin; - filename = "stdin"; - } - else - finput = fopen (filename, "r"); - if (finput == 0) - fatal_io_error ("can't open %s", filename); - -#ifdef IO_BUFFER_SIZE - setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE); -#endif - - ffecom_init_decl_processing (); - decl_printable_name = lang_printable_name; - print_error_function = lang_print_error_function; - - /* If the file is output from cpp, it should contain a first line - `# 1 "real-filename"', and the current design of gcc (toplev.c - in particular and the way it sets up information relied on by - INCLUDE) requires that we read this now, and store the - "real-filename" info in master_input_filename. Ask the lexer - to try doing this. */ - ffelex_hash_kludge (finput); - - /* FIXME: The ffelex_hash_kludge code needs to be cleaned up to - return the new file name. */ - if (main_input_filename) - filename = main_input_filename; - - return filename; -} - -static void -ffe_finish () -{ - ffe_terminate_0 (); - - if (ffe_is_ffedebug ()) - malloc_pool_display (malloc_pool_image ()); - - fclose (finput); -} - -static void -ffe_init_options () -{ - /* Set default options for Fortran. */ - flag_move_all_movables = 1; - flag_reduce_all_givs = 1; - flag_argument_noalias = 2; - flag_merge_constants = 2; - flag_errno_math = 0; - flag_complex_divide_method = 1; -} - -int -mark_addressable (exp) - tree exp; -{ - register tree x = exp; - while (1) - switch (TREE_CODE (x)) - { - case ADDR_EXPR: - case COMPONENT_REF: - case ARRAY_REF: - x = TREE_OPERAND (x, 0); - break; - - case CONSTRUCTOR: - TREE_ADDRESSABLE (x) = 1; - return 1; - - case VAR_DECL: - case CONST_DECL: - case PARM_DECL: - case RESULT_DECL: - if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) - && DECL_NONLOCAL (x)) - { - if (TREE_PUBLIC (x)) - { - assert ("address of global register var requested" == NULL); - return 0; - } - assert ("address of register variable requested" == NULL); - } - else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)) - { - if (TREE_PUBLIC (x)) - { - assert ("address of global register var requested" == NULL); - return 0; - } - assert ("address of register var requested" == NULL); - } - put_var_into_stack (x); - - /* drops in */ - case FUNCTION_DECL: - TREE_ADDRESSABLE (x) = 1; -#if 0 /* poplevel deals with this now. */ - if (DECL_CONTEXT (x) == 0) - TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; -#endif - - default: - return 1; - } -} - -/* If DECL has a cleanup, build and return that cleanup here. - This is a callback called by expand_expr. */ - -tree -maybe_build_cleanup (decl) - tree decl UNUSED; -{ - /* There are no cleanups in Fortran. */ - return NULL_TREE; -} - -/* Exit a binding level. - Pop the level off, and restore the state of the identifier-decl mappings - that were in effect when this level was entered. - - If KEEP is nonzero, this level had explicit declarations, so - and create a "block" (a BLOCK node) for the level - to record its declarations and subblocks for symbol table output. - - If FUNCTIONBODY is nonzero, this level is the body of a function, - so create a block as if KEEP were set and also clear out all - label names. - - If REVERSE is nonzero, reverse the order of decls before putting - them into the BLOCK. */ - -tree -poplevel (keep, reverse, functionbody) - int keep; - int reverse; - int functionbody; -{ - register tree link; - /* The chain of decls was accumulated in reverse order. - Put it into forward order, just for cleanliness. */ - tree decls; - tree subblocks = current_binding_level->blocks; - tree block = 0; - tree decl; - int block_previously_created; - - /* Get the decls in the order they were written. - Usually current_binding_level->names is in reverse order. - But parameter decls were previously put in forward order. */ - - if (reverse) - current_binding_level->names - = decls = nreverse (current_binding_level->names); - else - decls = current_binding_level->names; - - /* Output any nested inline functions within this block - if they weren't already output. */ - - for (decl = decls; decl; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == FUNCTION_DECL - && ! TREE_ASM_WRITTEN (decl) - && DECL_INITIAL (decl) != 0 - && TREE_ADDRESSABLE (decl)) - { - /* If this decl was copied from a file-scope decl - on account of a block-scope extern decl, - propagate TREE_ADDRESSABLE to the file-scope decl. - - DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is - true, since then the decl goes through save_for_inline_copying. */ - if (DECL_ABSTRACT_ORIGIN (decl) != 0 - && DECL_ABSTRACT_ORIGIN (decl) != decl) - TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; - else if (DECL_SAVED_INSNS (decl) != 0) - { - push_function_context (); - output_inline_function (decl); - pop_function_context (); - } - } - - /* If there were any declarations or structure tags in that level, - or if this level is a function body, - create a BLOCK to record them for the life of this function. */ - - block = 0; - block_previously_created = (current_binding_level->this_block != 0); - if (block_previously_created) - block = current_binding_level->this_block; - else if (keep || functionbody) - block = make_node (BLOCK); - if (block != 0) - { - BLOCK_VARS (block) = decls; - BLOCK_SUBBLOCKS (block) = subblocks; - } - - /* In each subblock, record that this is its superior. */ - - for (link = subblocks; link; link = TREE_CHAIN (link)) - BLOCK_SUPERCONTEXT (link) = block; - - /* Clear out the meanings of the local variables of this level. */ - - for (link = decls; link; link = TREE_CHAIN (link)) - { - if (DECL_NAME (link) != 0) - { - /* If the ident. was used or addressed via a local extern decl, - don't forget that fact. */ - if (DECL_EXTERNAL (link)) - { - if (TREE_USED (link)) - TREE_USED (DECL_NAME (link)) = 1; - if (TREE_ADDRESSABLE (link)) - TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; - } - IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; - } - } - - /* If the level being exited is the top level of a function, - check over all the labels, and clear out the current - (function local) meanings of their names. */ - - if (functionbody) - { - /* If this is the top level block of a function, - the vars are the function's parameters. - Don't leave them in the BLOCK because they are - found in the FUNCTION_DECL instead. */ - - BLOCK_VARS (block) = 0; - } - - /* Pop the current level, and free the structure for reuse. */ - - { - register struct binding_level *level = current_binding_level; - current_binding_level = current_binding_level->level_chain; - - level->level_chain = free_binding_level; - free_binding_level = level; - } - - /* Dispose of the block that we just made inside some higher level. */ - if (functionbody - && current_function_decl != error_mark_node) - DECL_INITIAL (current_function_decl) = block; - else if (block) - { - if (!block_previously_created) - current_binding_level->blocks - = chainon (current_binding_level->blocks, block); - } - /* If we did not make a block for the level just exited, - any blocks made for inner levels - (since they cannot be recorded as subblocks in that level) - must be carried forward so they will later become subblocks - of something else. */ - else if (subblocks) - current_binding_level->blocks - = chainon (current_binding_level->blocks, subblocks); - - if (block) - TREE_USED (block) = 1; - return block; -} - -static void -ffe_print_identifier (file, node, indent) - FILE *file; - tree node; - int indent; -{ - print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4); - print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4); -} - -/* Record a decl-node X as belonging to the current lexical scope. - Check for errors (such as an incompatible declaration for the same - name already seen in the same scope). - - Returns either X or an old decl for the same name. - If an old decl is returned, it may have been smashed - to agree with what X says. */ - -tree -pushdecl (x) - tree x; -{ - register tree t; - register tree name = DECL_NAME (x); - register struct binding_level *b = current_binding_level; - - if ((TREE_CODE (x) == FUNCTION_DECL) - && (DECL_INITIAL (x) == 0) - && DECL_EXTERNAL (x)) - DECL_CONTEXT (x) = NULL_TREE; - else - DECL_CONTEXT (x) = current_function_decl; - - if (name) - { - if (IDENTIFIER_INVENTED (name)) - { - DECL_ARTIFICIAL (x) = 1; - DECL_IN_SYSTEM_HEADER (x) = 1; - } - - t = lookup_name_current_level (name); - - assert ((t == NULL_TREE) || (DECL_CONTEXT (x) == NULL_TREE)); - - /* Don't push non-parms onto list for parms until we understand - why we're doing this and whether it works. */ - - assert ((b == global_binding_level) - || !ffecom_transform_only_dummies_ - || TREE_CODE (x) == PARM_DECL); - - if ((t != NULL_TREE) && duplicate_decls (x, t)) - return t; - - /* If we are processing a typedef statement, generate a whole new - ..._TYPE node (which will be just an variant of the existing - ..._TYPE node with identical properties) and then install the - TYPE_DECL node generated to represent the typedef name as the - TYPE_NAME of this brand new (duplicate) ..._TYPE node. - - The whole point here is to end up with a situation where each and every - ..._TYPE node the compiler creates will be uniquely associated with - AT MOST one node representing a typedef name. This way, even though - the compiler substitutes corresponding ..._TYPE nodes for TYPE_DECL - (i.e. "typedef name") nodes very early on, later parts of the - compiler can always do the reverse translation and get back the - corresponding typedef name. For example, given: - - typedef struct S MY_TYPE; MY_TYPE object; - - Later parts of the compiler might only know that `object' was of type - `struct S' if it were not for code just below. With this code - however, later parts of the compiler see something like: - - struct S' == struct S typedef struct S' MY_TYPE; struct S' object; - - And they can then deduce (from the node for type struct S') that the - original object declaration was: - - MY_TYPE object; - - Being able to do this is important for proper support of protoize, and - also for generating precise symbolic debugging information which - takes full account of the programmer's (typedef) vocabulary. - - Obviously, we don't want to generate a duplicate ..._TYPE node if the - TYPE_DECL node that we are now processing really represents a - standard built-in type. - - Since all standard types are effectively declared at line zero in the - source file, we can easily check to see if we are working on a - standard type by checking the current value of lineno. */ - - if (TREE_CODE (x) == TYPE_DECL) - { - if (DECL_SOURCE_LINE (x) == 0) - { - if (TYPE_NAME (TREE_TYPE (x)) == 0) - TYPE_NAME (TREE_TYPE (x)) = x; - } - else if (TREE_TYPE (x) != error_mark_node) - { - tree tt = TREE_TYPE (x); - - tt = build_type_copy (tt); - TYPE_NAME (tt) = x; - TREE_TYPE (x) = tt; - } - } - - /* This name is new in its binding level. Install the new declaration - and return it. */ - if (b == global_binding_level) - IDENTIFIER_GLOBAL_VALUE (name) = x; - else - IDENTIFIER_LOCAL_VALUE (name) = x; - } - - /* Put decls on list in reverse order. We will reverse them later if - necessary. */ - TREE_CHAIN (x) = b->names; - b->names = x; - - return x; -} - -/* Nonzero if the current level needs to have a BLOCK made. */ - -static int -kept_level_p () -{ - tree decl; - - for (decl = current_binding_level->names; - decl; - decl = TREE_CHAIN (decl)) - { - if (TREE_USED (decl) || TREE_CODE (decl) != VAR_DECL - || (DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))) - /* Currently, there aren't supposed to be non-artificial names - at other than the top block for a function -- they're - believed to always be temps. But it's wise to check anyway. */ - return 1; - } - return 0; -} - -/* Enter a new binding level. - If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, - not for that of tags. */ - -void -pushlevel (tag_transparent) - int tag_transparent; -{ - register struct binding_level *newlevel = NULL_BINDING_LEVEL; - - assert (! tag_transparent); - - if (current_binding_level == global_binding_level) - { - named_labels = 0; - } - - /* Reuse or create a struct for this binding level. */ - - if (free_binding_level) - { - newlevel = free_binding_level; - free_binding_level = free_binding_level->level_chain; - } - else - { - newlevel = make_binding_level (); - } - - /* Add this level to the front of the chain (stack) of levels that - are active. */ - - *newlevel = clear_binding_level; - newlevel->level_chain = current_binding_level; - current_binding_level = newlevel; -} - -/* Set the BLOCK node for the innermost scope - (the one we are currently in). */ - -void -set_block (block) - register tree block; -{ - current_binding_level->this_block = block; - current_binding_level->names = chainon (current_binding_level->names, - BLOCK_VARS (block)); - current_binding_level->blocks = chainon (current_binding_level->blocks, - BLOCK_SUBBLOCKS (block)); -} - -tree -signed_or_unsigned_type (unsignedp, type) - int unsignedp; - tree type; -{ - tree type2; - - if (! INTEGRAL_TYPE_P (type)) - return type; - if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - - type2 = type_for_size (TYPE_PRECISION (type), unsignedp); - if (type2 == NULL_TREE) - return type; - - return type2; -} - -tree -signed_type (type) - tree type; -{ - tree type1 = TYPE_MAIN_VARIANT (type); - ffeinfoKindtype kt; - tree type2; - - if (type1 == unsigned_char_type_node || type1 == char_type_node) - return signed_char_type_node; - if (type1 == unsigned_type_node) - return integer_type_node; - if (type1 == short_unsigned_type_node) - return short_integer_type_node; - if (type1 == long_unsigned_type_node) - return long_integer_type_node; - if (type1 == long_long_unsigned_type_node) - return long_long_integer_type_node; -#if 0 /* gcc/c-* files only */ - if (type1 == unsigned_intDI_type_node) - return intDI_type_node; - if (type1 == unsigned_intSI_type_node) - return intSI_type_node; - if (type1 == unsigned_intHI_type_node) - return intHI_type_node; - if (type1 == unsigned_intQI_type_node) - return intQI_type_node; -#endif - - type2 = type_for_size (TYPE_PRECISION (type1), 0); - if (type2 != NULL_TREE) - return type2; - - for (kt = 0; kt < ARRAY_SIZE (ffecom_tree_type[0]); ++kt) - { - type2 = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt]; - - if (type1 == type2) - return ffecom_tree_type[FFEINFO_basictypeINTEGER][kt]; - } - - return type; -} - -/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, - or validate its data type for an `if' or `while' statement or ?..: exp. - - This preparation consists of taking the ordinary - representation of an expression expr and producing a valid tree - boolean expression describing whether expr is nonzero. We could - simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1), - but we optimize comparisons, &&, ||, and !. - - The resulting type should always be `integer_type_node'. */ - -tree -truthvalue_conversion (expr) - tree expr; -{ - if (TREE_CODE (expr) == ERROR_MARK) - return expr; - -#if 0 /* This appears to be wrong for C++. */ - /* These really should return error_mark_node after 2.4 is stable. - But not all callers handle ERROR_MARK properly. */ - switch (TREE_CODE (TREE_TYPE (expr))) - { - case RECORD_TYPE: - error ("struct type value used where scalar is required"); - return integer_zero_node; - - case UNION_TYPE: - error ("union type value used where scalar is required"); - return integer_zero_node; - - case ARRAY_TYPE: - error ("array type value used where scalar is required"); - return integer_zero_node; - - default: - break; - } -#endif /* 0 */ - - switch (TREE_CODE (expr)) - { - /* It is simpler and generates better code to have only TRUTH_*_EXPR - or comparison expressions as truth values at this level. */ -#if 0 - case COMPONENT_REF: - /* A one-bit unsigned bit-field is already acceptable. */ - if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1))) - && TREE_UNSIGNED (TREE_OPERAND (expr, 1))) - return expr; - break; -#endif - - case EQ_EXPR: - /* It is simpler and generates better code to have only TRUTH_*_EXPR - or comparison expressions as truth values at this level. */ -#if 0 - if (integer_zerop (TREE_OPERAND (expr, 1))) - return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0); -#endif - case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - TREE_TYPE (expr) = integer_type_node; - return expr; - - case ERROR_MARK: - return expr; - - case INTEGER_CST: - return integer_zerop (expr) ? integer_zero_node : integer_one_node; - - case REAL_CST: - return real_zerop (expr) ? integer_zero_node : integer_one_node; - - case ADDR_EXPR: - if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) - return build (COMPOUND_EXPR, integer_type_node, - TREE_OPERAND (expr, 0), integer_one_node); - else - return integer_one_node; - - case COMPLEX_EXPR: - return ffecom_2 ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) - ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), - integer_type_node, - truthvalue_conversion (TREE_OPERAND (expr, 0)), - truthvalue_conversion (TREE_OPERAND (expr, 1))); - - case NEGATE_EXPR: - case ABS_EXPR: - case FLOAT_EXPR: - case FFS_EXPR: - /* These don't change whether an object is non-zero or zero. */ - return truthvalue_conversion (TREE_OPERAND (expr, 0)); - - case LROTATE_EXPR: - case RROTATE_EXPR: - /* These don't change whether an object is zero or non-zero, but - we can't ignore them if their second arg has side-effects. */ - if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) - return build (COMPOUND_EXPR, integer_type_node, TREE_OPERAND (expr, 1), - truthvalue_conversion (TREE_OPERAND (expr, 0))); - else - return truthvalue_conversion (TREE_OPERAND (expr, 0)); - - case COND_EXPR: - /* Distribute the conversion into the arms of a COND_EXPR. */ - return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0), - truthvalue_conversion (TREE_OPERAND (expr, 1)), - truthvalue_conversion (TREE_OPERAND (expr, 2)))); - - case CONVERT_EXPR: - /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, - since that affects how `default_conversion' will behave. */ - if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE - || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) - break; - /* fall through... */ - case NOP_EXPR: - /* If this is widening the argument, we can ignore it. */ - if (TYPE_PRECISION (TREE_TYPE (expr)) - >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) - return truthvalue_conversion (TREE_OPERAND (expr, 0)); - break; - - case MINUS_EXPR: - /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize - this case. */ - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT - && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) - break; - /* fall through... */ - case BIT_XOR_EXPR: - /* This and MINUS_EXPR can be changed into a comparison of the - two objects. */ - if (TREE_TYPE (TREE_OPERAND (expr, 0)) - == TREE_TYPE (TREE_OPERAND (expr, 1))) - return ffecom_2 (NE_EXPR, integer_type_node, - TREE_OPERAND (expr, 0), - TREE_OPERAND (expr, 1)); - return ffecom_2 (NE_EXPR, integer_type_node, - TREE_OPERAND (expr, 0), - fold (build1 (NOP_EXPR, - TREE_TYPE (TREE_OPERAND (expr, 0)), - TREE_OPERAND (expr, 1)))); - - case BIT_AND_EXPR: - if (integer_onep (TREE_OPERAND (expr, 1))) - return expr; - break; - - case MODIFY_EXPR: -#if 0 /* No such thing in Fortran. */ - if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR) - warning ("suggest parentheses around assignment used as truth value"); -#endif - break; - - default: - break; - } - - if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) - return (ffecom_2 - ((TREE_SIDE_EFFECTS (expr) - ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), - integer_type_node, - truthvalue_conversion (ffecom_1 (REALPART_EXPR, - TREE_TYPE (TREE_TYPE (expr)), - expr)), - truthvalue_conversion (ffecom_1 (IMAGPART_EXPR, - TREE_TYPE (TREE_TYPE (expr)), - expr)))); - - return ffecom_2 (NE_EXPR, integer_type_node, - expr, - convert (TREE_TYPE (expr), integer_zero_node)); -} - -tree -type_for_mode (mode, unsignedp) - enum machine_mode mode; - int unsignedp; -{ - int i; - int j; - tree t; - - if (mode == TYPE_MODE (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - - if (mode == TYPE_MODE (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - - if (mode == TYPE_MODE (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - - if (mode == TYPE_MODE (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (mode == TYPE_MODE (long_long_integer_type_node)) - return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; - -#if HOST_BITS_PER_WIDE_INT >= 64 - if (mode == TYPE_MODE (intTI_type_node)) - return unsignedp ? unsigned_intTI_type_node : intTI_type_node; -#endif - - if (mode == TYPE_MODE (float_type_node)) - return float_type_node; - - if (mode == TYPE_MODE (double_type_node)) - return double_type_node; - - if (mode == TYPE_MODE (long_double_type_node)) - return long_double_type_node; - - if (mode == TYPE_MODE (build_pointer_type (char_type_node))) - return build_pointer_type (char_type_node); - - if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) - return build_pointer_type (integer_type_node); - - for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i) - for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j) - { - if (((t = ffecom_tree_type[i][j]) != NULL_TREE) - && (mode == TYPE_MODE (t))) - { - if ((i == FFEINFO_basictypeINTEGER) && unsignedp) - return ffecom_tree_type[FFEINFO_basictypeHOLLERITH][j]; - else - return t; - } - } - - return 0; -} - -tree -type_for_size (bits, unsignedp) - unsigned bits; - int unsignedp; -{ - ffeinfoKindtype kt; - tree type_node; - - if (bits == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - - if (bits == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - - if (bits == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - - if (bits == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (bits == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - - for (kt = 0; kt < ARRAY_SIZE (ffecom_tree_type[0]); ++kt) - { - type_node = ffecom_tree_type[FFEINFO_basictypeINTEGER][kt]; - - if ((type_node != NULL_TREE) && (bits == TYPE_PRECISION (type_node))) - return unsignedp ? ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt] - : type_node; - } - - return 0; -} - -tree -unsigned_type (type) - tree type; -{ - tree type1 = TYPE_MAIN_VARIANT (type); - ffeinfoKindtype kt; - tree type2; - - if (type1 == signed_char_type_node || type1 == char_type_node) - return unsigned_char_type_node; - if (type1 == integer_type_node) - return unsigned_type_node; - if (type1 == short_integer_type_node) - return short_unsigned_type_node; - if (type1 == long_integer_type_node) - return long_unsigned_type_node; - if (type1 == long_long_integer_type_node) - return long_long_unsigned_type_node; -#if 0 /* gcc/c-* files only */ - if (type1 == intDI_type_node) - return unsigned_intDI_type_node; - if (type1 == intSI_type_node) - return unsigned_intSI_type_node; - if (type1 == intHI_type_node) - return unsigned_intHI_type_node; - if (type1 == intQI_type_node) - return unsigned_intQI_type_node; -#endif - - type2 = type_for_size (TYPE_PRECISION (type1), 1); - if (type2 != NULL_TREE) - return type2; - - for (kt = 0; kt < ARRAY_SIZE (ffecom_tree_type[0]); ++kt) - { - type2 = ffecom_tree_type[FFEINFO_basictypeINTEGER][kt]; - - if (type1 == type2) - return ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt]; - } - - return type; -} - -void -lang_mark_tree (t) - union tree_node *t ATTRIBUTE_UNUSED; -{ - if (TREE_CODE (t) == IDENTIFIER_NODE) - { - struct lang_identifier *i = (struct lang_identifier *) t; - ggc_mark_tree (IDENTIFIER_GLOBAL_VALUE (i)); - ggc_mark_tree (IDENTIFIER_LOCAL_VALUE (i)); - ggc_mark_tree (IDENTIFIER_LABEL_VALUE (i)); - } - else if (TYPE_P (t) && TYPE_LANG_SPECIFIC (t)) - ggc_mark (TYPE_LANG_SPECIFIC (t)); -} - -/* From gcc/cccp.c, the code to handle -I. */ - -/* Skip leading "./" from a directory name. - This may yield the empty string, which represents the current directory. */ - -static const char * -skip_redundant_dir_prefix (const char *dir) -{ - while (dir[0] == '.' && dir[1] == '/') - for (dir += 2; *dir == '/'; dir++) - continue; - if (dir[0] == '.' && !dir[1]) - dir++; - return dir; -} - -/* The file_name_map structure holds a mapping of file names for a - particular directory. This mapping is read from the file named - FILE_NAME_MAP_FILE in that directory. Such a file can be used to - map filenames on a file system with severe filename restrictions, - such as DOS. The format of the file name map file is just a series - of lines with two tokens on each line. The first token is the name - to map, and the second token is the actual name to use. */ - -struct file_name_map -{ - struct file_name_map *map_next; - char *map_from; - char *map_to; -}; - -#define FILE_NAME_MAP_FILE "header.gcc" - -/* Current maximum length of directory names in the search path - for include files. (Altered as we get more of them.) */ - -static int max_include_len = 0; - -struct file_name_list - { - struct file_name_list *next; - char *fname; - /* Mapping of file names for this directory. */ - struct file_name_map *name_map; - /* Non-zero if name_map is valid. */ - int got_name_map; - }; - -static struct file_name_list *include = NULL; /* First dir to search */ -static struct file_name_list *last_include = NULL; /* Last in chain */ - -/* I/O buffer structure. - The `fname' field is nonzero for source files and #include files - and for the dummy text used for -D and -U. - It is zero for rescanning results of macro expansion - and for expanding macro arguments. */ -#define INPUT_STACK_MAX 400 -static struct file_buf { - const char *fname; - /* Filename specified with #line command. */ - const char *nominal_fname; - /* Record where in the search path this file was found. - For #include_next. */ - struct file_name_list *dir; - ffewhereLine line; - ffewhereColumn column; -} instack[INPUT_STACK_MAX]; - -static int last_error_tick = 0; /* Incremented each time we print it. */ -static int input_file_stack_tick = 0; /* Incremented when status changes. */ - -/* Current nesting level of input sources. - `instack[indepth]' is the level currently being read. */ -static int indepth = -1; - -typedef struct file_buf FILE_BUF; - -/* Nonzero means -I- has been seen, - so don't look for #include "foo" the source-file directory. */ -static int ignore_srcdir; - -#ifndef INCLUDE_LEN_FUDGE -#define INCLUDE_LEN_FUDGE 0 -#endif - -static void append_include_chain (struct file_name_list *first, - struct file_name_list *last); -static FILE *open_include_file (char *filename, - struct file_name_list *searchptr); -static void print_containing_files (ffebadSeverity sev); -static char *read_filename_string (int ch, FILE *f); -static struct file_name_map *read_name_map (const char *dirname); - -/* Append a chain of `struct file_name_list's - to the end of the main include chain. - FIRST is the beginning of the chain to append, and LAST is the end. */ - -static void -append_include_chain (first, last) - struct file_name_list *first, *last; -{ - struct file_name_list *dir; - - if (!first || !last) - return; - - if (include == 0) - include = first; - else - last_include->next = first; - - for (dir = first; ; dir = dir->next) { - int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE; - if (len > max_include_len) - max_include_len = len; - if (dir == last) - break; - } - - last->next = NULL; - last_include = last; -} - -/* Try to open include file FILENAME. SEARCHPTR is the directory - being tried from the include file search path. This function maps - filenames on file systems based on information read by - read_name_map. */ - -static FILE * -open_include_file (filename, searchptr) - char *filename; - struct file_name_list *searchptr; -{ - register struct file_name_map *map; - register char *from; - char *p, *dir; - - if (searchptr && ! searchptr->got_name_map) - { - searchptr->name_map = read_name_map (searchptr->fname - ? searchptr->fname : "."); - searchptr->got_name_map = 1; - } - - /* First check the mapping for the directory we are using. */ - if (searchptr && searchptr->name_map) - { - from = filename; - if (searchptr->fname) - from += strlen (searchptr->fname) + 1; - for (map = searchptr->name_map; map; map = map->map_next) - { - if (! strcmp (map->map_from, from)) - { - /* Found a match. */ - return fopen (map->map_to, "r"); - } - } - } - - /* Try to find a mapping file for the particular directory we are - looking in. Thus #include will look up sys/types.h - in /usr/include/header.gcc and look up types.h in - /usr/include/sys/header.gcc. */ - p = strrchr (filename, '/'); -#ifdef DIR_SEPARATOR - if (! p) p = strrchr (filename, DIR_SEPARATOR); - else { - char *tmp = strrchr (filename, DIR_SEPARATOR); - if (tmp != NULL && tmp > p) p = tmp; - } -#endif - if (! p) - p = filename; - if (searchptr - && searchptr->fname - && strlen (searchptr->fname) == (size_t) (p - filename) - && ! strncmp (searchptr->fname, filename, (int) (p - filename))) - { - /* FILENAME is in SEARCHPTR, which we've already checked. */ - return fopen (filename, "r"); - } - - if (p == filename) - { - from = filename; - map = read_name_map ("."); - } - else - { - dir = (char *) xmalloc (p - filename + 1); - memcpy (dir, filename, p - filename); - dir[p - filename] = '\0'; - from = p + 1; - map = read_name_map (dir); - free (dir); - } - for (; map; map = map->map_next) - if (! strcmp (map->map_from, from)) - return fopen (map->map_to, "r"); - - return fopen (filename, "r"); -} - -/* Print the file names and line numbers of the #include - commands which led to the current file. */ - -static void -print_containing_files (ffebadSeverity sev) -{ - FILE_BUF *ip = NULL; - int i; - int first = 1; - const char *str1; - const char *str2; - - /* If stack of files hasn't changed since we last printed - this info, don't repeat it. */ - if (last_error_tick == input_file_stack_tick) - return; - - for (i = indepth; i >= 0; i--) - if (instack[i].fname != NULL) { - ip = &instack[i]; - break; - } - - /* Give up if we don't find a source file. */ - if (ip == NULL) - return; - - /* Find the other, outer source files. */ - for (i--; i >= 0; i--) - if (instack[i].fname != NULL) - { - ip = &instack[i]; - if (first) - { - first = 0; - str1 = "In file included"; - } - else - { - str1 = "... ..."; - } - - if (i == 1) - str2 = ":"; - else - str2 = ""; - - /* xgettext:no-c-format */ - ffebad_start_msg ("%A from %B at %0%C", sev); - ffebad_here (0, ip->line, ip->column); - ffebad_string (str1); - ffebad_string (ip->nominal_fname); - ffebad_string (str2); - ffebad_finish (); - } - - /* Record we have printed the status as of this time. */ - last_error_tick = input_file_stack_tick; -} - -/* Read a space delimited string of unlimited length from a stdio - file. */ - -static char * -read_filename_string (ch, f) - int ch; - FILE *f; -{ - char *alloc, *set; - int len; - - len = 20; - set = alloc = xmalloc (len + 1); - if (! ISSPACE (ch)) - { - *set++ = ch; - while ((ch = getc (f)) != EOF && ! ISSPACE (ch)) - { - if (set - alloc == len) - { - len *= 2; - alloc = xrealloc (alloc, len + 1); - set = alloc + len / 2; - } - *set++ = ch; - } - } - *set = '\0'; - ungetc (ch, f); - return alloc; -} - -/* Read the file name map file for DIRNAME. */ - -static struct file_name_map * -read_name_map (dirname) - const char *dirname; -{ - /* This structure holds a linked list of file name maps, one per - directory. */ - struct file_name_map_list - { - struct file_name_map_list *map_list_next; - char *map_list_name; - struct file_name_map *map_list_map; - }; - static struct file_name_map_list *map_list; - register struct file_name_map_list *map_list_ptr; - char *name; - FILE *f; - size_t dirlen; - int separator_needed; - - dirname = skip_redundant_dir_prefix (dirname); - - for (map_list_ptr = map_list; map_list_ptr; - map_list_ptr = map_list_ptr->map_list_next) - if (! strcmp (map_list_ptr->map_list_name, dirname)) - return map_list_ptr->map_list_map; - - map_list_ptr = ((struct file_name_map_list *) - xmalloc (sizeof (struct file_name_map_list))); - map_list_ptr->map_list_name = xstrdup (dirname); - map_list_ptr->map_list_map = NULL; - - dirlen = strlen (dirname); - separator_needed = dirlen != 0 && dirname[dirlen - 1] != '/'; - name = (char *) xmalloc (dirlen + strlen (FILE_NAME_MAP_FILE) + 2); - strcpy (name, dirname); - name[dirlen] = '/'; - strcpy (name + dirlen + separator_needed, FILE_NAME_MAP_FILE); - f = fopen (name, "r"); - free (name); - if (!f) - map_list_ptr->map_list_map = NULL; - else - { - int ch; - - while ((ch = getc (f)) != EOF) - { - char *from, *to; - struct file_name_map *ptr; - - if (ISSPACE (ch)) - continue; - from = read_filename_string (ch, f); - while ((ch = getc (f)) != EOF && ISSPACE (ch) && ch != '\n') - ; - to = read_filename_string (ch, f); - - ptr = ((struct file_name_map *) - xmalloc (sizeof (struct file_name_map))); - ptr->map_from = from; - - /* Make the real filename absolute. */ - if (*to == '/') - ptr->map_to = to; - else - { - ptr->map_to = xmalloc (dirlen + strlen (to) + 2); - strcpy (ptr->map_to, dirname); - ptr->map_to[dirlen] = '/'; - strcpy (ptr->map_to + dirlen + separator_needed, to); - free (to); - } - - ptr->map_next = map_list_ptr->map_list_map; - map_list_ptr->map_list_map = ptr; - - while ((ch = getc (f)) != '\n') - if (ch == EOF) - break; - } - fclose (f); - } - - map_list_ptr->map_list_next = map_list; - map_list = map_list_ptr; - - return map_list_ptr->map_list_map; -} - -static void -ffecom_file_ (const char *name) -{ - FILE_BUF *fp; - - /* Do partial setup of input buffer for the sake of generating - early #line directives (when -g is in effect). */ - - fp = &instack[++indepth]; - memset ((char *) fp, 0, sizeof (FILE_BUF)); - if (name == NULL) - name = ""; - fp->nominal_fname = fp->fname = name; -} - -static void -ffecom_close_include_ (FILE *f) -{ - fclose (f); - - indepth--; - input_file_stack_tick++; - - ffewhere_line_kill (instack[indepth].line); - ffewhere_column_kill (instack[indepth].column); -} - -static int -ffecom_decode_include_option_ (char *spec) -{ - struct file_name_list *dirtmp; - - if (! ignore_srcdir && !strcmp (spec, "-")) - ignore_srcdir = 1; - else - { - dirtmp = (struct file_name_list *) - xmalloc (sizeof (struct file_name_list)); - dirtmp->next = 0; /* New one goes on the end */ - dirtmp->fname = spec; - dirtmp->got_name_map = 0; - if (spec[0] == 0) - error ("directory name must immediately follow -I"); - else - append_include_chain (dirtmp, dirtmp); - } - return 1; -} - -/* Open INCLUDEd file. */ - -static FILE * -ffecom_open_include_ (char *name, ffewhereLine l, ffewhereColumn c) -{ - char *fbeg = name; - size_t flen = strlen (fbeg); - struct file_name_list *search_start = include; /* Chain of dirs to search */ - struct file_name_list dsp[1]; /* First in chain, if #include "..." */ - struct file_name_list *searchptr = 0; - char *fname; /* Dynamically allocated fname buffer */ - FILE *f; - FILE_BUF *fp; - - if (flen == 0) - return NULL; - - dsp[0].fname = NULL; - - /* If -I- was specified, don't search current dir, only spec'd ones. */ - if (!ignore_srcdir) - { - for (fp = &instack[indepth]; fp >= instack; fp--) - { - int n; - char *ep; - const char *nam; - - if ((nam = fp->nominal_fname) != NULL) - { - /* Found a named file. Figure out dir of the file, - and put it in front of the search list. */ - dsp[0].next = search_start; - search_start = dsp; -#ifndef VMS - ep = strrchr (nam, '/'); -#ifdef DIR_SEPARATOR - if (ep == NULL) ep = strrchr (nam, DIR_SEPARATOR); - else { - char *tmp = strrchr (nam, DIR_SEPARATOR); - if (tmp != NULL && tmp > ep) ep = tmp; - } -#endif -#else /* VMS */ - ep = strrchr (nam, ']'); - if (ep == NULL) ep = strrchr (nam, '>'); - if (ep == NULL) ep = strrchr (nam, ':'); - if (ep != NULL) ep++; -#endif /* VMS */ - if (ep != NULL) - { - n = ep - nam; - dsp[0].fname = (char *) xmalloc (n + 1); - strncpy (dsp[0].fname, nam, n); - dsp[0].fname[n] = '\0'; - if (n + INCLUDE_LEN_FUDGE > max_include_len) - max_include_len = n + INCLUDE_LEN_FUDGE; - } - else - dsp[0].fname = NULL; /* Current directory */ - dsp[0].got_name_map = 0; - break; - } - } - } - - /* Allocate this permanently, because it gets stored in the definitions - of macros. */ - fname = xmalloc (max_include_len + flen + 4); - /* + 2 above for slash and terminating null. */ - /* + 2 added for '.h' on VMS (to support '#include filename') (NOT USED - for g77 yet). */ - - /* If specified file name is absolute, just open it. */ - - if (*fbeg == '/' -#ifdef DIR_SEPARATOR - || *fbeg == DIR_SEPARATOR -#endif - ) - { - strncpy (fname, (char *) fbeg, flen); - fname[flen] = 0; - f = open_include_file (fname, NULL); - } - else - { - f = NULL; - - /* Search directory path, trying to open the file. - Copy each filename tried into FNAME. */ - - for (searchptr = search_start; searchptr; searchptr = searchptr->next) - { - if (searchptr->fname) - { - /* The empty string in a search path is ignored. - This makes it possible to turn off entirely - a standard piece of the list. */ - if (searchptr->fname[0] == 0) - continue; - strcpy (fname, skip_redundant_dir_prefix (searchptr->fname)); - if (fname[0] && fname[strlen (fname) - 1] != '/') - strcat (fname, "/"); - fname[strlen (fname) + flen] = 0; - } - else - fname[0] = 0; - - strncat (fname, fbeg, flen); -#ifdef VMS - /* Change this 1/2 Unix 1/2 VMS file specification into a - full VMS file specification */ - if (searchptr->fname && (searchptr->fname[0] != 0)) - { - /* Fix up the filename */ - hack_vms_include_specification (fname); - } - else - { - /* This is a normal VMS filespec, so use it unchanged. */ - strncpy (fname, (char *) fbeg, flen); - fname[flen] = 0; -#if 0 /* Not for g77. */ - /* if it's '#include filename', add the missing .h */ - if (strchr (fname, '.') == NULL) - strcat (fname, ".h"); -#endif - } -#endif /* VMS */ - f = open_include_file (fname, searchptr); -#ifdef EACCES - if (f == NULL && errno == EACCES) - { - print_containing_files (FFEBAD_severityWARNING); - /* xgettext:no-c-format */ - ffebad_start_msg ("At %0, INCLUDE file %A exists, but is not readable", - FFEBAD_severityWARNING); - ffebad_string (fname); - ffebad_here (0, l, c); - ffebad_finish (); - } -#endif - if (f != NULL) - break; - } - } - - if (f == NULL) - { - /* A file that was not found. */ - - strncpy (fname, (char *) fbeg, flen); - fname[flen] = 0; - print_containing_files (ffebad_severity (FFEBAD_OPEN_INCLUDE)); - ffebad_start (FFEBAD_OPEN_INCLUDE); - ffebad_here (0, l, c); - ffebad_string (fname); - ffebad_finish (); - } - - if (dsp[0].fname != NULL) - free (dsp[0].fname); - - if (f == NULL) - return NULL; - - if (indepth >= (INPUT_STACK_MAX - 1)) - { - print_containing_files (FFEBAD_severityFATAL); - /* xgettext:no-c-format */ - ffebad_start_msg ("At %0, INCLUDE nesting too deep", - FFEBAD_severityFATAL); - ffebad_string (fname); - ffebad_here (0, l, c); - ffebad_finish (); - return NULL; - } - - instack[indepth].line = ffewhere_line_use (l); - instack[indepth].column = ffewhere_column_use (c); - - fp = &instack[indepth + 1]; - memset ((char *) fp, 0, sizeof (FILE_BUF)); - fp->nominal_fname = fp->fname = fname; - fp->dir = searchptr; - - indepth++; - input_file_stack_tick++; - - return f; -} - -/**INDENT* (Do not reformat this comment even with -fca option.) - Data-gathering files: Given the source file listed below, compiled with - f2c I obtained the output file listed after that, and from the output - file I derived the above code. - --------- (begin input file to f2c) - implicit none - character*10 A1,A2 - complex C1,C2 - integer I1,I2 - real R1,R2 - double precision D1,D2 -C - call getem(A1,A2,C1,C2,I1,I2,R1,R2,D1,D2) -c / - call fooI(I1/I2) - call fooR(R1/I1) - call fooD(D1/I1) - call fooC(C1/I1) - call fooR(R1/R2) - call fooD(R1/D1) - call fooD(D1/D2) - call fooD(D1/R1) - call fooC(C1/C2) - call fooC(C1/R1) - call fooZ(C1/D1) -c ** - call fooI(I1**I2) - call fooR(R1**I1) - call fooD(D1**I1) - call fooC(C1**I1) - call fooR(R1**R2) - call fooD(R1**D1) - call fooD(D1**D2) - call fooD(D1**R1) - call fooC(C1**C2) - call fooC(C1**R1) - call fooZ(C1**D1) -c FFEINTRIN_impABS - call fooR(ABS(R1)) -c FFEINTRIN_impACOS - call fooR(ACOS(R1)) -c FFEINTRIN_impAIMAG - call fooR(AIMAG(C1)) -c FFEINTRIN_impAINT - call fooR(AINT(R1)) -c FFEINTRIN_impALOG - call fooR(ALOG(R1)) -c FFEINTRIN_impALOG10 - call fooR(ALOG10(R1)) -c FFEINTRIN_impAMAX0 - call fooR(AMAX0(I1,I2)) -c FFEINTRIN_impAMAX1 - call fooR(AMAX1(R1,R2)) -c FFEINTRIN_impAMIN0 - call fooR(AMIN0(I1,I2)) -c FFEINTRIN_impAMIN1 - call fooR(AMIN1(R1,R2)) -c FFEINTRIN_impAMOD - call fooR(AMOD(R1,R2)) -c FFEINTRIN_impANINT - call fooR(ANINT(R1)) -c FFEINTRIN_impASIN - call fooR(ASIN(R1)) -c FFEINTRIN_impATAN - call fooR(ATAN(R1)) -c FFEINTRIN_impATAN2 - call fooR(ATAN2(R1,R2)) -c FFEINTRIN_impCABS - call fooR(CABS(C1)) -c FFEINTRIN_impCCOS - call fooC(CCOS(C1)) -c FFEINTRIN_impCEXP - call fooC(CEXP(C1)) -c FFEINTRIN_impCHAR - call fooA(CHAR(I1)) -c FFEINTRIN_impCLOG - call fooC(CLOG(C1)) -c FFEINTRIN_impCONJG - call fooC(CONJG(C1)) -c FFEINTRIN_impCOS - call fooR(COS(R1)) -c FFEINTRIN_impCOSH - call fooR(COSH(R1)) -c FFEINTRIN_impCSIN - call fooC(CSIN(C1)) -c FFEINTRIN_impCSQRT - call fooC(CSQRT(C1)) -c FFEINTRIN_impDABS - call fooD(DABS(D1)) -c FFEINTRIN_impDACOS - call fooD(DACOS(D1)) -c FFEINTRIN_impDASIN - call fooD(DASIN(D1)) -c FFEINTRIN_impDATAN - call fooD(DATAN(D1)) -c FFEINTRIN_impDATAN2 - call fooD(DATAN2(D1,D2)) -c FFEINTRIN_impDCOS - call fooD(DCOS(D1)) -c FFEINTRIN_impDCOSH - call fooD(DCOSH(D1)) -c FFEINTRIN_impDDIM - call fooD(DDIM(D1,D2)) -c FFEINTRIN_impDEXP - call fooD(DEXP(D1)) -c FFEINTRIN_impDIM - call fooR(DIM(R1,R2)) -c FFEINTRIN_impDINT - call fooD(DINT(D1)) -c FFEINTRIN_impDLOG - call fooD(DLOG(D1)) -c FFEINTRIN_impDLOG10 - call fooD(DLOG10(D1)) -c FFEINTRIN_impDMAX1 - call fooD(DMAX1(D1,D2)) -c FFEINTRIN_impDMIN1 - call fooD(DMIN1(D1,D2)) -c FFEINTRIN_impDMOD - call fooD(DMOD(D1,D2)) -c FFEINTRIN_impDNINT - call fooD(DNINT(D1)) -c FFEINTRIN_impDPROD - call fooD(DPROD(R1,R2)) -c FFEINTRIN_impDSIGN - call fooD(DSIGN(D1,D2)) -c FFEINTRIN_impDSIN - call fooD(DSIN(D1)) -c FFEINTRIN_impDSINH - call fooD(DSINH(D1)) -c FFEINTRIN_impDSQRT - call fooD(DSQRT(D1)) -c FFEINTRIN_impDTAN - call fooD(DTAN(D1)) -c FFEINTRIN_impDTANH - call fooD(DTANH(D1)) -c FFEINTRIN_impEXP - call fooR(EXP(R1)) -c FFEINTRIN_impIABS - call fooI(IABS(I1)) -c FFEINTRIN_impICHAR - call fooI(ICHAR(A1)) -c FFEINTRIN_impIDIM - call fooI(IDIM(I1,I2)) -c FFEINTRIN_impIDNINT - call fooI(IDNINT(D1)) -c FFEINTRIN_impINDEX - call fooI(INDEX(A1,A2)) -c FFEINTRIN_impISIGN - call fooI(ISIGN(I1,I2)) -c FFEINTRIN_impLEN - call fooI(LEN(A1)) -c FFEINTRIN_impLGE - call fooL(LGE(A1,A2)) -c FFEINTRIN_impLGT - call fooL(LGT(A1,A2)) -c FFEINTRIN_impLLE - call fooL(LLE(A1,A2)) -c FFEINTRIN_impLLT - call fooL(LLT(A1,A2)) -c FFEINTRIN_impMAX0 - call fooI(MAX0(I1,I2)) -c FFEINTRIN_impMAX1 - call fooI(MAX1(R1,R2)) -c FFEINTRIN_impMIN0 - call fooI(MIN0(I1,I2)) -c FFEINTRIN_impMIN1 - call fooI(MIN1(R1,R2)) -c FFEINTRIN_impMOD - call fooI(MOD(I1,I2)) -c FFEINTRIN_impNINT - call fooI(NINT(R1)) -c FFEINTRIN_impSIGN - call fooR(SIGN(R1,R2)) -c FFEINTRIN_impSIN - call fooR(SIN(R1)) -c FFEINTRIN_impSINH - call fooR(SINH(R1)) -c FFEINTRIN_impSQRT - call fooR(SQRT(R1)) -c FFEINTRIN_impTAN - call fooR(TAN(R1)) -c FFEINTRIN_impTANH - call fooR(TANH(R1)) -c FFEINTRIN_imp_CMPLX_C - call fooC(cmplx(C1,C2)) -c FFEINTRIN_imp_CMPLX_D - call fooZ(cmplx(D1,D2)) -c FFEINTRIN_imp_CMPLX_I - call fooC(cmplx(I1,I2)) -c FFEINTRIN_imp_CMPLX_R - call fooC(cmplx(R1,R2)) -c FFEINTRIN_imp_DBLE_C - call fooD(dble(C1)) -c FFEINTRIN_imp_DBLE_D - call fooD(dble(D1)) -c FFEINTRIN_imp_DBLE_I - call fooD(dble(I1)) -c FFEINTRIN_imp_DBLE_R - call fooD(dble(R1)) -c FFEINTRIN_imp_INT_C - call fooI(int(C1)) -c FFEINTRIN_imp_INT_D - call fooI(int(D1)) -c FFEINTRIN_imp_INT_I - call fooI(int(I1)) -c FFEINTRIN_imp_INT_R - call fooI(int(R1)) -c FFEINTRIN_imp_REAL_C - call fooR(real(C1)) -c FFEINTRIN_imp_REAL_D - call fooR(real(D1)) -c FFEINTRIN_imp_REAL_I - call fooR(real(I1)) -c FFEINTRIN_imp_REAL_R - call fooR(real(R1)) -c -c FFEINTRIN_imp_INT_D: -c -c FFEINTRIN_specIDINT - call fooI(IDINT(D1)) -c -c FFEINTRIN_imp_INT_R: -c -c FFEINTRIN_specIFIX - call fooI(IFIX(R1)) -c FFEINTRIN_specINT - call fooI(INT(R1)) -c -c FFEINTRIN_imp_REAL_D: -c -c FFEINTRIN_specSNGL - call fooR(SNGL(D1)) -c -c FFEINTRIN_imp_REAL_I: -c -c FFEINTRIN_specFLOAT - call fooR(FLOAT(I1)) -c FFEINTRIN_specREAL - call fooR(REAL(I1)) -c - end --------- (end input file to f2c) - --------- (begin output from providing above input file as input to: --------- `f2c | gcc -E -C - | sed -e "s:/[*]*://:g" -e "s:[*]*[/]://:g" \ --------- -e "s:^#.*$::g"') - -// -- translated by f2c (version 19950223). - You must link the resulting object file with the libraries: - -lf2c -lm (in that order) -// - - -// f2c.h -- Standard Fortran to C header file // - -/// barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed." - - - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) // - - - - -// F2C_INTEGER will normally be `int' but would be `long' on 16-bit systems // -// we assume short, float are OK // -typedef long int // long int // integer; -typedef char *address; -typedef short int shortint; -typedef float real; -typedef double doublereal; -typedef struct { real r, i; } complex; -typedef struct { doublereal r, i; } doublecomplex; -typedef long int // long int // logical; -typedef short int shortlogical; -typedef char logical1; -typedef char integer1; -// typedef long long longint; // // system-dependent // - - - - -// Extern is for use with -E // - - - - -// I/O stuff // - - - - - - - - -typedef long int // int or long int // flag; -typedef long int // int or long int // ftnlen; -typedef long int // int or long int // ftnint; - - -//external read, write// -typedef struct -{ flag cierr; - ftnint ciunit; - flag ciend; - char *cifmt; - ftnint cirec; -} cilist; - -//internal read, write// -typedef struct -{ flag icierr; - char *iciunit; - flag iciend; - char *icifmt; - ftnint icirlen; - ftnint icirnum; -} icilist; - -//open// -typedef struct -{ flag oerr; - ftnint ounit; - char *ofnm; - ftnlen ofnmlen; - char *osta; - char *oacc; - char *ofm; - ftnint orl; - char *oblnk; -} olist; - -//close// -typedef struct -{ flag cerr; - ftnint cunit; - char *csta; -} cllist; - -//rewind, backspace, endfile// -typedef struct -{ flag aerr; - ftnint aunit; -} alist; - -// inquire // -typedef struct -{ flag inerr; - ftnint inunit; - char *infile; - ftnlen infilen; - ftnint *inex; //parameters in standard's order// - ftnint *inopen; - ftnint *innum; - ftnint *innamed; - char *inname; - ftnlen innamlen; - char *inacc; - ftnlen inacclen; - char *inseq; - ftnlen inseqlen; - char *indir; - ftnlen indirlen; - char *infmt; - ftnlen infmtlen; - char *inform; - ftnint informlen; - char *inunf; - ftnlen inunflen; - ftnint *inrecl; - ftnint *innrec; - char *inblank; - ftnlen inblanklen; -} inlist; - - - -union Multitype { // for multiple entry points // - integer1 g; - shortint h; - integer i; - // longint j; // - real r; - doublereal d; - complex c; - doublecomplex z; - }; - -typedef union Multitype Multitype; - -typedef long Long; // No longer used; formerly in Namelist // - -struct Vardesc { // for Namelist // - char *name; - char *addr; - ftnlen *dims; - int type; - }; -typedef struct Vardesc Vardesc; - -struct Namelist { - char *name; - Vardesc **vars; - int nvars; - }; -typedef struct Namelist Namelist; - - - - - - - - -// procedure parameter types for -A and -C++ // - - - - -typedef int // Unknown procedure type // (*U_fp)(); -typedef shortint (*J_fp)(); -typedef integer (*I_fp)(); -typedef real (*R_fp)(); -typedef doublereal (*D_fp)(), (*E_fp)(); -typedef // Complex // void (*C_fp)(); -typedef // Double Complex // void (*Z_fp)(); -typedef logical (*L_fp)(); -typedef shortlogical (*K_fp)(); -typedef // Character // void (*H_fp)(); -typedef // Subroutine // int (*S_fp)(); - -// E_fp is for real functions when -R is not specified // -typedef void C_f; // complex function // -typedef void H_f; // character function // -typedef void Z_f; // double complex function // -typedef doublereal E_f; // real function with -R not specified // - -// undef any lower-case symbols that your C compiler predefines, e.g.: // - - -// (No such symbols should be defined in a strict ANSI C compiler. - We can avoid trouble with f2c-translated code by using - gcc -ansi [-traditional].) // - - - - - - - - - - - - - - - - - - - - - - - -// Main program // MAIN__() -{ - // System generated locals // - integer i__1; - real r__1, r__2; - doublereal d__1, d__2; - complex q__1; - doublecomplex z__1, z__2, z__3; - logical L__1; - char ch__1[1]; - - // Builtin functions // - void c_div(); - integer pow_ii(); - double pow_ri(), pow_di(); - void pow_ci(); - double pow_dd(); - void pow_zz(); - double acos(), r_imag(), r_int(), log(), r_lg10(), r_mod(), r_nint(), - asin(), atan(), atan2(), c_abs(); - void c_cos(), c_exp(), c_log(), r_cnjg(); - double cos(), cosh(); - void c_sin(), c_sqrt(); - double d_dim(), exp(), r_dim(), d_int(), d_lg10(), d_mod(), d_nint(), - d_sign(), sin(), sinh(), sqrt(), tan(), tanh(); - integer i_dim(), i_dnnt(), i_indx(), i_sign(), i_len(); - logical l_ge(), l_gt(), l_le(), l_lt(); - integer i_nint(); - double r_sign(); - - // Local variables // - extern // Subroutine // int fooa_(), fooc_(), food_(), fooi_(), foor_(), - fool_(), fooz_(), getem_(); - static char a1[10], a2[10]; - static complex c1, c2; - static doublereal d1, d2; - static integer i1, i2; - static real r1, r2; - - - getem_(a1, a2, &c1, &c2, &i1, &i2, &r1, &r2, &d1, &d2, 10L, 10L); -// / // - i__1 = i1 / i2; - fooi_(&i__1); - r__1 = r1 / i1; - foor_(&r__1); - d__1 = d1 / i1; - food_(&d__1); - d__1 = (doublereal) i1; - q__1.r = c1.r / d__1, q__1.i = c1.i / d__1; - fooc_(&q__1); - r__1 = r1 / r2; - foor_(&r__1); - d__1 = r1 / d1; - food_(&d__1); - d__1 = d1 / d2; - food_(&d__1); - d__1 = d1 / r1; - food_(&d__1); - c_div(&q__1, &c1, &c2); - fooc_(&q__1); - q__1.r = c1.r / r1, q__1.i = c1.i / r1; - fooc_(&q__1); - z__1.r = c1.r / d1, z__1.i = c1.i / d1; - fooz_(&z__1); -// ** // - i__1 = pow_ii(&i1, &i2); - fooi_(&i__1); - r__1 = pow_ri(&r1, &i1); - foor_(&r__1); - d__1 = pow_di(&d1, &i1); - food_(&d__1); - pow_ci(&q__1, &c1, &i1); - fooc_(&q__1); - d__1 = (doublereal) r1; - d__2 = (doublereal) r2; - r__1 = pow_dd(&d__1, &d__2); - foor_(&r__1); - d__2 = (doublereal) r1; - d__1 = pow_dd(&d__2, &d1); - food_(&d__1); - d__1 = pow_dd(&d1, &d2); - food_(&d__1); - d__2 = (doublereal) r1; - d__1 = pow_dd(&d1, &d__2); - food_(&d__1); - z__2.r = c1.r, z__2.i = c1.i; - z__3.r = c2.r, z__3.i = c2.i; - pow_zz(&z__1, &z__2, &z__3); - q__1.r = z__1.r, q__1.i = z__1.i; - fooc_(&q__1); - z__2.r = c1.r, z__2.i = c1.i; - z__3.r = r1, z__3.i = 0.; - pow_zz(&z__1, &z__2, &z__3); - q__1.r = z__1.r, q__1.i = z__1.i; - fooc_(&q__1); - z__2.r = c1.r, z__2.i = c1.i; - z__3.r = d1, z__3.i = 0.; - pow_zz(&z__1, &z__2, &z__3); - fooz_(&z__1); -// FFEINTRIN_impABS // - r__1 = (doublereal)(( r1 ) >= 0 ? ( r1 ) : -( r1 )) ; - foor_(&r__1); -// FFEINTRIN_impACOS // - r__1 = acos(r1); - foor_(&r__1); -// FFEINTRIN_impAIMAG // - r__1 = r_imag(&c1); - foor_(&r__1); -// FFEINTRIN_impAINT // - r__1 = r_int(&r1); - foor_(&r__1); -// FFEINTRIN_impALOG // - r__1 = log(r1); - foor_(&r__1); -// FFEINTRIN_impALOG10 // - r__1 = r_lg10(&r1); - foor_(&r__1); -// FFEINTRIN_impAMAX0 // - r__1 = (real) (( i1 ) >= ( i2 ) ? ( i1 ) : ( i2 )) ; - foor_(&r__1); -// FFEINTRIN_impAMAX1 // - r__1 = (doublereal)(( r1 ) >= ( r2 ) ? ( r1 ) : ( r2 )) ; - foor_(&r__1); -// FFEINTRIN_impAMIN0 // - r__1 = (real) (( i1 ) <= ( i2 ) ? ( i1 ) : ( i2 )) ; - foor_(&r__1); -// FFEINTRIN_impAMIN1 // - r__1 = (doublereal)(( r1 ) <= ( r2 ) ? ( r1 ) : ( r2 )) ; - foor_(&r__1); -// FFEINTRIN_impAMOD // - r__1 = r_mod(&r1, &r2); - foor_(&r__1); -// FFEINTRIN_impANINT // - r__1 = r_nint(&r1); - foor_(&r__1); -// FFEINTRIN_impASIN // - r__1 = asin(r1); - foor_(&r__1); -// FFEINTRIN_impATAN // - r__1 = atan(r1); - foor_(&r__1); -// FFEINTRIN_impATAN2 // - r__1 = atan2(r1, r2); - foor_(&r__1); -// FFEINTRIN_impCABS // - r__1 = c_abs(&c1); - foor_(&r__1); -// FFEINTRIN_impCCOS // - c_cos(&q__1, &c1); - fooc_(&q__1); -// FFEINTRIN_impCEXP // - c_exp(&q__1, &c1); - fooc_(&q__1); -// FFEINTRIN_impCHAR // - *(unsigned char *)&ch__1[0] = i1; - fooa_(ch__1, 1L); -// FFEINTRIN_impCLOG // - c_log(&q__1, &c1); - fooc_(&q__1); -// FFEINTRIN_impCONJG // - r_cnjg(&q__1, &c1); - fooc_(&q__1); -// FFEINTRIN_impCOS // - r__1 = cos(r1); - foor_(&r__1); -// FFEINTRIN_impCOSH // - r__1 = cosh(r1); - foor_(&r__1); -// FFEINTRIN_impCSIN // - c_sin(&q__1, &c1); - fooc_(&q__1); -// FFEINTRIN_impCSQRT // - c_sqrt(&q__1, &c1); - fooc_(&q__1); -// FFEINTRIN_impDABS // - d__1 = (( d1 ) >= 0 ? ( d1 ) : -( d1 )) ; - food_(&d__1); -// FFEINTRIN_impDACOS // - d__1 = acos(d1); - food_(&d__1); -// FFEINTRIN_impDASIN // - d__1 = asin(d1); - food_(&d__1); -// FFEINTRIN_impDATAN // - d__1 = atan(d1); - food_(&d__1); -// FFEINTRIN_impDATAN2 // - d__1 = atan2(d1, d2); - food_(&d__1); -// FFEINTRIN_impDCOS // - d__1 = cos(d1); - food_(&d__1); -// FFEINTRIN_impDCOSH // - d__1 = cosh(d1); - food_(&d__1); -// FFEINTRIN_impDDIM // - d__1 = d_dim(&d1, &d2); - food_(&d__1); -// FFEINTRIN_impDEXP // - d__1 = exp(d1); - food_(&d__1); -// FFEINTRIN_impDIM // - r__1 = r_dim(&r1, &r2); - foor_(&r__1); -// FFEINTRIN_impDINT // - d__1 = d_int(&d1); - food_(&d__1); -// FFEINTRIN_impDLOG // - d__1 = log(d1); - food_(&d__1); -// FFEINTRIN_impDLOG10 // - d__1 = d_lg10(&d1); - food_(&d__1); -// FFEINTRIN_impDMAX1 // - d__1 = (( d1 ) >= ( d2 ) ? ( d1 ) : ( d2 )) ; - food_(&d__1); -// FFEINTRIN_impDMIN1 // - d__1 = (( d1 ) <= ( d2 ) ? ( d1 ) : ( d2 )) ; - food_(&d__1); -// FFEINTRIN_impDMOD // - d__1 = d_mod(&d1, &d2); - food_(&d__1); -// FFEINTRIN_impDNINT // - d__1 = d_nint(&d1); - food_(&d__1); -// FFEINTRIN_impDPROD // - d__1 = (doublereal) r1 * r2; - food_(&d__1); -// FFEINTRIN_impDSIGN // - d__1 = d_sign(&d1, &d2); - food_(&d__1); -// FFEINTRIN_impDSIN // - d__1 = sin(d1); - food_(&d__1); -// FFEINTRIN_impDSINH // - d__1 = sinh(d1); - food_(&d__1); -// FFEINTRIN_impDSQRT // - d__1 = sqrt(d1); - food_(&d__1); -// FFEINTRIN_impDTAN // - d__1 = tan(d1); - food_(&d__1); -// FFEINTRIN_impDTANH // - d__1 = tanh(d1); - food_(&d__1); -// FFEINTRIN_impEXP // - r__1 = exp(r1); - foor_(&r__1); -// FFEINTRIN_impIABS // - i__1 = (( i1 ) >= 0 ? ( i1 ) : -( i1 )) ; - fooi_(&i__1); -// FFEINTRIN_impICHAR // - i__1 = *(unsigned char *)a1; - fooi_(&i__1); -// FFEINTRIN_impIDIM // - i__1 = i_dim(&i1, &i2); - fooi_(&i__1); -// FFEINTRIN_impIDNINT // - i__1 = i_dnnt(&d1); - fooi_(&i__1); -// FFEINTRIN_impINDEX // - i__1 = i_indx(a1, a2, 10L, 10L); - fooi_(&i__1); -// FFEINTRIN_impISIGN // - i__1 = i_sign(&i1, &i2); - fooi_(&i__1); -// FFEINTRIN_impLEN // - i__1 = i_len(a1, 10L); - fooi_(&i__1); -// FFEINTRIN_impLGE // - L__1 = l_ge(a1, a2, 10L, 10L); - fool_(&L__1); -// FFEINTRIN_impLGT // - L__1 = l_gt(a1, a2, 10L, 10L); - fool_(&L__1); -// FFEINTRIN_impLLE // - L__1 = l_le(a1, a2, 10L, 10L); - fool_(&L__1); -// FFEINTRIN_impLLT // - L__1 = l_lt(a1, a2, 10L, 10L); - fool_(&L__1); -// FFEINTRIN_impMAX0 // - i__1 = (( i1 ) >= ( i2 ) ? ( i1 ) : ( i2 )) ; - fooi_(&i__1); -// FFEINTRIN_impMAX1 // - i__1 = (integer) (doublereal)(( r1 ) >= ( r2 ) ? ( r1 ) : ( r2 )) ; - fooi_(&i__1); -// FFEINTRIN_impMIN0 // - i__1 = (( i1 ) <= ( i2 ) ? ( i1 ) : ( i2 )) ; - fooi_(&i__1); -// FFEINTRIN_impMIN1 // - i__1 = (integer) (doublereal)(( r1 ) <= ( r2 ) ? ( r1 ) : ( r2 )) ; - fooi_(&i__1); -// FFEINTRIN_impMOD // - i__1 = i1 % i2; - fooi_(&i__1); -// FFEINTRIN_impNINT // - i__1 = i_nint(&r1); - fooi_(&i__1); -// FFEINTRIN_impSIGN // - r__1 = r_sign(&r1, &r2); - foor_(&r__1); -// FFEINTRIN_impSIN // - r__1 = sin(r1); - foor_(&r__1); -// FFEINTRIN_impSINH // - r__1 = sinh(r1); - foor_(&r__1); -// FFEINTRIN_impSQRT // - r__1 = sqrt(r1); - foor_(&r__1); -// FFEINTRIN_impTAN // - r__1 = tan(r1); - foor_(&r__1); -// FFEINTRIN_impTANH // - r__1 = tanh(r1); - foor_(&r__1); -// FFEINTRIN_imp_CMPLX_C // - r__1 = c1.r; - r__2 = c2.r; - q__1.r = r__1, q__1.i = r__2; - fooc_(&q__1); -// FFEINTRIN_imp_CMPLX_D // - z__1.r = d1, z__1.i = d2; - fooz_(&z__1); -// FFEINTRIN_imp_CMPLX_I // - r__1 = (real) i1; - r__2 = (real) i2; - q__1.r = r__1, q__1.i = r__2; - fooc_(&q__1); -// FFEINTRIN_imp_CMPLX_R // - q__1.r = r1, q__1.i = r2; - fooc_(&q__1); -// FFEINTRIN_imp_DBLE_C // - d__1 = (doublereal) c1.r; - food_(&d__1); -// FFEINTRIN_imp_DBLE_D // - d__1 = d1; - food_(&d__1); -// FFEINTRIN_imp_DBLE_I // - d__1 = (doublereal) i1; - food_(&d__1); -// FFEINTRIN_imp_DBLE_R // - d__1 = (doublereal) r1; - food_(&d__1); -// FFEINTRIN_imp_INT_C // - i__1 = (integer) c1.r; - fooi_(&i__1); -// FFEINTRIN_imp_INT_D // - i__1 = (integer) d1; - fooi_(&i__1); -// FFEINTRIN_imp_INT_I // - i__1 = i1; - fooi_(&i__1); -// FFEINTRIN_imp_INT_R // - i__1 = (integer) r1; - fooi_(&i__1); -// FFEINTRIN_imp_REAL_C // - r__1 = c1.r; - foor_(&r__1); -// FFEINTRIN_imp_REAL_D // - r__1 = (real) d1; - foor_(&r__1); -// FFEINTRIN_imp_REAL_I // - r__1 = (real) i1; - foor_(&r__1); -// FFEINTRIN_imp_REAL_R // - r__1 = r1; - foor_(&r__1); - -// FFEINTRIN_imp_INT_D: // - -// FFEINTRIN_specIDINT // - i__1 = (integer) d1; - fooi_(&i__1); - -// FFEINTRIN_imp_INT_R: // - -// FFEINTRIN_specIFIX // - i__1 = (integer) r1; - fooi_(&i__1); -// FFEINTRIN_specINT // - i__1 = (integer) r1; - fooi_(&i__1); - -// FFEINTRIN_imp_REAL_D: // - -// FFEINTRIN_specSNGL // - r__1 = (real) d1; - foor_(&r__1); - -// FFEINTRIN_imp_REAL_I: // - -// FFEINTRIN_specFLOAT // - r__1 = (real) i1; - foor_(&r__1); -// FFEINTRIN_specREAL // - r__1 = (real) i1; - foor_(&r__1); - -} // MAIN__ // - --------- (end output file from f2c) - -*/