Commit Graph

107 Commits

Author SHA1 Message Date
Julien Fischer
f2c99cc0b2 More spelling fixes, etc.
compiler/cse_detection.m:
compiler/ml_lookup_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_target_util.m:
compiler/switch_util.m:
     As above.
2023-04-03 21:41:32 +10:00
Zoltan Somogyi
8e7a1b2a11 Further simplify the management of MLDS switches.
compiler/ml_switch_gen.m:
    The code for deciding how to implement switches on strings was
    a convoluted nest of tests, which tested several different properties
    of the target language. The flexibility this afforded could have been
    useful in the past when the MLDS backend targeted MSIL and gcc asm,
    but with today's three target languages, they are just overkill,
    especially since several parts of the old code were unreachable.
    Replace all that code with a simple switch on the target language.
    Move the switch arm for C into its own predicate in order to reduce
    the required indentation level.

    Assume that all target languages support switches on (smaller-than-64-bit)
    integers, because they all do.

    Use Defns, not Decls, to refer to lists of local var definitions.

    Fix an misleading old comment.

compiler/ml_target_util.m:
    Delete the code testing whether a target language supports switches on
    smaller-than-64-bit integers.
2023-04-03 19:52:58 +10:00
Zoltan Somogyi
10a8473cc2 Simplify the management of smart indexing.
compiler/switch_util.m:
    Simplify the interface of the find_switch_category predicate.
    Instead of returning (a) a *smart switch category*, and (b) a flag
    that says whether that category may be used, simply return
    a *switch category*, which includes a non-smart switch category,
    the if-then-else chain.

    Give some data constructors in the switch_category type names that
    clarify the differences between them.

    Move the type_ctor_cat_to_switch_cat function just after its only caller.

compiler/ml_switch_gen.m:
compiler/switch_gen.m:
    Flatten the switches on the return values of find_switch_category.

    Merge arms of these switches that handle dumb switches and switches
    on floats, because they are both implemented as if-then-else chains.

    In ml_switch_gen.m, inline the ml_gen_smart_int64_switch predicate,
    which made only one decision, at its only call site.

    Add XXXs that point out opportunities for further simplification.

compiler/ml_lookup_switch.m:
    Rename a predicate to conform to the new names of switch categories.
2023-04-03 10:02:39 +10:00
Zoltan Somogyi
ea4f95a7ed Use var_tables in lco.m, and when dumping goals.
Since this is the first converted module that dumps out goals when
debugging trace flags are enabled, this required generalizing the code
that does that, to take either varsets or var_tables as a means of
specifying the names of variables. We do this via a new type,
var_name_source, which contains either a varset or a var_table.

Almost all of this diff is there to implement this generalization.
A large part of it affects code in the parse_tree package that we use
to write out the parts of HLDS goals that are defined by types defined
in that package. Since we want to avoid making any part of the parse_tree
package dependent on the hlds package, this required defining the
var_name_source type in the parse_tree package, which in turn requires
var_table.m to be in that same package.

compiler/lco.m:
    Convert this module to use var_tables instead of varsets and vartypes.

compiler/var_table.m:
    Move this module from the hlds package to the parse_tree package.

    To make this, possible, move the parts that required access to the HLDS
    to hlds_pred.m, from where it was usually invoked.

    Export some utility predicates to allow the moved code to work
    in hlds_pred.m without access to the actual definition of the
    var_table type.

    Define the var_name_source type.

    Add some utility functions for use by code writing out variable names.

compiler/hlds_pred.m:
    Add the code moved from var_table.m.

compiler/vartypes.m:
    Move this module from the hlds package to the parse_tree package,
    for symmetry with var_table.m. It did not depend on being in hlds
    in any way.

compiler/hlds.m:
compiler/parse_tree.m:
    Move vartypes.m and var_table.m from the hlds package
    to the parse_tree package.

compiler/hlds_out_goal.m:
    Change all the predicates in this module to take a var_name_source
    instead of a prog_varset.

    Fix some comments.

compiler/hlds_out_util.m:
    Change some of the predicates in this module (those called from
    hlds_out_goal.m) to take a var_name_source instead of a prog_varset.

compiler/parse_tree_out_term.m:
    Provide variants of some existing predicates and functions that take
    var_name_sources instead of varsets. The code of the copies
    duplicates the logic of the originals, though I hope that this
    duplication can be done away with at the end of the transition.
    (The best solution would be to use a typeclass with methods
    that convert vars to their names, but we would want to ensure
    that the compiler can specialize all the affected predicates
    and functions to the two instances of this typeclass, which is
    something that we cannot do yet. In the meantime, the lack of
    any generalization in the old versions preserves their performance.)

tools/sort_imports:
tools/filter_sort_imports:
    A new tool that automatically sorts any occurrences of consecutive
    ":- import_module" declarations in the named files. The sorting is done
    in filter_sort_imports; sort_imports loops over the named files.

    After automatically replacing all occurrences of hlds.{vartypes,var_table}
    in import_module declarations with their parse_tree versions, the updated
    import_module declarations were usually out of order with respect to
    their neighbours. I used this script to fix that, and some earlier
    out-of-order imports.

compiler/accumulator.m:
compiler/add_class.m:
compiler/add_clause.m:
compiler/add_foreign_proc.m:
compiler/add_heap_ops.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_trail_ops.m:
compiler/analysis.m:
compiler/arg_info.m:
compiler/build_mode_constraints.m:
compiler/bytecode_gen.m:
compiler/call_gen.m:
compiler/check_promise.m:
compiler/closure_analysis.m:
compiler/closure_gen.m:
compiler/code_info.m:
compiler/code_loc_dep.m:
compiler/common.m:
compiler/compile_target_code.m:
compiler/complexity.m:
compiler/const_prop.m:
compiler/constraint.m:
compiler/continuation_info.m:
compiler/convert_parse_tree.m:
compiler/coverage_profiling.m:
compiler/cse_detection.m:
compiler/ctgc.datastruct.m:
compiler/ctgc.util.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/delay_construct.m:
compiler/delay_partial_inst.m:
compiler/dep_par_conj.m:
compiler/det_analysis.m:
compiler/det_report.m:
compiler/det_util.m:
compiler/direct_arg_in_out.m:
compiler/disj_gen.m:
compiler/distance_granularity.m:
compiler/equiv_type_hlds.m:
compiler/exception_analysis.m:
compiler/file_names.m:
compiler/float_regs.m:
compiler/follow_vars.m:
compiler/format_call.m:
compiler/generate_dep_d_files.m:
compiler/get_dependencies.m:
compiler/goal_expr_to_goal.m:
compiler/goal_mode.m:
compiler/goal_path.m:
compiler/goal_store.m:
compiler/goal_util.m:
compiler/granularity.m:
compiler/hhf.m:
compiler/higher_order.m:
compiler/hlds_clauses.m:
compiler/hlds_code_util.m:
compiler/hlds_error_util.m:
compiler/hlds_goal.m:
compiler/hlds_llds.m:
compiler/hlds_out_pred.m:
compiler/hlds_rtti.m:
compiler/hlds_statistics.m:
compiler/inlining.m:
compiler/inst_check.m:
compiler/inst_test.m:
compiler/inst_user.m:
compiler/instance_method_clauses.m:
compiler/instmap.m:
compiler/intermod.m:
compiler/intermod_analysis.m:
compiler/interval.m:
compiler/introduce_exists_casts.m:
compiler/introduce_parallelism.m:
compiler/item_util.m:
compiler/lambda.m:
compiler/live_vars.m:
compiler/liveness.m:
compiler/llds.m:
compiler/llds_out_data.m:
compiler/llds_out_file.m:
compiler/llds_out_util.m:
compiler/lookup_switch.m:
compiler/loop_inv.m:
compiler/make.module_target.m:
compiler/make.util.m:
compiler/make_goal.m:
compiler/make_hlds_separate_items.m:
compiler/make_hlds_types.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_mlds_back_end.m:
compiler/middle_rec.m:
compiler/ml_accurate_gc.m:
compiler/ml_args_util.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_gen_info.m:
compiler/ml_lookup_switch.m:
compiler/ml_proc_gen.m:
compiler/ml_simplify_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_unify_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_c_func.m:
compiler/mlds_to_c_global.m:
compiler/mlds_to_cs_class.m:
compiler/mlds_to_cs_file.m:
compiler/mlds_to_java_data.m:
compiler/mlds_to_java_file.m:
compiler/mlds_to_java_stmt.m:
compiler/mlds_to_java_type.m:
compiler/mmc_analysis.m:
compiler/mode_comparison.m:
compiler/mode_constraints.m:
compiler/mode_debug.m:
compiler/mode_errors.m:
compiler/mode_info.m:
compiler/mode_ordering.m:
compiler/modecheck_call.m:
compiler/modecheck_coerce.m:
compiler/modecheck_goal.m:
compiler/modecheck_unify.m:
compiler/modecheck_util.m:
compiler/modes.m:
compiler/module_cmds.m:
compiler/old_type_constraints.m:
compiler/opt_debug.m:
compiler/optimize.m:
compiler/options_file.m:
compiler/ordering_mode_constraints.m:
compiler/par_loop_control.m:
compiler/parse_item.m:
compiler/parse_string_format.m:
compiler/parse_tree_out_inst.m:
compiler/parse_tree_to_term.m:
compiler/parse_util.m:
compiler/pd_debug.m:
compiler/pd_info.m:
compiler/pd_util.m:
compiler/peephole.m:
compiler/polymorphism.m:
compiler/polymorphism_info.m:
compiler/polymorphism_lambda.m:
compiler/polymorphism_type_class_info.m:
compiler/polymorphism_type_info.m:
compiler/post_typecheck.m:
compiler/pragma_c_gen.m:
compiler/pred_name.m:
compiler/pred_table.m:
compiler/prog_item.m:
compiler/prog_rep.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/push_goals_together.m:
compiler/qual_info.m:
compiler/quantification.m:
compiler/rbmm.execution_path.m:
compiler/rbmm.m:
compiler/rbmm.points_to_analysis.m:
compiler/rbmm.points_to_graph.m:
compiler/rbmm.points_to_info.m:
compiler/rbmm.region_resurrection_renaming.m:
compiler/rbmm.region_transformation.m:
compiler/recompilation.used_file.m:
compiler/recompilation.version.m:
compiler/recompute_instmap_deltas.m:
compiler/resolve_unify_functor.m:
compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
compiler/saved_vars.m:
compiler/set_of_var.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_conj.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/simplify_goal_scope.m:
compiler/simplify_goal_switch.m:
compiler/simplify_goal_unify.m:
compiler/simplify_info.m:
compiler/simplify_proc.m:
compiler/size_prof.m:
compiler/smm_common.m:
compiler/ssdebug.m:
compiler/stack_alloc.m:
compiler/stack_layout.m:
compiler/stack_opt.m:
compiler/stm_expand.m:
compiler/store_alloc.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/structure_reuse.direct.detect_garbage.m:
compiler/structure_reuse.domain.m:
compiler/structure_reuse.indirect.m:
compiler/structure_reuse.lbu.m:
compiler/structure_reuse.lfu.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/superhomogeneous.m:
compiler/switch_detection.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/table_gen.m:
compiler/tabling_analysis.m:
compiler/term_constr_build.m:
compiler/term_constr_data.m:
compiler/term_constr_initial.m:
compiler/term_constr_main.m:
compiler/term_constr_main_types.m:
compiler/term_constr_util.m:
compiler/term_pass1.m:
compiler/term_traversal.m:
compiler/term_util.m:
compiler/trace_gen.m:
compiler/trailing_analysis.m:
compiler/transform_llds.m:
compiler/try_expand.m:
compiler/tupling.m:
compiler/type_assign.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/typecheck_debug.m:
compiler/typecheck_errors.m:
compiler/typecheck_info.m:
compiler/unify_gen_construct.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_proc.m:
compiler/unique_modes.m:
compiler/unneeded_code.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/var_locn.m:
compiler/write_deps_file.m:
compiler/write_module_interface_files.m:
    Conform to the changes above.
2022-04-18 02:00:38 +10:00
Zoltan Somogyi
8ebe125a6a Introduce var_table.m.
Most compiler passes need to know both the names and the types
of the variables they operate on. Until now, they had to pass along
two separate data structures for that, the varset and the vartypes,
and many operations required looking a variable up in both of these.

The var table is a single data structure that records for each variable

- its name, as the varset has traditionally done,
- its type, as the vartypes has traditionally done,
- the is_dummy_type flag which says whether its type is a dummy type,
  which traditionally had to computed afresh at each lookup.

Switch the MLDS code generator to use var_tables instead of varsets and
vartypes. The code generator often needs to know the name and the type
of a variable at the same time, and it often needs to know which variables'
types are dummies, often enough that precomputing this info should be a win.

compiler/var_table.m:
    Add this new module which defines the var_table.

    Its operations are modelled after the operation in var_types.m.

compiler/hlds.m:
compiler/notes/compiler_design.html:
    Add the new module to the hlds package.

compiler/prog_type.m:
compiler/type_util.m:
    Move the is_dummy_type from type_util.m, which is in the
    check_hlds package, to prog_type.m, which in the parse_tree package,
    to avoid having this part of the hlds package depend on check_hlds.
    (It already depends on parse_tree, for a lot of different things.)

    Given a function and a predicate that each took a vartypes arg,
    make new versions that take a var_table arg instead.
    Rationalize the argument list of the function.

compiler/ml_gen_info.m:
    Replace the varset and vartypes fields of the ml_gen_info with a
    var_table field.

compiler/ml_code_util.m:
    Replace code that used to operate on varsets and vartypes with code
    that operates on var_tables.

    Create new versions of a few operations to exploit the info in var_tables.

    Give some predicates more meaningful names.

compiler/ml_accurate_gc.m:
compiler/ml_args_util.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_lookup_switch.m:
compiler/ml_proc_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_unify_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
    Replace code that used to operate on varsets and vartypes with code
    that operates on var_tables.

    In ml_switch_gen.m and ml_tag_switch.m, put some predicates' arguments
    into an reasonable order by moving related args next to each other.

compiler/vartypes.m:
    Delete an operation that was only needed in the MLDS backend,
    in code that this diff replaces.

compiler/switch_util.m:
    Put the larger input first in the arg list of a predicate.

compiler/closure_gen.m:
compiler/code_info.m:
compiler/code_loc_dep.m:
compiler/export.m:
compiler/lambda.m:
compiler/live_vars.m:
compiler/liveness.m:
compiler/llds.m:
compiler/llds_out_instr.m:
compiler/mark_tail_calls.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/stack_alloc.m:
compiler/stack_layout.m:
compiler/tag_switch.m:
compiler/term_constr_util.m:
compiler/tupling.m:
compiler/unify_gen.m:
compiler/unify_gen_deconstruct.m:
compiler/var_locn.m:
    Conform to the changes above.
2022-03-28 10:20:49 +11:00
Zoltan Somogyi
9012395ec2 Don't let ml_tag_switch.m generate duplicate fields.
This fixes the second problem identified by Mantis bug #548.

compiler/ml_tag_switch.m:
    Detect the circumstances in which this problem would arise.
    In such cases, simply fail, and let ml_switch_gen.m fall back
    to implementing the switch as an if-then-else chain.

compiler/ml_switch_gen.m:
    Implement that fallback.

compiler/switch_util.m:
    The new code in ml_tag_switch.m needs to thread a fourth piece of state
    through the predicate it passes to group_cases_by_ptag, so change
    its argument list to accommodate such predicates. And since some other
    modules pass the same predicates to group_cases_by_ptag and
    string_binary_cases, make the same change in the argument list
    of that predicate as well.

    Delete one stray comment, and note that another comment seems misplaced.

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

tests/hard_coded/bug548.exp:
tests/hard_coded/Mmakefile:
    Enable the previously-added test case for Mantis #548, after
    add an .exp file for it.
2022-02-11 21:32:53 +11:00
Zoltan Somogyi
5b711e3a3f Move code needed in one switch arm to that arm. 2022-02-10 09:51:38 +11:00
Zoltan Somogyi
9ddb180757 Handle const_var_maps left by add_trail_ops.m.
This fixes Mantis bug #544.

The code of add_trail_ops.m can transform

    <code that adds an entry to const_var_map>

into

    (
        ...
        <code that adds an entry to const_var_map>
        ...
    ;
        ...,
        fail
    )

where the const_var_map in the MLDS code generator records which variables'
values are available as ground terms.

The MLDS code generator used to reset the const_var_map in its main data
structure, the ml_gen_info, at the end of every disjunction (actually,
at the end of every branched control structure) to the value it had
at the start. This was intended to prevent the code following the branched
structure from relying on const_var_map entries that were added to the
const_var_map on *some* branches, but not others. However, in this case,
it has the effect of forgetting the entry added by the first disjunct,
even though

- the code after the disjunction can be reached *only* via the first disjunct,
  and

- the code after the disjunction (legitimately, until add_trail_ops) depended
  on that entry being available.

The fix is to allow the code after a branched control structure to depend
on any const_var_map entry that is present in the final const_var_map
in every branch of the branched control structure whose end is reachable.

The LLDS code generator was not affected by the bug, because it uses
totally separate systems both for implementing trailing, and for keeping
track of what variables' values are available statically. In particular,
it does not rely on operations inserted and the annotations left on
unifications by the add_trail_ops and mark_static_term passes,
having been written long before either module existed.

compiler/hlds_goal.m:
    Document the update above to what may be marked static.

compiler/ml_gen_info.m:
    Document the updated protocol for handling the const_var_map field.

    Use a named type instead of its expansion.

compiler/ml_code_gen.m:
    Make the predicates that generate code for a branch in a branched
    control structure return the final const_var_maps from the branches
    whose endpoints are reachable.

    Add a predicate that computes the consensus of all the gathered
    const_var_maps.

    Compute consensus const_var_maps for if-then-elses and negations.

    Fix some inconsistencies in variable naming.

    Simplify some code.

compiler/ml_disj_gen.m:
    Compute consensus const_var_maps for disjunctions.

compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
    Compute consensus const_var_maps for various kinds of switches.

    In some predicates, put related arguments next to each other.

compiler/ml_unify_gen_construct.m:
    Delete "dynamic" from the names of several predicates that also handled
    non-dynamic construction unifications.

    Fix an out-of-date comment.

compiler/mark_static_terms:
    Fix grammar in a comment.

library/map.m:
    Fix a careless bug: when doing a merge in map.common_subset_loop,
    we threw away an entry from the wrong list in one of three cases.

    Make such bugs harder to overlook by

    - deleting the common parts from variable names, leaving the differences
      easier to see, and

    - replacing numeric suffixes for completely separate data structures
      with A and B suffixes.

tests/valid/bug544.m:
    A new test case for the bug.

tests/valid/Mercury.options:
tests/valid/Mmakefile:
    Enable the bug, and run it with -O5.
2022-02-07 17:30:32 +11:00
Zoltan Somogyi
181ada0dbf Avoid -O<n> resetting previously set options.
This implements Mantis feature request #495.

NEWS:
    Announce the change.

compiler/optimization_options.m:
    A new module for managing optimization options.

    It defines a separate bespoke type for every boolean optimization option
    to make it harder to confuse them. It defines a tuple type (opt_tuple)
    for accessing optimization options quickly. It implements the turning on
    (but NOT turning off) of optimizations when a given optimization level
    is selected.

tools/make_optimization_options_middle:
tools/make_optimization_options_db:
    The script that generates the meat of optimization_options.m,
    and the database of option names, kinds and initial values
    that it uses as its input. The script also generates some code
    for the special_handler predicate in compiler/options.m.

tools/make_optimization_options_start:
tools/make_optimization_options_end:
    The handwritten initial and final parts of optimization_options.m.

tools/make_optimization_options:
    The script that pulls these parts together to form optimization_options.m.

compiler/options.m:
    Make every optimization option a special option, to be handled by
    the special_handler predicate. That handling consists of simply
    adding a representation of the option to the end of a cord of
    optimization options, to be processed later by optimization_options.m.
    That processing will record the values of these options in the opt_tuple,
    which is where every other part of the compiler should get them from.

    Change the interface of special_handler to make the above possible.

    Add an "optopt_" (optimization option) prefix to the name of
    every optimization option, to make them inaccessible to the rest
    of the compiler under their old name, and thus help enforce the switch
    to using the opt_tuple. Any access to these options to look up
    their values would fail anyway, since the option data would no longer be
    e.g. bool(yes), but bool_special, but the name change makes this failure
    happen at compile time, not runtime.

    Reclassify a few options to make the above make sense. Some options
    (unneeded_code_debug, unneeded_code_debug_pred_name, and
    common_struct_preds) were classified as oc_opt even though they
    control only the *debugging* of optimizations, while some options
    (c_optimize and inline_alloc) were not classified as oc_opt
    even though we do set them automatically at some optimization levels.

    Delete the opt_level_number option, since it was not used anywhere.

    Delete the code for handling -ON and --opt-space, since that is now
    done in optimization_options.m.

    Add some XXXs.

compiler/handle_options.m:
    Switch to using getopt_io.process_options_userdata_se, as required
    by the new interface of the special_handler in options.m.
    In the absence of errors, invoke optimization_options.m to initialize
    the opt_tuple. Then update the opt_tuple incrementally when processing
    option implications that affect optimization options.

compiler/globals.m:
    Put the opt_tuple into a new field of the globals structure.

compiler/accumulator.m:
compiler/add_pragma_type_spec.m:
compiler/add_trail_ops.m:
compiler/code_info.m:
compiler/code_loc_dep.m:
compiler/compile_target_code.m:
compiler/const_struct.m:
compiler/deforest.m:
compiler/dep_par_conj.m:
compiler/disj_gen.m:
compiler/erl_code_gen.m:
compiler/format_call.m:
compiler/global_data.m:
compiler/grab_modules.m:
compiler/higher_order.m:
compiler/hlds_pred.m:
compiler/inlining.m:
compiler/intermod.m:
compiler/ite_gen.m:
compiler/jumpopt.m:
compiler/libs.m:
compiler/llds_out_code_addr.m:
compiler/llds_out_data.m:
compiler/llds_out_file.m:
compiler/llds_out_instr.m:
compiler/llds_out_util.m:
compiler/matching.m:
compiler/mercury_compile_front_end.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mercury_compile_main.m:
compiler/mercury_compile_middle_passes.m:
compiler/mercury_compile_mlds_back_end.m:
compiler/ml_disj_gen.m:
compiler/ml_gen_info.m:
compiler/ml_lookup_switch.m:
compiler/ml_optimize.m:
compiler/ml_proc_gen.m:
compiler/ml_simplify_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/optimize.m:
compiler/pd_util.m:
compiler/peephole.m:
compiler/polymorphism.m:
compiler/proc_gen.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_scope.m:
compiler/simplify_info.m:
compiler/simplify_proc.m:
compiler/simplify_tasks.m:
compiler/stack_layout.m:
compiler/stack_opt.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/tag_switch.m:
compiler/tupling.m:
compiler/unify_gen_construct.m:
compiler/unneeded_code.m:
compiler/unused_args.m:
    Conform to the changes above, mostly by looking up optimization options
    in the opt_tuple. In some places, replace bools containing optimization
    options with the bespoke type of that specific optimization option.

library/getopt_template:
    Fix a bug that screwed up an error message.

    The bug happened when processing a --file option. If one of the
    options in the file was a special option whose special handler failed,
    the code handling that failing option returned both an error indication,
    and the rest of the argument list read in from the file. The code
    handling the --file option then *ignored* the error indication from
    the failed special option, and returned an error message of its own
    complaining about the unconsumed remaining arguments in the file,
    believing them to be non-option arguments, even though these arguments
    were never looked it to see if they were options.

    The fix is for the code handling --flag options to check whether
    the code processing the file contents found any errors, and if so,
    return that error *without* looking at the list of remaining arguments.

    In an unrelated change, factor out a duplicate call.
2020-09-28 18:16:13 +10:00
Julien Fischer
ca9d664391 Compute limits of integer tags for switches over all integer types.
This is a step towards getting smart indexing working for integer switches on
types other than 'int'.

compiler/switch_util.m:
    Extend the maybe_int_switch_info/0 type to represent tag limits for
    switches on all of the integer types.

    Generalise the code that computes those limits to handle all builtin
    integer types.

compiler/ml_switch_gen.m:
compiler/switch_gen.m:
    Conform to the above change.
2019-01-07 06:03:37 +00:00
Zoltan Somogyi
b66f45e4db Tighten the mlds_type type.
compiler/mlds.m:
    Make two changes to mlds_type.

    The simpler change is the deletion of the maybe(foreign_type_assertions)
    field from the MLDS representations of Mercury types. It was never used,
    because Mercury types that are defined in a foreign language that is
    acceptable for the current MLDS target platform are represented
    as mlds_foreign_type, not as mercury_type.

    The more involved change is to change the representation of builtin types.
    Until now, we had separate function symbols in mlds_type to represent
    ints, uints, floats and chars, but not strings or values of the sized
    types {int,uint}{8,16,32,64}; those had to be represented as Mercury types.
    This is an unnecessary inconsistency. It also had two allowed
    representations for ints, uints, floats and chars, which meant that
    some of the code handling those conceptual types had to be duplicated
    to handle both representations.

    This diff provides mlds_builtin_type_{int(_),float,string,char} function
    symbols to represent every builtin type, and changes mercury_type
    to mercury_nb_type to make clear that it is NOT to be used for builtins
    (the nb is short for "not builtin").

compiler/ml_code_util.m:
compiler/ml_util.m:
    Delete functions that used to construct MLDS representations of builtin
    types. The new representation of those types is so simple that using
    such functions is no less cumbersome than writing down the representations
    directly.

compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_global_data.m:
compiler/ml_lookup_switch.m:
compiler/ml_proc_gen.m:
compiler/ml_rename_classes.m:
compiler/ml_simplify_switch.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_util.m:
compiler/mlds_dump.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_c_export.m:
compiler/mlds_to_c_func.m:
compiler/mlds_to_c_global.m:
compiler/mlds_to_c_stmt.m:
compiler/mlds_to_c_type.m:
compiler/mlds_to_cs_data.m:
compiler/mlds_to_cs_stmt.m:
compiler/mlds_to_cs_type.m:
compiler/mlds_to_java_data.m:
compiler/mlds_to_java_stmt.m:
compiler/mlds_to_java_type.m:
compiler/mlds_to_java_wrap.m:
compiler/rtti_to_mlds.m:
    Conform to the changes above.
2018-09-28 23:07:23 +10:00
Zoltan Somogyi
6a915eef05 Optimize field updates inside packed arg words.
Since june, we have been copying words containing packed-together
sub-word-sized arguments all in one piece if possible, for hlc grades.
This means that given a type such as

:- type t
    --->    f1(int8, bool, int8, int, bool, int8, bool).

whose first three and last three arguments are packed into one word each,
and a predicate such as

    p(T0, T) :-
        T0 = f1(A, B, C, _, E, F, G),
        D = 42,
        T  = f1(A, B, C, D, E, F, G).

we generated code such as

    MR_Integer D_12 = (MR_Integer) 42;
    MR_Unsigned packed_args_0 =
        (MR_Unsigned) ((MR_hl_field(MR_mktag(0), T0_3, (MR_Integer) 0)));
    MR_Unsigned packed_args_1 =
        (MR_Unsigned) ((MR_hl_field(MR_mktag(0), T0_3, (MR_Integer) 2)));

    base = (MR_Word) MR_new_object(MR_Word,
        ((MR_Integer) 3 * sizeof(MR_Word)), NULL, NULL);
    *T_4 = base;
    MR_hl_field(MR_mktag(0), base, 0) = (MR_Box) (packed_args_0);
    MR_hl_field(MR_mktag(0), base, 1) = ((MR_Box) (D_12));
    MR_hl_field(MR_mktag(0), base, 2) = (MR_Box) (packed_args_1);

which does NOT pick up the values A, B, C, E, F and G individually.
However, until now, we could reuse packed-together words only in their
unchanged form.

This diff lifts that limitation, which means that now, we can *also*
optimize code such as

    p(T0, T) :-
        T0 = f1(A, B, _, D, E, _, G),
        C = 42i8,
        F = 43i8,
        T  = f1(A, B, C, D, E, F, G).

by generating code like this:

    base = (MR_Word) MR_new_object(MR_Word,
        (3 * sizeof(MR_Word)), NULL, NULL);
    *T_4 = base;
    MR_hl_field(MR_mktag(0), base, 0) = (MR_Box)
        ((((packed_word_0 & (~((MR_Unsigned) 255U)))) |
        (MR_Unsigned) ((uint8_t) (C_12))));
    MR_hl_field(MR_mktag(0), base, 1) = ((MR_Box) (D_8));
    MR_hl_field(MR_mktag(0), base, 2) = (MR_Box)
        ((((packed_word_1 & (~((MR_Unsigned) 510U)))) |
        (((MR_Unsigned) ((uint8_t) (F_13)) << 1))));

The general scheme when reusing *part* of a word is: first set the bits
not being reused to zero, and then OR in new values of those bits.

Make this optimization as general as possible by making it work
not just for

- words in memory cells containing only arguments,

but also for

- words in memory cells containing a remote sectag as well as arguments, and
- words in registers cells containing a ptag, a local sectag as well as
  arguments.

compiler/ml_gen_info.m:
    Generalize the data structure we use to represent information about
    packed words to make possible approximate as well as exact lookups.
    The key in the old map was "these bitfields with the values of these
    variables in them", while the key in the new map is just "these bitfields",
    with the associated value being a list, each element of which says
    "the word with these values in those bitfields is available in this rval".
    This makes it possible to look for matches words that have some, but not
    all, of the right values in the bitfields.

    Since the packed words may now contain tags as well as arguments,
    rename "packed args" to "packed word".

compiler/ml_unify_gen_deconstruct.m:
    When deconstructing a term containing packed words, add them to the
    packed word map even when one of the bitfields inside the packed word
    contains tag information.

    Move the code that adds a packed word to the map into a separate predicate,
    now that it is needed from more than one place.

compiler/ml_unify_gen_construct.m:
    Change the code that handles packed words to work in terms of filled
    bitfields. Use this not only to implement the optimization described
    at the top, but also to make the handling of bitfields more systematic.
    At least one previous bug was caused by doing sign extension differently
    for the bitfield containing the first packed argument in a word than for
    the later packed arguments in that word; with the new design, such
    inconsistencies should not happen.

compiler/ml_unify_gen_util.m:
    Add utility predicates now needed for both construct and deconstruct
    unifications.

compiler/mlds.m:
    Document the new use of lvnc_packed_word (renamed from lvnc_packed_args).

compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
    Conform to the changes above (mostly the packed_word rename).

compiler/mlds_to_c_data.m:
compiler/mlds_to_c_stmt.m:
    Omit unneeded casts from the output. Specifically, don't put (MR_Integer)
    casts in front of integer constants being used either as shift amounts,
    or as the number of words that a new_object MLDS operation should allocate.
    The casts only cluttered the output, making it harder to read, and
    therefore to judge its correctness.
2018-09-10 16:17:17 +10:00
Zoltan Somogyi
86f563a94d Pack subword-sized arguments next to a remote sectag.
compiler/du_type_layout.m:
    If the --allow-packing-remote-sectag option is set, then try to pack
    an initial subsequence of subword-sized arguments next to remote sectags.

    To allow the polymorphism transformation to put the type_infos and/or
    typeclass_infos it adds to a function symbol's argument list at the
    *front* of that argument list, pack arguments next to remote sectags
    only in function symbols that won't have any such extra arguments
    added to them.

    Do not write all new code for the new optimization; instead, generalize
    the code that already does a very similar job for packing args next to
    local sectags.

    Delete the code we used to have that picked the packed representation
    over the base unpacked representation only if it reduced the
    "rounded-to-even" number of words. A case could be made for its usefulness,
    but in the presence of the new optimization the extra code complexity
    it requires is not worth it (in my opinion).

    Extend the code that informs users about possible argument order
    rearrangements that yield better packing to take packing next to sectags
    into account.

compiler/hlds_data.m:
    Provide a representation for cons_tags that use the new optimization.
    Instead of adding a new cons_tag, we do this by replacing several old
    cons_tags that all represent pointers to memory cells with a single
    cons_tag named remote_args_tag with an argument that selects among
    the old cons_tags being replaced, and adding a new alternative inside
    this new type. The new alternative is remote_args_shared with a
    remote_sectag whose size is rsectag_subword(...).

    Instead of representing the value of the "data" field in classes
    on the Java and C# backends as a strange kind of secondary tag
    that is added to a memory cell by a class constructor instead of
    having to be explicitly added to the front of the argument vector
    by the code of a unification, represent it more directly as separate
    kind of remote_args_tag. Continuing to treat it as a sectag would have
    been very confusing to readers of the code of ml_unify_gen_*.m in the
    presence of the new optimization.

    Replacing several cons_tags that were usually treated similarly with
    one cons_tag simplifies many switches. Instead of an switch with that
    branches to the same switch arm for single_functor_tag, unshared_tag
    and shared_remote_tag, and then switches on these three tags again
    to get e.g. the primary tag of each, the new code of the switch arm
    is executed for just cons_tag value (remote_args_tag), and switches
    on the various kinds of remote args tags only when it needs to.
    In is also more natural to pass around the argument of remote_args_tag
    than to pass around a variable of type cons_tag that can be bound to only
    single_functor_tag, unshared_tag or shared_remote_tag.

    Add an XXX about possible further steps along these lines, such as
    making a new cons_tag named something like "user_const_tag" represent
    all user-visible constants.

compiler/unify_gen_construct.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_gen_test.m:
compiler/unify_gen_util.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
    Implement X = f(Yi) unifications where f uses the new representation,
    i.e. some of its arguments are stored next to a remote sectag.

    Some of the Yi are stored in a tagword (a word that also contains a tag,
    in this case the remote secondary tag), while some are stored in other
    words in a memory cell. This means that such unifications have similarities
    both to unifications involving arguments being packed next to local
    sectags, and to unifications involving ordinary arguments in memory cells.
    Therefore wherever possible, their implemenation uses suitably generalized
    versions of existing code that did those two jobs for two separate kinds of
    cons_tags.

    Making such generalizations possible in some cases required shifting the
    boundary between predicates, moving work from a caller to a callee
    or vice versa.

    In unify_gen_deconstruct.m, stop using uni_vals to represent *either* a var
    *or* a word in a memory cell. While this enabled us to factor out some
    common code, the predicate boundaries it lead to are unsuitable for the
    generalizations we now need.

    Consistently use unsigned ints to represent both the whole and the parts
    of words containing packed arguments (and maybe sectags), except when
    comparing ptag constants with the result of applying the "tag" unop
    to a word, (since that unop returns an int, at least for now).

    In a few cases, avoid the recomputation of some information that we
    already know. The motivation is not efficiency, since the recomputation
    we avoid is usually cheap, but the simplification of the code's correctness
    argument.

    Use more consistent terminology in things such as variable names.

    Note the possibility of further future improvements in several places.

compiler/ml_foreign_proc_gen.m:
    Delete a long unused predicate.

compiler/mlds.m:
    Add an XXX documenting a possible improvement.

compiler/rtti.m:
    Update the compiler's internal representation of RTTI data structures
    to make them able to describe secondary tags that are smaller than
    a full word.

compiler/rtti_out.m:
    Conform to the changes above, and delete a long-unused predicate.

compiler/type_ctor_info.m:
    Use the RTTI's du_hl_rep to represent cons_tags that distinguish
    between function symbols using a field in a class.

compiler/ml_type_gen.m:
    Provide a specialized form of a function for code in ml_unify_gen_*.m.
    Conform to the changes above.

compiler/add_special_pred.m:
compiler/bytecode_gen.m:
compiler/export.m:
compiler/hlds_code_util.m:
compiler/lco.m:
compiler/ml_closure_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/rtti_to_mlds.m:
compiler/switch_util.m:
compiler/tag_switch.m:
    Conform to the changes above.

runtime/mercury_type_info.h:
    Update the runtime's representation of RTTI data structures to make them
    able to describe remote secondary tags that are smaller than a full word.

runtime/mercury_deconstruct.[ch]:
runtime/mercury_deconstruct.h:
runtime/mercury_deconstruct_macros.h:
runtime/mercury_ml_expand_body.h:
runtime/mercury_ml_arg_body.h:
runtime/mercury_ml_deconstruct_body.h:
runtime/mercury_ml_functor_body.h:
    These modules collectively implement the predicates in deconstruct.m
    in the library, and provide access to its functionality to other C code,
    e.g. in the debugger. Update these to be able to handle terms with the
    new data representation optimization.

    This update requires a significant change in the distribution of work
    between these files for the predicates deconstruct.deconstruct and
    deconstruct.limited_deconstruct. We used to have mercury_ml_expand_body.h
    fill in the fields of their expand_info structures (whose types are
    defined in mercury_deconstruct.h) with pointers to three vectors:
    (a) a vector of arg_locns with one element per argument, with a NULL
    pointer being equivalent to a vector with a given element in every slot;
    (b) a vector of type_infos with one element per argument, constructed
    dynamically (and later freed) if necessary; and (c) a vector of argument
    words. Once upon a time, before double-word and sub-word arguments,
    vector (c) also had one word per argument, but that hasn't been true
    for a while; we added vector (a) help the consumers of the expand_info
    decode the difference. The consumers of this info  always used these
    vectors to build up a Mercury term containing a list of univs,
    with one univ for each argument.

    This structure could be stretched to handle function symbols that store
    *all* their arguments in a tagword next to a local sectag, but I found
    that stretching it to cover function symbols that have *some* of their
    arguments packed next to a remote sectag and *some other* of their
    arguments in a memory cell as usual would have required a well-nigh
    incomprehensibly complex, and therefore almost undebuggable, interface
    between mercury_ml_expand_body.h and the other files above. This diff
    therefore changes the interface to have mercury_ml_expand_body.h
    build the list of univs directly. This make its code relatively simple
    and self-contained, and it should be somewhat faster then the old code
    as well, since it never needs to allocate, fill in and then free
    vectors of type_infos (each such typeinfo now gets put into a univ
    as soon as it is constructed). The downside is that if we ever wanted
    to get all the arguments at once for a purpose other than constructing
    a list of univs from them, it would nevertheless require constructing
    that list of univs anyway as an intermediate data structure. I don't see
    this downside is significant, because (a) I don't think such a use case
    is very likely, and (b) even if one arises, debuggable but a bit slow
    is probably preferable to faster but very hard to debug.

    Reduce the level of indentation of some of these files to make the code
    easier to edit. Do this by

    - not adding an indent level from switch statements to their cases; and
    - not adding an indent level when a case in a switch has a local block.

    Move the break or return ending a case inside that case's block,
    if it has one.

runtime/mercury_deep_copy_body.h:
runtime/mercury_table_type_body.h:
    Update these to enable the copying or tabling of terms whose
    representations uses the new optimization.

    Use the techniques listed above to reduce the level of indentation
    make the code easier to edit.

runtime/mercury_tabling.c:
runtime/mercury_term_size.c:
    Conform to the changes above.

runtime/mercury_unify_compare_body.h:
    Make this code compile after the changes above. It does need to work
    correctly, since we only ever used this code to compare the speed
    of unify-by-rtti with the speed of unify-by-compiler-generated-code,
    and in real life, we always use the latter. (It hasn't been updated
    to work right with previous arg packing changes either.)

library/construct.m:
    Update to enable the code to construct terms whose representations
    uses the new optimization.

    Add some sanity checks.

library/private_builtin.m:
runtime/mercury_dotnet.cs.in:
java/runtime/Sectag_Locn.java:
    Update the list of possible sectag kinds.

library/store.m:
    Conform to the changes above.

trace/mercury_trace_vars.c:
    Conform to the changes above.

tests/hard_coded/deconstruct_arg.{m,exp,exp2}:
    Extend this test to test the deconstruction of terms whose
    representations uses the new optimization.

    Modify some of the existing terms being tested to make them more diverse,
    in order to make the output easier to navigate.

tests/hard_coded/construct_packed.{m,exp}:
    A new test case to test the construction of terms whose
    representations uses the new optimization.

tests/debugger/browse_packed.{m,exp}:
    A new test case to test access to the fields of terms whose
    representations uses the new optimization.

tests/tabling/test_packed.{m,exp}:
    A new test case to test the tabling of terms whose
    representations uses the new optimization.

tests/debugger/Mmakefile:
tests/hard_coded/Mmakefile:
tests/tabling/Mmakefile:
    Enable the new test cases.
2018-08-30 05:14:38 +10:00
Zoltan Somogyi
cb4454ac28 Extend local arg packing to single-ctor types.
compiler/du_type_layout.m:
    For the last three weeks, we have been packing subword-sized arguments
    next to a local sectag (if the relevant option was set). However, we
    did this only for types with two or more function symbols. This diff
    extends this optimization to apply also to types with only one function
    symbol, whose representation is decided by a separate piece of code.

    Factor out a piece of code to be usable from both of those pieces of code.

    Delete a sanity test. By not failing for the last three weeks,
    it has done its job.

compiler/hlds_data.m:
    Replace the shared_local_tag_with_args cons_tag added in that change
    about three weeks ago with the local_args_tag cons_tag, which is more
    general, in that it can indicate whether the function symbol is the only
    one in its type or not. (We need to know this when generating code
    for deconstruction unifications.)

compiler/bytecode_gen.m:
compiler/export.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
compiler/unify_gen_construct.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_gen_test.m:
    Conform to the changes above.
2018-07-28 06:40:03 +10:00
Zoltan Somogyi
5f7629e1db Harmonize unify_gen_test.m with its MLDS counterpart.
compiler/unify_gen_test.m:
compiler/ml_unify_gen_test.m:
    Harmonise the code of the predicates that test whether the top functor
    of the term referred to by a given variable is bound
    (a) to a given cons_id, for unifications, or
    (b) to one of a list of given cons_ids, for switch arms,
    between the backends, as much as possible.

    Give the predicates involved more meaningful names.

    Factor out some common code.

compiler/ml_switch_gen.m:
    The code for handling the "list of cons_ids" part was previously here.
    Delete it after moving it to ml_unify_gen_test.m.

compiler/ml_code_util.m:
    Factor out some common code, and note a relationship to
    ml_unify_gen_test.m.

compiler/unify_gen_deconstruct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/middle_rec.m:
compiler/switch_gen.m:
    Conform to the changes above.
2018-07-12 00:18:55 +02:00
Zoltan Somogyi
1fb59caa47 Split up ml_unify_gen.m.
compiler/ml_unify_gen_construct.m:
compiler/ml_unify_gen_deconstruct.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
    Carve these four modules out of ml_unify_gen.m. The first two handle
    the construction and deconstruction of terms, the third tests whether
    a variable is bound to a given cons_id, and the fourth contains utility
    types and predicates needed by more than one of the other modules.

compiler/ml_unify_gen.m:
    Remove the code moved to the modules above.

compiler/ml_backend.m:
compiler/notes/compiler_design.html:
    Add and document the new modules.

compiler/Mercury.options:
    Require the new modules to have consistency between the order of predicate
    declarations and the order of predicate definitions.

compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_top_gen.m:
    Conform to the change above.
2018-07-09 14:36:54 +02:00
Zoltan Somogyi
624aaa01f1 Pack subword-sized arguments next to a local sectag.
compiler/du_type_layout.m:
    If a new option is set, then try to represent function symbols with
    only subword-sized arguments by packing those arguments into the same word
    as the primary tag and (if it is needed) a secondary tag.

    If there are too many such function symbols for the available number of
    bits, pick the ones that need the least number of bits, in order to
    allow us to use this representation for as many such function symbols
    as possible.

    This diff implements this packing only for types that have more than one
    argument, because implementing it for types that have only one argument
    has two extra complications. One is the need for another new cons_id
    (see below), which would make this diff bigger and harder to review.
    The other is the need to consider interactions with the direct_arg
    optimization.

    Don't invoke the code for deciding the representation of arguments
    if either (a) the function symbol has no arguments, or (b) its cons_id
    alone dictates how we will treat its argument (in such cases, there is
    always exactly one).

    Fix a bug in computing the number of bits needed to distinguish N things.

    Store the value of the "experiment" option in the params for now,
    since it has helped track down bugs in this change, and may do the same
    for my next change. It costs next to nothing.

compiler/options.m:
    Add an option that controls whether we allow du_type_layout to pack
    arguments next to local secondary tags. The default value is "no",
    since "yes" may break binary compatibility.

    Add an option that controls whether we allow du_type_layout to pack
    arguments next to remote secondary tags. This option is not yet used.

compiler/hlds_data.m:
    Add a new cons_id, shared_local_tag_with_args, to represent function
    symbols in which the arguments are packed next to a local secondary tag.
    Rename the existing shared_local_tag cons_id as shared_local_tag_no_args,
    to clarify the distinction.

    Redesign the representation of secondary tags a bit, to meet the
    requirements I discovered while implementing the new data representation.

compiler/prog_data.m:
    Document the now-expanded uses of the arg_pos_width type.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:
    Implement unifications involving the new cons_id.

compiler/var_locn.m:
    Implement deconstruction unifications involving both right-to-left data
    flow and the new cons_id for the LLDS backend requires var_locn.m
    to implement a new kind of assignment to a variable: one that updates
    its old value. Add a predicate for this. (Previously, deconstructions
    with right-to-left flow could update the old value of a word in a
    memory cell, whose state var_locn.m does *not* track.)

compiler/code_loc_dep.m:
    Provide the interface between unify_gen. and var_locn.m.

compiler/code_info.m:
    Store the number of primary tag bits in the code_info, to save it looking
    up in the globals structure, since with its new code, unify_gen.m needs it
    more often now.

compiler/hlds_out_module.m:
doc/user_guide.texi:
    Implement the capability of restricting the dump of the type table
    to only the types defined in the module being compiled. Without this,
    the type table is cluttered with information about types in other
    modules, including the automatically-included builtin modules.

compiler/handle_options.m:
    Add a new value of the -D option. The new value, du, asks for the
    dumping out of the representations of only the locally defined types.

compiler/ml_gen_info.m:
    Store the number of primary tag bits as a uint8, not as int.

compiler/ml_tag_switch.m:
compiler/switch_util.m:
compiler/tag_switch.m:
    Update the code that generates switches on du types to handle
    local secondary tags that must be masked off before use.

compiler/rtti.m:
    Update the compiler's representation of RTTI information to account for
    the new data representation.

compiler/type_ctor_info.m:
    Construct the updated RTTI representation.

compiler/bytecode_gen.m:
compiler/export.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/modecheck_goal.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
    Conform for the changes above.

runtime/mercury_type_info.h:
    Extend the representation of du functors in the RTTI to account for
    the new data representation scheme. The extensions add only to the
    *ends* of structures, or to lists of enum values, with the extensions
    only being used if the representation is actually used, which should
    allow the updated runtime to also work with .c files that were compiled
    with a compiler that does *not* have this diff. For the same reason,
    make the old enum value MR_SECTAG_LOCAL a synonym for the new
    MR_SECTAG_LOCAL_REST_OF_WORD, which expresses a distinction that
    did not previously exist.

    Delete a reference to a file that no longer exists.

runtime/mercury_dotnet.cs.in:
library/rtti_implementation.m:
    Update the C# and Mercury mirrors of the types updated in
    mercury_type_info.h.

runtime/mercury_deconstruct.c:
runtime/mercury_deconstruct_macros.h:
runtime/mercury_ml_expand_body.h:
    Implement the deconstruction of terms using the new data representation.

runtime/mercury_deep_copy_body.h:
    Implement the copying of terms using the new data representation.

runtime/mercury_table_type_body.h:
    Implement the tabling of terms using the new data representation.

runtime/mercury_term_size.c:
    Implement computing the size of terms using the new data representation.

runtime/mercury_unify_compare_body.h:
    Implement RTTI-based unifications of terms using the new data
    representation. (Or at least make a first attempt at this implementation.
    We never use RTTI-based unification, so this code has not been tested,
    but it is not clear that it *needs* to be tested.)

library/construct.m:
    Implement the construction of terms using the new data representation.

library/private_builtin.m:
    List MR_SECTAG_LOCAL_REST_OF_WORD as a synonym of MR_SECTAG_LOCAL for Java,
    since rtti_to_mlds.m will now emit the new version.

    Note that the new data representation is not applicable to Java (or C#),
    so it should never see the other kind of sectag (MR_SECTAG_LOCAL_BITS).

tests/hard_coded/sectag_bits.{m,exp}:
tests/hard_coded/sectag_bits_test_data:
    A new test case to test the reading in and writing out (and therefore
    the construction and deconstruction) of terms containing arguments
    packed with a local sectag.

tests/hard_coded/Mmakefile:
    Enable the new test case.
2018-07-08 17:54:11 +02:00
Zoltan Somogyi
b06b2621b3 Move towards packing args with secondary tags.
compiler/hlds_data.m:
    Add bespoke types to record information about local and remote secondary
    tags. The one for local secondary tags includes the value of the
    primary and secondary tag together, since construct unifications
    need to assign this value, and it is better to compute this once,
    instead leaving the target language compiler to do it, potentially
    many times.

    Use a wrapped uint8 to record primary tag values, and wrapped uints
    to record secondary tag values. The wrap is to prevent any accidental
    confusion with other values. The use of uint8 and uint has two purposes.
    First, using the tighest possible representation. Tags are never negative,
    and primary tags cannot exceed 7. Second, using these types in the compiler
    help us eat our own dogfood; if a change causes a problem affecting
    these types, its bootcheck should fail, alerting us to the problem.

    Add commented-out types and fields that will be needed for packing
    sub-word-sized arguments together with both local and remote secondary
    tags.

compiler/du_type_layout.m:
    Generate references to tags in the new format.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:

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

    Fix an old bug: the inst corresponding to a constant with a primary
    and a local secondary tag is not the secondary tag alone, but both tags
    together.

compiler/bytecode.m:
compiler/bytecode_gen.m:
compiler/closure_gen.m:
compiler/disj_gen.m:
compiler/export.m:
compiler/hlds_code_util.m:
compiler/jumpopt.m:
compiler/lco.m:
compiler/llds_out_data.m:
compiler/llds_out_instr.m:
compiler/lookup_switch.m:
compiler/lookup_util.m:
compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_util.m:
compiler/ml_elim_nested.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_type_gen.m:
compiler/mlds_dump.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_c_stmt.m:
compiler/opt_debug.m:
compiler/peephole.m:
compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
compiler/string_switch.m:
compiler/switch_util.m:
compiler/tag_switch.m:
compiler/type_ctor_info.m:
    Conform to the change to hlds_data.m.

    In two places, in rtti_out.m and rtti_to_mlds.m, delete old code
    that was needed only to implement reserved tags, which we have
    stopped supporting a few months ago.

library/uint8.m:
library/uint16.m:
library/uint32.m:
library/uint64.m:
    Add predicates to cast from each of these types to uint.
2018-06-06 03:35:20 +02:00
Zoltan Somogyi
bbe0f28f3b Copy packed arguments all at once.
Copy words containing packed-together sub-word-sized arguments all
in one piece if possible, for hlc grades.

Given a type such as

:- type t
    --->    f1(int8, bool, int8, int, bool, int8, bool).

whose first three and last three arguments are packed into one word each,
and a predicate such as

p(T0, T) :-
    T0 = f1(A, B, C, _, E, F, G),
    D = 42,
    T  = f1(A, B, C, D, E, F, G).

we used to generate code that picked up each of the six named arguments
from T0, and used them to construct T. With this diff, we now translate
the above to

    MR_Integer D_12 = (MR_Integer) 42;
    MR_Unsigned packed_args_0 =
        (MR_Unsigned) ((MR_hl_field(MR_mktag(0), T0_3, (MR_Integer) 0)));
    MR_Unsigned packed_args_1 =
        (MR_Unsigned) ((MR_hl_field(MR_mktag(0), T0_3, (MR_Integer) 2)));

    base = (MR_Word) MR_new_object(MR_Word,
        ((MR_Integer) 3 * sizeof(MR_Word)), NULL, NULL);
    *T_4 = base;
    MR_hl_field(MR_mktag(0), base, 0) = (MR_Box) (packed_args_0);
    MR_hl_field(MR_mktag(0), base, 1) = ((MR_Box) (D_12));
    MR_hl_field(MR_mktag(0), base, 2) = (MR_Box) (packed_args_1);

compiler/ml_unify_gen.m:
    Implement the two main parts of this optimization.

    Part one is the change to deconstruction unifications. When we generate
    assignments from all the fields packed together into a word to their
    corresponding argument variables (such as A/B/C or E/F/G above),
    create a fresh variable (such as packed_args_0 above), assign to it
    the value of the whole word, and record in a new data structure (the
    packed_args_map) that these argument variables, in these positions
    within the word, are now available in the newly created variable.
    (We still define the argument variables as well, since they may be needed;
    deleting them if they are *not* needed is the job of ml_unused_assign.m.)

    Part two is the change to construction unifications. When we generate code
    to OR together the shifted and/or masked values of two or more variables
    to fill in one word in a new heap cell, we search the packed_args_map
    to see whether those variables, in the positions we need, are available
    in one of the variables created in part one. If yes, we discard
    the whole OR-ing together operation and we use that variable instead.

    Since part one can now create local variable definitions, return these
    upwards as needed.

compiler/ml_gen_info.m:
    Add two fields to the ml_gen_info structure (actually, to one of its
    substructures). One is the packed_args_map described above, the other
    is a counter we use to give a unique name to all the fresh variables.

    When creating ml_gen_infos, put the code defining each field of a
    substructure next to the creation of that substructure.

compiler/mlds.m:
    Add a kind of compiler-generated variable holding packed argument words.
    It is used in part one above.

compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
    Save, reset and restore the packed_args_map as necessary to ensure that
    a construction unification sees an entry in that map only if the
    deconstruction unification that created that entry *had* to be executed
    before execution reaches the construction unification.

    This means that when we process a branched control structure, we have to
    make sure that (a) entries created by one branch are not seen when
    we generate code for the other branches, and (b) that code *after* the
    branched control structure sees only the entries created *before* the
    branched control structure, since such code following cannot use an entry
    that was created by a branch that may or may NOT have been executed
    on the way there.

    We also reset the packed_args_map to empty when generating code
    that will end up inside a nested function, for two reasons. First,
    I am not sure whether the code in ml_elim_nested.m that flattens out
    nested functions is general enough to handle the new kind of compiler
    generated variable correctly. And second, even if it is, the additional
    memory traffic for putting those variables into environments, and later
    pulling them out again, would definitely reduce and maybe completely
    eliminate the speedup from optimizing constructions.

compiler/ml_closure_gen.m:
    Conform to the change in ml_unify_gen.m.

compiler/ml_proc_gen.m:
    Invoke ml_unused_assign.m in both branches of an if-then-else.
    Previously, it was invoked in only the rarely executed branch,
    which is what hid its bugs.

    Fix one bug: for model_semi procedures, include the succeeded variable
    in the set of variables whose values is needed after the generated
    function body.

    Work around another bug: the ml_unused_assign.m cannot yet handle
    nested functions properly, so throw away its output in their presence.

compiler/ml_unused_assign.m:
    As part of the same workaround, if a block contains nested functions,
    tell ml_proc_gen.m to use the original code.

    Fix several other bugs.

    Don't delete variables from the seen_set when the backwards traversal
    finds an assignment to them, because the variable's absence from
    the seen_set would lead to the declaration of the variable being deleted.

    Delete a sanity check that made sense only the presence of such deletions.

    Never delete assignments to compiler-generated variables; we generate
    such assignments only when their results *will* be needed.

    When exiting the traversal of a block, *do* delete the variables
    declared locally in that block from the seen_set; being undeclared there,
    they cannot possibly be seen before that block. leaving them in
    does not compromise correctness, but does reduce performance
    by making operations on the seen_set slower than necessary.

    If deleting unused assignments makes the else part of an if-then-else
    empty, then delete the whole else part.

compiler/mlds_to_c_stmt.m:
    Generate a valid C statement even for an MLDS comment. When an buggy
    version of ml_unused_assign.m (incorrectly) deleted assignments to
    succeeded, it sometimes left an else part containing only a comment,
    which lead gcc to report syntax errors.
2018-06-02 18:56:40 +02:00
Zoltan Somogyi
fc903a0911 Eliminate the double storage of types in the MLDS.
compiler/mlds.m:
    When we record a Mercury type in the MLDS, we used to record with it
    not just its type category (which some aux predicates need), but also
    the name by which it is known to the target language compiler, if the
    type is defined in that foreign language. Unfortunaly, the data structure
    we used to represent the name of the foreign type (and any assertions
    on it) also stored a duplicate copy of the Mercury type in the usual
    case where the Mercury type was *not* defined in the foreign language.
    Having two copies of the same information was dangerous, due to the
    possibility of inconsistency between them. It was also unnecessary work
    for the compiler passes that had to create the duplicate copies.

    Eliminate these problems by always storing *one* copy of the Mercury type.

    Store the Mercury and foreign type information next to each other.

compiler/foreign.m:
    Make the above possible by deleting up the old exported_type type,
    which contained the duplicate copy of the Mercury type in usual case
    of a type that is not defined by foreign code, and replacing it
    with a type that contains information about just a foreign type.

    In the argument lists of the predicates and functions of this module,
    replace arguments that used to be type exported_type with a pair
    of the Mercury type and a maybe of the new type, which is yes(...)
    iff the Mercury type *is* defined in foreign code.

    Give some predicates and functions more meaningful names.

    Make specialized versions of these functions available (specialized
    e.g. to a target language) where these would be useful.

    Delete the auxiliary predicates that aren't needed with the
    new data structure design.

compiler/export.m:
compiler/ml_accurate_gc.m:
compiler/ml_code_util.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_global_data.m:
compiler/ml_simplify_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_unify_gen.m:
compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/rtti_to_mlds.m:
    Conform to the changes above.
2018-05-08 00:17:34 +02:00
Zoltan Somogyi
860f54cafd Make offset tracking work for C# (and Java).
My recent diff adding position information to the representation of constructor
arguments assumed that the remote secondary tag, if any, was always added
to the start of the memory cell by the compiler module handling unifications.
However, for the C# and Java grades, secondary tags are in fact added
by a class constructor, so the offsets of the arguments of such cells
were off by one, leading to an assertion failure in the compiler.

compiler/hlds_data.m:
    Fix the above problem by recording with each remote secondary tag
    whether it is added by the unify code or by the constructor.

compiler/du_type_layout.m:
    Set the new field in remote secondary tags.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:
    Use the new field to decide whether a remote secondary tag counts
    as occupying the first word of its memory cell.

compiler/bytecode_gen.m:
compiler/export.m:
compiler/lco.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
    Conform to the change in hlds_data.m.
2018-05-06 23:43:15 +02:00
Zoltan Somogyi
24b98fdafe Pack sub-word-sized ints and dummies in terms.
Previously, the only situation in which we could pack two or more arguments
of a term into a single word was when all those arguments are enums. This diff
changes that, so that the arguments can also be sub-word-sized integers
(signed or unsigned), or values of dummy types (which occupy zero bits).

This diff also records, for each argument of a function symbol, not just
whether, and if yes, how it is packed into a word, but also at *what offset*
that word is in the term's heap cell. It is more economical to compute this
once, when the representation of the type is being decided, than to compute
it over and over again when terms with that function symbol are being
constructed or deconstructed. However, for a transition period, we compute
these offsets at *both* times, to check the consistency of the new algorithm
for computing offsets that is run at "decide representation time" with
the old algorithms run at "generate code for a unification time".

compiler/du_type_layout.m:
    Make the changes described above: pack sub-word-sized integers and
    dummy values into argument words, if possible, and if the relevant
    new option allows it. These options are temporary. If we find no problems
    with the new packing algorithm in a few weeks, we should be able to
    delete them.

    Allow 64 bit ints and uints to be stored in unboxed in two words
    on 32 bit platforms, if the relevant new option allows it. Support
    for this is not yet complete, but it makes sense to implement the
    RTTI changes for both this change and one described in the above
    paragraph together.

    For each packed argument, record not just its width, its shift and
    the mask, but also the number of bits the argument takes. Previously,
    we computed this on demand from the mask, but there is no real need
    for that when simply storing this info is so cheap.

    For all arguments, packed or not, record its offset, relative to both
    the start of the arguments, and the start of the memory cell. (The two
    are different if the arguments are preceded by either a remote secondary
    tag, the typeinfos and/or typeclass_infos describing some existentially
    typed arguments, or both.) The reason for this is given at the top.

    Centralize the decision of the parameters of packing in one predicate.

    If the option --inform-suboptimal-packing is given, print an informational
    message whenever the code deciding type representations finds that
    reordering the arguments of a function symbol would allow it to pack
    the arguments of that function symbol into less space.

compiler/options.m:
    Add the option --allow-packing-ints which controls whether
    du_type_layout.m will attempt to pack {int,uint}{8,16,32} arguments
    alongside enum arguments.

    Add the option --allow-packing-dummies which controls whether
    du_type_layout.m will optimize away (in other words, represent in 0 bits)
    arguments of dummy types.

    Add the option --allow-double-word-ints which controls whether
    du_type_layout.m will store arguments of the types int64 and uint64
    unboxed in two words on 32 bit platforms, the way it currently stores
    double precision floats.

    All three those options are off by default, which preserves binary
    compatibility with existing code. However, the first two are ready
    to be switched on (the third is not).

    All three options are intended to be present in the compiler
    only until these changes are tested. Once we deem them sufficiently
    tested, I will modify the compiler to always do the packing they control,
    at which point we can delete these options. This is why they are not
    documented.

    Add the option --inform-suboptimal-packing, whose meaning is described
    above.

doc/user_guide.texi:
    Document --inform-suboptimal-packing.

compiler/prog_data.m:
    For each argument of a function symbol in a type definition, use
    a new type called arg_pos_width to record the extra information
    mentioned above in (offsets for all arguments, and number of bits
    for packed arguments).

    For each function symbol that has some existential type constraints,
    record the extra information mentioned for parse_type_defn.m below.

compiler/hlds_data.m:
    Include the position, as well as the width, in the representation
    of the arguments of function symbols.

    Previously, we used the integer 0 as a tag for dummies. Add a tag to
    represent dummy values, since this gives more information to any code
    that sees that tag.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:
    Handle the packing of dummy values, and of sub-word-sized ints and uints.

    Compare the cell offset of each argument computed using existing
    algorithms here with the cell offset recorded in the argument's
    representation, and abort if they are different.

    In some cases, restructure code a bit to make it possible.
    For example, for tuples and closures, this means that instead of
    simply recording that each tuple argument or closure element
    is a full word, we must record its correct offset as well.

    Handle the new dummy_tag.

    Add prelim (not yet finished) support for double-word int64s/uint64s
    on 32 bit platforms.

    When packing the values of two or more variables (or constants) into a
    single word in a memory cell, optimize away operations that are no-ops,
    such as shifting anything by zero bits, shifting the constant zero
    by any number of bits, and ORing anything with zero. This makes the
    generated code easier to read. It is probably also faster for us
    to do it here than to write out a bigger expression, have the C compiler
    read in the bigger expression, and then later make the same optimization.

    In ml_unify_gen.m, avoid the unnecessary use of a list of the argument
    variables' types separate from the list of the argument variables
    themselves; just look up the type of each argument variable when it is
    processed.

compiler/add_special_pred.m:
    When creating special (unify and compare) predicates for tuples,
    include the offsets in the representation of their arguments.

    Delete an unused predicate.

compiler/llds.m:
    Add a new way to create an rval: a cast. We use it to implement
    the extraction of signed sub-word-sized integers from packed argument
    words in terms. Masking the right N bits out of the packed word
    leaves the other 32-N or 64-N bits as zeroes; a cast to int8_t,
    int16_t or int32_t will copy the sign bit to these bits.
    Likewise, when we pack signed int{8,16,32} values into words,
    we cast them to their unsigned versions to throw away any sign-extension
    bits in their original word-sized representations.

    No similar change is needed for the MLDS, since that already had
    a mechanism for casts.

compiler/mlds.m:
    Note a potential simplification in the MLDS.

compiler/builtin_lib_types.m:
    Add functions to return the Mercury representation of the int64
    and uint64 types.

compiler/foreign.m:
    Export a specialized version of an existing predicate, to allow
    ml_unify_gen.m to avoid the costs of the more general version.

compiler/hlds_out_module.m:
    Always print the representations of all arguments, since the
    inclusion of position information in those representation means that
    the representations of even all-full-word-argument terms are of potential
    interest when debugging term representations.

compiler/lco.m:
    Do not try to apply LCO to arguments of dummy types. (We could optimize
    them differently, by filling them in before they are "computed", but
    that is a separate optimization, which is of *very* low priority.)

compiler/liveness.m:
    Do not include variables of dummy types in resume points.

    The reason for this is that the code that establishes a resume point
    returns, for each such variable, a list of *lvals* where that variable
    can be found. The new code in unify_gen.m will optimize away assignments
    to values of dummy types, so there is *no* lval where they can be found.
    We could allocate one, but doing so would be a pessimization. Instead,
    we simply don't save and restore such values. When their value (which is
    always 0) is needed, we can create them out of thin air.

compiler/ml_global_data.m:
    Include the target language in the ml_global_data structure, to prevent
    some of its users having to look it up in the module_info.

    Add notes about the specializing the implementation of arrays of
    int64s/uint64s on 32 bit platforms.

compiler/check_typeclass.m:
compiler/ml_type_gen.m:
    Add sanity checks of the new precomputed fields of exist_constraints.

    Conform to the changes above.

compiler/mlds_to_c.m:
    Add prelim (not yet finished) support for double-word int64s/uint64s
    on 32 bit platforms.

    Add notes about possible optimizations.

compiler/parse_type_defn.m:
    When a function symbol in a type definition contains existential
    arguments, precompute and store the set of constrained and unconstrained
    type variables. The code in du_type_layout.m needs this information
    to compute the number of slots occupied by typeinfos and typeclass_infos
    in memory cells for this function symbol, and several other places
    in the compiler do too. It is easier and faster to compute this
    information just once, and this is the earliest time what that can be done.

compiler/type_ctor_info.m:
    Use the prerecorded information about existential types to simplify
    the code here

compiler/polymorphism.m:
    Add an XXX about possibly using the extra info we now record in
    exist_constraints to simplify the job of polymorphism.m.

compiler/pragma_c_gen.m:
compiler/var_locn.m:
    Create the values of dummy variables from scratch, if needed.

compiler/rtti.m:
    Replace a bool with a bespoke type.

compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
    When generating RTTI information for the LLDS and MLDS backends
    respectively, record new kinds of arguments as needing special
    treatment. These are int64s and uint64s stored unboxed in two words
    on 32 bit platforms, {int,uint}{8,16,32} values packed into words,
    and dummy arguments. Each of these has a special code: its own negative
    negative value in the num_bits field of the argument.

    Generate slightly better formatted output.

compiler/type_util.m:
    Delete a predicate that isn't needed anymore.

compiler/opt_util.m:
    Delete a function that hasn't been needed for a while.

    Conform to the changes above.

compiler/arg_pack.m:
compiler/bytecode_gen.m:
compiler/call_gen.m:
compiler/code_util.m:
compiler/ctgc.selector.m:
compiler/dupelim.m:
compiler/dupproc.m:
compiler/equiv_type.m:
compiler/equiv_type_hlds.m:
compiler/erl_code_gen.m:
compiler/erl_rtti.m:
compiler/export.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_out_data.m:
compiler/middle_rec.m:
compiler/ml_closure_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_top_gen.m:
compiler/module_qual.qualify_items.m:
compiler/opt_debug.m:
compiler/parse_tree_out.m:
compiler/peephole.m:
compiler/recompilation.usage.m:
compiler/resolve_unify_functor.m:
compiler/stack_layout.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/switch_util.m:
compiler/typecheck.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
    Conform to the changes above.

compiler/llds_out_util.m:
    Add a comment.

compiler/ml_code_util.m:
    Factor out some common code.

runtime/mercury_type_info.h:
    Allocate special values of the MR_arg_bits field of the MR_DuArgLocn type
    to designate arguments as two word int64/uint64s, as sub-word-sized
    arguments of types {int,uint}{8,16,32}, or as arguments of dummy types.
    (We already had a special value for two word float arguments.)

    Document the list of places that know about this code, so that they
    can be updated if and when it changes.

library/construct.m:
    Handle the construction of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

    Factor out the code common to the sectag-present and sectag-absent cases,
    to make it possible to do the above in just *one* place.

library/store.m:
    Add an XXX to a place that I don't think handles two word arguments
    correctly. (I think this is an old bug.)

runtime/mercury_deconstruct.c:
    Handle the deconstruction of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

runtime/mercury_deep_copy_body.h:
    Handle the copying of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

    Give a macro a more descriptive name.

runtime/mercury_type_info.c:
    Handle taking the size of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

runtime/mercury.h:
    Put related definitions next to each other.

runtime/mercury_deconstruct.h:
runtime/mercury_ml_expand_body.h:
    Fix indentation.

tests/hard_coded/construct_test.{m,exp}:
    Add to this test case a test of the construction, via the library's
    construct.m module, of terms containing packed sub-word-sized integers,
    and packed dummies.

tests/hard_coded/deconstruct_arg.{m,exp}:
    Convert the source code of this test case to state variable notation,
    and update the line number references (in the names of predicates created
    from lambda expressions) accordingly.

tests/hard_coded/uint64_ground_term.{m,exp}:
    A new test case to check that uint64 values too large to be int64 values
    can be stored in static structures.

tests/hard_coded/Mmakefile:
    Enable the new test case.
2018-05-05 13:22:19 +02:00
Julien Fischer
63572bc9a8 Fix bug #449 - switches on 64-bit integers in the Java grade.
Switches on 64-bit integers in the Java grade are causing us to generate
invalid Java code because Java's switch statement does not work with 64-bit
integers.  (This limitation is apparently built into the JVM.)

Fix this for now by generating if-then-else chains for switches on 64-bit
integers.   We can almost certainly do better, but that is future work.

compiler/switch_util.m:
    Add a separate switch category for switches on 64-bit integer types.

compiler/switch_gen.m:
    For the low-level C backend, treat switches on 64-bit integers as
    other switches on atomic types.

compiler/ml_target_util.m:
    Add a function that returns whether the target language supports
    switching on 64-bit integers.   Add another that allows us to
    test whether switches on a given integer type are supported by
    a given target language.

compiler/ml_switch_gen.m:
compiler/ml_simplify_switch.m:
    Use the above functions to only generate switches on 64-bit integers
    as target language switches if the target language supports switches
    on 64-bit integers (C# and C do; Java does not).
2018-02-12 20:52:34 -05:00
Zoltan Somogyi
4b98f58d9d Don't use reserved addresses to represent functors.
Late last year, we agreed to delete the ability to use the addresses
of reserved objects as cons_tags. After another (very short) discussion
on m-dev, this diff also deletes the ability to use small integers
(including zero) acting as pointers.

compiler/options.m:
    Delete the --num-reserved-addresses option.

    Add a synomym for --compiler-sufficiently-recent, with the intention
    that support for the representation of reserved addresses in RTTI
    code in the runtime will be deleted when all installed compilers
    have this new synonym.

compiler/hlds_data.m:
    Delete any mention of the reserved addresses from the cons_tag type,
    since we don't have reserved addresses anymore.

    Don't record for each type whether it uses reserved addresses;
    no type can do so anymore.

compiler/rtti.m:
    Delete the part of the RTTI representation that dealt with reserved
    addresses.

compiler/add_foreign_enum.m:
compiler/add_special_pred.m:
compiler/bytecode_gen.m:
compiler/code_info.m:
compiler/du_type_layout.m:
compiler/equiv_type_hlds.m:
compiler/erl_rtti.m:
compiler/export.m:
compiler/hlds_out_module.m:
compiler/intermod.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/opt_debug.m:
compiler/prog_data.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/unify_gen.m:
    Conform to the changes above, mostly by deleting code that used to deal
    with reserved addresses.
2018-02-06 16:03:44 +11:00
Zoltan Somogyi
1c01ed85eb Fix lines. 2017-07-29 14:15:15 +02:00
Zoltan Somogyi
11c232f060 Store different kinds of definitions in blocks separately.
An ml_stmt_block contains some definitions and some statements.
The definitions were traditionally stored in a single list of mlds_defns,
but lots of code knew that some kinds of mlds_defns just couldn't occur
in blocks. This diff, by storing the definitions of (a) local variables
and (b) continuation functions in separate field in ml_stmt_blocks,
gets the type system to enforce the invariant that other kinds of definitions
can't occur in blocks.

This also allows the compiler to do less work, since definitions
don't have to wrapped and then later unwrapped, and code that wants to look
at only e.g. the function definitions in a block don't have to traverse
the definitions of local variables (of which there are many more).

compiler/mlds.m:
    Make the change described above.

compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_elim_nested.m:
compiler/ml_lookup_switch.m:
compiler/ml_optimize.m:
compiler/ml_proc_gen.m:
compiler/ml_simplify_switch.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tailcall.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/mlds_to_target_util.m:
    Conform to the change above. This allows us to avoid lots of wrapping
    up definitions.

    In some cases, after this change, we don't need to process mlds_defns
    *in general*, which leaves the predicates that used to do that,
    and some of the predicates that they used to call, unused. Delete these.

    In code that generated MLDS code, consistently use names containing
    the word "Defn", instead of "Decl", for variables that contain
    mlds_local_var_defns or mlds_function_defns. Some such predicates
    generate lists of both local var definition and function definitions,
    but most generate only one, and some generate neither.
2017-07-26 00:57:13 +02:00
Julien Fischer
7c42aa1aa2 Use a separate type to describe integer tags.
compiler/hlds_data.m
     Use a separate type to describe integer tags and parameterise
     the int_tag functor of the cons_tag/0 type by that new type.

compiler/bytecode_gen.m:
compiler/dense_switch.m:
compiler/du_type_layout.m:
compiler/export.m:
compiler/hlds_code_util.m:
compiler/make_tags.m:
compiler/ml_type_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_unify_gen.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
compiler/unify_gen.m:
     Conform to the above change.

compiler/ml_code_util.m:
    Add a utility function for use by the above.
2017-07-23 12:05:57 +10:00
Zoltan Somogyi
47f1df4a0a Split mlds_data_defn into three separate types.
We used to use mlds_data_defns to represent three related but nevertheless
distinct kinds of entities: global variables, local variables, and fields
in classes. This diff replaces the mlds_data_defn type with three separate
types: mlds_global_var_defn, mlds_local_var_defn and mlds_field_var_defn
respectively, with corresponding changes to related types, such as
mlds_data_name.

The global variables are completely separate from the other two kinds.
Local and field variables are *mostly* separate from each other, but they
are related in one way. When we flatten out nested functions, the child
nested function can no longer access its parent function's local variables,
so we pass those variables to it as fields of an environment structure.
This requires turning local variables to fields of that structure,
and the code in the flattened previously-nested function that accesses
those fields naturally wants to treat them as if they were local variables
(as indeed they sort-of were before the flattening). There are therefore
ways to convert each of local and fields vars into the other.

This restructuring makes clear several invariants of the MLDS we generate
that were previously hidden. For example, variables with certain kinds of
names (in the before-this-diff, general version of the mlds_var_name type)
could appear only as function arguments or as locals in ml_stmt_blocks,
not in ml_global_data, while for some other names the opposite was the case.
And in several cases, functions used to take a general mlds_data_defn
as argument but aborted if given the "wrong kind" of mlds_data_defn.

This diff also makes possible further simplifications. For example,
local vars should not need some flags (since e.g. they are never per-instance),
and should never need either module or type qualification, while global
variables (which are also never per-instance) should never need type
qualification (since they are not fields of a type). The definitions
in blocks should consist of local variables and (before flattening) functions,
not global variables, field variables or classes, while the members in classes
should be only field variables and functions (and maybe classes), not
global or local variables. Those changes will be in future diffs;
this is already large enough.

compiler/mlds.m:
    Make the changes described above.

    Use tighter types where possible.

    Use (a generalized version) of the mlconst_named_const functor
    to represent values of enum types defined in the runtimes
    of the target platforms.

compiler/ml_global_data.m:
    Store *only* global variables in fields that previously stored general
    mlds_datas (that by design were always global).

    Store *only* closure wrapper functions in the previous non-flat-defns
    field. Before this diff, the code generator only put closure wrapper
    functions in this field, but then ml_elim_nested.m put everything
    resulting from the expansion of those functions back into those fields
    as well, some of which were not functions. It now puts those non-function
    things into the MLDS data structure directly.

compiler/ml_code_util.m:
compiler/ml_util.m:
    Conform to the changes above.

    Use tighter types where possible. If appropriate, change the name
    of the function or predicate accordingly.

    Represent references to enum constants defined in the runtime of the
    target language as named constants (since they is what they are),
    instead of representing them as MLDS "variables", which required
    the code of mlds_to_cs.m had to special-case the treatment
    of those "variables".

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

    Use tighter types where possible.

    Don't put the environment types resulting from flattening nested scopes
    back into the non-flat-defns slot of the ml_elim_info; instead, return
    them separately to code that puts them directly in the MLDS.

compiler/rtti.m:
    When returning the names of enum constants in the C runtime, return also
    the prefixes that you need to place in front of these to obtain their names
    in the Java and C# runtimes.

compiler/mercury_compile_mlds_back_end.m:
compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_gen_info.m:
compiler/ml_lookup_switch.m:
compiler/ml_optimize.m:
compiler/ml_proc_gen.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tailcall.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/mlds_to_target_util.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
    Conform to the changes above.

    Move a utility function from ml_util.m to mlds_to_target_util.m,
    since it is used only in mlds_to_*.m.
2017-07-22 00:20:40 +02:00
Julien Fischer
8a240ba3f0 Add builtin 8, 16 and 32 bit integer types -- Part 1.
Add the new builtin types: int8, uint8, int16, uint16, int32 and uint32.
Support for these new types will need to be bootstrapped over several changes.
This is the first such change and does the following:

- Extends the compiler to recognise 'int8', 'uint8', 'int16', 'uint16', 'int32'
  and 'uint32' as builtin types.
- Extends the set of builtin arithmetic, bitwise and relational operators to
  cover the new types.
- Extends all of the code generators to handle new types.  There currently lots
  of limitations and placeholders marked by 'XXX FIXED SIZE INT'.  These will
  be lifted in later changes.
- Extends the runtimes to support the new types.
- Adds new modules to the standard library intended to hold the basic
  operations on the new types.  (These are currently empty and not documented.)

This change does not introduce the two 64-bit types, 'int64' and 'uint64'.
Their implementation is more complicated and is best left to a separate change.

compiler/prog_type.m:
compiler/prog_data.m:
compiler/builtin_lib_types.m:
    Recognise int8, uint8, int16, uint16, int32 and uint32 as builtin types.

    Add new type, int_type/0,that enumerates all the possible integer types.

    Extend the cons_id/0 type to cover the new types.

compiler/builtin_ops.m:
    Parameterize the integer operations in the unary_op/0 and binary_op/0
    types by the new int_type/0 type.

    Add builtin operations for all the new types.

compiler/hlds_data.m:
    Add new tag types for the new types.

compiler/hlds_pred.m:
    Parameterize integers in the table_trie_step/0 type.

compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/export.m:
compiler/foreign.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/hlds_out_util.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/mercury_to_mercury.m:
compiler/mode_util.m:
compiler/module_qual.qualify_items.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/parse_tree_out_info.m:
compiler/parse_tree_to_term.m:
compiler/parse_type_name.m:
compiler/polymorphism.m:
compiler/prog_out.m:
compiler/prog_rep.m:
compiler/prog_rep_tables.m:
compiler/prog_util.m:
compiler/rbmm.exection_path.m:
compiler/rtti.m:
compiler/rtti_to_mlds.m:
compiler/switch_util.m:
compiler/table_gen.m:
compiler/type_constraints.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
    Conform to the above changes to the parse tree and HLDS.

compiler/c_util.m:
    Support generating the builtin operations for the new types.

doc/reference_manual.texi:
    Add the new types to the list of reserved type names.

    Add the mapping from the new types to their target language types.
    These are commented out for now.

compiler/llds.m:
    Replace the lt_integer/0 and lt_unsigned functors of the llds_type/0,
    with a single lt_int/1 functor that is parameterized by the int_type/0
    type.

    Add a representations for constants of the new types to the LLDS.

compiler/call_gen.m:
compiler/dupproc.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/llds_out_data.m:
compiler/llds_out_global.m:
compiler/llds_out_instr.m:
compiler/lookup_switch.m:
compiler/middle_rec.m:
compiler/peephole.m:
compiler/pragma_c_gen.m:
compiler/stack_layout.m:
compiler/string_switch.m:
compiler/switch_gen.m:
compiler/tag_switch.m:
compiler/trace_gen.m:
compiler/transform_llds.m:
    Support the new types in the LLDS code generator.

compiler/mlds.m:
    Support constants of the new types in the MLDS.

compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_code_util.m:
compiler/ml_disj_gen.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_global_data.m:
compiler/ml_lookup_switch.m:
compiler/ml_simplify_switch.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tailcall.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/mlds_to_target_util.m:
    Conform to the above changes to the MLDS.

compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
    Generate the appropriate target code for constants of the new
    types and operations involving them.

compiler/bytecode.m:
compiler/bytecode_gen.m:
    Handle the new types in the bytecode generator; we just abort if we
    encounter them for now.

compiler/elds.m:
compiler/elds_to_erlang.m:
compiler/erl_call_gen.m:
compiler/erl_code_util.m:
compiler/erl_rtti.m:
compiler/erl_unify_gen.m:
    Handle the new types in the Erlang code generator.

library/private_builtin.m:
    Add placeholders for the builtin unify and compare operations for
    the new types.  Since the bootstrapping compiler will not recognise
    the new types we give the polymorphic arguments.  These can be
    replaced after this change has bootstrapped.

    Update the Java list of TypeCtorRep constants.

library/int8.m:
library/int16.m:
library/int32.m:
library/uint8.m:
library/uint16.m:
library/uint32.m:
    New modules that will eventually contain builtin operations
    on the new types.

library/library.m:
library/MODULES_UNDOC:
    Do not include the above modules in the library documentation
    for now.

library/construct.m:
library/erlang_rtti_implementation.m:
library/rtti_implementation.m:
deep_profiler/program_representation_utils.m:
mdbcomp/program_representation.m:
    Handle the new types.

runtime/mercury_dotnet.cs.in:
java/runtime/TypeCtorRep.java:
runtime/mercury_type_info.h:
    Update the list of TypeCtorReps.

configure.ac:
runtime/mercury_conf.h.in:
    Check for the header stdint.h.

runtime/mercury_std.h:
    Include stdint.h; abort if that header is no present.

runtime/mercury_builtin_types.[ch]:
runtime/mercury_builtin_types_proc_layouts.h:
runtime/mercury_construct.c:
runtime/mercury_deconstruct.c:
runtime/mercury_deep_copy_body.h:
runtime/mercury_ml_expand_body.h
runtime/mercury_table_type_body.h:
runtime/mercury_tabling_macros.h:
runtime/mercury_tabling_preds.h:
runtime/mercury_term_size.c:
runtime/mercury_unify_compare_body.h:
    Add the new builtin types and handle them throughout the runtime.
2017-07-18 01:31:01 +10:00
Zoltan Somogyi
18a586f564 Delete more output args that always return the same value. 2017-07-10 02:43:50 +02:00
Zoltan Somogyi
0d5dac8018 Delete output args that always return the same value. 2017-07-10 00:51:41 +02:00
Zoltan Somogyi
083f990dbb Simplify the use of contexts in the MLDS.
compiler/mlds.m:
    This diff fixes two minor annoyances imposed by the old use of the
    mlds_context type in the MLDS.

    The first annoyance was that the mlds_context type used to be an
    abstract type that was privately defined to be a trivial wrapper
    around a prog_context. It had the exact same information content
    as a prog_context, but you had to go through translation functions
    to translate prog_contexts to mlds_contexts and vice versa.
    I think Fergus's idea was that we may want to add other information
    to the mlds_context type. However, since we haven't felt the need
    to anything like that in the 18 years (almost to the day) that the
    mlds_context type existed, I think this turned out to be a classic
    case of YAGNI (you ain't gonna need it).

    This diff deletes the mlds_context type, and replaces its uses
    with prog_context.

    The second annoyance was that actual MLDS code, i.e. values of the
    mlds_stmt type, always had to wrapped up inside a term of the statement
    type, a term which paired a context with the mlds_stmt.

    This diff moves the context information (now prog_context, not
    mlds_context) into each function symbol of the mlds_stmt type,
    deletes the statement type, and replaces its uses with the now-expanded
    mlds_stmt type. This simplifies most code that deals with MLDS code.

compiler/ml_util.m:
    Add a function, get_mlds_stmt_context, for the (very rare) occasions
    where we want to know the context of an mlds_stmt *before* testing
    to see what function symbol it is bound to.

compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_elim_nested.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_global_data.m:
compiler/ml_lookup_switch.m:
compiler/ml_optimize.m:
compiler/ml_proc_gen.m:
compiler/ml_simplify_switch.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tag_switch.m:
compiler/ml_tailcall.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/rtti_to_mlds.m:
    Conform to the changes above.

    In some cases, a function was given two separate contexts, sometimes from
    two separate sources; a prog_context and an mlds_context. In such cases,
    keep only one source.

    Standardize on Stmt as the variable name for "statement".

    Delete redundant $module references from unexpected and other abort
    predicates.

    In one case, delete a function that was a duplicate of another function.

    Give some predicates and functions more meaningful names.
2017-07-09 18:44:05 +02:00
Zoltan Somogyi
869605956c Make MLDS definitions self-contained.
Until now, we used a single type, mlds_defn, to contain both

- generic information that we need for all MLDS definitions, such as
  name and context, and

- information that is specific to each different kind of MLDS definition,
  such as a variable's initializer or a function's list of parameter types.

The former were contained in three fields in the mlds_defns directly,
while the latter were contained in a fourth field that was a discriminated
union of mlds_data_defn, mlds_function_defn and mlds_class_defn.

While seemingly parsimonious, this design meant that if we had e.g. a list
of variable definitions, we would have to wrap the mlds_defn/4 wrapper around
them to give them their names, and thereafter, any code that processed
that list would have to be prepared to process not just variables but also
functions and classes.

This diff moves the three generic fields into each of the mlds_data_defn,
mlds_function_defn and mlds_class_defn types, making each those types
self-contained, and leaving mlds_defn as nothing more than a discriminated
union of those types.

In the few places that want to look at the generic fields *without*
caring about what kind of entity is being defined, this design requires
a bit of extra work compared to the old design, but in many other places,
the new design allows us to return mlds_data_defns, mlds_function_defns
or mlds_class_defns instead of just mlds_defns.

compiler/mlds.m:
    Make the change described above.

    Store type definions (for high level data) and table structures definitions
    separately from other definitions in the MLDS type, since we can now
    give them tighter types.

compiler/ml_global_data.m:
    Change the fields that store flat cells from storing mlds_defns to
    storing mlds_data_defns, since we can now do so.

    Add an XXX about an obsolete comment.

compiler/mercury_compile_mlds_back_end.m:
compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_elim_nested.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_gen_info.m:
compiler/ml_lookup_switch.m:
compiler/ml_optimize.m:
compiler/ml_proc_gen.m:
compiler/ml_string_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tailcall.m:
compiler/ml_type_gen.m:
compiler/ml_util.m:
compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/rtti_to_mlds.m:
    Conform to the changes above. Where possible with only local changes,
    return mlds_data_defns mlds_function_defns or mlds_class_defns instead
    of just mlds_defns. Put the mlds_data(_), mlds_function(_) or mlds_class(_)
    wrapper around those definitions as late as possible (typically, when
    our current code wants to put it into the same list as some other kind
    of definition), in the hope that in the future, that wrapping can be
    delayed even later, or even avoided altogether. Make the places where
    such improvements may be possible with "XXX MLDS_DEFN".

    In some places, the tighter data representation allows us to *delete*
    "XXX MLDS_DEFN" markers.

    Move some common code from mlds_to_{cs,java}.m to ml_util.m.

    In mlds_to_{cs,java}.m, add prefixes to the function symbols in a type
    to reduce ambiguity.
2017-05-24 09:45:21 +02:00
Julien Fischer
e9b0c489d2 Two fixes for uint support.
1. Fix an abort in the MLDS backend involving switches on uints.

2. Make string.string/1 handle uints.

compiler/ml_switch_gen.m:
    Handle uints properly in a spot.

library/string.to_string.m:
     Make string.string/1 handle uint values.

tests/hard_coded/Mmakefile:
tests/hard_coded/uint_switch_test.{m,exp}:
     Add a test case.
2017-05-24 09:59:01 +10:00
Julien Fischer
092e175f45 Add a builtin unsigned word sized integer type -- Part 1.
Add a new builtin type: uint, which is an unsigned word sized integer type.
Support for this new type will need be bootstrapped over several changes.
This is the first such change and does the following:

- Extends the compiler to recognize 'uint' as a builtin type.
- Extends the set of builtin operations to include relational and (some)
  arithmetic operations on uints.
- Extends all of the code generators to handle the above.  There are some
  limitations currently marked by 'XXX UINT'.  These will be lifted once
  the compiler recognised uint and additional library support becomes
  available.
- Extends the runtime to support uints.

compiler/prog_type.m:
compiler/prog_data.m:
compiler/builtin_lib_types.m:
    Recognize uint as a builtin type.

    Add a new alternative to the cons_id/0 type corresponding to the uint type
    -- for bootstrapping purposes its argument is currently an int.

compiler/builtin_ops.m:
    Add builtin relational and arithmetic operations on uints.  Note that the
    existing 'unsigned_le' operation is actually intended for use with signed
    values.  Rather than attempt to modify its meaning, I have just added new
    operations specific to the uint type.

compiler/hlds_data.m:
    Add a new tag type for uints.

compiler/type_ctor_info.m:
    Recognise uint as a builtin.

    Bump the RTTI version number here.

compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/dependency_graph.m:
compiler/export.m:
compiler/foreign.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_out_pred.m:
compiler/hlds_out_util.m:
compiler/hlds_pred.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/mercury_to_mercury.m:
compiler/mode_util.m:
compiler/module_qual.qualify_items.m:
compiler/parse_tree_to_term.m:
compiler/parse_type_name.m:
compiler/polymorphism.m:
compiler/prog_out.m:
compiler/prog_rep.m:
compiler/prog_rep_tables.m:
compiler/prog_util.m:
compiler/rbmm.execution_path.m:
compiler/rtti.m:
compiler/special_pred.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/table_gen.m:
compiler/type_constraints.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/write_module_interface_files.m:
compiler/xml_documentation.m:
    Conform to the above changes to the parse tree and HLDS.

compiler/c_util.m:
    Support generating builtin operations for uints.

compiler/llds.m:
    Add a representation for uint constants to the LLDS.

    Map uints onto MR_Unsigned.

compiler/call_gen.m:
compiler/dupproc.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/llds_out_data.m:
compiler/llds_out_instr.m:
compiler/opt_debug.m:
compiler/opt_util.m:
    Support uints in the LLDS code generator.

compiler/mlds.m:
     Support uint constants in the MLDS.

compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_global_data.m:
compiler/ml_simplify_switch.m:
compiler/ml_switch_gen.m:
compiler/ml_tailcall.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/rtti_to_mlds.m:
    Conform to the above change to the MLDS.

compiler/mlds_to_c.m:
compiler/mlds_to_java.m:
compiler/mlds_to_cs.m:
     Generate the appropriate target code for uint constants and uint
     relational operations.

compiler/bytecode.m:
compiler/bytecode_gen.m:
     Handle uints in the bytecode generator: we just abort if we
     encounter them for now.

compiler/elds.m:
compiler/elds_to_erlang.m:
compiler/erl_call_gen.m:
compiler/erl_code_util.m:
compiler/erl_rtti.m:
compiler/erl_unify_gen.m:
    Handle uints in the Erlang code generator.

library/private_builtin.m:
    Add placeholders for builtin_{unify,compare}_uint.  Since the
    bootstrapping compiler will not recognize uint as a type, we
    give them polymorphic arguments.  These can be replaced after
    this change has bootstrapped.

    Update the Java list of TypeCtorRep constants, which for some
    reason is defined here.

library/uint.m:
    New module that will eventually contain operations on uints.

library/MODULES_DOCS:
library/library.m:
     Add the uint module.

library/construct.m:
library/erlang_rtti_implementation.m:
library/rtti_implementation.m:
mdbcomp/program_representation.m:
     Handle uints.

deep_profiler/program_representation_utils.m:
     Conform to the above change.

runtime/mercury_dotnet.cs.in:
     Update the list of TypeCtorReps for C#

java/runtime/TypeCtorRep.java:
     Update this, although the actual TypeCtorRep constants
     are defined the library.

runtime/mercury_type_info.h:
    Bump the RTTI version number.

    Add an alternative for uints to the tyepctor rep enum.

runtime/mercury_builtin_types.{h,c}:
runtime/mercury_builtin_types_proc_layouts.h:
runtime/mercury_deconstruct.c:
runtime/mercury_deep_copy_body.h:
runtime/mercury_table_type_body.h:
runtime/mercury_tabling.h:
runtime/mercury_tabling_macros.h:
runtime/mercury_unify_compare_body.h:
    Add uint as a builtin type and handle it throughout the runtime.

runtime/mercury_grade.h:
    Bump the binary compatibility version.

runtime/mercury_term_size.c:
runtime/mercury_ml_expand_body.h:
    Handle uint and fix probable bugs with the handling of ints on
    64-bit Windows.
2016-10-24 12:55:35 +11:00
Zoltan Somogyi
cc9912faa8 Don't import anything in packages.
Packages are modules whose only job is to serve as a container for submodules.
Modules like top_level.m, hlds.m, parse_tree.m and ll_backend.m are packages
in this (informal) sense.

Besides the include_module declarations for their submodules, most of the
packages in the compiler used to import some modules, mostly other packages
whose component modules their submodules may need. For example, ll_backend.m
used to import parse_tree.m. This meant that modules in the ll_backend package
did not have to import parse_tree.m before importing modules in the parse_tree
package.

However, this had a price. When we add a new module to the parse_tree package,
parse_tree.int would change, and this would require the recompilation of ALL
the modules in the ll_backend package, even the ones that did NOT import ANY
of the modules in the parse_tree package.

This happened even at one remove. Pretty much all modules in every one
of the backend have to import one or more modules in the hlds package,
and they therefore have import hlds.m. Since hlds.m imported transform_hlds.m,
any addition of a new middle pass to the transform_hlds package required
the recompilation of all backend modules, even in the usual case of the two
having nothing to do with each other.

This diff removes all import_module declarations from the packages,
and replaces them with import_module declarations in the modules that need
them. This includes only a SUBSET of their child modules and of the non-child
modules that import them.
2015-11-13 15:03:20 +11:00
Zoltan Somogyi
7654ec847e Convert (C->T;E) to (if C then T else E). 2015-09-18 09:37:29 +10:00
Zoltan Somogyi
62ec97d443 Report imports shadowed by other imports.
If a module has two or more import_module or use_module declarations
for the same module, (typically, but not always, one being in its interface
and one in its implementation), generate an informational message about
each redundant declaration if --warn-unused-imports is enabled.

compiler/hlds_module.m:
    We used to record the set of imported/used modules, and the set of
    modules imported/used in the interface of the current module. However,
    these sets

    - did not record the distinction between imports and uses;
    - did not allow distinction between single and multiple imports/uses;
    - did not record the locations of the imports/uses.

    The first distinction was needed only by module_qual.m, which *did*
    pay attention to it; the other two were not needed at all.

    To generate messages for imports/uses shadowing other imports/uses,
    we need all three, so change the data structure storing such information
    for *direct* imports to one that records all three of the above kinds
    of information. (For imports made by read-in interface and optimization
    files, the old set of modules approach is fine, and this diff leaves
    the set of thus *indirectly* imported module names alone.)

compiler/unused_imports.m:
    Use the extra information now available to generate a
    severity_informational message about any import or use that is made
    redundant by an earlier, more general import or use.

    Fix two bugs in the code that generated warnings for just plain unused
    modules.

    (1) It did not consider that a use of the builtin type char justified
    an import of char.m, but without that import, the type is not visible.

    (2) It scanned cons_ids in goals in procedure bodies, but did not scan
    cons_ids that have been put into the const_struct_db. (I did not update
    the code here when I added the const_struct_db.)

    Also, add a (hopefully temporary) workaround for a bug in
    make_hlds_passes.m, which is noted below.

    However, there are at least three problems that prevent us from enabling
    --warn-unused-imports by default.

    (1) In some places, the import of a module is used only by clauses for
    a predicate that also has foreign procs. When compiled in a grade that
    selects one of those foreign_procs as the implementation of the predicate,
    the clauses are discarded *without* being added to the HLDS at all.
    This leads unused_imports.m to generate an uncalled-for warning in such
    cases. To fix this, we would need to preserve the Mercury clauses for
    *all* predicates, even those with foreign procs, and do all the semantic
    checks on them before throwing them away. (I tried to do this once, and
    failed, but the task should be easier after the item list change.)

    (2) We have two pieces of code to generate import warnings. The one in
    unused_imports.m operates on the HLDS after type and mode checking,
    while module_qual.m operates on the parse tree before the creation of
    the HLDS. The former is more powerful, since it knows e.g. what types and
    modes are used in the bodies of predicates, and hence can generate warnings
    about an import being unused *anywhere* in a module, as opposed to just
    unused in its interface.

    If --warn-unused-imports is enabled, we will get two separate set of
    reports about an interface import being unused in the interface,
    *unless* we get a type or mode error, in which case unused_imports.m
    won't be invoked. But in case we do get such errors, we don't want to
    throw away the warnings from module_qual.m. We could store them and
    throw them away only after we know we won't need them, or just get
    the two modules to generate identical error_specs for each warning,
    so that the sort_and_remove_dups of the error specs will do the
    throwing away for us for free, if we get that far.

    (3) The valid/bug100.m test case was added as a regression test for a bug
    that was fixed in module_qual.m. However the bug is still present in
    unused_imports.m.

compiler/make_hlds_passes.m:
    Give hlds_module.m the extra information it now needs for each item_avail.

    Add an XXX for a bug that cannot be fixed right now: the setting of
    the status of abstract instances to abstract_imported. (The "abstract"
    part is correct; the "imported" part may not be.)

compiler/intermod.m:
compiler/try_expand.m:
compiler/xml_documentation.m:
    Conform to the change in hlds_module.m.

compiler/module_qual.m:
    Update the documentation of the relationship of this module
    with unused_imports.m.

compiler/hlds_data.m:
    Document a problem with the status of instance definitions.

compiler/hlds_out_module.m:
    Update the code that prints out the module_info to conform to the change
    to hlds_module.m.

    Print status information about instances, which was needed to diagnose
    one of the bugs in unused_imports.m. Format the output for instances
    nicer.

compiler/prog_item.m:
    Add a convenience predicate.

compiler/prog_data.m:
    Remove a type synonym that makes things harder to understand, not easier.

compiler/modules.m:
    Delete an XXX that asks for the feature this diff implements.
    Add another XXX about how that feature could be improved.

compiler/Mercury.options.m:
    Add some more modules to the list of modules on which the compiler
    should be invoked with --no-warn-unused-imports.

compiler/*.m:
library/*.m:
mdbcomp/*.m:
browser/*.m:
deep_profiler/*.m:
mfilterjavac/*.m:
    Delete unneeded imports. Many of these shadow other imports, and some
    are just plain unneeded, as shown by --warn-unused-imports. In a few
    modules, there were a *lot* of unneeded imports, but most had just
    one or two.

    In a few cases, removing an import from a module, because it *itself*
    does not need it, required adding that same import to those of its
    submodules which *do* need it.

    In a few cases, conform to other changes above.

tests/invalid/Mercury.options:
    Test the generation of messages about import shadowing on the existing
    import_in_parent.m test case (although it was also tested very thoroughly
    when giving me the information needed for the deletion of all the
    unneeded imports above).

tests/*/*.{m,*exp}:
    Delete unneeded imports, and update any expected error messages
    to expect the now-smaller line numbers.
2015-08-25 00:38:49 +10:00
Peter Wang
9979764072 Build string switch tries in the target string encoding.
The compiler should work in code units of the TARGET string encoding
when building tries for string switches.  Using its own string encoding
would be incorrect if it differs from the target encoding.  Currently
that would only occur if the compiler is built in a java/csharp grade
(uses UTF-16 internally) and invoked to target high-level C (uses UTF-8).

Another motivation for this change is to remove a place where the
compiler behaviour depends on the setting of `--cross-compiling'.
As of now, the `--cross-compiling' option has no effect.

compiler/backend_libs.m:
compiler/string_encoding.m:
	Add new module with helper predicates.

compiler/ml_string_switch.m:
	Convert strings to/from code units in the target string
	encoding.

compiler/ml_switch_gen.m:
	Remove restriction on compiling string switches using tries when
	`--cross-compiling' is enabled.

compiler/notes/compiler_design.html:
	Document the new module.
2015-03-23 14:16:20 +11:00
Zoltan Somogyi
d041b83943 Implement string switches via tries for the MLDS backend.
The code we emit to decide which arm of the switch is selected looks like this:

    case_num = -1;
    switch (MR_nth_code_unit(switchvar, 0)) {
        case '98':
            switch (MR_nth_code_unit(switchvar, 1)) {
                case '99':
                    if (MR_offset_streq(2, switchvar, "abc"))
                        case_num = 0;
                    break;
                case '100':
                    if (MR_offset_streq(2, switchvar, "aceg"))
                        case_num = 1;
                    break;
            }
            break;
        case '99':
            if (MR_offset_streq(2, switchvar, "bbb"))
                case_num = 2;
            break;
    }

The part that acts on this will look like this for lookup switches:

    if (case_num < 0)
        succeeded = MR_FALSE;
    else {
        outvar1 = vector_common[case_num].f1;
        ...
        outvarn = vector_common[case_num].fn;
        succeeded = MR_TRUE;
    }

and like this for non-lookup switches:

    switch (case_num) {
    case 0:
        <code for case 0>
        break;
    ...
    case n:
        <code for case n>
        break;
    default:                    /* if the switch is can_fail */
        <code for failure>
        break;
    }

compiler/ml_string_switch.m:
    Implement both non-lookup and lookup string switches via tries,
    along the lines shown above.

compiler/ml_switch_gen.m:
    Invoke the predicates that implement string switches via tries
    in the circumstances in which option values call for them.

    For now, we generate tries only for the C backend. Once the
    problems identified for mlds_to_{cs,java,managed} below are fixed,
    we can enable them on those backends as well.

compiler/options.m:
doc/user_guide.texi:
    Add an option that governs the minimum size of trie switches.

compiler/ml_lookup_switch.m:
    Factor out the code common to the implementation of all model-non
    lookup switches, both in ml_lookup_switch.m and ml_string_switch.m,
    and put it all into a new exported predicate.

    The previously existing MLDS implementation methods for lookup switches
    all build their lookup tables from maps that maps each cons_id
    in the switch cases to the values of the output arguments of those cases.
    For switch cases that apply to more than one cons_id, this map had
    one entry for each of those cons_ids. For tries, we need a map
    from *case ids*, not *cons ids* to the outputs. Since it is
    easier to convert the one-to-one case_id->outputs map to the
    many-to-one cons_id->outputs map than vice versa, change the
    main data structure from which lookup tables are built to store data
    in a case_id->outputs format, and provide predicates for its conversion
    to the other (previously the only) format.

    Rename ml_gen_lookup_switch to ml_gen_atomic_lookup_swith to distinguish
    it from other predicates that also generate (other kinds of) lookup
    switches.

compiler/switch_util.m:
    Have the types representating lookup tables represent their contents
    as a map, not as the assoc list derived from the map. Previously,
    we didn't do anything with the map other than flatten it to the assoc list,
    but for the MLDS backend, we may now also need to convert it to another
    form of map (see immediately above).

compiler/builtin_ops.m:
    Add two new builtin ops. The first, string_unsafe_index_code_unit,
    returns the nth code unit in a string; the second, offset_str_eq,
    does a string equality test on the nth and later code units of
    two strings. They are used in the implementation of tries.

compiler/c_util.m:
    Add a new binop category for each new binop, since they are not like
    existing binops.

    Put some existing binops into their own categories as well, since
    bundling them with the other ops they were bundled with seems like
    a bad idea.

compiler/hlds_goal.m:
    Make the identifier of switch arms in tagged_cases a separate type
    from int.

compiler/mlds_to_c.m:
compiler/llds_out_data.m:
    Handle the new kinds of binops.

    When writing out binop expressions, we used to do a switch on the binop
    to get its category, and then another switch on the category. We now
    switch on the binop directory, since this much harder to write out
    code using new binops badly, and should be faster to boot.

    In mlds_to_c.m, also make some cosmetic changes to the output to make it
    easier to read, and thus to debug.

compiler/mlds_to_il.m:
    Handle the new kinds of binops.

compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/mlds_to_managed.m:
    Do not handle the new kinds of binops, since doing so would require
    changing the whole approach of how these modules handle binops.

    Clean up some predicates.

compiler/bytecode.m:
compiler/erl_call_gen.m:
compiler/lookup_switch.m:
compiler/ml_global_data.m:
compiler/ml_optimize.m:
compiler/ml_tag_switch.m:
compiler/opt_debug.m:
compiler/string_switch.m:
    Conform to the changes above.

compiler/ml_code_gen.m:
    Put the predicates of this module into a consistent order.

library/string.m:
    Fix white space.

runtime/mercury_string.h:
    Add a macro for each of the two new builtin operations.
2015-02-24 16:03:30 +11:00
Zoltan Somogyi
0337b3b6fb Break up a too-large predicate. 2015-02-17 06:09:38 +11:00
Zoltan Somogyi
dddb9e552d Factor out common code in code generation for switches.
compiler/switch_util.m:
    Move here some code that was common to switch_gen.m and ml_switch_gen.m.

compiler/switch_gen.m:
compiler/ml_switch_gen.m:
    Remove the code moved to switch_util.m.

    In switch_gen.m, remove a long unused predicate.

compiler/code_info.m:
    Simplify the interface of the init predicate for code_infos.

compiler/proc_gen.m:
    Conform to the change in code_info.m.
2014-12-18 23:28:28 +11:00
Zoltan Somogyi
8a6ffaab19 Fix Mantis bug #354.
I/O tabling has two main purposes. The first and more important is to allow the
debugger to replay parts of the program execution for the programmer, which
requires making I/O operations idempotent (so that we get the same results on
the second, third etc "execution" as on the first). The second purpose is to
let the person using the debugger actually see a list of the I/O actions, and
their results.

The root of the problem here is that the compiler can do the second part
only if it has access to the type_infos describing the types of the arguments
of the I/O action. With the current infrastructure for representing typeclass
information, this is not always possible in the presence of typeclass
constraints on I/O action predicates. The reason is that polymorphism.m can
put the typeinfo for a type variable that is subject to a typeclass constraint
arbitrarily deep inside the typeclass_info for that constraint, but the RTTI
can encode such locations only up to a fixed depth (currently only the
shallowest embedded is encodable).

Before this fix, the test case for this bug got a compiler abort when the
I/O tabling transformation tried to figure out how to table the typeclass
info representing the typeclass constraint on a I/O action predicate.

We still cannot table typeclass infos. We could store them (I/O tabling
does not require anything more complicated), but the problem of deeply buried
typeinfos inside them would still remain. So this fix consists of two parts:

- for typeclass constrained I/O primitives, recording only enough information
  to allow them to replayed (the first purpose above), and not to print them
  out (the second purpose), and
- getting the runtime system to understand this, and not crash with a core dump
  in the absence of the information required for the second purpose.

This second part requires changes to the RTTI used by I/O tabling. These
changes BREAK BINARY COMPATIBILITY in debug grades.

runtime/mercury_stack_layout.h:
    Rename the MR_TableIoDecl structure as the MR_TableIoEntry structure,
    since the I/O table entries that it describes are used not just for
    declarative debugging, but also for printing out I/O actions.

    Add a field to it that specifies whether the fields describing
    the types of the I/O action's arguments are meaningful.

runtime/mercury_grade.h:
    Bump the debug-only binary compatibility version number, since
    the change to mercury_stack_layout.h requires it.

runtime/mercury_trace_base.[ch]:
    When returning information about a tabled I/O action, return a boolean
    that says whether the information abouts its arguments is actually
    present or not. Do not return information about the arguments if
    we cannot convert them into univs due to missing type information.

browser/io_action.m:
    Pay attention to the new info returned by MR_trace_get_action,
    and avoid a potential core dump by generating a description of the
    requested I/O action only if the argument type information needed
    to generate that description is actually available.

trace/mercury_trace_vars.c:
    Pay attention to the new info returned by MR_trace_get_action.
    When the argument type information needed to generate an accurate
    description of the I/O action is not available, generate a
    "description" that mentions this fact.

trace/mercury_trace_cmd_browsing.c:
    Make the fix to mercury_trace_vars.c easier to test by adding a mechanism
    to print out all existing I/O actions, as long as there aren't too many
    of them.

compiler/hlds_pred.m:
compiler/layout.m:
compiler/prog_data.m:
    Prepare for the possibility that we have cannot record the information
    needed to reconstruct the runtime types of the arguments of a I/O tabled
    predicate.

compiler/table_gen.m:
    If an I/O tabled predicate has one or more typeclass constraints,
    do not attempt to record the RTTI needed to reconstruct the types
    of its arguments at runtime.

compiler/continuation_info.m:
compiler/hlds_data.m:
    Rename some data structures that referred to the old MR_TableIoDecl
    structure to refer to its replacement, the MR_TableIoEntry structure.

compiler/bytecode_gen.m:
compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/dependency_graph.m:
compiler/erl_unify_gen.m:
compiler/export.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_out_mode.m:
compiler/hlds_out_pred.m:
compiler/hlds_out_util.m:
compiler/hlds_pred.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/layout.m:
compiler/layout_out.m:
compiler/llds.m:
compiler/llds_out_data.m:
compiler/llds_out_file.m:
compiler/llds_out_util.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mercury_to_mercury.m:
compiler/ml_global_data.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/mode_util.m:
compiler/module_qual.m:
compiler/opt_debug.m:
compiler/proc_gen.m:
compiler/prog_data.m:
compiler/prog_out.m:
compiler/prog_rep.m:
compiler/prog_type.m:
compiler/prog_util.m:
compiler/rbmm.execution_path.m:
compiler/stack_layout.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
compiler/unify_gen.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
runtime/mercury_misc.h:
runtime/mercury_tabling.h:
    Conform to the above changes.

tests/debugger/tabled_typeclass.{m,inp,exp,exp2}:
    New test case to test that I/O actions that have typeclass constraints
    on them can be printed in mdb.

tests/debugger/Mmakefile:
tests/debugger/Mercury.options:
    Enable the new case.
2014-08-30 00:48:53 +02:00
Julien Fischer
9a932f8d47 Provide finer grained control over --smart-indexing.
The --smart-indexing option enables a number of smart indexing strategies
depending on the switch category and backend.  This diff adds new developer
only options that provide finer grained control over which smart indexing
strategies are enabled.  I need this to assist in tracking down some problems
with the use of --smart-indexing on the MinGW64 port.

compiler/options.m:
	Add new command line options that can be used to selectively disable
	various types of smart indexing.

compiler/switch_util.m:
	Add a predicate to test whether the user has chosen to disable smart
	indexing for a particular category of switch.

compiler/switch_gen.m:
compiler/ml_switch_gen.m:
	Respect the new options.
2013-04-03 21:45:09 +11:00
Zoltan Somogyi
884838b9df If the backend supports constant structures, and we do not need unifications
Estimated hours taken: 8
Branches: main

If the backend supports constant structures, and we do not need unifications
to retain their original shapes, then convert each from_ground_term scope
into a unification with a cons_id that represents the ground term being
built up.

This speeds up the compilation of training_cars_full.m by about 6%.

compiler/simplify.m:
	Make the conversion if enabled. By doing the conversion in this phase,
	we don't have to teach the semantic analysis passes about unifications
	with the new cons_id, but we do get the benefit of later passes being
	faster, because they have less code to process.

compiler/const_struct.m:
	The declarative debugger does not yet know how to handle the new
	cons_id, so do not introduce it if we are preparing for declarative
	debugging.

compiler/trace_params.m:
	Export a predicate for const_struct.m.

compiler/prog_data.m:
	Add the new cons_id, ground_term_const.

compiler/hlds_data.m:
	Add the tag of the new cons_id, ground_term_const_tag.

compiler/hlds_code_util.m:
	Convert the new cons_id to the new cons_tag.

	Fix an old problem with that conversion process: it always converted
	tuple_cons to single_functor_tag. However, arity-zero tuples are
	(dummy) constants, not heap cells, so we now convert them to a (dummy)
	integer tag. This matters now because the process that generates
	code (actually data) for constant structures handles the cons_tags that
	build constants and heap cells separately. As a side benefit, we
	no longer reserve a word-sized heap cell for arity-zero tuples.

compiler/unify_gen.m:
compiler/ml_unify_gen.m:
	Implement the generation of code for arbitrary constant structures,
	not just those that can implement typeinfos and typeclass_infos.

compiler/term_norm.m:
	Compute the sizes of ground terms for each of our norms.

compiler/term_traversal.m:
	Manage the computation of sizes of ground terms.

	Simplify and thereby speed up a predicate.

compiler/term_constr_build.m:
	Note that we should manage the computation of sizes of ground terms.

compiler/term_util.m:
	Simplify the style of a predicate.

compiler/layout.m:
	Give some field names prefixes to avoid ambiguities.

compiler/bytecode_gen.m:
compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/dependency_graph.m:
compiler/erl_unify_gen.m:
compiler/export.m:
compiler/higher_order.m:
compiler/hlds_out_mode.m:
compiler/hlds_out_util.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/mercury_to_mercury.m:
compiler/ml_global_data.m:
compiler/ml_type_gen.m:
compiler/mode_util.m:
compiler/module_qual.m:
compiler/polymorphism.m:
compiler/prog_rep.m:
compiler/prog_type.m:
compiler/prog_util.m:
compiler/rbmm.execution_path.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
	Conform to the changes above.

tests/hard_coded/ground_terms.{m,exp}:
	A new test case to test the handling of ground terms.

tests/hard_coded/Mmakefile:
tests/hard_coded/Mercury.options:
	Enable the new test case.
2012-06-11 03:13:24 +00:00
Zoltan Somogyi
77adfe5439 Add all the copyright year updates that were left off in my previous commit
Estimated hours taken: 0.1
Branches: main

Add all the copyright year updates that were left off in my previous commit
over the ext protocol.
2012-06-08 15:46:21 +00:00
Zoltan Somogyi
ee63cb8d84 Heavily polymorphic code, such as that generated by g12, often builds the same
Estimated hours taken: 80
Branches: main

Heavily polymorphic code, such as that generated by g12, often builds the same
typeinfos and typeclass infos over and over again. We have long had caches
that avoid building a new typeinfo or typeclass info if some variable in the
current scope already contains the right value, but a program that has many
scopes may still build the same typeinfo or typeclass info many times.
If that typeinfo or typeclass info is a ground term, the code generators
will recognize that fact, and will turn all the constructions of that ground
term in different scopes into referencess to the same constant structure.
However, in the meantime, the program can be much bigger than necessary.
In the motivating test case for this change, a single call to fdic_post
is preceded by 133 goals that build the four typeclass infos it needs.

The main idea of this diff is to construct constant typeinfos and typeclass
infos out of line, in a separate data structure. Polymorphism then binds
variables representing typeinfo and typeclass infos to reference to these
constant structures. In the motivating example, this allows polymorphism.m
to insert just four goals before the call to fdic_post, the minimal possible
number: one for each typeclass info that predicate needs.

On Leslie's bug344 program, this change speeds up the compiler by a factor
of five to eight (reducing compile time from about 80 or 85 seconds to
10 or 15).

There is a drawback to this scheme, but it is minor. That drawback is that
once a constant structure is entered into our database of constant structures,
it cannot (yet) be removed. Even if all the references to a constant structure
are eliminated by optimizations, the structure will remain.

------------------------------------------

CHANGES IN THE FRONT END

compiler/const_struct.m:
	A new module to look after our new database of constant structures.
	Currently, its use is enable only on the LLDS and MLDS C backends.

compiler/hlds.m:
compiler/notes/compiler_design.html:
	Add the new module to the HLDS package.

compiler/hlds_module.m:
	Include the constant structure database in the module_info.

compiler/hlds_data.m:
	Add two new cons_ids, which refer to typeinfos and typeclass infos
	implemented as constant structures.

	Move the code for calculating the number of extra instance args
	in base_typeclass_infos here from base_typeclass_info.m, since
	polymorphism.m now needs it too. We can now also eliminate the
	duplicate copy of that code in higher_order.m.

	Make an independent optimization: make the restrict_list_elements
	function more efficient by avoiding redundant tests.

compiler/polymorphism.m:
	When building typeinfo and typeclass infos, keep track of whether
	the structure being built is constant. If it is, then put it in the
	database of constant structures, and replace the code building it
	with a simple reference to that new entry.

	Since I now expect most goal sequences inserted before goals to be
	short, consistent use lists of goals to represent these, since the
	costs of conversions to and from cord form are unlikely to be paid back
	by the higher efficiency of cord operations on longer sequences.

	When we want to get the typeclass info of a superclass out of the
	typeclass info of a subclass, if the typeclass info of the subclass
	is known, do the extraction here. We used to do this optimization
	only in higher_order.m, but doing so here reduces the size of the HLDS
	between polymorphism.m and higher_order.m, and thus improves
	compilation time.

	Reorganize some of the structure of this module to make the above
	changes possible. In particular, our new approach requires making
	snapshots of the varsets and vartypes, and later restoring those
	snapshots if the variables allocated turn out to be unnecessary,
	due to all of them describing the components of a constant structure.
	The correctness of such code is much easier to check if the taking
	and restoring of each snapshot takes places in a single predicate.

	Remove the code moved to higher_order.m.

	Add some debugging code for now. If no issues arise in the next few
	weeks, it can be deleted.

compiler/modecheck_unify.m:
	Treat unifications whose right hand side has a cons_id referring to a
	constant structure specially.

compiler/base_typeclass_info.m:
	Replace the code that is now in num_extra_instance_args with a call
	to that predicate.

	Put the arguments of some predicates in a more logical order.

compiler/higher_order.m:
	When looking up the components of existing typeclass infos, handle
	cases where those typeclass infos are constant structures.

	Give some types, fields and variables better names.

	Avoid a redundant map search.

	Avoid some redundant tests by providing separate predicates to handle
	higher order calls and method calls.

	Move the predicate is_typeclass_info_manipulator here from
	polymorphism.m, since this is the only module that uses that predicate.

------------------------------------------

CHANGES IN THE LLDS BACKEND:

compiler/llds.m:
	Add a type to map constant structure numbers to rvals together with
	their LLDS types.

	Introduce a type to represent rvals together with their LLDS types.

compiler/mercury_compile_llds_back_end.m:
	Before we generate code for the predicates of the module, convert
	the constant structures to typed LLDS rvals. Create a map mapping
	each constant structure number to the corresponding typed rvals.

compiler/proc_gen.m:
	Take that map, and put it into the code_info, to allow references
	to those structures to be translated.

	Put the arguments of some predicates into a more logical order.

compiler/code_info.m:
	Include a map giving the representation of each constant structure
	in the code_info.

compiler/unify_gen.m:
	Add the predicates needed to convert the constant structures of a
	module to LLDS rvals. For now, this code works only on the kinds of
	constant structures generated by polymorphism.m.

	Handle unifications whose right hand side is a reference to a constant
	structure.

compiler/global_data.m:
compiler/stack_layout.m:
	Use the new typed_rval type where relevant.

------------------------------------------

CHANGES IN THE MLDS BACKEND:

compiler/ml_proc_gen.m:
	Before we generate code for the predicates of the module, convert
	the constant structures to typed MLDS rvals. Create a map mapping
	each constant structure number to the corresponding typed rvals.

	Factor out some code into a predicate of its own.

compiler/ml_gen_info.m:
	Include a map giving the representation of each constant structure
	in the ml_gen_info.

	Also add to the ml_gen_info an indication of what GC system we are
	generating code for, since the code generator needs to know this often.

compiler/ml_unify_gen.m:
	Add the predicates needed to convert the constant structures of a
	module to MLDS rvals. For now, this code works only on the kinds of
	constant structures generated by polymorphism.m.

	Handle unifications whose right hand side is a reference to a constant
	structure.

	Simplify some existing code.

------------------------------------------

MINOR CHANGES:

mdbcomp/prim_data.m:
	Add a predicate that gets both the module name and the base name
	from a sym_name at the same time. This is used for minor speedups
	in other code updated in this diff.

compiler/dead_proc_elim.m:
	Scan constant structures for references to entities that need to be
	kept alive.

compiler/term_constr_build.m:
compiler/term_traversal.m:
	Do not build size constraints from references to constant structures.
	The sizes of constant terms don't change, so they are irrelevant
	when building constraints for finding argument size changes.

------------------------------------------

TRIVIAL CHANGES TO CONFORM TO OTHER CHANGES:

compiler/hlds_out_module.m:
	Print out the constant structure database if asked.

doc/user_guide.tex:
	Document how to ask for it.

compiler/hlds_out_util.m:
	Print out the new cons_ids.

compiler/hlds_out_mode.m:
	Print out the new cons_ids in insts.

	Remove a compiler abort, to help debug a problem.

	Improve the structure of a predicate.

compiler/hlds_out_goal.m:
	Fix some missing newlines.

compiler/hlds_code_util.m:
	Add some utility predicates needed by the modules above.

	Conform to the changes above.

compiler/mlds_to_il.m:
	Reorder some predicates.

	Conform to the changes above.

compiler/bytecode_gen.m:
compiler/ctgc.selector.m:
compiler/dependency_graph.m:
compiler/erl_unify_gen.m:
compiler/export.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/llds_out_globals.m:
compiler/mercury_to_mercury.m:
compiler/ml_global_data.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/module_qual.m:
compiler/prog_rep.m:
compiler/prog_type.m:
compiler/prog_util.m:
compiler/rbmm.execution_path.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/type_ctor_info.m:
compiler/unused_imports.m:
compiler/var_locn.m:
compiler/xml_documentation.m:
	Conform to the changes above.

------------------------------------------

OTHER INDEPENDENT CHANGES:

compiler/handle_options.m:
	Add a dump option that is useful for debugging when working on
	polymorphism.m and constant structures.

compiler/equiv_type_hlds.m:
	Fix an old performance bug: make the code handling try goals keep
	the old memory cells representing such goals, instead of rebuilding
	them, if no changes took place inside them.

compiler/ml_accurate_gc.m:
	Move a test earlier, to allow us to avoid more work in the common case.

compiler/erl_code_gen.m:
compiler/error_util.m:
compiler/hhf.m:
compiler/inst_util.m:
compiler/ml_code_util.m:
compiler/ml_util.m:
compiler/mlds_to_c.m:
compiler/modecheck_call.m:
compiler/modecheck_util.m:
compiler/post_typecheck.m:
compiler/size_prof.m:
compiler/stack_opt.m:
compiler/stratify.m:
compiler/unused_args.m:
compiler/post_type_analysis.m:
library/erland_rtti_implementation.m:
	Minor cleanups.

------------------------------------------

CHANGES TO THE TEST SUITE:

tests/invalid/any_passed_as_ground.err_exp2:
tests/invalid/invalid_default_func_1.err_exp2:
tests/invalid/invalid_default_func_3.err_exp2:
tests/invalid/try_detism.err_exp2:
	Add second expected output files for these tests. We need alternate
	expected outputs because the numbers of some of the typeinfo variables
	mentioned in error message are different depending on whether or not
	const structures are enabled.
2012-06-08 15:37:07 +00:00
Zoltan Somogyi
7ca1a07296 Allow the MLDS backend to generate indexing switches (switches implemented
Estimated hours taken: 16
Branches: main

Allow the MLDS backend to generate indexing switches (switches implemented
more efficiently than just a if-then-else chain) for strings even if the target
language does not support gotos.

Previously, we use always used gotos to break out of search loops
after we found a match:

    do {
        if (we have a match) {
            ... handle the match ...
            goto end
        } else {
            ... handle nonmatches ...
        }
    } while (loop should continue);
    maybe some code to handle the failure of the search
end:

Now, if the "maybe some code" is empty, we prefer to use break statements
if the target language supports this:

    do {
        if (we have a match) {
            ... handle the match ...
            break;
        } else {
            ... handle nonmatches ...
        }
    } while (loop should continue)

If we cannot use either gotos or break statements, we instead use
a boolean variable named "stop_loop":

    stop_loop = 0;
    do {
        if (we have a match) {
            ... handle the match ...
            stop_loop = 1;
        } else {
            ... handle nonmatches ...
        }
    } while (stop_loop == 0 && loop should continue)
    if (stop_loop == 0) {
    	maybe some code to handle the failure of the search
    }

We omit the final if statement if the then-part would be empty.

The break method generates the smallest code, followed by the goto code.
I don't have information on speed, since we don't have a benchmark that
runs long enough, and the compiler itself does not spend any significant
amount of time on string switches. Probably the break method is also the
fastest, simply because it leaves the code looking most like normal C code.
(Some optimizations are harder to apply to code containing gotos, and some
optimizer writers do not bother.)

For C, we now normally prefer to generate code using the second method
(breaks), if we can, though normally "maybe some code" is not empty,
in which case we use the first method (goto).

However, if the value of the --experiment option is set to "use_stop_loop",
we always use the third method, and if it is set to "use_end_label", we always
use the first, even when we could use the second. This allow us to test all
three approaches using the C back end.

With backends that support neither gotos nor break, we always use the third
method (stop_loop).

With backends that don't support gotos but do support breaks, we also always
use the third method. This is because trying to use the second method would
require us to commit to not creating the stop_loop variable BEFORE we know
that the "maybe some code to handle the failure of the search" is empty,
and if it isn't empty, then we don't have the goto method to fall back on.

compiler/ml_string_switch.m:
	Make the change described above. Where possible, make the required
	change not to the original code, but to a version in which common
	parts have been factored out. (Previously, the duplicated code was
	small; now, it would be big.)

compiler/ml_target_util.m:
	A new module containing existing functions that test various properties
	of the target language. Keeping some of those functions in their
	original modules would have introduced a circular dependency.

compiler/ml_switch_gen.m:
	Enable the new functionality by removing the tests that previously
	prevented the compiler from using indexing switches on strings
	if the target language did not support gotos.

	Remove the code moved to ml_target_util.m.

compiler/ml_optimize.m:
compiler/ml_unify_gen.m:
	Remove the code moved to ml_target_util.m.

compiler/ml_backend.m:
compiler/notes/compiler_design.m:
	Add the new module.

compiler/ml_proc_gen.m:
	Delete a predicate that hasn't been used for a long time.

tools/makebatch:
	Fix an old pair of typos.
2011-08-15 06:23:20 +00:00
Zoltan Somogyi
de56f9b77c Implement lookup table versions of hash and binary search switches for strings
Estimated hours taken: 24
Branches: main

Implement lookup table versions of hash and binary search switches for strings
in the MLDS backend (those versions already exist in the LLDS backend).

compiler/ml_string_switch.m:
	Make the above change.

	Where possible, factor out and reuse existing code.

compiler/ml_lookup_switch.m:
	Break up the predicate that used to both test a switch whether it is a
	lookup switch and also generate code for it if it was, into two parts,
	each doing just one job. The first part is now useful for switches on
	strings as well.

	Group auxiliary predicates with the main predicates they support.

	Factor out some code into new predicates, and export them for use
	by the new code in ml_string_switch.m.

	Make some predicates tail recursive.

	Remove some predicates made unnecessary by changes to lookup_switch.m.

compiler/ml_switch_gen.m:
	Invoke the new code when appropriate, and conform to the updated
	interface of ml_lookup_switch.m.

compiler/switch_util.m:
	Change some types, and the predicates that operate on them, to make
	them useful for lookup switches for the MLDS backend as well the LLDS
	backend.

	Add some utility predicates.

compiler/lookup_switch.m:
	Change the interface of some of the predicates in this module to allow
	us to factor out some common code from the higher order values passed
	by callers.

	Conform to the changes in switch_util.m.

compiler/string_switch.m:
	Conform to changes in switch_util.m.

compiler/switch_gen.m:
	Conform to changes in lookup_switch.m.
2011-08-09 05:34:35 +00:00
Peter Wang
d8c1b3eac7 Disable binary search switches for strings when targetting Java
Branches: main

compiler/ml_switch_gen.m:
	Disable binary search switches for strings when targetting Java
	as it currently requires gotos.
2011-08-03 01:20:12 +00:00