[vm] Faster double.floor()/ceil()/truncate() in AOT mode (x64, arm64)

1) double.truncate() now simply calls toInt(), omitting
truncateToDouble() call.

2) double.floor() and ceil() are now intrinsified on arm64 and AOT/x64
and generated using DoubleToInteger instruction.

3) DoubleToInteger instruction is extended to support floor and ceil.
On arm64 DoubleToInteger is implemented using fcvtms and fcvtps
instructions. On x64 DoubleToInteger is implemented using roundsd
under a check if it is supported (with a fallback to a stub and a
runtime call).

AOT/x64:
Before: BenchFloor(RunTime): 318.82148549569655 us.
After:  BenchFloor(RunTime): 133.29430189936687 us.

TEST=ci
Closes https://github.com/dart-lang/sdk/issues/46876
Closes https://github.com/dart-lang/sdk/issues/46650

Change-Id: I16ca18faf97954f8e8e25f0b72a2bbfac5bdc672
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212381
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Alexander Markov 2021-09-07 19:52:04 +00:00 committed by commit-bot@chromium.org
parent 176a0f42f5
commit 16e8dc257e
32 changed files with 478 additions and 131 deletions

View file

@ -1148,12 +1148,12 @@ void AsmIntrinsifier::Double_hashCode(Assembler* assembler,
#if !defined(DART_COMPRESSED_POINTERS)
// Convert double value to signed 64-bit int in R0 and back to a
// double value in V1.
__ fcvtzdsx(R0, V0);
__ fcvtzsxd(R0, V0);
__ scvtfdx(V1, R0);
#else
// Convert double value to signed 32-bit int in R0 and back to a
// double value in V1.
__ fcvtzdsw(R0, V0);
__ fcvtzswd(R0, V0);
__ scvtfdw(V1, R0);
#endif

View file

@ -1331,17 +1331,41 @@ class Assembler : public AssemblerBase {
const Register crn = ConcreteRegister(rn);
EmitFPIntCvtOp(SCVTFD, static_cast<Register>(vd), crn, kFourBytes);
}
void fcvtzdsx(Register rd, VRegister vn) {
void fcvtzsxd(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn));
EmitFPIntCvtOp(FCVTZS_D, crd, static_cast<Register>(vn));
}
void fcvtzdsw(Register rd, VRegister vn) {
void fcvtzswd(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn), kFourBytes);
EmitFPIntCvtOp(FCVTZS_D, crd, static_cast<Register>(vn), kFourBytes);
}
void fcvtmsxd(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTMS_D, crd, static_cast<Register>(vn));
}
void fcvtmswd(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTMS_D, crd, static_cast<Register>(vn), kFourBytes);
}
void fcvtpsxd(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTPS_D, crd, static_cast<Register>(vn));
}
void fcvtpswd(Register rd, VRegister vn) {
ASSERT(rd != R31);
ASSERT(rd != CSP);
const Register crd = ConcreteRegister(rd);
EmitFPIntCvtOp(FCVTPS_D, crd, static_cast<Register>(vn), kFourBytes);
}
void fmovdd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FMOVDD, vd, vn); }
void fabsd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FABSD, vd, vn); }

View file

@ -3161,69 +3161,206 @@ ASSEMBLER_TEST_RUN(FldrqFstrqPrePostIndex, test) {
EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzdsx, assembler) {
__ LoadDImmediate(V0, 42.0);
__ fcvtzdsx(R0, V0);
ASSEMBLER_TEST_GENERATE(Fcvtzsxd, assembler) {
__ LoadDImmediate(V0, 42.5);
__ fcvtzsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzdsx, test) {
ASSEMBLER_TEST_RUN(Fcvtzsxd, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzdsw, assembler) {
__ LoadDImmediate(V0, 42.0);
__ fcvtzdsw(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzdsw, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow, assembler) {
__ LoadDImmediate(V0, 1e20);
__ fcvtzdsx(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e20);
__ fcvtzdsx(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow, assembler) {
__ LoadDImmediate(V0, 1e10);
__ fcvtzdsw(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e10);
__ fcvtzdsw(R0, V0);
ASSEMBLER_TEST_GENERATE(Fcvtzswd, assembler) {
__ LoadDImmediate(V0, -42.5);
__ fcvtzswd(R0, V0);
__ sxtw(R0, R0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow_negative, test) {
ASSEMBLER_TEST_RUN(Fcvtzswd, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(-42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzsxd_overflow, assembler) {
__ LoadDImmediate(V0, 1e20);
__ fcvtzsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzsxd_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzsxd_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e20);
__ fcvtzsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzsxd_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzswd_overflow, assembler) {
__ LoadDImmediate(V0, 1e10);
__ fcvtzswd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzswd_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtzswd_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e10);
__ fcvtzswd(R0, V0);
__ sxtw(R0, R0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtzswd_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtpsxd, assembler) {
__ LoadDImmediate(V0, 42.5);
__ fcvtpsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtpsxd, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(43, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtpswd, assembler) {
__ LoadDImmediate(V0, -42.5);
__ fcvtpswd(R0, V0);
__ sxtw(R0, R0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtpswd, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(-42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtpsxd_overflow, assembler) {
__ LoadDImmediate(V0, 1e20);
__ fcvtpsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtpsxd_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtpsxd_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e20);
__ fcvtpsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtpsxd_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtpswd_overflow, assembler) {
__ LoadDImmediate(V0, 1e10);
__ fcvtpswd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtpswd_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtpswd_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e10);
__ fcvtpswd(R0, V0);
__ sxtw(R0, R0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtpswd_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtmsxd, assembler) {
__ LoadDImmediate(V0, 42.5);
__ fcvtmsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtmsxd, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtmswd, assembler) {
__ LoadDImmediate(V0, -42.5);
__ fcvtmswd(R0, V0);
__ sxtw(R0, R0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtmswd, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(-43, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtmsxd_overflow, assembler) {
__ LoadDImmediate(V0, 1e20);
__ fcvtmsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtmsxd_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtmsxd_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e20);
__ fcvtmsxd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtmsxd_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtmswd_overflow, assembler) {
__ LoadDImmediate(V0, 1e10);
__ fcvtmswd(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtmswd_overflow, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Fcvtmswd_overflow_negative, assembler) {
__ LoadDImmediate(V0, -1e10);
__ fcvtmswd(R0, V0);
__ sxtw(R0, R0);
__ ret();
}
ASSEMBLER_TEST_RUN(Fcvtmswd_overflow_negative, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(kMinInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}

View file

@ -1435,8 +1435,12 @@ void ARM64Decoder::DecodeFPIntCvt(Instr* instr) {
Format(instr, "fmovrd'sf 'rd, 'vn");
} else if (instr->Bits(16, 5) == 7) {
Format(instr, "fmovdr'sf 'vd, 'rn");
} else if (instr->Bits(16, 5) == 8) {
Format(instr, "fcvtps'sf 'rd, 'vn");
} else if (instr->Bits(16, 5) == 16) {
Format(instr, "fcvtms'sf 'rd, 'vn");
} else if (instr->Bits(16, 5) == 24) {
Format(instr, "fcvtzds'sf 'rd, 'vn");
Format(instr, "fcvtzs'sf 'rd, 'vn");
} else {
Unknown(instr);
}

View file

@ -298,9 +298,11 @@ class BoxAllocationSlowPath : public TemplateSlowPathCode<Instruction> {
const Register result_;
};
class DoubleToIntegerSlowPath : public TemplateSlowPathCode<Instruction> {
class DoubleToIntegerSlowPath
: public TemplateSlowPathCode<DoubleToIntegerInstr> {
public:
DoubleToIntegerSlowPath(Instruction* instruction, FpuRegister value_reg)
DoubleToIntegerSlowPath(DoubleToIntegerInstr* instruction,
FpuRegister value_reg)
: TemplateSlowPathCode(instruction), value_reg_(value_reg) {}
virtual void EmitNativeCode(FlowGraphCompiler* compiler);

View file

@ -5617,6 +5617,9 @@ void DoubleToIntegerSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->SlowPathEnvironmentFor(instruction(), /*num_slow_path_args=*/0);
__ MoveUnboxedDouble(DoubleToIntegerStubABI::kInputReg, value_reg_);
__ LoadImmediate(
DoubleToIntegerStubABI::kRecognizedKindReg,
compiler::target::ToRawSmi(instruction()->recognized_kind()));
compiler->GenerateStubCall(instruction()->source(),
StubCode::DoubleToInteger(),
UntaggedPcDescriptors::kOther, locs,
@ -6200,10 +6203,10 @@ InvokeMathCFunctionInstr::InvokeMathCFunctionInstr(
intptr_t InvokeMathCFunctionInstr::ArgumentCountFor(
MethodRecognizer::Kind kind) {
switch (kind) {
case MethodRecognizer::kDoubleTruncate:
case MethodRecognizer::kDoubleFloor:
case MethodRecognizer::kDoubleCeil:
case MethodRecognizer::kDoubleRound:
case MethodRecognizer::kDoubleTruncateToDouble:
case MethodRecognizer::kDoubleFloorToDouble:
case MethodRecognizer::kDoubleCeilToDouble:
case MethodRecognizer::kDoubleRoundToDouble:
case MethodRecognizer::kMathAtan:
case MethodRecognizer::kMathTan:
case MethodRecognizer::kMathAcos:
@ -6225,13 +6228,13 @@ intptr_t InvokeMathCFunctionInstr::ArgumentCountFor(
const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const {
switch (recognized_kind_) {
case MethodRecognizer::kDoubleTruncate:
case MethodRecognizer::kDoubleTruncateToDouble:
return kLibcTruncRuntimeEntry;
case MethodRecognizer::kDoubleRound:
case MethodRecognizer::kDoubleRoundToDouble:
return kLibcRoundRuntimeEntry;
case MethodRecognizer::kDoubleFloor:
case MethodRecognizer::kDoubleFloorToDouble:
return kLibcFloorRuntimeEntry;
case MethodRecognizer::kDoubleCeil:
case MethodRecognizer::kDoubleCeilToDouble:
return kLibcCeilRuntimeEntry;
case MethodRecognizer::kMathDoublePow:
return kLibcPowRuntimeEntry;

View file

@ -8320,13 +8320,20 @@ class Int64ToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
class DoubleToIntegerInstr : public TemplateDefinition<1, Throws, Pure> {
public:
DoubleToIntegerInstr(Value* value, intptr_t deopt_id)
: TemplateDefinition(deopt_id) {
DoubleToIntegerInstr(Value* value,
MethodRecognizer::Kind recognized_kind,
intptr_t deopt_id)
: TemplateDefinition(deopt_id), recognized_kind_(recognized_kind) {
ASSERT((recognized_kind == MethodRecognizer::kDoubleToInteger) ||
(recognized_kind == MethodRecognizer::kDoubleFloorToInt) ||
(recognized_kind == MethodRecognizer::kDoubleCeilToInt));
SetInputAt(0, value);
}
Value* value() const { return inputs_[0]; }
MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
DECLARE_INSTRUCTION(DoubleToInteger)
virtual CompileType ComputeType() const;
@ -8348,9 +8355,13 @@ class DoubleToIntegerInstr : public TemplateDefinition<1, Throws, Pure> {
virtual bool HasUnknownSideEffects() const { return false; }
virtual bool AttributesEqual(const Instruction& other) const { return true; }
virtual bool AttributesEqual(const Instruction& other) const {
return other.AsDoubleToInteger()->recognized_kind() == recognized_kind();
}
private:
const MethodRecognizer::Kind recognized_kind_;
DISALLOW_COPY_AND_ASSIGN(DoubleToIntegerInstr);
};
@ -8389,6 +8400,9 @@ class DoubleToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
MethodRecognizer::Kind recognized_kind,
intptr_t deopt_id)
: TemplateDefinition(deopt_id), recognized_kind_(recognized_kind) {
ASSERT((recognized_kind == MethodRecognizer::kDoubleTruncateToDouble) ||
(recognized_kind == MethodRecognizer::kDoubleFloorToDouble) ||
(recognized_kind == MethodRecognizer::kDoubleCeilToDouble));
SetInputAt(0, value);
}

View file

@ -4914,12 +4914,24 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->AddSlowPathCode(slow_path);
// First check for NaN. Checking for minint after the conversion doesn't work
// on ARM64 because fcvtzds gives 0 for NaN.
// on ARM64 because fcvtzs gives 0 for NaN.
__ fcmpd(value_double, value_double);
__ b(slow_path->entry_label(), VS);
__ fcvtzdsx(result, value_double);
// Overflow is signaled with minint.
switch (recognized_kind()) {
case MethodRecognizer::kDoubleToInteger:
__ fcvtzsxd(result, value_double);
break;
case MethodRecognizer::kDoubleFloorToInt:
__ fcvtmsxd(result, value_double);
break;
case MethodRecognizer::kDoubleCeilToInt:
__ fcvtpsxd(result, value_double);
break;
default:
UNREACHABLE();
}
// Overflow is signaled with minint.
#if !defined(DART_COMPRESSED_POINTERS)
// Check for overflow and that it fits into Smi.
@ -4952,12 +4964,12 @@ void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register result = locs()->out(0).reg();
const VRegister value = locs()->in(0).fpu_reg();
// First check for NaN. Checking for minint after the conversion doesn't work
// on ARM64 because fcvtzds gives 0 for NaN.
// on ARM64 because fcvtzs gives 0 for NaN.
// TODO(zra): Check spec that this is true.
__ fcmpd(value, value);
__ b(deopt, VS);
__ fcvtzdsx(result, value);
__ fcvtzsxd(result, value);
#if !defined(DART_COMPRESSED_POINTERS)
// Check for overflow and that it fits into Smi.

View file

@ -5021,6 +5021,7 @@ LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(Zone* zone,
}
void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(recognized_kind() == MethodRecognizer::kDoubleToInteger);
const Register result = locs()->out(0).reg();
const XmmRegister value_double = locs()->in(0).fpu_reg();
@ -5075,13 +5076,13 @@ void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
XmmRegister value = locs()->in(0).fpu_reg();
XmmRegister result = locs()->out(0).fpu_reg();
switch (recognized_kind()) {
case MethodRecognizer::kDoubleTruncate:
case MethodRecognizer::kDoubleTruncateToDouble:
__ roundsd(result, value, compiler::Assembler::kRoundToZero);
break;
case MethodRecognizer::kDoubleFloor:
case MethodRecognizer::kDoubleFloorToDouble:
__ roundsd(result, value, compiler::Assembler::kRoundDown);
break;
case MethodRecognizer::kDoubleCeil:
case MethodRecognizer::kDoubleCeilToDouble:
__ roundsd(result, value, compiler::Assembler::kRoundUp);
break;
default:

View file

@ -5216,13 +5216,45 @@ LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(Zone* zone,
void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register result = locs()->out(0).reg();
const Register temp = locs()->temp(0).reg();
const XmmRegister value_double = locs()->in(0).fpu_reg();
XmmRegister value_double = locs()->in(0).fpu_reg();
ASSERT(result != temp);
DoubleToIntegerSlowPath* slow_path =
new DoubleToIntegerSlowPath(this, value_double);
compiler->AddSlowPathCode(slow_path);
if (recognized_kind() != MethodRecognizer::kDoubleToInteger) {
// In JIT mode VM knows target CPU features at compile time
// and can pick more optimal representation for DoubleToDouble
// conversion. In AOT mode we test if roundsd instruction is
// available at run time and fall back to stub if it isn't.
ASSERT(CompilerState::Current().is_aot());
if (FLAG_use_slow_path) {
__ jmp(slow_path->entry_label());
__ Bind(slow_path->exit_label());
return;
}
__ cmpb(
compiler::Address(
THR,
compiler::target::Thread::double_truncate_round_supported_offset()),
compiler::Immediate(0));
__ j(EQUAL, slow_path->entry_label());
__ xorps(FpuTMP, FpuTMP);
switch (recognized_kind()) {
case MethodRecognizer::kDoubleFloorToInt:
__ roundsd(FpuTMP, value_double, compiler::Assembler::kRoundDown);
break;
case MethodRecognizer::kDoubleCeilToInt:
__ roundsd(FpuTMP, value_double, compiler::Assembler::kRoundUp);
break;
default:
UNREACHABLE();
}
value_double = FpuTMP;
}
__ OBJ(cvttsd2si)(result, value_double);
// Overflow is signalled with minint.
// Check for overflow and that it fits into Smi.
@ -5282,13 +5314,13 @@ void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ xorps(result, result);
}
switch (recognized_kind()) {
case MethodRecognizer::kDoubleTruncate:
case MethodRecognizer::kDoubleTruncateToDouble:
__ roundsd(result, value, compiler::Assembler::kRoundToZero);
break;
case MethodRecognizer::kDoubleFloor:
case MethodRecognizer::kDoubleFloorToDouble:
__ roundsd(result, value, compiler::Assembler::kRoundDown);
break;
case MethodRecognizer::kDoubleCeil:
case MethodRecognizer::kDoubleCeilToDouble:
__ roundsd(result, value, compiler::Assembler::kRoundUp);
break;
default:

View file

@ -1010,8 +1010,8 @@ bool CallSpecializer::TryInlineInstanceMethod(InstanceCallInstr* call) {
Definition* d2i_instr = NULL;
if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) {
// Do not repeatedly deoptimize because result didn't fit into Smi.
d2i_instr = new (Z)
DoubleToIntegerInstr(new (Z) Value(input), call->deopt_id());
d2i_instr = new (Z) DoubleToIntegerInstr(
new (Z) Value(input), recognized_kind, call->deopt_id());
} else {
// Optimistically assume result fits into Smi.
d2i_instr =

View file

@ -1217,9 +1217,11 @@ Fragment BaseFlowGraphBuilder::DoubleToDouble(
return Fragment(instr);
}
Fragment BaseFlowGraphBuilder::DoubleToInteger() {
Fragment BaseFlowGraphBuilder::DoubleToInteger(
MethodRecognizer::Kind recognized_kind) {
Value* value = Pop();
auto* instr = new (Z) DoubleToIntegerInstr(value, GetNextDeoptId());
auto* instr =
new (Z) DoubleToIntegerInstr(value, recognized_kind, GetNextDeoptId());
Push(instr);
return Fragment(instr);
}

View file

@ -451,12 +451,14 @@ class BaseFlowGraphBuilder {
intptr_t num_inputs);
// Pops double value and converts it to double as specified
// by the recognized method (kDoubleTruncate,
// kDoubleFloor or kDoubleCeil).
// by the recognized method (kDoubleTruncateToDouble,
// kDoubleFloorToDouble or kDoubleCeilToDouble).
Fragment DoubleToDouble(MethodRecognizer::Kind recognized_kind);
// Pops double value and converts it to int.
Fragment DoubleToInteger();
// Pops double value and converts it to int as specified
// by the recognized method (kDoubleToInteger,
// kDoubleFloorToInt or kDoubleCeilToInt).
Fragment DoubleToInteger(MethodRecognizer::Kind recognized_kind);
// Pops double value and applies unary math operation.
Fragment MathUnary(MathUnaryInstr::MathUnaryKind kind);

View file

@ -897,10 +897,10 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
return true;
case MethodRecognizer::kDoubleToInteger:
case MethodRecognizer::kDoubleMod:
case MethodRecognizer::kDoubleRound:
case MethodRecognizer::kDoubleTruncate:
case MethodRecognizer::kDoubleFloor:
case MethodRecognizer::kDoubleCeil:
case MethodRecognizer::kDoubleRoundToDouble:
case MethodRecognizer::kDoubleTruncateToDouble:
case MethodRecognizer::kDoubleFloorToDouble:
case MethodRecognizer::kDoubleCeilToDouble:
case MethodRecognizer::kMathDoublePow:
case MethodRecognizer::kMathSin:
case MethodRecognizer::kMathCos:
@ -913,6 +913,16 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
case MethodRecognizer::kMathLog:
case MethodRecognizer::kMathSqrt:
return FlowGraphCompiler::SupportsUnboxedDoubles();
case MethodRecognizer::kDoubleCeilToInt:
case MethodRecognizer::kDoubleFloorToInt:
if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
#if defined(TARGET_ARCH_X64)
return CompilerState::Current().is_aot();
#elif defined(TARGET_ARCH_ARM64)
return true;
#else
return false;
#endif
default:
return false;
}
@ -1540,15 +1550,17 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
body += LoadIndexed(kIntPtrCid);
body += Box(kUnboxedIntPtr);
} break;
case MethodRecognizer::kDoubleToInteger: {
case MethodRecognizer::kDoubleToInteger:
case MethodRecognizer::kDoubleCeilToInt:
case MethodRecognizer::kDoubleFloorToInt: {
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += DoubleToInteger();
body += DoubleToInteger(kind);
} break;
case MethodRecognizer::kDoubleMod:
case MethodRecognizer::kDoubleRound:
case MethodRecognizer::kDoubleTruncate:
case MethodRecognizer::kDoubleFloor:
case MethodRecognizer::kDoubleCeil:
case MethodRecognizer::kDoubleRoundToDouble:
case MethodRecognizer::kDoubleTruncateToDouble:
case MethodRecognizer::kDoubleFloorToDouble:
case MethodRecognizer::kDoubleCeilToDouble:
case MethodRecognizer::kMathDoublePow:
case MethodRecognizer::kMathSin:
case MethodRecognizer::kMathCos:
@ -1564,9 +1576,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
}
if (!CompilerState::Current().is_aot() &&
TargetCPUFeatures::double_truncate_round_supported() &&
((kind == MethodRecognizer::kDoubleTruncate) ||
(kind == MethodRecognizer::kDoubleFloor) ||
(kind == MethodRecognizer::kDoubleCeil))) {
((kind == MethodRecognizer::kDoubleTruncateToDouble) ||
(kind == MethodRecognizer::kDoubleFloorToDouble) ||
(kind == MethodRecognizer::kDoubleCeilToDouble))) {
body += DoubleToDouble(kind);
} else {
body += InvokeMathCFunction(kind, function.NumParameters());

View file

@ -37,7 +37,7 @@
namespace dart {
void Assert::Fail(const char* format, ...) {
void Assert::Fail(const char* format, ...) const {
abort();
}

View file

@ -88,11 +88,13 @@ namespace dart {
V(_Double, _mul, DoubleMul, 0x1f98c76c) \
V(_Double, _div, DoubleDiv, 0x287d3791) \
V(_Double, _modulo, DoubleMod, 0xfdb397ef) \
V(_Double, ceilToDouble, DoubleCeil, 0x5f1bced9) \
V(_Double, floorToDouble, DoubleFloor, 0x54b4cb48) \
V(_Double, roundToDouble, DoubleRound, 0x5649ca00) \
V(_Double, ceil, DoubleCeilToInt, 0xcef8d7c5) \
V(_Double, ceilToDouble, DoubleCeilToDouble, 0x5f1bced9) \
V(_Double, floor, DoubleFloorToInt, 0x2a323f88) \
V(_Double, floorToDouble, DoubleFloorToDouble, 0x54b4cb48) \
V(_Double, roundToDouble, DoubleRoundToDouble, 0x5649ca00) \
V(_Double, toInt, DoubleToInteger, 0x676f20a9) \
V(_Double, truncateToDouble, DoubleTruncate, 0x62d48659) \
V(_Double, truncateToDouble, DoubleTruncateToDouble, 0x62d48659) \
V(::, min, MathMin, 0x504a28df) \
V(::, max, MathMax, 0xead7161a) \
V(::, _doublePow, MathDoublePow, 0x989f3334) \

View file

@ -1056,6 +1056,7 @@ class MonomorphicSmiableCall : public AllStatic {
class Thread : public AllStatic {
public:
static word api_top_scope_offset();
static word double_truncate_round_supported_offset();
static word exit_through_ffi_offset();
static uword exit_through_runtime_call();
static uword exit_through_ffi();

View file

@ -286,9 +286,11 @@ static constexpr dart::compiler::target::word
Thread_call_to_runtime_entry_point_offset = 276;
static constexpr dart::compiler::target::word
Thread_call_to_runtime_stub_offset = 144;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 796;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 800;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 48;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 792;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
316;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 232;
@ -330,7 +332,7 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
784;
static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 800;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 804;
static constexpr dart::compiler::target::word Thread_field_table_values_offset =
68;
static constexpr dart::compiler::target::word
@ -838,6 +840,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -1385,9 +1389,11 @@ static constexpr dart::compiler::target::word
Thread_call_to_runtime_entry_point_offset = 276;
static constexpr dart::compiler::target::word
Thread_call_to_runtime_stub_offset = 144;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 764;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 768;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 48;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 760;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
316;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 232;
@ -1429,7 +1435,7 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
752;
static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 768;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 772;
static constexpr dart::compiler::target::word Thread_field_table_values_offset =
68;
static constexpr dart::compiler::target::word
@ -1934,6 +1940,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1664;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -2487,6 +2495,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -3039,6 +3049,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1664;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -3583,9 +3595,11 @@ static constexpr dart::compiler::target::word
Thread_call_to_runtime_entry_point_offset = 276;
static constexpr dart::compiler::target::word
Thread_call_to_runtime_stub_offset = 144;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 796;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 800;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 48;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 792;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
316;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 232;
@ -3627,7 +3641,7 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
784;
static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 800;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 804;
static constexpr dart::compiler::target::word Thread_field_table_values_offset =
68;
static constexpr dart::compiler::target::word
@ -4129,6 +4143,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -4670,9 +4686,11 @@ static constexpr dart::compiler::target::word
Thread_call_to_runtime_entry_point_offset = 276;
static constexpr dart::compiler::target::word
Thread_call_to_runtime_stub_offset = 144;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 764;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 768;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 48;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 760;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
316;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 232;
@ -4714,7 +4732,7 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
752;
static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 768;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 772;
static constexpr dart::compiler::target::word Thread_field_table_values_offset =
68;
static constexpr dart::compiler::target::word
@ -5213,6 +5231,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1664;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -5760,6 +5780,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -6306,6 +6328,8 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1664;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 448;
@ -6888,9 +6912,11 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word
AOT_Thread_call_to_runtime_stub_offset = 144;
static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
796;
800;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 48;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 792;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
316;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -6934,7 +6960,7 @@ static constexpr dart::compiler::target::word
AOT_Thread_exit_through_ffi_offset = 784;
static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44;
static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
800;
804;
static constexpr dart::compiler::target::word
AOT_Thread_field_table_values_offset = 68;
static constexpr dart::compiler::target::word
@ -7502,6 +7528,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1600;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -8119,6 +8147,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1664;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -8733,6 +8763,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1600;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -9346,6 +9378,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1664;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -9952,9 +9986,11 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word
AOT_Thread_call_to_runtime_stub_offset = 144;
static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
796;
800;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 48;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 792;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
316;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -9998,7 +10034,7 @@ static constexpr dart::compiler::target::word
AOT_Thread_exit_through_ffi_offset = 784;
static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44;
static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
800;
804;
static constexpr dart::compiler::target::word
AOT_Thread_field_table_values_offset = 68;
static constexpr dart::compiler::target::word
@ -10559,6 +10595,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1600;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -11169,6 +11207,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1664;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -11776,6 +11816,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1600;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1592;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@ -12382,6 +12424,8 @@ static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
1664;
static constexpr dart::compiler::target::word
AOT_Thread_dispatch_table_array_offset = 96;
static constexpr dart::compiler::target::word
AOT_Thread_double_truncate_round_supported_offset = 1656;
static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
616;
static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =

View file

@ -213,6 +213,7 @@
FIELD(Thread, call_to_runtime_stub_offset) \
FIELD(Thread, dart_stream_offset) \
FIELD(Thread, dispatch_table_array_offset) \
FIELD(Thread, double_truncate_round_supported_offset) \
FIELD(Thread, optimize_entry_offset) \
FIELD(Thread, optimize_stub_offset) \
FIELD(Thread, deoptimize_entry_offset) \

View file

@ -1061,7 +1061,9 @@ void StubCodeCompiler::GenerateDoubleToIntegerStub(Assembler* assembler) {
__ StoreUnboxedDouble(DoubleToIntegerStubABI::kInputReg, THR,
target::Thread::unboxed_double_runtime_arg_offset());
__ PushObject(NullObject()); /* Make room for result. */
__ CallRuntime(kDoubleToIntegerRuntimeEntry, 0);
__ PushRegister(DoubleToIntegerStubABI::kRecognizedKindReg);
__ CallRuntime(kDoubleToIntegerRuntimeEntry, 1);
__ Drop(1);
__ PopRegister(DoubleToIntegerStubABI::kResultReg);
__ LeaveStubFrame();
__ Ret();

View file

@ -497,6 +497,7 @@ struct BoxDoubleStubABI {
// ABI for DoubleToIntegerStub.
struct DoubleToIntegerStubABI {
static const FpuRegister kInputReg = Q0;
static const Register kRecognizedKindReg = R0;
static const Register kResultReg = R0;
};

View file

@ -337,6 +337,7 @@ struct BoxDoubleStubABI {
// ABI for DoubleToIntegerStub.
struct DoubleToIntegerStubABI {
static const FpuRegister kInputReg = V0;
static const Register kRecognizedKindReg = R0;
static const Register kResultReg = R0;
};
@ -930,7 +931,9 @@ enum FPIntCvtOp {
FMOVSR = FPIntCvtFixed | B18 | B17 | B16,
FMOVRD = FPIntCvtFixed | B22 | B18 | B17,
FMOVDR = FPIntCvtFixed | B22 | B18 | B17 | B16,
FCVTZDS = FPIntCvtFixed | B22 | B20 | B19,
FCVTZS_D = FPIntCvtFixed | B22 | B20 | B19,
FCVTMS_D = FPIntCvtFixed | B22 | B20,
FCVTPS_D = FPIntCvtFixed | B22 | B19,
SCVTFD = FPIntCvtFixed | B22 | B17,
};

View file

@ -236,6 +236,7 @@ struct BoxDoubleStubABI {
// ABI for DoubleToIntegerStub.
struct DoubleToIntegerStubABI {
static const FpuRegister kInputReg = XMM0;
static const Register kRecognizedKindReg = EAX;
static const Register kResultReg = EAX;
};

View file

@ -309,6 +309,7 @@ struct BoxDoubleStubABI {
// ABI for DoubleToIntegerStub.
struct DoubleToIntegerStubABI {
static const FpuRegister kInputReg = XMM0;
static const Register kRecognizedKindReg = RAX;
static const Register kResultReg = RAX;
};

View file

@ -340,6 +340,7 @@ char* Dart::DartInit(const uint8_t* vm_isolate_snapshot,
NOT_IN_PRODUCT(Metric::Init());
StoreBuffer::Init();
MarkingStack::Init();
TargetCPUFeatures::Init();
#if defined(USING_SIMULATOR)
Simulator::Init();
@ -387,7 +388,6 @@ char* Dart::DartInit(const uint8_t* vm_isolate_snapshot,
Object::InitNullAndBool(vm_isolate_->group());
vm_isolate_->isolate_group_->set_object_store(new ObjectStore());
vm_isolate_->isolate_object_store()->Init();
TargetCPUFeatures::Init();
Object::Init(vm_isolate_->group());
OffsetsTable::Init();
ArgumentsDescriptor::Init();

View file

@ -301,9 +301,22 @@ DEFINE_RUNTIME_ENTRY(ArgumentErrorUnboxedInt64, 0) {
Exceptions::ThrowArgumentError(value);
}
DEFINE_RUNTIME_ENTRY(DoubleToInteger, 0) {
DEFINE_RUNTIME_ENTRY(DoubleToInteger, 1) {
// Unboxed value is passed through a dedicated slot in Thread.
const double val = arguments.thread()->unboxed_double_runtime_arg();
double val = arguments.thread()->unboxed_double_runtime_arg();
const Smi& recognized_kind = Smi::CheckedHandle(zone, arguments.ArgAt(0));
switch (recognized_kind.Value()) {
case MethodRecognizer::kDoubleToInteger:
break;
case MethodRecognizer::kDoubleFloorToInt:
val = floor(val);
break;
case MethodRecognizer::kDoubleCeilToInt:
val = ceil(val);
break;
default:
UNREACHABLE();
}
arguments.SetReturn(Integer::Handle(zone, DoubleToInteger(zone, val)));
}

View file

@ -3350,11 +3350,24 @@ void Simulator::DecodeFPIntCvt(Instr* instr) {
const int64_t rn_val = get_register(rn, R31IsZR);
set_vregisterd(vd, 0, rn_val);
set_vregisterd(vd, 1, 0);
} else if (instr->Bits(16, 5) == 24) {
// Format(instr, "fcvtzds'sf 'rd, 'vn");
} else if ((instr->Bits(16, 5) == 8) || (instr->Bits(16, 5) == 16) ||
(instr->Bits(16, 5) == 24)) {
const intptr_t max = instr->Bit(31) == 1 ? INT64_MAX : INT32_MAX;
const intptr_t min = instr->Bit(31) == 1 ? INT64_MIN : INT32_MIN;
const double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
switch (instr->Bits(16, 5)) {
case 8:
// Format(instr, "fcvtps'sf 'rd, 'vn");
vn_val = ceil(vn_val);
break;
case 16:
// Format(instr, "fcvtms'sf 'rd, 'vn");
vn_val = floor(vn_val);
break;
case 24:
// Format(instr, "fcvtzs'sf 'rd, 'vn");
break;
}
int64_t result;
if (vn_val >= static_cast<double>(max)) {
result = max;

View file

@ -4,6 +4,7 @@
#include "vm/thread.h"
#include "vm/cpu.h"
#include "vm/dart_api_state.h"
#include "vm/growable_array.h"
#include "vm/heap/safepoint.h"
@ -83,6 +84,8 @@ Thread::Thread(bool is_vm_isolate)
ffi_callback_code_(GrowableObjectArray::null()),
ffi_callback_stack_return_(TypedData::null()),
api_top_scope_(NULL),
double_truncate_round_supported_(
TargetCPUFeatures::double_truncate_round_supported() ? 1 : 0),
task_kind_(kUnknownTask),
dart_stream_(NULL),
thread_lock_(),

View file

@ -445,6 +445,10 @@ class Thread : public ThreadState {
void EnterApiScope();
void ExitApiScope();
static intptr_t double_truncate_round_supported_offset() {
return OFFSET_OF(Thread, double_truncate_round_supported_);
}
// The isolate that this thread is operating on, or nullptr if none.
Isolate* isolate() const { return isolate_; }
static intptr_t isolate_offset() { return OFFSET_OF(Thread, isolate_); }
@ -1088,6 +1092,7 @@ class Thread : public ThreadState {
// JumpToExceptionHandler state:
ObjectPtr active_exception_;
ObjectPtr active_stacktrace_;
ObjectPoolPtr global_object_pool_;
uword resume_pc_;
uword saved_shadow_call_stack_ = 0;
@ -1097,6 +1102,7 @@ class Thread : public ThreadState {
TypedDataPtr ffi_callback_stack_return_;
uword exit_through_ffi_ = 0;
ApiLocalScope* api_top_scope_;
uint8_t double_truncate_round_supported_;
// ---- End accessed from generated code. ----

View file

@ -178,9 +178,14 @@ class _Double implements double {
}
int round() => roundToDouble().toInt();
int truncate() => toInt();
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
int floor() => floorToDouble().toInt();
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
int ceil() => ceilToDouble().toInt();
int truncate() => truncateToDouble().toInt();
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")

View file

@ -1,8 +1,11 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Dart test program to test arithmetic operations.
// VMOptions=--optimization-counter-threshold=10 --no-use-osr --no-background-compilation
// VMOptions=--use_slow_path
library arithmetic_test;

View file

@ -1,8 +1,11 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Dart test program to test arithmetic operations.
// VMOptions=--optimization-counter-threshold=10 --no-use-osr --no-background-compilation
// VMOptions=--use_slow_path
// @dart = 2.9