Files
mercury/tests/hard_coded/opt_format.m
Zoltan Somogyi 02f9532cc1 Optimize calls to formatting functions and predicates such as
Estimated hours taken: 16
Branches: main

Optimize calls to formatting functions and predicates such as

	Str = string.format("%s_%d", [s(Prefix), i(Num)])

into
	V1 = string.int_to_string(Num),
	V2 = "_" ++ V1,
	Str = Prefix ++ V2

essentially interpreting the format string at compile time rather than runtime.

At the moment, the optimization applies to calls to string.format/3,
io.format/3 and io.format/4, and only in the case where the format specifiers
are just "%c", "%d", or "%s", with no widths, precisions etc, though
that could be changed relatively easily, though at the cost of coupling
the compiler more tightly to the implementation of library/string.m.
(We don't handle %f, because float_to_string(F) yields a different string
than string.format("%f", [f(F)]). The former yields e.g. "1.23", while the
latter yields "1.23000".)

compiler/format_call.m:
	Change the code that looks for malformed calls to formatting predicates
	to also look for well-formed, optimizable calls, and to transform them
	as shown above.

mdbcomp/prim_data.m:
	List the standard library's string module here, since the compiler now
	needs to know what its name is (it generates calls to its predicates).

compiler/options.m:
doc/user_guide.texi:
	Add a new option, --optimize-format-calls, that calls for this
	optimization. Make it enabled by default.

compiler/simplify.m:
	Since the transformation in format_call.m will typically introduce
	nested conjunctions, we now do it before the rest of the
	simplifications. We also invoke the fixups needed by the output
	of format_call.m if it actually optimized any code.

	Delete the code that used to record whether the procedure has any
	format calls, since it now comes too late.

	Decide once, when setting up for processing a procedure, whether
	we want to invoke format_call.m if appropriate, instead of doing it
	later. This allows us to reduce the size of the simplications
	data structure we pass around.

	Protect the predicates that format_call.m can generate calls to
	from being deleted by dead_pred_elim before the simplification pass.

compiler/det_analysis.m:
	Since simplify.m itself cannot record early enough whether a given
	procedure body contains calls to formatting predicates, do it here.

compiler/det_info.m:
	Add a new field to the det_info that records whether we have seen
	a call to a formatting predicate.

	Add another field to the det_info that records the list of errors
	we have found so far, so that we can stop passing it around separately.

compiler/hlds_pred.m:
	Add a marker that allows det_analysis.m to record its conclusions.

compiler/hlds_goal.m:
	Add utility predicate.

compiler/goal_util.m:
	Make the predicates for creating new plain calls (and, for the sake of
	uniformity, calls to foreign code) take instmap_deltas, such as those
	created by the new utility functions in instmap.m. This allows these
	predicates' caller to avoid creating unnecessary intermediate data
	structures.

compiler/instmap.m:
	Make an existing predicate into a function to allow it to be used
	more flexibly.

	Move some utility functions for creating instmap_deltas here from
	table_gen.m, so that they can be used by other modules.

compiler/liveness.m:
	Delete an unused predicate.

compiler/accumulator.m:
compiler/add_heap_ops.m:
compiler/add_trail_ops.m:
compiler/builtin_lib_types.m:
compiler/common.m:
compiler/complexity.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/dep_par_conj.m:
compiler/det_report.m:
compiler/distance_granularity.m:
compiler/granularity.m:
compiler/higher_order.m:
compiler/hlds_out.m:
compiler/inlining.m:
compiler/intermod.m:
compiler/modecheck_unify.m:
compiler/modes.m:
compiler/pd_util.m:
compiler/prog_type.m:
compiler/purity.m:
compiler/rbmm.region_transformation.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/table_gen.m:
compiler/try_expand.m:
compiler/typecheck.m:
compiler/unify_proc.m:
	Conform to the changes above.

compiler/stm_expand.m:
	Conform to the changes above. Also, build pairs by using "-" directly
	as the function symbol, instead of this module's old practice
	of doing it the slow way by calling the "pair" function.

tests/general/string_format_lib.m:
	Cleanup the style of the code of this test case.

tests/hard_coded/opt_format.{m,exp}:
	New test case to exercise the behavior of format_call.m's
	transformation.

tests/hard_coded/Mmakefile:
tests/hard_coded/Mercury.options:
	Enable the new test case.
2009-09-03 23:57:51 +00:00

93 lines
2.7 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%-----------------------------------------------------------------------------%
%
% This test case is designed to test the correctness of the program
% transformation performed by compiler/format_call.m and the associated
% code in compiler/simplify.m.
:- module opt_format.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module char.
:- import_module int.
:- import_module list.
:- import_module string.
main(!IO) :-
io.write_string(test_string_format_1(42, 'x', "HAL"), !IO),
io.write_string(test_string_format_2(142, 'y', "IBM"), !IO),
io.write_string(test_string_format_2(242, 'z', "JCN"), !IO),
io.write_string(test_string_format_2(342, 'v', "KDO"), !IO),
test_io_format_1(42, 'a', "WHAL", !IO),
test_io_format_2(142, 'b', "WIBM", !IO),
test_io_format_2(242, 'c', "WJCN", !IO),
test_io_format_2(342, 'd', "WKDO", !IO).
:- func test_string_format_1(int, char, string) = string.
test_string_format_1(Int, Char, Str) =
string.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n", [i(Int), c(Char), s(Str)]).
:- func test_string_format_2(int, char, string) = string.
test_string_format_2(Int, Char, Str) = Result :-
PolyStr = s(Str),
(
Int > 300
->
Tail = [c(Char), PolyStr],
IntX = Int + 1,
Result = string.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n",
[i(IntX) | Tail])
;
Int > 200,
IntY = Int - 1,
FmtStr = "cba_%s_fed_%%%c_ghi_%d_jkl\\\n",
Values = [PolyStr, c(Char), i(IntY)]
->
Result = string.format(FmtStr, Values)
;
IntX = Int + 1,
Tail = [PolyStr],
Result = string.format("cba_%c_def_%%%d_ghi_%s_jkl\\\n",
[c(Char), i(IntX) | Tail])
).
:- pred test_io_format_1(int::in, char::in, string::in, io::di, io::uo) is det.
test_io_format_1(Int, Char, Str, !IO) :-
io.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n", [i(Int), c(Char), s(Str)], !IO).
:- pred test_io_format_2(int::in, char::in, string::in, io::di, io::uo) is det.
test_io_format_2(Int, Char, Str, !IO) :-
PolyStr = s(Str),
io.output_stream(OutStream, !IO),
(
Int > 300
->
Tail = [c(Char), PolyStr],
IntX = Int + 1,
io.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n", [i(IntX) | Tail], !IO)
;
Int > 200,
IntY = Int - 1,
FmtStr = "cba_%s_fed_%%%c_ghi_%d_jkl\\\n",
Values = [PolyStr, c(Char), i(IntY)]
->
io.format(FmtStr, Values, !IO)
;
IntX = Int + 1,
Tail = [PolyStr],
io.format(OutStream, "cba_%c_def_%%%d_ghi_%s_jkl\\\n",
[c(Char), i(IntX) | Tail], !IO)
).