~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to lib/hipe/arm/hipe_rtl_to_arm.erl

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%%% -*- erlang-indent-level: 2 -*-
 
2
%%% $Id$
 
3
 
 
4
-module(hipe_rtl_to_arm).
 
5
-export([translate/1]).
 
6
 
 
7
-include("../rtl/hipe_rtl.hrl").
 
8
 
 
9
translate(RTL) ->
 
10
  hipe_gensym:init(arm),
 
11
  hipe_gensym:set_var(arm, hipe_arm_registers:first_virtual()),
 
12
  hipe_gensym:set_label(arm, hipe_gensym:get_label(rtl)),
 
13
  Map0 = vmap_empty(),
 
14
  {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),
 
15
  OldData = hipe_rtl:rtl_data(RTL),
 
16
  {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),
 
17
  {RegFormals,_} = split_args(Formals),
 
18
  Code =
 
19
    case RegFormals of
 
20
      [] -> Code0;
 
21
      _ -> [hipe_arm:mk_label(hipe_gensym:get_next_label(arm)) |
 
22
            move_formals(RegFormals, Code0)]
 
23
    end,
 
24
  IsClosure = hipe_rtl:rtl_is_closure(RTL),
 
25
  IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
 
26
  hipe_arm:mk_defun(conv_mfa(hipe_rtl:rtl_fun(RTL)),
 
27
                    Formals,
 
28
                    IsClosure,
 
29
                    IsLeaf,
 
30
                    Code,
 
31
                    NewData,
 
32
                    [], 
 
33
                    []).
 
34
 
 
35
conv_insn_list([H|T], Map, Data) ->
 
36
  {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),
 
37
  %% io:format("~w \n  ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),
 
38
  {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),
 
39
  {NewH ++ NewT, NewData2};
 
40
conv_insn_list([], _, Data) ->
 
41
  {[], Data}.
 
42
 
 
43
conv_insn(I, Map, Data) ->
 
44
  case I of
 
45
    #alu{} -> conv_alu(I, Map, Data);
 
46
    #alub{} -> conv_alub(I, Map, Data);
 
47
    #branch{} -> conv_branch(I, Map, Data);
 
48
    #call{} -> conv_call(I, Map, Data);
 
49
    #comment{} -> conv_comment(I, Map, Data);
 
50
    #enter{} -> conv_enter(I, Map, Data);
 
51
    #goto{} -> conv_goto(I, Map, Data);
 
52
    #label{} -> conv_label(I, Map, Data);
 
53
    #load{} -> conv_load(I, Map, Data);
 
54
    #load_address{} -> conv_load_address(I, Map, Data);
 
55
    #load_atom{} -> conv_load_atom(I, Map, Data);
 
56
    #move{} -> conv_move(I, Map, Data);
 
57
    #return{} -> conv_return(I, Map, Data);
 
58
    #store{} -> conv_store(I, Map, Data);
 
59
    #switch{} -> conv_switch(I, Map, Data);
 
60
    _ -> exit({?MODULE,conv_insn,I})
 
61
  end.
 
62
 
 
63
conv_alu(I, Map, Data) ->
 
64
  %% dst = src1 aluop src2
 
65
  {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),
 
66
  {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),
 
67
  {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),
 
68
  RtlAluOp = hipe_rtl:alu_op(I),
 
69
  S = false,
 
70
  I2 = mk_alu(S, Dst, Src1, RtlAluOp, Src2),
 
71
  {I2, Map2, Data}.
 
72
 
 
73
conv_shift(RtlShiftOp) ->
 
74
  case RtlShiftOp of
 
75
    'sll' -> 'lsl';
 
76
    'srl' -> 'lsr';
 
77
    'sra' -> 'asr'
 
78
  end.
 
79
 
 
80
conv_arith(RtlAluOp) -> % RtlAluOp \ RtlShiftOp -> ArmArithOp
 
81
  case RtlAluOp of
 
82
    'add' -> 'add';
 
83
    'sub' -> 'sub';
 
84
    'or'  -> 'orr';
 
85
    'and' -> 'and';
 
86
    'xor' -> 'eor'
 
87
  end.
 
88
 
 
89
commute_arithop(ArithOp) ->
 
90
  case ArithOp of
 
91
    'sub' -> 'rsb';
 
92
    _ -> ArithOp
 
93
  end.
 
94
 
 
95
mk_alu(S, Dst, Src1, RtlAluOp, Src2) ->
 
96
  case hipe_rtl:is_shift_op(RtlAluOp) of
 
97
    true ->
 
98
      mk_shift(S, Dst, Src1, conv_shift(RtlAluOp), Src2);
 
99
    false ->
 
100
      mk_arith(S, Dst, Src1, conv_arith(RtlAluOp), Src2)
 
101
  end.
 
102
 
 
103
mk_shift(S, Dst, Src1, ShiftOp, Src2) ->
 
104
  case hipe_arm:is_temp(Src1) of
 
105
    true ->
 
106
      case hipe_arm:is_temp(Src2) of
 
107
        true ->
 
108
          mk_shift_rr(S, Dst, Src1, ShiftOp, Src2);
 
109
        _ ->
 
110
          mk_shift_ri(S, Dst, Src1, ShiftOp, Src2)
 
111
      end;
 
112
    _ ->
 
113
      case hipe_arm:is_temp(Src2) of
 
114
        true ->
 
115
          mk_shift_ir(S, Dst, Src1, ShiftOp, Src2);
 
116
        _ ->
 
117
          mk_shift_ii(S, Dst, Src1, ShiftOp, Src2)
 
118
      end
 
119
  end.
 
120
 
 
121
mk_shift_ii(S, Dst, Src1, ShiftOp, Src2) ->
 
122
  io:format("~w: RTL alu with two immediates\n", [?MODULE]),
 
123
  Tmp = new_untagged_temp(),
 
124
  mk_li(Tmp, Src1,
 
125
        mk_shift_ri(S, Dst, Tmp, ShiftOp, Src2)).
 
126
 
 
127
mk_shift_ir(S, Dst, Src1, ShiftOp, Src2) ->
 
128
  Tmp = new_untagged_temp(),
 
129
  mk_li(Tmp, Src1,
 
130
        mk_shift_rr(S, Dst, Tmp, ShiftOp, Src2)).
 
131
 
 
132
mk_shift_ri(S, Dst, Src1, ShiftOp, Src2) ->
 
133
  if Src2 >= 0, Src2 < 32 -> [];
 
134
     true -> io:format("~w: excessive immediate shift ~w\n", [?MODULE,Src2])
 
135
  end,
 
136
  Am1 = {Src1,ShiftOp,Src2},
 
137
  [hipe_arm:mk_move(S, Dst, Am1)].
 
138
 
 
139
mk_shift_rr(S, Dst, Src1, ShiftOp, Src2) ->
 
140
  Am1 = {Src1,ShiftOp,Src2},
 
141
  [hipe_arm:mk_move(S, Dst, Am1)].
 
142
 
 
143
mk_arith(S, Dst, Src1, ArithOp, Src2) ->
 
144
  case hipe_arm:is_temp(Src1) of
 
145
    true ->
 
146
      case hipe_arm:is_temp(Src2) of
 
147
        true ->
 
148
          mk_arith_rr(S, Dst, Src1, ArithOp, Src2);
 
149
        _ ->
 
150
          mk_arith_ri(S, Dst, Src1, ArithOp, Src2)
 
151
      end;
 
152
    _ ->
 
153
      case hipe_arm:is_temp(Src2) of
 
154
        true ->
 
155
          mk_arith_ir(S, Dst, Src1, ArithOp, Src2);
 
156
        _ ->
 
157
          mk_arith_ii(S, Dst, Src1, ArithOp, Src2)
 
158
      end
 
159
  end.
 
160
 
 
161
mk_arith_ii(S, Dst, Src1, ArithOp, Src2) ->
 
162
  io:format("~w: RTL alu with two immediates\n", [?MODULE]),
 
163
  Tmp = new_untagged_temp(),
 
164
  mk_li(Tmp, Src1,
 
165
        mk_arith_ri(S, Dst, Tmp, ArithOp, Src2)).
 
166
 
 
167
mk_arith_ir(S, Dst, Src1, ArithOp, Src2) ->
 
168
  mk_arith_ri(S, Dst, Src2, commute_arithop(ArithOp), Src1).
 
169
 
 
170
mk_arith_ri(S, Dst, Src1, ArithOp, Src2) ->
 
171
  {FixAm1,NewArithOp,Am1} = fix_aluop_imm(ArithOp, Src2),
 
172
  FixAm1 ++ [hipe_arm:mk_alu(NewArithOp, S, Dst, Src1, Am1)].
 
173
 
 
174
mk_arith_rr(S, Dst, Src1, ArithOp, Src2) ->
 
175
  [hipe_arm:mk_alu(ArithOp, S, Dst, Src1, Src2)].
 
176
 
 
177
fix_aluop_imm(AluOp, Imm) -> % {FixAm1,NewAluOp,Am1}
 
178
  case hipe_arm:try_aluop_imm(AluOp, Imm) of
 
179
    {NewAluOp,Am1} -> {[], NewAluOp, Am1};
 
180
    [] ->
 
181
      Tmp = new_untagged_temp(),
 
182
      {mk_li(Tmp, Imm), AluOp, Tmp}
 
183
  end.
 
184
 
 
185
conv_alub(I, Map, Data) ->
 
186
  %% dst = src1 aluop src2; if COND goto label
 
187
  {Dst, Map0} = conv_dst(hipe_rtl:alub_dst(I), Map),
 
188
  {Src1, Map1} = conv_src(hipe_rtl:alub_src1(I), Map0),
 
189
  {Src2, Map2} = conv_src(hipe_rtl:alub_src2(I), Map1),
 
190
  Cond = conv_alub_cond(hipe_rtl:alub_cond(I)),
 
191
  I2 = mk_pseudo_bc(
 
192
          Cond,
 
193
          hipe_rtl:alub_true_label(I),
 
194
          hipe_rtl:alub_false_label(I),
 
195
          hipe_rtl:alub_pred(I)),
 
196
  RtlAluOp = hipe_rtl:alub_op(I),
 
197
  S = true,
 
198
  I1 = mk_alu(S, Dst, Src1, RtlAluOp, Src2),
 
199
  {I1 ++ I2, Map2, Data}.
 
200
 
 
201
conv_branch(I, Map, Data) ->
 
202
  %% <unused> = src1 - src2; if COND goto label
 
203
  {Src1, Map0} = conv_src(hipe_rtl:branch_src1(I), Map),
 
204
  {Src2, Map1} = conv_src(hipe_rtl:branch_src2(I), Map0),
 
205
  Cond = conv_branch_cond(hipe_rtl:branch_cond(I)),
 
206
  I2 = mk_branch(Src1, Cond, Src2,
 
207
                 hipe_rtl:branch_true_label(I),
 
208
                 hipe_rtl:branch_false_label(I),
 
209
                 hipe_rtl:branch_pred(I)),
 
210
  {I2, Map1, Data}.
 
211
 
 
212
mk_branch(Src1, Cond, Src2, TrueLab, FalseLab, Pred) ->
 
213
  case hipe_arm:is_temp(Src1) of
 
214
    true ->
 
215
      case hipe_arm:is_temp(Src2) of
 
216
        true ->
 
217
          mk_branch_rr(Src1, Src2, Cond, TrueLab, FalseLab, Pred);
 
218
        _ ->
 
219
          mk_branch_ri(Src1, Cond, Src2, TrueLab, FalseLab, Pred)
 
220
      end;
 
221
    _ ->
 
222
      case hipe_arm:is_temp(Src2) of
 
223
        true ->
 
224
          NewCond = commute_cond(Cond),
 
225
          mk_branch_ri(Src2, NewCond, Src1, TrueLab, FalseLab, Pred);
 
226
        _ ->
 
227
          mk_branch_ii(Src1, Cond, Src2, TrueLab, FalseLab, Pred)
 
228
      end
 
229
  end.
 
230
 
 
231
mk_branch_ii(Imm1, Cond, Imm2, TrueLab, FalseLab, Pred) ->
 
232
  io:format("~w: RTL branch with two immediates\n", [?MODULE]),
 
233
  Tmp = new_untagged_temp(),
 
234
  mk_li(Tmp, Imm1,
 
235
        mk_branch_ri(Tmp, Cond, Imm2,
 
236
                     TrueLab, FalseLab, Pred)).
 
237
 
 
238
mk_branch_ri(Src, Cond, Imm, TrueLab, FalseLab, Pred) ->
 
239
  {FixAm1,NewCmpOp,Am1} = fix_aluop_imm('cmp', Imm),
 
240
  FixAm1 ++ mk_cmp_bc(NewCmpOp, Src, Am1, Cond, TrueLab, FalseLab, Pred).
 
241
 
 
242
mk_branch_rr(Src1, Src2, Cond, TrueLab, FalseLab, Pred) ->
 
243
  mk_cmp_bc('cmp', Src1, Src2, Cond, TrueLab, FalseLab, Pred).
 
244
 
 
245
mk_cmp_bc(CmpOp, Src, Am1, Cond, TrueLab, FalseLab, Pred) ->
 
246
  [hipe_arm:mk_cmp(CmpOp, Src, Am1) |
 
247
   mk_pseudo_bc(Cond, TrueLab, FalseLab, Pred)].
 
248
 
 
249
conv_call(I, Map, Data) ->
 
250
  {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),
 
251
  {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),
 
252
  {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),
 
253
  ContLab = hipe_rtl:call_continuation(I),
 
254
  ExnLab = hipe_rtl:call_fail(I),
 
255
  Linkage = hipe_rtl:call_type(I),
 
256
  I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage),
 
257
  {I2, Map2, Data}.
 
258
 
 
259
mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
 
260
  case hipe_arm:is_prim(Fun) of
 
261
    true ->
 
262
      mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);
 
263
    false ->
 
264
      mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)
 
265
  end.
 
266
 
 
267
mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->
 
268
  case hipe_arm:prim_prim(Prim) of
 
269
    %% no ARM-specific primops defined yet
 
270
    _ ->
 
271
      mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)
 
272
  end.
 
273
 
 
274
mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
 
275
  %% The backend does not support pseudo_calls without a
 
276
  %% continuation label, so we make sure each call has one.
 
277
  {RealContLab, Tail} =
 
278
    case mk_call_results(Dsts) of
 
279
      [] ->
 
280
        %% Avoid consing up a dummy basic block if the moves list
 
281
        %% is empty, as is typical for calls to suspend/0.
 
282
        %% This should be subsumed by a general "optimise the CFG"
 
283
        %% module, and could probably be removed.
 
284
        case ContLab of
 
285
          [] ->
 
286
            NewContLab = hipe_gensym:get_next_label(arm),
 
287
            {NewContLab, [hipe_arm:mk_label(NewContLab)]};
 
288
          _ ->
 
289
            {ContLab, []}
 
290
        end;
 
291
      Moves ->
 
292
        %% Change the call to continue at a new basic block.
 
293
        %% In this block move the result registers to the Dsts,
 
294
        %% then continue at the call's original continuation.
 
295
        NewContLab = hipe_gensym:get_next_label(arm),
 
296
        case ContLab of
 
297
          [] ->
 
298
            %% This is just a fallthrough
 
299
            %% No jump back after the moves.
 
300
            {NewContLab,
 
301
             [hipe_arm:mk_label(NewContLab) |
 
302
              Moves]};
 
303
          _ ->
 
304
            %% The call has a continuation. Jump to it.
 
305
            {NewContLab,
 
306
             [hipe_arm:mk_label(NewContLab) |
 
307
              Moves ++
 
308
              [hipe_arm:mk_b_label(ContLab)]]}
 
309
        end
 
310
    end,
 
311
  SDesc = hipe_arm:mk_sdesc(ExnLab, 0, length(Args), {}),
 
312
  CallInsn = hipe_arm:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage),
 
313
  {RegArgs,StkArgs} = split_args(Args),
 
314
  mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).
 
315
 
 
316
mk_call_results([]) ->
 
317
  [];
 
318
mk_call_results([Dst]) ->
 
319
  RV = hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged'),
 
320
  [hipe_arm:mk_pseudo_move(Dst, RV)];
 
321
mk_call_results(Dsts) ->
 
322
  exit({?MODULE,mk_call_results,Dsts}).
 
323
 
 
324
mk_push_args(StkArgs, Tail) ->
 
325
  case length(StkArgs) of
 
326
    0 ->
 
327
      Tail;
 
328
    NrStkArgs ->
 
329
      [hipe_arm:mk_pseudo_call_prepare(NrStkArgs) |
 
330
       mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)]
 
331
  end.
 
332
  
 
333
mk_store_args([Arg|Args], PrevOffset, Tail) ->
 
334
  Offset = PrevOffset - word_size(),
 
335
  {Src,FixSrc} =
 
336
    case hipe_arm:is_temp(Arg) of
 
337
      true ->
 
338
        {Arg, []};
 
339
      _ ->
 
340
        Tmp = new_tagged_temp(),
 
341
        {Tmp, mk_li(Tmp, Arg)}
 
342
    end,
 
343
  NewTail = hipe_arm:mk_store('str', Src, mk_sp(), Offset, 'new', Tail),
 
344
  mk_store_args(Args, Offset, FixSrc ++ NewTail);
 
345
mk_store_args([], _, Tail) ->
 
346
  Tail.
 
347
 
 
348
conv_comment(I, Map, Data) ->
 
349
  I2 = [hipe_arm:mk_comment(hipe_rtl:comment_text(I))],
 
350
  {I2, Map, Data}.
 
351
 
 
352
conv_enter(I, Map, Data) ->
 
353
  {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),
 
354
  {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),
 
355
  I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)),
 
356
  {I2, Map1, Data}.
 
357
 
 
358
mk_enter(Fun, Args, Linkage) ->
 
359
  Arity = length(Args),
 
360
  {RegArgs,StkArgs} = split_args(Args),
 
361
  move_actuals(RegArgs,
 
362
               [hipe_arm:mk_pseudo_tailcall_prepare(),
 
363
                hipe_arm:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]).
 
364
 
 
365
conv_goto(I, Map, Data) ->
 
366
  I2 = [hipe_arm:mk_b_label(hipe_rtl:goto_label(I))],
 
367
  {I2, Map, Data}.
 
368
 
 
369
conv_label(I, Map, Data) ->
 
370
  I2 = [hipe_arm:mk_label(hipe_rtl:label_name(I))],
 
371
  {I2, Map, Data}.
 
372
 
 
373
conv_load(I, Map, Data) ->
 
374
  {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),
 
375
  {Base1, Map1} = conv_src(hipe_rtl:load_src(I), Map0),
 
376
  {Base2, Map2} = conv_src(hipe_rtl:load_offset(I), Map1),
 
377
  LoadSize = hipe_rtl:load_size(I),
 
378
  LoadSign = hipe_rtl:load_sign(I),
 
379
  I2 = mk_load(Dst, Base1, Base2, LoadSize, LoadSign),
 
380
  {I2, Map2, Data}.
 
381
 
 
382
mk_load(Dst, Base1, Base2, LoadSize, LoadSign) ->
 
383
  case {LoadSize,LoadSign} of
 
384
    {byte,signed} ->
 
385
      case hipe_arm:is_temp(Base1) of
 
386
        true ->
 
387
          case hipe_arm:is_temp(Base2) of
 
388
            true ->
 
389
              mk_ldrsb_rr(Dst, Base1, Base2);
 
390
            _ ->
 
391
              mk_ldrsb_ri(Dst, Base1, Base2)
 
392
          end;
 
393
        _ ->
 
394
          case hipe_arm:is_temp(Base2) of
 
395
            true ->
 
396
              mk_ldrsb_ri(Dst, Base2, Base1);
 
397
            _ ->
 
398
              mk_ldrsb_ii(Dst, Base1, Base2)
 
399
          end
 
400
      end;
 
401
    _ ->
 
402
      LdOp =
 
403
        case LoadSize of
 
404
          byte -> 'ldrb';
 
405
          int32 -> 'ldr';
 
406
          word -> 'ldr'
 
407
        end,
 
408
      case hipe_arm:is_temp(Base1) of
 
409
        true ->
 
410
          case hipe_arm:is_temp(Base2) of
 
411
            true ->
 
412
              mk_load_rr(Dst, Base1, Base2, LdOp);
 
413
            _ ->
 
414
              mk_load_ri(Dst, Base1, Base2, LdOp)
 
415
          end;
 
416
        _ ->
 
417
          case hipe_arm:is_temp(Base2) of
 
418
            true ->
 
419
              mk_load_ri(Dst, Base2, Base1, LdOp);
 
420
            _ ->
 
421
              mk_load_ii(Dst, Base1, Base2, LdOp)
 
422
          end
 
423
      end
 
424
  end.
 
425
 
 
426
mk_load_ii(Dst, Base1, Base2, LdOp) ->
 
427
  io:format("~w: RTL load with two immediates\n", [?MODULE]),
 
428
  Tmp = new_untagged_temp(),
 
429
  mk_li(Tmp, Base1,
 
430
        mk_load_ri(Dst, Tmp, Base2, LdOp)).
 
431
   
 
432
mk_load_ri(Dst, Base, Offset, LdOp) ->
 
433
  hipe_arm:mk_load(LdOp, Dst, Base, Offset, 'new', []).
 
434
 
 
435
mk_load_rr(Dst, Base1, Base2, LdOp) ->
 
436
  Am2 = hipe_arm:mk_am2(Base1, '+', Base2),
 
437
  [hipe_arm:mk_load(LdOp, Dst, Am2)].
 
438
 
 
439
mk_ldrsb_ii(Dst, Base1, Base2) ->
 
440
  io:format("~w: RTL load signed byte with two immediates\n", [?MODULE]),
 
441
  Tmp = new_untagged_temp(),
 
442
  mk_li(Tmp, Base1,
 
443
        mk_ldrsb_ri(Dst, Tmp, Base2)).
 
444
   
 
445
mk_ldrsb_ri(Dst, Base, Offset) ->
 
446
  {Sign,AbsOffset} =
 
447
    if Offset < 0 -> {'-', -Offset};
 
448
       true -> {'+', Offset}
 
449
    end,
 
450
  if AbsOffset =< 255 ->
 
451
      Am3 = hipe_arm:mk_am3(Base, Sign, AbsOffset),
 
452
      [hipe_arm:mk_ldrsb(Dst, Am3)];
 
453
     true ->
 
454
      Index = new_untagged_temp(),
 
455
      Am3 = hipe_arm:mk_am3(Base, Sign, Index),
 
456
      [mk_li(Index, AbsOffset),
 
457
       hipe_arm:mk_ldrsb(Dst, Am3)]
 
458
  end.
 
459
 
 
460
mk_ldrsb_rr(Dst, Base1, Base2) ->
 
461
  Am3 = hipe_arm:mk_am3(Base1, '+', Base2),
 
462
  [hipe_arm:mk_ldrsb(Dst, Am3)].
 
463
 
 
464
conv_load_address(I, Map, Data) ->
 
465
  {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map),
 
466
  Addr = hipe_rtl:load_address_address(I),
 
467
  Type = hipe_rtl:load_address_type(I),
 
468
  Src = {Addr,Type},
 
469
  I2 = [hipe_arm:mk_pseudo_li(Dst, Src)],
 
470
  {I2, Map0, Data}.
 
471
 
 
472
conv_load_atom(I, Map, Data) ->
 
473
  {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map),
 
474
  Src = hipe_rtl:load_atom_atom(I),
 
475
  I2 = [hipe_arm:mk_pseudo_li(Dst, Src)],
 
476
  {I2, Map0, Data}.
 
477
 
 
478
conv_move(I, Map, Data) ->
 
479
  {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map),
 
480
  {Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0),
 
481
  I2 = mk_move(Dst, Src, []),
 
482
  {I2, Map1, Data}.
 
483
 
 
484
mk_move(Dst, Src, Tail) ->
 
485
  case hipe_arm:is_temp(Src) of
 
486
    true -> [hipe_arm:mk_pseudo_move(Dst, Src) | Tail];
 
487
    _ -> mk_li(Dst, Src, Tail)
 
488
  end.
 
489
 
 
490
conv_return(I, Map, Data) ->
 
491
  %% TODO: multiple-value returns
 
492
  {[Arg], Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map),
 
493
  I2 = mk_move(mk_rv(), Arg,
 
494
               [hipe_arm:mk_pseudo_blr()]),
 
495
  {I2, Map0, Data}.
 
496
 
 
497
conv_store(I, Map, Data) ->
 
498
  {Base, Map0} = conv_dst(hipe_rtl:store_base(I), Map),
 
499
  {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),
 
500
  {Offset, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),
 
501
  StoreSize = hipe_rtl:store_size(I),
 
502
  I2 = mk_store(Src, Base, Offset, StoreSize),
 
503
  {I2, Map2, Data}.
 
504
 
 
505
mk_store(Src, Base, Offset, StoreSize) ->
 
506
  StOp =
 
507
    case StoreSize of
 
508
      byte -> 'strb';
 
509
      int32 -> 'str';
 
510
      word -> 'str'
 
511
    end,
 
512
  case hipe_arm:is_temp(Src) of
 
513
    true ->
 
514
      mk_store2(Src, Base, Offset, StOp);
 
515
    _ ->
 
516
      Tmp = new_untagged_temp(),
 
517
      mk_li(Tmp, Src,
 
518
            mk_store2(Tmp, Base, Offset, StOp))
 
519
  end.
 
520
 
 
521
mk_store2(Src, Base, Offset, StOp) ->
 
522
  case hipe_arm:is_temp(Offset) of
 
523
    true ->
 
524
      mk_store_rr(Src, Base, Offset, StOp);
 
525
    _ ->
 
526
      mk_store_ri(Src, Base, Offset, StOp)
 
527
  end.
 
528
  
 
529
mk_store_ri(Src, Base, Offset, StOp) ->
 
530
  hipe_arm:mk_store(StOp, Src, Base, Offset, 'new', []).
 
531
   
 
532
mk_store_rr(Src, Base, Index, StOp) ->
 
533
  Am2 = hipe_arm:mk_am2(Base, '+', Index),
 
534
  [hipe_arm:mk_store(StOp, Src, Am2)].
 
535
 
 
536
conv_switch(I, Map, Data) ->
 
537
  Labels = hipe_rtl:switch_labels(I),
 
538
  LMap = [{label,L} || L <- Labels],
 
539
  {NewData, JTabLab} =
 
540
    case hipe_rtl:switch_sort_order(I) of
 
541
      [] ->
 
542
        hipe_consttab:insert_block(Data, word, LMap);
 
543
      SortOrder ->
 
544
        hipe_consttab:insert_sorted_block(
 
545
          Data, word, LMap, SortOrder)
 
546
    end,
 
547
  %% no immediates allowed here
 
548
  {IndexR, Map1} = conv_dst(hipe_rtl:switch_src(I), Map),
 
549
  JTabR = new_untagged_temp(),
 
550
  I2 =
 
551
    [hipe_arm:mk_pseudo_li(JTabR, {JTabLab,constant}),
 
552
     hipe_arm:mk_pseudo_switch(JTabR, IndexR, Labels)],
 
553
  {I2, Map1, NewData}.
 
554
 
 
555
%%% Create a conditional branch.
 
556
 
 
557
mk_pseudo_bc(Cond, TrueLabel, FalseLabel, Pred) ->
 
558
  [hipe_arm:mk_pseudo_bc(Cond, TrueLabel, FalseLabel, Pred)].
 
559
 
 
560
%%% Load an integer constant into a register.
 
561
 
 
562
mk_li(Dst, Value) -> mk_li(Dst, Value, []).
 
563
 
 
564
mk_li(Dst, Value, Tail) ->
 
565
  hipe_arm:mk_li(Dst, Value, Tail).
 
566
 
 
567
%%% Convert an RTL condition code.
 
568
 
 
569
conv_alub_cond(Cond) -> % only signed
 
570
  case Cond of
 
571
    eq  -> 'eq';
 
572
    ne  -> 'ne';
 
573
    gt  -> 'gt';
 
574
    ge  -> 'ge';
 
575
    lt  -> 'lt';
 
576
    le  -> 'le';
 
577
    overflow -> 'vs';
 
578
    not_overflow -> 'vc';
 
579
    _   -> exit({?MODULE,conv_alub_cond,Cond})
 
580
  end.
 
581
 
 
582
conv_branch_cond(Cond) -> % may be unsigned
 
583
  case Cond of
 
584
    gtu -> 'hi';
 
585
    geu -> 'hs';
 
586
    ltu -> 'lo';
 
587
    leu -> 'ls';
 
588
    _   -> conv_alub_cond(Cond)
 
589
  end.    
 
590
 
 
591
%%% Commute an ARM condition code.
 
592
 
 
593
commute_cond(Cond) ->   % if x Cond y, then y commute_cond(Cond) x
 
594
  case Cond of
 
595
    'eq' -> 'eq';       % ==, ==
 
596
    'ne' -> 'ne';       % !=, !=
 
597
    'gt' -> 'lt';       % >, <
 
598
    'ge' -> 'le';       % >=, <=
 
599
    'lt' -> 'gt';       % <, >
 
600
    'le' -> 'ge';       % <=, >=
 
601
    'hi' -> 'lo';       % >u, <u
 
602
    'hs' -> 'ls';       % >=u, <=u
 
603
    'lo' -> 'hi';       % <u, >u
 
604
    'ls' -> 'hs';       % <=u, >=u
 
605
    %% vs/vc: n/a
 
606
    _ -> exit({?MODULE,commute_cond,Cond})
 
607
  end.
 
608
 
 
609
%%% Split a list of formal or actual parameters into the
 
610
%%% part passed in registers and the part passed on the stack.
 
611
%%% The parameters passed in registers are also tagged with
 
612
%%% the corresponding registers.
 
613
 
 
614
split_args(Args) ->
 
615
  split_args(0, hipe_arm_registers:nr_args(), Args, []).
 
616
 
 
617
split_args(I, N, [Arg|Args], RegArgs) when I < N ->
 
618
  Reg = hipe_arm_registers:arg(I),
 
619
  Temp = hipe_arm:mk_temp(Reg, 'tagged'),
 
620
  split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]);
 
621
split_args(_, _, StkArgs, RegArgs) ->
 
622
  {RegArgs, StkArgs}.
 
623
 
 
624
%%% Convert a list of actual parameters passed in
 
625
%%% registers (from split_args/1) to a list of moves.
 
626
 
 
627
move_actuals([{Src,Dst}|Actuals], Rest) ->
 
628
  move_actuals(Actuals, mk_move(Dst, Src, Rest));
 
629
move_actuals([], Rest) ->
 
630
  Rest.
 
631
 
 
632
%%% Convert a list of formal parameters passed in
 
633
%%% registers (from split_args/1) to a list of moves.
 
634
 
 
635
move_formals([{Dst,Src}|Formals], Rest) ->
 
636
  move_formals(Formals, [hipe_arm:mk_pseudo_move(Dst, Src) | Rest]);
 
637
move_formals([], Rest) ->
 
638
  Rest.
 
639
 
 
640
%%% Convert a 'fun' operand (MFA, prim, or temp)
 
641
 
 
642
conv_fun(Fun, Map) ->
 
643
  case hipe_rtl:is_var(Fun) of
 
644
    true ->
 
645
      conv_dst(Fun, Map);
 
646
    false ->
 
647
      case hipe_rtl:is_reg(Fun) of
 
648
        true ->
 
649
          conv_dst(Fun, Map);
 
650
        false ->
 
651
          if is_atom(Fun) ->
 
652
              {hipe_arm:mk_prim(Fun), Map};
 
653
             true ->
 
654
              {conv_mfa(Fun), Map}
 
655
          end
 
656
      end
 
657
  end.
 
658
 
 
659
%%% Convert an MFA operand.
 
660
 
 
661
conv_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
 
662
  hipe_arm:mk_mfa(M, F, A).
 
663
 
 
664
%%% Convert an RTL source operand (imm/var/reg).
 
665
%%% Returns a temp or a naked integer.
 
666
 
 
667
conv_src(Opnd, Map) ->
 
668
  case hipe_rtl:is_imm(Opnd) of
 
669
    true ->
 
670
      Value = hipe_rtl:imm_value(Opnd),
 
671
      if is_integer(Value) ->
 
672
          {Value, Map}
 
673
      end;
 
674
    false ->
 
675
      conv_dst(Opnd, Map)
 
676
  end.
 
677
 
 
678
conv_src_list([O|Os], Map) ->
 
679
  {V, Map1} = conv_src(O, Map),
 
680
  {Vs, Map2} = conv_src_list(Os, Map1),
 
681
  {[V|Vs], Map2};
 
682
conv_src_list([], Map) ->
 
683
  {[], Map}.
 
684
 
 
685
%%% Convert an RTL destination operand (var/reg).
 
686
 
 
687
conv_dst(Opnd, Map) ->
 
688
  {Name, Type} =
 
689
    case hipe_rtl:is_var(Opnd) of
 
690
      true ->
 
691
        {hipe_rtl:var_index(Opnd), 'tagged'};
 
692
      false ->
 
693
        case hipe_rtl:is_fpreg(Opnd) of
 
694
          true ->
 
695
            {hipe_rtl:fpreg_index(Opnd), 'double'};
 
696
          false ->
 
697
            {hipe_rtl:reg_index(Opnd), 'untagged'}
 
698
        end
 
699
    end,
 
700
  IsPrecoloured =
 
701
    case Type of
 
702
      'double' -> false; %hipe_arm_registers:is_precoloured_fpr(Name);
 
703
      _ -> hipe_arm_registers:is_precoloured_gpr(Name)
 
704
    end,
 
705
  case IsPrecoloured of
 
706
    true ->
 
707
      {hipe_arm:mk_temp(Name, Type), Map};
 
708
    false ->
 
709
      case vmap_lookup(Map, Opnd) of
 
710
        {value, NewTemp} ->
 
711
          {NewTemp, Map};
 
712
        _ ->
 
713
          NewTemp = hipe_arm:mk_new_temp(Type),
 
714
          {NewTemp, vmap_bind(Map, Opnd, NewTemp)}
 
715
      end
 
716
  end.
 
717
 
 
718
conv_dst_list([O|Os], Map) ->
 
719
  {Dst, Map1} = conv_dst(O, Map),
 
720
  {Dsts, Map2} = conv_dst_list(Os, Map1),
 
721
  {[Dst|Dsts], Map2};
 
722
conv_dst_list([], Map) ->
 
723
  {[], Map}.
 
724
 
 
725
conv_formals(Os, Map) ->
 
726
  conv_formals(hipe_arm_registers:nr_args(), Os, Map, []).
 
727
 
 
728
conv_formals(N, [O|Os], Map, Res) ->
 
729
  Type =
 
730
    case hipe_rtl:is_var(O) of
 
731
      true -> 'tagged';
 
732
      _ -> 'untagged'
 
733
    end,
 
734
  Dst =
 
735
    if N > 0 -> hipe_arm:mk_new_temp(Type);     % allocatable
 
736
       true -> hipe_arm:mk_new_nonallocatable_temp(Type)
 
737
    end,
 
738
  Map1 = vmap_bind(Map, O, Dst),
 
739
  conv_formals(N-1, Os, Map1, [Dst|Res]);
 
740
conv_formals(_, [], Map, Res) ->
 
741
  {lists:reverse(Res), Map}.
 
742
 
 
743
%%% Create a temp representing the stack pointer register.
 
744
 
 
745
mk_sp() ->
 
746
  hipe_arm:mk_temp(hipe_arm_registers:stack_pointer(), 'untagged').
 
747
 
 
748
%%% Create a temp representing the return value register.
 
749
 
 
750
mk_rv() ->
 
751
  hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged').
 
752
 
 
753
%%% new_untagged_temp -- conjure up an untagged scratch reg
 
754
 
 
755
new_untagged_temp() ->
 
756
  hipe_arm:mk_new_temp('untagged').
 
757
 
 
758
%%% new_tagged_temp -- conjure up a tagged scratch reg
 
759
 
 
760
new_tagged_temp() ->
 
761
  hipe_arm:mk_new_temp('tagged').
 
762
 
 
763
%%% Map from RTL var/reg operands to temps.
 
764
 
 
765
vmap_empty() ->
 
766
  gb_trees:empty().
 
767
 
 
768
vmap_lookup(Map, Key) ->
 
769
  gb_trees:lookup(Key, Map).
 
770
 
 
771
vmap_bind(Map, Key, Val) ->
 
772
  gb_trees:insert(Key, Val, Map).
 
773
 
 
774
word_size() ->
 
775
  4.