mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 20:34:19 +00:00
Estimated hours taken: 12 Branches: main Bug fixes for the Java back-end. compiler/mlds_to_java.m: Fix a bug where we were outputting an incorrect type for nested structure initializers Fix a bug where we were outputting invalid syntax for some array initializers. Fix a bug where the code output for string comparisons was not properly parenthesized. compiler/mlds.m: Add a new argument to init_struct that specifies the type of the structure being initialized. This is needed to handled nested structure initializers for the Java back-end. compiler/rtti.m: Add new alternatives to ctor_rtti_name for all the types which are used as nested components of RTTI structures. This is needed in order to have appropriate RTTI types to use in rtti_to_mlds.m for the new field of init_struct. compiler/rtti_to_mlds.m: Substantial changes to fill in the new field of init_struct in all the generated initializers. compiler/ml_elim_nested.m: compiler/ml_optimize.m: compiler/ml_unify_gen.m: compiler/ml_util.m: compiler/mlds_to_c.m: compiler/mlds_to_gcc.m: compiler/mlds_to_il.m: Minor changes to handle the new argument to init_struct. compiler/mlds_to_gcc.m: compiler/opt_debug.m: Minor changes to handle the new alternatives for ctor_rtti_name. compiler/mlds_to_gcc.m: Fix a bug where it was generating a structure type, rather than an array thereof, for res_name_ordered_table.
3653 lines
118 KiB
Mathematica
3653 lines
118 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2003 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% mlds_to_c - Convert MLDS to C/C++ code.
|
|
% Main author: fjh.
|
|
|
|
% TODO:
|
|
% - RTTI for debugging (module_layout, proc_layout, internal_layout)
|
|
% - trail ops
|
|
% - foreign language interfacing for languages other than C
|
|
% (handle `user_foreign_code' and `foreign_code_decl' --
|
|
% actually perhaps this should be done in an earlier pass,
|
|
% in which case the only thing that would need to be done here
|
|
% is to change some calls to sorry/2 to unexpected/2).
|
|
% - packages, classes and inheritance
|
|
% (currently we just generate all classes as structs)
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend__mlds_to_c.
|
|
:- interface.
|
|
|
|
:- import_module aditi_backend.
|
|
:- import_module aditi_backend__rl_file.
|
|
:- import_module ml_backend__mlds.
|
|
|
|
:- import_module io, std_util.
|
|
|
|
% output_mlds(MLDS, MaybeRLFile, Suffix):
|
|
% Output C code the the appropriate C file and
|
|
% C declarations to the appropriate header file.
|
|
% The file names are determined by the module name,
|
|
% with the specified Suffix appended at the end.
|
|
% (The suffix is used for debugging dumps. For normal
|
|
% output, the suffix should be the empty string.)
|
|
:- pred mlds_to_c__output_mlds(mlds, maybe(rl_file),
|
|
string, io__state, io__state).
|
|
:- mode mlds_to_c__output_mlds(in, in, in, di, uo) is det.
|
|
|
|
% output_header_file(MLDS, Suffix):
|
|
% Output C declarations for the procedures (etc.) in the
|
|
% specified MLDS module to the appropriate .mih header file.
|
|
% See output_mlds for the meaning of Suffix.
|
|
:- pred mlds_to_c__output_header_file(mlds, string, io__state, io__state).
|
|
:- mode mlds_to_c__output_header_file(in, in, di, uo) is det.
|
|
|
|
% output_c_file(MLDS, MaybeRLFile, Suffix):
|
|
% Output C code for the specified MLDS module to the
|
|
% appropriate C file.
|
|
% See output_mlds for the meaning of Suffix.
|
|
:- pred mlds_to_c__output_c_file(mlds, maybe(rl_file),
|
|
string, io__state, io__state).
|
|
:- mode mlds_to_c__output_c_file(in, in, in, di, uo) is det.
|
|
|
|
% output an MLDS context in C #line format.
|
|
% this is useful for other foreign language interfaces such as
|
|
% managed extensions for C++.
|
|
:- pred mlds_to_c__output_context(mlds__context, io__state, io__state).
|
|
:- mode mlds_to_c__output_context(in, di, uo) is det.
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs__builtin_ops.
|
|
:- import_module backend_libs__c_util.
|
|
:- import_module backend_libs__code_model.
|
|
:- import_module backend_libs__foreign.
|
|
:- import_module backend_libs__name_mangle.
|
|
:- import_module backend_libs__rtti. % for rtti__addr_to_string.
|
|
:- import_module check_hlds__type_util.
|
|
:- import_module hlds__error_util.
|
|
:- import_module hlds__hlds_pred. % for pred_proc_id.
|
|
:- import_module hlds__passes_aux.
|
|
:- import_module libs__globals.
|
|
:- import_module libs__options.
|
|
:- import_module ml_backend__ml_code_util.
|
|
% for ml_gen_public_field_decl_flags, which is
|
|
% used by the code that handles derived classes
|
|
:- import_module ml_backend__ml_type_gen. % for ml_gen_type_name
|
|
:- import_module ml_backend__ml_util.
|
|
:- import_module ml_backend__rtti_to_mlds. % for mlds_rtti_type_name.
|
|
:- import_module parse_tree__modules.
|
|
:- import_module parse_tree__prog_data.
|
|
:- import_module parse_tree__prog_out.
|
|
|
|
:- import_module bool, int, string, library, list, map.
|
|
:- import_module assoc_list, term, std_util, require.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type output_type == pred(mlds__type, io__state, io__state).
|
|
:- inst output_type = (pred(in, di, uo) is det).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
mlds_to_c__output_mlds(MLDS, MaybeRLFile, Suffix) -->
|
|
% We output the source file before outputting the header,
|
|
% since the Mmake dependencies say the header file depends
|
|
% on the source file, and so if we wrote them out in the
|
|
% other order this might lead to unnecessary recompilation
|
|
% next time Mmake is run.
|
|
%
|
|
% XXX at some point we should also handle output of any non-C
|
|
% foreign code (Ada, Fortran, etc.) to appropriate files.
|
|
%
|
|
output_c_file(MLDS, MaybeRLFile, Suffix),
|
|
output_header_file(MLDS, Suffix).
|
|
|
|
mlds_to_c__output_c_file(MLDS, MaybeRLFile, Suffix) -->
|
|
{ ModuleName = mlds__get_module_name(MLDS) },
|
|
module_name_to_file_name(ModuleName, ".c" ++ Suffix, yes, SourceFile),
|
|
{ Indent = 0 },
|
|
output_to_file(SourceFile,
|
|
mlds_output_src_file(Indent, MLDS, MaybeRLFile)).
|
|
|
|
%
|
|
% Generate the header file
|
|
%
|
|
mlds_to_c__output_header_file(MLDS, Suffix) -->
|
|
%
|
|
% We write the header file out to <module>.mih.tmp and then
|
|
% call `update_interface' to move the <module>.mih.tmp file to
|
|
% <module>.mih; this avoids updating the timestamp on the `.mih'
|
|
% file if it hasn't changed.
|
|
%
|
|
{ ModuleName = mlds__get_module_name(MLDS) },
|
|
module_name_to_file_name(ModuleName, ".mih" ++ Suffix ++ ".tmp",
|
|
yes, TmpHeaderFile),
|
|
module_name_to_file_name(ModuleName, ".mih" ++ Suffix, yes,
|
|
HeaderFile),
|
|
{ Indent = 0 },
|
|
output_to_file(TmpHeaderFile, mlds_output_hdr_file(Indent, MLDS)),
|
|
update_interface(HeaderFile).
|
|
|
|
:- pred mlds_output_hdr_file(indent, mlds, io__state, io__state).
|
|
:- mode mlds_output_hdr_file(in, in, di, uo) is det.
|
|
|
|
mlds_output_hdr_file(Indent, MLDS) -->
|
|
{ MLDS = mlds(ModuleName, AllForeignCode, Imports, Defns) },
|
|
mlds_output_hdr_start(Indent, ModuleName), io__nl,
|
|
mlds_output_hdr_imports(Indent, Imports), io__nl,
|
|
% Get the foreign code for C
|
|
{ ForeignCode = mlds_get_c_foreign_code(AllForeignCode) },
|
|
mlds_output_c_hdr_decls(MLDS_ModuleName, Indent, ForeignCode), io__nl,
|
|
%
|
|
% The header file must contain _definitions_ of all public types,
|
|
% but only _declarations_ of all public variables, constants,
|
|
% and functions.
|
|
%
|
|
% Note that we don't forward-declare the types here; the
|
|
% forward declarations that we need for types used in function
|
|
% prototypes are generated by mlds_output_type_forward_decls.
|
|
% See the comment in mlds_output_decl.
|
|
%
|
|
{ list__filter(defn_is_public, Defns, PublicDefns) },
|
|
{ list__filter(defn_is_type, PublicDefns, PublicTypeDefns,
|
|
PublicNonTypeDefns) },
|
|
{ MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName) },
|
|
mlds_output_defns(Indent, MLDS_ModuleName, PublicTypeDefns), io__nl,
|
|
mlds_output_decls(Indent, MLDS_ModuleName, PublicNonTypeDefns), io__nl,
|
|
mlds_output_init_fn_decls(MLDS_ModuleName), io__nl,
|
|
mlds_output_hdr_end(Indent, ModuleName).
|
|
|
|
:- pred mlds_output_hdr_imports(indent, mlds__imports, io__state, io__state).
|
|
:- mode mlds_output_hdr_imports(in, in, di, uo) is det.
|
|
|
|
% XXX currently we assume all imports are source imports,
|
|
% i.e. that the header file does not depend on any types
|
|
% defined in other header files.
|
|
mlds_output_hdr_imports(_Indent, _Imports) --> [].
|
|
|
|
:- pred mlds_output_src_imports(indent, mlds__imports, io__state, io__state).
|
|
:- mode mlds_output_src_imports(in, in, di, uo) is det.
|
|
|
|
mlds_output_src_imports(Indent, Imports) -->
|
|
globals__io_get_target(Target),
|
|
( { Target = asm } ->
|
|
% For --target asm, we don't create the header files
|
|
% for modules that don't contain C code, so we'd better
|
|
% not include them, since they might not exist.
|
|
% XXX This is a hack; it may lead to warnings or errors
|
|
% when compiling the generated code, since the functions
|
|
% that we call (e.g. for `pragma export') may not have
|
|
% been declared.
|
|
[]
|
|
;
|
|
list__foldl(mlds_output_src_import(Indent), Imports)
|
|
).
|
|
|
|
:- pred mlds_output_src_import(indent, mlds__import, io__state, io__state).
|
|
:- mode mlds_output_src_import(in, in, di, uo) is det.
|
|
|
|
mlds_output_src_import(_Indent, Import) -->
|
|
{
|
|
Import = mercury_import(ImportType, ImportName),
|
|
ModuleName0 = mlds_module_name_to_sym_name(ImportName),
|
|
( ImportType = user_visible_interface, HeaderExt = ".mh"
|
|
; ImportType = compiler_visible_interface, HeaderExt = ".mih"
|
|
),
|
|
|
|
% Strip off the "mercury" qualifier for standard
|
|
% library modules.
|
|
(
|
|
ModuleName0 = qualified(unqualified("mercury"),
|
|
ModuleName1),
|
|
mercury_std_library_module(ModuleName1)
|
|
->
|
|
ModuleName = unqualified(ModuleName1)
|
|
;
|
|
ModuleName = ModuleName0
|
|
)
|
|
;
|
|
Import = foreign_import(ForeignImport),
|
|
% This case shouldn't happen when compiling to C,
|
|
% but we need to handle it for MLDS dumps when
|
|
% compiling to IL.
|
|
ForeignImport = il_assembly_name(ImportName),
|
|
ModuleName = mlds_module_name_to_sym_name(ImportName),
|
|
HeaderExt = ".dll"
|
|
},
|
|
|
|
module_name_to_search_file_name(ModuleName, HeaderExt, HeaderFile),
|
|
io__write_strings(["#include """, HeaderFile, """\n"]).
|
|
|
|
|
|
%
|
|
% Generate the `.c' file
|
|
%
|
|
% (Calling it the "source" file is a bit of a misnomer,
|
|
% since in our case it is actually the target file,
|
|
% but there's no obvious alternative term to use which
|
|
% also has a clear and concise abbreviation, so never mind...)
|
|
%
|
|
:- pred mlds_output_src_file(indent, mlds, maybe(rl_file),
|
|
io__state, io__state).
|
|
:- mode mlds_output_src_file(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_src_file(Indent, MLDS, MaybeRLFile) -->
|
|
{ MLDS = mlds(ModuleName, AllForeignCode, Imports, Defns) },
|
|
% Get the foreign code for C
|
|
{ ForeignCode = mlds_get_c_foreign_code(AllForeignCode) },
|
|
|
|
mlds_output_src_start(Indent, ModuleName, ForeignCode), io__nl,
|
|
mlds_output_src_imports(Indent, Imports), io__nl,
|
|
|
|
mlds_output_c_decls(Indent, ForeignCode), io__nl,
|
|
%
|
|
% The public types have already been defined in the
|
|
% header file, and the public vars, consts, and functions
|
|
% have already been declared in the header file.
|
|
% In the source file, we need to have
|
|
% #1. definitions of the private types,
|
|
% #2. forward-declarations of the private non-types
|
|
% #3. definitions of all the non-types
|
|
% #4. initialization functions
|
|
% in that order.
|
|
% #2 is needed to allow #3 to contain forward references,
|
|
% which can arise for e.g. mutually recursive procedures.
|
|
% #1 is needed since #2 may refer to the types.
|
|
%
|
|
% Note that we don't forward-declare the types here; the
|
|
% forward declarations that we need for types used in function
|
|
% prototypes are generated by mlds_output_type_forward_decls.
|
|
% See the comment in mlds_output_decl.
|
|
%
|
|
{ list__filter(defn_is_public, Defns, _PublicDefns, PrivateDefns) },
|
|
{ list__filter(defn_is_type, PrivateDefns, PrivateTypeDefns,
|
|
PrivateNonTypeDefns) },
|
|
{ list__filter(defn_is_type, Defns, _TypeDefns, NonTypeDefns) },
|
|
{ list__filter(defn_is_function, NonTypeDefns, FuncDefns) },
|
|
{ list__filter(defn_is_type_ctor_info, NonTypeDefns,
|
|
TypeCtorInfoDefns) },
|
|
{ MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName) },
|
|
mlds_output_defns(Indent, MLDS_ModuleName, PrivateTypeDefns), io__nl,
|
|
mlds_output_decls(Indent, MLDS_ModuleName, PrivateNonTypeDefns), io__nl,
|
|
|
|
mlds_output_c_defns(MLDS_ModuleName, Indent, ForeignCode), io__nl,
|
|
mlds_output_defns(Indent, MLDS_ModuleName, NonTypeDefns), io__nl,
|
|
mlds_output_init_fn_defns(MLDS_ModuleName, FuncDefns,
|
|
TypeCtorInfoDefns), io__nl,
|
|
c_util__output_rl_file(ModuleName, MaybeRLFile), io__nl,
|
|
mlds_output_grade_var, io__nl,
|
|
mlds_output_src_end(Indent, ModuleName).
|
|
|
|
:- pred mlds_output_hdr_start(indent, mercury_module_name,
|
|
io__state, io__state).
|
|
:- mode mlds_output_hdr_start(in, in, di, uo) is det.
|
|
|
|
mlds_output_hdr_start(Indent, ModuleName) -->
|
|
mlds_output_auto_gen_comment(ModuleName),
|
|
mlds_indent(Indent),
|
|
io__write_string("/* :- module "),
|
|
prog_out__write_sym_name(ModuleName),
|
|
io__write_string(". */\n"),
|
|
mlds_indent(Indent),
|
|
io__write_string("/* :- interface. */\n"),
|
|
io__nl,
|
|
mlds_indent(Indent),
|
|
io__write_string("#ifndef MR_HEADER_GUARD_"),
|
|
{ MangledModuleName = sym_name_mangle(ModuleName) },
|
|
io__write_string(MangledModuleName),
|
|
io__nl,
|
|
mlds_indent(Indent),
|
|
io__write_string("#define MR_HEADER_GUARD_"),
|
|
io__write_string(MangledModuleName),
|
|
io__nl,
|
|
io__nl,
|
|
%
|
|
% If we're outputting C (rather than C++), then add a
|
|
% conditional `extern "C"' wrapper around the header file,
|
|
% so that the header file can be #included by C++ programs.
|
|
%
|
|
globals__io_get_target(Target),
|
|
( { Target = c } ->
|
|
mlds_indent(Indent),
|
|
io__write_string("#ifdef __cplusplus\n"),
|
|
mlds_indent(Indent),
|
|
io__write_string("extern ""C"" {\n"),
|
|
mlds_indent(Indent),
|
|
io__write_string("#endif\n"),
|
|
io__nl
|
|
;
|
|
[]
|
|
),
|
|
mlds_indent(Indent),
|
|
io__write_string("#include ""mercury.h""\n").
|
|
|
|
:- pred mlds_output_src_start(indent, mercury_module_name, mlds__foreign_code,
|
|
io__state, io__state).
|
|
:- mode mlds_output_src_start(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_src_start(Indent, ModuleName, ForeignCode) -->
|
|
mlds_output_auto_gen_comment(ModuleName),
|
|
mlds_indent(Indent),
|
|
io__write_string("/* :- module "),
|
|
prog_out__write_sym_name(ModuleName),
|
|
io__write_string(". */\n"),
|
|
mlds_indent(Indent),
|
|
io__write_string("/* :- implementation. */\n"),
|
|
mlds_output_src_bootstrap_defines, io__nl,
|
|
|
|
mlds_output_src_import(Indent,
|
|
mercury_import(
|
|
compiler_visible_interface,
|
|
mercury_module_name_to_mlds(ModuleName))),
|
|
|
|
%
|
|
% If there are `:- pragma export' declarations,
|
|
% #include the `.mh' file.
|
|
%
|
|
( { ForeignCode = mlds__foreign_code(_, _, _, []) } ->
|
|
[]
|
|
;
|
|
mlds_output_src_import(Indent,
|
|
mercury_import(
|
|
user_visible_interface,
|
|
mercury_module_name_to_mlds(ModuleName)))
|
|
),
|
|
io__nl.
|
|
|
|
%
|
|
% Output any #defines which are required to bootstrap in the hlc
|
|
% grade.
|
|
%
|
|
:- pred mlds_output_src_bootstrap_defines(io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_src_bootstrap_defines -->
|
|
[].
|
|
|
|
:- pred mlds_output_hdr_end(indent, mercury_module_name,
|
|
io__state, io__state).
|
|
:- mode mlds_output_hdr_end(in, in, di, uo) is det.
|
|
|
|
mlds_output_hdr_end(Indent, ModuleName) -->
|
|
globals__io_get_target(Target),
|
|
( { Target = c } ->
|
|
% terminate the `extern "C"' wrapper
|
|
mlds_indent(Indent),
|
|
io__write_string("#ifdef __cplusplus\n"),
|
|
mlds_indent(Indent),
|
|
io__write_string("}\n"),
|
|
mlds_indent(Indent),
|
|
io__write_string("#endif\n"),
|
|
io__nl
|
|
;
|
|
[]
|
|
),
|
|
mlds_indent(Indent),
|
|
io__write_string("#endif /* MR_HEADER_GUARD_"),
|
|
prog_out__write_sym_name(ModuleName),
|
|
io__write_string(" */\n"),
|
|
io__nl,
|
|
mlds_indent(Indent),
|
|
io__write_string("/* :- end_interface "),
|
|
prog_out__write_sym_name(ModuleName),
|
|
io__write_string(". */\n").
|
|
|
|
:- pred mlds_output_src_end(indent, mercury_module_name,
|
|
io__state, io__state).
|
|
:- mode mlds_output_src_end(in, in, di, uo) is det.
|
|
|
|
mlds_output_src_end(Indent, ModuleName) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("/* :- end_module "),
|
|
prog_out__write_sym_name(ModuleName),
|
|
io__write_string(". */\n").
|
|
|
|
%
|
|
% Output a C comment saying that the file was automatically
|
|
% generated (and giving details such as the compiler version).
|
|
%
|
|
:- pred mlds_output_auto_gen_comment(module_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_auto_gen_comment(ModuleName) -->
|
|
{ library__version(Version) },
|
|
module_name_to_file_name(ModuleName, ".m", no, SourceFileName),
|
|
output_c_file_intro_and_grade(SourceFileName, Version),
|
|
io__nl.
|
|
|
|
%
|
|
% Output a reference to the mangled grade name for the grade
|
|
% that the C file gets compiled with. This ensures that
|
|
% we don't try to link objects files compiled in different
|
|
% grades.
|
|
%
|
|
:- pred mlds_output_grade_var(io__state::di, io__state::uo) is det.
|
|
mlds_output_grade_var -->
|
|
io__write_string(
|
|
"/* ensure everything is compiled with the same grade */\n"),
|
|
io__write_string(
|
|
"static const void *const MR_grade = &MR_GRADE_VAR;\n").
|
|
|
|
:- func mlds_get_c_foreign_code(map(foreign_language, mlds__foreign_code))
|
|
= mlds__foreign_code.
|
|
|
|
% Get the foreign code for C
|
|
mlds_get_c_foreign_code(AllForeignCode) = ForeignCode :-
|
|
( map__search(AllForeignCode, c, ForeignCode0) ->
|
|
ForeignCode = ForeignCode0
|
|
;
|
|
% this can occur when compiling to a non-C target
|
|
% using "--mlds-dump all"
|
|
ForeignCode = foreign_code([], [], [], [])
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% Maybe output the function `mercury__<modulename>__init()'.
|
|
% The body of the function consists of calls
|
|
% MR_init_entry(<function>) for each function defined in the
|
|
% module.
|
|
%
|
|
:- pred mlds_output_init_fn_decls(mlds_module_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_init_fn_decls(ModuleName) -->
|
|
output_init_fn_name(ModuleName, ""),
|
|
io__write_string(";\n"),
|
|
output_init_fn_name(ModuleName, "_type_tables"),
|
|
io__write_string(";\n"),
|
|
output_init_fn_name(ModuleName, "_debugger"),
|
|
io__write_string(";\n").
|
|
|
|
:- pred mlds_output_init_fn_defns(mlds_module_name::in, mlds__defns::in,
|
|
mlds__defns::in, io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_init_fn_defns(ModuleName, FuncDefns, TypeCtorInfoDefns) -->
|
|
output_init_fn_name(ModuleName, ""),
|
|
io__write_string("\n{\n"),
|
|
io_get_globals(Globals),
|
|
(
|
|
{ need_to_init_entries(Globals) },
|
|
{ FuncDefns \= [] }
|
|
->
|
|
io__write_strings(
|
|
["\tstatic MR_bool initialised = MR_FALSE;\n",
|
|
"\tif (initialised) return;\n",
|
|
"\tinitialised = MR_TRUE;\n\n"]),
|
|
mlds_output_calls_to_init_entry(ModuleName, FuncDefns)
|
|
;
|
|
[]
|
|
),
|
|
io__write_string("}\n\n"),
|
|
|
|
output_init_fn_name(ModuleName, "_type_tables"),
|
|
io__write_string("\n{\n"),
|
|
(
|
|
{ TypeCtorInfoDefns \= [] }
|
|
->
|
|
io__write_strings(
|
|
["\tstatic MR_bool initialised = MR_FALSE;\n",
|
|
"\tif (initialised) return;\n",
|
|
"\tinitialised = MR_TRUE;\n\n"]),
|
|
mlds_output_calls_to_register_tci(ModuleName,
|
|
TypeCtorInfoDefns)
|
|
;
|
|
[]
|
|
),
|
|
io__write_string("}\n\n"),
|
|
|
|
output_init_fn_name(ModuleName, "_debugger"),
|
|
io__write_string("\n{\n"),
|
|
io__write_string(
|
|
"\tMR_fatal_error(""debugger initialization in MLDS grade"");\n"),
|
|
io__write_string("}\n").
|
|
|
|
:- pred output_init_fn_name(mlds_module_name::in, string::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
output_init_fn_name(ModuleName, Suffix) -->
|
|
% Here we ensure that we only get one "mercury__" at the
|
|
% start of the function name.
|
|
{ prog_out__sym_name_to_string(
|
|
mlds_module_name_to_sym_name(ModuleName), "__",
|
|
ModuleNameString0) },
|
|
{
|
|
string__prefix(ModuleNameString0, "mercury__")
|
|
->
|
|
ModuleNameString = ModuleNameString0
|
|
;
|
|
string__append("mercury__", ModuleNameString0,
|
|
ModuleNameString)
|
|
},
|
|
io__write_string("void "),
|
|
io__write_string(ModuleNameString),
|
|
io__write_string("__init"),
|
|
io__write_string(Suffix),
|
|
io__write_string("(void)").
|
|
|
|
:- pred need_to_init_entries(globals::in) is semidet.
|
|
need_to_init_entries(Globals) :-
|
|
% We only need to output calls to MR_init_entry() if profiling is
|
|
% enabled. (It would be OK to output the calls regardless, since
|
|
% they will macro-expand to nothing if profiling is not enabled,
|
|
% but for readability of the generated code we prefer not to.)
|
|
( Option = profile_calls
|
|
; Option = profile_time
|
|
; Option = profile_memory
|
|
),
|
|
globals__lookup_bool_option(Globals, Option, yes).
|
|
|
|
% Generate calls to MR_init_entry() for the specified functions.
|
|
%
|
|
:- pred mlds_output_calls_to_init_entry(mlds_module_name::in, mlds__defns::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_calls_to_init_entry(_ModuleName, []) --> [].
|
|
mlds_output_calls_to_init_entry(ModuleName, [FuncDefn | FuncDefns]) -->
|
|
{ FuncDefn = mlds__defn(EntityName, _, _, _) },
|
|
io__write_string("\tMR_init_entry("),
|
|
mlds_output_fully_qualified_name(qual(ModuleName, EntityName)),
|
|
io__write_string(");\n"),
|
|
mlds_output_calls_to_init_entry(ModuleName, FuncDefns).
|
|
|
|
% Generate calls to MR_register_type_ctor_info() for the specified
|
|
% type_ctor_infos.
|
|
%
|
|
:- pred mlds_output_calls_to_register_tci(mlds_module_name::in, mlds__defns::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_calls_to_register_tci(_ModuleName, []) --> [].
|
|
mlds_output_calls_to_register_tci(ModuleName,
|
|
[TypeCtorInfoDefn | TypeCtorInfoDefns]) -->
|
|
{ TypeCtorInfoDefn = mlds__defn(EntityName, _, _, _) },
|
|
io__write_string("\tMR_register_type_ctor_info(&"),
|
|
mlds_output_fully_qualified_name(qual(ModuleName, EntityName)),
|
|
io__write_string(");\n"),
|
|
mlds_output_calls_to_register_tci(ModuleName, TypeCtorInfoDefns).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Foreign language interface stuff
|
|
%
|
|
|
|
:- pred mlds_output_c_hdr_decls(mlds_module_name, indent, mlds__foreign_code,
|
|
io__state, io__state).
|
|
:- mode mlds_output_c_hdr_decls(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_c_hdr_decls(ModuleName, Indent, ForeignCode) -->
|
|
{ ForeignCode = mlds__foreign_code(RevHeaderCode, _RevImports,
|
|
_RevBodyCode, _ExportDefns) },
|
|
{ HeaderCode = list__reverse(RevHeaderCode) },
|
|
{ is_std_lib_module(ModuleName, ModuleNameStr) ->
|
|
SymName = unqualified(ModuleNameStr)
|
|
;
|
|
SymName = mlds_module_name_to_sym_name(ModuleName)
|
|
},
|
|
{ DeclGuard = decl_guard(SymName) },
|
|
io__write_strings(["#ifndef ", DeclGuard,
|
|
"\n#define ", DeclGuard, "\n"]),
|
|
io__write_list(HeaderCode, "\n", mlds_output_c_hdr_decl(Indent)),
|
|
io__write_string("\n#endif\n").
|
|
|
|
:- pred mlds_output_c_hdr_decl(indent,
|
|
foreign_decl_code, io__state, io__state).
|
|
:- mode mlds_output_c_hdr_decl(in, in, di, uo) is det.
|
|
|
|
mlds_output_c_hdr_decl(_Indent, foreign_decl_code(Lang, Code, Context)) -->
|
|
% only output C code in the C header file.
|
|
( { Lang = c } ->
|
|
mlds_to_c__output_context(mlds__make_context(Context)),
|
|
io__write_string(Code)
|
|
;
|
|
{ sorry(this_file, "foreign code other than C") }
|
|
).
|
|
|
|
:- pred mlds_output_c_decls(indent, mlds__foreign_code,
|
|
io__state, io__state).
|
|
:- mode mlds_output_c_decls(in, in, di, uo) is det.
|
|
|
|
% all of the declarations go in the header file or as c_code
|
|
mlds_output_c_decls(_, _) --> [].
|
|
|
|
:- pred mlds_output_c_defns(mlds_module_name, indent, mlds__foreign_code,
|
|
io__state, io__state).
|
|
:- mode mlds_output_c_defns(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_c_defns(ModuleName, Indent, ForeignCode) -->
|
|
{ ForeignCode = mlds__foreign_code(_RevHeaderCode, RevImports,
|
|
RevBodyCode, ExportDefns) },
|
|
{ Imports = list__reverse(RevImports) },
|
|
list__foldl(
|
|
(pred(ForeignImport::in, di, uo) is det -->
|
|
{ ForeignImport = foreign_import_module(Lang, Import, _) },
|
|
( { Lang = c } ->
|
|
mlds_output_src_import(Indent,
|
|
mercury_import(user_visible_interface,
|
|
mercury_module_name_to_mlds(Import)))
|
|
;
|
|
{ sorry(this_file, "foreign code other than C") }
|
|
)
|
|
), Imports),
|
|
{ BodyCode = list__reverse(RevBodyCode) },
|
|
io__write_list(BodyCode, "\n", mlds_output_c_defn(Indent)),
|
|
io__write_string("\n"),
|
|
io__write_list(ExportDefns, "\n",
|
|
mlds_output_pragma_export_defn(ModuleName, Indent)).
|
|
|
|
:- pred mlds_output_c_defn(indent, user_foreign_code,
|
|
io__state, io__state).
|
|
:- mode mlds_output_c_defn(in, in, di, uo) is det.
|
|
|
|
mlds_output_c_defn(_Indent, user_foreign_code(c, Code, Context)) -->
|
|
mlds_to_c__output_context(mlds__make_context(Context)),
|
|
io__write_string(Code).
|
|
mlds_output_c_defn(_Indent, user_foreign_code(managed_cplusplus, _, _)) -->
|
|
{ sorry(this_file, "foreign code other than C") }.
|
|
mlds_output_c_defn(_Indent, user_foreign_code(csharp, _, _)) -->
|
|
{ sorry(this_file, "foreign code other than C") }.
|
|
mlds_output_c_defn(_Indent, user_foreign_code(il, _, _)) -->
|
|
{ sorry(this_file, "foreign code other than C") }.
|
|
mlds_output_c_defn(_Indent, user_foreign_code(java, _, _)) -->
|
|
{ sorry(this_file, "foreign code other than C") }.
|
|
|
|
:- pred mlds_output_pragma_export_defn(mlds_module_name, indent,
|
|
mlds__pragma_export, io__state, io__state).
|
|
:- mode mlds_output_pragma_export_defn(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_pragma_export_defn(ModuleName, Indent, PragmaExport) -->
|
|
{ PragmaExport = ml_pragma_export(_C_name, MLDS_Name, MLDS_Signature,
|
|
Context) },
|
|
mlds_output_pragma_export_func_name(ModuleName, Indent, PragmaExport),
|
|
io__write_string("\n"),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("{\n"),
|
|
mlds_indent(Context, Indent),
|
|
mlds_output_pragma_export_defn_body(ModuleName, MLDS_Name,
|
|
MLDS_Signature),
|
|
io__write_string("}\n").
|
|
|
|
:- pred mlds_output_pragma_export_func_name(mlds_module_name, indent,
|
|
mlds__pragma_export, io__state, io__state).
|
|
:- mode mlds_output_pragma_export_func_name(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_pragma_export_func_name(ModuleName, Indent,
|
|
ml_pragma_export(C_name, _MLDS_Name, Signature, Context)) -->
|
|
{ Name = qual(ModuleName, export(C_name)) },
|
|
mlds_indent(Context, Indent),
|
|
% For functions exported using `pragma export',
|
|
% we use the default C calling convention.
|
|
{ CallingConvention = "" },
|
|
mlds_output_func_decl_ho(Indent, Name, Context,
|
|
CallingConvention, Signature,
|
|
mlds_output_pragma_export_type(prefix),
|
|
mlds_output_pragma_export_type(suffix)).
|
|
|
|
:- pred mlds_output_pragma_export_type(mlds__type::in,
|
|
io__state::di, io__state::uo) is det.
|
|
mlds_output_pragma_export_type(Type) -->
|
|
mlds_output_pragma_export_type(prefix, Type),
|
|
mlds_output_pragma_export_type(suffix, Type).
|
|
|
|
:- type locn ---> prefix ; suffix.
|
|
:- pred mlds_output_pragma_export_type(locn, mlds__type, io__state, io__state).
|
|
:- mode mlds_output_pragma_export_type(in, in, di, uo) is det.
|
|
|
|
mlds_output_pragma_export_type(suffix, _Type) --> [].
|
|
mlds_output_pragma_export_type(prefix, mercury_array_type(_ElemType)) -->
|
|
io__write_string("MR_ArrayPtr").
|
|
mlds_output_pragma_export_type(prefix, mercury_type(_, _, ExportedType)) -->
|
|
io__write_string(foreign__to_type_string(c, ExportedType)).
|
|
mlds_output_pragma_export_type(prefix, mlds__cont_type(_)) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__commit_type) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__native_bool_type) -->
|
|
io__write_string("MR_bool").
|
|
mlds_output_pragma_export_type(prefix, mlds__native_int_type) -->
|
|
io__write_string("MR_Integer").
|
|
mlds_output_pragma_export_type(prefix, mlds__native_float_type) -->
|
|
io__write_string("MR_Float").
|
|
mlds_output_pragma_export_type(prefix, mlds__native_char_type) -->
|
|
io__write_string("MR_Char").
|
|
mlds_output_pragma_export_type(prefix, mlds__foreign_type(ForeignType)) -->
|
|
( { ForeignType = c(c(Name)) },
|
|
io__write_string(Name)
|
|
; { ForeignType = il(_) },
|
|
{ unexpected(this_file,
|
|
"mlds_output_type_prefix: il foreign_type") }
|
|
; { ForeignType = java(_) },
|
|
{ unexpected(this_file,
|
|
"mlds_output_type_prefix: java foreign_type") }
|
|
).
|
|
mlds_output_pragma_export_type(prefix, mlds__class_type(_, _, _)) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__array_type(_)) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__ptr_type(Type)) -->
|
|
mlds_output_pragma_export_type(prefix, Type),
|
|
io__write_string(" *").
|
|
mlds_output_pragma_export_type(prefix, mlds__func_type(_)) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__generic_type) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__generic_env_ptr_type) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__type_info_type) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__pseudo_type_info_type) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__rtti_type(_)) -->
|
|
io__write_string("MR_Word").
|
|
mlds_output_pragma_export_type(prefix, mlds__unknown_type) -->
|
|
{ unexpected(this_file,
|
|
"mlds_output_pragma_export_type: unknown_type") }.
|
|
|
|
%
|
|
% Output the definition body for a pragma export
|
|
%
|
|
:- pred mlds_output_pragma_export_defn_body(mlds_module_name,
|
|
mlds__qualified_entity_name, func_params, io__state, io__state).
|
|
:- mode mlds_output_pragma_export_defn_body(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_pragma_export_defn_body(ModuleName, FuncName, Signature) -->
|
|
{ Signature = mlds__func_params(Parameters, RetTypes) },
|
|
|
|
% Declare local variables corresponding to any foreign_type
|
|
% parameters
|
|
{ IsCForeignType = (pred(Arg::in) is semidet :-
|
|
Arg = mlds__argument(_Name, Type, _GCTraceCode),
|
|
Type = mlds__foreign_type(c(_))) },
|
|
{ IsCForeignTypePtr = (pred(Arg::in) is semidet :-
|
|
Arg = mlds__argument(_Name, Type, _GCTraceCode),
|
|
Type = mlds__ptr_type(mlds__foreign_type(c(_)))) },
|
|
{ CForeignTypeInputs = list__filter(IsCForeignType, Parameters) },
|
|
{ CForeignTypeOutputs = list__filter(IsCForeignTypePtr, Parameters) },
|
|
io__write_list(CForeignTypeInputs, "",
|
|
mlds_output_pragma_export_input_defns(ModuleName)),
|
|
io__write_list(CForeignTypeOutputs, "",
|
|
mlds_output_pragma_export_output_defns(ModuleName)),
|
|
|
|
% Declare a local variable or two for the return value, if needed
|
|
( { RetTypes = [RetType1] } ->
|
|
( { RetType1 = mlds__foreign_type(c(_)) } ->
|
|
io__write_string("\t"),
|
|
mlds_output_pragma_export_type(RetType1),
|
|
io__write_string(" ret_value;\n"),
|
|
io__write_string("\t"),
|
|
mlds_output_type(RetType1),
|
|
io__write_string(" boxed_ret_value;\n")
|
|
;
|
|
io__write_string("\t"),
|
|
mlds_output_pragma_export_type(RetType1),
|
|
io__write_string(" ret_value;\n")
|
|
)
|
|
;
|
|
[]
|
|
),
|
|
|
|
% Generate code to box any non-word-sized foreign_type input parameters;
|
|
% these need to be converted to a uniform size before passing them
|
|
% to Mercury code.
|
|
io__write_list(CForeignTypeInputs, "",
|
|
(pred(Arg::in, di, uo) is det -->
|
|
{ Arg = mlds__argument(Name, Type, _GC_TraceCode) },
|
|
{ QualName = qual(ModuleName, Name) },
|
|
{ BoxedQualName = qual(ModuleName, boxed_name(Name)) },
|
|
io__write_string("\tMR_MAYBE_BOX_FOREIGN_TYPE("),
|
|
mlds_output_pragma_export_type(Type),
|
|
io__write_string(", "),
|
|
mlds_output_fully_qualified_name(QualName),
|
|
io__write_string(", "),
|
|
mlds_output_fully_qualified_name(BoxedQualName),
|
|
io__write_string(");\n"))),
|
|
|
|
% Generate code to actually call the Mercury procedure which
|
|
% is being exported
|
|
( { RetTypes = [] } ->
|
|
io__write_string("\t"),
|
|
mlds_output_pragma_export_call(ModuleName, FuncName,
|
|
Parameters)
|
|
; { RetTypes = [RetType2] } ->
|
|
( { RetType2 = mlds__foreign_type(c(_)) } ->
|
|
io__write_string("\tboxed_ret_value = ")
|
|
;
|
|
io__write_string("\tret_value = ("),
|
|
mlds_output_pragma_export_type(RetType2),
|
|
io__write_string(")")
|
|
),
|
|
mlds_output_pragma_export_call(ModuleName, FuncName,
|
|
Parameters)
|
|
;
|
|
% This is just for MLDS dumps when compiling to non-C targets.
|
|
% So we don't need to worry about boxing/unboxing foreign types
|
|
% here.
|
|
io__write_string("\treturn ("),
|
|
mlds_output_return_list(RetTypes,
|
|
mlds_output_pragma_export_type),
|
|
io__write_string(") ")
|
|
),
|
|
|
|
% Generate code to unbox any foreign_type output parameters,
|
|
% since we are returning those parameters to C code.
|
|
io__write_list(CForeignTypeOutputs, "",
|
|
(pred(Arg::in, di, uo) is det -->
|
|
{ Arg = mlds__argument(Name, Type, _GC_TraceCode) },
|
|
{ QualName = qual(ModuleName, Name) },
|
|
{ BoxedQualName = qual(ModuleName, boxed_name(Name)) },
|
|
io__write_string("\tMR_MAYBE_UNBOX_FOREIGN_TYPE("),
|
|
mlds_output_pragma_export_type(pointed_to_type(Type)),
|
|
io__write_string(", "),
|
|
mlds_output_fully_qualified_name(BoxedQualName),
|
|
io__write_string(", *"),
|
|
mlds_output_fully_qualified_name(QualName),
|
|
io__write_string(");\n"))),
|
|
|
|
% Generate the final statement to unbox and return the
|
|
% return value, if needed.
|
|
( { RetTypes = [RetType3] } ->
|
|
( { RetType3 = mlds__foreign_type(c(_)) } ->
|
|
io__write_string("\tMR_MAYBE_UNBOX_FOREIGN_TYPE("),
|
|
mlds_output_pragma_export_type(RetType3),
|
|
io__write_string(", boxed_ret_value, ret_value);\n")
|
|
;
|
|
[]
|
|
),
|
|
io__write_string("\treturn ret_value;\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_pragma_export_input_defns(mlds_module_name::in,
|
|
mlds__argument::in, io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_pragma_export_input_defns(ModuleName, Arg) -->
|
|
{ Arg = mlds__argument(Name, Type, _GC_TraceCode) },
|
|
io__write_string("\t"),
|
|
mlds_output_data_decl_ho(mlds_output_type_prefix,
|
|
mlds_output_type_suffix,
|
|
qual(ModuleName, boxed_name(Name)), Type),
|
|
io__write_string(";\n").
|
|
|
|
:- pred mlds_output_pragma_export_output_defns(mlds_module_name::in,
|
|
mlds__argument::in, io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_pragma_export_output_defns(ModuleName, Arg) -->
|
|
{ Arg = mlds__argument(Name, Type, _GC_TraceCode) },
|
|
io__write_string("\t"),
|
|
mlds_output_data_decl_ho(mlds_output_type_prefix,
|
|
mlds_output_type_suffix,
|
|
qual(ModuleName, boxed_name(Name)), pointed_to_type(Type)),
|
|
io__write_string(";\n").
|
|
|
|
:- func pointed_to_type(mlds__type) = mlds__type.
|
|
|
|
pointed_to_type(PtrType) =
|
|
( PtrType = mlds__ptr_type(Type) ->
|
|
Type
|
|
;
|
|
func_error("pointed_to_type: not pointer")
|
|
).
|
|
|
|
:- func boxed_name(mlds__entity_name) = mlds__entity_name.
|
|
boxed_name(Name) = BoxedName :-
|
|
( Name = data(var(var_name(VarName, Seq))) ->
|
|
BoxedName = data(var(var_name("boxed_" ++ VarName, Seq)))
|
|
;
|
|
unexpected(this_file, "boxed_name called for non-var argument")
|
|
).
|
|
|
|
:- pred mlds_output_pragma_export_call(mlds_module_name,
|
|
mlds__qualified_entity_name, mlds__arguments,
|
|
io__state, io__state).
|
|
:- mode mlds_output_pragma_export_call(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_pragma_export_call(ModuleName, FuncName, Parameters) -->
|
|
mlds_output_fully_qualified_name(FuncName),
|
|
io__write_string("("),
|
|
io__write_list(Parameters, ", ",
|
|
mlds_output_pragma_export_arg(ModuleName)),
|
|
io__write_string(");\n").
|
|
|
|
%
|
|
% Output a fully qualified name preceded by a cast.
|
|
%
|
|
:- pred mlds_output_pragma_export_arg(mlds_module_name::in, mlds__argument::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_output_pragma_export_arg(ModuleName, Arg) -->
|
|
{ Arg = mlds__argument(Name, Type, _GC_TraceCode) },
|
|
( { Type = mlds__foreign_type(c(_)) } ->
|
|
% This is a foreign_type input. Pass in the already-boxed
|
|
% value.
|
|
{ BoxedName = boxed_name(Name) },
|
|
mlds_output_fully_qualified_name(qual(ModuleName, BoxedName))
|
|
; { Type = mlds__ptr_type(mlds__foreign_type(c(_))) } ->
|
|
% This is a foreign_type output. Pass in the address of the
|
|
% local variable which will hold the boxed value.
|
|
io__write_string("&"),
|
|
{ BoxedName = boxed_name(Name) },
|
|
mlds_output_fully_qualified_name(qual(ModuleName, BoxedName))
|
|
;
|
|
% Otherwise, no boxing or unboxing is needed.
|
|
% Just cast the argument to the right type.
|
|
mlds_output_cast(Type),
|
|
mlds_output_fully_qualified_name(qual(ModuleName, Name))
|
|
).
|
|
|
|
%
|
|
% Generates the signature for det functions in the forward mode.
|
|
%
|
|
:- func det_func_signature(mlds__func_params) = mlds__func_params.
|
|
|
|
det_func_signature(mlds__func_params(Args, _RetTypes)) = Params :-
|
|
list__length(Args, NumArgs),
|
|
NumFuncArgs = NumArgs - 1,
|
|
( list__split_list(NumFuncArgs, Args, InputArgs0, [ReturnArg0]) ->
|
|
InputArgs = InputArgs0,
|
|
ReturnArg = ReturnArg0
|
|
;
|
|
error("det_func_signature: function missing return value?")
|
|
),
|
|
(
|
|
ReturnArg = mlds__argument(_ReturnArgName,
|
|
mlds__ptr_type(ReturnArgType0), _GC_TraceCode)
|
|
->
|
|
ReturnArgType = ReturnArgType0
|
|
;
|
|
error("det_func_signature: function return type!")
|
|
),
|
|
Params = mlds__func_params(InputArgs, [ReturnArgType]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output declarations and definitions
|
|
%
|
|
|
|
|
|
:- pred mlds_output_decls(indent, mlds_module_name, mlds__defns,
|
|
io__state, io__state).
|
|
:- mode mlds_output_decls(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_decls(Indent, ModuleName, Defns) -->
|
|
list__foldl(mlds_output_decl(Indent, ModuleName), Defns).
|
|
|
|
:- pred mlds_output_defns(indent, mlds_module_name, mlds__defns,
|
|
io__state, io__state).
|
|
:- mode mlds_output_defns(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_defns(Indent, ModuleName, Defns) -->
|
|
{ OutputDefn = mlds_output_defn(Indent, ModuleName) },
|
|
globals__io_lookup_bool_option(gcc_local_labels, GCC_LocalLabels),
|
|
( { GCC_LocalLabels = yes } ->
|
|
%
|
|
% GNU C __label__ declarations must precede
|
|
% ordinary variable declarations.
|
|
%
|
|
{ list__filter(defn_is_commit_type_var, Defns, LabelDecls,
|
|
OtherDefns) },
|
|
list__foldl(OutputDefn, LabelDecls),
|
|
list__foldl(OutputDefn, OtherDefns)
|
|
;
|
|
list__foldl(OutputDefn, Defns)
|
|
).
|
|
|
|
|
|
:- pred mlds_output_decl(indent, mlds_module_name, mlds__defn,
|
|
io__state, io__state).
|
|
:- mode mlds_output_decl(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_decl(Indent, ModuleName, Defn) -->
|
|
{ Defn = mlds__defn(Name, Context, Flags, DefnBody) },
|
|
(
|
|
%
|
|
% ANSI C does not permit forward declarations
|
|
% of enumeration types. So we just skip those.
|
|
% Currently they're not needed since we don't
|
|
% actually use the enum types.
|
|
%
|
|
{ DefnBody = mlds__class(ClassDefn) },
|
|
{ ClassDefn^kind = mlds__enum }
|
|
->
|
|
[]
|
|
;
|
|
%
|
|
% If we're using --high-level-data, then
|
|
% for function declarations, we need to ensure
|
|
% that we forward-declare any types used in
|
|
% the function parameters. This is because
|
|
% otherwise, for any struct names whose first
|
|
% occurence is in the function parameters,
|
|
% the scope of such struct names is just that
|
|
% function declaration, which is never right.
|
|
%
|
|
% We generate such forward declarations here,
|
|
% rather than generating type declarations in a
|
|
% header file and #including that header file,
|
|
% because doing the latter would significantly
|
|
% complicate the dependencies (to avoid cyclic
|
|
% #includes, you'd need to generate the type
|
|
% declarations in a different header file than
|
|
% the function declarations).
|
|
%
|
|
globals__io_lookup_bool_option(highlevel_data, HighLevelData),
|
|
(
|
|
{ HighLevelData = yes },
|
|
{ DefnBody = mlds__function(_, Params, _, _) }
|
|
->
|
|
{ Params = mlds__func_params(Arguments, _RetTypes) },
|
|
{ ParamTypes = mlds__get_arg_types(Arguments) },
|
|
mlds_output_type_forward_decls(Indent, ParamTypes)
|
|
;
|
|
[]
|
|
),
|
|
%
|
|
% Now output the declaration for this mlds__defn.
|
|
%
|
|
mlds_indent(Context, Indent),
|
|
mlds_output_decl_flags(Flags, forward_decl, Name, DefnBody),
|
|
mlds_output_decl_body(Indent, qual(ModuleName, Name), Context,
|
|
DefnBody)
|
|
).
|
|
|
|
:- pred mlds_output_type_forward_decls(indent, list(mlds__type),
|
|
io__state, io__state).
|
|
:- mode mlds_output_type_forward_decls(in, in, di, uo) is det.
|
|
|
|
mlds_output_type_forward_decls(Indent, ParamTypes) -->
|
|
%
|
|
% Output forward declarations for all struct types
|
|
% that are contained in the parameter types.
|
|
%
|
|
aggregate(mlds_type_list_contains_type(ParamTypes),
|
|
mlds_output_type_forward_decl(Indent)).
|
|
|
|
% mlds_type_list_contains_type(Types, SubType):
|
|
% True iff the type SubType occurs (directly or indirectly)
|
|
% in the specified list of Types.
|
|
%
|
|
:- pred mlds_type_list_contains_type(list(mlds__type), mlds__type).
|
|
:- mode mlds_type_list_contains_type(in, out) is nondet.
|
|
|
|
mlds_type_list_contains_type(Types, SubType) :-
|
|
list__member(Type, Types),
|
|
mlds_type_contains_type(Type, SubType).
|
|
|
|
% mlds_type_contains_type(Type, SubType):
|
|
% True iff the type Type contains the type SubType.
|
|
%
|
|
:- pred mlds_type_contains_type(mlds__type, mlds__type).
|
|
:- mode mlds_type_contains_type(in, out) is multi.
|
|
|
|
mlds_type_contains_type(Type, Type).
|
|
mlds_type_contains_type(mlds__mercury_array_type(Type), Type).
|
|
mlds_type_contains_type(mlds__array_type(Type), Type).
|
|
mlds_type_contains_type(mlds__ptr_type(Type), Type).
|
|
mlds_type_contains_type(mlds__func_type(Parameters), Type) :-
|
|
Parameters = mlds__func_params(Arguments, RetTypes),
|
|
( list__member(mlds__argument(_Name, Type, _GC_TraceCode), Arguments)
|
|
; list__member(Type, RetTypes)
|
|
).
|
|
|
|
:- pred mlds_output_type_forward_decl(indent, mlds__type,
|
|
io__state, io__state).
|
|
:- mode mlds_output_type_forward_decl(in, in, di, uo) is det.
|
|
|
|
mlds_output_type_forward_decl(Indent, Type) -->
|
|
(
|
|
{
|
|
Type = mlds__class_type(_Name, _Arity, Kind),
|
|
Kind \= mlds__enum,
|
|
ClassType = Type
|
|
;
|
|
Type = mercury_type(MercuryType, user_ctor_type, _),
|
|
type_to_ctor_and_args(MercuryType, TypeCtor,
|
|
_ArgsTypes),
|
|
ml_gen_type_name(TypeCtor, ClassName, ClassArity),
|
|
ClassType = mlds__class_type(ClassName, ClassArity,
|
|
mlds__class)
|
|
}
|
|
->
|
|
mlds_indent(Indent),
|
|
mlds_output_type(ClassType),
|
|
io__write_string(";\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_defn(indent, mlds_module_name, mlds__defn,
|
|
io__state, io__state).
|
|
:- mode mlds_output_defn(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_defn(Indent, ModuleName, Defn) -->
|
|
{ Defn = mlds__defn(Name, Context, Flags, DefnBody) },
|
|
( { DefnBody \= mlds__data(_, _, _) } ->
|
|
io__nl
|
|
;
|
|
[]
|
|
),
|
|
mlds_indent(Context, Indent),
|
|
mlds_output_decl_flags(Flags, definition, Name, DefnBody),
|
|
mlds_output_defn_body(Indent, qual(ModuleName, Name), Context,
|
|
DefnBody).
|
|
|
|
:- pred mlds_output_decl_body(indent, mlds__qualified_entity_name,
|
|
mlds__context, mlds__entity_defn, io__state, io__state).
|
|
:- mode mlds_output_decl_body(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_decl_body(Indent, Name, Context, DefnBody) -->
|
|
(
|
|
{ DefnBody = mlds__data(Type, Initializer, _GC_TraceCode) },
|
|
mlds_output_data_decl(Name, Type,
|
|
initializer_array_size(Initializer))
|
|
;
|
|
{ DefnBody = mlds__function(MaybePredProcId, Signature,
|
|
_MaybeBody, _Attrs) },
|
|
mlds_output_maybe(MaybePredProcId, mlds_output_pred_proc_id),
|
|
mlds_output_func_decl(Indent, Name, Context, Signature)
|
|
;
|
|
{ DefnBody = mlds__class(ClassDefn) },
|
|
mlds_output_class_decl(Indent, Name, ClassDefn)
|
|
),
|
|
io__write_string(";\n").
|
|
|
|
:- pred mlds_output_defn_body(indent, mlds__qualified_entity_name,
|
|
mlds__context, mlds__entity_defn, io__state, io__state).
|
|
:- mode mlds_output_defn_body(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_defn_body(Indent, Name, Context, DefnBody) -->
|
|
(
|
|
{ DefnBody = mlds__data(Type, Initializer,
|
|
Maybe_GC_TraceCode) },
|
|
mlds_output_data_defn(Name, Type, Initializer),
|
|
mlds_output_maybe_gc_trace_code(Indent, Name,
|
|
Maybe_GC_TraceCode, "")
|
|
;
|
|
{ DefnBody = mlds__function(MaybePredProcId, Signature,
|
|
MaybeBody, _Attributes) },
|
|
mlds_output_maybe(MaybePredProcId, mlds_output_pred_proc_id),
|
|
mlds_output_func(Indent, Name, Context, Signature, MaybeBody)
|
|
;
|
|
{ DefnBody = mlds__class(ClassDefn) },
|
|
mlds_output_class(Indent, Name, Context, ClassDefn)
|
|
).
|
|
|
|
:- pred mlds_output_maybe_gc_trace_code(indent::in,
|
|
mlds__qualified_entity_name::in,
|
|
maybe(mlds__statement)::in, string::in,
|
|
io__state::di, io__state::uo) is det.
|
|
mlds_output_maybe_gc_trace_code(Indent, Name, Maybe_GC_TraceCode,
|
|
MaybeNewLine) -->
|
|
(
|
|
{ Maybe_GC_TraceCode = no }
|
|
;
|
|
{ Maybe_GC_TraceCode = yes(GC_TraceCode) },
|
|
io__write_string(MaybeNewLine),
|
|
io__write_string("#if 0 /* GC trace code */\n"),
|
|
% XXX this value for FuncInfo is bogus
|
|
% However, this output is only for debugging anyway,
|
|
% so it doesn't really matter.
|
|
{ FuncInfo = func_info(Name, mlds__func_signature([], [])) },
|
|
mlds_output_statement(Indent, FuncInfo, GC_TraceCode),
|
|
io__write_string("#endif\n")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output type declarations/definitions
|
|
%
|
|
|
|
:- pred mlds_output_class_decl(indent, mlds__qualified_entity_name,
|
|
mlds__class_defn, io__state, io__state).
|
|
:- mode mlds_output_class_decl(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_class_decl(_Indent, Name, ClassDefn) -->
|
|
( { ClassDefn^kind = mlds__enum } ->
|
|
io__write_string("enum "),
|
|
mlds_output_fully_qualified_name(Name),
|
|
io__write_string("_e")
|
|
;
|
|
io__write_string("struct "),
|
|
mlds_output_fully_qualified_name(Name),
|
|
io__write_string("_s")
|
|
).
|
|
|
|
:- pred mlds_output_class(indent, mlds__qualified_entity_name, mlds__context,
|
|
mlds__class_defn, io__state, io__state).
|
|
:- mode mlds_output_class(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_class(Indent, Name, Context, ClassDefn) -->
|
|
%
|
|
% To avoid name clashes, we need to qualify the names of
|
|
% the member constants with the class name.
|
|
% (In particular, this is needed for enumeration constants
|
|
% and for the nested classes that we generate for constructors
|
|
% of discriminated union types.)
|
|
% Here we compute the appropriate qualifier.
|
|
%
|
|
{ Name = qual(ModuleName, UnqualName) },
|
|
{ UnqualName = type(ClassName, ClassArity) ->
|
|
ClassModuleName = mlds__append_class_qualifier(ModuleName,
|
|
ClassName, ClassArity)
|
|
;
|
|
error("mlds_output_enum_constants")
|
|
},
|
|
|
|
%
|
|
% Hoist out static members, since plain old C doesn't support
|
|
% static members in structs (except for enumeration constants).
|
|
%
|
|
% XXX this should be conditional: only when compiling to C,
|
|
% not when compiling to C++
|
|
%
|
|
{ ClassDefn = class_defn(Kind, _Imports, BaseClasses, _Implements,
|
|
Ctors, Members) },
|
|
|
|
{ AllMembers = Ctors ++ Members },
|
|
|
|
( { Kind = mlds__enum } ->
|
|
{ StaticMembers = [] },
|
|
{ StructMembers = AllMembers }
|
|
;
|
|
{ list__filter(is_static_member, AllMembers, StaticMembers,
|
|
NonStaticMembers) },
|
|
{ StructMembers = NonStaticMembers }
|
|
),
|
|
|
|
%
|
|
% Convert the base classes into member variables,
|
|
% since plain old C doesn't support base classes.
|
|
%
|
|
% XXX this should be conditional: only when compiling to C,
|
|
% not when compiling to C++
|
|
%
|
|
{ list__map_foldl(mlds_make_base_class(Context),
|
|
BaseClasses, BaseDefns, 1, _) },
|
|
{ list__append(BaseDefns, StructMembers, BasesAndMembers) },
|
|
|
|
%
|
|
% Output the class declaration and the class members.
|
|
% We treat enumerations specially.
|
|
%
|
|
% Note that standard ANSI/ISO C does not allow empty structs.
|
|
% We could handle empty structs here, by adding a dummy member,
|
|
% but that would waste a lot of space, and would also
|
|
% cause incompatibilities between the data layout for
|
|
% --high-level-data and --no-high-level-data. So instead,
|
|
% we make it is the responsibility of the MLDS code generator
|
|
% to not generate any. (E.g. ml_type_gen.m checks whether
|
|
% `target_uses_empty_base_classes' before generating empty
|
|
% structs.) Hence we don't need to check for empty structs here.
|
|
%
|
|
mlds_output_class_decl(Indent, Name, ClassDefn),
|
|
io__write_string(" {\n"),
|
|
( { Kind = mlds__enum } ->
|
|
mlds_output_enum_constants(Indent + 1, ClassModuleName,
|
|
BasesAndMembers)
|
|
;
|
|
mlds_output_defns(Indent + 1, ClassModuleName,
|
|
BasesAndMembers)
|
|
),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("};\n"),
|
|
mlds_output_defns(Indent, ClassModuleName, StaticMembers).
|
|
|
|
:- pred is_static_member(mlds__defn::in) is semidet.
|
|
|
|
is_static_member(Defn) :-
|
|
Defn = mlds__defn(Name, _, Flags, _),
|
|
( Name = type(_, _)
|
|
; per_instance(Flags) = one_copy
|
|
).
|
|
|
|
% Convert a base class class_id into a member variable
|
|
% that holds the value of the base class.
|
|
%
|
|
:- pred mlds_make_base_class(mlds__context, mlds__class_id, mlds__defn,
|
|
int, int).
|
|
:- mode mlds_make_base_class(in, in, out, in, out) is det.
|
|
|
|
mlds_make_base_class(Context, ClassId, MLDS_Defn, BaseNum0, BaseNum) :-
|
|
BaseName = mlds__var_name(string__format("base_%d", [i(BaseNum0)]),
|
|
no),
|
|
Type = ClassId,
|
|
% We only need GC tracing code for top-level variables,
|
|
% not for base classes.
|
|
GC_TraceCode = no,
|
|
MLDS_Defn = mlds__defn(data(var(BaseName)), Context,
|
|
ml_gen_public_field_decl_flags,
|
|
data(Type, no_initializer, GC_TraceCode)),
|
|
BaseNum = BaseNum0 + 1.
|
|
|
|
% Output the definitions of the enumeration constants
|
|
% for an enumeration type.
|
|
%
|
|
:- pred mlds_output_enum_constants(indent, mlds_module_name,
|
|
mlds__defns, io__state, io__state).
|
|
:- mode mlds_output_enum_constants(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_enum_constants(Indent, EnumModuleName, Members) -->
|
|
%
|
|
% Select the enumeration constants from the list of members
|
|
% for this enumeration type, and output them.
|
|
%
|
|
{ EnumConsts = list__filter(is_enum_const, Members) },
|
|
io__write_list(EnumConsts, ",\n",
|
|
mlds_output_enum_constant(Indent, EnumModuleName)),
|
|
io__nl.
|
|
|
|
% Test whether one of the members of an mlds__enum class
|
|
% is an enumeration constant.
|
|
%
|
|
:- pred is_enum_const(mlds__defn).
|
|
:- mode is_enum_const(in) is semidet.
|
|
|
|
is_enum_const(Defn) :-
|
|
Defn = mlds__defn(_Name, _Context, Flags, _DefnBody),
|
|
constness(Flags) = const.
|
|
|
|
% Output the definition of a single enumeration constant.
|
|
%
|
|
:- pred mlds_output_enum_constant(indent, mlds_module_name, mlds__defn,
|
|
io__state, io__state).
|
|
:- mode mlds_output_enum_constant(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_enum_constant(Indent, EnumModuleName, Defn) -->
|
|
{ Defn = mlds__defn(Name, Context, _Flags, DefnBody) },
|
|
(
|
|
{ DefnBody = data(Type, Initializer, _GC_TraceCode) }
|
|
->
|
|
mlds_indent(Context, Indent),
|
|
mlds_output_fully_qualified_name(qual(EnumModuleName, Name)),
|
|
mlds_output_initializer(Type, Initializer)
|
|
;
|
|
{ error("mlds_output_enum_constant: constant is not data") }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output data declarations/definitions
|
|
%
|
|
|
|
:- pred mlds_output_data_decl(mlds__qualified_entity_name, mlds__type,
|
|
initializer_array_size, io__state, io__state).
|
|
:- mode mlds_output_data_decl(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_data_decl(Name, Type, InitializerSize) -->
|
|
mlds_output_data_decl_ho(mlds_output_type_prefix,
|
|
(pred(Tp::in, di, uo) is det -->
|
|
mlds_output_type_suffix(Tp, InitializerSize)),
|
|
Name, Type).
|
|
|
|
:- pred mlds_output_data_decl_ho(output_type, output_type,
|
|
mlds__qualified_entity_name, mlds__type, io__state, io__state).
|
|
:- mode mlds_output_data_decl_ho(in(output_type), in(output_type),
|
|
in, in, di, uo) is det.
|
|
|
|
mlds_output_data_decl_ho(OutputPrefix, OutputSuffix, Name, Type) -->
|
|
OutputPrefix(Type),
|
|
io__write_char(' '),
|
|
mlds_output_fully_qualified_name(Name),
|
|
OutputSuffix(Type).
|
|
|
|
:- pred mlds_output_data_defn(mlds__qualified_entity_name, mlds__type,
|
|
mlds__initializer, io__state, io__state).
|
|
:- mode mlds_output_data_defn(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_data_defn(Name, Type, Initializer) -->
|
|
mlds_output_data_decl(Name, Type, initializer_array_size(Initializer)),
|
|
mlds_output_initializer(Type, Initializer),
|
|
io__write_string(";\n").
|
|
|
|
:- pred mlds_output_maybe(maybe(T), pred(T, io__state, io__state),
|
|
io__state, io__state).
|
|
:- mode mlds_output_maybe(in, pred(in, di, uo) is det, di, uo) is det.
|
|
|
|
mlds_output_maybe(MaybeValue, OutputAction) -->
|
|
( { MaybeValue = yes(Value) } ->
|
|
OutputAction(Value)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_initializer(mlds__type, mlds__initializer,
|
|
io__state, io__state).
|
|
:- mode mlds_output_initializer(in, in, di, uo) is det.
|
|
|
|
mlds_output_initializer(_Type, Initializer) -->
|
|
( { mlds_needs_initialization(Initializer) = yes } ->
|
|
io__write_string(" = "),
|
|
mlds_output_initializer_body(Initializer)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- func mlds_needs_initialization(mlds__initializer) = bool.
|
|
|
|
mlds_needs_initialization(no_initializer) = no.
|
|
mlds_needs_initialization(init_obj(_)) = yes.
|
|
mlds_needs_initialization(init_struct(_Type, [])) = no.
|
|
mlds_needs_initialization(init_struct(_Type, [_|_])) = yes.
|
|
mlds_needs_initialization(init_array(_)) = yes.
|
|
|
|
:- pred mlds_output_initializer_body(mlds__initializer, io__state, io__state).
|
|
:- mode mlds_output_initializer_body(in, di, uo) is det.
|
|
|
|
mlds_output_initializer_body(no_initializer) --> [].
|
|
mlds_output_initializer_body(init_obj(Rval)) -->
|
|
mlds_output_rval(Rval).
|
|
mlds_output_initializer_body(init_struct(_Type, FieldInits)) -->
|
|
% Note that standard ANSI/ISO C does not allow empty structs.
|
|
% But it is the responsibility of the MLDS code generator
|
|
% to not generate any. So we don't need to handle empty
|
|
% initializers specially here.
|
|
io__write_string("{\n\t\t"),
|
|
io__write_list(FieldInits, ",\n\t\t", mlds_output_initializer_body),
|
|
io__write_string("}").
|
|
mlds_output_initializer_body(init_array(ElementInits)) -->
|
|
io__write_string("{\n\t\t"),
|
|
% Standard ANSI/ISO C does not allow empty arrays. But the MLDS does.
|
|
% To keep the C compiler happy, we therefore convert zero-element
|
|
% MLDS arrays into one-element C arrays. (The extra element is
|
|
% a minor waste of space, but it will otherwise be ignored.)
|
|
% So if the initializer list here is empty, we need to output
|
|
% a single initializer. We can initialize the extra element
|
|
% with any value; we use "0", since that is a valid initializer
|
|
% for any type.
|
|
( { ElementInits = [] } ->
|
|
io__write_string("0")
|
|
;
|
|
io__write_list(ElementInits,
|
|
",\n\t\t", mlds_output_initializer_body)
|
|
),
|
|
io__write_string("}").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output function declarations/definitions
|
|
%
|
|
|
|
:- pred mlds_output_pred_proc_id(pred_proc_id, io__state, io__state).
|
|
:- mode mlds_output_pred_proc_id(in, di, uo) is det.
|
|
|
|
mlds_output_pred_proc_id(proc(PredId, ProcId)) -->
|
|
globals__io_lookup_bool_option(auto_comments, AddComments),
|
|
( { AddComments = yes } ->
|
|
io__write_string("/* pred_id: "),
|
|
{ pred_id_to_int(PredId, PredIdNum) },
|
|
io__write_int(PredIdNum),
|
|
io__write_string(", proc_id: "),
|
|
{ proc_id_to_int(ProcId, ProcIdNum) },
|
|
io__write_int(ProcIdNum),
|
|
io__write_string(" */\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_func(indent, qualified_entity_name, mlds__context,
|
|
func_params, function_body, io__state, io__state).
|
|
:- mode mlds_output_func(in, in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_func(Indent, Name, Context, Params, FunctionBody) -->
|
|
mlds_output_func_decl(Indent, Name, Context, Params),
|
|
(
|
|
{ FunctionBody = external },
|
|
io__write_string(";\n")
|
|
;
|
|
{ FunctionBody = defined_here(Body) },
|
|
io__write_string("\n"),
|
|
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("{\n"),
|
|
|
|
mlds_maybe_output_time_profile_instr(Context, Indent + 1, Name),
|
|
|
|
{ Signature = mlds__get_func_signature(Params) },
|
|
{ FuncInfo = func_info(Name, Signature) },
|
|
mlds_output_statement(Indent + 1, FuncInfo, Body),
|
|
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("}\n") % end the function
|
|
).
|
|
|
|
:- pred mlds_output_func_decl(indent, qualified_entity_name, mlds__context,
|
|
func_params, io__state, io__state).
|
|
:- mode mlds_output_func_decl(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_func_decl(Indent, QualifiedName, Context, Signature) -->
|
|
{ CallingConvention = "MR_CALL " },
|
|
mlds_output_func_decl_ho(Indent, QualifiedName, Context,
|
|
CallingConvention, Signature,
|
|
mlds_output_type_prefix, mlds_output_type_suffix).
|
|
|
|
:- pred mlds_output_func_decl_ho(indent, qualified_entity_name, mlds__context,
|
|
string, func_params, output_type, output_type,
|
|
io__state, io__state).
|
|
:- mode mlds_output_func_decl_ho(in, in, in, in, in, in(output_type),
|
|
in(output_type), di, uo) is det.
|
|
|
|
mlds_output_func_decl_ho(Indent, QualifiedName, Context,
|
|
CallingConvention, Signature, OutputPrefix, OutputSuffix) -->
|
|
{ Signature = mlds__func_params(Parameters, RetTypes) },
|
|
( { RetTypes = [] } ->
|
|
io__write_string("void")
|
|
; { RetTypes = [RetType] } ->
|
|
OutputPrefix(RetType)
|
|
;
|
|
mlds_output_return_list(RetTypes,
|
|
(pred(T::in, di, uo) is det -->
|
|
OutputPrefix(T),
|
|
OutputSuffix(T)))
|
|
),
|
|
io__write_char(' '),
|
|
io__write_string(CallingConvention),
|
|
mlds_output_fully_qualified_name(QualifiedName),
|
|
{ QualifiedName = qual(ModuleName, _) },
|
|
mlds_output_params(OutputPrefix, OutputSuffix,
|
|
Indent, ModuleName, Context, Parameters),
|
|
( { RetTypes = [RetType2] } ->
|
|
OutputSuffix(RetType2)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_params(output_type, output_type,
|
|
indent, mlds_module_name, mlds__context,
|
|
mlds__arguments, io__state, io__state).
|
|
:- mode mlds_output_params(in(output_type), in(output_type),
|
|
in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_params(OutputPrefix, OutputSuffix, Indent, ModuleName,
|
|
Context, Parameters) -->
|
|
io__write_char('('),
|
|
( { Parameters = [] } ->
|
|
io__write_string("void")
|
|
;
|
|
io__nl,
|
|
io__write_list(Parameters, ",\n",
|
|
mlds_output_param(OutputPrefix, OutputSuffix,
|
|
Indent + 1, ModuleName, Context))
|
|
),
|
|
io__write_char(')').
|
|
|
|
:- pred mlds_output_param(output_type, output_type,
|
|
indent, mlds_module_name, mlds__context, mlds__argument,
|
|
io__state, io__state).
|
|
:- mode mlds_output_param(in(output_type), in(output_type), in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
|
|
mlds_output_param(OutputPrefix, OutputSuffix, Indent, ModuleName, Context,
|
|
Arg) -->
|
|
{ Arg = mlds__argument(Name, Type, Maybe_GC_TraceCode) },
|
|
{ QualName = qual(ModuleName, Name) },
|
|
mlds_indent(Context, Indent),
|
|
mlds_output_data_decl_ho(OutputPrefix, OutputSuffix, QualName, Type),
|
|
mlds_output_maybe_gc_trace_code(Indent, QualName, Maybe_GC_TraceCode,
|
|
"\n").
|
|
|
|
:- pred mlds_output_func_type_prefix(func_params, io__state, io__state).
|
|
:- mode mlds_output_func_type_prefix(in, di, uo) is det.
|
|
|
|
mlds_output_func_type_prefix(Params) -->
|
|
{ Params = mlds__func_params(_Parameters, RetTypes) },
|
|
( { RetTypes = [] } ->
|
|
io__write_string("void")
|
|
; { RetTypes = [RetType] } ->
|
|
mlds_output_type(RetType)
|
|
;
|
|
mlds_output_return_list(RetTypes, mlds_output_type)
|
|
),
|
|
% Note that mlds__func_type actually corresponds to a
|
|
% function _pointer_ type in C. This is necessary because
|
|
% function types in C are not first class.
|
|
io__write_string(" MR_CALL (*").
|
|
|
|
:- pred mlds_output_func_type_suffix(func_params, io__state, io__state).
|
|
:- mode mlds_output_func_type_suffix(in, di, uo) is det.
|
|
|
|
mlds_output_func_type_suffix(Params) -->
|
|
{ Params = mlds__func_params(Parameters, _RetTypes) },
|
|
io__write_string(")"),
|
|
mlds_output_param_types(Parameters).
|
|
|
|
:- pred mlds_output_param_types(mlds__arguments, io__state, io__state).
|
|
:- mode mlds_output_param_types(in, di, uo) is det.
|
|
|
|
mlds_output_param_types(Parameters) -->
|
|
io__write_char('('),
|
|
( { Parameters = [] } ->
|
|
io__write_string("void")
|
|
;
|
|
io__write_list(Parameters, ", ", mlds_output_param_type)
|
|
),
|
|
io__write_char(')').
|
|
|
|
:- pred mlds_output_param_type(mlds__argument, io__state, io__state).
|
|
:- mode mlds_output_param_type(in, di, uo) is det.
|
|
|
|
mlds_output_param_type(mlds__argument(_Name, Type, _GC_TraceCode)) -->
|
|
mlds_output_type(Type).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output names of various entities
|
|
%
|
|
|
|
:- pred mlds_output_fully_qualified_name(mlds__qualified_entity_name,
|
|
io__state, io__state).
|
|
:- mode mlds_output_fully_qualified_name(in, di, uo) is det.
|
|
|
|
mlds_output_fully_qualified_name(QualifiedName) -->
|
|
{ QualifiedName = qual(_ModuleName, Name) },
|
|
(
|
|
(
|
|
%
|
|
% don't module-qualify main/2
|
|
%
|
|
{ Name = function(PredLabel, _, _, _) },
|
|
{ PredLabel = pred(predicate, no, "main", 2,
|
|
model_det, no) }
|
|
;
|
|
%
|
|
% don't module-qualify base_typeclass_infos
|
|
%
|
|
% We don't want to include the module name as part
|
|
% of the name if it is a base_typeclass_info, since
|
|
% we _want_ to cause a link error for overlapping
|
|
% instance decls, even if they are in a different
|
|
% module
|
|
%
|
|
{ Name = data(rtti(tc_rtti_id(_))) }
|
|
;
|
|
% We don't module qualify pragma export names.
|
|
{ Name = export(_) }
|
|
)
|
|
->
|
|
mlds_output_name(Name)
|
|
;
|
|
mlds_output_fully_qualified(QualifiedName, mlds_output_name)
|
|
).
|
|
|
|
:- pred mlds_output_fully_qualified_proc_label(mlds__qualified_proc_label,
|
|
io__state, io__state).
|
|
:- mode mlds_output_fully_qualified_proc_label(in, di, uo) is det.
|
|
|
|
mlds_output_fully_qualified_proc_label(QualifiedName) -->
|
|
(
|
|
%
|
|
% don't module-qualify main/2
|
|
%
|
|
{ QualifiedName = qual(_ModuleName, Name) },
|
|
{ Name = PredLabel - _ProcId },
|
|
{ PredLabel = pred(predicate, no, "main", 2, model_det, no) }
|
|
->
|
|
mlds_output_proc_label(Name)
|
|
;
|
|
mlds_output_fully_qualified(QualifiedName,
|
|
mlds_output_proc_label)
|
|
).
|
|
|
|
:- pred mlds_output_fully_qualified(mlds__fully_qualified_name(T),
|
|
pred(T, io__state, io__state), io__state, io__state).
|
|
:- mode mlds_output_fully_qualified(in, pred(in, di, uo) is det,
|
|
di, uo) is det.
|
|
|
|
mlds_output_fully_qualified(qual(ModuleName, Name), OutputFunc) -->
|
|
{ SymName = mlds_module_name_to_sym_name(ModuleName) },
|
|
{ MangledModuleName = sym_name_mangle(SymName) },
|
|
io__write_string(MangledModuleName),
|
|
io__write_string("__"),
|
|
OutputFunc(Name).
|
|
|
|
:- pred mlds_output_module_name(mercury_module_name, io__state, io__state).
|
|
:- mode mlds_output_module_name(in, di, uo) is det.
|
|
|
|
mlds_output_module_name(ModuleName) -->
|
|
{ MangledModuleName = sym_name_mangle(ModuleName) },
|
|
io__write_string(MangledModuleName).
|
|
|
|
:- pred mlds_output_name(mlds__entity_name, io__state, io__state).
|
|
:- mode mlds_output_name(in, di, uo) is det.
|
|
|
|
% XXX we should avoid appending the arity, modenum, and seqnum
|
|
% if they are not needed.
|
|
|
|
mlds_output_name(type(Name, Arity)) -->
|
|
{ MangledName = name_mangle(Name) },
|
|
io__format("%s_%d", [s(MangledName), i(Arity)]).
|
|
mlds_output_name(data(DataName)) -->
|
|
mlds_output_data_name(DataName).
|
|
mlds_output_name(function(PredLabel, ProcId, MaybeSeqNum, _PredId)) -->
|
|
mlds_output_pred_label(PredLabel),
|
|
{ proc_id_to_int(ProcId, ModeNum) },
|
|
io__format("_%d", [i(ModeNum)]),
|
|
( { MaybeSeqNum = yes(SeqNum) } ->
|
|
io__format("_%d", [i(SeqNum)])
|
|
;
|
|
[]
|
|
).
|
|
mlds_output_name(export(Name)) -->
|
|
io__write_string(Name).
|
|
|
|
:- pred mlds_output_pred_label(mlds__pred_label, io__state, io__state).
|
|
:- mode mlds_output_pred_label(in, di, uo) is det.
|
|
|
|
mlds_output_pred_label(pred(PredOrFunc, MaybeDefiningModule, Name, Arity,
|
|
_CodeModel, _NonOutputFunc)) -->
|
|
( { PredOrFunc = predicate, Suffix = "p" }
|
|
; { PredOrFunc = function, Suffix = "f" }
|
|
),
|
|
{ MangledName = name_mangle(Name) },
|
|
io__format("%s_%d_%s", [s(MangledName), i(Arity), s(Suffix)]),
|
|
( { MaybeDefiningModule = yes(DefiningModule) } ->
|
|
io__write_string("_in__"),
|
|
mlds_output_module_name(DefiningModule)
|
|
;
|
|
[]
|
|
).
|
|
mlds_output_pred_label(special_pred(PredName, MaybeTypeModule,
|
|
TypeName, TypeArity)) -->
|
|
{ MangledPredName = name_mangle(PredName) },
|
|
{ MangledTypeName = name_mangle(TypeName) },
|
|
io__write_string(MangledPredName),
|
|
io__write_string("__"),
|
|
( { MaybeTypeModule = yes(TypeModule) } ->
|
|
mlds_output_module_name(TypeModule),
|
|
io__write_string("__")
|
|
;
|
|
[]
|
|
),
|
|
io__write_string(MangledTypeName),
|
|
io__write_string("_"),
|
|
io__write_int(TypeArity).
|
|
|
|
:- pred mlds_output_data_name(mlds__data_name, io__state, io__state).
|
|
:- mode mlds_output_data_name(in, di, uo) is det.
|
|
|
|
mlds_output_data_name(var(Name)) -->
|
|
mlds_output_mangled_name(ml_var_name_to_string(Name)).
|
|
mlds_output_data_name(common(Num)) -->
|
|
io__write_string("common_"),
|
|
io__write_int(Num).
|
|
mlds_output_data_name(rtti(RttiId)) -->
|
|
{ rtti__id_to_c_identifier(RttiId, RttiAddrName) },
|
|
io__write_string(RttiAddrName).
|
|
mlds_output_data_name(module_layout) -->
|
|
{ error("mlds_to_c.m: NYI: module_layout") }.
|
|
mlds_output_data_name(proc_layout(_ProcLabel)) -->
|
|
{ error("mlds_to_c.m: NYI: proc_layout") }.
|
|
mlds_output_data_name(internal_layout(_ProcLabel, _FuncSeqNum)) -->
|
|
{ error("mlds_to_c.m: NYI: internal_layout") }.
|
|
mlds_output_data_name(tabling_pointer(ProcLabel)) -->
|
|
io__write_string("table_for_"),
|
|
mlds_output_proc_label(ProcLabel).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output types
|
|
%
|
|
|
|
%
|
|
% Because of the joys of C syntax, the code for outputting
|
|
% types needs to be split into two parts; first the prefix,
|
|
% i.e. the part of the type name that goes before the variable
|
|
% name in a variable declaration, and then the suffix, i.e.
|
|
% the part which goes after the variable name, e.g. the "[]"
|
|
% for array types.
|
|
%
|
|
|
|
:- pred mlds_output_type(mlds__type, io__state, io__state).
|
|
:- mode mlds_output_type(in, di, uo) is det.
|
|
|
|
mlds_output_type(Type) -->
|
|
mlds_output_type_prefix(Type),
|
|
mlds_output_type_suffix(Type).
|
|
|
|
:- pred mlds_output_type_prefix(mlds__type, io__state, io__state).
|
|
:- mode mlds_output_type_prefix(in, di, uo) is det.
|
|
|
|
mlds_output_type_prefix(mercury_type(Type, TypeCategory, _)) -->
|
|
mlds_output_mercury_type_prefix(Type, TypeCategory).
|
|
mlds_output_type_prefix(mercury_array_type(_ElemType)) -->
|
|
globals__io_lookup_bool_option(highlevel_data, HighLevelData),
|
|
( { HighLevelData = yes } ->
|
|
mlds_output_mercury_user_type_name(
|
|
qualified(unqualified("array"), "array") - 1,
|
|
user_ctor_type)
|
|
;
|
|
io__write_string("MR_ArrayPtr")
|
|
).
|
|
mlds_output_type_prefix(mlds__native_int_type) --> io__write_string("int").
|
|
mlds_output_type_prefix(mlds__native_float_type) --> io__write_string("float").
|
|
mlds_output_type_prefix(mlds__native_bool_type) -->
|
|
io__write_string("MR_bool").
|
|
mlds_output_type_prefix(mlds__native_char_type) --> io__write_string("char").
|
|
mlds_output_type_prefix(mlds__foreign_type(_ForeignType)) -->
|
|
% for binary compatibility with the --target asm back-end,
|
|
% we need to output these as a generic type, rather than making
|
|
% use of the C type name
|
|
io__write_string("MR_Box").
|
|
mlds_output_type_prefix(mlds__class_type(Name, Arity, ClassKind)) -->
|
|
( { ClassKind = mlds__enum } ->
|
|
%
|
|
% We can't just use the enumeration type,
|
|
% since the enumeration type's definition
|
|
% is not guaranteed to be in scope at this point.
|
|
% (Fixing that would be somewhat complicated; it would
|
|
% require writing enum definitions to a separate header file.)
|
|
% Also the enumeration might not be word-sized,
|
|
% which would cause problems for e.g. `std_util:arg/2'.
|
|
% So we just use `MR_Integer', and output the
|
|
% actual enumeration type as a comment.
|
|
%
|
|
io__write_string("MR_Integer /* actually `enum "),
|
|
mlds_output_fully_qualified(Name, mlds_output_mangled_name),
|
|
io__format("_%d_e", [i(Arity)]),
|
|
io__write_string("' */")
|
|
;
|
|
% For struct types it's OK to output an incomplete type,
|
|
% since don't use these types directly, we only
|
|
% use pointers to them.
|
|
io__write_string("struct "),
|
|
mlds_output_fully_qualified(Name, mlds_output_mangled_name),
|
|
io__format("_%d_s", [i(Arity)])
|
|
).
|
|
mlds_output_type_prefix(mlds__ptr_type(Type)) -->
|
|
mlds_output_type(Type),
|
|
io__write_string(" *").
|
|
mlds_output_type_prefix(mlds__array_type(Type)) -->
|
|
% Here we just output the element type.
|
|
% The "[]" goes in the type suffix.
|
|
mlds_output_type(Type).
|
|
mlds_output_type_prefix(mlds__func_type(FuncParams)) -->
|
|
mlds_output_func_type_prefix(FuncParams).
|
|
mlds_output_type_prefix(mlds__generic_type) -->
|
|
io__write_string("MR_Box").
|
|
mlds_output_type_prefix(mlds__generic_env_ptr_type) -->
|
|
io__write_string("void *").
|
|
mlds_output_type_prefix(mlds__type_info_type) -->
|
|
io__write_string("MR_TypeInfo").
|
|
mlds_output_type_prefix(mlds__pseudo_type_info_type) -->
|
|
io__write_string("MR_PseudoTypeInfo").
|
|
mlds_output_type_prefix(mlds__cont_type(ArgTypes)) -->
|
|
( { ArgTypes = [] } ->
|
|
globals__io_lookup_bool_option(gcc_nested_functions,
|
|
GCC_NestedFuncs),
|
|
( { GCC_NestedFuncs = yes } ->
|
|
io__write_string("MR_NestedCont")
|
|
;
|
|
io__write_string("MR_Cont")
|
|
)
|
|
;
|
|
% This case only happens for --nondet-copy-out
|
|
io__write_string("void MR_CALL (*")
|
|
).
|
|
mlds_output_type_prefix(mlds__commit_type) -->
|
|
globals__io_lookup_bool_option(gcc_local_labels, GCC_LocalLabels),
|
|
( { GCC_LocalLabels = yes } ->
|
|
io__write_string("__label__")
|
|
;
|
|
io__write_string("jmp_buf")
|
|
).
|
|
mlds_output_type_prefix(mlds__rtti_type(RttiId)) -->
|
|
{ rtti_id_c_type(RttiId, CType, _IsArray) },
|
|
io__write_string(CType).
|
|
mlds_output_type_prefix(mlds__unknown_type) -->
|
|
{ error("mlds_to_c.m: prefix has unknown type") }.
|
|
|
|
:- pred mlds_output_mercury_type_prefix(mercury_type, type_category,
|
|
io__state, io__state).
|
|
:- mode mlds_output_mercury_type_prefix(in, in, di, uo) is det.
|
|
|
|
mlds_output_mercury_type_prefix(Type, TypeCategory) -->
|
|
(
|
|
{ TypeCategory = char_type },
|
|
io__write_string("MR_Char")
|
|
;
|
|
{ TypeCategory = int_type },
|
|
io__write_string("MR_Integer")
|
|
;
|
|
{ TypeCategory = str_type },
|
|
io__write_string("MR_String")
|
|
;
|
|
{ TypeCategory = float_type },
|
|
io__write_string("MR_Float")
|
|
;
|
|
{ TypeCategory = void_type },
|
|
io__write_string("MR_Word")
|
|
;
|
|
{ TypeCategory = variable_type },
|
|
io__write_string("MR_Box")
|
|
;
|
|
{ TypeCategory = type_info_type },
|
|
% runtime/mercury_hlc_types requires typeclass_infos
|
|
% to be treated as user defined types.
|
|
mlds_output_mercury_user_type_prefix(Type, user_ctor_type)
|
|
;
|
|
{ TypeCategory = type_ctor_info_type },
|
|
% runtime/mercury_hlc_types requires typeclass_infos
|
|
% to be treated as user defined types.
|
|
mlds_output_mercury_user_type_prefix(Type, user_ctor_type)
|
|
;
|
|
{ TypeCategory = typeclass_info_type },
|
|
% runtime/mercury_hlc_types requires typeclass_infos
|
|
% to be treated as user defined types.
|
|
mlds_output_mercury_user_type_prefix(Type, user_ctor_type)
|
|
;
|
|
{ TypeCategory = base_typeclass_info_type },
|
|
% runtime/mercury_hlc_types requires typeclass_infos
|
|
% to be treated as user defined types.
|
|
mlds_output_mercury_user_type_prefix(Type, user_ctor_type)
|
|
;
|
|
{ TypeCategory = tuple_type },
|
|
io__write_string("MR_Tuple")
|
|
;
|
|
{ TypeCategory = higher_order_type },
|
|
globals__io_lookup_bool_option(highlevel_data, HighLevelData),
|
|
( { HighLevelData = yes } ->
|
|
io__write_string("MR_ClosurePtr")
|
|
;
|
|
io__write_string("MR_Word")
|
|
)
|
|
;
|
|
{ TypeCategory = enum_type },
|
|
mlds_output_mercury_user_type_prefix(Type, TypeCategory)
|
|
;
|
|
{ TypeCategory = user_ctor_type },
|
|
mlds_output_mercury_user_type_prefix(Type, TypeCategory)
|
|
).
|
|
|
|
:- pred mlds_output_mercury_user_type_prefix(mercury_type, type_category,
|
|
io__state, io__state).
|
|
:- mode mlds_output_mercury_user_type_prefix(in, in, di, uo) is det.
|
|
|
|
mlds_output_mercury_user_type_prefix(Type, TypeCategory) -->
|
|
globals__io_lookup_bool_option(highlevel_data, HighLevelData),
|
|
( { HighLevelData = yes } ->
|
|
( { type_to_ctor_and_args(Type, TypeCtor, _ArgsTypes) } ->
|
|
mlds_output_mercury_user_type_name(TypeCtor,
|
|
TypeCategory)
|
|
;
|
|
{ error("mlds_output_mercury_user_type_prefix") }
|
|
)
|
|
;
|
|
% for the --no-high-level-data case,
|
|
% we just treat everything as `MR_Word'
|
|
io__write_string("MR_Word")
|
|
).
|
|
|
|
:- pred mlds_output_mercury_user_type_name(type_ctor, type_category,
|
|
io__state, io__state).
|
|
:- mode mlds_output_mercury_user_type_name(in, in, di, uo) is det.
|
|
|
|
mlds_output_mercury_user_type_name(TypeCtor, TypeCategory) -->
|
|
{ ml_gen_type_name(TypeCtor, ClassName, ClassArity) },
|
|
{ TypeCategory = enum_type ->
|
|
MLDS_Type = mlds__class_type(ClassName,
|
|
ClassArity, mlds__enum)
|
|
;
|
|
MLDS_Type = mlds__ptr_type(mlds__class_type(
|
|
ClassName, ClassArity, mlds__class))
|
|
},
|
|
mlds_output_type_prefix(MLDS_Type).
|
|
|
|
:- pred mlds_output_type_suffix(mlds__type, io__state, io__state).
|
|
:- mode mlds_output_type_suffix(in, di, uo) is det.
|
|
|
|
mlds_output_type_suffix(Type) -->
|
|
mlds_output_type_suffix(Type, no_size).
|
|
|
|
:- type initializer_array_size
|
|
---> array_size(int)
|
|
; no_size. % either the size is unknown,
|
|
% or the data is not an array
|
|
|
|
:- func initializer_array_size(mlds__initializer) = initializer_array_size.
|
|
initializer_array_size(no_initializer) = no_size.
|
|
initializer_array_size(init_obj(_)) = no_size.
|
|
initializer_array_size(init_struct(_, _)) = no_size.
|
|
initializer_array_size(init_array(Elems)) = array_size(list__length(Elems)).
|
|
|
|
:- pred mlds_output_type_suffix(mlds__type, initializer_array_size,
|
|
io__state, io__state).
|
|
:- mode mlds_output_type_suffix(in, in, di, uo) is det.
|
|
|
|
mlds_output_type_suffix(mercury_type(_, _, _), _) --> [].
|
|
mlds_output_type_suffix(mercury_array_type(_), _) --> [].
|
|
mlds_output_type_suffix(mlds__native_int_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__native_float_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__native_bool_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__native_char_type, _) --> [].
|
|
% XXX Currently we can't output a type suffix.
|
|
mlds_output_type_suffix(mlds__foreign_type(_), _) --> [].
|
|
mlds_output_type_suffix(mlds__class_type(_, _, _), _) --> [].
|
|
mlds_output_type_suffix(mlds__ptr_type(_), _) --> [].
|
|
mlds_output_type_suffix(mlds__array_type(_), ArraySize) -->
|
|
mlds_output_array_type_suffix(ArraySize).
|
|
mlds_output_type_suffix(mlds__func_type(FuncParams), _) -->
|
|
mlds_output_func_type_suffix(FuncParams).
|
|
mlds_output_type_suffix(mlds__generic_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__generic_env_ptr_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__type_info_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__pseudo_type_info_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__cont_type(ArgTypes), _) -->
|
|
( { ArgTypes = [] } ->
|
|
[]
|
|
;
|
|
% This case only happens for --nondet-copy-out
|
|
io__write_string(")("),
|
|
io__write_list(ArgTypes, ", ", mlds_output_type),
|
|
% add the type for the environment parameter, if needed
|
|
globals__io_lookup_bool_option(gcc_nested_functions,
|
|
GCC_NestedFuncs),
|
|
( { GCC_NestedFuncs = no } ->
|
|
io__write_string(", void *")
|
|
;
|
|
[]
|
|
),
|
|
io__write_string(")")
|
|
).
|
|
mlds_output_type_suffix(mlds__commit_type, _) --> [].
|
|
mlds_output_type_suffix(mlds__rtti_type(RttiId), ArraySize) -->
|
|
( { rtti_id_has_array_type(RttiId) = yes } ->
|
|
mlds_output_array_type_suffix(ArraySize)
|
|
;
|
|
[]
|
|
).
|
|
mlds_output_type_suffix(mlds__unknown_type, _) -->
|
|
{ unexpected(this_file,
|
|
"mlds_output_type_suffix: unknown_type") }.
|
|
|
|
:- pred mlds_output_array_type_suffix(initializer_array_size::in,
|
|
io__state::di, io__state::uo) is det.
|
|
mlds_output_array_type_suffix(no_size) -->
|
|
io__write_string("[]").
|
|
mlds_output_array_type_suffix(array_size(Size0)) -->
|
|
% Standard ANSI/ISO C does not allow arrays of size 0.
|
|
% But the MLDS does. To keep the C compiler happy,
|
|
% we therefore convert zero-element MLDS arrays into
|
|
% one-element C arrays.
|
|
{ int__max(Size0, 1, Size) },
|
|
io__format("[%d]", [i(Size)]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output declaration specifiers
|
|
%
|
|
|
|
:- type decl_or_defn
|
|
---> forward_decl
|
|
; definition.
|
|
|
|
:- pred mlds_output_decl_flags(mlds__decl_flags, decl_or_defn,
|
|
mlds__entity_name, mlds__entity_defn, io__state, io__state).
|
|
:- mode mlds_output_decl_flags(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_decl_flags(Flags, DeclOrDefn, Name, DefnBody) -->
|
|
%
|
|
% mlds_output_extern_or_static handles both the
|
|
% `access' and the `per_instance' fields of the mlds__decl_flags.
|
|
% We have to handle them together because C overloads `static'
|
|
% to mean both `private' and `one_copy', rather than having
|
|
% separate keywords for each. To make it clear which MLDS
|
|
% construct each `static' keyword means, we precede the `static'
|
|
% without (optionally-enabled) comments saying whether it is
|
|
% `private', `one_copy', or both.
|
|
%
|
|
mlds_output_access_comment(access(Flags)),
|
|
mlds_output_per_instance_comment(per_instance(Flags)),
|
|
mlds_output_extern_or_static(access(Flags), per_instance(Flags),
|
|
DeclOrDefn, Name, DefnBody),
|
|
mlds_output_virtuality(virtuality(Flags)),
|
|
mlds_output_finality(finality(Flags)),
|
|
mlds_output_constness(constness(Flags)),
|
|
mlds_output_abstractness(abstractness(Flags)).
|
|
|
|
:- pred mlds_output_access_comment(access, io__state, io__state).
|
|
:- mode mlds_output_access_comment(in, di, uo) is det.
|
|
|
|
mlds_output_access_comment(Access) -->
|
|
globals__io_lookup_bool_option(auto_comments, Comments),
|
|
( { Comments = yes } ->
|
|
mlds_output_access_comment_2(Access)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_access_comment_2(access, io__state, io__state).
|
|
:- mode mlds_output_access_comment_2(in, di, uo) is det.
|
|
|
|
mlds_output_access_comment_2(public) --> io__write_string("/* public: */ ").
|
|
mlds_output_access_comment_2(private) --> io__write_string("/* private: */ ").
|
|
mlds_output_access_comment_2(protected) --> io__write_string("/* protected: */ ").
|
|
mlds_output_access_comment_2(default) --> io__write_string("/* default access */ ").
|
|
mlds_output_access_comment_2(local) --> io__write_string("/* local: */ ").
|
|
|
|
:- pred mlds_output_per_instance_comment(per_instance, io__state, io__state).
|
|
:- mode mlds_output_per_instance_comment(in, di, uo) is det.
|
|
|
|
mlds_output_per_instance_comment(PerInstance) -->
|
|
globals__io_lookup_bool_option(auto_comments, Comments),
|
|
( { Comments = yes } ->
|
|
mlds_output_per_instance_comment_2(PerInstance)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_per_instance_comment_2(per_instance, io__state, io__state).
|
|
:- mode mlds_output_per_instance_comment_2(in, di, uo) is det.
|
|
|
|
mlds_output_per_instance_comment_2(per_instance) --> [].
|
|
mlds_output_per_instance_comment_2(one_copy) --> io__write_string("/* one_copy */ ").
|
|
|
|
:- pred mlds_output_extern_or_static(access, per_instance, decl_or_defn,
|
|
mlds__entity_name, mlds__entity_defn, io__state, io__state).
|
|
:- mode mlds_output_extern_or_static(in, in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_extern_or_static(Access, PerInstance, DeclOrDefn, Name, DefnBody)
|
|
-->
|
|
(
|
|
{ Access = private
|
|
; Access = local, PerInstance = one_copy
|
|
},
|
|
{ Name \= type(_, _) },
|
|
% Don't output "static" for functions that don't have a body.
|
|
% This can happen for Mercury procedures declared `:- external'
|
|
{ DefnBody \= mlds__function(_, _, external, _) }
|
|
->
|
|
io__write_string("static ")
|
|
;
|
|
{ DeclOrDefn = forward_decl },
|
|
{ Name = data(_) }
|
|
->
|
|
io__write_string("extern ")
|
|
;
|
|
% forward declarations for GNU C nested functions need
|
|
% to be prefixed with "auto"
|
|
{ DeclOrDefn = forward_decl },
|
|
{ Name = function(_, _, _, _) },
|
|
{ Access = local }
|
|
->
|
|
io__write_string("auto ")
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred mlds_output_virtuality(virtuality, io__state, io__state).
|
|
:- mode mlds_output_virtuality(in, di, uo) is det.
|
|
|
|
mlds_output_virtuality(virtual) --> io__write_string("virtual ").
|
|
mlds_output_virtuality(non_virtual) --> [].
|
|
|
|
:- pred mlds_output_finality(finality, io__state, io__state).
|
|
:- mode mlds_output_finality(in, di, uo) is det.
|
|
|
|
mlds_output_finality(final) --> io__write_string("/* final */ ").
|
|
mlds_output_finality(overridable) --> [].
|
|
|
|
:- pred mlds_output_constness(constness, io__state, io__state).
|
|
:- mode mlds_output_constness(in, di, uo) is det.
|
|
|
|
mlds_output_constness(const) --> io__write_string("const ").
|
|
mlds_output_constness(modifiable) --> [].
|
|
|
|
:- pred mlds_output_abstractness(abstractness, io__state, io__state).
|
|
:- mode mlds_output_abstractness(in, di, uo) is det.
|
|
|
|
mlds_output_abstractness(abstract) --> io__write_string("/* abstract */ ").
|
|
mlds_output_abstractness(concrete) --> [].
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output statements
|
|
%
|
|
|
|
:- type func_info
|
|
---> func_info(mlds__qualified_entity_name, mlds__func_signature).
|
|
|
|
:- pred mlds_output_statements(indent, func_info, list(mlds__statement),
|
|
io__state, io__state).
|
|
:- mode mlds_output_statements(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_statements(Indent, FuncInfo, Statements) -->
|
|
list__foldl(mlds_output_statement(Indent, FuncInfo), Statements).
|
|
|
|
:- pred mlds_output_statement(indent, func_info, mlds__statement,
|
|
io__state, io__state).
|
|
:- mode mlds_output_statement(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_statement(Indent, FuncInfo, mlds__statement(Statement, Context)) -->
|
|
mlds_to_c__output_context(Context),
|
|
mlds_output_stmt(Indent, FuncInfo, Statement, Context).
|
|
|
|
:- pred mlds_output_stmt(indent, func_info, mlds__stmt, mlds__context,
|
|
io__state, io__state).
|
|
:- mode mlds_output_stmt(in, in, in, in, di, uo) is det.
|
|
|
|
%
|
|
% sequence
|
|
%
|
|
mlds_output_stmt(Indent, FuncInfo, block(Defns, Statements), Context) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("{\n"),
|
|
( { Defns \= [] } ->
|
|
{ FuncInfo = func_info(FuncName, _) },
|
|
{ FuncName = qual(ModuleName, _) },
|
|
|
|
% output forward declarations for any nested functions
|
|
% defined in this block, in case they are referenced before
|
|
% they are defined
|
|
{ list__filter(defn_is_function, Defns, NestedFuncDefns) },
|
|
( { NestedFuncDefns \= [] } ->
|
|
mlds_output_decls(Indent + 1, ModuleName,
|
|
NestedFuncDefns),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
|
|
mlds_output_defns(Indent + 1, ModuleName, Defns),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
),
|
|
mlds_output_statements(Indent + 1, FuncInfo, Statements),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("}\n").
|
|
|
|
%
|
|
% iteration
|
|
%
|
|
mlds_output_stmt(Indent, FuncInfo, while(Cond, Statement, no), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("while ("),
|
|
mlds_output_rval(Cond),
|
|
io__write_string(")\n"),
|
|
mlds_output_statement(Indent + 1, FuncInfo, Statement).
|
|
mlds_output_stmt(Indent, FuncInfo, while(Cond, Statement, yes), Context) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("do\n"),
|
|
mlds_output_statement(Indent + 1, FuncInfo, Statement),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("while ("),
|
|
mlds_output_rval(Cond),
|
|
io__write_string(");\n").
|
|
|
|
%
|
|
% selection (see also computed_goto)
|
|
%
|
|
mlds_output_stmt(Indent, FuncInfo, if_then_else(Cond, Then0, MaybeElse),
|
|
Context) -->
|
|
%
|
|
% we need to take care to avoid problems caused by the
|
|
% dangling else ambiguity
|
|
%
|
|
{
|
|
%
|
|
% For examples of the form
|
|
%
|
|
% if (...)
|
|
% if (...)
|
|
% ...
|
|
% else
|
|
% ...
|
|
%
|
|
% we need braces around the inner `if', otherwise
|
|
% they wouldn't parse they way we want them to:
|
|
% C would match the `else' with the inner `if'
|
|
% rather than the outer `if'.
|
|
%
|
|
MaybeElse = yes(_),
|
|
Then0 = statement(if_then_else(_, _, no), ThenContext)
|
|
->
|
|
Then = statement(block([], [Then0]), ThenContext)
|
|
;
|
|
%
|
|
% For examples of the form
|
|
%
|
|
% if (...)
|
|
% if (...)
|
|
% ...
|
|
% else
|
|
% ...
|
|
%
|
|
% we don't _need_ braces around the inner `if',
|
|
% since C will match the else with the inner `if',
|
|
% but we add braces anyway, to avoid a warning from gcc.
|
|
%
|
|
MaybeElse = no,
|
|
Then0 = statement(if_then_else(_, _, yes(_)), ThenContext)
|
|
->
|
|
Then = statement(block([], [Then0]), ThenContext)
|
|
;
|
|
Then = Then0
|
|
},
|
|
|
|
mlds_indent(Indent),
|
|
io__write_string("if ("),
|
|
mlds_output_rval(Cond),
|
|
io__write_string(")\n"),
|
|
mlds_output_statement(Indent + 1, FuncInfo, Then),
|
|
( { MaybeElse = yes(Else) } ->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("else\n"),
|
|
mlds_output_statement(Indent + 1, FuncInfo, Else)
|
|
;
|
|
[]
|
|
).
|
|
mlds_output_stmt(Indent, FuncInfo, switch(_Type, Val, _Range, Cases, Default),
|
|
Context) -->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("switch ("),
|
|
mlds_output_rval(Val),
|
|
io__write_string(") {\n"),
|
|
% we put the default case first, so that if it is unreachable,
|
|
% it will get merged in with the first case.
|
|
mlds_output_switch_default(Indent + 1, FuncInfo, Context, Default),
|
|
list__foldl(mlds_output_switch_case(Indent + 1, FuncInfo, Context),
|
|
Cases),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("}\n").
|
|
|
|
%
|
|
% transfer of control
|
|
%
|
|
mlds_output_stmt(Indent, _FuncInfo, label(LabelName), _) -->
|
|
%
|
|
% Note: MLDS allows labels at the end of blocks.
|
|
% C doesn't. Hence we need to insert a semi-colon after the colon
|
|
% to ensure that there is a statement to attach the label to.
|
|
%
|
|
mlds_indent(Indent - 1),
|
|
mlds_output_label_name(LabelName),
|
|
io__write_string(":;\n").
|
|
mlds_output_stmt(Indent, _FuncInfo, goto(label(LabelName)), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("goto "),
|
|
mlds_output_label_name(LabelName),
|
|
io__write_string(";\n").
|
|
mlds_output_stmt(Indent, _FuncInfo, goto(break), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("break;\n").
|
|
mlds_output_stmt(Indent, _FuncInfo, goto(continue), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("continue;\n").
|
|
mlds_output_stmt(Indent, _FuncInfo, computed_goto(Expr, Labels), Context) -->
|
|
% XXX for GNU C, we could output potentially more efficient code
|
|
% by using an array of labels; this would tell the compiler that
|
|
% it didn't need to do any range check.
|
|
mlds_indent(Indent),
|
|
io__write_string("switch ("),
|
|
mlds_output_rval(Expr),
|
|
io__write_string(") {\n"),
|
|
{ OutputLabel =
|
|
(pred(Label::in, Count0::in, Count::out, di, uo) is det -->
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("case "),
|
|
io__write_int(Count0),
|
|
io__write_string(": goto "),
|
|
mlds_output_label_name(Label),
|
|
io__write_string(";\n"),
|
|
{ Count = Count0 + 1 }
|
|
) },
|
|
list__foldl2(OutputLabel, Labels, 0, _FinalCount),
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("default: /*NOTREACHED*/ MR_assert(0);\n"),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("}\n").
|
|
|
|
%
|
|
% function call/return
|
|
%
|
|
mlds_output_stmt(Indent, CallerFuncInfo, Call, Context) -->
|
|
{ Call = call(Signature, FuncRval, MaybeObject, CallArgs,
|
|
Results, IsTailCall) },
|
|
{ CallerFuncInfo = func_info(CallerName, CallerSignature) },
|
|
|
|
%
|
|
% We need to enclose the generated code inside an extra pair
|
|
% of curly braces, in case we generate more than one statement
|
|
% (e.g. because we generate extra statements for profiling
|
|
% or for tail call optimization) and the generated code is
|
|
% e.g. inside an if-then-else.
|
|
%
|
|
mlds_indent(Indent),
|
|
io__write_string("{\n"),
|
|
|
|
mlds_maybe_output_call_profile_instr(Context,
|
|
Indent + 1, FuncRval, CallerName),
|
|
|
|
%
|
|
% Optimize general tail calls.
|
|
% We can't really do much here except to insert `return'
|
|
% as an extra hint to the C compiler.
|
|
% XXX these optimizations should be disable-able
|
|
%
|
|
% If Results = [], i.e. the function has `void' return type,
|
|
% then this would result in code that is not legal ANSI C
|
|
% (although it _is_ legal in GNU C and in C++),
|
|
% so for that case, we put the return statement after
|
|
% the call -- see below.
|
|
%
|
|
% Note that it's only safe to add such a return statement if
|
|
% the calling procedure has the same return types as the callee,
|
|
% or if the calling procedure has no return value.
|
|
% (Calls where the types are different can be marked as tail calls
|
|
% if they are known to never return.)
|
|
%
|
|
mlds_indent(Context, Indent + 1),
|
|
{ Signature = mlds__func_signature(_, RetTypes) },
|
|
{ CallerSignature = mlds__func_signature(_, CallerRetTypes) },
|
|
(
|
|
{ IsTailCall = tail_call ; IsTailCall = no_return_call },
|
|
{ Results \= [] },
|
|
{ RetTypes = CallerRetTypes }
|
|
->
|
|
io__write_string("return ")
|
|
;
|
|
[]
|
|
),
|
|
( { MaybeObject = yes(Object) } ->
|
|
mlds_output_bracketed_rval(Object),
|
|
io__write_string(".") % XXX should this be "->"?
|
|
;
|
|
[]
|
|
),
|
|
( { Results = [] } ->
|
|
[]
|
|
; { Results = [Lval] } ->
|
|
mlds_output_lval(Lval),
|
|
io__write_string(" = ")
|
|
;
|
|
mlds_output_return_list(Results, mlds_output_lval),
|
|
io__write_string(" = ")
|
|
),
|
|
mlds_output_bracketed_rval(FuncRval),
|
|
io__write_string("("),
|
|
io__write_list(CallArgs, ", ", mlds_output_rval),
|
|
io__write_string(");\n"),
|
|
|
|
(
|
|
{ IsTailCall = tail_call ; IsTailCall = no_return_call },
|
|
{ CallerRetTypes = [] }
|
|
->
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("return;\n")
|
|
;
|
|
mlds_maybe_output_time_profile_instr(Context,
|
|
Indent + 1, CallerName)
|
|
),
|
|
mlds_indent(Indent),
|
|
io__write_string("}\n").
|
|
|
|
mlds_output_stmt(Indent, _FuncInfo, return(Results), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("return"),
|
|
( { Results = [] } ->
|
|
[]
|
|
; { Results = [Rval] } ->
|
|
io__write_char(' '),
|
|
mlds_output_rval(Rval)
|
|
;
|
|
mlds_output_return_list(Results, mlds_output_rval)
|
|
),
|
|
io__write_string(";\n").
|
|
|
|
%
|
|
% commits
|
|
%
|
|
mlds_output_stmt(Indent, _FuncInfo, do_commit(Ref), _) -->
|
|
mlds_indent(Indent),
|
|
globals__io_lookup_bool_option(gcc_local_labels, GCC_LocalLabels),
|
|
( { GCC_LocalLabels = yes } ->
|
|
% output "goto <Ref>"
|
|
io__write_string("goto "),
|
|
mlds_output_rval(Ref)
|
|
;
|
|
% output "MR_builtin_longjmp(<Ref>, 1)".
|
|
% This is a macro that expands to either the standard longjmp()
|
|
% or the GNU C's __builtin_longjmp().
|
|
% Note that the second argument to GNU C's
|
|
% __builtin_longjmp() *must* be `1'.
|
|
io__write_string("MR_builtin_longjmp("),
|
|
mlds_output_rval(Ref),
|
|
io__write_string(", 1)")
|
|
),
|
|
io__write_string(";\n").
|
|
mlds_output_stmt(Indent, FuncInfo, try_commit(Ref, Stmt0, Handler), Context) -->
|
|
globals__io_lookup_bool_option(gcc_local_labels, GCC_LocalLabels),
|
|
(
|
|
{ GCC_LocalLabels = yes },
|
|
|
|
% Output the following:
|
|
%
|
|
% <Stmt>
|
|
% goto <Ref>_done;
|
|
% <Ref>:
|
|
% <Handler>
|
|
% <Ref>_done:
|
|
% ;
|
|
|
|
% Note that <Ref> should be just variable name,
|
|
% not a complicated expression. If not, the
|
|
% C compiler will catch it.
|
|
|
|
mlds_output_statement(Indent, FuncInfo, Stmt0),
|
|
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("goto "),
|
|
mlds_output_lval(Ref),
|
|
io__write_string("_done;\n"),
|
|
|
|
mlds_indent(Context, Indent - 1),
|
|
mlds_output_lval(Ref),
|
|
io__write_string(":\n"),
|
|
|
|
mlds_output_statement(Indent, FuncInfo, Handler),
|
|
|
|
mlds_indent(Context, Indent - 1),
|
|
mlds_output_lval(Ref),
|
|
io__write_string("_done:\t;\n")
|
|
|
|
;
|
|
{ GCC_LocalLabels = no },
|
|
|
|
% Output the following:
|
|
%
|
|
% if (MR_builtin_setjmp(<Ref>) == 0)
|
|
% <Stmt>
|
|
% else
|
|
% <Handler>
|
|
%
|
|
% MR_builtin_setjmp() expands to either the
|
|
% standard setjmp() or GNU C's __builtin_setjmp().
|
|
%
|
|
% Note that ISO C says that any non-volatile variables
|
|
% that are local to the function containing the setjmp()
|
|
% and which are modified between the setjmp() and the
|
|
% longjmp() become indeterminate after the longjmp().
|
|
% The MLDS code generator handles that by generating
|
|
% each commit in its own nested function, with the
|
|
% local variables remaining in the containing function.
|
|
% This ensures that none of the variables which get
|
|
% modified between the setjmp() and the longjmp() and
|
|
% which get referenced after the longjmp() are local
|
|
% variables in the function containing the setjmp(),
|
|
% so we don't need to mark them as volatile.
|
|
%
|
|
|
|
%
|
|
% we need to take care to avoid problems caused by the
|
|
% dangling else ambiguity
|
|
%
|
|
{
|
|
Stmt0 = statement(if_then_else(_, _, no), Context)
|
|
->
|
|
Stmt = statement(block([], [Stmt0]), Context)
|
|
;
|
|
Stmt = Stmt0
|
|
},
|
|
|
|
mlds_indent(Indent),
|
|
io__write_string("if (MR_builtin_setjmp("),
|
|
mlds_output_lval(Ref),
|
|
io__write_string(") == 0)\n"),
|
|
|
|
mlds_output_statement(Indent + 1, FuncInfo, Stmt),
|
|
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("else\n"),
|
|
|
|
mlds_output_statement(Indent + 1, FuncInfo, Handler)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% Extra code for outputting switch statements
|
|
%
|
|
|
|
:- pred mlds_output_switch_case(indent, func_info, mlds__context,
|
|
mlds__switch_case, io__state, io__state).
|
|
:- mode mlds_output_switch_case(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_switch_case(Indent, FuncInfo, Context, Case) -->
|
|
{ Case = (Conds - Statement) },
|
|
list__foldl(mlds_output_case_cond(Indent, Context), Conds),
|
|
mlds_output_statement(Indent + 1, FuncInfo, Statement),
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("break;\n").
|
|
|
|
:- pred mlds_output_case_cond(indent, mlds__context,
|
|
mlds__case_match_cond, io__state, io__state).
|
|
:- mode mlds_output_case_cond(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_case_cond(Indent, Context, match_value(Val)) -->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("case "),
|
|
mlds_output_rval(Val),
|
|
io__write_string(":\n").
|
|
mlds_output_case_cond(Indent, Context, match_range(Low, High)) -->
|
|
% This uses the GNU C extension `case <Low> ... <High>:'.
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("case "),
|
|
mlds_output_rval(Low),
|
|
io__write_string(" ... "),
|
|
mlds_output_rval(High),
|
|
io__write_string(":\n").
|
|
|
|
:- pred mlds_output_switch_default(indent, func_info, mlds__context,
|
|
mlds__switch_default, io__state, io__state).
|
|
:- mode mlds_output_switch_default(in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_switch_default(Indent, _FuncInfo, Context, default_is_unreachable) -->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("default: /*NOTREACHED*/ MR_assert(0);\n").
|
|
mlds_output_switch_default(_Indent, _FuncInfo, _Context, default_do_nothing) --> [].
|
|
mlds_output_switch_default(Indent, FuncInfo, Context, default_case(Statement)) -->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("default:\n"),
|
|
mlds_output_statement(Indent + 1, FuncInfo, Statement),
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("break;\n").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% If memory profiling is turned on output an instruction to
|
|
% record the heap allocation.
|
|
%
|
|
:- pred mlds_maybe_output_heap_profile_instr(mlds__context::in,
|
|
indent::in, list(mlds__rval)::in,
|
|
mlds__qualified_entity_name::in, maybe(ctor_name)::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_maybe_output_heap_profile_instr(Context, Indent, Args, FuncName,
|
|
MaybeCtorName) -->
|
|
globals__io_lookup_bool_option(profile_memory, ProfileMem),
|
|
(
|
|
{ ProfileMem = yes }
|
|
->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("MR_record_allocation("),
|
|
io__write_int(list__length(Args)),
|
|
io__write_string(", "),
|
|
mlds_output_fully_qualified_name(FuncName),
|
|
io__write_string(", """),
|
|
mlds_output_fully_qualified_name(FuncName),
|
|
io__write_string(""", "),
|
|
( { MaybeCtorName = yes(CtorId) } ->
|
|
io__write_char('"'),
|
|
{ CtorId = qual(_ModuleName, CtorDefn) },
|
|
{ CtorDefn = ctor_id(CtorName, _CtorArity) },
|
|
c_util__output_quoted_string(CtorName),
|
|
io__write_char('"')
|
|
;
|
|
/*
|
|
** Just use an empty string. Note that we can't use
|
|
** a null pointer here, because MR_record_allocation()
|
|
** requires its string arguments to not be NULL.
|
|
*/
|
|
io__write_string("\"\"")
|
|
),
|
|
io__write_string(");\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
%
|
|
% If call profiling is turned on output an instruction to record
|
|
% an arc in the call profile between the callee and caller.
|
|
%
|
|
:- pred mlds_maybe_output_call_profile_instr(mlds__context::in,
|
|
indent::in, mlds__rval::in, mlds__qualified_entity_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_maybe_output_call_profile_instr(Context, Indent,
|
|
CalleeFuncRval, CallerName) -->
|
|
globals__io_lookup_bool_option(profile_calls, ProfileCalls),
|
|
( { ProfileCalls = yes } ->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("MR_prof_call_profile("),
|
|
mlds_output_bracketed_rval(CalleeFuncRval),
|
|
io__write_string(", "),
|
|
mlds_output_fully_qualified_name(CallerName),
|
|
io__write_string(");\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
%
|
|
% If time profiling is turned on output an instruction which
|
|
% informs the runtime which procedure we are currently located
|
|
% in.
|
|
%
|
|
:- pred mlds_maybe_output_time_profile_instr(mlds__context::in,
|
|
indent::in, mlds__qualified_entity_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
mlds_maybe_output_time_profile_instr(Context, Indent, Name) -->
|
|
globals__io_lookup_bool_option(profile_time, ProfileTime),
|
|
(
|
|
{ ProfileTime = yes }
|
|
->
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("MR_set_prof_current_proc("),
|
|
mlds_output_fully_qualified_name(Name),
|
|
io__write_string(");\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% exception handling
|
|
%
|
|
|
|
/* XXX not yet implemented */
|
|
|
|
|
|
%
|
|
% atomic statements
|
|
%
|
|
mlds_output_stmt(Indent, FuncInfo, atomic(AtomicStatement), Context) -->
|
|
mlds_output_atomic_stmt(Indent, FuncInfo, AtomicStatement, Context).
|
|
|
|
:- pred mlds_output_label_name(mlds__label, io__state, io__state).
|
|
:- mode mlds_output_label_name(in, di, uo) is det.
|
|
|
|
mlds_output_label_name(LabelName) -->
|
|
mlds_output_mangled_name(LabelName).
|
|
|
|
:- pred mlds_output_atomic_stmt(indent, func_info,
|
|
mlds__atomic_statement, mlds__context, io__state, io__state).
|
|
:- mode mlds_output_atomic_stmt(in, in, in, in, di, uo) is det.
|
|
|
|
%
|
|
% comments
|
|
%
|
|
mlds_output_atomic_stmt(Indent, _FuncInfo, comment(Comment), _) -->
|
|
% XXX we should escape any "*/"'s in the Comment.
|
|
% we should also split the comment into lines and indent
|
|
% each line appropriately.
|
|
mlds_indent(Indent),
|
|
io__write_string("/* "),
|
|
io__write_string(Comment),
|
|
io__write_string(" */\n").
|
|
|
|
%
|
|
% assignment
|
|
%
|
|
mlds_output_atomic_stmt(Indent, _FuncInfo, assign(Lval, Rval), _) -->
|
|
mlds_indent(Indent),
|
|
mlds_output_lval(Lval),
|
|
io__write_string(" = "),
|
|
mlds_output_rval(Rval),
|
|
io__write_string(";\n").
|
|
|
|
%
|
|
% heap management
|
|
%
|
|
mlds_output_atomic_stmt(_Indent, _FuncInfo, delete_object(_Lval), _) -->
|
|
{ error("mlds_to_c.m: sorry, delete_object not implemented") }.
|
|
|
|
mlds_output_atomic_stmt(Indent, FuncInfo, NewObject, Context) -->
|
|
{ NewObject = new_object(Target, MaybeTag, _HasSecTag, Type, MaybeSize,
|
|
MaybeCtorName, Args, ArgTypes) },
|
|
mlds_indent(Indent),
|
|
io__write_string("{\n"),
|
|
|
|
% When filling in the fields of a newly allocated cell, use a fresh
|
|
% local variable as the base address for the field references in
|
|
% preference to an lval that is more expensive to access. This yields
|
|
% a speedup of about 0.3%.
|
|
|
|
( { Target = var(_, _) } ->
|
|
{ Base = lval(Target) }
|
|
;
|
|
% It doesn't matter what string we pick for BaseVarName,
|
|
% as long as its declaration doesn't hide any of the variables
|
|
% inside Args. This is not hard to ensure, since the printed
|
|
% forms of the variables inside Args all include "__".
|
|
{ BaseVarName = "base" },
|
|
{ Base = string(BaseVarName) },
|
|
mlds_indent(Context, Indent + 1),
|
|
mlds_output_type_prefix(Type),
|
|
io__write_string(" "),
|
|
io__write_string(BaseVarName),
|
|
mlds_output_type_suffix(Type),
|
|
io__write_string(";\n")
|
|
),
|
|
|
|
% for --gc accurate, we need to insert a call to GC_check()
|
|
% before every allocation
|
|
globals__io_get_gc_method(GC_Method),
|
|
( { GC_Method = accurate } ->
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("MR_GC_check();\n"),
|
|
% For types which hold RTTI that will be traversed
|
|
% by the collector at GC-time, we need to allocate
|
|
% an extra word at the start, to hold the forwarding
|
|
% pointer. Normally we would just overwrite the
|
|
% first word of the object in the "from" space,
|
|
% but this can't be done for objects which will be
|
|
% referenced during the garbage collection process.
|
|
( { type_needs_forwarding_pointer_space(Type) = yes } ->
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string(
|
|
"/* reserve space for GC forwarding pointer*/\n"),
|
|
mlds_indent(Context, Indent + 1),
|
|
io__write_string("MR_hp_alloc(1);\n")
|
|
;
|
|
[]
|
|
)
|
|
;
|
|
[]
|
|
),
|
|
|
|
{ FuncInfo = func_info(FuncName, _FuncSignature) },
|
|
mlds_maybe_output_heap_profile_instr(Context, Indent + 1, Args,
|
|
FuncName, MaybeCtorName),
|
|
|
|
mlds_indent(Context, Indent + 1),
|
|
write_lval_or_string(Base),
|
|
io__write_string(" = "),
|
|
( { MaybeTag = yes(Tag0) } ->
|
|
{ Tag = Tag0 },
|
|
mlds_output_cast(Type),
|
|
io__write_string("MR_mkword("),
|
|
mlds_output_tag(Tag),
|
|
io__write_string(", "),
|
|
{ EndMkword = ")" }
|
|
;
|
|
{ Tag = 0 },
|
|
%
|
|
% XXX we shouldn't need the cast here,
|
|
% but currently the type that we include
|
|
% in the call to MR_new_object() is not
|
|
% always correct.
|
|
%
|
|
mlds_output_cast(Type),
|
|
{ EndMkword = "" }
|
|
),
|
|
io__write_string("MR_new_object("),
|
|
mlds_output_type(Type),
|
|
io__write_string(", "),
|
|
( { MaybeSize = yes(Size) } ->
|
|
io__write_string("("),
|
|
mlds_output_rval(Size),
|
|
io__write_string(" * sizeof(MR_Word))")
|
|
;
|
|
% XXX what should we do here?
|
|
io__write_int(-1)
|
|
),
|
|
io__write_string(", "),
|
|
( { MaybeCtorName = yes(QualifiedCtorId) } ->
|
|
io__write_char('"'),
|
|
{ QualifiedCtorId = qual(_ModuleName, CtorDefn) },
|
|
{ CtorDefn = ctor_id(CtorName, _CtorArity) },
|
|
c_util__output_quoted_string(CtorName),
|
|
io__write_char('"')
|
|
;
|
|
io__write_string("NULL")
|
|
),
|
|
io__write_string(")"),
|
|
io__write_string(EndMkword),
|
|
io__write_string(";\n"),
|
|
(
|
|
{ Base = lval(_) }
|
|
;
|
|
{ Base = string(BaseVarName1) },
|
|
mlds_indent(Context, Indent + 1),
|
|
mlds_output_lval(Target),
|
|
io__write_string(" = "),
|
|
io__write_string(BaseVarName1),
|
|
io__write_string(";\n")
|
|
),
|
|
mlds_output_init_args(Args, ArgTypes, Context, 0, Base, Tag,
|
|
Indent + 1),
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("}\n").
|
|
|
|
mlds_output_atomic_stmt(Indent, _FuncInfo, gc_check, _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("MR_GC_check();\n").
|
|
|
|
mlds_output_atomic_stmt(Indent, _FuncInfo, mark_hp(Lval), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("MR_mark_hp("),
|
|
mlds_output_lval(Lval),
|
|
io__write_string(");\n").
|
|
|
|
mlds_output_atomic_stmt(Indent, _FuncInfo, restore_hp(Rval), _) -->
|
|
mlds_indent(Indent),
|
|
io__write_string("MR_restore_hp("),
|
|
mlds_output_rval(Rval),
|
|
io__write_string(");\n").
|
|
|
|
%
|
|
% trail management
|
|
%
|
|
mlds_output_atomic_stmt(_Indent, _FuncInfo, trail_op(_TrailOp), _) -->
|
|
{ error("mlds_to_c.m: sorry, trail_ops not implemented") }.
|
|
|
|
%
|
|
% foreign language interfacing
|
|
%
|
|
mlds_output_atomic_stmt(_Indent, _FuncInfo,
|
|
inline_target_code(TargetLang, Components), Context) -->
|
|
( { TargetLang = lang_C } ->
|
|
list__foldl(
|
|
mlds_output_target_code_component(Context),
|
|
Components)
|
|
;
|
|
{ error("mlds_to_c.m: sorry, inline_target_code only works for lang_C") }
|
|
).
|
|
|
|
mlds_output_atomic_stmt(_Indent, _FuncInfo,
|
|
outline_foreign_proc(_Lang, _Vs, _Lvals, _Code), _Context) -->
|
|
{ error("mlds_to_c.m: outline_foreign_proc is not used in C backend") }.
|
|
|
|
:- pred mlds_output_target_code_component(mlds__context, target_code_component,
|
|
io__state, io__state).
|
|
:- mode mlds_output_target_code_component(in, in, di, uo) is det.
|
|
|
|
% Note: `name(Name)' target_code_components are used to
|
|
% generate the #define for `MR_PROC_LABEL'.
|
|
% The fact that they're used in a #define means that we can't do
|
|
% an mlds_to_c__output_context(Context) here, since #line directives
|
|
% aren't allowed inside #defines.
|
|
% Similarly, all the target_code_components except user_target_code
|
|
% can get emitted inside calls to the MR_BOX_FOREIGN_TYPE
|
|
% or MR_UNBOX_FOREIGN_TYPE macros, which means that we can't output
|
|
% the contexts for those either, since #line directives aren't
|
|
% allowed inside macro invocations in standard C
|
|
% (although some compilers, e.g. gcc 3.2, do allow it).
|
|
mlds_output_target_code_component(Context,
|
|
user_target_code(CodeString, MaybeUserContext, _Attrs)) -->
|
|
( { MaybeUserContext = yes(UserContext) } ->
|
|
mlds_to_c__output_context(mlds__make_context(UserContext))
|
|
;
|
|
mlds_to_c__output_context(Context)
|
|
),
|
|
io__write_string(CodeString),
|
|
io__write_string("\n"),
|
|
mlds_to_c__reset_context.
|
|
mlds_output_target_code_component(_Context, raw_target_code(CodeString,
|
|
_Attrs)) -->
|
|
io__write_string(CodeString).
|
|
mlds_output_target_code_component(_Context, target_code_input(Rval)) -->
|
|
mlds_output_rval(Rval),
|
|
io__write_string("\n").
|
|
mlds_output_target_code_component(_Context, target_code_output(Lval)) -->
|
|
mlds_output_lval(Lval),
|
|
io__write_string("\n").
|
|
mlds_output_target_code_component(_Context, name(Name)) -->
|
|
mlds_output_fully_qualified_name(Name),
|
|
io__write_string("\n").
|
|
|
|
:- func type_needs_forwarding_pointer_space(mlds__type) = bool.
|
|
type_needs_forwarding_pointer_space(mlds__type_info_type) = yes.
|
|
type_needs_forwarding_pointer_space(mlds__pseudo_type_info_type) = yes.
|
|
type_needs_forwarding_pointer_space(mercury_type(_, TypeCategory, _)) =
|
|
is_introduced_type_info_type_category(TypeCategory).
|
|
type_needs_forwarding_pointer_space(mercury_array_type(_)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__cont_type(_)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__commit_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__native_bool_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__native_int_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__native_float_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__native_char_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__foreign_type(_)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__class_type(_, _, _)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__array_type(_)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__ptr_type(_)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__func_type(_)) = no.
|
|
type_needs_forwarding_pointer_space(mlds__generic_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__generic_env_ptr_type) = no.
|
|
type_needs_forwarding_pointer_space(mlds__rtti_type(_)) = _ :-
|
|
% these should all be statically allocated, not dynamically allocated,
|
|
% so we should never get here
|
|
unexpected(this_file,
|
|
"type_needs_forwarding_pointer_space: rtti_type").
|
|
type_needs_forwarding_pointer_space(mlds__unknown_type) = _ :-
|
|
unexpected(this_file,
|
|
"type_needs_forwarding_pointer_space: unknown_type").
|
|
|
|
:- type lval_or_string
|
|
---> lval(mlds__lval)
|
|
; string(string).
|
|
|
|
:- pred mlds_output_init_args(list(mlds__rval), list(mlds__type), mlds__context,
|
|
int, lval_or_string, mlds__tag, indent, io__state, io__state).
|
|
:- mode mlds_output_init_args(in, in, in, in, in, in, in, di, uo) is det.
|
|
|
|
mlds_output_init_args([_|_], [], _, _, _, _, _) -->
|
|
{ error("mlds_output_init_args: length mismatch") }.
|
|
mlds_output_init_args([], [_|_], _, _, _, _, _) -->
|
|
{ error("mlds_output_init_args: length mismatch") }.
|
|
mlds_output_init_args([], [], _, _, _, _, _) --> [].
|
|
mlds_output_init_args([Arg|Args], [ArgType|ArgTypes], Context,
|
|
ArgNum, Base, Tag, Indent) -->
|
|
%
|
|
% The MR_hl_field() macro expects its argument to
|
|
% have type MR_Box, so we need to box the arguments
|
|
% if they aren't already boxed. Hence the use of
|
|
% mlds_output_boxed_rval below.
|
|
%
|
|
% XXX For --high-level-data, we ought to generate
|
|
% assignments to the fields (or perhaps a call to
|
|
% a constructor function) rather than using the
|
|
% MR_hl_field() macro.
|
|
%
|
|
mlds_indent(Context, Indent),
|
|
io__write_string("MR_hl_field("),
|
|
mlds_output_tag(Tag),
|
|
io__write_string(", "),
|
|
write_lval_or_string(Base),
|
|
io__write_string(", "),
|
|
io__write_int(ArgNum),
|
|
io__write_string(") = "),
|
|
mlds_output_boxed_rval(ArgType, Arg),
|
|
io__write_string(";\n"),
|
|
mlds_output_init_args(Args, ArgTypes, Context,
|
|
ArgNum + 1, Base, Tag, Indent).
|
|
|
|
:- pred write_lval_or_string(lval_or_string::in, io::di, io::uo) is det.
|
|
|
|
write_lval_or_string(Base) -->
|
|
(
|
|
{ Base = lval(Target) },
|
|
mlds_output_lval(Target)
|
|
;
|
|
{ Base = string(BaseVarName) },
|
|
io__write_string(BaseVarName)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Code to output expressions
|
|
%
|
|
|
|
:- pred mlds_output_lval(mlds__lval, io__state, io__state).
|
|
:- mode mlds_output_lval(in, di, uo) is det.
|
|
|
|
mlds_output_lval(field(MaybeTag, Rval, offset(OffsetRval),
|
|
FieldType, _ClassType)) -->
|
|
(
|
|
{ FieldType = mlds__generic_type
|
|
; FieldType = mlds__mercury_type(term__variable(_), _, _)
|
|
}
|
|
->
|
|
io__write_string("(")
|
|
;
|
|
% The field type for field(_, _, offset(_), _, _) lvals
|
|
% must be something that maps to MR_Box.
|
|
{ error("unexpected field type") }
|
|
),
|
|
( { MaybeTag = yes(Tag) } ->
|
|
io__write_string("MR_hl_field("),
|
|
mlds_output_tag(Tag),
|
|
io__write_string(", ")
|
|
;
|
|
io__write_string("MR_hl_mask_field("),
|
|
io__write_string("(MR_Word) ")
|
|
),
|
|
mlds_output_rval(Rval),
|
|
io__write_string(", "),
|
|
mlds_output_rval(OffsetRval),
|
|
io__write_string("))").
|
|
mlds_output_lval(field(MaybeTag, PtrRval, named_field(FieldName, CtorType),
|
|
_FieldType, PtrType)) -->
|
|
io__write_string("("),
|
|
( { MaybeTag = yes(0) } ->
|
|
( { PtrType \= CtorType } ->
|
|
mlds_output_cast(CtorType)
|
|
;
|
|
[]
|
|
),
|
|
( { PtrRval = mem_addr(Lval) } ->
|
|
mlds_output_lval(Lval),
|
|
io__write_string(").")
|
|
;
|
|
mlds_output_bracketed_rval(PtrRval),
|
|
io__write_string(")->")
|
|
)
|
|
;
|
|
mlds_output_cast(CtorType),
|
|
( { MaybeTag = yes(Tag) } ->
|
|
io__write_string("MR_body("),
|
|
mlds_output_rval(PtrRval),
|
|
io__write_string(", "),
|
|
mlds_output_tag(Tag)
|
|
;
|
|
io__write_string("MR_strip_tag("),
|
|
mlds_output_rval(PtrRval)
|
|
),
|
|
io__write_string("))->")
|
|
),
|
|
mlds_output_fully_qualified(FieldName, mlds_output_mangled_name).
|
|
mlds_output_lval(mem_ref(Rval, _Type)) -->
|
|
io__write_string("*"),
|
|
mlds_output_bracketed_rval(Rval).
|
|
mlds_output_lval(var(VarName, _VarType)) -->
|
|
mlds_output_var(VarName).
|
|
|
|
:- pred mlds_output_var(mlds__var, io__state, io__state).
|
|
:- mode mlds_output_var(in, di, uo) is det.
|
|
|
|
mlds_output_var(VarName) -->
|
|
mlds_output_fully_qualified(VarName, mlds_output_var_name).
|
|
|
|
:- pred mlds_output_var_name(mlds__var_name, io__state, io__state).
|
|
:- mode mlds_output_var_name(in, di, uo) is det.
|
|
mlds_output_var_name(VarName) -->
|
|
mlds_output_mangled_name(ml_var_name_to_string(VarName)).
|
|
|
|
:- pred mlds_output_mangled_name(string, io__state, io__state).
|
|
:- mode mlds_output_mangled_name(in, di, uo) is det.
|
|
|
|
mlds_output_mangled_name(Name) -->
|
|
io__write_string(name_mangle(Name)).
|
|
|
|
:- pred mlds_output_bracketed_lval(mlds__lval, io__state, io__state).
|
|
:- mode mlds_output_bracketed_lval(in, di, uo) is det.
|
|
|
|
mlds_output_bracketed_lval(Lval) -->
|
|
(
|
|
% if it's just a variable name, then we don't need parentheses
|
|
{ Lval = var(_, _) }
|
|
->
|
|
mlds_output_lval(Lval)
|
|
;
|
|
io__write_char('('),
|
|
mlds_output_lval(Lval),
|
|
io__write_char(')')
|
|
).
|
|
|
|
:- pred mlds_output_bracketed_rval(mlds__rval, io__state, io__state).
|
|
:- mode mlds_output_bracketed_rval(in, di, uo) is det.
|
|
|
|
mlds_output_bracketed_rval(Rval) -->
|
|
(
|
|
% if it's just a variable name, then we don't need parentheses
|
|
{ Rval = lval(var(_,_))
|
|
; Rval = const(code_addr_const(_))
|
|
}
|
|
->
|
|
mlds_output_rval(Rval)
|
|
;
|
|
io__write_char('('),
|
|
mlds_output_rval(Rval),
|
|
io__write_char(')')
|
|
).
|
|
|
|
:- pred mlds_output_return_list(list(T), pred(T, io__state, io__state),
|
|
io__state, io__state).
|
|
:- mode mlds_output_return_list(in, pred(in, di, uo) is det, di, uo) is det.
|
|
% mlds_output_return_list(List, OutputPred, IO0, IO) outputs a List
|
|
% of return types/values using OutputPred.
|
|
|
|
mlds_output_return_list(List, OutputPred) -->
|
|
% Even though C doesn't support multiple return types,
|
|
% this case needs to be handled for e.g. MLDS dumps when
|
|
% compiling to Java. We generate an "#error" directive
|
|
% to make the error message clearer, but then we go ahead
|
|
% and generate C-like psuedo-code for the purposes of MLDS
|
|
% dumps.
|
|
io__write_string("\n#error multiple return values\n"),
|
|
io__write_string("\t{"),
|
|
io__write_list(List, ", ", OutputPred),
|
|
io__write_string("}").
|
|
|
|
:- pred mlds_output_rval(mlds__rval, io__state, io__state).
|
|
:- mode mlds_output_rval(in, di, uo) is det.
|
|
|
|
mlds_output_rval(lval(Lval)) -->
|
|
mlds_output_lval(Lval).
|
|
/**** XXX do we need this?
|
|
mlds_output_rval(lval(Lval)) -->
|
|
% if a field is used as an rval, then we need to use
|
|
% the MR_hl_const_field() macro, not the MR_hl_field() macro,
|
|
% to avoid warnings about discarding const,
|
|
% and similarly for MR_mask_field.
|
|
( { Lval = field(MaybeTag, Rval, FieldNum, _, _) } ->
|
|
( { MaybeTag = yes(Tag) } ->
|
|
io__write_string("MR_hl_const_field("),
|
|
mlds_output_tag(Tag),
|
|
io__write_string(", ")
|
|
;
|
|
io__write_string("MR_hl_const_mask_field(")
|
|
),
|
|
mlds_output_rval(Rval),
|
|
io__write_string(", "),
|
|
mlds_output_rval(FieldNum),
|
|
io__write_string(")")
|
|
;
|
|
mlds_output_lval(Lval)
|
|
).
|
|
****/
|
|
|
|
mlds_output_rval(mkword(Tag, Rval)) -->
|
|
io__write_string("MR_mkword("),
|
|
mlds_output_tag(Tag),
|
|
io__write_string(", "),
|
|
mlds_output_rval(Rval),
|
|
io__write_string(")").
|
|
|
|
mlds_output_rval(const(Const)) -->
|
|
mlds_output_rval_const(Const).
|
|
|
|
mlds_output_rval(unop(Op, Rval)) -->
|
|
mlds_output_unop(Op, Rval).
|
|
|
|
mlds_output_rval(binop(Op, Rval1, Rval2)) -->
|
|
mlds_output_binop(Op, Rval1, Rval2).
|
|
|
|
mlds_output_rval(mem_addr(Lval)) -->
|
|
% XXX are parentheses needed?
|
|
io__write_string("&"),
|
|
mlds_output_lval(Lval).
|
|
|
|
mlds_output_rval(self(_)) -->
|
|
io__write_string("this").
|
|
|
|
:- pred mlds_output_unop(mlds__unary_op, mlds__rval, io__state, io__state).
|
|
:- mode mlds_output_unop(in, in, di, uo) is det.
|
|
|
|
mlds_output_unop(cast(Type), Exprn) -->
|
|
mlds_output_cast_rval(Type, Exprn).
|
|
mlds_output_unop(box(Type), Exprn) -->
|
|
mlds_output_boxed_rval(Type, Exprn).
|
|
mlds_output_unop(unbox(Type), Exprn) -->
|
|
mlds_output_unboxed_rval(Type, Exprn).
|
|
mlds_output_unop(std_unop(Unop), Exprn) -->
|
|
mlds_output_std_unop(Unop, Exprn).
|
|
|
|
:- pred mlds_output_cast_rval(mlds__type, mlds__rval, io__state, io__state).
|
|
:- mode mlds_output_cast_rval(in, in, di, uo) is det.
|
|
|
|
mlds_output_cast_rval(Type, Exprn) -->
|
|
mlds_output_cast(Type),
|
|
mlds_output_rval(Exprn).
|
|
|
|
:- pred mlds_output_cast(mlds__type, io__state, io__state).
|
|
:- mode mlds_output_cast(in, di, uo) is det.
|
|
|
|
mlds_output_cast(Type) -->
|
|
io__write_string("("),
|
|
mlds_output_type(Type),
|
|
io__write_string(") ").
|
|
|
|
:- pred mlds_output_boxed_rval(mlds__type, mlds__rval, io__state, io__state).
|
|
:- mode mlds_output_boxed_rval(in, in, di, uo) is det.
|
|
|
|
mlds_output_boxed_rval(Type, Exprn) -->
|
|
(
|
|
{ Type = mlds__generic_type
|
|
; Type = mlds__mercury_type(_, variable_type, _)
|
|
}
|
|
->
|
|
% It already has type MR_Box, so no cast is needed
|
|
mlds_output_rval(Exprn)
|
|
;
|
|
{ Exprn = unop(cast(OtherType), InnerExprn) },
|
|
( { Type = OtherType }
|
|
; { is_an_address(InnerExprn) }
|
|
)
|
|
->
|
|
% avoid unnecessary double-casting -- strip away the inner cast
|
|
% This is necessary for ANSI/ISO C conformance, to avoid
|
|
% casts from pointers to integers in static initializers.
|
|
mlds_output_boxed_rval(Type, InnerExprn)
|
|
;
|
|
{ Type = mlds__mercury_type(term__functor(term__atom("float"),
|
|
[], _), _, _)
|
|
; Type = mlds__native_float_type
|
|
}
|
|
->
|
|
io__write_string("MR_box_float("),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string(")")
|
|
;
|
|
{ Type = mlds__mercury_type(term__functor(
|
|
term__atom("character"), [], _), _, _)
|
|
; Type = mlds__native_char_type
|
|
; Type = mlds__native_bool_type
|
|
; Type = mlds__native_int_type
|
|
}
|
|
->
|
|
% We cast first to MR_Word, and then to MR_Box.
|
|
% This is done to avoid spurious warnings about "cast from
|
|
% integer to pointer of different size" from gcc.
|
|
io__write_string("((MR_Box) (MR_Word) ("),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string("))")
|
|
;
|
|
io__write_string("((MR_Box) ("),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string("))")
|
|
).
|
|
|
|
% Succeed if the specified rval is an address
|
|
% (possibly tagged and/or cast to a different type).
|
|
:- pred is_an_address(mlds__rval::in) is semidet.
|
|
is_an_address(mkword(_Tag, Expr)) :-
|
|
is_an_address(Expr).
|
|
is_an_address(unop(cast(_), Expr)) :-
|
|
is_an_address(Expr).
|
|
is_an_address(mem_addr(_)).
|
|
is_an_address(const(null(_))).
|
|
is_an_address(const(code_addr_const(_))).
|
|
is_an_address(const(data_addr_const(_))).
|
|
|
|
:- pred mlds_output_unboxed_rval(mlds__type, mlds__rval, io__state, io__state).
|
|
:- mode mlds_output_unboxed_rval(in, in, di, uo) is det.
|
|
|
|
mlds_output_unboxed_rval(Type, Exprn) -->
|
|
(
|
|
{ Type = mlds__mercury_type(term__functor(term__atom("float"),
|
|
[], _), _, _)
|
|
; Type = mlds__native_float_type
|
|
}
|
|
->
|
|
io__write_string("MR_unbox_float("),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string(")")
|
|
;
|
|
{ Type = mlds__mercury_type(term__functor(
|
|
term__atom("character"), [], _), _, _)
|
|
; Type = mlds__native_char_type
|
|
; Type = mlds__native_bool_type
|
|
; Type = mlds__native_int_type
|
|
}
|
|
->
|
|
% We cast first to MR_Word, and then to the desired type.
|
|
% This is done to avoid spurious warnings about "cast from
|
|
% pointer to integer of different size" from gcc.
|
|
io__write_string("("),
|
|
mlds_output_cast(Type),
|
|
io__write_string("(MR_Word) "),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string(")")
|
|
;
|
|
io__write_string("("),
|
|
mlds_output_cast(Type),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string(")")
|
|
).
|
|
|
|
:- pred mlds_output_std_unop(builtin_ops__unary_op, mlds__rval,
|
|
io__state, io__state).
|
|
:- mode mlds_output_std_unop(in, in, di, uo) is det.
|
|
|
|
mlds_output_std_unop(UnaryOp, Exprn) -->
|
|
{ c_util__unary_prefix_op(UnaryOp, UnaryOpString) },
|
|
io__write_string(UnaryOpString),
|
|
io__write_string("("),
|
|
( { UnaryOp = tag } ->
|
|
% The MR_tag macro requires its argument to be of type
|
|
% `MR_Word'.
|
|
% XXX should we put this cast inside the definition of MR_tag?
|
|
io__write_string("(MR_Word) ")
|
|
;
|
|
[]
|
|
),
|
|
mlds_output_rval(Exprn),
|
|
io__write_string(")").
|
|
|
|
:- pred mlds_output_binop(binary_op, mlds__rval, mlds__rval,
|
|
io__state, io__state).
|
|
:- mode mlds_output_binop(in, in, in, di, uo) is det.
|
|
|
|
mlds_output_binop(Op, X, Y) -->
|
|
(
|
|
{ Op = array_index(_Type) }
|
|
->
|
|
mlds_output_bracketed_rval(X),
|
|
io__write_string("["),
|
|
mlds_output_rval(Y),
|
|
io__write_string("]")
|
|
;
|
|
{ Op = body }
|
|
->
|
|
io__write_string("MR_body("),
|
|
mlds_output_rval(X),
|
|
io__write_string(", "),
|
|
mlds_output_rval(Y),
|
|
io__write_string(")")
|
|
;
|
|
{ c_util__string_compare_op(Op, OpStr) }
|
|
->
|
|
io__write_string("(strcmp("),
|
|
mlds_output_rval(X),
|
|
io__write_string(", "),
|
|
mlds_output_rval(Y),
|
|
io__write_string(")"),
|
|
io__write_string(" "),
|
|
io__write_string(OpStr),
|
|
io__write_string(" "),
|
|
io__write_string("0)")
|
|
;
|
|
( { c_util__float_compare_op(Op, OpStr1) } ->
|
|
{ OpStr = OpStr1 }
|
|
; { c_util__float_op(Op, OpStr2) } ->
|
|
{ OpStr = OpStr2 }
|
|
;
|
|
{ fail }
|
|
)
|
|
->
|
|
io__write_string("("),
|
|
mlds_output_bracketed_rval(X),
|
|
io__write_string(" "),
|
|
io__write_string(OpStr),
|
|
io__write_string(" "),
|
|
mlds_output_bracketed_rval(Y),
|
|
io__write_string(")")
|
|
;
|
|
/****
|
|
XXX broken for C == minint
|
|
(since `NewC is 0 - C' overflows)
|
|
{ Op = (+) },
|
|
{ Y = const(int_const(C)) },
|
|
{ C < 0 }
|
|
->
|
|
{ NewOp = (-) },
|
|
{ NewC is 0 - C },
|
|
{ NewY = const(int_const(NewC)) },
|
|
io__write_string("("),
|
|
mlds_output_rval(X),
|
|
io__write_string(" "),
|
|
mlds_output_binary_op(NewOp),
|
|
io__write_string(" "),
|
|
mlds_output_rval(NewY),
|
|
io__write_string(")")
|
|
;
|
|
******/
|
|
io__write_string("("),
|
|
mlds_output_rval(X),
|
|
io__write_string(" "),
|
|
mlds_output_binary_op(Op),
|
|
io__write_string(" "),
|
|
mlds_output_rval(Y),
|
|
io__write_string(")")
|
|
).
|
|
|
|
:- pred mlds_output_binary_op(binary_op, io__state, io__state).
|
|
:- mode mlds_output_binary_op(in, di, uo) is det.
|
|
|
|
mlds_output_binary_op(Op) -->
|
|
( { c_util__binary_infix_op(Op, OpStr) } ->
|
|
io__write_string(OpStr)
|
|
;
|
|
{ error("mlds_output_binary_op: invalid binary operator") }
|
|
).
|
|
|
|
:- pred mlds_output_rval_const(mlds__rval_const, io__state, io__state).
|
|
:- mode mlds_output_rval_const(in, di, uo) is det.
|
|
|
|
mlds_output_rval_const(true) -->
|
|
io__write_string("MR_TRUE").
|
|
mlds_output_rval_const(false) -->
|
|
io__write_string("MR_FALSE").
|
|
mlds_output_rval_const(int_const(N)) -->
|
|
% we need to cast to (MR_Integer) to ensure
|
|
% things like 1 << 32 work when `Integer' is 64 bits
|
|
% but `int' is 32 bits.
|
|
io__write_string("(MR_Integer) "),
|
|
io__write_int(N).
|
|
mlds_output_rval_const(float_const(FloatVal)) -->
|
|
% the cast to (MR_Float) here lets the C compiler
|
|
% do arithmetic in `float' rather than `double'
|
|
% if `MR_Float' is `float' not `double'.
|
|
io__write_string("(MR_Float) "),
|
|
c_util__output_float_literal(FloatVal).
|
|
mlds_output_rval_const(string_const(String)) -->
|
|
% the cast avoids the following gcc warning
|
|
% "assignment discards qualifiers from pointer target type"
|
|
io__write_string("(MR_String) "),
|
|
io__write_string(""""),
|
|
c_util__output_quoted_string(String),
|
|
io__write_string("""").
|
|
mlds_output_rval_const(multi_string_const(Length, String)) -->
|
|
io__write_string(""""),
|
|
c_util__output_quoted_multi_string(Length, String),
|
|
io__write_string("""").
|
|
mlds_output_rval_const(code_addr_const(CodeAddr)) -->
|
|
mlds_output_code_addr(CodeAddr).
|
|
mlds_output_rval_const(data_addr_const(DataAddr)) -->
|
|
mlds_output_data_addr(DataAddr).
|
|
mlds_output_rval_const(null(_)) -->
|
|
io__write_string("NULL").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred mlds_output_tag(mlds__tag, io__state, io__state).
|
|
:- mode mlds_output_tag(in, di, uo) is det.
|
|
|
|
mlds_output_tag(Tag) -->
|
|
io__write_string("MR_mktag("),
|
|
io__write_int(Tag),
|
|
io__write_string(")").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred mlds_output_code_addr(mlds__code_addr, io__state, io__state).
|
|
:- mode mlds_output_code_addr(in, di, uo) is det.
|
|
|
|
mlds_output_code_addr(proc(Label, _Sig)) -->
|
|
mlds_output_fully_qualified_proc_label(Label).
|
|
mlds_output_code_addr(internal(Label, SeqNum, _Sig)) -->
|
|
mlds_output_fully_qualified_proc_label(Label),
|
|
io__write_string("_"),
|
|
io__write_int(SeqNum).
|
|
|
|
:- pred mlds_output_proc_label(mlds__proc_label, io__state, io__state).
|
|
:- mode mlds_output_proc_label(in, di, uo) is det.
|
|
|
|
mlds_output_proc_label(PredLabel - ProcId) -->
|
|
mlds_output_pred_label(PredLabel),
|
|
{ proc_id_to_int(ProcId, ModeNum) },
|
|
io__format("_%d", [i(ModeNum)]).
|
|
|
|
:- pred mlds_output_data_addr(mlds__data_addr, io__state, io__state).
|
|
:- mode mlds_output_data_addr(in, di, uo) is det.
|
|
|
|
mlds_output_data_addr(data_addr(ModuleName, DataName)) -->
|
|
(
|
|
% if its an array type, then we just use the name,
|
|
% otherwise we must prefix the name with `&'.
|
|
{ DataName = rtti(RttiId) },
|
|
{ rtti_id_has_array_type(RttiId) = yes }
|
|
->
|
|
mlds_output_data_var_name(ModuleName, DataName)
|
|
;
|
|
io__write_string("(&"),
|
|
mlds_output_data_var_name(ModuleName, DataName),
|
|
io__write_string(")")
|
|
).
|
|
|
|
:- pred mlds_output_data_var_name(mlds_module_name, mlds__data_name,
|
|
io__state, io__state).
|
|
:- mode mlds_output_data_var_name(in, in, di, uo) is det.
|
|
|
|
mlds_output_data_var_name(ModuleName, DataName) -->
|
|
(
|
|
%
|
|
% don't module-qualify base_typeclass_infos
|
|
%
|
|
% We don't want to include the module name as part
|
|
% of the name if it is a base_typeclass_info, since
|
|
% we _want_ to cause a link error for overlapping
|
|
% instance decls, even if they are in a different
|
|
% module
|
|
%
|
|
{ DataName = rtti(tc_rtti_id(_)) }
|
|
->
|
|
[]
|
|
;
|
|
mlds_output_module_name(
|
|
mlds_module_name_to_sym_name(ModuleName)),
|
|
io__write_string("__")
|
|
),
|
|
mlds_output_data_name(DataName).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Miscellaneous stuff to handle indentation and generation of
|
|
% source context annotations (#line directives).
|
|
%
|
|
|
|
mlds_to_c__output_context(Context) -->
|
|
{ ProgContext = mlds__get_prog_context(Context) },
|
|
{ term__context_file(ProgContext, FileName) },
|
|
{ term__context_line(ProgContext, LineNumber) },
|
|
c_util__set_line_num(FileName, LineNumber).
|
|
|
|
:- pred mlds_to_c__reset_context(io__state, io__state).
|
|
:- mode mlds_to_c__reset_context(di, uo) is det.
|
|
|
|
mlds_to_c__reset_context -->
|
|
c_util__reset_line_num.
|
|
|
|
:- pred mlds_indent(mlds__context, indent, io__state, io__state).
|
|
:- mode mlds_indent(in, in, di, uo) is det.
|
|
|
|
mlds_indent(Context, N) -->
|
|
mlds_to_c__output_context(Context),
|
|
mlds_indent(N).
|
|
|
|
% A value of type `indent' records the number of levels
|
|
% of indentation to indent the next piece of code.
|
|
% Currently we output two spaces for each level of indentation.
|
|
:- type indent == int.
|
|
|
|
:- pred mlds_indent(indent, io__state, io__state).
|
|
:- mode mlds_indent(in, di, uo) is det.
|
|
|
|
mlds_indent(N) -->
|
|
( { N =< 0 } ->
|
|
[]
|
|
;
|
|
io__write_string(" "),
|
|
mlds_indent(N - 1)
|
|
).
|
|
|
|
:- func this_file = string.
|
|
this_file = "mlds_to_c.m".
|
|
|
|
:- end_module mlds_to_c.
|
|
|
|
%-----------------------------------------------------------------------------%
|