diff options
Diffstat (limited to 'erts/emulator/test/small_SUITE.erl')
-rw-r--r-- | erts/emulator/test/small_SUITE.erl | 674 |
1 files changed, 670 insertions, 4 deletions
diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl index cbd40042b9..10dd36a2cf 100644 --- a/erts/emulator/test/small_SUITE.erl +++ b/erts/emulator/test/small_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2019-2021. All Rights Reserved. +%% Copyright Ericsson AB 2019-2023. 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. @@ -19,8 +19,14 @@ %% -module(small_SUITE). --export([all/0, suite/0]). --export([edge_cases/1]). +-include_lib("syntax_tools/include/merl.hrl"). + +-export([all/0, suite/0, groups/0]). +-export([edge_cases/1, + addition/1, subtraction/1, multiplication/1, division/1, + test_bitwise/1, test_bsl/1, + element/1, + range_optimization/1]). -include_lib("common_test/include/ct.hrl"). @@ -29,7 +35,15 @@ suite() -> {timetrap, {minutes, 1}}]. all() -> - [edge_cases]. + [{group, p}]. + +groups() -> + [{p, [parallel], + [edge_cases, + addition, subtraction, multiplication, division, + test_bitwise, test_bsl, + element, + range_optimization]}]. edge_cases(Config) when is_list(Config) -> {MinSmall, MaxSmall} = Limits = determine_small_limits(0), @@ -111,6 +125,658 @@ arith_test_1(A, B, MinS, MaxS) -> ok. +%% Test that the JIT only omits the overflow check when it's safe. +addition(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = add_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_add_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_addition(Fs0, Mod), + ok. + +add_gen_pairs() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + %% Generate random pairs of smalls. + N = 1000, + M = MaxSmall + N div 2, + Pairs0 = [{M - rand:uniform(N), rand:uniform(N)} || + _ <- lists:seq(1, 75)], + + Seq = lists:seq(MinSmall-3, MinSmall+2) ++ + lists:seq(-5, 5), + lists:seq(MaxSmall-2, MaxSmall+2), + [{N1, N2} || N1 <- Seq, N2 <- Seq] ++ Pairs0. + +gen_add_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + ?Q("'@Name@'(X0, Y0) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + Res = X0 + Y0, + Res = X1 + Y1, + Res = Y1 + X1, + Res = X0 + Y1, + Res = X1 + Y0. "). + +test_addition([{Name,{A,B}}|T], Mod) -> + try + Res0 = A + B, + Res0 = Mod:Name(A, B), + + Res1 = -A + B, + Res1 = Mod:Name(-A, B), + + Res2 = A + (-B), + Res2 = Mod:Name(A, -B), + + Res3 = -A + (-B), + Res3 = Mod:Name(-A, -B) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + test_addition(T, Mod); +test_addition([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +subtraction(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = sub_gen_pairs(), + io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_sub_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_subtraction(Fs0, Mod), + ok. + +sub_gen_pairs() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + %% Generate random pairs of smalls. + N = 1000, + M = MaxSmall + N div 2, + Pairs0 = [{M - rand:uniform(N), M - rand:uniform(N)} || + _ <- lists:seq(1, 75)], + + [{N1, N2} || + N1 <- lists:seq(MinSmall-2, MinSmall+2), + N2 <- lists:seq(MaxSmall-2, MaxSmall+2)] ++ Pairs0. + +gen_sub_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + ?Q("'@Name@'(X0, Y0) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + Res = X0 - Y0, + Res = X1 - Y1, + Res = X0 - Y1, + Res = X1 - Y0. "). + +test_subtraction([{Name,{A,B}}|T], Mod) -> + try + Res0 = A - B, + Res0 = Mod:Name(A, B), + + Res1 = -A - B, + Res1 = Mod:Name(-A, B), + + Res2 = A - (-B), + Res2 = Mod:Name(A, -B), + + Res3 = -A - (-B), + Res3 = Mod:Name(-A, -B) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + test_subtraction(T, Mod); +test_subtraction([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +multiplication(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = mul_gen_pairs(), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_mul_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_multiplication(Fs0, Mod), + ok. + +mul_gen_pairs() -> + {_, MaxSmall} = determine_small_limits(0), + NumBitsMaxSmall = num_bits(MaxSmall), + + %% Generate random pairs of smalls. + Pairs0 = [{rand:uniform(MaxSmall),rand:uniform(MaxSmall)} || + _ <- lists:seq(1, 75)], + + %% Generate pairs of numbers whose product is small. + Pairs1 = [{N, MaxSmall div N} || N <- [1,2,3,5,17,63,64,1111,22222]] ++ Pairs0, + + %% Add prime factors of 2^59 - 1 (MAX_SMALL for 64-bit architecture + %% at the time of writing). + Pairs2 = [{179951,3203431780337}|Pairs1], + + %% Generate pairs of numbers whose product are bignums. + LeastBig = MaxSmall + 1, + Divisors = [(1 bsl Pow) + Offset || + Pow <- lists:seq(NumBitsMaxSmall - 4, NumBitsMaxSmall - 1), + Offset <- [0,1,17,20333]], + [{Div,ceil(LeastBig / Div)} || Div <- Divisors] ++ Pairs2. + +gen_mul_function({Name,{A,B}}) -> + APlusOne = A + 1, + BPlusOne = B + 1, + NumBitsA = num_bits(A), + NumBitsB = num_bits(B), + ?Q("'@Name@'(X0, Y0, More) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + Res = X0 * Y0, + Res = X1 * Y1, + Res = Y1 * X1, + if More -> + Res = X1 * _@B@, + Res = _@A@ * Y1, + <<X2:_@NumBitsA@>> = <<X0:_@NumBitsA@>>, + <<Y2:_@NumBitsB@>> = <<Y0:_@NumBitsB@>>, + Res = X2 * Y2, + Res = X1 * Y2, + Res = X2 * Y1; + true -> + Res + end. "). + +test_multiplication([{Name,{A,B}}|T], Mod) -> + try + Res0 = A * B, + %% io:format("~p * ~p = ~p; size = ~p\n", + %% [A,B,Res0,erts_debug:flat_size(Res0)]), + + Res0 = Mod:Name(A, B, true), + Res0 = Mod:Name(-A, -B, false), + + Res1 = -(A * B), + Res1 = Mod:Name(-A, B, false), + Res1 = Mod:Name(A, -B, false) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + test_multiplication(T, Mod); +test_multiplication([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +division(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = div_gen_pairs(), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_div_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_division(Fs0, Mod), + + 3 = ignore_rem(ignore, 10, 3), + 1 = ignore_div(ignore, 16, 5), + + ok. + +ignore_rem(_, X, Y) -> + _ = X rem Y, %Result in x0. + X div Y. %Reuse x0 for result. + +ignore_div(_, X, Y) -> + _ = X div Y, %Result in x0. + X rem Y. %Reuse x0 for result. + +div_gen_pairs() -> + {_, MaxSmall} = determine_small_limits(0), + NumBitsMaxSmall = num_bits(MaxSmall), + + %% Generate random pairs of smalls. + Pairs0 = [{rand:uniform(MaxSmall),rand:uniform(MaxSmall)} || + _ <- lists:seq(1, 75)], + + Pairs1 = [{rand:uniform(MaxSmall), N} || + N <- [-3,-2,-1,1,2,3,5,17,63,64,1111,22222]] ++ Pairs0, + + %% Generate pairs of numbers whose product are bignums. + [{rand:uniform(MaxSmall),1 bsl Pow} || + Pow <- lists:seq(NumBitsMaxSmall - 4, NumBitsMaxSmall - 1)] ++ Pairs1. + + +gen_div_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + NumBitsA = num_bits(abs(A)+1), + NumBitsB = num_bits(abs(B)+1), + ?Q("'@Name@'(integer0, X0, Y0) -> + 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@'(integer1, X, fixed) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(integer2, X, fixed) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(number0, X, Y) when -_@APlusOne@ < X, X < _@APlusOne@, + -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(number1, X, Y) when -_@APlusOne@ < X, X < _@APlusOne@, + -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + R = X rem Y, + Q = X div Y, + {Q, R}. "). + +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(number0, A, B), + Res0 = F(number1, A, B) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + test_division(T, Mod); +test_division([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +test_bitwise(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = bitwise_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_bitwise_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_bitwise(Fs0, Mod), + + %% Test invalid operands. + expect_badarith(fun(X) -> 42 band X end), + expect_badarith(fun(X) -> 42 bor X end), + expect_badarith(fun(X) -> 42 bxor X end), + expect_badarith(fun(X) -> X band 42 end), + expect_badarith(fun(X) -> X bor 42 end), + expect_badarith(fun(X) -> X bxor 42 end), + expect_fc(fun(X) when is_integer(42 band X) -> ok end), + expect_fc(fun(X) when is_integer(42 bor X) -> ok end), + expect_fc(fun(X) when is_integer(42 bxor X) -> ok end), + expect_fc(fun(X) when is_integer(X band 42) -> ok end), + expect_fc(fun(X) when is_integer(X bor 42) -> ok end), + expect_fc(fun(X) when is_integer(X bxor 42) -> ok end), + + ok. + +expect_fc(Fun) -> + {'EXIT',{function_clause,_}} = catch Fun(id(bad)), + ok. + +expect_badarith(Fun) -> + {'EXIT',{badarith,_}} = catch Fun(id(bad)), + ok. + +bitwise_gen_pairs() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + %% Generate random pairs of smalls. + N = 1000, + M = MaxSmall + N div 2, + Pairs0 = [{M - rand:uniform(N), rand:uniform(N)} || + _ <- lists:seq(1, 75)], + + Seq = lists:seq(MinSmall-3, MinSmall+2) ++ + lists:seq(-5, 5), + lists:seq(MaxSmall-2, MaxSmall+2), + [{N1, N2} || N1 <- Seq, N2 <- Seq] ++ Pairs0. + +gen_bitwise_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + ?Q("'@Name@'(X0, Y0) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + + AndRes = X0 band Y0, + AndRes = X1 band Y1, + AndRes = Y1 band X1, + AndRes = X0 band Y1, + AndRes = X1 band Y0, + + OrRes = X0 bor Y0, + OrRes = X1 bor Y1, + OrRes = Y1 bor X1, + OrRes = X0 bor Y1, + OrRes = X1 bor Y0, + + XorRes = X0 bxor Y0, + XorRes = X1 bxor Y1, + XorRes = Y1 bxor X1, + XorRes = X0 bxor Y1, + XorRes = X1 bxor Y0, + + {AndRes, OrRes, XorRes}. "). + +test_bitwise([{Name,{A,B}}|T], Mod) -> + try + test_bitwise_1(A, B, Mod, Name), + test_bitwise_1(-A, B, Mod, Name), + test_bitwise_1(A, -B, Mod, Name), + test_bitwise_1(-A, -B, Mod, Name) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + test_bitwise(T, Mod); +test_bitwise([], _) -> + ok. + +test_bitwise_1(A, B, Mod, Name) -> + AndRes = A band B, + OrRes = A bor B, + XorRes = A bxor B, + {AndRes, OrRes, XorRes} = Mod:Name(A, B), + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +test_bsl(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = bsl_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_bsl_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_bsl(Fs0, Mod), + ok. + +bsl_gen_pairs() -> + {_MinSmall, MaxSmall} = determine_small_limits(0), + SmallBits = num_bits(MaxSmall), + + [{N,S} || + P <- lists:seq(20, SmallBits), + N <- [(1 bsl P)-rand:uniform(1000), (1 bsl P)-1, 1 bsl P], + S <- lists:seq(SmallBits-P-4, SmallBits - P + 3)]. + +gen_bsl_function({Name,{N,S}}) -> + Mask = (1 bsl num_bits(N)) - 1, + ?Q("'@Name@'(N0) -> + N = N0 band _@Mask@, + N bsl _@S@. "). + +test_bsl([{Name,{N,S}}|T], Mod) -> + Res = N bsl S, + try Mod:Name(N) of + Res -> + ok + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,N,S]), + erlang:raise(C, R, Stk) + end, + test_bsl(T, Mod); +test_bsl([], _) -> + ok. + +element(_Config) -> + %% Test element_1: Can't fail for integer arguments. + zero = element_1(0), + one = element_1(1), + two = element_1(2), + three = element_1(3), + + three = element_1(3-4), + two = element_1(2-4), + one = element_1(1-4), + zero = element_1(0-4), + + zero = element_1(0+4), + one = element_1(1+4), + + {'EXIT',{badarith,_}} = catch element_1(id(a)), + + %% Test element_2: Test that it fails for 0. + one = element_2(1), + two = element_2(2), + three = element_2(3), + + one = element_2(1+4), + two = element_2(2+4), + three = element_2(3+4), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_2(id(0)), + {'EXIT',{badarith,_}} = catch element_2(id(b)), + + %% Test element_3: Test that if fails for integers less than 1. + one = element_3(1), + two = element_3(2), + three = element_3(3), + + one = element_3(1+4), + two = element_3(2+4), + three = element_3(3+4), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_3(id(0)), + {'EXIT',{badarg,_}} = catch element_3(id(-1)), + {'EXIT',{badarg,_}} = catch element_3(id(-999)), + {'EXIT',{badarith,_}} = catch element_3(id(c)), + + %% Test element_4: Test that it fails for integers outside of the range 1..3. + one = element_4(1), + two = element_4(2), + three = element_4(3), + + one = element_4(1+8), + two = element_4(2+8), + three = element_4(3+8), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_4(id(0)), + {'EXIT',{badarg,[{erlang,element,[5,{one,two,three}],_}|_]}} = + catch element_4(id(5)), + {'EXIT',{badarg,_}} = catch element_4(id(-1)), + {'EXIT',{badarg,[{erlang,element,[-7,{one,two,three}],_}|_]}} = + catch element_4(id(-999)), + {'EXIT',{badarith,_}} = catch element_4(id(d)), + + %% Test element_5: Test that it fails for integers outside of the + %% range 0..3. + zero = element_5(0), + one = element_5(1), + two = element_5(2), + three = element_5(3), + + zero = element_5(0+8), + one = element_5(1+8), + two = element_5(2+8), + three = element_5(3+8), + + {'EXIT',{badarg,[{erlang,element,[5,{zero,one,two,three}],_}|_]}} = + catch element_5(id(4)), + {'EXIT',{badarg,[{erlang,element,[0,{zero,one,two,three}],_}|_]}} = + catch element_5(id(-1)), + {'EXIT',{badarith,_}} = catch element_5(id(e)), + + %% element_6: Test that it fails for values outside of 0..3. + zero = element_6(0), + one = element_6(1), + two = element_6(2), + three = element_6(3), + + {'EXIT',{badarg,[{erlang,element,[5,{zero,one,two,three}],_}|_]}} = + catch element_6(id(4)), + {'EXIT',{badarg,[{erlang,element,[0,{zero,one,two,three}],_}|_]}} = + catch element_6(id(-1)), + + %% Test element_7: Test that it fails for values outside of 1..3. + one = element_7(1), + two = element_7(2), + three = element_7(3), + + one = element_7(1+5), + two = element_7(2+5), + three = element_7(3+5), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_7(id(0)), + {'EXIT',{badarg,[{erlang,element,[4,{one,two,three}],_}|_]}} = + catch element_7(id(4)), + {'EXIT',{badarith,_}} = catch element_7(id(f)), + + %% element_8: Test that it works in a guard. + ok = element_8(id(1), id(a)), + error = element_8(id(1), id(b)), + error = element_8(id(-1), whatever), + error = element_8(id(0), whatever), + error = element_8(id(5), whatever), + + ok. + +element_1(N0) -> + N = N0 band 3, + element(N + 1, {zero,one,two,three}). + +element_2(N0) -> + N = N0 band 3, + element(N, {one,two,three}). + +element_3(N0) -> + N = N0 rem 4, + element(N, {one,two,three}). + +element_4(N0) -> + N = N0 rem 8, + element(N, {one,two,three}). + +element_5(N0) -> + N = N0 rem 8, + element(N + 1, {zero,one,two,three}). + +element_6(N) when is_integer(N) -> + element(N + 1, {zero,one,two,three}). + +element_7(N0) -> + N = N0 rem 5, + %% Max N is one more than the size of the tuple. + element(N, {one,two,three}). + +element_8(N0, E) -> + N = N0 rem 8, + if + element(N, {a,b,c,d}) =:= E -> + ok; + true -> + error + end. + +%% Test basic range optimization of arguments. +range_optimization(_Config) -> + immed_reg_confusion(), + + ok. + +%% The JIT confused x15/y15 with smalls when checking whether an argument fell +%% within the range of a small, because `is_small(arg.getValue())` happened to +%% be true. +immed_reg_confusion() -> + M = any_integer(1), + N = any_integer(1 bsl 128), + Res = any_integer(M bor N), + + Res = bor_x0_x15(M, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, N), + + ok. + +bor_x0_x15(_x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7, _x8, _x9, + _x10, _x11, _x12, _x13, _x14, _x15) -> + _x0 bor _x15. + +any_integer(I) -> + case id(I) of + N when is_integer(N) -> N + end. + +%%% +%%% Helpers. +%%% + +gen_func_names([E|Es], I) -> + Name = list_to_atom("f" ++ integer_to_list(I)), + [{Name,E}|gen_func_names(Es, I+1)]; +gen_func_names([], _) -> []. + +num_bits(Int) when Int >= 0 -> + num_bits(Int, 0). + +num_bits(0, N) -> N; +num_bits(Int, N) -> num_bits(Int bsr 1, N + 1). + %% Verifies that N is a small when it should be verify_kind(N, MinS, MaxS) -> true = is_small(N) =:= (N >= MinS andalso N =< MaxS). |