diff options
Diffstat (limited to 'lib/hipe/rtl/hipe_rtl_binary_construct.erl')
-rw-r--r-- | lib/hipe/rtl/hipe_rtl_binary_construct.erl | 1363 |
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)]. + + |