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%%% File    : hipe_rtl_binary_match.erl
17%%% Author  : Per Gustafsson <pergu@it.uu.se>
18%%% Description :
19%%%
20%%% Created :  5 Mar 2007 by Per Gustafsson <pergu@it.uu.se>
21%%%-------------------------------------------------------------------
22-module(hipe_rtl_binary_match).
23
24-export([gen_rtl/5]).
25
26-import(hipe_tagscheme, [set_field_from_term/3, get_field_from_term/3]).
27
28-import(hipe_rtl_binary, [make_size/3]).
29
30-include("hipe_literals.hrl").
31
32%%--------------------------------------------------------------------
33
34-define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa
35-define(LOW_BITS, 7). %% Three lowest bits set
36-define(BYTE_SIZE, 8).
37-define(MAX_SMALL_BITS, (hipe_rtl_arch:word_size() * ?BYTE_SIZE - 5)).
38
39%%--------------------------------------------------------------------
40
41%% ----- bs_start_match -----
42gen_rtl({bs_start_match, 0}, [Ms], [Binary], TrueLblName, FalseLblName) ->
43  ReInitLbl = hipe_rtl:mk_new_label(),
44  BinaryLbl = hipe_rtl:mk_new_label(),
45  TestCode =
46    [hipe_rtl:mk_move(Ms,Binary),
47     hipe_tagscheme:test_matchstate(Binary,
48				    hipe_rtl:label_name(ReInitLbl),
49				    hipe_rtl:label_name(BinaryLbl),
50				    0.99)],
51  ReInitCode = reinit_matchstate(Ms, TrueLblName),
52  OrdinaryCode = make_matchstate(Binary, 0, Ms, TrueLblName, FalseLblName),
53  [TestCode,[ReInitLbl|ReInitCode],[BinaryLbl|OrdinaryCode]];
54gen_rtl({bs_start_match, Max}, [Ms], [Binary], TrueLblName, FalseLblName) ->
55  MatchStateLbl = hipe_rtl:mk_new_label(),
56  BinaryLbl = hipe_rtl:mk_new_label(),
57  ReSizeLbl = hipe_rtl:mk_new_label(),
58  ReInitLbl = hipe_rtl:mk_new_label(),
59  TestCode =
60    [hipe_rtl:mk_move(Ms,Binary),
61     hipe_tagscheme:test_matchstate(Binary,
62				    hipe_rtl:label_name(MatchStateLbl),
63				    hipe_rtl:label_name(BinaryLbl),
64				    0.99)],
65  MatchStateTestCode =
66    [hipe_tagscheme:compare_matchstate(Max, Ms,
67				       hipe_rtl:label_name(ReInitLbl),
68				       hipe_rtl:label_name(ReSizeLbl))],
69  ReSizeCode = resize_matchstate(Ms, Max, TrueLblName),
70  ReInitCode = reinit_matchstate(Ms, TrueLblName),
71  OrdinaryCode = make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName),
72  [TestCode, [MatchStateLbl|MatchStateTestCode], [ReSizeLbl|ReSizeCode],
73   [ReInitLbl|ReInitCode], [BinaryLbl|OrdinaryCode]];
74gen_rtl({bs_start_match, _Max}, [], [Binary], TrueLblName, FalseLblName) ->
75  MatchStateLbl = hipe_rtl:mk_new_label(),
76  [hipe_tagscheme:test_bitstr(Binary, TrueLblName,
77			      hipe_rtl:label_name(MatchStateLbl), 0.99),
78   MatchStateLbl,
79   hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)];
80gen_rtl({{bs_start_match, bitstr}, Max}, [Ms], [Binary],
81	TrueLblName, FalseLblName) ->
82  make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName);
83gen_rtl({{bs_start_match, bitstr}, _Max}, [], [_Binary],
84	TrueLblName, _FalseLblName) ->
85  [hipe_rtl:mk_goto(TrueLblName)];
86gen_rtl({{bs_start_match, ok_matchstate}, Max}, [Ms], [Binary],
87	TrueLblName, FalseLblName) ->
88  MatchStateLbl = hipe_rtl:mk_new_label(),
89  BinaryLbl = hipe_rtl:mk_new_label(),
90  TestCode =
91    [hipe_rtl:mk_move(Ms,Binary),
92     hipe_tagscheme:test_matchstate(Binary,
93				    hipe_rtl:label_name(MatchStateLbl),
94				    hipe_rtl:label_name(BinaryLbl),
95				    0.99)],
96  MatchStateCode = reinit_matchstate(Ms, TrueLblName),
97  OrdinaryCode = make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName),
98  TestCode ++ [MatchStateLbl|MatchStateCode] ++ [BinaryLbl|OrdinaryCode];
99gen_rtl({{bs_start_match, ok_matchstate}, _Max}, [], [Binary],
100	TrueLblName, FalseLblName) ->
101  MatchStateLbl = hipe_rtl:mk_new_label(),
102  [hipe_tagscheme:test_bitstr(Binary, TrueLblName,
103			      hipe_rtl:label_name(MatchStateLbl), 0.99),
104   MatchStateLbl,
105   hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)];
106%% ----- bs_get_integer -----
107gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms],
108	TrueLblName, _FalseLblName) ->
109  update_ms(NewMs, Ms) ++
110    [hipe_rtl:mk_move(Dst, hipe_rtl:mk_imm(15)),
111     hipe_rtl:mk_goto(TrueLblName)];
112gen_rtl({bs_get_integer, Size, Flags}, [Dst, NewMs], Args,
113	TrueLblName, FalseLblName) ->
114  case is_illegal_const(Size) of
115    true ->
116      [hipe_rtl:mk_goto(FalseLblName)];
117    false ->
118      Signed = signed(Flags),
119      LittleEndian = littleendian(Flags),
120      Aligned = aligned(Flags),
121      UnSafe = unsafe(Flags),
122      case Args of
123	[Ms] ->
124	  CCode = int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size),
125				 Flags, TrueLblName, FalseLblName),
126	  update_ms(NewMs, Ms) ++
127	    get_static_int(Dst, Ms, Size, CCode,
128			   Signed, LittleEndian, Aligned, UnSafe,
129			   TrueLblName, FalseLblName);
130	[Ms, Arg] ->
131	  {SizeCode1, SizeReg1} = make_size(Size, Arg, FalseLblName),
132	  CCode = int_get_c_code(Dst, Ms, SizeReg1, Flags,
133				 TrueLblName, FalseLblName),
134	  InCode = get_dynamic_int(Dst, Ms, SizeReg1, CCode,
135				   Signed, LittleEndian, Aligned,
136				   TrueLblName, FalseLblName),
137	  update_ms(NewMs, Ms) ++ SizeCode1 ++ InCode
138      end
139  end;
140%% ----- bs_get_float -----
141gen_rtl({bs_get_float,Size,Flags}, [Dst1, NewMs], Args,
142	TrueLblName, FalseLblName) ->
143  case is_illegal_const(Size) of
144    true ->
145      [hipe_rtl:mk_goto(FalseLblName)];
146    false ->
147      [hipe_rtl:mk_gctest(3)] ++
148	case Args of
149	  [Ms] ->
150	    CCode = float_get_c_code(Dst1, Ms, hipe_rtl:mk_imm(Size), Flags,
151				     TrueLblName, FalseLblName),
152	    update_ms(NewMs, Ms) ++ CCode;
153	  [Ms, Arg]  ->
154	    {SizeCode, SizeReg} = make_size(Size, Arg, FalseLblName),
155	    CCode = float_get_c_code(Dst1, Ms, SizeReg, Flags,
156				     TrueLblName, FalseLblName),
157	    update_ms(NewMs, Ms) ++ SizeCode ++ CCode
158	end
159  end;
160%% ----- bs_get_binary_all -----
161gen_rtl({bs_get_binary_all, Unit, _Flags}, [Dst], [Ms],
162	TrueLblName, FalseLblName) ->
163  [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
164    get_binary_all(Dst, Unit, Ms, TrueLblName,FalseLblName);
165%% ----- bs_get_binary_all_2 -----
166gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst, NewMs], [Ms],
167	TrueLblName, FalseLblName) ->
168  [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
169    update_ms(NewMs, Ms) ++
170    get_binary_all(Dst, Unit, Ms, TrueLblName, FalseLblName);
171%% ----- bs_get_binary -----
172gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args,
173	TrueLblName, FalseLblName) ->
174  case is_illegal_const(Size) of
175    true ->
176      [hipe_rtl:mk_goto(FalseLblName)];
177    false ->
178      Unsafe = unsafe(Flags),
179      {OldMs, SizeReg, SizeCode} =
180	case Args of
181	  [Ms] ->
182	    SzReg = hipe_rtl:mk_new_reg(),
183	    SzCode = [hipe_rtl:mk_move(SzReg, hipe_rtl:mk_imm(Size))],
184	    {Ms, SzReg, SzCode};
185	  [Ms, BitsVar] ->
186	    {SzCode, SzReg} = make_size(Size, BitsVar, FalseLblName),
187	    {Ms, SzReg, SzCode}
188	end,
189      InCode = get_binary(Dst, OldMs, SizeReg, Unsafe,
190			  TrueLblName, FalseLblName),
191      [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
192	update_ms(NewMs, OldMs) ++ SizeCode ++ InCode
193  end;
194%% ----- bs_get_utf8 -----
195gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
196  update_ms(NewMs, Ms) ++ utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName);
197%% ----- bs_get_utf16 -----
198gen_rtl({bs_get_utf16, Flags}, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
199  update_ms(NewMs, Ms) ++
200    utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName);
201%% ----- bs_validate_unicode_retract -----
202gen_rtl(bs_validate_unicode_retract, [NewMs], [Src, Ms],
203	TrueLblName, FalseLblName) ->
204  update_ms(NewMs, Ms) ++
205    validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName);
206%% ----- bs_test_tail -----
207gen_rtl({bs_test_tail, NumBits}, [NewMs], [Ms], TrueLblName, FalseLblName) ->
208  {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
209    update_ms(NewMs, Ms) ++ ExCode ++
210    [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
211     hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
212%% ----- bs_test_unit -----
213gen_rtl({bs_test_unit, Unit}, [], [Ms], TrueLblName, FalseLblName) ->
214  {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
215  SizeReg = hipe_rtl:mk_new_reg(),
216  ExCode ++
217    [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
218    test_alignment_code(SizeReg, Unit, TrueLblName, FalseLblName)];
219gen_rtl({bs_test_tail, NumBits}, [], [Ms], TrueLblName, FalseLblName) ->
220  {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
221    ExCode ++
222    [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
223     hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
224%% ----- bs_skip_bits_all -----
225gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
226	TrueLblName, FalseLblName) ->
227  opt_update_ms(Dst, Ms) ++
228    skip_bits_all(Unit, Ms, TrueLblName, FalseLblName);
229%% ----- bs_skip_bits -----
230gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) ->
231  MaxValue = (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)),
232  opt_update_ms(Dst, Ms) ++
233    case Bits < MaxValue of
234      true ->
235	case Args of
236	  [] ->
237	    skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
238	  [Arg] ->
239	    {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
240	    InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
241	    SizeCode ++ InCode
242	end;
243      false -> % handle overflow case
244	case Args of
245	  [] ->
246	    [hipe_rtl:mk_goto(FalseLblName)];
247	  [Arg] ->
248	    [hipe_rtl:mk_branch(Arg, 'eq', hipe_tagscheme:mk_fixnum(0),
249				TrueLblName, FalseLblName, 0.5)]
250	end
251    end;
252%% ----- bs_restore -----
253gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
254  Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
255  update_ms(NewMs, Ms) ++
256    [get_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Tmp1),
257     set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp1),
258     hipe_rtl:mk_goto(TrueLblName)];
259%% ----- bs_save -----
260gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
261  {Offset, Instr} = extract_matchstate_var(offset, Ms),
262  update_ms(NewMs, Ms) ++
263    [Instr,
264     set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset),
265     hipe_rtl:mk_goto(TrueLblName)];
266%% ----- bs_match_string -----
267gen_rtl({bs_match_string, String, BitSize}, Dst, [Ms],
268	TrueLblName, FalseLblName) ->
269  {[Offset, BinSize, Base], Instrs} =
270    extract_matchstate_vars([offset, binsize, base], Ms),
271  [SuccessLbl, ALbl, ULbl] = create_lbls(3),
272  [NewOffset, BitOffset] = create_gcsafe_regs(2),
273  Unit = (hipe_rtl_arch:word_size() - 1) * ?BYTE_SIZE,
274  Init =
275    [Instrs,
276     opt_update_ms(Dst, Ms),
277     check_size(Offset, hipe_rtl:mk_imm(BitSize), BinSize,
278		NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName),
279     SuccessLbl],
280  SplitCode =
281    [hipe_rtl:mk_alub(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq,
282		      hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))],
283  Loops = BitSize div Unit,
284  SkipSize = Loops * Unit,
285  {ACode1, UCode1} =
286    case Loops of
287      0 ->
288	{[], []};
289      _ ->
290	create_loops(Loops, Unit, String, Base,
291		     Offset, BitOffset, FalseLblName)
292    end,
293  <<_:SkipSize/bits, RestString/bits>> = String,
294  {ACode2, UCode2} =
295    case BitSize rem Unit of
296      0 ->
297	{[], []};
298      Rem ->
299	create_rests(Rem, RestString, Base, Offset, BitOffset, FalseLblName)
300    end,
301  GoTo = hipe_rtl:mk_goto(TrueLblName),
302  End = case Dst of
303	  [] -> [GoTo];
304	  [NewMs] -> [update_offset(NewOffset, NewMs), GoTo]
305	end,
306  [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2, End];
307%% ----- bs_context_to_binary -----
308gen_rtl(bs_context_to_binary, [Bin], [Var], TrueLblName, _FalseLblName) ->
309  MSLabel = hipe_rtl:mk_new_label(),
310  [hipe_rtl:mk_move(Bin, Var),
311   hipe_tagscheme:test_matchstate(Var, hipe_rtl:label_name(MSLabel),
312				  TrueLblName, 0.5),
313   MSLabel,
314   hipe_tagscheme:convert_matchstate(Bin),
315   hipe_rtl:mk_goto(TrueLblName)].
316
317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Calls to C %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318
319int_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
320  make_int_gc_code(Size) ++
321    get_c_code(bs_get_integer_2, Dst1, Ms, Size, Flags,
322	       TrueLblName, FalseLblName).
323
324float_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
325  get_c_code(bs_get_float_2, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName).
326
327get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
328  SizeReg = hipe_rtl:mk_new_reg_gcsafe(),
329  FlagsReg = hipe_rtl:mk_new_reg_gcsafe(),
330  RetReg = hipe_rtl:mk_new_reg_gcsafe(),
331  MatchBuf = hipe_rtl:mk_new_reg(),
332  RetLabel = hipe_rtl:mk_new_label(),
333  OkLabel = hipe_rtl:mk_new_label(),
334  NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
335  [hipe_rtl:mk_move(SizeReg, Size),
336   hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
337   hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
338   hipe_rtl_arch:call_bif([RetReg], Func, [SizeReg, FlagsReg, MatchBuf],
339			  hipe_rtl:label_name(RetLabel), FalseLblName),
340   RetLabel,
341   hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
342		      hipe_rtl:label_name(OkLabel), 0.01),
343   OkLabel,
344   hipe_rtl:mk_move(Dst1, RetReg),
345   hipe_rtl:mk_goto(TrueLblName)].
346
347utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) ->
348  RetReg = hipe_rtl:mk_new_reg_gcsafe(),
349  OkLabel = hipe_rtl:mk_new_label(),
350  MatchBuf = hipe_rtl:mk_new_reg(),
351  NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
352  [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
353   hipe_rtl_arch:call_bif([RetReg], bs_get_utf8, [MatchBuf], [], []),
354   hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
355		      hipe_rtl:label_name(OkLabel), 0.01),
356   OkLabel,
357   hipe_rtl:mk_move(Dst, RetReg),
358   hipe_rtl:mk_goto(TrueLblName)].
359
360utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName) ->
361  RetReg = hipe_rtl:mk_new_reg_gcsafe(),
362  OkLabel = hipe_rtl:mk_new_label(),
363  MatchBuf = hipe_rtl:mk_new_reg(),
364  NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
365  FlagsReg = hipe_rtl:mk_new_reg_gcsafe(),
366  [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
367   hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
368   hipe_rtl_arch:call_bif([RetReg], bs_get_utf16, [MatchBuf, FlagsReg], [], []),
369   hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
370		      hipe_rtl:label_name(OkLabel), 0.01),
371   OkLabel,
372   hipe_rtl:mk_move(Dst, RetReg),
373   hipe_rtl:mk_goto(TrueLblName)].
374
375validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
376  MatchBuf = hipe_rtl:mk_new_reg(),
377  Zero = hipe_rtl:mk_imm(0),
378  Tmp = hipe_rtl:mk_new_reg(),
379  [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
380   hipe_rtl_arch:call_bif([Tmp], bs_validate_unicode_retract,
381			  [MatchBuf, Src], [], []),
382   hipe_rtl:mk_branch(Tmp, eq, Zero, FalseLblName, TrueLblName, 0.01)].
383
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Int Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385
386create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) ->
387  [Reg] = create_gcsafe_regs(1),
388  AlignedFun = fun(Value) ->
389		   [get_int_to_reg(Reg, Unit, Base, Offset, 'srl',
390				   {unsigned, big}),
391		    update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
392	       end,
393  UnAlignedFun = fun(Value) ->
394		     [get_unaligned_int_to_reg(Reg, Unit,
395					       Base, Offset, BitOffset,
396					       'srl', {unsigned, big})|
397		      update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
398		 end,
399  {create_loops(Loops, Unit, String, AlignedFun),
400   create_loops(Loops, Unit, String, UnAlignedFun)}.
401
402create_rests(RemBits, String, Base, Offset, BitOffset, FalseLblName) ->
403  [Reg] = create_gcsafe_regs(1),
404  AlignedFun = fun(Value) ->
405		   [get_int_to_reg(Reg, RemBits, Base, Offset, 'srl',
406				   {unsigned, big})|
407		    just_test(Reg, Value, FalseLblName)]
408	       end,
409  UnAlignedFun = fun(Value) ->
410		     [get_unaligned_int_to_reg(Reg, RemBits,
411					       Base, Offset, BitOffset,
412					       'srl', {unsigned, big})|
413		      just_test(Reg, Value, FalseLblName)]
414		 end,
415  {create_loops(1, RemBits, String, AlignedFun),
416   create_loops(1, RemBits, String, UnAlignedFun)}.
417
418create_loops(0, _Unit, _String, _IntFun) ->
419  [];
420create_loops(N, Unit, String, IntFun) ->
421  {Value, RestString} = get_value(Unit, String),
422  [IntFun(Value),
423   create_loops(N-1, Unit, RestString, IntFun)].
424
425update_and_test(Reg, Unit, Offset, Value, FalseLblName) ->
426  [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit), FalseLblName),
427   just_test(Reg, Value, FalseLblName)].
428
429just_test(Reg, Value, FalseLblName) ->
430  [ContLbl] = create_lbls(1),
431  [hipe_rtl:mk_branch(Reg, eq, hipe_rtl:mk_imm(Value),
432		      hipe_rtl:label_name(ContLbl), FalseLblName),
433   ContLbl].
434
435get_value(N, String) ->
436  <<I:N, Rest/bits>> = String,
437  {I, Rest}.
438
439make_int_gc_code(I) when is_integer(I) ->
440  case hipe_tagscheme:bignum_sizeneed(I) of
441    0 -> [];
442    X when is_integer(X) -> [hipe_rtl:mk_gctest(X)]
443  end;
444make_int_gc_code(SReg) ->
445  FixNumLbl = hipe_rtl:mk_new_label(),
446  FixNumLblName = hipe_rtl:label_name(FixNumLbl),
447  {ResReg,Code} = hipe_tagscheme:bignum_sizeneed_code(SReg, FixNumLblName),
448  Code ++
449    [hipe_rtl:mk_gctest(ResReg),
450     hipe_rtl:mk_goto(FixNumLblName),
451     FixNumLbl].
452
453get_static_int(Dst1, Ms, Size, CCode, Signed, LittleEndian, Aligned,
454	       Unsafe, TrueLblName, FalseLblName) ->
455  WordSize = hipe_rtl_arch:word_size(),
456  case Size =< WordSize*?BYTE_SIZE of
457    true ->
458      case {Aligned, LittleEndian} of
459	{true, false} ->
460	  get_int_from_bin(Ms, Size, Dst1,Signed, LittleEndian,
461			   Unsafe, FalseLblName, TrueLblName);
462	{true, true} ->
463	  case Size rem ?BYTE_SIZE of
464	    0 ->
465	      get_int_from_bin(Ms, Size, Dst1, Signed, LittleEndian,
466			       Unsafe, FalseLblName, TrueLblName);
467	    _ ->
468	      CCode
469	  end;
470	{false, false} ->
471	  get_int_from_unaligned_bin(Ms, Size, Dst1, Signed,
472				     Unsafe, FalseLblName, TrueLblName);
473	{false, true} ->
474	  CCode
475      end;
476    false ->
477      CCode
478  end.
479
480get_dynamic_int(Dst1, Ms, SizeReg, CCode, Signed, LittleEndian, true,
481		TrueLblName, FalseLblName) ->
482  {Init, End} = make_dyn_prep(SizeReg, CCode),
483  Init ++
484    get_unknown_size_int(SizeReg, Ms, Dst1, Signed, LittleEndian,
485			 FalseLblName, TrueLblName) ++
486    End;
487get_dynamic_int(_Dst1, _Ms, _SizeReg, CCode, _Signed, _LittleEndian, false,
488		_TrueLblName, _FalseLblName) ->
489  CCode.
490
491get_int_from_bin(Ms, Size, Dst1, Signed, LittleEndian,
492		 Unsafe, FalseLblName, TrueLblName) ->
493  Shiftr = shift_type(Signed),
494  Type = get_type(Signed, LittleEndian),
495  NewOffset = hipe_rtl:mk_new_reg_gcsafe(),
496  [SuccessLbl] = create_lbls(1),
497  {[Base,Offset,BinSize], ExCode} =
498    extract_matchstate_vars([base,offset,binsize], Ms),
499  ExCode ++
500    [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
501		Unsafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
502     SuccessLbl] ++
503    [update_offset(NewOffset, Ms)] ++
504    get_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName).
505
506get_int_from_unaligned_bin(Ms, Size, Dst1, Signed,
507			   UnSafe, FalseLblName, TrueLblName)  ->
508  Shiftr = shift_type(Signed),
509  Type = get_type(Signed, false),
510  NewOffset = hipe_rtl:mk_new_reg_gcsafe(),
511  [SuccessLbl] = create_lbls(1),
512  {[Base,Offset,BinSize], ExCode} =
513    extract_matchstate_vars([base,offset,binsize], Ms),
514  ExCode ++
515    [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
516		UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
517     SuccessLbl] ++
518    [update_offset(NewOffset, Ms)] ++
519    get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName).
520
521get_unknown_size_int(SizeReg, Ms, Dst1, Signed, Little,
522		     FalseLblName, TrueLblName) ->
523  Shiftr = shift_type(Signed),
524  Type = get_type(Signed, false),
525  [NewOffset] = create_gcsafe_regs(1),
526  [SuccessLbl] = create_lbls(1),
527  {[Base,Offset,BinSize], ExCode} =
528    extract_matchstate_vars([base,offset,binsize], Ms),
529  ExCode ++
530  [check_size(Offset, SizeReg, BinSize, NewOffset,
531	      hipe_rtl:label_name(SuccessLbl), FalseLblName),
532   SuccessLbl,
533   update_offset(NewOffset, Ms)] ++
534  case Little of
535    true ->
536      get_little_unknown_int(Dst1, Base, Offset, NewOffset,
537			     Shiftr, Type, TrueLblName);
538    false ->
539      get_big_unknown_int(Dst1, Base, Offset, NewOffset,
540			  Shiftr, Type, TrueLblName)
541  end.
542
543make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName) ->
544  Base = hipe_rtl:mk_new_reg(),
545  Orig = hipe_rtl:mk_new_var(),
546  BinSize = hipe_rtl:mk_new_reg_gcsafe(),
547  Offset = hipe_rtl:mk_new_reg_gcsafe(),
548  Lbl = hipe_rtl:mk_new_label(),
549  [hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max),
550   get_binary_bytes(Binary, BinSize, Base, Offset,
551		    Orig, hipe_rtl:label_name(Lbl), FalseLblName),
552   Lbl,
553   hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms),
554   hipe_rtl:mk_goto(TrueLblName)].
555
556resize_matchstate(Ms, Max, TrueLblName) ->
557  Base = hipe_rtl:mk_new_reg(),
558  Orig = hipe_rtl:mk_new_var(),
559  BinSize = hipe_rtl:mk_new_reg_gcsafe(),
560  Offset = hipe_rtl:mk_new_reg_gcsafe(),
561  [hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max),
562   get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize),
563   get_field_from_term({matchstate, {matchbuffer, base}}, Ms, Base),
564   get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig),
565   get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Offset),
566   hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms),
567   hipe_rtl:mk_goto(TrueLblName)].
568
569reinit_matchstate(Ms, TrueLblName) ->
570  Tmp = hipe_rtl:mk_new_reg_gcsafe(),
571  [get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp),
572   set_field_from_term({matchstate, {saveoffset, 0}}, Ms, Tmp),
573   hipe_rtl:mk_goto(TrueLblName)].
574
575%%%%%%%%%%%%%%%%%%%%%%%%%%%% Binary Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576
577get_binary_all(Dst1, 1, Ms, TrueLblName, _FalseLblName) ->
578  [SizeReg] = create_gcsafe_regs(1),
579  {[Offset,BinSize,Orig], ExCode} =
580    extract_matchstate_vars([offset,binsize,orig], Ms),
581  MakeCode =
582    [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
583     construct_subbin(Dst1,SizeReg,Offset,Orig)] ++
584    [update_offset(BinSize, Ms),
585     hipe_rtl:mk_goto(TrueLblName)],
586  ExCode ++ MakeCode;
587get_binary_all(Dst1, Unit, Ms, TrueLblName, FalseLblName) ->
588  [SizeReg] = create_gcsafe_regs(1),
589  [SuccessLbl] = create_lbls(1),
590  SLblName = hipe_rtl:label_name(SuccessLbl),
591  {[Offset,BinSize,Orig], ExCode} =
592    extract_matchstate_vars([offset,binsize,orig], Ms),
593  MakeCode =
594    [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
595     test_alignment_code(SizeReg,Unit,SLblName,FalseLblName)] ++
596    [SuccessLbl|
597     construct_subbin(Dst1,SizeReg,Offset,Orig)] ++
598    [update_offset(BinSize, Ms),
599     hipe_rtl:mk_goto(TrueLblName)],
600  ExCode ++ MakeCode.
601
602get_binary(Dst1, Ms, SizeReg, UnSafe, TrueLblName, FalseLblName) ->
603  [SuccessLbl] = create_lbls(1),
604  [EndOffset] = create_gcsafe_regs(1),
605  {[Offset,BinSize,Orig], ExCode} =
606    extract_matchstate_vars([offset,binsize,orig], Ms),
607  CheckCode =
608    [check_size(Offset, SizeReg, BinSize, EndOffset, UnSafe,
609		hipe_rtl:label_name(SuccessLbl), FalseLblName),
610     SuccessLbl],
611  MakeCode =
612    construct_subbin(Dst1, SizeReg, Offset, Orig)
613    ++ [update_offset(EndOffset, Ms),
614	hipe_rtl:mk_goto(TrueLblName)],
615  ExCode ++ CheckCode ++ MakeCode.
616
617construct_subbin(Dst, Size, Offset, Orig) ->
618  [BitOffset, ByteOffset, BitSize, ByteSize] = create_gcsafe_regs(4),
619  [hipe_rtl:mk_alu(ByteSize, Size, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
620   hipe_rtl:mk_alu(BitSize, Size, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
621   hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
622   hipe_rtl:mk_alu(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
623   hipe_tagscheme:mk_sub_binary(Dst, ByteSize, ByteOffset,
624				BitSize, BitOffset, Orig)].
625
626%%%%%%%%%%%%%%%%%%%%%%%%% Skip Bits %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627
628skip_bits_all(1, Ms, TrueLblName, _FalseLblName) ->
629  {[BinSize], ExCode} = extract_matchstate_vars([binsize], Ms),
630  ExCode ++ [update_offset(BinSize,Ms), hipe_rtl:mk_goto(TrueLblName)];
631skip_bits_all(Unit,Ms, TrueLblName, FalseLblName) ->
632  [Size] = create_gcsafe_regs(1),
633  [SuccessLbl] = create_lbls(1),
634  SLblName = hipe_rtl:label_name(SuccessLbl),
635  {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
636  ExCode ++
637    [hipe_rtl:mk_alu(Size,BinSize,sub,Offset)]
638    ++
639    test_alignment_code(Size,Unit,SLblName,FalseLblName) ++
640    [SuccessLbl,
641     update_offset(BinSize,Ms),
642     hipe_rtl:mk_goto(TrueLblName)].
643
644test_alignment_code(Size, Unit, SLblName, FalseLblName) ->
645  case Unit of
646    1 -> [hipe_rtl:mk_goto(SLblName)];
647    2 -> get_fast_test_code(Size,1,SLblName,FalseLblName);
648    4 -> get_fast_test_code(Size,3,SLblName,FalseLblName);
649    8 -> get_fast_test_code(Size,7,SLblName,FalseLblName);
650    16 -> get_fast_test_code(Size,15,SLblName,FalseLblName);
651    32 -> get_fast_test_code(Size,31,SLblName,FalseLblName);
652    _ -> get_slow_test_code(Size,Unit,SLblName,FalseLblName)
653  end.
654
655get_fast_test_code(Size, AndTest, SLblName, FalseLblName) ->
656  [hipe_rtl:mk_branch(Size, 'and', hipe_rtl:mk_imm(AndTest), 'eq',
657		      SLblName, FalseLblName, 0.5)].
658
659%% This is really slow
660get_slow_test_code(Size, Unit, SLblName, FalseLblName) ->
661  [Tmp] = create_gcsafe_regs(1),
662  [LoopLbl,Lbl1,Lbl2] = create_lbls(3),
663  LoopLblName = hipe_rtl:label_name(LoopLbl),
664  Lbl1Name = hipe_rtl:label_name(Lbl1),
665  Lbl2Name = hipe_rtl:label_name(Lbl2),
666  [hipe_rtl:mk_move(Tmp,Size),
667   LoopLbl,
668   hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0), SLblName, Lbl1Name),
669   Lbl1,
670   hipe_rtl:mk_branch(Tmp, lt, hipe_rtl:mk_imm(0), FalseLblName, Lbl2Name),
671   Lbl2,
672   hipe_rtl:mk_alu(Tmp,Tmp,sub,hipe_rtl:mk_imm(Unit)),
673   hipe_rtl:mk_goto(LoopLblName)].
674
675skip_bits2(Ms, NoOfBits, TrueLblName, FalseLblName) ->
676  [NewOffset] = create_gcsafe_regs(1),
677  [TempLbl] = create_lbls(1),
678  {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
679  ExCode ++
680    add_to_offset(NewOffset, NoOfBits, Offset, FalseLblName) ++
681    [hipe_rtl:mk_branch(BinSize, 'ltu', NewOffset, FalseLblName,
682			hipe_rtl:label_name(TempLbl), 0.01),
683     TempLbl,
684     update_offset(NewOffset, Ms),
685     hipe_rtl:mk_goto(TrueLblName)].
686
687add_to_offset(Result, Extra, Original, FalseLblName) ->
688  TrueLbl = hipe_rtl:mk_new_label(),
689  %% Note: 'ltu' means 'unsigned overflow'.
690  [hipe_rtl:mk_alub(Result, Extra, 'add', Original, 'ltu',
691		    FalseLblName, hipe_rtl:label_name(TrueLbl)),
692   TrueLbl].
693
694%%%%%%%%%%%%%%%%%%%%%%% Code for start match %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695
696get_binary_bytes(Binary, BinSize, Base, Offset, Orig,
697		 TrueLblName, FalseLblName) ->
698  [OrigOffset,BitSize,BitOffset] = create_gcsafe_regs(3),
699  [SuccessLbl,SubLbl,OtherLbl,JoinLbl] = create_lbls(4),
700  [hipe_tagscheme:test_bitstr(Binary, hipe_rtl:label_name(SuccessLbl),
701			      FalseLblName, 0.99),
702   SuccessLbl,
703   get_field_from_term({sub_binary, binsize}, Binary, BinSize),
704   hipe_rtl:mk_alu(BinSize, BinSize, sll, hipe_rtl:mk_imm(?BYTE_SHIFT)),
705   hipe_tagscheme:test_subbinary(Binary, hipe_rtl:label_name(SubLbl),
706				 hipe_rtl:label_name(OtherLbl)),
707   SubLbl,
708   get_field_from_term({sub_binary, offset}, Binary, OrigOffset),
709   hipe_rtl:mk_alu(Offset, OrigOffset, sll, hipe_rtl:mk_imm(?BYTE_SHIFT)),
710   get_field_from_term({sub_binary, bitoffset}, Binary, BitOffset),
711   hipe_rtl:mk_alu(Offset, Offset, add, BitOffset),
712   get_field_from_term({sub_binary, bitsize}, Binary, BitSize),
713   hipe_rtl:mk_alu(BinSize, BinSize, add, Offset),
714   hipe_rtl:mk_alu(BinSize, BinSize, add, BitSize),
715   get_field_from_term({sub_binary, orig}, Binary, Orig),
716   hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
717   OtherLbl,
718   hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
719   hipe_rtl:mk_move(Orig, Binary),
720   JoinLbl] ++
721    get_base(Orig,Base) ++
722    [hipe_rtl:mk_goto(TrueLblName)].
723
724%%%%%%%%%%%%%%%%%%%%%%%%% UTILS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725
726get_base(Orig,Base) ->
727  [HeapLbl,REFCLbl,WritableLbl,NotWritableLbl,EndLbl] = create_lbls(5),
728  Flags = hipe_rtl:mk_new_reg_gcsafe(),
729
730  [hipe_tagscheme:test_heap_binary(Orig, hipe_rtl:label_name(HeapLbl),
731				   hipe_rtl:label_name(REFCLbl)),
732   HeapLbl,
733   hipe_tagscheme:get_field_addr_from_term({heap_bin, {data, 0}}, Orig, Base),
734   hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
735   REFCLbl,
736   get_field_from_term({proc_bin, flags}, Orig, Flags),
737   hipe_rtl:mk_branch(Flags, 'ne', hipe_rtl:mk_imm(0),
738		      hipe_rtl:label_name(WritableLbl),
739		      hipe_rtl:label_name(NotWritableLbl)),
740   WritableLbl,
741   hipe_rtl:mk_call([], emasculate_binary, [Orig], [], [], 'not_remote'),
742   NotWritableLbl,
743   get_field_from_term({proc_bin, bytes}, Orig, Base),
744   EndLbl].
745
746extract_matchstate_var(binsize, Ms) ->
747  BinSize = hipe_rtl:mk_new_reg_gcsafe(),
748  {BinSize,
749   get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize)};
750extract_matchstate_var(offset, Ms) ->
751  Offset = hipe_rtl:mk_new_reg_gcsafe(),
752  {Offset,
753  get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Offset)};
754extract_matchstate_var(base, Ms) ->
755  Base = hipe_rtl:mk_new_reg(),
756  {Base,
757   get_field_from_term({matchstate, {matchbuffer, base}}, Ms, Base)};
758extract_matchstate_var(orig, Ms) ->
759  Orig = hipe_rtl:mk_new_var(),
760  {Orig,
761   get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig)}.
762
763extract_matchstate_vars(List, Ms) ->
764  lists:unzip([extract_matchstate_var(Name, Ms) || Name <- List]).
765
766check_size(Offset, Size, BinSize, Tmp1, ContLblName, FalseLblName) ->
767  [add_to_offset(Tmp1, Offset, Size, FalseLblName),
768   hipe_rtl:mk_branch(Tmp1, leu, BinSize, ContLblName, FalseLblName, 0.99)].
769
770check_size(Offset, Size, _BinSize, Tmp1, true, ContLblName, _FalseLblName) ->
771  [hipe_rtl:mk_alu(Tmp1, Offset, add, Size),
772   hipe_rtl:mk_goto(ContLblName)];
773check_size(Offset, Size, BinSize, Tmp1, false, ContLblName, FalseLblName) ->
774  check_size(Offset, Size, BinSize, Tmp1, ContLblName, FalseLblName).
775
776shift_type(true) ->
777  sra;
778shift_type(false) ->
779  srl.
780
781get_type(true, LittleEndian) ->
782  {signed, endianess(LittleEndian)};
783get_type(false, LittleEndian) ->
784  {unsigned, endianess(LittleEndian)}.
785
786endianess(true) ->
787  little;
788endianess(false) ->
789  big.
790
791aligned(Flags) ->
792  case Flags band ?BSF_ALIGNED of
793    1 -> true;
794    0 -> false
795  end.
796
797littleendian(Flags) ->
798  case Flags band 2 of
799    2 -> true;
800    0 -> false
801  end.
802
803signed(Flags) ->
804  case Flags band 4 of
805    4 -> true;
806    0 -> false
807  end.
808
809unsafe(Flags) ->
810  case Flags band 16 of
811    16 -> true;
812    0 -> false
813  end.
814
815update_offset(NewOffset, Ms) ->
816  set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, NewOffset).
817
818opt_update_ms([NewMs], OldMs) ->
819  [hipe_rtl:mk_move(NewMs, OldMs)];
820opt_update_ms([], _OldMs) ->
821  [].
822
823update_ms(NewMs, OldMs) ->
824  [hipe_rtl:mk_move(NewMs, OldMs)].
825
826create_lbls(0) ->
827  [];
828create_lbls(X) when X > 0 ->
829  [hipe_rtl:mk_new_label()|create_lbls(X-1)].
830
831make_dyn_prep(SizeReg, CCode) ->
832  [CLbl, SuccessLbl] = create_lbls(2),
833  Init = [hipe_rtl:mk_branch(SizeReg, leu, hipe_rtl:mk_imm(?MAX_SMALL_BITS),
834			     hipe_rtl:label_name(SuccessLbl),
835			     hipe_rtl:label_name(CLbl)),
836	  SuccessLbl],
837  End = [CLbl|CCode],
838  {Init, End}.
839
840%%------------------------------------------------------------------------
841%% From hipe_rtl_binutil.erl
842%%------------------------------------------------------------------------
843
844get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) ->
845  [Reg] = create_gcsafe_regs(1),
846  [get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
847   do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)].
848
849get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) ->
850  [LowBits] = create_gcsafe_regs(1),
851  [AlignedLbl, UnAlignedLbl, EndLbl] = create_lbls(3),
852  [hipe_rtl:mk_alub(LowBits, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS),
853		    eq, hipe_rtl:label_name(AlignedLbl),
854		    hipe_rtl:label_name(UnAlignedLbl)),
855   AlignedLbl,
856   get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
857   hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
858   UnAlignedLbl,
859   get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type),
860   EndLbl].
861
862get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type) ->
863  [ByteOffset, ShiftBits, LoadDst, Tmp, TotBits] = create_gcsafe_regs(5),
864  [MoreLbl, LessLbl, JoinLbl] = create_lbls(3),
865  WordSize = hipe_rtl_arch:word_size(),
866  MinLoad = (Size-1) div ?BYTE_SIZE +1,
867  MaxLoad = MinLoad + 1,
868  Code1 =
869    [hipe_rtl:mk_alu(TotBits, LowBits, 'add', hipe_rtl:mk_imm(Size)),
870     hipe_rtl:mk_alu(ByteOffset, Offset, 'srl', hipe_rtl:mk_imm(?BYTE_SHIFT))],
871  Code2 =
872    case {Size rem ?BYTE_SIZE, MinLoad} of
873      {1, _} ->
874	[load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad),
875	 hipe_rtl:mk_alu(ShiftBits, LowBits, 'add',
876			 hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE))];
877      {_, WordSize} ->
878	UnsignedBig = {unsigned, big},
879	[hipe_rtl:mk_branch(TotBits, leu, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE),
880			    hipe_rtl:label_name(LessLbl),
881			    hipe_rtl:label_name(MoreLbl)),
882	 LessLbl,
883	 load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad),
884	 hipe_rtl:mk_alu(ShiftBits, LowBits, 'add',
885			 hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE)),
886	 hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
887	 MoreLbl,
888	 load_bytes(LoadDst, Base, ByteOffset, UnsignedBig, MinLoad),
889	 hipe_rtl:mk_alu(LoadDst, LoadDst, 'sll', LowBits),
890	 load_bytes(Tmp, Base, ByteOffset, UnsignedBig, 1),
891	 hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', LowBits),
892	 hipe_rtl:mk_alu(Tmp, Tmp, 'srl', LowBits),
893	 hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
894	 hipe_rtl:mk_move(ShiftBits, hipe_rtl:mk_imm(0)),
895	 JoinLbl];
896      {_, _} ->
897	[load_bytes(LoadDst, Base, ByteOffset, Type, MaxLoad),
898	 hipe_rtl:mk_alu(ShiftBits, LowBits, 'add',
899			 hipe_rtl:mk_imm((WordSize-MaxLoad)*?BYTE_SIZE))]
900    end,
901  Code3 =
902    [hipe_rtl:mk_alu(Tmp, LoadDst, sll, ShiftBits),
903     hipe_rtl:mk_alu(Reg, Tmp, Shiftr,
904		     hipe_rtl:mk_imm(WordSize*?BYTE_SIZE-Size))],
905  Code1 ++ Code2 ++ Code3.
906
907get_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) ->
908  [Reg] = create_gcsafe_regs(1),
909  [get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
910   do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)].
911
912get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) ->
913  [ByteOffset] = create_gcsafe_regs(1),
914  Code1 =
915    [hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
916     load_bytes(Reg, Base, ByteOffset, Type, ((Size-1) div ?BYTE_SIZE +1))],
917  Code2 =
918    case Size rem ?BYTE_SIZE  of
919      0 ->
920	[];
921      _ ->
922	[hipe_rtl:mk_alu(Reg, Reg, Shiftr,
923			 hipe_rtl:mk_imm(?BYTE_SIZE -Size rem ?BYTE_SIZE))]
924    end,
925  Code1 ++ Code2.
926
927get_big_unknown_int(Dst1, Base, Offset, NewOffset,
928		    Shiftr, Type, TrueLblName) ->
929  [LoadDst, ByteOffset, Limit, Tmp, LowBits] = create_gcsafe_regs(5),
930  [ContLbl, BackLbl, LoopLbl, TagLbl, LastLbl, EndLbl] = create_lbls(6),
931  [hipe_rtl:mk_move(LoadDst, hipe_rtl:mk_imm(0)),
932   hipe_rtl:mk_branch(NewOffset, ne, Offset, hipe_rtl:label_name(ContLbl),
933		      hipe_rtl:label_name(TagLbl), 0.99),
934   ContLbl,
935   hipe_rtl:mk_alu(Limit, NewOffset, sub, hipe_rtl:mk_imm(1)),
936   hipe_rtl:mk_alu(Limit, Limit, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
937   hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
938   load_bytes(LoadDst, Base, ByteOffset, Type, 1),
939   BackLbl,
940   hipe_rtl:mk_branch(ByteOffset, leu, Limit, hipe_rtl:label_name(LoopLbl),
941		      hipe_rtl:label_name(EndLbl)),
942   LoopLbl,
943   load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1),
944   hipe_rtl:mk_alu(LoadDst, LoadDst, sll, hipe_rtl:mk_imm(?BYTE_SIZE)),
945   hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
946   hipe_rtl:mk_goto(hipe_rtl:label_name(BackLbl)),
947   EndLbl,
948   hipe_rtl:mk_alub(LowBits, NewOffset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq,
949		    hipe_rtl:label_name(TagLbl), hipe_rtl:label_name(LastLbl)),
950   LastLbl,
951   hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', LowBits),
952   hipe_rtl:mk_alu(LoadDst, LoadDst, Shiftr, LowBits),
953   TagLbl] ++
954    do_bignum_code(64, Type, LoadDst, Dst1, TrueLblName).
955
956get_little_unknown_int(Dst1, Base, Offset, NewOffset,
957		       Shiftr, Type, TrueLblName) ->
958  [LoadDst, ByteOffset, Limit, ShiftReg, LowBits, Tmp] = create_gcsafe_regs(6),
959  [ContLbl, BackLbl, LoopLbl, DoneLbl, TagLbl] = create_lbls(5),
960  [hipe_rtl:mk_move(LoadDst, hipe_rtl:mk_imm(0)),
961   hipe_rtl:mk_branch(NewOffset, ne, Offset, hipe_rtl:label_name(ContLbl),
962		      hipe_rtl:label_name(TagLbl), 0.99),
963   ContLbl,
964   hipe_rtl:mk_alu(Tmp, NewOffset, sub, hipe_rtl:mk_imm(1)),
965   hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
966   hipe_rtl:mk_alu(Limit, Tmp, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
967   hipe_rtl:mk_move(ShiftReg, hipe_rtl:mk_imm(0)),
968   BackLbl,
969   hipe_rtl:mk_branch(ByteOffset, ltu, Limit,
970		      hipe_rtl:label_name(LoopLbl),
971		      hipe_rtl:label_name(DoneLbl)),
972   LoopLbl,
973   load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1),
974   hipe_rtl:mk_alu(Tmp, Tmp, sll, ShiftReg),
975   hipe_rtl:mk_alu(ShiftReg, ShiftReg, add, hipe_rtl:mk_imm(?BYTE_SIZE)),
976   hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
977   hipe_rtl:mk_goto(hipe_rtl:label_name(BackLbl)),
978   DoneLbl,
979   hipe_rtl:mk_alu(LowBits, NewOffset, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
980   hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), sub, LowBits),
981   hipe_rtl:mk_alu(LowBits, LowBits, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
982   load_bytes(Tmp, Base, ByteOffset, Type, 1),
983   hipe_rtl:mk_alu(Tmp, Tmp, Shiftr, LowBits),
984   hipe_rtl:mk_alu(Tmp, Tmp, sll, ShiftReg),
985   hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
986   TagLbl] ++
987     do_bignum_code(64, Type, LoadDst, Dst1, TrueLblName).
988
989do_bignum_code(Size, {Signedness,_}, Src, Dst1, TrueLblName)
990  when is_integer(Size) ->
991  case {Size > ?MAX_SMALL_BITS, Signedness} of
992    {false, _} ->
993      [hipe_tagscheme:tag_fixnum(Dst1, Src),
994       hipe_rtl:mk_goto(TrueLblName)];
995    {true, signed} ->
996      make_int_gc_code(Size) ++
997      signed_bignum(Dst1, Src, TrueLblName);
998    {true, unsigned} ->
999      make_int_gc_code(Size) ++
1000      unsigned_bignum(Dst1, Src, TrueLblName)
1001    end.
1002
1003signed_bignum(Dst1, Src, TrueLblName) ->
1004  Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
1005  BignumLabel = hipe_rtl:mk_new_label(),
1006  [hipe_tagscheme:realtag_fixnum(Dst1, Src),
1007   hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1),
1008   hipe_rtl:mk_branch(Tmp1, eq, Src, TrueLblName,
1009		      hipe_rtl:label_name(BignumLabel)),
1010   BignumLabel,
1011   hipe_tagscheme:unsafe_mk_big(Dst1, Src, signed),
1012   hipe_rtl:mk_goto(TrueLblName)].
1013
1014unsigned_bignum(Dst1, Src, TrueLblName) ->
1015  Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
1016  BignumLbl = hipe_rtl:mk_new_label(),
1017  BignumLblName = hipe_rtl:label_name(BignumLbl),
1018  NxtLbl = hipe_rtl:mk_new_label(),
1019  NxtLblName = hipe_rtl:label_name(NxtLbl),
1020  [hipe_rtl:mk_branch(Src, lt, hipe_rtl:mk_imm(0), BignumLblName, NxtLblName),
1021   NxtLbl,
1022   hipe_tagscheme:realtag_fixnum(Dst1, Src),
1023   hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1),
1024   hipe_rtl:mk_branch(Tmp1, eq, Src, TrueLblName, BignumLblName),
1025   BignumLbl,
1026   hipe_tagscheme:unsafe_mk_big(Dst1, Src, unsigned),
1027   hipe_rtl:mk_goto(TrueLblName)].
1028
1029load_bytes(Dst, Base, Offset, {Signedness, _Endianness},1) ->
1030  [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
1031   hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))];
1032load_bytes(Dst, Base, Offset, {Signedness, Endianness},2) ->
1033  case Endianness of
1034    big ->
1035      hipe_rtl_arch:load_big_2(Dst, Base, Offset, Signedness);
1036    little ->
1037      hipe_rtl_arch:load_little_2(Dst, Base, Offset, Signedness)
1038  end;
1039load_bytes(Dst, Base, Offset, {Signedness, Endianness},3) ->
1040  Tmp1 = hipe_rtl:mk_new_reg(),
1041  case Endianness of
1042    big ->
1043      [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
1044       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
1045       hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
1046       hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
1047       hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
1048       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
1049       hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
1050       hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
1051       hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
1052       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))];
1053    little ->
1054      [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned),
1055       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
1056       hipe_rtl:mk_load(Tmp1, Base, Offset, byte,unsigned),
1057       hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)),
1058       hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
1059       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
1060       hipe_rtl:mk_load(Tmp1, Base, Offset, byte,Signedness),
1061       hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(16)),
1062       hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
1063       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))]
1064  end;
1065load_bytes(Dst, Base, Offset, {Signedness, Endianness}, 4) ->
1066  case Endianness of
1067    big ->
1068      hipe_rtl_arch:load_big_4(Dst, Base, Offset, Signedness);
1069    little ->
1070      hipe_rtl_arch:load_little_4(Dst, Base, Offset, Signedness)
1071  end;
1072
1073load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 ->
1074  [LoopLbl, EndLbl] = create_lbls(2),
1075  [Tmp1, Limit, TmpOffset] = create_regs(3),
1076  case Endianness of
1077    big ->
1078      [hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)),
1079       hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
1080       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
1081       LoopLbl,
1082       hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
1083       hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
1084       hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
1085       hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
1086       hipe_rtl:mk_branch(Offset, ltu, Limit, hipe_rtl:label_name(LoopLbl),
1087			  hipe_rtl:label_name(EndLbl)),
1088       EndLbl];
1089    little ->
1090      [hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)),
1091       hipe_rtl:mk_alu(TmpOffset, Limit, sub, hipe_rtl:mk_imm(1)),
1092       hipe_rtl:mk_load(Dst, Base, TmpOffset, byte, Signedness),
1093       LoopLbl,
1094       hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
1095       hipe_rtl:mk_load(Tmp1, Base, TmpOffset, byte, Signedness),
1096       hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
1097       hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
1098       hipe_rtl:mk_branch(Offset, ltu, TmpOffset, hipe_rtl:label_name(LoopLbl),
1099			  hipe_rtl:label_name(EndLbl)),
1100       EndLbl,
1101       hipe_rtl:mk_move(Offset, Limit)]
1102  end.
1103
1104create_regs(X) when X > 0 ->
1105  [hipe_rtl:mk_new_reg()|create_regs(X-1)];
1106create_regs(0) ->
1107  [].
1108
1109create_gcsafe_regs(X) when X > 0 ->
1110  [hipe_rtl:mk_new_reg_gcsafe()|create_gcsafe_regs(X-1)];
1111create_gcsafe_regs(0) ->
1112  [].
1113
1114is_illegal_const(Const) ->
1115  Const >=  1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0.
1116