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%% ====================================================================
16%%  Module   : hipe_rtl_binary_construct
17%%  Purpose  :
18%%  Notes    :
19%%  History  : Written mostly by Per Gustafsson
20%% ====================================================================
21%%  Exports  :
22%%
23%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
24
25-module(hipe_rtl_binary_construct).
26
27-export([gen_rtl/7]).
28
29-import(hipe_rtl_binary, [get_word_integer/4]).
30
31%%-------------------------------------------------------------------------
32
33-include("../main/hipe.hrl").
34-include("hipe_rtl.hrl").
35-include("hipe_literals.hrl").
36
37-define(BYTE_SHIFT, hipe_rtl:mk_imm(3)). %% Turn bits into bytes or vice versa
38-define(LOW_BITS, hipe_rtl:mk_imm(7)). %% Three lowest bits set
39-define(LOW_BITS_INT, 7).
40-define(BYTE_SIZE, 8).
41-define(MAX_BINSIZE, ((1 bsl ((hipe_rtl_arch:word_size()*?BYTE_SIZE)-3)) - 1)).
42
43%% -------------------------------------------------------------------------
44%% The code is generated as a list of lists, it will be flattened later.
45%%
46
47gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab) ->
48  %%io:format("~w, ~w, ~w~n", [BsOP, Args, Dst]),
49  case BsOP of
50    {bs_put_string, String, SizeInBytes} ->
51      [NewOffset] = get_real(Dst),
52      [Base, Offset] = Args,
53      put_string(NewOffset, ConstTab, String, SizeInBytes, Base, Offset,
54		 TrueLblName);
55    _ ->
56      Code =
57	case BsOP of
58	  {bs_init, Size, _Flags} ->
59	    [] = Args,
60	    [Dst0, Base, Offset] = Dst,
61	    case is_illegal_const(Size bsl 3) of
62	      true ->
63		hipe_rtl:mk_goto(SystemLimitLblName);
64	      false ->
65		const_init2(Size, Dst0, Base, Offset, TrueLblName)
66	    end;
67
68	  {bs_init, _Flags} ->
69	    [Size] = Args,
70	    [Dst0, Base, Offset] = Dst,
71	    var_init2(Size, Dst0, Base, Offset, TrueLblName,
72		      SystemLimitLblName, FalseLblName);
73
74	  {bs_init_bits, Size, _Flags} ->
75	    [] = Args,
76	    [Dst0, Base, Offset] = Dst,
77	    case is_illegal_const(Size) of
78	      true ->
79		hipe_rtl:mk_goto(SystemLimitLblName);
80	      false ->
81		const_init_bits(Size, Dst0, Base, Offset, TrueLblName)
82	    end;
83
84	  {bs_init_bits, _Flags} ->
85	    [Size] = Args,
86	    [Dst0, Base, Offset] = Dst,
87	    var_init_bits(Size, Dst0, Base, Offset, TrueLblName,
88			  SystemLimitLblName, FalseLblName);
89
90	  {bs_put_binary_all, Unit, _Flags} ->
91	    [Src, Base, Offset] = Args,
92	    [NewOffset] = get_real(Dst),
93	    put_binary_all(NewOffset, Src, Base, Offset, Unit,
94			   TrueLblName, FalseLblName);
95
96	  {bs_put_binary, Size, _Flags} ->
97	    case is_illegal_const(Size) of
98	      true ->
99		[hipe_rtl:mk_goto(FalseLblName)];
100	      false ->
101		[NewOffset] = get_real(Dst),
102		case Args of
103		  [Src, Base, Offset] ->
104		    put_static_binary(NewOffset, Src, Size, Base, Offset,
105				      TrueLblName, FalseLblName);
106		  [Src, Bits, Base, Offset]  ->
107		    {SizeCode, SizeReg} =
108		      hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
109						FalseLblName),
110		    InCode = put_dynamic_binary(NewOffset, Src, SizeReg, Base,
111						Offset, TrueLblName, FalseLblName),
112		    SizeCode ++ InCode
113		end
114	    end;
115
116	  {bs_put_float, Size, Flags, ConstInfo} ->
117	    [NewOffset] = get_real(Dst),
118	    Aligned = aligned(Flags),
119	    LittleEndian = littleendian(Flags),
120	   case is_illegal_const(Size) of
121	     true ->
122	     	[hipe_rtl:mk_goto(FalseLblName)];
123	     false ->
124	       case Args of
125		 [Src, Base, Offset] ->
126		   CCode = static_float_c_code(NewOffset, Src, Base, Offset, Size, Flags,
127					       TrueLblName, FalseLblName),
128		   put_float(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
129			     LittleEndian, ConstInfo, TrueLblName);
130		 [Src, Bits, Base, Offset] ->
131		   {SizeCode, SizeReg} =
132		     hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
133					       FalseLblName),
134		   InCode = float_c_code(NewOffset, Src, Base, Offset, SizeReg,
135					 Flags, TrueLblName, FalseLblName),
136		   SizeCode ++ InCode
137	       end
138	   end;
139
140	  {unsafe_bs_put_integer, 0, _Flags, _ConstInfo} ->
141	    [NewOffset] = get_real(Dst),
142	    case Args of
143	      [_Src, _Base, Offset] ->
144		[hipe_rtl:mk_move(NewOffset,Offset),
145		 hipe_rtl:mk_goto(TrueLblName)];
146	      [_Src, _Bits, _Base, Offset] ->
147		[hipe_rtl:mk_move(NewOffset,Offset),
148		 hipe_rtl:mk_goto(TrueLblName)]
149	    end;
150
151	  {unsafe_bs_put_integer, Size, Flags, ConstInfo} ->
152	    do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, true,
153			      TrueLblName, FalseLblName, SystemLimitLblName);
154
155	  {bs_put_integer, Size, Flags, ConstInfo} ->
156	    do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, false,
157			      TrueLblName, FalseLblName, SystemLimitLblName);
158
159	  bs_utf8_size ->
160	    case Dst of
161	      [_DstVar] ->
162		[_Arg] = Args,
163		[hipe_rtl:mk_call(Dst, bs_utf8_size, Args,
164				  TrueLblName, [], not_remote)];
165	      [] ->
166		[hipe_rtl:mk_goto(TrueLblName)]
167	    end;
168
169	  bs_put_utf8 ->
170	    [_Src, _Base, _Offset] = Args,
171	    [NewOffs] = get_real(Dst),
172            RetLbl = hipe_rtl:mk_new_label(),
173            [hipe_rtl:mk_call([NewOffs], bs_put_utf8, Args,
174                              hipe_rtl:label_name(RetLbl), [], not_remote),
175             RetLbl,
176             hipe_rtl:mk_branch(NewOffs, ne, hipe_rtl:mk_imm(0),
177                                TrueLblName, FalseLblName, 0.99)];
178
179	  bs_utf16_size ->
180	    case Dst of
181	      [_DstVar] ->
182		[_Arg] = Args,
183		[hipe_rtl:mk_call(Dst, bs_utf16_size, Args,
184				  TrueLblName, [], not_remote)];
185	      [] ->
186		[hipe_rtl:mk_goto(TrueLblName)]
187	    end;
188
189	  {bs_put_utf16, Flags} ->
190	    [_Src, _Base, _Offset] = Args,
191	    NewDsts = get_real(Dst),
192	    PrimOp =	% workaround for bif/primop arity restrictions
193	      case littleendian(Flags) of
194		false -> bs_put_utf16be;
195		true -> bs_put_utf16le
196	      end,
197	    [hipe_rtl:mk_call(NewDsts, PrimOp, Args,
198			      TrueLblName, FalseLblName, not_remote)];
199
200	  bs_validate_unicode ->
201	    [_Arg] = Args,
202            [IsUnicode] = create_regs(1),
203            RetLbl = hipe_rtl:mk_new_label(),
204            [hipe_rtl:mk_call([IsUnicode], is_unicode, Args,
205                              hipe_rtl:label_name(RetLbl), [], not_remote),
206             RetLbl,
207             hipe_rtl:mk_branch(IsUnicode, ne, hipe_rtl:mk_imm(0),
208                                TrueLblName, FalseLblName, 0.99)];
209
210	  bs_final ->
211	    Zero = hipe_rtl:mk_imm(0),
212	    [Src, Offset] = Args,
213	    [BitSize, ByteSize] = create_regs(2),
214	    [ShortLbl, LongLbl] = create_lbls(2),
215	    case Dst of
216	      [DstVar] ->
217		[hipe_rtl:mk_alub(BitSize, Offset, 'and', ?LOW_BITS, eq,
218				  hipe_rtl:label_name(ShortLbl),
219				  hipe_rtl:label_name(LongLbl)), ShortLbl,
220		 hipe_rtl:mk_move(DstVar, Src),
221		 hipe_rtl:mk_goto(TrueLblName),
222		 LongLbl,
223		 hipe_rtl:mk_alu(ByteSize, Offset, 'srl', ?BYTE_SHIFT),
224		 hipe_tagscheme:mk_sub_binary(DstVar, ByteSize,
225					      Zero, BitSize, Zero, Src),
226		 hipe_rtl:mk_goto(TrueLblName)];
227	      [] ->
228		[hipe_rtl:mk_goto(TrueLblName)]
229	    end;
230
231	  bs_init_writable ->
232	    Zero = hipe_rtl:mk_imm(0),
233	    [Size] = Args,
234	    [DstVar] = Dst,
235	    [SizeReg] = create_regs(1),
236	    [Base] = create_unsafe_regs(1),
237	    [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE + ?SUB_BIN_WORDSIZE),
238	     get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
239	     allocate_writable(DstVar, Base, SizeReg, Zero, Zero),
240	     hipe_rtl:mk_goto(TrueLblName)];
241
242	  {bs_private_append, _U, _F} ->
243	    [Size, Bin] = Args,
244	    [DstVar, Base, Offset] = Dst,
245	    [ProcBin] = create_vars(1),
246	    [SubSize, SizeReg, EndSubSize, EndSubBitSize] = create_regs(4),
247	    SubBinSize = {sub_binary, binsize},
248	    [hipe_tagscheme:get_field_from_term({sub_binary, orig}, Bin, ProcBin),
249	     hipe_tagscheme:get_field_from_term(SubBinSize, Bin, SubSize),
250	     get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
251	     realloc_binary(SizeReg, ProcBin, Base),
252	     calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
253	     hipe_tagscheme:set_field_from_term(SubBinSize, Bin, EndSubSize),
254	     hipe_tagscheme:set_field_from_term({sub_binary, bitsize}, Bin, EndSubBitSize),
255	     hipe_rtl:mk_move(DstVar, Bin),
256	     hipe_rtl:mk_goto(TrueLblName)];
257
258	  {bs_append, _U, _F, Unit, _Bla} ->
259	    [Size, Bin] = Args,
260	    [DstVar, Base, Offset] = Dst,
261	    [ProcBin] = create_vars(1),
262	    [Flags, SizeReg, IsWritable, EndSubSize, EndSubBitSize] =
263	      create_regs(5),
264	    [ContLbl,ContLbl2,ContLbl3,ContLbl4,WritableLbl,NotWritableLbl] =
265	      Lbls = create_lbls(6),
266	    [ContLblName, ContLbl2Name, ContLbl3Name, ContLbl4Name,
267	     Writable, NotWritable] =
268	      [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
269	    Zero = hipe_rtl:mk_imm(0),
270	    SubIsWritable = {sub_binary, is_writable},
271	    [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE + ?PROC_BIN_WORDSIZE),
272	     get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
273	     hipe_tagscheme:test_bitstr(Bin, ContLblName, FalseLblName, 0.99),
274	     ContLbl,
275	     hipe_tagscheme:test_subbinary(Bin,ContLbl2Name, NotWritable),
276	     ContLbl2,
277	     hipe_tagscheme:get_field_from_term(SubIsWritable, Bin, IsWritable),
278	     hipe_rtl:mk_branch(IsWritable, 'ne', Zero,
279				ContLbl3Name, NotWritable),
280	     ContLbl3,
281	     hipe_tagscheme:get_field_from_term({sub_binary, orig}, Bin, ProcBin),
282	     hipe_tagscheme:get_field_from_term({proc_bin, flags}, ProcBin, Flags),
283	     hipe_rtl:mk_alub(Flags, Flags, 'and',
284			      hipe_rtl:mk_imm(?PB_IS_WRITABLE),
285			      eq, NotWritable, ContLbl4Name, 0.01),
286	     ContLbl4,
287	     calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
288	     is_divisible(Offset, Unit, Writable, FalseLblName),
289	     WritableLbl,
290	     hipe_tagscheme:set_field_from_term(SubIsWritable, Bin, Zero),
291	     realloc_binary(SizeReg, ProcBin, Base),
292	     hipe_tagscheme:mk_sub_binary(DstVar, EndSubSize, Zero,
293					  EndSubBitSize, Zero,
294					  hipe_rtl:mk_imm(1), ProcBin),
295	     hipe_rtl:mk_goto(TrueLblName),
296	     NotWritableLbl,
297	     not_writable_code(Bin, SizeReg, DstVar, Base, Offset, Unit,
298			       TrueLblName, FalseLblName)]
299	end,
300      {Code, ConstTab}
301  end.
302
303%% Common implementation of bs_put_integer and unsafe_bs_put_integer
304do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, SrcUnsafe,
305		  TrueLblName, FalseLblName, SystemLimitLblName) ->
306  case is_illegal_const(Size) of
307    true ->
308      [hipe_rtl:mk_goto(FalseLblName)];
309    false ->
310      Aligned = aligned(Flags),
311      LittleEndian = littleendian(Flags),
312      [NewOffset] = get_real(Dst),
313      case ConstInfo of
314	fail ->
315	  [hipe_rtl:mk_goto(FalseLblName)];
316	_ ->
317	  case Args of
318	    [Src, Base, Offset] ->
319	      CCode = static_int_c_code(NewOffset, Src, Base, Offset, Size,
320					Flags, TrueLblName, FalseLblName),
321	      put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
322			     LittleEndian, SrcUnsafe, TrueLblName);
323	    [Src, Bits, Base, Offset] ->
324	      {SizeCode, SizeReg} =
325		hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
326					  FalseLblName),
327	      CCode = int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
328				 TrueLblName, FalseLblName),
329	      InCode = put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg,
330				       CCode, Aligned, LittleEndian, SrcUnsafe,
331				       TrueLblName),
332	      SizeCode ++ InCode
333	  end
334      end
335  end.
336
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338%%
339%%  Code that is used in the append and init writeable functions
340%%
341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342
343not_writable_code(Bin, SizeReg, Dst, Base, Offset, Unit,
344		  TrueLblName, FalseLblName) ->
345  [SrcBase] = create_unsafe_regs(1),
346  [SrcOffset, SrcSize, TotSize, TotBytes, UsedBytes] = create_regs(5),
347  [IncLbl,AllLbl] = Lbls = create_lbls(2),
348  [IncLblName,AllLblName] = get_label_names(Lbls),
349  [get_base_offset_size(Bin, SrcBase, SrcOffset, SrcSize, FalseLblName),
350   hipe_rtl:mk_alu(TotSize, SrcSize, add, SizeReg),
351   hipe_rtl:mk_alu(TotBytes, TotSize, add, ?LOW_BITS),
352   hipe_rtl:mk_alu(TotBytes, TotBytes, srl, ?BYTE_SHIFT),
353   hipe_rtl:mk_alu(UsedBytes, TotBytes, sll, hipe_rtl:mk_imm(1)),
354   hipe_rtl:mk_branch(UsedBytes, geu, hipe_rtl:mk_imm(256),
355		      AllLblName, IncLblName),
356   IncLbl,
357   hipe_rtl:mk_move(UsedBytes, hipe_rtl:mk_imm(256)),
358   AllLbl,
359   allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize),
360   put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0), Unit,
361		  TrueLblName, FalseLblName)].
362
363allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
364  Zero = hipe_rtl:mk_imm(0),
365  [NextLbl] = create_lbls(1),
366  [EndSubSize, EndSubBitSize] = create_regs(2),
367  [ProcBin] = create_unsafe_regs(1),
368  [hipe_rtl:mk_call([Base], bs_allocate, [UsedBytes],
369		    hipe_rtl:label_name(NextLbl), [], not_remote),
370   NextLbl,
371   hipe_tagscheme:create_refc_binary(Base, TotBytes,
372				     hipe_rtl:mk_imm(?PB_IS_WRITABLE bor
373						     ?PB_ACTIVE_WRITER),
374				     ProcBin),
375   hipe_rtl:mk_alu(EndSubSize, TotSize, srl, ?BYTE_SHIFT),
376   hipe_rtl:mk_alu(EndSubBitSize, TotSize, 'and', ?LOW_BITS),
377   hipe_tagscheme:mk_sub_binary(Dst, EndSubSize, Zero, EndSubBitSize,
378				Zero, hipe_rtl:mk_imm(1), ProcBin)].
379
380realloc_binary(SizeReg, ProcBin, Base) ->
381  [NoReallocLbl, ReallocLbl, NextLbl, ContLbl] = Lbls = create_lbls(4),
382  [NoReallocLblName, ReallocLblName, NextLblName, ContLblName] =
383    [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
384  [PBSize, Tmp, ByteSize, NewSize, Flags, ResultingSize, OrigSize,
385   BinPointer] = create_regs(8),
386  ProcBinSizeTag = {proc_bin, binsize},
387  ProcBinFlagsTag = {proc_bin, flags},
388  ProcBinValTag = {proc_bin, val},
389  ProcBinBytesTag = {proc_bin, bytes},
390  BinOrigSizeTag = {binary, orig_size},
391  [hipe_tagscheme:get_field_from_term(ProcBinSizeTag, ProcBin, PBSize),
392   hipe_rtl:mk_alu(Tmp, SizeReg, 'add', ?LOW_BITS),
393   hipe_rtl:mk_alu(ByteSize, Tmp, 'srl', ?BYTE_SHIFT),
394   hipe_rtl:mk_alu(ResultingSize, ByteSize, 'add', PBSize),
395   hipe_tagscheme:set_field_from_term(ProcBinSizeTag, ProcBin, ResultingSize),
396   hipe_tagscheme:get_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
397   hipe_rtl:mk_alu(Flags, Flags, 'or', hipe_rtl:mk_imm(?PB_ACTIVE_WRITER)),
398   hipe_tagscheme:set_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
399   hipe_tagscheme:get_field_from_term(ProcBinValTag, ProcBin, BinPointer),
400   hipe_tagscheme:get_field_from_pointer(BinOrigSizeTag, BinPointer, OrigSize),
401   hipe_rtl:mk_branch(OrigSize, 'geu', ResultingSize, NoReallocLblName,
402		      ReallocLblName),
403   NoReallocLbl,
404   hipe_tagscheme:get_field_from_term(ProcBinBytesTag, ProcBin, Base),
405   hipe_rtl:mk_goto(ContLblName),
406   ReallocLbl,
407   hipe_rtl:mk_alu(NewSize, ResultingSize, 'sll', hipe_rtl:mk_imm(1)),
408   hipe_rtl:mk_call([BinPointer], bs_reallocate, [BinPointer, NewSize],
409		    NextLblName, [], not_remote),
410   NextLbl,
411   hipe_tagscheme:set_field_from_pointer(BinOrigSizeTag, BinPointer, NewSize),
412   hipe_tagscheme:set_field_from_term(ProcBinValTag, ProcBin, BinPointer),
413   hipe_tagscheme:extract_binary_bytes(BinPointer, Base),
414   hipe_tagscheme:set_field_from_term(ProcBinBytesTag, ProcBin, Base),
415   ContLbl].
416
417calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize) ->
418  [SubSize, SubBitSize, EndSize] = create_regs(3),
419  [hipe_tagscheme:get_field_from_term({sub_binary, binsize}, Bin, SubSize),
420   hipe_tagscheme:get_field_from_term({sub_binary, bitsize}, Bin, SubBitSize),
421   hipe_rtl:mk_alu(Offset, SubSize, 'sll', ?BYTE_SHIFT),
422   hipe_rtl:mk_alu(Offset, Offset, 'add', SubBitSize),
423   hipe_rtl:mk_alu(EndSize, Offset, 'add', SizeReg),
424   hipe_rtl:mk_alu(EndSubSize, EndSize, srl, ?BYTE_SHIFT),
425   hipe_rtl:mk_alu(EndSubBitSize, EndSize, 'and', ?LOW_BITS)].
426
427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428%%
429%%  Code that is used to create calls to beam functions
430%%
431%%  X_c_code/8, used for putting terms into binaries
432%%
433%%  X_get_c_code/10, used for getting terms from binaries
434%%
435%% - gen_test_sideffect_bs_call/4 is used to make a C-call that might
436%%       fail but doesn't return an erlang value.
437%%
438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439
440static_float_c_code(NewOffset, Src, Base, Offset, Size, Flags,
441		    TrueLblName, FalseLblName) ->
442  [SizeReg] = create_regs(1),
443  [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))|
444   float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
445		TrueLblName, FalseLblName)].
446
447float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
448	     TrueLblName, FalseLblName) ->
449  put_c_code(bs_put_small_float, NewOffset, Src, Base, Offset, SizeReg,
450	     Flags, TrueLblName, FalseLblName).
451
452static_int_c_code(NewOffset, Src, Base, Offset, Size, Flags,
453		  TrueLblName, FalseLblName) ->
454  [SizeReg] = create_regs(1),
455  [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))|
456   int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
457	      TrueLblName, FalseLblName)].
458
459int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
460	   TrueLblName, FalseLblName) ->
461  put_c_code(bs_put_big_integer, NewOffset, Src, Base, Offset, SizeReg,
462	     Flags, TrueLblName, FalseLblName).
463
464binary_c_code(NewOffset, Src, Base, Offset, Size, TrueLblName) ->
465  PassedLbl = hipe_rtl:mk_new_label(),
466  [SizeReg, FlagsReg] = create_regs(2),
467  [hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(0)),
468   hipe_rtl:mk_move(SizeReg, Size),
469   hipe_rtl:mk_call([], bs_put_bits, [Src, SizeReg, Base, Offset, FlagsReg],
470		    hipe_rtl:label_name(PassedLbl), [], not_remote),
471   PassedLbl,
472   hipe_rtl:mk_alu(NewOffset, Offset, add, SizeReg),
473   hipe_rtl:mk_goto(TrueLblName)].
474
475put_c_code(Func, NewOffset, Src, Base, Offset, SizeReg, Flags,
476	   TrueLblName, FalseLblName) ->
477  PassedLbl = hipe_rtl:mk_new_label(),
478  [FlagsReg] = create_regs(1),
479  [hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
480   gen_test_sideffect_bs_call(Func, [Src, SizeReg, Base, Offset, FlagsReg],
481			      hipe_rtl:label_name(PassedLbl), FalseLblName),
482   PassedLbl,
483   hipe_rtl:mk_alu(NewOffset, Offset, add, SizeReg),
484   hipe_rtl:mk_goto(TrueLblName)].
485
486gen_test_sideffect_bs_call(Name, Args, TrueLblName, FalseLblName) ->
487  [Tmp1] = create_regs(1),
488  RetLbl = hipe_rtl:mk_new_label(),
489  [hipe_rtl:mk_call([Tmp1], Name, Args,
490		    hipe_rtl:label_name(RetLbl), [], not_remote),
491   RetLbl,
492   hipe_rtl:mk_branch(Tmp1, eq, hipe_rtl:mk_imm(0),
493		      FalseLblName, TrueLblName, 0.01)].
494
495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496%%
497%% Small utility functions:
498%%
499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500
501create_regs(X) when X > 0 ->
502  [hipe_rtl:mk_new_reg_gcsafe()|create_regs(X-1)];
503create_regs(0) ->
504  [].
505
506create_unsafe_regs(X) when X > 0 ->
507  [hipe_rtl:mk_new_reg()|create_unsafe_regs(X-1)];
508create_unsafe_regs(0) ->
509  [].
510
511create_vars(X) when X > 0 ->
512  [hipe_rtl:mk_new_var()|create_vars(X-1)];
513create_vars(0) ->
514  [].
515
516create_lbls(X) when X > 0 ->
517  [hipe_rtl:mk_new_label()|create_lbls(X-1)];
518create_lbls(0) ->
519  [].
520
521get_label_names(Lbls) ->
522  [hipe_rtl:label_name(Lbl) || Lbl <- Lbls].
523
524aligned(Flags) ->
525  case Flags band ?BSF_ALIGNED of
526    1 -> true;
527    0 -> false
528  end.
529
530littleendian(Flags) ->
531  case Flags band 2 of
532    2 -> true;
533    0 -> false
534  end.
535
536is_illegal_const(Const) ->
537  Const >= (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)) orelse Const < 0.
538
539get_real(Dst) ->
540  case Dst of
541    [_NewOffset] -> Dst;
542    [] -> create_regs(1)
543  end.
544
545%%-----------------------------------------------------------------------------
546%% Help functions implementing the bs operations in rtl code.
547%%
548%% The following functions are called from the translation switch:
549%%
550%% - put_string/7 creates code to copy a string to a binary
551%%       starting at base+offset and ending at base+newoffset
552%%
553%% - const_init2/6 initializes the creation of a binary of constant size
554%%
555%% - var_init2/6 initializes the creation of a binary of variable size
556%%
557%% - get_int_from_unaligned_bin/11 creates code to extract a fixed
558%%       size integer from a binary or makes a c-call if it does not
559%%       conform to some certain rules.
560%%
561%% - get_unknown_size_int/11 creates code to extract a variable size
562%%       byte-aligned integer from a binary or makes a c-call if it
563%%       does not conform to some certain rules.
564%%
565%% - skip_no_of_bits/5 creates code to skip a variable amount of bits
566%%       in a binary.
567%%
568%% - load_match_buffer/7 reloads the C-matchbuffer to RTL registers.
569%%
570%% - expand_runtime/4 creates code that calculates a maximal heap need
571%%       before a binary match
572%%-----------------------------------------------------------------------------
573
574put_string(NewOffset, ConstTab, String, SizeInBytes, Base, Offset, TLName) ->
575  [StringBase] = create_regs(1),
576  {NewTab, Lbl} = hipe_consttab:insert_block(ConstTab, byte, String),
577  {[hipe_rtl:mk_load_address(StringBase, Lbl, constant)|
578    copy_string(StringBase, SizeInBytes, Base, Offset, NewOffset, TLName)],
579   NewTab}.
580
581const_init2(Size, Dst, Base, Offset, TrueLblName) ->
582  Log2WordSize = hipe_rtl_arch:log2_word_size(),
583  WordSize = hipe_rtl_arch:word_size(),
584  NextLbl = hipe_rtl:mk_new_label(),
585  case Size =< ?MAX_HEAP_BIN_SIZE of
586    true ->
587      [hipe_rtl:mk_gctest(((Size + 3*WordSize-1) bsr Log2WordSize)+?SUB_BIN_WORDSIZE),
588       hipe_tagscheme:create_heap_binary(Base, Size, Dst),
589       hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
590       hipe_rtl:mk_goto(TrueLblName)];
591    false ->
592      ByteSize = hipe_rtl:mk_new_reg(),
593      [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
594       hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm(Size)),
595       hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
596			hipe_rtl:label_name(NextLbl), [], not_remote),
597       NextLbl,
598       hipe_tagscheme:create_refc_binary(Base, ByteSize, Dst),
599       hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
600       hipe_rtl:mk_goto(TrueLblName)]
601  end.
602
603const_init_bits(Size, Dst, Base, Offset, TrueLblName) ->
604  Log2WordSize = hipe_rtl_arch:log2_word_size(),
605  WordSize = hipe_rtl_arch:word_size(),
606  [NextLbl] = create_lbls(1),
607  TmpDst = hipe_rtl:mk_new_var(),
608  Zero = hipe_rtl:mk_imm(0),
609  {ExtraSpace, SubBinCode} =
610    case (Size rem ?BYTE_SIZE) =:= 0 of
611      true ->
612	{0, [hipe_rtl:mk_move(Dst, TmpDst)]};
613      false ->
614	{?SUB_BIN_WORDSIZE,
615	 hipe_tagscheme:mk_sub_binary(Dst, hipe_rtl:mk_imm(Size bsr 3), Zero,
616				      hipe_rtl:mk_imm(Size band ?LOW_BITS_INT),
617				      Zero, TmpDst)}
618    end,
619  BaseBinCode =
620    case Size =< (?MAX_HEAP_BIN_SIZE * 8) of
621      true ->
622	ByteSize = (Size + 7) div 8,
623	[hipe_rtl:mk_gctest(((ByteSize + 3*WordSize-1) bsr Log2WordSize) + ExtraSpace),
624	 hipe_tagscheme:create_heap_binary(Base, ByteSize, TmpDst),
625	 hipe_rtl:mk_move(Offset, Zero)];
626      false ->
627	ByteSize = hipe_rtl:mk_new_reg(),
628	[hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+ExtraSpace),
629	 hipe_rtl:mk_move(Offset, Zero),
630	 hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm((Size+7) bsr 3)),
631	 hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
632			  hipe_rtl:label_name(NextLbl), [], not_remote),
633	 NextLbl,
634	 hipe_tagscheme:create_refc_binary(Base, ByteSize, TmpDst)]
635    end,
636  [BaseBinCode, SubBinCode, hipe_rtl:mk_goto(TrueLblName)].
637
638var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
639  Log2WordSize = hipe_rtl_arch:log2_word_size(),
640  WordSize = hipe_rtl_arch:word_size(),
641  [ContLbl, HeapLbl, REFCLbl, NextLbl] = create_lbls(4),
642  [USize, Tmp] = create_regs(2),
643  [get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
644   hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_BINSIZE),
645		      hipe_rtl:label_name(ContLbl),
646		      SystemLimitLblName),
647   ContLbl,
648   hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
649		      hipe_rtl:label_name(HeapLbl),
650		      hipe_rtl:label_name(REFCLbl)),
651   HeapLbl,
652   hipe_rtl:mk_alu(Tmp, USize, add, hipe_rtl:mk_imm(3*WordSize-1)),
653   hipe_rtl:mk_alu(Tmp, Tmp, srl, hipe_rtl:mk_imm(Log2WordSize)),
654   hipe_rtl:mk_alu(Tmp, Tmp, add, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
655   hipe_rtl:mk_gctest(Tmp),
656   hipe_tagscheme:create_heap_binary(Base, USize, Dst),
657   hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
658   hipe_rtl:mk_goto(TrueLblName),
659   REFCLbl,
660   hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
661   hipe_rtl:mk_call([Base], bs_allocate, [USize],
662		    hipe_rtl:label_name(NextLbl), [], not_remote),
663   NextLbl,
664   hipe_tagscheme:create_refc_binary(Base, USize, Dst),
665   hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
666   hipe_rtl:mk_goto(TrueLblName)].
667
668var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
669  [HeapLbl, REFCLbl, NextLbl, NoSubLbl, SubLbl,
670   NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(9),
671  [USize, ByteSize, TotByteSize, OffsetBits] = create_regs(4),
672  [TmpDst] = create_unsafe_regs(1),
673  Log2WordSize = hipe_rtl_arch:log2_word_size(),
674  WordSize = hipe_rtl_arch:word_size(),
675  MaximumWords =
676    erlang:max((?MAX_HEAP_BIN_SIZE + 3*WordSize) bsr Log2WordSize,
677	       ?PROC_BIN_WORDSIZE) + ?SUB_BIN_WORDSIZE,
678  Zero = hipe_rtl:mk_imm(0),
679  [hipe_rtl:mk_gctest(MaximumWords),
680   get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
681   hipe_rtl:mk_alu(ByteSize, USize, srl, ?BYTE_SHIFT),
682   hipe_rtl:mk_alub(OffsetBits, USize, 'and', ?LOW_BITS, eq,
683		    hipe_rtl:label_name(NoSubLbl),
684		    hipe_rtl:label_name(SubLbl)),
685   NoSubLbl,
686   hipe_rtl:mk_move(TotByteSize, ByteSize),
687   hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
688   SubLbl,
689   hipe_rtl:mk_alu(TotByteSize, ByteSize, 'add', hipe_rtl:mk_imm(1)),
690   JoinLbl,
691   hipe_rtl:mk_branch(TotByteSize, 'leu', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
692		      hipe_rtl:label_name(HeapLbl),
693		      hipe_rtl:label_name(REFCLbl)),
694   HeapLbl,
695   hipe_tagscheme:create_heap_binary(Base, TotByteSize, TmpDst),
696   hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl2)),
697   REFCLbl,
698   hipe_rtl:mk_call([Base], bs_allocate, [TotByteSize],
699		    hipe_rtl:label_name(NextLbl), [], not_remote),
700   NextLbl,
701   hipe_tagscheme:create_refc_binary(Base, TotByteSize, TmpDst),
702   JoinLbl2,
703   hipe_rtl:mk_move(Offset, Zero),
704   hipe_rtl:mk_branch(OffsetBits, 'eq', Zero,
705		      hipe_rtl:label_name(NoCreateSubBin),
706		      hipe_rtl:label_name(CreateSubBin)),
707   CreateSubBin,
708   hipe_tagscheme:mk_sub_binary(Dst, ByteSize, Zero, OffsetBits, Zero, TmpDst),
709   hipe_rtl:mk_goto(TrueLblName),
710   NoCreateSubBin,
711   hipe_rtl:mk_move(Dst, TmpDst),
712   hipe_rtl:mk_goto(TrueLblName)].
713
714put_binary_all(NewOffset, Src, Base, Offset, Unit, TLName, FLName) ->
715  [SrcBase, SrcOffset, NumBits] = create_regs(3),
716  [ContLbl] = create_lbls(1),
717  CCode = binary_c_code(NewOffset, Src, Base, Offset, NumBits, TLName),
718  AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, NumBits, Base, Offset,
719				   NewOffset, TLName),
720  [get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName),
721   is_divisible(NumBits, Unit, hipe_rtl:label_name(ContLbl), FLName),
722   ContLbl
723   |test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode)].
724
725test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode) ->
726  [Tmp] = create_regs(1),
727  [AlignedLbl, CLbl] = create_lbls(2),
728   [hipe_rtl:mk_alu(Tmp, SrcOffset, 'or', NumBits),
729   hipe_rtl:mk_alu(Tmp, Tmp, 'or', Offset),
730   hipe_rtl:mk_branch(Tmp, 'and', ?LOW_BITS, 'eq',
731		      hipe_rtl:label_name(AlignedLbl),
732		      hipe_rtl:label_name(CLbl), 0.5),
733   AlignedLbl,
734   AlignedCode,
735   CLbl,
736   CCode].
737
738put_static_binary(NewOffset, Src, Size, Base, Offset, TLName, FLName) ->
739  [SrcBase] = create_unsafe_regs(1),
740  [SrcOffset, SrcSize] = create_regs(2),
741    case Size of
742      0 ->
743	get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
744	[hipe_rtl:mk_move(NewOffset, Offset),
745	 hipe_rtl:mk_goto(TLName)];
746      _ ->
747	SizeImm = hipe_rtl:mk_imm(Size),
748	CCode = binary_c_code(NewOffset, Src, Base, Offset, SizeImm, TLName),
749	AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, SizeImm, Base,
750					 Offset, NewOffset, TLName),
751	get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
752	  small_check(SizeImm, SrcSize, FLName) ++
753	  test_alignment(SrcOffset, SizeImm, Offset, AlignedCode, CCode)
754     end.
755
756put_dynamic_binary(NewOffset, Src, SizeReg, Base, Offset, TLName, FLName) ->
757  [SrcBase] = create_unsafe_regs(1),
758  [SrcOffset, SrcSize] = create_regs(2),
759  CCode = binary_c_code(NewOffset, Src, Base, Offset, SizeReg, TLName),
760  AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, SizeReg, Base, Offset,
761				   NewOffset, TLName),
762  get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
763    small_check(SizeReg, SrcSize, FLName) ++
764    test_alignment(SrcOffset, SizeReg, Offset, AlignedCode, CCode).
765
766put_float(NewOffset, Src, Base, Offset, 64, CCode, Aligned, LittleEndian,
767	  ConstInfo, TrueLblName) ->
768  [CLbl] = create_lbls(1),
769  case {Aligned, LittleEndian} of
770    {true, false} ->
771      copy_float_big(Base, Offset, NewOffset, Src,
772		     hipe_rtl:label_name(CLbl), TrueLblName, ConstInfo) ++
773	[CLbl|CCode];
774    {true, true} ->
775      copy_float_little(Base, Offset, NewOffset, Src,
776			hipe_rtl:label_name(CLbl), TrueLblName, ConstInfo) ++
777	[CLbl|CCode];
778    {false, _} ->
779      CCode
780  end;
781put_float(_NewOffset, _Src, _Base, _Offset, _Size, CCode, _Aligned,
782	  _LittleEndian, _ConstInfo, _TrueLblName) ->
783  CCode.
784
785put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
786	       LittleEndian, SrcUnsafe, TrueLblName) ->
787  {Init, End, UntaggedSrc} = make_init_end(Src, CCode, SrcUnsafe, TrueLblName),
788  case {Aligned, LittleEndian} of
789    {true, true} ->
790      Init ++
791	copy_int_little(Base, Offset, NewOffset, Size, UntaggedSrc) ++
792	End;
793    {true, false} ->
794      Init ++
795	copy_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
796	End;
797    {false, true} ->
798      CCode;
799    {false, false} ->
800      Init ++
801	copy_offset_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
802	End
803  end.
804
805put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
806		LittleEndian, SrcUnsafe, TrueLblName) ->
807  {Init, End, UntaggedSrc} = make_init_end(Src, CCode, SrcUnsafe, TrueLblName),
808  case Aligned of
809    true ->
810      case LittleEndian of
811	true ->
812	  Init ++
813	    copy_int_little(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
814	    End;
815	false ->
816	  Init ++
817	    copy_int_big(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
818	    End
819	end;
820    false ->
821      CCode
822  end.
823
824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825%%
826%% Help functions used by the above
827%%
828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829
830make_init_end(Src, CCode, false, TrueLblName) ->
831  [CLbl, SuccessLbl] = create_lbls(2),
832  [UntaggedSrc] = create_regs(1),
833  Init = [hipe_tagscheme:test_fixnum(Src, hipe_rtl:label_name(SuccessLbl),
834				     hipe_rtl:label_name(CLbl), 0.99),
835	  SuccessLbl,
836	  hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
837  End = [hipe_rtl:mk_goto(TrueLblName), CLbl| CCode],
838  {Init, End, UntaggedSrc};
839make_init_end(Src, _CCode, true, TrueLblName) ->
840  [UntaggedSrc] = create_regs(1),
841  Init = [hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
842  End = [hipe_rtl:mk_goto(TrueLblName)],
843  {Init, End, UntaggedSrc}.
844
845get_base_offset_size(Binary, SrcBase, SrcOffset, SrcSize, FLName) ->
846  [JoinLbl, EndLbl, SuccessLbl, SubLbl, OtherLbl, HeapLbl, REFCLbl] =
847    Lbls = create_lbls(7),
848  [JoinLblName, EndLblName, SuccessLblName, SubLblName,
849   OtherLblName, HeapLblName, REFCLblName] = get_label_names(Lbls),
850  [BitSize, BitOffset] = create_regs(2),
851  [Orig] = create_vars(1),
852  [hipe_tagscheme:test_bitstr(Binary, SuccessLblName, FLName, 0.99),
853   SuccessLbl,
854   hipe_tagscheme:get_field_from_term({sub_binary,binsize}, Binary, SrcSize),
855   hipe_rtl:mk_alu(SrcSize, SrcSize, sll, ?BYTE_SHIFT),
856   hipe_tagscheme:test_subbinary(Binary, SubLblName, OtherLblName),
857   SubLbl,
858   hipe_tagscheme:get_field_from_term({sub_binary,bitsize}, Binary, BitSize),
859   hipe_tagscheme:get_field_from_term({sub_binary,offset}, Binary, SrcOffset),
860   hipe_rtl:mk_alu(SrcSize, SrcSize, add, BitSize),
861   hipe_tagscheme:get_field_from_term({sub_binary,bitoffset}, Binary, BitOffset),
862   hipe_rtl:mk_alu(SrcOffset, SrcOffset, sll, ?BYTE_SHIFT),
863   hipe_rtl:mk_alu(SrcOffset, SrcOffset, add, BitOffset),
864   hipe_tagscheme:get_field_from_term({sub_binary,orig}, Binary, Orig),
865   hipe_rtl:mk_goto(JoinLblName),
866   OtherLbl,
867   hipe_rtl:mk_move(SrcOffset, hipe_rtl:mk_imm(0)),
868   hipe_rtl:mk_move(Orig, Binary),
869   JoinLbl,
870   hipe_tagscheme:test_heap_binary(Orig, HeapLblName, REFCLblName),
871   HeapLbl,
872   hipe_tagscheme:get_field_addr_from_term({heap_bin, {data, 0}}, Orig, SrcBase),
873   hipe_rtl:mk_goto(EndLblName),
874   REFCLbl,
875   hipe_tagscheme:get_field_from_term({proc_bin,bytes}, Orig, SrcBase),
876   EndLbl].
877
878copy_aligned_bytes(CopyBase, CopyOffset, Size, Base, Offset, NewOffset, TrueLblName) ->
879  [BaseDst, BaseSrc] = create_unsafe_regs(2),
880  [Iter, Extra, BothOffset] = create_regs(3),
881  initializations(BaseSrc, BaseDst, BothOffset, CopyOffset, Offset, CopyBase, Base) ++
882    [hipe_rtl:mk_alu(Extra, Size, 'and', ?LOW_BITS),
883     hipe_rtl:mk_alu(Iter, Size, srl, ?BYTE_SHIFT),
884     hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)] ++
885    easy_loop(BaseSrc, BaseDst, BothOffset, Iter, Extra, TrueLblName).
886
887copy_string(StringBase, StringSize, BinBase, BinOffset, NewOffset, TrueLblName) ->
888  [TmpOffset,BothOffset,InitOffs] = create_regs(3),
889  [NewBinBase] = create_unsafe_regs(1),
890  [EasyLbl, HardLbl] = create_lbls(2),
891  [hipe_rtl:mk_alu(TmpOffset, BinOffset, srl, ?BYTE_SHIFT),
892   hipe_rtl:mk_alu(NewBinBase, BinBase, add, TmpOffset),
893   hipe_rtl:mk_move(BothOffset, hipe_rtl:mk_imm(0)),
894   hipe_rtl:mk_alub(InitOffs, BinOffset, 'and', ?LOW_BITS, eq,
895		    hipe_rtl:label_name(EasyLbl), hipe_rtl:label_name(HardLbl)),
896   EasyLbl,
897   hipe_rtl:mk_alu(NewOffset, BinOffset, add,
898		   hipe_rtl:mk_imm(?bytes_to_bits(StringSize)))] ++
899   easy_loop(StringBase, NewBinBase, BothOffset,
900	     hipe_rtl:mk_imm(StringSize), hipe_rtl:mk_imm(0), TrueLblName) ++
901    [HardLbl,
902     hipe_rtl:mk_alu(NewOffset, BinOffset, add,
903		     hipe_rtl:mk_imm(?bytes_to_bits(StringSize)))] ++
904    hard_loop(StringBase, NewBinBase, BothOffset, hipe_rtl:mk_imm(StringSize),
905	      InitOffs, TrueLblName).
906
907small_check(SizeVar, CopySize, FalseLblName) ->
908  SuccessLbl = hipe_rtl:mk_new_label(),
909  [hipe_rtl:mk_branch(SizeVar, leu, CopySize,
910		      hipe_rtl:label_name(SuccessLbl), FalseLblName),
911   SuccessLbl].
912
913easy_loop(BaseSrc, BaseDst, BothOffset, Iterations, Extra, TrueLblName) ->
914  [Tmp1, Shift] = create_regs(2),
915  [LoopLbl, TopLbl, EndLbl, ExtraLbl] = create_lbls(4),
916  [TopLbl,
917   hipe_rtl:mk_branch(BothOffset, ne, Iterations, hipe_rtl:label_name(LoopLbl),
918		      hipe_rtl:label_name(EndLbl), 0.99),
919   LoopLbl,
920   hipe_rtl:mk_load(Tmp1, BaseSrc, BothOffset, byte, unsigned),
921   hipe_rtl:mk_store(BaseDst, BothOffset, Tmp1, byte),
922   hipe_rtl:mk_alu(BothOffset, BothOffset, add, hipe_rtl:mk_imm(1)),
923   hipe_rtl:mk_goto(hipe_rtl:label_name(TopLbl)),
924   EndLbl,
925   hipe_rtl:mk_branch(Extra, eq, hipe_rtl:mk_imm(0), TrueLblName,
926		      hipe_rtl:label_name(ExtraLbl)),
927   ExtraLbl,
928   hipe_rtl:mk_load(Tmp1, BaseSrc, BothOffset, byte, unsigned),
929   hipe_rtl:mk_alu(Shift, hipe_rtl:mk_imm(?BYTE_SIZE), sub, Extra),
930   hipe_rtl:mk_alu(Tmp1, Tmp1, srl, Shift),
931   hipe_rtl:mk_alu(Tmp1, Tmp1, sll, Shift),
932   hipe_rtl:mk_store(BaseDst, BothOffset, Tmp1, byte),
933   hipe_rtl:mk_goto(TrueLblName)].
934
935hard_loop(BaseSrc, BaseDst, BothOffset, Iterations,
936	  InitOffset, TrueLblName) ->
937  [Tmp1, Tmp2, OldByte, NewByte, SaveByte] = create_regs(5),
938  [LoopLbl, EndLbl, TopLbl] = create_lbls(3),
939  [hipe_rtl:mk_load(OldByte, BaseDst, BothOffset, byte, unsigned),
940   hipe_rtl:mk_alu(Tmp1, hipe_rtl:mk_imm(?BYTE_SIZE), sub, InitOffset),
941   TopLbl,
942   hipe_rtl:mk_branch(BothOffset, ne, Iterations,
943		      hipe_rtl:label_name(LoopLbl),
944		      hipe_rtl:label_name(EndLbl)),
945   LoopLbl,
946   hipe_rtl:mk_load(NewByte, BaseSrc, BothOffset, byte, unsigned),
947   hipe_rtl:mk_alu(Tmp2, NewByte, srl, InitOffset),
948   hipe_rtl:mk_alu(SaveByte, OldByte, 'or', Tmp2),
949   hipe_rtl:mk_store(BaseDst, BothOffset, SaveByte, byte),
950   hipe_rtl:mk_alu(OldByte, NewByte, sll, Tmp1),
951   hipe_rtl:mk_alu(BothOffset, BothOffset, 'add', hipe_rtl:mk_imm(1)),
952   hipe_rtl:mk_goto(hipe_rtl:label_name(TopLbl)),
953   EndLbl,
954   hipe_rtl:mk_store(BaseDst, BothOffset, OldByte, byte),
955   hipe_rtl:mk_goto(TrueLblName)].
956
957initializations(BaseTmp1, BaseTmp2, BothOffset, CopyOffset, Offset, CopyBase, Base) ->
958  [OffsetTmp1,OffsetTmp2] = create_regs(2),
959  [hipe_rtl:mk_alu(OffsetTmp1, CopyOffset, srl, ?BYTE_SHIFT),
960   hipe_rtl:mk_alu(OffsetTmp2, Offset, srl, ?BYTE_SHIFT),
961   hipe_rtl:mk_alu(BaseTmp1, CopyBase, add, OffsetTmp1),
962   hipe_rtl:mk_alu(BaseTmp2, Base, add, OffsetTmp2),
963   hipe_rtl:mk_move(BothOffset, hipe_rtl:mk_imm(0))].
964
965copy_int_little(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
966  [Tmp2,TmpOffset] = create_regs(2),
967  ByteSize = Size div ?BYTE_SIZE,
968  [hipe_rtl:mk_alu(TmpOffset, Offset, srl, ?BYTE_SHIFT),
969   hipe_rtl:mk_alu(Tmp2, hipe_rtl:mk_imm(ByteSize), 'add', TmpOffset)] ++
970
971    little_loop(Tmp1, Tmp2, TmpOffset, Base) ++
972
973    case Size band 7 of
974      0 ->
975	[hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))];
976      Bits ->
977	[hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(?BYTE_SIZE-Bits)),
978	 hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
979	 hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))]
980    end;
981copy_int_little(Base, Offset, NewOffset, Size, Tmp1) ->
982  [Tmp2, Tmp3, Tmp4, TmpOffset] = create_regs(4),
983  [hipe_rtl:mk_alu(Tmp2, Size, srl, ?BYTE_SHIFT),
984   hipe_rtl:mk_alu(TmpOffset, Offset, srl, ?BYTE_SHIFT),
985   hipe_rtl:mk_alu(Tmp3, Tmp2, 'add', TmpOffset)] ++
986
987    little_loop(Tmp1, Tmp3, TmpOffset, Base) ++
988
989    [hipe_rtl:mk_alu(Tmp4, Size, 'and', ?LOW_BITS),
990     hipe_rtl:mk_alu(Tmp4, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp4),
991     hipe_rtl:mk_alu(Tmp1, Tmp1, sll, Tmp4),
992     hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
993     hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)].
994
995little_loop(Tmp1, Tmp3, TmpOffset, Base) ->
996  [BranchLbl, BodyLbl, EndLbl] = create_lbls(3),
997  [BranchLbl,
998   hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3,
999		      hipe_rtl:label_name(BodyLbl),
1000		      hipe_rtl:label_name(EndLbl)),
1001   BodyLbl,
1002   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1003   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
1004   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
1005   hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
1006   EndLbl].
1007
1008big_loop(Tmp1, Tmp3, TmpOffset, Base) ->
1009  [BranchLbl, BodyLbl, EndLbl] = create_lbls(3),
1010  [BranchLbl,
1011   hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3,
1012		      hipe_rtl:label_name(BodyLbl),
1013		      hipe_rtl:label_name(EndLbl)),
1014   BodyLbl,
1015   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
1016   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1017   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
1018   hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
1019   EndLbl].
1020
1021copy_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
1022  [hipe_rtl:mk_move(NewOffset, Offset)];
1023copy_int_big(Base, Offset, NewOffset, ?BYTE_SIZE, Tmp1) ->
1024  TmpOffset = hipe_rtl:mk_new_reg(),
1025  [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
1026   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1027   hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(8))];
1028copy_int_big(Base, Offset, NewOffset, 2*?BYTE_SIZE, Tmp1) ->
1029  TmpOffset = hipe_rtl:mk_new_reg(),
1030  [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
1031   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
1032   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1033   hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
1034   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(8)),
1035   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1036   hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(16))];
1037copy_int_big(Base, Offset, NewOffset, 3*?BYTE_SIZE, Tmp1) ->
1038  TmpOffset = hipe_rtl:mk_new_reg(),
1039  [hipe_rtl:mk_alu(TmpOffset, Offset, srl, hipe_rtl:mk_imm(3)),
1040   hipe_rtl:mk_alu(TmpOffset, TmpOffset, add, hipe_rtl:mk_imm(2)),
1041   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1042   hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
1043   hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(8)),
1044   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1045   hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
1046   hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(8)),
1047   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1048   hipe_rtl:mk_alu(NewOffset, Offset, add, hipe_rtl:mk_imm(24))];
1049copy_int_big(Base, Offset,NewOffset, 4*?BYTE_SIZE, Tmp1) ->
1050  copy_big_word(Base, Offset, NewOffset, Tmp1);
1051copy_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
1052  [OldOffset, TmpOffset, Bits] = create_regs(3),
1053  ByteSize = (Size + 7) div ?BYTE_SIZE,
1054  case Size band 7 of
1055    0 ->
1056      [hipe_rtl:mk_alu(OldOffset, Offset, sra, hipe_rtl:mk_imm(3)),
1057       hipe_rtl:mk_alu(TmpOffset, OldOffset, add, hipe_rtl:mk_imm(ByteSize))];
1058    Rest ->
1059      [hipe_rtl:mk_alu(OldOffset, Offset, sra, hipe_rtl:mk_imm(3)),
1060       hipe_rtl:mk_alu(TmpOffset, OldOffset, add, hipe_rtl:mk_imm(ByteSize-1)),
1061       hipe_rtl:mk_alu(Bits, Tmp1, sll, hipe_rtl:mk_imm(?BYTE_SIZE-Rest)),
1062       hipe_rtl:mk_store(Base, TmpOffset, Bits, byte),
1063       hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(Rest))]
1064  end ++
1065    big_loop(Tmp1, OldOffset, TmpOffset, Base) ++
1066    [hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))];
1067copy_int_big(Base, Offset, NewOffset, Size, Tmp1) ->
1068  Tmp2 = hipe_rtl:mk_new_reg(),
1069  Tmp3 = hipe_rtl:mk_new_reg(),
1070  Tmp4 = hipe_rtl:mk_new_reg(),
1071  Tmp5 = hipe_rtl:mk_new_reg(),
1072  Tmp6 = hipe_rtl:mk_new_reg(),
1073  TmpOffset = hipe_rtl:mk_new_reg(),
1074  EvenLbl = hipe_rtl:mk_new_label(),
1075  OddLbl = hipe_rtl:mk_new_label(),
1076  [hipe_rtl:mk_alu(Tmp2, Size, 'srl', hipe_rtl:mk_imm(3)),
1077   hipe_rtl:mk_alu(Tmp3, Offset, 'srl', hipe_rtl:mk_imm(3)),
1078   hipe_rtl:mk_alu(TmpOffset, Tmp2, 'add', Tmp3),
1079   hipe_rtl:mk_alub(Tmp4, Size, 'and', hipe_rtl:mk_imm(7), 'eq',
1080		    hipe_rtl:label_name(EvenLbl), hipe_rtl:label_name(OddLbl)),
1081   OddLbl,
1082   hipe_rtl:mk_alu(Tmp6, hipe_rtl:mk_imm(8), 'sub', Tmp4),
1083   hipe_rtl:mk_alu(Tmp5, Tmp1, 'sll', Tmp6),
1084   hipe_rtl:mk_store(Base, TmpOffset, Tmp5, byte),
1085   EvenLbl,
1086   hipe_rtl:mk_alu(Tmp1, Tmp1, srl, Tmp4)] ++
1087    big_loop(Tmp1, Tmp3, TmpOffset, Base) ++
1088    [hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)].
1089
1090copy_big_word(Base, Offset, NewOffset, Word) ->
1091  TmpOffset = hipe_rtl:mk_new_reg(),
1092  [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
1093   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(3)),
1094   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1095   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
1096   hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
1097   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1098   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
1099   hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
1100   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1101   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
1102   hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
1103   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1104   hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
1105
1106copy_little_word(Base, Offset, NewOffset, Word) ->
1107  TmpOffset = hipe_rtl:mk_new_reg(),
1108  [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', ?BYTE_SHIFT),
1109   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1110   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
1111   hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
1112   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1113   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
1114   hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
1115   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1116   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
1117   hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
1118   hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
1119   hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
1120
1121copy_offset_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
1122  [hipe_rtl:mk_move(NewOffset, Offset)];
1123copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1)
1124  when is_integer(Size), Size > 0 ->
1125  Tmp2 = hipe_rtl:mk_new_reg(),
1126  Tmp3 = hipe_rtl:mk_new_reg(),
1127  Tmp4 = hipe_rtl:mk_new_reg(),
1128  Tmp5 = hipe_rtl:mk_new_reg(),
1129  Tmp6 = hipe_rtl:mk_new_reg(),
1130  Tmp7 = hipe_rtl:mk_new_reg(),
1131  Tmp8 = hipe_rtl:mk_new_reg(),
1132  Tmp9 = hipe_rtl:mk_new_reg(),
1133  OldByte = hipe_rtl:mk_new_reg(),
1134  TmpOffset = hipe_rtl:mk_new_reg(),
1135  BranchLbl = hipe_rtl:mk_new_label(),
1136  BodyLbl = hipe_rtl:mk_new_label(),
1137  EndLbl = hipe_rtl:mk_new_label(),
1138  NextLbl = hipe_rtl:mk_new_label(),
1139  WordSize = hipe_rtl_arch:word_size(),
1140  [hipe_rtl:mk_alu(Tmp2, Offset, 'and', ?LOW_BITS),
1141   hipe_rtl:mk_alu(Tmp3, Offset, srl, ?BYTE_SHIFT),
1142   hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size)),
1143   hipe_rtl:mk_alu(Tmp9, NewOffset, 'sub', hipe_rtl:mk_imm(1)),
1144   hipe_rtl:mk_alu(TmpOffset, Tmp9, srl, ?BYTE_SHIFT),
1145   hipe_rtl:mk_alu(Tmp4, NewOffset, 'and', ?LOW_BITS),
1146   hipe_rtl:mk_alu(Tmp6, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp4),
1147   hipe_rtl:mk_alu(Tmp6, Tmp6, 'and', ?LOW_BITS),
1148   hipe_rtl:mk_alu(Tmp4, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp6),
1149   hipe_rtl:mk_move(Tmp5, Tmp1),
1150   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sll', Tmp6),
1151   hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3, hipe_rtl:label_name(NextLbl),
1152		      hipe_rtl:label_name(EndLbl)),
1153   NextLbl,
1154   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1155   hipe_rtl:mk_move(Tmp1, Tmp5),
1156   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', Tmp4),
1157   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
1158   BranchLbl,
1159   hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3, hipe_rtl:label_name(BodyLbl),
1160		      hipe_rtl:label_name(EndLbl)),
1161   BodyLbl,
1162   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
1163   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
1164   hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
1165   hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
1166   EndLbl,
1167   hipe_rtl:mk_load(OldByte, Base, TmpOffset, byte, unsigned),
1168   hipe_rtl:mk_alu(Tmp8, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp2),
1169   hipe_rtl:mk_alu(OldByte, OldByte, 'srl', Tmp8),
1170   hipe_rtl:mk_alu(OldByte, OldByte, 'sll', Tmp8),
1171   hipe_rtl:mk_alu(Tmp7, Tmp2, 'add',
1172		   hipe_rtl:mk_imm(?bytes_to_bits(WordSize-1))),
1173   hipe_rtl:mk_alu(Tmp1, Tmp1, 'sll', Tmp7),
1174   hipe_rtl:mk_alu(Tmp1, Tmp1, 'srl', Tmp7),
1175   hipe_rtl:mk_alu(Tmp1, Tmp1, 'or', OldByte),
1176   hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte)].
1177
1178copy_float_little(_Base, _Offset, _NewOffset, _Src, FalseLblName, _TrueLblName, fail) ->
1179  [hipe_rtl:mk_goto(FalseLblName)];
1180copy_float_little(Base, Offset, NewOffset, Src, _FalseLblName, TrueLblName, pass) ->
1181  FloatLo = hipe_rtl:mk_new_reg(),
1182  FloatHi = hipe_rtl:mk_new_reg(),
1183  TmpOffset = hipe_rtl:mk_new_reg(),
1184   hipe_tagscheme:unsafe_load_float(FloatLo, FloatHi, Src) ++
1185    copy_little_word(Base, Offset, TmpOffset, FloatLo) ++
1186    copy_little_word(Base, TmpOffset, NewOffset, FloatHi) ++
1187    [hipe_rtl:mk_goto(TrueLblName)];
1188copy_float_little(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
1189  SuccessLbl = hipe_rtl:mk_new_label(),
1190  hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
1191    [SuccessLbl|copy_float_little(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
1192
1193copy_float_big(_Base, _Offset, _NewOffset, _Src, FalseLblName, _TrueLblName, fail) ->
1194  [hipe_rtl:mk_goto(FalseLblName)];
1195copy_float_big(Base, Offset, NewOffset, Src, _FalseLblName, TrueLblName,pass) ->
1196  FloatLo = hipe_rtl:mk_new_reg(),
1197  FloatHi = hipe_rtl:mk_new_reg(),
1198  TmpOffset = hipe_rtl:mk_new_reg(),
1199  hipe_tagscheme:unsafe_load_float(FloatLo, FloatHi, Src) ++
1200    copy_big_word(Base, Offset, TmpOffset, FloatHi) ++
1201    copy_big_word(Base, TmpOffset, NewOffset, FloatLo) ++
1202    [hipe_rtl:mk_goto(TrueLblName)];
1203copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
1204  SuccessLbl = hipe_rtl:mk_new_label(),
1205  hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
1206    [SuccessLbl|copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
1207
1208is_divisible(_Dividend, 1, SuccLbl, _FailLbl) ->
1209  [hipe_rtl:mk_goto(SuccLbl)];
1210is_divisible(Dividend, Divisor, SuccLbl, FailLbl) ->
1211  Log2 = hipe_rtl_binary:floorlog2(Divisor),
1212  case Divisor =:= 1 bsl Log2 of
1213    true -> %% Divisor is a power of 2
1214      %% Test that the Log2-1 lowest bits are clear
1215      Mask = hipe_rtl:mk_imm(Divisor - 1),
1216      [hipe_rtl:mk_branch(Dividend, 'and', Mask, eq, SuccLbl, FailLbl, 0.99)];
1217    false ->
1218      %% We need division, fall back to a primop
1219      [Tmp] = create_regs(1),
1220      RetLbl = hipe_rtl:mk_new_label(),
1221      [hipe_rtl:mk_call([Tmp], is_divisible,
1222                        [Dividend, hipe_rtl:mk_imm(Divisor)],
1223                        hipe_rtl:label_name(RetLbl), [], not_remote),
1224       RetLbl,
1225       hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
1226                          SuccLbl, FailLbl, 0.99)]
1227  end.
1228