[m-rev.] for review: improve debugging support for il grade.

Peter Ross pro at missioncriticalit.com
Tue Nov 4 05:05:52 AEDT 2003


On Sat, Nov 01, 2003 at 12:50:49PM +0100, Peter Ross wrote:
> On Sat, Nov 01, 2003 at 09:05:49PM +1100, Fergus Henderson wrote:
> > On 31-Oct-2003, Peter Ross <pro at missioncriticalit.com> wrote:
> > > On Wed, Oct 29, 2003 at 10:01:17AM +1100, Fergus Henderson wrote:
> > > > On 28-Oct-2003, Peter Ross <pro at missioncriticalit.com> wrote:
> > > > > Improve the support for debugging in the il grade, by not optimizing
> > > > > the generated il code, unless needed for verifiability.
> > > > > 
> > > > > Using
> > > > > 	mmc --make --grade il --target-debug -O0 diff
> > > > > now generates code which is relatively easier to debug in an IL
> > > > > debugger.
> > > > 
> > > > This is a good idea, but whether or not the generated IL code is
> > > > peephole optimized should depend on the "-O" setting, not on whether
> > > > or not --target-debug is specified.  Otherwise there's too much danger
> > > > of Heisenbugs (bugs which go away when you enabled debugging).
> > > > 
> > > > Currently peephole optimization is enabled at "-O0".
> > > > I'd be happy to change that so that it was instead enabled at "-O1"
> > > > for the IL back-end if and only if this speeds up compilation at "-O0".
> > > > 
> > > > Otherwise, I'd say use "--target-debug -O-1" or
> > > > "--target-debug -O0 --no-optimize-peep" if you want
> > > > the IL code to be maximally easy to debug.
> > > > If that is too complicated, we could consider introducing
> > > > a new option (perhaps "--opt-debug", by analogy with to "--opt-space"?),
> > > > which disabled optimizations that inhibit debugging.
> > >
> > > IMHO when compiling Mercury with debugging turned on at the default
> > > optimization level, one should have a reasonable debugging experience.
> > 
> > For Mercury debugging, I agree.  That's why we default to --no-trace-optimized,
> > and why --trace deep turns off all optimizations that would inhibit debugging
> > unless --trace-optimized is specified.
> > 
> > But for --target-debug, the argument is much less strong.  If you're
> > debugging things at the level of the target code, you're already
> > looking under the hood.  That's why we default to --c-optimize, even if
> > --target-debug is specified.
> > 
> > I guess for IL it may be a bit different, since we don't support mdb for the
> > IL back-end yet.
> > 
> I understand what you mean.
> 
> This is what I believe should change.
> 
> --debug should be allowed on the il backend.
> 
> When --debug is enabled it implies --trace-debug.
> 
> --no-trace-optimized should turn off --il-peephole-optimize.
> 
> The peephole optimization phase should look at --verifiable-code and
> --il-peephole-optimization when deciding what type of peephole
> optimization to do.
> 
> This I believe would satisfy us all.
> 

Hi,


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


Estimated hours taken: 4
Branches: main

Improve the support for debugging in the il grade, by not optimizing
the generated il code, unless needed for verifiability.

Using
	mmc --make --grade il --debug diff
now generates code which is relatively easier to debug in an IL
debugger.

compiler/handle_options.m:
	--debug imples --target-debug for the il backend.
	if debugging and --no-trace-optimize and il backend then
	--no-optimize-peep.
	Allow --debug as valid option for the il backend.
	
compiler/mlds_to_ilasm.m:
	Use --verifiable-code and --optimize-peep to decide what level
	of peephole optimization is needed to be done.

compiler/il_peephole.m:
	Change the peephole optimizer so that it can do all peephole
	optimizations, or only those which are needed for
	verifiability.


diff -u compiler/il_peephole.m compiler/il_peephole.m
--- compiler/il_peephole.m
+++ compiler/il_peephole.m
@@ -38,9 +38,9 @@
 
 :- import_module bool, list.
 
-	% Peephole optimize a list of instructions.
-	% Taking into account whether or not we are generating debuggable
-	% code.
+	% il_peephole__optimize(VerifyOnly, IL0, IL)
+	% Peephole optimize a list of instructions, possibly only doing
+	% those optimizations which are necessary for verifiable code.
 
 :- pred il_peephole__optimize(bool::in,
 		list(ilasm__decl)::in, list(ilasm__decl)::out) is det.
@@ -59,25 +59,25 @@
 	% when we find a sequence we can't optimize, we back up and try
 	% to optimize the sequence starting with the previous instruction.
 
-optimize(TargetDebug, Decls0, Decls) :-
-	list__map_foldl(optimize_decl(TargetDebug), Decls0, Decls, no, _Mod).
+optimize(VerifyOnly, Decls0, Decls) :-
+	list__map_foldl(optimize_decl(VerifyOnly), Decls0, Decls, no, _Mod).
 
 	% Mod is a bool that says whether the code was modified as a
 	% result of the optimization (that is, whether Decl \= Decl0).
 	% This can be used to decide whether to keep repeat the
 	% optimizations.
 :- pred optimize_decl(bool::in, decl::in, decl::out, bool::in, bool::out) is det.
-optimize_decl(TargetDebug, Decl0, Decl, Mod0, Mod) :-
+optimize_decl(VerifyOnly, Decl0, Decl, Mod0, Mod) :-
 	( Decl0 = class(A, B, C, D, ClassMembers0) ->
-		list__map_foldl(optimize_class_member(TargetDebug),
+		list__map_foldl(optimize_class_member(VerifyOnly),
 			ClassMembers0, ClassMembers, Mod0, Mod),
 		Decl = class(A, B, C, D, ClassMembers)
 	; Decl0 = method(A, MethodDecls0) ->
-		list__map_foldl(optimize_method_decl(TargetDebug), MethodDecls0,
+		list__map_foldl(optimize_method_decl(VerifyOnly), MethodDecls0,
 			MethodDecls, Mod0, Mod),
 		Decl = method(A, MethodDecls)
 	; Decl0 = namespace(A, NamespaceDecls0) ->
-		list__map_foldl(optimize_decl(TargetDebug), NamespaceDecls0,
+		list__map_foldl(optimize_decl(VerifyOnly), NamespaceDecls0,
 			NamespaceDecls, Mod0, Mod),
 		Decl = namespace(A, NamespaceDecls)
 	;
@@ -87,9 +87,9 @@
 
 :- pred optimize_class_member(bool::in, class_member::in, class_member::out, 
 	bool::in, bool::out) is det.
-optimize_class_member(TargetDebug, Decl0, Decl, Mod0, Mod) :-
+optimize_class_member(VerifyOnly, Decl0, Decl, Mod0, Mod) :-
 	( Decl0 = method(A, MethodDecls0) ->
-		list__map_foldl(optimize_method_decl(TargetDebug), MethodDecls0,
+		list__map_foldl(optimize_method_decl(VerifyOnly), MethodDecls0,
 			MethodDecls1, Mod0, Mod),
 		( Mod = yes ->
 				% find the new maxstack
@@ -119,9 +119,9 @@
 :- pred optimize_method_decl(bool::in,
 	method_body_decl::in, method_body_decl::out, 
 	bool::in, bool::out) is det.
-optimize_method_decl(TargetDebug, Decl0, Decl, Mod0, Mod) :-
+optimize_method_decl(VerifyOnly, Decl0, Decl, Mod0, Mod) :-
 	( Decl0 = instrs(Instrs0) ->
-		optimize_instrs(TargetDebug, Instrs0, Instrs, Mod1),
+		optimize_instrs(VerifyOnly, Instrs0, Instrs, Mod1),
 		bool__or(Mod0, Mod1, Mod),
 		Decl = instrs(Instrs)
 	;
@@ -131,15 +131,15 @@
 
 :- pred optimize_instrs(bool::in, instrs::in, instrs::out, bool::out) is det.
 
-optimize_instrs(TargetDebug, Instrs0, Instrs, Mod) :-
-	optimize_2(TargetDebug, Instrs0, Instrs, Mod).
+optimize_instrs(VerifyOnly, Instrs0, Instrs, Mod) :-
+	optimize_2(VerifyOnly, Instrs0, Instrs, Mod).
 
 :- pred optimize_2(bool, instrs, instrs, bool).
 :- mode optimize_2(in, in, out, out) is det.
 optimize_2(_, [], [], no).
-optimize_2(TargetDebug, [Instr0 | Instrs0], Instrs, Mod) :-
-	optimize_2(TargetDebug, Instrs0, Instrs1, Mod0),
-	opt_instr(TargetDebug, Instr0, Instrs1, Instrs, Mod1),
+optimize_2(VerifyOnly, [Instr0 | Instrs0], Instrs, Mod) :-
+	optimize_2(VerifyOnly, Instrs0, Instrs1, Mod0),
+	opt_instr(VerifyOnly, Instr0, Instrs1, Instrs, Mod1),
 	bool__or(Mod0, Mod1, Mod).
 
 	% Try to optimize the beginning of the given instruction sequence.
@@ -148,12 +148,12 @@
 :- pred opt_instr(bool, instr, instrs, instrs, bool).
 :- mode opt_instr(in, in, in, out, out) is det.
 
-opt_instr(TargetDebug, Instr0, Instrs0, Instrs, Mod) :-
+opt_instr(VerifyOnly, Instr0, Instrs0, Instrs, Mod) :-
 	(
-		match(Instr0, TargetDebug, Instrs0, Instrs2)
+		match(Instr0, VerifyOnly, Instrs0, Instrs2)
 	->
 		( Instrs2 = [Instr2 | Instrs3] ->
-			opt_instr(TargetDebug, Instr2, Instrs3, Instrs, _)
+			opt_instr(VerifyOnly, Instr2, Instrs3, Instrs, _)
 		;
 			Instrs = Instrs2
 		),
diff -u compiler/mlds_to_ilasm.m compiler/mlds_to_ilasm.m
--- compiler/mlds_to_ilasm.m
+++ compiler/mlds_to_ilasm.m
@@ -123,14 +123,23 @@
 
 	generate_il(MLDS, ILAsm0, ForeignLangs),
 
-		% Perform peephole optimization if requested.
+		% Perform peephole optimization if requested.  If peephole
+		% optimization was not requested, we may still need to invoke
+		% the peephole optimization pass, because some of the peephole
+		% optimizations are actually needed for verifiability of the
+		% generated IL.
 	globals__io_lookup_bool_option(optimize_peep, Peephole),
+	globals__io_lookup_bool_option(verifiable_code, Verifiable),
 	( { Peephole = yes } ->
-		globals__io_lookup_bool_option(target_debug, TargetDebug),
-		{ il_peephole__optimize(TargetDebug, ILAsm0, ILAsm) }
+		{ VerifyOnly = no },
+		{ il_peephole__optimize(VerifyOnly, ILAsm0, ILAsm) }
+	; { Verifiable = yes } ->
+		{ VerifyOnly = yes },
+		{ il_peephole__optimize(VerifyOnly, ILAsm0, ILAsm) }
 	;
 		{ ILAsm0 = ILAsm }
 	),
+
 		% Output the assembly.
 	ilasm__output(ILAsm),
 
only in patch2:
--- compiler/handle_options.m	26 Oct 2003 18:08:23 -0000	1.189
+++ compiler/handle_options.m	3 Nov 2003 17:57:45 -0000
@@ -386,6 +386,15 @@
 			globals__io_set_option(optimize_dead_procs, bool(yes))
 		;
 			[]
+		),
+
+
+		% On the .NET backend we will be using a language independent
+		% debugger not mdb.  Thus --debug has to imply --target-debug.
+		( { given_trace_level_is_none(TraceLevel) = no } ->
+			globals__io_set_option(target_debug, bool(yes))
+		;
+			[]
 		)
 	;
 		[]
@@ -747,7 +756,17 @@
 				bool(no)),
 			globals__io_set_option(optimize_saved_vars_cell,
 				bool(no)),
-			globals__io_set_option(loop_invariants, bool(no))
+			globals__io_set_option(loop_invariants, bool(no)),
+
+			% For the IL backend we turn off optimize_peep
+			% so that we don't optimize away references to the 
+			% local variables of a procedure.
+			( { Target = il } ->
+				globals__io_set_option(optimize_peep,
+					bool(no))
+			;
+				[]
+			)
 		;
 			[]
 		),
@@ -852,6 +871,7 @@
 	(
 		{ given_trace_level_is_none(TraceLevel) = yes
 		; HighLevel = no, Target = c
+		; Target = il
 		}
 	->
 		[]

Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.189
diff -u -r1.189 handle_options.m
--- compiler/handle_options.m	26 Oct 2003 18:08:23 -0000	1.189
+++ compiler/handle_options.m	3 Nov 2003 17:57:45 -0000
@@ -386,6 +386,15 @@
 			globals__io_set_option(optimize_dead_procs, bool(yes))
 		;
 			[]
+		),
+
+
+		% On the .NET backend we will be using a language independent
+		% debugger not mdb.  Thus --debug has to imply --target-debug.
+		( { given_trace_level_is_none(TraceLevel) = no } ->
+			globals__io_set_option(target_debug, bool(yes))
+		;
+			[]
 		)
 	;
 		[]
@@ -747,7 +756,17 @@
 				bool(no)),
 			globals__io_set_option(optimize_saved_vars_cell,
 				bool(no)),
-			globals__io_set_option(loop_invariants, bool(no))
+			globals__io_set_option(loop_invariants, bool(no)),
+
+			% For the IL backend we turn off optimize_peep
+			% so that we don't optimize away references to the 
+			% local variables of a procedure.
+			( { Target = il } ->
+				globals__io_set_option(optimize_peep,
+					bool(no))
+			;
+				[]
+			)
 		;
 			[]
 		),
@@ -852,6 +871,7 @@
 	(
 		{ given_trace_level_is_none(TraceLevel) = yes
 		; HighLevel = no, Target = c
+		; Target = il
 		}
 	->
 		[]
Index: compiler/il_peephole.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/il_peephole.m,v
retrieving revision 1.8
diff -u -r1.8 il_peephole.m
--- compiler/il_peephole.m	15 Mar 2003 03:08:52 -0000	1.8
+++ compiler/il_peephole.m	3 Nov 2003 17:57:45 -0000
@@ -36,12 +36,14 @@
 
 :- import_module ml_backend__ilasm.
 
-:- import_module list.
+:- import_module bool, list.
 
-	% Peephole optimize a list of instructions.
+	% il_peephole__optimize(VerifyOnly, IL0, IL)
+	% Peephole optimize a list of instructions, possibly only doing
+	% those optimizations which are necessary for verifiable code.
 
-:- pred il_peephole__optimize(list(ilasm__decl)::in, list(ilasm__decl)::out) 
-	is det.
+:- pred il_peephole__optimize(bool::in,
+		list(ilasm__decl)::in, list(ilasm__decl)::out) is det.
 
 :- implementation.
 
@@ -57,25 +59,25 @@
 	% when we find a sequence we can't optimize, we back up and try
 	% to optimize the sequence starting with the previous instruction.
 
-optimize(Decls0, Decls) :-
-	list__map_foldl(optimize_decl, Decls0, Decls, no, _Mod).
+optimize(VerifyOnly, Decls0, Decls) :-
+	list__map_foldl(optimize_decl(VerifyOnly), Decls0, Decls, no, _Mod).
 
 	% Mod is a bool that says whether the code was modified as a
 	% result of the optimization (that is, whether Decl \= Decl0).
 	% This can be used to decide whether to keep repeat the
 	% optimizations.
-:- pred optimize_decl(decl::in, decl::out, bool::in, bool::out) is det.
-optimize_decl(Decl0, Decl, Mod0, Mod) :-
+:- pred optimize_decl(bool::in, decl::in, decl::out, bool::in, bool::out) is det.
+optimize_decl(VerifyOnly, Decl0, Decl, Mod0, Mod) :-
 	( Decl0 = class(A, B, C, D, ClassMembers0) ->
-		list__map_foldl(optimize_class_member, ClassMembers0,
-			ClassMembers, Mod0, Mod),
+		list__map_foldl(optimize_class_member(VerifyOnly),
+			ClassMembers0, ClassMembers, Mod0, Mod),
 		Decl = class(A, B, C, D, ClassMembers)
 	; Decl0 = method(A, MethodDecls0) ->
-		list__map_foldl(optimize_method_decl, MethodDecls0,
+		list__map_foldl(optimize_method_decl(VerifyOnly), MethodDecls0,
 			MethodDecls, Mod0, Mod),
 		Decl = method(A, MethodDecls)
 	; Decl0 = namespace(A, NamespaceDecls0) ->
-		list__map_foldl(optimize_decl, NamespaceDecls0,
+		list__map_foldl(optimize_decl(VerifyOnly), NamespaceDecls0,
 			NamespaceDecls, Mod0, Mod),
 		Decl = namespace(A, NamespaceDecls)
 	;
@@ -83,11 +85,11 @@
 	 	Decl0 = Decl 
 	).
 
-:- pred optimize_class_member(class_member::in, class_member::out, 
+:- pred optimize_class_member(bool::in, class_member::in, class_member::out, 
 	bool::in, bool::out) is det.
-optimize_class_member(Decl0, Decl, Mod0, Mod) :-
+optimize_class_member(VerifyOnly, Decl0, Decl, Mod0, Mod) :-
 	( Decl0 = method(A, MethodDecls0) ->
-		list__map_foldl(optimize_method_decl, MethodDecls0,
+		list__map_foldl(optimize_method_decl(VerifyOnly), MethodDecls0,
 			MethodDecls1, Mod0, Mod),
 		( Mod = yes ->
 				% find the new maxstack
@@ -114,11 +116,12 @@
 	 	Decl0 = Decl 
 	).
 
-:- pred optimize_method_decl(method_body_decl::in, method_body_decl::out, 
+:- pred optimize_method_decl(bool::in,
+	method_body_decl::in, method_body_decl::out, 
 	bool::in, bool::out) is det.
-optimize_method_decl(Decl0, Decl, Mod0, Mod) :-
+optimize_method_decl(VerifyOnly, Decl0, Decl, Mod0, Mod) :-
 	( Decl0 = instrs(Instrs0) ->
-		optimize_instrs(Instrs0, Instrs, Mod1),
+		optimize_instrs(VerifyOnly, Instrs0, Instrs, Mod1),
 		bool__or(Mod0, Mod1, Mod),
 		Decl = instrs(Instrs)
 	;
@@ -126,31 +129,31 @@
 	 	Decl0 = Decl 
 	).
 
-:- pred optimize_instrs(instrs::in, instrs::out, bool::out) is det.
+:- pred optimize_instrs(bool::in, instrs::in, instrs::out, bool::out) is det.
 
-optimize_instrs(Instrs0, Instrs, Mod) :-
-	optimize_2(Instrs0, Instrs, Mod).
+optimize_instrs(VerifyOnly, Instrs0, Instrs, Mod) :-
+	optimize_2(VerifyOnly, Instrs0, Instrs, Mod).
 
-:- pred optimize_2(instrs, instrs, bool).
-:- mode optimize_2(in, out, out) is det.
-optimize_2([], [], no).
-optimize_2([Instr0 | Instrs0], Instrs, Mod) :-
-	optimize_2(Instrs0, Instrs1, Mod0),
-	opt_instr(Instr0, Instrs1, Instrs, Mod1),
+:- pred optimize_2(bool, instrs, instrs, bool).
+:- mode optimize_2(in, in, out, out) is det.
+optimize_2(_, [], [], no).
+optimize_2(VerifyOnly, [Instr0 | Instrs0], Instrs, Mod) :-
+	optimize_2(VerifyOnly, Instrs0, Instrs1, Mod0),
+	opt_instr(VerifyOnly, Instr0, Instrs1, Instrs, Mod1),
 	bool__or(Mod0, Mod1, Mod).
 
 	% Try to optimize the beginning of the given instruction sequence.
 	% If successful, try it again.
 
-:- pred opt_instr(instr, instrs, instrs, bool).
-:- mode opt_instr(in, in, out, out) is det.
+:- pred opt_instr(bool, instr, instrs, instrs, bool).
+:- mode opt_instr(in, in, in, out, out) is det.
 
-opt_instr(Instr0, Instrs0, Instrs, Mod) :-
+opt_instr(VerifyOnly, Instr0, Instrs0, Instrs, Mod) :-
 	(
-		match(Instr0, Instrs0, Instrs2)
+		match(Instr0, VerifyOnly, Instrs0, Instrs2)
 	->
 		( Instrs2 = [Instr2 | Instrs3] ->
-			opt_instr(Instr2, Instrs3, Instrs, _)
+			opt_instr(VerifyOnly, Instr2, Instrs3, Instrs, _)
 		;
 			Instrs = Instrs2
 		),
@@ -163,9 +166,11 @@
 %-----------------------------------------------------------------------------%
 
 	% Look for code patterns that can be optimized, and optimize them.
+	% The second argument says whether or not to only do the optimizations
+	% which are needed for verifiability.
 
-:- pred match(instr, instrs, instrs).
-:- mode match(in, in, out) is semidet.
+:- pred match(instr, bool, instrs, instrs).
+:- mode match(in, in, in, out) is semidet.
 
 	% If a ret is followed by anything other than a label,
 	% then we can delete the instruction that follows,
@@ -177,7 +182,7 @@
 	% Push ret past nops so we can find instructions on the other
 	% side of them (but don't eliminate them because they may be
 	% useful).
-match(ret, Instrs0, Replacement) :-
+match(ret, _, Instrs0, Replacement) :-
 	list__takewhile((pred(X::in) is semidet :- 
 		X \= label(_)
 	), Instrs0, PreLabel, NextInstrs0),
@@ -194,7 +199,8 @@
 	% to just the return.
 	% NOTE: We only look for forwards branches. 
 
-match(br(label_target(Label)), Instrs0, Instrs) :-
+match(br(label_target(Label)), VerifyOnly, Instrs0, Instrs) :-
+	VerifyOnly = no,
 	list__takewhile((pred(X::in) is semidet :- 
 		X \= label(Label)
 	), Instrs0, _, [label(Label) | NextInstrs0]),
@@ -214,7 +220,8 @@
 	% This might be slightly denser, and is easier to detect and
 	% remove if it turns out the local is not used.
 
-match(stloc(Var), Instrs0, Instrs) :-
+match(stloc(Var), VerifyOnly, Instrs0, Instrs) :-
+	VerifyOnly = no,
 		% The pattern
 	skip_nops(Instrs0, Instrs1, Nops),
 	Instrs1 = [ldloc(Var) | Rest],
@@ -235,7 +242,8 @@
 	% dup
 	% stloc(X)
 
-match(ldc(Type, Const), [stloc(Var)| Instrs0], Instrs) :-
+match(ldc(Type, Const), VerifyOnly, [stloc(Var)| Instrs0], Instrs) :-
+	VerifyOnly = no,
 		% The pattern
 	list__takewhile((pred(X::in) is semidet :- 
 		X \= ldloc(Var),
@@ -254,7 +262,8 @@
 	Instrs = list__append(Replacement, Rest).
 
 	% Two patterns begin with start_scope.
-match(start_block(scope(Locals), Id)) -->
+match(start_block(scope(Locals), Id), VerifyOnly) -->
+	{ VerifyOnly = no },
 	( 
 		match_start_scope_1(start_block(scope(Locals), Id))
 	->
Index: compiler/mlds_to_ilasm.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_ilasm.m,v
retrieving revision 1.21
diff -u -r1.21 mlds_to_ilasm.m
--- compiler/mlds_to_ilasm.m	15 Mar 2003 03:09:01 -0000	1.21
+++ compiler/mlds_to_ilasm.m	3 Nov 2003 17:57:51 -0000
@@ -123,13 +123,23 @@
 
 	generate_il(MLDS, ILAsm0, ForeignLangs),
 
-		% Perform peephole optimization if requested.
+		% Perform peephole optimization if requested.  If peephole
+		% optimization was not requested, we may still need to invoke
+		% the peephole optimization pass, because some of the peephole
+		% optimizations are actually needed for verifiability of the
+		% generated IL.
 	globals__io_lookup_bool_option(optimize_peep, Peephole),
-	{ Peephole = yes ->
-		il_peephole__optimize(ILAsm0, ILAsm)
+	globals__io_lookup_bool_option(verifiable_code, Verifiable),
+	( { Peephole = yes } ->
+		{ VerifyOnly = no },
+		{ il_peephole__optimize(VerifyOnly, ILAsm0, ILAsm) }
+	; { Verifiable = yes } ->
+		{ VerifyOnly = yes },
+		{ il_peephole__optimize(VerifyOnly, ILAsm0, ILAsm) }
 	;
-		ILAsm0 = ILAsm
-	},
+		{ ILAsm0 = ILAsm }
+	),
+
 		% Output the assembly.
 	ilasm__output(ILAsm),
 
--------------------------------------------------------------------------
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