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-module(hipe_arm_cfg).
16
17-export([init/1,
18         labels/1, start_label/1,
19         succ/2,
20         map_bbs/2, fold_bbs/3,
21         bb/2, bb_add/3]).
22-export([postorder/1]).
23-export([linearise/1]).
24-export([params/1, reverse_postorder/1]).
25-export([arity/1]). % for linear scan
26%%-export([redirect_jmp/3]).
27-export([branch_preds/1]).
28
29%%% these tell cfg.inc what to define (ugly as hell)
30-define(BREADTH_ORDER,true).  % for linear scan
31-define(PARAMS_NEEDED,true).
32-define(START_LABEL_UPDATE_NEEDED,true).
33-define(MAP_FOLD_NEEDED,true).
34
35-include("hipe_arm.hrl").
36-include("../flow/cfg.hrl").
37-include("../flow/cfg.inc").
38
39init(Defun) ->
40  Code = hipe_arm:defun_code(Defun),
41  StartLab = hipe_arm:label_label(hd(Code)),
42  Data = hipe_arm:defun_data(Defun),
43  IsClosure = hipe_arm:defun_is_closure(Defun),
44  Name = hipe_arm:defun_mfa(Defun),
45  IsLeaf = hipe_arm:defun_is_leaf(Defun),
46  Formals = hipe_arm:defun_formals(Defun),
47  CFG0 = mk_empty_cfg(Name, StartLab, Data, IsClosure, IsLeaf, Formals),
48  take_bbs(Code, CFG0).
49
50is_branch(I) ->
51  case I of
52    #b_fun{} -> true;
53    #b_label{'cond'='al'} -> true;
54    #pseudo_bc{} -> true;
55    #pseudo_blr{} -> true;
56    #pseudo_bx{} -> true;
57    #pseudo_call{} -> true;
58    #pseudo_switch{} -> true;
59    #pseudo_tailcall{} -> true;
60    _ -> false
61  end.
62
63branch_successors(Branch) ->
64  case Branch of
65    #b_fun{} -> [];
66    #b_label{'cond'='al',label=Label} -> [Label];
67    #pseudo_bc{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
68    #pseudo_blr{} -> [];
69    #pseudo_bx{} -> [];
70    #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=ExnLab}} ->
71      case ExnLab of
72	[] -> [ContLab];
73	_ -> [ContLab,ExnLab]
74      end;
75    #pseudo_switch{labels=Labels} -> Labels;
76    #pseudo_tailcall{} -> []
77  end.
78
79branch_preds(Branch) ->
80  case Branch of
81    #pseudo_bc{true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
82      [{FalseLab, 1.0-Pred}, {TrueLab, Pred}];
83    #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=[]}} ->
84      %% A function can still cause an exception, even if we won't catch it
85      [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}];
86    #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=ExnLab}} ->
87      CallExnPred = hipe_bb_weights:call_exn_pred(),
88      [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}];
89    #pseudo_switch{labels=Labels} ->
90      Prob = 1.0/length(Labels),
91      [{L, Prob} || L <- Labels];
92    _ ->
93      case branch_successors(Branch) of
94	[] -> [];
95	[Single] -> [{Single, 1.0}]
96      end
97  end.
98
99-ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
100fails_to(_Instr) -> [].
101-endif.
102
103-ifdef(notdef).
104redirect_jmp(I, Old, New) ->
105  case I of
106    #b_label{label=Label} ->
107      if Old =:= Label -> I#b_label{label=New};
108	 true -> I
109      end;
110    #pseudo_bc{true_label=TrueLab, false_label=FalseLab} ->
111      I1 = if Old =:= TrueLab -> I#pseudo_bc{true_label=New};
112	      true -> I
113	   end,
114      if Old =:= FalseLab -> I1#pseudo_bc{false_label=New};
115	 true -> I1
116      end;
117    %% handle pseudo_call too?
118    _ -> I
119  end.
120-endif.
121
122mk_goto(Label) ->
123  hipe_arm:mk_b_label(Label).
124
125is_label(I) ->
126  hipe_arm:is_label(I).
127
128label_name(Label) ->
129  hipe_arm:label_label(Label).
130
131mk_label(Name) ->
132  hipe_arm:mk_label(Name).
133
134linearise(CFG) ->	% -> defun, not insn list
135  MFA = function(CFG),
136  Formals = params(CFG),
137  Code = linearize_cfg(CFG),
138  Data = data(CFG),
139  VarRange = hipe_gensym:var_range(arm),
140  LabelRange = hipe_gensym:label_range(arm),
141  IsClosure = is_closure(CFG),
142  IsLeaf = is_leaf(CFG),
143  hipe_arm:mk_defun(MFA, Formals, IsClosure, IsLeaf,
144		    Code, Data, VarRange, LabelRange).
145
146arity(CFG) ->
147  {_M, _F, A} = function(CFG),
148  A.
149