[m-rev.] for prelim review: fix generation of type_ctor_info for unboxed types bug
Peter Ross
pro at missioncriticalit.com
Tue Dec 2 09:48:51 AEDT 2003
On Tue, Dec 02, 2003 at 03:38:36AM +1100, Fergus Henderson wrote:
> On 01-Dec-2003, Peter Ross <pro at missioncriticalit.com> wrote:
> > This is for preliminary review. How does this look to you Fergus?
>
I updated some of the comments and added a test case.
===================================================================
Estimated hours taken: 8
Branches: main
The comparison and unification function pointers stored in the
type_ctor_info must be pointers to functions where all the arguments
are boxed. This wasn't occuring on the IL backend for types which
are value types.
compiler/rtti_to_mlds.m:
Call ml_gen_closure_wrapper to construct a version of the
comparison and unification functions where the arguments are
boxed. The wrapper function simply unboxes the arguments and
calls the actual special pred.
compiler/ml_closure_gen.m:
Adapt ml_gen_closure_wrapper so that it can generate a wrapper
function for special preds.
tests/hard_coded/Mmakefile:
tests/hard_coded/equality_pred_which_requires_boxing.exp:
tests/hard_coded/equality_pred_which_requires_boxing.m:
Add a test case for this bug.
Index: mercury/compiler/ml_closure_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_closure_gen.m,v
retrieving revision 1.22
diff -u -r1.22 ml_closure_gen.m
--- mercury/compiler/ml_closure_gen.m 13 Nov 2003 13:04:33 -0000 1.22
+++ mercury/compiler/ml_closure_gen.m 1 Dec 2003 20:41:14 -0000
@@ -50,7 +50,8 @@
%
% The ClosureKind parameter specifies whether the closure is
% an ordinary closure, used for higher-order procedure calls,
- % or a typeclass_info, used for class method calls.
+ % or a typeclass_info, used for class method calls, or a call
+ % to a special pred.
% The NumClosuresArgs parameter specifies how many arguments
% to extract from the closure.
%
@@ -62,7 +63,8 @@
:- type closure_kind
---> higher_order_proc_closure
- ; typeclass_info_closure.
+ ; typeclass_info_closure
+ ; special_pred.
% ml_gen_local_for_output_arg(VarName, Type, ArgNum, Context,
% LocalVarDefn):
@@ -565,6 +567,8 @@
% }
%
% Actually, that is a simplified form.
+ % Also when calling a special pred then the closure argument isn't
+ % required.
% In full generality, it will look more like this:
%
% #if MODEL_SEMI
@@ -769,19 +773,25 @@
% some unbox operations).
{ WrapperArgs1 = list__map(arg_delete_gc_trace_code, WrapperArgs0) },
- % then insert the `closure_arg' parameter
- { ClosureArgType = mlds__generic_type },
- { ClosureArgName = mlds__var_name("closure_arg", no) },
- { ClosureArgDeclType = list__det_head(ml_make_boxed_types(1)) },
- gen_closure_gc_trace_code(ClosureArgName, ClosureArgDeclType,
- ClosureKind, WrapperArgTypes, Purity, PredOrFunc,
- Context, ClosureArgGCTraceCode),
- { ClosureArg = mlds__argument(
- data(var(ClosureArgName)),
- ClosureArgType,
- ClosureArgGCTraceCode) },
- { WrapperParams = mlds__func_params([ClosureArg | WrapperArgs1],
- WrapperRetType) },
+ % then insert the `closure_arg' parameter, if needed.
+ ( { ClosureKind = special_pred } ->
+ { MaybeClosureA = no },
+ { WrapperArgs = WrapperArgs1 }
+ ;
+ { ClosureArgType = mlds__generic_type },
+ { ClosureArgName = mlds__var_name("closure_arg", no) },
+ { ClosureArgDeclType = list__det_head(ml_make_boxed_types(1)) },
+ gen_closure_gc_trace_code(ClosureArgName, ClosureArgDeclType,
+ ClosureKind, WrapperArgTypes, Purity, PredOrFunc,
+ Context, ClosureArgGCTraceCode),
+ { ClosureArg = mlds__argument(
+ data(var(ClosureArgName)),
+ ClosureArgType,
+ ClosureArgGCTraceCode) },
+ { MaybeClosureA = yes({ClosureArgType, ClosureArgName}) },
+ { WrapperArgs = [ClosureArg | WrapperArgs1] }
+ ),
+ { WrapperParams = mlds__func_params(WrapperArgs, WrapperRetType) },
% also compute the lvals for the parameters,
% and local declarations for any by-value output parameters
@@ -790,7 +800,8 @@
WrapperHeadVarDecls, WrapperHeadVarLvals, WrapperCopyOutLvals),
%
- % generate code to declare and initialize the closure pointer.
+ % generate code to declare and initialize the closure pointer,
+ % if needed
% XXX we should use a struct type for the closure, but
% currently we're using a low-level data representation
% in the closure
@@ -802,26 +813,35 @@
% #endif
% closure = closure_arg;
%
- { ClosureName = mlds__var_name("closure", no) },
- { ClosureType = mlds__generic_type },
- % If we were to generate GC tracing code for the closure pointer,
- % it would look like this:
- % { ClosureDeclType = list__det_head(ml_make_boxed_types(1)) },
- % gen_closure_gc_trace_code(ClosureName, ClosureDeclType,
- % ClosureKind, WrapperArgTypes, Purity, PredOrFunc,
- % Context, ClosureGCTraceCode),
- % But we don't need any GC tracing code for the closure pointer,
- % because it won't be live across an allocation, and because
- % (unlike the closure_arg parameter) it isn't referenced from
- % the GC tracing for other variables.
- { ClosureGCTraceCode = no },
{ MLDS_Context = mlds__make_context(Context) },
- { ClosureDecl = ml_gen_mlds_var_decl(var(ClosureName),
- ClosureType, ClosureGCTraceCode, MLDS_Context) },
- ml_gen_var_lval(ClosureName, ClosureType, ClosureLval),
- ml_gen_var_lval(ClosureArgName, ClosureArgType, ClosureArgLval),
- { InitClosure = ml_gen_assign(ClosureLval, lval(ClosureArgLval),
- Context) },
+ ( { MaybeClosureA = yes({ClosureArgType1, ClosureArgName1}) } ->
+ { ClosureName = mlds__var_name("closure", no) },
+ { ClosureType = mlds__generic_type },
+ % If we were to generate GC tracing code for the closure
+ % pointer, it would look like this:
+ % { ClosureDeclType = list__det_head(
+ % ml_make_boxed_types(1)) },
+ % gen_closure_gc_trace_code(ClosureName, ClosureDeclType,
+ % ClosureKind, WrapperArgTypes, Purity,
+ % PredOrFunc, Context, ClosureGCTraceCode),
+ % But we don't need any GC tracing code for the closure pointer,
+ % because it won't be live across an allocation, and because
+ % (unlike the closure_arg parameter) it isn't referenced from
+ % the GC tracing for other variables.
+ { ClosureGCTraceCode = no },
+ { ClosureDecl = ml_gen_mlds_var_decl(var(ClosureName),
+ ClosureType, ClosureGCTraceCode, MLDS_Context) },
+ ml_gen_var_lval(ClosureName, ClosureType, ClosureLval),
+ ml_gen_var_lval(ClosureArgName1, ClosureArgType1,
+ ClosureArgLval),
+ { InitClosure = ml_gen_assign(ClosureLval, lval(ClosureArgLval),
+ Context) },
+ { MaybeClosureB = yes({ClosureDecl, InitClosure}) },
+ { MaybeClosureC = yes(ClosureLval) }
+ ;
+ { MaybeClosureB = no },
+ { MaybeClosureC = no }
+ ),
%
% if the wrapper function is model_non, then
@@ -867,23 +887,33 @@
% `Offset' specifies the offset to add to the argument number to
% get the field number within the closure. (Argument numbers start
% from 1, and field numbers start from 0.)
- {
- ClosureKind = higher_order_proc_closure,
- Offset = ml_closure_arg_offset
+ ( { MaybeClosureC = yes(ClosureLval1) } ->
+ { ClosureKind = higher_order_proc_closure,
+ Offset = ml_closure_arg_offset
+ ; ClosureKind = typeclass_info_closure,
+ Offset = ml_typeclass_info_arg_offset
+ ; ClosureKind = special_pred,
+ unexpected(this_file,
+ "ml_gen_closure_wrapper: special_pred")
+ },
+ ml_gen_closure_field_lvals(ClosureLval1, Offset, 1,
+ NumClosureArgs, ClosureArgLvals)
;
- ClosureKind = typeclass_info_closure,
- Offset = ml_typeclass_info_arg_offset
- },
- ml_gen_closure_field_lvals(ClosureLval, Offset, 1, NumClosureArgs,
- ClosureArgLvals),
+ { ClosureArgLvals = [] }
+ ),
{ CallLvals = list__append(ClosureArgLvals, WrapperHeadVarLvals) },
ml_gen_call(PredId, ProcId, ProcHeadVarNames, CallLvals,
ProcBoxedArgTypes, CodeModel, Context, yes,
Decls0, Statements0),
% insert the stuff to declare and initialize the closure
- { Decls1 = [ClosureDecl | Decls0] },
- { Statements1 = [InitClosure | Statements0] },
+ ( { MaybeClosureB = yes({ClosureDecl1, InitClosure1}) } ->
+ { Decls1 = [ClosureDecl1 | Decls0] },
+ { Statements1 = [InitClosure1 | Statements0] }
+ ;
+ { Decls1 = Decls0 },
+ { Statements1 = Statements0 }
+ ),
%
% For semidet code, add the declaration `MR_bool succeeded;'
@@ -904,9 +934,12 @@
% needed for accurate GC
%
{ module_info_globals(ModuleInfo, Globals) },
- ( { globals__get_gc_method(Globals, accurate) } ->
- ml_gen_closure_wrapper_gc_decls(ClosureKind, ClosureArgName,
- ClosureArgType, PredId, ProcId, Context, GC_Decls)
+ (
+ { MaybeClosureA = yes({ClosureArgType2, ClosureArgName2}) },
+ { globals__get_gc_method(Globals, accurate) }
+ ->
+ ml_gen_closure_wrapper_gc_decls(ClosureKind, ClosureArgName2,
+ ClosureArgType2, PredId, ProcId, Context, GC_Decls)
;
{ GC_Decls = [] }
),
@@ -970,6 +1003,10 @@
;
{ ClosureKind = typeclass_info_closure },
{ ClosureActualType = sample_typeclass_info_type }
+ ;
+ { ClosureKind = special_pred },
+ { unexpected(this_file,
+ "gen_closure_gc_trace_code: special_pred") }
),
ml_gen_maybe_gc_trace_code(ClosureName, ClosureDeclType,
ClosureActualType, Context, ClosureGCTraceCode).
@@ -1177,6 +1214,11 @@
target_code_input(lval(ClosureLayoutPtrLval)),
raw_target_code(");\n", [])
] }
+ ;
+ { ClosureKind = special_pred },
+ { unexpected(this_file,
+ "ml_gen_closure_wrapper_gc_decls: special_pred") }
+
),
{ TypeParamsGCInit = mlds__statement(atomic(inline_target_code(
lang_C, TypeParamsGCInitFragments)), MLDS_Context) },
Index: mercury/compiler/rtti_to_mlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/rtti_to_mlds.m,v
retrieving revision 1.43
diff -u -r1.43 rtti_to_mlds.m
--- mercury/compiler/rtti_to_mlds.m 1 Dec 2003 06:53:29 -0000 1.43
+++ mercury/compiler/rtti_to_mlds.m 1 Dec 2003 20:41:25 -0000
@@ -195,17 +195,32 @@
prog_out__sym_name_to_string(TypeModule, TypeModuleName),
NumPtags = type_ctor_details_num_ptags(TypeCtorDetails),
NumFunctors = type_ctor_details_num_functors(TypeCtorDetails),
- gen_functors_layout_info(ModuleInfo, RttiTypeCtor, TypeCtorDetails,
- FunctorsInfo, LayoutInfo, SubDefns),
FunctorsRttiId = ctor_rtti_id(RttiTypeCtor, type_functors),
LayoutRttiId = ctor_rtti_id(RttiTypeCtor, type_layout),
+
+ some [!Defns] (
+ gen_functors_layout_info(ModuleInfo, RttiTypeCtor,
+ TypeCtorDetails, FunctorsInfo, LayoutInfo, !:Defns),
+
+ %
+ % Note that gen_init_special_pred will by necessity add an extra
+ % level of indirection to calling the special preds. However the
+ % backend compiler should be smart enough to ensure that this is
+ % inlined away.
+ %
+ gen_init_special_pred(ModuleInfo, UnifyUniv, UnifyInit, !Defns),
+ gen_init_special_pred(ModuleInfo, CompareUniv, CompareInit, !Defns),
+
+ SubDefns = !.Defns
+ ),
+
Init = init_struct(mlds__rtti_type(RttiId), [
gen_init_int(TypeArity),
gen_init_int(Version),
gen_init_int(NumPtags),
gen_init_type_ctor_rep(TypeCtorData),
- gen_init_proc_id_from_univ(ModuleInfo, UnifyUniv),
- gen_init_proc_id_from_univ(ModuleInfo, CompareUniv),
+ UnifyInit,
+ CompareInit,
gen_init_string(TypeModuleName),
gen_init_string(TypeName),
% In the C back-end, these two "structs" are actually unions.
@@ -224,6 +239,8 @@
% commented out.
% gen_init_maybe(gen_init_rtti_name(RttiTypeCtor),
% MaybeHashCons),
+ % XXX this may need to change to call
+ % gen_init_special_pred, if this is re-enabled.
% gen_init_proc_id_from_univ(ModuleInfo, PrettyprinterProc)
]).
@@ -1048,8 +1065,7 @@
list(mlds__defn), list(mlds__defn)).
:- mode gen_init_method(in, in, in, out, in, out) is det.
-gen_init_method(ModuleInfo, NumExtra, RttiProcId, Init,
- ExtraDefns0, ExtraDefns) :-
+gen_init_method(ModuleInfo, NumExtra, RttiProcId, Init, !ExtraDefns) :-
%
% we can't store the address of the typeclass method directly in
% the base_typeclass_info; instead, we need to generate
@@ -1064,7 +1080,36 @@
% Hopefully the Mercury HLDS->HLDS inlining and/or
% the target code compiler will be able to optimize this...
%
+ gen_wrapper_func_and_initializer(ModuleInfo, NumExtra, RttiProcId,
+ typeclass_info_closure, Init, !ExtraDefns).
+
+:- pred gen_init_special_pred(module_info::in, univ::in, mlds__initializer::out,
+ list(mlds__defn)::in, list(mlds__defn)::out) is det.
+
+gen_init_special_pred(ModuleInfo, RttiProcIdUniv, Init, !ExtraDefns) :-
+ %
+ % we can't store the address of the special pred procedure directly
+ % in the type_ctor_info because when the special pred is called
+ % by looking up its address in the type_ctor_info its always called
+ % with its arguments boxed, but the generated special pred may operate
+ % on unboxed values, hence we need to generate a wrapper function
+ % which unboxes the arguments if necessary.
+ %
+ ( univ_to_type(RttiProcIdUniv, RttiProcId) ->
+ NumExtra = 0,
+ gen_wrapper_func_and_initializer(ModuleInfo, NumExtra,
+ RttiProcId, special_pred, Init, !ExtraDefns)
+ ;
+ error("gen_init_special_pred: cannot extract univ value")
+ ).
+
+:- pred gen_wrapper_func_and_initializer(module_info, int, rtti_proc_label,
+ closure_kind, mlds__initializer,
+ list(mlds__defn), list(mlds__defn)).
+:- mode gen_wrapper_func_and_initializer(in, in, in, in, out, in, out) is det.
+gen_wrapper_func_and_initializer(ModuleInfo, NumExtra, RttiProcId,
+ ClosureKind, Init, ExtraDefns0, ExtraDefns) :-
%
% We start off by creating a fresh MLGenInfo here,
% using the pred_id and proc_id of the wrapped procedure.
@@ -1083,16 +1128,15 @@
% Now we can safely go ahead and generate the wrapper function
%
term__context_init(Context),
- ml_gen_closure_wrapper(PredId, ProcId, typeclass_info_closure,
+ ml_gen_closure_wrapper(PredId, ProcId, ClosureKind,
NumExtra, Context, WrapperFuncRval, WrapperFuncType,
MLGenInfo1, MLGenInfo),
ml_gen_info_get_extra_defns(MLGenInfo, ExtraDefns1),
ExtraDefns = list__append(ExtraDefns1, ExtraDefns0),
%
- % The initializer for the method field of the base_typeclass_info
- % is just the wrapper function's address, converted to
- % mlds__generic_type (by boxing).
+ % The initializer for the wrapper is just the wrapper function's
+ % address, converted to mlds__generic_type (by boxing).
%
Init = init_obj(unop(box(WrapperFuncType), WrapperFuncRval)).
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.208
diff -u -r1.208 Mmakefile
--- tests/hard_coded/Mmakefile 1 Dec 2003 15:56:07 -0000 1.208
+++ tests/hard_coded/Mmakefile 1 Dec 2003 20:41:43 -0000
@@ -43,6 +43,7 @@
dupcall_types_bug \
dupcall_impurity \
elim_special_pred \
+ equality_pred_which_requires_boxing \
eqv_type_bug \
erroneous_liveness \
error_func \
New File: tests/hard_coded/equality_pred_which_requires_boxing.exp
===================================================================
float (boxed): true
float (unboxed): true
foreign_type (boxed): true
foreign_type (unboxed): true
foreign_type(T) (boxed): true
foreign_type(T) (unboxed): true
New File: tests/hard_coded/equality_pred_which_requires_boxing.m
===================================================================
% equality_pred_which_requires_boxing
%
% Check that the unification predicate we generate handles the case where
% the arguments are boxed and unboxed correctly.
:- module equality_pred_which_requires_boxing.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- type type_which_needs_boxing.
:- pragma foreign_type(c, type_which_needs_boxing, "double")
where equality is unify_ft.
:- pragma foreign_type(il, type_which_needs_boxing,
"valuetype [mscorlib]System.Double") where equality is unify_ft.
:- type type_which_needs_boxing(T).
:- pragma foreign_type(c, type_which_needs_boxing(T), "double")
where equality is unify_ft_T.
:- pragma foreign_type(il, type_which_needs_boxing(T),
"valuetype [mscorlib]System.Double")
where equality is unify_ft_T.
main(!IO) :-
% Test a builtin type which requires boxing.
A = float_a,
B = float_b,
unify("float (boxed)", A, B, !IO),
( A = B ->
io__write_string("float (unboxed): true\n", !IO)
;
io__write_string("float (unboxed): false\n", !IO)
),
% Test a simple foreign_type.
X = create(A),
Y = create(B),
unify("foreign_type (boxed)", X, Y, !IO),
( X = Y ->
io__write_string("foreign_type (unboxed): true\n", !IO)
;
io__write_string("foreign_type (unboxed): false\n", !IO)
),
% Test a foreign_type which requires a type_info.
G = create_T(A),
H = create_T(B),
unify("foreign_type(T) (boxed)", G, H, !IO),
( G = H ->
io__write_string("foreign_type(T) (unboxed): true\n", !IO)
;
io__write_string("foreign_type(T) (unboxed): false\n", !IO)
).
% Here we pass in a generic type, so if needed the input
% arguments will have been boxed. We then test if the
% unification pred handles this correctly.
:- pragma no_inline(unify/5).
:- pred unify(string::in, T::in, T::in, io::di, io::uo) is det.
unify(S, X, Y, !IO) :-
io__write_string(S, !IO),
( X = Y ->
io__write_string(": true\n", !IO)
;
io__write_string(": false\n", !IO)
).
:- func create(float) = type_which_needs_boxing.
:- pragma foreign_proc("C", create(X::in) = (Y::out), [promise_pure], "
Y = X;
").
:- pragma foreign_proc("C#", create(X::in) = (Y::out), [promise_pure], "
Y = X;
").
:- func create_T(float) = type_which_needs_boxing(int).
:- pragma foreign_proc("C", create_T(X::in) = (Y::out), [promise_pure], "
Y = X;
").
:- pragma foreign_proc("C#", create_T(X::in) = (Y::out), [promise_pure], "
Y = X;
").
:- pred unify_ft(type_which_needs_boxing::in, type_which_needs_boxing::in)
is semidet.
:- pragma foreign_proc("C", unify_ft(X::in, Y::in), [promise_pure], "
SUCCESS_INDICATOR = (X == Y);
").
:- pragma foreign_proc("C#", unify_ft(X::in, Y::in), [promise_pure], "
SUCCESS_INDICATOR = (X == Y);
").
:- pred unify_ft_T(type_which_needs_boxing(T)::in,
type_which_needs_boxing(T)::in) is semidet.
:- pragma foreign_proc("C", unify_ft_T(X::in, Y::in), [promise_pure], "
SUCCESS_INDICATOR = (X == Y);
").
:- pragma foreign_proc("C#", unify_ft_T(X::in, Y::in), [promise_pure], "
SUCCESS_INDICATOR = (X == Y);
").
:- pragma no_inline(float_a/0).
:- func float_a = float.
float_a = 1.0.
:- pragma no_inline(float_b/0).
:- func float_b = float.
float_b = 1.0.
--------------------------------------------------------------------------
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