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_rtl_to_sparc).
16
17-export([translate/1]).
18
19-include("../rtl/hipe_rtl.hrl").
20
21translate(RTL) ->
22  hipe_gensym:init(sparc),
23  hipe_gensym:set_var(sparc, hipe_sparc_registers:first_virtual()),
24  hipe_gensym:set_label(sparc, hipe_gensym:get_label(rtl)),
25  Map0 = vmap_empty(),
26  {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),
27  OldData = hipe_rtl:rtl_data(RTL),
28  {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),
29  {RegFormals, _} = split_args(Formals),
30  Code =
31    case RegFormals of
32      [] -> Code0;
33      _ -> [hipe_sparc:mk_label(hipe_gensym:get_next_label(sparc)) |
34	    move_formals(RegFormals, Code0)]
35    end,
36  IsClosure = hipe_rtl:rtl_is_closure(RTL),
37  IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
38  hipe_sparc:mk_defun(hipe_rtl:rtl_fun(RTL),
39		      Formals,
40		      IsClosure,
41		      IsLeaf,
42		      Code,
43		      NewData,
44		      [],
45		      []).
46
47conv_insn_list([H|T], Map, Data) ->
48  {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),
49  %% io:format("~w \n  ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),
50  {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),
51  {NewH ++ NewT, NewData2};
52conv_insn_list([], _, Data) ->
53  {[], Data}.
54
55conv_insn(I, Map, Data) ->
56  case I of
57    #alu{} -> conv_alu(I, Map, Data);
58    #alub{} -> conv_alub(I, Map, Data);
59    #call{} -> conv_call(I, Map, Data);
60    #comment{} -> conv_comment(I, Map, Data);
61    #enter{} -> conv_enter(I, Map, Data);
62    #goto{} -> conv_goto(I, Map, Data);
63    #label{} -> conv_label(I, Map, Data);
64    #load{} -> conv_load(I, Map, Data);
65    #load_address{} -> conv_load_address(I, Map, Data);
66    #load_atom{} -> conv_load_atom(I, Map, Data);
67    #move{} -> conv_move(I, Map, Data);
68    #return{} -> conv_return(I, Map, Data);
69    #store{} -> conv_store(I, Map, Data);
70    #switch{} -> conv_switch(I, Map, Data); % XXX: only switch uses/updates Data
71    #fconv{} -> conv_fconv(I, Map, Data);
72    #fmove{} -> conv_fmove(I, Map, Data);
73    #fload{} -> conv_fload(I, Map, Data);
74    #fstore{} -> conv_fstore(I, Map, Data);
75    #fp{} -> conv_fp_binary(I, Map, Data);
76    #fp_unop{} -> conv_fp_unary(I, Map, Data);
77    _ -> exit({?MODULE,conv_insn,I})
78  end.
79
80conv_fconv(I, Map, Data) ->
81  %% Dst := (double)Src, where Dst is FP reg and Src is GP reg or imm
82  {Src, Map1} = conv_src(hipe_rtl:fconv_src(I), Map),
83  {Dst, Map2} = conv_fpreg(hipe_rtl:fconv_dst(I), Map1),
84  I2 = mk_fconv(Src, Dst),
85  {I2, Map2, Data}.
86
87mk_fconv(Src, Dst) ->
88  CSP = hipe_sparc:mk_temp(14, 'untagged'), % o6
89  Offset = 100,
90  mk_store('stw', Src, CSP, Offset) ++
91  [hipe_sparc:mk_pseudo_fload(CSP, hipe_sparc:mk_simm13(Offset), Dst, true),
92   hipe_sparc:mk_fp_unary('fitod', Dst, Dst)].
93
94conv_fmove(I, Map, Data) ->
95  %% Dst := Src, where both Dst and Src are FP regs
96  {Src, Map1} = conv_fpreg(hipe_rtl:fmove_src(I), Map),
97  {Dst, Map2} = conv_fpreg(hipe_rtl:fmove_dst(I), Map1),
98  I2 = mk_fmove(Src, Dst),
99  {I2, Map2, Data}.
100
101mk_fmove(Src, Dst) ->
102  [hipe_sparc:mk_pseudo_fmove(Src, Dst)].
103
104conv_fload(I, Map, Data) ->
105  %% Dst := MEM[Base+Off], where Dst is FP reg
106  {Base1, Map1} = conv_src(hipe_rtl:fload_src(I), Map),
107  {Base2, Map2} = conv_src(hipe_rtl:fload_offset(I), Map1),
108  {Dst, Map3} = conv_fpreg(hipe_rtl:fload_dst(I), Map2),
109  I2 = mk_fload(Base1, Base2, Dst),
110  {I2, Map3, Data}.
111
112mk_fload(Base1, Base2, Dst) ->
113  case hipe_sparc:is_temp(Base1) of
114    true ->
115      case hipe_sparc:is_temp(Base2) of
116	true ->
117	  mk_fload_rr(Base1, Base2, Dst);
118	_ ->
119	  mk_fload_ri(Base1, Base2, Dst)
120      end;
121    _ ->
122      case hipe_sparc:is_temp(Base2) of
123	true ->
124	  mk_fload_ri(Base2, Base1, Dst);
125	_ ->
126	  mk_fload_ii(Base1, Base2, Dst)
127      end
128  end.
129
130mk_fload_rr(Base1, Base2, Dst) ->
131  Tmp = new_untagged_temp(),
132  Disp = hipe_sparc:mk_simm13(0),
133  [hipe_sparc:mk_alu('add', Base1, Base2, Tmp),
134   hipe_sparc:mk_pseudo_fload(Tmp, Disp, Dst, false)].
135
136mk_fload_ii(Base1, Base2, Dst) ->
137  io:format("~w: RTL fload with two immediates\n", [?MODULE]),
138  Tmp = new_untagged_temp(),
139  mk_set(Base1, Tmp, mk_fload_ri(Tmp, Base2, Dst)).
140
141mk_fload_ri(Base, Disp, Dst) ->
142  hipe_sparc:mk_fload(Base, Disp, Dst, 'new').
143
144conv_fstore(I, Map, Data) ->
145  %% MEM[Base+Off] := Src, where Src is FP reg
146  {Base1, Map1} = conv_dst(hipe_rtl:fstore_base(I), Map),
147  {Base2, Map2} = conv_src(hipe_rtl:fstore_offset(I), Map1),
148  {Src, Map3} = conv_fpreg(hipe_rtl:fstore_src(I), Map2),
149  I2 = mk_fstore(Src, Base1, Base2),
150  {I2, Map3, Data}.
151
152mk_fstore(Src, Base1, Base2) ->
153  case hipe_sparc:is_temp(Base2) of
154    true ->
155      mk_fstore_rr(Src, Base1, Base2);
156    _ ->
157      mk_fstore_ri(Src, Base1, Base2)
158  end.
159
160mk_fstore_rr(Src, Base1, Base2) ->
161  Tmp = new_untagged_temp(),
162  Disp = hipe_sparc:mk_simm13(0),
163  [hipe_sparc:mk_alu('add', Base1, Base2, Tmp),
164   hipe_sparc:mk_pseudo_fstore(Src, Tmp, Disp)].
165
166mk_fstore_ri(Src, Base, Disp) ->
167  hipe_sparc:mk_fstore(Src, Base, Disp, 'new').
168
169conv_fp_binary(I, Map, Data) ->
170  {Src1, Map1} = conv_fpreg(hipe_rtl:fp_src1(I), Map),
171  {Src2, Map2} = conv_fpreg(hipe_rtl:fp_src2(I), Map1),
172  {Dst, Map3} = conv_fpreg(hipe_rtl:fp_dst(I), Map2),
173  RtlFpOp = hipe_rtl:fp_op(I),
174  I2 = mk_fp_binary(RtlFpOp, Src1, Src2, Dst),
175  {I2, Map3, Data}.
176
177mk_fp_binary(RtlFpOp, Src1, Src2, Dst) ->
178  FpBinOp =
179    case RtlFpOp of
180      'fadd' -> 'faddd';
181      'fdiv' -> 'fdivd';
182      'fmul' -> 'fmuld';
183      'fsub' -> 'fsubd'
184    end,
185  [hipe_sparc:mk_fp_binary(FpBinOp, Src1, Src2, Dst)].
186
187conv_fp_unary(I, Map, Data) ->
188  {Src, Map1} = conv_fpreg(hipe_rtl:fp_unop_src(I), Map),
189  {Dst, Map2} = conv_fpreg(hipe_rtl:fp_unop_dst(I), Map1),
190  RtlFpUnOp = hipe_rtl:fp_unop_op(I),
191  I2 = mk_fp_unary(RtlFpUnOp, Src, Dst),
192  {I2, Map2, Data}.
193
194mk_fp_unary(RtlFpUnOp, Src, Dst) ->
195  FpUnOp =
196    case RtlFpUnOp of
197      'fchs' -> 'fnegd'
198    end,
199  [hipe_sparc:mk_fp_unary(FpUnOp, Src, Dst)].
200
201conv_alu(I, Map, Data) ->
202  %% dst = src1 aluop src2
203  {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),
204  {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),
205  {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),
206  AluOp = conv_aluop(hipe_rtl:alu_op(I)),
207  {I2, _DidCommute} = mk_alu(AluOp, Src1, Src2, Dst),
208  {I2, Map2, Data}.
209
210mk_alu(XAluOp, Src1, Src2, Dst) ->
211  case hipe_sparc:is_temp(Src1) of
212    true ->
213      case hipe_sparc:is_temp(Src2) of
214	true ->
215	  {mk_alu_rs(XAluOp, Src1, Src2, Dst),
216	   false};
217	_ ->
218	  {mk_alu_ri(XAluOp, Src1, Src2, Dst),
219	   false}
220      end;
221    _ ->
222      case hipe_sparc:is_temp(Src2) of
223	true ->
224	  mk_alu_ir(XAluOp, Src1, Src2, Dst);
225	_ ->
226	  {mk_alu_ii(XAluOp, Src1, Src2, Dst),
227	   false}
228      end
229  end.
230
231mk_alu_ii(XAluOp, Src1, Src2, Dst) ->
232  io:format("~w: ALU with two immediates (~w ~w ~w ~w)\n",
233	    [?MODULE, XAluOp, Src1, Src2, Dst]),
234  Tmp = new_untagged_temp(),
235  mk_set(Src1, Tmp, mk_alu_ri(XAluOp, Tmp, Src2, Dst)).
236
237mk_alu_ir(XAluOp, Src1, Src2, Dst) ->
238  case xaluop_commutes(XAluOp) of
239    true ->
240      {mk_alu_ri(XAluOp, Src2, Src1, Dst),
241       true};
242    _ ->
243      Tmp = new_untagged_temp(),
244      {mk_set(Src1, Tmp, mk_alu_rs(XAluOp, Tmp, Src2, Dst)),
245       false}
246  end.
247
248mk_alu_ri(XAluOp, Src1, Src2, Dst) ->
249  case xaluop_is_shift(XAluOp) of
250    true ->
251      mk_shift_ri(XAluOp, Src1, Src2, Dst);
252    false ->
253      mk_arith_ri(XAluOp, Src1, Src2, Dst)
254  end.
255
256mk_shift_ri(XShiftOp, Src1, Src2, Dst) when is_integer(Src2) ->
257  if Src2 >= 0, Src2 < 32 ->	% XXX: sparc64: < 64
258      mk_alu_rs(XShiftOp, Src1, hipe_sparc:mk_uimm5(Src2), Dst);
259     true ->
260      exit({?MODULE,mk_shift_ri,Src2})	% excessive shifts are errors
261  end.
262
263mk_arith_ri(XAluOp, Src1, Src2, Dst) when is_integer(Src2) ->
264  if -4096 =< Src2, Src2 < 4096 ->
265      mk_alu_rs(XAluOp, Src1, hipe_sparc:mk_simm13(Src2), Dst);
266     true ->
267      Tmp = new_untagged_temp(),
268      mk_set(Src2, Tmp, mk_alu_rs(XAluOp, Src1, Tmp, Dst))
269  end.
270
271mk_alu_rs(XAluOp, Src1, Src2, Dst) ->
272  [hipe_sparc:mk_alu(xaluop_normalise(XAluOp), Src1, Src2, Dst)].
273
274conv_alub(I, Map, Data) ->
275  %% dst = src1 aluop src2; if COND goto label
276  HasDst = hipe_rtl:alub_has_dst(I),
277  {Dst, Map0} =
278    case HasDst of
279      false -> {hipe_sparc:mk_g0(), Map};
280      true -> conv_dst(hipe_rtl:alub_dst(I), Map)
281    end,
282  {Src1, Map1} = conv_src(hipe_rtl:alub_src1(I), Map0),
283  {Src2, Map2} = conv_src(hipe_rtl:alub_src2(I), Map1),
284  Cond = conv_cond(hipe_rtl:alub_cond(I)),
285  RtlAlubOp = hipe_rtl:alub_op(I),
286  I2 =
287    case RtlAlubOp of
288      'mul' ->
289	%% To check for overflow in 32x32->32 multiplication:
290	%% smul Src1,Src2,Dst	% Dst is lo32(Res), %y is %hi32(Res)
291	%% rd %y,TmpHi
292	%% sra Dst,31,TmpSign	% fill TmpSign with sign of Dst
293	%% subcc TmpSign,TmpHi,%g0
294	%% [bne OverflowLabel]
295	NewCond =
296	  case Cond of
297	    vs -> ne;
298	    vc -> eq
299	  end,
300	TmpHi = hipe_sparc:mk_new_temp('untagged'),
301	TmpSign = hipe_sparc:mk_new_temp('untagged'),
302	G0 = hipe_sparc:mk_g0(),
303	{I1, _DidCommute} = mk_alu('smul', Src1, Src2, Dst),
304	I1 ++
305	[hipe_sparc:mk_rdy(TmpHi),
306	 hipe_sparc:mk_alu('sra', Dst, hipe_sparc:mk_uimm5(31), TmpSign) |
307	 conv_alub2(G0, TmpSign, 'cmpcc', NewCond, TmpHi, I)];
308      _ ->
309	XAluOp =
310	  case (not HasDst) andalso RtlAlubOp =:= 'sub' of
311	    true -> 'cmpcc'; % == a subcc that commutes
312	    false -> conv_alubop_cc(RtlAlubOp)
313	  end,
314	conv_alub2(Dst, Src1, XAluOp, Cond, Src2, I)
315    end,
316  {I2, Map2, Data}.
317
318conv_alub2(Dst, Src1, XAluOp, Cond, Src2, I) ->
319  conv_alub_bp(Dst, Src1, XAluOp, Cond, Src2, I).
320
321conv_alub_bp(Dst, Src1, XAluOp, Cond, Src2, I) ->
322  TrueLab = hipe_rtl:alub_true_label(I),
323  FalseLab = hipe_rtl:alub_false_label(I),
324  Pred = hipe_rtl:alub_pred(I),
325  %% "Dst = Src1 AluOp Src2; if COND" becomes
326  %% "Dst = Src1 AluOpCC Src22; if-COND(CC)"
327  {I2, DidCommute} = mk_alu(XAluOp, Src1, Src2, Dst),
328  NewCond =
329    case DidCommute andalso XAluOp =:= 'cmpcc' of
330      true -> commute_cond(Cond); % subcc does not commute; its conditions do
331      false -> Cond
332    end,
333  I2 ++ mk_pseudo_bp(NewCond, TrueLab, FalseLab, Pred).
334
335conv_alubop_cc(RtlAlubOp) ->
336  case RtlAlubOp of
337    'add' -> 'addcc';
338    'sub' -> 'subcc';
339    %% mul: handled elsewhere
340    'or' -> 'orcc';
341    'and' -> 'andcc';
342    'xor' -> 'xorcc'
343    %% no shift ops
344  end.
345
346conv_call(I, Map, Data) ->
347  {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),
348  {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),
349  {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),
350  ContLab = hipe_rtl:call_continuation(I),
351  ExnLab = hipe_rtl:call_fail(I),
352  Linkage = hipe_rtl:call_type(I),
353  I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage),
354  {I2, Map2, Data}.
355
356mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
357  case hipe_sparc:is_prim(Fun) of
358    true ->
359      mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);
360    false ->
361      mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)
362  end.
363
364mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->
365  case hipe_sparc:prim_prim(Prim) of
366    %% no SPARC-specific primops defined yet
367    _ ->
368      mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)
369  end.
370
371mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
372  %% The backend does not support pseudo_calls without a
373  %% continuation label, so we make sure each call has one.
374  {RealContLab, Tail} =
375    case mk_call_results(Dsts) of
376      [] ->
377	%% Avoid consing up a dummy basic block if the moves list
378	%% is empty, as is typical for calls to suspend/0.
379	%% This should be subsumed by a general "optimise the CFG"
380	%% module, and could probably be removed.
381	case ContLab of
382	  [] ->
383	    NewContLab = hipe_gensym:get_next_label(sparc),
384	    {NewContLab, [hipe_sparc:mk_label(NewContLab)]};
385	  _ ->
386	    {ContLab, []}
387	end;
388      Moves ->
389	%% Change the call to continue at a new basic block.
390	%% In this block move the result registers to the Dsts,
391	%% then continue at the call's original continuation.
392	NewContLab = hipe_gensym:get_next_label(sparc),
393	case ContLab of
394	  [] ->
395	    %% This is just a fallthrough
396	    %% No jump back after the moves.
397	    {NewContLab,
398	     [hipe_sparc:mk_label(NewContLab) |
399	      Moves]};
400	  _ ->
401	    %% The call has a continuation. Jump to it.
402	    {NewContLab,
403	     [hipe_sparc:mk_label(NewContLab) |
404	      Moves ++
405	      [hipe_sparc:mk_b_label(ContLab)]]}
406	end
407    end,
408  SDesc = hipe_sparc:mk_sdesc(ExnLab, 0, length(Args), {}),
409  CallInsn = hipe_sparc:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage),
410  {RegArgs,StkArgs} = split_args(Args),
411  mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).
412
413mk_call_results(Dsts) ->
414  case Dsts of
415    [] -> [];
416    [Dst] ->
417      RV = hipe_sparc:mk_rv(),
418      [hipe_sparc:mk_pseudo_move(RV, Dst)]
419  end.
420
421mk_push_args(StkArgs, Tail) ->
422  case length(StkArgs) of
423    0 ->
424      Tail;
425    NrStkArgs ->
426      [hipe_sparc:mk_pseudo_call_prepare(NrStkArgs) |
427       mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)]
428  end.
429
430mk_store_args([Arg|Args], PrevOffset, Tail) ->
431  Offset = PrevOffset - word_size(),
432  {Src,FixSrc} =
433    case hipe_sparc:is_temp(Arg) of
434      true ->
435	{Arg, []};
436      _ ->
437	Tmp = new_tagged_temp(),
438	{Tmp, mk_set(Arg, Tmp)}
439    end,
440  %% XXX: sparc64: stx
441  Store = hipe_sparc:mk_store('stw', Src, hipe_sparc:mk_sp(), hipe_sparc:mk_simm13(Offset)),
442  mk_store_args(Args, Offset, FixSrc ++ [Store | Tail]);
443mk_store_args([], _, Tail) ->
444  Tail.
445
446conv_comment(I, Map, Data) ->
447  I2 = [hipe_sparc:mk_comment(hipe_rtl:comment_text(I))],
448  {I2, Map, Data}.
449
450conv_enter(I, Map, Data) ->
451  {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),
452  {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),
453  I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)),
454  {I2, Map1, Data}.
455
456mk_enter(Fun, Args, Linkage) ->
457  Arity = length(Args),
458  {RegArgs,StkArgs} = split_args(Args),
459  move_actuals(RegArgs,
460	       [hipe_sparc:mk_pseudo_tailcall_prepare(),
461		hipe_sparc:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]).
462
463conv_goto(I, Map, Data) ->
464  I2 = [hipe_sparc:mk_b_label(hipe_rtl:goto_label(I))],
465  {I2, Map, Data}.
466
467conv_label(I, Map, Data) ->
468  I2 = [hipe_sparc:mk_label(hipe_rtl:label_name(I))],
469  {I2, Map, Data}.
470
471conv_load(I, Map, Data) ->
472  {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),
473  {Base1, Map1} = conv_src(hipe_rtl:load_src(I), Map0),
474  {Base2, Map2} = conv_src(hipe_rtl:load_offset(I), Map1),
475  LdOp = conv_ldop(hipe_rtl:load_size(I), hipe_rtl:load_sign(I)),
476  {I2, _DidCommute} = mk_alu(LdOp, Base1, Base2, Dst),
477  {I2, Map2, Data}.
478
479conv_ldop(LoadSize, LoadSign) ->
480  case LoadSize of
481    word -> 'lduw';	% XXX: sparc64: ldx
482    int32 -> 'lduw';	% XXX: sparc64: lduw or ldsw
483    int16 ->
484      case LoadSign of
485	signed -> 'ldsh';
486	unsigned -> 'lduh'
487      end;
488    byte ->
489      case LoadSign of
490	signed -> 'ldsb';
491	unsigned -> 'ldub'
492      end
493  end.
494
495conv_load_address(I, Map, Data) ->
496  {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map),
497  Addr = hipe_rtl:load_address_addr(I),
498  Type = hipe_rtl:load_address_type(I),
499  Src = {Addr,Type},
500  I2 = [hipe_sparc:mk_pseudo_set(Src, Dst)],
501  {I2, Map0, Data}.
502
503conv_load_atom(I, Map, Data) ->
504  {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map),
505  Src = hipe_rtl:load_atom_atom(I),
506  I2 = [hipe_sparc:mk_pseudo_set(Src, Dst)],
507  {I2, Map0, Data}.
508
509conv_move(I, Map, Data) ->
510  {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map),
511  {Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0),
512  I2 = mk_move(Src, Dst, []),
513  {I2, Map1, Data}.
514
515mk_move(Src, Dst, Tail) ->
516  case hipe_sparc:is_temp(Src) of
517    true -> [hipe_sparc:mk_pseudo_move(Src, Dst) | Tail];
518    _ -> mk_set(Src, Dst, Tail)
519  end.
520
521conv_return(I, Map, Data) ->
522  %% TODO: multiple-value returns
523  {[Arg], Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map),
524  I2 = mk_move(Arg, hipe_sparc:mk_rv(), [hipe_sparc:mk_pseudo_ret()]),
525  {I2, Map0, Data}.
526
527conv_store(I, Map, Data) ->
528  {Base1, Map0} = conv_src(hipe_rtl:store_base(I), Map),
529  {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),
530  {Base2, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),
531  StOp = conv_stop(hipe_rtl:store_size(I)),
532  I2 = mk_store(StOp, Src, Base1, Base2),
533  {I2, Map2, Data}.
534
535conv_stop(StoreSize) ->
536  case StoreSize of
537    word -> 'stw';	% XXX: sparc64: stx
538    int32 -> 'stw';
539    byte -> 'stb'
540  end.
541
542mk_store(StOp, Src, Base1, Base2) ->
543  case hipe_sparc:is_temp(Src) of
544    true ->
545      mk_store2(StOp, Src, Base1, Base2);
546    _ ->
547      Tmp = new_untagged_temp(),
548      mk_set(Src, Tmp, mk_store2(StOp, Tmp, Base1, Base2))
549  end.
550
551mk_store2(StOp, Src, Base1, Base2) ->
552  case hipe_sparc:is_temp(Base1) of
553    true ->
554      case hipe_sparc:is_temp(Base2) of
555	true ->
556	  mk_store_rr(StOp, Src, Base1, Base2);
557	_ ->
558	  mk_store_ri(StOp, Src, Base1, Base2)
559      end;
560    _ ->
561      case hipe_sparc:is_temp(Base2) of
562	true ->
563	  mk_store_ri(StOp, Src, Base2, Base1);
564	_ ->
565	  mk_store_ii(StOp, Src, Base1, Base2)
566      end
567  end.
568
569mk_store_ii(StOp, Src, Base, Disp) ->
570  Tmp = new_untagged_temp(),
571  mk_set(Base, Tmp, mk_store_ri(StOp, Src, Tmp, Disp)).
572
573mk_store_ri(StOp, Src, Base, Disp) ->
574  hipe_sparc:mk_store(StOp, Src, Base, Disp, 'new', []).
575
576mk_store_rr(StOp, Src, Base1, Base2) ->
577  [hipe_sparc:mk_store(StOp, Src, Base1, Base2)].
578
579conv_switch(I, Map, Data) ->
580  Labels = hipe_rtl:switch_labels(I),
581  LMap = [{label,L} || L <- Labels],
582  {NewData, JTabLab} =
583    case hipe_rtl:switch_sort_order(I) of
584      [] ->
585	hipe_consttab:insert_block(Data, word, LMap);
586      SortOrder ->
587	hipe_consttab:insert_sorted_block(Data, word, LMap, SortOrder)
588    end,
589  %% no immediates allowed here
590  {IndexR, Map1} = conv_dst(hipe_rtl:switch_src(I), Map),
591  JTabR = new_untagged_temp(),
592  OffsetR = new_untagged_temp(),
593  DestR = new_untagged_temp(),
594  I2 =
595    [hipe_sparc:mk_pseudo_set({JTabLab,constant}, JTabR),
596     %% XXX: sparc64: << 3
597     hipe_sparc:mk_alu('sll', IndexR, hipe_sparc:mk_uimm5(2), OffsetR),
598     %% XXX: sparc64: ldx
599     hipe_sparc:mk_alu('lduw', JTabR, OffsetR, DestR),
600     hipe_sparc:mk_jmp(DestR, hipe_sparc:mk_simm13(0), Labels)],
601  {I2, Map1, NewData}.
602
603%%% Create a conditional branch.
604
605mk_pseudo_bp(Cond, TrueLabel, FalseLabel, Pred) ->
606  [hipe_sparc:mk_pseudo_bp(Cond, TrueLabel, FalseLabel, Pred)].
607
608%%% Load an integer constant into a register.
609
610mk_set(Value, Dst) -> mk_set(Value, Dst, []).
611
612mk_set(Value, Dst, Tail) ->
613  hipe_sparc:mk_set(Value, Dst, Tail).
614
615%%% Convert an RTL ALU op.
616
617conv_aluop(RtlAluOp) ->
618  case RtlAluOp of
619    'add' -> 'add';
620    'sub' -> 'sub';
621    'mul' -> 'mulx';
622    'or' -> 'or';
623    'and' -> 'and';
624    'xor' -> 'xor';
625    'sll' -> 'sll';	% XXX: sparc64: sllx
626    'srl' -> 'srl';	% XXX: sparc64: srlx
627    'sra' -> 'sra'	% XXX: sparc64: srax
628  end.
629
630%%% Check if an extended SPARC AluOp commutes.
631
632xaluop_commutes(XAluOp) ->
633  case XAluOp of
634    %% 'cmp' -> true;
635    'cmpcc' -> true;
636    'add' -> true;
637    'addcc' -> true;
638    'and' -> true;
639    'andcc' -> true;
640    'or' -> true;
641    'orcc' -> true;
642    'xor' -> true;
643    'xorcc' -> true;
644    'sub' -> false;
645    'subcc' -> false;
646    'mulx' -> true;
647    'smul' -> true;
648    'sll' -> false;
649    'srl' -> false;
650    'sra' -> false;
651    %% 'sllx' -> false;
652    %% 'srlx' -> false;
653    %% 'srax' -> false;
654    'ldsb' -> true;
655    'ldsh' -> true;
656    %% 'ldsw' -> true;
657    'ldub' -> true;
658    'lduh' -> true;
659    'lduw' -> true
660    %% 'ldx' -> true
661  end.
662
663%%% Check if an extended SPARC AluOp is a shift.
664
665xaluop_is_shift(XAluOp) ->
666  case XAluOp of
667    'add' -> false;
668    'addcc' -> false;
669    'and' -> false;
670    'andcc' -> false;
671    'cmpcc' -> false;
672    'ldsb' -> false;
673    'ldub' -> false;
674    'lduw' -> false;
675    'or' -> false;
676    'sll' -> true;
677    %% 'sllx' -> true;
678    'smul' -> false;
679    'sra' -> true;
680    %% 'srax' -> true;
681    'srl' -> true;
682    %% 'srlx' -> true;
683    'sub' -> false;
684    'subcc' -> false;
685    'xor' -> false
686  end.
687
688%%% Convert an extended SPARC AluOp back to a plain AluOp.
689%%% This just maps cmp{,cc} to sub{,cc}.
690
691xaluop_normalise(XAluOp) ->
692  case XAluOp of
693    'add' -> 'add';
694    'addcc' -> 'addcc';
695    'and' -> 'and';
696    'andcc' -> 'andcc';
697    %% 'cmp' -> 'sub';
698    'cmpcc' -> 'subcc';
699    'ldsb' -> 'ldsb';
700    'ldub' -> 'ldub';
701    'lduw' -> 'lduw';
702    'or' -> 'or';
703    'sll' -> 'sll';
704    'smul' -> 'smul';
705    'sra' -> 'sra';
706    'srl' -> 'srl';
707    'sub' -> 'sub';
708    'subcc' -> 'subcc';
709    'xor' -> 'xor'
710  end.
711
712%%% Convert an RTL condition code.
713
714conv_cond(RtlCond) ->
715  case RtlCond of
716    eq	-> 'e';
717    ne	-> 'ne';
718    gt	-> 'g';
719    gtu -> 'gu';	% >u
720    ge	-> 'ge';
721    geu -> 'geu';	% >=u
722    lt	-> 'l';
723    ltu -> 'lu';	% <u
724    le	-> 'le';
725    leu -> 'leu';	% <=u
726    overflow -> 'vs';
727    not_overflow -> 'vc'
728  end.
729
730%%% Commute a SPARC condition code.
731
732commute_cond(Cond) ->	% if x Cond y, then y commute_cond(Cond) x
733  case Cond of
734    'e'   -> 'e';	% ==, ==
735    'ne'  -> 'ne';	% !=, !=
736    'g'   -> 'l';	% >, <
737    'ge'  -> 'le';	% >=, <=
738    'l'   -> 'g';	% <, >
739    'le'  -> 'ge';	% <=, >=
740    'gu'  -> 'lu';	% >u, <u
741    'geu' -> 'leu';	% >=u, <=u
742    'lu'  -> 'gu';	% <u, >u
743    'leu' -> 'geu'	% <=u, >=u
744    %% vs/vc: n/a
745  end.
746
747%%% Split a list of formal or actual parameters into the
748%%% part passed in registers and the part passed on the stack.
749%%% The parameters passed in registers are also tagged with
750%%% the corresponding registers.
751
752split_args(Args) ->
753  split_args(0, hipe_sparc_registers:nr_args(), Args, []).
754
755split_args(I, N, [Arg|Args], RegArgs) when I < N ->
756  Reg = hipe_sparc_registers:arg(I),
757  Temp = hipe_sparc:mk_temp(Reg, 'tagged'),
758  split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]);
759split_args(_, _, StkArgs, RegArgs) ->
760  {RegArgs, StkArgs}.
761
762%%% Convert a list of actual parameters passed in
763%%% registers (from split_args/1) to a list of moves.
764
765move_actuals([{Src,Dst}|Actuals], Rest) ->
766  move_actuals(Actuals, mk_move(Src, Dst, Rest));
767move_actuals([], Rest) ->
768  Rest.
769
770%%% Convert a list of formal parameters passed in
771%%% registers (from split_args/1) to a list of moves.
772
773move_formals([{Dst,Src}|Formals], Rest) ->
774  move_formals(Formals, [hipe_sparc:mk_pseudo_move(Src, Dst) | Rest]);
775move_formals([], Rest) ->
776  Rest.
777
778%%% Convert a 'fun' operand (MFA, prim, or temp)
779
780conv_fun(Fun, Map) ->
781  case hipe_rtl:is_var(Fun) of
782    true ->
783      conv_dst(Fun, Map);
784    false ->
785      case hipe_rtl:is_reg(Fun) of
786	true ->
787	  conv_dst(Fun, Map);
788	false ->
789	  if is_atom(Fun) ->
790	      {hipe_sparc:mk_prim(Fun), Map};
791	     true ->
792	      {conv_mfa(Fun), Map}
793	  end
794      end
795  end.
796
797%%% Convert an MFA operand.
798
799conv_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
800  hipe_sparc:mk_mfa(M, F, A).
801
802%%% Convert an RTL source operand (imm/var/reg).
803%%% Returns a temp or a naked integer.
804
805conv_src(Opnd, Map) ->
806  case hipe_rtl:is_imm(Opnd) of
807    true ->
808      Value = hipe_rtl:imm_value(Opnd),
809      if is_integer(Value) ->
810	  {Value, Map}
811      end;
812    false ->
813      conv_dst(Opnd, Map)
814  end.
815
816conv_src_list([O|Os], Map) ->
817  {V, Map1} = conv_src(O, Map),
818  {Vs, Map2} = conv_src_list(Os, Map1),
819  {[V|Vs], Map2};
820conv_src_list([], Map) ->
821  {[], Map}.
822
823%%% Convert an RTL destination operand (var/reg).
824
825conv_fpreg(Opnd, Map) ->
826  true = hipe_rtl:is_fpreg(Opnd),
827  conv_dst(Opnd, Map).
828
829conv_dst(Opnd, Map) ->
830  {Name, Type} =
831    case hipe_rtl:is_var(Opnd) of
832      true ->
833	{hipe_rtl:var_index(Opnd), 'tagged'};
834      false ->
835	case hipe_rtl:is_fpreg(Opnd) of
836	  true ->
837	    {hipe_rtl:fpreg_index(Opnd), 'double'};
838	  false ->
839	    {hipe_rtl:reg_index(Opnd), 'untagged'}
840	end
841    end,
842  IsPrecoloured =
843    case Type of
844      'double' -> false; %hipe_sparc_registers:is_precoloured_fpr(Name);
845      _ -> hipe_sparc_registers:is_precoloured_gpr(Name)
846    end,
847  case IsPrecoloured of
848    true ->
849      {hipe_sparc:mk_temp(Name, Type), Map};
850    false ->
851      case vmap_lookup(Map, Opnd) of
852	{value, NewTemp} ->
853	  {NewTemp, Map};
854	_ ->
855	  NewTemp = hipe_sparc:mk_new_temp(Type),
856	  {NewTemp, vmap_bind(Map, Opnd, NewTemp)}
857      end
858  end.
859
860conv_dst_list([O|Os], Map) ->
861  {Dst, Map1} = conv_dst(O, Map),
862  {Dsts, Map2} = conv_dst_list(Os, Map1),
863  {[Dst|Dsts], Map2};
864conv_dst_list([], Map) ->
865  {[], Map}.
866
867conv_formals(Os, Map) ->
868  conv_formals(hipe_sparc_registers:nr_args(), Os, Map, []).
869
870conv_formals(N, [O|Os], Map, Res) ->
871  Type =
872    case hipe_rtl:is_var(O) of
873      true -> 'tagged';
874      _ -> 'untagged'
875    end,
876  Dst =
877    if N > 0 -> hipe_sparc:mk_new_temp(Type);	% allocatable
878       true -> hipe_sparc:mk_new_nonallocatable_temp(Type)
879    end,
880  Map1 = vmap_bind(Map, O, Dst),
881  conv_formals(N-1, Os, Map1, [Dst|Res]);
882conv_formals(_, [], Map, Res) ->
883  {lists:reverse(Res), Map}.
884
885%%% new_untagged_temp -- conjure up an untagged scratch reg
886
887new_untagged_temp() ->
888  hipe_sparc:mk_new_temp('untagged').
889
890%%% new_tagged_temp -- conjure up a tagged scratch reg
891
892new_tagged_temp() ->
893  hipe_sparc:mk_new_temp('tagged').
894
895%%% Map from RTL var/reg operands to temps.
896
897vmap_empty() ->
898  gb_trees:empty().
899
900vmap_lookup(Map, Key) ->
901  gb_trees:lookup(Key, Map).
902
903vmap_bind(Map, Key, Val) ->
904  gb_trees:insert(Key, Val, Map).
905
906word_size() ->
907  hipe_rtl_arch:word_size().
908