Use the new in_range builtin.

configure.ac:
    Require the installed compiler to support this new builtin.

library/private_builtin.m:
    Declare the builtin, making it usable.

library/string.m:
    Use it to replace the old hand-written range check.
This commit is contained in:
Zoltan Somogyi
2025-10-02 18:30:47 +10:00
parent 72c9d21f5b
commit b6a0b12fc0
3 changed files with 14 additions and 34 deletions

View File

@@ -605,7 +605,7 @@ EOF
$BOOTSTRAP_MC \
--verbose \
$link_static_opt conftest \
--subtype-int2-2025-07-07 \
--inrange-2025-10-01 \
--warn-include-and-non-include \
--allow-ho-insts-as-modes \
--no-ssdb \

View File

@@ -147,9 +147,18 @@
:- pred builtin_uint64_lt(uint64::in, uint64::in) is semidet.
:- pred builtin_uint64_gt(uint64::in, uint64::in) is semidet.
% Compare two integers after casting both to unsigned.
%
:- pred unsigned_lt(int::in, int::in) is semidet.
:- pred unsigned_le(int::in, int::in) is semidet.
% in_range(X, Max) is true if and only if 0 <= X, X < Max.
%
% Implemented as the above test when targeting Java,
% and as unsigned_lt(X, Max) when targeting C or C#.
%
:- pred in_range(int::in, int::in) is semidet.
% A "typed" version of unify/2 -- i.e. one that can handle arguments
% of different types. It first unifies their types, and then (if the types
% are equal) it unifies the values.

View File

@@ -2614,7 +2614,7 @@ duplicate_char(Char, Count, String) :-
index(Str, Index, Char) :-
Len = string.count_code_units(Str),
( if string_index_is_in_bounds(Index, Len) then
( if private_builtin.in_range(Index, Len) then
unsafe_index(Str, Index, Char)
else
fail
@@ -2683,7 +2683,7 @@ index_next(Str, Index, NextIndex, Char) :-
index_next_repl(Str, Index, NextIndex, Char, MaybeReplaced) :-
Len = string.count_code_units(Str),
( if string_index_is_in_bounds(Index, Len) then
( if private_builtin.in_range(Index, Len) then
unsafe_index_next_repl(Str, Index, NextIndex, Char, MaybeReplaced)
else
fail
@@ -2777,7 +2777,7 @@ prev_index(Str, Index, PrevIndex, Char) :-
prev_index_repl(Str, Index, PrevIndex, Char, MaybeReplaced) :-
Len = string.count_code_units(Str),
( if string_index_is_in_bounds(Index - 1, Len) then
( if private_builtin.in_range(Index - 1, Len) then
unsafe_prev_index_repl(Str, Index, PrevIndex, Char, MaybeReplaced)
else
fail
@@ -2878,35 +2878,6 @@ unsafe_prev_index_repl(Str, Index, PrevIndex, Ch, MaybeReplaced) :-
}
").
%---------------------%
% XXX We should consider making this routine a compiler built-in.
%
:- pred string_index_is_in_bounds(int::in, int::in) is semidet.
:- pragma foreign_proc("C",
string_index_is_in_bounds(Index::in, Length::in),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness, no_sharing],
"
// We do not test for negative values of Index because (a) MR_Unsigned
// is unsigned and hence a negative argument will appear as a very large
// positive one after the cast and (b) anybody dealing with the case
// where strlen(Str) > MAXINT is clearly barking mad (and one may well get
// an integer overflow error in this case).
SUCCESS_INDICATOR = ((MR_Unsigned) Index < (MR_Unsigned) Length);
").
:- pragma foreign_proc("C#",
string_index_is_in_bounds(Index::in, Length::in),
[will_not_call_mercury, promise_pure, thread_safe],
"
SUCCESS_INDICATOR = ((uint) Index < (uint) Length);
").
string_index_is_in_bounds(Index, Length) :-
Index >= 0,
Index < Length.
%---------------------%
:- pragma foreign_proc("C",
@@ -2944,7 +2915,7 @@ set_char(Char, Index, Str0, Str) :-
unexpected($pred, "surrogate code point")
else
Len0 = string.count_code_units(Str0),
( if string_index_is_in_bounds(Index, Len0) then
( if private_builtin.in_range(Index, Len0) then
unsafe_set_char_copy_string(Char, Index, Len0, Str0, Str)
else
fail