mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 18:03:36 +00:00
We have two main notions of trace levels. The first is the global trace level,
which is set by compiler options, and the second is the effective trace level
for a given procedure. The two are different not just in that the effective
trace level for a procedure may differ from the global trace level, but also
in that there exist effective trace levels that cannot be specified using
compiler options.
compiler/trace_params.m:
Add the new type eff_trace_level for representing effective trace levels.
(Old code has long used "Eff" as an abbreviation for "effective".)
Use it where relevant.
Delete functions that (a) first compute the effective trace level
for a procedure, and (b) then test that effective trace level,
and replace each of them with a function that does only (b).
There was already a function that did only (a); rename it to avoid
an ambiguity.
compiler/code_info.m:
Store the effective trace level of the procedure being translated
in the code_info, to save it from having to be recomputed many times.
compiler/code_loc_dep.m:
Get the effective trace level for the procedure being compiled
from code_info.
compiler/hlds_out_pred.m:
Write out each procedure's effective trace level.
compiler/llds.m:
Include the effective trace level in generated c_procs, for use by
continuation_info.m.
compiler/continuation_info.m:
Rename a predicate to avoid a name clash.
Conform to the changes above.
compiler/handle_options.m:
Note a non-problem.
compiler/globals.m:
compiler/layout.m:
compiler/layout_out.m:
compiler/liveness.m:
compiler/optimize.m:
compiler/proc_gen.m:
compiler/simplify_goal_conj.m:
compiler/simplify_goal_scope.m:
compiler/simplify_info.m:
compiler/stack_alloc.m:
compiler/stack_layout.m:
compiler/store_alloc.m:
compiler/trace_gen.m:
compiler/transform_llds.m:
Conform to the changes above.
compiler/mercury_compile_front_end.m:
Fix a misleading predicate name.
compiler/hlds_out_module.m:
Simplify some code.
runtime/mercury_goto.h:
Fix misplaced/wrong casts and stray backslashes in macros that are usually
only used when debugging the debugger.
219 lines
8.9 KiB
Mathematica
219 lines
8.9 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-2001,2003-2007, 2009-2011 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.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: transform_llds.
|
|
% Main author: petdr.
|
|
%
|
|
% This module does source to source transformations of the llds data
|
|
% structure. This is sometimes necessary to avoid limits in some compilers.
|
|
%
|
|
% This module currently transforms computed gotos into a binary search down to
|
|
% smaller computed gotos. This avoids a limitation in the lcc compiler.
|
|
%
|
|
% If accurate GC is enabled, we also append a module containing an end label
|
|
% to the list of comp_gen_c_modules.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.transform_llds.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module ll_backend.llds.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred transform_llds(globals::in, c_file::in, c_file::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.builtin_ops.
|
|
:- import_module hlds.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module libs.options.
|
|
:- import_module libs.trace_params.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module counter.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
transform_llds(Globals, !CFile) :-
|
|
ModuleName = !.CFile ^ cfile_modulename,
|
|
Modules0 = !.CFile ^ cfile_code,
|
|
% Split up large computed gotos.
|
|
globals.lookup_int_option(Globals, max_jump_table_size, MaxSize),
|
|
( if MaxSize = 0 then
|
|
Modules1 = Modules0
|
|
else
|
|
transform_c_module_list(Modules0, Modules1, MaxSize)
|
|
),
|
|
% Append an end label for accurate GC.
|
|
globals.get_gc_method(Globals, GC),
|
|
( if
|
|
GC = gc_accurate,
|
|
Modules1 = [_ | _]
|
|
then
|
|
list.det_last(Modules1, LastModule),
|
|
LastModule = comp_gen_c_module(LastModuleName, _),
|
|
Modules = Modules1 ++
|
|
[gen_end_label_module(ModuleName, LastModuleName)]
|
|
else
|
|
Modules = Modules1
|
|
),
|
|
!CFile ^ cfile_code := Modules.
|
|
|
|
% For LLDS native GC, we need to add a dummy comp_gen_c_module at the end
|
|
% of the list. This dummy module contains only a single dummy procedure
|
|
% which in turn contains only a single label, for which there is no
|
|
% stack layout structure. The point of this is to ensure that the
|
|
% address of this label gets inserted into the entry table, so that
|
|
% we know where the preceding procedure finishes when mapping from
|
|
% instruction pointer values to stack layout entries.
|
|
%
|
|
% Without this, we might think that the following C function was
|
|
% actually part of the last Mercury procedure in the preceding module,
|
|
% and then incorrectly use the stack layout of the Mercury procedure
|
|
% if we happened to get a heap overflow signal (SIGSEGV) while in that
|
|
% C function.
|
|
%
|
|
% Note that it is not sufficient to generate a label at end of the module,
|
|
% because GCC (e.g. GCC 3.2) sometimes reorders code within a single C
|
|
% function, so that a label declared at the end of the module might not
|
|
% be actually have highest address. So we generate a new module (which
|
|
% corresponds to a new C function). XXX Hopefully GCC won't mess with the
|
|
% order of the functions ...
|
|
%
|
|
:- func gen_end_label_module(module_name, string) = comp_gen_c_module.
|
|
|
|
gen_end_label_module(ModuleName, LastModule) = EndLabelModule :-
|
|
Arity = 0,
|
|
ProcId = hlds_pred.initial_proc_id,
|
|
PredId = hlds_pred.initial_pred_id,
|
|
PredName = "ACCURATE_GC_END_LABEL",
|
|
ProcLabel = ordinary_proc_label(ModuleName, pf_predicate, ModuleName,
|
|
PredName, Arity, proc_id_to_int(ProcId)),
|
|
Instrs = [llds_instr(label(entry_label(entry_label_local, ProcLabel)),
|
|
"label to indicate end of previous procedure")],
|
|
DummyProc = c_procedure(PredName, Arity, proc(PredId, ProcId), ProcLabel,
|
|
model_det, eff_trace_level_none, Instrs, counter.init(0),
|
|
must_not_alter_rtti, set.init),
|
|
EndLabelModule = comp_gen_c_module(LastModule ++ "_END", [DummyProc]).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred transform_c_module_list(list(comp_gen_c_module)::in,
|
|
list(comp_gen_c_module)::out, int::in) is det.
|
|
|
|
transform_c_module_list([], [], _MaxSize).
|
|
transform_c_module_list([Module0 | Module0s], [Module | Modules], MaxSize) :-
|
|
transform_c_module(Module0, Module, MaxSize),
|
|
transform_c_module_list(Module0s, Modules, MaxSize).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred transform_c_module(comp_gen_c_module::in, comp_gen_c_module::out,
|
|
int::in) is det.
|
|
|
|
transform_c_module(Module0, Module, MaxSize) :-
|
|
Module0 = comp_gen_c_module(Name, Procedures0),
|
|
transform_c_procedure_list(Procedures0, Procedures, MaxSize),
|
|
Module = comp_gen_c_module(Name, Procedures).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred transform_c_procedure_list(list(c_procedure)::in,
|
|
list(c_procedure)::out, int::in) is det.
|
|
|
|
transform_c_procedure_list([], [], _MaxSize).
|
|
transform_c_procedure_list([Proc0 | Proc0s], [Proc | Procs], MaxSize) :-
|
|
transform_c_procedure(Proc0, Proc, MaxSize),
|
|
transform_c_procedure_list(Proc0s, Procs, MaxSize).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred transform_c_procedure(c_procedure::in, c_procedure::out, int::in)
|
|
is det.
|
|
|
|
transform_c_procedure(!Proc, MaxSize) :-
|
|
ProcLabel = !.Proc ^ cproc_proc_label,
|
|
Instrs0 = !.Proc ^ cproc_code,
|
|
C0 = !.Proc ^ cproc_label_nums,
|
|
transform_instructions(Instrs0, Instrs, C0, C, ProcLabel, MaxSize),
|
|
!Proc ^ cproc_code := Instrs,
|
|
!Proc ^ cproc_label_nums := C.
|
|
|
|
:- pred transform_instructions(list(instruction)::in, list(instruction)::out,
|
|
counter::in, counter::out, proc_label::in, int::in) is det.
|
|
|
|
transform_instructions([], [], !C, _, _).
|
|
transform_instructions([Instr0 | Instrs0], Instrs, !C, ProcLabel, MaxSize) :-
|
|
transform_instructions(Instrs0, InstrsTail, !C, ProcLabel, MaxSize),
|
|
( if
|
|
Instr0 = llds_instr(computed_goto(Rval, Targets), Comment),
|
|
list.length(Targets, NumTargets),
|
|
NumTargets > MaxSize
|
|
then
|
|
split_computed_goto(Rval, Targets, Comment, InstrsHead, !C,
|
|
MaxSize, NumTargets, ProcLabel),
|
|
list.append(InstrsHead, InstrsTail, Instrs)
|
|
else
|
|
Instrs = [Instr0 | InstrsTail]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Given the pieces of a computed_goto instruction, split the table
|
|
% in half as many times as necessary to bring the jump table size
|
|
% below MaxSize, doing a binary search on the way.
|
|
%
|
|
:- pred split_computed_goto(rval::in, list(maybe(label))::in, string::in,
|
|
list(instruction)::out, counter::in, counter::out, int::in, int::in,
|
|
proc_label::in) is det.
|
|
|
|
split_computed_goto(Rval, Targets, Comment, Instrs, !C, MaxSize, NumTargets,
|
|
ProcLabel) :-
|
|
( if NumTargets =< MaxSize then
|
|
Instrs = [llds_instr(computed_goto(Rval, Targets), Comment)]
|
|
else
|
|
counter.allocate(LabelNum, !C),
|
|
Mid = NumTargets // 2,
|
|
list.det_split_list(Mid, Targets, StartTargets, EndTargets),
|
|
Index = binop(int_sub(int_type_int), Rval, const(llconst_int(Mid))),
|
|
Test = binop(int_ge(int_type_int), Rval, const(llconst_int(Mid))),
|
|
ElseAddr = code_label(internal_label(LabelNum, ProcLabel)),
|
|
IfInstr = llds_instr(if_val(Test, ElseAddr), "binary search"),
|
|
ElseInstr = llds_instr(label(internal_label(LabelNum, ProcLabel)), ""),
|
|
|
|
split_computed_goto(Rval, StartTargets, Comment ++ " then",
|
|
ThenInstrs, !C, MaxSize, Mid, ProcLabel),
|
|
split_computed_goto(Index, EndTargets, Comment ++ " else",
|
|
ElseInstrs, !C, MaxSize, NumTargets - Mid, ProcLabel),
|
|
|
|
Instrs = [IfInstr | ThenInstrs] ++ [ElseInstr | ElseInstrs]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module ll_backend.transform_llds.
|
|
%-----------------------------------------------------------------------------%
|