blob: d9b63bee655222b8799106f92adbeff6bb216933 [file] [log] [blame]
/* gm2-lang.cc language-dependent hooks for GNU Modula-2.
Copyright (C) 2002-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.ac.uk>.
This file is part of GNU Modula-2.
GNU Modula-2 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 3, or (at your option)
any later version.
GNU Modula-2 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 Modula-2; see the file COPYING. If not, write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
#define INCLUDE_VECTOR
#include "gm2-gcc/gcc-consolidation.h"
#include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name. */
#include "tree-pass.h" /* FIXME: only for PROP_gimple_any. */
#include "toplev.h"
#include "debug.h"
#include "opts.h"
#define GM2_LANG_C
#include "gm2-lang.h"
#include "m2block.h"
#include "dynamicstrings.h"
#include "m2options.h"
#include "m2convert.h"
#include "m2linemap.h"
#include "init.h"
#include "m2-tree.h"
#include "convert.h"
#include "rtegraph.h"
static void write_globals (void);
static int insideCppArgs = FALSE;
/* We default to pim in the absence of fiso. */
static bool iso = false;
/* The language include paths are based on the libraries in use. */
static bool allow_libraries = true;
static const char *flibs = nullptr;
static const char *iprefix = nullptr;
static const char *imultilib = nullptr;
static std::vector<const char*>Ipaths;
static std::vector<const char*>isystem;
static std::vector<const char*>iquote;
#define EXPR_STMT_EXPR(NODE) TREE_OPERAND (EXPR_STMT_CHECK (NODE), 0)
/* start of new stuff. */
/* Language-dependent contents of a type. */
struct GTY (()) lang_type
{
char dummy;
};
/* Language-dependent contents of a decl. */
struct GTY (()) lang_decl
{
char dummy;
};
/* Language-dependent contents of an identifier. This must include a
tree_identifier. */
struct GTY (()) lang_identifier
{
struct tree_identifier common;
};
/* The resulting tree type. */
union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), "
"TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN "
"(&%h.generic)) : NULL"))) lang_tree_node
{
union tree_node GTY ((tag ("0"),
desc ("tree_node_structure (&%h)"))) generic;
struct lang_identifier GTY ((tag ("1"))) identifier;
};
struct GTY (()) language_function
{
/* While we are parsing the function, this contains information about
the statement-tree that we are building. */
/* struct stmt_tree_s stmt_tree; */
tree stmt_tree;
};
/* Language hooks. */
static void gm2_langhook_parse_file (void);
bool
gm2_langhook_init (void)
{
build_common_tree_nodes (false);
build_common_builtin_nodes ();
/* The default precision for floating point numbers. This is used
for floating point constants with abstract type. This may eventually
be controllable by a command line option. */
mpfr_set_default_prec (256);
/* GNU Modula-2 uses exceptions. */
using_eh_for_cleanups ();
if (M2Options_GetPPOnly ())
{
/* preprocess the file here. */
gm2_langhook_parse_file ();
return false; /* Finish now, no further compilation. */
}
return true;
}
/* The option mask. */
static unsigned int
gm2_langhook_option_lang_mask (void)
{
return CL_ModulaX2;
}
/* Initialize the options structure. */
static void
gm2_langhook_init_options_struct (struct gcc_options *opts)
{
/* Default to avoiding range issues for complex multiply and divide. */
opts->x_flag_complex_method = 2;
/* The builtin math functions should not set errno. */
opts->x_flag_errno_math = 0;
opts->frontend_set_flag_errno_math = true;
/* Exceptions are used. */
opts->x_flag_exceptions = 1;
init_FrontEndInit ();
}
/* Infrastructure for a VEC of bool values. */
/* This array determines whether the filename is associated with the
C preprocessor. */
static vec<bool> filename_cpp;
/* Build the C preprocessor command line here, since we need to include
options that are not passed to the handle_option function. */
void
gm2_langhook_init_options (unsigned int decoded_options_count,
struct cl_decoded_option *decoded_options)
{
unsigned int i;
bool in_cpp_args = false;
bool building_cpp_command = false;
for (i = 1; i < decoded_options_count; i++)
{
enum opt_code code = (enum opt_code)decoded_options[i].opt_index;
const struct cl_option *option = &cl_options[code];
const char *opt = (const char *)option->opt_text;
const char *arg = decoded_options[i].arg;
HOST_WIDE_INT value = decoded_options[i].value;
switch (code)
{
case OPT_fcpp:
gcc_checking_assert (building_cpp_command);
break;
case OPT_fcpp_begin:
in_cpp_args = true;
building_cpp_command = true;
break;
case OPT_fcpp_end:
in_cpp_args = false;
break;
case OPT_SPECIAL_input_file:
filename_cpp.safe_push (in_cpp_args);
break;
/* C and driver opts that are not passed to the preprocessor for
modula-2, but that we use internally for building preprocesor
command lines. */
case OPT_B:
M2Options_SetB (arg);
break;
case OPT_c:
M2Options_Setc (value);
break;
case OPT_dumpdir:
if (building_cpp_command)
M2Options_SetDumpDir (arg);
break;
case OPT_save_temps:
if (building_cpp_command)
M2Options_SetSaveTemps (value);
break;
case OPT_save_temps_:
if (building_cpp_command)
/* Also sets SaveTemps. */
M2Options_SetSaveTempsDir (arg);
break;
case OPT_E:
if (!in_cpp_args)
{
M2Options_SetPPOnly (value);
building_cpp_command = true;
}
M2Options_CppArg (opt, arg, (option->flags & CL_JOINED)
&& !(option->flags & CL_SEPARATE));
break;
case OPT_M:
case OPT_MM:
gcc_checking_assert (building_cpp_command);
M2Options_SetPPOnly (value);
/* This is a preprocessor command. */
M2Options_CppArg (opt, arg, (option->flags & CL_JOINED)
&& !(option->flags & CL_SEPARATE));
break;
/* We can only use MQ when the command line is either PP-only, or
when there is a MD/MMD on it. */
case OPT_MQ:
M2Options_SetMQ (arg);
break;
case OPT_o:
M2Options_SetObj (arg);
break;
/* C and driver options that we ignore for the preprocessor lines. */
case OPT_fpch_deps:
case OPT_fpch_preprocess:
break;
case OPT_fplugin_:
/* FIXME: We might need to handle this specially, since the modula-2
plugin is not usable here, but others might be.
For now skip all plugins to avoid fails with the m2 one. */
break;
/* Preprocessor arguments with a following filename, we add these
back to the main file preprocess line, but not to dependents
TODO Handle MF. */
case OPT_MD:
M2Options_SetMD (arg);
break;
case OPT_MMD:
M2Options_SetMMD (arg);
break;
/* Modula 2 claimed options we pass to the preprocessor. */
case OPT_ansi:
case OPT_traditional_cpp:
if (building_cpp_command)
M2Options_CppArg (opt, arg, (option->flags & CL_JOINED)
&& !(option->flags & CL_SEPARATE));
break;
/* Options we act on and also pass to the preprocessor. */
case OPT_O:
M2Options_SetOptimizing (value);
if (building_cpp_command)
M2Options_CppArg (opt, arg, (option->flags & CL_JOINED)
&& !(option->flags & CL_SEPARATE));
break;
case OPT_quiet:
M2Options_SetQuiet (value);
if (building_cpp_command)
M2Options_CppArg (opt, arg, (option->flags & CL_JOINED)
&& !(option->flags & CL_SEPARATE));
break;
case OPT_v:
M2Options_SetVerbose (value);
/* FALLTHROUGH */
default:
/* We handled input files above. */
if (code >= N_OPTS)
break;
/* Do not pass Modula-2 args to the preprocessor, any that we care
about here should already have been handled above. */
if (option->flags & CL_ModulaX2)
break;
/* Otherwise, add this to the CPP command line. */
if (building_cpp_command)
M2Options_CppArg (opt, arg, (option->flags & CL_JOINED)
&& !(option->flags & CL_SEPARATE));
break;
}
}
filename_cpp.safe_push (false);
}
static bool
is_cpp_filename (unsigned int i)
{
gcc_assert (i < filename_cpp.length ());
return filename_cpp[i];
}
/* Handle gm2 specific options. Return 0 if we didn't do anything. */
bool
gm2_langhook_handle_option (
size_t scode, const char *arg, HOST_WIDE_INT value, int kind ATTRIBUTE_UNUSED,
location_t loc ATTRIBUTE_UNUSED,
const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
{
enum opt_code code = (enum opt_code)scode;
const struct cl_option *option = &cl_options[scode];
/* ignore file names. */
if (code == N_OPTS)
return 1;
switch (code)
{
case OPT_I:
Ipaths.push_back (arg);
return 1;
case OPT_fiso:
M2Options_SetISO (value);
iso = value;
return 1;
case OPT_fpim:
M2Options_SetPIM (value);
iso = value ? false : iso;
return 1;
case OPT_fpim2:
M2Options_SetPIM2 (value);
iso = value ? false : iso;
return 1;
case OPT_fpim3:
M2Options_SetPIM3 (value);
iso = value ? false : iso;
return 1;
case OPT_fpim4:
M2Options_SetPIM4 (value);
iso = value ? false : iso;
return 1;
case OPT_fpositive_mod_floor_div:
M2Options_SetPositiveModFloor (value);
return 1;
case OPT_flibs_:
allow_libraries = value;
flibs = arg;
return 1;
case OPT_fgen_module_list_:
M2Options_SetGenModuleList (value, arg);
return 1;
case OPT_fnil:
M2Options_SetNilCheck (value);
return 1;
case OPT_fwholediv:
M2Options_SetWholeDiv (value);
return 1;
case OPT_findex:
M2Options_SetIndex (value);
return 1;
case OPT_frange:
M2Options_SetRange (value);
return 1;
case OPT_ffloatvalue:
M2Options_SetFloatValueCheck (value);
return 1;
case OPT_fwholevalue:
M2Options_SetWholeValueCheck (value);
return 1;
case OPT_freturn:
M2Options_SetReturnCheck (value);
return 1;
case OPT_fcase:
M2Options_SetCaseCheck (value);
return 1;
case OPT_fd:
M2Options_SetCompilerDebugging (value);
return 1;
case OPT_fdebug_trace_quad:
M2Options_SetDebugTraceQuad (value);
return 1;
case OPT_fdebug_trace_api:
M2Options_SetDebugTraceAPI (value);
return 1;
case OPT_fdebug_function_line_numbers:
M2Options_SetDebugFunctionLineNumbers (value);
return 1;
case OPT_fauto_init:
M2Options_SetAutoInit (value);
return 1;
case OPT_fsoft_check_all:
M2Options_SetCheckAll (value);
return 1;
case OPT_fexceptions:
M2Options_SetExceptions (value);
return 1;
case OPT_Wstyle:
M2Options_SetStyle (value);
return 1;
case OPT_Wpedantic:
M2Options_SetPedantic (value);
return 1;
case OPT_Wpedantic_param_names:
M2Options_SetPedanticParamNames (value);
return 1;
case OPT_Wpedantic_cast:
M2Options_SetPedanticCast (value);
return 1;
case OPT_fextended_opaque:
M2Options_SetExtendedOpaque (value);
return 1;
case OPT_Wverbose_unbounded:
M2Options_SetVerboseUnbounded (value);
return 1;
case OPT_Wunused_variable:
M2Options_SetUnusedVariableChecking (value);
return 1;
case OPT_Wunused_parameter:
M2Options_SetUnusedParameterChecking (value);
return 1;
case OPT_fm2_strict_type:
M2Options_SetStrictTypeChecking (value);
return 1;
case OPT_Wall:
M2Options_SetWall (value);
return 1;
#if 0
/* Not yet implemented. */
case OPT_fxcode:
M2Options_SetXCode (value);
return 1;
#endif
case OPT_fm2_lower_case:
M2Options_SetLowerCaseKeywords (value);
return 1;
case OPT_fuse_list_:
M2Options_SetUselist (value, arg);
return 1;
case OPT_fruntime_modules_:
M2Options_SetRuntimeModuleOverride (arg);
return 1;
case OPT_fpthread:
/* Handled in the driver. */
return 1;
case OPT_fm2_plugin:
/* Handled in the driver. */
return 1;
case OPT_fscaffold_dynamic:
M2Options_SetScaffoldDynamic (value);
return 1;
case OPT_fscaffold_static:
M2Options_SetScaffoldStatic (value);
return 1;
case OPT_fscaffold_main:
M2Options_SetScaffoldMain (value);
return 1;
case OPT_fcpp:
M2Options_SetCpp (value);
return 1;
case OPT_fpreprocessed:
/* Provided for compatibility; ignore for now. */
return 1;
case OPT_fcpp_begin:
insideCppArgs = TRUE;
return 1;
case OPT_fcpp_end:
insideCppArgs = FALSE;
return 1;
case OPT_fq:
M2Options_SetQuadDebugging (value);
return 1;
case OPT_fsources:
M2Options_SetSources (value);
return 1;
case OPT_funbounded_by_reference:
M2Options_SetUnboundedByReference (value);
return 1;
case OPT_fdef_:
M2Options_setdefextension (arg);
return 1;
case OPT_fmod_:
M2Options_setmodextension (arg);
return 1;
case OPT_fdump_system_exports:
M2Options_SetDumpSystemExports (value);
return 1;
case OPT_fswig:
M2Options_SetSwig (value);
return 1;
case OPT_fshared:
M2Options_SetShared (value);
return 1;
case OPT_fm2_statistics:
M2Options_SetStatistics (value);
return 1;
case OPT_fm2_g:
M2Options_SetM2g (value);
return 1;
break;
case OPT_iprefix:
iprefix = arg;
return 1;
break;
case OPT_imultilib:
imultilib = arg;
return 1;
break;
case OPT_isystem:
isystem.push_back (arg);
return 1;
break;
case OPT_iquote:
iquote.push_back (arg);
return 1;
break;
case OPT_isysroot:
/* Otherwise, ignored, at least for now. */
return 1;
break;
case OPT_fm2_whole_program:
M2Options_SetWholeProgram (value);
return 1;
case OPT_flocation_:
if (strcmp (arg, "builtins") == 0)
{
M2Options_SetForcedLocation (BUILTINS_LOCATION);
return 1;
}
else if (strcmp (arg, "unknown") == 0)
{
M2Options_SetForcedLocation (UNKNOWN_LOCATION);
return 1;
}
else if ((arg != NULL) && (ISDIGIT (arg[0])))
{
M2Options_SetForcedLocation (atoi (arg));
return 1;
}
else
return 0;
default:
if (insideCppArgs)
/* Handled in gm2_langhook_init_options (). */
return 1;
else if (option->flags & CL_DRIVER)
/* Driver options (unless specifically claimed above) should be handled
in gm2_langhook_init_options (). */
return 1;
else if (option->flags & CL_C)
/* C options (unless specifically claimed above) should be handled
in gm2_langhook_init_options (). */
return 1;
break;
}
return 0;
}
/* This prefixes LIBNAME with the current compiler prefix (if it has been
relocated) or the LIBSUBDIR, if not. */
static void
add_one_import_path (const char *libname)
{
const char *libpath = iprefix ? iprefix : LIBSUBDIR;
const char dir_sep[] = {DIR_SEPARATOR, (char)0};
size_t dir_sep_size = strlen (dir_sep);
unsigned int mlib_len = 0;
if (imultilib)
{
mlib_len = strlen (imultilib);
mlib_len += strlen (dir_sep);
}
char *lib = (char *)alloca (strlen (libpath) + dir_sep_size
+ strlen ("m2") + dir_sep_size
+ strlen (libname) + 1
+ mlib_len + 1);
strcpy (lib, libpath);
/* iprefix has a trailing dir separator, LIBSUBDIR does not. */
if (!iprefix)
strcat (lib, dir_sep);
if (imultilib)
{
strcat (lib, imultilib);
strcat (lib, dir_sep);
}
strcat (lib, "m2");
strcat (lib, dir_sep);
strcat (lib, libname);
M2Options_SetSearchPath (lib);
}
/* For each comma-separated standard library name in LIBLIST, add the
corresponding include path. */
static void
add_m2_import_paths (const char *liblist)
{
while (*liblist != 0 && *liblist != '-')
{
const char *comma = strstr (liblist, ",");
size_t len;
if (comma)
len = comma - liblist;
else
len = strlen (liblist);
char *libname = (char *) alloca (len+1);
strncpy (libname, liblist, len);
libname[len] = 0;
add_one_import_path (libname);
liblist += len;
if (*liblist == ',')
liblist++;
}
}
/* Run after parsing options. */
static bool
gm2_langhook_post_options (const char **pfilename)
{
const char *filename = *pfilename;
flag_excess_precision = EXCESS_PRECISION_FAST;
M2Options_SetCC1Quiet (quiet_flag);
M2Options_FinaliseOptions ();
main_input_filename = filename;
/* Add the include paths as per the libraries specified.
NOTE: This assumes that the driver has validated the input and makes
no attempt to be defensive of nonsense input in flibs=. */
if (allow_libraries)
{
if (!flibs)
{
if (iso)
flibs = "m2iso,m2cor,m2pim,m2log";
else
flibs = "m2pim,m2iso,m2cor,m2log";
}
}
/* Add search paths.
We are not handling all of the cases yet (e.g idirafter).
This (barring the missing cases) is intended to follow the directory
search rules used for c-family. It would be less confusing if the
presence of absence of these search paths was not dependent on the
flibs= option. */
for (auto *s : iquote)
M2Options_SetSearchPath (s);
iquote.clear();
for (auto *s : Ipaths)
M2Options_SetSearchPath (s);
Ipaths.clear();
for (auto *s : isystem)
M2Options_SetSearchPath (s);
isystem.clear();
/* FIXME: this is not a good way to suppress the addition of the import
paths. */
if (allow_libraries)
add_m2_import_paths (flibs);
/* Returning false means that the backend should be used. */
return M2Options_GetPPOnly ();
}
/* Call the compiler for every source filename on the command line. */
static void
gm2_parse_input_files (const char **filenames, unsigned int filename_count)
{
unsigned int i;
gcc_assert (filename_count > 0);
for (i = 0; i < filename_count; i++)
if (!is_cpp_filename (i))
{
main_input_filename = filenames[i];
init_PerCompilationInit (filenames[i]);
}
}
static void
gm2_langhook_parse_file (void)
{
gm2_parse_input_files (in_fnames, num_in_fnames);
if (!M2Options_GetPPOnly ())
write_globals ();
}
static tree
gm2_langhook_type_for_size (unsigned int bits, int unsignedp)
{
return gm2_type_for_size (bits, unsignedp);
}
static tree
gm2_langhook_type_for_mode (machine_mode mode, int unsignedp)
{
tree type;
for (int i = 0; i < NUM_INT_N_ENTS; i ++)
if (int_n_enabled_p[i]
&& mode == int_n_data[i].m)
return (unsignedp ? int_n_trees[i].unsigned_type
: int_n_trees[i].signed_type);
if (VECTOR_MODE_P (mode))
{
tree inner;
inner = gm2_langhook_type_for_mode (GET_MODE_INNER (mode), unsignedp);
if (inner != NULL_TREE)
return build_vector_type_for_mode (inner, mode);
return NULL_TREE;
}
scalar_int_mode imode;
if (is_int_mode (mode, &imode))
return gm2_langhook_type_for_size (GET_MODE_BITSIZE (imode), unsignedp);
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 (COMPLEX_MODE_P (mode))
{
if (mode == TYPE_MODE (complex_float_type_node))
return complex_float_type_node;
if (mode == TYPE_MODE (complex_double_type_node))
return complex_double_type_node;
if (mode == TYPE_MODE (complex_long_double_type_node))
return complex_long_double_type_node;
}
#if HOST_BITS_PER_WIDE_INT >= 64
/* The middle-end and some backends rely on TImode being supported
for 64-bit HWI. */
if (mode == TImode)
{
type = build_nonstandard_integer_type (GET_MODE_BITSIZE (TImode),
unsignedp);
if (type && TYPE_MODE (type) == TImode)
return type;
}
#endif
return NULL_TREE;
}
/* Record a builtin function. We just ignore builtin functions. */
static tree
gm2_langhook_builtin_function (tree decl)
{
return decl;
}
/* Return true if we are in the global binding level. */
static bool
gm2_langhook_global_bindings_p (void)
{
return current_function_decl == NULL_TREE;
}
/* Unused langhook. */
static tree
gm2_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
{
gcc_unreachable ();
}
/* This hook is used to get the current list of declarations as trees.
We don't support that; instead we use write_globals. This can't
simply crash because it is called by -gstabs. */
static tree
gm2_langhook_getdecls (void)
{
return NULL;
}
/* m2_write_global_declarations writes out globals creating an array
of the declarations and calling wrapup_global_declarations. */
static void
m2_write_global_declarations (tree globals)
{
auto_vec<tree> global_decls;
tree decl = globals;
int n = 0;
while (decl != NULL)
{
global_decls.safe_push (decl);
decl = TREE_CHAIN (decl);
n++;
}
wrapup_global_declarations (global_decls.address (), n);
}
/* Write out globals. */
static void
write_globals (void)
{
tree t;
unsigned i;
m2block_finishGlobals ();
/* Process all file scopes in this compilation, and the
external_scope, through wrapup_global_declarations and
check_global_declarations. */
FOR_EACH_VEC_ELT (*all_translation_units, i, t)
m2_write_global_declarations (BLOCK_VARS (DECL_INITIAL (t)));
}
/* Gimplify an EXPR_STMT node. */
static void
gimplify_expr_stmt (tree *stmt_p)
{
gcc_assert (EXPR_STMT_EXPR (*stmt_p) != NULL_TREE);
*stmt_p = EXPR_STMT_EXPR (*stmt_p);
}
/* Genericize a TRY_BLOCK. */
static void
genericize_try_block (tree *stmt_p)
{
tree body = TRY_STMTS (*stmt_p);
tree cleanup = TRY_HANDLERS (*stmt_p);
*stmt_p = build2 (TRY_CATCH_EXPR, void_type_node, body, cleanup);
}
/* Genericize a HANDLER by converting to a CATCH_EXPR. */
static void
genericize_catch_block (tree *stmt_p)
{
tree type = HANDLER_TYPE (*stmt_p);
tree body = HANDLER_BODY (*stmt_p);
/* FIXME should the caught type go in TREE_TYPE? */
*stmt_p = build2 (CATCH_EXPR, void_type_node, type, body);
}
/* Convert the tree representation of FNDECL from m2 frontend trees
to GENERIC. */
extern void pf (tree);
void
gm2_genericize (tree fndecl)
{
tree t;
struct cgraph_node *cgn;
#if 0
pf (fndecl);
#endif
/* Fix up the types of parms passed by invisible reference. */
for (t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t))
if (TREE_ADDRESSABLE (TREE_TYPE (t)))
{
/* If a function's arguments are copied to create a thunk, then
DECL_BY_REFERENCE will be set -- but the type of the argument will be
a pointer type, so we will never get here. */
gcc_assert (!DECL_BY_REFERENCE (t));
gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t));
TREE_TYPE (t) = DECL_ARG_TYPE (t);
DECL_BY_REFERENCE (t) = 1;
TREE_ADDRESSABLE (t) = 0;
relayout_decl (t);
}
/* Dump all nested functions now. */
cgn = cgraph_node::get_create (fndecl);
for (cgn = first_nested_function (cgn);
cgn != NULL; cgn = next_nested_function (cgn))
gm2_genericize (cgn->decl);
}
/* gm2 gimplify expression, currently just change THROW in the same
way as C++ */
static int
gm2_langhook_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
gimple_seq *post_p ATTRIBUTE_UNUSED)
{
enum tree_code code = TREE_CODE (*expr_p);
switch (code)
{
case THROW_EXPR:
/* FIXME communicate throw type to back end, probably by moving
THROW_EXPR into ../tree.def. */
*expr_p = TREE_OPERAND (*expr_p, 0);
return GS_OK;
case EXPR_STMT:
gimplify_expr_stmt (expr_p);
return GS_OK;
case TRY_BLOCK:
genericize_try_block (expr_p);
return GS_OK;
case HANDLER:
genericize_catch_block (expr_p);
return GS_OK;
default:
return GS_UNHANDLED;
}
}
static GTY(()) tree gm2_eh_personality_decl;
static tree
gm2_langhook_eh_personality (void)
{
if (!gm2_eh_personality_decl)
gm2_eh_personality_decl = build_personality_function ("gxx");
return gm2_eh_personality_decl;
}
/* Functions called directly by the generic backend. */
tree
convert_loc (location_t location, tree type, tree expr)
{
if (type == error_mark_node || expr == error_mark_node
|| TREE_TYPE (expr) == error_mark_node)
return error_mark_node;
if (type == TREE_TYPE (expr))
return expr;
gcc_assert (TYPE_MAIN_VARIANT (type) != NULL);
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
return fold_convert (type, expr);
expr = m2convert_GenericToType (location, type, expr);
switch (TREE_CODE (type))
{
case VOID_TYPE:
case BOOLEAN_TYPE:
return fold_convert (type, expr);
case INTEGER_TYPE:
return fold (convert_to_integer (type, expr));
case POINTER_TYPE:
return fold (convert_to_pointer (type, expr));
case REAL_TYPE:
return fold (convert_to_real (type, expr));
case COMPLEX_TYPE:
return fold (convert_to_complex (type, expr));
case ENUMERAL_TYPE:
return fold (convert_to_integer (type, expr));
default:
error_at (location, "cannot convert expression, only base types can be converted");
break;
}
return error_mark_node;
}
/* Functions called directly by the generic backend. */
tree
convert (tree type, tree expr)
{
return convert_loc (m2linemap_UnknownLocation (), type, expr);
}
/* Mark EXP saying that we need to be able to take the address of it;
it should not be allocated in a register. Returns true if
successful. */
bool
gm2_mark_addressable (tree exp)
{
tree x = exp;
while (TRUE)
switch (TREE_CODE (x))
{
case COMPONENT_REF:
if (DECL_PACKED (TREE_OPERAND (x, 1)))
return false;
x = TREE_OPERAND (x, 0);
break;
case ADDR_EXPR:
case ARRAY_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
x = TREE_OPERAND (x, 0);
break;
case COMPOUND_LITERAL_EXPR:
case CONSTRUCTOR:
case STRING_CST:
case VAR_DECL:
case CONST_DECL:
case PARM_DECL:
case RESULT_DECL:
case FUNCTION_DECL:
TREE_ADDRESSABLE (x) = 1;
return true;
default:
return true;
}
/* Never reach here. */
gcc_unreachable ();
}
/* Return an integer type with BITS bits of precision, that is
unsigned if UNSIGNEDP is nonzero, otherwise signed. */
tree
gm2_type_for_size (unsigned int bits, int unsignedp)
{
tree type;
if (unsignedp)
{
if (bits == INT_TYPE_SIZE)
type = unsigned_type_node;
else if (bits == CHAR_TYPE_SIZE)
type = unsigned_char_type_node;
else if (bits == SHORT_TYPE_SIZE)
type = short_unsigned_type_node;
else if (bits == LONG_TYPE_SIZE)
type = long_unsigned_type_node;
else if (bits == LONG_LONG_TYPE_SIZE)
type = long_long_unsigned_type_node;
else
type = build_nonstandard_integer_type (bits,
unsignedp);
}
else
{
if (bits == INT_TYPE_SIZE)
type = integer_type_node;
else if (bits == CHAR_TYPE_SIZE)
type = signed_char_type_node;
else if (bits == SHORT_TYPE_SIZE)
type = short_integer_type_node;
else if (bits == LONG_TYPE_SIZE)
type = long_integer_type_node;
else if (bits == LONG_LONG_TYPE_SIZE)
type = long_long_integer_type_node;
else
type = build_nonstandard_integer_type (bits,
unsignedp);
}
return type;
}
/* Allow the analyzer to understand Storage ALLOCATE/DEALLOCATE. */
bool
gm2_langhook_new_dispose_storage_substitution (void)
{
return true;
}
#undef LANG_HOOKS_NAME
#undef LANG_HOOKS_INIT
#undef LANG_HOOKS_INIT_OPTIONS
#undef LANG_HOOKS_OPTION_LANG_MASK
#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
#undef LANG_HOOKS_HANDLE_OPTION
#undef LANG_HOOKS_POST_OPTIONS
#undef LANG_HOOKS_PARSE_FILE
#undef LANG_HOOKS_TYPE_FOR_MODE
#undef LANG_HOOKS_TYPE_FOR_SIZE
#undef LANG_HOOKS_BUILTIN_FUNCTION
#undef LANG_HOOKS_GLOBAL_BINDINGS_P
#undef LANG_HOOKS_PUSHDECL
#undef LANG_HOOKS_GETDECLS
#undef LANG_HOOKS_GIMPLIFY_EXPR
#undef LANG_HOOKS_EH_PERSONALITY
#undef LANG_HOOKS_NEW_DISPOSE_STORAGE_SUBSTITUTION
#define LANG_HOOKS_NAME "GNU Modula-2"
#define LANG_HOOKS_INIT gm2_langhook_init
#define LANG_HOOKS_INIT_OPTIONS gm2_langhook_init_options
#define LANG_HOOKS_OPTION_LANG_MASK gm2_langhook_option_lang_mask
#define LANG_HOOKS_INIT_OPTIONS_STRUCT gm2_langhook_init_options_struct
#define LANG_HOOKS_HANDLE_OPTION gm2_langhook_handle_option
#define LANG_HOOKS_POST_OPTIONS gm2_langhook_post_options
#define LANG_HOOKS_PARSE_FILE gm2_langhook_parse_file
#define LANG_HOOKS_TYPE_FOR_MODE gm2_langhook_type_for_mode
#define LANG_HOOKS_TYPE_FOR_SIZE gm2_langhook_type_for_size
#define LANG_HOOKS_BUILTIN_FUNCTION gm2_langhook_builtin_function
#define LANG_HOOKS_GLOBAL_BINDINGS_P gm2_langhook_global_bindings_p
#define LANG_HOOKS_PUSHDECL gm2_langhook_pushdecl
#define LANG_HOOKS_GETDECLS gm2_langhook_getdecls
#define LANG_HOOKS_GIMPLIFY_EXPR gm2_langhook_gimplify_expr
#define LANG_HOOKS_EH_PERSONALITY gm2_langhook_eh_personality
#define LANG_HOOKS_NEW_DISPOSE_STORAGE_SUBSTITUTION \
gm2_langhook_new_dispose_storage_substitution
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
#include "gt-m2-gm2-lang.h"
#include "gtype-m2.h"