diff options
Diffstat (limited to 'lib/hipe/rtl/hipe_rtl_binary_match.erl')
-rw-r--r-- | lib/hipe/rtl/hipe_rtl_binary_match.erl | 1134 |
1 files changed, 1134 insertions, 0 deletions
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl new file mode 100644 index 0000000000..d147bed6d8 --- /dev/null +++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl @@ -0,0 +1,1134 @@ +%%% -*- 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% +%%% +%%%------------------------------------------------------------------- +%%% File : hipe_rtl_binary_match.erl +%%% Author : Per Gustafsson <[email protected]> +%%% Description : +%%% +%%% Created : 5 Mar 2007 by Per Gustafsson <[email protected]> +%%%------------------------------------------------------------------- +-module(hipe_rtl_binary_match). + +-export([gen_rtl/5]). + +-import(hipe_tagscheme, [set_field_from_term/3, get_field_from_term/3]). + +-include("hipe_literals.hrl"). + +%%-------------------------------------------------------------------- + +-define(MAX_BINSIZE, trunc(?MAX_HEAP_BIN_SIZE / hipe_rtl_arch:word_size()) + 2). +-define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa +-define(LOW_BITS, 7). %% Three lowest bits set +-define(BYTE_SIZE, 8). +-define(MAX_SMALL_BITS, (hipe_rtl_arch:word_size() * ?BYTE_SIZE - 5)). + +%%-------------------------------------------------------------------- + +gen_rtl({bs_start_match, 0}, [Ms], [Binary], TrueLblName, FalseLblName) -> + ReInitLbl = hipe_rtl:mk_new_label(), + BinaryLbl = hipe_rtl:mk_new_label(), + TestCode = + [hipe_rtl:mk_move(Ms,Binary), + hipe_tagscheme:test_matchstate(Binary, + hipe_rtl:label_name(ReInitLbl), + hipe_rtl:label_name(BinaryLbl), + 0.99)], + ReInitCode = reinit_matchstate(Ms, TrueLblName), + OrdinaryCode = make_matchstate(Binary, 0, Ms, TrueLblName, FalseLblName), + [TestCode,[ReInitLbl|ReInitCode],[BinaryLbl|OrdinaryCode]]; +gen_rtl({bs_start_match, Max}, [Ms], [Binary], TrueLblName, FalseLblName) -> + MatchStateLbl = hipe_rtl:mk_new_label(), + BinaryLbl = hipe_rtl:mk_new_label(), + ReSizeLbl = hipe_rtl:mk_new_label(), + ReInitLbl = hipe_rtl:mk_new_label(), + TestCode = + [hipe_rtl:mk_move(Ms,Binary), + hipe_tagscheme:test_matchstate(Binary, + hipe_rtl:label_name(MatchStateLbl), + hipe_rtl:label_name(BinaryLbl), + 0.99)], + MatchStateTestCode = + [hipe_tagscheme:compare_matchstate(Max, Ms, + hipe_rtl:label_name(ReInitLbl), + hipe_rtl:label_name(ReSizeLbl))], + ReSizeCode = resize_matchstate(Ms, Max, TrueLblName), + ReInitCode = reinit_matchstate(Ms, TrueLblName), + OrdinaryCode = make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName), + [TestCode, [MatchStateLbl|MatchStateTestCode], [ReSizeLbl|ReSizeCode], + [ReInitLbl|ReInitCode], [BinaryLbl|OrdinaryCode]]; +gen_rtl({bs_start_match, _Max}, [], [Binary], TrueLblName, FalseLblName) -> + MatchStateLbl = hipe_rtl:mk_new_label(), + [hipe_tagscheme:test_bitstr(Binary, TrueLblName, + hipe_rtl:label_name(MatchStateLbl), 0.99), + MatchStateLbl, + hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)]; +gen_rtl({{bs_start_match, bitstr}, Max}, [Ms], [Binary], + TrueLblName, FalseLblName) -> + make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName); +gen_rtl({{bs_start_match, bitstr}, _Max}, [], [_Binary], + TrueLblName, _FalseLblName) -> + [hipe_rtl:mk_goto(TrueLblName)]; +gen_rtl({{bs_start_match,ok_matchstate}, Max}, [Ms], [Binary], + TrueLblName, FalseLblName) -> + MatchStateLbl = hipe_rtl:mk_new_label(), + BinaryLbl = hipe_rtl:mk_new_label(), + TestCode = + [hipe_rtl:mk_move(Ms,Binary), + hipe_tagscheme:test_matchstate(Binary, + hipe_rtl:label_name(MatchStateLbl), + hipe_rtl:label_name(BinaryLbl), + 0.99)], + MatchStateCode = reinit_matchstate(Ms, TrueLblName), + OrdinaryCode = make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName), + TestCode ++ [MatchStateLbl|MatchStateCode] ++ [BinaryLbl|OrdinaryCode]; +gen_rtl({{bs_start_match, ok_matchstate}, _Max}, [], [Binary], + TrueLblName, FalseLblName) -> + MatchStateLbl = hipe_rtl:mk_new_label(), + [hipe_tagscheme:test_bitstr(Binary, TrueLblName, + hipe_rtl:label_name(MatchStateLbl), 0.99), + MatchStateLbl, + hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)]; +gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms], + TrueLblName, _FalseLblName) -> + update_ms(NewMs, Ms) ++ + [hipe_rtl:mk_move(Dst, hipe_rtl:mk_imm(15)), + hipe_rtl:mk_goto(TrueLblName)]; +gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args, + TrueLblName, FalseLblName) -> + case is_illegal_const(Size) of + true -> + [hipe_rtl:mk_goto(FalseLblName)]; + false -> + Signed = signed(Flags), + LittleEndian = littleendian(Flags), + Aligned = aligned(Flags), + UnSafe = unsafe(Flags), + case Args of + [Ms] -> + CCode= int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size), + Flags, TrueLblName, FalseLblName), + update_ms(NewMs, Ms) ++ + get_static_int(Dst, Ms, Size, CCode, + Signed, LittleEndian, Aligned, UnSafe, + TrueLblName, FalseLblName); + [Ms, Arg] -> + {SizeCode1, SizeReg1} = + make_size(Size, Arg, FalseLblName), + CCode = int_get_c_code(Dst, Ms, SizeReg1, Flags, + TrueLblName, FalseLblName), + InCode = get_dynamic_int(Dst, Ms, SizeReg1, CCode, + Signed, LittleEndian, Aligned, + TrueLblName, FalseLblName), + update_ms(NewMs, Ms) ++ SizeCode1 ++ InCode + end + end; +gen_rtl({bs_get_float,Size,Flags}, [Dst1,NewMs], Args, + TrueLblName, FalseLblName) -> + case is_illegal_const(Size) of + true -> + [hipe_rtl:mk_goto(FalseLblName)]; + false -> + [hipe_rtl:mk_gctest(3)] ++ + case Args of + [Ms] -> + CCode = float_get_c_code(Dst1, Ms, hipe_rtl:mk_imm(Size), Flags, + TrueLblName, FalseLblName), + update_ms(NewMs, Ms) ++ CCode; + [Ms,Arg] -> + {SizeCode, SizeReg} = make_size(Size, Arg, + FalseLblName), + CCode = float_get_c_code(Dst1, Ms, SizeReg, Flags, + TrueLblName, FalseLblName), + update_ms(NewMs, Ms) ++ SizeCode ++ CCode + end + end; +gen_rtl({bs_get_binary_all, Unit, _Flags}, [Dst], [Ms], + TrueLblName, FalseLblName) -> + [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++ + get_binary_all(Dst, Unit, Ms, TrueLblName,FalseLblName); +gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst,NewMs], [Ms], + TrueLblName, FalseLblName) -> + [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++ + update_ms(NewMs, Ms) ++ + get_binary_all(Dst, Unit, Ms, TrueLblName, FalseLblName); +gen_rtl({bs_get_binary,Size,Flags}, [Dst,NewMs], Args, + TrueLblName, FalseLblName) -> + case is_illegal_const(Size) of + true -> + [hipe_rtl:mk_goto(FalseLblName)]; + false -> + Unsafe = unsafe(Flags), + case Args of + [Ms] -> + SizeReg = hipe_rtl:mk_new_reg(), + SizeCode = [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))]; + [Ms, BitsVar] -> + {SizeCode, SizeReg} = make_size(Size, BitsVar, FalseLblName) + end, + InCode = get_binary(Dst, Ms, SizeReg, Unsafe, + TrueLblName, FalseLblName), + [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++ + update_ms(NewMs, Ms) ++ SizeCode ++ InCode + end; +gen_rtl(bs_get_utf8, [Dst,NewMs], [Ms], TrueLblName, FalseLblName) -> + update_ms(NewMs, Ms) ++ utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName); +gen_rtl({bs_get_utf16,Flags}, [Dst,NewMs], [Ms], TrueLblName, FalseLblName) -> + update_ms(NewMs, Ms) ++ utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName); +gen_rtl(bs_validate_unicode_retract, [NewMs], [Src,Ms], TrueLblName, FalseLblName) -> + update_ms(NewMs, Ms) ++ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName); +gen_rtl({bs_test_tail, NumBits}, [NewMs], [Ms], TrueLblName, FalseLblName) -> + {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms), + update_ms(NewMs, Ms) ++ ExCode ++ + [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName), + hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)]; +gen_rtl({bs_test_unit, Unit}, [], [Ms], TrueLblName, FalseLblName) -> + {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms), + SizeReg = hipe_rtl:mk_new_reg(), + ExCode ++ + [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)| + test_alignment_code(SizeReg, Unit, TrueLblName, FalseLblName)]; +gen_rtl({bs_test_tail, NumBits}, [], [Ms], TrueLblName, FalseLblName) -> + {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms), + ExCode ++ + [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName), + hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)]; +gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms], + TrueLblName, FalseLblName) -> + opt_update_ms(Dst, Ms) ++ + skip_bits_all(Unit, Ms, TrueLblName, FalseLblName); +gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) -> + opt_update_ms(Dst,Ms) ++ + case Args of + [] -> + skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName); + [Arg] -> + {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName), + InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName), + SizeCode ++ InCode + end; +gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) -> + Tmp1 = hipe_rtl:mk_new_reg_gcsafe(), + update_ms(NewMs, Ms) ++ + [get_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Tmp1), + set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp1), + hipe_rtl:mk_goto(TrueLblName)]; +gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) -> + {Offset, Instr} = extract_matchstate_var(offset, Ms), + update_ms(NewMs, Ms) ++ + [Instr, + set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset), + hipe_rtl:mk_goto(TrueLblName)]; +gen_rtl({bs_match_string, String, ByteSize}, [NewMs], + [Ms], TrueLblName, FalseLblName) -> + {[Offset, BinSize, Base], Instrs} = + extract_matchstate_vars([offset, binsize, base], Ms), + [SuccessLbl, ALbl, ULbl] = create_lbls(3), + [NewOffset,BitOffset] = create_gcsafe_regs(2), + Unit = hipe_rtl_arch:word_size() - 1, + Loops = ByteSize div Unit, + Init = + [Instrs, + update_ms(NewMs,Ms), + check_size(Offset, hipe_rtl:mk_imm(ByteSize*?BYTE_SIZE), BinSize, + NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName), + SuccessLbl], + SplitCode = + [hipe_rtl:mk_alub(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq, + hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))], + Loops = ByteSize div Unit, + SkipSize = Loops * Unit, + {ACode1,UCode1} = + case Loops of + 0 -> + {[],[]}; + _ -> + create_loops(Loops, Unit, String, Base, + Offset, BitOffset, FalseLblName) + end, + <<_:SkipSize/binary, RestString/binary>> = String, + {ACode2, UCode2} = + case ByteSize rem Unit of + 0 -> + {[],[]}; + Rem -> + create_rests(Rem, RestString, Base, Offset, BitOffset, FalseLblName) + end, + End = [update_offset(NewOffset, NewMs), hipe_rtl:mk_goto(TrueLblName)], + [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2,End]; +gen_rtl(bs_context_to_binary, [Bin], [Var], TrueLblName, _FalseLblName) -> + MSLabel = hipe_rtl:mk_new_label(), + [hipe_rtl:mk_move(Bin, Var), + hipe_tagscheme:test_matchstate(Var, hipe_rtl:label_name(MSLabel), + TrueLblName, 0.5), + MSLabel, + hipe_tagscheme:convert_matchstate(Bin), + hipe_rtl:mk_goto(TrueLblName)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Calls to C %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +int_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) -> + make_int_gc_code(Size) ++ + get_c_code(bs_get_integer_2, Dst1, Ms, Size, Flags, + TrueLblName, FalseLblName). + +float_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) -> + get_c_code(bs_get_float_2, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName). + +get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) -> + SizeReg = hipe_rtl:mk_new_reg_gcsafe(), + FlagsReg = hipe_rtl:mk_new_reg_gcsafe(), + MatchBuf = hipe_rtl:mk_new_reg(), + RetLabel = hipe_rtl:mk_new_label(), + NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()), + [hipe_rtl:mk_move(SizeReg, Size), + hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)), + hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), + hipe_rtl_arch:call_bif([Dst1], Func, [SizeReg, FlagsReg, MatchBuf], + hipe_rtl:label_name(RetLabel), FalseLblName), + RetLabel, + hipe_rtl:mk_branch(Dst1, eq, NonVal, + FalseLblName, + TrueLblName, 0.01)]. + +utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) -> + MatchBuf = hipe_rtl:mk_new_reg(), + NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()), + [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), + hipe_rtl_arch:call_bif([Dst], bs_get_utf8, [MatchBuf], [], []), + hipe_rtl:mk_branch(Dst, eq, NonVal, FalseLblName, TrueLblName, 0.01)]. + +utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName) -> + MatchBuf = hipe_rtl:mk_new_reg(), + NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()), + FlagsReg = hipe_rtl:mk_new_reg_gcsafe(), + [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), + hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)), + hipe_rtl_arch:call_bif([Dst], bs_get_utf16, [MatchBuf, FlagsReg], [], []), + hipe_rtl:mk_branch(Dst, eq, NonVal, FalseLblName, TrueLblName, 0.01)]. + +validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) -> + MatchBuf = hipe_rtl:mk_new_reg(), + Zero = hipe_rtl:mk_imm(0), + Tmp = hipe_rtl:mk_new_reg(), + [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms), + hipe_rtl_arch:call_bif([Tmp], bs_validate_unicode_retract, + [MatchBuf,Src], [], []), + hipe_rtl:mk_branch(Tmp, eq, Zero, FalseLblName, TrueLblName, 0.01)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Int Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) -> + [Reg] = create_gcsafe_regs(1), + AlignedFun = fun(Value) -> + [get_int_to_reg(Reg, Unit*?BYTE_SIZE, Base, Offset, 'srl', + {unsigned, big}), + update_and_test(Reg, Unit, Offset, Value, FalseLblName)] + end, + UnAlignedFun = fun(Value) -> + [get_unaligned_int_to_reg(Reg, Unit*?BYTE_SIZE, + Base, Offset, BitOffset, + 'srl', {unsigned, big})| + update_and_test(Reg, Unit, Offset, Value, FalseLblName)] + end, + {create_loops(Loops, Unit, String, AlignedFun), + create_loops(Loops, Unit, String, UnAlignedFun)}. + +create_rests(Rem, String, Base, Offset, BitOffset, FalseLblName) -> + [Reg] = create_gcsafe_regs(1), + AlignedFun = fun(Value) -> + [get_int_to_reg(Reg, Rem*?BYTE_SIZE, Base, Offset, 'srl', + {unsigned, big})| + just_test(Reg, Value, FalseLblName)] + end, + UnAlignedFun = fun(Value) -> + [get_unaligned_int_to_reg(Reg, Rem*?BYTE_SIZE, + Base, Offset, BitOffset, + 'srl', {unsigned, big})| + just_test(Reg, Value, FalseLblName)] + end, + {create_loops(1, Rem, String, AlignedFun), + create_loops(1, Rem, String, UnAlignedFun)}. + +create_loops(0, _Unit, _String, _IntFun) -> + []; +create_loops(N, Unit, String, IntFun) -> + {Value, RestString} = get_value(Unit,String), + [IntFun(Value), + create_loops(N-1, Unit, RestString, IntFun)]. + +update_and_test(Reg, Unit, Offset, Value, FalseLblName) -> + [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit*?BYTE_SIZE), FalseLblName), + just_test(Reg, Value, FalseLblName)]. + +just_test(Reg, Value, FalseLblName) -> + [ContLbl] = create_lbls(1), + [hipe_rtl:mk_branch(Reg, eq, hipe_rtl:mk_imm(Value), + hipe_rtl:label_name(ContLbl), FalseLblName), + ContLbl]. + +get_value(N,String) -> + <<I:N/integer-unit:8, Rest/binary>> = String, + {I, Rest}. + +make_int_gc_code(I) when is_integer(I) -> + case hipe_tagscheme:bignum_sizeneed(I) of + 0 -> []; + X when is_integer(X) -> [hipe_rtl:mk_gctest(X)] + end; +make_int_gc_code(SReg) -> + FixNumLbl = hipe_rtl:mk_new_label(), + FixNumLblName = hipe_rtl:label_name(FixNumLbl), + {ResReg,Code} = hipe_tagscheme:bignum_sizeneed_code(SReg, FixNumLblName), + Code ++ + [hipe_rtl:mk_gctest(ResReg), + hipe_rtl:mk_goto(FixNumLblName), + FixNumLbl]. + +get_static_int(Dst1, Ms, Size, CCode, Signed, LittleEndian, Aligned, + Unsafe, TrueLblName, FalseLblName) -> + WordSize = hipe_rtl_arch:word_size(), + case Size =< WordSize*?BYTE_SIZE of + true -> + case {Aligned, LittleEndian} of + {true, false} -> + get_int_from_bin(Ms, Size, Dst1,Signed, LittleEndian, + Unsafe, FalseLblName, TrueLblName); + {true, true} -> + case Size rem ?BYTE_SIZE of + 0 -> + get_int_from_bin(Ms, Size, Dst1, Signed, LittleEndian, + Unsafe, FalseLblName, TrueLblName); + _ -> + CCode + end; + {false, false} -> + get_int_from_unaligned_bin(Ms, Size, Dst1, Signed, + Unsafe, FalseLblName, TrueLblName); + {false, true} -> + CCode + end; + false -> + CCode + end. + +get_dynamic_int(Dst1, Ms, SizeReg, CCode, Signed, LittleEndian, true, + TrueLblName, FalseLblName) -> + {Init, End} = make_dyn_prep(SizeReg, CCode), + Init ++ + get_unknown_size_int(SizeReg, Ms, Dst1, Signed, LittleEndian, + FalseLblName, TrueLblName) ++ + End; +get_dynamic_int(_Dst1, _Ms, _SizeReg, CCode, _Signed, _LittleEndian, false, + _TrueLblName, _FalseLblName) -> + CCode. + +get_int_from_bin(Ms, Size, Dst1, Signed, LittleEndian, + Unsafe, FalseLblName, TrueLblName) -> + Shiftr = shift_type(Signed), + Type = get_type(Signed, LittleEndian), + NewOffset = hipe_rtl:mk_new_reg_gcsafe(), + [SuccessLbl] = create_lbls(1), + {[Base,Offset,BinSize], ExCode} = + extract_matchstate_vars([base,offset,binsize], Ms), + ExCode ++ + [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset, + Unsafe, hipe_rtl:label_name(SuccessLbl), FalseLblName), + SuccessLbl] ++ + [update_offset(NewOffset, Ms)] ++ + get_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName). + +get_int_from_unaligned_bin(Ms, Size, Dst1, Signed, + UnSafe, FalseLblName, TrueLblName) -> + Shiftr = shift_type(Signed), + Type = get_type(Signed, false), + NewOffset = hipe_rtl:mk_new_reg_gcsafe(), + [SuccessLbl] = create_lbls(1), + {[Base,Offset,BinSize], ExCode} = + extract_matchstate_vars([base,offset,binsize], Ms), + ExCode ++ + [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset, + UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName), + SuccessLbl] ++ + [update_offset(NewOffset, Ms)] ++ + get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName). + +get_unknown_size_int(SizeReg, Ms, Dst1, Signed, Little, + FalseLblName, TrueLblName) -> + Shiftr = shift_type(Signed), + Type = get_type(Signed, false), + [NewOffset] = create_gcsafe_regs(1), + [SuccessLbl] = create_lbls(1), + {[Base,Offset,BinSize], ExCode} = + extract_matchstate_vars([base,offset,binsize], Ms), + ExCode ++ + [check_size(Offset, SizeReg, BinSize, NewOffset, + hipe_rtl:label_name(SuccessLbl), FalseLblName), + SuccessLbl, + update_offset(NewOffset, Ms)] ++ + case Little of + true -> + get_little_unknown_int(Dst1, Base, Offset, NewOffset, + Shiftr, Type, TrueLblName); + false -> + get_big_unknown_int(Dst1, Base, Offset, NewOffset, + Shiftr, Type, TrueLblName) + end. + +make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName) -> + Base = hipe_rtl:mk_new_reg(), + Orig = hipe_rtl:mk_new_var(), + BinSize = hipe_rtl:mk_new_reg_gcsafe(), + Offset = hipe_rtl:mk_new_reg_gcsafe(), + Lbl = hipe_rtl:mk_new_label(), + [hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max), + get_binary_bytes(Binary, BinSize, Base, Offset, + Orig, hipe_rtl:label_name(Lbl), FalseLblName), + Lbl, + hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms), + hipe_rtl:mk_goto(TrueLblName)]. + +resize_matchstate(Ms, Max, TrueLblName) -> + Base = hipe_rtl:mk_new_reg(), + Orig = hipe_rtl:mk_new_var(), + BinSize = hipe_rtl:mk_new_reg_gcsafe(), + Offset = hipe_rtl:mk_new_reg_gcsafe(), + [hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max), + get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize), + get_field_from_term({matchstate, {matchbuffer, base}}, Ms, Base), + get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig), + get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Offset), + hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms), + hipe_rtl:mk_goto(TrueLblName)]. + +reinit_matchstate(Ms, TrueLblName) -> + Tmp = hipe_rtl:mk_new_reg_gcsafe(), + [get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp), + set_field_from_term({matchstate, {saveoffset, 0}}, Ms, Tmp), + hipe_rtl:mk_goto(TrueLblName)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% Binary Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_binary_all(Dst1, 1, Ms, TrueLblName, _FalseLblName) -> + [SizeReg] = create_gcsafe_regs(1), + {[Offset,BinSize,Orig], ExCode} = + extract_matchstate_vars([offset,binsize,orig], Ms), + MakeCode = + [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)| + construct_subbin(Dst1,SizeReg,Offset,Orig)] ++ + [update_offset(BinSize, Ms), + hipe_rtl:mk_goto(TrueLblName)], + ExCode ++ MakeCode; +get_binary_all(Dst1, Unit, Ms, TrueLblName, FalseLblName) -> + [SizeReg] = create_gcsafe_regs(1), + [SuccessLbl] = create_lbls(1), + SLblName = hipe_rtl:label_name(SuccessLbl), + {[Offset,BinSize,Orig], ExCode} = + extract_matchstate_vars([offset,binsize,orig], Ms), + MakeCode = + [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)| + test_alignment_code(SizeReg,Unit,SLblName,FalseLblName)] ++ + [SuccessLbl| + construct_subbin(Dst1,SizeReg,Offset,Orig)] ++ + [update_offset(BinSize, Ms), + hipe_rtl:mk_goto(TrueLblName)], + ExCode ++ MakeCode. + +get_binary(Dst1, Ms, SizeReg, + UnSafe, TrueLblName, FalseLblName) -> + [SuccessLbl] = create_lbls(1), + [EndOffset] = create_gcsafe_regs(1), + {[Offset,BinSize,Orig], ExCode} = + extract_matchstate_vars([offset,binsize,orig], Ms), + CheckCode = + [check_size(Offset, SizeReg, BinSize, EndOffset, + UnSafe, hipe_rtl:label_name(SuccessLbl), + FalseLblName), + SuccessLbl], + MakeCode = + construct_subbin(Dst1,SizeReg,Offset,Orig) + ++ [update_offset(EndOffset, Ms), + hipe_rtl:mk_goto(TrueLblName)], + ExCode ++ CheckCode ++ MakeCode. + +construct_subbin(Dst,Size,Offset,Orig) -> + [BitOffset, ByteOffset, BitSize, ByteSize] = create_gcsafe_regs(4), + [hipe_rtl:mk_alu(ByteSize, Size, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + hipe_rtl:mk_alu(BitSize, Size, 'and', hipe_rtl:mk_imm(?LOW_BITS)), + hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + hipe_rtl:mk_alu(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS)), + hipe_tagscheme:mk_sub_binary(Dst, ByteSize, ByteOffset, + BitSize, BitOffset, Orig)]. + +%%%%%%%%%%%%%%%%%%%%%%%%% Skip Bits %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +skip_bits_all(1, Ms, TrueLblName,_FalseLblName) -> + {[BinSize], ExCode} = extract_matchstate_vars([binsize], Ms), + ExCode ++ + [update_offset(BinSize,Ms), + hipe_rtl:mk_goto(TrueLblName)]; +skip_bits_all(Unit,Ms, TrueLblName,FalseLblName) -> + [Size] = create_gcsafe_regs(1), + [SuccessLbl] = create_lbls(1), + SLblName = hipe_rtl:label_name(SuccessLbl), + {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms), + ExCode ++ + [hipe_rtl:mk_alu(Size,BinSize,sub,Offset)] + ++ + test_alignment_code(Size,Unit,SLblName,FalseLblName) ++ + [SuccessLbl, + update_offset(BinSize,Ms), + hipe_rtl:mk_goto(TrueLblName)]. + +test_alignment_code(Size,Unit,SLblName,FalseLblName) -> + case Unit of + 1 -> [hipe_rtl:mk_goto(SLblName)]; + 2 -> get_fast_test_code(Size,1,SLblName,FalseLblName); + 4 -> get_fast_test_code(Size,3,SLblName,FalseLblName); + 8 -> get_fast_test_code(Size,7,SLblName,FalseLblName); + 16 -> get_fast_test_code(Size,15,SLblName,FalseLblName); + 32 -> get_fast_test_code(Size,31,SLblName,FalseLblName); + _ -> get_slow_test_code(Size,Unit,SLblName,FalseLblName) + end. + +get_fast_test_code(Size,AndTest,SLblName,FalseLblName) -> + [Tmp] = create_gcsafe_regs(1), + [hipe_rtl:mk_alub(Tmp,Size,'and',hipe_rtl:mk_imm(AndTest), + eq,SLblName,FalseLblName)]. + +%% This is really slow +get_slow_test_code(Size,Unit,SLblName,FalseLblName) -> + [Tmp] = create_gcsafe_regs(1), + [LoopLbl,Lbl1,Lbl2] = create_lbls(3), + LoopLblName = hipe_rtl:label_name(LoopLbl), + Lbl1Name = hipe_rtl:label_name(Lbl1), + Lbl2Name = hipe_rtl:label_name(Lbl2), + [hipe_rtl:mk_move(Tmp,Size), + LoopLbl, + hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0), SLblName, Lbl1Name), + Lbl1, + hipe_rtl:mk_branch(Tmp, lt, hipe_rtl:mk_imm(0), FalseLblName, Lbl2Name), + Lbl2, + hipe_rtl:mk_alu(Tmp,Tmp,sub,hipe_rtl:mk_imm(Unit)), + hipe_rtl:mk_goto(LoopLblName)]. + +skip_bits2(Ms, NoOfBits, TrueLblName, FalseLblName) -> + [NewOffset] = create_gcsafe_regs(1), + [TempLbl] = create_lbls(1), + {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms), + ExCode ++ + add_to_offset(NewOffset, NoOfBits, Offset, FalseLblName) ++ + [hipe_rtl:mk_branch(BinSize, 'ltu', NewOffset, FalseLblName, + hipe_rtl:label_name(TempLbl), 0.01), + TempLbl, + update_offset(NewOffset,Ms), + hipe_rtl:mk_goto(TrueLblName)]. + +add_to_offset(Result, Extra, Original, FalseLblName) -> + TrueLbl = hipe_rtl:mk_new_label(), + %% Note: 'ltu' means 'unsigned overflow'. + [hipe_rtl:mk_alub(Result, Extra, 'add', Original, 'ltu', + FalseLblName, hipe_rtl:label_name(TrueLbl)), + TrueLbl]. + +%%%%%%%%%%%%%%%%%%%%%%% Code for start match %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_binary_bytes(Binary, BinSize, Base, Offset, Orig, + TrueLblName, FalseLblName) -> + [OrigOffset,BitSize,BitOffset] = create_gcsafe_regs(3), + [SuccessLbl,SubLbl,OtherLbl,JoinLbl] = create_lbls(4), + [hipe_tagscheme:test_bitstr(Binary, hipe_rtl:label_name(SuccessLbl), + FalseLblName, 0.99), + SuccessLbl, + get_field_from_term({sub_binary, binsize}, Binary, BinSize), + hipe_rtl:mk_alu(BinSize, BinSize, sll, hipe_rtl:mk_imm(?BYTE_SHIFT)), + hipe_tagscheme:test_subbinary(Binary, hipe_rtl:label_name(SubLbl), + hipe_rtl:label_name(OtherLbl)), + SubLbl, + get_field_from_term({sub_binary, offset}, Binary, OrigOffset), + hipe_rtl:mk_alu(Offset, OrigOffset, sll, hipe_rtl:mk_imm(?BYTE_SHIFT)), + get_field_from_term({sub_binary, bitoffset}, Binary, BitOffset), + hipe_rtl:mk_alu(Offset, Offset, add, BitOffset), + get_field_from_term({sub_binary, bitsize}, Binary, BitSize), + hipe_rtl:mk_alu(BinSize, BinSize, add, Offset), + hipe_rtl:mk_alu(BinSize, BinSize, add, BitSize), + get_field_from_term({sub_binary, orig}, Binary, Orig), + hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)), + OtherLbl, + hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)), + hipe_rtl:mk_move(Orig, Binary), + JoinLbl] ++ + get_base(Orig,Base) ++ + [hipe_rtl:mk_goto(TrueLblName)]. + +%%%%%%%%%%%%%%%%%%%%%%%%% UTILS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_base(Orig,Base) -> + [HeapLbl,REFCLbl,EndLbl] = create_lbls(3), + [hipe_tagscheme:test_heap_binary(Orig, hipe_rtl:label_name(HeapLbl), + hipe_rtl:label_name(REFCLbl)), + HeapLbl, + hipe_rtl:mk_alu(Base, Orig, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)), + hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)), + REFCLbl, + hipe_rtl:mk_load(Base, Orig, hipe_rtl:mk_imm(?PROC_BIN_BYTES-2)), + EndLbl]. + +extract_matchstate_var(binsize, Ms) -> + BinSize = hipe_rtl:mk_new_reg_gcsafe(), + {BinSize, + get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize)}; +extract_matchstate_var(offset, Ms) -> + Offset = hipe_rtl:mk_new_reg_gcsafe(), + {Offset, + get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Offset)}; +extract_matchstate_var(base, Ms) -> + Base = hipe_rtl:mk_new_reg(), + {Base, + get_field_from_term({matchstate, {matchbuffer, base}}, Ms, Base)}; +extract_matchstate_var(orig, Ms) -> + Orig = hipe_rtl:mk_new_var(), + {Orig, + get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig)}. + +extract_matchstate_vars(List, Ms) -> + lists:unzip([extract_matchstate_var(Name, Ms) || Name <- List]). + +check_size(Offset, Size, BinSize, Tmp1, ContLblName, FalseLblName) -> + [add_to_offset(Tmp1, Offset, Size, FalseLblName), + hipe_rtl:mk_branch(Tmp1, leu, BinSize, ContLblName, FalseLblName, 0.99)]. + +check_size(Offset, Size, _BinSize, Tmp1, true, ContLblName, _FalseLblName) -> + [hipe_rtl:mk_alu(Tmp1, Offset, add, Size), + hipe_rtl:mk_goto(ContLblName)]; +check_size(Offset, Size, BinSize, Tmp1, false, ContLblName, FalseLblName) -> + check_size(Offset, Size, BinSize, Tmp1, ContLblName, FalseLblName). + +shift_type(true) -> + sra; +shift_type(false) -> + srl. + +get_type(true, LittleEndian) -> + {signed, endianess(LittleEndian)}; +get_type(false, LittleEndian) -> + {unsigned, endianess(LittleEndian)}. + +endianess(true) -> + little; +endianess(false) -> + big. + +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. + +signed(Flags) -> + case Flags band 4 of + 4 -> true; + 0 -> false + end. + +unsafe(Flags) -> + case Flags band 16 of + 16 -> true; + 0 -> false + end. + +update_offset(NewOffset, Ms) -> + set_field_from_term({matchstate,{matchbuffer,offset}}, + Ms, NewOffset). + +opt_update_ms([NewMs], OldMs) -> + [hipe_rtl:mk_move(NewMs, OldMs)]; +opt_update_ms([], _OldMs) -> + []. + +update_ms(NewMs, OldMs) -> + [hipe_rtl:mk_move(NewMs, OldMs)]. + +create_lbls(0) -> + []; +create_lbls(X) when X > 0-> + [hipe_rtl:mk_new_label()|create_lbls(X-1)]. + +make_dyn_prep(SizeReg, CCode) -> + [CLbl, SuccessLbl] = create_lbls(2), + Init = [hipe_rtl:mk_branch(SizeReg, le, hipe_rtl:mk_imm(?MAX_SMALL_BITS), + hipe_rtl:label_name(SuccessLbl), + hipe_rtl:label_name(CLbl)), + SuccessLbl], + End = [CLbl|CCode], + {Init, End}. + +%%------------------------------------------------------------------------ +%% From hipe_rtl_binutil.erl +%%------------------------------------------------------------------------ + +get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) -> + [Reg] = create_regs(1), + [get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type), + do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)]. + +get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) -> + [LowBits] = create_regs(1), + [AlignedLbl, UnAlignedLbl, EndLbl] = create_lbls(3), + [hipe_rtl:mk_alub(LowBits, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS), + eq, hipe_rtl:label_name(AlignedLbl), + hipe_rtl:label_name(UnAlignedLbl)), + AlignedLbl, + get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type), + hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)), + UnAlignedLbl, + get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type), + EndLbl]. + +get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type) -> + [ByteOffset, ShiftBits, LoadDst, Tmp, TotBits] = create_gcsafe_regs(5), + [MoreLbl, LessLbl, JoinLbl] = create_lbls(3), + WordSize = hipe_rtl_arch:word_size(), + MinLoad = (Size-1) div ?BYTE_SIZE +1, + MaxLoad = MinLoad + 1, + Code1 = + [hipe_rtl:mk_alu(TotBits, LowBits, 'add', hipe_rtl:mk_imm(Size)), + hipe_rtl:mk_alu(ByteOffset, Offset, 'srl', hipe_rtl:mk_imm(?BYTE_SHIFT))], + Code2 = + case {Size rem ?BYTE_SIZE, MinLoad} of + {1, _} -> + [load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad), + hipe_rtl:mk_alu(ShiftBits, LowBits, 'add', + hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE))]; + {_, WordSize} -> + UnsignedBig = {unsigned, big}, + [hipe_rtl:mk_branch(TotBits, le, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE), + hipe_rtl:label_name(LessLbl), + hipe_rtl:label_name(MoreLbl)), + LessLbl, + load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad), + hipe_rtl:mk_alu(ShiftBits, LowBits, 'add', + hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE)), + hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)), + MoreLbl, + load_bytes(LoadDst, Base, ByteOffset, UnsignedBig, MinLoad), + hipe_rtl:mk_alu(LoadDst, LoadDst, 'sll', LowBits), + load_bytes(Tmp, Base, ByteOffset, UnsignedBig, 1), + hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', LowBits), + hipe_rtl:mk_alu(Tmp, Tmp, 'srl', LowBits), + hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp), + hipe_rtl:mk_move(ShiftBits, hipe_rtl:mk_imm(0)), + JoinLbl]; + {_, _} -> + [load_bytes(LoadDst, Base, ByteOffset, Type, MaxLoad), + hipe_rtl:mk_alu(ShiftBits, LowBits, 'add', + hipe_rtl:mk_imm((WordSize-MaxLoad)*?BYTE_SIZE))] + end, + Code3 = + [hipe_rtl:mk_alu(Tmp, LoadDst, sll, ShiftBits), + hipe_rtl:mk_alu(Reg, Tmp, Shiftr, + hipe_rtl:mk_imm(WordSize*?BYTE_SIZE-Size))], + Code1 ++ Code2 ++ Code3. + +get_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) -> + [Reg] = create_gcsafe_regs(1), + [get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type), + do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)]. + +get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) -> + [ByteOffset] = create_gcsafe_regs(1), + Code1 = + [hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + load_bytes(Reg, Base, ByteOffset, Type, ((Size-1) div ?BYTE_SIZE +1))], + Code2 = + case Size rem ?BYTE_SIZE of + 0 -> + []; + _ -> + [hipe_rtl:mk_alu(Reg, Reg, Shiftr, + hipe_rtl:mk_imm(?BYTE_SIZE -Size rem ?BYTE_SIZE))] + end, + Code1 ++ Code2. + +get_big_unknown_int(Dst1, Base, Offset, NewOffset, + Shiftr, Type, TrueLblName) -> + [LoadDst, ByteOffset, Limit, Tmp, LowBits] = create_gcsafe_regs(5), + [ContLbl, BackLbl, LoopLbl, TagLbl, LastLbl, EndLbl] = create_lbls(6), + [hipe_rtl:mk_move(LoadDst, hipe_rtl:mk_imm(0)), + hipe_rtl:mk_branch(NewOffset, ne, Offset, hipe_rtl:label_name(ContLbl), + hipe_rtl:label_name(TagLbl), 0.99), + ContLbl, + hipe_rtl:mk_alu(Limit, NewOffset, sub, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_alu(Limit, Limit, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + load_bytes(LoadDst, Base, ByteOffset, Type, 1), + BackLbl, + hipe_rtl:mk_branch(ByteOffset, le, Limit, hipe_rtl:label_name(LoopLbl), + hipe_rtl:label_name(EndLbl)), + LoopLbl, + load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1), + hipe_rtl:mk_alu(LoadDst, LoadDst, sll, hipe_rtl:mk_imm(?BYTE_SIZE)), + hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp), + hipe_rtl:mk_goto(hipe_rtl:label_name(BackLbl)), + EndLbl, + hipe_rtl:mk_alub(LowBits, NewOffset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq, + hipe_rtl:label_name(TagLbl), hipe_rtl:label_name(LastLbl)), + LastLbl, + hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', LowBits), + hipe_rtl:mk_alu(LoadDst, LoadDst, Shiftr, LowBits), + TagLbl] ++ + do_bignum_code(64, Type, LoadDst, Dst1, TrueLblName). + +get_little_unknown_int(Dst1, Base, Offset, NewOffset, + Shiftr, Type, TrueLblName) -> + [LoadDst, ByteOffset, Limit, ShiftReg, LowBits, Tmp] = create_gcsafe_regs(6), + [ContLbl, BackLbl, LoopLbl, DoneLbl, TagLbl] = create_lbls(5), + [hipe_rtl:mk_move(LoadDst, hipe_rtl:mk_imm(0)), + hipe_rtl:mk_branch(NewOffset, ne, Offset, hipe_rtl:label_name(ContLbl), + hipe_rtl:label_name(TagLbl), 0.99), + ContLbl, + hipe_rtl:mk_alu(Tmp, NewOffset, sub, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + hipe_rtl:mk_alu(Limit, Tmp, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)), + hipe_rtl:mk_move(ShiftReg, hipe_rtl:mk_imm(0)), + BackLbl, + hipe_rtl:mk_branch(ByteOffset, lt, Limit, + hipe_rtl:label_name(LoopLbl), + hipe_rtl:label_name(DoneLbl)), + LoopLbl, + load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1), + hipe_rtl:mk_alu(Tmp, Tmp, sll, ShiftReg), + hipe_rtl:mk_alu(ShiftReg, ShiftReg, add, hipe_rtl:mk_imm(?BYTE_SIZE)), + hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp), + hipe_rtl:mk_goto(hipe_rtl:label_name(BackLbl)), + DoneLbl, + hipe_rtl:mk_alu(LowBits, NewOffset, 'and', hipe_rtl:mk_imm(?LOW_BITS)), + hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), sub, LowBits), + hipe_rtl:mk_alu(LowBits, LowBits, 'and', hipe_rtl:mk_imm(?LOW_BITS)), + load_bytes(Tmp, Base, ByteOffset, Type, 1), + hipe_rtl:mk_alu(Tmp, Tmp, Shiftr, LowBits), + hipe_rtl:mk_alu(Tmp, Tmp, sll, ShiftReg), + hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp), + TagLbl] ++ + do_bignum_code(64, Type, LoadDst, Dst1, TrueLblName). + +do_bignum_code(Size, {Signedness,_}, Src, Dst1, TrueLblName) + when is_integer(Size) -> + case {Size > ?MAX_SMALL_BITS, Signedness} of + {false, _} -> + [hipe_tagscheme:tag_fixnum(Dst1, Src), + hipe_rtl:mk_goto(TrueLblName)]; + {true, signed} -> + make_int_gc_code(Size) ++ + signed_bignum(Dst1, Src, TrueLblName); + {true, unsigned} -> + make_int_gc_code(Size) ++ + unsigned_bignum(Dst1, Src, TrueLblName) + end. + +signed_bignum(Dst1, Src, TrueLblName) -> + Tmp1 = hipe_rtl:mk_new_reg(), + BignumLabel = hipe_rtl:mk_new_label(), + [hipe_tagscheme:realtag_fixnum(Dst1, Src), + hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1), + hipe_rtl:mk_branch(Tmp1, eq, Src, TrueLblName, + hipe_rtl:label_name(BignumLabel)), + BignumLabel, + hipe_tagscheme:unsafe_mk_big(Dst1, Src, signed), + hipe_rtl:mk_goto(TrueLblName)]. + +unsigned_bignum(Dst1, Src, TrueLblName) -> + Tmp1 = hipe_rtl:mk_new_reg_gcsafe(), + BignumLbl = hipe_rtl:mk_new_label(), + BignumLblName = hipe_rtl:label_name(BignumLbl), + NxtLbl = hipe_rtl:mk_new_label(), + NxtLblName = hipe_rtl:label_name(NxtLbl), + [hipe_rtl:mk_branch(Src, lt, hipe_rtl:mk_imm(0), BignumLblName, NxtLblName), + NxtLbl, + hipe_tagscheme:realtag_fixnum(Dst1, Src), + hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1), + hipe_rtl:mk_branch(Tmp1, eq, Src, TrueLblName, BignumLblName), + BignumLbl, + hipe_tagscheme:unsafe_mk_big(Dst1, Src, unsigned), + hipe_rtl:mk_goto(TrueLblName)]. + +load_bytes(Dst, Base, Offset, {Signedness, _Endianess},1) -> + [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))]; +load_bytes(Dst, Base, Offset, {Signedness, Endianess},2) -> + case Endianess of + big -> + hipe_rtl_arch:load_big_2(Dst, Base, Offset, Signedness); + little -> + hipe_rtl_arch:load_little_2(Dst, Base, Offset, Signedness) + end; +load_bytes(Dst, Base, Offset, {Signedness, Endianess},3) -> + Tmp1 = hipe_rtl:mk_new_reg(), + case Endianess of + big -> + [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)), + hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned), + hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)), + hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned), + hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))]; + little -> + [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_load(Tmp1, Base, Offset, byte,unsigned), + hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)), + hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_load(Tmp1, Base, Offset, byte,Signedness), + hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(16)), + hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))] + end; +load_bytes(Dst, Base, Offset, {Signedness, Endianess}, 4) -> + case Endianess of + big -> + hipe_rtl_arch:load_big_4(Dst, Base, Offset, Signedness); + little -> + hipe_rtl_arch:load_little_4(Dst, Base, Offset, Signedness) + end; + +load_bytes(Dst, Base, Offset, {Signedness, Endianess}, X) when X > 1 -> + [LoopLbl, EndLbl] = create_lbls(2), + [Tmp1, Limit, TmpOffset] = create_regs(3), + case Endianess of + big -> + [hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)), + hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), + LoopLbl, + hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned), + hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)), + hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), + hipe_rtl:mk_branch(Offset, lt, Limit, hipe_rtl:label_name(LoopLbl), + hipe_rtl:label_name(EndLbl)), + EndLbl]; + little -> + [hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)), + hipe_rtl:mk_alu(TmpOffset, Limit, sub, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_load(Dst, Base, TmpOffset, byte, Signedness), + LoopLbl, + hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)), + hipe_rtl:mk_load(Tmp1, Base, TmpOffset, byte, Signedness), + hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)), + hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1), + hipe_rtl:mk_branch(Offset, lt, TmpOffset, hipe_rtl:label_name(LoopLbl), + hipe_rtl:label_name(EndLbl)), + EndLbl, + hipe_rtl:mk_move(Offset, Limit)] + end. + +create_regs(X) when X > 0 -> + [hipe_rtl:mk_new_reg()|create_regs(X-1)]; +create_regs(0) -> + []. + +create_gcsafe_regs(X) when X > 0 -> + [hipe_rtl:mk_new_reg_gcsafe()|create_gcsafe_regs(X-1)]; +create_gcsafe_regs(0) -> + []. + +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)]. + +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, hipe_rtl:mk_imm(?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))). + +is_illegal_const(Const) -> + Const >= 1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0. |