Files
mercury/compiler/prog_rep.m
Zoltan Somogyi 2c21dcc4c0 Avoid an ambiguity.
compiler/hlds_goal.m:
    Change the names of the fields of the hlds_goal structure to avoid
    conflicts with the names of the hlds_goal_expr and hlds_goal_info types.

compiler/coverage_profiling.m:
compiler/deep_profiling.m:
compiler/dep_par_conj.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/introduce_parallelism.m:
compiler/middle_rec.m:
compiler/mode_ordering.m:
compiler/modecheck_conj.m:
compiler/modecheck_goal.m:
compiler/ordering_mode_constraints.m:
compiler/par_conj_gen.m:
compiler/par_loop_control.m:
compiler/prog_rep.m:
compiler/stm_expand.m:
compiler/term_constr_build.m:
compiler/tupling.m:
compiler/untupling.m:
    Conform to the change above.
2018-01-16 17:19:04 +11:00

1037 lines
42 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2000-2012 University of Melbourne.
% Copyright (C) 2015-2017 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: prog_rep.m.
% Authors: zs, maclarty.
%
% This module generates a representation of HLDS goals for the declarative
% debugger. Since this representation is to be included in debuggable
% executables, it should be as compact as possible, and therefore contains
% only the information required by the declarative debugger. The structure
% of this representation is defined by mdbcomp/program_representation.m.
%
%-----------------------------------------------------------------------------%
:- module ll_backend.prog_rep.
:- interface.
:- import_module hlds.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_module.
:- import_module hlds.instmap.
:- import_module hlds.vartypes.
:- import_module ll_backend.prog_rep_tables.
:- import_module mdbcomp.
:- import_module mdbcomp.program_representation.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module assoc_list.
:- import_module cord.
:- import_module list.
:- import_module map.
:- import_module pair.
%-----------------------------------------------------------------------------%
% A var_num_map maps each variable that occurs in any of a procedure's
% layout structures to a number that uniquely identifies that variable,
% and to its name.
%
% The integer returned by term.var_to_int are a dense set when we consider
% all the original variables of a procedure. However, it can become less
% dense when an optimization removes all references to a variable, and
% becomes less dense still when we consider only variables that occur
% in a layout structure. This is why we allocate our own id numbers.
%
:- type var_num_map == map(prog_var, pair(int, string)).
% Encode the information in a module's oisu pragmas into bytecode,
% for use by the automatic parallelization feedback tool.
%
:- pred encode_oisu_type_procs(module_info::in,
assoc_list(type_ctor, oisu_preds)::in, int::out, cord(int)::out) is det.
% Create the bytecodes for the given procedure.
%
:- pred represent_proc_as_bytecodes(list(prog_var)::in, hlds_goal::in,
instmap::in, vartypes::in, var_num_map::in, module_info::in,
maybe_include_var_name_table::in, maybe_include_var_types::in,
determinism::in, string_table_info::in, string_table_info::out,
type_table_info::in, type_table_info::out, list(int)::out) is det.
%-----------------------------------------------------------------------------%
:- type prog_rep_info
---> prog_rep_info(
pri_filename :: string,
pri_vartypes :: vartypes,
pri_var_num_map :: var_num_map,
pri_var_num_rep :: var_num_rep,
pri_module_info :: module_info,
pri_flatten_par_conjs :: flatten_par_conjs
).
:- type flatten_par_conjs
---> flatten_par_conjs
; expect_no_par_conjs.
:- pred goal_to_goal_rep(prog_rep_info::in, instmap::in, hlds_goal::in,
goal_rep::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.
:- import_module backend_libs.proc_label.
:- import_module check_hlds.
:- import_module check_hlds.inst_test.
:- import_module check_hlds.mode_util.
:- import_module hlds.code_model.
:- import_module hlds.goal_util.
:- import_module hlds.hlds_pred.
:- import_module hlds.special_pred.
:- import_module mdbcomp.goal_path.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.rtti_access.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.prog_util.
:- import_module parse_tree.set_of_var.
:- import_module int.
:- import_module maybe.
:- import_module require.
:- import_module std_util.
:- import_module string.
:- import_module term.
:- import_module unit.
%-----------------------------------------------------------------------------%
encode_oisu_type_procs(_ModuleInfo, [], 0, cord.init).
encode_oisu_type_procs(ModuleInfo, [Pair | Pairs], NumOISUTypes, Bytes) :-
encode_oisu_type_procs(ModuleInfo, Pairs, TailNumOISUTypes, TailBytes),
module_info_get_name(ModuleInfo, ModuleName),
Pair = TypeCtor - Preds,
TypeCtor = type_ctor(TypeCtorSymName, _TypeCtorArity),
(
TypeCtorSymName = qualified(TypeCtorModuleName, TypeCtorName)
;
TypeCtorSymName = unqualified(_),
unexpected($module, $pred, "unqualified type_ctor name")
),
( if TypeCtorModuleName = ModuleName then
encode_len_string(TypeCtorName, TypeCtorNameBytes),
Preds = oisu_preds(CreatorPreds, MutatorPreds, DestructorPreds),
list.length(CreatorPreds, NumCreatorPreds),
list.length(MutatorPreds, NumMutatorPreds),
list.length(DestructorPreds, NumDestructorPreds),
encode_num_det(NumCreatorPreds, NumCreatorPredsBytes),
encode_num_det(NumMutatorPreds, NumMutatorPredsBytes),
encode_num_det(NumDestructorPreds, NumDestructorPredsBytes),
list.map(encode_oisu_proc(ModuleInfo), CreatorPreds,
CreatorPredBytes),
list.map(encode_oisu_proc(ModuleInfo), MutatorPreds,
MutatorPredBytes),
list.map(encode_oisu_proc(ModuleInfo), DestructorPreds,
DestructorPredBytes),
HeadBytes = cord.from_list(TypeCtorNameBytes)
++ cord.from_list(NumCreatorPredsBytes)
++ cord.cord_list_to_cord(CreatorPredBytes)
++ cord.from_list(NumMutatorPredsBytes)
++ cord.cord_list_to_cord(MutatorPredBytes)
++ cord.from_list(NumDestructorPredsBytes)
++ cord.cord_list_to_cord(DestructorPredBytes),
NumOISUTypes = 1 + TailNumOISUTypes,
Bytes = HeadBytes ++ TailBytes
else
NumOISUTypes = TailNumOISUTypes,
Bytes = TailBytes
).
:- pred encode_oisu_proc(module_info::in, pred_id::in, cord(int)::out) is det.
encode_oisu_proc(ModuleInfo, PredId, BytesCord) :-
module_info_pred_info(ModuleInfo, PredId, PredInfo),
pred_info_get_proc_table(PredInfo, ProcTable),
map.to_assoc_list(ProcTable, Procs),
( if Procs = [ProcId - _ProcInfo] then
ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId),
encode_string_proc_label(ProcLabel, BytesCord)
else
unexpected($module, $pred, "OISU pred should have exactly one proc")
).
:- pred encode_string_proc_label(proc_label::in, cord(int)::out) is det.
encode_string_proc_label(ProcLabel, BytesCord) :-
(
ProcLabel = ordinary_proc_label(DefModuleName, PredOrFunc,
DeclModuleName, PredName, Arity, ModeNum),
(
PredOrFunc = pf_predicate,
KindByte = string_proclabel_kind_user_predicate
;
PredOrFunc = pf_function,
KindByte = string_proclabel_kind_user_function
),
encode_len_string(sym_name_to_string(DeclModuleName),
DeclModuleNameBytes),
encode_len_string(sym_name_to_string(DefModuleName),
DefModuleNameBytes),
encode_len_string(PredName, PredNameBytes),
encode_num_det(Arity, ArityBytes),
encode_num_det(ModeNum, ModeNumBytes),
BytesCord = cord.from_list([KindByte | DeclModuleNameBytes])
++ cord.from_list(DefModuleNameBytes)
++ cord.from_list(PredNameBytes)
++ cord.from_list(ArityBytes)
++ cord.from_list(ModeNumBytes)
;
ProcLabel = special_proc_label(DefModuleName, SpecialPredId,
TypeModuleName, TypeName, TypeArity, ModeNum),
TypeCtor = type_ctor(qualified(TypeModuleName, TypeName), TypeArity),
PredName = special_pred_name(SpecialPredId, TypeCtor),
KindByte = string_proclabel_kind_special,
encode_len_string(TypeName, TypeNameBytes),
encode_len_string(sym_name_to_string(TypeModuleName),
TypeModuleNameBytes),
encode_len_string(sym_name_to_string(DefModuleName),
DefModuleNameBytes),
encode_len_string(PredName, PredNameBytes),
encode_num_det(TypeArity, TypeArityBytes),
encode_num_det(ModeNum, ModeNumBytes),
BytesCord = cord.from_list([KindByte | TypeNameBytes])
++ cord.from_list(TypeModuleNameBytes)
++ cord.from_list(DefModuleNameBytes)
++ cord.from_list(PredNameBytes)
++ cord.from_list(TypeArityBytes)
++ cord.from_list(ModeNumBytes)
).
% The definitions of these functions should be kept in sync with
% the definition of the MR_ProcLabelToken type in mercury_deep_profiling.h.
%
:- func string_proclabel_kind_user_predicate = int.
:- func string_proclabel_kind_user_function = int.
:- func string_proclabel_kind_special = int.
string_proclabel_kind_user_predicate = 0.
string_proclabel_kind_user_function = 1.
string_proclabel_kind_special = 2.
%-----------------------------------------------------------------------------%
represent_proc_as_bytecodes(HeadVars, Goal, InstMap0, VarTypes, VarNumMap,
ModuleInfo, IncludeVarNameTable, IncludeVarTypes, ProcDetism,
!StringTable, !TypeTable, ProcRepBytes) :-
Goal = hlds_goal(_, GoalInfo),
Context = goal_info_get_context(GoalInfo),
term.context_file(Context, FileName),
represent_var_table_as_bytecode(IncludeVarNameTable, IncludeVarTypes,
VarTypes, VarNumMap, VarNumRep, VarNameTableBytes,
!StringTable, !TypeTable),
Info = prog_rep_info(FileName, VarTypes, VarNumMap, VarNumRep, ModuleInfo,
expect_no_par_conjs),
InstmapDelta = goal_info_get_instmap_delta(GoalInfo),
encode_string_as_table_offset(FileName, FileNameBytes, !StringTable),
goal_to_byte_list(Goal, InstMap0, Info, GoalBytes, !StringTable),
DetismByte = represent_determinism(ProcDetism),
ProcRepBytes0 = FileNameBytes ++ VarNameTableBytes ++
encode_head_vars_func(Info, InstMap0, InstmapDelta, HeadVars) ++
GoalBytes ++ [DetismByte],
encode_int32_det(list.length(ProcRepBytes0) + 4, LimitBytes),
ProcRepBytes = LimitBytes ++ ProcRepBytes0.
%-----------------------------------------------------------------------------%
% Create bytecodes for the variable name table.
%
% If a variable name table is not requested, an empty table is created.
% The variable name table also includes information about the
% representation of variable numbers within the bytecode.
%
% The representation of variables and the variable name table
% restricts the number of possible variables in a procedure to 2^31.
%
:- pred represent_var_table_as_bytecode(maybe_include_var_name_table::in,
maybe_include_var_types::in, vartypes::in,
var_num_map::in, var_num_rep::out, list(int)::out,
string_table_info::in, string_table_info::out,
type_table_info::in, type_table_info::out) is det.
represent_var_table_as_bytecode(IncludeVarNameTable, IncludeVarTypes,
VarTypes, VarNumMap, VarNumRep, Bytes, !StringTable, !TypeTable) :-
map.foldl(max_var_num, VarNumMap, 0) = MaxVarNum,
( if MaxVarNum =< 127 then
VarNumRep = var_num_1_byte
else if MaxVarNum =< 32767 then
VarNumRep = var_num_2_bytes
else
VarNumRep = var_num_4_bytes
),
var_flag_byte(VarNumRep, IncludeVarNameTable, IncludeVarTypes, FlagByte),
(
IncludeVarNameTable = include_var_name_table,
(
IncludeVarTypes = do_not_include_var_types,
% It is more efficient to make the switch over the representation
% size just once here, than to make it when representing each
% variable.
(
VarNumRep = var_num_1_byte,
map.foldl3(encode_var_name_table_entry_1_byte, VarNumMap,
0, NumVars, [], VarNameTableEntriesBytes, !StringTable)
;
VarNumRep = var_num_2_bytes,
map.foldl3(encode_var_name_table_entry_2_byte, VarNumMap,
0, NumVars, [], VarNameTableEntriesBytes, !StringTable)
;
VarNumRep = var_num_4_bytes,
map.foldl3(encode_var_name_table_entry_4_byte, VarNumMap,
0, NumVars, [], VarNameTableEntriesBytes, !StringTable)
)
;
IncludeVarTypes = include_var_types,
map.foldl4(encode_var_name_type_table_entry(VarNumRep, VarTypes),
VarNumMap, 0, NumVars,
[], VarNameTableEntriesBytes, !StringTable, !TypeTable)
),
encode_num_det(NumVars, NumVarsBytes),
Bytes = [FlagByte] ++ NumVarsBytes ++ VarNameTableEntriesBytes
;
IncludeVarNameTable = do_not_include_var_name_table,
expect(unify(IncludeVarTypes, do_not_include_var_types),
$module, $pred, "IncludeVarTypes but not IncludeVarNameTable"),
Bytes = [FlagByte]
).
:- func max_var_num(prog_var, pair(int, string), int) = int.
max_var_num(_, VarNum1 - _, VarNum2) = Max :-
Max = max(VarNum1, VarNum2).
%-----------------------------------------------------------------------------%
%
% To avoid repeated tests of the size of variable representations, we have
% a specialized version for each different variable number encoding size.
%
% Some variables that the compiler creates are named automatically,
% these and unnamed variables should not be included in the variable
% name table.
%
:- pred encode_var_name_table_entry_1_byte(prog_var::in, pair(int, string)::in,
int::in, int::out, list(int)::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_var_name_table_entry_1_byte(_ProgVar, VarNum - VarName,
!NumVars, !VarNameTableBytes, !StringTable) :-
( if compiler_introduced_varname(VarName) then
true
else
!:NumVars = !.NumVars + 1,
VarBytes = [VarNum],
encode_string_as_table_offset(VarName, VarNameBytes, !StringTable),
!:VarNameTableBytes = VarBytes ++ VarNameBytes ++ !.VarNameTableBytes
).
:- pred encode_var_name_table_entry_2_byte(prog_var::in, pair(int, string)::in,
int::in, int::out, list(int)::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_var_name_table_entry_2_byte(_ProgVar, VarNum - VarName,
!NumVars, !VarNameTableBytes, !StringTable) :-
( if compiler_introduced_varname(VarName) then
true
else
!:NumVars = !.NumVars + 1,
encode_short_det(VarNum, VarBytes),
encode_string_as_table_offset(VarName, VarNameBytes, !StringTable),
!:VarNameTableBytes = VarBytes ++ VarNameBytes ++ !.VarNameTableBytes
).
:- pred encode_var_name_table_entry_4_byte(prog_var::in, pair(int, string)::in,
int::in, int::out, list(int)::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_var_name_table_entry_4_byte(_ProgVar, VarNum - VarName,
!NumVars, !VarNameTableBytes, !StringTable) :-
( if compiler_introduced_varname(VarName) then
true
else
!:NumVars = !.NumVars + 1,
encode_int32_det(VarNum, VarBytes),
encode_string_as_table_offset(VarName, VarNameBytes, !StringTable),
!:VarNameTableBytes = VarBytes ++ VarNameBytes ++ !.VarNameTableBytes
).
:- pred encode_var_name_type_table_entry(var_num_rep::in, vartypes::in,
prog_var::in, pair(int, string)::in, int::in, int::out,
list(int)::in, list(int)::out,
string_table_info::in, string_table_info::out,
type_table_info::in, type_table_info::out) is det.
encode_var_name_type_table_entry(VarNumRep, VarTypes, Var, VarNum - VarName,
!NumVars, !VarNameTableBytes, !StringTable, !TypeTable) :-
!:NumVars = !.NumVars + 1,
lookup_var_type(VarTypes, Var, Type),
(
VarNumRep = var_num_1_byte,
VarBytes = [VarNum]
;
VarNumRep = var_num_2_bytes,
encode_short_det(VarNum, VarBytes)
;
VarNumRep = var_num_4_bytes,
encode_int32_det(VarNum, VarBytes)
),
encode_string_as_table_offset(VarName, VarNameBytes, !StringTable),
encode_type_as_table_ref(Type, TypeBytes, !StringTable, !TypeTable),
!:VarNameTableBytes = VarBytes ++ VarNameBytes ++ TypeBytes
++ !.VarNameTableBytes.
%-----------------------------------------------------------------------------%
:- pred compiler_introduced_varname(string::in) is semidet.
compiler_introduced_varname("").
compiler_introduced_varname("ProcStaticLayout").
compiler_introduced_varname("TopCSD").
compiler_introduced_varname("MiddleCSD").
compiler_introduced_varname("ActivationPtr").
compiler_introduced_varname("SiteNum").
compiler_introduced_varname("MethodNum").
compiler_introduced_varname(VarName) :-
( Prefix = "V_"
; Prefix = "HeadVar__"
; Prefix = "TypeClassInfo_for_"
; Prefix = "TypeInfo_"
; Prefix = "TypeCtorInfo_"
; Prefix = "STATE_VARIABLE_"
; Prefix = "DCG_"
),
prefix(VarName, Prefix).
%-----------------------------------------------------------------------------%
:- pred goal_to_byte_list(hlds_goal::in, instmap::in, prog_rep_info::in,
list(int)::out, string_table_info::in, string_table_info::out) is det.
goal_to_byte_list(Goal, InstMap0, Info, Bytes, !StringTable) :-
goal_to_goal_rep(Info, InstMap0, Goal, GoalRep),
encode_goal_rep(Info, GoalRep, Bytes, !StringTable).
goal_to_goal_rep(Info, Instmap0, hlds_goal(GoalExpr, GoalInfo), GoalRep) :-
Detism = goal_info_get_determinism(GoalInfo),
detism_to_detism_rep(Detism, DetismRep),
GoalRep = goal_rep(GoalExprRep, DetismRep, unit),
(
GoalExpr = conj(ConjType, Goals0),
FlattenParConjs = Info ^ pri_flatten_par_conjs,
(
FlattenParConjs = flatten_par_conjs,
% Flatten all conjunction types, the current conjunction may be a
% plain conjunction with par conjunctions in it, or vice-versa.
flatten_conj(Goals0, Goals)
;
FlattenParConjs = expect_no_par_conjs,
Goals = Goals0,
expect(unify(ConjType, plain_conj), $module, $pred,
"non-plain conjunction and declarative debugging")
),
conj_to_conj_rep(Info, Instmap0, Goals, GoalReps),
GoalExprRep = conj_rep(GoalReps)
;
GoalExpr = disj(Goals),
% Since eash disjunct begins with the same instmap we can use map
map(goal_to_goal_rep(Info, Instmap0), Goals, GoalReps),
GoalExprRep = disj_rep(GoalReps)
;
GoalExpr = negation(SubGoal),
goal_to_goal_rep(Info, Instmap0, SubGoal, SubGoalRep),
GoalExprRep = negation_rep(SubGoalRep)
;
GoalExpr = if_then_else(_, Cond, Then, Else),
Cond = hlds_goal(_, CondGoalInfo),
InstmapDelta = goal_info_get_instmap_delta(CondGoalInfo),
instmap.apply_instmap_delta(Instmap0, InstmapDelta, InstmapAfterCond),
goal_to_goal_rep(Info, Instmap0, Cond, CondRep),
goal_to_goal_rep(Info, InstmapAfterCond, Then, ThenRep),
goal_to_goal_rep(Info, Instmap0, Else, ElseRep),
GoalExprRep = ite_rep(CondRep, ThenRep, ElseRep)
;
GoalExpr = switch(Var, CanFail, Cases),
map(case_to_case_rep(Info, Instmap0), Cases, CasesRep),
(
CanFail = can_fail,
CanFailRep = switch_can_fail_rep
;
CanFail = cannot_fail,
CanFailRep = switch_can_not_fail_rep
),
VarRep = var_to_var_rep(Info, Var),
GoalExprRep = switch_rep(VarRep, CanFailRep, CasesRep)
;
GoalExpr = scope(_, SubGoal),
SubGoal = hlds_goal(_, SubGoalInfo),
goal_to_goal_rep(Info, Instmap0, SubGoal, SubGoalRep),
OuterDetism = goal_info_get_determinism(GoalInfo),
InnerDetism = goal_info_get_determinism(SubGoalInfo),
( if InnerDetism = OuterDetism then
MaybeCut = scope_is_no_cut
else
MaybeCut = scope_is_cut
),
GoalExprRep = scope_rep(SubGoalRep, MaybeCut)
;
( GoalExpr = unify(_, _, _, _, _)
; GoalExpr = generic_call(_, _, _, _, _)
; GoalExpr = plain_call(_, _, _, _, _, _)
; GoalExpr = call_foreign_proc(_, _, _, _, _, _, _)
),
goal_info_to_atomic_goal_rep_fields(GoalInfo, Instmap0, Info,
FileName, LineNo, BoundVars),
BoundVarsRep = map(var_to_var_rep(Info), BoundVars),
(
GoalExpr = unify(_, _, _, Unification, _),
(
Unification = assign(Target, Source),
AtomicGoalRep = unify_assign_rep(
var_to_var_rep(Info, Target),
var_to_var_rep(Info, Source))
;
( Unification = construct(Var, ConsId, Args, ArgModes, _, _, _)
; Unification = deconstruct(Var, ConsId, Args, ArgModes, _, _)
),
VarRep = var_to_var_rep(Info, Var),
ConsIdRep = cons_id_rep(ConsId),
ArgsRep = map(var_to_var_rep(Info), Args),
filter_input_args(Info, ArgModes, Args, MaybeArgs),
MaybeArgsRep = map(map_maybe(var_to_var_rep(Info)), MaybeArgs),
(
Unification = construct(_, _, _, _, _, _, _),
( if
list.all_true(lhs_final_is_ground(Info), ArgModes)
then
AtomicGoalRep = unify_construct_rep(VarRep, ConsIdRep,
ArgsRep)
else
AtomicGoalRep = partial_construct_rep(VarRep,
ConsIdRep, MaybeArgsRep)
)
;
Unification = deconstruct(_, _, _, _, _, _),
( if list.member(Var, BoundVars) then
AtomicGoalRep = partial_deconstruct_rep(VarRep,
ConsIdRep, MaybeArgsRep)
else
AtomicGoalRep = unify_deconstruct_rep(VarRep,
ConsIdRep, ArgsRep)
)
)
;
Unification = simple_test(Var1, Var2),
AtomicGoalRep = unify_simple_test_rep(
var_to_var_rep(Info, Var1),
var_to_var_rep(Info, Var2))
;
Unification = complicated_unify(_, _, _),
unexpected($module, $pred, "complicated_unify")
)
;
GoalExpr = generic_call(GenericCall, Args, _, _, _),
ArgsRep = map(var_to_var_rep(Info), Args),
(
GenericCall = higher_order(PredVar, _, _, _),
PredVarRep = var_to_var_rep(Info, PredVar),
AtomicGoalRep = higher_order_call_rep(PredVarRep, ArgsRep)
;
GenericCall = class_method(Var, Num, _, _),
VarRep = var_to_var_rep(Info, Var),
AtomicGoalRep = method_call_rep(VarRep, Num, ArgsRep)
;
GenericCall = event_call(EventName),
AtomicGoalRep = event_call_rep(EventName, ArgsRep)
;
GenericCall = cast(_),
( if ArgsRep = [InputArgRep, OutputArgRep] then
AtomicGoalRep = cast_rep(OutputArgRep, InputArgRep)
else
unexpected($module, $pred, "cast arity != 2")
)
)
;
GoalExpr = plain_call(PredId, _, Args, Builtin, _, _),
module_info_pred_info(Info ^ pri_module_info, PredId, PredInfo),
ModuleSymName = pred_info_module(PredInfo),
ModuleName = sym_name_to_string(ModuleSymName),
PredName = pred_info_name(PredInfo),
ArgsRep = map(var_to_var_rep(Info), Args),
(
Builtin = not_builtin,
AtomicGoalRep = plain_call_rep(ModuleName, PredName, ArgsRep)
;
Builtin = inline_builtin,
AtomicGoalRep = builtin_call_rep(ModuleName, PredName, ArgsRep)
)
;
GoalExpr = call_foreign_proc(_, _PredId, _, Args, _, _, _),
ArgVarsRep = list.map(
compose(var_to_var_rep(Info), foreign_arg_var), Args),
AtomicGoalRep = pragma_foreign_code_rep(ArgVarsRep)
),
GoalExprRep = atomic_goal_rep(FileName, LineNo, BoundVarsRep,
AtomicGoalRep)
;
GoalExpr = shorthand(_),
% These should have been expanded out by now.
unexpected($module, $pred, "unexpected shorthand")
).
:- pred conj_to_conj_rep(prog_rep_info::in, instmap::in, list(hlds_goal)::in,
list(goal_rep)::out) is det.
conj_to_conj_rep(_, _, [], []).
conj_to_conj_rep(Info, Instmap0, [Conj | Conjs], [ConjRep | ConjReps]) :-
goal_to_goal_rep(Info, Instmap0, Conj, ConjRep),
GoalInfo = Conj ^ hg_info,
InstmapDelta = goal_info_get_instmap_delta(GoalInfo),
instmap.apply_instmap_delta(Instmap0, InstmapDelta, Instmap1),
conj_to_conj_rep(Info, Instmap1, Conjs, ConjReps).
:- pred case_to_case_rep(prog_rep_info::in, instmap::in,
case::in, case_rep::out) is det.
case_to_case_rep(Info, Instmap, case(FirstConsId, OtherConsIds, Goal),
case_rep(FirstConsIdRep, OtherConsIdsRep, GoalRep)) :-
goal_to_goal_rep(Info, Instmap, Goal, GoalRep),
cons_id_to_cons_id_rep(FirstConsId, FirstConsIdRep),
map(cons_id_to_cons_id_rep, OtherConsIds, OtherConsIdsRep).
:- pred cons_id_to_cons_id_rep(cons_id::in, cons_id_arity_rep::out) is det.
cons_id_to_cons_id_rep(ConsId, cons_id_arity_rep(ConsIdName, Arity)) :-
ConsIdName = cons_id_rep(ConsId),
MaybeArity = cons_id_maybe_arity(ConsId),
(
MaybeArity = yes(Arity)
;
MaybeArity = no,
Arity = 0
).
:- pred detism_to_detism_rep(determinism::in, detism_rep::out) is det.
detism_to_detism_rep(detism_det, det_rep).
detism_to_detism_rep(detism_semi, semidet_rep).
detism_to_detism_rep(detism_multi, multidet_rep).
detism_to_detism_rep(detism_non, nondet_rep).
detism_to_detism_rep(detism_cc_multi, cc_multidet_rep).
detism_to_detism_rep(detism_cc_non, cc_nondet_rep).
detism_to_detism_rep(detism_erroneous, erroneous_rep).
detism_to_detism_rep(detism_failure, failure_rep).
:- pred encode_goal_rep(prog_rep_info::in, goal_rep::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_goal_rep(Info, goal_rep(GoalExpr, Detism, _), Bytes, !StringTable) :-
(
GoalExpr = conj_rep(GoalReps),
map_foldl(encode_goal_rep(Info), GoalReps, ConjBytesList,
!StringTable),
ExprBytes = [goal_type_to_byte(goal_conj)] ++
encode_length_func(GoalReps) ++ condense(ConjBytesList)
;
GoalExpr = disj_rep(GoalReps),
map_foldl(encode_goal_rep(Info), GoalReps, DisjBytesList,
!StringTable),
ExprBytes = [goal_type_to_byte(goal_disj)] ++
encode_length_func(GoalReps) ++ condense(DisjBytesList)
;
GoalExpr = negation_rep(SubGoal),
encode_goal_rep(Info, SubGoal, SubGoalBytes, !StringTable),
ExprBytes = [goal_type_to_byte(goal_neg)] ++ SubGoalBytes
;
GoalExpr = ite_rep(Cond, Then, Else),
encode_goal_rep(Info, Cond, CondBytes, !StringTable),
encode_goal_rep(Info, Then, ThenBytes, !StringTable),
encode_goal_rep(Info, Else, ElseBytes, !StringTable),
ExprBytes = [goal_type_to_byte(goal_ite)] ++
CondBytes ++ ThenBytes ++ ElseBytes
;
GoalExpr = atomic_goal_rep(FileName, Line, BoundVars, AtomicGoalRep),
encode_string_as_table_offset(FileName, FileNameBytes, !StringTable),
AtomicBytes = FileNameBytes ++ encode_lineno_func(Line) ++
encode_var_reps_func(Info, BoundVars),
(
AtomicGoalRep = unify_assign_rep(Target, Source),
ExprBytes = [goal_type_to_byte(goal_assign)] ++
encode_var_rep_func(Info, Target) ++
encode_var_rep_func(Info, Source) ++
AtomicBytes
;
( AtomicGoalRep = unify_construct_rep(_, _, _)
; AtomicGoalRep = unify_deconstruct_rep(_, _, _)
; AtomicGoalRep = partial_construct_rep(_, _, _)
; AtomicGoalRep = partial_deconstruct_rep(_, _, _)
),
(
(
AtomicGoalRep = unify_construct_rep(Var, ConsId, Args),
AtomicTypeByte = goal_type_to_byte(goal_construct)
;
AtomicGoalRep = unify_deconstruct_rep(Var, ConsId, Args),
AtomicTypeByte = goal_type_to_byte(goal_deconstruct)
),
ArgsBytes = encode_var_reps_func(Info, Args)
;
(
AtomicGoalRep = partial_deconstruct_rep(Var, ConsId,
MaybeArgs),
AtomicTypeByte =
goal_type_to_byte(goal_partial_deconstruct)
;
AtomicGoalRep = partial_construct_rep(Var, ConsId,
MaybeArgs),
AtomicTypeByte = goal_type_to_byte(goal_partial_construct)
),
ArgsBytes = encode_maybe_var_reps_func(Info, MaybeArgs)
),
encode_string_as_table_offset(ConsId, ConsIdBytes, !StringTable),
VarBytes = encode_var_rep_func(Info, Var),
ExprBytes = [AtomicTypeByte] ++ VarBytes ++ ConsIdBytes ++
ArgsBytes ++ AtomicBytes
;
AtomicGoalRep = unify_simple_test_rep(Var1, Var2),
ExprBytes = [goal_type_to_byte(goal_simple_test)] ++
encode_var_rep_func(Info, Var1) ++
encode_var_rep_func(Info, Var2) ++
AtomicBytes
;
AtomicGoalRep = higher_order_call_rep(PredVar, Args),
ExprBytes = [goal_type_to_byte(goal_ho_call)] ++
encode_var_rep_func(Info, PredVar) ++
encode_var_reps_func(Info, Args) ++
AtomicBytes
;
AtomicGoalRep = method_call_rep(Var, MethodNum, Args),
ExprBytes = [goal_type_to_byte(goal_method_call)] ++
encode_var_rep_func(Info, Var) ++
encode_method_num_func(MethodNum) ++
encode_var_reps_func(Info, Args) ++
AtomicBytes
;
AtomicGoalRep = event_call_rep(EventName, Args),
encode_string_as_table_offset(EventName, EventNameBytes,
!StringTable),
ExprBytes = [goal_type_to_byte(goal_event_call)] ++
EventNameBytes ++
encode_var_reps_func(Info, Args) ++
AtomicBytes
;
AtomicGoalRep = cast_rep(Target, Source),
ExprBytes = [goal_type_to_byte(goal_cast)] ++
encode_var_rep_func(Info, Target) ++
encode_var_rep_func(Info, Source) ++
AtomicBytes
;
(
AtomicGoalRep = plain_call_rep(ModuleName, PredName, Args),
CallType = goal_plain_call
;
AtomicGoalRep = builtin_call_rep(ModuleName, PredName, Args),
CallType = goal_builtin_call
),
encode_string_as_table_offset(ModuleName, ModuleNameBytes,
!StringTable),
encode_string_as_table_offset(PredName, PredNameBytes,
!StringTable),
ExprBytes = [goal_type_to_byte(CallType)] ++
ModuleNameBytes ++
PredNameBytes ++
encode_var_reps_func(Info, Args) ++
AtomicBytes
;
AtomicGoalRep = pragma_foreign_code_rep(Args),
ExprBytes = [goal_type_to_byte(goal_foreign)] ++
encode_var_reps_func(Info, Args) ++ AtomicBytes
)
;
GoalExpr = switch_rep(SwitchVar, CanFail, Cases),
list.map_foldl(encode_case_rep(Info), Cases, CasesBytesList,
!StringTable),
can_fail_byte(CanFail, CanFailByte),
ExprBytes = [goal_type_to_byte(goal_switch)] ++
[CanFailByte] ++
encode_var_rep_func(Info, SwitchVar) ++
encode_length_func(Cases) ++ list.condense(CasesBytesList)
;
GoalExpr = scope_rep(SubGoal, MaybeCut),
cut_byte(MaybeCut, MaybeCutByte),
encode_goal_rep(Info, SubGoal, SubGoalBytes, !StringTable),
ExprBytes = [goal_type_to_byte(goal_scope)] ++ [MaybeCutByte] ++
SubGoalBytes
),
determinism_representation(Detism, DetismByte),
Bytes = ExprBytes ++ [DetismByte].
:- pred encode_case_rep(prog_rep_info::in, case_rep::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_case_rep(Info, Case, Bytes, !StringTable) :-
Case = case_rep(MainConsId, OtherConsIds, Goal),
encode_goal_rep(Info, Goal, GoalBytes, !StringTable),
encode_cons_id_and_arity_rep(MainConsId, MainConsIdBytes, !StringTable),
map_foldl(encode_cons_id_and_arity_rep,
OtherConsIds, OtherConsIdsByteLists, !StringTable),
Bytes = MainConsIdBytes ++ encode_length_func(OtherConsIds) ++
list.condense(OtherConsIdsByteLists) ++ GoalBytes.
:- pred lhs_final_is_ground(prog_rep_info::in, unify_mode::in) is semidet.
lhs_final_is_ground(Info, UnifyMode) :-
UnifyMode = unify_modes_lhs_rhs(from_to_insts(_, LHSFinalInst), _),
inst_is_ground(Info ^ pri_module_info, LHSFinalInst).
:- pred rhs_is_input(prog_rep_info::in, unify_mode::in) is semidet.
rhs_is_input(Info, UnifyMode) :-
UnifyMode = unify_modes_lhs_rhs(_, RHSFromToInsts),
from_to_insts_is_input(Info ^ pri_module_info, RHSFromToInsts).
:- pred filter_input_args(prog_rep_info::in, list(unify_mode)::in,
list(prog_var)::in, list(maybe(prog_var))::out) is det.
filter_input_args(_, [], [], []).
filter_input_args(_, [], [_ | _], _) :-
unexpected($module, $pred, "mismatched lists").
filter_input_args(_, [_ | _], [], _) :-
unexpected($module, $pred, "mismatched lists").
filter_input_args(Info, [Mode | Modes], [Var | Vars],
[MaybeVar | MaybeVars]) :-
( if rhs_is_input(Info, Mode) then
MaybeVar = yes(Var)
else
MaybeVar = no
),
filter_input_args(Info, Modes, Vars, MaybeVars).
%-----------------------------------------------------------------------------%
:- pred goal_info_to_atomic_goal_rep_fields(hlds_goal_info::in, instmap::in,
prog_rep_info::in, string::out, int::out, list(prog_var)::out) is det.
goal_info_to_atomic_goal_rep_fields(GoalInfo, Instmap0, Info, FileName, LineNo,
BoundVars) :-
Context = goal_info_get_context(GoalInfo),
term.context_file(Context, FileName0),
( if FileName0 = Info ^ pri_filename then
FileName = ""
else
FileName = FileName0
),
term.context_line(Context, LineNo),
InstmapDelta = goal_info_get_instmap_delta(GoalInfo),
instmap_delta_changed_vars(InstmapDelta, ChangedVarsSet),
set_of_var.to_sorted_list(ChangedVarsSet, ChangedVars),
ModuleInfo = Info ^ pri_module_info,
list.negated_filter(var_is_ground_in_instmap(ModuleInfo, Instmap0),
ChangedVars, BoundVars).
:- pred encode_cons_id_and_arity_rep(cons_id_arity_rep::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_cons_id_and_arity_rep(ConsIdArity, ConsIdBytes, !StringTable) :-
ConsIdArity = cons_id_arity_rep(ConsId, Arity),
encode_string_as_table_offset(ConsId, FunctorBytes, !StringTable),
encode_short_det(Arity, ArityBytes),
ConsIdBytes = FunctorBytes ++ ArityBytes.
:- func cons_id_rep(cons_id) = string.
cons_id_rep(cons(SymName, _, _)) =
prog_rep.sym_base_name_to_string(SymName).
cons_id_rep(tuple_cons(_)) = "{}".
cons_id_rep(int_const(Int)) = string.int_to_string(Int).
cons_id_rep(uint_const(UInt)) = string.uint_to_string(UInt).
cons_id_rep(int8_const(Int8)) = string.int8_to_string(Int8).
cons_id_rep(uint8_const(UInt8)) = string.uint8_to_string(UInt8).
cons_id_rep(int16_const(Int16)) = string.int16_to_string(Int16).
cons_id_rep(uint16_const(UInt16)) = string.uint16_to_string(UInt16).
cons_id_rep(int32_const(Int32)) = string.int32_to_string(Int32).
cons_id_rep(uint32_const(UInt32)) = string.uint32_to_string(UInt32).
cons_id_rep(int64_const(Int64)) = string.int_to_string(Int64). % XXX INT64.
cons_id_rep(uint64_const(UInt64)) = string.int_to_string(UInt64). % XXX INT64.
cons_id_rep(float_const(Float)) = string.float_to_string(Float).
cons_id_rep(char_const(Char)) = string.char_to_string(Char).
cons_id_rep(string_const(String)) = """" ++ String ++ """".
cons_id_rep(impl_defined_const(Name)) = "$" ++ Name.
cons_id_rep(closure_cons(_, _)) = "$closure_cons".
cons_id_rep(type_ctor_info_const(_, _, _)) = "$type_ctor_info_const".
cons_id_rep(base_typeclass_info_const(_, _, _, _)) =
"$base_typeclass_info_const".
cons_id_rep(type_info_cell_constructor(_)) = "$type_info_cell_constructor".
cons_id_rep(typeclass_info_cell_constructor) =
"$typeclass_info_cell_constructor".
cons_id_rep(type_info_const(_)) = "$type_info_const".
cons_id_rep(typeclass_info_const(_)) = "$typeclass_info_const".
cons_id_rep(ground_term_const(_, _)) = "$ground_term_const".
cons_id_rep(tabling_info_const(_)) = "$tabling_info_const".
cons_id_rep(table_io_entry_desc(_)) = "$table_io_entry_desc".
cons_id_rep(deep_profiling_proc_layout(_)) = "$deep_profiling_proc_layout".
:- func sym_base_name_to_string(sym_name) = string.
sym_base_name_to_string(unqualified(String)) = String.
sym_base_name_to_string(qualified(_, String)) = String.
%-----------------------------------------------------------------------------%
% The operations to convert primitive constructs to bytecode.
%
% We use the operations defined in bytecode_data. Each of the functions below
% stands for a given primitive construct. If we need to expand the number of
% bytes we use to represent one of these, it should be sufficient to change
% the number of bits here and in mdbcomp/program_representation.m.
%
% Warning: the predicates we use from bytecode_data deal with signed integers,
% but we here use them to represent unsigned quantities. This effectively
% halves their range.
:- pred encode_string_as_table_offset(string::in, list(int)::out,
string_table_info::in, string_table_info::out) is det.
encode_string_as_table_offset(String, Bytes, !StringTable) :-
lookup_string_in_table(String, Index, !StringTable),
encode_int32_det(Index, Bytes).
:- pred encode_type_as_table_ref(mer_type::in, list(int)::out,
string_table_info::in, string_table_info::out,
type_table_info::in, type_table_info::out) is det.
encode_type_as_table_ref(Type, Bytes, !StringTable, !TypeTable) :-
lookup_type_in_table(Type, Index, !StringTable, !TypeTable),
encode_num_det(Index, Bytes).
:- func encode_var_reps_func(prog_rep_info, list(var_rep)) = list(int).
encode_var_reps_func(Info, Vars) =
encode_length_func(Vars) ++
list.condense(list.map(encode_var_rep_func(Info), Vars)).
:- func var_to_var_rep(prog_rep_info, prog_var) = int.
var_to_var_rep(Info, Var) = Num :-
map.lookup(Info ^ pri_var_num_map, Var, Num - _).
:- func encode_var_rep_func(prog_rep_info, var_rep) = list(int).
encode_var_rep_func(Info, Var) = Bytes :-
VarNumRep = Info ^ pri_var_num_rep,
(
VarNumRep = var_num_1_byte,
Bytes = [Var]
;
VarNumRep = var_num_2_bytes,
encode_short_det(Var, Bytes)
;
VarNumRep = var_num_4_bytes,
encode_int32_det(Var, Bytes)
).
:- func encode_maybe_var_reps_func(prog_rep_info, list(maybe(var_rep))) =
list(int).
encode_maybe_var_reps_func(Info, Vars) =
encode_length_func(Vars) ++
list.condense(list.map(encode_maybe_var_rep_func(Info), Vars)).
:- func encode_maybe_var_rep_func(prog_rep_info, maybe(var_rep)) = list(int).
encode_maybe_var_rep_func(Info, MaybeVar) = Bytes :-
% This is not the most efficient representation, however maybe(var_rep)s
% are only used for partial unifications, which are rare.
(
MaybeVar = yes(Var),
Bytes = [1 | encode_var_rep_func(Info, Var)]
;
MaybeVar = no,
Bytes = [0]
).
:- func encode_head_vars_func(prog_rep_info, instmap, instmap_delta,
list(prog_var)) = list(int).
encode_head_vars_func(Info, InitialInstmap, InstmapDelta, Vars) =
encode_length_func(Vars) ++
list.condense(list.map(
encode_head_var_func(Info, InitialInstmap, InstmapDelta), Vars)).
:- func encode_head_var_func(prog_rep_info, instmap, instmap_delta,
prog_var) = list(int).
encode_head_var_func(Info, InitialInstmap, InstmapDelta, Var) = Bytes :-
encode_var_rep_func(Info, var_to_var_rep(Info, Var)) = VarBytes,
ModuleInfo = Info ^ pri_module_info,
instmap_lookup_var(InitialInstmap, Var, InitialInst),
( if instmap_delta_search_var(InstmapDelta, Var, FinalInstPrime) then
FinalInst = FinalInstPrime
else
% If the variable is not in the instmap delta, then its instantiation
% cannot possibly change.
FinalInst = InitialInst
),
Bytes = VarBytes ++ [inst_to_byte(ModuleInfo, InitialInst),
inst_to_byte(ModuleInfo, FinalInst)].
:- func inst_to_byte(module_info, mer_inst) = int.
inst_to_byte(ModuleInfo, MerInst) = Byte :-
( if
( MerInst = free
; MerInst = free(_)
)
then
InstRep = ir_free_rep
else if
inst_is_ground(ModuleInfo, MerInst)
then
InstRep = ir_ground_rep
else
InstRep = ir_other_rep
),
inst_representation(InstRep, Byte).
:- func encode_length_func(list(T)) = list(int).
encode_length_func(List) = Bytes :-
encode_int32_det(list.length(List), Bytes).
:- func encode_lineno_func(int) = list(int).
encode_lineno_func(VarNum) = Bytes :-
encode_int32_det(VarNum, Bytes).
:- func encode_method_num_func(int) = list(int).
encode_method_num_func(VarNum) = Bytes :-
encode_short_det(VarNum, Bytes).
%-----------------------------------------------------------------------------%
:- end_module ll_backend.prog_rep.
%-----------------------------------------------------------------------------%