[m-dev.] for review: compiler-generated procedures

Zoltan Somogyi zs at cs.mu.OZ.AU
Fri Oct 1 10:34:19 AEST 1999


> > 	Fix the generation of the compare procedures for enumerated types;
> > 	instead of calling mercury__compare_3_3, we cast the args to ints
> > 	and call builtin_compare_int.
> 
> You fixed the problem for compare, but won't the same problem arise
> for index and unify?

I didn't think so. The body generated for unifications is just a call to
unify; this gets recognized as an atomic test unification, which gets inline
code generated for it. And I thought that the index procedure for an enum
type should never be used.

However, I have now adopted a similar approach for the unify and index
predicates of enum types as well.

> Is there any particular reason to do that specialization here,
> rather than just relying on the compiler's usual specialization
> optimizations to do it?

Yes. The specialization is turned off by debugging. Arranging to selectively
leave this use of specialization turned on with debugging would be more
difficult than the approach I used.

> I don't think you're right about it only working by accident.
> There's quite a bit of code which goes to some trouble to ensure
> that the type used in the body of the unification/compare/index
> predicates for an equivalence type is the expanded type,
> even though the types used for the interface are the unexpanded type.

> > +			{ construct_type(unqualified("int") - 0, [],
> > +				IntType) },
> 
> Better to use the int_type/0 function in type_util.m.

Then why doesn't the rest of unify_proc.m, which I copied from use that
predicate? :-( Because it predates that predicate, I expect.

Here is a relative diff. Note that the only reason why I call builtin:unify
on two integers is that there is no builtin_int_eq, even though there is
builtin_int_{lt,gt}.

--- unify_proc.m.was	Fri Oct  1 11:58:32 1999
+++ unify_proc.m	Fri Oct  1 12:22:29 1999
@@ -523,20 +523,42 @@
 			unify_proc__quantify_clause_body([H1, H2], Goal,
 				Context, Clauses)
 		; { IsEnum = yes } ->
-			{ create_atomic_unification(H1, var(H2), Context,
-				explicit, [], Goal) },
-			unify_proc__quantify_clause_body([H1, H2], Goal,
+			{ IntType = int_type },
+			unify_proc__info_new_var(IntType, TC1),
+			unify_proc__info_new_var(IntType, TC2),
+			{ TC1ArgVars = [H1, TC1] },
+			unify_proc__build_call("unsafe_type_cast",
+				TC1ArgVars, Context, TC1Goal),
+			{ TC2ArgVars = [H2, TC2] },
+			unify_proc__build_call("unsafe_type_cast",
+				TC2ArgVars, Context, TC2Goal),
+			{ UnifyArgVars = [TC1, TC2] },
+			unify_proc__build_call("unify",
+				UnifyArgVars, Context, UnifyGoal),
+			{ goal_info_init(GoalInfo0) },
+			{ goal_info_set_context(GoalInfo0, Context,
+				GoalInfo) },
+			{ conj_list_to_goal([TC1Goal, TC2Goal, UnifyGoal],
+				GoalInfo, Goal) },
+			{ ArgVars = [H1, H2] },
+			unify_proc__quantify_clause_body(ArgVars, Goal,
 				Context, Clauses)
 		;
 			unify_proc__generate_du_unify_clauses(Ctors,
 				H1, H2, Context, Clauses)
 		)
-
 	;
 		{ TypeBody = eqv_type(_Type) },
-		% We should check whether _Type is abstract or not.
-		% If it is, we should call its unification procedure;
-		% if it is not, we should generate its body inline here.
+		% We should check whether _Type is a type variable,
+		% an abstract type or a concrete type.
+		% If it is type variable, then we should generate the same code
+		% we generate now. If it is an abstract type, we should call
+		% its unification procedure directly; if it is a concrete type,
+		% we should generate the body of its unification procedure
+		% inline here.
+		%
+		% XXX Somebody should document here what the later stages
+		% of the compiler do to prevent an infinite recursion here.
 		{ create_atomic_unification(H1, var(H2), Context, explicit, [],
 			Goal) },
 		unify_proc__quantify_clause_body([H1, H2], Goal, Context,
@@ -550,7 +572,7 @@
 	).
 
 :- pred unify_proc__generate_index_clauses(hlds_type_body, prog_var, prog_var,
-		prog_context, list(clause), unify_proc_info, unify_proc_info).
+	prog_context, list(clause), unify_proc_info, unify_proc_info).
 :- mode unify_proc__generate_index_clauses(in, in, in, in, out, in, out)
 	is det.
 
@@ -571,8 +593,8 @@
 				Context, Clauses)
 		; { IsEnum = yes } ->
 			{ ArgVars = [X, Index] },
-			unify_proc__build_call(
-				"index", ArgVars, Context, Goal),
+			unify_proc__build_call("unsafe_type_cast",
+				ArgVars, Context, Goal),
 			unify_proc__quantify_clause_body(ArgVars, Goal,
 				Context, Clauses)
 		;
@@ -581,8 +603,16 @@
 		)
 	;
 		{ TypeBody = eqv_type(_Type) },
-		% XXX zs: I believe this code works only by accident.
-		% XXX the point for unify also applies here
+		% We should check whether _Type is a type variable,
+		% an abstract type or a concrete type.
+		% If it is type variable, then we should generate the same code
+		% we generate now. If it is an abstract type, we should call
+		% its index procedure directly; if it is a concrete type,
+		% we should generate the body of its index procedure
+		% inline here.
+		%
+		% XXX Somebody should document here what the later stages
+		% of the compiler do to prevent an infinite recursion here.
 		{ ArgVars = [X, Index] },
 		unify_proc__build_call("index", ArgVars, Context, Goal),
 		unify_proc__quantify_clause_body(ArgVars, Goal, Context,
@@ -596,8 +626,7 @@
 	).
 
 :- pred unify_proc__generate_compare_clauses(hlds_type_body, prog_var, prog_var,
-		prog_var, prog_context, list(clause),
-		unify_proc_info, unify_proc_info).
+	prog_var, prog_context, list(clause), unify_proc_info, unify_proc_info).
 :- mode unify_proc__generate_compare_clauses(in, in, in, in, in, out, in, out)
 	is det.
 
@@ -616,21 +645,17 @@
 			unify_proc__quantify_clause_body(ArgVars, Goal,
 				Context, Clauses)
 		; { IsEnum = yes } ->
-			{ construct_type(unqualified("int") - 0, [],
-				IntType) },
+			{ IntType = int_type },
 			unify_proc__info_new_var(IntType, TC1),
 			unify_proc__info_new_var(IntType, TC2),
 			{ TC1ArgVars = [H1, TC1] },
-			unify_proc__build_call(
-				"unsafe_type_cast",
+			unify_proc__build_call("unsafe_type_cast",
 				TC1ArgVars, Context, TC1Goal),
 			{ TC2ArgVars = [H2, TC2] },
-			unify_proc__build_call(
-				"unsafe_type_cast",
+			unify_proc__build_call("unsafe_type_cast",
 				TC2ArgVars, Context, TC2Goal),
 			{ CompareArgVars = [Res, TC1, TC2] },
-			unify_proc__build_call(
-				"builtin_compare_int",
+			unify_proc__build_call("builtin_compare_int",
 				CompareArgVars, Context, CompareGoal),
 			{ goal_info_init(GoalInfo0) },
 			{ goal_info_set_context(GoalInfo0, Context,
@@ -646,6 +671,16 @@
 		)
 	;
 		{ TypeBody = eqv_type(_) },
+		% We should check whether _Type is a type variable,
+		% an abstract type or a concrete type.
+		% If it is type variable, then we should generate the same code
+		% we generate now. If it is an abstract type, we should call
+		% its compare procedure directly; if it is a concrete type,
+		% we should generate the body of its compare procedure
+		% inline here.
+		%
+		% XXX Somebody should document here what the later stages
+		% of the compiler do to prevent an infinite recursion here.
 		{ ArgVars = [Res, H1, H2] },
 		unify_proc__build_call("compare", ArgVars, Context, Goal),
 		unify_proc__quantify_clause_body(ArgVars, Goal, Context,
@@ -863,7 +898,7 @@
 		out, in, out) is det.
 
 unify_proc__generate_du_compare_clauses_2(Ctors, Res, X, Y, Context, Goal) -->
-	{ construct_type(unqualified("int") - 0, [], IntType) },
+	{ IntType = int_type },
 	{ mercury_public_builtin_module(MercuryBuiltin) },
 	{ construct_type(qualified(MercuryBuiltin, "comparison_result") - 0,
 					[], ResType) },
Zoltan.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list