Files
mercury/tests/valid/bug50.m
2019-07-26 01:29:53 +02:00

182 lines
7.3 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
%
% This program causes rotd-2008-03-03 to abort in debug grades with the
% following uncaught Mercury exception from find_typeinfos_for_tvars in
% continuation_info.m:
%
% can't find rval for type_info var V_<nn>
%
% when compiling the "crash" predicate.
%
% To reproduce compile with:
%
% $ mmc -C --grade asm_fast.gc.debug
%
% (This test case is derived from g12/zinc/compiler/flatzinc_colgen_solver.m
% in r4693 of G12.)
%
%---------------------------------------------------------------------------%
%
% The compiler crashed when compiling the call to crash_location (pred_id 2)
% in the body of crash (pred_id 0).
%
% The crash came when the compiler is trying to record the type of
% SpSolversRep_9 in the RTTI. It was trying to record this because
% SpSolversRep_9 is a named variable. Even though it is not live after
% the call, the user may wish to inspect its value on the call stack
% when he/she stops the program execution somewhere iside the call tree
% of the call. This is why the delay_death pass of liveness.m prolongs
% the life of SpSolversRep_9 beyond the call.
%
% SpSolversRep_9's type is tree234(int, Solver_1), so the compiler needs
% to know where the type_info for the type represented by type variable
% Solver_1 is.
%
% The rtti varmaps records it as being in slot 1 of the typeclass_info
% variable V_20, which is indeed its location.
%
% The problem was that V_20 is the post-death set of the call, and since
% calls are atomic goals, the variables in the post-death set are deleted
% from the code generator state BEFORE we generate code for the call.
% (This is done to avoid the storing them on the stack across the call.)
%
% There were two reasons why V_20 died in the post-death set of the call,
% and not into the post-death set of the switch.
%
% First, FCBackend is nonlocal to the switch, and thus it dies in the
% post-death set of the switch. However, while V_20 is needed to describe
% the type of the ARGUMENTS of FCBackend, it is not needed to describe
% the type of FCBackend itself, since that type is just flatzinc_colgen_solver.
% Therefore the initial_deadness predicate in liveness.m does NOT believe
% that V_20 is needed outside the switch.
%
% Second, the delay_death pass of liveness.m COULD have delayed the death
% of V_20, moving it from the post-death set of the call to the post-death
% set of the switch, but it didn't, because V_20 did not have a name.
% The reason it didn't have a name was that V_20 was created by cse_detection.m
% when it hoisted desconstructions of FCBackend out of both arms of the switch.
% Even though polymorphism.m gave names to the field variables inside FCBackend
% containing the typeclass info in both arms of the switch, cse_detection put
% an UNNAMED variable into the deconstruction of FCBackend that it hoisted
% out of the switch. (This is why removing the deconstruction of FCBackend
% in the var_ann_ok arm used to eliminate the crash.) This unnamed variable
% (V_20) was later unified with the original named variable (which was
% TypeClassInfo_for_flatzinc_solver_14). The typeclass info needed to describe
% the type of SpSolversRep_9 was thus available in both
%
% - a named variable (TypeClassInfo_for_flatzinc_solver_14) that was local
% to the switch arm, and
% - an unnamed variable (V_20) that was visible outside (before) the switch,
%
% but it was not recorded as being in a NAMED variable that was visible OUTSIDE
% the switch. Without the second condition being fulfilled, the delay_death
% pass COULD not delay the death of V_20, and without the first, it CHOSE
% not to delay it.
%
% Making delay_death delay the death of all variables, even the unnamed ones,
% would be a bad idea, since there are a LOT of them. Making it delay the death
% of unnamed variables only if they contain typeinfos or typeclass_infos
% would have a smaller impact on the size and speed of the generate code,
% but would probably confuse debugger users being presented with those
% unnamed variables.
%
% The better fix is to have cse_detection copy the names (if any) of the
% field variables containing type_infos and typeclass_infos from the original
% deconstruction unification in the first switch arm it processes
% to the new field variables it creates for the hoisted-out deconstruction.
% Since polymorphism always names typeinfo and typeclass info variables,
% with this fix, if delay_death preserves the value of a named variable
% past a call, it will also preserve the values of the typeinfo and typeclass
% info variables needed to make sense of it.
%
%---------------------------------------------------------------------------%
:- module bug50.
:- interface.
:- import_module map.
:- import_module list.
:- type solver_annotation(Var)
---> solver_annotation(string, list(Var)).
:- typeclass flatzinc_solver(Solver, Var) <= (Solver -> Var) where [
pred new_float_var(Solver::in,
solver_annotation(Var)::ia, Var::oa) is det
].
:- type dummy
---> dummy.
:- type flatzinc_colgen_solver
---> some [Solver, Var]
flatzinc_colgen_solver(
fcb_colgen_dw_solver :: dummy,
fcb_sp_solvers :: map(int, Solver)
) => ( flatzinc_solver(Solver, Var) ).
:- type flatzinc_colgen_var
---> colgen_var(int)
; colgen_master_var
; sp_var(int).
:- type var_ann
---> var_ann_ok
; var_ann_buggy.
:- pred crash(flatzinc_colgen_solver::in, var_ann::ia,
flatzinc_colgen_var::oa) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module exception.
:- import_module int.
%---------------------------------------------------------------------------%
:- type sp_solver_instance
---> some [Solver, Var]
sp_solver_instance(
spsi_solver :: Solver,
spsi_var_map :: map(flatzinc_colgen_var, Var)
) => flatzinc_solver(Solver, Var).
%---------------------------------------------------------------------------%
crash(FCBackend, VarAnn, FCVar) :-
(
VarAnn = var_ann_ok,
% Commenting out the assignment to _Dummy makes the compiler abort
% go away.
FCBackend = flatzinc_colgen_solver(_Dummy, _SPSolversRef),
% _Dummy = _Y,
FCVar = colgen_master_var
;
VarAnn = var_ann_buggy,
FCBackend = flatzinc_colgen_solver(_Dummy, SPSolversRef),
VarCreator = new_float_var_wrapper,
crash_location(SPSolversRef, VarCreator, FCVar)
).
%---------------------------------------------------------------------------%
:- pred new_float_var_wrapper(
Solver::in, solver_annotation(Var)::ia, Var::oa) is det
<= flatzinc_solver(Solver, Var).
:- pragma external_pred(new_float_var_wrapper/3).
:- pred crash_location(map(int, Solver)::in,
pred(Solver, solver_annotation(Var), Var)::in(pred(in, ia, oa) is det),
flatzinc_colgen_var::oa) is det <= flatzinc_solver(Solver, Var).
:- pragma external_pred(crash_location/3).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%