Zoltan's recent addition of support for formatting fixed size integer types
using string.format and friends works by casting the fixed size integer value
to an int or uint value and then re-using the existing code we already have for
formatting those. This works in all cases except when formatting 64-bit integer
types on systems where int / uint is a 32-bit quantity (notably, both the C#
and Java backends). This diff lifts that restrictions.
library/string.format.m:
Add support for formatting 64-bit integers without having to cast them
to an int or uint.
Export new format predicates for use by the code generated by
compiler/format_call.m.
compiler/format_call.m:
Generate calls to the 64-bit versions of the format_*_component predicates
where necessary.
compiler/simplify_proc.m:
Update the list of predicates that may be introduced by the compiler.
NEWS:
Delete the mention of the restriction.
tests/hard_coded/opt_format.{m,exp}:
Extend this test to cover 64-bit integers.
compiler/format_call.m:
As above.
Factor out some common code.
compiler/module_imports.m:
Fix a cut-and-paste bug.
library/builtin_modules.m:
Add a way to retrieve the name of the stream module, since the compiler
can now generate calls to stream.put.
tests/hard_codes/opt_format.{m,exp}:
Expand this test case to include tests of calls to
stream.string_writer.format.
Make the existing tests a bit tougher as well.
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.