[m-rev.] for review: better code for unify and compare procs
Zoltan Somogyi
zs at cs.mu.OZ.AU
Mon Jan 12 15:52:41 AEDT 2004
For review by Fergus. Together with the change to jumpopt, this change
reduces the size of aditi_backend.rl_code.c by 13 to 18%, depending on
the measure (lines, characters, object code size). It should also make
some compare predicates faster.
Zoltan.
compiler/unify_proc.m:
Modify the clauses handling constants in the code we generate for
unify and compare predicates to make the generated code more compact.
For unify predicates, instead of clauses such as
(
...
;
X = f, Y = f
;
X = g, Y = g
;
...
),
generate clauses such as
(
...
;
X = f, Y = X
;
X = g, Y = X
;
...
),
since the latter allows dupelim.m to merge the code of the affected
clauses, whereas the former doesn't. To avoid infinite recursion,
we compare X and Y as integers. (If the target doesn't allow constants
to be compared as integers, we generate code we used to generate.)
For compare predicates, once we know that X and Y have the same index
and X is a constant, do not check the value of Y; it must be the same
as X.
compiler/options.m:
Add an option that says whether constants can be compared as integers.
compiler/handle_options.m:
Set the value of the new option depending on the characteristics of the
target.
cvs diff: Diffing .
Index: handle_options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.193
diff -u -b -r1.193 handle_options.m
--- handle_options.m 1 Dec 2003 15:55:34 -0000 1.193
+++ handle_options.m 10 Jan 2004 16:01:02 -0000
@@ -1304,6 +1304,15 @@
[]
),
+ (
+ { Target = c },
+ { TagsMethod = low }
+ ->
+ globals__io_set_option(can_compare_constants_as_ints, bool(yes))
+ ;
+ globals__io_set_option(can_compare_constants_as_ints, bool(no))
+ ),
+
( { HighLevel = no } ->
postprocess_options_lowlevel
;
Index: options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.419
diff -u -b -r1.419 options.m
--- options.m 23 Oct 2003 02:02:09 -0000 1.419
+++ options.m 12 Jan 2004 04:48:36 -0000
@@ -339,6 +339,14 @@
% the predicates deciding interface typeinfo
% liveness, should go through there.
; body_typeinfo_liveness
+ % Should be set to yes if the target back end
+ % guarantees that comparing two values for
+ % equality, at least one of which is a
+ % constant, can be done by casting them both
+ % to integers and comparing the integers
+ % for equality.
+ ; can_compare_constants_as_ints
+
% Options for internal use only
% (setting these options to non-default values can result in
% programs that do not link, or programs that dump core)
@@ -944,6 +952,7 @@
procid_stack_layout - bool(no),
trace_stack_layout - bool(no),
body_typeinfo_liveness - bool(no),
+ can_compare_constants_as_ints - bool(no),
special_preds - bool(yes),
type_ctor_info - bool(yes),
type_ctor_layout - bool(yes),
@@ -1575,6 +1584,7 @@
long_option("procid-stack-layout", procid_stack_layout).
long_option("trace-stack-layout", trace_stack_layout).
long_option("body-typeinfo-liveness", body_typeinfo_liveness).
+long_option("can-compare-constants-as-ints", can_compare_constants_as_ints).
long_option("special-preds", special_preds).
long_option("type-ctor-info", type_ctor_info).
long_option("type-ctor-layout", type_ctor_layout).
@@ -3313,6 +3323,11 @@
% This is a developer only option.
% "--body-typeinfo-liveness",
+% "(This option is not for general use.)",
+% For documentation, see the comment in the type declaration.
+
+ % This is a developer only option.
+% "--can-compare-constants-as-ints",
% "(This option is not for general use.)",
% For documentation, see the comment in the type declaration.
Index: unify_proc.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unify_proc.m,v
retrieving revision 1.130
diff -u -b -r1.130 unify_proc.m
--- unify_proc.m 21 Dec 2003 05:04:38 -0000 1.130
+++ unify_proc.m 10 Jan 2004 16:54:58 -0000
@@ -1164,29 +1164,39 @@
% For a type such as
%
-% type t(X) ---> a ; b(int) ; c(X); d(int, X, t)
+% type t ---> a1 ; a2 ; b(int) ; c(float); d(int, string, t).
%
-% we want to generate code
+% we want to generate the code
%
-% eq(H1, H2) :-
+% __Unify__(X, Y) :-
% (
-% H1 = a,
-% H2 = a
+% X = a1,
+% Y = X
+% ;
+% X = a2,
+% Y = X
% ;
-% H1 = b(X1),
-% H2 = b(X2),
+% X = b(X1),
+% Y = b(Y2),
+% X1 = Y2,
+% ;
+% X = c(X1),
+% Y = c(Y1),
% X1 = X2,
% ;
-% H1 = c(Y1),
-% H2 = c(Y2),
-% Y1 = Y2,
-% ;
-% H1 = d(A1, B1, C1),
-% H2 = c(A2, B2, C2),
-% A1 = A2,
-% B1 = B2,
-% C1 = C2
+% X = d(X1, X2, X3),
+% Y = c(Y1, Y2, Y3),
+% X1 = y1,
+% X2 = Y2,
+% X3 = Y3
% ).
+%
+% Note that in the disjuncts handling constants, we want to unify Y with X,
+% not with the constant. This allows dupelim to take the code fragments
+% implementing the switch arms for constants and eliminate all but one of them.
+% This can be a significant code size saving for types with lots of constants,
+% such as the one representing Aditi bytecodes, which can lead to significant
+% reductions in C compilation time.
:- pred unify_proc__generate_du_unify_clauses(list(constructor), prog_var,
prog_var, prog_context, list(clause),
@@ -1194,29 +1204,60 @@
:- mode unify_proc__generate_du_unify_clauses(in, in, in, in, out, in, out)
is det.
-unify_proc__generate_du_unify_clauses([], _H1, _H2, _Context, []) --> [].
-unify_proc__generate_du_unify_clauses([Ctor | Ctors], H1, H2, Context,
- [Clause | Clauses]) -->
- { Ctor = ctor(ExistQTVars, _Constraints, FunctorName, ArgTypes) },
- { list__length(ArgTypes, FunctorArity) },
- { FunctorConsId = cons(FunctorName, FunctorArity) },
- unify_proc__make_fresh_vars(ArgTypes, ExistQTVars, Vars1),
- unify_proc__make_fresh_vars(ArgTypes, ExistQTVars, Vars2),
- { create_atomic_unification(
- H1, functor(FunctorConsId, no, Vars1), Context, explicit, [],
- UnifyH1_Goal) },
- { create_atomic_unification(
- H2, functor(FunctorConsId, no, Vars2), Context, explicit, [],
- UnifyH2_Goal) },
- unify_proc__unify_var_lists(ArgTypes, ExistQTVars, Vars1, Vars2,
- UnifyArgs_Goal),
- { GoalList = [UnifyH1_Goal, UnifyH2_Goal | UnifyArgs_Goal] },
- { goal_info_init(GoalInfo0) },
- { goal_info_set_context(GoalInfo0, Context,
- GoalInfo) },
- { conj_list_to_goal(GoalList, GoalInfo, Goal) },
- unify_proc__quantify_clause_body([H1, H2], Goal, Context, Clause),
- unify_proc__generate_du_unify_clauses(Ctors, H1, H2, Context, Clauses).
+unify_proc__generate_du_unify_clauses([], _X, _Y, _Context, [], !Info).
+unify_proc__generate_du_unify_clauses([Ctor | Ctors], X, Y, Context,
+ [Clause | Clauses], !Info) :-
+ Ctor = ctor(ExistQTVars, _Constraints, FunctorName, ArgTypes),
+ list__length(ArgTypes, FunctorArity),
+ FunctorConsId = cons(FunctorName, FunctorArity),
+ (
+ ArgTypes = [],
+ can_compare_constants_as_ints(!.Info) = yes
+ ->
+ create_atomic_unification(
+ X, functor(FunctorConsId, no, []), Context,
+ explicit, [], UnifyX_Goal),
+ unify_proc__info_new_named_var(int_type, "CastX", CastX,
+ !Info),
+ unify_proc__info_new_named_var(int_type, "CastY", CastY,
+ !Info),
+ generate_unsafe_cast(X, CastX, Context, CastXGoal),
+ generate_unsafe_cast(Y, CastY, Context, CastYGoal),
+ create_atomic_unification(CastY, var(CastX), Context,
+ explicit, [], UnifyY_Goal),
+ GoalList = [UnifyX_Goal, CastXGoal, CastYGoal, UnifyY_Goal]
+ ;
+ unify_proc__make_fresh_vars(ArgTypes, ExistQTVars, Vars1,
+ !Info),
+ unify_proc__make_fresh_vars(ArgTypes, ExistQTVars, Vars2,
+ !Info),
+ create_atomic_unification(
+ X, functor(FunctorConsId, no, Vars1), Context,
+ explicit, [], UnifyX_Goal),
+ create_atomic_unification(
+ Y, functor(FunctorConsId, no, Vars2), Context,
+ explicit, [], UnifyY_Goal),
+ unify_proc__unify_var_lists(ArgTypes, ExistQTVars,
+ Vars1, Vars2, UnifyArgs_Goals, !Info),
+ GoalList = [UnifyX_Goal, UnifyY_Goal | UnifyArgs_Goals]
+ ),
+ goal_info_init(GoalInfo0),
+ goal_info_set_context(GoalInfo0, Context, GoalInfo),
+ conj_list_to_goal(GoalList, GoalInfo, Goal),
+ unify_proc__quantify_clause_body([X, Y], Goal, Context, Clause, !Info),
+ unify_proc__generate_du_unify_clauses(Ctors, X, Y, Context, Clauses,
+ !Info).
+
+ % Succeed iff the target back end guarantees that comparing two
+ % constants for equality can be done by casting them both to integers
+ % and comparing the integers for equality.
+:- func can_compare_constants_as_ints(unify_proc_info) = bool.
+
+can_compare_constants_as_ints(Info) = CanCompareAsInt :-
+ ModuleInfo = Info ^ module_info,
+ module_info_globals(ModuleInfo, Globals),
+ lookup_bool_option(Globals, can_compare_constants_as_ints,
+ CanCompareAsInt).
%-----------------------------------------------------------------------------%
@@ -1224,7 +1265,7 @@
%
% :- type foo ---> f ; g(a, b, c) ; h(foo).
%
-% we want to generate code
+% we want to generate the code
%
% index(X, Index) :-
% (
@@ -1298,7 +1339,7 @@
% For a du type, such as
%
-% :- type foo ---> f(a) ; g(a, b, c)
+% :- type foo ---> f(a) ; g(a, b, c) ; h.
%
% the quadratic code we want to generate is
%
@@ -1312,6 +1353,10 @@
% Y = g(_, _, _),
% R = (<)
% ;
+% X = f(_),
+% Y = h,
+% R = (<)
+% ;
% X = g(_, _, _),
% Y = f(_),
% R = (>)
@@ -1325,7 +1370,28 @@
% ;
% compare(R, X3, Y3)
% )
+% ;
+% X = g(_, _, _),
+% Y = h,
+% R = (<)
+% ;
+% X = f(_),
+% Y = h,
+% R = (<)
+% ;
+% X = g(_, _, _),
+% Y = h,
+% R = (<)
+% ;
+% X = h,
+% Y = h,
+% R = (<)
% ).
+%
+% Note that in the clauses handling two copies of the same constant,
+% we unify Y with the constant, not with X. This is required to get
+% switch_detection and det_analysis to recognize the determinism of the
+% predicate.
:- pred unify_proc__generate_du_quad_compare_clauses(list(constructor)::in,
prog_var::in, prog_var::in, prog_var::in, prog_context::in,
@@ -1369,7 +1435,7 @@
Cases0, Cases) -->
( { LeftCtor = RightCtor } ->
unify_proc__generate_compare_case(LeftCtor, R, X, Y, Context,
- Case),
+ quad, Case),
{ Cmp1 = "<" }
;
unify_proc__generate_asymmetric_compare_case(LeftCtor,
@@ -1398,13 +1464,15 @@
% % This disjunction is generated by
% % unify_proc__generate_compare_cases, below.
% (
-% X = f, Y = f,
+% X = f
% R = (=)
% ;
-% X = g(X1), Y = g(Y1),
+% X = g(X1),
+% Y = g(Y1),
% compare(R, X1, Y1)
% ;
-% X = h(X1, X2), Y = h(Y1, Y2),
+% X = h(X1, X2),
+% Y = h(Y1, Y2),
% ( compare(R1, X1, Y1), R1 \= (=) ->
% R = R1
% ;
@@ -1416,6 +1484,9 @@
% ;
% compare_error % Abort
% ).
+%
+% Note that disjuncts covering constants do not test Y, since for constants
+% X_Index = Y_Index implies X = Y.
:- pred unify_proc__generate_du_linear_compare_clauses((type)::in,
list(constructor)::in, prog_var::in, prog_var::in, prog_var::in,
@@ -1495,7 +1566,7 @@
%
% (
% X = f, % UnifyX_Goal
-% Y = f, % UnifyY_Goal
+% Y = X, % UnifyY_Goal
% R = (=) % CompareArgs_Goal
% ;
% X = g(X1),
@@ -1510,6 +1581,10 @@
% compare(R, X2, Y2)
% )
% )
+%
+% Note that in the clauses for constants, we unify Y with X, not with
+% the constant. This is to allow dupelim to eliminate all but one of
+% the code fragments implementing such switch arms.
:- pred unify_proc__generate_compare_cases(list(constructor), prog_var,
prog_var, prog_var, prog_context, list(hlds_goal),
@@ -1520,30 +1595,55 @@
unify_proc__generate_compare_cases([], _R, _X, _Y, _Context, []) --> [].
unify_proc__generate_compare_cases([Ctor | Ctors], R, X, Y, Context,
[Case | Cases]) -->
- unify_proc__generate_compare_case(Ctor, R, X, Y, Context, Case),
+ unify_proc__generate_compare_case(Ctor, R, X, Y, Context, linear,
+ Case),
unify_proc__generate_compare_cases(Ctors, R, X, Y, Context, Cases).
-:- pred unify_proc__generate_compare_case(constructor, prog_var, prog_var,
- prog_var, prog_context, hlds_goal,
- unify_proc_info, unify_proc_info).
-:- mode unify_proc__generate_compare_case(in, in, in, in, in, out, in, out)
- is det.
+:- type linear_or_quad ---> linear ; quad.
+
+:- pred unify_proc__generate_compare_case(constructor::in,
+ prog_var::in, prog_var::in, prog_var::in, prog_context::in,
+ linear_or_quad::in, hlds_goal::out,
+ unify_proc_info::in, unify_proc_info::out) is det.
-unify_proc__generate_compare_case(Ctor, R, X, Y, Context, Case) -->
+unify_proc__generate_compare_case(Ctor, R, X, Y, Context, Kind, Case) -->
{ Ctor = ctor(ExistQTVars, _Constraints, FunctorName, ArgTypes) },
{ list__length(ArgTypes, FunctorArity) },
{ FunctorConsId = cons(FunctorName, FunctorArity) },
+ (
+ { ArgTypes = [] },
+ { create_atomic_unification(
+ X, functor(FunctorConsId, no, []), Context,
+ explicit, [], UnifyX_Goal) },
+ { unify_proc__generate_return_equal(R, Context, EqualGoal) },
+ (
+ { Kind = linear },
+ % The disjunct we are generating is executed only if
+ % the index values of X and Y are the same, so if X is
+ % bound to a constant, Y must also be bound to that
+ % same constant.
+ { GoalList = [UnifyX_Goal, EqualGoal] }
+ ;
+ { Kind = quad },
+ { create_atomic_unification(
+ Y, functor(FunctorConsId, no, []), Context,
+ explicit, [], UnifyY_Goal) },
+ { GoalList = [UnifyX_Goal, UnifyY_Goal, EqualGoal] }
+ )
+ ;
+ { ArgTypes = [_ | _] },
unify_proc__make_fresh_vars(ArgTypes, ExistQTVars, Vars1),
unify_proc__make_fresh_vars(ArgTypes, ExistQTVars, Vars2),
{ create_atomic_unification(
- X, functor(FunctorConsId, no, Vars1), Context, explicit, [],
- UnifyX_Goal) },
+ X, functor(FunctorConsId, no, Vars1), Context,
+ explicit, [], UnifyX_Goal) },
{ create_atomic_unification(
- Y, functor(FunctorConsId, no, Vars2), Context, explicit, [],
- UnifyY_Goal) },
+ Y, functor(FunctorConsId, no, Vars2), Context,
+ explicit, [], UnifyY_Goal) },
unify_proc__compare_args(ArgTypes, ExistQTVars, Vars1, Vars2,
R, Context, CompareArgs_Goal),
- { GoalList = [UnifyX_Goal, UnifyY_Goal, CompareArgs_Goal] },
+ { GoalList = [UnifyX_Goal, UnifyY_Goal, CompareArgs_Goal] }
+ ),
{ goal_info_init(GoalInfo0) },
{ goal_info_set_context(GoalInfo0, Context, GoalInfo) },
{ conj_list_to_goal(GoalList, GoalInfo, Case) }.
@@ -1624,10 +1724,7 @@
is semidet.
unify_proc__compare_args_2([], _, [], [], R, Context, Return_Equal) -->
- { create_atomic_unification(
- R, functor(cons(unqualified("="), 0), no, []),
- Context, explicit, [],
- Return_Equal) }.
+ { unify_proc__generate_return_equal(R, Context, Return_Equal) }.
unify_proc__compare_args_2([_Name - Type|ArgTypes], ExistQTVars, [X|Xs], [Y|Ys],
R, Context, Goal) -->
{ goal_info_init(GoalInfo0) },
@@ -1670,6 +1767,14 @@
unify_proc__compare_args_2(ArgTypes, ExistQTVars, Xs, Ys, R,
Context, ElseCase)
).
+
+:- pred unify_proc__generate_return_equal(prog_var::in, prog_context::in,
+ hlds_goal::out) is det.
+
+unify_proc__generate_return_equal(ResultVar, Context, Return_Equal) :-
+ create_atomic_unification(
+ ResultVar, functor(cons(unqualified("="), 0), no, []),
+ Context, explicit, [], Return_Equal).
%-----------------------------------------------------------------------------%
cvs diff: Diffing notes
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list