From d0dc1ebc5da30f67cd8a8f9abe5f5a2c8742f681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 20 Mar 2024 08:24:03 +0100 Subject: [PATCH] Fix failing binary match Closes #8280 --- lib/compiler/src/beam_ssa_codegen.erl | 4 ++++ lib/compiler/src/beam_ssa_opt.erl | 13 +++++++++++-- lib/compiler/test/bs_match_SUITE.erl | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl index 6f6de9996268..7879861c097e 100644 --- a/lib/compiler/src/beam_ssa_codegen.erl +++ b/lib/compiler/src/beam_ssa_codegen.erl @@ -2260,6 +2260,10 @@ bs_translate([]) -> []. bs_translate_collect([I|Is]=Is0, Ctx, Fail, Acc) -> case bs_translate_instr(I) of + {Ctx,_,{ensure_at_least,_,_}} -> + %% There should only be a single `ensure_at_least` + %% instruction in each `bs_match` instruction. + {bs_translate_fixup(Acc),Fail,Is0}; {Ctx,Fail,Instr} -> bs_translate_collect(Is, Ctx, Fail, [Instr|Acc]); {Ctx,{f,0},Instr} -> diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl index 13e4114319db..0be627760535 100644 --- a/lib/compiler/src/beam_ssa_opt.erl +++ b/lib/compiler/src/beam_ssa_opt.erl @@ -304,8 +304,8 @@ late_epilogue_passes(Opts) -> ?PASS(ssa_opt_sink), ?PASS(ssa_opt_blockify), ?PASS(ssa_opt_redundant_br), - ?PASS(ssa_opt_bs_ensure), ?PASS(ssa_opt_merge_blocks), + ?PASS(ssa_opt_bs_ensure), ?PASS(ssa_opt_try), ?PASS(ssa_opt_get_tuple_element), ?PASS(ssa_opt_tail_literals), @@ -3325,7 +3325,7 @@ redundant_br_safe_bool(Is, Bool) -> end. %%% -%%% Add the bs_ensure instruction before a sequence of `bs_match` +%%% Add the `bs_ensure` instruction before a sequence of `bs_match` %%% (SSA) instructions, each having a literal size and the %%% same failure label. %%% @@ -3333,6 +3333,15 @@ redundant_br_safe_bool(Is, Bool) -> %%% instruction that can match multiple segments having the same %%% failure label. %%% +%%% It is beneficial but not essential to run this pass after +%%% the `merge_blocks/1` pass. For the following example, two separate +%%% `bs_match/1` instructions will emitted if blocks have not been +%%% merged before this pass: +%%% +%%% A = 0, +%%% B = <<1, 2, 3>>, +%%% <> = <<0, 1, 2, 3>> +%%% ssa_opt_bs_ensure({#opt_st{ssa=Blocks0,cnt=Count0}=St, FuncDb}) when is_map(Blocks0) -> RPO = beam_ssa:rpo(Blocks0), diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index b24f1afdd8e5..45c3ab04a9e5 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -2724,6 +2724,8 @@ bs_match(_Config) -> {'EXIT',{{badmatch,<<>>},_}} = catch do_bs_match_gh_7467(<<>>), + {0,<<1,2,3>>} = do_bs_match_gh_8280(), + ok. do_bs_match_1(_, X) -> @@ -2798,6 +2800,12 @@ do_bs_match_gh_6755(B) -> do_bs_match_gh_7467(A) -> do_bs_match_gh_7467(<<_:1/bits>> = A). +do_bs_match_gh_8280() -> + A = 0, + B = <<1, 2, 3>>, + <> = id(<<0, 1, 2, 3>>), + {A, B}. + %% GH-6348/OTP-18297: Allow aliases for binaries. -record(ba_foo, {a,b,c}).