mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-27 23:34:52 +00:00
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.
93 lines
2.7 KiB
Mathematica
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)
|
|
).
|