Commit Graph

2 Commits

Author SHA1 Message Date
Zoltan Somogyi
4db9b2adbf Until now, the only indexing we did for switches on strings was using a hash
Estimated hours taken: 40
Branches: main

Until now, the only indexing we did for switches on strings was using a hash
table containing jump targets (represented as indices into a list of labels).
This diff supplements this with

- binary searches of tables containing jump targets,
- binary searches of tables containing values (lookup tables), and
- hash searches of tables containing values (lookup tables).

For now, the new methods exist in the LLDS backend only.

NEWS:
	Mention the new capability.

compiler/string_switch.m:
	Add predicates that implement the new indexing methods on strings.
	Factor out code from existing predicates as required for this.

compiler/switch_gen.m:
	Invoke the new predicates in string_switch.m when relevant.

	Avoid passing the constant "no" as the initial value of !MaybeEnd
	to predicates where we know this will ALWAYS happen.

compiler/options.m:
doc/user_guide.texi:
	Add an option to control when we use binary searches for switches
	on strings.

compiler/lookup_switch.m:
	This module previously handled lookup switches on integers.
	Generalize it so that pieces of it are now also usable to help
	implement lookup switches on strings. Rename the predicates specific
	to switches on integers to make clear this specificity, and separate
	them from the predicates that help implement lookup switches on
	variables of all the supported types.

	Export some types, predicates and functions for use in string_switch.m.

	Fix the code so that it correctly handles det switches, which
	can happen e.g. if we know the possible set of values of the
	switched-on variable.

	Use tail-recursive code to handle the list of switch arms, to allow us
	to handle very large switches.

	Remove an obsolete comment from the top about a previously implemented
	optimization.

compiler/lookup_util.m:
	Make set_liveness_and_end_branch update MaybeEnd, to account for the
	reservation of stack slots for holding the current and last rows in
	later solutions tables for model_non lookup switches.

compiler/switch_util.m:
	Make the exported predicates of this module more general, making them
	usable for switches on strings as well as ints. Also make them easier
	to use. In one case this meant bundling two predicates that were always
	used together into one predicate. In another, it meant splitting one
	predicate into two, since some of its callers needed an intermediate
	result. In the case of a type, it means reordering its fields
	to make the order match the order of their use in the implementation.

	Add some predicates specifically for switches on strings.

compiler/ml_lookup_switch.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
	Conform to the changes to switch_util.m.

compiler/jumpopt.m:
	If the comment associated with a label ends with "nofulljump", then
	inhibit fulljump optimization of jumps to that label. That
	optimization would replace the jumps with the code starting at that
	label. This is avoids the overhead of jump instructions, and it is a
	good idea in the usual case of forward jumps. However, for the few
	backward jumps we generate, the block that replaces the jump
	instruction can actually END with the same jump instruction (which may
	be conditionally executed), which means that our usual repeated
	invocation of jumpopt can replace the original jump instruction
	with MANY copies of the block it jumps to. In some cases, such as those
	in hash switches, you get more copies than can ever be executed in any
	actual execution. Lookup switches therefore now mark the labels that
	are targets of backward jumps with this marker.

compiler/llds.m:
	Document the new behavior of jumpopt.

compiler/code_info.m:
	Export a predicate for use in improving the code we generate for lookup
	switches.

	Make some other predicates simpler and/or more efficient.

compiler/builtin_ops.m:
	Add a builtin op for doing string comparisons by calling strcmp.
	This is to prevent the need for two traversals of the strings being
	compared in each iteration of binary search.

compiler/bytecode.m:
compiler/c_util.m:
compiler/mlds_to_gcc.m:
compiler/mlds_to_il.m:
compiler/llds.m:
compiler/llds_to_x86_64.m:
	Conform to the change in builtin_ops.m.

compiler/disj_gen.m:
	Conform to the change in lookup_util.m

compiler/frameopt.m:
compiler/proc_gen.m:
compiler/unify_gen.m:
	Take advantage of the change in fulljump optimization.

compiler/opt_debug.m:
	Improve the string representation of rvals by recording the types of
	the operands of binary operations, and making the output a bit more
	consistent looking.

compiler/dupproc.m:
compiler/var_locn.m:
	Minor style fixes.

runtime/mercury_string.h:
	Add a version of strcmp for use by our code generator. This version
	casts the arguments before calling the real strcmp. We need it since we
	usually specify the arguments as r1, r2 etc, which are declared as
	MR_Word, not char *.

tests/hard_coded/lookup_disj.{m,exp}:
tests/hard_coded/string_switch.{m,exp}:
	Make these existing tests significantly tougher by making them exercise
	a wider range of use scenarios.

tests/hard_coded/string_switch{2,3}.{m,exp}:
tests/hard_coded/Mercury.options
	While the string_switch test case tests the handling of jump switches,
	these two new test cases test the handling of binary search tables and
	hash tables respectively. Their code is identical to the code of
	the string_switch test case, but Mercury.options causes them to be
	compiled with different options.

tests/hard_coded/int_switch.{m,exp}:
	A new test case, equivalent in structure to the string switch test
	cases, to test the handling of lookup switches on atomic values.
2010-11-01 04:03:06 +00:00
Zoltan Somogyi
cbe2ebf496 Implement multi-arm switches for the MLDS backend.
Estimated hours taken: 24
Branches: main

Implement multi-arm switches for the MLDS backend. When possible, the code of a
switch arm that has more than one cons_id is included in the output only once,
though of course with a condition that causes it to be executed for any of its
matching cons_ids. However, in the case of a tag switch in which a switch arm
has cons_ids with different primary tags, at least one of which has a
secondary tag that requires a switch on *it*, we duplicate the MLDS code of the
switch arm (we generate one copy for each such primary tag).

The diff yields a speedup of 0.4% on speedtest and a 0.5% reduction in code
size, but the main reason for it is so that programmers don't have any
incentive anymore to prefer an if-then-else chain to a switch for code
that is logically a switch with a default case that applies to many cons_ids.

compiler/handle_options.m:
	Keep disabling multi-arm switches for non-C MLDS backends, but stop
	disabling it for the C MLDS backend.

compiler/hlds_goal.m:
	Add a case number to the tagged_case type. This is to allow us to
	create maps that effectively function as maps from pieces of code
	(the code generated for the goal in the tagged case) to other things
	(various forms of the switch conditions in which that code applies)
	without making the code itself the key in the map; we can use the
	code's associated case number as the key instead.

compiler/mlds.m:
	Change the representation of the match conditions of a switch arm
	from just a simple list of conditions to a first condition and a list
	of other conditions. This enforces the invariant that the switch arm
	must always apply in at least one condition.

compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
	Implement the above.

	In ml_switch_gen.m, change the structure of the predicate that decides
	which code generation scheme to employ from an if-then-else chain
	to being basically a switch. This structure, which is modelled on the
	one used in the LLDS code generator, should be significantly clearer.

	As part of this change of structure, sort the cases by the cost of the
	tag tests only if the chosen code generation wants the cases sorted in
	this way.

compiler/switch_util.m:
	Add facilities for grouping together primary tags that both have
	exactly the same code, so that we don't have to duplicate its code.
	This is possible only when neither primary tag is shared by more
	than one cons_id. This grouping benefits even the LLDS backend.

	This involved separating out the types and predicates that are intended
	for use in compilation schemes in which more than one switch value can
	share the same piece of code (such as switches or if-then-else chains
	in C) from those intended for use in compilation in which this is not
	possible (such as lookup tables).

	Replace several uses of pairs with named types and function symbols.

	Delete a predicate that isn't needed anymore.

	Add a predicate to support the fix to switch_gen.m.

compiler/switch_gen.m:
	Fix an old oversight. When I added multi-arm switches for the LLDS
	backend, I did not update the test for whether the switch is big enough
	for each kind of nontrivial indexing to count cons_ids rather than
	switch arms (the benefit of smart indexing is proportional to the
	former). This diff fixes that.

compiler/ml_unify_gen.m:
	Change the interface of some predicates to make them more useful
	for generating code for switches.

compiler/tag_switch.m:
	Conform to the changes in switch_util.m.

compiler/ml_simplify_switch.m:
	Conform to the changes above.

	Rename some predicates to better reflect their purpose.

compiler/dense_switch.m:
compiler/lookup_switch.m:
compiler/ml_elim_nested.m:
compiler/ml_optimize.m:
compiler/ml_tailcall.m:
compiler/ml_util.m:
compiler/mlds_to_c.m:
compiler/mlds_to_gcc.m:
compiler/mlds_to_il.m:
compiler/mlds_to_java.m:
compiler/switch_case.m:
	Conform to the changes above.

tests/hard_coded/multi_arm_switch_2.{m,exp}:
tests/hard_coded/string_switch.{m,exp}:
	New test cases to exercise the new functionality.

tests/hard_coded/Mmakefile:
	Enable the new tests.
2009-08-25 23:47:00 +00:00