mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:47:50 +00:00
[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:
parent
176a0f42f5
commit
16e8dc257e
|
@ -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
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
namespace dart {
|
||||
|
||||
void Assert::Fail(const char* format, ...) {
|
||||
void Assert::Fail(const char* format, ...) const {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_(),
|
||||
|
|
|
@ -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. ----
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue