summaryrefslogtreecommitdiff
path: root/lib/compiler/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/Makefile2
-rw-r--r--lib/compiler/src/beam_bounds.erl23
-rw-r--r--lib/compiler/src/beam_ssa_pre_codegen.erl2
-rw-r--r--lib/compiler/src/beam_validator.erl8
4 files changed, 31 insertions, 4 deletions
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 82b0a12a7d..e0625337b5 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -157,7 +157,7 @@ docs:
clean:
rm -f $(TARGET_FILES)
- rm -f $(EGEN)/beam_opcodes.erl $(EGEN)/beam_opcodes.hrl
+ rm -f $(EGEN)/beam_opcodes.erl $(EGEN)/beam_opcodes.hrl $(EGEN)/OPCODES-GENERATED
rm -f $(EGEN)/core_parse.erl
rm -f core
diff --git a/lib/compiler/src/beam_bounds.erl b/lib/compiler/src/beam_bounds.erl
index 6f3902596e..6ac5141821 100644
--- a/lib/compiler/src/beam_bounds.erl
+++ b/lib/compiler/src/beam_bounds.erl
@@ -46,7 +46,28 @@
bounds('bnot', R0) ->
case R0 of
- {A,B} ->
+ {A, B} when is_integer(A), is_integer(B), A =/= B ->
+ %% While it's easy to get an exact range, doing so can make certain
+ %% chains of operations slow to converge, e.g.
+ %%
+ %% f(0) -> -1; f(N) -> abs(bnot f(N)).
+ %%
+ %% Where the range increases by 1 every time we pass through,
+ %% making it more or less impossible to reach a fixpoint.
+ %%
+ %% We therefore widen the range a bit quicker to ensure that we
+ %% converge on 'any' within a reasonable time frame, hoping that
+ %% the range will still be tight enough in the cases where we
+ %% don't feed the result into itself.
+ case {abs(A) bsr ?NUM_BITS, abs(B) bsr ?NUM_BITS} of
+ {0, 0} ->
+ Min = min(-B - 1, -(B bsl 1) - 1),
+ Max = max(-A - 1, -(A bsl 1) - 1),
+ normalize({Min, Max});
+ {_, _} ->
+ any
+ end;
+ {A, B} ->
R = {inf_add(inf_neg(B), -1), inf_add(inf_neg(A), -1)},
normalize(R);
_ ->
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
index e3406f12de..dc76755aad 100644
--- a/lib/compiler/src/beam_ssa_pre_codegen.erl
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -680,7 +680,7 @@ sanitize([L|Ls], InBlocks, Count0, Values0, Blocks0) ->
no_change ->
Blk = sanitize_last(Blk0, Values0),
Blocks1 = Blocks0#{L := Blk},
- Blocks = sanitize_reachable(Blk0, Blocks1),
+ Blocks = sanitize_reachable(Blk, Blocks1),
sanitize(Ls, InBlocks, Count0, Values0, Blocks);
{Is,Last,Count,Values} ->
Blk1 = Blk0#b_blk{is=Is,last=Last},
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index f19ea897fe..285db8a26a 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -2830,7 +2830,13 @@ unpack_typed_arg(#tr{r=Reg,t=Type}, Vst) ->
%% The validator is not yet clever enough to do proper range analysis like
%% the main type pass, so our types will be a bit cruder here, but they
%% should at the very least not be in direct conflict.
- true = none =/= beam_types:meet(get_movable_term_type(Reg, Vst), Type),
+ Current = get_movable_term_type(Reg, Vst),
+ case beam_types:meet(Current, Type) of
+ none ->
+ throw({bad_typed_register, Current, Type});
+ _ ->
+ ok
+ end,
Reg;
unpack_typed_arg(Arg, _Vst) ->
Arg.