-
-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
See erlang/otp#7567 for details.
- Loading branch information
Showing
1 changed file
with
312 additions
and
0 deletions.
There are no files selected for viewing
312 changes: 312 additions & 0 deletions
312
patches/buildroot/0016-erlang-add-aarch64-div-rem-JIT-fix.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,312 @@ | ||
From 1aaad4a32e6fcf5df01d9f8a5447afd0e29ea8dd Mon Sep 17 00:00:00 2001 | ||
From: Frank Hunleth <fhunleth@troodon-software.com> | ||
Date: Fri, 25 Aug 2023 15:18:39 -0400 | ||
Subject: [PATCH] erlang: add aarch64 div/rem JIT fix | ||
|
||
--- | ||
...-Fix-incorrect-fusion-of-div-and-rem.patch | 293 ++++++++++++++++++ | ||
1 file changed, 293 insertions(+) | ||
create mode 100644 package/erlang/26.0.2/0004-Fix-incorrect-fusion-of-div-and-rem.patch | ||
|
||
diff --git a/package/erlang/26.0.2/0004-Fix-incorrect-fusion-of-div-and-rem.patch b/package/erlang/26.0.2/0004-Fix-incorrect-fusion-of-div-and-rem.patch | ||
new file mode 100644 | ||
index 0000000000..6f2f5957a3 | ||
--- /dev/null | ||
+++ b/package/erlang/26.0.2/0004-Fix-incorrect-fusion-of-div-and-rem.patch | ||
@@ -0,0 +1,293 @@ | ||
+From 9f46c61840c699228694716edbd31ee002e733ba Mon Sep 17 00:00:00 2001 | ||
+From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> | ||
+Date: Wed, 16 Aug 2023 18:17:31 +0200 | ||
+Subject: [PATCH] Fix incorrect fusion of `div` and `rem` | ||
+ | ||
+The JIT would generate code that calculated the remainder incorrectly | ||
+for the following example: | ||
+ | ||
+ bug(Bin) -> | ||
+ N = byte_size(Bin), | ||
+ {N rem 128, N div 128}. | ||
+ | ||
+Essentially, the JIT would rewrite the code like this: | ||
+ | ||
+ bug(Bin) -> | ||
+ N = byte_size(Bin), | ||
+ Q = N bsr 7, | ||
+ {Q band 16#7f, Q}. | ||
+ | ||
+That is, the remainder would be calculated as `(N div 128) rem 128`. | ||
+ | ||
+Fixes #7566 | ||
+--- | ||
+ erts/emulator/beam/jit/arm/instr_arith.cpp | 7 +- | ||
+ erts/emulator/test/small_SUITE.erl | 198 +++++++++++++++++++-- | ||
+ 2 files changed, 188 insertions(+), 17 deletions(-) | ||
+ | ||
+diff --git a/erts/emulator/beam/jit/arm/instr_arith.cpp b/erts/emulator/beam/jit/arm/instr_arith.cpp | ||
+index 1fbec6dbb2..485f93956d 100644 | ||
+--- a/erts/emulator/beam/jit/arm/instr_arith.cpp | ||
++++ b/erts/emulator/beam/jit/arm/instr_arith.cpp | ||
+@@ -696,9 +696,14 @@ 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)); | ||
+ } | ||
+@@ -706,7 +711,7 @@ void BeamModuleAssembler::emit_div_rem(const ArgLabel &Fail, | ||
+ 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)); | ||
+diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl | ||
+index c3ca540cd5..7d49522f05 100644 | ||
+--- a/erts/emulator/test/small_SUITE.erl | ||
++++ b/erts/emulator/test/small_SUITE.erl | ||
+@@ -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 | ||
+@@ -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, | ||
+@@ -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), | ||
+@@ -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]), | ||
+-- | ||
+2.34.1 | ||
+ | ||
-- | ||
2.34.1 | ||
|