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_x86_cfg).
16
17-export([init/1,
18         labels/1, start_label/1,
19         succ/2, pred/2,
20         bb/2, bb_add/3, map_bbs/2, fold_bbs/3]).
21-export([postorder/1, reverse_postorder/1]).
22-export([linearise/1, params/1, arity/1, redirect_jmp/3, branch_preds/1]).
23
24%%% these tell cfg.inc what to define (ugly as hell)
25-define(PRED_NEEDED,true).
26-define(BREADTH_ORDER,true).
27-define(PARAMS_NEEDED,true).
28-define(START_LABEL_UPDATE_NEEDED,true).
29-define(MAP_FOLD_NEEDED,true).
30
31-include("hipe_x86.hrl").
32-include("../flow/cfg.hrl").
33-include("../flow/cfg.inc").
34
35init(Defun) ->
36    %% XXX: this assumes that the code starts with a label insn.
37    %% Is that guaranteed?
38    Code = hipe_x86:defun_code(Defun),
39    StartLab = hipe_x86:label_label(hd(Code)),
40    Data = hipe_x86:defun_data(Defun),
41    IsClosure = hipe_x86:defun_is_closure(Defun),
42    MFA = hipe_x86:defun_mfa(Defun),
43    IsLeaf = hipe_x86:defun_is_leaf(Defun),
44    Formals = hipe_x86:defun_formals(Defun),
45    CFG0 = mk_empty_cfg(MFA, StartLab, Data, IsClosure, IsLeaf, Formals),
46    take_bbs(Code, CFG0).
47
48is_branch(I) ->
49    case I of
50	#jmp_fun{} -> true;
51	#jmp_label{} -> true;
52	#jmp_switch{} -> true;
53	#pseudo_call{} -> true;
54	#pseudo_jcc{} -> true;
55	#pseudo_tailcall{} -> true;
56	#ret{} -> true;
57	_ -> false
58    end.
59
60branch_successors(Branch) ->
61    case Branch of
62	#jmp_fun{} -> [];
63	#jmp_label{label=Label} -> [Label];
64	#jmp_switch{labels=Labels} -> Labels;
65	#pseudo_call{contlab=ContLab, sdesc=#x86_sdesc{exnlab=ExnLab}} ->
66	    case ExnLab of
67		[] -> [ContLab];
68		_ -> [ContLab,ExnLab]
69	    end;
70	#pseudo_jcc{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
71	#pseudo_tailcall{} -> [];
72	#ret{} -> []
73    end.
74
75branch_preds(Branch) ->
76  case Branch of
77    #jmp_switch{labels=Labels} ->
78      Prob = 1.0/length(Labels),
79      [{L, Prob} || L <- Labels];
80    #pseudo_call{contlab=ContLab, sdesc=#x86_sdesc{exnlab=[]}} ->
81      %% A function can still cause an exception, even if we won't catch it
82      [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}];
83    #pseudo_call{contlab=ContLab, sdesc=#x86_sdesc{exnlab=ExnLab}} ->
84      CallExnPred = hipe_bb_weights:call_exn_pred(),
85      [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}];
86    #pseudo_jcc{true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
87      [{FalseLab, 1.0-Pred}, {TrueLab, Pred}];
88    _ ->
89      case branch_successors(Branch) of
90	[] -> [];
91	[Single] -> [{Single, 1.0}]
92      end
93    end.
94
95-ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
96fails_to(_Instr) -> [].
97-endif.
98
99redirect_jmp(I, Old, New) ->
100    case I of
101	#jmp_label{label=Label} ->
102	    if Old =:= Label -> I#jmp_label{label=New};
103	       true -> I
104	    end;
105	#pseudo_jcc{true_label=TrueLab, false_label=FalseLab} ->
106	    J0 = if Old =:= TrueLab -> I#pseudo_jcc{true_label=New};
107		    true -> I
108		 end,
109	    if Old =:= FalseLab -> J0#pseudo_jcc{false_label=New};
110	       true -> J0
111	    end;
112	%% handle pseudo_call too?
113	_ -> I
114    end.
115
116%%% XXX: fix if labels can occur in operands
117%% redirect_ops(_Labels, CFG, _Map) ->
118%%   CFG.
119
120mk_goto(Label) ->
121  hipe_x86:mk_jmp_label(Label).
122
123is_label(I) ->
124  case I of #label{} -> true; _ -> false end.
125
126label_name(Label) ->
127  hipe_x86:label_label(Label).
128
129mk_label(Name) ->
130  hipe_x86:mk_label(Name).
131
132%% is_comment(I) ->
133%%   hipe_x86:is_comment(I).
134%%
135%% is_goto(I) ->
136%%   hipe_x86:is_jmp_label(I).
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(x86),
144  LabelRange = hipe_gensym:label_range(x86),
145  IsClosure = is_closure(CFG),
146  IsLeaf = is_leaf(CFG),
147  hipe_x86:mk_defun(MFA, Formals, IsClosure, IsLeaf,
148		    Code, Data, VarRange, LabelRange).
149
150arity(CFG) ->
151  {_M,_F,A} = function(CFG),
152  A.
153
154%% init_gensym(CFG) ->
155%%   HighestVar = find_highest_var(CFG),
156%%   HighestLabel = find_highest_label(CFG),
157%%   hipe_gensym:init(),
158%%   hipe_gensym:set_var(x86, HighestVar),
159%%   hipe_gensym:set_label(x86, HighestLabel).
160%%
161%% highest_var(Code) ->
162%%   hipe_x86:highest_temp(Code).
163