mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Estimated hours taken: 6 Eliminated a lot of the dependencies on the the `code_model' type, and move that type from llds.m into a new module `code_model'. The aim of this change is to improve the modularity of the compiler by reducing the number of places in the compiler front-end that depend on back-end concepts and the number of places in the MLDS back-end which depend on the LLDS. compiler/code_model.m: New module. Contains the code_model type and associated procedures. compiler/llds.m: Move the code_model type into code_model.m. compiler/hlds_goal.m: Move the goal_info_get_code_model procedure into code_model.m, to avoid having the HLDS modules import code_model. compiler/hlds_out.m: Delete `hlds_out__write_code_model', since it wasn't being used. compiler/hlds_pred.m: Move the proc_info_interface_code_model procedure into code_model.m, to avoid having the HLDS modules import code_model. compiler/goal_path.m: When computing the `maybe_cut' field for `some' goals, compute it by comparing the determinism rather than by comparing the goal_infos. compiler/unique_modes.m: Use determinism and test for soln_count = at_most_many rather than using code_model and testing for model_non. compiler/inlining.m: Test for determinism nondet/multi rather than testing for code_model model_non. compiler/hlds_pred.m: compiler/det_report.m: Change valid_code_model_for_eval_method, which succeeded unless the eval_method was minimal_model and the code_model was model_det, to valid_determinism_for_eval_method, which succeeds unless the eval_method is minimal_model and the determinism cannot fail. As well as avoiding a dependency on code_model in the HLDS modules, this also fixes a bug where det_report could give misleading error messages, saying that `multi' was a valid determinism for `minimal_model' predicates, when in fact the compiler will always report a determinism error if you declare a `minimal_model' predicate with determinism `multi'. (Actually the code in which this bug occurs is in fact unreachable, but this is no doubt also a bug... I'll address that one in a separate change.) compiler/lookup_switch.m: Simplify the code a bit by using globals__lookup_*_option rather than globals__get_option and then getopt__lookup_option. compiler/*.m: Add `import_module' declarations for `code_model', and in some cases remove `import_module' declarations for `llds'.
295 lines
9.0 KiB
Mathematica
295 lines
9.0 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2000 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% file: ml_string_switch.m
|
|
% author: fjh (adapted from string_switch.m)
|
|
|
|
% For switches on strings, we generate a hash table using open addressing
|
|
% to resolve hash conflicts.
|
|
|
|
% WARNING: the code here is quite similar to the code in string_switch.m.
|
|
% Any changes here may require similar changes there and vice versa.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ml_string_switch.
|
|
|
|
:- interface.
|
|
|
|
:- import_module prog_data.
|
|
:- import_module hlds_data, switch_util.
|
|
:- import_module code_model.
|
|
:- import_module mlds, ml_code_util.
|
|
|
|
:- pred ml_string_switch__generate(cases_list::in, prog_var::in,
|
|
code_model::in, can_fail::in, prog_context::in,
|
|
mlds__defns::out, mlds__statements::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module ml_code_gen, ml_switch_gen, ml_simplify_switch.
|
|
:- import_module builtin_ops, type_util.
|
|
:- import_module globals, options.
|
|
|
|
:- import_module bool, int, string, list, map, std_util, assoc_list, require.
|
|
|
|
ml_string_switch__generate(Cases, Var, CodeModel, _CanFail, Context,
|
|
MLDS_Decls, MLDS_Statements) -->
|
|
{ MLDS_Context = mlds__make_context(Context) },
|
|
%
|
|
% Compute the value we're going to switch on
|
|
%
|
|
ml_gen_var(Var, VarLval),
|
|
{ VarRval = lval(VarLval) },
|
|
|
|
%
|
|
% Generate the following local variable declarations:
|
|
% int slot;
|
|
% MR_String str;
|
|
%
|
|
ml_gen_info_new_cond_var(SlotVarSeq),
|
|
{ SlotVarName = string__format("slot_%d", [i(SlotVarSeq)]) },
|
|
{ SlotVarDefn = ml_gen_mlds_var_decl(var(SlotVarName),
|
|
mlds__native_int_type, MLDS_Context) },
|
|
ml_qualify_var(SlotVarName, SlotVarLval),
|
|
|
|
ml_gen_info_new_cond_var(StringVarSeq),
|
|
{ StringVarName = string__format("str_%d", [i(StringVarSeq)]) },
|
|
{ StringVarDefn = ml_gen_mlds_var_decl(var(StringVarName),
|
|
ml_string_type, MLDS_Context) },
|
|
ml_qualify_var(StringVarName, StringVarLval),
|
|
|
|
%
|
|
% Generate new labels
|
|
%
|
|
ml_gen_new_label(EndLabel),
|
|
{ GotoEndStatement = mlds__statement(
|
|
goto(EndLabel),
|
|
MLDS_Context) },
|
|
|
|
{
|
|
% Determine how big to make the hash table.
|
|
% Currently we round the number of cases up to the nearest power
|
|
% of two, and then double it. This should hopefully ensure that
|
|
% we don't get too many hash collisions.
|
|
%
|
|
list__length(Cases, NumCases),
|
|
int__log2(NumCases, LogNumCases),
|
|
int__pow(2, LogNumCases, RoundedNumCases),
|
|
TableSize is 2 * RoundedNumCases,
|
|
HashMask is TableSize - 1,
|
|
|
|
% Compute the hash table
|
|
%
|
|
switch_util__string_hash_cases(Cases, HashMask, HashValsMap),
|
|
map__to_assoc_list(HashValsMap, HashValsList),
|
|
switch_util__calc_hash_slots(HashValsList, HashValsMap,
|
|
HashSlotsMap)
|
|
},
|
|
|
|
% Generate the code for when the hash lookup fails.
|
|
%
|
|
ml_gen_failure(CodeModel, Context, FailStatements),
|
|
|
|
% Generate the code etc. for the hash table
|
|
%
|
|
ml_string_switch__gen_hash_slots(0, TableSize, HashSlotsMap, CodeModel,
|
|
Context, Strings, NextSlots, SlotsCases),
|
|
|
|
%
|
|
% Generate the following local constant declarations:
|
|
% static const int next_slots_table = { <NextSlots> };
|
|
% static const MR_String string_table = { <Strings> };
|
|
%
|
|
ml_gen_info_new_const(NextSlotsSeq),
|
|
ml_format_static_const_name("next_slots_table", NextSlotsSeq,
|
|
NextSlotsName),
|
|
{ NextSlotsType = mlds__array_type(mlds__native_int_type) },
|
|
{ NextSlotsDefn = ml_gen_static_const_defn(NextSlotsName,
|
|
NextSlotsType,
|
|
init_array(NextSlots), Context) },
|
|
ml_qualify_var(NextSlotsName, NextSlotsLval),
|
|
|
|
ml_gen_info_new_const(StringTableSeq),
|
|
ml_format_static_const_name("string_table", StringTableSeq,
|
|
StringTableName),
|
|
{ StringTableType = mlds__array_type(ml_string_type) },
|
|
{ StringTableDefn = ml_gen_static_const_defn(StringTableName,
|
|
StringTableType, init_array(Strings), Context) },
|
|
ml_qualify_var(StringTableName, StringTableLval),
|
|
|
|
%
|
|
% Generate code which does the hash table lookup.
|
|
%
|
|
|
|
{ SwitchStmt0 = switch(mlds__native_int_type, lval(SlotVarLval),
|
|
range(0, TableSize - 1),
|
|
SlotsCases, default_is_unreachable) },
|
|
ml_simplify_switch(SwitchStmt0, MLDS_Context, SwitchStatement),
|
|
{
|
|
FoundMatchCond =
|
|
binop(and,
|
|
binop(ne,
|
|
lval(StringVarLval),
|
|
const(null(ml_string_type))),
|
|
binop(str_eq,
|
|
lval(StringVarLval),
|
|
VarRval)
|
|
),
|
|
FoundMatchCode = mlds__statement(
|
|
block([], [
|
|
mlds__statement(atomic(comment(
|
|
"we found a match")),
|
|
MLDS_Context),
|
|
mlds__statement(atomic(comment(
|
|
"dispatch to the corresponding code")),
|
|
MLDS_Context),
|
|
SwitchStatement,
|
|
GotoEndStatement
|
|
]),
|
|
MLDS_Context),
|
|
LoopBody = ml_gen_block([], [
|
|
mlds__statement(atomic(comment(
|
|
"lookup the string for this hash slot")),
|
|
MLDS_Context),
|
|
mlds__statement(
|
|
atomic(assign(StringVarLval,
|
|
binop(array_index,
|
|
lval(StringTableLval),
|
|
lval(SlotVarLval)))),
|
|
MLDS_Context),
|
|
mlds__statement(atomic(comment(
|
|
"did we find a match?")),
|
|
MLDS_Context),
|
|
mlds__statement(
|
|
if_then_else(FoundMatchCond, FoundMatchCode,
|
|
no),
|
|
MLDS_Context),
|
|
mlds__statement(atomic(comment(
|
|
"no match yet, so get next slot in hash chain")),
|
|
MLDS_Context),
|
|
mlds__statement(
|
|
atomic(assign(SlotVarLval,
|
|
binop(array_index,
|
|
lval(NextSlotsLval),
|
|
lval(SlotVarLval)))),
|
|
MLDS_Context)
|
|
],
|
|
Context),
|
|
HashLookupStatements = [
|
|
mlds__statement(
|
|
atomic(comment("hashed string switch")),
|
|
MLDS_Context),
|
|
mlds__statement(atomic(comment(
|
|
"compute the hash value of the input string")),
|
|
MLDS_Context),
|
|
mlds__statement(
|
|
atomic(assign(SlotVarLval, binop(&,
|
|
unop(std_unop(hash_string), VarRval),
|
|
const(int_const(HashMask))))),
|
|
MLDS_Context),
|
|
mlds__statement(atomic(comment(
|
|
"hash chain loop")),
|
|
MLDS_Context),
|
|
mlds__statement(
|
|
while(binop(>=, lval(SlotVarLval),
|
|
const(int_const(0))),
|
|
LoopBody,
|
|
yes), % this is a do...while loop
|
|
MLDS_Context)
|
|
],
|
|
FailComment =
|
|
mlds__statement(
|
|
atomic(comment("no match, so fail")),
|
|
MLDS_Context),
|
|
EndLabelStatement =
|
|
mlds__statement(
|
|
label(EndLabel),
|
|
MLDS_Context),
|
|
EndComment =
|
|
mlds__statement(
|
|
atomic(comment("end of hashed string switch")),
|
|
MLDS_Context)
|
|
},
|
|
|
|
%
|
|
% Collect all the generated variable/constant declarations
|
|
% and code fragments together.
|
|
%
|
|
{ MLDS_Decls = [NextSlotsDefn, StringTableDefn,
|
|
SlotVarDefn, StringVarDefn] },
|
|
{ MLDS_Statements = HashLookupStatements ++
|
|
[FailComment | FailStatements] ++
|
|
[EndLabelStatement, EndComment] }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred ml_string_switch__gen_hash_slots(int::in, int::in,
|
|
map(int, hash_slot)::in, code_model::in, prog_context::in,
|
|
list(mlds__initializer)::out, list(mlds__initializer)::out,
|
|
list(mlds__switch_case)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
ml_string_switch__gen_hash_slots(Slot, TableSize, HashSlotMap, CodeModel,
|
|
Context, Strings, NextSlots, MLDS_Cases) -->
|
|
( { Slot = TableSize } ->
|
|
{ Strings = [] },
|
|
{ NextSlots = [] },
|
|
{ MLDS_Cases = [] }
|
|
;
|
|
{ MLDS_Context = mlds__make_context(Context) },
|
|
ml_string_switch__gen_hash_slot(Slot, HashSlotMap,
|
|
CodeModel, MLDS_Context, String, NextSlot, SlotCases),
|
|
ml_string_switch__gen_hash_slots(Slot + 1, TableSize,
|
|
HashSlotMap, CodeModel, Context,
|
|
Strings0, NextSlots0, MLDS_Cases0),
|
|
{ Strings = [String | Strings0] },
|
|
{ NextSlots = [NextSlot | NextSlots0] },
|
|
{ MLDS_Cases = SlotCases ++ MLDS_Cases0 }
|
|
).
|
|
|
|
:- pred ml_string_switch__gen_hash_slot(int::in, map(int, hash_slot)::in,
|
|
code_model::in, mlds__context::in, mlds__initializer::out,
|
|
mlds__initializer::out, list(mlds__switch_case)::out,
|
|
ml_gen_info::in, ml_gen_info::out) is det.
|
|
|
|
ml_string_switch__gen_hash_slot(Slot, HashSlotMap, CodeModel, MLDS_Context,
|
|
init_obj(StringRval), init_obj(NextSlotRval), MLDS_Cases) -->
|
|
(
|
|
{ map__search(HashSlotMap, Slot, hash_slot(Case, Next)) }
|
|
->
|
|
{ NextSlotRval = const(int_const(Next)) },
|
|
{ Case = case(_, ConsTag, _, Goal) },
|
|
{ ConsTag = string_constant(String0) ->
|
|
String = String0
|
|
;
|
|
error("ml_string_switch__gen_hash_slots: string expected")
|
|
},
|
|
{ StringRval = const(string_const(String)) },
|
|
ml_gen_goal(CodeModel, Goal, GoalStatement),
|
|
|
|
{ string__append_list(["case """, String, """"],
|
|
CommentString) },
|
|
{ Comment = mlds__statement(
|
|
atomic(comment(CommentString)),
|
|
MLDS_Context) },
|
|
{ CaseStatement = mlds__statement(
|
|
block([], [Comment, GoalStatement]),
|
|
MLDS_Context) },
|
|
{ MLDS_Cases = [[match_value(const(int_const(Slot)))] -
|
|
CaseStatement] }
|
|
;
|
|
{ StringRval = const(null(ml_string_type)) },
|
|
{ NextSlotRval = const(int_const(-2)) },
|
|
{ MLDS_Cases = [] }
|
|
).
|
|
|
|
:- func ml_string_type = mlds__type.
|
|
ml_string_type = mercury_type(string_type, str_type).
|