aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/test
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2015-09-23 07:23:15 +0200
committerBjörn Gustavsson <[email protected]>2015-09-28 10:26:39 +0200
commitc0c5943c3a2646a3383d974c2a1afcff8c5d16d3 (patch)
treeb0e7ab5d8c7aa77aadc14944703922c9f6a6edba /lib/compiler/test
parentae125a3bc62c2165a9db028e12aa6e9f90c7d9cf (diff)
downloadotp-c0c5943c3a2646a3383d974c2a1afcff8c5d16d3.tar.gz
otp-c0c5943c3a2646a3383d974c2a1afcff8c5d16d3.tar.bz2
otp-c0c5943c3a2646a3383d974c2a1afcff8c5d16d3.zip
beam_type: Improve optimization by keeping track of integers
The ASN.1 compiler often generates code similar to: f(<<0:1,...>>) -> ...; f(<<1:1,...>>) -> .... Internally that will be rewritten to (conceptually): f(<<B:1,Tail/binary>>) -> case B of 0 -> case Tail of ... end; 1 -> case Tail of ... end; _ -> error(case_clause) end. Since B comes from a bit field of one bit, we know that the only possible values are 0 and 1. Therefore the error clause can be eliminated like this: f(<<B:1,Tail/binary>>) -> case B of 0 -> case Tail of ... end; _ -> case Tail of ... end end. Similarly, we can also a deduce the range for an integer from a 'band' operation with a literal integer. While we are at it, also add a test case to improve the coverage.
Diffstat (limited to 'lib/compiler/test')
-rw-r--r--lib/compiler/test/Makefile2
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl87
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl18
3 files changed, 105 insertions, 2 deletions
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 6553d10077..0cd8618730 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -11,6 +11,7 @@ MODULES= \
beam_validator_SUITE \
beam_disasm_SUITE \
beam_except_SUITE \
+ beam_type_SUITE \
beam_utils_SUITE \
bs_bincomp_SUITE \
bs_bit_binaries_SUITE \
@@ -43,6 +44,7 @@ NO_OPT= \
andor \
apply \
beam_except \
+ beam_type \
beam_utils \
bs_construct \
bs_match \
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
new file mode 100644
index 0000000000..8d99d76180
--- /dev/null
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_type_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ integers/1,coverage/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [integers,
+ coverage
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+integers(_Config) ->
+ a = do_integers_1(2#11000),
+ b = do_integers_1(2#11001),
+
+ a = do_integers_2(<<0:1>>),
+ {'EXIT',{{case_clause,-1},_}} = (catch do_integers_2(<<1:1>>)),
+
+ ok.
+
+do_integers_1(B0) ->
+ B = B0 band 1,
+ case B band 15 of
+ 0 -> a;
+ 1 -> b
+ end.
+
+do_integers_2(Bin) ->
+ <<B:1/signed>> = Bin,
+ case B of
+ 0 -> a;
+ 1 -> b
+ end.
+
+coverage(_Config) ->
+ {'EXIT',{badarith,_}} = (catch id(1) bsl 0.5),
+ {'EXIT',{badarith,_}} = (catch id(2.0) bsl 2),
+ {'EXIT',{badarith,_}} = (catch a + 0.5),
+ {'EXIT',{badarith,_}} = (catch 2.0 * b),
+
+ {'EXIT',{badarith,_}} = (catch id(42.0) / (1 bsl 2000)),
+
+ id(id(42) band 387439739874298734983787934283479243879),
+ id(-1 band id(13)),
+
+ ok.
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 6e138b0a43..a19b152bc5 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -36,7 +36,7 @@
match_string/1,zero_width/1,bad_size/1,haystack/1,
cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1,
no_partition/1,calling_a_binary/1,binary_in_map/1,
- match_string_opt/1]).
+ match_string_opt/1,select_on_integer/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -62,7 +62,7 @@ groups() ->
otp_7498,match_string,zero_width,bad_size,haystack,
cover_beam_bool,matched_out_size,follow_fail_branch,
no_partition,calling_a_binary,binary_in_map,
- match_string_opt]}].
+ match_string_opt,select_on_integer]}].
init_per_suite(Config) ->
@@ -1225,6 +1225,20 @@ match_string_opt(Config) when is_list(Config) ->
do_match_string_opt({<<1>>,{v,V}}=T) ->
{x,V,T}.
+select_on_integer(Config) when is_list(Config) ->
+ 42 = do_select_on_integer(<<42>>),
+ <<"abc">> = do_select_on_integer(<<128,"abc">>),
+
+ {'EXIT',_} = (catch do_select_on_integer(<<0:1>>)),
+ {'EXIT',_} = (catch do_select_on_integer(<<1:1>>)),
+ {'EXIT',_} = (catch do_select_on_integer(<<0:1,0:15>>)),
+ ok.
+
+%% The ASN.1 compiler frequently generates code like this.
+do_select_on_integer(<<0:1,I:7>>) ->
+ I;
+do_select_on_integer(<<1:1,_:7,Bin/binary>>) ->
+ Bin.
check(F, R) ->
R = F().