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_sparc).
16-export([
17	 mk_temp/2,
18	 mk_new_temp/1,
19	 mk_new_nonallocatable_temp/1,
20	 is_temp/1,
21	 temp_reg/1,
22	 temp_type/1,
23	 temp_is_allocatable/1,
24	 temp_is_precoloured/1,
25
26	 mk_g0/0,
27	 mk_ra/0,
28	 mk_rv/0,
29	 mk_sp/0,
30	 mk_temp1/0,
31	 mk_temp2/0,
32
33	 mk_simm13/1,
34	 mk_uimm5/1,
35
36	 mk_mfa/3,
37
38	 mk_prim/1,
39	 is_prim/1,
40	 prim_prim/1,
41
42	 mk_sdesc/4,
43
44	 mk_alu/4,
45	 mk_mov/2,
46	 mk_load/6,
47
48	 mk_bp/3,
49	 mk_b_label/1,
50
51	 %% mk_br/4,
52
53	 mk_call_rec/3,
54
55	 mk_call_tail/2,
56
57	 mk_comment/1,
58
59	 mk_label/1,
60	 is_label/1,
61	 label_label/1,
62
63	 mk_jmp/3,
64	 mk_jmpl/2,
65
66	 mk_pseudo_bp/4,
67	 negate_cond/1,
68
69	 %% mk_pseudo_br/5,
70	 %% negate_rcond/1,
71
72	 mk_pseudo_call/4,
73	 pseudo_call_contlab/1,
74	 pseudo_call_funv/1,
75	 pseudo_call_linkage/1,
76	 pseudo_call_sdesc/1,
77
78	 mk_pseudo_call_prepare/1,
79	 pseudo_call_prepare_nrstkargs/1,
80
81	 mk_pseudo_move/2,
82	 is_pseudo_move/1,
83	 pseudo_move_dst/1,
84	 pseudo_move_src/1,
85
86	 mk_pseudo_ret/0,
87
88	 mk_pseudo_set/2,
89
90	 mk_pseudo_spill_move/3,
91	 is_pseudo_spill_move/1,
92
93	 mk_pseudo_tailcall/4,
94	 pseudo_tailcall_funv/1,
95	 pseudo_tailcall_linkage/1,
96	 pseudo_tailcall_stkargs/1,
97
98	 mk_pseudo_tailcall_prepare/0,
99
100	 mk_rdy/1,
101
102	 %% mk_sethi/2,
103	 mk_nop/0,
104	 mk_set/2,
105	 mk_set/3,
106	 mk_addi/4,
107
108	 mk_store/4,
109	 mk_store/6,
110
111	 mk_fp_binary/4,
112
113	 mk_fp_unary/3,
114
115	 mk_pseudo_fload/4,
116	 mk_fload/4,
117
118	 mk_pseudo_fmove/2,
119	 is_pseudo_fmove/1,
120	 pseudo_fmove_src/1,
121	 pseudo_fmove_dst/1,
122
123	 mk_pseudo_spill_fmove/3,
124	 is_pseudo_spill_fmove/1,
125
126	 mk_pseudo_fstore/3,
127	 mk_fstore/4,
128
129	 mk_defun/8,
130	 defun_code/1,
131	 defun_data/1,
132	 defun_formals/1,
133	 defun_is_closure/1,
134	 defun_is_leaf/1,
135	 defun_mfa/1,
136	 defun_var_range/1
137	]).
138
139-include("hipe_sparc.hrl").
140
141mk_temp(Reg, Type, Allocatable) ->
142  #sparc_temp{reg=Reg, type=Type, allocatable=Allocatable}.
143mk_temp(Reg, Type) -> mk_temp(Reg, Type, true).
144mk_new_temp(Type, Allocatable) ->
145  mk_temp(hipe_gensym:get_next_var(sparc), Type, Allocatable).
146mk_new_temp(Type) -> mk_new_temp(Type, true).
147mk_new_nonallocatable_temp(Type) -> mk_new_temp(Type, false).
148is_temp(X) -> case X of #sparc_temp{} -> true; _ -> false end.
149temp_reg(#sparc_temp{reg=Reg}) -> Reg.
150temp_type(#sparc_temp{type=Type}) -> Type.
151temp_is_allocatable(#sparc_temp{allocatable=A}) -> A.
152temp_is_precoloured(#sparc_temp{reg=Reg,type=Type}) ->
153  case Type of
154    %% 'double' -> hipe_sparc_registers:is_precoloured_fpr(Reg);
155    _ -> hipe_sparc_registers:is_precoloured_gpr(Reg)
156  end.
157
158mk_g0() -> mk_temp(hipe_sparc_registers:g0(), 'untagged').
159mk_ra() -> mk_temp(hipe_sparc_registers:return_address(), 'untagged').
160mk_rv() -> mk_temp(hipe_sparc_registers:return_value(), 'tagged').
161mk_sp() -> mk_temp(hipe_sparc_registers:stack_pointer(), 'untagged').
162mk_temp1() -> mk_temp(hipe_sparc_registers:temp1(), 'untagged').
163mk_temp2() -> mk_temp(hipe_sparc_registers:temp2(), 'untagged').
164
165mk_simm13(Value) -> #sparc_simm13{value=Value}.
166mk_uimm5(Value) -> #sparc_uimm5{value=Value}.
167mk_uimm22(Value) -> #sparc_uimm22{value=Value}.
168
169mk_mfa(M, F, A) -> #sparc_mfa{m=M, f=F, a=A}.
170
171mk_prim(Prim) -> #sparc_prim{prim=Prim}.
172is_prim(X) -> case X of #sparc_prim{} -> true; _ -> false end.
173prim_prim(#sparc_prim{prim=Prim}) -> Prim.
174
175mk_sdesc(ExnLab, FSize, Arity, Live) ->
176  #sparc_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}.
177
178mk_alu(AluOp, Src1, Src2, Dst) ->
179  #alu{aluop=AluOp, src1=Src1, src2=Src2, dst=Dst}.
180mk_mov(Src, Dst) -> mk_alu('or', mk_g0(), Src, Dst).
181
182mk_bp(Cond, Label, Pred) -> #bp{'cond'=Cond, label=Label, pred=Pred}.
183mk_b_label(Label) -> mk_bp('a', Label, 1.0).
184
185-ifdef(notdef).	% XXX: only for sparc64, alas
186mk_br(RCond, Src, Label, Pred) ->
187  #br{rcond=RCond, src=Src, label=Label, pred=Pred}.
188-endif.
189
190mk_call_rec(Fun, SDesc, Linkage) ->
191  #call_rec{'fun'=Fun, sdesc=SDesc, linkage=Linkage}.
192
193mk_call_tail(Fun, Linkage) -> #call_tail{'fun'=Fun, linkage=Linkage}.
194
195mk_comment(Term) -> #comment{term=Term}.
196
197mk_label(Label) -> #label{label=Label}.
198is_label(I) -> case I of #label{} -> true; _ -> false end.
199label_label(#label{label=Label}) -> Label.
200
201mk_jmp(Src1, Src2, Labels) -> #jmp{src1=Src1, src2=Src2, labels=Labels}.
202
203mk_jmpl(Src, SDesc) -> #jmpl{src=Src, sdesc=SDesc}.
204
205mk_pseudo_bp(Cond, TrueLab, FalseLab, Pred) ->
206  if Pred >= 0.5 ->
207      mk_pseudo_bp_simple(negate_cond(Cond), FalseLab,
208			  TrueLab, 1.0-Pred);
209     true ->
210      mk_pseudo_bp_simple(Cond, TrueLab, FalseLab, Pred)
211  end.
212
213mk_pseudo_bp_simple(Cond, TrueLab, FalseLab, Pred) when Pred =< 0.5 ->
214  #pseudo_bp{'cond'=Cond, true_label=TrueLab,
215	     false_label=FalseLab, pred=Pred}.
216
217negate_cond(Cond) ->
218  case Cond of
219    'l'  -> 'ge';	% <, >=
220    'ge' -> 'l';	% >=, <
221    'g'  -> 'le';	% >, <=
222    'le' -> 'g';	% <=, >
223    'e'  -> 'ne';	% ==, !=
224    'ne' -> 'e';	% !=, ==
225    'gu' -> 'leu';	% >u, <=u
226    'leu'-> 'gu';	% <=u, >u
227    'geu'-> 'lu';	% >=u, <u
228    'lu' -> 'geu';	% <u, >=u
229    'vs' -> 'vc';	% overflow, not_overflow
230    'vc' -> 'vs'	% not_overflow, overflow
231  end.
232
233-ifdef(notdef).	% XXX: only for sparc64, alas
234mk_pseudo_br(RCond, Src, TrueLab, FalseLab, Pred) ->
235  if Pred >= 0.5 ->
236      mk_pseudo_br_simple(negate_rcond(RCond), Src, FalseLab,
237			  TrueLab, 1.0-Pred);
238     true ->
239      mk_pseudo_br_simple(RCond, Src, TrueLab, FalseLab, Pred)
240  end.
241
242mk_pseudo_br_simple(RCond, Src, TrueLab, FalseLab, Pred) when Pred =< 0.5 ->
243  #pseudo_br{rcond=RCond, src=Src, true_label=TrueLab,
244	     false_label=FalseLab, pred=Pred}.
245
246negate_rcond(RCond) ->
247  case RCond of
248    'z'   -> 'nz';	% ==, !=
249    'nz'  -> 'z';	% !=, ==
250    'gz'  -> 'lez';	% >, <=
251    'lez' -> 'gz';	% <=, >
252    'gez' -> 'lz';	% >=, <
253    'lz'  -> 'gez'	% <, >=
254  end.
255-endif.
256
257mk_pseudo_call(FunV, SDesc, ContLab, Linkage) ->
258  #pseudo_call{funv=FunV, sdesc=SDesc, contlab=ContLab, linkage=Linkage}.
259pseudo_call_funv(#pseudo_call{funv=FunV}) -> FunV.
260pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab.
261pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage.
262pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc.
263
264mk_pseudo_call_prepare(NrStkArgs) ->
265  #pseudo_call_prepare{nrstkargs=NrStkArgs}.
266pseudo_call_prepare_nrstkargs(#pseudo_call_prepare{nrstkargs=NrStkArgs}) ->
267  NrStkArgs.
268
269mk_pseudo_move(Src, Dst) -> #pseudo_move{src=Src, dst=Dst}.
270is_pseudo_move(I) -> case I of #pseudo_move{} -> true; _ -> false end.
271pseudo_move_dst(#pseudo_move{dst=Dst}) -> Dst.
272pseudo_move_src(#pseudo_move{src=Src}) -> Src.
273
274mk_pseudo_ret() -> #pseudo_ret{}.
275
276mk_pseudo_set(Imm, Dst) -> #pseudo_set{imm=Imm, dst=Dst}.
277
278mk_pseudo_spill_move(Src, Temp, Dst) ->
279  #pseudo_spill_move{src=Src, temp=Temp, dst=Dst}.
280is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move).
281
282mk_pseudo_tailcall(FunV, Arity, StkArgs, Linkage) ->
283  #pseudo_tailcall{funv=FunV, arity=Arity, stkargs=StkArgs, linkage=Linkage}.
284pseudo_tailcall_funv(#pseudo_tailcall{funv=FunV}) -> FunV.
285pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage.
286pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs.
287
288mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}.
289
290mk_rdy(Dst) -> #rdy{dst=Dst}.
291
292mk_sethi(UImm22, Dst) -> #sethi{uimm22=UImm22, dst=Dst}.
293mk_nop() -> mk_sethi(mk_uimm22(0), mk_g0()).
294
295%%% Load an integer constant into a register.
296mk_set(Value, Dst) -> mk_set(Value, Dst, []).
297
298mk_set(Value, Dst, Tail) ->
299  if -4096 =< Value, Value < 4096 ->
300      [mk_alu('or', mk_g0(), mk_simm13(Value), Dst) | Tail];
301     true ->
302      Hi22 = mk_uimm22((Value bsr 10) band 16#003FFFFF),
303      case (Value band 16#3FF) of
304	0 ->
305	  [mk_sethi(Hi22, Dst) | Tail];
306	Lo10 ->
307	  [mk_sethi(Hi22, Dst),
308	   mk_alu('or', Dst, mk_simm13(Lo10), Dst) |
309	   Tail]
310      end
311  end.
312
313%%% Add an integer constant. Dst may equal Src,
314%%% in which case temp2 may be clobbered.
315mk_addi(Src, Value, Dst, Tail) ->
316  if -4096 =< Value, Value < 4096 ->
317      [mk_alu('add', Src, mk_simm13(Value), Dst) | Tail];
318     true ->
319      Tmp =
320	begin
321	  DstReg = temp_reg(Dst),
322	  SrcReg = temp_reg(Src),
323	  if DstReg =:= SrcReg -> mk_temp2();
324	     true -> Dst
325	  end
326	end,
327      mk_set(Value, Tmp, [mk_alu('add', Src, Tmp, Dst) | Tail])
328  end.
329
330mk_store(StOp, Src, Base, Disp) ->
331  #store{stop=StOp, src=Src, base=Base, disp=Disp}.
332
333mk_store(StOp, Src, Base, Offset, Scratch, Rest) when is_integer(Offset) ->
334  if -4096 =< Offset, Offset < 4096 ->
335      [mk_store(StOp, Src, Base, mk_simm13(Offset)) | Rest];
336     true ->
337      Index = mk_scratch(Scratch),
338      mk_set(Offset, Index, [mk_store(StOp, Src, Base, Index) | Rest])
339  end.
340
341mk_load(LdOp, Base, Disp, Dst) ->
342  mk_alu(LdOp, Base, Disp, Dst).
343
344mk_load(LdOp, Base, Offset, Dst, Scratch, Rest) when is_integer(Offset) ->
345  if -4096 =< Offset, Offset < 4096 ->
346      [mk_load(LdOp, Base, mk_simm13(Offset), Dst) | Rest];
347     true ->
348      Index =
349	begin
350	  DstReg = temp_reg(Dst),
351	  BaseReg = temp_reg(Base),
352	  if DstReg =/= BaseReg -> Dst;
353	     true -> mk_scratch(Scratch)
354	  end
355	end,
356      mk_set(Offset, Index, [mk_load(LdOp, Base, Index, Dst) | Rest])
357  end.
358
359mk_scratch(Scratch) ->
360  case Scratch of
361    'temp2' -> mk_temp2();
362    'new' -> mk_new_temp('untagged')
363  end.
364
365mk_fp_binary(FpBinOp, Src1, Src2, Dst) ->
366  #fp_binary{fp_binop=FpBinOp, src1=Src1, src2=Src2, dst=Dst}.
367
368mk_fp_unary(FpUnOp, Src, Dst) -> #fp_unary{fp_unop=FpUnOp, src=Src, dst=Dst}.
369
370mk_pseudo_fload(Base, Disp, Dst, IsSingle) ->
371  #pseudo_fload{base=Base, disp=Disp, dst=Dst, is_single=IsSingle}.
372
373mk_fload(Base, Disp, Dst, Scratch) when is_integer(Disp) ->
374  if -4096 =< Disp, Disp < (4096-4) ->
375      [mk_pseudo_fload(Base, mk_simm13(Disp), Dst, false)];
376     true ->
377      Tmp = mk_scratch(Scratch),
378      mk_set(Disp, Tmp,
379	     [mk_alu('add', Tmp, Base, Tmp),
380	      mk_pseudo_fload(Tmp, mk_simm13(0), Dst, false)])
381  end.
382
383mk_pseudo_fmove(Src, Dst) -> #pseudo_fmove{src=Src, dst=Dst}.
384is_pseudo_fmove(I) -> case I of #pseudo_fmove{} -> true; _ -> false end.
385pseudo_fmove_src(#pseudo_fmove{src=Src}) -> Src.
386pseudo_fmove_dst(#pseudo_fmove{dst=Dst}) -> Dst.
387
388mk_pseudo_spill_fmove(Src, Temp, Dst) ->
389  #pseudo_spill_fmove{src=Src, temp=Temp, dst=Dst}.
390is_pseudo_spill_fmove(I) -> is_record(I, pseudo_spill_fmove).
391
392mk_pseudo_fstore(Src, Base, Disp) ->
393  #pseudo_fstore{src=Src, base=Base, disp=Disp}.
394
395mk_fstore(Src, Base, Disp, Scratch) when is_integer(Disp) ->
396  if -4096 =< Disp, Disp < (4096-4) ->
397      [mk_pseudo_fstore(Src, Base, hipe_sparc:mk_simm13(Disp))];
398     true ->
399      Tmp = mk_scratch(Scratch),
400      mk_set(Disp, Tmp,
401	     [mk_alu('add', Tmp, Base, Tmp),
402	      mk_pseudo_fstore(Src, Tmp, mk_simm13(0))])
403  end.
404
405mk_defun(MFA, Formals, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) ->
406  #defun{mfa=MFA, formals=Formals, code=Code, data=Data,
407	 isclosure=IsClosure, isleaf=IsLeaf,
408	 var_range=VarRange, label_range=LabelRange}.
409defun_code(#defun{code=Code}) -> Code.
410defun_data(#defun{data=Data}) -> Data.
411defun_formals(#defun{formals=Formals}) -> Formals.
412defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure.
413defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf.
414defun_mfa(#defun{mfa=MFA}) -> MFA.
415defun_var_range(#defun{var_range=VarRange}) -> VarRange.
416