mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 14:25:56 +00:00
The main aim of this change is to make the overall, high-level structure of the compiler clearer, and to encourage better encapsulation of the major components. compiler/libs.m: compiler/backend_libs.m: compiler/parse_tree.m: compiler/hlds.m: compiler/check_hlds.m: compiler/transform_hlds.m: compiler/bytecode_backend.m: compiler/aditi_backend.m: compiler/ml_backend.m: compiler/ll_backend.m: compiler/top_level.m: New files. One module for each of the major components of the Mercury compiler. These modules contain (as separate sub-modules) all the other modules in the Mercury compiler, except gcc.m and mlds_to_gcc.m. Mmakefile: compiler/Mmakefile: Handle the fact that the top-level module is now `top_level', not `mercury_compile' (since `mercury_compile' is a sub-module of `top_level'). compiler/Mmakefile: Update settings of *FLAGS-<modulename> to use the appropriate nested module names. compiler/recompilation_check.m: compiler/recompilation_version.m: compiler/recompilation_usage.m: compiler/recompilation.check.m: compiler/recompilation.version.m: compiler/recompilation.version.m: Convert the `recompilation_*' modules into sub-modules of the `recompilation' module. compiler/*.m: compiler/*.pp: Module-qualify the module names in `:- module', `:- import_module', and `:- use_module' declarations. compiler/base_type_info.m: compiler/base_type_layout.m: Deleted these unused empty modules. compiler/prog_data.m: compiler/globals.m: Move the `foreign_language' type from prog_data to globals. compiler/mlds.m: compiler/ml_util.m: compiler/mlds_to_il.m: Import `globals', for `foreign_language'. Mmake.common.in: trace/Mmakefile: runtime/Mmakefile: Rename the %.check.c targets as %.check_hdr.c, to avoid conflicts with compiler/recompilation.check.c.
1955 lines
66 KiB
Mathematica
1955 lines
66 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2002 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: ml_unify_gen.m
|
|
% Main author: fjh
|
|
|
|
% This module is part of the MLDS code generator.
|
|
% It handles MLDS code generation for unifications.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend__ml_unify_gen.
|
|
:- interface.
|
|
|
|
:- import_module parse_tree__prog_data.
|
|
:- import_module hlds__hlds_module, hlds__hlds_data, hlds__hlds_goal.
|
|
:- import_module backend_libs__code_model.
|
|
:- import_module ml_backend__mlds, ml_backend__ml_code_util.
|
|
|
|
:- import_module bool, list, std_util.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate MLDS code for a unification.
|
|
%
|
|
:- pred ml_gen_unification(unification, code_model, prog_context,
|
|
mlds__defns, mlds__statements, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_unification(in, in, in, out, out, in, out) is det.
|
|
|
|
% Convert a cons_id for a given type to a cons_tag.
|
|
%
|
|
:- pred ml_cons_id_to_tag(cons_id, prog_type, cons_tag,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_cons_id_to_tag(in, in, out, in, out) is det.
|
|
|
|
% ml_gen_tag_test(Var, ConsId, Defns, Statements, Expression):
|
|
% Generate code to perform a tag test.
|
|
%
|
|
% The test checks whether Var has the functor specified by
|
|
% ConsId. The generated code may contain Defns, Statements
|
|
% and an Expression. The Expression is a boolean rval.
|
|
% After execution of the Statements, Expression will evaluate
|
|
% to true iff the Var has the functor specified by ConsId.
|
|
%
|
|
:- pred ml_gen_tag_test(prog_var, cons_id, mlds__defns, mlds__statements,
|
|
mlds__rval, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_tag_test(in, in, out, out, out, in, out) is det.
|
|
|
|
% ml_gen_secondary_tag_rval(PrimaryTag, VarType, ModuleInfo, VarRval):
|
|
% Return the rval for the secondary tag field of VarRval,
|
|
% assuming that VarRval has the specified VarType and PrimaryTag.
|
|
:- func ml_gen_secondary_tag_rval(tag_bits, prog_type, module_info, mlds__rval)
|
|
= mlds__rval.
|
|
|
|
% Generate an MLDS rval for a given reserved address,
|
|
% cast to the appropriate type.
|
|
:- func ml_gen_reserved_address(module_info, reserved_address, mlds__type) =
|
|
mlds__rval.
|
|
|
|
%
|
|
% ml_gen_new_object(MaybeConsId, Tag, HasSecTag, MaybeCtorName, Var,
|
|
% ExtraRvals, ExtraTypes, ArgVars, ArgModes, HowToConstruct,
|
|
% Context, MLDS_Decls, MLDS_Statements):
|
|
% Generate a `new_object' statement, or a static constant,
|
|
% depending on the value of the how_to_construct argument.
|
|
% The `ExtraRvals' and `ExtraTypes' arguments specify
|
|
% additional constants to insert at the start of the
|
|
% argument list.
|
|
%
|
|
:- pred ml_gen_new_object(maybe(cons_id), mlds__tag, bool, maybe(ctor_name),
|
|
prog_var, list(mlds__rval), list(mlds__type), prog_vars,
|
|
list(uni_mode), how_to_construct,
|
|
prog_context, mlds__defns, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_new_object(in, in, in, in, in, in, in, in, in, in, in, out, out,
|
|
in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds__hlds_pred, hlds__hlds_out, backend_libs__builtin_ops.
|
|
:- import_module ml_backend__ml_code_gen, ml_backend__ml_call_gen.
|
|
:- import_module ml_backend__ml_type_gen, ml_backend__ml_closure_gen.
|
|
:- import_module parse_tree__prog_util, check_hlds__type_util.
|
|
:- import_module check_hlds__mode_util.
|
|
:- import_module backend_libs__rtti, hlds__error_util.
|
|
:- import_module libs__globals, libs__options.
|
|
|
|
% XXX The following modules depend on the LLDS,
|
|
% so ideally they should not be used here.
|
|
:- import_module ll_backend__code_util. % needed for `cons_id_to_tag'.
|
|
|
|
:- import_module int, string, map, require, term, varset.
|
|
:- import_module assoc_list, set.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
ml_gen_unification(assign(Var1, Var2), CodeModel, Context,
|
|
[], MLDS_Statements) -->
|
|
{ require(unify(CodeModel, model_det),
|
|
"ml_code_gen: assign not det") },
|
|
(
|
|
%
|
|
% skip dummy argument types, since they will not have
|
|
% been declared
|
|
%
|
|
ml_variable_type(Var1, Type),
|
|
{ type_util__is_dummy_argument_type(Type) }
|
|
->
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
ml_gen_var(Var1, Var1Lval),
|
|
ml_gen_var(Var2, Var2Lval),
|
|
{ MLDS_Statement = ml_gen_assign(Var1Lval, lval(Var2Lval),
|
|
Context) },
|
|
{ MLDS_Statements = [MLDS_Statement] }
|
|
).
|
|
|
|
ml_gen_unification(simple_test(Var1, Var2), CodeModel, Context,
|
|
[], [MLDS_Statement]) -->
|
|
{ require(unify(CodeModel, model_semi),
|
|
"ml_code_gen: simple_test not semidet") },
|
|
ml_variable_type(Var1, Type),
|
|
{ Type = term__functor(term__atom("string"), [], _) ->
|
|
EqualityOp = str_eq
|
|
; Type = term__functor(term__atom("float"), [], _) ->
|
|
EqualityOp = float_eq
|
|
;
|
|
EqualityOp = eq
|
|
},
|
|
ml_gen_var(Var1, Var1Lval),
|
|
ml_gen_var(Var2, Var2Lval),
|
|
{ Test = binop(EqualityOp, lval(Var1Lval), lval(Var2Lval)) },
|
|
ml_gen_set_success(Test, Context, MLDS_Statement).
|
|
|
|
ml_gen_unification(construct(Var, ConsId, Args, ArgModes,
|
|
HowToConstruct, _CellIsUnique, MaybeAditiRLExprnID),
|
|
CodeModel, Context, MLDS_Decls, MLDS_Statements) -->
|
|
{ require(unify(CodeModel, model_det),
|
|
"ml_code_gen: construct not det") },
|
|
{ MaybeAditiRLExprnID = yes(_) ->
|
|
sorry(this_file, "Aditi closures")
|
|
;
|
|
true
|
|
},
|
|
ml_gen_construct(Var, ConsId, Args, ArgModes, HowToConstruct, Context,
|
|
MLDS_Decls, MLDS_Statements).
|
|
|
|
ml_gen_unification(deconstruct(Var, ConsId, Args, ArgModes, CanFail, CanCGC),
|
|
CodeModel, Context, MLDS_Decls, MLDS_Statements) -->
|
|
(
|
|
{ CanFail = can_fail },
|
|
{ ExpectedCodeModel = model_semi },
|
|
ml_gen_semi_deconstruct(Var, ConsId, Args, ArgModes, Context,
|
|
MLDS_Decls, MLDS_Unif_Statements)
|
|
;
|
|
{ CanFail = cannot_fail },
|
|
{ ExpectedCodeModel = model_det },
|
|
ml_gen_det_deconstruct(Var, ConsId, Args, ArgModes, Context,
|
|
MLDS_Decls, MLDS_Unif_Statements)
|
|
),
|
|
(
|
|
%
|
|
% Note that we can deallocate a cell even if the
|
|
% unification fails, it is the responsibility of the
|
|
% structure reuse phase to ensure that this is safe.
|
|
%
|
|
{ CanCGC = yes },
|
|
ml_gen_var(Var, VarLval),
|
|
{ MLDS_Stmt = atomic(delete_object(VarLval)) },
|
|
{ MLDS_CGC_Statements = [mlds__statement(MLDS_Stmt,
|
|
mlds__make_context(Context)) ] }
|
|
;
|
|
{ CanCGC = no },
|
|
{ MLDS_CGC_Statements = [] }
|
|
),
|
|
{ MLDS_Statements0 = MLDS_Unif_Statements `list__append`
|
|
MLDS_CGC_Statements },
|
|
%
|
|
% We used to require that CodeModel = ExpectedCodeModel.
|
|
% But the determinism field in the goal_info is allowed to
|
|
% be a conservative approximation, so we need to handle
|
|
% the case were CodeModel is less precise than
|
|
% ExpectedCodeModel.
|
|
%
|
|
ml_gen_wrap_goal(CodeModel, ExpectedCodeModel, Context,
|
|
MLDS_Statements0, MLDS_Statements).
|
|
|
|
ml_gen_unification(complicated_unify(_, _, _), _, _, [], []) -->
|
|
% simplify.m should convert these into procedure calls
|
|
{ error("ml_code_gen: complicated unify") }.
|
|
|
|
% ml_gen_construct generations code for a construction unification.
|
|
%
|
|
% Note that the code for ml_gen_static_const_arg is very similar to
|
|
% the code here, and any changes may need to be done in both places.
|
|
%
|
|
:- pred ml_gen_construct(prog_var, cons_id, prog_vars, list(uni_mode),
|
|
how_to_construct, prog_context, mlds__defns, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_construct(in, in, in, in, in, in, out, out, in, out) is det.
|
|
|
|
ml_gen_construct(Var, ConsId, Args, ArgModes, HowToConstruct, Context,
|
|
MLDS_Decls, MLDS_Statements) -->
|
|
%
|
|
% figure out how this cons_id is represented
|
|
%
|
|
ml_variable_type(Var, Type),
|
|
ml_cons_id_to_tag(ConsId, Type, Tag),
|
|
|
|
ml_gen_construct_2(Tag, Type, Var, ConsId, Args, ArgModes,
|
|
HowToConstruct, Context, MLDS_Decls, MLDS_Statements).
|
|
|
|
:- pred ml_gen_construct_2(cons_tag, prog_type, prog_var, cons_id, prog_vars,
|
|
list(uni_mode), how_to_construct, prog_context,
|
|
mlds__defns, mlds__statements, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_construct_2(in, in, in, in, in, in, in, in, out, out, in, out)
|
|
is det.
|
|
|
|
ml_gen_construct_2(Tag, Type, Var, ConsId, Args, ArgModes, HowToConstruct,
|
|
Context, MLDS_Decls, MLDS_Statements) -->
|
|
(
|
|
%
|
|
% types for which some other constructor has a
|
|
% reserved_address -- that only makes a difference when
|
|
% deconstructing, so here we ignore that, and just
|
|
% recurse on the representation for this constructor.
|
|
%
|
|
{ Tag = shared_with_reserved_addresses(_, ThisTag) }
|
|
->
|
|
ml_gen_construct_2(ThisTag, Type, Var, ConsId, Args, ArgModes,
|
|
HowToConstruct, Context, MLDS_Decls, MLDS_Statements)
|
|
;
|
|
%
|
|
% no_tag types
|
|
%
|
|
{ Tag = no_tag }
|
|
->
|
|
( { Args = [Arg], ArgModes = [ArgMode] } ->
|
|
ml_variable_type(Arg, ArgType),
|
|
ml_variable_type(Var, VarType),
|
|
ml_gen_var(Arg, ArgLval),
|
|
ml_gen_var(Var, VarLval),
|
|
ml_gen_sub_unify(ArgMode, ArgLval, ArgType, VarLval,
|
|
VarType, Context, [], MLDS_Statements),
|
|
{ MLDS_Decls = [] }
|
|
;
|
|
{ error("ml_code_gen: no_tag: arity != 1") }
|
|
)
|
|
;
|
|
%
|
|
% lambda expressions
|
|
%
|
|
{ Tag = pred_closure_tag(PredId, ProcId, EvalMethod) }
|
|
->
|
|
ml_gen_closure(PredId, ProcId, EvalMethod, Var, Args,
|
|
ArgModes, HowToConstruct, Context,
|
|
MLDS_Decls, MLDS_Statements)
|
|
;
|
|
%
|
|
% ordinary compound terms
|
|
%
|
|
{ Tag = single_functor
|
|
; Tag = unshared_tag(_TagVal)
|
|
; Tag = shared_remote_tag(_PrimaryTag, _SecondaryTag)
|
|
}
|
|
->
|
|
ml_gen_compound(Tag, ConsId, Var, Args,
|
|
ArgModes, HowToConstruct, Context,
|
|
MLDS_Decls, MLDS_Statements)
|
|
;
|
|
%
|
|
% constants
|
|
%
|
|
{ Args = [] }
|
|
->
|
|
ml_gen_var(Var, VarLval),
|
|
ml_gen_constant(Tag, Type, Rval),
|
|
{ MLDS_Statement = ml_gen_assign(VarLval, Rval, Context) },
|
|
{ MLDS_Decls = [] },
|
|
{ MLDS_Statements = [MLDS_Statement] }
|
|
;
|
|
{ error("ml_gen_construct: unknown compound term") }
|
|
).
|
|
|
|
% ml_gen_static_const_arg is similar to ml_gen_construct
|
|
% with HowToConstruct = construct_statically(_),
|
|
% except that for compound terms, rather than generating
|
|
% a new static constant, it just generates a reference
|
|
% to one that has already been defined.
|
|
%
|
|
% Note that any changes here may require similar changes to
|
|
% ml_gen_construct.
|
|
%
|
|
:- pred ml_gen_static_const_arg(prog_var, static_cons, mlds__rval,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_static_const_arg(in, in, out, in, out) is det.
|
|
|
|
ml_gen_static_const_arg(Var, StaticCons, Rval) -->
|
|
%
|
|
% figure out how this argument is represented
|
|
%
|
|
{ StaticCons = static_cons(ConsId, _ArgVars, _StaticArgs) },
|
|
ml_variable_type(Var, VarType),
|
|
ml_cons_id_to_tag(ConsId, VarType, Tag),
|
|
|
|
ml_gen_static_const_arg_2(Tag, VarType, Var, StaticCons, Rval).
|
|
|
|
:- pred ml_gen_static_const_arg_2(cons_tag, prog_type, prog_var, static_cons,
|
|
mlds__rval, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_static_const_arg_2(in, in, in, in, out, in, out) is det.
|
|
|
|
ml_gen_static_const_arg_2(Tag, VarType, Var, StaticCons, Rval) -->
|
|
{ StaticCons = static_cons(ConsId, ArgVars, StaticArgs) },
|
|
(
|
|
%
|
|
% types for which some other constructor has a
|
|
% reserved_address -- that only makes a difference when
|
|
% constructing, so here we ignore that, and just
|
|
% recurse on the representation for this constructor.
|
|
%
|
|
{ Tag = shared_with_reserved_addresses(_, ThisTag) }
|
|
->
|
|
ml_gen_static_const_arg_2(ThisTag, VarType, Var, StaticCons,
|
|
Rval)
|
|
;
|
|
%
|
|
% no_tag types
|
|
%
|
|
{ Tag = no_tag }
|
|
->
|
|
( { ArgVars = [Arg], StaticArgs = [StaticArg] } ->
|
|
% construct (statically) the argument,
|
|
% and then convert it to the appropriate type
|
|
ml_gen_static_const_arg(Arg, StaticArg, ArgRval),
|
|
ml_variable_type(Arg, ArgType),
|
|
ml_gen_box_or_unbox_rval(ArgType, VarType,
|
|
ArgRval, Rval)
|
|
;
|
|
{ error("ml_code_gen: no_tag: arity != 1") }
|
|
)
|
|
;
|
|
%
|
|
% compound terms, including lambda expressions
|
|
%
|
|
{ Tag = pred_closure_tag(_, _, _), TagVal = 0
|
|
; Tag = single_functor, TagVal = 0
|
|
; Tag = unshared_tag(TagVal)
|
|
; Tag = shared_remote_tag(TagVal, _SecondaryTag)
|
|
}
|
|
->
|
|
%
|
|
% If this argument is something that would normally be allocated
|
|
% on the heap, just generate a reference to the static constant
|
|
% that we must have already generated for it.
|
|
%
|
|
ml_gen_type(VarType, MLDS_VarType),
|
|
ml_gen_info_get_globals(Globals),
|
|
{ globals__lookup_bool_option(Globals, highlevel_data,
|
|
HighLevelData) },
|
|
{ UsesBaseClass = (ml_tag_uses_base_class(Tag) -> yes ; no) },
|
|
{ ConstType = get_type_for_cons_id(MLDS_VarType,
|
|
UsesBaseClass, yes(ConsId), HighLevelData) },
|
|
ml_gen_static_const_addr(Var, ConstType, ConstAddrRval),
|
|
{ TagVal = 0 ->
|
|
TaggedRval = ConstAddrRval
|
|
;
|
|
TaggedRval = mkword(TagVal, ConstAddrRval)
|
|
},
|
|
{ Rval = unop(cast(MLDS_VarType), TaggedRval) }
|
|
;
|
|
%
|
|
% If this argument is just a constant,
|
|
% then generate the rval for the constant
|
|
%
|
|
{ StaticArgs = [] }
|
|
->
|
|
ml_gen_constant(Tag, VarType, Rval)
|
|
;
|
|
{ error("ml_gen_static_const_arg: unknown compound term") }
|
|
).
|
|
|
|
%
|
|
% generate the rval for a given constant
|
|
%
|
|
:- pred ml_gen_constant(cons_tag, prog_type, mlds__rval,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_constant(in, in, out, in, out) is det.
|
|
|
|
ml_gen_constant(string_constant(String), _, const(string_const(String)))
|
|
--> [].
|
|
|
|
ml_gen_constant(int_constant(Int), _, const(int_const(Int))) --> [].
|
|
|
|
ml_gen_constant(float_constant(Float), _, const(float_const(Float))) --> [].
|
|
|
|
ml_gen_constant(shared_local_tag(Bits1, Num1), VarType, Rval) -->
|
|
ml_gen_type(VarType, MLDS_Type),
|
|
{ Rval = unop(cast(MLDS_Type), mkword(Bits1,
|
|
unop(std_unop(mkbody), const(int_const(Num1))))) }.
|
|
|
|
ml_gen_constant(type_ctor_info_constant(ModuleName0, TypeName, TypeArity),
|
|
VarType, Rval) -->
|
|
ml_gen_type(VarType, MLDS_VarType),
|
|
{ ModuleName = fixup_builtin_module(ModuleName0) },
|
|
{ MLDS_Module = mercury_module_name_to_mlds(ModuleName) },
|
|
{ RttiTypeCtor = rtti_type_ctor(ModuleName, TypeName, TypeArity) },
|
|
{ DataAddr = data_addr(MLDS_Module,
|
|
rtti(RttiTypeCtor, type_ctor_info)) },
|
|
{ Rval = unop(cast(MLDS_VarType),
|
|
const(data_addr_const(DataAddr))) }.
|
|
|
|
ml_gen_constant(base_typeclass_info_constant(ModuleName, ClassId,
|
|
Instance), VarType, Rval) -->
|
|
ml_gen_type(VarType, MLDS_VarType),
|
|
{ MLDS_Module = mercury_module_name_to_mlds(ModuleName) },
|
|
{ DataAddr = data_addr(MLDS_Module,
|
|
base_typeclass_info(ClassId, Instance)) },
|
|
{ Rval = unop(cast(MLDS_VarType),
|
|
const(data_addr_const(DataAddr))) }.
|
|
|
|
ml_gen_constant(tabling_pointer_constant(PredId, ProcId), VarType, Rval) -->
|
|
ml_gen_type(VarType, MLDS_VarType),
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ ml_gen_pred_label(ModuleInfo, PredId, ProcId,
|
|
PredLabel, PredModule) },
|
|
{ DataAddr = data_addr(PredModule,
|
|
tabling_pointer(PredLabel - ProcId)) },
|
|
{ Rval = unop(cast(MLDS_VarType),
|
|
const(data_addr_const(DataAddr))) }.
|
|
|
|
ml_gen_constant(deep_profiling_proc_static_tag(_), _, _) -->
|
|
{ error("ml_gen_constant: deep_profiling_proc_static_tag not yet supported") }.
|
|
|
|
ml_gen_constant(table_io_decl_tag(_), _, _) -->
|
|
{ error("ml_gen_constant: table_io_decl_tag not yet supported") }.
|
|
|
|
ml_gen_constant(code_addr_constant(PredId, ProcId), _, ProcAddrRval) -->
|
|
ml_gen_proc_addr_rval(PredId, ProcId, ProcAddrRval).
|
|
|
|
ml_gen_constant(reserved_address(ReservedAddr), VarType, Rval) -->
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
ml_gen_type(VarType, MLDS_VarType),
|
|
{ Rval = ml_gen_reserved_address(ModuleInfo, ReservedAddr,
|
|
MLDS_VarType) }.
|
|
|
|
ml_gen_constant(shared_with_reserved_addresses(_, ThisTag), VarType, Rval) -->
|
|
% For shared_with_reserved_address, the sharing is only
|
|
% important for tag tests, not for constructions,
|
|
% so here we just recurse on the real representation.
|
|
ml_gen_constant(ThisTag, VarType, Rval).
|
|
|
|
% these tags, which are not (necessarily) constants, are handled
|
|
% in ml_gen_construct and ml_gen_static_const_arg,
|
|
% so we don't need to handle them here.
|
|
ml_gen_constant(no_tag, _, _) -->
|
|
{ error("ml_gen_constant: no_tag") }.
|
|
ml_gen_constant(single_functor, _, _) -->
|
|
{ error("ml_gen_constant: single_functor") }.
|
|
ml_gen_constant(unshared_tag(_), _, _) -->
|
|
{ error("ml_gen_constant: unshared_tag") }.
|
|
ml_gen_constant(shared_remote_tag(_, _), _, _) -->
|
|
{ error("ml_gen_constant: shared_remote_tag") }.
|
|
ml_gen_constant(pred_closure_tag(_, _, _), _, _) -->
|
|
{ error("ml_gen_constant: pred_closure_tag") }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate an MLDS rval for a given reserved address,
|
|
% cast to the appropriate type.
|
|
ml_gen_reserved_address(_, null_pointer, MLDS_Type) = const(null(MLDS_Type)).
|
|
ml_gen_reserved_address(_, small_pointer(Int), MLDS_Type) =
|
|
unop(cast(MLDS_Type), const(int_const(Int))).
|
|
ml_gen_reserved_address(ModuleInfo, reserved_object(TypeCtor, QualCtorName,
|
|
CtorArity), _Type) = Rval :-
|
|
( QualCtorName = qualified(ModuleName, CtorName) ->
|
|
MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName),
|
|
TypeCtor = TypeName - TypeArity,
|
|
unqualify_name(TypeName, UnqualTypeName),
|
|
MLDS_TypeName = mlds__append_class_qualifier(MLDS_ModuleName,
|
|
UnqualTypeName, TypeArity),
|
|
Name = ml_format_reserved_object_name(CtorName, CtorArity),
|
|
Rval0 = const(data_addr_const(
|
|
data_addr(MLDS_TypeName, var(Name)))),
|
|
%
|
|
% The MLDS type of the reserved object may be a class
|
|
% derived from the base class for this Mercury type.
|
|
% So for some back-ends, we need to insert a (down-)cast
|
|
% here to convert from the derived class to the base class.
|
|
% In particular, this is needed to avoid compiler warnings
|
|
% in the C code generated by the MLDS->C back-end.
|
|
% But inserting the cast could slow down the
|
|
% generated code for the .NET back-end (where
|
|
% the JIT probably doesn't optimize downcasts).
|
|
% So we only do it if the back-end requires it.
|
|
%
|
|
module_info_globals(ModuleInfo, Globals),
|
|
globals__get_target(Globals, Target),
|
|
( target_supports_inheritence(Target) = yes ->
|
|
Rval = Rval0
|
|
;
|
|
MLDS_Type = mlds__ptr_type(mlds__class_type(
|
|
qual(MLDS_ModuleName, UnqualTypeName),
|
|
TypeArity, mlds__class)),
|
|
Rval = unop(cast(MLDS_Type), Rval0)
|
|
)
|
|
;
|
|
unexpected(this_file,
|
|
"unqualified ctor name in reserved_object")
|
|
).
|
|
|
|
% This should return `yes' iff downcasts are not needed.
|
|
:- func target_supports_inheritence(compilation_target) = bool.
|
|
target_supports_inheritence(c) = no.
|
|
target_supports_inheritence(il) = yes.
|
|
target_supports_inheritence(java) = yes.
|
|
target_supports_inheritence(asm) = no.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% convert a cons_id for a given type to a cons_tag
|
|
ml_cons_id_to_tag(ConsId, Type, Tag) -->
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ code_util__cons_id_to_tag(ConsId, Type, ModuleInfo, Tag) }.
|
|
|
|
% generate code to construct a new object
|
|
:- pred ml_gen_compound(cons_tag, cons_id, prog_var, prog_vars,
|
|
list(uni_mode), how_to_construct, prog_context,
|
|
mlds__defns, mlds__statements, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_compound(in, in, in, in, in, in, in, out, out, in, out)
|
|
is det.
|
|
|
|
ml_gen_compound(Tag, ConsId, Var, ArgVars, ArgModes,
|
|
HowToConstruct, Context, MLDS_Decls, MLDS_Statements) -->
|
|
%
|
|
% get the primary and secondary tags
|
|
%
|
|
{ get_primary_tag(Tag) = yes(PrimaryTag0) ->
|
|
PrimaryTag = PrimaryTag0
|
|
;
|
|
unexpected(this_file, "ml_gen_compound: primary tag unknown")
|
|
},
|
|
{ MaybeSecondaryTag = get_secondary_tag(Tag) },
|
|
|
|
%
|
|
% figure out which class name to construct
|
|
%
|
|
( { ml_tag_uses_base_class(Tag) } ->
|
|
{ MaybeCtorName = no }
|
|
;
|
|
ml_cons_name(ConsId, CtorName),
|
|
{ MaybeCtorName = yes(CtorName) }
|
|
),
|
|
|
|
%
|
|
% If there is a secondary tag, it goes in the first field
|
|
%
|
|
=(Info),
|
|
{ MaybeSecondaryTag = yes(SecondaryTag) ->
|
|
HasSecTag = yes,
|
|
SecondaryTagRval0 = const(int_const(SecondaryTag)),
|
|
SecondaryTagType0 = mlds__native_int_type,
|
|
%
|
|
% With the low-level data representation,
|
|
% all fields -- even the secondary tag --
|
|
% are boxed, and so we need box it here.
|
|
%
|
|
ml_gen_info_get_module_info(Info, ModuleInfo),
|
|
module_info_globals(ModuleInfo, Globals),
|
|
globals__lookup_bool_option(Globals, highlevel_data,
|
|
HighLevelData),
|
|
( HighLevelData = no ->
|
|
SecondaryTagRval = unop(box(SecondaryTagType0),
|
|
SecondaryTagRval0),
|
|
SecondaryTagType = mlds__generic_type
|
|
;
|
|
SecondaryTagRval = SecondaryTagRval0,
|
|
SecondaryTagType = SecondaryTagType0
|
|
),
|
|
ExtraRvals = [SecondaryTagRval],
|
|
ExtraArgTypes = [SecondaryTagType]
|
|
;
|
|
HasSecTag = no,
|
|
ExtraRvals = [],
|
|
ExtraArgTypes = []
|
|
},
|
|
ml_gen_new_object(yes(ConsId), PrimaryTag, HasSecTag, MaybeCtorName,
|
|
Var, ExtraRvals, ExtraArgTypes, ArgVars, ArgModes,
|
|
HowToConstruct, Context, MLDS_Decls, MLDS_Statements).
|
|
|
|
%
|
|
% ml_gen_new_object:
|
|
% Generate a `new_object' statement, or a static constant,
|
|
% depending on the value of the how_to_construct argument.
|
|
% The `ExtraRvals' and `ExtraTypes' arguments specify
|
|
% additional constants to insert at the start of the
|
|
% argument list.
|
|
%
|
|
ml_gen_new_object(MaybeConsId, Tag, HasSecTag, MaybeCtorName, Var,
|
|
ExtraRvals, ExtraTypes, ArgVars, ArgModes, HowToConstruct,
|
|
Context, MLDS_Decls, MLDS_Statements) -->
|
|
%
|
|
% Determine the variable's type and lval,
|
|
% the tag to use, and the types of the argument vars.
|
|
%
|
|
ml_variable_type(Var, Type),
|
|
ml_gen_type(Type, MLDS_Type),
|
|
ml_gen_var(Var, VarLval),
|
|
{ Tag = 0 ->
|
|
MaybeTag = no
|
|
;
|
|
MaybeTag = yes(Tag)
|
|
},
|
|
ml_variable_types(ArgVars, ArgTypes),
|
|
|
|
(
|
|
{ HowToConstruct = construct_dynamically },
|
|
|
|
%
|
|
% Find out the types of the constructor arguments
|
|
% and generate rvals for them (boxing/unboxing if needed)
|
|
%
|
|
ml_gen_var_list(ArgVars, ArgLvals),
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ get_maybe_cons_id_arg_types(MaybeConsId, ArgTypes, Type,
|
|
ModuleInfo, ConsArgTypes) },
|
|
ml_gen_cons_args(ArgLvals, ArgTypes, ConsArgTypes, ArgModes,
|
|
ModuleInfo, ArgRvals0, MLDS_ArgTypes0),
|
|
|
|
%
|
|
% Insert the extra rvals at the start
|
|
%
|
|
{ list__append(ExtraRvals, ArgRvals0, ArgRvals) },
|
|
{ list__append(ExtraTypes, MLDS_ArgTypes0, MLDS_ArgTypes) },
|
|
|
|
%
|
|
% Compute the number of bytes to allocate
|
|
%
|
|
{ list__length(ArgRvals, NumArgs) },
|
|
{ SizeInWordsRval = const(int_const(NumArgs)) },
|
|
|
|
%
|
|
% Generate a `new_object' statement to dynamically allocate
|
|
% the memory for this term from the heap. The `new_object'
|
|
% statement will also initialize the fields of this term
|
|
% with the specified arguments.
|
|
%
|
|
{ MakeNewObject = new_object(VarLval, MaybeTag, HasSecTag,
|
|
MLDS_Type, yes(SizeInWordsRval), MaybeCtorName,
|
|
ArgRvals, MLDS_ArgTypes) },
|
|
{ MLDS_Stmt = atomic(MakeNewObject) },
|
|
{ MLDS_Statement = mlds__statement(MLDS_Stmt,
|
|
mlds__make_context(Context)) },
|
|
{ MLDS_Statements = [MLDS_Statement] },
|
|
{ MLDS_Decls = [] }
|
|
;
|
|
{ HowToConstruct = construct_statically(StaticArgs) },
|
|
%
|
|
% Find out the types of the constructor arguments
|
|
%
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ get_maybe_cons_id_arg_types(MaybeConsId, ArgTypes, Type,
|
|
ModuleInfo, ConsArgTypes) },
|
|
list__map_foldl(ml_gen_field_type, ConsArgTypes,
|
|
FieldTypes),
|
|
|
|
%
|
|
% Generate rvals for the arguments
|
|
%
|
|
list__map_foldl(ml_gen_type, ArgTypes, MLDS_ArgTypes0),
|
|
ml_gen_static_const_arg_list(ArgVars, StaticArgs, ArgRvals0),
|
|
|
|
%
|
|
% Box or unbox the arguments, if needed,
|
|
% and insert the extra rvals at the start
|
|
%
|
|
ml_gen_info_get_globals(Globals),
|
|
{ globals__lookup_bool_option(Globals, highlevel_data,
|
|
HighLevelData) },
|
|
(
|
|
{ HighLevelData = no },
|
|
%
|
|
% Box *all* the arguments, including the ExtraRvals
|
|
%
|
|
{ list__append(ExtraRvals, ArgRvals0, ArgRvals1) },
|
|
{ list__append(ExtraTypes, MLDS_ArgTypes0,
|
|
MLDS_ArgTypes) },
|
|
ml_gen_box_const_rval_list(MLDS_ArgTypes, ArgRvals1,
|
|
Context, BoxConstDefns, ArgRvals)
|
|
;
|
|
{ HighLevelData = yes },
|
|
ml_gen_box_or_unbox_const_rval_list(ArgTypes,
|
|
FieldTypes, ArgRvals0,
|
|
Context, BoxConstDefns, ArgRvals1),
|
|
% For --high-level-data, the ExtraRvals should
|
|
% already have the right type, so we don't need
|
|
% to worry about boxing or unboxing them
|
|
{ list__append(ExtraRvals, ArgRvals1, ArgRvals) }
|
|
),
|
|
|
|
%
|
|
% Generate a local static constant for this term.
|
|
%
|
|
ml_gen_static_const_name(Var, ConstName),
|
|
{ UsesBaseClass = (MaybeCtorName = yes(_) -> no ; yes) },
|
|
{ ConstType = get_type_for_cons_id(MLDS_Type, UsesBaseClass,
|
|
MaybeConsId, HighLevelData) },
|
|
% XXX if the secondary tag is in a base class, then ideally its
|
|
% initializer should be wrapped in `init_struct([init_obj(X)])'
|
|
% rather than just `init_obj(X)' -- the fact that we don't
|
|
% leads to some warnings from GNU C about missing braces in
|
|
% initializers.
|
|
{ ArgInits = list__map(func(X) = init_obj(X), ArgRvals) },
|
|
{ ConstType = mlds__array_type(_) ->
|
|
Initializer = init_array(ArgInits)
|
|
;
|
|
Initializer = init_struct(ArgInits)
|
|
},
|
|
{ ConstDefn = ml_gen_static_const_defn(ConstName, ConstType,
|
|
local, Initializer, Context) },
|
|
|
|
%
|
|
% Assign the address of the local static constant to
|
|
% the variable.
|
|
%
|
|
ml_gen_static_const_addr(Var, ConstType, ConstAddrRval),
|
|
{ MaybeTag = no ->
|
|
TaggedRval = ConstAddrRval
|
|
;
|
|
TaggedRval = mkword(Tag, ConstAddrRval)
|
|
},
|
|
{ Rval = unop(cast(MLDS_Type), TaggedRval) },
|
|
{ AssignStatement = ml_gen_assign(VarLval, Rval, Context) },
|
|
{ MLDS_Decls = list__append(BoxConstDefns, [ConstDefn]) },
|
|
{ MLDS_Statements = [AssignStatement] }
|
|
;
|
|
{ HowToConstruct = reuse_cell(CellToReuse) },
|
|
{ CellToReuse = cell_to_reuse(ReuseVar, ReuseConsIds, _) },
|
|
|
|
{ MaybeConsId = yes(ConsId0) ->
|
|
ConsId = ConsId0
|
|
;
|
|
error("ml_gen_new_object: unknown cons id")
|
|
},
|
|
|
|
list__map_foldl(
|
|
(pred(ReuseConsId::in, ReusePrimTag::out,
|
|
in, out) is det -->
|
|
ml_variable_type(ReuseVar, ReuseType),
|
|
ml_cons_id_to_tag(ReuseConsId, ReuseType,
|
|
ReuseConsIdTag),
|
|
{ ml_tag_offset_and_argnum(ReuseConsIdTag,
|
|
ReusePrimTag,
|
|
_ReuseOffSet, _ReuseArgNum) }
|
|
), ReuseConsIds, ReusePrimaryTags0),
|
|
{ list__remove_dups(ReusePrimaryTags0, ReusePrimaryTags) },
|
|
|
|
ml_cons_id_to_tag(ConsId, Type, ConsIdTag),
|
|
ml_field_names_and_types(Type, ConsId, ArgTypes, Fields),
|
|
{ ml_tag_offset_and_argnum(ConsIdTag,
|
|
PrimaryTag, OffSet, ArgNum) },
|
|
|
|
ml_gen_var(Var, Var1Lval),
|
|
ml_gen_var(ReuseVar, Var2Lval),
|
|
|
|
{ list__filter((pred(ReuseTag::in) is semidet :-
|
|
ReuseTag \= PrimaryTag
|
|
), ReusePrimaryTags, DifferentTags) },
|
|
{ DifferentTags = [] ->
|
|
Var2Rval = lval(Var2Lval)
|
|
; DifferentTags = [ReusePrimaryTag] ->
|
|
% The body operator is slightly more
|
|
% efficient than the strip_tag operator so
|
|
% we use it when the old tag is known.
|
|
Var2Rval = mkword(PrimaryTag,
|
|
binop(body, lval(Var2Lval),
|
|
ml_gen_mktag(ReusePrimaryTag)))
|
|
;
|
|
Var2Rval = mkword(PrimaryTag,
|
|
unop(std_unop(strip_tag),
|
|
lval(Var2Lval)))
|
|
},
|
|
|
|
{ MLDS_Statement = ml_gen_assign(Var1Lval, Var2Rval, Context) },
|
|
|
|
%
|
|
% For each field in the construction unification we need
|
|
% to generate an rval.
|
|
% XXX we do more work than we need to here, as some of
|
|
% the cells may already contain the correct values.
|
|
%
|
|
ml_gen_unify_args(ConsId, ArgVars, ArgModes, ArgTypes,
|
|
Fields, Type, VarLval, OffSet, ArgNum,
|
|
ConsIdTag, Context, MLDS_Statements0),
|
|
|
|
{ MLDS_Decls = [] },
|
|
{ MLDS_Statements = [MLDS_Statement | MLDS_Statements0] }
|
|
).
|
|
|
|
% Return the MLDS type suitable for constructing a constant static
|
|
% ground term with the specified cons_id.
|
|
:- func get_type_for_cons_id(mlds__type, bool, maybe(cons_id), bool)
|
|
= mlds__type.
|
|
get_type_for_cons_id(MLDS_Type, UsesBaseClass, MaybeConsId, HighLevelData)
|
|
= ConstType :-
|
|
(
|
|
HighLevelData = no,
|
|
ConstType = mlds__array_type(mlds__generic_type)
|
|
;
|
|
HighLevelData = yes,
|
|
(
|
|
% Check for type_infos and typeclass_infos,
|
|
% since these need to be handled specially;
|
|
% their Mercury type definitions are lies.
|
|
MLDS_Type = mercury_type(MercuryType, user_type, _),
|
|
type_util__is_introduced_type_info_type(MercuryType)
|
|
->
|
|
ConstType = mlds__array_type(mlds__generic_type)
|
|
;
|
|
% Check if we're constructing a value for a
|
|
% discriminated union where the specified cons_id
|
|
% which is represented as a derived class that
|
|
% is derived from the base class for this
|
|
% discriminated union type.
|
|
UsesBaseClass = no,
|
|
MaybeConsId = yes(ConsId),
|
|
ConsId = cons(CtorSymName, CtorArity),
|
|
(
|
|
MLDS_Type = mlds__class_type(QualTypeName,
|
|
TypeArity, _)
|
|
;
|
|
MLDS_Type = mercury_type(MercuryType,
|
|
user_type, _),
|
|
type_to_ctor_and_args(MercuryType, TypeCtor,
|
|
_ArgsTypes),
|
|
ml_gen_type_name(TypeCtor, QualTypeName,
|
|
TypeArity)
|
|
)
|
|
->
|
|
% If so, append the name of the derived class to
|
|
% the name of the base class for this type
|
|
% (since the derived class will also be nested
|
|
% inside the base class).
|
|
unqualify_name(CtorSymName, CtorName),
|
|
QualTypeName = qual(MLDS_Module, TypeName),
|
|
ClassQualifier = mlds__append_class_qualifier(
|
|
MLDS_Module, TypeName, TypeArity),
|
|
ConstType = mlds__class_type(
|
|
qual(ClassQualifier, CtorName),
|
|
CtorArity, mlds__class)
|
|
;
|
|
% Convert mercury_types for user-defined types
|
|
% to the corresponding `mlds__class_type'.
|
|
% This is needed because these types get mapped to
|
|
% `mlds__ptr_type(mlds__class_type(...))', but when
|
|
% declarating static constants we want just the
|
|
% class type, not the pointer type.
|
|
MLDS_Type = mercury_type(MercuryType, user_type, _),
|
|
type_to_ctor_and_args(MercuryType, TypeCtor, _ArgsTypes)
|
|
->
|
|
ml_gen_type_name(TypeCtor, ClassName, ClassArity),
|
|
ConstType = mlds__class_type(ClassName, ClassArity,
|
|
mlds__class)
|
|
;
|
|
% For tuples, a similar issue arises;
|
|
% we want tuple constants to have array type,
|
|
% not the pointer type MR_Tuple.
|
|
MLDS_Type = mercury_type(_, tuple_type, _)
|
|
->
|
|
ConstType = mlds__array_type(mlds__generic_type)
|
|
;
|
|
% Likewise for closures, we need to use an array type
|
|
% rather than the pointer type MR_ClosurePtr.
|
|
% Note that we're still using a low-level data
|
|
% representation for closures, even when
|
|
% --high-level-data is enabled.
|
|
MLDS_Type = mercury_type(_, pred_type, _)
|
|
->
|
|
ConstType = mlds__array_type(mlds__generic_type)
|
|
;
|
|
ConstType = MLDS_Type
|
|
)
|
|
).
|
|
|
|
:- pred ml_gen_field_type(prog_type, prog_type, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_field_type(in, out, in, out) is det.
|
|
ml_gen_field_type(Type, FieldType) -->
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ module_info_globals(ModuleInfo, Globals) },
|
|
{ globals__lookup_bool_option(Globals, highlevel_data,
|
|
HighLevelData) },
|
|
{ ml_type_as_field(Type, ModuleInfo, HighLevelData, FieldType) }.
|
|
|
|
:- pred ml_type_as_field(prog_type, module_info, bool, prog_type).
|
|
:- mode ml_type_as_field(in, in, in, out) is det.
|
|
ml_type_as_field(FieldType, ModuleInfo, HighLevelData, BoxedFieldType) :-
|
|
(
|
|
%
|
|
% With the low-level data representation,
|
|
% we store all fields as boxed, so we ignore the
|
|
% original field type and instead generate a polymorphic
|
|
% type BoxedFieldType which we use for the type of the field.
|
|
% This type is used in the calls to
|
|
% ml_gen_box_or_unbox_rval to ensure that we
|
|
% box values when storing them into fields and
|
|
% unbox them when extracting them from fields.
|
|
%
|
|
% With the high-level data representation,
|
|
% we don't box everything, but for the MLDS->C and MLDS->asm
|
|
% back-ends we still need to box floating point fields
|
|
%
|
|
(
|
|
HighLevelData = no
|
|
;
|
|
HighLevelData = yes,
|
|
ml_must_box_field_type(FieldType, ModuleInfo)
|
|
)
|
|
->
|
|
varset__init(TypeVarSet0),
|
|
varset__new_var(TypeVarSet0, TypeVar, _TypeVarSet),
|
|
type_util__var(BoxedFieldType, TypeVar)
|
|
;
|
|
BoxedFieldType = FieldType
|
|
).
|
|
|
|
:- pred get_maybe_cons_id_arg_types(maybe(cons_id)::in, list(prog_type)::in,
|
|
prog_type::in, module_info::in, list(prog_type)::out) is det.
|
|
|
|
get_maybe_cons_id_arg_types(MaybeConsId, ArgTypes, Type, ModuleInfo,
|
|
ConsArgTypes) :-
|
|
( MaybeConsId = yes(ConsId) ->
|
|
ConsArgTypes = constructor_arg_types(ConsId,
|
|
ArgTypes, Type, ModuleInfo)
|
|
;
|
|
% it's a closure
|
|
% in this case, the arguments are all boxed
|
|
ConsArgTypes = ml_make_boxed_types(
|
|
list__length(ArgTypes))
|
|
).
|
|
|
|
:- func constructor_arg_types(cons_id, list(prog_type), prog_type,
|
|
module_info) = list(prog_type).
|
|
|
|
constructor_arg_types(CtorId, ArgTypes, Type, ModuleInfo) = ConsArgTypes :-
|
|
(
|
|
CtorId = cons(_, _),
|
|
\+ is_introduced_type_info_type(Type)
|
|
->
|
|
% Use the type to determine the type_ctor
|
|
( type_to_ctor_and_args(Type, TypeCtor0, _) ->
|
|
TypeCtor = TypeCtor0
|
|
;
|
|
% the type-checker should ensure that this never
|
|
% happens: the type for a ctor_id should never
|
|
% be a free type variable
|
|
unexpected(this_file,
|
|
"cons_id_to_arg_types: invalid type")
|
|
),
|
|
|
|
% Given the type_ctor, lookup up the constructor
|
|
(
|
|
type_util__get_cons_defn(ModuleInfo, TypeCtor, CtorId,
|
|
ConsDefn)
|
|
->
|
|
ConsDefn = hlds_cons_defn(_, _, ConsArgDefns, _, _),
|
|
assoc_list__values(ConsArgDefns, ConsArgTypes0),
|
|
%
|
|
% There may have been additional types inserted
|
|
% to hold the type_infos and type_class_infos
|
|
% for existentially quantified types.
|
|
% We can get these from the ArgTypes.
|
|
%
|
|
NumExtraArgs = list__length(ArgTypes) -
|
|
list__length(ConsArgTypes0),
|
|
ExtraArgTypes = list__take_upto(NumExtraArgs, ArgTypes),
|
|
ConsArgTypes = ExtraArgTypes ++ ConsArgTypes0
|
|
;
|
|
% If we didn't find a constructor definition,
|
|
% maybe that is because this type was a built-in
|
|
% tuple type
|
|
type_is_tuple(Type, _)
|
|
->
|
|
% In this case, the argument types are all fresh
|
|
% variables. Note that we don't need to worry about
|
|
% using the right varset here, since all we really
|
|
% care about at this point is whether something is
|
|
% a type variable or not, not which type variable it
|
|
% is.
|
|
ConsArgTypes = ml_make_boxed_types(
|
|
list__length(ArgTypes))
|
|
;
|
|
% type_util__get_cons_defn shouldn't have failed
|
|
unexpected(this_file,
|
|
"cons_id_to_arg_types: get_cons_defn failed")
|
|
)
|
|
;
|
|
% For cases when CtorId \= cons(_, _) and it is not a tuple,
|
|
% as can happen e.g. for closures and type_infos,
|
|
% we assume that the arguments all have the right type already
|
|
% XXX is this the right thing to do?
|
|
ArgTypes = ConsArgTypes
|
|
).
|
|
|
|
:- func ml_gen_mktag(int) = mlds__rval.
|
|
ml_gen_mktag(Tag) = unop(std_unop(mktag), const(int_const(Tag))).
|
|
|
|
|
|
:- pred ml_gen_box_or_unbox_const_rval_list(list(prog_type), list(prog_type),
|
|
list(mlds__rval), prog_context, mlds__defns, list(mlds__rval),
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_box_or_unbox_const_rval_list(in, in, in, in, out, out, in, out)
|
|
is det.
|
|
|
|
ml_gen_box_or_unbox_const_rval_list(ArgTypes, FieldTypes, ArgRvals,
|
|
Context, BoxConstDefns, FieldRvals) -->
|
|
(
|
|
{ ArgTypes = [], FieldTypes = [], ArgRvals = [] }
|
|
->
|
|
{ BoxConstDefns = [], FieldRvals = [] }
|
|
;
|
|
{ ArgTypes = [ArgType | ArgTypes1] },
|
|
{ FieldTypes = [FieldType | FieldTypes1] },
|
|
{ ArgRvals = [ArgRval | ArgRvals1] }
|
|
->
|
|
(
|
|
% Handle the case where the field type is a boxed
|
|
% type -- in that case, we can just box the argument
|
|
% type.
|
|
{ FieldType = term__variable(_) }
|
|
->
|
|
ml_gen_type(ArgType, MLDS_ArgType),
|
|
ml_gen_box_const_rval(MLDS_ArgType, ArgRval, Context,
|
|
BoxConstDefns0, FieldRval)
|
|
;
|
|
% Otherwise, fall back on ml_gen_box_or_unbox_rval.
|
|
% XXX this might still generate stuff which is not
|
|
% legal in a static initializer!
|
|
ml_gen_box_or_unbox_rval(ArgType, FieldType, ArgRval,
|
|
FieldRval),
|
|
{ BoxConstDefns0 = [] }
|
|
),
|
|
ml_gen_box_or_unbox_const_rval_list(ArgTypes1, FieldTypes1,
|
|
ArgRvals1, Context, BoxConstDefns1, FieldRvals1),
|
|
{ BoxConstDefns = BoxConstDefns0 ++ BoxConstDefns1 },
|
|
{ FieldRvals = [FieldRval | FieldRvals1] }
|
|
;
|
|
{ unexpected(this_file, "ml_gen_box_or_unbox_const_rval_list: "
|
|
++ "list length mismatch") }
|
|
).
|
|
|
|
:- pred ml_gen_box_const_rval_list(list(mlds__type), list(mlds__rval),
|
|
prog_context, mlds__defns, list(mlds__rval),
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_box_const_rval_list(in, in, in, out, out, in, out) is det.
|
|
|
|
ml_gen_box_const_rval_list([], [], _, [], []) --> [].
|
|
ml_gen_box_const_rval_list([Type | Types], [Rval | Rvals], Context,
|
|
ConstDefns, [BoxedRval | BoxedRvals]) -->
|
|
ml_gen_box_const_rval(Type, Rval, Context, ConstDefns1, BoxedRval),
|
|
ml_gen_box_const_rval_list(Types, Rvals, Context, ConstDefns2,
|
|
BoxedRvals),
|
|
{ ConstDefns = list__append(ConstDefns1, ConstDefns2) }.
|
|
ml_gen_box_const_rval_list([], [_|_], _, _, _) -->
|
|
{ error("ml_gen_box_const_rval_list: length mismatch") }.
|
|
ml_gen_box_const_rval_list([_|_], [], _, _, _) -->
|
|
{ error("ml_gen_box_const_rval_list: length mismatch") }.
|
|
|
|
:- pred ml_gen_box_const_rval(mlds__type, mlds__rval, prog_context,
|
|
mlds__defns, mlds__rval, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_box_const_rval(in, in, in, out, out, in, out) is det.
|
|
|
|
ml_gen_box_const_rval(Type, Rval, Context, ConstDefns, BoxedRval) -->
|
|
(
|
|
{ Type = mercury_type(term__variable(_), _, _)
|
|
; Type = mlds__generic_type
|
|
}
|
|
->
|
|
{ BoxedRval = Rval },
|
|
{ ConstDefns = [] }
|
|
;
|
|
%
|
|
% For the MLDS->C and MLDS->asm back-ends,
|
|
% we need to handle floats specially,
|
|
% since boxed floats normally get heap allocated,
|
|
% whereas for other types boxing is just a cast
|
|
% (casts are OK in static initializers,
|
|
% but calls to malloc() are not).
|
|
%
|
|
% [For the .NET and Java back-ends,
|
|
% this code currently never gets called,
|
|
% since currently we don't support static
|
|
% ground term optimization for those back-ends.]
|
|
%
|
|
{ Type = mercury_type(term__functor(term__atom("float"),
|
|
[], _), _, _)
|
|
; Type = mlds__native_float_type
|
|
}
|
|
->
|
|
%
|
|
% Generate a local static constant for this float
|
|
%
|
|
ml_gen_info_new_const(SequenceNum),
|
|
=(MLDSGenInfo),
|
|
{ ml_gen_info_get_pred_id(MLDSGenInfo, PredId) },
|
|
{ ml_gen_info_get_proc_id(MLDSGenInfo, ProcId) },
|
|
{ pred_id_to_int(PredId, PredIdNum) },
|
|
{ proc_id_to_int(ProcId, ProcIdNum) },
|
|
{ ConstName = mlds__var_name(string__format("float_%d_%d_%d",
|
|
[i(PredIdNum), i(ProcIdNum), i(SequenceNum)]), no) },
|
|
{ Initializer = init_obj(Rval) },
|
|
{ ConstDefn = ml_gen_static_const_defn(ConstName, Type,
|
|
local, Initializer, Context) },
|
|
{ ConstDefns = [ConstDefn] },
|
|
%
|
|
% Return as the boxed rval the address of that constant,
|
|
% cast to mlds__generic_type
|
|
%
|
|
ml_gen_var_lval(ConstName, Type, ConstLval),
|
|
{ ConstAddrRval = mem_addr(ConstLval) },
|
|
{ BoxedRval = unop(cast(mlds__generic_type), ConstAddrRval) }
|
|
;
|
|
{ BoxedRval = unop(box(Type), Rval) },
|
|
{ ConstDefns = [] }
|
|
).
|
|
|
|
:- pred ml_gen_static_const_arg_list(list(prog_var), list(static_cons),
|
|
list(mlds__rval), ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_static_const_arg_list(in, in, out, in, out) is det.
|
|
|
|
ml_gen_static_const_arg_list([], [], []) --> [].
|
|
ml_gen_static_const_arg_list([Var | Vars], [StaticCons | StaticConses],
|
|
[Rval | Rvals]) -->
|
|
ml_gen_static_const_arg(Var, StaticCons, Rval),
|
|
ml_gen_static_const_arg_list(Vars, StaticConses, Rvals).
|
|
ml_gen_static_const_arg_list([_|_], [], _) -->
|
|
{ error("ml_gen_static_const_arg_list: length mismatch") }.
|
|
ml_gen_static_const_arg_list([], [_|_], _) -->
|
|
{ error("ml_gen_static_const_arg_list: length mismatch") }.
|
|
|
|
% Generate the name of the local static constant
|
|
% for a given variable.
|
|
%
|
|
:- pred ml_gen_static_const_name(prog_var, mlds__var_name,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_static_const_name(in, out, in, out) is det.
|
|
ml_gen_static_const_name(Var, ConstName) -->
|
|
ml_gen_info_new_const(SequenceNum),
|
|
ml_gen_info_set_const_num(Var, SequenceNum),
|
|
=(MLDSGenInfo),
|
|
{ ml_gen_info_get_varset(MLDSGenInfo, VarSet) },
|
|
{ VarName = ml_gen_var_name(VarSet, Var) },
|
|
ml_format_static_const_name(ml_var_name_to_string(VarName),
|
|
SequenceNum, ConstName).
|
|
|
|
:- pred ml_lookup_static_const_name(prog_var, mlds__var_name,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_lookup_static_const_name(in, out, in, out) is det.
|
|
ml_lookup_static_const_name(Var, ConstName) -->
|
|
ml_gen_info_lookup_const_num(Var, SequenceNum),
|
|
=(MLDSGenInfo),
|
|
{ ml_gen_info_get_varset(MLDSGenInfo, VarSet) },
|
|
{ VarName = ml_gen_var_name(VarSet, Var) },
|
|
ml_format_static_const_name(ml_var_name_to_string(VarName),
|
|
SequenceNum, ConstName).
|
|
|
|
% Generate an rval containing the address of the local static constant
|
|
% for a given variable.
|
|
%
|
|
:- pred ml_gen_static_const_addr(prog_var, mlds__type, mlds__rval,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_static_const_addr(in, in, out, in, out) is det.
|
|
ml_gen_static_const_addr(Var, Type, ConstAddrRval) -->
|
|
ml_lookup_static_const_name(Var, ConstName),
|
|
ml_gen_var_lval(ConstName, Type, ConstLval),
|
|
{ ConstAddrRval = mem_addr(ConstLval) }.
|
|
|
|
:- pred ml_cons_name(cons_id, ctor_name, ml_gen_info, ml_gen_info).
|
|
:- mode ml_cons_name(in, out, in, out) is det.
|
|
|
|
ml_cons_name(HLDS_ConsId, QualifiedConsId) -->
|
|
(
|
|
{ HLDS_ConsId = cons(SymName, Arity),
|
|
SymName = qualified(SymModuleName, ConsName) }
|
|
->
|
|
{ ConsId = ctor_id(ConsName, Arity) },
|
|
{ ModuleName = mercury_module_name_to_mlds(SymModuleName) }
|
|
;
|
|
{ hlds_out__cons_id_to_string(HLDS_ConsId, ConsName) },
|
|
{ ConsId = ctor_id(ConsName, 0) },
|
|
{ ModuleName = mercury_module_name_to_mlds(unqualified("")) }
|
|
),
|
|
{ QualifiedConsId = qual(ModuleName, ConsId) }.
|
|
|
|
% Create a list of rvals for the arguments
|
|
% for a construction unification. For each argument which
|
|
% is input to the construction unification, we produce the
|
|
% corresponding lval, boxed or unboxed if needed,
|
|
% but if the argument is free, we produce a null value.
|
|
%
|
|
:- pred ml_gen_cons_args(list(mlds__lval), list(prog_type), list(prog_type),
|
|
list(uni_mode), module_info,
|
|
list(mlds__rval), list(mlds__type), ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_cons_args(in, in, in, in, in, out, out, in, out) is det.
|
|
|
|
ml_gen_cons_args(Lvals, ArgTypes, ConsArgTypes, UniModes, ModuleInfo,
|
|
Rvals, MLDS_Types) -->
|
|
(
|
|
{ Lvals = [] },
|
|
{ ArgTypes = [] },
|
|
{ ConsArgTypes = [] },
|
|
{ UniModes = [] }
|
|
->
|
|
{ Rvals = [] },
|
|
{ MLDS_Types = [] }
|
|
;
|
|
{ Lvals = [Lval | Lvals1] },
|
|
{ ArgTypes = [ArgType | ArgTypes1] },
|
|
{ ConsArgTypes = [ConsArgType | ConsArgTypes1] },
|
|
{ UniModes = [UniMode | UniModes1] }
|
|
->
|
|
%
|
|
% Figure out the type of the field.
|
|
% Note that for the MLDS->C and MLDS->asm back-ends,
|
|
% we need to box floating point fields.
|
|
%
|
|
{ module_info_globals(ModuleInfo, Globals) },
|
|
{ globals__lookup_bool_option(Globals, highlevel_data,
|
|
HighLevelData) },
|
|
{ ml_type_as_field(ConsArgType, ModuleInfo, HighLevelData,
|
|
BoxedArgType) },
|
|
{ MLDS_Type = mercury_type_to_mlds_type(ModuleInfo,
|
|
BoxedArgType) },
|
|
%
|
|
% Compute the value of the field
|
|
%
|
|
{ UniMode = ((_LI - RI) -> (_LF - RF)) },
|
|
(
|
|
{ mode_to_arg_mode(ModuleInfo, (RI -> RF), ArgType,
|
|
top_in) }
|
|
->
|
|
ml_gen_box_or_unbox_rval(ArgType, BoxedArgType,
|
|
lval(Lval), Rval)
|
|
;
|
|
{ Rval = const(null(MLDS_Type)) }
|
|
),
|
|
%
|
|
% Process the remaining arguments
|
|
%
|
|
ml_gen_cons_args(Lvals1, ArgTypes1, ConsArgTypes1, UniModes1,
|
|
ModuleInfo, Rvals1, MLDS_Types1),
|
|
{ Rvals = [Rval | Rvals1] },
|
|
{ MLDS_Types = [MLDS_Type | MLDS_Types1] }
|
|
;
|
|
{ unexpected(this_file,
|
|
"ml_gen_cons_args: length mismatch") }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate a deterministic deconstruction. In a deterministic
|
|
% deconstruction, we know the value of the tag, so we don't
|
|
% need to generate a test.
|
|
%
|
|
:- pred ml_gen_det_deconstruct(prog_var, cons_id, prog_vars, list(uni_mode),
|
|
prog_context, mlds__defns, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_det_deconstruct(in, in, in, in, in, out, out, in, out) is det.
|
|
|
|
% det (cannot_fail) deconstruction:
|
|
% <do (X => f(A1, A2, ...))>
|
|
% ===>
|
|
% A1 = arg(X, f, 1); % extract arguments
|
|
% A2 = arg(X, f, 2);
|
|
% ...
|
|
|
|
ml_gen_det_deconstruct(Var, ConsId, Args, Modes, Context,
|
|
MLDS_Decls, MLDS_Statements) -->
|
|
{ MLDS_Decls = [] },
|
|
ml_variable_type(Var, Type),
|
|
ml_cons_id_to_tag(ConsId, Type, Tag),
|
|
ml_gen_det_deconstruct_2(Tag, Type, Var, ConsId, Args, Modes, Context,
|
|
MLDS_Statements).
|
|
|
|
:- pred ml_gen_det_deconstruct_2(cons_tag, prog_type, prog_var, cons_id,
|
|
prog_vars, list(uni_mode), prog_context,
|
|
mlds__statements, ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_det_deconstruct_2(in, in, in, in, in, in, in, out, in, out)
|
|
is det.
|
|
|
|
ml_gen_det_deconstruct_2(Tag, Type, Var, ConsId, Args, Modes, Context,
|
|
MLDS_Statements) -->
|
|
% For constants, if the deconstruction is det, then we already know
|
|
% the value of the constant, so MLDS_Statements = [].
|
|
(
|
|
{ Tag = string_constant(_String) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = int_constant(_Int) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = float_constant(_Float) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = pred_closure_tag(_, _, _) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = code_addr_constant(_, _) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = type_ctor_info_constant(_, _, _) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = base_typeclass_info_constant(_, _, _) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = tabling_pointer_constant(_, _) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = deep_profiling_proc_static_tag(_) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = table_io_decl_tag(_) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
{ Tag = no_tag },
|
|
( { Args = [Arg], Modes = [Mode] } ->
|
|
ml_variable_type(Arg, ArgType),
|
|
ml_gen_var(Arg, ArgLval),
|
|
ml_gen_var(Var, VarLval),
|
|
ml_gen_sub_unify(Mode, ArgLval, ArgType, VarLval, Type,
|
|
Context, [], MLDS_Statements)
|
|
;
|
|
{ error("ml_code_gen: no_tag: arity != 1") }
|
|
)
|
|
;
|
|
{ Tag = single_functor },
|
|
ml_gen_var(Var, VarLval),
|
|
ml_variable_types(Args, ArgTypes),
|
|
ml_field_names_and_types(Type, ConsId, ArgTypes, Fields),
|
|
{ ml_tag_offset_and_argnum(Tag, _, OffSet, ArgNum) },
|
|
ml_gen_unify_args(ConsId, Args, Modes, ArgTypes, Fields, Type,
|
|
VarLval, OffSet, ArgNum,
|
|
Tag, Context, MLDS_Statements)
|
|
;
|
|
{ Tag = unshared_tag(_UnsharedTag) },
|
|
ml_gen_var(Var, VarLval),
|
|
ml_variable_types(Args, ArgTypes),
|
|
ml_field_names_and_types(Type, ConsId, ArgTypes, Fields),
|
|
{ ml_tag_offset_and_argnum(Tag, _, OffSet, ArgNum) },
|
|
ml_gen_unify_args(ConsId, Args, Modes, ArgTypes, Fields, Type,
|
|
VarLval, OffSet, ArgNum,
|
|
Tag, Context, MLDS_Statements)
|
|
;
|
|
{ Tag = shared_remote_tag(_PrimaryTag, _SecondaryTag) },
|
|
ml_gen_var(Var, VarLval),
|
|
ml_variable_types(Args, ArgTypes),
|
|
ml_field_names_and_types(Type, ConsId, ArgTypes, Fields),
|
|
{ ml_tag_offset_and_argnum(Tag, _, OffSet, ArgNum) },
|
|
ml_gen_unify_args(ConsId, Args, Modes, ArgTypes, Fields, Type,
|
|
VarLval, OffSet, ArgNum,
|
|
Tag, Context, MLDS_Statements)
|
|
;
|
|
% For constants, if the deconstruction is det, then we already
|
|
% know the value of the constant, so MLDS_Statements = [].
|
|
{ Tag = shared_local_tag(_Bits1, _Num1) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
% For constants, if the deconstruction is det, then we already
|
|
% know the value of the constant, so MLDS_Statements = [].
|
|
{ Tag = reserved_address(_) },
|
|
{ MLDS_Statements = [] }
|
|
;
|
|
% For shared_with_reserved_address, the sharing is only
|
|
% important for tag tests, not for det deconstructions,
|
|
% so here we just recurse on the real representation.
|
|
{ Tag = shared_with_reserved_addresses(_, ThisTag) },
|
|
ml_gen_det_deconstruct_2(ThisTag, Type, Var, ConsId, Args,
|
|
Modes, Context, MLDS_Statements)
|
|
).
|
|
|
|
% Calculate the integer offset used to reference the first field
|
|
% of a structure for lowlevel data or the first argument number
|
|
% to access the field using the highlevel data representation.
|
|
% Abort if the tag indicates that the data doesn't have any
|
|
% fields.
|
|
:- pred ml_tag_offset_and_argnum(cons_tag::in, tag_bits::out,
|
|
int::out, int::out) is det.
|
|
|
|
ml_tag_offset_and_argnum(Tag, TagBits, OffSet, ArgNum) :-
|
|
(
|
|
Tag = single_functor,
|
|
TagBits = 0,
|
|
OffSet = 0,
|
|
ArgNum = 1
|
|
;
|
|
Tag = unshared_tag(UnsharedTag),
|
|
TagBits = UnsharedTag,
|
|
OffSet = 0,
|
|
ArgNum = 1
|
|
;
|
|
Tag = shared_remote_tag(PrimaryTag, _SecondaryTag),
|
|
TagBits = PrimaryTag,
|
|
OffSet = 1,
|
|
ArgNum = 1
|
|
;
|
|
Tag = shared_with_reserved_addresses(_, ThisTag),
|
|
% just recurse on ThisTag
|
|
ml_tag_offset_and_argnum(ThisTag, TagBits, OffSet, ArgNum)
|
|
;
|
|
Tag = string_constant(_String),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = int_constant(_Int),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = float_constant(_Float),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = pred_closure_tag(_, _, _),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = code_addr_constant(_, _),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = type_ctor_info_constant(_, _, _),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = base_typeclass_info_constant(_, _, _),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = tabling_pointer_constant(_, _),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = deep_profiling_proc_static_tag(_),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = table_io_decl_tag(_),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = no_tag,
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = shared_local_tag(_Bits1, _Num1),
|
|
error("ml_tag_offset_and_argnum")
|
|
;
|
|
Tag = reserved_address(_),
|
|
error("ml_tag_offset_and_argnum")
|
|
).
|
|
|
|
|
|
% Given a type and a cons_id, and also the types of the actual
|
|
% arguments of that cons_id in some particular use of it,
|
|
% look up the original types of the fields of that cons_id from
|
|
% the type definition. Note that the field types need not be
|
|
% the same as the actual argument types; for polymorphic types,
|
|
% the types of the actual arguments can be an instance of the
|
|
% field types.
|
|
%
|
|
:- pred ml_field_names_and_types(prog_type, cons_id, list(prog_type),
|
|
list(constructor_arg), ml_gen_info, ml_gen_info).
|
|
:- mode ml_field_names_and_types(in, in, in, out, in, out) is det.
|
|
|
|
ml_field_names_and_types(Type, ConsId, ArgTypes, Fields) -->
|
|
%
|
|
% Lookup the field types for the arguments of this cons_id
|
|
%
|
|
{ MakeUnnamedField = (func(FieldType) = no - FieldType) },
|
|
(
|
|
{ type_is_tuple(Type, _) },
|
|
{ list__length(ArgTypes, TupleArity) }
|
|
->
|
|
% The argument types for tuples are unbound type variables.
|
|
{ FieldTypes = ml_make_boxed_types(TupleArity) },
|
|
{ Fields = list__map(MakeUnnamedField, FieldTypes) }
|
|
;
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ type_util__get_type_and_cons_defn(ModuleInfo, Type, ConsId,
|
|
_TypeDefn, ConsDefn) },
|
|
{ ConsDefn = hlds_cons_defn(_, _, Fields0, _, _) },
|
|
%
|
|
% Add the fields for any type_infos and/or typeclass_infos
|
|
% inserted for existentially quantified data types.
|
|
% For these, we just copy the types from the ArgTypes.
|
|
%
|
|
{ NumArgs = list__length(ArgTypes) },
|
|
{ NumFieldTypes0 = list__length(Fields0) },
|
|
{ NumExtraTypes = NumArgs - NumFieldTypes0 },
|
|
{ ExtraFieldTypes = list__take_upto(NumExtraTypes, ArgTypes) },
|
|
{ ExtraFields = list__map(MakeUnnamedField, ExtraFieldTypes) },
|
|
{ Fields = list__append(ExtraFields, Fields0) }
|
|
).
|
|
|
|
:- pred ml_gen_unify_args(cons_id, prog_vars, list(uni_mode), list(prog_type),
|
|
list(constructor_arg), prog_type, mlds__lval, int, int,
|
|
cons_tag, prog_context, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_unify_args(in, in, in, in, in, in, in, in, in, in, in, out,
|
|
in, out) is det.
|
|
|
|
ml_gen_unify_args(ConsId, Args, Modes, ArgTypes, Fields, VarType, VarLval,
|
|
Offset, ArgNum, Tag, Context, MLDS_Statements) -->
|
|
(
|
|
ml_gen_unify_args_2(ConsId, Args, Modes, ArgTypes, Fields,
|
|
VarType, VarLval, Offset, ArgNum, Tag, Context,
|
|
[], MLDS_Statements0)
|
|
->
|
|
{ MLDS_Statements = MLDS_Statements0 }
|
|
;
|
|
{ error("ml_gen_unify_args: length mismatch") }
|
|
).
|
|
|
|
:- pred ml_gen_unify_args_2(cons_id, prog_vars, list(uni_mode), list(prog_type),
|
|
list(constructor_arg), prog_type, mlds__lval, int, int,
|
|
cons_tag, prog_context, mlds__statements, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_unify_args_2(in, in, in, in, in, in, in, in, in, in, in, in, out,
|
|
in, out) is semidet.
|
|
|
|
ml_gen_unify_args_2(_, [], [], [], _, _, _, _, _, _, _, Statements, Statements)
|
|
--> [].
|
|
ml_gen_unify_args_2(ConsId, [Arg|Args], [Mode|Modes], [ArgType|ArgTypes],
|
|
[Field|Fields], VarType, VarLval, Offset, ArgNum, Tag,
|
|
Context, MLDS_Statements0, MLDS_Statements) -->
|
|
{ Offset1 = Offset + 1 },
|
|
{ ArgNum1 = ArgNum + 1 },
|
|
ml_gen_unify_args_2(ConsId, Args, Modes, ArgTypes, Fields, VarType,
|
|
VarLval, Offset1, ArgNum1, Tag, Context,
|
|
MLDS_Statements0, MLDS_Statements1),
|
|
ml_gen_unify_arg(ConsId, Arg, Mode, ArgType, Field, VarType, VarLval,
|
|
Offset, ArgNum, Tag, Context,
|
|
MLDS_Statements1, MLDS_Statements).
|
|
|
|
:- pred ml_gen_unify_arg(cons_id, prog_var, uni_mode, prog_type,
|
|
constructor_arg, prog_type, mlds__lval, int, int, cons_tag,
|
|
prog_context, mlds__statements, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_unify_arg(in, in, in, in, in, in, in, in, in, in, in, in, out,
|
|
in, out) is det.
|
|
|
|
ml_gen_unify_arg(ConsId, Arg, Mode, ArgType, Field, VarType, VarLval,
|
|
Offset, ArgNum, Tag, Context,
|
|
MLDS_Statements0, MLDS_Statements) -->
|
|
{ Field = MaybeFieldName - FieldType },
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ module_info_globals(ModuleInfo, Globals) },
|
|
{ globals__lookup_bool_option(Globals, highlevel_data,
|
|
HighLevelData) },
|
|
{
|
|
%
|
|
% With the low-level data representation,
|
|
% we access all fields using offsets.
|
|
%
|
|
HighLevelData = no,
|
|
FieldId = offset(const(int_const(Offset)))
|
|
;
|
|
%
|
|
% With the high-level data representation,
|
|
% we always used named fields, except for
|
|
% tuple types.
|
|
%
|
|
HighLevelData = yes,
|
|
( type_is_tuple(VarType, _) ->
|
|
FieldId = offset(const(int_const(Offset)))
|
|
;
|
|
FieldName = ml_gen_field_name(MaybeFieldName, ArgNum),
|
|
(
|
|
ConsId = cons(ConsName, ConsArity)
|
|
->
|
|
unqualify_name(ConsName, UnqualConsName),
|
|
FieldId = ml_gen_field_id(VarType, Tag,
|
|
UnqualConsName, ConsArity, FieldName)
|
|
;
|
|
error("ml_gen_unify_args: invalid cons_id")
|
|
)
|
|
)
|
|
},
|
|
%
|
|
% Box the field type, if needed
|
|
%
|
|
{ ml_type_as_field(FieldType, ModuleInfo, HighLevelData,
|
|
BoxedFieldType) },
|
|
|
|
%
|
|
% Generate lvals for the LHS and the RHS
|
|
%
|
|
ml_gen_type(VarType, MLDS_VarType),
|
|
ml_gen_type(BoxedFieldType, MLDS_BoxedFieldType),
|
|
{ MaybePrimaryTag = get_primary_tag(Tag) },
|
|
{ FieldLval = field(MaybePrimaryTag, lval(VarLval), FieldId,
|
|
MLDS_BoxedFieldType, MLDS_VarType) },
|
|
ml_gen_var(Arg, ArgLval),
|
|
|
|
%
|
|
% Now generate code to unify them
|
|
%
|
|
ml_gen_sub_unify(Mode, ArgLval, ArgType, FieldLval, BoxedFieldType,
|
|
Context, MLDS_Statements0, MLDS_Statements).
|
|
|
|
:- pred ml_gen_sub_unify(uni_mode, mlds__lval, prog_type, mlds__lval, prog_type,
|
|
prog_context, mlds__statements, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_sub_unify(in, in, in, in, in, in, in, out, in, out) is det.
|
|
|
|
ml_gen_sub_unify(Mode, ArgLval, ArgType, FieldLval, FieldType, Context,
|
|
MLDS_Statements0, MLDS_Statements) -->
|
|
%
|
|
% Figure out the direction of data-flow from the mode,
|
|
% and generate code accordingly
|
|
%
|
|
{ Mode = ((LI - RI) -> (LF - RF)) },
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ mode_to_arg_mode(ModuleInfo, (LI -> LF), ArgType, LeftMode) },
|
|
{ mode_to_arg_mode(ModuleInfo, (RI -> RF), ArgType, RightMode) },
|
|
(
|
|
% skip dummy argument types, since they will not have
|
|
% been declared
|
|
{ type_util__is_dummy_argument_type(ArgType) }
|
|
->
|
|
{ MLDS_Statements = MLDS_Statements0 }
|
|
;
|
|
% both input: it's a test unification
|
|
{ LeftMode = top_in },
|
|
{ RightMode = top_in }
|
|
->
|
|
% This shouldn't happen, since mode analysis should
|
|
% avoid creating any tests in the arguments
|
|
% of a construction or deconstruction unification.
|
|
{ error("test in arg of [de]construction") }
|
|
;
|
|
% input - output: it's an assignment to the RHS
|
|
{ LeftMode = top_in },
|
|
{ RightMode = top_out }
|
|
->
|
|
ml_gen_box_or_unbox_rval(FieldType, ArgType,
|
|
lval(FieldLval), FieldRval),
|
|
{ MLDS_Statement = ml_gen_assign(ArgLval, FieldRval,
|
|
Context) },
|
|
{ MLDS_Statements = [MLDS_Statement | MLDS_Statements0] }
|
|
;
|
|
% output - input: it's an assignment to the LHS
|
|
{ LeftMode = top_out },
|
|
{ RightMode = top_in }
|
|
->
|
|
ml_gen_box_or_unbox_rval(ArgType, FieldType,
|
|
lval(ArgLval), ArgRval),
|
|
{ MLDS_Statement = ml_gen_assign(FieldLval, ArgRval,
|
|
Context) },
|
|
{ MLDS_Statements = [MLDS_Statement | MLDS_Statements0] }
|
|
;
|
|
% unused - unused: the unification has no effect
|
|
{ LeftMode = top_unused },
|
|
{ RightMode = top_unused }
|
|
->
|
|
{ MLDS_Statements = MLDS_Statements0 }
|
|
;
|
|
{ error("ml_gen_sub_unify: some strange unify") }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate a semidet deconstruction.
|
|
% A semidet deconstruction unification is tag test
|
|
% followed by a deterministic deconstruction
|
|
% (which is executed only if the tag test succeeds).
|
|
%
|
|
:- pred ml_gen_semi_deconstruct(prog_var, cons_id, prog_vars, list(uni_mode),
|
|
prog_context, mlds__defns, mlds__statements,
|
|
ml_gen_info, ml_gen_info).
|
|
:- mode ml_gen_semi_deconstruct(in, in, in, in, in, out, out, in, out) is det.
|
|
|
|
% semidet (can_fail) deconstruction:
|
|
% <succeeded = (X => f(A1, A2, ...))>
|
|
% ===>
|
|
% <succeeded = (X => f(_, _, _, _))> % tag test
|
|
% if (succeeded) {
|
|
% A1 = arg(X, f, 1); % extract arguments
|
|
% A2 = arg(X, f, 2);
|
|
% ...
|
|
% }
|
|
|
|
ml_gen_semi_deconstruct(Var, ConsId, Args, ArgModes, Context,
|
|
MLDS_Decls, MLDS_Statements) -->
|
|
ml_gen_tag_test(Var, ConsId, TagTestDecls, TagTestStatements,
|
|
TagTestExpression),
|
|
ml_gen_set_success(TagTestExpression, Context, SetTagTestResult),
|
|
ml_gen_test_success(SucceededExpression),
|
|
ml_gen_det_deconstruct(Var, ConsId, Args, ArgModes, Context,
|
|
GetArgsDecls, GetArgsStatements),
|
|
{ GetArgsDecls = [], GetArgsStatements = [] ->
|
|
MLDS_Decls = TagTestDecls,
|
|
MLDS_Statements = list__append(TagTestStatements,
|
|
[SetTagTestResult])
|
|
;
|
|
GetArgs = ml_gen_block(GetArgsDecls, GetArgsStatements,
|
|
Context),
|
|
IfStmt = if_then_else(SucceededExpression, GetArgs, no),
|
|
IfStatement = mlds__statement(IfStmt,
|
|
mlds__make_context(Context)),
|
|
MLDS_Decls = TagTestDecls,
|
|
MLDS_Statements = list__append(TagTestStatements,
|
|
[SetTagTestResult, IfStatement])
|
|
}.
|
|
|
|
% ml_gen_tag_test(Var, ConsId, Defns, Statements, Expression):
|
|
% Generate code to perform a tag test.
|
|
%
|
|
% The test checks whether Var has the functor specified by
|
|
% ConsId. The generated code may contain Defns, Statements
|
|
% and an Expression. The Expression is a boolean rval.
|
|
% After execution of the Statements, Expression will evaluate
|
|
% to true iff the Var has the functor specified by ConsId.
|
|
%
|
|
% TODO: apply the reverse tag test optimization
|
|
% for types with two functors (see unify_gen.m).
|
|
|
|
ml_gen_tag_test(Var, ConsId, TagTestDecls, TagTestStatements,
|
|
TagTestExpression) -->
|
|
ml_gen_var(Var, VarLval),
|
|
ml_variable_type(Var, Type),
|
|
ml_cons_id_to_tag(ConsId, Type, Tag),
|
|
=(Info),
|
|
{ ml_gen_info_get_module_info(Info, ModuleInfo) },
|
|
{ TagTestExpression = ml_gen_tag_test_rval(Tag, Type, ModuleInfo,
|
|
lval(VarLval)) },
|
|
{ TagTestDecls = [] },
|
|
{ TagTestStatements = [] }.
|
|
|
|
% ml_gen_tag_test_rval(Tag, VarType, ModuleInfo, VarRval) = TestRval:
|
|
% TestRval is a Rval of type bool which evaluates to
|
|
% true if VarRval has the specified Tag and false otherwise.
|
|
% VarType is the type of VarRval.
|
|
%
|
|
:- func ml_gen_tag_test_rval(cons_tag, prog_type, module_info, mlds__rval)
|
|
= mlds__rval.
|
|
|
|
ml_gen_tag_test_rval(string_constant(String), _, _, Rval) =
|
|
binop(str_eq, Rval, const(string_const(String))).
|
|
ml_gen_tag_test_rval(float_constant(Float), _, _, Rval) =
|
|
binop(float_eq, Rval, const(float_const(Float))).
|
|
ml_gen_tag_test_rval(int_constant(Int), _, _, Rval) =
|
|
binop(eq, Rval, const(int_const(Int))).
|
|
ml_gen_tag_test_rval(pred_closure_tag(_, _, _), _, _, _Rval) = _TestRval :-
|
|
% This should never happen, since the error will be detected
|
|
% during mode checking.
|
|
error("Attempted higher-order unification").
|
|
ml_gen_tag_test_rval(code_addr_constant(_, _), _, _, _Rval) = _TestRval :-
|
|
% This should never happen
|
|
error("Attempted code_addr unification").
|
|
ml_gen_tag_test_rval(type_ctor_info_constant(_, _, _), _, _, _) = _ :-
|
|
% This should never happen
|
|
error("Attempted type_ctor_info unification").
|
|
ml_gen_tag_test_rval(base_typeclass_info_constant(_, _, _), _, _, _) = _ :-
|
|
% This should never happen
|
|
error("Attempted base_typeclass_info unification").
|
|
ml_gen_tag_test_rval(tabling_pointer_constant(_, _), _, _, _) = _ :-
|
|
% This should never happen
|
|
error("Attempted tabling_pointer unification").
|
|
ml_gen_tag_test_rval(deep_profiling_proc_static_tag(_), _, _, _) = _ :-
|
|
% This should never happen
|
|
error("Attempted deep_profiling_proc_static unification").
|
|
ml_gen_tag_test_rval(table_io_decl_tag(_), _, _, _) = _ :-
|
|
% This should never happen
|
|
error("Attempted table_io_decl unification").
|
|
ml_gen_tag_test_rval(no_tag, _, _, _Rval) = const(true).
|
|
ml_gen_tag_test_rval(single_functor, _, _, _Rval) = const(true).
|
|
ml_gen_tag_test_rval(unshared_tag(UnsharedTag), _, _, Rval) =
|
|
binop(eq, unop(std_unop(tag), Rval),
|
|
unop(std_unop(mktag), const(int_const(UnsharedTag)))).
|
|
ml_gen_tag_test_rval(shared_remote_tag(PrimaryTagVal, SecondaryTagVal),
|
|
VarType, ModuleInfo, Rval) = TagTest :-
|
|
SecondaryTagField = ml_gen_secondary_tag_rval(PrimaryTagVal,
|
|
VarType, ModuleInfo, Rval),
|
|
SecondaryTagTest = binop(eq, SecondaryTagField,
|
|
const(int_const(SecondaryTagVal))),
|
|
module_info_globals(ModuleInfo, Globals),
|
|
globals__lookup_int_option(Globals, num_tag_bits, NumTagBits),
|
|
( NumTagBits = 0 ->
|
|
% no need to test the primary tag
|
|
TagTest = SecondaryTagTest
|
|
;
|
|
PrimaryTagTest = binop(eq,
|
|
unop(std_unop(tag), Rval),
|
|
unop(std_unop(mktag),
|
|
const(int_const(PrimaryTagVal)))),
|
|
TagTest = binop(and, PrimaryTagTest, SecondaryTagTest)
|
|
).
|
|
ml_gen_tag_test_rval(shared_local_tag(Bits, Num), VarType, ModuleInfo, Rval) =
|
|
TestRval :-
|
|
MLDS_VarType = mercury_type_to_mlds_type(ModuleInfo, VarType),
|
|
TestRval = binop(eq, Rval,
|
|
unop(cast(MLDS_VarType), mkword(Bits,
|
|
unop(std_unop(mkbody), const(int_const(Num)))))).
|
|
|
|
ml_gen_tag_test_rval(reserved_address(ReservedAddr), VarType, ModuleInfo,
|
|
Rval) = TestRval :-
|
|
MLDS_VarType = mercury_type_to_mlds_type(ModuleInfo, VarType),
|
|
ReservedAddrRval = ml_gen_reserved_address(ModuleInfo, ReservedAddr,
|
|
MLDS_VarType),
|
|
TestRval = binop(eq, Rval, ReservedAddrRval).
|
|
|
|
ml_gen_tag_test_rval(shared_with_reserved_addresses(ReservedAddrs, ThisTag),
|
|
VarType, ModuleInfo, Rval) = FinalTestRval :-
|
|
%
|
|
% We first check that the Rval doesn't match any of the
|
|
% ReservedAddrs, and then check that it matches ThisTag.
|
|
%
|
|
CheckReservedAddrs = (func(RA, TestRval0) = TestRval :-
|
|
EqualRA = ml_gen_tag_test_rval(reserved_address(RA), VarType,
|
|
ModuleInfo, Rval),
|
|
TestRval = ml_gen_and(ml_gen_not(EqualRA), TestRval0)
|
|
),
|
|
MatchesThisTag = ml_gen_tag_test_rval(ThisTag, VarType, ModuleInfo,
|
|
Rval),
|
|
FinalTestRval = list__foldr(CheckReservedAddrs, ReservedAddrs,
|
|
MatchesThisTag).
|
|
|
|
% ml_gen_secondary_tag_rval(PrimaryTag, VarType, ModuleInfo, VarRval):
|
|
% Return the rval for the secondary tag field of VarRval,
|
|
% assuming that VarRval has the specified VarType and PrimaryTag.
|
|
ml_gen_secondary_tag_rval(PrimaryTagVal, VarType, ModuleInfo, Rval) =
|
|
SecondaryTagField :-
|
|
MLDS_VarType = mercury_type_to_mlds_type(ModuleInfo, VarType),
|
|
module_info_globals(ModuleInfo, Globals),
|
|
globals__lookup_bool_option(Globals, highlevel_data, HighLevelData),
|
|
( HighLevelData = no ->
|
|
% Note: with the low-level data representation,
|
|
% all fields -- even the secondary tag -- are boxed,
|
|
% and so we need to unbox (i.e. cast) it back to the
|
|
% right type here.
|
|
SecondaryTagField =
|
|
unop(unbox(mlds__native_int_type),
|
|
lval(field(yes(PrimaryTagVal), Rval,
|
|
offset(const(int_const(0))),
|
|
mlds__generic_type, MLDS_VarType)))
|
|
;
|
|
FieldId = ml_gen_hl_tag_field_id(VarType, ModuleInfo),
|
|
SecondaryTagField = lval(field(yes(PrimaryTagVal), Rval,
|
|
FieldId, mlds__native_int_type, MLDS_VarType))
|
|
).
|
|
|
|
% Return the field_id for the "data_tag" field of the specified
|
|
% Mercury type, which holds the secondary tag.
|
|
%
|
|
:- func ml_gen_hl_tag_field_id(prog_type, module_info) = mlds__field_id.
|
|
|
|
ml_gen_hl_tag_field_id(Type, ModuleInfo) = FieldId :-
|
|
FieldName = "data_tag",
|
|
|
|
% Figure out the type name and arity
|
|
( type_to_ctor_and_args(Type, TypeCtor0, _) ->
|
|
TypeCtor = TypeCtor0
|
|
;
|
|
error("ml_gen_hl_tag_field_id: invalid type")
|
|
),
|
|
ml_gen_type_name(TypeCtor, qual(MLDS_Module, TypeName), TypeArity),
|
|
|
|
% Figure out whether this type has constructors both
|
|
% with and without secondary tags. If so, then the
|
|
% secondary tag field is in a class "tag_type" that is
|
|
% derived from the base class for this type,
|
|
% rather than in the base class itself.
|
|
module_info_types(ModuleInfo, TypeTable),
|
|
TypeDefn = map__lookup(TypeTable, TypeCtor),
|
|
hlds_data__get_type_defn_body(TypeDefn, TypeDefnBody),
|
|
( TypeDefnBody = du_type(Ctors, TagValues, _, _) ->
|
|
(
|
|
(some [Ctor] (
|
|
list__member(Ctor, Ctors),
|
|
ml_uses_secondary_tag(TagValues, Ctor, _)
|
|
)),
|
|
(some [Ctor] (
|
|
list__member(Ctor, Ctors),
|
|
\+ ml_uses_secondary_tag(TagValues, Ctor, _)
|
|
))
|
|
->
|
|
ClassQualifier = mlds__append_class_qualifier(
|
|
MLDS_Module, TypeName, TypeArity),
|
|
ClassName = "tag_type",
|
|
ClassArity = 0
|
|
;
|
|
ClassQualifier = MLDS_Module,
|
|
ClassName = TypeName,
|
|
ClassArity = TypeArity
|
|
)
|
|
;
|
|
error("ml_gen_hl_tag_field_id: non-du type")
|
|
),
|
|
|
|
% Put it all together
|
|
QualClassName = qual(ClassQualifier, ClassName),
|
|
ClassPtrType = mlds__ptr_type(mlds__class_type(
|
|
QualClassName, ClassArity, mlds__class)),
|
|
FieldQualifier = mlds__append_class_qualifier(
|
|
ClassQualifier, ClassName, ClassArity),
|
|
QualifiedFieldName = qual(FieldQualifier, FieldName),
|
|
FieldId = named_field(QualifiedFieldName, ClassPtrType).
|
|
|
|
:- func ml_gen_field_id(prog_type, cons_tag, mlds__class_name, arity,
|
|
mlds__field_name) = mlds__field_id.
|
|
|
|
ml_gen_field_id(Type, Tag, ConsName, ConsArity, FieldName) = FieldId :-
|
|
(
|
|
type_to_ctor_and_args(Type, TypeCtor, _)
|
|
->
|
|
ml_gen_type_name(TypeCtor, QualTypeName, TypeArity),
|
|
QualTypeName = qual(MLDS_Module, TypeName),
|
|
TypeQualifier = mlds__append_class_qualifier(
|
|
MLDS_Module, TypeName, TypeArity),
|
|
|
|
( ml_tag_uses_base_class(Tag) ->
|
|
% in this case, there's only one functor for the type
|
|
% (other than reserved_address constants),
|
|
% and so the class name is determined by the type name
|
|
ClassPtrType = mlds__ptr_type(mlds__class_type(
|
|
QualTypeName, TypeArity, mlds__class)),
|
|
QualifiedFieldName = qual(TypeQualifier, FieldName)
|
|
;
|
|
% in this case, the class name is determined by the
|
|
% constructor
|
|
QualConsName = qual(TypeQualifier, ConsName),
|
|
ClassPtrType = mlds__ptr_type(mlds__class_type(
|
|
QualConsName, ConsArity, mlds__class)),
|
|
FieldQualifier = mlds__append_class_qualifier(
|
|
TypeQualifier, ConsName, ConsArity),
|
|
QualifiedFieldName = qual(FieldQualifier, FieldName)
|
|
),
|
|
FieldId = named_field(QualifiedFieldName, ClassPtrType)
|
|
;
|
|
error("ml_gen_field_id: invalid type")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
this_file = "ml_unify_gen.m".
|
|
|
|
:- end_module ml_unify_gen.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|