Precompilation/x64: Load float vector constants via Thread.

Cannot put these in the object pool because some of these instructions
are used in intrinsics.

BUG=http://dartbug.com/24450
R=fschneider@google.com

Review URL: https://codereview.chromium.org/1488403002 .
This commit is contained in:
Ryan Macnak 2015-12-03 13:35:31 -08:00
parent d9b1301821
commit 9cf30c9697
6 changed files with 131 additions and 117 deletions

View file

@ -1625,14 +1625,17 @@ ASSEMBLER_TEST_RUN(LoadImmediateMedNeg4, test) {
static void EnterTestFrame(Assembler* assembler) {
__ EnterFrame(0);
__ Push(CODE_REG);
__ Push(THR);
__ TagAndPushPP();
__ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle));
__ mov(THR, R1);
__ LoadPoolPointer(PP);
}
static void LeaveTestFrame(Assembler* assembler) {
__ PopAndUntagPP();
__ Pop(THR);
__ Pop(CODE_REG);
__ LeaveFrame();
}
@ -1652,7 +1655,7 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPSmall, assembler) {
ASSEMBLER_TEST_RUN(LoadImmediatePPSmall, test) {
EXPECT_EQ(42, test->InvokeWithCode<int64_t>());
EXPECT_EQ(42, test->InvokeWithCodeAndThread<int64_t>());
}
@ -1667,7 +1670,7 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPMed, assembler) {
ASSEMBLER_TEST_RUN(LoadImmediatePPMed, test) {
EXPECT_EQ(0xf1234123, test->InvokeWithCode<int64_t>());
EXPECT_EQ(0xf1234123, test->InvokeWithCodeAndThread<int64_t>());
}
@ -1682,7 +1685,7 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPMed2, assembler) {
ASSEMBLER_TEST_RUN(LoadImmediatePPMed2, test) {
EXPECT_EQ(0x4321f1234124, test->InvokeWithCode<int64_t>());
EXPECT_EQ(0x4321f1234124, test->InvokeWithCodeAndThread<int64_t>());
}
@ -1698,23 +1701,15 @@ ASSEMBLER_TEST_GENERATE(LoadImmediatePPLarge, assembler) {
ASSEMBLER_TEST_RUN(LoadImmediatePPLarge, test) {
EXPECT_EQ(static_cast<int64_t>(0x9287436598237465),
test->InvokeWithCode<int64_t>());
test->InvokeWithCodeAndThread<int64_t>());
}
#define ASSEMBLER_TEST_RUN_WITH_THREAD(result_type, var_name) \
Thread* thread = Thread::Current(); \
result_type var_name = test->InvokeWithCode<result_type>(thread);
// LoadObject null.
ASSEMBLER_TEST_GENERATE(LoadObjectNull, assembler) {
__ SetupDartSP(kTestStackSpace);
EnterTestFrame(assembler);
__ Push(THR);
__ mov(THR, R1);
__ LoadObject(R0, Object::null_object());
__ Pop(THR);
LeaveTestFrame(assembler);
__ mov(CSP, SP);
__ ret();
@ -1722,18 +1717,14 @@ ASSEMBLER_TEST_GENERATE(LoadObjectNull, assembler) {
ASSEMBLER_TEST_RUN(LoadObjectNull, test) {
ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
EXPECT_EQ(Object::null(), result);
EXPECT_EQ(Object::null(), test->InvokeWithCodeAndThread<RawObject*>());
}
ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
__ SetupDartSP(kTestStackSpace);
EnterTestFrame(assembler);
__ Push(THR);
__ mov(THR, R1);
__ LoadObject(R0, Bool::True());
__ Pop(THR);
LeaveTestFrame(assembler);
__ mov(CSP, SP);
__ ret();
@ -1741,18 +1732,14 @@ ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
ASSEMBLER_TEST_RUN(LoadObjectTrue, test) {
ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
EXPECT_EQ(Bool::True().raw(), result);
EXPECT_EQ(Bool::True().raw(), test->InvokeWithCodeAndThread<RawObject*>());
}
ASSEMBLER_TEST_GENERATE(LoadObjectFalse, assembler) {
__ SetupDartSP(kTestStackSpace);
EnterTestFrame(assembler);
__ Push(THR);
__ mov(THR, R1);
__ LoadObject(R0, Bool::False());
__ Pop(THR);
LeaveTestFrame(assembler);
__ mov(CSP, SP);
__ ret();
@ -1760,8 +1747,7 @@ ASSEMBLER_TEST_GENERATE(LoadObjectFalse, assembler) {
ASSEMBLER_TEST_RUN(LoadObjectFalse, test) {
ASSEMBLER_TEST_RUN_WITH_THREAD(RawObject*, result);
EXPECT_EQ(Bool::False().raw(), result);
EXPECT_EQ(Bool::False().raw(), test->InvokeWithCodeAndThread<RawObject*>());
}
@ -3591,7 +3577,7 @@ ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
__ SetupDartSP(kTestStackSpace);
EnterTestFrame(assembler);
Label miss, done;
__ ComputeRange(R0, R1, R2, &miss);
__ ComputeRange(R0, R2, R3, &miss);
__ b(&done);
__ Bind(&miss);
@ -3605,7 +3591,8 @@ ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
ASSEMBLER_TEST_RUN(ComputeRange, test) {
#define RANGE_OF(arg_type, v) test->InvokeWithCode<intptr_t, arg_type>(v)
#define RANGE_OF(arg_type, v) \
test->InvokeWithCodeAndThread<intptr_t, arg_type>(v)
EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(0)));
EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(1)));

View file

@ -785,57 +785,29 @@ void Assembler::orps(XmmRegister dst, XmmRegister src) {
}
void Assembler::notps(XmmRegister dst) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_not_constant =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)));
// { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
movq(TMP, Address(THR, Thread::float_not_address_offset()));
xorps(dst, Address(TMP, 0));
}
void Assembler::negateps(XmmRegister dst) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_negate_constant =
{ 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)));
// { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
movq(TMP, Address(THR, Thread::float_negate_address_offset()));
xorps(dst, Address(TMP, 0));
}
void Assembler::absps(XmmRegister dst) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_absolute_constant =
{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)));
// { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }
movq(TMP, Address(THR, Thread::float_absolute_address_offset()));
andps(dst, Address(TMP, 0));
}
void Assembler::zerowps(XmmRegister dst) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_zerow_constant =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)));
// { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }
movq(TMP, Address(THR, Thread::float_zerow_address_offset()));
andps(dst, Address(TMP, 0));
}
@ -1017,13 +989,8 @@ void Assembler::addpd(XmmRegister dst, XmmRegister src) {
void Assembler::negatepd(XmmRegister dst) {
static const struct ALIGN16 {
uint64_t a;
uint64_t b;
} double_negate_constant =
{ 0x8000000000000000LL, 0x8000000000000000LL };
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
// { 0x8000000000000000LL, 0x8000000000000000LL }
movq(TMP, Address(THR, Thread::double_negate_address_offset()));
xorpd(dst, Address(TMP, 0));
}
@ -1065,13 +1032,8 @@ void Assembler::divpd(XmmRegister dst, XmmRegister src) {
void Assembler::abspd(XmmRegister dst) {
static const struct ALIGN16 {
uint64_t a;
uint64_t b;
} double_absolute_const =
{ 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL };
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&double_absolute_const)));
// { 0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL }
movq(TMP, Address(THR, Thread::double_abs_address_offset()));
andpd(dst, Address(TMP, 0));
}
@ -3160,25 +3122,15 @@ void Assembler::IncrementSmiField(const Address& dest, int64_t increment) {
void Assembler::DoubleNegate(XmmRegister d) {
static const struct ALIGN16 {
uint64_t a;
uint64_t b;
} double_negate_constant =
{0x8000000000000000LL, 0x8000000000000000LL};
LoadImmediate(
TMP, Immediate(reinterpret_cast<intptr_t>(&double_negate_constant)));
// {0x8000000000000000LL, 0x8000000000000000LL}
movq(TMP, Address(THR, Thread::double_negate_address_offset()));
xorpd(d, Address(TMP, 0));
}
void Assembler::DoubleAbs(XmmRegister reg) {
static const struct ALIGN16 {
uint64_t a;
uint64_t b;
} double_abs_constant =
{0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
LoadImmediate(TMP,
Immediate(reinterpret_cast<intptr_t>(&double_abs_constant)));
// {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL}
movq(TMP, Address(THR, Thread::double_abs_address_offset()));
andpd(reg, Address(TMP, 0));
}

View file

@ -2021,16 +2021,21 @@ ASSEMBLER_TEST_RUN(PackedDoubleSub, test) {
static void EnterTestFrame(Assembler* assembler) {
COMPILE_ASSERT(THR != CallingConventions::kArg1Reg);
COMPILE_ASSERT(CODE_REG != CallingConventions::kArg2Reg);
__ EnterFrame(0);
__ pushq(CODE_REG);
__ pushq(PP);
__ pushq(THR);
__ movq(CODE_REG, Address(CallingConventions::kArg1Reg,
VMHandles::kOffsetOfRawPtrInHandle));
__ movq(THR, CallingConventions::kArg2Reg);
__ LoadPoolPointer(PP);
}
static void LeaveTestFrame(Assembler* assembler) {
__ popq(THR);
__ popq(PP);
__ popq(CODE_REG);
__ LeaveFrame();
@ -2053,7 +2058,7 @@ ASSEMBLER_TEST_GENERATE(PackedDoubleNegate, assembler) {
ASSEMBLER_TEST_RUN(PackedDoubleNegate, test) {
double res = test->InvokeWithCode<double>();
double res = test->InvokeWithCodeAndThread<double>();
EXPECT_FLOAT_EQ(-1.0, res, 0.000001f);
}
@ -2074,7 +2079,7 @@ ASSEMBLER_TEST_GENERATE(PackedDoubleAbsolute, assembler) {
ASSEMBLER_TEST_RUN(PackedDoubleAbsolute, test) {
double res = test->InvokeWithCode<double>();
double res = test->InvokeWithCodeAndThread<double>();
EXPECT_FLOAT_EQ(1.0, res, 0.000001f);
}
@ -2520,7 +2525,7 @@ ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
ASSEMBLER_TEST_RUN(PackedNegate, test) {
float res = test->InvokeWithCode<float>();
float res = test->InvokeWithCodeAndThread<float>();
EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
}
@ -2538,7 +2543,7 @@ ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
float res = test->InvokeWithCode<float>();
float res = test->InvokeWithCodeAndThread<float>();
EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
}
@ -2554,7 +2559,7 @@ ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
float res = test->InvokeWithCode<float>();
float res = test->InvokeWithCodeAndThread<float>();
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
}
@ -2678,7 +2683,7 @@ ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
uint32_t res = test->InvokeWithCode<uint32_t>();
uint32_t res = test->InvokeWithCodeAndThread<uint32_t>();
EXPECT_EQ(static_cast<uword>(0x0), res);
}
@ -3103,7 +3108,7 @@ ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
bool res = test->InvokeWithCode<bool>();
bool res = test->InvokeWithCodeAndThread<bool>();
EXPECT_EQ(true, res);
}
@ -3415,10 +3420,13 @@ ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, test) {
ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
EnterTestFrame(assembler);
#if defined(TARGET_OS_WINDOWS)
// First argument is code object, MSVC passes second argument in XMM1.
__ DoubleAbs(XMM1);
__ movaps(XMM0, XMM1);
// First argument is code object, second argument is thread. MSVC passes
// third argument in XMM2.
__ DoubleAbs(XMM2);
__ movaps(XMM0, XMM2);
#else
// SysV ABI allocates integral and double registers for arguments
// independently.
__ DoubleAbs(XMM0);
#endif
LeaveTestFrame(assembler);
@ -3428,10 +3436,10 @@ ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
ASSEMBLER_TEST_RUN(DoubleAbs, test) {
double val = -12.45;
double res = test->InvokeWithCode<double, double>(val);
double res = test->InvokeWithCodeAndThread<double, double>(val);
EXPECT_FLOAT_EQ(-val, res, 0.001);
val = 12.45;
res = test->InvokeWithCode<double, double>(val);
res = test->InvokeWithCodeAndThread<double, double>(val);
EXPECT_FLOAT_EQ(val, res, 0.001);
}

View file

@ -87,6 +87,51 @@ LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT)
}
static const struct ALIGN16 {
uint64_t a;
uint64_t b;
} double_negate_constant =
{0x8000000000000000LL, 0x8000000000000000LL};
static const struct ALIGN16 {
uint64_t a;
uint64_t b;
} double_abs_constant =
{0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_not_constant =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_negate_constant =
{ 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_absolute_constant =
{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} float_zerow_constant =
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
void Thread::InitVMConstants() {
#define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \
ASSERT((init_expr)->IsOldObject());

View file

@ -79,7 +79,6 @@ class Zone;
V(RawCode*, invoke_dart_code_stub_, \
StubCode::InvokeDartCode_entry()->code(), NULL) \
#define CACHED_ADDRESSES_LIST(V) \
V(uword, update_store_buffer_entry_point_, \
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0) \
@ -87,12 +86,23 @@ class Zone;
NativeEntry::NativeCallWrapperEntry(), 0) \
V(RawString**, predefined_symbols_address_, \
Symbols::PredefinedAddress(), NULL) \
V(uword, double_negate_address_, \
reinterpret_cast<uword>(&double_negate_constant), 0) \
V(uword, double_abs_address_, \
reinterpret_cast<uword>(&double_abs_constant), 0) \
V(uword, float_not_address_, \
reinterpret_cast<uword>(&float_not_constant), 0) \
V(uword, float_negate_address_, \
reinterpret_cast<uword>(&float_negate_constant), 0) \
V(uword, float_absolute_address_, \
reinterpret_cast<uword>(&float_absolute_constant), 0) \
V(uword, float_zerow_address_, \
reinterpret_cast<uword>(&float_zerow_constant), 0) \
#define CACHED_CONSTANTS_LIST(V) \
CACHED_VM_OBJECTS_LIST(V) \
CACHED_ADDRESSES_LIST(V) \
// A VM thread; may be executing Dart code or performing helper tasks like
// garbage collection or compilation. The Thread structure associated with
// a thread is allocated by EnsureInit before entering an isolate, and destroyed

View file

@ -360,36 +360,44 @@ class AssemblerTest {
uword entry() const { return code_.EntryPoint(); }
// Invoke/InvokeWithCode is used to call assembler test functions using the
// ABI calling convention.
// Invoke/InvokeWithCodeAndThread is used to call assembler test functions
// using the ABI calling convention.
// ResultType is the return type of the assembler test function.
// ArgNType is the type of the Nth argument.
#if defined(USING_SIMULATOR)
#if defined(ARCH_IS_64_BIT)
// TODO(fschneider): Make InvokeWithCode<> more general and work on 32-bit.
// TODO(fschneider): Make InvokeWithCodeAndThread<> more general and work on
// 32-bit.
// Since Simulator::Call always return a int64_t, bit_cast does not work
// on 32-bit platforms when returning an int32_t. Since template functions
// don't support partial specialization, we'd need to introduce a helper
// class to support 32-bit return types.
template<typename ResultType> ResultType InvokeWithCode() {
template<typename ResultType> ResultType InvokeWithCodeAndThread() {
const bool fp_return = is_double<ResultType>::value;
const bool fp_args = false;
Thread* thread = Thread::Current();
ASSERT(thread != NULL);
return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
bit_cast<intptr_t, uword>(entry()),
reinterpret_cast<intptr_t>(&code_), 0, 0, 0, fp_return, fp_args));
reinterpret_cast<intptr_t>(&code_),
reinterpret_cast<intptr_t>(thread),
0, 0, fp_return, fp_args));
}
template<typename ResultType, typename Arg1Type>
ResultType InvokeWithCode(Arg1Type arg1) {
ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
const bool fp_return = is_double<ResultType>::value;
const bool fp_args = is_double<Arg1Type>::value;
// TODO(fschneider): Support double arguments for simulator calls.
COMPILE_ASSERT(!fp_args);
Thread* thread = Thread::Current();
ASSERT(thread != NULL);
return bit_cast<ResultType, int64_t>(Simulator::Current()->Call(
bit_cast<intptr_t, uword>(entry()),
reinterpret_cast<intptr_t>(&code_),
reinterpret_cast<intptr_t>(thread),
reinterpret_cast<intptr_t>(arg1),
0, 0, fp_return, fp_args));
0, fp_return, fp_args));
}
#endif // ARCH_IS_64_BIT
@ -413,15 +421,19 @@ class AssemblerTest {
0, fp_return, fp_args);
}
#else
template<typename ResultType> ResultType InvokeWithCode() {
typedef ResultType (*FunctionType) (const Code&);
return reinterpret_cast<FunctionType>(entry())(code_);
template<typename ResultType> ResultType InvokeWithCodeAndThread() {
Thread* thread = Thread::Current();
ASSERT(thread != NULL);
typedef ResultType (*FunctionType) (const Code&, Thread*);
return reinterpret_cast<FunctionType>(entry())(code_, thread);
}
template<typename ResultType, typename Arg1Type>
ResultType InvokeWithCode(Arg1Type arg1) {
typedef ResultType (*FunctionType) (const Code&, Arg1Type);
return reinterpret_cast<FunctionType>(entry())(code_, arg1);
ResultType InvokeWithCodeAndThread(Arg1Type arg1) {
Thread* thread = Thread::Current();
ASSERT(thread != NULL);
typedef ResultType (*FunctionType) (const Code&, Thread*, Arg1Type);
return reinterpret_cast<FunctionType>(entry())(code_, thread, arg1);
}
template<typename ResultType,