aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/rtl/hipe_rtl_binary_construct.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/rtl/hipe_rtl_binary_construct.erl')
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl1363
1 files changed, 1363 insertions, 0 deletions
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
new file mode 100644
index 0000000000..29993b9715
--- /dev/null
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -0,0 +1,1363 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% ====================================================================
+%% Module : hipe_rtl_inline_bs_ops
+%% Purpose :
+%% Notes :
+%% History : * 2001-06-14 Erik Johansson ([email protected]): Created.
+%% ====================================================================
+%% Exports :
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-module(hipe_rtl_binary_construct).
+-export([gen_rtl/7]).
+-import(hipe_tagscheme, [set_field_from_term/3,
+ get_field_from_term/3,
+ set_field_from_pointer/3,
+ get_field_from_pointer/3]).
+%%-------------------------------------------------------------------------
+
+-include("../main/hipe.hrl").
+-include("hipe_rtl.hrl").
+-include("hipe_literals.hrl").
+
+-define(BYTE_SHIFT, hipe_rtl:mk_imm(3)). %% Turn bits into bytes or vice versa
+-define(LOW_BITS, hipe_rtl:mk_imm(7)). %% Three lowest bits set
+-define(LOW_BITS_INT, 7).
+-define(BYTE_SIZE, 8).
+-define(MAX_BINSIZE, ((1 bsl ((hipe_rtl_arch:word_size()*?BYTE_SIZE)-3)) - 1)).
+
+
+%% -------------------------------------------------------------------------
+%% The code is generated as a list of lists, it will be flattened later.
+%%
+
+gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab) ->
+ %%io:format("~w, ~w, ~w~n", [BsOP, Args, Dst]),
+ case BsOP of
+ {bs_put_string, String, SizeInBytes} ->
+ [NewOffset] = get_real(Dst),
+ [Base, Offset] = Args,
+ put_string(NewOffset, ConstTab, String, SizeInBytes, Base, Offset,
+ TrueLblName);
+ _ ->
+ Code =
+ case BsOP of
+ {bs_init, Size, _Flags} ->
+ [] = Args,
+ [Dst0, Base, Offset] = Dst,
+ case is_illegal_const(Size bsl 3) of
+ true ->
+ hipe_rtl:mk_goto(SystemLimitLblName);
+ false ->
+ const_init2(Size, Dst0, Base, Offset, TrueLblName)
+ end;
+
+ {bs_init, _Flags} ->
+ [Size] = Args,
+ [Dst0, Base, Offset] = Dst,
+ var_init2(Size, Dst0, Base, Offset, TrueLblName,
+ SystemLimitLblName, FalseLblName);
+
+ {bs_init_bits, Size, _Flags} ->
+ [] = Args,
+ [Dst0, Base, Offset] = Dst,
+ case is_illegal_const(Size) of
+ true ->
+ hipe_rtl:mk_goto(SystemLimitLblName);
+ false ->
+ const_init_bits(Size, Dst0, Base, Offset, TrueLblName)
+ end;
+
+ {bs_init_bits, _Flags} ->
+ [Size] = Args,
+ [Dst0, Base, Offset] = Dst,
+ var_init_bits(Size, Dst0, Base, Offset, TrueLblName,
+ SystemLimitLblName, FalseLblName);
+
+ {bs_put_binary_all, _Flags} ->
+ [Src, Base, Offset] = Args,
+ [NewOffset] = get_real(Dst),
+ put_binary_all(NewOffset, Src, Base, Offset, TrueLblName, FalseLblName);
+
+ {bs_put_binary, Size, _Flags} ->
+ case is_illegal_const(Size) of
+ true ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ false ->
+ [NewOffset] = get_real(Dst),
+ case Args of
+ [Src, Base, Offset] ->
+ put_static_binary(NewOffset, Src, Size, Base, Offset,
+ TrueLblName, FalseLblName);
+ [Src, Bits, Base, Offset] ->
+ {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName),
+ InCode = put_dynamic_binary(NewOffset, Src, SizeReg, Base,
+ Offset, TrueLblName, FalseLblName),
+ SizeCode ++ InCode
+ end
+ end;
+
+ {bs_put_float, Size, Flags, ConstInfo} ->
+ [NewOffset] = get_real(Dst),
+ Aligned = aligned(Flags),
+ LittleEndian = littleendian(Flags),
+ case is_illegal_const(Size) of
+ true ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ false ->
+ case Args of
+ [Src, Base, Offset] ->
+ CCode = static_float_c_code(NewOffset, Src, Base, Offset, Size, Flags,
+ TrueLblName, FalseLblName),
+ put_float(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
+ LittleEndian, ConstInfo, TrueLblName);
+ [Src, Bits, Base, Offset] ->
+ {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName),
+ InCode = float_c_code(NewOffset, Src, Base, Offset, SizeReg,
+ Flags, TrueLblName, FalseLblName),
+ SizeCode ++ InCode
+ end
+ end;
+
+ {bs_put_integer, Size, Flags, ConstInfo} ->
+ Aligned = aligned(Flags),
+ LittleEndian = littleendian(Flags),
+ [NewOffset] = get_real(Dst),
+ case is_illegal_const(Size) of
+ true ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ false ->
+ case ConstInfo of
+ fail ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ _ ->
+ case Args of
+ [Src, Base, Offset] ->
+ CCode = static_int_c_code(NewOffset, Src,
+ Base, Offset, Size,
+ Flags, TrueLblName,
+ FalseLblName),
+ put_static_int(NewOffset, Src, Base, Offset, Size,
+ CCode, Aligned, LittleEndian, TrueLblName);
+ [Src, Bits, Base, Offset] ->
+ {SizeCode, SizeReg} = make_size(Size, Bits,
+ FalseLblName),
+ CCode = int_c_code(NewOffset, Src, Base,
+ Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName),
+ InCode =
+ put_dynamic_int(NewOffset, Src, Base, Offset,
+ SizeReg, CCode, Aligned,
+ LittleEndian, TrueLblName),
+ SizeCode ++ InCode
+ end
+ end
+ end;
+
+ {unsafe_bs_put_integer, 0, _Flags, _ConstInfo} ->
+ [NewOffset] = get_real(Dst),
+ case Args of
+ [_Src, _Base, Offset] ->
+ [hipe_rtl:mk_move(NewOffset,Offset),
+ hipe_rtl:mk_goto(TrueLblName)];
+ [_Src, _Bits, _Base, Offset] ->
+ [hipe_rtl:mk_move(NewOffset,Offset),
+ hipe_rtl:mk_goto(TrueLblName)]
+ end;
+
+ {unsafe_bs_put_integer, Size, Flags, ConstInfo} ->
+ case is_illegal_const(Size) of
+ true ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ false ->
+ Aligned = aligned(Flags),
+ LittleEndian = littleendian(Flags),
+ [NewOffset] = get_real(Dst),
+ case ConstInfo of
+ fail ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ _ ->
+ case Args of
+ [Src, Base, Offset] ->
+ CCode = static_int_c_code(NewOffset, Src,
+ Base, Offset, Size,
+ Flags, TrueLblName,
+ FalseLblName),
+ put_unsafe_static_int(NewOffset, Src, Base,
+ Offset, Size,
+ CCode, Aligned, LittleEndian,
+ TrueLblName);
+ [Src, Bits, Base, Offset] ->
+ {SizeCode, SizeReg} = make_size(Size, Bits,
+ FalseLblName),
+ CCode = int_c_code(NewOffset, Src, Base,
+ Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName),
+ InCode =
+ put_unsafe_dynamic_int(NewOffset, Src, Base,
+ Offset, SizeReg, CCode,
+ Aligned, LittleEndian,
+ TrueLblName),
+ SizeCode ++ InCode
+ end
+ end
+ end;
+
+ bs_utf8_size ->
+ case Dst of
+ [_DstVar] ->
+ [_Arg] = Args,
+ [hipe_rtl:mk_call(Dst, bs_utf8_size, Args,
+ TrueLblName, [], not_remote)];
+ [] ->
+ [hipe_rtl:mk_goto(TrueLblName)]
+ end;
+
+ bs_put_utf8 ->
+ [_Src, _Base, _Offset] = Args,
+ NewDsts = get_real(Dst),
+ [hipe_rtl:mk_call(NewDsts, bs_put_utf8, Args,
+ TrueLblName, FalseLblName, not_remote)];
+
+ bs_utf16_size ->
+ case Dst of
+ [_DstVar] ->
+ [_Arg] = Args,
+ [hipe_rtl:mk_call(Dst, bs_utf16_size, Args,
+ TrueLblName, [], not_remote)];
+ [] ->
+ [hipe_rtl:mk_goto(TrueLblName)]
+ end;
+
+ {bs_put_utf16, Flags} ->
+ [_Src, _Base, _Offset] = Args,
+ NewDsts = get_real(Dst),
+ PrimOp = % workaround for bif/primop arity restrictions
+ case littleendian(Flags) of
+ false -> bs_put_utf16be;
+ true -> bs_put_utf16le
+ end,
+ [hipe_rtl:mk_call(NewDsts, PrimOp, Args,
+ TrueLblName, FalseLblName, not_remote)];
+
+ bs_validate_unicode ->
+ [_Arg] = Args,
+ [hipe_rtl:mk_call([], bs_validate_unicode, Args,
+ TrueLblName, FalseLblName, not_remote)];
+
+ bs_final ->
+ Zero = hipe_rtl:mk_imm(0),
+ [Src, Offset] = Args,
+ [BitSize, ByteSize] = create_regs(2),
+ [ShortLbl, LongLbl] = create_lbls(2),
+ case Dst of
+ [DstVar] ->
+ [hipe_rtl:mk_alub(BitSize, Offset, 'and', ?LOW_BITS, eq,
+ hipe_rtl:label_name(ShortLbl),
+ hipe_rtl:label_name(LongLbl)), ShortLbl,
+ hipe_rtl:mk_move(DstVar, Src),
+ hipe_rtl:mk_goto(TrueLblName),
+ LongLbl,
+ hipe_rtl:mk_alu(ByteSize, Offset, 'srl', ?BYTE_SHIFT),
+ hipe_tagscheme:mk_sub_binary(DstVar, ByteSize,
+ Zero, BitSize, Zero, Src),
+ hipe_rtl:mk_goto(TrueLblName)];
+ [] ->
+ [hipe_rtl:mk_goto(TrueLblName)]
+ end;
+
+ bs_init_writable ->
+ Zero = hipe_rtl:mk_imm(0),
+ [Size] = Args,
+ [DstVar] = Dst,
+ [SizeReg] = create_regs(1),
+ [Base] = create_unsafe_regs(1),
+ [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE + ?SUB_BIN_WORDSIZE),
+ check_and_untag_fixnum(Size, SizeReg, FalseLblName),
+ allocate_writable(DstVar, Base, SizeReg, Zero, Zero),
+ hipe_rtl:mk_goto(TrueLblName)];
+
+ {bs_private_append, _U, _F} ->
+ [Size, Bin] = Args,
+ [DstVar, Base, Offset] = Dst,
+ [ProcBin] = create_vars(1),
+ [SubSize, SizeReg, EndSubSize, EndSubBitSize] = create_regs(4),
+ SubBinSize = {sub_binary, binsize},
+ [get_field_from_term({sub_binary, orig}, Bin, ProcBin),
+ get_field_from_term(SubBinSize, Bin, SubSize),
+ check_and_untag_fixnum(Size, SizeReg, FalseLblName),
+ realloc_binary(SizeReg, ProcBin, Base),
+ calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
+ set_field_from_term(SubBinSize, Bin, EndSubSize),
+ set_field_from_term({sub_binary, bitsize}, Bin, EndSubBitSize),
+ hipe_rtl:mk_move(DstVar, Bin),
+ hipe_rtl:mk_goto(TrueLblName)];
+
+ {bs_append, _U, _F, _B, _Bla} ->
+ [Size, Bin] = Args,
+ [DstVar, Base, Offset] = Dst,
+ [ProcBin] = create_vars(1),
+ [Flags, SizeReg, IsWritable, EndSubSize, EndSubBitSize] =
+ create_regs(5),
+ [ContLbl,ContLbl2,ContLbl3,WritableLbl,NotWritableLbl] = Lbls =
+ create_lbls(5),
+ [ContLblName, ContLbl2Name, ContLbl3Name, Writable, NotWritable] =
+ [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
+ Zero = hipe_rtl:mk_imm(0),
+ SubIsWritable = {sub_binary, is_writable},
+ [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE + ?PROC_BIN_WORDSIZE),
+ check_and_untag_fixnum(Size, SizeReg, FalseLblName),
+ hipe_tagscheme:test_bitstr(Bin, ContLblName, FalseLblName, 0.99),
+ ContLbl,
+ hipe_tagscheme:test_subbinary(Bin,ContLbl2Name, NotWritable),
+ ContLbl2,
+ get_field_from_term(SubIsWritable, Bin, IsWritable),
+ hipe_rtl:mk_branch(IsWritable, 'ne', Zero,
+ ContLbl3Name, NotWritable),
+ ContLbl3,
+ get_field_from_term({sub_binary, orig}, Bin, ProcBin),
+ get_field_from_term({proc_bin, flags}, ProcBin, Flags),
+ hipe_rtl:mk_alub(Flags, Flags, 'and',
+ hipe_rtl:mk_imm(?PB_IS_WRITABLE),
+ eq, NotWritable, Writable, 0.01),
+ WritableLbl,
+ set_field_from_term(SubIsWritable, Bin, Zero),
+ realloc_binary(SizeReg, ProcBin, Base),
+ calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
+ hipe_tagscheme:mk_sub_binary(DstVar, EndSubSize, Zero,
+ EndSubBitSize, Zero,
+ hipe_rtl:mk_imm(1), ProcBin),
+ hipe_rtl:mk_goto(TrueLblName),
+ NotWritableLbl,
+ not_writable_code(Bin, SizeReg, DstVar, Base, Offset,
+ TrueLblName, FalseLblName)]
+ end,
+ {Code, ConstTab}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Code that is used in the append and init writeable functions
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+not_writable_code(Bin, SizeReg, Dst, Base, Offset,
+ TrueLblName, FalseLblName) ->
+ [SrcBase] = create_unsafe_regs(1),
+ [SrcOffset, SrcSize, TotSize, TotBytes, UsedBytes] = create_regs(5),
+ [IncLbl,AllLbl] = Lbls = create_lbls(2),
+ [IncLblName,AllLblName] = get_label_names(Lbls),
+ [get_base_offset_size(Bin, SrcBase, SrcOffset, SrcSize, FalseLblName),
+ hipe_rtl:mk_alu(TotSize, SrcSize, add, SizeReg),
+ hipe_rtl:mk_alu(TotBytes, TotSize, add, ?LOW_BITS),
+ hipe_rtl:mk_alu(TotBytes, TotBytes, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(UsedBytes, TotBytes, sll, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_branch(UsedBytes, ge, hipe_rtl:mk_imm(256),
+ AllLblName, IncLblName),
+ IncLbl,
+ hipe_rtl:mk_move(UsedBytes, hipe_rtl:mk_imm(256)),
+ AllLbl,
+ allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize),
+ put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0),
+ TrueLblName, FalseLblName)].
+
+allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
+ Zero = hipe_rtl:mk_imm(0),
+ [NextLbl] = create_lbls(1),
+ [EndSubSize, EndSubBitSize, ProcBin] = create_regs(3),
+ [hipe_rtl:mk_call([Base], bs_allocate, [UsedBytes],
+ hipe_rtl:label_name(NextLbl), [], not_remote),
+ NextLbl,
+ hipe_tagscheme:create_refc_binary(Base, TotBytes,
+ hipe_rtl:mk_imm(?PB_IS_WRITABLE bor
+ ?PB_ACTIVE_WRITER),
+ ProcBin),
+ hipe_rtl:mk_alu(EndSubSize, TotSize, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(EndSubBitSize, TotSize, 'and', ?LOW_BITS),
+ hipe_tagscheme:mk_sub_binary(Dst, EndSubSize, Zero, EndSubBitSize,
+ Zero, hipe_rtl:mk_imm(1), ProcBin)].
+
+check_and_untag_fixnum(Size, SizeReg, FalseLblName) ->
+ [ContLbl,NextLbl] = Lbls = create_lbls(2),
+ [ContLblName,NextLblName] = get_label_names(Lbls),
+ [hipe_tagscheme:test_fixnum(Size, ContLblName, FalseLblName, 0.99),
+ ContLbl,
+ hipe_tagscheme:untag_fixnum(SizeReg,Size),
+ hipe_rtl:mk_branch(SizeReg, ge, hipe_rtl:mk_imm(0), NextLblName,
+ FalseLblName),
+ NextLbl].
+
+realloc_binary(SizeReg, ProcBin, Base) ->
+ [NoReallocLbl, ReallocLbl, NextLbl, ContLbl] = Lbls = create_lbls(4),
+ [NoReallocLblName, ReallocLblName, NextLblName, ContLblName] =
+ [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
+ [PBSize, Tmp, ByteSize, NewSize, Flags, ResultingSize, OrigSize,
+ BinPointer] = create_regs(8),
+ ProcBinSizeTag = {proc_bin, binsize},
+ ProcBinFlagsTag = {proc_bin, flags},
+ ProcBinValTag = {proc_bin, val},
+ ProcBinBytesTag = {proc_bin, bytes},
+ BinOrigSizeTag = {binary, orig_size},
+ [get_field_from_term(ProcBinSizeTag, ProcBin, PBSize),
+ hipe_rtl:mk_alu(Tmp, SizeReg, 'add', ?LOW_BITS),
+ hipe_rtl:mk_alu(ByteSize, Tmp, 'srl', ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(ResultingSize, ByteSize, 'add', PBSize),
+ set_field_from_term(ProcBinSizeTag, ProcBin, ResultingSize),
+ get_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
+ hipe_rtl:mk_alu(Flags, Flags, 'or', hipe_rtl:mk_imm(?PB_ACTIVE_WRITER)),
+ set_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
+ get_field_from_term(ProcBinValTag, ProcBin, BinPointer),
+ get_field_from_pointer(BinOrigSizeTag, BinPointer, OrigSize),
+ hipe_rtl:mk_branch(OrigSize, 'lt', ResultingSize,
+ ReallocLblName, NoReallocLblName),
+ NoReallocLbl,
+ get_field_from_term(ProcBinBytesTag, ProcBin, Base),
+ hipe_rtl:mk_goto(ContLblName),
+ ReallocLbl,
+ hipe_rtl:mk_alu(NewSize, ResultingSize, 'sll', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_call([BinPointer], bs_reallocate, [BinPointer, NewSize],
+ NextLblName, [], not_remote),
+ NextLbl,
+ set_field_from_pointer(BinOrigSizeTag, BinPointer, NewSize),
+ set_field_from_term(ProcBinValTag, ProcBin, BinPointer),
+ hipe_tagscheme:extract_binary_bytes(BinPointer, Base),
+ set_field_from_term(ProcBinBytesTag, ProcBin, Base),
+ ContLbl].
+
+calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize) ->
+ [SubSize, SubBitSize, EndSize] = create_regs(3),
+ [get_field_from_term({sub_binary, binsize}, Bin, SubSize),
+ get_field_from_term({sub_binary, bitsize}, Bin, SubBitSize),
+ hipe_rtl:mk_alu(Offset, SubSize, 'sll', ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(Offset, Offset, 'add', SubBitSize),
+ hipe_rtl:mk_alu(EndSize, Offset, 'add', SizeReg),
+ hipe_rtl:mk_alu(EndSubSize, EndSize, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(EndSubBitSize, EndSize, 'and', ?LOW_BITS)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Code that is used to create calls to beam functions
+%%
+%% X_c_code/8, used for putting terms into binaries
+%%
+%% X_get_c_code/10, used for getting terms from binaries
+%%
+%% - gen_test_sideffect_bs_call/4 is used to make a C-call that might
+%% fail but doesn't return an erlang value.
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+static_float_c_code(NewOffset, Src, Base, Offset, Size, Flags,
+ TrueLblName, FalseLblName) ->
+ [SizeReg] = create_regs(1),
+ [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))|
+ float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName)].
+
+float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName) ->
+ put_c_code(bs_put_small_float, NewOffset, Src, Base, Offset, SizeReg,
+ Flags, TrueLblName, FalseLblName).
+
+static_int_c_code(NewOffset, Src, Base, Offset, Size, Flags,
+ TrueLblName, FalseLblName) ->
+ [SizeReg] = create_regs(1),
+ [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))|
+ int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName)].
+
+int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName) ->
+ put_c_code(bs_put_big_integer, NewOffset, Src, Base, Offset, SizeReg,
+ Flags, TrueLblName, FalseLblName).
+
+binary_c_code(NewOffset, Src, Base, Offset, Size, TrueLblName) ->
+ PassedLbl = hipe_rtl:mk_new_label(),
+ [SizeReg, FlagsReg] = create_regs(2),
+ [hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(0)),
+ hipe_rtl:mk_move(SizeReg, Size),
+ hipe_rtl:mk_call([], bs_put_bits, [Src, SizeReg, Base, Offset, FlagsReg],
+ hipe_rtl:label_name(PassedLbl),[],not_remote),
+ PassedLbl,
+ hipe_rtl:mk_alu(NewOffset, Offset, add, SizeReg),
+ hipe_rtl:mk_goto(TrueLblName)].
+
+put_c_code(Func, NewOffset, Src, Base, Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName) ->
+ PassedLbl = hipe_rtl:mk_new_label(),
+ [FlagsReg] = create_regs(1),
+ [hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
+ gen_test_sideffect_bs_call(Func, [Src, SizeReg, Base, Offset, FlagsReg],
+ hipe_rtl:label_name(PassedLbl), FalseLblName),
+ PassedLbl,
+ hipe_rtl:mk_alu(NewOffset, Offset, add, SizeReg),
+ hipe_rtl:mk_goto(TrueLblName)].
+
+gen_test_sideffect_bs_call(Name, Args, TrueLblName, FalseLblName) ->
+ [Tmp1] = create_regs(1),
+ RetLbl = hipe_rtl:mk_new_label(),
+ [hipe_rtl:mk_call([Tmp1], Name, Args,
+ hipe_rtl:label_name(RetLbl), [], not_remote),
+ RetLbl,
+ hipe_rtl:mk_branch(Tmp1, eq, hipe_rtl:mk_imm(0),
+ FalseLblName, TrueLblName, 0.01)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Small utility functions:
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+create_regs(X) when X > 0 ->
+ [hipe_rtl:mk_new_reg_gcsafe()|create_regs(X-1)];
+create_regs(0) ->
+ [].
+
+create_unsafe_regs(X) when X > 0 ->
+ [hipe_rtl:mk_new_reg()|create_unsafe_regs(X-1)];
+create_unsafe_regs(0) ->
+ [].
+
+create_vars(X) when X > 0 ->
+ [hipe_rtl:mk_new_var()|create_vars(X-1)];
+create_vars(0) ->
+ [].
+
+create_lbls(X) when X > 0 ->
+ [hipe_rtl:mk_new_label()|create_lbls(X-1)];
+create_lbls(0) ->
+ [].
+
+get_label_names(Lbls) ->
+ [hipe_rtl:label_name(Lbl) || Lbl <- Lbls].
+
+aligned(Flags) ->
+ case Flags band ?BSF_ALIGNED of
+ 1 -> true;
+ 0 -> false
+ end.
+
+littleendian(Flags) ->
+ case Flags band 2 of
+ 2 -> true;
+ 0 -> false
+ end.
+
+is_illegal_const(Const) ->
+ Const >= (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)) orelse Const < 0.
+
+get_real(Dst) ->
+ case Dst of
+ [_NewOffset] -> Dst;
+ [] -> create_regs(1)
+ end.
+
+%%-----------------------------------------------------------------------------
+%% Help functions implementing the bs operations in rtl code.
+%%
+%% The following functions are called from the translation switch:
+%%
+%% - put_string/7 creates code to copy a string to a binary
+%% starting at base+offset and ending at base+newoffset
+%%
+%% - const_init2/6 initializes the creation of a binary of constant size
+%%
+%% - var_init2/6 initializes the creation of a binary of variable size
+%%
+%% - get_int_from_unaligned_bin/11 creates code to extract a fixed
+%% size integer from a binary or makes a c-call if it does not
+%% conform to some certain rules.
+%%
+%% - get_unknown_size_int/11 creates code to extract a variable size
+%% byte-aligned integer from a binary or makes a c-call if it
+%% does not conform to some certain rules.
+%%
+%% - skip_no_of_bits/5 creates code to skip a variable amount of bits
+%% in a binary.
+%%
+%% - load_match_buffer/7 reloads the C-matchbuffer to RTL registers.
+%%
+%% - expand_runtime/4 creates code that calculates a maximal heap need
+%% before a binary match
+%%-----------------------------------------------------------------------------
+
+put_string(NewOffset, ConstTab, String, SizeInBytes, Base, Offset, TLName) ->
+ [StringBase] = create_regs(1),
+ {NewTab, Lbl} = hipe_consttab:insert_block(ConstTab, byte, String),
+ {[hipe_rtl:mk_load_address(StringBase, Lbl, constant)|
+ copy_string(StringBase, SizeInBytes, Base, Offset,
+ NewOffset, TLName)],
+ NewTab}.
+
+const_init2(Size, Dst, Base, Offset, TrueLblName) ->
+ Log2WordSize = hipe_rtl_arch:log2_word_size(),
+ WordSize = hipe_rtl_arch:word_size(),
+ NextLbl = hipe_rtl:mk_new_label(),
+ case Size =< ?MAX_HEAP_BIN_SIZE of
+ true ->
+ [hipe_rtl:mk_gctest(((Size + 3*WordSize-1) bsr Log2WordSize)+?SUB_BIN_WORDSIZE),
+ hipe_tagscheme:create_heap_binary(Base, Size, Dst),
+ hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
+ hipe_rtl:mk_goto(TrueLblName)];
+ false ->
+ ByteSize = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
+ hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
+ hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm(Size)),
+ hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
+ hipe_rtl:label_name(NextLbl), [], not_remote),
+ NextLbl,
+ hipe_tagscheme:create_refc_binary(Base, ByteSize, Dst),
+ hipe_rtl:mk_goto(TrueLblName)]
+ end.
+
+const_init_bits(Size, Dst, Base, Offset, TrueLblName) ->
+ Log2WordSize = hipe_rtl_arch:log2_word_size(),
+ WordSize = hipe_rtl_arch:word_size(),
+ [NextLbl] = create_lbls(1),
+ TmpDst = hipe_rtl:mk_new_var(),
+ Zero = hipe_rtl:mk_imm(0),
+ {ExtraSpace, SubBinCode} =
+ if (Size rem ?BYTE_SIZE) =:= 0 ->
+ {0,[hipe_rtl:mk_move(Dst, TmpDst)]};
+ true ->
+ {?SUB_BIN_WORDSIZE,
+ hipe_tagscheme:mk_sub_binary(Dst, hipe_rtl:mk_imm(Size bsr 3), Zero,
+ hipe_rtl:mk_imm(Size band ?LOW_BITS_INT),
+ Zero, TmpDst)}
+ end,
+ BaseBinCode =
+ if Size =< (?MAX_HEAP_BIN_SIZE * 8) ->
+ ByteSize = (Size + 7) div 8,
+ [hipe_rtl:mk_gctest(((ByteSize+ 3*WordSize-1) bsr Log2WordSize)+ ExtraSpace),
+ hipe_tagscheme:create_heap_binary(Base, ByteSize, TmpDst),
+ hipe_rtl:mk_move(Offset, Zero)];
+ true ->
+ ByteSize = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+ExtraSpace),
+ hipe_rtl:mk_move(Offset, Zero),
+ hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm((Size+7) bsr 3)),
+ hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
+ hipe_rtl:label_name(NextLbl),[],not_remote),
+ NextLbl,
+ hipe_tagscheme:create_refc_binary(Base, ByteSize, TmpDst)]
+ end,
+ [BaseBinCode, SubBinCode, hipe_rtl:mk_goto(TrueLblName)].
+
+var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
+ Log2WordSize = hipe_rtl_arch:log2_word_size(),
+ WordSize = hipe_rtl_arch:word_size(),
+ [ContLbl,HeapLbl,REFCLbl,NextLbl] = create_lbls(4),
+ [USize,Tmp] = create_unsafe_regs(2),
+ [get_32_bit_value(Size, USize, SystemLimitLblName, FalseLblName),
+ hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE),
+ hipe_rtl:label_name(ContLbl),
+ SystemLimitLblName),
+ ContLbl,
+ hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
+ hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
+ hipe_rtl:label_name(HeapLbl),
+ hipe_rtl:label_name(REFCLbl)),
+ HeapLbl,
+ hipe_rtl:mk_alu(Tmp, USize, add, hipe_rtl:mk_imm(3*WordSize-1)),
+ hipe_rtl:mk_alu(Tmp, Tmp, srl, hipe_rtl:mk_imm(Log2WordSize)),
+ hipe_rtl:mk_alu(Tmp, Tmp, add, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
+ hipe_rtl:mk_gctest(Tmp),
+ hipe_tagscheme:create_heap_binary(Base, USize, Dst),
+ hipe_rtl:mk_goto(TrueLblName),
+ REFCLbl,
+ hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
+ hipe_rtl:mk_call([Base], bs_allocate, [USize],
+ hipe_rtl:label_name(NextLbl), [], not_remote),
+ NextLbl,
+ hipe_tagscheme:create_refc_binary(Base, USize, Dst),
+ hipe_rtl:mk_goto(TrueLblName)].
+
+var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
+ [HeapLbl,REFCLbl,NextLbl,NoSubLbl,SubLbl,ContLbl,
+ NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(10),
+ [USize,ByteSize,TotByteSize,OffsetBits] = create_regs(4),
+ [TmpDst] = create_unsafe_regs(1),
+ Log2WordSize = hipe_rtl_arch:log2_word_size(),
+ WordSize = hipe_rtl_arch:word_size(),
+ MaximumWords =
+ erlang:max((?MAX_HEAP_BIN_SIZE + 3*WordSize) bsr Log2WordSize,
+ ?PROC_BIN_WORDSIZE) + ?SUB_BIN_WORDSIZE,
+ Zero = hipe_rtl:mk_imm(0),
+ [hipe_rtl:mk_gctest(MaximumWords),
+ get_32_bit_value(Size, USize, SystemLimitLblName, FalseLblName),
+ hipe_rtl:mk_alu(ByteSize, USize, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alub(OffsetBits, USize, 'and', ?LOW_BITS, eq,
+ hipe_rtl:label_name(NoSubLbl),
+ hipe_rtl:label_name(SubLbl)),
+ NoSubLbl,
+ hipe_rtl:mk_move(TotByteSize, ByteSize),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
+ SubLbl,
+ hipe_rtl:mk_alu(TotByteSize, ByteSize, 'add', hipe_rtl:mk_imm(1)),
+ JoinLbl,
+ hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE),
+ hipe_rtl:label_name(ContLbl),
+ SystemLimitLblName),
+ ContLbl,
+ hipe_rtl:mk_branch(TotByteSize, 'le', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
+ hipe_rtl:label_name(HeapLbl),
+ hipe_rtl:label_name(REFCLbl)),
+ HeapLbl,
+ hipe_tagscheme:create_heap_binary(Base, TotByteSize, TmpDst),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl2)),
+ REFCLbl,
+ hipe_rtl:mk_call([Base], bs_allocate, [TotByteSize],
+ hipe_rtl:label_name(NextLbl),[],not_remote),
+ NextLbl,
+ hipe_tagscheme:create_refc_binary(Base, TotByteSize, TmpDst),
+ JoinLbl2,
+ hipe_rtl:mk_move(Offset, Zero),
+ hipe_rtl:mk_branch(OffsetBits, 'eq', Zero,
+ hipe_rtl:label_name(NoCreateSubBin),
+ hipe_rtl:label_name(CreateSubBin)),
+ CreateSubBin,
+ hipe_tagscheme:mk_sub_binary(Dst, ByteSize, Zero, OffsetBits, Zero, TmpDst),
+ hipe_rtl:mk_goto(TrueLblName),
+ NoCreateSubBin,
+ hipe_rtl:mk_move(Dst, TmpDst),
+ hipe_rtl:mk_goto(TrueLblName)].
+
+put_binary_all(NewOffset, Src, Base, Offset, TLName, FLName) ->
+ [SrcBase,SrcOffset,NumBits] = create_regs(3),
+ CCode = binary_c_code(NewOffset, Src, Base, Offset, NumBits, TLName),
+ AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, NumBits, Base, Offset,
+ NewOffset, TLName),
+ get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName) ++
+ test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode).
+
+test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode) ->
+ [Tmp] = create_regs(1),
+ [AlignedLbl,CLbl] = create_lbls(2),
+ [hipe_rtl:mk_alu(Tmp, SrcOffset, 'or', NumBits),
+ hipe_rtl:mk_alu(Tmp, Tmp, 'or', Offset),
+ hipe_rtl:mk_alub(Tmp, Tmp, 'and', ?LOW_BITS, 'eq',
+ hipe_rtl:label_name(AlignedLbl),
+ hipe_rtl:label_name(CLbl)),
+ AlignedLbl,
+ AlignedCode,
+ CLbl,
+ CCode].
+
+put_static_binary(NewOffset, Src, Size, Base, Offset, TLName, FLName) ->
+ [SrcBase] = create_unsafe_regs(1),
+ [SrcOffset, SrcSize] = create_regs(2),
+ case Size of
+ 0 ->
+ get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
+ [hipe_rtl:mk_move(NewOffset, Offset),
+ hipe_rtl:mk_goto(TLName)];
+ _ ->
+ SizeImm = hipe_rtl:mk_imm(Size),
+ CCode = binary_c_code(NewOffset, Src, Base, Offset, SizeImm, TLName),
+ AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, SizeImm, Base,
+ Offset, NewOffset, TLName),
+ get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
+ small_check(SizeImm, SrcSize, FLName) ++
+ test_alignment(SrcOffset, SizeImm, Offset, AlignedCode, CCode)
+ end.
+
+put_dynamic_binary(NewOffset, Src, SizeReg, Base, Offset, TLName, FLName) ->
+ [SrcBase] = create_unsafe_regs(1),
+ [SrcOffset, SrcSize] = create_regs(2),
+ CCode = binary_c_code(NewOffset, Src, Base, Offset, SizeReg, TLName),
+ AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, SizeReg, Base, Offset,
+ NewOffset, TLName),
+ get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
+ small_check(SizeReg, SrcSize, FLName) ++
+ test_alignment(SrcOffset, SizeReg, Offset, AlignedCode, CCode).
+
+put_float(NewOffset, Src, Base, Offset, 64, CCode, Aligned, LittleEndian,
+ ConstInfo, TrueLblName) ->
+ [CLbl] = create_lbls(1),
+ case {Aligned, LittleEndian} of
+ {true, false} ->
+ copy_float_big(Base, Offset, NewOffset, Src,
+ hipe_rtl:label_name(CLbl), TrueLblName, ConstInfo) ++
+ [CLbl|CCode];
+ {true, true} ->
+ copy_float_little(Base, Offset, NewOffset, Src,
+ hipe_rtl:label_name(CLbl), TrueLblName, ConstInfo) ++
+ [CLbl|CCode];
+ {false, _} ->
+ CCode
+ end;
+put_float(_NewOffset, _Src, _Base, _Offset, _Size, CCode, _Aligned,
+ _LittleEndian, _ConstInfo, _TrueLblName) ->
+ CCode.
+
+put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
+ LittleEndian, TrueLblName) ->
+ {Init, End, UntaggedSrc} = make_init_end(Src, CCode, TrueLblName),
+ case {Aligned, LittleEndian} of
+ {true, true} ->
+ Init ++
+ copy_int_little(Base, Offset, NewOffset, Size, UntaggedSrc) ++
+ End;
+ {true, false} ->
+ Init ++
+ copy_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
+ End;
+ {false, true} ->
+ CCode;
+ {false, false} ->
+ Init ++
+ copy_offset_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
+ End
+ end.
+
+put_unsafe_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
+ LittleEndian, TrueLblName) ->
+ {Init, End, UntaggedSrc} = make_init_end(Src, TrueLblName),
+ case {Aligned, LittleEndian} of
+ {true, true} ->
+ Init ++
+ copy_int_little(Base, Offset, NewOffset, Size, UntaggedSrc) ++
+ End;
+ {true, false} ->
+ Init ++
+ copy_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
+ End;
+ {false, true} ->
+ CCode;
+ {false, false} ->
+ Init ++
+ copy_offset_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
+ End
+ end.
+
+put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
+ LittleEndian, TrueLblName) ->
+ {Init, End, UntaggedSrc} = make_init_end(Src, CCode, TrueLblName),
+ case Aligned of
+ true ->
+ case LittleEndian of
+ true ->
+ Init ++
+ copy_int_little(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
+ End;
+ false ->
+ Init ++
+ copy_int_big(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
+ End
+ end;
+ false ->
+ CCode
+ end.
+
+put_unsafe_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
+ LittleEndian, TrueLblName) ->
+ {Init, End, UntaggedSrc} = make_init_end(Src, TrueLblName),
+ case Aligned of
+ true ->
+ case LittleEndian of
+ true ->
+ Init ++
+ copy_int_little(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
+ End;
+ false ->
+ Init ++
+ copy_int_big(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
+ End
+ end;
+ false ->
+ CCode
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Help functions used by the above
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_init_end(Src, CCode, TrueLblName) ->
+ [CLbl, SuccessLbl] = create_lbls(2),
+ [UntaggedSrc] = create_regs(1),
+ Init = [hipe_tagscheme:test_fixnum(Src, hipe_rtl:label_name(SuccessLbl),
+ hipe_rtl:label_name(CLbl), 0.99),
+ SuccessLbl,
+ hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
+ End = [hipe_rtl:mk_goto(TrueLblName), CLbl| CCode],
+ {Init, End, UntaggedSrc}.
+
+make_init_end(Src, TrueLblName) ->
+ [UntaggedSrc] = create_regs(1),
+ Init = [hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
+ End = [hipe_rtl:mk_goto(TrueLblName)],
+ {Init, End, UntaggedSrc}.
+
+get_base_offset_size(Binary, SrcBase, SrcOffset, SrcSize, FLName) ->
+ [JoinLbl, EndLbl, SuccessLbl, SubLbl, OtherLbl, HeapLbl, REFCLbl] =
+ Lbls = create_lbls(7),
+ [JoinLblName, EndLblName, SuccessLblName, SubLblName,
+ OtherLblName, HeapLblName, REFCLblName] = get_label_names(Lbls),
+ [BitSize,BitOffset] = create_regs(2),
+ [Orig] = create_vars(1),
+ [hipe_tagscheme:test_bitstr(Binary, SuccessLblName, FLName, 0.99),
+ SuccessLbl,
+ get_field_from_term({sub_binary,binsize}, Binary, SrcSize),
+ hipe_rtl:mk_alu(SrcSize, SrcSize, sll, ?BYTE_SHIFT),
+ hipe_tagscheme:test_subbinary(Binary, SubLblName, OtherLblName),
+ SubLbl,
+ get_field_from_term({sub_binary,bitsize}, Binary, BitSize),
+ get_field_from_term({sub_binary,offset}, Binary, SrcOffset),
+ hipe_rtl:mk_alu(SrcSize, SrcSize, add, BitSize),
+ get_field_from_term({sub_binary,bitoffset}, Binary, BitOffset),
+ hipe_rtl:mk_alu(SrcOffset, SrcOffset, sll, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(SrcOffset, SrcOffset, add, BitOffset),
+ get_field_from_term({sub_binary,orig}, Binary, Orig),
+ hipe_rtl:mk_goto(JoinLblName),
+ OtherLbl,
+ hipe_rtl:mk_move(SrcOffset, hipe_rtl:mk_imm(0)),
+ hipe_rtl:mk_move(Orig, Binary),
+ JoinLbl,
+ hipe_tagscheme:test_heap_binary(Orig, HeapLblName, REFCLblName),
+ HeapLbl,
+ hipe_rtl:mk_alu(SrcBase, Orig, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
+ hipe_rtl:mk_goto(EndLblName),
+ REFCLbl,
+ get_field_from_term({proc_bin,bytes}, Orig, SrcBase),
+ EndLbl].
+
+copy_aligned_bytes(CopyBase, CopyOffset, Size, Base, Offset, NewOffset, TrueLblName) ->
+ [BaseDst, BaseSrc] = create_unsafe_regs(2),
+ [Iter, Extra, BothOffset] = create_regs(3),
+ initializations(BaseSrc, BaseDst, BothOffset, CopyOffset, Offset, CopyBase, Base) ++
+ [hipe_rtl:mk_alu(Extra, Size, 'and', ?LOW_BITS),
+ hipe_rtl:mk_alu(Iter, Size, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)] ++
+ easy_loop(BaseSrc, BaseDst, BothOffset, Iter, Extra, TrueLblName).
+
+copy_string(StringBase, StringSize, BinBase, BinOffset, NewOffset, TrueLblName) ->
+ [TmpOffset,BothOffset,InitOffs] = create_regs(3),
+ [NewBinBase] = create_unsafe_regs(1),
+ [EasyLbl,HardLbl] = create_lbls(2),
+ [hipe_rtl:mk_alu(TmpOffset, BinOffset, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(NewBinBase, BinBase, add, TmpOffset),
+ hipe_rtl:mk_move(BothOffset, hipe_rtl:mk_imm(0)),
+ hipe_rtl:mk_alub(InitOffs, BinOffset, 'and', ?LOW_BITS, eq,
+ hipe_rtl:label_name(EasyLbl), hipe_rtl:label_name(HardLbl)),
+ EasyLbl,
+ hipe_rtl:mk_alu(NewOffset, BinOffset, add,
+ hipe_rtl:mk_imm(?bytes_to_bits(StringSize)))] ++
+ easy_loop(StringBase, NewBinBase, BothOffset,
+ hipe_rtl:mk_imm(StringSize), hipe_rtl:mk_imm(0), TrueLblName) ++
+ [HardLbl,
+ hipe_rtl:mk_alu(NewOffset, BinOffset, add,
+ hipe_rtl:mk_imm(?bytes_to_bits(StringSize)))] ++
+ hard_loop(StringBase, NewBinBase, BothOffset, hipe_rtl:mk_imm(StringSize),
+ InitOffs, TrueLblName).
+
+small_check(SizeVar, CopySize, FalseLblName) ->
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ [hipe_rtl:mk_branch(SizeVar, le, CopySize,
+ hipe_rtl:label_name(SuccessLbl), FalseLblName),
+ SuccessLbl].
+
+easy_loop(BaseSrc, BaseDst, BothOffset, Iterations, Extra, TrueLblName) ->
+ [Tmp1,Shift] = create_regs(2),
+ [LoopLbl,TopLbl,EndLbl,ExtraLbl] = create_lbls(4),
+ [TopLbl,
+ hipe_rtl:mk_branch(BothOffset, ne, Iterations, hipe_rtl:label_name(LoopLbl),
+ hipe_rtl:label_name(EndLbl), 0.99),
+ LoopLbl,
+ hipe_rtl:mk_load(Tmp1, BaseSrc, BothOffset, byte, unsigned),
+ hipe_rtl:mk_store(BaseDst, BothOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(BothOffset, BothOffset, add, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(TopLbl)),
+ EndLbl,
+ hipe_rtl:mk_branch(Extra, eq, hipe_rtl:mk_imm(0), TrueLblName,
+ hipe_rtl:label_name(ExtraLbl)),
+ ExtraLbl,
+ hipe_rtl:mk_load(Tmp1, BaseSrc, BothOffset, byte, unsigned),
+ hipe_rtl:mk_alu(Shift, hipe_rtl:mk_imm(?BYTE_SIZE), sub, Extra),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, srl, Shift),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sll, Shift),
+ hipe_rtl:mk_store(BaseDst, BothOffset, Tmp1, byte),
+ hipe_rtl:mk_goto(TrueLblName)].
+
+hard_loop(BaseSrc, BaseDst, BothOffset, Iterations,
+ InitOffset, TrueLblName) ->
+ [Tmp1, Tmp2, OldByte, NewByte, SaveByte] = create_regs(5),
+ [LoopLbl,EndLbl,TopLbl] = create_lbls(3),
+ [hipe_rtl:mk_load(OldByte, BaseDst, BothOffset, byte, unsigned),
+ hipe_rtl:mk_alu(Tmp1, hipe_rtl:mk_imm(?BYTE_SIZE), sub, InitOffset),
+ TopLbl,
+ hipe_rtl:mk_branch(BothOffset, ne, Iterations,
+ hipe_rtl:label_name(LoopLbl),
+ hipe_rtl:label_name(EndLbl)),
+ LoopLbl,
+ hipe_rtl:mk_load(NewByte, BaseSrc, BothOffset, byte, unsigned),
+ hipe_rtl:mk_alu(Tmp2, NewByte, srl, InitOffset),
+ hipe_rtl:mk_alu(SaveByte, OldByte, 'or', Tmp2),
+ hipe_rtl:mk_store(BaseDst, BothOffset, SaveByte, byte),
+ hipe_rtl:mk_alu(OldByte, NewByte, sll, Tmp1),
+ hipe_rtl:mk_alu(BothOffset, BothOffset, 'add', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(TopLbl)),
+ EndLbl,
+ hipe_rtl:mk_store(BaseDst, BothOffset, OldByte, byte),
+ hipe_rtl:mk_goto(TrueLblName)].
+
+initializations(BaseTmp1, BaseTmp2, BothOffset, CopyOffset, Offset, CopyBase, Base) ->
+ [OffsetTmp1,OffsetTmp2] = create_regs(2),
+ [hipe_rtl:mk_alu(OffsetTmp1, CopyOffset, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(OffsetTmp2, Offset, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(BaseTmp1, CopyBase, add, OffsetTmp1),
+ hipe_rtl:mk_alu(BaseTmp2, Base, add, OffsetTmp2),
+ hipe_rtl:mk_move(BothOffset, hipe_rtl:mk_imm(0))].
+
+copy_int_little(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
+ [Tmp2,TmpOffset] = create_regs(2),
+ ByteSize = Size div ?BYTE_SIZE,
+ [hipe_rtl:mk_alu(TmpOffset, Offset, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(Tmp2, hipe_rtl:mk_imm(ByteSize), 'add', TmpOffset)] ++
+
+ little_loop(Tmp1, Tmp2, TmpOffset, Base) ++
+
+ case Size band 7 of
+ 0 ->
+ [hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))];
+ Bits ->
+ [hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(?BYTE_SIZE-Bits)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))]
+ end;
+
+copy_int_little(Base, Offset, NewOffset, Size, Tmp1) ->
+ [Tmp2, Tmp3, Tmp4, TmpOffset] = create_regs(4),
+
+ [hipe_rtl:mk_alu(Tmp2, Size, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(TmpOffset, Offset, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(Tmp3, Tmp2, 'add', TmpOffset)] ++
+
+ little_loop(Tmp1, Tmp3, TmpOffset, Base) ++
+
+ [hipe_rtl:mk_alu(Tmp4, Size, 'and', ?LOW_BITS),
+ hipe_rtl:mk_alu(Tmp4, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp4),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sll, Tmp4),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)].
+
+little_loop(Tmp1, Tmp3, TmpOffset, Base) ->
+ [BranchLbl, BodyLbl, EndLbl] = create_lbls(3),
+ [BranchLbl,
+ hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3,
+ hipe_rtl:label_name(BodyLbl),
+ hipe_rtl:label_name(EndLbl)),
+ BodyLbl,
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
+ EndLbl].
+
+big_loop(Tmp1, Tmp3, TmpOffset, Base) ->
+ [BranchLbl, BodyLbl, EndLbl] = create_lbls(3),
+ [BranchLbl,
+ hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3,
+ hipe_rtl:label_name(BodyLbl),
+ hipe_rtl:label_name(EndLbl)),
+ BodyLbl,
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
+ EndLbl].
+
+copy_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
+ [hipe_rtl:mk_move(NewOffset, Offset)];
+copy_int_big(Base, Offset, NewOffset, ?BYTE_SIZE, Tmp1) ->
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(8))];
+copy_int_big(Base, Offset, NewOffset, 2*?BYTE_SIZE, Tmp1) ->
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(16))];
+copy_int_big(Base, Offset, NewOffset, 3*?BYTE_SIZE, Tmp1) ->
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_alu(TmpOffset, Offset, srl, hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, add, hipe_rtl:mk_imm(2)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, add, hipe_rtl:mk_imm(24))];
+copy_int_big(Base, Offset,NewOffset, 4*?BYTE_SIZE, Tmp1) ->
+ copy_big_word(Base, Offset, NewOffset, Tmp1);
+copy_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
+ [OldOffset, TmpOffset, Bits] = create_regs(3),
+ ByteSize = (Size + 7) div ?BYTE_SIZE,
+ case Size band 7 of
+ 0 ->
+ [hipe_rtl:mk_alu(OldOffset, Offset, sra, hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(TmpOffset, OldOffset, add, hipe_rtl:mk_imm(ByteSize))];
+ Rest ->
+ [hipe_rtl:mk_alu(OldOffset, Offset, sra, hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(TmpOffset, OldOffset, add, hipe_rtl:mk_imm(ByteSize-1)),
+ hipe_rtl:mk_alu(Bits, Tmp1, sll, hipe_rtl:mk_imm(?BYTE_SIZE-Rest)),
+ hipe_rtl:mk_store(Base, TmpOffset, Bits, byte),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(Rest))]
+ end ++
+ big_loop(Tmp1, OldOffset, TmpOffset, Base) ++
+ [hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))];
+copy_int_big(Base, Offset, NewOffset, Size, Tmp1) ->
+ Tmp2 = hipe_rtl:mk_new_reg(),
+ Tmp3 = hipe_rtl:mk_new_reg(),
+ Tmp4 = hipe_rtl:mk_new_reg(),
+ Tmp5 = hipe_rtl:mk_new_reg(),
+ Tmp6 = hipe_rtl:mk_new_reg(),
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ EvenLbl = hipe_rtl:mk_new_label(),
+ OddLbl = hipe_rtl:mk_new_label(),
+ [hipe_rtl:mk_alu(Tmp2, Size, 'srl', hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(Tmp3, Offset, 'srl', hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(TmpOffset, Tmp2, 'add', Tmp3),
+ hipe_rtl:mk_alub(Tmp4, Size, 'and', hipe_rtl:mk_imm(7), 'eq',
+ hipe_rtl:label_name(EvenLbl), hipe_rtl:label_name(OddLbl)),
+ OddLbl,
+ hipe_rtl:mk_alu(Tmp6, hipe_rtl:mk_imm(8), 'sub', Tmp4),
+ hipe_rtl:mk_alu(Tmp5, Tmp1, 'sll', Tmp6),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp5, byte),
+ EvenLbl,
+ hipe_rtl:mk_alu(Tmp1, Tmp1, srl, Tmp4)] ++
+
+ big_loop(Tmp1, Tmp3, TmpOffset, Base) ++
+
+ [hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)].
+
+copy_big_word(Base, Offset, NewOffset, Word) ->
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(3)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
+
+copy_little_word(Base, Offset, NewOffset, Word) ->
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', ?BYTE_SHIFT),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
+ hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
+
+copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
+ Tmp2 = hipe_rtl:mk_new_reg(),
+ Tmp3 = hipe_rtl:mk_new_reg(),
+ Tmp4 = hipe_rtl:mk_new_reg(),
+ Tmp5 = hipe_rtl:mk_new_reg(),
+ Tmp6 = hipe_rtl:mk_new_reg(),
+ Tmp7 = hipe_rtl:mk_new_reg(),
+ Tmp8 = hipe_rtl:mk_new_reg(),
+ Tmp9 = hipe_rtl:mk_new_reg(),
+ OldByte = hipe_rtl:mk_new_reg(),
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ BranchLbl = hipe_rtl:mk_new_label(),
+ BodyLbl = hipe_rtl:mk_new_label(),
+ EndLbl = hipe_rtl:mk_new_label(),
+ NextLbl = hipe_rtl:mk_new_label(),
+ WordSize = hipe_rtl_arch:word_size(),
+ [hipe_rtl:mk_alu(Tmp2, Offset, 'and', ?LOW_BITS),
+ hipe_rtl:mk_alu(Tmp3, Offset, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size)),
+ hipe_rtl:mk_alu(Tmp9, NewOffset, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(TmpOffset, Tmp9, srl, ?BYTE_SHIFT),
+ hipe_rtl:mk_alu(Tmp4, NewOffset, 'and', ?LOW_BITS),
+ hipe_rtl:mk_alu(Tmp6, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp4),
+ hipe_rtl:mk_alu(Tmp6, Tmp6, 'and', ?LOW_BITS),
+ hipe_rtl:mk_alu(Tmp4, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp6),
+ hipe_rtl:mk_move(Tmp5, Tmp1),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sll', Tmp6),
+ hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3, hipe_rtl:label_name(NextLbl),
+ hipe_rtl:label_name(EndLbl)),
+ NextLbl,
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_move(Tmp1, Tmp5),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', Tmp4),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
+ BranchLbl,
+ hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3, hipe_rtl:label_name(BodyLbl),
+ hipe_rtl:label_name(EndLbl)),
+ BodyLbl,
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
+ hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
+ EndLbl,
+ hipe_rtl:mk_load(OldByte, Base, TmpOffset, byte, unsigned),
+ hipe_rtl:mk_alu(Tmp8, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp2),
+ hipe_rtl:mk_alu(OldByte, OldByte, 'srl', Tmp8),
+ hipe_rtl:mk_alu(OldByte, OldByte, 'sll', Tmp8),
+ hipe_rtl:mk_alu(Tmp7, Tmp2, 'add',
+ hipe_rtl:mk_imm(?bytes_to_bits(WordSize-1))),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'sll', Tmp7),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'srl', Tmp7),
+ hipe_rtl:mk_alu(Tmp1, Tmp1, 'or', OldByte),
+ hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte)].
+
+copy_float_little(_Base, _Offset, _NewOffset, _Src, FalseLblName, _TrueLblName, fail) ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+copy_float_little(Base, Offset, NewOffset, Src, _FalseLblName, TrueLblName, pass) ->
+ FloatLo = hipe_rtl:mk_new_reg(),
+ FloatHi = hipe_rtl:mk_new_reg(),
+ TmpOffset = hipe_rtl:mk_new_reg(),
+ hipe_tagscheme:unsafe_load_float(FloatLo, FloatHi, Src) ++
+ copy_little_word(Base, Offset, TmpOffset, FloatLo) ++
+ copy_little_word(Base, TmpOffset, NewOffset, FloatHi) ++
+ [hipe_rtl:mk_goto(TrueLblName)];
+copy_float_little(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
+ [SuccessLbl|copy_float_little(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
+
+copy_float_big(_Base, _Offset, _NewOffset, _Src, FalseLblName, _TrueLblName, fail) ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+copy_float_big(Base, Offset, NewOffset, Src, _FalseLblName, TrueLblName,pass) ->
+ FloatLo = hipe_rtl:mk_new_reg(),
+ FloatHi = hipe_rtl:mk_new_reg(),
+ TmpOffset =hipe_rtl:mk_new_reg(),
+ hipe_tagscheme:unsafe_load_float(FloatLo, FloatHi, Src) ++
+ copy_big_word(Base, Offset, TmpOffset, FloatHi) ++
+ copy_big_word(Base, TmpOffset, NewOffset, FloatLo) ++
+ [hipe_rtl:mk_goto(TrueLblName)];
+copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
+ [SuccessLbl|copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
+
+make_size(1, BitsVar, FalseLblName) ->
+ [DstReg] = create_regs(1),
+ {first_part(BitsVar, DstReg, FalseLblName), DstReg};
+make_size(?BYTE_SIZE, BitsVar, FalseLblName) ->
+ [DstReg] = create_regs(1),
+ Code =
+ first_part(BitsVar, DstReg, FalseLblName) ++
+ [hipe_rtl:mk_alu(DstReg, DstReg, 'sll', ?BYTE_SHIFT)],
+ {Code, DstReg};
+make_size(UnitImm, BitsVar, FalseLblName) ->
+ [DstReg] = create_regs(1),
+ UnitList = number2list(UnitImm),
+ Code = multiply_code(UnitList, BitsVar, DstReg, FalseLblName),
+ {Code, DstReg}.
+
+multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) ->
+ Test = set_high(Head),
+ Tmp1 = hipe_rtl:mk_new_reg(),
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ Register = hipe_rtl:mk_new_reg(),
+ Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))|
+ first_part(Variable, Register, FalseLblName)]
+ ++
+ [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test),
+ 'eq', hipe_rtl:label_name(SuccessLbl),
+ FalseLblName, 0.99),
+ SuccessLbl],
+ multiply_code(List, Register, Result, FalseLblName, Tmp1, Code).
+
+multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) ->
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ Code = OldCode ++ [hipe_rtl:mk_alu(Tmp1, Register, 'sll',
+ hipe_rtl:mk_imm(ShiftSize)),
+ hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
+ SuccessLbl],
+ multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code);
+multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) ->
+ Code.
+
+number2list(X) when is_integer(X), X >= 0 ->
+ number2list(X, []).
+
+number2list(1, Acc) ->
+ lists:reverse([0|Acc]);
+number2list(0, Acc) ->
+ lists:reverse(Acc);
+number2list(X, Acc) ->
+ F = floorlog2(X),
+ number2list(X-(1 bsl F), [F|Acc]).
+
+floorlog2(X) ->
+ round(math:log(X)/math:log(2)-0.5).
+
+set_high(X) ->
+ set_high(X, 0).
+
+set_high(0, Y) ->
+ Y;
+set_high(X, Y) ->
+ set_high(X-1, Y+(1 bsl (27-X))).
+
+get_32_bit_value(Size, USize, SystemLimitLblName, NegLblName) ->
+ Lbls = [FixLbl, BigLbl, OkLbl, PosBigLbl] = create_lbls(4),
+ [FixLblName, BigLblName, OkLblName, PosBigLblName] = [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
+ [hipe_tagscheme:test_fixnum(Size, FixLblName, BigLblName, 0.99),
+ FixLbl,
+ hipe_tagscheme:untag_fixnum(USize, Size),
+ hipe_rtl:mk_branch(USize, ge, hipe_rtl:mk_imm(0), OkLblName, NegLblName),
+ BigLbl,
+ hipe_tagscheme:test_pos_bignum(Size, PosBigLblName, NegLblName, 0.99),
+ PosBigLbl,
+ hipe_tagscheme:get_one_word_pos_bignum(USize, Size, SystemLimitLblName),
+ OkLbl].
+
+
+first_part(Var, Register, FalseLblName) ->
+ [SuccessLbl1, SuccessLbl2] = create_lbls(2),
+ [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(SuccessLbl1),
+ FalseLblName, 0.99),
+ SuccessLbl1,
+ hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
+ hipe_rtl:label_name(SuccessLbl2), FalseLblName, 0.99),
+ SuccessLbl2,
+ hipe_tagscheme:untag_fixnum(Register, Var)].
+
+