[m-rev.] diff: improve boxing and unboxing in IL backend.

Tyson Dowd trd at cs.mu.OZ.AU
Thu Jul 26 20:32:03 AEST 2001


Hi,

(There's a corresponding change coming for the runtime and library that
removes all the handwritten calls to box and unbox routines).

===================================================================


Estimated hours taken: 4
Branches: main

Simplify boxing, unboxing and casts in the IL backend.

compiler/mlds_to_il.m:
	Previously we generated calls to out-of-line procedures written
	in C++ (and then they forwarded to ones written in IL) for
	various reasons mostly to do with churn of the .NET
	implementation of boxing.

	Now we generate much better code:
		- "unbox" and "ldobj" for unboxing
		- "box" for boxing
		- "castclass" for casts between reference types
		- nothing for casts to the same type
		- for casting from mercury types to value types we
		  unload from the MR_Word, and unbox the value

	The last item fixes a bug where unification for characters
	wasn't working as it was being passed as an MR_Word, and was not
	being unpacked correctly.  This means samples/calculator.m now
	works (modulo cygwin not passing EOF correctly at the moment).
		


Index: compiler/mlds_to_il.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_il.m,v
retrieving revision 1.55
diff -u -r1.55 mlds_to_il.m
--- compiler/mlds_to_il.m	2001/07/20 14:14:02	1.55
+++ compiler/mlds_to_il.m	2001/07/26 10:00:15
@@ -1966,53 +1966,82 @@
 
 		% if we are casting from an unboxed type, we should box
 		% it first.
-		% XXX should also test the cast-to type, to handle the
-		% cases where it is unboxed.
 unaryop_to_il(cast(Type), Rval, Instrs) -->
 	DataRep =^ il_data_rep,
 	{ ILType = mlds_type_to_ilds_type(DataRep, Type) },
-	{ 
-		Rval = const(Const),
-		RvalType = rval_const_to_type(Const),
-		RvalILType = mlds_type_to_ilds_type(DataRep, RvalType),
-		not already_boxed(RvalILType)
-	->
-		Instrs = node([call(convert_to_object(RvalILType)),
-			castclass(ILType)])
+	{ rval_to_type(Rval, RvalType) },
+	{ RvalILType = mlds_type_to_ilds_type(DataRep, RvalType) },
+	{ already_boxed(ILType) ->
+		( already_boxed(RvalILType) ->
+			( RvalType = Type ->
+				Instrs = empty
+			;
+				Instrs = node([castclass(ILType)])
+			)
+		;
+			Instrs = tree__list([
+				convert_to_object(RvalILType),
+				instr_node(castclass(ILType))
+			])
+		)
 	;
-		Instrs = node([castclass(ILType)])
-	}.
+		( already_boxed(RvalILType) ->
+			( RvalType = mercury_type(_, user_type) ->
+				% XXX we should look into a nicer way to
+				% generate MLDS so we don't need to do this
+				Instrs = tree__list([
+					comment_node(
+						"loading out of an MR_Word"),
+					instr_node(ldc(int32, i(0))),
+					instr_node(ldelem(
+						il_generic_simple_type)),
+					comment_node(
+						"turning a cast into an unbox"),
+					convert_from_object(ILType)
+				])
 
 
-	% XXX boxing and unboxing should be fixed.
-	% currently for boxing and unboxing we call some conversion
-	% methods that written by hand. 
-	% We should do a small MLDS->MLDS transformation to introduce
-	% locals so we can box the address of the locals.
-	% then unboxing should just be castclass(System.Int32 or whatever),
-	% then unbox.
-unaryop_to_il(box(Type), _, Instrs) -->
+			;
+				% XXX It would be nicer if the MLDS used an
+				% unbox to do this.
+				Instrs = tree__list([
+					comment_node(
+					"turning a cast into an unbox"),
+					convert_from_object(ILType)
+				])
+			)
+		;
+			sorry(this_file, "cast operations between value types")
+		)
+	}.
+
+unaryop_to_il(box(UnboxedType), _, Instrs) -->
 	DataRep =^ il_data_rep,
-	{ ILType = mlds_type_to_ilds_type(DataRep, Type) },
-	{ already_boxed(ILType) ->
-		Instrs = node([isinst(il_generic_type)])
+	{ UnboxedILType = mlds_type_to_ilds_type(DataRep, UnboxedType) },
+	{ already_boxed(UnboxedILType) ->
+			% It is already boxed, so we don't need
+			% to do anything.
+			% It would be good if we didn't generate 
+			% such code, but it's no big deal
+		Instrs = empty
 	;
-		Instrs = node([call(convert_to_object(ILType))])
-		% XXX can't just use box, because it requires a pointer to
-		% the object, so it's useless for anything that isn't
-		% addressable
-		% Instrs = [box(ILType)]  
+		Instrs = convert_to_object(UnboxedILType)
 	}.
 
-unaryop_to_il(unbox(Type), _, Instrs) -->
+unaryop_to_il(unbox(UnboxedType), Rval, Instrs) -->
 	DataRep =^ il_data_rep,
-	{ ILType = mlds_type_to_ilds_type(DataRep, Type) },
-	{ ILType = ilds__type(_, class(_)) ->
-		Instrs = node([castclass(ILType)])
+	{ rval_to_type(Rval, RvalType) },
+	{ UnboxedILType = mlds_type_to_ilds_type(DataRep, UnboxedType) },
+	{ already_boxed(UnboxedILType) ->
+		( RvalType = UnboxedType ->
+				% We already have the correct type
+			Instrs = empty
+		;
+				% We have a different boxed type
+			Instrs = instr_node(castclass(UnboxedILType))
+		)
 	;
-		Instrs = node([call(convert_from_object(ILType))])
-		% since we can't use box, we can't use unbox
-		% Instrs = [unbox(ILType)]
+		Instrs = convert_from_object(UnboxedILType)
 	}.
 
 :- pred already_boxed(ilds__type::in) is semidet.
@@ -3066,63 +3095,61 @@
 % These functions are for converting to/from generic objects.
 %
 
-:- func convert_to_object(ilds__type) = methodref.
+:- func convert_to_object(ilds__type) = instr_tree.
 
-convert_to_object(Type) = methoddef(call_conv(no, default), 
-		simple_type(il_generic_simple_type),
-		class_member_name(il_conversion_class_name, id("ToObject")),
-		[Type]).
-
-:- func convert_from_object(ilds__type) = methodref.
-
-convert_from_object(Type) = 
-	methoddef(call_conv(no, default), simple_type(SimpleType),
-		class_member_name(il_conversion_class_name, id(Id)),
-			[il_generic_type]) :-
+convert_to_object(Type) = instr_node(box(ValueType)) :-
 	Type = ilds__type(_, SimpleType),
-	ValueClassName = simple_type_to_value_class_name(SimpleType),
-	string__append("To", ValueClassName, Id).
+	ValueType = simple_type_to_value_class(SimpleType).
 
+:- func convert_from_object(ilds__type) = instr_tree.
 
-	% XXX String and Array should be converted to/from Object using a
-	% cast, not a call to runtime convert.  When that is done they can be
-	% removed from this list
-:- func simple_type_to_value_class_name(simple_type) = string.
-simple_type_to_value_class_name(int8) = "Int8".
-simple_type_to_value_class_name(int16) = "Int16".
-simple_type_to_value_class_name(int32) = "Int32".
-simple_type_to_value_class_name(int64) = "Int64".
-simple_type_to_value_class_name(uint8) = "Int8".
-simple_type_to_value_class_name(uint16) = "UInt16".
-simple_type_to_value_class_name(uint32) = "UInt32".
-simple_type_to_value_class_name(uint64) = "UInt64".
-simple_type_to_value_class_name(float32) = "Single".
-simple_type_to_value_class_name(float64) = "Double".
-simple_type_to_value_class_name(bool) = "Bool".
-simple_type_to_value_class_name(char) = "Char".
-simple_type_to_value_class_name(refany) = _ :-
-	error("no value class name for refany").
-simple_type_to_value_class_name(class(Name)) = VCName :-
-	( Name = il_string_class_name ->
-		VCName = "String"
-	;
-		error("unknown class name")
-	).
-simple_type_to_value_class_name(value_class(_)) = _ :-
-	error("no value class name for value_class").
-simple_type_to_value_class_name(interface(_)) = _ :-
-	error("no value class name for interface").
-simple_type_to_value_class_name('[]'(_, _)) = "Array".
-simple_type_to_value_class_name('&'( _)) = _ :-
-	error("no value class name for '&'").
-simple_type_to_value_class_name('*'(_)) = _ :-
-	error("no value class name for '*'").
-simple_type_to_value_class_name(native_float) = _ :-
-	error("no value class name for native float").
-simple_type_to_value_class_name(native_int) = _ :-
-	error("no value class name for native int").
-simple_type_to_value_class_name(native_uint) = _ :-
-	error("no value class name for native uint").
+convert_from_object(Type) = node([unbox(Type), ldobj(Type)]).
+
+:- func simple_type_to_value_class(simple_type) = ilds__type.
+simple_type_to_value_class(int8) = 
+	ilds__type([], value_class(il_system_name(["SByte"]))).
+simple_type_to_value_class(int16) =
+	ilds__type([], value_class(il_system_name(["Int16"]))).
+simple_type_to_value_class(int32) =
+	ilds__type([], value_class(il_system_name(["Int32"]))).
+simple_type_to_value_class(int64) =
+	ilds__type([], value_class(il_system_name(["Int64"]))).
+simple_type_to_value_class(uint8) = 
+	ilds__type([], value_class(il_system_name(["Byte"]))).
+simple_type_to_value_class(uint16) =
+	ilds__type([], value_class(il_system_name(["UInt16"]))).
+simple_type_to_value_class(uint32) =
+	ilds__type([], value_class(il_system_name(["UInt32"]))).
+simple_type_to_value_class(uint64) = 
+	ilds__type([], value_class(il_system_name(["UInt64"]))).
+simple_type_to_value_class(float32) = 
+	ilds__type([], value_class(il_system_name(["Single"]))).
+simple_type_to_value_class(float64) = 
+	ilds__type([], value_class(il_system_name(["Double"]))).
+simple_type_to_value_class(bool) = 
+	ilds__type([], value_class(il_system_name(["Boolean"]))).
+simple_type_to_value_class(char) = 
+	ilds__type([], value_class(il_system_name(["Char"]))).
+simple_type_to_value_class(refany) = _ :-
+	error("no value class for refany").
+simple_type_to_value_class(class(_)) = _ :-
+	error("no value class for class").
+simple_type_to_value_class(value_class(_)) = _ :-
+	error("no value class for value_class").
+simple_type_to_value_class(interface(_)) = _ :-
+	error("no value class for interface").
+simple_type_to_value_class('[]'(_, _)) = _ :-
+	error("no value class for array").
+simple_type_to_value_class('&'( _)) = _ :-
+	error("no value class for '&'").
+simple_type_to_value_class('*'(_)) = _ :-
+	error("no value class for '*'").
+simple_type_to_value_class(native_float) = _ :-
+	error("no value class for native float").
+simple_type_to_value_class(native_int) = _ :-
+	error("no value class for native int").
+simple_type_to_value_class(native_uint) = _ :-
+	error("no value class for native uint").
 
 %-----------------------------------------------------------------------------%
 %

--------------------------------------------------------------------------
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