[m-dev.] for review: MLDS string switches
Fergus Henderson
fjh at cs.mu.OZ.AU
Thu Nov 9 06:09:25 AEDT 2000
Estimated hours taken: 8
Get the MLDS back-end to generate better code for string switches.
compiler/ml_code_util.m:
compiler/ml_unify_gen.m:
Move the routines for generating static constants from
ml_unify_gen.m to ml_code_util.m, for use by ml_string_switch.m.
compiler/ml_string_switch.m:
New file, adapted from string_switch.m.
This handles generation of string switches for the MLDS back-end.
It generates string switches using string hashing and either
computed gotos or int switches.
compiler/ml_switch_gen.m:
Add support for string switches.
Export the target_supports_* predicates, for use in ml_string_switch.m.
(Perhaps these predicates should be moved into a different module?)
Add `target_supports_goto'.
compiler/notes/compiler_design.html:
Mention the new module. Also mention other MLDS modules that
have been recently added and not yet documented here.
Workspace: /home/pgrad/fjh/ws/hg
Index: compiler/ml_code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_util.m,v
retrieving revision 1.28
diff -u -d -r1.28 ml_code_util.m
--- compiler/ml_code_util.m 2000/11/08 07:23:07 1.28
+++ compiler/ml_code_util.m 2000/11/08 15:31:45
@@ -249,6 +249,18 @@
% Routines for dealing with static constants
%
+ % Generate a name for a local static constant.
+ %
+:- pred ml_format_static_const_name(string, const_seq, mlds__var_name,
+ ml_gen_info, ml_gen_info).
+:- mode ml_format_static_const_name(in, in, out, in, out) is det.
+
+ % Generate a definition of a local static constant,
+ % given the constant's name, type, and initializer.
+ %
+:- func ml_gen_static_const_defn(mlds__var_name, mlds__type, mlds__initializer,
+ prog_context) = mlds__defn.
+
% Return the declaration flags appropriate for an
% initialized local static constant.
%
@@ -1305,6 +1317,24 @@
term__var_to_int(Var, VarNumber),
string__format("%s_%d", [s(VarName), i(VarNumber)], UniqueVarName).
+ % Generate a name for a local static constant.
+ %
+ % To ensure that the names are unique, we qualify them with the
+ % pred_id and proc_id numbers, as well as a sequence number.
+ % This is needed to allow ml_elim_nested.m to hoist
+ % such constants out to top level.
+ml_format_static_const_name(BaseName, SequenceNum, ConstName) -->
+ =(MLDSGenInfo),
+ { ml_gen_info_get_pred_id(MLDSGenInfo, PredId) },
+ { ml_gen_info_get_proc_id(MLDSGenInfo, ProcId) },
+ { pred_id_to_int(PredId, PredIdNum) },
+ { proc_id_to_int(ProcId, ProcIdNum) },
+ { string__format("const_%d_%d_%d_%s", [i(PredIdNum), i(ProcIdNum),
+ i(SequenceNum), s(BaseName)], ConstName) }.
+
+ % Qualify the name of the specified variable
+ % with the current module name.
+ %
ml_qualify_var(VarName, QualifiedVarLval) -->
=(MLDSGenInfo),
{ ml_gen_info_get_module_name(MLDSGenInfo, ModuleName) },
@@ -1331,6 +1361,17 @@
Defn = data(MLDS_Type, Initializer),
DeclFlags = ml_gen_var_decl_flags,
MLDS_Defn = mlds__defn(Name, Context, DeclFlags, Defn).
+
+ % Generate a definition of a local static constant,
+ % given the constant's name, type, and initializer.
+ %
+ml_gen_static_const_defn(ConstName, ConstType, Initializer, Context) =
+ MLDS_Defn :-
+ Name = data(var(ConstName)),
+ Defn = data(ConstType, Initializer),
+ DeclFlags = ml_static_const_decl_flags,
+ MLDS_Context = mlds__make_context(Context),
+ MLDS_Defn = mlds__defn(Name, MLDS_Context, DeclFlags, Defn).
% Return the declaration flags appropriate for a local variable.
%
Index: compiler/ml_string_switch.m
===================================================================
RCS file: ml_string_switch.m
diff -N ml_string_switch.m
--- /dev/null Thu Mar 30 14:06:13 2000
+++ ml_string_switch.m Thu Nov 9 05:52:55 2000
@@ -0,0 +1,487 @@
+%-----------------------------------------------------------------------------%
+% 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.
+:- import_module mlds, ml_code_util, ml_switch_gen.
+:- import_module llds. % XXX for code_model.
+
+:- pred ml_string_switch__generate(ml_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, 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(FailLabel),
+ 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
+ %
+ ml_string_switch__hash_cases(Cases, HashMask, HashValsMap),
+ map__to_assoc_list(HashValsMap, HashValsList),
+ ml_string_switch__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, FailLabel, EndLabel, Strings, Labels, NextSlots,
+ SlotsStatements, 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
+ % Note that we generate both the switch version and the
+ % computed goto version, and then use whichever one is
+ % appropriate for the target.
+ %
+
+ ml_gen_info_get_globals(Globals),
+ { globals__lookup_bool_option(Globals, prefer_switch, PreferSwitch) },
+ (
+ { target_supports_computed_goto(Globals) },
+ \+ {
+ PreferSwitch = yes,
+ target_supports_int_switch(Globals)
+ }
+ ->
+ { UseComputedGoto = yes },
+ {
+ FoundMatch = mlds__statement(
+ block([], [
+ mlds__statement(atomic(comment(
+ "we found a match")),
+ MLDS_Context),
+ mlds__statement(atomic(comment(
+ "jump to the corresponding code")),
+ MLDS_Context),
+ mlds__statement(
+ computed_goto(lval(SlotVarLval),
+ Labels),
+ MLDS_Context)
+ ]),
+ MLDS_Context)
+ }
+ ;
+ { UseComputedGoto = no },
+ {
+ FoundMatch = mlds__statement(
+ block([], [
+ mlds__statement(atomic(comment(
+ "we found a match")),
+ MLDS_Context),
+ mlds__statement(atomic(comment(
+ "dispatch to the corresponding code")),
+ MLDS_Context),
+ mlds__statement(
+ switch(mlds__native_int_type,
+ lval(SlotVarLval),
+ SlotsCases,
+ default_is_unreachable),
+ MLDS_Context),
+ 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(
+ binop(and,
+ binop(ne,
+ lval(StringVarLval),
+ const(null(
+ ml_string_type))),
+ binop(str_eq,
+ lval(StringVarLval),
+ VarRval)
+ ),
+ FoundMatch,
+ 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)
+ ],
+ FailLabelStatement =
+ mlds__statement(
+ label(FailLabel),
+ 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] },
+ { UseComputedGoto = yes ->
+ MLDS_Statements =
+ HashLookupStatements ++
+ [FailLabelStatement, FailComment | FailStatements] ++
+ [GotoEndStatement] ++
+ SlotsStatements ++
+ [EndLabelStatement, EndComment]
+ ;
+ MLDS_Statements = HashLookupStatements ++
+ [FailComment | FailStatements] ++
+ [EndLabelStatement, EndComment]
+ }.
+
+:- pred ml_string_switch__hash_cases(ml_cases_list, int,
+ map(int, ml_cases_list)).
+:- mode ml_string_switch__hash_cases(in, in, out) is det.
+
+ml_string_switch__hash_cases([], _, Map) :-
+ map__init(Map).
+ml_string_switch__hash_cases([Case | Cases], HashMask, Map) :-
+ ml_string_switch__hash_cases(Cases, HashMask, Map0),
+ ( Case = case(_, string_constant(String0), _, _) ->
+ String = String0
+ ;
+ error("ml_string_switch__hash_cases: non-string case?")
+ ),
+ string__hash(String, HashVal0),
+ HashVal is HashVal0 /\ HashMask,
+ ( map__search(Map0, HashVal, CaseList0) ->
+ map__det_update(Map0, HashVal, [Case | CaseList0], Map)
+ ;
+ map__det_insert(Map0, HashVal, [Case], Map)
+ ).
+
+:- type hash_slot ---> hash_slot(ml_extended_case, int).
+
+:- pred ml_string_switch__calc_hash_slots(assoc_list(int, ml_cases_list),
+ map(int, ml_cases_list), map(int, hash_slot)).
+:- mode ml_string_switch__calc_hash_slots(in, in, out) is det.
+
+ % ml_string_switch__calc_hash_slots(AssocList, HashMap, Map) :-
+ % For each (HashVal - Case) pair in AssocList,
+ % allocate a hash slot in Map for the case, as follows.
+ % If the hash slot corresponding to HashVal is not
+ % already used, then use that one. Otherwise, find
+ % the next spare slot (making sure that we don't
+ % use slots which can be used for a direct match with
+ % the hash value for one of the other cases), and
+ % use it instead. Keep track of the hash chains
+ % as we do this.
+
+ml_string_switch__calc_hash_slots(HashValList, HashMap, Map) :-
+ map__init(Map0),
+ ml_string_switch__calc_hash_slots_1(HashValList, HashMap, Map0, 0,
+ Map, _).
+
+:- pred ml_string_switch__calc_hash_slots_1(assoc_list(int, ml_cases_list),
+ map(int, ml_cases_list), map(int, hash_slot), int,
+ map(int, hash_slot), int).
+:- mode ml_string_switch__calc_hash_slots_1(in, in, in, in, out, out) is det.
+
+ml_string_switch__calc_hash_slots_1([], _, Map, LastUsed, Map, LastUsed).
+ml_string_switch__calc_hash_slots_1([HashVal-Cases | Rest], HashMap, Map0,
+ LastUsed0, Map, LastUsed) :-
+ ml_string_switch__calc_hash_slots_2(Cases, HashVal, HashMap, Map0,
+ LastUsed0, Map1, LastUsed1),
+ ml_string_switch__calc_hash_slots_1(Rest, HashMap, Map1,
+ LastUsed1, Map, LastUsed).
+
+:- pred ml_string_switch__calc_hash_slots_2(ml_cases_list, int,
+ map(int, ml_cases_list), map(int, hash_slot), int,
+ map(int, hash_slot), int).
+:- mode ml_string_switch__calc_hash_slots_2(in, in, in, in, in, out, out) is det.
+
+ml_string_switch__calc_hash_slots_2([], _HashVal, _HashMap, Map, LastUsed,
+ Map, LastUsed).
+ml_string_switch__calc_hash_slots_2([Case | Cases], HashVal, HashMap, Map0,
+ LastUsed0, Map, LastUsed) :-
+ ml_string_switch__calc_hash_slots_2(Cases, HashVal, HashMap, Map0,
+ LastUsed0, Map1, LastUsed1),
+ ( map__contains(Map1, HashVal) ->
+ ml_string_switch__follow_hash_chain(Map1, HashVal, ChainEnd),
+ ml_string_switch__next_free_hash_slot(Map1, HashMap, LastUsed1,
+ Next),
+ map__lookup(Map1, ChainEnd, hash_slot(PrevCase, _)),
+ map__det_update(Map1, ChainEnd, hash_slot(PrevCase, Next),
+ Map2),
+ map__det_insert(Map2, Next, hash_slot(Case, -1), Map),
+ LastUsed = Next
+ ;
+ map__det_insert(Map1, HashVal, hash_slot(Case, -1), Map),
+ LastUsed = LastUsed1
+ ).
+
+:- pred ml_string_switch__follow_hash_chain(map(int, hash_slot), int, int).
+:- mode ml_string_switch__follow_hash_chain(in, in, out) is det.
+
+ml_string_switch__follow_hash_chain(Map, Slot, LastSlot) :-
+ map__lookup(Map, Slot, hash_slot(_, NextSlot)),
+ (
+ NextSlot >= 0,
+ map__contains(Map, NextSlot)
+ ->
+ ml_string_switch__follow_hash_chain(Map, NextSlot, LastSlot)
+ ;
+ LastSlot = Slot
+ ).
+
+ % next_free_hash_slot(M, H_M, LastUsed, FreeSlot) :-
+ % Find the next available slot FreeSlot in the hash table
+ % which is not already used (contained in M) and which is not
+ % going to be used a primary slot (contained in H_M),
+ % starting at the slot after LastUsed.
+
+:- pred ml_string_switch__next_free_hash_slot(map(int, hash_slot),
+ map(int, ml_cases_list), int, int).
+:- mode ml_string_switch__next_free_hash_slot(in, in, in, out) is det.
+
+ml_string_switch__next_free_hash_slot(Map, H_Map, LastUsed, FreeSlot) :-
+ NextSlot is LastUsed + 1,
+ (
+ \+ map__contains(Map, NextSlot),
+ \+ map__contains(H_Map, NextSlot)
+ ->
+ FreeSlot = NextSlot
+ ;
+ ml_string_switch__next_free_hash_slot(Map, H_Map, NextSlot,
+ FreeSlot)
+ ).
+
+:- pred ml_string_switch__gen_hash_slots(int::in, int::in,
+ map(int, hash_slot)::in, code_model::in, prog_context::in,
+ mlds__label::in, mlds__label::in,
+ list(mlds__initializer)::out, list(mlds__label)::out,
+ list(mlds__initializer)::out, mlds__statements::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, FailLabel, EndLabel, Strings, Labels, NextSlots,
+ MLDS_Statements, MLDS_Cases) -->
+ { MLDS_Context = mlds__make_context(Context) },
+ ( { Slot = TableSize } ->
+ {
+ Strings = [],
+ Labels = [],
+ NextSlots = [],
+ MLDS_Statements = [],
+ MLDS_Cases = []
+ }
+ ;
+ ml_string_switch__gen_hash_slot(Slot, HashSlotMap,
+ CodeModel, MLDS_Context, FailLabel, EndLabel,
+ String, Label, NextSlot, SlotStatements, SlotCases),
+ { Slot1 is Slot + 1 },
+ {
+ Strings = [String | Strings0],
+ Labels = [Label | Labels0],
+ NextSlots = [NextSlot | NextSlots0],
+ MLDS_Statements = SlotStatements ++ MLDS_Statements0,
+ MLDS_Cases = SlotCases ++ MLDS_Cases0
+ },
+ ml_string_switch__gen_hash_slots(Slot1, TableSize, HashSlotMap,
+ CodeModel, Context, FailLabel, EndLabel,
+ Strings0, Labels0, NextSlots0, MLDS_Statements0,
+ MLDS_Cases0)
+ ).
+
+:- pred ml_string_switch__gen_hash_slot(int::in, map(int, hash_slot)::in,
+ code_model::in, mlds__context::in, mlds__label::in,
+ mlds__label::in, mlds__initializer::out,
+ mlds__label::out, mlds__initializer::out,
+ mlds__statements::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,
+ FailLabel, EndLabel, init_obj(StringRval), Label,
+ init_obj(NextSlotRval), MLDS_Statements, 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_new_label(Label),
+ { string__append_list(["case """, String, """"],
+ CommentString) },
+ { LabelComment = mlds__statement(
+ atomic(comment(CommentString)),
+ MLDS_Context) },
+ { LabelStatement = mlds__statement(
+ label(Label),
+ MLDS_Context) },
+ ml_gen_goal(CodeModel, Goal, GoalStatement),
+ { JumpComment = mlds__statement(
+ atomic(comment("jump to end of switch")),
+ MLDS_Context) },
+ { JumpStatement = mlds__statement(
+ goto(EndLabel),
+ MLDS_Context) },
+ { MLDS_Statements = [LabelComment, LabelStatement,
+ GoalStatement, JumpComment, JumpStatement] },
+ { MLDS_Cases = [[match_value(const(int_const(Slot)))] -
+ GoalStatement] }
+ ;
+ { StringRval = const(null(ml_string_type)) },
+ { Label = FailLabel },
+ { NextSlotRval = const(int_const(-2)) },
+ { MLDS_Statements = [] },
+ { MLDS_Cases = [] }
+ ).
+
+:- func ml_string_type = mlds__type.
+ml_string_type = mercury_type(string_type, str_type).
Index: compiler/ml_switch_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_switch_gen.m,v
retrieving revision 1.1
diff -u -d -r1.1 ml_switch_gen.m
--- compiler/ml_switch_gen.m 2000/11/08 07:23:10 1.1
+++ compiler/ml_switch_gen.m 2000/11/08 18:46:55
@@ -64,6 +64,7 @@
:- import_module prog_data, hlds_goal, hlds_data, mlds, ml_code_util.
:- import_module llds. % XXX for code_model
+:- import_module globals.
:- import_module list.
@@ -81,15 +82,21 @@
:- type ml_extended_case ---> case(int, cons_tag, cons_id, hlds_goal).
:- type ml_cases_list == list(ml_extended_case).
+ % Succeed iff the target supports the specified construct.
+:- pred target_supports_int_switch(globals::in) is semidet.
+:- pred target_supports_string_switch(globals::in) is semidet.
+:- pred target_supports_goto(globals::in) is semidet.
+:- pred target_supports_computed_goto(globals::in) is semidet.
+
%-----------------------------------------------------------------------------%
:- implementation.
% These ones are not yet implemented yet:
-% :- import_module ml_string_switch, ml_tag_switch, ml_lookup_switch.
-:- import_module ml_dense_switch.
+% :- import_module ml_tag_switch, ml_lookup_switch.
+:- import_module ml_dense_switch, ml_string_switch.
:- import_module ml_code_gen, ml_unify_gen, ml_code_util, type_util.
-:- import_module globals, options.
+:- import_module options.
:- import_module bool, int, string, map, tree, std_util, require.
@@ -170,8 +177,6 @@
CaseVar, CodeModel, CanFail1, Context,
MLDS_Decls, MLDS_Statements)
;
-/**********
-XXX String hash switches are NYI
%
% Try using a string hash switch
%
@@ -180,12 +185,28 @@
{ list__length(TaggedCases, NumCases) },
{ globals__lookup_int_option(Globals, string_switch_size,
StringSize) },
- { NumCases >= StringSize }
+ { NumCases >= StringSize },
+ % We can implement string hash switches using either
+ % computed gotos or int switches.
+ (
+ { target_supports_computed_goto(Globals) }
+ ;
+ { target_supports_int_switch(Globals) }
+ ),
+ % XXX Currently string hash switches always use gotos.
+ % We should change that, so that we can use string hash
+ % switches for the Java back-end too.
+ { target_supports_goto(Globals) },
+ % OK, we could use a string hash switch. But should we?
+ % We may prefer to do a direct-mapped string switch.
+ \+ {
+ target_supports_string_switch(Globals),
+ globals__lookup_bool_option(Globals, prefer_switch, yes)
+ }
->
ml_string_switch__generate(TaggedCases, CaseVar, CodeModel,
CanFail, Context, MLDS_Decls, MLDS_Statements)
;
-**********/
/**********
XXX Tag switches are NYI
%
@@ -234,10 +255,6 @@
target_supports_string_switch(Globals)
).
-:- pred target_supports_int_switch(globals::in) is semidet.
-:- pred target_supports_string_switch(globals::in) is semidet.
-:- pred target_supports_computed_goto(globals::in) is semidet.
-
target_supports_int_switch(Globals) :-
globals__get_target(Globals, Target),
target_supports_int_switch_2(Target) = yes.
@@ -246,12 +263,17 @@
globals__get_target(Globals, Target),
target_supports_string_switch_2(Target) = yes.
+target_supports_goto(Globals) :-
+ globals__get_target(Globals, Target),
+ target_supports_goto_2(Target) = yes.
+
target_supports_computed_goto(Globals) :-
globals__get_target(Globals, Target),
target_supports_computed_goto_2(Target) = yes.
:- func target_supports_int_switch_2(compilation_target) = bool.
:- func target_supports_string_switch_2(compilation_target) = bool.
+:- func target_supports_goto_2(compilation_target) = bool.
:- func target_supports_computed_goto_2(compilation_target) = bool.
target_supports_int_switch_2(c) = yes.
@@ -269,6 +291,11 @@
target_supports_computed_goto_2(java) = no.
% target_supports_computed_goto_2(c_sharp) = yes.
+target_supports_goto_2(c) = yes.
+target_supports_goto_2(il) = yes.
+target_supports_goto_2(java) = no.
+% target_supports_goto_2(c_sharp) = yes.
+
%-----------------------------------------------------------------------------%
% We categorize switches according to whether the value
@@ -431,6 +458,8 @@
ml_gen_goal(CodeModel, Goal, MLDS_Statement),
{ MLDS_Case = [match_value(Rval)] - MLDS_Statement }.
+ % Generate an appropriate default for a switch.
+ %
:- pred ml_switch_generate_default(can_fail::in, code_model::in,
prog_context::in, switch_default::out,
ml_gen_info::in, ml_gen_info::out) is det.
Index: compiler/ml_unify_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_unify_gen.m,v
retrieving revision 1.22
diff -u -d -r1.22 ml_unify_gen.m
--- compiler/ml_unify_gen.m 2000/10/30 07:09:04 1.22
+++ compiler/ml_unify_gen.m 2000/11/08 15:32:29
@@ -1154,11 +1154,7 @@
{ error("ml_gen_static_const_arg_list: length mismatch") }.
% Generate the name of the local static constant
- % for a given variable. To ensure that the names
- % are unique, we qualify them with the pred_id and
- % proc_id numbers, as well as a sequence number.
- % This is needed to allow ml_elim_nested.m to hoist
- % such constants out to top level.
+ % for a given variable.
%
:- pred ml_gen_static_const_name(prog_var, mlds__var_name,
ml_gen_info, ml_gen_info).
@@ -1166,29 +1162,20 @@
ml_gen_static_const_name(Var, ConstName) -->
ml_gen_info_new_const(SequenceNum),
ml_gen_info_set_const_num(Var, SequenceNum),
- ml_format_static_const_name(Var, SequenceNum, ConstName).
+ =(MLDSGenInfo),
+ { ml_gen_info_get_varset(MLDSGenInfo, VarSet) },
+ { VarName = ml_gen_var_name(VarSet, Var) },
+ ml_format_static_const_name(VarName, SequenceNum, ConstName).
:- pred ml_lookup_static_const_name(prog_var, mlds__var_name,
ml_gen_info, ml_gen_info).
:- mode ml_lookup_static_const_name(in, out, in, out) is det.
ml_lookup_static_const_name(Var, ConstName) -->
ml_gen_info_lookup_const_num(Var, SequenceNum),
- ml_format_static_const_name(Var, SequenceNum, ConstName).
-
-:- pred ml_format_static_const_name(prog_var, const_seq, mlds__var_name,
- ml_gen_info, ml_gen_info).
-:- mode ml_format_static_const_name(in, in, out, in, out) is det.
-
-ml_format_static_const_name(Var, SequenceNum, ConstName) -->
=(MLDSGenInfo),
- { ml_gen_info_get_pred_id(MLDSGenInfo, PredId) },
- { ml_gen_info_get_proc_id(MLDSGenInfo, ProcId) },
- { pred_id_to_int(PredId, PredIdNum) },
- { proc_id_to_int(ProcId, ProcIdNum) },
{ ml_gen_info_get_varset(MLDSGenInfo, VarSet) },
{ VarName = ml_gen_var_name(VarSet, Var) },
- { string__format("const_%d_%d_%d_%s", [i(PredIdNum), i(ProcIdNum),
- i(SequenceNum), s(VarName)], ConstName) }.
+ ml_format_static_const_name(VarName, SequenceNum, ConstName).
% Generate an rval containing the address of the local static constant
% for a given variable.
@@ -1200,19 +1187,6 @@
ml_lookup_static_const_name(Var, ConstName),
ml_qualify_var(ConstName, ConstLval),
{ ConstAddrRval = mem_addr(ConstLval) }.
-
- % Generate a definition of a local static constant,
- % given the constant's name, type, and initializer.
- %
-:- func ml_gen_static_const_defn(mlds__var_name, mlds__type, mlds__initializer,
- prog_context) = mlds__defn.
-ml_gen_static_const_defn(ConstName, ConstType, Initializer, Context) =
- MLDS_Defn :-
- Name = data(var(ConstName)),
- Defn = data(ConstType, Initializer),
- DeclFlags = ml_static_const_decl_flags,
- MLDS_Context = mlds__make_context(Context),
- MLDS_Defn = mlds__defn(Name, MLDS_Context, DeclFlags, Defn).
:- pred ml_cons_name(cons_id, ctor_name, ml_gen_info, ml_gen_info).
:- mode ml_cons_name(in, out, in, out) is det.
Index: compiler/notes/compiler_design.html
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/notes/compiler_design.html,v
retrieving revision 1.51
diff -u -d -r1.51 compiler_design.html
--- compiler/notes/compiler_design.html 2000/10/14 04:00:35 1.51
+++ compiler/notes/compiler_design.html 2000/11/08 19:07:07
@@ -920,6 +920,17 @@
<h4> 4b. MLDS code generation </h4>
<ul>
<li> ml_code_gen.m converts HLDS code to MLDS.
+ The following sub-modules are used to handle different constructs:
+ <dl>
+ <dt> ml_unify_gen.m
+ <dt> ml_call_gen.m
+ <dt> ml_switch_gen.m
+ <dt> ml_string_switch.m
+ <dt> ml_dense_switch.m
+ <dl>
+ The module ml_code_util.m provides utility routines for
+ MLDS code generation. The module ml_util.m provides some
+ general utility routines for the MLDS.
<li> ml_type_gen.m converts HLDS types to MLDS.
<li> type_ctor_info.m and base_typeclass_info.m generate
the RTTI data structures defined in rtti.m and pseudo_type_info.m
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
| of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list