mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
This is because in the presence of practices such as writing to a file
with one name (e.g. xyz.mih.tmp) and then renaming that file (e.g. to
xyz.mih), the stream name is NOT the right name.
compiler/c_util.m:
Require callers to specify the actual file name we should put
into #line directives.
compiler/export.m:
compiler/llds_out_file.m:
compiler/llds_out_instr.m:
compiler/llds_out_util.m:
compiler/mlds_to_c_file.m:
compiler/mlds_to_c_stmt.m:
compiler/mlds_to_c_util.m:
Pass the intended final filename to c_util.m, directly or indirectly.
1688 lines
68 KiB
Mathematica
1688 lines
68 KiB
Mathematica
%----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%----------------------------------------------------------------------------%
|
|
% Copyright (C) 2009-2011 The University of Melbourne.
|
|
% Copyright (C) 2013-2018, 2020-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%----------------------------------------------------------------------------%
|
|
%
|
|
% File: llds_out_file.m.
|
|
% Main authors: conway, fjh, zs.
|
|
%
|
|
% This module defines the top level routines for printing out LLDS modules.
|
|
% It looks after printing out global data, procedures (but not instructions),
|
|
% and module initialization functions.
|
|
%
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.llds_out.llds_out_file.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.maybe_util.
|
|
:- import_module ll_backend.llds.
|
|
|
|
:- import_module bool.
|
|
:- import_module io.
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
% Given a c_file structure, output the LLDS code inside it into a .c file.
|
|
%
|
|
:- pred output_llds(io.text_output_stream::in, globals::in, c_file::in,
|
|
maybe_succeeded::out, io::di, io::uo) is det.
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
% c_data_linkage_string(DefaultLinkage, BeingDefined):
|
|
%
|
|
% Return a C string that gives the storage class appropriate for the
|
|
% definition of a global variable with the specified properties.
|
|
%
|
|
:- func c_data_linkage_string(linkage, bool) = string.
|
|
|
|
% Given a boolean that states whether a data item includes code
|
|
% addresses or not, return a C string that gives its "const-ness".
|
|
%
|
|
:- func c_data_const_string(globals, bool) = string.
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
% Note that we need to know the linkage not just at the definition,
|
|
% but also at every use, because if the use is prior to the definition,
|
|
% then we need to declare the name first, and the linkage used in that
|
|
% declaration must be consistent with the linkage in the definition.
|
|
% For this reason, the field in c_data (which holds the information about
|
|
% the definition) which says whether or not a data name is exported
|
|
% is not useful. Instead, we need to determine whether or not something
|
|
% is exported from its `data_name'.
|
|
|
|
:- type linkage
|
|
---> extern
|
|
; static.
|
|
|
|
%----------------------------------------------------------------------------%
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.c_util.
|
|
:- import_module backend_libs.name_mangle.
|
|
:- import_module backend_libs.proc_label.
|
|
:- import_module backend_libs.rtti.
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module libs.compiler_util.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.optimization_options.
|
|
:- import_module libs.trace_params.
|
|
:- import_module ll_backend.exprn_aux.
|
|
:- import_module ll_backend.layout.
|
|
:- import_module ll_backend.layout_out.
|
|
:- import_module ll_backend.llds_out.llds_out_code_addr.
|
|
:- import_module ll_backend.llds_out.llds_out_data.
|
|
:- import_module ll_backend.llds_out.llds_out_global.
|
|
:- import_module ll_backend.llds_out.llds_out_instr.
|
|
:- import_module ll_backend.llds_out.llds_out_util.
|
|
:- import_module ll_backend.rtti_out.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.parse_tree_out_misc.
|
|
:- import_module parse_tree.parse_tree_output.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_foreign.
|
|
|
|
:- import_module cord.
|
|
:- import_module int.
|
|
:- import_module library. % for the version number.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module multi_map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module set_tree234.
|
|
:- import_module string.
|
|
:- import_module term_context.
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
output_llds(ProgressStream, Globals, CFile, Succeeded, !IO) :-
|
|
ModuleName = CFile ^ cfile_modulename,
|
|
% XXX LEGACY
|
|
module_name_to_file_name_create_dirs(Globals, $pred,
|
|
ext_cur_ngs_gs(ext_cur_ngs_gs_target_c), ModuleName,
|
|
FileName, _FileNameProposed, !IO),
|
|
output_to_file_stream(ProgressStream, Globals, FileName,
|
|
output_llds_2(Globals, FileName, CFile), Succeeded, !IO).
|
|
|
|
:- pred output_llds_2(globals::in, file_name::in, c_file::in,
|
|
io.text_output_stream::in, list(string)::out, io::di, io::uo) is det.
|
|
|
|
output_llds_2(Globals, FileName, CFile, Stream, Errors, !IO) :-
|
|
decl_set_init(DeclSet0),
|
|
output_single_c_file(Globals, Stream, FileName, CFile, Errors,
|
|
DeclSet0, _, !IO).
|
|
|
|
:- pred output_single_c_file(globals::in, io.text_output_stream::in,
|
|
file_name::in, c_file::in, list(string)::out,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_single_c_file(Globals, Stream, OutputFileName, CFile, Errors,
|
|
!DeclSet, !IO) :-
|
|
CFile = c_file(ModuleName, C_HeaderLines, ForeignBodyCodes, Exports,
|
|
TablingInfoStructs, ScalarCommonDatas, VectorCommonDatas,
|
|
RttiDatas, PseudoTypeInfos, HLDSVarNums, ShortLocns, LongLocns,
|
|
UserEventVarNums, UserEvents,
|
|
NoVarLabelLayouts, SVarLabelLayouts, LVarLabelLayouts,
|
|
InternalLabelToLayoutMap, EntryLabelToLayoutMap,
|
|
CallSiteStatics, CoveragePoints, ProcStatics,
|
|
ProcHeadVarNums, ProcVarNames, ProcBodyBytecodes, TSStringTable,
|
|
TableIoEntries, TableIoEntryMap, ProcEventLayouts, ExecTraces,
|
|
ProcLayoutDatas, ModuleLayoutDatas, ClosureLayoutDatas,
|
|
AllocSites, AllocSiteMap,
|
|
Modules, UserInitPredCNames, UserFinalPredCNames, ComplexityProcs),
|
|
library.version(Version, Fullarch),
|
|
module_name_to_source_file_name(ModuleName, SourceFileName, !IO),
|
|
output_c_file_intro_and_grade(Globals, Stream, SourceFileName,
|
|
Version, Fullarch, !IO),
|
|
|
|
Info = init_llds_out_info(ModuleName, SourceFileName, OutputFileName,
|
|
Globals, InternalLabelToLayoutMap, EntryLabelToLayoutMap,
|
|
TableIoEntryMap, AllocSiteMap),
|
|
annotate_c_modules(Info, Modules, AnnotatedModules,
|
|
cord.init, EntryLabelsCord, cord.init, InternalLabelsCord,
|
|
set.init, EnvVarNameSet),
|
|
EntryLabels = cord.list(EntryLabelsCord),
|
|
InternalLabels = cord.list(InternalLabelsCord),
|
|
EnvVarNames = set.to_sorted_list(EnvVarNameSet),
|
|
output_init_c_comment(Stream, ModuleName,
|
|
UserInitPredCNames, UserFinalPredCNames, EnvVarNames, !IO),
|
|
output_c_file_mercury_headers(Info, Stream, !IO),
|
|
|
|
output_foreign_header_include_lines(Info, Stream, C_HeaderLines,
|
|
ForeignIncludeResults, !IO),
|
|
io.write_string(Stream, "\n", !IO),
|
|
|
|
output_static_linkage_define(Stream, !IO),
|
|
list.foldl2(output_scalar_common_data_decl(Stream), ScalarCommonDatas,
|
|
!DeclSet, !IO),
|
|
list.foldl2(output_vector_common_data_decl(Stream), VectorCommonDatas,
|
|
!DeclSet, !IO),
|
|
output_rtti_data_decl_list(Info, Stream, RttiDatas, !DeclSet, !IO),
|
|
output_record_c_label_decls(Info, Stream, EntryLabels, InternalLabels,
|
|
!DeclSet, !IO),
|
|
list.foldl2(output_tabling_info_struct(Info, Stream), TablingInfoStructs,
|
|
!DeclSet, !IO),
|
|
list.foldl2(output_scalar_common_data_defn(Info, Stream),
|
|
ScalarCommonDatas, !DeclSet, !IO),
|
|
list.foldl2(output_vector_common_data_defn(Info, Stream),
|
|
VectorCommonDatas, !DeclSet, !IO),
|
|
list.foldl2(output_rtti_data_defn(Info, Stream), RttiDatas, !DeclSet, !IO),
|
|
|
|
io.nl(Stream, !IO),
|
|
output_layout_array_decls(Info, Stream, PseudoTypeInfos, HLDSVarNums,
|
|
ShortLocns, LongLocns, UserEventVarNums, UserEvents,
|
|
NoVarLabelLayouts, SVarLabelLayouts, LVarLabelLayouts,
|
|
CallSiteStatics, CoveragePoints, ProcStatics,
|
|
ProcHeadVarNums, ProcVarNames, ProcBodyBytecodes, TableIoEntries,
|
|
ProcEventLayouts, ExecTraces, AllocSites, !IO),
|
|
|
|
list.foldl2(output_proc_layout_data_defn(Info, Stream),
|
|
ProcLayoutDatas, !DeclSet, !IO),
|
|
list.foldl2(output_module_layout_data_defn(Info, Stream),
|
|
ModuleLayoutDatas, !DeclSet, !IO),
|
|
list.foldl2(output_closure_layout_data_defn(Info, Stream),
|
|
ClosureLayoutDatas, !DeclSet, !IO),
|
|
io.nl(Stream, !IO),
|
|
|
|
output_record_rvals_decls(Info, Stream, PseudoTypeInfos, !DeclSet, !IO),
|
|
output_layout_array_defns(Info, Stream, PseudoTypeInfos, HLDSVarNums,
|
|
ShortLocns, LongLocns, UserEventVarNums, UserEvents,
|
|
NoVarLabelLayouts, SVarLabelLayouts, LVarLabelLayouts,
|
|
CallSiteStatics, CoveragePoints, ProcStatics,
|
|
ProcHeadVarNums, ProcVarNames, ProcBodyBytecodes, TableIoEntries,
|
|
ProcEventLayouts, ExecTraces, TSStringTable, AllocSites,
|
|
!DeclSet, !IO),
|
|
|
|
list.map_foldl(output_foreign_body_code(Info, Stream), ForeignBodyCodes,
|
|
ForeignCodeResults, !IO),
|
|
list.foldl2(output_annotated_c_module(Info, Stream), AnnotatedModules,
|
|
!DeclSet, !IO),
|
|
WriteForeignExportDefn =
|
|
(pred(ForeignExportDefn::in, IO0::di, IO::uo) is det :-
|
|
ForeignExportDefn = foreign_export_defn(ForeignExportCode),
|
|
io.write_string(Stream, ForeignExportCode, IO0, IO)
|
|
),
|
|
list.foldl(WriteForeignExportDefn, Exports, !IO),
|
|
io.write_string(Stream, "\n", !IO),
|
|
output_c_module_init_list(Info, Stream, ModuleName, AnnotatedModules,
|
|
RttiDatas, ProcLayoutDatas, ModuleLayoutDatas, ComplexityProcs,
|
|
TSStringTable, AllocSites, UserInitPredCNames, UserFinalPredCNames,
|
|
!IO),
|
|
|
|
list.filter_map(maybe_is_error, ForeignIncludeResults, ErrorsA),
|
|
list.filter_map(maybe_is_error, ForeignCodeResults, ErrorsB),
|
|
Errors = ErrorsA ++ ErrorsB.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred output_c_file_mercury_headers(llds_out_info::in,
|
|
io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
output_c_file_mercury_headers(Info, Stream, !IO) :-
|
|
io.write_string(Stream, "#define MR_ALLOW_RESET\n", !IO),
|
|
io.write_string(Stream, "#include ""mercury_imp.h""\n", !IO),
|
|
TraceLevel = Info ^ lout_trace_level,
|
|
TraceEnabled = is_exec_trace_enabled_at_given_trace_level(TraceLevel),
|
|
(
|
|
TraceEnabled = exec_trace_is_enabled,
|
|
io.write_string(Stream, "#include ""mercury_trace_base.h""\n", !IO)
|
|
;
|
|
TraceEnabled = exec_trace_is_not_enabled
|
|
),
|
|
DeepProfile = Info ^ lout_profile_deep,
|
|
(
|
|
DeepProfile = yes,
|
|
io.write_string(Stream, "#include ""mercury_deep_profiling.h""\n", !IO)
|
|
;
|
|
DeepProfile = no
|
|
).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
% We need the set of entry and internal labels in a C module in several places
|
|
% for several purposes, so we compute them just once, and record the results.
|
|
%
|
|
% The set of internal labels that the generated C code actually defines
|
|
% will NOT include labels that actually occur in the LLDS code, but which
|
|
% start C loops that, and which are not referred to from anywhere except
|
|
% inside the loop; all those references get translated to C "continue"
|
|
% statements, and the label is optimized away. This is why the computation
|
|
% of the set of internal labels defined by C module must also compute
|
|
% the set of while labels, and undefined while labels. We record the results
|
|
% of this computation in the label_output_info next to the c_procedure.
|
|
|
|
:- type annotated_c_module
|
|
---> annotated_c_module(
|
|
acm_name :: string,
|
|
acm_procs :: list(annotated_c_procedure),
|
|
acm_entry_labels :: list(label),
|
|
acm_internal_labels :: list(label)
|
|
).
|
|
|
|
:- type annotated_c_procedure
|
|
---> annotated_c_procedure(
|
|
acp_proc :: c_procedure,
|
|
acp_label_output_info :: label_output_info
|
|
).
|
|
|
|
:- pred annotate_c_modules(llds_out_info::in,
|
|
list(comp_gen_c_module)::in, list(annotated_c_module)::out,
|
|
cord(label)::in, cord(label)::out, cord(label)::in, cord(label)::out,
|
|
set(string)::in, set(string)::out) is det.
|
|
|
|
annotate_c_modules(_, [], [], !EntryLabels, !InternalLabels, !EnvVarNames).
|
|
annotate_c_modules(Info,
|
|
[Module | Modules], [AnnotatedModule | AnnotatedModules],
|
|
!EntryLabels, !InternalLabels, !EnvVarNames) :-
|
|
annotate_c_module(Info, Module, AnnotatedModule,
|
|
!EntryLabels, !InternalLabels, !EnvVarNames),
|
|
annotate_c_modules(Info, Modules, AnnotatedModules,
|
|
!EntryLabels, !InternalLabels, !EnvVarNames).
|
|
|
|
:- pred annotate_c_module(llds_out_info::in,
|
|
comp_gen_c_module::in, annotated_c_module::out,
|
|
cord(label)::in, cord(label)::out, cord(label)::in, cord(label)::out,
|
|
set(string)::in, set(string)::out) is det.
|
|
|
|
annotate_c_module(Info, Module, AnnotatedModule,
|
|
!AllEntryLabels, !AllInternalLabels, !EnvVarNames) :-
|
|
Module = comp_gen_c_module(ModuleName, Procs),
|
|
annotate_c_procedures(Info, Procs, AnnotatedProcs,
|
|
cord.init, ModuleEntryLabels, cord.init, ModuleInternalLabels,
|
|
!EnvVarNames),
|
|
ModuleEntryLabelList = cord.list(ModuleEntryLabels),
|
|
ModuleInternalLabelList = cord.list(ModuleInternalLabels),
|
|
AnnotatedModule = annotated_c_module(ModuleName, AnnotatedProcs,
|
|
ModuleEntryLabelList, ModuleInternalLabelList),
|
|
!:AllEntryLabels = !.AllEntryLabels ++ ModuleEntryLabels,
|
|
!:AllInternalLabels = !.AllInternalLabels ++ ModuleInternalLabels.
|
|
|
|
:- pred annotate_c_procedures(llds_out_info::in,
|
|
list(c_procedure)::in, list(annotated_c_procedure)::out,
|
|
cord(label)::in, cord(label)::out, cord(label)::in, cord(label)::out,
|
|
set(string)::in, set(string)::out) is det.
|
|
|
|
annotate_c_procedures(_, [], [],
|
|
!AllEntryLabels, !AllInternalLabels, !EnvVarNames).
|
|
annotate_c_procedures(Info, [Proc | Procs], [AnnotatedProc | AnnotatedProcs],
|
|
!AllEntryLabels, !AllInternalLabels, !EnvVarNames) :-
|
|
annotate_c_procedure(Info, Proc, AnnotatedProc,
|
|
!AllEntryLabels, !AllInternalLabels, !EnvVarNames),
|
|
annotate_c_procedures(Info, Procs, AnnotatedProcs,
|
|
!AllEntryLabels, !AllInternalLabels, !EnvVarNames).
|
|
|
|
:- pred annotate_c_procedure(llds_out_info::in,
|
|
c_procedure::in, annotated_c_procedure::out,
|
|
cord(label)::in, cord(label)::out, cord(label)::in, cord(label)::out,
|
|
set(string)::in, set(string)::out) is det.
|
|
|
|
annotate_c_procedure(Info, Proc, AnnotatedProc,
|
|
!AllEntryLabels, !AllInternalLabels, !EnvVarNames) :-
|
|
ProcEnvVarNames = Proc ^ cproc_c_global_vars,
|
|
set.union(ProcEnvVarNames, !EnvVarNames),
|
|
|
|
Instrs = Proc ^ cproc_code,
|
|
gather_labels_from_instrs_acc(Instrs,
|
|
[], RevEntryLabels, [], RevInternalLabels0),
|
|
list.reverse(RevEntryLabels, EntryLabels),
|
|
list.reverse(RevInternalLabels0, InternalLabels0),
|
|
|
|
find_caller_label(Instrs, CallerLabel),
|
|
find_cont_labels(Instrs, set_tree234.init, ContLabels),
|
|
EmitCLoops = Info ^ lout_emit_c_loops,
|
|
(
|
|
EmitCLoops = do_not_emit_c_loops,
|
|
WhileLabels = set_tree234.init,
|
|
UndefWhileLabels = set_tree234.init
|
|
;
|
|
EmitCLoops = emit_c_loops,
|
|
find_while_labels(Instrs, set_tree234.init, WhileLabels),
|
|
|
|
% We compute UndefWhileLabels by starting with an overapproximation,
|
|
% which we then whittle down in two steps. Each whittling step
|
|
% removes from our initial UndefWhileLabels set some labels that
|
|
% actually do need to be defined.
|
|
%
|
|
% Step 1: if a label is in ContLabels, we cannot avoid defining it.
|
|
set_tree234.difference(WhileLabels, ContLabels, UndefWhileLabels0),
|
|
( if set_tree234.is_empty(UndefWhileLabels0) then
|
|
UndefWhileLabels = UndefWhileLabels0
|
|
else
|
|
% Step 2: if a label that starts a while loop is branched to
|
|
% from outside the while loop it starts, we cannot avoid
|
|
% defining it.
|
|
find_while_labels_to_define(Instrs, no, WhileLabels,
|
|
UndefWhileLabels0, UndefWhileLabels)
|
|
)
|
|
),
|
|
LabelOutputInfo = label_output_info(CallerLabel, ContLabels,
|
|
WhileLabels, UndefWhileLabels),
|
|
( if set_tree234.is_empty(UndefWhileLabels) then
|
|
InternalLabels = InternalLabels0
|
|
else
|
|
list.negated_filter(set_tree234.contains(UndefWhileLabels),
|
|
InternalLabels0, InternalLabels)
|
|
),
|
|
AnnotatedProc = annotated_c_procedure(Proc, LabelOutputInfo),
|
|
|
|
cord.snoc_list(EntryLabels, !AllEntryLabels),
|
|
!:AllInternalLabels = !.AllInternalLabels ++
|
|
cord.from_list(InternalLabels).
|
|
|
|
:- pred gather_labels_from_instrs_acc(list(instruction)::in,
|
|
list(label)::in, list(label)::out,
|
|
list(label)::in, list(label)::out) is det.
|
|
|
|
gather_labels_from_instrs_acc([], !RevEntryLabels, !RevInternalLabels).
|
|
gather_labels_from_instrs_acc([Instr | Instrs],
|
|
!RevEntryLabels, !RevInternalLabels) :-
|
|
( if Instr = llds_instr(label(Label), _) then
|
|
(
|
|
Label = entry_label(_, _),
|
|
!:RevEntryLabels = [Label | !.RevEntryLabels]
|
|
;
|
|
Label = internal_label(_, _),
|
|
!:RevInternalLabels = [Label | !.RevInternalLabels]
|
|
)
|
|
else
|
|
true
|
|
),
|
|
gather_labels_from_instrs_acc(Instrs,
|
|
!RevEntryLabels, !RevInternalLabels).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_c_module_init_list(llds_out_info::in,
|
|
io.text_output_stream::in, module_name::in,
|
|
list(annotated_c_module)::in, list(rtti_data)::in,
|
|
list(proc_layout_data)::in, list(module_layout_data)::in,
|
|
list(complexity_proc_info)::in, list(string)::in,
|
|
list(alloc_site_info)::in, list(string)::in, list(string)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_c_module_init_list(Info, Stream, ModuleName, AnnotatedModules,
|
|
RttiDatas, ProcLayoutDatas, ModuleLayoutDatas, ComplexityProcs,
|
|
TSStringTable, AllocSites, InitPredNames, FinalPredNames, !IO) :-
|
|
MustInit =
|
|
( pred(Module::in) is semidet :-
|
|
module_defines_label_with_layout(Info, Module)
|
|
),
|
|
list.filter(MustInit, AnnotatedModules,
|
|
AlwaysInitAnnotatedModules, MaybeInitAnnotatedModules),
|
|
list.chunk(AlwaysInitAnnotatedModules, 40,
|
|
AlwaysInitAnnotatedModuleBunches),
|
|
list.chunk(MaybeInitAnnotatedModules, 40,
|
|
MaybeInitAnnotatedModuleBunches),
|
|
|
|
output_init_bunch_defs(Info, Stream, "always", 0,
|
|
AlwaysInitAnnotatedModuleBunches, !IO),
|
|
(
|
|
MaybeInitAnnotatedModuleBunches = []
|
|
;
|
|
MaybeInitAnnotatedModuleBunches = [_ | _],
|
|
output_init_bunch_defs(Info, Stream, "maybe", 0,
|
|
MaybeInitAnnotatedModuleBunches, !IO)
|
|
),
|
|
|
|
ModuleInitName = make_init_name(ModuleName),
|
|
|
|
io.write_string(Stream,
|
|
"/* suppress gcc -Wmissing-decls warnings */\n", !IO),
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init(void);\n", !IO),
|
|
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_type_tables(void);\n", !IO),
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_debugger(void);\n", !IO),
|
|
|
|
io.write_string(Stream, "#ifdef MR_DEEP_PROFILING\n", !IO),
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream,
|
|
"write_out_proc_statics(FILE *deep_fp, FILE *procrep_fp);\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO),
|
|
|
|
io.write_string(Stream, "#ifdef MR_RECORD_TERM_SIZES\n", !IO),
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_complexity_procs(void);\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO),
|
|
|
|
io.write_string(Stream, "#ifdef MR_THREADSCOPE\n", !IO),
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_threadscope_string_table(void);\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO),
|
|
|
|
(
|
|
InitPredNames = []
|
|
;
|
|
InitPredNames = [_ | _],
|
|
io.format(Stream, "void %srequired_init(void);\n",
|
|
[s(ModuleInitName)], !IO)
|
|
),
|
|
|
|
(
|
|
FinalPredNames = []
|
|
;
|
|
FinalPredNames = [_ | _],
|
|
io.format(Stream, "void %srequired_final(void);\n",
|
|
[s(ModuleInitName)], !IO)
|
|
),
|
|
|
|
io.format(Stream, "const char *%sgrade_check(void);\n",
|
|
[s(ModuleInitName)], !IO),
|
|
|
|
io.write_string(Stream, "\n", !IO),
|
|
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
io.write_string(Stream, "\tstatic MR_bool done = MR_FALSE;\n", !IO),
|
|
io.write_string(Stream, "\tif (done) {\n", !IO),
|
|
io.write_string(Stream, "\t\treturn;\n", !IO),
|
|
io.write_string(Stream, "\t}\n", !IO),
|
|
io.write_string(Stream, "\tdone = MR_TRUE;\n", !IO),
|
|
|
|
output_init_bunch_calls(Info, Stream, "always", 0,
|
|
AlwaysInitAnnotatedModuleBunches, !IO),
|
|
(
|
|
MaybeInitAnnotatedModuleBunches = []
|
|
;
|
|
MaybeInitAnnotatedModuleBunches = [_ | _],
|
|
output_init_bunch_calls(Info, Stream, "maybe", 0,
|
|
MaybeInitAnnotatedModuleBunches, !IO)
|
|
),
|
|
|
|
output_c_data_init_list(Stream, RttiDatas, !IO),
|
|
output_alloc_sites_init(Info, Stream, AllocSites, !IO),
|
|
|
|
% The call to the debugger initialization function is for bootstrapping;
|
|
% once the debugger has been modified to call do_init_modules_debugger()
|
|
% and all debuggable object files created before this change have been
|
|
% overwritten, it can be deleted.
|
|
io.write_string(Stream, "\t", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_debugger();\n", !IO),
|
|
io.write_string(Stream, "}\n\n", !IO),
|
|
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_type_tables(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
io.write_string(Stream, "\tstatic MR_bool done = MR_FALSE;\n", !IO),
|
|
io.write_string(Stream, "\tif (done) {\n", !IO),
|
|
io.write_string(Stream, "\t\treturn;\n", !IO),
|
|
io.write_string(Stream, "\t}\n", !IO),
|
|
io.write_string(Stream, "\tdone = MR_TRUE;\n", !IO),
|
|
output_type_tables_init_list(Stream, RttiDatas, !IO),
|
|
io.write_string(Stream, "}\n\n", !IO),
|
|
|
|
io.write_string(Stream, "\n", !IO),
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_debugger(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
io.write_string(Stream, "\tstatic MR_bool done = MR_FALSE;\n", !IO),
|
|
io.write_string(Stream, "\tif (done) {\n", !IO),
|
|
io.write_string(Stream, "\t\treturn;\n", !IO),
|
|
io.write_string(Stream, "\t}\n", !IO),
|
|
io.write_string(Stream, "\tdone = MR_TRUE;\n", !IO),
|
|
output_debugger_init_list(Stream, ModuleLayoutDatas, !IO),
|
|
io.write_string(Stream, "}\n\n", !IO),
|
|
|
|
io.write_string(Stream, "#ifdef MR_DEEP_PROFILING\n", !IO),
|
|
io.write_string(Stream, "\nvoid ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream,
|
|
"write_out_proc_statics(FILE *deep_fp, FILE *procrep_fp)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
io.write_string(Stream,
|
|
"\tMR_write_out_module_proc_reps_start(procrep_fp, &", !IO),
|
|
ModuleLayoutName = module_layout(ModuleName),
|
|
output_layout_name(Stream, ModuleLayoutName, !IO),
|
|
io.write_string(Stream, ");\n", !IO),
|
|
output_write_proc_static_list(Stream, ProcLayoutDatas, !IO),
|
|
io.write_string(Stream,
|
|
"\tMR_write_out_module_proc_reps_end(procrep_fp);\n", !IO),
|
|
io.write_string(Stream, "}\n", !IO),
|
|
io.write_string(Stream, "\n#endif\n\n", !IO),
|
|
|
|
io.write_string(Stream, "#ifdef MR_RECORD_TERM_SIZES\n", !IO),
|
|
output_complexity_arg_info_arrays(Stream, ComplexityProcs, !IO),
|
|
io.write_string(Stream, "\nvoid ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_complexity_procs(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
output_init_complexity_proc_list(Stream, ComplexityProcs, !IO),
|
|
io.write_string(Stream, "}\n", !IO),
|
|
io.write_string(Stream, "\n#endif\n\n", !IO),
|
|
|
|
io.write_string(Stream, "#ifdef MR_THREADSCOPE\n", !IO),
|
|
io.write_string(Stream, "\nvoid ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "init_threadscope_string_table(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
(
|
|
TSStringTable = []
|
|
;
|
|
TSStringTable = [_ | _],
|
|
TSStringTableSize = length(TSStringTable),
|
|
io.write_string(Stream,
|
|
"\tMR_threadscope_register_strings_array(\n", !IO),
|
|
io.write_string(Stream, "\t\t", !IO),
|
|
MangledModuleName = Info ^ lout_mangled_module_name,
|
|
output_layout_array_name(Stream, use_layout_macro, MangledModuleName,
|
|
threadscope_string_table_array, !IO),
|
|
io.format(Stream, ", %d);\n", [i(TSStringTableSize)], !IO)
|
|
),
|
|
io.write_string(Stream, "}\n", !IO),
|
|
io.write_string(Stream, "\n#endif\n\n", !IO),
|
|
|
|
(
|
|
InitPredNames = []
|
|
;
|
|
InitPredNames = [_ | _],
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "required_init(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
output_required_init_or_final_calls(Stream, InitPredNames, !IO),
|
|
io.write_string(Stream, "}\n", !IO),
|
|
io.nl(Stream, !IO)
|
|
),
|
|
|
|
(
|
|
FinalPredNames = []
|
|
;
|
|
FinalPredNames = [_ | _],
|
|
io.write_string(Stream, "void ", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "required_final(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
output_required_init_or_final_calls(Stream, FinalPredNames, !IO),
|
|
io.write_string(Stream, "}\n", !IO),
|
|
io.nl(Stream, !IO)
|
|
),
|
|
|
|
io.write_string(Stream,
|
|
"// Ensure everything is compiled with the same grade.\n", !IO),
|
|
io.write_string(Stream, "const char *", !IO),
|
|
io.write_string(Stream, ModuleInitName, !IO),
|
|
io.write_string(Stream, "grade_check(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
io.write_string(Stream, " return &MR_GRADE_VAR;\n", !IO),
|
|
io.write_string(Stream, "}\n", !IO).
|
|
|
|
:- pred module_defines_label_with_layout(llds_out_info::in,
|
|
annotated_c_module::in) is semidet.
|
|
|
|
module_defines_label_with_layout(Info, AnnotatedModule) :-
|
|
AnnotatedModule = annotated_c_module(_, _, EntryLabels, InternalLabels),
|
|
% If a map is empty, there is no point in using it as a filter,
|
|
% and we can save ourselves the cost of a list traversal; we know
|
|
% the traversal wouldn't be able to find anything.
|
|
(
|
|
InternalLabelToLayoutMap = Info ^ lout_internal_label_to_layout,
|
|
\+ map.is_empty(InternalLabelToLayoutMap),
|
|
find_first_match(internal_label_has_layout(InternalLabelToLayoutMap),
|
|
InternalLabels, _)
|
|
;
|
|
EntryLabelToLayoutMap = Info ^ lout_entry_label_to_layout,
|
|
\+ map.is_empty(EntryLabelToLayoutMap),
|
|
find_first_match(entry_label_has_layout(EntryLabelToLayoutMap),
|
|
EntryLabels, _)
|
|
).
|
|
|
|
:- pred internal_label_has_layout(map(label, layout_slot_name)::in, label::in)
|
|
is semidet.
|
|
|
|
internal_label_has_layout(InternalLabelToLayoutMap, Label) :-
|
|
map.search(InternalLabelToLayoutMap, Label, _).
|
|
|
|
:- pred entry_label_has_layout(map(label, data_id)::in, label::in)
|
|
is semidet.
|
|
|
|
entry_label_has_layout(EntryLabelToLayoutMap, Label) :-
|
|
map.search(EntryLabelToLayoutMap, Label, _).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_init_bunch_defs(llds_out_info::in, io.text_output_stream::in,
|
|
string::in, int::in, list(list(annotated_c_module))::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_init_bunch_defs(_, _, _, _, [], !IO).
|
|
output_init_bunch_defs(Info, Stream, InitStatus, Seq,
|
|
[Bunch | Bunches], !IO) :-
|
|
io.write_string(Stream, "static void ", !IO),
|
|
output_bunch_name(Info, Stream, InitStatus, Seq, !IO),
|
|
io.write_string(Stream, "(void)\n", !IO),
|
|
io.write_string(Stream, "{\n", !IO),
|
|
output_init_bunch_def(Stream, Bunch, !IO),
|
|
io.write_string(Stream, "}\n\n", !IO),
|
|
NextSeq = Seq + 1,
|
|
output_init_bunch_defs(Info, Stream, InitStatus, NextSeq, Bunches, !IO).
|
|
|
|
:- pred output_init_bunch_def(io.text_output_stream::in,
|
|
list(annotated_c_module)::in, io::di, io::uo) is det.
|
|
|
|
output_init_bunch_def(_, [], !IO).
|
|
output_init_bunch_def(Stream, [AnnotatedModule | AnnotatedModules], !IO) :-
|
|
C_ModuleName = AnnotatedModule ^ acm_name,
|
|
io.format(Stream, "\t%s();\n", [s(C_ModuleName)], !IO),
|
|
output_init_bunch_def(Stream, AnnotatedModules, !IO).
|
|
|
|
:- pred output_init_bunch_calls(llds_out_info::in, io.text_output_stream::in,
|
|
string::in, int::in, list(list(annotated_c_module))::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_init_bunch_calls(_, _, _, _, [], !IO).
|
|
output_init_bunch_calls(Info, Stream, InitStatus, Seq, [_ | Bunches], !IO) :-
|
|
io.write_string(Stream, "\t", !IO),
|
|
output_bunch_name(Info, Stream, InitStatus, Seq, !IO),
|
|
io.write_string(Stream, "();\n", !IO),
|
|
NextSeq = Seq + 1,
|
|
output_init_bunch_calls(Info, Stream, InitStatus, NextSeq, Bunches, !IO).
|
|
|
|
:- pred output_bunch_name(llds_out_info::in, io.text_output_stream::in,
|
|
string::in, int::in, io::di, io::uo) is det.
|
|
|
|
output_bunch_name(Info, Stream, InitStatus, Number, !IO) :-
|
|
io.write_string(Stream, "mercury__", !IO),
|
|
MangledModuleName = Info ^ lout_mangled_module_name,
|
|
io.format(Stream, "%s_%s_bunch_%d",
|
|
[s(MangledModuleName), s(InitStatus), i(Number)], !IO).
|
|
|
|
% Output MR_INIT_TYPE_CTOR_INFO(TypeCtorInfo, Typector);
|
|
% for each type_ctor_info defined in this module.
|
|
%
|
|
:- pred output_c_data_init_list(io.text_output_stream::in,
|
|
list(rtti_data)::in, io::di, io::uo) is det.
|
|
|
|
output_c_data_init_list(_, [], !IO).
|
|
output_c_data_init_list(Stream, [Data | Datas], !IO) :-
|
|
rtti_out.init_rtti_data_if_nec(Stream, Data, !IO),
|
|
output_c_data_init_list(Stream, Datas, !IO).
|
|
|
|
% Output code to register the allocation sites defined in this module.
|
|
%
|
|
:- pred output_alloc_sites_init(llds_out_info::in, io.text_output_stream::in,
|
|
list(alloc_site_info)::in, io::di, io::uo) is det.
|
|
|
|
output_alloc_sites_init(Info, Stream, AllocSites, !IO) :-
|
|
(
|
|
AllocSites = []
|
|
;
|
|
AllocSites = [_ | _],
|
|
MangledModuleName = Info ^ lout_mangled_module_name,
|
|
NumAllocSites = list.length(AllocSites),
|
|
io.write_string(Stream,
|
|
"#ifdef MR_MPROF_PROFILE_MEMORY_ATTRIBUTION\n", !IO),
|
|
io.write_string(Stream, "\tMR_register_alloc_sites(", !IO),
|
|
output_layout_array_name(Stream, do_not_use_layout_macro,
|
|
MangledModuleName, alloc_site_array, !IO),
|
|
io.write_string(Stream, ", ", !IO),
|
|
io.write_int(Stream, NumAllocSites, !IO),
|
|
io.write_string(Stream, ");\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO)
|
|
).
|
|
|
|
% Output code to register each type_ctor_info defined in this module.
|
|
%
|
|
:- pred output_type_tables_init_list(io.text_output_stream::in,
|
|
list(rtti_data)::in, io::di, io::uo) is det.
|
|
|
|
output_type_tables_init_list(_, [], !IO).
|
|
output_type_tables_init_list(Stream, [Data | Datas], !IO) :-
|
|
rtti_out.register_rtti_data_if_nec(Stream, Data, !IO),
|
|
output_type_tables_init_list(Stream, Datas, !IO).
|
|
|
|
% Output calls to MR_register_module_layout()
|
|
% for each module layout defined in this module
|
|
% (there should only be one, of course).
|
|
%
|
|
:- pred output_debugger_init_list(io.text_output_stream::in,
|
|
list(module_layout_data)::in, io::di, io::uo) is det.
|
|
|
|
output_debugger_init_list(_, [], !IO).
|
|
output_debugger_init_list(Stream, [Data | Datas], !IO) :-
|
|
Data = module_layout_data(ModuleName, _, _, _, _),
|
|
io.write_string(Stream,
|
|
"\tif (MR_register_module_layout != NULL) {\n", !IO),
|
|
io.write_string(Stream, "\t\t(*MR_register_module_layout)(", !IO),
|
|
io.write_string(Stream, "\n\t\t\t&", !IO),
|
|
output_layout_name(Stream, module_layout(ModuleName), !IO),
|
|
io.write_string(Stream, ");\n\t}\n", !IO),
|
|
output_debugger_init_list(Stream, Datas, !IO).
|
|
|
|
:- pred output_write_proc_static_list(io.text_output_stream::in,
|
|
list(proc_layout_data)::in, io::di, io::uo) is det.
|
|
|
|
output_write_proc_static_list(_, [], !IO).
|
|
output_write_proc_static_list(Stream, [ProcLayout | ProcLayouts], !IO) :-
|
|
ProcLayout = proc_layout_data(RttiProcLabel, _, MaybeMore),
|
|
( if MaybeMore = proc_id_and_more(yes(_ProcStatic), _, _, _) then
|
|
ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
|
|
UserOrUCI = proc_label_user_or_uci(ProcLabel),
|
|
Kind = proc_layout_proc_id(UserOrUCI),
|
|
(
|
|
UserOrUCI = user,
|
|
io.write_string(Stream,
|
|
"\tMR_write_out_user_proc_static(deep_fp, procrep_fp,\n\t\t&",
|
|
!IO)
|
|
;
|
|
UserOrUCI = uci,
|
|
io.write_string(Stream,
|
|
"\tMR_write_out_uci_proc_static(deep_fp, procrep_fp,\n\t\t&",
|
|
!IO)
|
|
),
|
|
output_layout_name(Stream, proc_layout(RttiProcLabel, Kind), !IO),
|
|
io.write_string(Stream, ");\n", !IO)
|
|
else
|
|
true
|
|
),
|
|
output_write_proc_static_list(Stream, ProcLayouts, !IO).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_required_init_or_final_calls(io.text_output_stream::in,
|
|
list(string)::in, io::di, io::uo) is det.
|
|
|
|
output_required_init_or_final_calls(_, [], !IO).
|
|
output_required_init_or_final_calls(Stream, [Name | Names], !IO) :-
|
|
io.format(Stream, "\t%s();\n", [s(Name)], !IO),
|
|
output_required_init_or_final_calls(Stream, Names, !IO).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_annotated_c_module(llds_out_info::in, io.text_output_stream::in,
|
|
annotated_c_module::in, decl_set::in, decl_set::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_annotated_c_module(Info, Stream, AnnotatedModule, !DeclSet, !IO) :-
|
|
AnnotatedModule = annotated_c_module(ModuleName, AnnotatedProcedures,
|
|
EntryLabels, InternalLabels),
|
|
io.write_string(Stream, "\n", !IO),
|
|
list.foldl2(output_record_c_procedure_decls(Info, Stream),
|
|
AnnotatedProcedures, !DeclSet, !IO),
|
|
io.write_string(Stream, "\n", !IO),
|
|
io.write_string(Stream, "MR_BEGIN_MODULE(", !IO),
|
|
io.write_string(Stream, ModuleName, !IO),
|
|
io.write_string(Stream, ")\n", !IO),
|
|
output_c_label_inits(Info, Stream, EntryLabels, InternalLabels, !IO),
|
|
io.write_string(Stream, "MR_BEGIN_CODE\n", !IO),
|
|
list.foldl(output_annotated_c_procedure(Info, Stream),
|
|
AnnotatedProcedures, !IO),
|
|
io.write_string(Stream, "MR_END_MODULE\n", !IO).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_static_linkage_define(io.text_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_static_linkage_define(Stream, !IO) :-
|
|
% The MS Visual C compiler treats the following declarations as
|
|
% definitions, for which it cannot determine the size and hence aborts:
|
|
% static const struct s_name typename[];
|
|
% However if we mark the linkage as extern, it treats it as a declaration.
|
|
io.write_string(Stream, "#ifdef _MSC_VER\n", !IO),
|
|
io.write_string(Stream, "#define MR_STATIC_LINKAGE extern\n", !IO),
|
|
io.write_string(Stream, "#else\n", !IO),
|
|
io.write_string(Stream, "#define MR_STATIC_LINKAGE static\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_foreign_body_code(llds_out_info::in, io.text_output_stream::in,
|
|
foreign_body_code::in, maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_foreign_body_code(Info, Stream, ForeignBodyCode, Res, !IO) :-
|
|
ForeignBodyCode = foreign_body_code(Lang, LiteralOrInclude, Context),
|
|
(
|
|
Lang = lang_c,
|
|
output_foreign_decl_or_code(Info, Stream, "foreign_code", Lang,
|
|
LiteralOrInclude, Context, Res, !IO)
|
|
;
|
|
( Lang = lang_java
|
|
; Lang = lang_csharp
|
|
),
|
|
unexpected($pred, "unimplemented: foreign code other than C")
|
|
).
|
|
|
|
:- pred output_foreign_header_include_lines(llds_out_info::in,
|
|
io.text_output_stream::in, list(foreign_decl_code)::in,
|
|
list(maybe_error)::out, io::di, io::uo) is det.
|
|
|
|
output_foreign_header_include_lines(Info, Stream, Decls, Results, !IO) :-
|
|
list.map_foldl2(output_foreign_header_include_line(Info, Stream),
|
|
Decls, Results, set.init, _, !IO).
|
|
|
|
:- pred output_foreign_header_include_line(llds_out_info::in,
|
|
io.text_output_stream::in, foreign_decl_code::in, maybe_error::out,
|
|
set(foreign_literal_or_include)::in, set(foreign_literal_or_include)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_foreign_header_include_line(Info, Stream, Decl, Res,
|
|
!AlreadyDone, !IO) :-
|
|
Decl = foreign_decl_code(Lang, _IsLocal, LiteralOrInclude, Context),
|
|
(
|
|
Lang = lang_c,
|
|
% This will not deduplicate the content of included files.
|
|
( if set.insert_new(LiteralOrInclude, !AlreadyDone) then
|
|
output_foreign_decl_or_code(Info, Stream, "foreign_decl", Lang,
|
|
LiteralOrInclude, Context, Res, !IO)
|
|
else
|
|
Res = ok
|
|
)
|
|
;
|
|
( Lang = lang_java
|
|
; Lang = lang_csharp
|
|
),
|
|
unexpected($pred, "foreign decl code other than C")
|
|
).
|
|
|
|
:- pred output_foreign_decl_or_code(llds_out_info::in,
|
|
io.text_output_stream::in, string::in, foreign_language::in,
|
|
foreign_literal_or_include::in, prog_context::in,
|
|
maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_foreign_decl_or_code(Info, Stream, PragmaType, Lang, LiteralOrInclude,
|
|
Context, Result, !IO) :-
|
|
AutoComments = Info ^ lout_auto_comments,
|
|
ForeignLineNumbers = Info ^ lout_foreign_line_numbers,
|
|
( if
|
|
AutoComments = auto_comments,
|
|
ForeignLineNumbers = yes
|
|
then
|
|
ContextStr = context_to_string(Context),
|
|
LangStr = string.string(Lang),
|
|
io.format(Stream, "/* %s pragma %s(%s) */\n",
|
|
[s(ContextStr), s(PragmaType), s(LangStr)], !IO)
|
|
else
|
|
true
|
|
),
|
|
(
|
|
LiteralOrInclude = floi_literal(Code),
|
|
output_set_line_num(Stream, ForeignLineNumbers, Context, !IO),
|
|
io.write_string(Stream, Code, !IO),
|
|
Result = ok
|
|
;
|
|
LiteralOrInclude = floi_include_file(IncludeFileName),
|
|
SourceFileName = Info ^ lout_source_file_name,
|
|
make_include_file_path(SourceFileName, IncludeFileName, IncludePath),
|
|
output_set_line_num(Stream, ForeignLineNumbers,
|
|
context(IncludePath, 1), !IO),
|
|
Globals = Info ^ lout_globals,
|
|
write_include_file_contents(Stream, Globals, IncludePath, Result, !IO)
|
|
),
|
|
io.nl(Stream, !IO),
|
|
OutputFileName = Info ^ lout_output_file_name,
|
|
output_reset_line_num(Stream, ForeignLineNumbers, OutputFileName, !IO).
|
|
|
|
:- pred output_record_c_label_decls(llds_out_info::in,
|
|
io.text_output_stream::in, list(label)::in, list(label)::in,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_record_c_label_decls(Info, Stream, EntryLabels, InternalLabels,
|
|
!DeclSet, !IO) :-
|
|
group_decl_c_labels(InternalLabels, multi_map.init, InternalLabelMap),
|
|
multi_map.to_assoc_list(InternalLabelMap, InternalLabelList),
|
|
list.foldl2(output_record_internal_label_decls(Stream), InternalLabelList,
|
|
!DeclSet, !IO),
|
|
list.foldl2(output_record_entry_label_decl(Info, Stream), EntryLabels,
|
|
!DeclSet, !IO).
|
|
|
|
:- pred group_decl_c_labels(list(label)::in,
|
|
multi_map(proc_label, int)::in, multi_map(proc_label, int)::out) is det.
|
|
|
|
group_decl_c_labels([], !InternalLabelMap).
|
|
group_decl_c_labels([Label | Labels], !InternalLabelMap) :-
|
|
(
|
|
Label = internal_label(LabelNum, ProcLabel),
|
|
multi_map.set(ProcLabel, LabelNum, !InternalLabelMap)
|
|
;
|
|
Label = entry_label(_, _),
|
|
unexpected($pred, "entry label")
|
|
),
|
|
group_decl_c_labels(Labels, !InternalLabelMap).
|
|
|
|
:- pred output_record_internal_label_decls(io.text_output_stream::in,
|
|
pair(proc_label, list(int))::in,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_record_internal_label_decls(Stream, ProcLabel - RevLabelNums,
|
|
!DeclSet, !IO) :-
|
|
list.reverse(RevLabelNums, LabelNums),
|
|
% There must be a macro of the form MR_decl_label<n> for every <n>
|
|
% up to MaxChunkSize.
|
|
MaxChunkSize = 10,
|
|
list.chunk(LabelNums, MaxChunkSize, LabelNumChunks),
|
|
list.foldl2(output_record_internal_label_decl_group(Stream, ProcLabel),
|
|
LabelNumChunks, !DeclSet, !IO),
|
|
list.foldl(insert_internal_label_code_addr_decl(ProcLabel), LabelNums,
|
|
!DeclSet).
|
|
|
|
:- pred output_record_internal_label_decl_group(io.text_output_stream::in,
|
|
proc_label::in, list(int)::in,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_record_internal_label_decl_group(Stream, ProcLabel, LabelNums,
|
|
!DeclSet, !IO) :-
|
|
io.format(Stream, "MR_decl_label%d(%s, ",
|
|
[i(list.length(LabelNums)),
|
|
s(proc_label_to_c_string(do_not_add_label_prefix, ProcLabel))], !IO),
|
|
write_out_list(add_int, ",", LabelNums, Stream, !IO),
|
|
io.write_string(Stream, ")\n", !IO),
|
|
list.foldl(insert_internal_label_code_addr_decl(ProcLabel), LabelNums,
|
|
!DeclSet).
|
|
|
|
:- pred insert_internal_label_code_addr_decl(proc_label::in, int::in,
|
|
decl_set::in, decl_set::out) is det.
|
|
|
|
insert_internal_label_code_addr_decl(ProcLabel, LabelNum, !DeclSet) :-
|
|
DeclId = decl_code_addr(code_label(internal_label(LabelNum, ProcLabel))),
|
|
decl_set_insert(DeclId, !DeclSet).
|
|
|
|
:- pred output_record_entry_label_decl(llds_out_info::in,
|
|
io.text_output_stream::in, label::in,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_record_entry_label_decl(_Info, Stream, Label, !DeclSet, !IO) :-
|
|
(
|
|
Label = entry_label(entry_label_exported, _),
|
|
DeclMacro = "MR_def_extern_entry"
|
|
;
|
|
Label = entry_label(entry_label_local, _),
|
|
DeclMacro = "MR_decl_static"
|
|
;
|
|
Label = entry_label(entry_label_c_local, _),
|
|
DeclMacro = "MR_decl_local"
|
|
;
|
|
Label = internal_label(_, _),
|
|
unexpected($pred, "internal label")
|
|
),
|
|
io.write_string(Stream, DeclMacro, !IO),
|
|
io.write_string(Stream, "(", !IO),
|
|
output_label_no_prefix(Stream, Label, !IO),
|
|
io.write_string(Stream, ")\n", !IO),
|
|
decl_set_insert(decl_code_addr(code_label(Label)), !DeclSet).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_c_label_inits(llds_out_info::in, io.text_output_stream::in,
|
|
list(label)::in, list(label)::in, io::di, io::uo) is det.
|
|
|
|
output_c_label_inits(Info, Stream, EntryLabels, InternalLabels, !IO) :-
|
|
EntryLabelToLayoutMap = Info ^ lout_entry_label_to_layout,
|
|
list.foldl(output_c_entry_label_init(Stream, EntryLabelToLayoutMap),
|
|
EntryLabels, !IO),
|
|
|
|
InternalLabelToLayoutMap = Info ^ lout_internal_label_to_layout,
|
|
group_init_c_labels(InternalLabelToLayoutMap, InternalLabels,
|
|
multi_map.init, NoLayoutInternalMap,
|
|
multi_map.init, NoVarLayoutInternalMap,
|
|
multi_map.init, SVarLayoutInternalMap,
|
|
multi_map.init, LVarLayoutInternalMap),
|
|
|
|
multi_map.to_assoc_list(NoLayoutInternalMap, NoLayoutInternalList),
|
|
list.foldl(output_c_internal_label_no_layout_init_group(Stream),
|
|
NoLayoutInternalList, !IO),
|
|
|
|
multi_map.to_assoc_list(NoVarLayoutInternalMap, NoVarLayoutInternalList),
|
|
list.foldl(output_c_internal_label_layout_init_group(Info, Stream, "_nvi"),
|
|
NoVarLayoutInternalList, !IO),
|
|
|
|
multi_map.to_assoc_list(SVarLayoutInternalMap, SVarLayoutInternalList),
|
|
list.foldl(output_c_internal_label_layout_init_group(Info, Stream, "_svi"),
|
|
SVarLayoutInternalList, !IO),
|
|
|
|
multi_map.to_assoc_list(LVarLayoutInternalMap, LVarLayoutInternalList),
|
|
list.foldl(output_c_internal_label_layout_init_group(Info, Stream, "_lvi"),
|
|
LVarLayoutInternalList, !IO).
|
|
|
|
:- pred group_init_c_labels(map(label, layout_slot_name)::in, list(label)::in,
|
|
multi_map(proc_label, int)::in, multi_map(proc_label, int)::out,
|
|
multi_map(proc_label, {int, int})::in,
|
|
multi_map(proc_label, {int, int})::out,
|
|
multi_map(proc_label, {int, int})::in,
|
|
multi_map(proc_label, {int, int})::out,
|
|
multi_map(proc_label, {int, int})::in,
|
|
multi_map(proc_label, {int, int})::out) is det.
|
|
|
|
group_init_c_labels(_InternalLabelToLayoutMap, [],
|
|
!NoLayoutMap, !NoVarLayoutMap, !SVarLayoutMap, !LVarLayoutMap).
|
|
group_init_c_labels(InternalLabelToLayoutMap, [Label | Labels],
|
|
!NoLayoutMap, !NoVarLayoutMap, !SVarLayoutMap, !LVarLayoutMap) :-
|
|
(
|
|
Label = internal_label(LabelNum, ProcLabel),
|
|
( if map.search(InternalLabelToLayoutMap, Label, Slot) then
|
|
Slot = layout_slot(ArrayName, SlotNum),
|
|
( if ArrayName = label_layout_array(Vars) then
|
|
Pair = {LabelNum, SlotNum},
|
|
(
|
|
Vars = label_has_no_var_info,
|
|
multi_map.set(ProcLabel, Pair, !NoVarLayoutMap)
|
|
;
|
|
Vars = label_has_short_var_info,
|
|
multi_map.set(ProcLabel, Pair, !SVarLayoutMap)
|
|
;
|
|
Vars = label_has_long_var_info,
|
|
multi_map.set(ProcLabel, Pair, !LVarLayoutMap)
|
|
)
|
|
else
|
|
unexpected($pred, "bad slot type")
|
|
)
|
|
else
|
|
multi_map.set(ProcLabel, LabelNum, !NoLayoutMap)
|
|
)
|
|
;
|
|
Label = entry_label(_, _),
|
|
unexpected($pred, "entry label")
|
|
),
|
|
group_init_c_labels(InternalLabelToLayoutMap, Labels,
|
|
!NoLayoutMap, !NoVarLayoutMap, !SVarLayoutMap, !LVarLayoutMap).
|
|
|
|
:- pred output_c_internal_label_no_layout_init_group(
|
|
io.text_output_stream::in, pair(proc_label, list(int))::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_c_internal_label_no_layout_init_group(Stream, ProcLabel - RevLabelNums,
|
|
!IO) :-
|
|
list.reverse(RevLabelNums, LabelNums),
|
|
% There must be macros of the form MR_init_label_nvi<n> for every <n>
|
|
% up to MaxChunkSize.
|
|
MaxChunkSize = 10,
|
|
list.chunk(LabelNums, MaxChunkSize, LabelNumChunks),
|
|
list.foldl(
|
|
output_c_internal_label_no_layout_init_chunk(Stream, ProcLabel),
|
|
LabelNumChunks, !IO).
|
|
|
|
:- pred output_c_internal_label_no_layout_init_chunk(io.text_output_stream::in,
|
|
proc_label::in, list(int)::in, io::di, io::uo) is det.
|
|
|
|
output_c_internal_label_no_layout_init_chunk(Stream, ProcLabel, LabelNums,
|
|
!IO) :-
|
|
io.format(Stream, "\tMR_init_label%d(%s, ",
|
|
[i(list.length(LabelNums)),
|
|
s(proc_label_to_c_string(do_not_add_label_prefix, ProcLabel))], !IO),
|
|
write_out_list(add_int, ",", LabelNums, Stream, !IO),
|
|
io.write_string(Stream, ")\n", !IO).
|
|
|
|
:- pred output_c_internal_label_layout_init_group(llds_out_info::in,
|
|
io.text_output_stream::in, string::in,
|
|
pair(proc_label, list({int, int}))::in, io::di, io::uo) is det.
|
|
|
|
output_c_internal_label_layout_init_group(Info, Stream, Suffix,
|
|
ProcLabel - RevLabelSlotNums, !IO) :-
|
|
list.reverse(RevLabelSlotNums, LabelSlotNums),
|
|
% There must be macros of the form MR_init_label_vi<n> for every <n>
|
|
% up to MaxChunkSize.
|
|
MaxChunkSize = 10,
|
|
list.chunk(LabelSlotNums, MaxChunkSize, LabelSlotNumChunks),
|
|
list.foldl(
|
|
output_c_internal_label_layout_init_chunk(Info, Stream,
|
|
Suffix, ProcLabel),
|
|
LabelSlotNumChunks, !IO).
|
|
|
|
:- pred output_c_internal_label_layout_init_chunk(llds_out_info::in,
|
|
io.text_output_stream::in, string::in, proc_label::in,
|
|
list({int, int})::in, io::di, io::uo) is det.
|
|
|
|
output_c_internal_label_layout_init_chunk(Info, Stream, Suffix, ProcLabel,
|
|
LabelSlotNums, !IO) :-
|
|
ModuleName = Info ^ lout_mangled_module_name,
|
|
io.format(Stream, "\tMR_init_label%s%d(%s, %s,\n\t\t",
|
|
[s(Suffix), i(list.length(LabelSlotNums)),
|
|
s(proc_label_to_c_string(do_not_add_label_prefix, ProcLabel)),
|
|
s(ModuleName)], !IO),
|
|
write_out_list(write_int_pair, ", ", LabelSlotNums, Stream, !IO),
|
|
io.write_string(Stream, ")\n", !IO).
|
|
|
|
:- pred write_int_pair({int, int}::in, io.text_output_stream::in,
|
|
io::di, io::uo) is det.
|
|
|
|
write_int_pair({LabelNum, SlotNum}, Stream, !IO) :-
|
|
io.write_int(Stream, LabelNum, !IO),
|
|
io.write_string(Stream, ",", !IO),
|
|
io.write_int(Stream, SlotNum, !IO).
|
|
|
|
:- pred output_c_entry_label_init(io.text_output_stream::in,
|
|
map(label, data_id)::in, label::in, io::di, io::uo) is det.
|
|
|
|
output_c_entry_label_init(Stream, EntryLabelToLayoutMap, Label, !IO) :-
|
|
( if map.search(EntryLabelToLayoutMap, Label, _LayoutId) then
|
|
SuffixOpen = "_sl("
|
|
else
|
|
SuffixOpen = "("
|
|
% This label has no stack layout to initialize.
|
|
),
|
|
(
|
|
Label = entry_label(entry_label_exported, ProcLabel),
|
|
TabInitMacro = "\tMR_init_entry1"
|
|
;
|
|
Label = entry_label(entry_label_local, ProcLabel),
|
|
TabInitMacro = "\tMR_init_entry1"
|
|
;
|
|
Label = entry_label(entry_label_c_local, ProcLabel),
|
|
TabInitMacro = "\tMR_init_local1"
|
|
;
|
|
Label = internal_label(_, _),
|
|
% These should have been separated out by group_c_labels.
|
|
unexpected($pred, "internal label")
|
|
),
|
|
io.write_string(Stream, TabInitMacro, !IO),
|
|
io.write_string(Stream, SuffixOpen, !IO),
|
|
io.write_string(Stream,
|
|
proc_label_to_c_string(do_not_add_label_prefix, ProcLabel), !IO),
|
|
io.write_string(Stream, ");\n", !IO),
|
|
|
|
io.write_string(Stream, "\tMR_INIT_PROC_LAYOUT_ADDR(", !IO),
|
|
output_label(Stream, Label, !IO),
|
|
io.write_string(Stream, ");\n", !IO).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- pred output_record_c_procedure_decls(llds_out_info::in,
|
|
io.text_output_stream::in, annotated_c_procedure::in,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_record_c_procedure_decls(Info, Stream, AnnotatedProc, !DeclSet, !IO) :-
|
|
Proc = AnnotatedProc ^ acp_proc,
|
|
Instrs = Proc ^ cproc_code,
|
|
CGlobalVarSet = Proc ^ cproc_c_global_vars,
|
|
set.to_sorted_list(CGlobalVarSet, CGlobalVars),
|
|
list.foldl2(output_c_global_var_decl(Stream), CGlobalVars,
|
|
!DeclSet, !IO),
|
|
list.foldl2(output_record_instruction_decls(Info, Stream), Instrs,
|
|
!DeclSet, !IO),
|
|
true.
|
|
|
|
:- pred output_c_global_var_decl(io.text_output_stream::in, string::in,
|
|
decl_set::in, decl_set::out, io::di, io::uo) is det.
|
|
|
|
output_c_global_var_decl(Stream, VarName, !DeclSet, !IO) :-
|
|
GlobalVar = env_var_ref(VarName),
|
|
( if decl_set_insert_new(decl_c_global_var(GlobalVar), !DeclSet) then
|
|
io.format(Stream, "extern MR_Word %s;\n",
|
|
[s(c_global_var_name(GlobalVar))], !IO)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred output_annotated_c_procedure(llds_out_info::in,
|
|
io.text_output_stream::in, annotated_c_procedure::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_annotated_c_procedure(Info, Stream, AnnotatedProc, !IO) :-
|
|
Proc = AnnotatedProc ^ acp_proc,
|
|
LabelOutputInfo = AnnotatedProc ^ acp_label_output_info,
|
|
|
|
PorF = Proc ^ cproc_p_or_f,
|
|
Name = Proc ^ cproc_name,
|
|
user_arity(Arity) = Proc ^ cproc_user_arity,
|
|
Instrs = Proc ^ cproc_code,
|
|
PredProcId = Proc ^ cproc_id,
|
|
PredProcId = proc(_, ProcId),
|
|
proc_id_to_int(ProcId, ModeNum),
|
|
|
|
io.write_string(Stream, "\n/*-------------------------------------", !IO),
|
|
io.write_string(Stream, "------------------------------------*/\n", !IO),
|
|
% Now that we have unused_args.m mangling predicate names,
|
|
% we should probably demangle them here.
|
|
io.format(Stream, "/* code for %s '%s'/%d mode %d */\n",
|
|
[s(pred_or_func_to_str(PorF)), s(Name), i(Arity), i(ModeNum)], !IO),
|
|
|
|
LocalThreadEngineBase = Info ^ lout_local_thread_engine_base,
|
|
(
|
|
LocalThreadEngineBase = use_local_thread_engine_base,
|
|
io.write_string(Stream,
|
|
"#ifdef MR_maybe_local_thread_engine_base\n", !IO),
|
|
io.write_string(Stream,
|
|
"\t#undef MR_maybe_local_thread_engine_base\n", !IO),
|
|
io.write_string(Stream,
|
|
"\t#define MR_maybe_local_thread_engine_base " ++
|
|
"MR_local_thread_engine_base\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO)
|
|
;
|
|
LocalThreadEngineBase = do_not_use_local_thread_engine_base
|
|
),
|
|
output_instruction_list(Info, Stream, Instrs, LabelOutputInfo,
|
|
not_after_layout_label, !IO),
|
|
(
|
|
LocalThreadEngineBase = use_local_thread_engine_base,
|
|
io.write_string(Stream,
|
|
"#ifdef MR_maybe_local_thread_engine_base\n", !IO),
|
|
io.write_string(Stream,
|
|
"\t#undef MR_maybe_local_thread_engine_base\n", !IO),
|
|
io.write_string(Stream,
|
|
"\t#define MR_maybe_local_thread_engine_base " ++
|
|
"MR_thread_engine_base\n", !IO),
|
|
io.write_string(Stream, "#endif\n", !IO)
|
|
;
|
|
LocalThreadEngineBase = do_not_use_local_thread_engine_base
|
|
).
|
|
|
|
% Find the entry label for the procedure, for use as the profiling
|
|
% "caller label" field in calls within this procedure.
|
|
%
|
|
:- pred find_caller_label(list(instruction)::in, label::out) is det.
|
|
|
|
find_caller_label([], _) :-
|
|
unexpected($pred, "cannot find caller label").
|
|
find_caller_label([llds_instr(Uinstr, _) | Instrs], CallerLabel) :-
|
|
( if Uinstr = label(Label) then
|
|
(
|
|
Label = internal_label(_, _),
|
|
unexpected($pred, "caller label is internal label")
|
|
;
|
|
Label = entry_label(_, _),
|
|
CallerLabel = Label
|
|
)
|
|
else
|
|
find_caller_label(Instrs, CallerLabel)
|
|
).
|
|
|
|
% Locate all the labels which are the continuation labels for calls,
|
|
% nondet disjunctions, forks or joins, and store them in ContLabels.
|
|
%
|
|
:- pred find_cont_labels(list(instruction)::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
find_cont_labels([], !ContLabels).
|
|
find_cont_labels([Instr | Instrs], !ContLabels) :-
|
|
Instr = llds_instr(Uinstr, _),
|
|
( if
|
|
(
|
|
Uinstr = llcall(_, code_label(ContLabel), _, _, _, _)
|
|
;
|
|
Uinstr = mkframe(_, yes(code_label(ContLabel)))
|
|
;
|
|
Uinstr = join_and_continue(_, ContLabel)
|
|
;
|
|
Uinstr = assign(redoip_slot(_), const(Const)),
|
|
Const = llconst_code_addr(code_label(ContLabel))
|
|
)
|
|
then
|
|
set_tree234.insert(ContLabel, !ContLabels)
|
|
else if
|
|
Uinstr = fork_new_child(_, Label1)
|
|
then
|
|
set_tree234.insert(Label1, !ContLabels)
|
|
else if
|
|
Uinstr = block(_, _, Block)
|
|
then
|
|
find_cont_labels(Block, !ContLabels)
|
|
else
|
|
true
|
|
),
|
|
find_cont_labels(Instrs, !ContLabels).
|
|
|
|
% Locate all the labels which can be profitably turned into
|
|
% labels starting while loops. The idea is to do this transform:
|
|
%
|
|
% L1: L1:
|
|
% while (1) {
|
|
% ... ...
|
|
% if (...) goto L1 if (...) continue
|
|
% ... => ...
|
|
% if (...) goto L? if (...) goto L?
|
|
% ... ...
|
|
% if (...) goto L1 if (...) continue
|
|
% ... ...
|
|
% break;
|
|
% }
|
|
% L2: L2:
|
|
%
|
|
% The second of these is better if we don't have fast jumps.
|
|
%
|
|
:- pred find_while_labels(list(instruction)::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
find_while_labels([], !WhileSet).
|
|
find_while_labels([llds_instr(Uinstr0, _) | Instrs0], !WhileSet) :-
|
|
( if
|
|
Uinstr0 = label(Label),
|
|
is_while_label(Label, Instrs0, Instrs1, 0, UseCount),
|
|
UseCount > 0
|
|
then
|
|
set_tree234.insert(Label, !WhileSet),
|
|
find_while_labels(Instrs1, !WhileSet)
|
|
else
|
|
find_while_labels(Instrs0, !WhileSet)
|
|
).
|
|
|
|
:- pred is_while_label(label::in,
|
|
list(instruction)::in, list(instruction)::out, int::in, int::out) is det.
|
|
|
|
is_while_label(_, [], [], !Count).
|
|
is_while_label(Label, [Instr0 | Instrs0], Instrs, !Count) :-
|
|
Instr0 = llds_instr(Uinstr0, _),
|
|
( if Uinstr0 = label(_) then
|
|
Instrs = [Instr0 | Instrs0]
|
|
else
|
|
( if Uinstr0 = goto(code_label(Label)) then
|
|
!:Count = !.Count + 1
|
|
else if Uinstr0 = if_val(_, code_label(Label)) then
|
|
!:Count = !.Count + 1
|
|
else if Uinstr0 = block(_, _, BlockInstrs) then
|
|
count_while_label_in_block(Label, BlockInstrs, !Count)
|
|
else
|
|
true
|
|
),
|
|
is_while_label(Label, Instrs0, Instrs, !Count)
|
|
).
|
|
|
|
:- pred count_while_label_in_block(label::in, list(instruction)::in,
|
|
int::in, int::out) is det.
|
|
|
|
count_while_label_in_block(_, [], !Count).
|
|
count_while_label_in_block(Label, [Instr0 | Instrs0], !Count) :-
|
|
Instr0 = llds_instr(Uinstr0, _),
|
|
( if Uinstr0 = label(_) then
|
|
unexpected($pred, "label in block")
|
|
else
|
|
( if Uinstr0 = goto(code_label(Label)) then
|
|
!:Count = !.Count + 1
|
|
else if Uinstr0 = if_val(_, code_label(Label)) then
|
|
!:Count = !.Count + 1
|
|
else if Uinstr0 = block(_, _, _) then
|
|
unexpected($pred, "block in block")
|
|
else
|
|
true
|
|
),
|
|
count_while_label_in_block(Label, Instrs0, !Count)
|
|
).
|
|
|
|
% Given WhileLabels, a set of labels that we know should start while loops,
|
|
% and !.UndefWhileLabels, our current guess as to which of these labels
|
|
% we can avoid defining, remove from UndefWhileLabels the labels
|
|
% that we cannot avoid defining because they are used in ways that are
|
|
% incompatible with the labels elimination. This can happen because
|
|
% the label is branched to from outside its while loop, or because
|
|
% its address is treated as data. To help us with the former,
|
|
% MaybeCurWhileLabel tells us which while loop (if any) we are now in.
|
|
%
|
|
% Basically, *every* reference to a label will cause us to delete that
|
|
% label from UndefWhileLabels, with the *exception* of a goto to the label
|
|
% from *within* the while loop that it starts.
|
|
%
|
|
:- pred find_while_labels_to_define(list(instruction)::in,
|
|
maybe(label)::in, set_tree234(label)::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
find_while_labels_to_define([], _, _, !UndefWhileLabels).
|
|
find_while_labels_to_define([Instr0 | Instrs0], MaybeCurWhileLabel0,
|
|
WhileLabels, !UndefWhileLabels) :-
|
|
Instr0 = llds_instr(Uinstr0, _) ,
|
|
(
|
|
Uinstr0 = label(Label),
|
|
( if set_tree234.contains(WhileLabels, Label) then
|
|
MaybeCurWhileLabel = yes(Label)
|
|
else
|
|
MaybeCurWhileLabel = no
|
|
)
|
|
;
|
|
Uinstr0 = if_val(Rval, Target),
|
|
rval_addrs(Rval, RvalCodeAddrs, _),
|
|
delete_any_labels(RvalCodeAddrs, !UndefWhileLabels),
|
|
( if Target = code_label(TargetLabel) then
|
|
( if MaybeCurWhileLabel0 = yes(TargetLabel) then
|
|
% This reference will be turned into a continue statement.
|
|
true
|
|
else
|
|
set_tree234.delete(TargetLabel, !UndefWhileLabels)
|
|
)
|
|
else
|
|
true
|
|
),
|
|
MaybeCurWhileLabel = no
|
|
;
|
|
Uinstr0 = goto(Target),
|
|
( if Target = code_label(TargetLabel) then
|
|
set_tree234.delete(TargetLabel, !UndefWhileLabels)
|
|
else
|
|
true
|
|
),
|
|
MaybeCurWhileLabel = no
|
|
;
|
|
Uinstr0 = computed_goto(Rval, _MaybeMaxIndex, MaybeTargets),
|
|
rval_addrs(Rval, RvalCodeAddrs, _),
|
|
delete_any_labels(RvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_maybe_labels(MaybeTargets, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = no
|
|
;
|
|
Uinstr0 = llcall(Target, Continuation, _, _, _, _),
|
|
delete_any_label(Target, !UndefWhileLabels),
|
|
delete_any_label(Continuation, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = no
|
|
;
|
|
Uinstr0 = block(_, _, BlockInstrs),
|
|
find_while_labels_to_define(BlockInstrs, MaybeCurWhileLabel0,
|
|
WhileLabels, !UndefWhileLabels),
|
|
% The block is guaranteed not to contain any labels.
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = mkframe(_, MaybeNextCodeAddr),
|
|
(
|
|
MaybeNextCodeAddr = yes(NextCodeAddr),
|
|
delete_any_label(NextCodeAddr, !UndefWhileLabels)
|
|
;
|
|
MaybeNextCodeAddr = no
|
|
),
|
|
MaybeCurWhileLabel = no
|
|
;
|
|
( Uinstr0 = assign(Lval, Rval)
|
|
; Uinstr0 = keep_assign(Lval, Rval)
|
|
),
|
|
lval_addrs(Lval, LvalCodeAddrs, _),
|
|
rval_addrs(Rval, RvalCodeAddrs, _),
|
|
delete_any_labels(LvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(RvalCodeAddrs, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
( Uinstr0 = save_maxfr(Lval)
|
|
; Uinstr0 = restore_maxfr(Lval)
|
|
; Uinstr0 = mark_hp(Lval)
|
|
; Uinstr0 = store_ticket(Lval)
|
|
; Uinstr0 = mark_ticket_stack(Lval)
|
|
; Uinstr0 = init_sync_term(Lval, _, _)
|
|
; Uinstr0 = fork_new_child(Lval, _)
|
|
; Uinstr0 = join_and_continue(Lval, _)
|
|
; Uinstr0 = lc_create_loop_control(_, Lval)
|
|
),
|
|
lval_addrs(Lval, LvalCodeAddrs, _),
|
|
delete_any_labels(LvalCodeAddrs, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
( Uinstr0 = restore_hp(Rval)
|
|
; Uinstr0 = free_heap(Rval)
|
|
; Uinstr0 = region_set_fixed_slot(_, _, Rval)
|
|
; Uinstr0 = reset_ticket(Rval, _)
|
|
; Uinstr0 = prune_tickets_to(Rval)
|
|
),
|
|
rval_addrs(Rval, RvalCodeAddrs, _),
|
|
delete_any_labels(RvalCodeAddrs, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = incr_hp(TargetLval, _, _, SizeRval, _, _,
|
|
MaybeRegionIdRval, _),
|
|
lval_addrs(TargetLval, TargetLvalCodeAddrs, _),
|
|
rval_addrs(SizeRval, SizeRvalCodeAddrs, _),
|
|
delete_any_labels(TargetLvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(SizeRvalCodeAddrs, !UndefWhileLabels),
|
|
(
|
|
MaybeRegionIdRval = no
|
|
;
|
|
MaybeRegionIdRval = yes(RegionIdRval),
|
|
rval_addrs(RegionIdRval, RegionIdRvalCodeAddrs, _),
|
|
delete_any_labels(RegionIdRvalCodeAddrs, !UndefWhileLabels)
|
|
),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = foreign_proc_code(_, _, _, MaybeFixNoLayoutLabel,
|
|
MaybeFixLayoutLabel, MaybeFixOnlyLayoutLabel, MaybeNoFixLabel,
|
|
MaybeHashDefLabel, _, _),
|
|
delete_any_maybe_label(MaybeFixNoLayoutLabel, !UndefWhileLabels),
|
|
delete_any_maybe_label(MaybeFixLayoutLabel, !UndefWhileLabels),
|
|
delete_any_maybe_label(MaybeFixOnlyLayoutLabel, !UndefWhileLabels),
|
|
delete_any_maybe_label(MaybeNoFixLabel, !UndefWhileLabels),
|
|
delete_any_maybe_label(MaybeHashDefLabel, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = region_fill_frame(_, _, RegionIdRval, NumLval, AddrLval),
|
|
rval_addrs(RegionIdRval, RegionIdRvalCodeAddrs, _),
|
|
lval_addrs(NumLval, NumLvalCodeAddrs, _),
|
|
lval_addrs(AddrLval, AddrLvalCodeAddrs, _),
|
|
delete_any_labels(RegionIdRvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(NumLvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(AddrLvalCodeAddrs, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = lc_wait_free_slot(LoopControlRval, SlotLval, Label),
|
|
rval_addrs(LoopControlRval, LoopControlRvalCodeAddrs, _),
|
|
lval_addrs(SlotLval, SlotLvalCodeAddrs, _),
|
|
delete_any_labels(LoopControlRvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(SlotLvalCodeAddrs, !UndefWhileLabels),
|
|
set_tree234.delete(Label, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = lc_spawn_off(LoopControlRval, SlotRval, Label),
|
|
rval_addrs(LoopControlRval, LoopControlRvalCodeAddrs, _),
|
|
rval_addrs(SlotRval, SlotRvalCodeAddrs, _),
|
|
delete_any_labels(LoopControlRvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(SlotRvalCodeAddrs, !UndefWhileLabels),
|
|
set_tree234.delete(Label, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
Uinstr0 = lc_join_and_terminate(LoopControlRval, SlotRval),
|
|
rval_addrs(LoopControlRval, LoopControlRvalCodeAddrs, _),
|
|
rval_addrs(SlotRval, SlotRvalCodeAddrs, _),
|
|
delete_any_labels(LoopControlRvalCodeAddrs, !UndefWhileLabels),
|
|
delete_any_labels(SlotRvalCodeAddrs, !UndefWhileLabels),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
;
|
|
( Uinstr0 = comment(_)
|
|
; Uinstr0 = livevals(_)
|
|
; Uinstr0 = arbitrary_c_code(_, _, _)
|
|
; Uinstr0 = push_region_frame(_, _)
|
|
; Uinstr0 = use_and_maybe_pop_region_frame(_, _)
|
|
; Uinstr0 = prune_ticket
|
|
; Uinstr0 = discard_ticket
|
|
; Uinstr0 = incr_sp(_, _, _)
|
|
; Uinstr0 = decr_sp(_)
|
|
; Uinstr0 = decr_sp_and_return(_)
|
|
),
|
|
MaybeCurWhileLabel = MaybeCurWhileLabel0
|
|
),
|
|
find_while_labels_to_define(Instrs0, MaybeCurWhileLabel,
|
|
WhileLabels, !UndefWhileLabels).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
%
|
|
% The job of all these predicates is to remove any labels in their first
|
|
% argument from !.UndefWhileLabels.
|
|
%
|
|
|
|
:- pred delete_any_label(code_addr::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
delete_any_label(CodeAddr, !UndefWhileLabels) :-
|
|
( if CodeAddr = code_label(Label) then
|
|
set_tree234.delete(Label, !UndefWhileLabels)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred delete_any_labels(list(code_addr)::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
delete_any_labels([], !UndefWhileLabels).
|
|
delete_any_labels([CodeAddr | CodeAddrs], !UndefWhileLabels) :-
|
|
delete_any_label(CodeAddr, !UndefWhileLabels),
|
|
delete_any_labels(CodeAddrs, !UndefWhileLabels).
|
|
|
|
:- pred delete_any_maybe_label(maybe(label)::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
delete_any_maybe_label(MaybeLabel, !UndefWhileLabels) :-
|
|
(
|
|
MaybeLabel = no
|
|
;
|
|
MaybeLabel = yes(Label),
|
|
set_tree234.delete(Label, !UndefWhileLabels)
|
|
).
|
|
|
|
:- pred delete_any_maybe_labels(list(maybe(label))::in,
|
|
set_tree234(label)::in, set_tree234(label)::out) is det.
|
|
|
|
delete_any_maybe_labels([], !UndefWhileLabels).
|
|
delete_any_maybe_labels([MaybeLabel | MaybeLabels], !UndefWhileLabels) :-
|
|
delete_any_maybe_label(MaybeLabel, !UndefWhileLabels),
|
|
delete_any_maybe_labels(MaybeLabels, !UndefWhileLabels).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
%----------------------------------------------------------------------------%
|
|
|
|
c_data_linkage_string(DefaultLinkage, BeingDefined) = LinkageStr :-
|
|
(
|
|
DefaultLinkage = extern,
|
|
(
|
|
BeingDefined = yes,
|
|
LinkageStr = ""
|
|
;
|
|
BeingDefined = no,
|
|
LinkageStr = "extern "
|
|
)
|
|
;
|
|
DefaultLinkage = static,
|
|
% Previously we used to always write `extern' here, but declaring
|
|
% something `extern' and then later defining it as `static' causes
|
|
% undefined behavior -- on many systems, it works, but on some systems
|
|
% such as RS/6000s running AIX, it results in link errors.
|
|
%
|
|
LinkageStr = "static "
|
|
).
|
|
|
|
c_data_const_string(Globals, InclCodeAddr) =
|
|
( if
|
|
InclCodeAddr = yes,
|
|
globals.get_opt_tuple(Globals, OptTuple),
|
|
OptTuple ^ ot_use_static_code_addresses =
|
|
do_not_use_static_code_addresses
|
|
then
|
|
""
|
|
else
|
|
"const "
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ll_backend.llds_out.llds_out_file.
|
|
%---------------------------------------------------------------------------%
|