aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/x86/hipe_x86_subst.erl
blob: adc2e9dc6563f2d7644778e2ce31d97b55dbc302 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
%% -*- erlang-indent-level: 2 -*-
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.

-ifdef(HIPE_AMD64).
-define(HIPE_X86_SUBST, hipe_amd64_subst).
-else.
-define(HIPE_X86_SUBST, hipe_x86_subst).
-endif.

-module(?HIPE_X86_SUBST).
-export([insn_temps/2, insn_lbls/2]).
-include("../x86/hipe_x86.hrl").

%% These should be moved to hipe_x86 and exported
-type temp()   :: #x86_temp{}.
-type oper()   :: temp() | #x86_imm{} | #x86_mem{}.
-type mfarec() :: #x86_mfa{}.
-type prim()   :: #x86_prim{}.
-type funv()   :: mfarec() | prim() | temp().
-type label()  :: non_neg_integer().
-type insn()   :: tuple(). % for now

-type subst_fun() :: fun((temp()) -> temp()).

%% @doc Maps over the temporaries in an instruction
-spec insn_temps(subst_fun(), insn()) -> insn().
insn_temps(SubstTemp, I) ->
  O = fun(O) -> oper_temps(SubstTemp, O) end,
  case I of
    #alu     {src=S, dst=D}  -> I#alu     {src=O(S), dst=O(D)};
    #cmovcc  {src=S, dst=D}  -> I#cmovcc  {src=O(S), dst=O(D)};
    #cmp     {src=S, dst=D}  -> I#cmp     {src=O(S), dst=O(D)};
    #fmove   {src=S, dst=D}  -> I#fmove   {src=O(S), dst=O(D)};
    #fp_binop{src=S, dst=D}  -> I#fp_binop{src=O(S), dst=O(D)};
    #imul    {src=S, temp=T} -> I#imul    {src=O(S), temp=O(T)};
    #lea     {mem=M, temp=T} -> I#lea     {mem=O(M), temp=O(T)};
    #move    {src=S, dst=D}  -> I#move    {src=O(S), dst=O(D)};
    #movsx   {src=S, dst=D}  -> I#movsx   {src=O(S), dst=O(D)};
    #movzx   {src=S, dst=D}  -> I#movzx   {src=O(S), dst=O(D)};
    #shift   {src=S, dst=D}  -> I#shift   {src=O(S), dst=O(D)};
    #test    {src=S, dst=D}  -> I#test    {src=O(S), dst=O(D)};
    #fp_unop{arg=[]} -> I;
    #fp_unop{arg=A}  -> I#fp_unop{arg=O(A)};
    #move64 {dst=D}  -> I#move64 {dst=O(D)};
    #push   {src=S}  -> I#push   {src=O(S)};
    #pop    {dst=D}  -> I#pop    {dst=O(D)};
    #jmp_switch{temp=T, jtab=J} ->
      I#jmp_switch{temp=O(T), jtab=jtab_temps(SubstTemp, J)};
    #pseudo_call{'fun'=F} ->
      I#pseudo_call{'fun'=funv_temps(SubstTemp, F)};
    #pseudo_tailcall{'fun'=F, stkargs=Stk} ->
      I#pseudo_tailcall{'fun'=funv_temps(SubstTemp, F),
			stkargs=lists:map(O, Stk)};
    #comment{} -> I;
    #jmp_label{} -> I;
    #pseudo_tailcall_prepare{} -> I;
    #pseudo_jcc{} -> I;
    #ret{} -> I
  end.

-spec oper_temps(subst_fun(), oper()) -> oper().
oper_temps(_SubstTemp, I=#x86_imm{}) -> I;
oper_temps(SubstTemp,  T=#x86_temp{}) -> SubstTemp(T);
oper_temps(SubstTemp,  M=#x86_mem{base=Base,off=Off}) ->
  M#x86_mem{base=oper_temps(SubstTemp, Base),
	    off =oper_temps(SubstTemp, Off)}.

-spec funv_temps(subst_fun(), funv()) -> funv().
funv_temps(_SubstTemp, MFA=#x86_mfa{}) -> MFA;
funv_temps(_SubstTemp, P=#x86_prim{}) -> P;
funv_temps(SubstTemp,  T=#x86_temp{}) -> SubstTemp(T).

%% TODO: Undo this ifdeffery at the source (make jtab an #x86_imm{} on x86)
-ifdef(HIPE_AMD64).
jtab_temps(SubstTemp, T=#x86_temp{}) -> SubstTemp(T).
-else.
jtab_temps(_SubstTemp, DataLbl) when is_integer(DataLbl) -> DataLbl.
-endif.

-type lbl_subst_fun() :: fun((label()) -> label()).

%% @doc Maps over the branch targets in an instruction
-spec insn_lbls(lbl_subst_fun(), insn()) -> insn().
insn_lbls(SubstLbl, I) ->
  case I of
    #jmp_label{label=Label} ->
      I#jmp_label{label=SubstLbl(Label)};
    #pseudo_call{sdesc=Sdesc, contlab=Contlab} ->
      I#pseudo_call{sdesc=sdesc_lbls(SubstLbl, Sdesc),
		    contlab=SubstLbl(Contlab)};
    #pseudo_jcc{true_label=T, false_label=F} ->
      I#pseudo_jcc{true_label=SubstLbl(T), false_label=SubstLbl(F)}
  end.

sdesc_lbls(_SubstLbl, Sdesc=#x86_sdesc{exnlab=[]}) -> Sdesc;
sdesc_lbls(SubstLbl, Sdesc=#x86_sdesc{exnlab=Exnlab}) ->
  Sdesc#x86_sdesc{exnlab=SubstLbl(Exnlab)}.