diff options
Diffstat (limited to 'lib/compiler/test/inline_SUITE.erl')
-rw-r--r-- | lib/compiler/test/inline_SUITE.erl | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl new file mode 100644 index 0000000000..396fb450b7 --- /dev/null +++ b/lib/compiler/test/inline_SUITE.erl @@ -0,0 +1,280 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%% Purpose : Tests inlining. + +-module(inline_SUITE). + +-include("test_server.hrl"). + +-compile(export_all). +-compile({inline,[badarg/2]}). + +%% Needed by test case `lists'. +-compile(inline_list_funcs). + +all(suite) -> + test_lib:recompile(?MODULE), + [attribute,bsdecode,bsdes,barnes2,decode1,smith,itracer,pseudoknot,lists, + really_inlined,otp_7223,coverage]. + +attribute(Config) when is_list(Config) -> + Name = "attribute", + ?line Src = filename:join(?config(data_dir, Config), Name), + ?line Out = ?config(priv_dir,Config), + + ?line {ok,attribute=Mod} = compile:file(Src, [{outdir,Out},report,time]), + ?line Outfile = filename:join(Out, Name++".beam"), + ?line {ok,{Mod,[{locals,Locals}]}} = beam_lib:chunks(Outfile, [locals]), + ?line io:format("locals: ~p\n", [Locals]), + + %% The inliner should have removed all local functions. + ?line [] = Locals, + + ok. + +-define(comp(Name), + Name(Config) when list(Config) -> + try_inline(Name, Config)). + +?comp(bsdecode). +?comp(bsdes). +?comp(barnes2). +?comp(decode1). +?comp(smith). +?comp(itracer). +?comp(pseudoknot). + +try_inline(Mod, Config) -> + ?line Src = filename:join(?config(data_dir, Config), atom_to_list(Mod)), + ?line Out = ?config(priv_dir,Config), + + %% Normal compilation. + ?line io:format("Compiling: ~s\n", [Src]), + ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]), + + ?line Dog = test_server:timetrap(test_server:minutes(10)), + ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), + ?line {ok,Node} = start_node(compiler, Pa), + ?line NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]), + ?line test_server:timetrap_cancel(Dog), + + %% Inlining. + ?line io:format("Compiling with old inliner: ~s\n", [Src]), + ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info, + {inline,1000},clint]), + + %% Run inlined code. + ?line Dog3 = test_server:timetrap(test_server:minutes(10)), + ?line OldInlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]), + ?line test_server:timetrap_cancel(Dog3), + + %% Compare results. + ?line compare(NormalResult, OldInlinedResult), + ?line NormalResult = OldInlinedResult, + + %% Inlining. + ?line io:format("Compiling with new inliner: ~s\n", [Src]), + ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report, + bin_opt_info,inline,clint]), + + %% Run inlined code. + ?line Dog4 = test_server:timetrap(test_server:minutes(10)), + ?line InlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]), + ?line test_server:timetrap_cancel(Dog4), + + %% Compare results. + ?line compare(NormalResult, InlinedResult), + ?line NormalResult = InlinedResult, + + %% Delete Beam file. + ?line ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())), + + ?line ?t:stop_node(Node), + ok. + +compare(Same, Same) -> ok; +compare([Same|T1], [Same|T2]) -> + compare(T1, T2); +compare([{X,Y,RGB1}|T1], [{X,Y,RGB2}|T2]) -> + io:format("X = ~p, Y = ~p, RGB normal = ~p, RGB inlined ~p\n", [X,Y,RGB1,RGB2]), + compare(T1, T2); +compare([H1|_], [H2|_]) -> + io:format("Normal = ~p, Inlined = ~p\n", [H1,H2]), + ?t:fail(); +compare([], []) -> ok. + +start_node(Name, Args) -> + case test_server:start_node(Name, slave, [{args,Args}]) of + {ok,Node} -> {ok, Node}; + Error -> ?line test_server:fail(Error) + end. + +load_and_call(Out, Module) -> + ?line io:format("Loading...\n",[]), + ?line code:purge(Module), + ?line LoadRc = code:load_abs(filename:join(Out, Module)), + ?line {module,Module} = LoadRc, + + ?line io:format("Calling...\n",[]), + ?line {Time,CallResult} = timer:tc(Module, Module, []), + ?line io:format("Time: ~p\n", [Time]), + CallResult. + +%% Macros used by lists/1 below. + +-define(TestHighOrder_2(Name, Body, List), + begin + put(?MODULE, []), + (fun({Res,Res2}) -> + {Res,Res2} = my_apply(lists, Name, [Body,List], []) + end)(begin + (fun(R) -> + {R,get(?MODULE)} + end)(lists:Name(Body, List)) + end) + end). + +-define(TestHighOrder_3(Name, Body, Init, List), + begin + put(?MODULE, []), + (fun({Res,Res2}) -> + {Res,Res2} = my_apply(lists, Name, [Body,Init,List], []) + end)(begin + (fun(R) -> + {R,get(?MODULE)} + end)(lists:Name(Body, Init, List)) + end) + end). + +%% For each high order function in the lists module, verify +%% that the inlined version produces the same result and is evaluated +%% in the same order as the function in the lists module. +%% +%% Note: This module must be compiled with the inline_lists_funcs option. + +lists(Config) when is_list(Config) -> + ?line List = lists:seq(1, 20), + + %% lists:map/2 + ?line ?TestHighOrder_2(map, (fun(E) -> + R = E band 16#ff, + put(?MODULE, [E|get(?MODULE)]), + R + end), List), + + %% lists:flatmap/2 + ?line ?TestHighOrder_2(flatmap, (fun(E) -> + R = lists:duplicate(E, E), + put(?MODULE, [E|get(?MODULE)]), + R + end), List), + + %% lists:foreach/2 + ?line ?TestHighOrder_2(foreach, + (fun(E) -> + put(?MODULE, [E bor 7|get(?MODULE)]) + end), List), + + %% lists:filter/2 + ?line ?TestHighOrder_2(filter, (fun(E) -> + put(?MODULE, [E|get(?MODULE)]), + (E bsr 1) band 1 =/= 0 + end), List), + + %% lists:any/2 + ?line ?TestHighOrder_2(any, (fun(E) -> + put(?MODULE, [E|get(?MODULE)]), + false %Force it to go through all. + end), List), + + %% lists:all/2 + ?line ?TestHighOrder_2(all, (fun(E) -> + put(?MODULE, [E|get(?MODULE)]), + true %Force it to go through all. + end), List), + + %% lists:foldl/3 + ?line ?TestHighOrder_3(foldl, (fun(E, A) -> + put(?MODULE, [E|get(?MODULE)]), + A bxor E + end), 0, List), + + %% lists:foldr/3 + ?line ?TestHighOrder_3(foldr, (fun(E, A) -> + put(?MODULE, [E|get(?MODULE)]), + A bxor (bnot E) + end), 0, List), + + %% lists:mapfoldl/3 + ?line ?TestHighOrder_3(mapfoldl, (fun(E, A) -> + put(?MODULE, [E|get(?MODULE)]), + {bnot E,A bxor (bnot E)} + end), 0, List), + + %% lists:mapfoldr/3 + ?line ?TestHighOrder_3(mapfoldr, (fun(E, A) -> + put(?MODULE, [E|get(?MODULE)]), + {bnot E,A bxor (bnot E)} + end), 0, List), + + %% Cleanup. + erase(?MODULE), + ok. + +my_apply(M, F, A, Init) -> + put(?MODULE, Init), + Res = apply(M, F, A), + {Res,get(?MODULE)}. + +really_inlined(Config) when is_list(Config) -> + %% Make sure that badarg/2 really gets inlined. + {'EXIT',{badarg,[{?MODULE,fail_me_now,[]}|_]}} = (catch fail_me_now()), + ok. + +fail_me_now() -> + badarg(foo(bar), []). + +foo(_X) -> + badarg. + +%% Inlined. +badarg(badarg, A) -> + erlang:error(badarg, A); +badarg(Reply, _A) -> + Reply. + +otp_7223(Config) when is_list(Config) -> + ?line {'EXIT', {{case_clause,{1}},_}} = (catch otp_7223_1(1)), + ok. + +-compile({inline,[{otp_7223_1,1}]}). +otp_7223_1(X) -> + otp_7223_2(X). + +-compile({inline,[{otp_7223_2,1}]}). +otp_7223_2({a}) -> + 1. + +coverage(Config) when is_list(Config) -> + ?line Src = filename:join(?config(data_dir, Config), bsdecode), + ?line Out = ?config(priv_dir,Config), + ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,{inline,0},clint]), + ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,{inline,20},verbose,clint]), + ?line ok = file:delete(filename:join(Out, "bsdecode"++code:objfile_extension())), + ok. |