Files
mercury/compiler/hlds_code_util.m
Peter Wang 12281f3419 Implement a type representation optimisation ("direct argument functors"),
Branches: main

Implement a type representation optimisation ("direct argument functors"),
where a functor with exactly one argument can be represented by a tagged
pointer to the argument value, which itself does not require the tag bits,
e.g.

	:- type maybe_foo ---> yes(foo) ; no.
	:- type foo       ---> foo(int, int).  % aligned pointer

To ensure that all modules which could construct or deconstruct the functor
agree on the type representation, I had planned to automatically output
extra information to .int files to notify importing modules about functors
using the optimised representation:

	:- type maybe_foo ---> yes(foo) ; no
		where direct_arg is [yes/1].

However, the compiler does not perform enough (or any) semantic analysis
while making interface files.  The fallback solution is to only use the
optimised representation when all importing modules can be guaranteed to
import both the top-level type and the argument type, namely, when both
types are exported from the same module.  We also allow certain built-in
argument types; currently this only includes tuples.

Non-exported types may use the optimised representation, but when
intermodule optimisation is enabled, they may be written out to .opt files.
Then, we *do* add direct_arg attributes to .opt files to ensure that importing
modules agree on the type representation.  The attributes may also be added by
Mercury programmers to source files, which will be copied directly into .int
files without analysis.  They will be checked when the module is actually
compiled.

This patch includes work by Zoltan, who independently implemented a version
of this change.


compiler/hlds_data.m:
	Record the direct arg functors in hlds_du_type.

	Add a new option to cons_tag.

	Fix some comments.

compiler/prog_data.m:
compiler/prog_io_type_defn.m:
	Parse and record `direct_arg' attributes on type definitions.

compiler/prog_io_pragma.m:
	Issue an error if the `direct_arg' attribute is used with a foreign
	type.

compiler/make_tags.m:
compiler/mercury_compile_front_end.m:
	Add a pass to convert suitable functors to use the direct argument
	representation.  The argument type must have been added to the type
	table, so we do this after all type definitions have been added.

	Move code to compute cheaper_tag_test here.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:
	Generate different code to construct/deconstruct direct argument
	functors.

compiler/intermod.m:
	Write `direct_arg' attributes to .opt files for functors
	using the direct argument representation.

compiler/mercury_to_mercury.m:
	Write out `direct_arg' attributes.

compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
	Add an option to the types which describe the location of secondary
	tag options. The functors which can use the optimised representation
	are a subset of those which require no secondary tag.

	Output "MR_SECTAG_NONE_DIRECT_ARG" instead of "MR_SECTAG_NONE" in
	RTTI structures when applicable.

compiler/add_pragma.m:
compiler/add_type.m:
compiler/bytecode_gen.m:
compiler/check_typeclass.m
compiler/code_info.m:
compiler/equiv_type.m:
compiler/export.m:
compiler/foreign.m:
compiler/hlds_code_util.m:
compiler/hlds_out_module.m:
compiler/inst_check.m:
compiler/ml_proc_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_type_gen.m:
compiler/module_qual.m:
compiler/modules.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/recompilation.version.m:
compiler/simplify.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/tag_switch.m:
compiler/term_norm.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
	Conform to changes.

	Bump RTTI version number.

doc/reference_manual.texi:
	Add commented out documentation for `direct_arg' attributes.

library/construct.m:
	Handle MR_SECTAG_NONE_DIRECT_ARG in construct.construct/3.

library/private_builtin.m:
	Add MR_SECTAG_NONE_DIRECT_ARG constant for Java for consistency,
	though it won't be used.

runtime/mercury_grade.h:
	Bump binary compatibility version number.

runtime/mercury_type_info.h:
	Bump RTTI version number.

	Add MR_SECTAG_NONE_DIRECT_ARG.

runtime/mercury_deconstruct.c:
runtime/mercury_deep_copy_body.h:
runtime/mercury_ml_expand_body.h:
runtime/mercury_table_type_body.h:
runtime/mercury_term_size.c:
runtime/mercury_unify_compare_body.h:
	Handle MR_SECTAG_NONE_DIRECT_ARG in RTTI code.

tests/debugger/Mmakefile:
tests/debugger/chooser_tag_test.exp:
tests/debugger/chooser_tag_test.inp:
tests/debugger/chooser_tag_test.m:
tests/hard_coded/Mercury.options:
tests/hard_coded/Mmakefile:
tests/hard_coded/construct_test.exp:
tests/hard_coded/construct_test.m:
tests/hard_coded/direct_arg_cyclic1.exp:
tests/hard_coded/direct_arg_cyclic1.m:
tests/hard_coded/direct_arg_cyclic2.m:
tests/hard_coded/direct_arg_cyclic3.m:
tests/hard_coded/direct_arg_intermod1.exp:
tests/hard_coded/direct_arg_intermod1.m:
tests/hard_coded/direct_arg_intermod2.m:
tests/hard_coded/direct_arg_intermod3.m:
tests/hard_coded/direct_arg_parent.exp:
tests/hard_coded/direct_arg_parent.m:
tests/hard_coded/direct_arg_sub.m:
tests/invalid/Mmakefile:
tests/invalid/where_direct_arg.err_exp:
tests/invalid/where_direct_arg.m:
tests/invalid/where_direct_arg2.err_exp:
tests/invalid/where_direct_arg2.m:
	Add test cases.

tests/invalid/ee_invalid.err_exp:
	Update expected output.
2011-06-16 06:42:19 +00:00

175 lines
6.5 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2002-2011 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: hlds_code_util.m.
%
% Various utilities routines for use during HLDS generation.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module hlds.hlds_code_util.
:- interface.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_module.
:- import_module parse_tree.prog_data.
:- import_module list.
%-----------------------------------------------------------------------------%
% Find out how a function symbol (constructor) is represented
% in the given type.
%
:- func cons_id_to_tag(module_info, cons_id) = cons_tag.
% Given a list of types, mangle the names so into a string which
% identifies them. The types must all have their top level functor
% bound, with any arguments free variables.
%
:- pred make_instance_string(list(mer_type)::in, string::out) is det.
% Succeeds iff this inst is one that can be used in a valid
% mutable declaration.
%
:- pred is_valid_mutable_inst(module_info::in, mer_inst::in) is semidet.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds.mode_util.
:- import_module hlds.hlds_pred.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.prog_type.
:- import_module char.
:- import_module map.
:- import_module require.
:- import_module set.
:- import_module string.
%-----------------------------------------------------------------------------%
cons_id_to_tag(ModuleInfo, ConsId) = Tag:-
(
ConsId = int_const(Int),
Tag = int_tag(Int)
;
ConsId = float_const(Float),
Tag = float_tag(Float)
;
ConsId = char_const(Char),
char.to_int(Char, CharCode),
Tag = int_tag(CharCode)
;
ConsId = string_const(String),
Tag = string_tag(String)
;
ConsId = impl_defined_const(_),
unexpected($module, $pred, "implementation_defined_const")
;
ConsId = closure_cons(ShroudedPredProcId, EvalMethod),
proc(PredId, ProcId) = unshroud_pred_proc_id(ShroudedPredProcId),
Tag = closure_tag(PredId, ProcId, EvalMethod)
;
ConsId = type_ctor_info_const(ModuleName, TypeName, Arity),
Tag = type_ctor_info_tag(ModuleName, TypeName, Arity)
;
ConsId = base_typeclass_info_const(ModuleName, ClassName,
_Instance, EncodedArgs),
Tag = base_typeclass_info_tag(ModuleName, ClassName, EncodedArgs)
;
( ConsId = type_info_cell_constructor(_)
; ConsId = typeclass_info_cell_constructor
),
Tag = unshared_tag(0)
;
ConsId = tabling_info_const(ShroudedPredProcId),
proc(PredId, ProcId) = unshroud_pred_proc_id(ShroudedPredProcId),
Tag = tabling_info_tag(PredId, ProcId)
;
ConsId = deep_profiling_proc_layout(ShroudedPredProcId),
proc(PredId, ProcId) = unshroud_pred_proc_id(ShroudedPredProcId),
Tag = deep_profiling_proc_layout_tag(PredId, ProcId)
;
ConsId = table_io_decl(ShroudedPredProcId),
proc(PredId, ProcId) = unshroud_pred_proc_id(ShroudedPredProcId),
Tag = table_io_decl_tag(PredId, ProcId)
;
ConsId = tuple_cons(_Arity),
% Tuples do not need a tag. Note that unary tuples are not treated
% as no_tag types. There is no reason why they couldn't be, it is
% just not worth the effort.
Tag = single_functor_tag
;
ConsId = cons(_Name, _Arity, TypeCtor),
module_info_get_type_table(ModuleInfo, TypeTable),
lookup_type_ctor_defn(TypeTable, TypeCtor, TypeDefn),
hlds_data.get_type_defn_body(TypeDefn, TypeBody),
(
TypeBody = hlds_du_type(_, ConsTagTable, _, _, _, _, _, _, _),
map.lookup(ConsTagTable, ConsId, Tag)
;
( TypeBody = hlds_eqv_type(_)
; TypeBody = hlds_foreign_type(_)
; TypeBody = hlds_solver_type(_, _)
; TypeBody = hlds_abstract_type(_)
),
unexpected($module, $pred, "type is not d.u. type")
)
).
%-----------------------------------------------------------------------------%
make_instance_string(InstanceTypes, InstanceString) :-
% Note that for historical reasons, builtin types are treated as being
% unqualified (`int') rather than being qualified (`builtin.int')
% at this point.
list.map(type_to_string, InstanceTypes, InstanceStrings),
string.append_list(InstanceStrings, InstanceString).
:- pred type_to_string(mer_type::in, string::out) is det.
type_to_string(Type, String) :-
( type_to_ctor_and_args(Type, TypeCtor, _) ->
TypeCtor = type_ctor(TypeName, TypeArity),
TypeNameString = sym_name_to_string_sep(TypeName, "__"),
string.int_to_string(TypeArity, TypeArityString),
String = TypeNameString ++ "__arity" ++ TypeArityString ++ "__"
;
unexpected($module, $pred, "invalid type")
).
%----------------------------------------------------------------------------%
is_valid_mutable_inst(ModuleInfo, Inst) :-
set.init(Expansions),
is_valid_mutable_inst_2(ModuleInfo, Inst, Expansions).
:- pred is_valid_mutable_inst_2(module_info::in, mer_inst::in,
set(inst_name)::in) is semidet.
is_valid_mutable_inst_2(_, any(shared, _), _).
is_valid_mutable_inst_2(ModuleInfo, bound(shared, BoundInsts), Expansions) :-
list.member(bound_functor(_, Insts), BoundInsts),
list.member(Inst, Insts),
is_valid_mutable_inst_2(ModuleInfo, Inst, Expansions).
is_valid_mutable_inst_2(_, ground(shared, _), _).
is_valid_mutable_inst_2(ModuleInfo, defined_inst(InstName), Expansions0) :-
not set.member(InstName, Expansions0),
Expansions = set.insert(Expansions0, InstName),
inst_lookup(ModuleInfo, InstName, Inst),
is_valid_mutable_inst_2(ModuleInfo, Inst, Expansions).
%----------------------------------------------------------------------------%
:- end_module hlds_code_util.
%----------------------------------------------------------------------------%