Files
mercury/compiler/bytecode_gen.m
Simon Taylor 82c6cdb55e Make definitions of abstract types available when generating
Estimated hours taken: 100
Branches: main

Make definitions of abstract types available when generating
code for importing modules.  This is necessary for the .NET
back-end, and for `:- pragma export' on the C back-end.

compiler/prog_data.m:
compiler/modules.m:
compiler/make.dependencies.m:
compiler/recompilation.version.m:
	Handle implementation sections in interface files.

	There is a new pseudo-declaration `abstract_imported'
	which is applied to items from the implementation
	section of an interface file.  `abstract_imported'
	items may not be used in the error checking passes
	for the curent module.

compiler/equiv_type_hlds.m:
compiler/notes/compiler_design.html:
	New file.

	Go over the HLDS expanding all types fully after
	semantic checking has been run.

compiler/mercury_compile.m:
	Add the new pass.

	Don't write the `.opt' file if there are any errors.

compiler/instmap.m:
	Add a predicate instmap_delta_map_foldl to apply
	a procedure to all insts in an instmap.

compiler/equiv_type.m:
	Export predicates for use by equiv_type_hlds.m

	Reorder arguments so state variables and higher-order
	programming can be used.

compiler/prog_data.m:
compiler/prog_io_pragma.m:
compiler/make_hlds.m:
compiler/mercury_to_mercury.m:
	Handle `:- pragma foreign_type' as a form of type
	declaration rather than a pragma.

compiler/hlds_data.m:
compiler/*.m:
	Add a field to the type_info_cell_constructor cons_id
	to identify the type_ctor, which is needed by
	equiv_type_hlds.m.

compiler/module_qual.m:
	Donn't allow items from the implementation section of
	interface files to match items in the current module.

compiler/*.m:
tests/*/*.m:
	Add missing imports which only became apparent with
	the bug fixes above.

	Remove unnecessary imports which only became apparent with
	the bug fixes above.

tests/hard_coded/Mmakefile:
tests/hard_coded/export_test2.{m,exp}:
	Test case.

tests/invalid/Mmakefile:
tests/invalid/missing_interface_import2.{m,err_exp}:
	Test case.
2003-12-01 15:56:15 +00:00

928 lines
32 KiB
Mathematica

%---------------------------------------------------------------------------%
% Copyright (C) 1996-2003 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% This module generates bytecode, which is intended to be used by a
% (not yet implemented) bytecode interpreter/debugger.
%
% Author: zs.
%
%---------------------------------------------------------------------------%
:- module bytecode_backend__bytecode_gen.
:- interface.
:- import_module bytecode_backend__bytecode.
:- import_module hlds__hlds_module.
:- import_module io, list.
:- pred bytecode_gen__module(module_info::in, list(byte_code)::out,
io__state::di, io__state::uo) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
% We make use of some stuff from the LLDS back-end, in particular the stuff
% relating to the argument passing convention in arg_info.m and call_gen.m.
% The intent here is to use the same argument passing convention as for
% the LLDS, to allow interoperability between code compiled to bytecode
% and code compiled to machine code.
%
% XXX It might be nice to move the argument passing related stuff
% in call_gen.m that we use here into arg_info.m, and to then rework
% arg_info.m so that it didn't depend on the LLDS.
:- import_module backend_libs__builtin_ops.
:- import_module backend_libs__code_model.
:- import_module check_hlds__mode_util.
:- import_module check_hlds__type_util.
:- import_module hlds__error_util.
:- import_module hlds__goal_util.
:- import_module hlds__hlds_code_util.
:- import_module hlds__hlds_data.
:- import_module hlds__hlds_goal.
:- import_module hlds__hlds_pred.
:- import_module hlds__passes_aux.
:- import_module libs__globals.
:- import_module libs__tree.
:- import_module ll_backend__arg_info.
:- import_module ll_backend__call_gen. % XXX for arg passing convention
:- import_module parse_tree__prog_data.
:- import_module parse_tree__prog_out.
:- import_module bool, int, string, list, assoc_list, set, map, varset.
:- import_module std_util, require, term, counter.
%---------------------------------------------------------------------------%
bytecode_gen__module(ModuleInfo, Code) -->
{ module_info_predids(ModuleInfo, PredIds) },
bytecode_gen__preds(PredIds, ModuleInfo, CodeTree),
{ tree__flatten(CodeTree, CodeList) },
{ list__condense(CodeList, Code) }.
:- pred bytecode_gen__preds(list(pred_id)::in, module_info::in,
byte_tree::out, io__state::di, io__state::uo) is det.
bytecode_gen__preds([], _ModuleInfo, empty) --> [].
bytecode_gen__preds([PredId | PredIds], ModuleInfo, Code) -->
{ module_info_preds(ModuleInfo, PredTable) },
{ map__lookup(PredTable, PredId, PredInfo) },
{ ProcIds = pred_info_non_imported_procids(PredInfo) },
( { ProcIds = [] } ->
{ PredCode = empty }
;
bytecode_gen__pred(PredId, ProcIds, PredInfo, ModuleInfo,
ProcsCode),
{ predicate_name(ModuleInfo, PredId, PredName) },
{ list__length(ProcIds, ProcsCount) },
{ Arity = pred_info_arity(PredInfo) },
{ bytecode_gen__get_is_func(PredInfo, IsFunc) },
{ EnterCode = node([enter_pred(PredName, Arity, IsFunc,
ProcsCount)]) },
{ EndofCode = node([endof_pred]) },
{ PredCode = tree(EnterCode, tree(ProcsCode, EndofCode)) }
),
bytecode_gen__preds(PredIds, ModuleInfo, OtherCode),
{ Code = tree(PredCode, OtherCode) }.
:- pred bytecode_gen__pred(pred_id::in, list(proc_id)::in, pred_info::in,
module_info::in, byte_tree::out, io__state::di, io__state::uo) is det.
bytecode_gen__pred(_PredId, [], _PredInfo, _ModuleInfo, empty) --> [].
bytecode_gen__pred(PredId, [ProcId | ProcIds], PredInfo, ModuleInfo, Code) -->
write_proc_progress_message("% Generating bytecode for ",
PredId, ProcId, ModuleInfo),
{ bytecode_gen__proc(ProcId, PredInfo, ModuleInfo, ProcCode) },
bytecode_gen__pred(PredId, ProcIds, PredInfo, ModuleInfo, ProcsCode),
{ Code = tree(ProcCode, ProcsCode) }.
:- pred bytecode_gen__proc(proc_id::in, pred_info::in,
module_info::in, byte_tree::out) is det.
bytecode_gen__proc(ProcId, PredInfo, ModuleInfo, Code) :-
pred_info_procedures(PredInfo, ProcTable),
map__lookup(ProcTable, ProcId, ProcInfo),
proc_info_goal(ProcInfo, Goal),
proc_info_vartypes(ProcInfo, VarTypes),
proc_info_varset(ProcInfo, VarSet),
proc_info_interface_determinism(ProcInfo, Detism),
determinism_to_code_model(Detism, CodeModel),
goal_util__goal_vars(Goal, GoalVars),
proc_info_headvars(ProcInfo, ArgVars),
set__insert_list(GoalVars, ArgVars, Vars),
set__to_sorted_list(Vars, VarList),
map__init(VarMap0),
bytecode_gen__create_varmap(VarList, VarSet, VarTypes, 0,
VarMap0, VarMap, VarInfos),
bytecode_gen__init_byte_info(ModuleInfo, VarMap, VarTypes, ByteInfo0),
bytecode_gen__get_next_label(ByteInfo0, ZeroLabel, ByteInfo1),
proc_info_arg_info(ProcInfo, ArgInfo),
assoc_list__from_corresponding_lists(ArgVars, ArgInfo, Args),
call_gen__input_arg_locs(Args, InputArgs),
bytecode_gen__gen_pickups(InputArgs, ByteInfo, PickupCode),
call_gen__output_arg_locs(Args, OutputArgs),
bytecode_gen__gen_places(OutputArgs, ByteInfo, PlaceCode),
% If semideterministic, reserve temp slot 0 for the return value
( CodeModel = model_semi ->
bytecode_gen__get_next_temp(ByteInfo1, _FrameTemp, ByteInfo2)
;
ByteInfo2 = ByteInfo1
),
bytecode_gen__goal(Goal, ByteInfo2, ByteInfo3, GoalCode),
bytecode_gen__get_next_label(ByteInfo3, EndLabel, ByteInfo),
bytecode_gen__get_counts(ByteInfo, LabelCount, TempCount),
ZeroLabelCode = node([label(ZeroLabel)]),
BodyTree =
tree(PickupCode,
tree(ZeroLabelCode,
tree(GoalCode,
PlaceCode))),
tree__flatten(BodyTree, BodyList),
list__condense(BodyList, BodyCode0),
( list__member(not_supported, BodyCode0) ->
BodyCode = node([not_supported])
;
BodyCode = node(BodyCode0)
),
proc_id_to_int(ProcId, ProcInt),
EnterCode = node([enter_proc(ProcInt, Detism, LabelCount, EndLabel,
TempCount, VarInfos)]),
( CodeModel = model_semi ->
EndofCode = node([semidet_succeed, label(EndLabel), endof_proc])
;
EndofCode = node([label(EndLabel), endof_proc])
),
Code = tree(EnterCode, tree(BodyCode, EndofCode)).
%---------------------------------------------------------------------------%
:- pred bytecode_gen__goal(hlds_goal::in, byte_info::in, byte_info::out,
byte_tree::out) is det.
bytecode_gen__goal(GoalExpr - GoalInfo, ByteInfo0, ByteInfo, Code) :-
bytecode_gen__goal_expr(GoalExpr, GoalInfo, ByteInfo0, ByteInfo,
GoalCode),
goal_info_get_context(GoalInfo, Context),
term__context_line(Context, Line),
Code = tree(node([context(Line)]), GoalCode).
:- pred bytecode_gen__goal_expr(hlds_goal_expr::in, hlds_goal_info::in,
byte_info::in, byte_info::out, byte_tree::out) is det.
bytecode_gen__goal_expr(GoalExpr, GoalInfo, ByteInfo0, ByteInfo, Code) :-
(
GoalExpr = generic_call(GenericCallType,
ArgVars, ArgModes, Detism),
( GenericCallType = higher_order(PredVar, _, _, _) ->
bytecode_gen__higher_order_call(PredVar, ArgVars,
ArgModes, Detism, ByteInfo0, Code),
ByteInfo = ByteInfo0
;
% XXX
functor(GenericCallType, _GenericCallFunctor, _),
/*string__append_list([
"bytecode for ", GenericCallFunctor, " calls"], Msg),
sorry(this_file, Msg)*/
Code = node([not_supported]),
ByteInfo = ByteInfo0
)
;
GoalExpr = call(PredId, ProcId, ArgVars, BuiltinState, _, _),
( BuiltinState = not_builtin ->
goal_info_get_determinism(GoalInfo, Detism),
bytecode_gen__call(PredId, ProcId, ArgVars, Detism,
ByteInfo0, Code)
;
bytecode_gen__builtin(PredId, ProcId, ArgVars,
ByteInfo0, Code)
),
ByteInfo = ByteInfo0
;
GoalExpr = unify(Var, RHS, _Mode, Unification, _),
bytecode_gen__unify(Unification, Var, RHS, ByteInfo0, Code),
ByteInfo = ByteInfo0
;
GoalExpr = not(Goal),
bytecode_gen__goal(Goal, ByteInfo0, ByteInfo1, SomeCode),
bytecode_gen__get_next_label(ByteInfo1, EndLabel, ByteInfo2),
bytecode_gen__get_next_temp(ByteInfo2, FrameTemp, ByteInfo),
EnterCode = node([enter_negation(FrameTemp, EndLabel)]),
EndofCode = node([endof_negation_goal(FrameTemp),
label(EndLabel), endof_negation]),
Code = tree(EnterCode,
tree(SomeCode,
EndofCode))
;
GoalExpr = some(_, _, Goal),
bytecode_gen__goal(Goal, ByteInfo0, ByteInfo1, SomeCode),
bytecode_gen__get_next_temp(ByteInfo1, Temp, ByteInfo),
EnterCode = node([enter_commit(Temp)]),
EndofCode = node([endof_commit(Temp)]),
Code = tree(EnterCode, tree(SomeCode, EndofCode))
;
GoalExpr = conj(GoalList),
bytecode_gen__conj(GoalList, ByteInfo0, ByteInfo, Code)
;
GoalExpr = par_conj(_GoalList),
sorry(this_file, "bytecode_gen of parallel conjunction")
;
GoalExpr = disj(GoalList),
( GoalList = [] ->
Code = node([fail]),
ByteInfo = ByteInfo0
;
bytecode_gen__get_next_label(ByteInfo0, EndLabel,
ByteInfo1),
bytecode_gen__disj(GoalList, ByteInfo1, EndLabel,
ByteInfo, DisjCode),
EnterCode = node([enter_disjunction(EndLabel)]),
EndofCode = node([endof_disjunction, label(EndLabel)]),
Code = tree(EnterCode, tree(DisjCode, EndofCode))
)
;
GoalExpr = switch(Var, _, CasesList),
bytecode_gen__get_next_label(ByteInfo0, EndLabel, ByteInfo1),
bytecode_gen__switch(CasesList, Var, ByteInfo1, EndLabel,
ByteInfo, SwitchCode),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
EnterCode = node([enter_switch(ByteVar, EndLabel)]),
EndofCode = node([endof_switch, label(EndLabel)]),
Code = tree(EnterCode, tree(SwitchCode, EndofCode))
;
GoalExpr = if_then_else(_Vars, Cond, Then, Else),
bytecode_gen__get_next_label(ByteInfo0, EndLabel, ByteInfo1),
bytecode_gen__get_next_label(ByteInfo1, ElseLabel, ByteInfo2),
bytecode_gen__get_next_temp(ByteInfo2, FrameTemp, ByteInfo3),
bytecode_gen__goal(Cond, ByteInfo3, ByteInfo4, CondCode),
bytecode_gen__goal(Then, ByteInfo4, ByteInfo5, ThenCode),
bytecode_gen__goal(Else, ByteInfo5, ByteInfo, ElseCode),
EnterIfCode = node([enter_if(ElseLabel, EndLabel, FrameTemp)]),
EnterThenCode = node([enter_then(FrameTemp)]),
EndofThenCode = node([endof_then(EndLabel), label(ElseLabel),
enter_else(FrameTemp)]),
EndofIfCode = node([endof_if, label(EndLabel)]),
Code =
tree(EnterIfCode,
tree(CondCode,
tree(EnterThenCode,
tree(ThenCode,
tree(EndofThenCode,
tree(ElseCode,
EndofIfCode))))))
;
GoalExpr = foreign_proc(_, _, _, _, _, _, _),
Code = node([not_supported]),
ByteInfo = ByteInfo0
;
GoalExpr = shorthand(_),
% these should have been expanded out by now
unexpected(this_file, "bytecode_gen__goal_expr: unexpected shorthand")
).
%---------------------------------------------------------------------------%
:- pred bytecode_gen__gen_places(list(pair(prog_var, arg_loc))::in,
byte_info::in, byte_tree::out) is det.
bytecode_gen__gen_places([], _, empty).
bytecode_gen__gen_places([Var - Loc | OutputArgs], ByteInfo, Code) :-
bytecode_gen__gen_places(OutputArgs, ByteInfo, OtherCode),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
Code = tree(node([place_arg(r, Loc, ByteVar)]), OtherCode).
:- pred bytecode_gen__gen_pickups(list(pair(prog_var, arg_loc))::in,
byte_info::in, byte_tree::out) is det.
bytecode_gen__gen_pickups([], _, empty).
bytecode_gen__gen_pickups([Var - Loc | OutputArgs], ByteInfo, Code) :-
bytecode_gen__gen_pickups(OutputArgs, ByteInfo, OtherCode),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
Code = tree(node([pickup_arg(r, Loc, ByteVar)]), OtherCode).
%---------------------------------------------------------------------------%
% Generate bytecode for a higher order call.
:- pred bytecode_gen__higher_order_call(prog_var::in, list(prog_var)::in,
list(mode)::in, determinism::in, byte_info::in, byte_tree::out) is det.
bytecode_gen__higher_order_call(PredVar, ArgVars, ArgModes, Detism,
ByteInfo, Code) :-
determinism_to_code_model(Detism, CodeModel),
bytecode_gen__get_module_info(ByteInfo, ModuleInfo),
list__map(bytecode_gen__get_var_type(ByteInfo), ArgVars, ArgTypes),
make_arg_infos(ArgTypes, ArgModes, CodeModel, ModuleInfo, ArgInfo),
assoc_list__from_corresponding_lists(ArgVars, ArgInfo, ArgVarsInfos),
arg_info__partition_args(ArgVarsInfos, InVars, OutVars),
list__length(InVars, NInVars),
list__length(OutVars, NOutVars),
call_gen__input_arg_locs(ArgVarsInfos, InputArgs),
bytecode_gen__gen_places(InputArgs, ByteInfo, PlaceArgs),
call_gen__output_arg_locs(ArgVarsInfos, OutputArgs),
bytecode_gen__gen_pickups(OutputArgs, ByteInfo, PickupArgs),
bytecode_gen__map_var(ByteInfo, PredVar, BytePredVar),
Call = node([higher_order_call(BytePredVar, NInVars, NOutVars,
Detism)]),
( CodeModel = model_semi ->
Check = node([semidet_success_check])
;
Check = empty
),
Code = tree(PlaceArgs, tree(Call, tree(Check, PickupArgs))).
% Generate bytecode for an ordinary call.
:- pred bytecode_gen__call(pred_id::in, proc_id::in, list(prog_var)::in,
determinism::in, byte_info::in, byte_tree::out) is det.
bytecode_gen__call(PredId, ProcId, ArgVars, Detism, ByteInfo, Code) :-
bytecode_gen__get_module_info(ByteInfo, ModuleInfo),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_arg_info(ProcInfo, ArgInfo),
assoc_list__from_corresponding_lists(ArgVars, ArgInfo, ArgVarsInfos),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
bytecode_gen__get_is_func(PredInfo, IsFunc),
call_gen__input_arg_locs(ArgVarsInfos, InputArgs),
bytecode_gen__gen_places(InputArgs, ByteInfo, PlaceArgs),
call_gen__output_arg_locs(ArgVarsInfos, OutputArgs),
bytecode_gen__gen_pickups(OutputArgs, ByteInfo, PickupArgs),
predicate_id(ModuleInfo, PredId, ModuleName, PredName, Arity),
proc_id_to_int(ProcId, ProcInt),
Call = node([call(ModuleName, PredName, Arity, IsFunc, ProcInt)]),
determinism_to_code_model(Detism, CodeModel),
( CodeModel = model_semi ->
Check = node([semidet_success_check])
;
Check = empty
),
Code = tree(PlaceArgs, tree(Call, tree(Check, PickupArgs))).
% Generate bytecode for a call to a builtin.
:- pred bytecode_gen__builtin(pred_id::in, proc_id::in, list(prog_var)::in,
byte_info::in, byte_tree::out) is det.
bytecode_gen__builtin(PredId, ProcId, Args, ByteInfo, Code) :-
bytecode_gen__get_module_info(ByteInfo, ModuleInfo),
predicate_module(ModuleInfo, PredId, ModuleName),
predicate_name(ModuleInfo, PredId, PredName),
(
builtin_ops__translate_builtin(ModuleName, PredName, ProcId,
Args, SimpleCode)
->
(
SimpleCode = test(Test),
bytecode_gen__map_test(ByteInfo, Test, Code)
;
SimpleCode = assign(Var, Expr),
bytecode_gen__map_assign(ByteInfo, Var, Expr,
Code)
)
;
string__append("unknown builtin predicate ", PredName, Msg),
unexpected(this_file, Msg)
).
:- pred bytecode_gen__map_test(byte_info::in,
simple_expr(prog_var)::in(simple_test_expr),
byte_tree::out) is det.
bytecode_gen__map_test(ByteInfo, TestExpr, Code) :-
(
TestExpr = binary(Binop, X, Y),
bytecode_gen__map_arg(ByteInfo, X, ByteX),
bytecode_gen__map_arg(ByteInfo, Y, ByteY),
Code = node([builtin_bintest(Binop, ByteX, ByteY)])
;
TestExpr = unary(Unop, X),
bytecode_gen__map_arg(ByteInfo, X, ByteX),
Code = node([builtin_untest(Unop, ByteX)])
).
:- pred bytecode_gen__map_assign(byte_info::in, prog_var::in,
simple_expr(prog_var)::in(simple_assign_expr),
byte_tree::out) is det.
bytecode_gen__map_assign(ByteInfo, Var, Expr, Code) :-
(
Expr = binary(Binop, X, Y),
bytecode_gen__map_arg(ByteInfo, X, ByteX),
bytecode_gen__map_arg(ByteInfo, Y, ByteY),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
Code = node([builtin_binop(Binop, ByteX, ByteY, ByteVar)])
;
Expr = unary(Unop, X),
bytecode_gen__map_arg(ByteInfo, X, ByteX),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
Code = node([builtin_unop(Unop, ByteX, ByteVar)])
;
Expr = leaf(X),
bytecode_gen__map_var(ByteInfo, X, ByteX),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
Code = node([assign(ByteVar, ByteX)])
).
:- pred bytecode_gen__map_arg(byte_info::in,
simple_expr(prog_var)::in(simple_arg_expr),
byte_arg::out) is det.
bytecode_gen__map_arg(ByteInfo, Expr, ByteArg) :-
(
Expr = leaf(Var),
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
ByteArg = var(ByteVar)
;
Expr = int_const(IntVal),
ByteArg = int_const(IntVal)
;
Expr = float_const(FloatVal),
ByteArg = float_const(FloatVal)
).
%---------------------------------------------------------------------------%
% Generate bytecode for a unification.
:- pred bytecode_gen__unify(unification::in, prog_var::in, unify_rhs::in,
byte_info::in, byte_tree::out) is det.
bytecode_gen__unify(construct(Var, ConsId, Args, UniModes, _, _, _),
_, _, ByteInfo, Code) :-
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
bytecode_gen__map_vars(ByteInfo, Args, ByteArgs),
bytecode_gen__map_cons_id(ByteInfo, Var, ConsId, ByteConsId),
(
ByteConsId = pred_const(_, _, _, _, _)
->
Code = node([construct(ByteVar, ByteConsId, ByteArgs)])
;
% Don't call bytecode_gen__map_uni_modes until after
% the pred_const test fails, since the arg-modes on
% unifications that create closures aren't like other arg-modes.
bytecode_gen__map_uni_modes(UniModes, Args, ByteInfo, Dirs),
(
bytecode_gen__all_dirs_same(Dirs, to_var)
->
Code = node([construct(ByteVar, ByteConsId, ByteArgs)])
;
assoc_list__from_corresponding_lists(ByteArgs, Dirs,
Pairs),
Code = node([complex_construct(ByteVar, ByteConsId,
Pairs)])
)
).
bytecode_gen__unify(deconstruct(Var, ConsId, Args, UniModes, _, _), _, _,
ByteInfo, Code) :-
bytecode_gen__map_var(ByteInfo, Var, ByteVar),
bytecode_gen__map_vars(ByteInfo, Args, ByteArgs),
bytecode_gen__map_cons_id(ByteInfo, Var, ConsId, ByteConsId),
bytecode_gen__map_uni_modes(UniModes, Args, ByteInfo, Dirs),
(
bytecode_gen__all_dirs_same(Dirs, to_arg)
->
Code = node([deconstruct(ByteVar, ByteConsId, ByteArgs)])
;
assoc_list__from_corresponding_lists(ByteArgs, Dirs, Pairs),
Code = node([complex_deconstruct(ByteVar, ByteConsId, Pairs)])
).
bytecode_gen__unify(assign(Target, Source), _, _, ByteInfo, Code) :-
bytecode_gen__map_var(ByteInfo, Target, ByteTarget),
bytecode_gen__map_var(ByteInfo, Source, ByteSource),
Code = node([assign(ByteTarget, ByteSource)]).
bytecode_gen__unify(simple_test(Var1, Var2), _, _, ByteInfo, Code) :-
bytecode_gen__map_var(ByteInfo, Var1, ByteVar1),
bytecode_gen__map_var(ByteInfo, Var2, ByteVar2),
bytecode_gen__get_var_type(ByteInfo, Var1, Var1Type),
bytecode_gen__get_var_type(ByteInfo, Var2, Var2Type),
(
type_to_ctor_and_args(Var1Type, TypeCtor1, _),
type_to_ctor_and_args(Var2Type, TypeCtor2, _)
->
( TypeCtor2 = TypeCtor1 ->
TypeCtor = TypeCtor1
; unexpected(this_file,
"simple_test between different types")
)
;
unexpected(this_file, "failed lookup of type id")
),
ByteInfo = byte_info(_, _, ModuleInfo, _, _),
TypeCategory = classify_type_ctor(ModuleInfo, TypeCtor),
(
TypeCategory = int_type,
TestId = int_test
;
TypeCategory = char_type,
TestId = char_test
;
TypeCategory = str_type,
TestId = string_test
;
TypeCategory = float_type,
TestId = float_test
;
TypeCategory = enum_type,
TestId = enum_test
;
TypeCategory = higher_order_type,
unexpected(this_file, "higher_order_type in simple_test")
;
TypeCategory = tuple_type,
unexpected(this_file, "tuple_type in simple_test")
;
TypeCategory = user_ctor_type,
unexpected(this_file, "user_ctor_type in simple_test")
;
TypeCategory = variable_type,
unexpected(this_file, "variable_type in simple_test")
;
TypeCategory = void_type,
unexpected(this_file, "void_type in simple_test")
;
TypeCategory = type_info_type,
unexpected(this_file, "type_info_type in simple_test")
;
TypeCategory = type_ctor_info_type,
unexpected(this_file, "type_ctor_info_type in simple_test")
;
TypeCategory = typeclass_info_type,
unexpected(this_file, "typeclass_info_type in simple_test")
;
TypeCategory = base_typeclass_info_type,
unexpected(this_file, "base_typeclass_info_type in simple_test")
),
Code = node([test(ByteVar1, ByteVar2, TestId)]).
bytecode_gen__unify(complicated_unify(_,_,_), _Var, _RHS, _ByteInfo, _Code) :-
unexpected(this_file,
"complicated unifications should have been handled by polymorphism.m").
:- pred bytecode_gen__map_uni_modes(list(uni_mode)::in, list(prog_var)::in,
byte_info::in, list(byte_dir)::out) is det.
bytecode_gen__map_uni_modes([], [], _, []).
bytecode_gen__map_uni_modes([UniMode | UniModes], [Arg | Args], ByteInfo,
[Dir | Dirs]) :-
UniMode = ((VarInitial - ArgInitial) -> (VarFinal - ArgFinal)),
bytecode_gen__get_module_info(ByteInfo, ModuleInfo),
bytecode_gen__get_var_type(ByteInfo, Arg, Type),
mode_to_arg_mode(ModuleInfo, (VarInitial -> VarFinal), Type, VarMode),
mode_to_arg_mode(ModuleInfo, (ArgInitial -> ArgFinal), Type, ArgMode),
(
VarMode = top_in,
ArgMode = top_out
->
Dir = to_arg
;
VarMode = top_out,
ArgMode = top_in
->
Dir = to_var
;
VarMode = top_unused,
ArgMode = top_unused
->
Dir = to_none
;
unexpected(this_file, "invalid mode for (de)construct unification")
),
bytecode_gen__map_uni_modes(UniModes, Args, ByteInfo, Dirs).
bytecode_gen__map_uni_modes([], [_|_], _, _) :-
unexpected(this_file, "bytecode_gen__map_uni_modes: length mismatch").
bytecode_gen__map_uni_modes([_|_], [], _, _) :-
unexpected(this_file, "bytecode_gen__map_uni_modes: length mismatch").
:- pred bytecode_gen__all_dirs_same(list(byte_dir)::in, byte_dir::in)
is semidet.
bytecode_gen__all_dirs_same([], _).
bytecode_gen__all_dirs_same([Dir | Dirs], Dir) :-
bytecode_gen__all_dirs_same(Dirs, Dir).
%---------------------------------------------------------------------------%
% Generate bytecode for a conjunction
:- pred bytecode_gen__conj(list(hlds_goal)::in, byte_info::in, byte_info::out,
byte_tree::out) is det.
bytecode_gen__conj([], ByteInfo, ByteInfo, empty).
bytecode_gen__conj([Goal | Goals], ByteInfo0, ByteInfo, Code) :-
bytecode_gen__goal(Goal, ByteInfo0, ByteInfo1, ThisCode),
bytecode_gen__conj(Goals, ByteInfo1, ByteInfo, OtherCode),
Code = tree(ThisCode, OtherCode).
%---------------------------------------------------------------------------%
% Generate bytecode for each disjunct of a disjunction.
:- pred bytecode_gen__disj(list(hlds_goal)::in, byte_info::in,
int::in, byte_info::out, byte_tree::out) is det.
bytecode_gen__disj([], _, _, _, _) :-
unexpected(this_file, "empty disjunction in bytecode_gen__disj").
bytecode_gen__disj([Disjunct | Disjuncts], ByteInfo0, EndLabel,
ByteInfo, Code) :-
bytecode_gen__goal(Disjunct, ByteInfo0, ByteInfo1, ThisCode),
( Disjuncts = [] ->
EnterCode = node([enter_disjunct(-1)]),
EndofCode = node([endof_disjunct(EndLabel)]),
Code = tree(EnterCode, tree(ThisCode, EndofCode)),
ByteInfo = ByteInfo1
;
bytecode_gen__disj(Disjuncts, ByteInfo1, EndLabel,
ByteInfo2, OtherCode),
bytecode_gen__get_next_label(ByteInfo2, NextLabel, ByteInfo),
EnterCode = node([enter_disjunct(NextLabel)]),
EndofCode = node([endof_disjunct(EndLabel), label(NextLabel)]),
Code =
tree(EnterCode,
tree(ThisCode,
tree(EndofCode,
OtherCode)))
).
%---------------------------------------------------------------------------%
% Generate bytecode for each arm of a switch.
:- pred bytecode_gen__switch(list(case)::in, prog_var::in, byte_info::in,
int::in, byte_info::out, byte_tree::out) is det.
bytecode_gen__switch([], _, ByteInfo, _, ByteInfo, empty).
bytecode_gen__switch([case(ConsId, Goal) | Cases], Var, ByteInfo0, EndLabel,
ByteInfo, Code) :-
bytecode_gen__map_cons_id(ByteInfo, Var, ConsId, ByteConsId),
bytecode_gen__goal(Goal, ByteInfo0, ByteInfo1, ThisCode),
bytecode_gen__switch(Cases, Var, ByteInfo1, EndLabel,
ByteInfo2, OtherCode),
bytecode_gen__get_next_label(ByteInfo2, NextLabel, ByteInfo),
EnterCode = node([enter_switch_arm(ByteConsId, NextLabel)]),
EndofCode = node([endof_switch_arm(EndLabel), label(NextLabel)]),
Code = tree(EnterCode, tree(ThisCode, tree(EndofCode, OtherCode))).
%---------------------------------------------------------------------------%
:- pred bytecode_gen__map_cons_id(byte_info::in, prog_var::in, cons_id::in,
byte_cons_id::out) is det.
bytecode_gen__map_cons_id(ByteInfo, Var, ConsId, ByteConsId) :-
bytecode_gen__get_module_info(ByteInfo, ModuleInfo),
(
ConsId = cons(Functor, Arity),
bytecode_gen__get_var_type(ByteInfo, Var, Type),
(
% Everything other than characters and tuples should
% be module qualified.
Functor = unqualified(FunctorName),
\+ type_is_tuple(Type, _)
->
string__to_char_list(FunctorName, FunctorList),
( FunctorList = [Char] ->
ByteConsId = char_const(Char)
;
unexpected(this_file,
"map_cons_id: unqualified cons_id is not a char_const")
)
;
(
Functor = unqualified(FunctorName),
ModuleName = unqualified("builtin")
;
Functor = qualified(ModuleName, FunctorName)
),
ConsTag = cons_id_to_tag(ConsId, Type, ModuleInfo),
bytecode_gen__map_cons_tag(ConsTag, ByteConsTag),
ByteConsId = cons(ModuleName, FunctorName,
Arity, ByteConsTag)
)
;
ConsId = int_const(IntVal),
ByteConsId = int_const(IntVal)
;
ConsId = string_const(StringVal),
ByteConsId = string_const(StringVal)
;
ConsId = float_const(FloatVal),
ByteConsId = float_const(FloatVal)
;
ConsId = pred_const(PredId, ProcId, EvalMethod),
( EvalMethod = normal ->
predicate_id(ModuleInfo, PredId,
ModuleName, PredName, Arity),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
bytecode_gen__get_is_func(PredInfo, IsFunc),
proc_id_to_int(ProcId, ProcInt),
ByteConsId = pred_const(ModuleName,
PredName, Arity, IsFunc, ProcInt)
;
% XXX
sorry(this_file, "bytecode for Aditi lambda expressions")
)
;
ConsId = type_ctor_info_const(ModuleName, TypeName, TypeArity),
ByteConsId = type_ctor_info_const(ModuleName, TypeName,
TypeArity)
;
ConsId = base_typeclass_info_const(ModuleName, ClassId,
_, Instance),
ByteConsId = base_typeclass_info_const(ModuleName, ClassId,
Instance)
;
ConsId = type_info_cell_constructor(_),
ByteConsId = type_info_cell_constructor
;
ConsId = typeclass_info_cell_constructor,
ByteConsId = typeclass_info_cell_constructor
;
ConsId = tabling_pointer_const(_, _),
sorry(this_file, "bytecode cannot implement tabling")
;
ConsId = table_io_decl(_),
sorry(this_file, "bytecode cannot implement table io decl")
;
ConsId = deep_profiling_proc_static(_),
sorry(this_file, "bytecode cannot implement deep profiling")
).
:- pred bytecode_gen__map_cons_tag(cons_tag::in, byte_cons_tag::out) is det.
bytecode_gen__map_cons_tag(no_tag, no_tag).
% `single_functor' is just an optimized version of `unshared_tag(0)'
% this optimization is not important for the bytecode
bytecode_gen__map_cons_tag(single_functor, unshared_tag(0)).
bytecode_gen__map_cons_tag(unshared_tag(Primary), unshared_tag(Primary)).
bytecode_gen__map_cons_tag(shared_remote_tag(Primary, Secondary),
shared_remote_tag(Primary, Secondary)).
bytecode_gen__map_cons_tag(shared_local_tag(Primary, Secondary),
shared_local_tag(Primary, Secondary)).
bytecode_gen__map_cons_tag(string_constant(_), _) :-
unexpected(this_file, "string_constant cons tag for non-string_constant cons id").
bytecode_gen__map_cons_tag(int_constant(IntVal), enum_tag(IntVal)).
bytecode_gen__map_cons_tag(float_constant(_), _) :-
unexpected(this_file, "float_constant cons tag for non-float_constant cons id").
bytecode_gen__map_cons_tag(pred_closure_tag(_, _, _), _) :-
unexpected(this_file, "pred_closure_tag cons tag for non-pred_const cons id").
bytecode_gen__map_cons_tag(type_ctor_info_constant(_, _, _), _) :-
unexpected(this_file, "type_ctor_info_constant cons tag for non-type_ctor_info_constant cons id").
bytecode_gen__map_cons_tag(base_typeclass_info_constant(_, _, _), _) :-
unexpected(this_file, "base_typeclass_info_constant cons tag for non-base_typeclass_info_constant cons id").
bytecode_gen__map_cons_tag(tabling_pointer_constant(_, _), _) :-
unexpected(this_file, "tabling_pointer_constant cons tag for non-tabling_pointer_constant cons id").
bytecode_gen__map_cons_tag(deep_profiling_proc_static_tag(_), _) :-
unexpected(this_file, "deep_profiling_proc_static_tag cons tag for non-deep_profiling_proc_static cons id").
bytecode_gen__map_cons_tag(table_io_decl_tag(_), _) :-
unexpected(this_file, "table_io_decl_tag cons tag for non-table_io_decl cons id").
bytecode_gen__map_cons_tag(reserved_address(_), _) :-
% These should only be generated if the --num-reserved-addresses
% or --num-reserved-objects options are used.
sorry(this_file,
"bytecode with --num-reserved-addresses or --num-reserved-objects").
bytecode_gen__map_cons_tag(shared_with_reserved_addresses(_, _), _) :-
% These should only be generated if the --num-reserved-addresses
% or --num-reserved-objects options are used.
sorry(this_file,
"bytecode with --num-reserved-addresses or --num-reserved-objects").
%---------------------------------------------------------------------------%
:- pred bytecode_gen__create_varmap(list(prog_var)::in, prog_varset::in,
map(prog_var, type)::in, int::in, map(prog_var, byte_var)::in,
map(prog_var, byte_var)::out, list(byte_var_info)::out) is det.
bytecode_gen__create_varmap([], _, _, _, VarMap, VarMap, []).
bytecode_gen__create_varmap([Var | VarList], VarSet, VarTypes, N0,
VarMap0, VarMap, VarInfos) :-
map__det_insert(VarMap0, Var, N0, VarMap1),
N1 = N0 + 1,
varset__lookup_name(VarSet, Var, VarName),
map__lookup(VarTypes, Var, VarType),
bytecode_gen__create_varmap(VarList, VarSet, VarTypes, N1,
VarMap1, VarMap, VarInfos1),
VarInfos = [var_info(VarName, VarType) | VarInfos1].
%---------------------------------------------------------------------------%(
:- type byte_info
---> byte_info(
byteinfo_varmap :: map(prog_var, byte_var),
byteinfo_vartypes :: map(prog_var, type),
byteinfo_moduleinfo :: module_info,
byteinfo_label_counter :: counter,
byteinfo_temp_counter :: counter
).
:- pred bytecode_gen__init_byte_info(module_info::in,
map(prog_var, byte_var)::in, map(prog_var, type)::in,
byte_info::out) is det.
bytecode_gen__init_byte_info(ModuleInfo, VarMap, VarTypes, ByteInfo) :-
ByteInfo = byte_info(VarMap, VarTypes, ModuleInfo,
counter__init(0), counter__init(0)).
:- pred bytecode_gen__get_module_info(byte_info::in, module_info::out) is det.
bytecode_gen__get_module_info(ByteInfo, ByteInfo ^ byteinfo_moduleinfo).
:- pred bytecode_gen__map_vars(byte_info::in,
list(prog_var)::in, list(byte_var)::out) is det.
bytecode_gen__map_vars(ByteInfo, Vars, ByteVars) :-
bytecode_gen__map_vars_2(ByteInfo ^ byteinfo_varmap, Vars, ByteVars).
:- pred bytecode_gen__map_vars_2(map(prog_var, byte_var)::in,
list(prog_var)::in, list(byte_var)::out) is det.
bytecode_gen__map_vars_2(_VarMap, [], []).
bytecode_gen__map_vars_2(VarMap, [Var | Vars], [ByteVar | ByteVars]) :-
map__lookup(VarMap, Var, ByteVar),
bytecode_gen__map_vars_2(VarMap, Vars, ByteVars).
:- pred bytecode_gen__map_var(byte_info::in, prog_var::in,
byte_var::out) is det.
bytecode_gen__map_var(ByteInfo, Var, ByteVar) :-
map__lookup(ByteInfo ^ byteinfo_varmap, Var, ByteVar).
:- pred bytecode_gen__get_var_type(byte_info::in, prog_var::in,
(type)::out) is det.
bytecode_gen__get_var_type(ByteInfo, Var, Type) :-
map__lookup(ByteInfo ^ byteinfo_vartypes, Var, Type).
:- pred bytecode_gen__get_next_label(byte_info::in, int::out, byte_info::out)
is det.
bytecode_gen__get_next_label(ByteInfo0, Label, ByteInfo) :-
LabelCounter0 = ByteInfo0 ^ byteinfo_label_counter,
counter__allocate(Label, LabelCounter0, LabelCounter),
ByteInfo = ByteInfo0 ^ byteinfo_label_counter := LabelCounter.
:- pred bytecode_gen__get_next_temp(byte_info::in, int::out, byte_info::out)
is det.
bytecode_gen__get_next_temp(ByteInfo0, Temp, ByteInfo) :-
TempCounter0 = ByteInfo0 ^ byteinfo_temp_counter,
counter__allocate(Temp, TempCounter0, TempCounter),
ByteInfo = ByteInfo0 ^ byteinfo_temp_counter := TempCounter.
:- pred bytecode_gen__get_counts(byte_info::in, int::out, int::out) is det.
bytecode_gen__get_counts(ByteInfo0, Label, Temp) :-
LabelCounter0 = ByteInfo0 ^ byteinfo_label_counter,
counter__allocate(Label, LabelCounter0, _LabelCounter),
TempCounter0 = ByteInfo0 ^ byteinfo_temp_counter,
counter__allocate(Temp, TempCounter0, _TempCounter).
%---------------------------------------------------------------------------%
:- pred bytecode_gen__get_is_func(pred_info, byte_is_func).
:- mode bytecode_gen__get_is_func(in, out) is det.
bytecode_gen__get_is_func(PredInfo, IsFunc) :-
( pred_info_is_pred_or_func(PredInfo) = predicate ->
IsFunc = 0
;
IsFunc = 1
).
%---------------------------------------------------------------------------%
:- func this_file = string.
this_file = "bytecode_gen.m".
:- end_module bytecode_gen.
%---------------------------------------------------------------------------%