[m-rev.] diff: compute limits of integer tags for switches over all integer types

Julien Fischer jfischer at opturion.com
Sun Jan 6 02:30:16 AEDT 2019


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.

Julien.

diff --git a/compiler/ml_switch_gen.m b/compiler/ml_switch_gen.m
index d60278c..94d7d8e 100644
--- a/compiler/ml_switch_gen.m
+++ b/compiler/ml_switch_gen.m
@@ -244,7 +244,8 @@ ml_gen_smart_atomic_switch(SwitchVar, SwitchVarType, CanFail, TaggedCases,
      module_info_get_globals(ModuleInfo, Globals),
      ( if
          ml_gen_info_get_high_level_data(!.Info, no),
-        MaybeIntSwitchInfo = int_switch(LowerLimit, UpperLimit, NumValues),
+        MaybeIntSwitchInfo = int_switch(IntSwitchInfo),
+        IntSwitchInfo = int_switch_info(LowerLimit, UpperLimit, NumValues),
          globals.lookup_bool_option(Globals, static_ground_cells, yes),
          globals.lookup_int_option(Globals, lookup_switch_size, LookupSize),
          NumConsIds >= LookupSize,
diff --git a/compiler/switch_gen.m b/compiler/switch_gen.m
index 72bad0b..182cccd 100644
--- a/compiler/switch_gen.m
+++ b/compiler/switch_gen.m
@@ -201,8 +201,8 @@ generate_atomic_or_int64_switch(ModuleInfo, Globals, CodeModel, CanFail,
          TaggedCases, GoalInfo, EndLabel, MaybeEnd, SwitchCode, !CI, !.CLD) :-
      num_cons_ids_in_tagged_cases(TaggedCases, NumConsIds, NumArms),
      ( if
-        MaybeIntSwitchInfo =
-            int_switch(LowerLimit, UpperLimit, NumValues),
+        MaybeIntSwitchInfo = int_switch(IntSwitchInfo),
+        IntSwitchInfo = int_switch_info(LowerLimit, UpperLimit, NumValues),
          % Since lookup switches rely on static ground terms to work
          % efficiently, there is no point in using a lookup switch
          % if static ground terms are not enabled. Well, actually,
@@ -242,8 +242,8 @@ generate_atomic_or_int64_switch(ModuleInfo, Globals, CodeModel, CanFail,
              NeedBitVecCheck, NeedRangeCheck,
              MaybeEnd1, MaybeEnd, SwitchCode, !CI, !.CLD)
      else if
-        MaybeIntSwitchInfo =
-            int_switch(LowerLimit, UpperLimit, NumValues),
+        MaybeIntSwitchInfo = int_switch(IntSwitchInfo),
+        IntSwitchInfo = int_switch_info(LowerLimit, UpperLimit, NumValues),
          globals.lookup_int_option(Globals, dense_switch_size,
              DenseSize),
          NumConsIds >= DenseSize,
diff --git a/compiler/switch_util.m b/compiler/switch_util.m
index 1e2fd83..5498564 100644
--- a/compiler/switch_util.m
+++ b/compiler/switch_util.m
@@ -46,13 +46,25 @@
  %

  :- type maybe_int_switch_info
-    --->    int_switch(
-                lower_limit     :: int,
-                upper_limit     :: int,
-                num_values      :: int
-            )
+    --->    int_switch(int_switch_info(int))
+    ;       uint_switch(int_switch_info(uint))
+    ;       int8_switch(int_switch_info(int8))
+    ;       uint8_switch(int_switch_info(uint8))
+    ;       int16_switch(int_switch_info(int16))
+    ;       uint16_switch(int_switch_info(uint16))
+    ;       int32_switch(int_switch_info(int32))
+    ;       uint32_switch(int_switch_info(uint32))
+    ;       int64_switch(int_switch_info(int64))
+    ;       uint64_switch(int_switch_info(uint64))
      ;       not_int_switch.

+:- type int_switch_info(T)
+    --->    int_switch_info(
+                lower_limt  :: T,
+                upper_limit :: T,
+                num_values  :: int
+            ).
+
      % tag_cases(ModuleInfo, Type, Cases, TaggedCases, MaybeIntSwitchInfo):
      %
      % Given a switch on a variable of type Type, tag each case in Cases
@@ -77,8 +89,8 @@

  :- type switch_category
      --->    atomic_switch
-            % A switch on int, char, enum or a 8-, 16 or 32-bit signed
-            % or unsigned ineger.
+            % A switch on int, uint, char, enum or a 8-, 16 or 32-bit signed or
+            % unsigned integer.

      ;       int64_switch
              % A switch on a 64-bit integer.
@@ -381,12 +393,19 @@
  :- import_module libs.options.

  :- import_module int.
+:- import_module int8.
+:- import_module int16.
+:- import_module int32.
+:- import_module int64.
  :- import_module io.
  :- import_module maybe.
  :- import_module require.
  :- import_module string.
  :- import_module uint.
  :- import_module uint8.
+:- import_module uint16.
+:- import_module uint32.
+:- import_module uint64.

  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%
@@ -406,24 +425,57 @@ tag_cases(ModuleInfo, SwitchVarType, [Case | Cases],
      Case = case(MainConsId, OtherConsIds, Goal),
      MainConsTag = cons_id_to_tag(ModuleInfo, MainConsId),
      TaggedMainConsId = tagged_cons_id(MainConsId, MainConsTag),
-    ( if MainConsTag = int_tag(int_tag_int(IntTag)) then
-        list.map_foldl4(tag_cons_id_in_int_switch(ModuleInfo),
-            OtherConsIds, TaggedOtherConsIds,
-            IntTag, LowerLimit1, IntTag, UpperLimit1,
-            1, NumValues1, is_int_switch, IsIntSwitch1),
-        TaggedCase = tagged_case(TaggedMainConsId, TaggedOtherConsIds,
-            case_id(0), Goal),
-        tag_cases_in_int_switch(ModuleInfo, SwitchVarType, 1,
-            Cases, TaggedCases,
-            LowerLimit1, LowerLimit, UpperLimit1, UpperLimit,
-            NumValues1, NumValues, IsIntSwitch1, IsIntSwitch),
+    ( if MainConsTag = int_tag(IntTag) then
          (
-            IsIntSwitch = is_int_switch,
-            MaybeIntSwitchLimits = int_switch(LowerLimit, UpperLimit,
-                NumValues)
+            IntTag = int_tag_int(IntTagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, IntTagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_uint(UIntTagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, UIntTagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_int8(Int8TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, Int8TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_uint8(UInt8TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, UInt8TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_int16(Int16TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, Int16TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
          ;
-            IsIntSwitch = is_not_int_switch,
-            MaybeIntSwitchLimits = not_int_switch
+            IntTag = int_tag_uint16(UInt16TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, UInt16TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_int32(Int32TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, Int32TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_uint32(UInt32TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, UInt32TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_int64(Int64TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, Int64TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
+        ;
+            IntTag = int_tag_uint64(UInt64TagVal),
+            tag_cases_in_int_switch(ModuleInfo, SwitchVarType,
+                TaggedMainConsId, OtherConsIds, Goal, Cases, UInt64TagVal,
+                TaggedCase, TaggedCases, MaybeIntSwitchLimits)
          )
      else
          list.map(tag_cons_id(ModuleInfo), OtherConsIds, TaggedOtherConsIds),
@@ -433,27 +485,160 @@ tag_cases(ModuleInfo, SwitchVarType, [Case | Cases],
          MaybeIntSwitchLimits = not_int_switch
      ).

-:- pred tag_cases_plain(module_info::in, mer_type::in, int::in, list(case)::in,
-    list(tagged_case)::out) is det.
+%---------------------%

-tag_cases_plain(_, _, _, [], []).
-tag_cases_plain(ModuleInfo, SwitchVarType, CaseNum, [Case | Cases],
-        [TaggedCase | TaggedCases]) :-
-    Case = case(MainConsId, OtherConsIds, Goal),
-    tag_cons_id(ModuleInfo, MainConsId, TaggedMainConsId),
-    list.map(tag_cons_id(ModuleInfo), OtherConsIds, TaggedOtherConsIds),
+:- typeclass int_tag_value(T) where [
+    func int_tag_min(T, T) = T,
+    func int_tag_max(T, T) = T,
+    pred cons_tag_is_int_tag(cons_tag::in, T::out) is semidet,
+    func wrap_int_switch_info(int_switch_info(T)) = maybe_int_switch_info
+].
+
+:- instance int_tag_value(int) where [
+    func(int_tag_min/2) is int.min,
+    func(int_tag_max/2) is int.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_int(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+        int_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(int8) where [
+    func(int_tag_min/2) is int8.min,
+    func(int_tag_max/2) is int8.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_int8(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       int8_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(int16) where [
+    func(int_tag_min/2) is int16.min,
+    func(int_tag_max/2) is int16.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_int16(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       int16_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(int32) where [
+    func(int_tag_min/2) is int32.min,
+    func(int_tag_max/2) is int32.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_int32(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+        int32_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(int64) where [
+    func(int_tag_min/2) is int64.min,
+    func(int_tag_max/2) is int64.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_int64(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       int64_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(uint) where [
+    func(int_tag_min/2) is uint.min,
+    func(int_tag_max/2) is uint.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_uint(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       uint_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(uint8) where [
+    func(int_tag_min/2) is uint8.min,
+    func(int_tag_max/2) is uint8.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_uint8(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       uint8_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(uint16) where [
+    func(int_tag_min/2) is uint16.min,
+    func(int_tag_max/2) is uint16.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_uint16(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       uint16_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(uint32) where [
+    func(int_tag_min/2) is uint32.min,
+    func(int_tag_max/2) is uint32.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_uint32(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       uint32_switch(IntSwitchInfo)
+    )
+].
+
+:- instance int_tag_value(uint64) where [
+    func(int_tag_min/2) is uint64.min,
+    func(int_tag_max/2) is uint64.max,
+    ( cons_tag_is_int_tag(ConsTag, TagVal) :-
+        ConsTag = int_tag(int_tag_uint64(TagVal))
+    ),
+    ( wrap_int_switch_info(IntSwitchInfo) =
+       uint64_switch(IntSwitchInfo)
+    )
+].
+
+:- pred tag_cases_in_int_switch(module_info::in, mer_type::in,
+    tagged_cons_id::in, list(cons_id)::in, hlds_goal::in,
+    list(case)::in, T::in, tagged_case::out, list(tagged_case)::out,
+    maybe_int_switch_info::out) is det <= int_tag_value(T).
+
+tag_cases_in_int_switch(ModuleInfo, SwitchVarType, TaggedMainConsId,
+        OtherConsIds, Goal, Cases, IntTagVal, TaggedCase, TaggedCases,
+        MaybeIntSwitchLimits) :-
+    list.map_foldl4(tag_cons_id_in_int_switch(ModuleInfo),
+        OtherConsIds, TaggedOtherConsIds,
+        IntTagVal, LowerLimit1, IntTagVal, UpperLimit1,
+        1, NumValues1, is_int_switch, IsIntSwitch1),
      TaggedCase = tagged_case(TaggedMainConsId, TaggedOtherConsIds,
-        case_id(CaseNum), Goal),
-    tag_cases_plain(ModuleInfo, SwitchVarType, CaseNum + 1, Cases,
-        TaggedCases).
+        case_id(0), Goal),
+    do_tag_cases_in_int_switch(ModuleInfo, SwitchVarType, 1,
+        Cases, TaggedCases,
+        LowerLimit1, LowerLimit, UpperLimit1, UpperLimit,
+        NumValues1, NumValues, IsIntSwitch1, IsIntSwitch),
+    (
+        IsIntSwitch = is_int_switch,
+        IntSwitchInfo = int_switch_info(LowerLimit, UpperLimit, NumValues),
+        MaybeIntSwitchLimits = wrap_int_switch_info(IntSwitchInfo)
+    ;
+        IsIntSwitch = is_not_int_switch,
+        MaybeIntSwitchLimits = not_int_switch
+    ).

-:- pred tag_cases_in_int_switch(module_info::in, mer_type::in, int::in,
-    list(case)::in, list(tagged_case)::out, int::in, int::out, int::in,
-    int::out, int::in, int::out, is_int_switch::in, is_int_switch::out) is det.
+:- pred do_tag_cases_in_int_switch(module_info::in, mer_type::in, int::in,
+    list(case)::in, list(tagged_case)::out, T::in, T::out,
+    T::in, T::out, int::in, int::out, is_int_switch::in, is_int_switch::out)
+    is det <= int_tag_value(T).

-tag_cases_in_int_switch(_, _, _, [], [], !LowerLimit, !UpperLimit,
+do_tag_cases_in_int_switch(_, _, _, [], [], !LowerLimit, !UpperLimit,
          !NumValues, !IsIntSwitch).
-tag_cases_in_int_switch(ModuleInfo, SwitchVarType, CaseNum, [Case | Cases],
+do_tag_cases_in_int_switch(ModuleInfo, SwitchVarType, CaseNum, [Case | Cases],
          [TaggedCase | TaggedCases], !LowerLimit, !UpperLimit,
          !NumValues, !IsIntSwitch) :-
      Case = case(MainConsId, OtherConsIds, Goal),
@@ -464,33 +649,49 @@ tag_cases_in_int_switch(ModuleInfo, SwitchVarType, CaseNum, [Case | Cases],
          !NumValues, !IsIntSwitch),
      TaggedCase = tagged_case(TaggedMainConsId, TaggedOtherConsIds,
          case_id(CaseNum), Goal),
-    tag_cases_in_int_switch(ModuleInfo, SwitchVarType, CaseNum + 1,
+    do_tag_cases_in_int_switch(ModuleInfo, SwitchVarType, CaseNum + 1,
          Cases, TaggedCases, !LowerLimit, !UpperLimit,
          !NumValues, !IsIntSwitch).

-:- pred tag_cons_id(module_info::in, cons_id::in, tagged_cons_id::out) is det.
-
-tag_cons_id(ModuleInfo, ConsId, TaggedConsId) :-
-    ConsTag = cons_id_to_tag(ModuleInfo, ConsId),
-    TaggedConsId = tagged_cons_id(ConsId, ConsTag).
-
  :- pred tag_cons_id_in_int_switch(module_info::in,
      cons_id::in, tagged_cons_id::out,
-    int::in, int::out, int::in, int::out, int::in, int::out,
-    is_int_switch::in, is_int_switch::out) is det.
+    T::in, T::out, T::in, T::out, int::in, int::out,
+    is_int_switch::in, is_int_switch::out) is det <= int_tag_value(T).

  tag_cons_id_in_int_switch(ModuleInfo, ConsId, TaggedConsId,
          !LowerLimit, !UpperLimit, !NumValues, !IsIntSwitch) :-
      ConsTag = cons_id_to_tag(ModuleInfo, ConsId),
      TaggedConsId = tagged_cons_id(ConsId, ConsTag),
-    ( if ConsTag = int_tag(int_tag_int(IntTag)) then
-        int.min(IntTag, !LowerLimit),
-        int.max(IntTag, !UpperLimit),
+    ( if cons_tag_is_int_tag(ConsTag, IntTag) then
+        !:LowerLimit = int_tag_min(IntTag, !.LowerLimit),
+        !:UpperLimit = int_tag_max(IntTag, !.UpperLimit),
          !:NumValues = !.NumValues + 1
      else
          !:IsIntSwitch = is_not_int_switch
      ).

+%---------------------%
+
+:- pred tag_cons_id(module_info::in, cons_id::in, tagged_cons_id::out) is det.
+
+tag_cons_id(ModuleInfo, ConsId, TaggedConsId) :-
+    ConsTag = cons_id_to_tag(ModuleInfo, ConsId),
+    TaggedConsId = tagged_cons_id(ConsId, ConsTag).
+
+:- pred tag_cases_plain(module_info::in, mer_type::in, int::in, list(case)::in,
+    list(tagged_case)::out) is det.
+
+tag_cases_plain(_, _, _, [], []).
+tag_cases_plain(ModuleInfo, SwitchVarType, CaseNum, [Case | Cases],
+        [TaggedCase | TaggedCases]) :-
+    Case = case(MainConsId, OtherConsIds, Goal),
+    tag_cons_id(ModuleInfo, MainConsId, TaggedMainConsId),
+    list.map(tag_cons_id(ModuleInfo), OtherConsIds, TaggedOtherConsIds),
+    TaggedCase = tagged_case(TaggedMainConsId, TaggedOtherConsIds,
+        case_id(CaseNum), Goal),
+    tag_cases_plain(ModuleInfo, SwitchVarType, CaseNum + 1, Cases,
+        TaggedCases).
+
  %-----------------------------------------------------------------------------%

  num_cons_ids_in_tagged_cases(TaggedCases, NumConsIds, NumArms) :-


More information about the reviews mailing list