Files
mercury/compiler/ml_unify_gen.m
Fergus Henderson 7597790760 Use sub-modules to structure the modules in the Mercury compiler directory.
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.
2002-03-20 12:37:56 +00:00

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.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%