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