Skip to content

Commit

Permalink
[vm/compiler] DIV/MOD magic for ARM64
Browse files Browse the repository at this point in the history
Rationale:
Follow up on prior CL, now with the ARM64 version.
Unit tests were included in that previous CL.
(https://dart-review.googlesource.com/c/sdk/+/114901)

#37789

Change-Id: I6177b48743cd615914dbfbddab166a6c71ef71c7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115064
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Aart Bik <ajcbik@google.com>
  • Loading branch information
aartbik authored and commit-bot@chromium.org committed Sep 10, 2019
1 parent 03b1951 commit 13ba681
Showing 1 changed file with 49 additions and 0 deletions.
49 changes: 49 additions & 0 deletions runtime/vm/compiler/backend/il_arm64.cc
Expand Up @@ -5419,6 +5419,55 @@ static void EmitInt64ModTruncDiv(FlowGraphCompiler* compiler,
Register out) {
ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);

// Special case 64-bit div/mod by compile-time constant. Note that various
// special constants (such as powers of two) should have been optimized
// earlier in the pipeline. Div or mod by zero falls into general code
// to implement the exception.
if (FLAG_optimization_level <= 2) {
// We only consider magic operations under O3.
} else if (auto c = instruction->right()->definition()->AsConstant()) {
if (c->value().IsInteger()) {
const int64_t divisor = Integer::Cast(c->value()).AsInt64Value();
if (divisor <= -2 || divisor >= 2) {
// For x DIV c or x MOD c: use magic operations.
compiler::Label pos;
int64_t magic = 0;
int64_t shift = 0;
Utils::CalculateMagicAndShiftForDivRem(divisor, &magic, &shift);
// Compute tmp = high(magic * numerator).
__ LoadImmediate(TMP2, magic);
__ smulh(TMP2, TMP2, left);
// Compute tmp +/-= numerator.
if (divisor > 0 && magic < 0) {
__ add(TMP2, TMP2, compiler::Operand(left));
} else if (divisor < 0 && magic > 0) {
__ sub(TMP2, TMP2, compiler::Operand(left));
}
// Shift if needed.
if (shift != 0) {
__ add(TMP2, ZR, compiler::Operand(TMP2, ASR, shift));
}
// Finalize DIV or MOD.
if (op_kind == Token::kTRUNCDIV) {
__ sub(out, TMP2, compiler::Operand(TMP2, ASR, 63));
} else {
__ sub(TMP2, TMP2, compiler::Operand(TMP2, ASR, 63));
__ LoadImmediate(TMP, divisor);
__ msub(out, TMP2, TMP, left);
// Compensate for Dart's Euclidean view of MOD.
__ CompareRegisters(out, ZR);
if (divisor > 0) {
__ add(TMP2, out, compiler::Operand(TMP));
} else {
__ sub(TMP2, out, compiler::Operand(TMP));
}
__ csel(out, TMP2, out, LT);
}
return;
}
}
}

// Prepare a slow path.
Range* right_range = instruction->right()->definition()->range();
Int64DivideSlowPath* slow_path = new (Z) Int64DivideSlowPath(
Expand Down

0 comments on commit 13ba681

Please sign in to comment.