1%% -*- erlang-indent-level: 2 -*-
2%%
3%% Licensed under the Apache License, Version 2.0 (the "License");
4%% you may not use this file except in compliance with the License.
5%% You may obtain a copy of the License at
6%%
7%%     http://www.apache.org/licenses/LICENSE-2.0
8%%
9%% Unless required by applicable law or agreed to in writing, software
10%% distributed under the License is distributed on an "AS IS" BASIS,
11%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12%% See the License for the specific language governing permissions and
13%% limitations under the License.
14%%----------------------------------------------------------------------
15%% File    : hipe_icode_call_elim.erl
16%% Authors : Daniel S. McCain <dsmccain@acm.org>,
17%%           Magnus Lång <margnus1@telia.com>
18%% Created : 14 Apr 2014 by Magnus Lång <margnus1@telia.com>
19%% Purpose : Eliminate calls to BIFs that are side-effect free only when
20%%           executed on some argument types.
21%%----------------------------------------------------------------------
22-module(hipe_icode_call_elim).
23-export([cfg/1]).
24
25-include("hipe_icode.hrl").
26-include("../flow/cfg.hrl").
27
28-spec cfg(cfg()) -> cfg().
29
30cfg(IcodeSSA) ->
31  lists:foldl(fun (Lbl, CFG1) ->
32		  BB1 = hipe_icode_cfg:bb(CFG1, Lbl),
33		  Code1 = hipe_bb:code(BB1),
34		  Code2 = lists:map(fun elim_insn/1, Code1),
35		  BB2 = hipe_bb:code_update(BB1, Code2),
36		  hipe_icode_cfg:bb_add(CFG1, Lbl, BB2)
37	      end, IcodeSSA, hipe_icode_cfg:labels(IcodeSSA)).
38
39-spec elim_insn(icode_instr()) -> icode_instr().
40elim_insn(Insn=#icode_call{'fun'={_,_,_}=MFA, args=Args, type=remote,
41			   dstlist=[Dst=#icode_variable{
42					   annotation={type_anno, RetType, _}}],
43			   continuation=[], fail_label=[]}) ->
44  Opaques = 'universe',
45  case erl_types:t_is_singleton(RetType, Opaques) of
46    true ->
47      ArgTypes = [case Arg of
48		    #icode_variable{annotation={type_anno, Type, _}} -> Type;
49		    #icode_const{} ->
50		      erl_types:t_from_term(hipe_icode:const_value(Arg))
51		  end || Arg <- Args],
52      case can_be_eliminated(MFA, ArgTypes) of
53	true ->
54	  Const = hipe_icode:mk_const(
55		    erl_types:t_singleton_to_term(RetType, Opaques)),
56	  #icode_move{dst=Dst, src=Const};
57	false -> Insn
58      end;
59    false -> Insn
60  end;
61elim_insn(Insn) -> Insn.
62
63
64%% A function can be eliminated for some argument types if it has no side
65%% effects when run on arguments of those types.
66
67-spec can_be_eliminated(mfa(), [erl_types:erl_type()]) -> boolean().
68
69can_be_eliminated({maps, is_key, 2}, [_K, M]) ->
70  erl_types:t_is_map(M);
71can_be_eliminated(_, _) ->
72  false.
73