diff --git a/erts/emulator/beam/jit/arm/instr_bs.cpp b/erts/emulator/beam/jit/arm/instr_bs.cpp index b8ffbad52955..43e0228369ab 100644 --- a/erts/emulator/beam/jit/arm/instr_bs.cpp +++ b/erts/emulator/beam/jit/arm/instr_bs.cpp @@ -870,25 +870,52 @@ void BeamModuleAssembler::emit_i_bs_skip_bits2(const ArgRegister &Ctx, const ArgWord &Unit) { Label fail = resolve_beam_label(Fail, dispUnknown); - bool can_fail = true; - - if (always_small(Size)) { - auto [min, max] = getClampedRange(Size); - can_fail = !(0 <= min && (max >> (SMALL_BITS - ERL_UNIT_BITS)) == 0); - } - - if (!can_fail && Unit.get() == 1) { - comment("simplified skipping because the types are known"); - + if (Support::isPowerOf2(Unit.get())) { + int trailing_bits = Support::ctz(Unit.get()); + arm::Shift shift; + bool type_can_fail = true; const int position_offset = offsetof(ErlBinMatchState, mb.offset); const int size_offset = offsetof(ErlBinMatchState, mb.size); auto [ctx, size] = load_sources(Ctx, TMP1, Size, TMP2); + arm::Gp current_size_reg = size.reg; + + if (always_small(Size)) { + auto [min, max] = getClampedRange(Size); + type_can_fail = + !(0 <= min && (max >> (SMALL_BITS - ERL_UNIT_BITS)) == 0); + } + + if (trailing_bits < _TAG_IMMED1_SIZE) { + shift = arm::lsr(_TAG_IMMED1_SIZE - trailing_bits); + } else if (trailing_bits > _TAG_IMMED1_SIZE) { + shift = arm::lsl(trailing_bits - _TAG_IMMED1_SIZE); + } a.ldur(TMP3, emit_boxed_val(ctx.reg, position_offset)); a.ldur(TMP4, emit_boxed_val(ctx.reg, size_offset)); - a.add(TMP3, TMP3, size.reg, arm::lsr(_TAG_IMMED1_SIZE)); - a.cmp(TMP3, TMP4); + if (type_can_fail || trailing_bits > 0) { + a.eor(ARG1, size.reg, imm(_TAG_IMMED1_SMALL)); + current_size_reg = ARG1; + } + if (type_can_fail) { + ASSERT(current_size_reg == ARG1); + a.tst(ARG1, imm(0xFFF0000000000000UL | _TAG_IMMED1_MASK)); + } else { + comment("skipped type test for known safe size"); + } + + if (trailing_bits == 0) { + a.add(TMP3, TMP3, size.reg, shift); + } else { + a.add(TMP3, TMP3, ARG1, shift); + } + + if (type_can_fail) { + a.ccmp(TMP3, TMP4, imm(NZCV::kCF), arm::CondCode::kEQ); + } else { + a.cmp(TMP3, TMP4); + } a.b_hi(resolve_beam_label(Fail, disp1MB)); a.stur(TMP3, emit_boxed_val(ctx.reg, position_offset));