Skip to content

Commit

Permalink
Merge branch 'maint'
Browse files Browse the repository at this point in the history
* maint:
  Eliminate consistency failure for non-matching binary pattern
  Fix incorrect fusion of `div` and `rem`
  • Loading branch information
bjorng committed Aug 18, 2023
2 parents 4697f9c + 0db74ed commit dd69768
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 20 deletions.
7 changes: 6 additions & 1 deletion erts/emulator/beam/jit/arm/instr_arith.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,17 +696,22 @@ void BeamModuleAssembler::emit_div_rem(const ArgLabel &Fail,
if (Support::isPowerOf2(divisor) &&
std::get<0>(getClampedRange(LHS)) >= 0) {
int trailing_bits = Support::ctz<Eterm>(divisor);
arm::Gp LHS_reg = lhs.reg;
if (need_div) {
comment("optimized div by replacing with right shift");
ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK);
if (need_rem && quotient.reg == lhs.reg) {
LHS_reg = TMP1;
a.mov(LHS_reg, lhs.reg);
}
a.lsr(quotient.reg, lhs.reg, imm(trailing_bits));
a.orr(quotient.reg, quotient.reg, imm(_TAG_IMMED1_SMALL));
}
if (need_rem) {
comment("optimized rem by replacing with masking");
auto mask = Support::lsbMask<Uint>(trailing_bits +
_TAG_IMMED1_SIZE);
a.and_(remainder.reg, lhs.reg, imm(mask));
a.and_(remainder.reg, LHS_reg, imm(mask));
}
} else {
a.asr(TMP1, lhs.reg, imm(_TAG_IMMED1_SIZE));
Expand Down
198 changes: 182 additions & 16 deletions erts/emulator/test/small_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -521,17 +521,21 @@ div_gen_pairs() ->
{_, MaxSmall} = determine_small_limits(0),
NumBitsMaxSmall = num_bits(MaxSmall),

Divisors = [-8,-2,-1,1,2,3,4,5,8,16,17,64,22222333] ++
[1 bsl P || P <- lists:seq(8, 12) ++ lists:seq(26, 36)],

%% Generate random pairs of smalls.
Pairs0 = [{rand:uniform(MaxSmall) * rand_sign(),
Pairs0 = [{rand:uniform(MaxSmall),
rand:uniform(MaxSmall) * rand_sign()} ||
_ <- lists:seq(1, 75)],

Pairs1 = [{rand:uniform(MaxSmall), N} ||
N <- [-4,-3,-2,-1,1,2,3,5,17,63,64,1111,22222]] ++ Pairs0,
_ <- lists:seq(1, 50)],
Pairs1 = [{rand:uniform(MaxSmall), N} || N <- Divisors] ++ Pairs0,
Pairs2 = [{N, M} || N <- lists:seq(0, 7), M <- [-2,-1,1,2,3,4]] ++ Pairs1,
Pairs3 = [{abs(M) * (rand:uniform(10)+1) + rand:uniform(1000), M} ||
M <- Divisors] ++ Pairs2,

%% Generate pairs of numbers whose product are bignums.
[{rand:uniform(MaxSmall),1 bsl Pow} ||
Pow <- lists:seq(NumBitsMaxSmall - 4, NumBitsMaxSmall - 1)] ++ Pairs1.
Pow <- lists:seq(NumBitsMaxSmall - 4, NumBitsMaxSmall - 1)] ++ Pairs3.

rand_sign() ->
case rand:uniform() < 0.2 of
Expand Down Expand Up @@ -572,6 +576,22 @@ gen_div_function({Name,{A,B}}) ->
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(pos_integer1, X, fixed) when is_integer(X), 0 =< X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(pos_integer2, X, fixed) when is_integer(X), 0 =< X, X < _@APlusOne@ ->
Y = _@B@,
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(pos_integer3, X, fixed) when is_integer(X), 0 =< X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(number0, X, Y) when -_@APlusOne@ < X, X < _@APlusOne@,
-_@BPlusOne@ < Y, Y < _@BPlusOne@ ->
Q = X div Y,
Expand All @@ -593,6 +613,108 @@ gen_div_function({Name,{A,B}}) ->
Q = X div Y,
{Q, R};
'@Name@'(number4, X, fixed) when -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(any0, X, fixed) ->
Y = _@B@,
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(any1, X, fixed) ->
Y = _@B@,
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(any2, X, fixed) ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(X0, Y0, integer0) ->
Q = X0 div Y0,
R = X0 rem Y0,
if X0 > 0, Y0 > 0 ->
<<X:_@NumBitsA@>> = <<X0:_@NumBitsA@>>,
<<Y:_@NumBitsB@>> = <<Y0:_@NumBitsB@>>,
Q = X div Y,
R = X rem Y,
{Q, R};
true ->
{Q, R}
end;
'@Name@'(X, fixed, integer1) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(X, fixed, integer2) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(X, fixed, integer3) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(X, fixed, pos_integer1) when is_integer(X), 0 =< X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(X, fixed, pos_integer2) when is_integer(X), 0 =< X, X < _@APlusOne@ ->
Y = _@B@,
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(X, fixed, pos_integer3) when is_integer(X), 0 =< X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(X, Y, number0) when -_@APlusOne@ < X, X < _@APlusOne@,
-_@BPlusOne@ < Y, Y < _@BPlusOne@ ->
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(X, Y, number1) when -_@APlusOne@ < X, X < _@APlusOne@,
-_@BPlusOne@ < Y, Y < _@BPlusOne@ ->
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(X, fixed, number2) when -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(X, fixed, number3) when -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(X, fixed, number4) when -_@APlusOne@ < X, X < _@APlusOne@ ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
R = X rem Y,
{Q, R};
'@Name@'(X, fixed, any0) ->
Y = _@B@,
Q = X div Y,
R = X rem Y,
{Q, R};
'@Name@'(X, fixed, any1) ->
Y = _@B@,
R = X rem Y,
Q = X div Y,
{Q, R};
'@Name@'(X, fixed, any2) ->
Y = _@B@,
Q = X div Y,
put(prevent_div_rem_fusion, Q),
Expand All @@ -602,16 +724,60 @@ gen_div_function({Name,{A,B}}) ->
test_division([{Name,{A,B}}|T], Mod) ->
F = fun Mod:Name/3,
try
Res0 = {A div B, A rem B},
Res0 = F(integer0, A, B),
Res0 = F(integer1, A, fixed),
Res0 = F(integer2, A, fixed),
Res0 = F(integer3, A, fixed),
Res0 = F(number0, A, B),
Res0 = F(number1, A, B),
Res0 = F(number2, A, fixed),
Res0 = F(number3, A, fixed),
Res0 = F(number4, A, fixed)
PosRes = {A div B, A rem B},
NegRes = {-A div B, -A rem B},

PosRes = F(integer0, A, B),
PosRes = F(integer1, A, fixed),
PosRes = F(integer2, A, fixed),
PosRes = F(integer3, A, fixed),
PosRes = F(pos_integer1, A, fixed),
PosRes = F(pos_integer2, A, fixed),
PosRes = F(pos_integer3, A, fixed),
PosRes = F(number0, A, B),
PosRes = F(number1, A, B),
PosRes = F(number2, A, fixed),
PosRes = F(number3, A, fixed),
PosRes = F(number4, A, fixed),
PosRes = F(any0, A, fixed),
PosRes = F(any1, A, fixed),
PosRes = F(any2, A, fixed),

PosRes = F(A, B, integer0),
PosRes = F(A, fixed, integer1),
PosRes = F(A, fixed, integer2),
PosRes = F(A, fixed, integer3),
PosRes = F(A, fixed, pos_integer1),
PosRes = F(A, fixed, pos_integer2),
PosRes = F(A, fixed, pos_integer3),
PosRes = F(A, B, number0),
PosRes = F(A, B, number1),
PosRes = F(A, fixed, number2),
PosRes = F(A, fixed, number3),
PosRes = F(A, fixed, number4),
PosRes = F(A, fixed, any0),
PosRes = F(A, fixed, any1),
PosRes = F(A, fixed, any2),

NegRes = F(integer0, -A, B),
NegRes = F(integer1, -A, fixed),
NegRes = F(integer2, -A, fixed),
NegRes = F(integer3, -A, fixed),
NegRes = F(number0, -A, B),
NegRes = F(number1, -A, B),
NegRes = F(number2, -A, fixed),
NegRes = F(number3, -A, fixed),
NegRes = F(number4, -A, fixed),

NegRes = F(-A, B, integer0),
NegRes = F(-A, fixed, integer1),
NegRes = F(-A, fixed, integer2),
NegRes = F(-A, fixed, integer3),
NegRes = F(-A, B, number0),
NegRes = F(-A, B, number1),
NegRes = F(-A, fixed, number2),
NegRes = F(-A, fixed, number3),
NegRes = F(-A, fixed, number4)
catch
C:R:Stk ->
io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]),
Expand Down
5 changes: 2 additions & 3 deletions lib/compiler/src/beam_validator.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1699,9 +1699,8 @@ validate_bs_match([I|Is], Ctx, Unit0, Vst0) ->
Vst1 = update_bs_unit(Ctx, Unit, Vst0),
Vst = update_type(fun meet/2, Type, Ctx, Vst1),
validate_bs_match(Is, Ctx, Unit, Vst);
{ensure_exactly,Stride} ->
Vst = advance_bs_context(Ctx, Stride, Vst0),
validate_bs_match(Is, Ctx, Unit0, Vst);
{ensure_exactly,_Stride} ->
validate_bs_match(Is, Ctx, Unit0, Vst0);
{'=:=',nil,Bits,Value} when Bits =< 64, is_integer(Value) ->
validate_bs_match(Is, Ctx, Unit0, Vst0);
{Type0,Live,{literal,Flags},Size,Unit,Dst} when Type0 =:= binary;
Expand Down
5 changes: 5 additions & 0 deletions lib/compiler/test/bs_match_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2743,6 +2743,8 @@ bs_match(_Config) ->

{'EXIT',{{case_clause,_},_}} = catch do_bs_match_gh_6755(id(<<"1000">>)),

{'EXIT',{{badmatch,<<>>},_}} = catch do_bs_match_gh_7467(<<>>),

ok.

do_bs_match_1(_, X) ->
Expand Down Expand Up @@ -2814,6 +2816,9 @@ do_bs_match_gh_6755(B) ->
<<"b">> -> b
end.

do_bs_match_gh_7467(A) ->
do_bs_match_gh_7467(<<_:1/bits>> = A).

%% GH-6348/OTP-18297: Allow aliases for binaries.
-record(ba_foo, {a,b,c}).

Expand Down

0 comments on commit dd69768

Please sign in to comment.