bug fix to frameopt

Zoltan Somogyi zs at cs.mu.oz.au
Thu Jul 17 11:31:27 AEST 1997


Comments, anyone?

Zoltan.

cvs diff: Diffing .
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/frameopt.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/frameopt.m,v
retrieving revision 1.58
diff -u -r1.58 frameopt.m
--- frameopt.m	1997/07/16 06:22:58	1.58
+++ frameopt.m	1997/07/17 00:13:50
@@ -59,24 +59,28 @@
 %		detstackvar(N) = succip
 %	L1:
 %		...
+%		succip = detstackvar(N)
 %		finalization
 %		goto L1
 %
 % The advantage is that we don't destroy the stack frame just to set it up
-% again.
+% again. The restore of succip can be omitted if the procedure makes no calls,
+% since in that case succip must still contain the value it had when this
+% procedure was called.
 %
 % Since the second transformation is a bigger win, we prefer to use it
 % whenever both transformations are possible.
 %
-% NOTE: This module requires label optimisation to be turned on because
-% it cannot handle code sequences of the form
+% NOTE: This module cannot handle code sequences of the form
 %
 %	label1:
 %	label2:
 %
-% The "null block" between the labels makes frameopt choke.  This should
-% be handled by handle_options, but if you see an error of the form
-% "label in substitute_labels_instr", this is a possible cause.
+% Jump optimization converts any gotos to label1 to gotos to label2, making
+% label1 unused, and label optimization removes unused labels. (This works
+% for any number of labels in a sequence, not just two.) Therefore the
+% handle_options module turns on the jump and label optimizations whenever
+% frame optimization is turned on.
 
 %-----------------------------------------------------------------------------%
 
@@ -87,9 +91,6 @@
 :- import_module llds.
 :- import_module bool, list.
 
-	% Delay the construction of det stack frames as long as possible,
-	% in order to avoid the construction in as many cases as possible.
-	%
 	% The first bool output says whether we performed any modifications.
 	% If yes, then we also introduced some extra labels that should be
 	% deleted. The second says whether we introduced any jumps that
@@ -120,8 +121,9 @@
 		analyze_block_map(LabelSeq0, BlockMap1, BlockMap2, KeepFrame),
 		(
 			KeepFrame = yes(FirstLabel - SecondLabel),
+			find_any_calls(LabelSeq0, BlockMap2, AnyCalls),
 			keep_frame(LabelSeq0, BlockMap2,
-				FirstLabel, SecondLabel, BlockMap),
+				FirstLabel, SecondLabel, AnyCalls, BlockMap),
 			LabelSeq = LabelSeq0,
 			NewComment = comment("keeping stack frame") - "",
 			list__append(Comments0, [NewComment], Comments),
@@ -190,13 +192,15 @@
 						% setup or teardown. The bool
 						% says whether the code in the
 						% block needs a stack frame.
-			;	teardown(list(instruction)).
+			;	teardown(list(instruction), list(instruction)).
 						% This block contains stack
 						% teardown and goto code;
-						% the arg gives just the goto
-						% code (which should have a
-						% label instruction put before
-						% it if used).
+						% the two args give the instr
+						% that restores succip (if any)
+						% and the goto code (which must
+						% be a list because it may or
+						% mey not contain a liveness
+						% annotation).
 
 %-----------------------------------------------------------------------------%
 
@@ -295,7 +299,7 @@
 			LabelSeq = [Label | LabelSeq0]
 		;
 			frameopt__detstack_teardown(Instrs0, FrameSize,
-				Tail, Teardown, Goto, Remain)
+				Tail, Teardown, RestoreSuccip, Goto, Remain)
 		->
 			( Tail = [] ->
 				MaybeTailInfo = no,
@@ -305,7 +309,7 @@
 				TeardownLabel = Label,
 				TeardownInfo = block_info(TeardownLabel,
 					TeardownBlock, [], no,
-					teardown(Goto))
+					teardown(RestoreSuccip, Goto))
 			;
 				block_needs_frame(Tail, Needs),
 				TailInfo = block_info(Label, [Instr0 | Tail],
@@ -319,7 +323,7 @@
 				TeardownLabel = NewLabel,
 				TeardownInfo = block_info(TeardownLabel,
 					TeardownBlock, [], no,
-					teardown(Goto))
+					teardown(RestoreSuccip, Goto))
 			),
 			build_block_map(Remain, FrameSize, LabelSeq0,
 				BlockMap0, BlockMap1, ProcLabel, N1, N),
@@ -417,14 +421,15 @@
 	% We are looking for the teardown components in any order, since
 	% value numbering may change the original order. This is also the
 	% reason why we allow teardown instructions to be interleaved with
-	% instructions that do not access the stack.
+	% instructions that do not access the stack, and why some teardown
+	% instructions (e.g. the one that restores succip) may be missing.
 
 :- pred frameopt__detstack_teardown(list(instruction)::in, int::in,
-	list(instruction)::out, list(instruction)::out,
+	list(instruction)::out, list(instruction)::out, list(instruction)::out,
 	list(instruction)::out, list(instruction)::out) is semidet.
 
 frameopt__detstack_teardown([Instr0 | Instrs0], FrameSize,
-		Tail, Teardown, Goto, Remain) :-
+		Tail, Teardown, RestoreSuccip, Goto, Remain) :-
 	(
 		Instr0 = label(_) - _
 	->
@@ -432,26 +437,29 @@
 	;
 		frameopt__detstack_teardown_2([Instr0 | Instrs0], FrameSize,
 			[], [], [], [],
-			TailPrime, TeardownPrime, GotoPrime, RemainPrime)
+			TailPrime, TeardownPrime, RestoreSuccipPrime,
+			GotoPrime, RemainPrime)
 	->
 		Tail = TailPrime,
 		Teardown = TeardownPrime,
+		RestoreSuccip = RestoreSuccipPrime,
 		Goto = GotoPrime,
 		Remain = RemainPrime
 	;
 		frameopt__detstack_teardown(Instrs0, FrameSize,
-			Tail1, Teardown, Goto, Remain),
+			Tail1, Teardown, RestoreSuccip, Goto, Remain),
 		Tail = [Instr0 | Tail1]
 	).
 
 :- pred frameopt__detstack_teardown_2(list(instruction)::in, int::in,
 	list(instruction)::in, list(instruction)::in, list(instruction)::in,
 	list(instruction)::in, list(instruction)::out, list(instruction)::out,
-	list(instruction)::out, list(instruction)::out) is semidet.
+	list(instruction)::out, list(instruction)::out, list(instruction)::out)
+	is semidet.
 
 frameopt__detstack_teardown_2(Instrs0, FrameSize,
 		SeenSuccip0, SeenDecrsp0, SeenExtra0, SeenLivevals0,
-		Tail, Teardown, Goto, Remain) :-
+		Tail, Teardown, RestoreSuccip, Goto, Remain) :-
 	opt_util__skip_comments(Instrs0, Instrs1),
 	Instrs1 = [Instr1 | Instrs2],
 	Instr1 = Uinstr1 - _,
@@ -466,14 +474,16 @@
 			SeenSuccip1 = [Instr1],
 			frameopt__detstack_teardown_2(Instrs2, FrameSize,
 				SeenSuccip1, SeenDecrsp0, SeenExtra0,
-				SeenLivevals0, Tail, Teardown, Goto, Remain)
+				SeenLivevals0, Tail, Teardown,
+				RestoreSuccip, Goto, Remain)
 		;
 			opt_util__lval_refers_stackvars(Lval, no),
 			opt_util__rval_refers_stackvars(Rval, no),
 			list__append(SeenExtra0, [Instr1], SeenExtra1),
 			frameopt__detstack_teardown_2(Instrs2, FrameSize,
 				SeenSuccip0, SeenDecrsp0, SeenExtra1,
-				SeenLivevals0, Tail, Teardown, Goto, Remain)
+				SeenLivevals0, Tail, Teardown,
+				RestoreSuccip, Goto, Remain)
 		)
 	;
 		Uinstr1 = decr_sp(FrameSize),
@@ -481,19 +491,20 @@
 		SeenDecrsp1 = [Instr1],
 		frameopt__detstack_teardown_2(Instrs2, FrameSize,
 			SeenSuccip0, SeenDecrsp1, SeenExtra0, SeenLivevals0,
-			Tail, Teardown, Goto, Remain)
+			Tail, Teardown, RestoreSuccip, Goto, Remain)
 	;
 		Uinstr1 = livevals(_),
 		SeenLivevals0 = [],
 		SeenLivevals1 = [Instr1],
 		frameopt__detstack_teardown_2(Instrs2, FrameSize,
 			SeenSuccip0, SeenDecrsp0, SeenExtra0, SeenLivevals1,
-			Tail, Teardown, Goto, Remain)
+			Tail, Teardown, RestoreSuccip, Goto, Remain)
 	;
 		Uinstr1 = goto(_),
 		SeenDecrsp0 = [_],
 		list__append(SeenSuccip0, SeenDecrsp0, Teardown),
 		Tail = SeenExtra0,
+		RestoreSuccip = SeenSuccip0,
 		list__append(SeenLivevals0, [Instr1], Goto),
 		Remain = Instrs2
 	).
@@ -672,6 +683,23 @@
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
+:- pred find_any_calls(list(label)::in, block_map::in, bool::out) is det.
+
+find_any_calls([], _BlockMap, no).
+find_any_calls([Label | Labels], BlockMap, AnyCalls) :-
+	map__lookup(BlockMap, Label, BlockInfo),
+	BlockInfo = block_info(_, Instrs, _, _, _),
+	(
+		list__member(Instr, Instrs),
+		Instr = call(_, _, _, _) - _
+	->
+		AnyCalls = yes
+	;
+		find_any_calls(Labels, BlockMap, AnyCalls)
+	).
+
+%-----------------------------------------------------------------------------%
+
 	% Transform the given block sequence to effect the optimization
 	% of keeping the stack frame for recursive tail calls once it has
 	% been set up by the initial entry to the procedure.
@@ -680,38 +708,45 @@
 	% should replace it in tailcalls that avoid the stack teardown.
 
 :- pred keep_frame(list(label)::in, block_map::in, label::in, label::in,
-	block_map::out) is det.
+	bool::in, block_map::out) is det.
 
-keep_frame([], BlockMap, _FirstLabel, _SecondLabel, BlockMap).
-keep_frame([Label | Labels], BlockMap0, FirstLabel, SecondLabel, BlockMap) :-
+keep_frame([], BlockMap, _FirstLabel, _SecondLabel, _AnyCalls, BlockMap).
+keep_frame([Label | Labels], BlockMap0, FirstLabel, SecondLabel, AnyCalls,
+		BlockMap) :-
 	map__lookup(BlockMap0, Label, BlockInfo0),
 	(
-		BlockInfo0 = block_info(Label, Instrs0, [_], no,
-			teardown(Instrs1)),
-		pick_last(Instrs0, _NonLastInstrs, LastInstr),
-		LastInstr = goto(label(GotoLabel)) - Comment,
+		BlockInfo0 = block_info(Label, OrigInstrs, [_], no,
+			teardown(RestoreSuccip, BareInstrs)),
+		pick_last(OrigInstrs, _NonLastOrigInstrs, LastOrigInstr),
+		LastOrigInstr = goto(label(GotoLabel)) - Comment,
 		same_label_ref(FirstLabel, GotoLabel)
 	->
 		(
-			Instrs0 = [Instr0 | _],
-			Instr0 = label(_) - _
+			OrigInstrs = [OrigInstr0 | _],
+			OrigInstr0 = label(_) - _
 		->
-			NewLabelInstr = Instr0
+			NewLabelInstr = OrigInstr0
 		;
 			error("block does not begin with label")
 		),
-		pick_last(Instrs1, NonLastInstrs, _LastInstr),
+		pick_last(BareInstrs, NonLastBareInstrs, _LastBareInstr),
 		string__append(Comment, " (keeping frame)", NewComment),
 		NewGoto = goto(label(SecondLabel)) - NewComment,
-		list__append([NewLabelInstr | NonLastInstrs], [NewGoto],
-			Instrs),
+		NewFrontInstrs = [NewLabelInstr | NonLastBareInstrs],
+		( AnyCalls = yes ->
+			list__append(RestoreSuccip, [NewGoto], NewBackInstrs)
+		;
+			NewBackInstrs = [NewGoto]
+		),
+		list__append(NewFrontInstrs, NewBackInstrs, Instrs),
 		BlockInfo = block_info(Label, Instrs, [SecondLabel], no,
 			ordinary(yes)),
 		map__det_update(BlockMap0, Label, BlockInfo, BlockMap1)
 	;
 		BlockMap1 = BlockMap0
 	),
-	keep_frame(Labels, BlockMap1, FirstLabel, SecondLabel, BlockMap).
+	keep_frame(Labels, BlockMap1, FirstLabel, SecondLabel, AnyCalls,
+		BlockMap).
 
 :- pred pick_last(list(T)::in, list(T)::out, T::out) is det.
 
@@ -868,7 +903,7 @@
 			queue__put(Queue0, Label, Queue1)
 		)
 	;
-		BlockType = teardown(_),
+		BlockType = teardown(_, _),
 		Queue1 = Queue0
 	),
 	rev_map_side_labels(SideLabels, Label, RevMap0, RevMap1),
@@ -1031,7 +1066,7 @@
 				Labels, BlockMap, ParMap, FallIntoParallel)
 		)
 	;
-		Type = teardown(_),
+		Type = teardown(_, _),
 		process_frame_delay(Labels0, BlockMap0,
 			ParMap0, FallIntoParallel0, FramedLabels,
 			FrameSize, Msg, ProcLabel, N0,
@@ -1094,7 +1129,7 @@
 				N2 = N1
 			)
 		;
-			FallThroughType = teardown(_),
+			FallThroughType = teardown(_, _),
 			MaybeFallThrough = yes(FallThrough),
 			BlockMap1 = BlockMap0,
 			set__insert(FallIntoParallel0,
@@ -1153,7 +1188,7 @@
 		N1 = N0,
 		ParMap1 = ParMap0
 	;
-		Type = teardown(_),
+		Type = teardown(_, _),
 		mark_parallel(Label0, Label, ProcLabel, N0, N1,
 			ParMap0, ParMap1)
 	),
@@ -1288,7 +1323,7 @@
 		;
 			error("block with parallel has fall through")
 		),
-		( Type = teardown(Replacement0) ->
+		( Type = teardown(_, Replacement0) ->
 			LabelInstr = label(ParallelLabel)
 				- "non-teardown parallel",
 			Replacement = [LabelInstr | Replacement0],
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.24
diff -u -r1.24 handle_options.m
--- handle_options.m	1997/07/16 06:22:59	1.24
+++ handle_options.m	1997/07/17 00:09:47
@@ -293,10 +293,11 @@
 		[]
 	),
 	
-	% --optimize-frames implies --optimize-labels
+	% --optimize-frames requires --optimize-labels and --optimize-jumps
 	globals__io_lookup_bool_option(optimize_frames, OptFrames),
 	( { OptFrames = yes } ->
-		globals__io_set_option(optimize_labels, bool(yes))
+		globals__io_set_option(optimize_labels, bool(yes)),
+		globals__io_set_option(optimize_jumps, bool(yes))
 	;
 		[]
 	).
cvs diff: Diffing compiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing library
cvs diff: Diffing lp_solve
cvs diff: Diffing lp_solve/lp_examples
cvs diff: Diffing profiler
cvs diff: Diffing runtime
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/diff
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/general
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trial
cvs diff: Diffing util



More information about the developers mailing list