[m-rev.] dynamic_cast optimizations
Fergus Henderson
fjh at cs.mu.OZ.AU
Fri Feb 13 13:17:26 AEDT 2004
Estimated hours taken: 4
Branches: main
Do constant propagation for calls to private_builtin.typed_unify and
std_util.dynamic_cast, i.e. evaluate them at compile time if the types
are known, and optimize the implementation of dynamic_cast.
Also clean up the code in const_prop.m.
library/std_util.m:
Implement dynamic_cast more efficiently, using typed_unify(X, Y)
rather than univ_to_type(univ(X), Y). This avoids allocating a
cell on the heap.
compiler/const_prop.m:
Keep track of the types of the arguments.
Add new code for evaluating semidet calls with one output,
and use this to evaluate calls to dynamic_cast and typed_unify.
Rename evaluate_builtin to evaluate_call, since it may evaluate
any standard library procedure, not just those which are builtin
(in the sense of pred_info_is_builtin). Likewise for its subroutines.
Various other clean-ups, e.g. combine evaluate_builtin_bi and
evaluate_builtin_tri into a single predicate evaluate_det_call,
delete unused arguments, reorder arguments so that inputs precede
outputs, use combined pred-mode declarations, and add some comments.
compiler/simplify.m:
Update to reflect the new interface to const_prop.m.
tests/hard_coded/constant_prop_2.m:
tests/hard_coded/constant_prop_2.exp:
Test that we do constant propagation for calls to typed_unify
and dynamic_cast.
Workspace: /home/jupiter/fjh/ws-jupiter/mercury
Index: compiler/const_prop.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/const_prop.m,v
retrieving revision 1.21
diff -u -d -r1.21 const_prop.m
--- compiler/const_prop.m 12 Jan 2004 05:56:21 -0000 1.21
+++ compiler/const_prop.m 13 Feb 2004 01:45:37 -0000
@@ -7,10 +7,14 @@
% file: const_prop.m
% main author: conway.
%
-% This module provides the facility to evaluate calls at compile time -
-% transforming them to simpler goals such as construction unifications.
+% This module provides the facility to evaluate calls to standard library
+% routines at compile time, transforming them to simpler goals such as
+% construction unifications.
%
-% XXX We should check for overflow.
+% XXX We should check for overflow. This is particularly important when
+% cross-compiling, since the overflow behaviour of the host machine might
+% not be the same as that of the target machine, e.g. if they have different
+% word sizes.
%
%------------------------------------------------------------------------------%
@@ -22,10 +26,18 @@
:- import_module parse_tree__prog_data, hlds__instmap.
:- import_module list.
-:- pred evaluate_builtin(pred_id, proc_id, list(prog_var), hlds_goal_info,
- hlds_goal_expr, hlds_goal_info, instmap,
- module_info, module_info).
-:- mode evaluate_builtin(in, in, in, in, out, out, in, in, out) is semidet.
+ % evaluate_call(PredId, ProcId, Args, GoalInfo0,
+ % GoalExpr, GoalInfo, VarTypes, Instmap, !ModuleInfo):
+ %
+ % This attempts to evaluate a call to the specified procedure
+ % with the specified arguments. If the call can be statically
+ % evaluated, evaluate_builtin will succeed, returning the new
+ % goal in GoalExpr (and the new GoalInfo).
+ % Otherwise it fails.
+
+:- pred evaluate_call(pred_id::in, proc_id::in, list(prog_var)::in,
+ hlds_goal_info::in, vartypes::in, instmap::in, module_info::in,
+ hlds_goal_expr::out, hlds_goal_info::out) is semidet.
%------------------------------------------------------------------------------%
@@ -56,290 +68,313 @@
%------------------------------------------------------------------------------%
-evaluate_builtin(PredId, ProcId, Args, GoalInfo0, Goal, GoalInfo,
- InstMap, ModuleInfo0, ModuleInfo) :-
- predicate_module(ModuleInfo0, PredId, ModuleName),
- predicate_name(ModuleInfo0, PredId, PredName),
+ % This type groups the information from the HLDS
+ % about a procedure call argument.
+:- type arg_hlds_info
+ ---> arg_hlds_info(
+ arg_var :: prog_var,
+ arg_type :: prog_data__type,
+ arg_inst :: (inst)
+ ).
+
+evaluate_call(PredId, ProcId, Args, GoalInfo0, VarTypes, InstMap, ModuleInfo,
+ Goal, GoalInfo) :-
+ predicate_module(ModuleInfo, PredId, ModuleName),
+ predicate_name(ModuleInfo, PredId, PredName),
proc_id_to_int(ProcId, ProcInt),
- LookupVarInsts = (pred(V::in, J::out) is det :-
- instmap__lookup_var(InstMap, V, VInst),
- J = V - VInst
+ LookupArgs = (func(Var) = arg_hlds_info(Var, Type, Inst) :-
+ instmap__lookup_var(InstMap, Var, Inst),
+ Type = VarTypes ^ det_elem(Var)
),
- list__map(LookupVarInsts, Args, ArgInsts),
- evaluate_builtin_2(ModuleName, PredName, ProcInt, ArgInsts, GoalInfo0,
- Goal, GoalInfo, ModuleInfo0, ModuleInfo).
+ ArgHldsInfos = list__map(LookupArgs, Args),
+ evaluate_call_2(ModuleName, PredName, ProcInt, ArgHldsInfos,
+ GoalInfo0, Goal, GoalInfo).
-:- pred evaluate_builtin_2(module_name, string, int,
- list(pair(prog_var, (inst))), hlds_goal_info, hlds_goal_expr,
- hlds_goal_info, module_info, module_info).
-:- mode evaluate_builtin_2(in, in, in, in, in, out, out, in, out) is semidet.
+:- pred evaluate_call_2(module_name::in, string::in, int::in,
+ list(arg_hlds_info)::in, hlds_goal_info::in,
+ hlds_goal_expr::out, hlds_goal_info::out) is semidet.
% Module_info is not actually used at the moment.
-evaluate_builtin_2(Module, Pred, ModeNum, Args, GoalInfo0, Goal, GoalInfo,
- ModuleInfo, ModuleInfo) :-
+evaluate_call_2(Module, Pred, ModeNum, Args, GoalInfo0, Goal, GoalInfo) :-
% -- not yet:
% Module = qualified(unqualified("std"), Mod),
Module = unqualified(Mod),
(
- Args = [X, Y],
- evaluate_builtin_bi(Mod, Pred, ModeNum, X, Y, W, Cons)
+ evaluate_det_call(Mod, Pred, ModeNum, Args, OutputArg, Cons)
->
- make_construction(W, Cons, Goal),
- goal_info_get_instmap_delta(GoalInfo0, Delta0),
- W = Var - _WInst,
- instmap_delta_set(Delta0, Var,
- bound(unique, [functor(Cons, [])]), Delta),
- goal_info_set_instmap_delta(GoalInfo0, Delta, GoalInfo)
+ make_construction_goal(OutputArg, Cons, GoalInfo0,
+ Goal, GoalInfo)
;
- Args = [X, Y, Z],
- evaluate_builtin_tri(Mod, Pred, ModeNum, X, Y, Z, W, Cons)
+ evaluate_test(Mod, Pred, ModeNum, Args, Succeeded)
->
- make_construction(W, Cons, Goal),
- goal_info_get_instmap_delta(GoalInfo0, Delta0),
- W = Var - _WInst,
- instmap_delta_set(Delta0, Var,
- bound(unique, [functor(Cons, [])]), Delta),
- goal_info_set_instmap_delta(GoalInfo0, Delta, GoalInfo)
+ make_true_or_fail(Succeeded, GoalInfo0, Goal, GoalInfo)
;
- evaluate_builtin_test(Mod, Pred, ModeNum, Args, Result)
+ evaluate_semidet_call(Mod, Pred, ModeNum, Args, Result)
->
- make_true_or_fail(Result, GoalInfo0, Goal, GoalInfo)
+ (
+ Result = yes(OutputArg - const(Cons)),
+ make_construction_goal(OutputArg, Cons, GoalInfo0,
+ Goal, GoalInfo)
+ ;
+ Result = yes(OutputArg - var(InputArg)),
+ make_assignment_goal(OutputArg, InputArg, GoalInfo0,
+ Goal, GoalInfo)
+ ;
+ Result = no,
+ make_true_or_fail(no, GoalInfo0, Goal, GoalInfo)
+ )
;
fail
).
%------------------------------------------------------------------------------%
-:- pred evaluate_builtin_bi(string, string, int,
- pair(prog_var, (inst)), pair(prog_var, (inst)),
- pair(prog_var, (inst)), cons_id).
-:- mode evaluate_builtin_bi(in, in, in, in, in, out, out) is semidet.
+ % evaluate_det_call(ModuleName, ProcName, ModeNum,
+ % Args, OutputArg, OutputArgVal):
+ %
+ % This attempts to evaluate a call to
+ % ModuleName.ProcName(Args)
+ % whose mode is specified by ModeNum.
+ % If the call is a det call with one output that can be
+ % statically evaluated, evaluate_det_call succeeds with
+ % OutputArg being whichever of Args is output,
+ % and with OutputArgVal being the computed value of OutputArg.
+ % Otherwise it fails.
+
+:- pred evaluate_det_call(string::in, string::in, int::in,
+ list(arg_hlds_info)::in, arg_hlds_info::out, cons_id::out)
+ is semidet.
+
+%
+% Unary operators
+%
% Integer arithmetic
-evaluate_builtin_bi("int", "+", 0, X, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- ZVal = XVal.
+evaluate_det_call("int", "+", 0, [X, Y], Y, int_const(YVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ YVal = XVal.
-evaluate_builtin_bi("int", "-", 0, X, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- ZVal = -XVal.
+evaluate_det_call("int", "-", 0, [X, Y], Y, int_const(YVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ YVal = -XVal.
-evaluate_builtin_bi("int", "\\", 0, X, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- ZVal = \ XVal.
+evaluate_det_call("int", "\\", 0, [X, Y], Y, int_const(YVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ YVal = \ XVal.
% Floating point arithmetic
-evaluate_builtin_bi("float", "+", 0, X, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- ZVal = XVal.
-
-evaluate_builtin_bi("float", "-", 0, X, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- ZVal = -XVal.
+evaluate_det_call("float", "+", 0, [X, Y], Y, int_const(YVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ YVal = XVal.
-%------------------------------------------------------------------------------%
+evaluate_det_call("float", "-", 0, [X, Y], Y, int_const(YVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ YVal = -XVal.
-:- pred evaluate_builtin_tri(string, string, int,
- pair(prog_var, (inst)), pair(prog_var, (inst)),
- pair(prog_var, (inst)), pair(prog_var, (inst)), cons_id).
-:- mode evaluate_builtin_tri(in, in, in, in, in, in, out, out) is semidet.
+%
+% Binary operators
+%
- %
% Integer arithmetic
- %
-evaluate_builtin_tri("int", "+", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+
+evaluate_det_call("int", "+", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal + YVal.
-evaluate_builtin_tri("int", "+", 1, X, Y, Z, X, int_const(XVal)) :-
- Z = _ZVar - bound(_ZUniq, [functor(int_const(ZVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "+", 1, [X, Y, Z], X, int_const(XVal)) :-
+ Z ^ arg_inst = bound(_ZUniq, [functor(int_const(ZVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
XVal = ZVal - YVal.
-evaluate_builtin_tri("int", "+", 2, X, Y, Z, Y, int_const(YVal)) :-
- Z = _ZVar - bound(_ZUniq, [functor(int_const(ZVal), [])]),
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
+evaluate_det_call("int", "+", 2, [X, Y, Z], Y, int_const(YVal)) :-
+ Z ^ arg_inst = bound(_ZUniq, [functor(int_const(ZVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
YVal = ZVal - XVal.
-evaluate_builtin_tri("int", "-", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "-", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal - YVal.
-evaluate_builtin_tri("int", "-", 1, X, Y, Z, X, int_const(XVal)) :-
- Z = _ZVar - bound(_ZUniq, [functor(int_const(ZVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "-", 1, [X, Y, Z], X, int_const(XVal)) :-
+ Z ^ arg_inst = bound(_ZUniq, [functor(int_const(ZVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
XVal = YVal + ZVal.
-evaluate_builtin_tri("int", "-", 2, X, Y, Z, Y, int_const(YVal)) :-
- Z = _ZVar - bound(_ZUniq, [functor(int_const(ZVal), [])]),
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
+evaluate_det_call("int", "-", 2, [X, Y, Z], Y, int_const(YVal)) :-
+ Z ^ arg_inst = bound(_ZUniq, [functor(int_const(ZVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
YVal = XVal - ZVal.
-evaluate_builtin_tri("int", "*", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "*", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal * YVal.
- % This isn't actually a builtin.
-evaluate_builtin_tri("int", "//", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "//", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
YVal \= 0,
ZVal = XVal // YVal.
-evaluate_builtin_tri("int", "unchecked_quotient", 0, X, Y, Z, Z,
+evaluate_det_call("int", "unchecked_quotient", 0, [X, Y, Z], Z,
int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
YVal \= 0,
ZVal = unchecked_quotient(XVal, YVal).
- % This isn't actually a builtin.
-evaluate_builtin_tri("int", "mod", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "mod", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
YVal \= 0,
ZVal = XVal mod YVal.
- % This isn't actually a builtin.
-evaluate_builtin_tri("int", "rem", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "rem", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
YVal \= 0,
ZVal = XVal rem YVal.
-evaluate_builtin_tri("int", "unchecked_rem", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "unchecked_rem", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
YVal \= 0,
ZVal = unchecked_rem(XVal, YVal).
-evaluate_builtin_tri("int", "unchecked_left_shift",
- 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "unchecked_left_shift",
+ 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = unchecked_left_shift(XVal, YVal).
- % This isn't actually a builtin.
-evaluate_builtin_tri("int", "<<", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "<<", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal << YVal.
-evaluate_builtin_tri("int", "unchecked_right_shift",
- 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "unchecked_right_shift",
+ 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = unchecked_right_shift(XVal, YVal).
- % This isn't actually a builtin.
-evaluate_builtin_tri("int", ">>", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", ">>", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal >> YVal.
-evaluate_builtin_tri("int", "/\\", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "/\\", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal /\ YVal.
-evaluate_builtin_tri("int", "\\/", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "\\/", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal \/ YVal.
-evaluate_builtin_tri("int", "xor", 0, X, Y, Z, Z, int_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+evaluate_det_call("int", "xor", 0, [X, Y, Z], Z, int_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
ZVal = XVal `xor` YVal.
- %
% float arithmetic
- %
-evaluate_builtin_tri("float", "+", 0, X, Y, Z, Z, float_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+evaluate_det_call("float", "+", 0, [X, Y, Z], Z, float_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
ZVal = XVal + YVal.
-evaluate_builtin_tri("float", "-", 0, X, Y, Z, Z, float_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+evaluate_det_call("float", "-", 0, [X, Y, Z], Z, float_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
ZVal = XVal - YVal.
-evaluate_builtin_tri("float", "*", 0, X, Y, Z, Z, float_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+evaluate_det_call("float", "*", 0, [X, Y, Z], Z, float_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
ZVal = XVal * YVal.
- % This isn't actually a builtin.
-evaluate_builtin_tri("float", "/", 0, X, Y, Z, Z, float_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+evaluate_det_call("float", "/", 0, [X, Y, Z], Z, float_const(ZVal)) :-
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
YVal \= 0.0,
ZVal = XVal / YVal.
-evaluate_builtin_tri("float", "unchecked_quotient", 0, X, Y, Z, Z,
+evaluate_det_call("float", "unchecked_quotient", 0, [X, Y, Z], Z,
float_const(ZVal)) :-
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
YVal \= 0.0,
ZVal = unchecked_quotient(XVal, YVal).
- % This isn't actually a builtin.
-evaluate_builtin_tri("string", Name, _, X, Y, Z, Z, string_const(ZVal)) :-
+ % string operations
+
+evaluate_det_call("string", Name, _, [X, Y, Z], Z, string_const(ZVal)) :-
( Name = "++"
; Name = "append"
),
- X = _XVar - bound(_XUniq, [functor(string_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(string_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(string_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(string_const(YVal), [])]),
% We can only do the append if Z is free (this allows
% us to ignore the mode number and pick up both the
% predicate and function versions of append)
- Z = _ZVar - free,
+ Z ^ arg_inst = free,
ZVal = XVal ++ YVal.
%------------------------------------------------------------------------------%
-:- pred evaluate_builtin_test(string, string, int,
- list(pair(prog_var, inst)), bool).
-:- mode evaluate_builtin_test(in, in, in, in, out) is semidet.
+ % evaluate_test(ModuleName, ProcName, ModeNum, ArgList, Result):
+ %
+ % This attempts to evaluate a call to
+ % ModuleName.ProcName(ArgList)
+ % whose mode is specified by ModeNum.
+ %
+ % If the call is a semidet call with no outputs that can be
+ % statically evaluated, evaluate_test succeeds with
+ % Result being "yes" if the call will succeed and "no" if the
+ % call will fail.
+ % Otherwise (i.e. if the call is not semidet, has any outputs,
+ % or cannot be statically evaluated), evaluate_test fails.
+
+:- pred evaluate_test(string::in, string::in, int::in,
+ list(arg_hlds_info)::in, bool::out) is semidet.
% Integer comparisons
-evaluate_builtin_test("int", "<", 0, Args, Result) :-
+evaluate_test("int", "<", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
( XVal < YVal ->
Result = yes
;
Result = no
).
-evaluate_builtin_test("int", "=<", 0, Args, Result) :-
+evaluate_test("int", "=<", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
( XVal =< YVal ->
Result = yes
;
Result = no
).
-evaluate_builtin_test("int", ">", 0, Args, Result) :-
+evaluate_test("int", ">", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
( XVal > YVal ->
Result = yes
;
Result = no
).
-evaluate_builtin_test("int", ">=", 0, Args, Result) :-
+evaluate_test("int", ">=", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(int_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(int_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(int_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(int_const(YVal), [])]),
( XVal >= YVal ->
Result = yes
;
@@ -348,52 +383,186 @@
% Float comparisons
-evaluate_builtin_test("float", "<", 0, Args, Result) :-
+evaluate_test("float", "<", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
( XVal < YVal ->
Result = yes
;
Result = no
).
-evaluate_builtin_test("float", "=<", 0, Args, Result) :-
+evaluate_test("float", "=<", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
( XVal =< YVal ->
Result = yes
;
Result = no
).
-evaluate_builtin_test("float", ">", 0, Args, Result) :-
+evaluate_test("float", ">", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
( XVal > YVal ->
Result = yes
;
Result = no
).
-evaluate_builtin_test("float", ">=", 0, Args, Result) :-
+evaluate_test("float", ">=", 0, Args, Result) :-
Args = [X, Y],
- X = _XVar - bound(_XUniq, [functor(float_const(XVal), [])]),
- Y = _YVar - bound(_YUniq, [functor(float_const(YVal), [])]),
+ X ^ arg_inst = bound(_XUniq, [functor(float_const(XVal), [])]),
+ Y ^ arg_inst = bound(_YUniq, [functor(float_const(YVal), [])]),
( XVal >= YVal ->
Result = yes
;
Result = no
).
+evaluate_test("private_builtin", "typed_unify", Mode, Args, Result) :-
+ % mode 0 is the (in, in) mode
+ % mode 1 is the (in, out) mode
+ % both modes are semidet
+ Mode = 0,
+ Args = [TypeOfX, TypeOfY, X, Y],
+ eval_unify(TypeOfX, TypeOfY, Result0),
+ (
+ Result0 = no,
+ Result = no
+ ;
+ Result0 = yes,
+ eval_unify(X, Y, Result)
+ ).
+
+ % evaluate_semidet_call(ModuleName, ProcName, ModeNum,
+ % Args, Result):
+ %
+ % This attempts to evaluate a call to
+ % ModuleName.ProcName(Args)
+ % whose mode is specified by ModeNum.
+ %
+ % If the call is a semidet call with one output that can be
+ % statically evaluated, evaluate_semidet_call succeeds with
+ % Result being "no" if the call will fail, or
+ % yes(OutputArg - OutputArgValue) if it will succeed, with
+ % OutputArg being whichever of the arguments is output,
+ % and with OutputArgVal being the computed value of OutputArg.
+ %
+ % Otherwise (i.e. if the call is not semidet, or has no outputs
+ % or more than one output, or cannot be statically evaluated),
+ % evaluate_semidet_call fails.
+
+:- type arg_val
+ ---> const(cons_id)
+ ; var(arg_hlds_info).
+
+:- pred evaluate_semidet_call(string::in, string::in, int::in,
+ list(arg_hlds_info)::in,
+ maybe(pair(arg_hlds_info, arg_val))::out) is semidet.
+
+evaluate_semidet_call("std_util", "dynamic_cast", 0, Args, Result) :-
+ evaluate_semidet_call("private_builtin", "typed_unify", 1,
+ Args, Result).
+
+evaluate_semidet_call("private_builtin", "typed_unify", Mode, Args, Result) :-
+ % mode 0 is the (in, in) mode
+ % mode 1 is the (in, out) mode
+ % both modes are semidet
+ Mode = 1,
+ Args = [TypeOfX, TypeOfY, X, Y],
+ eval_unify(TypeOfX, TypeOfY, Result0),
+ (
+ Result0 = no,
+ Result = no
+ ;
+ Result0 = yes,
+ Result = yes(Y - var(X))
+ ).
+
+ % evaluate_unify(FirstArg, SecondArg, Result):
+ %
+ % This attempts to evaluate a call to
+ % builtin.unify(FirstArg, SecondArg)
+ % with mode (in, in).
+ % If the unification can be statically evaluated,
+ % evaluate_builtin_test succeeds with Result being "yes"
+ % if the unification will succeed and "no" if the
+ % unification will fail. Otherwise (i.e. if the unification
+ % cannot be statically evaluated), evaluate_unify fails.
+
+:- pred eval_unify(arg_hlds_info::in, arg_hlds_info::in, bool::out) is semidet.
+eval_unify(X, Y, Result) :-
+ (
+ X ^ arg_var = Y ^ arg_var
+ ->
+ Result = yes
+ ;
+ X ^ arg_inst = bound(_, [functor(XCtor, XArgVars)]),
+ Y ^ arg_inst = bound(_, [functor(YCtor, YArgVars)])
+ ->
+ % XXX is it safe to use unification here to test for
+ % functors being equal?
+ ( XCtor = YCtor, XArgVars = YArgVars ->
+ Result = yes
+ ;
+ ( XCtor \= YCtor
+ ; length(XArgVars) \= length(YArgVars) `with_type` int
+ )
+ ->
+ Result = no
+ ;
+ fail
+ )
+ ;
+ fail
+ ).
%------------------------------------------------------------------------------%
+:- pred make_assignment_goal(arg_hlds_info::in, arg_hlds_info::in,
+ hlds_goal_info::in, hlds_goal_expr::out, hlds_goal_info::out)
+ is det.
+make_assignment_goal(OutputArg, InputArg, GoalInfo0, Goal, GoalInfo) :-
+ make_assignment(OutputArg, InputArg, Goal),
+ goal_info_get_instmap_delta(GoalInfo0, Delta0),
+ instmap_delta_set(Delta0, OutputArg ^ arg_var, InputArg ^ arg_inst,
+ Delta),
+ goal_info_set_instmap_delta(GoalInfo0, Delta, GoalInfo1),
+ goal_info_set_determinism(GoalInfo1, det, GoalInfo).
+
+
+:- pred make_construction_goal(arg_hlds_info::in, cons_id::in,
+ hlds_goal_info::in, hlds_goal_expr::out, hlds_goal_info::out)
+ is det.
+make_construction_goal(OutputArg, Cons, GoalInfo0, Goal, GoalInfo) :-
+ make_construction(OutputArg, Cons, Goal),
+ goal_info_get_instmap_delta(GoalInfo0, Delta0),
+ instmap_delta_set(Delta0, OutputArg ^ arg_var,
+ bound(unique, [functor(Cons, [])]), Delta),
+ goal_info_set_instmap_delta(GoalInfo0, Delta, GoalInfo1),
+ goal_info_set_determinism(GoalInfo1, det, GoalInfo).
+
+:- pred make_assignment(arg_hlds_info::in, arg_hlds_info::in,
+ hlds_goal_expr::out) is det.
+
+make_assignment(OutputArg, InputArg, Goal) :-
+ OutVar = OutputArg ^ arg_var,
+ InVar = InputArg ^ arg_var,
+ Inst = InputArg ^ arg_inst,
+ OutputArgMode = (free -> Inst),
+ InputArgMode = (Inst -> Inst),
+ UniMode = OutputArgMode - InputArgMode,
+ Context = unify_context(explicit, []),
+ Goal = unify(OutVar, var(InVar), UniMode, assign(OutVar, InVar),
+ Context).
+
% recompute_instmap_delta is run by simplify.m if anything changes,
% so the insts are not important here.
-:- pred make_construction(pair(prog_var, inst), cons_id, hlds_goal_expr).
+:- pred make_construction(arg_hlds_info, cons_id, hlds_goal_expr).
:- mode make_construction(in, in, out) is det.
-make_construction(Var - _, ConsId, Goal) :-
- make_const_construction(Var, ConsId, Goal - _).
+make_construction(Arg, ConsId, Goal) :-
+ make_const_construction(Arg ^ arg_var, ConsId, Goal - _).
%------------------------------------------------------------------------------%
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.127
diff -u -d -r1.127 simplify.m
--- compiler/simplify.m 21 Dec 2003 05:04:37 -0000 1.127
+++ compiler/simplify.m 12 Feb 2004 23:16:45 -0000
@@ -1348,15 +1348,17 @@
( simplify_do_const_prop(Info3) ->
simplify_info_get_instmap(Info3, Instmap0),
simplify_info_get_module_info(Info3, ModuleInfo2),
+ simplify_info_get_var_types(Info3, VarTypes),
(
Goal1 = call(_, _, _, _, _, _),
- evaluate_builtin(PredId, ProcId, Args, GoalInfo0,
- Goal2, GoalInfo2, Instmap0,
- ModuleInfo2, ModuleInfo3)
+ const_prop.evaluate_call(PredId, ProcId, Args,
+ GoalInfo0, VarTypes, Instmap0, ModuleInfo2,
+ Goal2, GoalInfo2)
->
Goal = Goal2,
GoalInfo = GoalInfo2,
- simplify_info_set_module_info(Info3, ModuleInfo3, Info4),
+ simplify_info_set_module_info(Info3, ModuleInfo2,
+ Info4),
simplify_info_set_requantify(Info4, Info)
;
Goal = Goal1,
Index: library/std_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/std_util.m,v
retrieving revision 1.290
diff -u -d -r1.290 std_util.m
--- library/std_util.m 20 Jan 2004 23:05:43 -0000 1.290
+++ library/std_util.m 13 Feb 2004 00:35:19 -0000
@@ -1607,7 +1607,7 @@
univ_value(Univ) = X.
dynamic_cast(X, Y) :-
- univ_to_type(univ(X), Y).
+ private_builtin__typed_unify(X, Y).
%-----------------------------------------------------------------------------%
Index: tests/hard_coded/constant_prop_2.exp
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/constant_prop_2.exp,v
retrieving revision 1.1
diff -u -d -r1.1 constant_prop_2.exp
--- tests/hard_coded/constant_prop_2.exp 10 Feb 2004 13:13:11 -0000 1.1
+++ tests/hard_coded/constant_prop_2.exp 13 Feb 2004 01:48:20 -0000
@@ -1,3 +1,9 @@
yes
yes
yes
+yes
+no
+43
+no
+45
+no
Index: tests/hard_coded/constant_prop_2.m
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/constant_prop_2.m,v
retrieving revision 1.1
diff -u -d -r1.1 constant_prop_2.m
--- tests/hard_coded/constant_prop_2.m 10 Feb 2004 13:13:11 -0000 1.1
+++ tests/hard_coded/constant_prop_2.m 13 Feb 2004 00:44:39 -0000
@@ -5,7 +5,7 @@
:- pred main(io::di, io::uo) is det.
:- implementation.
-:- import_module string, int, float.
+:- import_module string, int, float, private_builtin, std_util.
main -->
( { "abc" ++ "xyz" = "abcxyz" } ->
@@ -22,6 +22,36 @@
io.write_string("yes"), io.nl
;
link_error
+ ),
+ ( { private_builtin.typed_unify(42, 42) } ->
+ io.write_string("yes"), io.nl
+ ;
+ link_error
+ ),
+ ( { private_builtin.typed_unify(1, 2) } ->
+ link_error
+ ;
+ io.write_string("no"), io.nl
+ ),
+ ( { private_builtin.typed_unify(43, X1) } ->
+ io.write_int(X1), io.nl
+ ;
+ link_error
+ ),
+ ( { private_builtin.typed_unify(44, _ `with_type` string) } ->
+ link_error
+ ;
+ io.write_string("no"), io.nl
+ ),
+ ( { std_util.dynamic_cast(45, X2) } ->
+ io.write_int(X2), io.nl
+ ;
+ link_error
+ ),
+ ( { std_util.dynamic_cast(46, _ `with_type` string) } ->
+ link_error
+ ;
+ io.write_string("no"), io.nl
).
% We should be able to optimize away all calls to this procedure
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
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