Skip to content

Commit

Permalink
Optimize skipping of a binary segment
Browse files Browse the repository at this point in the history
Combining validation of a the size with the skip operation
makes it possible to reduce the number of instructions.
  • Loading branch information
bjorng committed Aug 30, 2023
1 parent 137302d commit d0b6fb9
Showing 1 changed file with 39 additions and 12 deletions.
51 changes: 39 additions & 12 deletions erts/emulator/beam/jit/arm/instr_bs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Eterm>(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));
Expand Down

0 comments on commit d0b6fb9

Please sign in to comment.