aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
authorMagnus Lång <[email protected]>2015-11-20 14:38:13 +0100
committerMagnus Lång <[email protected]>2015-11-27 18:18:38 +0100
commitd5a877aeb8e7845bf92469456a8246cb62cd7036 (patch)
tree5bb42391f5cf1b93ff7ab044288bd0019c4d040a /lib/hipe
parent4ce3f357aca2b418dda22ce5434b080ba41ffa45 (diff)
downloadotp-d5a877aeb8e7845bf92469456a8246cb62cd7036.tar.gz
otp-d5a877aeb8e7845bf92469456a8246cb62cd7036.tar.bz2
otp-d5a877aeb8e7845bf92469456a8246cb62cd7036.zip
hipe: Fix constructing huge binaries
Bugs were fixed in hipe_rtl_binary_match:{first_part/3,make_size/3,set_high/1} in commit 5aea81c49, but it turns out these had been copy-pasted verbatim into hipe_rtl_binary_construct, where they were causing further bugs. They have now moved to hipe_rtl_binary, from where they are included by the other two modules. Furthermore, first_part/3 (reamed get_word_integer/3, since it loads integers that fits into an unsigned word), and make_size/3 now accepts a fourth argument to distinguish too large arguments (which should cause a system_limit exception) from negative or non-integral arguments. The use of first_part/3 (get_word_integer/3) from 5aea81c49 in hipe_rtl_binary_construct now allows several binary construction instructions to accept bignum sizes, as they were supposed to. Additionally, calls to hipe_rtl_binary_construct:check_and_untag_fixnum/3 were replaced with get_word_integer/4 since all of them were also supposed to accept sufficiently small bignums, but didn't, and check_and_untag_fixnum/3 was essentially identical to first_part/3 anyway. HiPE is now capable of passing bs_construct_SUITE completely unmodified.
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary.erl142
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl131
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl100
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl23
4 files changed, 176 insertions, 220 deletions
diff --git a/lib/hipe/rtl/hipe_rtl_binary.erl b/lib/hipe/rtl/hipe_rtl_binary.erl
index 4525994f7d..9cbab08ee2 100644
--- a/lib/hipe/rtl/hipe_rtl_binary.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary.erl
@@ -1,3 +1,4 @@
+%% -*- erlang-indent-level: 2 -*-
%%%
%%% %CopyrightBegin%
%%%
@@ -28,11 +29,20 @@
-export([gen_rtl/7]).
+-export([floorlog2/1, get_word_integer/4, make_size/3, make_size/4]).
+
+%%--------------------------------------------------------------------
+
+-define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa
+-define(BYTE_SIZE, 8).
+
+%%--------------------------------------------------------------------
+
gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab) ->
case type_of_operation(BsOP) of
match ->
{hipe_rtl_binary_match:gen_rtl(
- BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab};
+ BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab};
construct ->
hipe_rtl_binary_construct:gen_rtl(
BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab)
@@ -79,3 +89,133 @@ type_of_operation(bs_final) -> construct;
type_of_operation({bs_append,_,_,_,_}) -> construct;
type_of_operation({bs_private_append,_,_}) -> construct;
type_of_operation(bs_init_writable) -> construct.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Small utility functions:
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+create_lbls(X) when X > 0 ->
+ [hipe_rtl:mk_new_label()|create_lbls(X-1)];
+create_lbls(0) ->
+ [].
+
+%%------------------------------------------------------------------------------
+%% Utilities used by both hipe_rtl_binary_construct and hipe_rtl_binary_match
+%%------------------------------------------------------------------------------
+
+get_word_integer(Var, Register, SystemLimitLblName, FalseLblName) ->
+ [EndLbl] = create_lbls(1),
+ EndName = hipe_rtl:label_name(EndLbl),
+ get_word_integer(Var, Register,SystemLimitLblName, FalseLblName, EndName, EndName,
+ [EndLbl]).
+
+get_word_integer(Var, Register, SystemLimitLblName, FalseLblName, TrueLblName,
+ BigLblName, Tail) ->
+ [FixnumLbl, NotFixnumLbl, BignumLbl, SuccessLbl] = create_lbls(4),
+ [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(FixnumLbl),
+ hipe_rtl:label_name(NotFixnumLbl), 0.99),
+ FixnumLbl,
+ hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
+ hipe_rtl:label_name(SuccessLbl), FalseLblName,
+ 0.99),
+ SuccessLbl,
+ hipe_tagscheme:untag_fixnum(Register, Var),
+ hipe_rtl:mk_goto(TrueLblName),
+ NotFixnumLbl,
+ hipe_tagscheme:test_pos_bignum_arity(Var, 1, hipe_rtl:label_name(BignumLbl),
+ FalseLblName, SystemLimitLblName, 0.99),
+ BignumLbl,
+ hipe_tagscheme:unsafe_get_one_word_pos_bignum(Register, Var),
+ hipe_rtl:mk_goto(BigLblName) | Tail].
+
+make_size(UnitImm, BitsVar, FailLblName) ->
+ make_size(UnitImm, BitsVar, FailLblName, FailLblName).
+
+make_size(1, BitsVar, OverflowLblName, FalseLblName) ->
+ DstReg = hipe_rtl:mk_new_reg_gcsafe(),
+ {get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName), DstReg};
+make_size(?BYTE_SIZE, BitsVar, OverflowLblName, FalseLblName) ->
+ DstReg = hipe_rtl:mk_new_reg_gcsafe(),
+ [FixnumLbl, BignumLbl] = create_lbls(2),
+ WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
+ FixnumLblName = hipe_rtl:label_name(FixnumLbl),
+ Tail = [BignumLbl,
+ hipe_rtl:mk_branch(DstReg, 'ltu',
+ hipe_rtl:mk_imm(1 bsl (WordBits - ?BYTE_SHIFT)),
+ FixnumLblName, OverflowLblName, 0.99),
+ FixnumLbl,
+ hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
+ Code = get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName,
+ FixnumLblName, hipe_rtl:label_name(BignumLbl), Tail),
+ {Code, DstReg};
+make_size(UnitImm, BitsVar, OverflowLblName, FalseLblName) ->
+ DstReg = hipe_rtl:mk_new_reg_gcsafe(),
+ UnitList = number2list(UnitImm),
+ Code = multiply_code(UnitList, BitsVar, DstReg, OverflowLblName, FalseLblName),
+ {Code, DstReg}.
+
+multiply_code(List=[Head|_Tail], Variable, Result, OverflowLblName,
+ 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))|
+ get_word_integer(Variable, Register, OverflowLblName, FalseLblName)]
+ ++
+ [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test),
+ eq, hipe_rtl:label_name(SuccessLbl),
+ OverflowLblName, 0.99),
+ SuccessLbl],
+ multiply_code(List, Register, Result, OverflowLblName, Tmp1, Code).
+
+multiply_code([ShiftSize|Rest], Register, Result, OverflowLblName, 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), OverflowLblName, 0.99),
+ SuccessLbl],
+ multiply_code(Rest, Register, Result, OverflowLblName, Tmp1, Code);
+multiply_code([], _Register, _Result, _OverflowLblName, _Tmp1, Code) ->
+ Code.
+
+set_high(X) ->
+ WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
+ set_high(min(X, WordBits), WordBits, 0).
+
+set_high(0, _, Y) ->
+ Y;
+set_high(X, WordBits, Y) ->
+ set_high(X-1, WordBits, Y+(1 bsl (WordBits-X))).
+
+
+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) ->
+ %% Double-precision floats do not have enough precision to make floorlog2
+ %% exact for integers larger than 2^47.
+ Approx = round(math:log(X)/math:log(2)-0.5),
+ floorlog2_refine(X, Approx).
+
+floorlog2_refine(X, Approx) ->
+ if (1 bsl Approx) > X ->
+ floorlog2_refine(X, Approx - 1);
+ (1 bsl (Approx+1)) > X ->
+ Approx;
+ true ->
+ floorlog2_refine(X, Approx + 1)
+ end.
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index 1a78320592..80436a6931 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -34,6 +34,10 @@
get_field_from_term/3,
set_field_from_pointer/3,
get_field_from_pointer/3]).
+
+-import(hipe_rtl_binary, [floorlog2/1,
+ get_word_integer/4,
+ make_size/4]).
%%-------------------------------------------------------------------------
-include("../main/hipe.hrl").
@@ -111,7 +115,9 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
put_static_binary(NewOffset, Src, Size, Base, Offset,
TrueLblName, FalseLblName);
[Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName),
+ {SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
+ FalseLblName),
InCode = put_dynamic_binary(NewOffset, Src, SizeReg, Base,
Offset, TrueLblName, FalseLblName),
SizeCode ++ InCode
@@ -133,7 +139,9 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
put_float(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
LittleEndian, ConstInfo, TrueLblName);
[Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName),
+ {SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
+ FalseLblName),
InCode = float_c_code(NewOffset, Src, Base, Offset, SizeReg,
Flags, TrueLblName, FalseLblName),
SizeCode ++ InCode
@@ -162,6 +170,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
CCode, Aligned, LittleEndian, TrueLblName);
[Src, Bits, Base, Offset] ->
{SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
FalseLblName),
CCode = int_c_code(NewOffset, Src, Base,
Offset, SizeReg, Flags,
@@ -210,6 +219,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
TrueLblName);
[Src, Bits, Base, Offset] ->
{SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
FalseLblName),
CCode = int_c_code(NewOffset, Src, Base,
Offset, SizeReg, Flags,
@@ -294,7 +304,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
[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),
+ get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
allocate_writable(DstVar, Base, SizeReg, Zero, Zero),
hipe_rtl:mk_goto(TrueLblName)];
@@ -306,7 +316,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
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),
+ get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
realloc_binary(SizeReg, ProcBin, Base),
calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
set_field_from_term(SubBinSize, Bin, EndSubSize),
@@ -328,7 +338,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
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),
+ get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
hipe_tagscheme:test_bitstr(Bin, ContLblName, FalseLblName, 0.99),
ContLbl,
hipe_tagscheme:test_subbinary(Bin,ContLbl2Name, NotWritable),
@@ -401,16 +411,6 @@ allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
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] =
@@ -673,7 +673,7 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName
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),
+ [get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE),
hipe_rtl:label_name(ContLbl),
SystemLimitLblName),
@@ -709,7 +709,7 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl
?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),
+ get_word_integer(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),
@@ -1286,103 +1286,6 @@ copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
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) ->
- %% Double-precision floats do not have enough precision to make floorlog2
- %% exact for integers larger than 2^47.
- Approx = round(math:log(X)/math:log(2)-0.5),
- floorlog2_refine(X, Approx).
-
-floorlog2_refine(X, Approx) ->
- if (1 bsl Approx) > X ->
- floorlog2_refine(X, Approx - 1);
- (1 bsl (Approx+1)) > X ->
- Approx;
- true ->
- floorlog2_refine(X, Approx + 1)
- end.
-
-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)].
-
is_divisible(_Dividend, 1, SuccLbl, _FailLbl) ->
[hipe_rtl:mk_goto(SuccLbl)];
is_divisible(Dividend, Divisor, SuccLbl, FailLbl) ->
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 51213b71d1..b385ea6afc 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -31,6 +31,8 @@
-import(hipe_tagscheme, [set_field_from_term/3, get_field_from_term/3]).
+-import(hipe_rtl_binary, [make_size/3]).
+
-include("hipe_literals.hrl").
%%--------------------------------------------------------------------
@@ -1100,103 +1102,5 @@ create_gcsafe_regs(X) when X > 0 ->
create_gcsafe_regs(0) ->
[].
-first_part(Var, Register, FalseLblName) ->
- [EndLbl] = create_lbls(1),
- EndName = hipe_rtl:label_name(EndLbl),
- first_part(Var, Register, FalseLblName, EndName, EndName, [EndLbl]).
-
-first_part(Var, Register, FalseLblName, TrueLblName, BigLblName, Tail) ->
- [FixnumLbl, NotFixnumLbl, BignumLbl, SuccessLbl] = create_lbls(4),
- [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(FixnumLbl),
- hipe_rtl:label_name(NotFixnumLbl), 0.99),
- FixnumLbl,
- hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
- hipe_rtl:label_name(SuccessLbl), FalseLblName,
- 0.99),
- SuccessLbl,
- hipe_tagscheme:untag_fixnum(Register, Var),
- hipe_rtl:mk_goto(TrueLblName),
- NotFixnumLbl,
- %% Since binaries are not allowed to be larger than 2^wordsize bits
- %% and since bignum digits are words, we know that a bignum with an
- %% arity larger than one can't match.
- hipe_tagscheme:test_pos_bignum_arity(Var, 1, hipe_rtl:label_name(BignumLbl),
- FalseLblName, 0.99),
- BignumLbl,
- hipe_tagscheme:unsafe_get_one_word_pos_bignum(Register, Var),
- hipe_rtl:mk_goto(BigLblName) | Tail].
-
-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),
- [FixnumLbl, BignumLbl] = create_lbls(2),
- WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
- FixnumLblName = hipe_rtl:label_name(FixnumLbl),
- Tail = [BignumLbl,
- hipe_rtl:mk_branch(DstReg, 'ltu',
- hipe_rtl:mk_imm(1 bsl (WordBits - ?BYTE_SHIFT)),
- FixnumLblName, FalseLblName, 0.99),
- FixnumLbl,
- hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
- Code = first_part(BitsVar, DstReg, FalseLblName, FixnumLblName,
- hipe_rtl:label_name(BignumLbl), Tail),
- {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) ->
- WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
- set_high(min(X, WordBits), WordBits, 0).
-
-set_high(0, _, Y) ->
- Y;
-set_high(X, WordBits, Y) ->
- set_high(X-1, WordBits, Y+(1 bsl (WordBits-X))).
-
is_illegal_const(Const) ->
Const >= 1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index d77078acb6..8825a3ade3 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -42,7 +42,7 @@
test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
test_binary/4, test_bitstr/4, test_list/4, test_map/4,
test_integer/4, test_number/4, test_tuple_N/5,
- test_pos_bignum_arity/5]).
+ test_pos_bignum_arity/6]).
-export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
-export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
unsafe_fixnum_sub/3,
@@ -351,14 +351,23 @@ test_pos_bignum(X, TrueLab, FalseLab, Pred) ->
mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
TrueLab, FalseLab, Pred)].
-test_pos_bignum_arity(X, Arity, TrueLab, FalseLab, Pred) ->
+test_pos_bignum_arity(X, Arity, TrueLab, NotPosBignumLab, FalseLab, Pred) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
+ BoxedLab = hipe_rtl:mk_new_label(),
HeaderImm = hipe_rtl:mk_imm(mk_header(Arity, ?TAG_HEADER_POS_BIG)),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- hipe_rtl:mk_branch(Tmp, 'eq', HeaderImm, TrueLab, FalseLab, Pred)].
+ [test_is_boxed(X, hipe_rtl:label_name(BoxedLab), NotPosBignumLab, Pred),
+ BoxedLab,
+ get_header(Tmp, X)] ++
+ case NotPosBignumLab =:= FalseLab of
+ true -> [];
+ false ->
+ BignumLab = hipe_rtl:mk_new_label(),
+ BigMask = ?TAG_HEADER_MASK,
+ [mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
+ hipe_rtl:label_name(BignumLab), NotPosBignumLab, Pred),
+ BignumLab]
+ end ++
+ [hipe_rtl:mk_branch(Tmp, 'eq', HeaderImm, TrueLab, FalseLab, Pred)].
test_matchstate(X, TrueLab, FalseLab, Pred) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),