Skip to content

Commit

Permalink
x86_64: Optimize arithmetic instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Nov 25, 2023
1 parent e1bb0ae commit f79691e
Showing 1 changed file with 46 additions and 37 deletions.
83 changes: 46 additions & 37 deletions erts/emulator/beam/jit/x86/instr_arith.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,31 +174,30 @@ void BeamModuleAssembler::emit_i_plus(const ArgSource &LHS,
const ArgSource &RHS,
const ArgLabel &Fail,
const ArgRegister &Dst) {
bool is_rhs_literal = false;
Sint rhs_untagged;

bool small_result = is_sum_small_if_args_are_small(LHS, RHS);

if (always_small(LHS) && always_small(RHS) && small_result) {
/* Since we don't need the order on this path (no exceptions), we'll
* simplify the code below by shuffling constants to the right-hand
* side. */
const ArgSource A = LHS.isSmall() ? RHS : LHS,
B = LHS.isSmall() ? LHS : RHS;
if (RHS.isSmall()) {
/* Must be signed for the template magic in isInt32 to work for
* negative numbers. */
rhs_untagged = RHS.as<ArgSmall>().getSigned() << _TAG_IMMED1_SIZE;
is_rhs_literal = Support::isInt32(rhs_untagged);
}

if (always_small(LHS) && always_small(RHS) && small_result) {
comment("add without overflow check");
mov_arg(RET, A);

if (B.isSmall()) {
/* Must be signed for the template magic in isInt32 to work for
* negative numbers. */
Sint untagged = B.as<ArgSmall>().getSigned() << _TAG_IMMED1_SIZE;
mov_arg(RET, LHS);

if (Support::isInt32(untagged)) {
a.add(RET, imm(untagged));
} else {
mov_imm(ARG2, B.as<ArgSmall>().get() & ~_TAG_IMMED1_MASK);
a.add(RET, ARG2);
}
if (is_rhs_literal) {
a.add(RET, imm(rhs_untagged));
} else if (RHS.isSmall()) {
mov_imm(ARG2, RHS.as<ArgSmall>().get() & ~_TAG_IMMED1_MASK);
a.add(RET, ARG2);
} else {
mov_arg(ARG2, B);
mov_arg(ARG2, RHS);
a.lea(RET, x86::qword_ptr(RET, ARG2, 0, -_TAG_IMMED1_SMALL));
}

Expand All @@ -216,13 +215,13 @@ void BeamModuleAssembler::emit_i_plus(const ArgSource &LHS,
} else {
emit_are_both_small(mixed, LHS, ARG2, RHS, ARG3);

a.mov(RET, ARG2);
a.and_(RET, imm(~_TAG_IMMED1_MASK));
a.add(RET, ARG3);
if (small_result) {
comment("skipped overflow test because the result is always small");
a.lea(RET, x86::qword_ptr(ARG2, ARG3, 0, -_TAG_IMMED1_SMALL));
a.short_().jmp(next);
} else {
a.lea(RET, x86::qword_ptr(ARG2, -_TAG_IMMED1_SMALL));
a.add(RET, ARG3);
a.short_().jno(next);
}
}
Expand Down Expand Up @@ -297,23 +296,26 @@ void BeamModuleAssembler::emit_i_minus(const ArgSource &LHS,
const ArgSource &RHS,
const ArgLabel &Fail,
const ArgRegister &Dst) {
bool is_rhs_literal = false;
Sint rhs_untagged = 0;
bool small_result = is_diff_small_if_args_are_small(LHS, RHS);

if (RHS.isSmall()) {
/* Must be signed for the template magic in isInt32 to work for
* negative numbers. */
rhs_untagged = RHS.as<ArgSmall>().getSigned() << _TAG_IMMED1_SIZE;
is_rhs_literal = Support::isInt32(rhs_untagged);
}

if (always_small(LHS) && always_small(RHS) && small_result) {
comment("subtract without overflow check");
mov_arg(RET, LHS);

if (RHS.isSmall()) {
/* Must be signed for the template magic in isInt32 to work for
* negative numbers. */
Sint untagged = RHS.as<ArgSmall>().getSigned() << _TAG_IMMED1_SIZE;

if (Support::isInt32(untagged)) {
a.sub(RET, imm(untagged));
} else {
mov_imm(ARG2, RHS.as<ArgSmall>().get() & ~_TAG_IMMED1_MASK);
a.sub(RET, ARG2);
}
if (is_rhs_literal) {
a.sub(RET, imm(rhs_untagged));
} else if (RHS.isSmall()) {
mov_imm(ARG2, RHS.as<ArgSmall>().get() & ~_TAG_IMMED1_MASK);
a.sub(RET, ARG2);
} else {
mov_arg(ARG2, RHS);
a.and_(ARG2, imm(~_TAG_IMMED1_MASK));
Expand All @@ -337,14 +339,21 @@ void BeamModuleAssembler::emit_i_minus(const ArgSource &LHS,
if (small_result) {
comment("skipped overflow test because the result is always small");
a.mov(RET, ARG2);
a.and_(ARG3, imm(~_TAG_IMMED1_MASK));
a.sub(RET, ARG3);
if (is_rhs_literal) {
a.sub(RET, imm(rhs_untagged));
} else {
a.and_(ARG3, imm(~_TAG_IMMED1_MASK));
a.sub(RET, ARG3);
}
a.short_().jmp(next);
} else {
a.mov(RET, ARG2);
a.mov(ARG4, ARG3);
a.and_(ARG4, imm(~_TAG_IMMED1_MASK));
a.sub(RET, ARG4);
if (is_rhs_literal) {
a.sub(RET, imm(rhs_untagged));
} else {
a.lea(ARG4, x86::qword_ptr(ARG3, -_TAG_IMMED1_SMALL));
a.sub(RET, ARG4);
}
a.short_().jno(next);
}
}
Expand Down

0 comments on commit f79691e

Please sign in to comment.