[m-rev.] diff: generate simpler unify/compare preds for erlang
Peter Wang
wangp at students.csse.unimelb.edu.au
Tue Jul 3 13:16:38 AEST 2007
Estimated hours taken: 3
Branches: main
compiler/erl_code_gen.m:
When possible, ignore the compiler generated unify/compare predicates
and directly output simpler code that compares high level data
structures with Erlang =:= and < operators. This is similar a
previous change, but in that change we were changing the call sites.
compiler/type_util.m:
Fix type_definitely_has_no_user_defined_equality_pred. It was
incorrectly succeeding for d.u. types which have data constructors with
arguments of types that have user-defined equality predicates.
Index: compiler/erl_code_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erl_code_gen.m,v
retrieving revision 1.16
diff -u -r1.16 erl_code_gen.m
--- compiler/erl_code_gen.m 2 Jul 2007 05:49:32 -0000 1.16
+++ compiler/erl_code_gen.m 3 Jul 2007 03:02:46 -0000
@@ -63,6 +63,7 @@
:- import_module libs.compiler_util.
:- import_module libs.globals.
:- import_module libs.options.
+:- import_module mdbcomp.prim_data.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_foreign.
:- import_module parse_tree.prog_type.
@@ -189,10 +190,122 @@
erl_gen_procs([ProcId | ProcIds], ModuleInfo, PredId, PredInfo, ProcTable,
!Defns) :-
map.lookup(ProcTable, ProcId, ProcInfo),
- erl_gen_proc(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo, !Defns),
+ (
+ erl_maybe_gen_simple_special_pred(ModuleInfo, PredId, ProcId,
+ PredInfo, ProcInfo, !Defns)
+ ->
+ true
+ ;
+ erl_gen_proc(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo, !Defns)
+ ),
erl_gen_procs(ProcIds, ModuleInfo, PredId, PredInfo, ProcTable, !Defns).
%-----------------------------------------------------------------------------%
+
+ % erl_maybe_gen_simple_special_pred(ModuleInfo, PredId, ProcId,
+ % PredInfo, ProcInfo, !Defns)
+ %
+ % If the procedure is a compiler generated unification or comparison
+ % procedure, and the arguments are ground, and the values of the types they
+ % are comparing do not have user-defined equality or comparison then
+ % generate simpler versions of those procedures using the Erlang comparison
+ % operators. Otherwise fail.
+ %
+:- pred erl_maybe_gen_simple_special_pred(module_info::in,
+ pred_id::in, proc_id::in, pred_info::in, proc_info::in,
+ list(elds_defn)::in, list(elds_defn)::out) is semidet.
+
+erl_maybe_gen_simple_special_pred(ModuleInfo, PredId, ProcId,
+ PredInfo, ProcInfo, !Defns) :-
+ PredName = pred_info_name(PredInfo),
+ PredArity = pred_info_orig_arity(PredInfo),
+ special_pred_name_arity(SpecialId, _, PredName, PredArity),
+ proc_info_get_headvars(ProcInfo, Args),
+ proc_info_get_vartypes(ProcInfo, VarTypes),
+ (
+ SpecialId = spec_pred_unify,
+ in_in_unification_proc_id(ProcId),
+ list.reverse(Args, [Y, X | _]),
+ map.lookup(VarTypes, Y, Type),
+ type_definitely_has_no_user_defined_equality_pred(ModuleInfo, Type),
+ erl_gen_simple_in_in_unification(ModuleInfo, PredId, ProcId, X, Y,
+ ProcDefn)
+ ;
+ SpecialId = spec_pred_compare,
+ list.reverse(Args, [Y, X, _Res | _]),
+ map.lookup(VarTypes, Y, Type),
+ type_definitely_has_no_user_defined_equality_pred(ModuleInfo, Type),
+ erl_gen_simple_compare(ModuleInfo, PredId, ProcId, X, Y, ProcDefn)
+ ),
+ !:Defns = [ProcDefn | !.Defns].
+
+:- pred erl_gen_simple_in_in_unification(module_info::in,
+ pred_id::in, proc_id::in, prog_var::in, prog_var::in, elds_defn::out)
+ is det.
+
+erl_gen_simple_in_in_unification(ModuleInfo, PredId, ProcId, X, Y, ProcDefn) :-
+ Info = erl_gen_info_init(ModuleInfo, PredId, ProcId),
+ erl_gen_info_get_input_vars(Info, InputVars),
+
+ % '__Unify__'(X, Y) ->
+ % case X =:= Y of
+ % true -> {};
+ % false -> fail
+ % end.
+
+ Clause = elds_clause(terms_from_vars(InputVars), ClauseExpr),
+ ClauseExpr = elds_case_expr(CompareXY, [TrueCase, FalseCase]),
+ CompareXY = elds_binop((=:=), expr_from_var(X), expr_from_var(Y)),
+ TrueCase = elds_case(elds_true, elds_term(elds_empty_tuple)),
+ FalseCase = elds_case(elds_false, elds_term(elds_fail)),
+
+ erl_gen_info_get_varset(Info, ProcVarSet),
+ erl_gen_info_get_env_vars(Info, EnvVarNames),
+ ProcDefn = elds_defn(proc(PredId, ProcId), ProcVarSet,
+ body_defined_here(Clause), EnvVarNames).
+
+:- pred erl_gen_simple_compare(module_info::in, pred_id::in, proc_id::in,
+ prog_var::in, prog_var::in, elds_defn::out) is det.
+
+erl_gen_simple_compare(ModuleInfo, PredId, ProcId, X, Y, ProcDefn) :-
+ Info = erl_gen_info_init(ModuleInfo, PredId, ProcId),
+ erl_gen_info_get_input_vars(Info, InputVars),
+
+ XExpr = expr_from_var(X),
+ YExpr = expr_from_var(Y),
+
+ % '__Compare__'(X, Y) ->
+ % case X =:= Y of
+ % true -> {{'='}};
+ % false ->
+ % case X < Y of
+ % true -> {{'<'}};
+ % false -> {{'>'}};
+ % end
+ % end.
+ %
+ Clause = elds_clause(terms_from_vars(InputVars), ClauseExpr),
+ ClauseExpr = elds_case_expr(CondEq, [IsEq, IsNotEq]),
+
+ CondEq = elds_binop((=:=), XExpr, YExpr),
+ IsEq = elds_case(elds_true, enum_in_tuple("=")),
+ IsNotEq = elds_case(elds_false, elds_case_expr(CondLt, [IsLt, IsGt])),
+
+ CondLt = elds_binop((<), XExpr, YExpr),
+ IsLt = elds_case(elds_true, enum_in_tuple("<")),
+ IsGt = elds_case(elds_false, enum_in_tuple(">")),
+
+ erl_gen_info_get_varset(Info, ProcVarSet),
+ erl_gen_info_get_env_vars(Info, EnvVarNames),
+ ProcDefn = elds_defn(proc(PredId, ProcId), ProcVarSet,
+ body_defined_here(Clause), EnvVarNames).
+
+:- func enum_in_tuple(string) = elds_expr.
+
+enum_in_tuple(X) =
+ elds_term(elds_tuple([elds_term(make_enum_alternative(X))])).
+
+%-----------------------------------------------------------------------------%
%
% Code for handling individual procedures
%
@@ -202,9 +315,9 @@
:- pred erl_gen_proc(module_info::in, pred_id::in, proc_id::in, pred_info::in,
proc_info::in, list(elds_defn)::in, list(elds_defn)::out) is det.
-erl_gen_proc(ModuleInfo, PredId, ProcId, _PredInfo, _ProcInfo, !Defns) :-
- erl_gen_proc_defn(ModuleInfo, PredId, ProcId, ProcVarSet, ProcBody,
- EnvVarNames),
+erl_gen_proc(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo, !Defns) :-
+ erl_gen_proc_defn(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo,
+ ProcVarSet, ProcBody, EnvVarNames),
ProcDefn = elds_defn(proc(PredId, ProcId), ProcVarSet, ProcBody,
EnvVarNames),
!:Defns = [ProcDefn | !.Defns].
@@ -212,11 +325,11 @@
% Generate an ELDS definition for the specified procedure.
%
:- pred erl_gen_proc_defn(module_info::in, pred_id::in, proc_id::in,
- prog_varset::out, elds_body::out, set(string)::out) is det.
+ pred_info::in, proc_info::in, prog_varset::out, elds_body::out,
+ set(string)::out) is det.
-erl_gen_proc_defn(ModuleInfo, PredId, ProcId, ProcVarSet, ProcBody,
- EnvVarNames) :-
- module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo),
+erl_gen_proc_defn(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo,
+ ProcVarSet, ProcBody, EnvVarNames) :-
pred_info_get_import_status(PredInfo, ImportStatus),
proc_info_interface_code_model(ProcInfo, CodeModel),
proc_info_get_headvars(ProcInfo, HeadVars),
Index: compiler/type_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/type_util.m,v
retrieving revision 1.177
diff -u -r1.177 type_util.m
--- compiler/type_util.m 2 Jul 2007 05:30:30 -0000 1.177
+++ compiler/type_util.m 3 Jul 2007 03:02:47 -0000
@@ -73,9 +73,8 @@
:- pred type_body_has_user_defined_equality_pred(module_info::in,
hlds_type_body::in, unify_compare::out) is semidet.
- % Succeed iff the principal type constructor of the specified type and none
- % of its arguments are known not to have user-defined equality or
- % comparison predicates.
+ % Succeed iff the type (not just the principal type constructor) is known
+ % to not have user-defined equality or comparison predicates.
%
% If the type is a type variable, or is abstract, etc. make the
% conservative approximation and fail.
@@ -323,6 +322,7 @@
:- import_module char.
:- import_module int.
:- import_module map.
+:- import_module set.
:- import_module term.
%-----------------------------------------------------------------------------%
@@ -397,20 +397,36 @@
).
type_definitely_has_no_user_defined_equality_pred(ModuleInfo, Type) :-
- type_to_type_defn_body(ModuleInfo, Type, TypeBody),
- type_body_definitely_has_no_user_defined_equality_pred(ModuleInfo,
- TypeBody),
- type_to_ctor_and_args_det(Type, _, Args),
- all [Arg] (
- list.member(Arg, Args)
- =>
- type_definitely_has_no_user_defined_equality_pred(ModuleInfo, Arg)
+ type_definitely_has_no_user_defined_equality_pred_2(ModuleInfo,
+ set.init, Type).
+
+:- pred type_definitely_has_no_user_defined_equality_pred_2(module_info::in,
+ set(mer_type)::in, mer_type::in) is semidet.
+
+type_definitely_has_no_user_defined_equality_pred_2(ModuleInfo,
+ SeenTypes0, Type) :-
+ (if set.contains(SeenTypes0, Type) then
+ % Don't loop on recursive types.
+ true
+ else
+ set.insert(SeenTypes0, Type, SeenTypes),
+ type_to_type_defn_body(ModuleInfo, Type, TypeBody),
+ type_body_definitely_has_no_user_defined_equality_pred(ModuleInfo,
+ SeenTypes, TypeBody),
+ type_to_ctor_and_args_det(Type, _, Args),
+ all [Arg] (
+ list.member(Arg, Args)
+ =>
+ type_definitely_has_no_user_defined_equality_pred_2(ModuleInfo,
+ SeenTypes, Arg)
+ )
).
:- pred type_body_definitely_has_no_user_defined_equality_pred(module_info::in,
- hlds_type_body::in) is semidet.
+ set(mer_type)::in, hlds_type_body::in) is semidet.
-type_body_definitely_has_no_user_defined_equality_pred(ModuleInfo, TypeBody) :-
+type_body_definitely_has_no_user_defined_equality_pred(ModuleInfo, SeenTypes,
+ TypeBody) :-
module_info_get_globals(ModuleInfo, Globals),
globals.get_target(Globals, Target),
(
@@ -423,12 +439,21 @@
ForeignTypeBody, _)
;
TypeBody ^ du_type_usereq = no,
- % There must not be any existentially quantified type variables.
all [Ctor] (
list.member(Ctor, Ctors)
- =>
- Ctor = ctor([], _, _, _, _)
- )
+ => (
+ % There must not be any existentially quantified type
+ % variables.
+ Ctor = ctor([], _, _, Args, _),
+ % The data constructor argument types must not have
+ % user-defined equality preds.
+ all [Arg] (
+ list.member(ctor_arg(_, ArgType, _), Args)
+ =>
+ type_definitely_has_no_user_defined_equality_pred_2(
+ ModuleInfo, SeenTypes, ArgType)
+ )
+ ))
)
;
TypeBody = hlds_eqv_type(EqvType),
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list