// 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. #include "vm/globals.h" #if defined(TARGET_ARCH_IA32) #include "vm/assembler.h" #include "vm/os.h" #include "vm/unit_test.h" #include "vm/virtual_memory.h" namespace dart { #define __ assembler-> ASSEMBLER_TEST_GENERATE(Simple, assembler) { __ movl(EAX, Immediate(42)); __ ret(); } ASSEMBLER_TEST_RUN(Simple, entry) { typedef int (*SimpleCode)(); EXPECT_EQ(42, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(ReadArgument, assembler) { __ movl(EAX, Address(ESP, kWordSize)); __ ret(); } ASSEMBLER_TEST_RUN(ReadArgument, entry) { typedef int (*ReadArgumentCode)(int n); EXPECT_EQ(42, reinterpret_cast(entry)(42)); EXPECT_EQ(87, reinterpret_cast(entry)(87)); } ASSEMBLER_TEST_GENERATE(AddressingModes, assembler) { __ movl(EAX, Address(ESP, 0)); __ movl(EAX, Address(EBP, 0)); __ movl(EAX, Address(EAX, 0)); __ movl(EAX, Address(ESP, kWordSize)); __ movl(EAX, Address(EBP, kWordSize)); __ movl(EAX, Address(EAX, kWordSize)); __ movl(EAX, Address(ESP, -kWordSize)); __ movl(EAX, Address(EBP, -kWordSize)); __ movl(EAX, Address(EAX, -kWordSize)); __ movl(EAX, Address(ESP, 256 * kWordSize)); __ movl(EAX, Address(EBP, 256 * kWordSize)); __ movl(EAX, Address(EAX, 256 * kWordSize)); __ movl(EAX, Address(ESP, -256 * kWordSize)); __ movl(EAX, Address(EBP, -256 * kWordSize)); __ movl(EAX, Address(EAX, -256 * kWordSize)); __ movl(EAX, Address(EAX, TIMES_1)); __ movl(EAX, Address(EAX, TIMES_2)); __ movl(EAX, Address(EAX, TIMES_4)); __ movl(EAX, Address(EAX, TIMES_8)); __ movl(EAX, Address(EBP, TIMES_2)); __ movl(EAX, Address(EAX, TIMES_2)); __ movl(EAX, Address(EBP, TIMES_2, kWordSize)); __ movl(EAX, Address(EAX, TIMES_2, kWordSize)); __ movl(EAX, Address(EBP, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(EAX, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(EAX, EBP, TIMES_2, 0)); __ movl(EAX, Address(EAX, EAX, TIMES_2, 0)); __ movl(EAX, Address(EBP, EBP, TIMES_2, 0)); __ movl(EAX, Address(EBP, EAX, TIMES_2, 0)); __ movl(EAX, Address(ESP, EBP, TIMES_2, 0)); __ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); __ movl(EAX, Address(EAX, EBP, TIMES_2, kWordSize)); __ movl(EAX, Address(EAX, EAX, TIMES_2, kWordSize)); __ movl(EAX, Address(EBP, EBP, TIMES_2, kWordSize)); __ movl(EAX, Address(EBP, EAX, TIMES_2, kWordSize)); __ movl(EAX, Address(ESP, EBP, TIMES_2, kWordSize)); __ movl(EAX, Address(ESP, EAX, TIMES_2, kWordSize)); __ movl(EAX, Address(EAX, EBP, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(EAX, EAX, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(EBP, EBP, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(EBP, EAX, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(ESP, EBP, TIMES_2, 256 * kWordSize)); __ movl(EAX, Address(ESP, EAX, TIMES_2, 256 * kWordSize)); } ASSEMBLER_TEST_RUN(AddressingModes, entry) { // Avoid running the code since it is constructed to lead to crashes. } ASSEMBLER_TEST_GENERATE(JumpAroundCrash, assembler) { Label done; // Make sure all the condition jumps work. for (Condition condition = OVERFLOW; condition <= GREATER; condition = static_cast(condition + 1)) { __ j(condition, &done); } // This isn't strictly necessary, but we do an unconditional // jump around the crashing code anyway. __ jmp(&done); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&done); __ ret(); } ASSEMBLER_TEST_RUN(JumpAroundCrash, entry) { Instr* instr = Instr::At(entry); EXPECT(!instr->IsBreakPoint()); typedef void (*JumpAroundCrashCode)(); reinterpret_cast(entry)(); } ASSEMBLER_TEST_GENERATE(NearJumpAroundCrash, assembler) { Label done; // Make sure all the condition jumps work. for (Condition condition = OVERFLOW; condition <= GREATER; condition = static_cast(condition + 1)) { __ j(condition, &done, Assembler::kNearJump); } // This isn't strictly necessary, but we do an unconditional // jump around the crashing code anyway. __ jmp(&done, Assembler::kNearJump); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&done); __ ret(); } ASSEMBLER_TEST_RUN(NearJumpAroundCrash, entry) { typedef void (*NearJumpAroundCrashCode)(); reinterpret_cast(entry)(); } ASSEMBLER_TEST_GENERATE(SimpleLoop, assembler) { __ movl(EAX, Immediate(0)); __ movl(ECX, Immediate(0)); Label loop; __ Bind(&loop); __ addl(EAX, Immediate(2)); __ incl(ECX); __ cmpl(ECX, Immediate(87)); __ j(LESS, &loop); __ ret(); } ASSEMBLER_TEST_RUN(SimpleLoop, entry) { typedef int (*SimpleLoopCode)(); EXPECT_EQ(2 * 87, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(Increment, assembler) { __ movl(EAX, Immediate(0)); __ pushl(EAX); __ incl(Address(ESP, 0)); __ movl(ECX, Address(ESP, 0)); __ incl(ECX); __ popl(EAX); __ movl(EAX, ECX); __ ret(); } ASSEMBLER_TEST_RUN(Increment, entry) { typedef int (*IncrementCode)(); EXPECT_EQ(2, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(Decrement, assembler) { __ movl(EAX, Immediate(2)); __ pushl(EAX); __ decl(Address(ESP, 0)); __ movl(ECX, Address(ESP, 0)); __ decl(ECX); __ popl(EAX); __ movl(EAX, ECX); __ ret(); } ASSEMBLER_TEST_RUN(Decrement, entry) { typedef int (*DecrementCode)(); EXPECT_EQ(0, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(AddressBinOp, assembler) { __ movl(EAX, Address(ESP, kWordSize)); __ addl(EAX, Address(ESP, kWordSize)); __ incl(EAX); __ subl(EAX, Address(ESP, kWordSize)); __ imull(EAX, Address(ESP, kWordSize)); __ ret(); } ASSEMBLER_TEST_RUN(AddressBinOp, entry) { typedef int (*AddressBinOpCode)(int a); EXPECT_EQ((2 + 2 + 1 - 2) * 2, reinterpret_cast(entry)(2)); } ASSEMBLER_TEST_GENERATE(SignedMultiply, assembler) { __ movl(EAX, Immediate(2)); __ movl(ECX, Immediate(4)); __ imull(EAX, ECX); __ imull(EAX, Immediate(1000)); __ ret(); } ASSEMBLER_TEST_RUN(SignedMultiply, entry) { typedef int (*SignedMultiply)(); EXPECT_EQ(8000, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(OverflowSignedMultiply, assembler) { __ movl(EDX, Immediate(0)); __ movl(EAX, Immediate(0x0fffffff)); __ movl(ECX, Immediate(0x0fffffff)); __ imull(EAX, ECX); __ imull(EAX, EDX); __ ret(); } ASSEMBLER_TEST_RUN(OverflowSignedMultiply, entry) { typedef int (*OverflowSignedMultiply)(); EXPECT_EQ(0, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(SignedMultiply1, assembler) { __ pushl(EBX); // preserve EBX. __ movl(EBX, Immediate(2)); __ movl(ECX, Immediate(4)); __ imull(EBX, ECX); __ imull(EBX, Immediate(1000)); __ movl(EAX, EBX); __ popl(EBX); // restore EBX. __ ret(); } ASSEMBLER_TEST_RUN(SignedMultiply1, entry) { typedef int (*SignedMultiply1)(); EXPECT_EQ(8000, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(Negate, assembler) { __ movl(ECX, Immediate(42)); __ negl(ECX); __ movl(EAX, ECX); __ ret(); } ASSEMBLER_TEST_RUN(Negate, entry) { typedef int (*Negate)(); EXPECT_EQ(-42, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(MoveExtend, assembler) { __ pushl(EBX); // preserve EBX. __ movl(EDX, Immediate(0x1234ffff)); __ movzxb(EAX, DL); // EAX = 0xff __ movsxw(EBX, EDX); // EBX = -1 __ movzxw(ECX, EDX); // ECX = 0xffff __ addl(EBX, ECX); __ addl(EAX, EBX); __ popl(EBX); // restore EBX. __ ret(); } ASSEMBLER_TEST_RUN(MoveExtend, entry) { typedef int (*MoveExtend)(); EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(MoveExtendMemory, assembler) { __ pushl(EBX); // preserve EBX. __ movl(EDX, Immediate(0x1234ffff)); __ pushl(EDX); __ movzxb(EAX, Address(ESP, 0)); // EAX = 0xff __ movsxw(EBX, Address(ESP, 0)); // EBX = -1 __ movzxw(ECX, Address(ESP, 0)); // ECX = 0xffff __ addl(ESP, Immediate(kWordSize)); __ addl(EBX, ECX); __ addl(EAX, EBX); __ popl(EBX); // restore EBX. __ ret(); } ASSEMBLER_TEST_RUN(MoveExtendMemory, entry) { typedef int (*MoveExtendMemory)(); EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(Bitwise, assembler) { __ movl(ECX, Immediate(42)); __ xorl(ECX, ECX); __ orl(ECX, Immediate(256)); __ movl(EAX, Immediate(4)); __ orl(ECX, EAX); __ movl(EAX, Immediate(0xfff0)); __ andl(ECX, EAX); __ movl(EAX, Immediate(1)); __ orl(ECX, EAX); __ xorl(ECX, Immediate(0)); __ movl(EAX, ECX); __ ret(); } ASSEMBLER_TEST_RUN(Bitwise, entry) { typedef int (*Bitwise)(); EXPECT_EQ(256 + 1, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(LogicalOps, assembler) { Label donetest1; __ movl(EAX, Immediate(4)); __ andl(EAX, Immediate(2)); __ cmpl(EAX, Immediate(0)); __ j(EQUAL, &donetest1); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest1); Label donetest2; __ movl(ECX, Immediate(4)); __ andl(ECX, Immediate(4)); __ cmpl(ECX, Immediate(0)); __ j(NOT_EQUAL, &donetest2); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest2); Label donetest3; __ movl(EAX, Immediate(0)); __ orl(EAX, Immediate(0)); __ cmpl(EAX, Immediate(0)); __ j(EQUAL, &donetest3); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest3); Label donetest4; __ movl(EAX, Immediate(4)); __ orl(EAX, Immediate(0)); __ cmpl(EAX, Immediate(0)); __ j(NOT_EQUAL, &donetest4); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest4); Label donetest5; __ movl(EAX, Immediate(1)); __ shll(EAX, Immediate(1)); __ cmpl(EAX, Immediate(2)); __ j(EQUAL, &donetest5); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest5); Label donetest6; __ movl(EAX, Immediate(1)); __ shll(EAX, Immediate(3)); __ cmpl(EAX, Immediate(8)); __ j(EQUAL, &donetest6); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest6); Label donetest7; __ movl(EAX, Immediate(2)); __ shrl(EAX, Immediate(1)); __ cmpl(EAX, Immediate(1)); __ j(EQUAL, &donetest7); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest7); Label donetest8; __ movl(EAX, Immediate(8)); __ shrl(EAX, Immediate(3)); __ cmpl(EAX, Immediate(1)); __ j(EQUAL, &donetest8); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest8); Label donetest9; __ movl(EAX, Immediate(1)); __ movl(ECX, Immediate(3)); __ shll(EAX, ECX); __ cmpl(EAX, Immediate(8)); __ j(EQUAL, &donetest9); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest9); Label donetest10; __ movl(EAX, Immediate(8)); __ movl(ECX, Immediate(3)); __ shrl(EAX, ECX); __ cmpl(EAX, Immediate(1)); __ j(EQUAL, &donetest10); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest10); Label donetest11; __ movl(EAX, Immediate(1)); __ shll(EAX, Immediate(31)); __ shrl(EAX, Immediate(3)); __ cmpl(EAX, Immediate(0x10000000)); __ j(EQUAL, &donetest11); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest11); Label donetest12; __ movl(EAX, Immediate(1)); __ shll(EAX, Immediate(31)); __ sarl(EAX, Immediate(3)); __ cmpl(EAX, Immediate(0xf0000000)); __ j(EQUAL, &donetest12); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest12); Label donetest13; __ movl(EAX, Immediate(1)); __ movl(ECX, Immediate(3)); __ shll(EAX, Immediate(31)); __ sarl(EAX, ECX); __ cmpl(EAX, Immediate(0xf0000000)); __ j(EQUAL, &donetest13); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest13); Label donetest14; __ subl(ESP, Immediate(kWordSize)); __ movl(Address(ESP, 0), Immediate(0x80000000)); __ movl(EAX, Immediate(0)); __ movl(ECX, Immediate(3)); __ sarl(Address(ESP, 0), ECX); __ shrd(Address(ESP, 0), EAX); __ cmpl(Address(ESP, 0), Immediate(0x1e000000)); __ j(EQUAL, &donetest14); __ int3(); __ Bind(&donetest14); __ addl(ESP, Immediate(kWordSize)); Label donetest15; __ subl(ESP, Immediate(kWordSize)); __ movl(Address(ESP, 0), Immediate(0xFF000000)); __ movl(EAX, Immediate(-1)); __ movl(ECX, Immediate(2)); __ shll(Address(ESP, 0), ECX); __ shld(Address(ESP, 0), EAX); __ cmpl(Address(ESP, 0), Immediate(0xF0000003)); __ j(EQUAL, &donetest15); __ int3(); __ Bind(&donetest15); __ addl(ESP, Immediate(kWordSize)); __ movl(EAX, Immediate(0)); __ ret(); } ASSEMBLER_TEST_RUN(LogicalOps, entry) { typedef int (*LogicalOpsCode)(); EXPECT_EQ(0, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(LogicalTest, assembler) { __ pushl(EBX); // save EBX. Label donetest1; __ movl(EAX, Immediate(4)); __ movl(ECX, Immediate(2)); __ testl(EAX, ECX); __ j(EQUAL, &donetest1); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest1); Label donetest2; __ movl(EDX, Immediate(4)); __ movl(ECX, Immediate(4)); __ testl(EDX, ECX); __ j(NOT_EQUAL, &donetest2); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest2); Label donetest3; __ movl(EAX, Immediate(0)); __ testl(EAX, Immediate(0)); __ j(EQUAL, &donetest3); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest3); Label donetest4; __ movl(EBX, Immediate(4)); __ testl(EBX, Immediate(4)); __ j(NOT_EQUAL, &donetest4); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest4); Label donetest5; __ movl(EBX, Immediate(0xff)); __ testl(EBX, Immediate(0xff)); __ j(NOT_EQUAL, &donetest5); // Be sure to skip this crashing code. __ movl(EAX, Immediate(0)); __ movl(Address(EAX, 0), EAX); __ Bind(&donetest5); __ movl(EAX, Immediate(0)); __ popl(EBX); // restore EBX. __ ret(); } ASSEMBLER_TEST_RUN(LogicalTest, entry) { typedef int (*LogicalTestCode)(); EXPECT_EQ(0, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(CompareSwapEQ, assembler) { __ movl(EAX, Immediate(0)); __ pushl(EAX); __ movl(EAX, Immediate(4)); __ movl(ECX, Immediate(0)); __ movl(Address(ESP, 0), EAX); __ LockCmpxchgl(Address(ESP, 0), ECX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(CompareSwapEQ, entry) { typedef int (*CompareSwapEQCode)(); EXPECT_EQ(0, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(CompareSwapNEQ, assembler) { __ movl(EAX, Immediate(0)); __ pushl(EAX); __ movl(EAX, Immediate(2)); __ movl(ECX, Immediate(4)); __ movl(Address(ESP, 0), ECX); __ LockCmpxchgl(Address(ESP, 0), ECX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(CompareSwapNEQ, entry) { typedef int (*CompareSwapNEQCode)(); EXPECT_EQ(4, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(SignedDivide, assembler) { __ movl(EAX, Immediate(-87)); __ movl(EDX, Immediate(123)); __ cdq(); __ movl(ECX, Immediate(42)); __ idivl(ECX); __ ret(); } ASSEMBLER_TEST_RUN(SignedDivide, entry) { typedef int (*SignedDivide)(); EXPECT_EQ(-87 / 42, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(Exchange, assembler) { __ movl(EAX, Immediate(123456789)); __ movl(EDX, Immediate(987654321)); __ xchgl(EAX, EDX); __ subl(EAX, EDX); __ ret(); } ASSEMBLER_TEST_RUN(Exchange, entry) { typedef int (*Exchange)(); EXPECT_EQ(987654321 - 123456789, reinterpret_cast(entry)()); } static int ComputeStackSpaceReservation(int needed, int fixed) { static const int kFrameAlignment = OS::ActivationFrameAlignment(); return (kFrameAlignment > 0) ? Utils::RoundUp(needed + fixed, kFrameAlignment) - fixed : needed; } static int LeafReturn42() { return 42; } static int LeafReturnArgument(int x) { return x + 87; } ASSEMBLER_TEST_GENERATE(CallSimpleLeaf, assembler) { ExternalLabel call1("LeafReturn42", reinterpret_cast(LeafReturn42)); ExternalLabel call2("LeafReturnArgument", reinterpret_cast(LeafReturnArgument)); int space = ComputeStackSpaceReservation(0, 4); __ AddImmediate(ESP, Immediate(-space)); __ call(&call1); __ AddImmediate(ESP, Immediate(space)); space = ComputeStackSpaceReservation(4, 4); __ AddImmediate(ESP, Immediate(-space)); __ movl(Address(ESP, 0), EAX); __ call(&call2); __ AddImmediate(ESP, Immediate(space)); __ ret(); } ASSEMBLER_TEST_RUN(CallSimpleLeaf, entry) { typedef int (*CallSimpleLeafCode)(); EXPECT_EQ(42 + 87, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(JumpSimpleLeaf, assembler) { ExternalLabel call1("LeafReturn42", reinterpret_cast(LeafReturn42)); Label L; int space = ComputeStackSpaceReservation(0, 4); __ AddImmediate(ESP, Immediate(-space)); __ call(&L); __ AddImmediate(ESP, Immediate(space)); __ ret(); __ Bind(&L); __ jmp(&call1); } ASSEMBLER_TEST_RUN(JumpSimpleLeaf, entry) { typedef int (*JumpSimpleLeafCode)(); EXPECT_EQ(42, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(JumpConditionalSimpleLeaf, assembler) { ExternalLabel call1("LeafReturn42", reinterpret_cast(LeafReturn42)); Label L; int space = ComputeStackSpaceReservation(0, 4); __ AddImmediate(ESP, Immediate(-space)); __ call(&L); __ AddImmediate(ESP, Immediate(space)); __ ret(); __ Bind(&L); __ cmpl(EAX, EAX); __ j(EQUAL, &call1); __ int3(); } ASSEMBLER_TEST_RUN(JumpConditionalSimpleLeaf, entry) { typedef int (*JumpConditionalSimpleLeafCode)(); EXPECT_EQ(42, reinterpret_cast(entry)()); } ASSEMBLER_TEST_GENERATE(SingleFPMoves, assembler) { __ movl(EAX, Immediate(bit_cast(234.0f))); __ movd(XMM0, EAX); __ movss(XMM1, XMM0); __ movss(XMM2, XMM1); __ movss(XMM3, XMM2); __ movss(XMM4, XMM3); __ movss(XMM5, XMM4); __ movss(XMM6, XMM5); __ movss(XMM7, XMM6); __ pushl(EAX); __ movl(Address(ESP, 0), Immediate(0)); __ movss(Address(ESP, 0), XMM7); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(SingleFPMoves, entry) { typedef float (*SingleFPMovesCode)(); float res = reinterpret_cast(entry)(); EXPECT_EQ(234.0f, res); } ASSEMBLER_TEST_GENERATE(SingleFPMoves2, assembler) { __ pushl(EBX); // preserve EBX. __ pushl(ECX); // preserve ECX. __ movl(EBX, Immediate(bit_cast(234.0f))); __ movd(XMM0, EBX); __ movss(XMM1, XMM0); __ movd(ECX, XMM1); __ pushl(ECX); __ flds(Address(ESP, 0)); __ popl(EAX); __ popl(ECX); __ popl(EBX); __ ret(); } ASSEMBLER_TEST_RUN(SingleFPMoves2, entry) { typedef float (*SingleFPMoves2Code)(); float res = reinterpret_cast(entry)(); EXPECT_EQ(234.0f, res); } ASSEMBLER_TEST_GENERATE(SingleFPUStackMoves, assembler) { __ movl(EAX, Immediate(1131020288)); // 234.0f __ pushl(EAX); __ flds(Address(ESP, 0)); __ xorl(ECX, ECX); __ pushl(ECX); __ fstps(Address(ESP, 0)); __ popl(EAX); __ popl(ECX); __ ret(); } ASSEMBLER_TEST_RUN(SingleFPUStackMoves, entry) { typedef int (*SingleFPUStackMovesCode)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(234.0f, (bit_cast(res))); } ASSEMBLER_TEST_GENERATE(SingleFPOperations, assembler) { __ movl(EAX, Immediate(bit_cast(12.3f))); __ movd(XMM0, EAX); __ movl(EAX, Immediate(bit_cast(3.4f))); __ movd(XMM1, EAX); __ addss(XMM0, XMM1); // 15.7f __ mulss(XMM0, XMM1); // 53.38f __ subss(XMM0, XMM1); // 49.98f __ divss(XMM0, XMM1); // 14.7f __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(SingleFPOperations, entry) { typedef float (*SingleFPOperationsCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(14.7f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) { __ movl(EAX, Immediate(bit_cast(12.3f))); __ movd(XMM0, EAX); __ shufps(XMM0, XMM0, Immediate(0x0)); __ movl(EAX, Immediate(bit_cast(3.4f))); __ movd(XMM1, EAX); __ shufps(XMM1, XMM1, Immediate(0x0)); __ addps(XMM0, XMM1); // 15.7f __ mulps(XMM0, XMM1); // 53.38f __ subps(XMM0, XMM1); // 49.98f __ divps(XMM0, XMM1); // 14.7f __ shufps(XMM0, XMM0, Immediate(0x55)); // Copy second lane into all 4 lanes. __ pushl(EAX); // Copy the low lane at ESP. __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedFPOperations, entry) { typedef float (*PackedFPOperationsCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(14.7f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) { __ movl(EAX, Immediate(bit_cast(4.0f))); __ movd(XMM0, EAX); __ shufps(XMM0, XMM0, Immediate(0x0)); __ movaps(XMM1, XMM0); // Copy XMM0 __ reciprocalps(XMM1); // 0.25 __ sqrtps(XMM1); // 0.5 __ rsqrtps(XMM0); // ~0.5 __ subps(XMM0, XMM1); // ~0.0 __ shufps(XMM0, XMM0, Immediate(0x00)); // Copy second lane into all 4 lanes. __ pushl(EAX); // Copy the low lane at ESP. __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) { typedef float (*PackedFPOperations2Code)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(0.0f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ cmppseq(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) { typedef uint32_t (*PackedCompareEQCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0x0), res); } ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ cmppsneq(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) { typedef uint32_t (*PackedCompareNEQCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0xFFFFFFFF), res); } ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ cmppslt(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedCompareLT, entry) { typedef uint32_t (*PackedCompareLTCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0xFFFFFFFF), res); } ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ cmppsle(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedCompareLE, entry) { typedef uint32_t (*PackedCompareLECode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0xFFFFFFFF), res); } ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ cmppsnlt(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) { typedef uint32_t (*PackedCompareNLTCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0x0), res); } ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ cmppsnle(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) { typedef uint32_t (*PackedCompareNLECode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0x0), res); } ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) { __ movl(EAX, Immediate(bit_cast(12.3f))); __ movd(XMM0, EAX); __ shufps(XMM0, XMM0, Immediate(0x0)); __ negateps(XMM0); __ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes. __ pushl(EAX); // Copy the low lane at ESP. __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedNegate, entry) { typedef float (*PackedNegateCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(-12.3f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) { __ movl(EAX, Immediate(bit_cast(-15.3f))); __ movd(XMM0, EAX); __ shufps(XMM0, XMM0, Immediate(0x0)); __ absps(XMM0); __ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes. // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedAbsolute, entry) { typedef float (*PackedAbsoluteCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(15.3f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(12.3f))); __ zerowps(XMM0); __ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0. // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedSetWZero, entry) { typedef float (*PackedSetWZeroCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(0.0f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedMin, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ minps(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedMin, entry) { typedef float (*PackedMinCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(2.0f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedMax, assembler) { __ set1ps(XMM0, EAX, Immediate(bit_cast(2.0f))); __ set1ps(XMM1, EAX, Immediate(bit_cast(4.0f))); __ maxps(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedMax, entry) { typedef float (*PackedMaxCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(4.0f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(PackedLogicalOr, assembler) { static const struct ALIGN16 { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } constant1 = { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 }; static const struct ALIGN16 { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } constant2 = { 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F }; __ movups(XMM0, Address::Absolute(reinterpret_cast(&constant1))); __ movups(XMM1, Address::Absolute(reinterpret_cast(&constant2))); __ orps(XMM0, XMM1); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) { typedef uint32_t (*PackedLogicalOrCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(0xFFFFFFFF, res); } ASSEMBLER_TEST_GENERATE(PackedLogicalAnd, assembler) { static const struct ALIGN16 { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } constant1 = { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 }; static const struct ALIGN16 { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } constant2 = { 0x0F0FFF0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F }; __ movups(XMM0, Address::Absolute(reinterpret_cast(&constant1))); __ andps(XMM0, Address::Absolute(reinterpret_cast(&constant2))); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) { typedef uint32_t (*PackedLogicalAndCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0x0000F000), res); } ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) { static const struct ALIGN16 { uint32_t a; uint32_t b; uint32_t c; uint32_t d; } constant1 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; __ movups(XMM0, Address::Absolute(reinterpret_cast(&constant1))); __ notps(XMM0); // Copy the low lane at ESP. __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) { typedef uint32_t (*PackedLogicalNotCode)(); uint32_t res = reinterpret_cast(entry)(); EXPECT_EQ(static_cast(0x0), res); } ASSEMBLER_TEST_GENERATE(SingleFPOperationsStack, assembler) { __ movl(EAX, Immediate(bit_cast(12.3f))); __ movd(XMM0, EAX); __ addss(XMM0, Address(ESP, kWordSize)); // 15.7f __ mulss(XMM0, Address(ESP, kWordSize)); // 53.38f __ subss(XMM0, Address(ESP, kWordSize)); // 49.98f __ divss(XMM0, Address(ESP, kWordSize)); // 14.7f __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(SingleFPOperationsStack, entry) { typedef float (*SingleFPOperationsStackCode)(float f); float res = reinterpret_cast(entry)(3.4); EXPECT_FLOAT_EQ(14.7f, res, 0.001f); } ASSEMBLER_TEST_GENERATE(DoubleFPMoves, assembler) { int64_t l = bit_cast(1024.67); __ movl(EAX, Immediate(Utils::High32Bits(l))); __ pushl(EAX); __ movl(EAX, Immediate(Utils::Low32Bits(l))); __ pushl(EAX); __ movsd(XMM0, Address(ESP, 0)); __ movsd(XMM1, XMM0); __ movsd(XMM2, XMM1); __ movsd(XMM3, XMM2); __ movsd(XMM4, XMM3); __ movsd(XMM5, XMM4); __ movsd(XMM6, XMM5); __ movsd(XMM7, XMM6); __ movl(Address(ESP, 0), Immediate(0)); __ movl(Address(ESP, kWordSize), Immediate(0)); __ movsd(XMM0, Address(ESP, 0)); __ movsd(Address(ESP, 0), XMM7); __ movsd(XMM7, Address(ESP, 0)); __ movaps(XMM6, XMM7); __ movaps(XMM5, XMM6); __ movaps(XMM4, XMM5); __ movaps(XMM3, XMM4); __ movaps(XMM2, XMM3); __ movaps(XMM1, XMM2); __ movaps(XMM0, XMM1); __ movl(Address(ESP, 0), Immediate(0)); __ movl(Address(ESP, kWordSize), Immediate(0)); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleFPMoves, entry) { typedef double (*DoubleFPMovesCode)(); double res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(1024.67, res, 0.0001); } ASSEMBLER_TEST_GENERATE(DoubleFPUStackMoves, assembler) { int64_t l = bit_cast(1024.67); __ movl(EAX, Immediate(Utils::High32Bits(l))); __ pushl(EAX); __ movl(EAX, Immediate(Utils::Low32Bits(l))); __ pushl(EAX); __ fldl(Address(ESP, 0)); __ movl(Address(ESP, 0), Immediate(0)); __ movl(Address(ESP, kWordSize), Immediate(0)); __ fstpl(Address(ESP, 0)); __ popl(EAX); __ popl(EDX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleFPUStackMoves, entry) { typedef int64_t (*DoubleFPUStackMovesCode)(); int64_t res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(1024.67, (bit_cast(res)), 0.001); } ASSEMBLER_TEST_GENERATE(DoubleFPOperations, assembler) { int64_t l = bit_cast(12.3); __ movl(EAX, Immediate(Utils::High32Bits(l))); __ pushl(EAX); __ movl(EAX, Immediate(Utils::Low32Bits(l))); __ pushl(EAX); __ movsd(XMM0, Address(ESP, 0)); __ popl(EAX); __ popl(EAX); l = bit_cast(3.4); __ movl(EAX, Immediate(Utils::High32Bits(l))); __ pushl(EAX); __ movl(EAX, Immediate(Utils::Low32Bits(l))); __ pushl(EAX); __ movsd(XMM1, Address(ESP, 0)); __ addsd(XMM0, XMM1); // 15.7 __ mulsd(XMM0, XMM1); // 53.38 __ subsd(XMM0, XMM1); // 49.98 __ divsd(XMM0, XMM1); // 14.7 __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleFPOperations, entry) { typedef double (*DoubleFPOperationsCode)(); double res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(14.7, res, 0.001); } ASSEMBLER_TEST_GENERATE(DoubleFPOperationsStack, assembler) { int64_t l = bit_cast(12.3); __ movl(EAX, Immediate(Utils::High32Bits(l))); __ pushl(EAX); __ movl(EAX, Immediate(Utils::Low32Bits(l))); __ pushl(EAX); __ movsd(XMM0, Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ addsd(XMM0, Address(ESP, kWordSize)); // 15.7 __ mulsd(XMM0, Address(ESP, kWordSize)); // 53.38 __ subsd(XMM0, Address(ESP, kWordSize)); // 49.98 __ divsd(XMM0, Address(ESP, kWordSize)); // 14.7 __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleFPOperationsStack, entry) { typedef double (*DoubleFPOperationsStackCode)(double d); double res = reinterpret_cast(entry)(3.4); EXPECT_FLOAT_EQ(14.7, res, 0.001); } ASSEMBLER_TEST_GENERATE(IntToDoubleConversion, assembler) { __ movl(EDX, Immediate(6)); __ cvtsi2sd(XMM1, EDX); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM1); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(IntToDoubleConversion, entry) { typedef double (*IntToDoubleConversionCode)(); double res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(6.0, res, 0.001); } ASSEMBLER_TEST_GENERATE(IntToDoubleConversion2, assembler) { __ filds(Address(ESP, kWordSize)); __ ret(); } ASSEMBLER_TEST_RUN(IntToDoubleConversion2, entry) { typedef double (*IntToDoubleConversion2Code)(int i); double res = reinterpret_cast(entry)(3); EXPECT_FLOAT_EQ(3.0, res, 0.001); } ASSEMBLER_TEST_GENERATE(IntToFloatConversion, assembler) { __ movl(EDX, Immediate(6)); __ cvtsi2ss(XMM1, EDX); __ pushl(EAX); __ movss(Address(ESP, 0), XMM1); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(IntToFloatConversion, entry) { typedef float (*IntToFloatConversionCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(6.0, res, 0.001); } ASSEMBLER_TEST_GENERATE(FloatToIntConversionRound, assembler) { __ movsd(XMM1, Address(ESP, kWordSize)); __ cvtss2si(EDX, XMM1); __ movl(EAX, EDX); __ ret(); } ASSEMBLER_TEST_RUN(FloatToIntConversionRound, entry) { typedef int (*FloatToIntConversionRoundCode)(float f); int res = reinterpret_cast(entry)(12.3); EXPECT_EQ(12, res); res = reinterpret_cast(entry)(12.8); EXPECT_EQ(13, res); } ASSEMBLER_TEST_GENERATE(FloatToIntConversionTrunc, assembler) { __ movsd(XMM1, Address(ESP, kWordSize)); __ cvttss2si(EDX, XMM1); __ movl(EAX, EDX); __ ret(); } ASSEMBLER_TEST_RUN(FloatToIntConversionTrunc, entry) { typedef int (*FloatToIntConversionTruncCode)(float f); int res = reinterpret_cast(entry)(12.3); EXPECT_EQ(12, res); res = reinterpret_cast(entry)(12.8); EXPECT_EQ(12, res); } ASSEMBLER_TEST_GENERATE(FloatToDoubleConversion, assembler) { __ movl(EAX, Immediate(bit_cast(12.3f))); __ movd(XMM1, EAX); __ xorl(EAX, EAX); __ cvtss2sd(XMM2, XMM1); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM2); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(FloatToDoubleConversion, entry) { typedef double (*FloatToDoubleConversionCode)(); double res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(12.3, res, 0.001); } ASSEMBLER_TEST_GENERATE(FloatCompare, assembler) { // Count errors in EAX. EAX is zero if no errors found. Label is_nan, is_above, is_ok, cont_1, cont_2; // Test 12.3f vs 12.5f. __ xorl(EAX, EAX); __ movl(EDX, Immediate(bit_cast(12.3f))); __ movd(XMM0, EDX); __ movl(EDX, Immediate(bit_cast(12.5f))); __ movd(XMM1, EDX); __ comiss(XMM0, XMM1); __ j(PARITY_EVEN, &is_nan); __ Bind(&cont_1); __ j(ABOVE, &is_above); __ Bind(&cont_2); __ j(BELOW, &is_ok); __ incl(EAX); __ Bind(&is_ok); // Test NaN. Label is_nan_ok; // Create NaN by dividing 0.0f/0.0f. __ movl(EDX, Immediate(bit_cast(0.0f))); __ movd(XMM1, EDX); __ divss(XMM1, XMM1); __ comiss(XMM1, XMM1); __ j(PARITY_EVEN, &is_nan_ok); __ incl(EAX); __ Bind(&is_nan_ok); // EAX is 0 if all tests passed. __ ret(); __ Bind(&is_nan); __ incl(EAX); __ jmp(&cont_1); __ Bind(&is_above); __ incl(EAX); __ jmp(&cont_2); } ASSEMBLER_TEST_RUN(FloatCompare, entry) { typedef int (*FloatCompareCode)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(0, res); } ASSEMBLER_TEST_GENERATE(DoubleCompare, assembler) { int64_t a = bit_cast(12.3); int64_t b = bit_cast(12.5); __ movl(EDX, Immediate(Utils::High32Bits(a))); __ pushl(EDX); __ movl(EDX, Immediate(Utils::Low32Bits(a))); __ pushl(EDX); __ movsd(XMM0, Address(ESP, 0)); __ popl(EDX); __ popl(EDX); __ movl(EDX, Immediate(Utils::High32Bits(b))); __ pushl(EDX); __ movl(EDX, Immediate(Utils::Low32Bits(b))); __ pushl(EDX); __ movsd(XMM1, Address(ESP, 0)); __ popl(EDX); __ popl(EDX); // Count errors in EAX. EAX is zero if no errors found. Label is_nan, is_above, is_ok, cont_1, cont_2; // Test 12.3 vs 12.5. __ xorl(EAX, EAX); __ comisd(XMM0, XMM1); __ j(PARITY_EVEN, &is_nan); __ Bind(&cont_1); __ j(ABOVE, &is_above); __ Bind(&cont_2); __ j(BELOW, &is_ok); __ incl(EAX); __ Bind(&is_ok); // Test NaN. Label is_nan_ok; // Create NaN by dividing 0.0d/0.0d. int64_t zero = bit_cast(0.0); __ movl(EDX, Immediate(Utils::High32Bits(zero))); __ pushl(EDX); __ movl(EDX, Immediate(Utils::Low32Bits(zero))); __ pushl(EDX); __ movsd(XMM1, Address(ESP, 0)); __ popl(EDX); __ popl(EDX); __ divsd(XMM1, XMM1); __ comisd(XMM1, XMM1); __ j(PARITY_EVEN, &is_nan_ok); __ incl(EAX); __ Bind(&is_nan_ok); // EAX is 0 if all tests passed. __ ret(); __ Bind(&is_nan); __ incl(EAX); __ jmp(&cont_1); __ Bind(&is_above); __ incl(EAX); __ jmp(&cont_2); } ASSEMBLER_TEST_RUN(DoubleCompare, entry) { typedef int (*DoubleCompareCode)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(0, res); } ASSEMBLER_TEST_GENERATE(DoubleToFloatConversion, assembler) { int64_t l = bit_cast(12.3); __ movl(EAX, Immediate(Utils::High32Bits(l))); __ pushl(EAX); __ movl(EAX, Immediate(Utils::Low32Bits(l))); __ pushl(EAX); __ movsd(XMM0, Address(ESP, 0)); __ cvtsd2ss(XMM1, XMM0); __ movss(Address(ESP, 0), XMM1); __ flds(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleToFloatConversion, entry) { typedef float (*DoubleToFloatConversionCode)(); float res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(12.3f, res, 0.001); } ASSEMBLER_TEST_GENERATE(DoubleToIntConversionRound, assembler) { __ movsd(XMM3, Address(ESP, kWordSize)); __ cvtsd2si(EAX, XMM3); __ ret(); } ASSEMBLER_TEST_RUN(DoubleToIntConversionRound, entry) { typedef int (*DoubleToIntConversionRoundCode)(double d); int res = reinterpret_cast(entry)(12.3); EXPECT_EQ(12, res); res = reinterpret_cast(entry)(12.8); EXPECT_EQ(13, res); } ASSEMBLER_TEST_GENERATE(DoubleToIntConversionTrunc, assembler) { __ movsd(XMM3, Address(ESP, kWordSize)); __ cvttsd2si(EAX, XMM3); __ ret(); } ASSEMBLER_TEST_RUN(DoubleToIntConversionTrunc, entry) { typedef int (*DoubleToIntConversionTruncCode)(double d); int res = reinterpret_cast(entry)(12.3); EXPECT_EQ(12, res); res = reinterpret_cast(entry)(12.8); EXPECT_EQ(12, res); } ASSEMBLER_TEST_GENERATE(DoubleToDoubleTrunc, assembler) { __ movsd(XMM3, Address(ESP, kWordSize)); __ roundsd(XMM2, XMM3, Assembler::kRoundToZero); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM2); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, entry) { typedef double (*DoubleToDoubleTruncCode)(double d); double res = reinterpret_cast(entry)(12.3); EXPECT_EQ(12.0, res); res = reinterpret_cast(entry)(12.8); EXPECT_EQ(12.0, res); res = reinterpret_cast(entry)(-12.3); EXPECT_EQ(-12.0, res); res = reinterpret_cast(entry)(-12.8); EXPECT_EQ(-12.0, res); } ASSEMBLER_TEST_GENERATE(DoubleToDoubleRound, assembler) { __ movsd(XMM3, Address(ESP, kWordSize)); __ DoubleRound(XMM2, XMM3, XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM2); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleToDoubleRound, entry) { typedef double (*DoubleToDoubleRoundCode)(double d); double res = reinterpret_cast(entry)(12.3); EXPECT_EQ(12.0, res); res = reinterpret_cast(entry)(12.8); EXPECT_EQ(13.0, res); res = reinterpret_cast(entry)(0.5); EXPECT_EQ(1.0, res); res = reinterpret_cast(entry)(-12.3); EXPECT_EQ(-12.0, res); res = reinterpret_cast(entry)(-12.8); EXPECT_EQ(-13.0, res); res = reinterpret_cast(entry)(-0.5); EXPECT_EQ(-1.0, res); res = reinterpret_cast(entry)(0.49999999999999994); EXPECT_EQ(0.0, res); res = reinterpret_cast(entry)(-0.49999999999999994); EXPECT_EQ(-0.0, res); res = reinterpret_cast(entry)(9007199254740991.0); EXPECT_EQ(9007199254740991.0, res); res = reinterpret_cast(entry)(-9007199254740991.0); EXPECT_EQ(-9007199254740991.0, res); } static const double kDoubleConst = 3.226; ASSEMBLER_TEST_GENERATE(GlobalAddress, assembler) { __ movsd(XMM0, Address::Absolute(reinterpret_cast(&kDoubleConst))); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(GlobalAddress, entry) { typedef double (*GlobalAddressCode)(); double res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(kDoubleConst, res, 0.000001); } ASSEMBLER_TEST_GENERATE(Sine, assembler) { __ flds(Address(ESP, kWordSize)); __ fsin(); __ ret(); } ASSEMBLER_TEST_RUN(Sine, entry) { typedef float (*SineCode)(float f); const float kFloatConst = 0.7; float res = reinterpret_cast(entry)(kFloatConst); EXPECT_FLOAT_EQ(sin(kFloatConst), res, 0.0001); } ASSEMBLER_TEST_GENERATE(Cosine, assembler) { __ flds(Address(ESP, kWordSize)); __ fcos(); __ ret(); } ASSEMBLER_TEST_RUN(Cosine, entry) { typedef float (*CosineCode)(float f); const float kFloatConst = 0.7; float res = reinterpret_cast(entry)(kFloatConst); EXPECT_FLOAT_EQ(cos(kFloatConst), res, 0.0001); } ASSEMBLER_TEST_GENERATE(Tangent, assembler) { __ fldl(Address(ESP, kWordSize)); __ fptan(); __ ffree(0); __ fincstp(); __ ret(); } ASSEMBLER_TEST_RUN(Tangent, entry) { typedef double (*TangentCode)(double d); const double kDoubleConst = 0.6108652375000001; double res = reinterpret_cast(entry)(kDoubleConst); EXPECT_FLOAT_EQ(tan(kDoubleConst), res, 0.0001); } ASSEMBLER_TEST_GENERATE(SquareRootFloat, assembler) { __ movss(XMM0, Address(ESP, kWordSize)); __ sqrtss(XMM1, XMM0); __ pushl(EAX); __ movss(Address(ESP, 0), XMM1); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(SquareRootFloat, entry) { typedef float (*SquareRootFloatCode)(float f); const float kFloatConst = 0.7; float res = reinterpret_cast(entry)(kFloatConst); EXPECT_FLOAT_EQ(sqrt(kFloatConst), res, 0.0001); } ASSEMBLER_TEST_GENERATE(SquareRootDouble, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ sqrtsd(XMM1, XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM1); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(SquareRootDouble, entry) { typedef double (*SquareRootDoubleCode)(double d); const double kDoubleConst = .7; double res = reinterpret_cast(entry)(kDoubleConst); EXPECT_FLOAT_EQ(sqrt(kDoubleConst), res, 0.0001); } ASSEMBLER_TEST_GENERATE(FloatNegate, assembler) { __ movss(XMM0, Address(ESP, kWordSize)); __ FloatNegate(XMM0); __ pushl(EAX); __ movss(Address(ESP, 0), XMM0); __ flds(Address(ESP, 0)); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(FloatNegate, entry) { typedef float (*FloatNegateCode)(float f); const float kFloatConst = 12.345; float res = reinterpret_cast(entry)(kFloatConst); EXPECT_FLOAT_EQ(-kFloatConst, res, 0.0001); } ASSEMBLER_TEST_GENERATE(DoubleNegate, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ DoubleNegate(XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleNegate, entry) { typedef double (*DoubleNegateCode)(double f); const double kDoubleConst = 12.345; double res = reinterpret_cast(entry)(kDoubleConst); EXPECT_FLOAT_EQ(-kDoubleConst, res, 0.0001); } ASSEMBLER_TEST_GENERATE(LongMulReg, assembler) { __ movl(ECX, Address(ESP, kWordSize)); __ movl(EAX, Address(ESP, 2 * kWordSize)); __ imull(ECX); __ ret(); } ASSEMBLER_TEST_RUN(LongMulReg, entry) { typedef int64_t (*LongMulRegCode)(int a, int b); const int a = -12; const int b = 13; const int64_t mul_res = a * b; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ(mul_res, res); } ASSEMBLER_TEST_GENERATE(LongMulAddress, assembler) { __ movl(EAX, Address(ESP, 2 * kWordSize)); __ imull(Address(ESP, kWordSize)); __ ret(); } ASSEMBLER_TEST_RUN(LongMulAddress, entry) { typedef int64_t (*LongMulAddressCode)(int a, int b); const int a = -12; const int b = 13; const int64_t mul_res = a * b; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ(mul_res, res); } ASSEMBLER_TEST_GENERATE(LongUnsignedMulReg, assembler) { __ movl(ECX, Address(ESP, kWordSize)); __ movl(EAX, Address(ESP, 2 * kWordSize)); __ mull(ECX); __ ret(); } ASSEMBLER_TEST_RUN(LongUnsignedMulReg, entry) { typedef uint64_t (*LongUnsignedMulRegCode)(uint32_t a, uint32_t b); uint32_t a = 3; uint32_t b = 13; uint64_t mul_res = a * b; uint64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ(mul_res, res); a = 4021288948u; b = 13; res = reinterpret_cast(entry)(a, b); mul_res = static_cast(a) * static_cast(b); EXPECT_EQ(mul_res, res); } ASSEMBLER_TEST_GENERATE(LongUnsignedMulAddress, assembler) { __ movl(EAX, Address(ESP, 2 * kWordSize)); __ mull(Address(ESP, kWordSize)); __ ret(); } ASSEMBLER_TEST_RUN(LongUnsignedMulAddress, entry) { typedef uint64_t (*LongUnsignedMulAddressCode)(uint32_t a, uint32_t b); uint32_t a = 12; uint32_t b = 13; uint64_t mul_res = a * b; uint64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ(mul_res, res); a = 4294967284u; b = 13; res = reinterpret_cast(entry)(a, b); mul_res = static_cast(a) * static_cast(b); EXPECT_EQ(mul_res, res); } ASSEMBLER_TEST_GENERATE(LongAddReg, assembler) { // Preserve clobbered callee-saved register (EBX). __ pushl(EBX); __ movl(EAX, Address(ESP, 2 * kWordSize)); // left low. __ movl(EDX, Address(ESP, 3 * kWordSize)); // left high. __ movl(ECX, Address(ESP, 4 * kWordSize)); // right low. __ movl(EBX, Address(ESP, 5 * kWordSize)); // right high __ addl(EAX, ECX); __ adcl(EDX, EBX); __ popl(EBX); // Result is in EAX/EDX. __ ret(); } ASSEMBLER_TEST_RUN(LongAddReg, entry) { typedef int64_t (*LongAddRegCode)(int64_t a, int64_t b); int64_t a = 12; int64_t b = 14; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a + b), res); a = 2147483647; b = 600000; res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a + b), res); } ASSEMBLER_TEST_GENERATE(LongAddAddress, assembler) { __ movl(EAX, Address(ESP, 1 * kWordSize)); // left low. __ movl(EDX, Address(ESP, 2 * kWordSize)); // left high. __ addl(EAX, Address(ESP, 3 * kWordSize)); // low. __ adcl(EDX, Address(ESP, 4 * kWordSize)); // high. // Result is in EAX/EDX. __ ret(); } ASSEMBLER_TEST_RUN(LongAddAddress, entry) { typedef int64_t (*LongAddAddressCode)(int64_t a, int64_t b); int64_t a = 12; int64_t b = 14; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a + b), res); a = 2147483647; b = 600000; res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a + b), res); } ASSEMBLER_TEST_GENERATE(LongSubReg, assembler) { // Preserve clobbered callee-saved register (EBX). __ pushl(EBX); __ movl(EAX, Address(ESP, 2 * kWordSize)); // left low. __ movl(EDX, Address(ESP, 3 * kWordSize)); // left high. __ movl(ECX, Address(ESP, 4 * kWordSize)); // right low. __ movl(EBX, Address(ESP, 5 * kWordSize)); // right high __ subl(EAX, ECX); __ sbbl(EDX, EBX); __ popl(EBX); // Result is in EAX/EDX. __ ret(); } ASSEMBLER_TEST_RUN(LongSubReg, entry) { typedef int64_t (*LongSubRegCode)(int64_t a, int64_t b); int64_t a = 12; int64_t b = 14; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a - b), res); a = 600000; b = 2147483647; res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a - b), res); } ASSEMBLER_TEST_GENERATE(LongSubAddress, assembler) { __ movl(EAX, Address(ESP, 1 * kWordSize)); // left low. __ movl(EDX, Address(ESP, 2 * kWordSize)); // left high. __ subl(EAX, Address(ESP, 3 * kWordSize)); // low. __ sbbl(EDX, Address(ESP, 4 * kWordSize)); // high. // Result is in EAX/EDX. __ ret(); } ASSEMBLER_TEST_RUN(LongSubAddress, entry) { typedef int64_t (*LongSubAddressCode)(int64_t a, int64_t b); int64_t a = 12; int64_t b = 14; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a - b), res); a = 600000; b = 2147483647; res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a - b), res); } ASSEMBLER_TEST_GENERATE(LongSubAddress2, assembler) { // Preserve clobbered callee-saved register (EBX). __ pushl(EBX); __ movl(EAX, Address(ESP, 2 * kWordSize)); // left low. __ movl(EDX, Address(ESP, 3 * kWordSize)); // left high. __ movl(ECX, Address(ESP, 4 * kWordSize)); // right low. __ movl(EBX, Address(ESP, 5 * kWordSize)); // right high __ subl(ESP, Immediate(2 * kWordSize)); __ movl(Address(ESP, 0 * kWordSize), EAX); // left low. __ movl(Address(ESP, 1 * kWordSize), EDX); // left high. __ subl(Address(ESP, 0 * kWordSize), ECX); __ sbbl(Address(ESP, 1 * kWordSize), EBX); __ movl(EAX, Address(ESP, 0 * kWordSize)); __ movl(EDX, Address(ESP, 1 * kWordSize)); __ addl(ESP, Immediate(2 * kWordSize)); __ popl(EBX); // Result is in EAX/EDX. __ ret(); } ASSEMBLER_TEST_RUN(LongSubAddress2, entry) { typedef int64_t (*LongSubAddress2Code)(int64_t a, int64_t b); int64_t a = 12; int64_t b = 14; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a - b), res); a = 600000; b = 2147483647; res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a - b), res); } ASSEMBLER_TEST_GENERATE(LongAddAddress2, assembler) { // Preserve clobbered callee-saved register (EBX). __ pushl(EBX); __ movl(EAX, Address(ESP, 2 * kWordSize)); // left low. __ movl(EDX, Address(ESP, 3 * kWordSize)); // left high. __ movl(ECX, Address(ESP, 4 * kWordSize)); // right low. __ movl(EBX, Address(ESP, 5 * kWordSize)); // right high __ subl(ESP, Immediate(2 * kWordSize)); __ movl(Address(ESP, 0 * kWordSize), EAX); // left low. __ movl(Address(ESP, 1 * kWordSize), EDX); // left high. __ addl(Address(ESP, 0 * kWordSize), ECX); __ adcl(Address(ESP, 1 * kWordSize), EBX); __ movl(EAX, Address(ESP, 0 * kWordSize)); __ movl(EDX, Address(ESP, 1 * kWordSize)); __ addl(ESP, Immediate(2 * kWordSize)); __ popl(EBX); // Result is in EAX/EDX. __ ret(); } ASSEMBLER_TEST_RUN(LongAddAddress2, entry) { typedef int64_t (*LongAddAddress2Code)(int64_t a, int64_t b); int64_t a = 12; int64_t b = 14; int64_t res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a + b), res); a = 600000; b = 2147483647; res = reinterpret_cast(entry)(a, b); EXPECT_EQ((a + b), res); } // Testing only the lower 64-bit value of 'cvtdq2pd'. ASSEMBLER_TEST_GENERATE(IntegerToDoubleConversion, assembler) { __ movsd(XMM1, Address(ESP, kWordSize)); __ cvtdq2pd(XMM2, XMM1); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM2); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(IntegerToDoubleConversion, entry) { typedef double (*IntegerToDoubleConversionCode)(int32_t); const int32_t val = -12; double res = reinterpret_cast(entry)(val); EXPECT_FLOAT_EQ(static_cast(val), res, 0.001); } // Implement with truncation. ASSEMBLER_TEST_GENERATE(FPUStoreLong, assembler) { __ fldl(Address(ESP, kWordSize)); __ pushl(EAX); __ pushl(EAX); __ fnstcw(Address(ESP, 0)); __ movzxw(EAX, Address(ESP, 0)); __ orl(EAX, Immediate(0x0c00)); __ movw(Address(ESP, kWordSize), EAX); __ fldcw(Address(ESP, kWordSize)); __ pushl(EAX); __ pushl(EAX); __ fistpl(Address(ESP, 0)); __ popl(EAX); __ popl(EDX); __ fldcw(Address(ESP, 0)); __ addl(ESP, Immediate(kWordSize * 2)); __ ret(); } ASSEMBLER_TEST_RUN(FPUStoreLong, entry) { typedef int64_t (*FPUStoreLongCode)(double d); double val = 12.2; int64_t res = reinterpret_cast(entry)(val); EXPECT_EQ(static_cast(val), res); val = -12.2; res = reinterpret_cast(entry)(val); EXPECT_EQ(static_cast(val), res); val = 12.8; res = reinterpret_cast(entry)(val); EXPECT_EQ(static_cast(val), res); val = -12.8; res = reinterpret_cast(entry)(val); EXPECT_EQ(static_cast(val), res); } ASSEMBLER_TEST_GENERATE(XorpdZeroing, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ xorpd(XMM0, XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(XorpdZeroing, entry) { typedef double (*XorpdZeroingCode)(double d); double res = reinterpret_cast(entry)(12.56e3); EXPECT_FLOAT_EQ(0.0, res, 0.0001); } ASSEMBLER_TEST_GENERATE(Pxor, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ pxor(XMM0, XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(Pxor, entry) { typedef double (*PxorCode)(double d); double res = reinterpret_cast(entry)(12.3456e3); EXPECT_FLOAT_EQ(0.0, res, 0.0); } ASSEMBLER_TEST_GENERATE(Orpd, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ xorpd(XMM1, XMM1); __ DoubleNegate(XMM1); __ orpd(XMM0, XMM1); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(Orpd, entry) { typedef double (*OrpdCode)(double d); double res = reinterpret_cast(entry)(12.56e3); EXPECT_FLOAT_EQ(-12.56e3, res, 0.0); } ASSEMBLER_TEST_GENERATE(Pextrd0, assembler) { if (CPUFeatures::sse4_1_supported()) { __ movsd(XMM0, Address(ESP, kWordSize)); __ pextrd(EAX, XMM0, Immediate(0)); } __ ret(); } ASSEMBLER_TEST_RUN(Pextrd0, entry) { if (CPUFeatures::sse4_1_supported()) { typedef int32_t (*PextrdCode0)(double d); int32_t res = reinterpret_cast(entry)(123456789); EXPECT_EQ(0x54000000, res); } } ASSEMBLER_TEST_GENERATE(Pextrd1, assembler) { if (CPUFeatures::sse4_1_supported()) { __ movsd(XMM0, Address(ESP, kWordSize)); __ pextrd(EAX, XMM0, Immediate(1)); } __ ret(); } ASSEMBLER_TEST_RUN(Pextrd1, entry) { if (CPUFeatures::sse4_1_supported()) { typedef int32_t (*PextrdCode1)(double d); int32_t res = reinterpret_cast(entry)(123456789); EXPECT_EQ(0x419d6f34, res); } } ASSEMBLER_TEST_GENERATE(Pmovsxdq, assembler) { if (CPUFeatures::sse4_1_supported()) { __ movsd(XMM0, Address(ESP, kWordSize)); __ pmovsxdq(XMM0, XMM0); __ pextrd(EAX, XMM0, Immediate(1)); } __ ret(); } ASSEMBLER_TEST_RUN(Pmovsxdq, entry) { if (CPUFeatures::sse4_1_supported()) { typedef int32_t (*PmovsxdqCode)(double d); int32_t res = reinterpret_cast(entry)(123456789); EXPECT_EQ(0, res); } } ASSEMBLER_TEST_GENERATE(Pcmpeqq, assembler) { if (CPUFeatures::sse4_1_supported()) { __ movsd(XMM0, Address(ESP, kWordSize)); __ xorpd(XMM1, XMM1); __ pcmpeqq(XMM0, XMM1); __ movd(EAX, XMM0); } __ ret(); } ASSEMBLER_TEST_RUN(Pcmpeqq, entry) { if (CPUFeatures::sse4_1_supported()) { typedef int32_t (*PcmpeqqCode)(double d); int32_t res = reinterpret_cast(entry)(0); EXPECT_EQ(-1, res); } } ASSEMBLER_TEST_GENERATE(AndPd, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ andpd(XMM0, XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(AndPd, entry) { typedef double (*AndpdCode)(double d); double res = reinterpret_cast(entry)(12.56e3); EXPECT_FLOAT_EQ(12.56e3, res, 0.0); } ASSEMBLER_TEST_GENERATE(Movq, assembler) { __ movq(XMM0, Address(ESP, kWordSize)); __ subl(ESP, Immediate(kDoubleSize)); __ movq(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ addl(ESP, Immediate(kDoubleSize)); __ ret(); } ASSEMBLER_TEST_RUN(Movq, entry) { typedef double (*MovqCode)(double d); double res = reinterpret_cast(entry)(12.34e5); EXPECT_FLOAT_EQ(12.34e5, res, 0.0); } ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ DoubleAbs(XMM0); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM0); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(DoubleAbs, entry) { typedef double (*DoubleAbsCode)(double d); double val = -12.45; double res = reinterpret_cast(entry)(val); EXPECT_FLOAT_EQ(-val, res, 0.001); val = 12.45; res = reinterpret_cast(entry)(val); EXPECT_FLOAT_EQ(val, res, 0.001); } ASSEMBLER_TEST_GENERATE(ExtractSignBits, assembler) { __ movsd(XMM0, Address(ESP, kWordSize)); __ movmskpd(EAX, XMM0); __ andl(EAX, Immediate(0x1)); __ ret(); } ASSEMBLER_TEST_RUN(ExtractSignBits, entry) { typedef int (*ExtractSignBits)(double d); int res = reinterpret_cast(entry)(1.0); EXPECT_EQ(0, res); res = reinterpret_cast(entry)(-1.0); EXPECT_EQ(1, res); res = reinterpret_cast(entry)(-0.0); EXPECT_EQ(1, res); } // Return -1 if signed, 1 if not signed and 0 otherwise. ASSEMBLER_TEST_GENERATE(ConditionalMovesSign, assembler) { // Preserve clobbered callee-saved register (EBX). __ pushl(EBX); __ movl(EDX, Address(ESP, 2 * kWordSize)); __ xorl(EAX, EAX); __ movl(EBX, Immediate(1)); __ movl(ECX, Immediate(-1)); __ testl(EDX, EDX); __ cmovs(EAX, ECX); // return -1. __ testl(EDX, EDX); __ cmovns(EAX, EBX); // return 1. // Restore callee-saved register (EBX) and return. __ popl(EBX); __ ret(); } ASSEMBLER_TEST_RUN(ConditionalMovesSign, entry) { typedef int (*ConditionalMovesSignCode)(int i); int res = reinterpret_cast(entry)(785); EXPECT_EQ(1, res); res = reinterpret_cast(entry)(-12); EXPECT_EQ(-1, res); } ASSEMBLER_TEST_GENERATE(TestLoadDoubleConstant, assembler) { __ LoadDoubleConstant(XMM3, -12.34); __ pushl(EAX); __ pushl(EAX); __ movsd(Address(ESP, 0), XMM3); __ fldl(Address(ESP, 0)); __ popl(EAX); __ popl(EAX); __ ret(); } ASSEMBLER_TEST_RUN(TestLoadDoubleConstant, entry) { typedef double (*TestLoadDoubleConstantCode)(); double res = reinterpret_cast(entry)(); EXPECT_FLOAT_EQ(-12.34, res, 0.0001); } ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) { ObjectStore* object_store = Isolate::Current()->object_store(); const Object& obj = Object::ZoneHandle(object_store->smi_class()); Label fail; __ LoadObject(EAX, obj); __ CompareObject(EAX, obj); __ j(NOT_EQUAL, &fail); __ LoadObject(ECX, obj); __ CompareObject(ECX, obj); __ j(NOT_EQUAL, &fail); __ movl(EAX, Immediate(1)); // OK __ ret(); __ Bind(&fail); __ movl(EAX, Immediate(0)); // Fail. __ ret(); } ASSEMBLER_TEST_RUN(TestObjectCompare, entry) { typedef bool (*TestObjectCompare)(); bool res = reinterpret_cast(entry)(); EXPECT_EQ(true, res); } ASSEMBLER_TEST_GENERATE(TestNop, assembler) { __ nop(1); __ nop(2); __ nop(3); __ nop(4); __ nop(5); __ nop(6); __ nop(7); __ nop(8); __ movl(EAX, Immediate(assembler->CodeSize())); // Return code size. __ ret(); } ASSEMBLER_TEST_RUN(TestNop, entry) { typedef int (*TestNop)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(36, res); // 36 nop bytes emitted. } ASSEMBLER_TEST_GENERATE(TestAlign0, assembler) { __ Align(4, 0); __ movl(EAX, Immediate(assembler->CodeSize())); // Return code size. __ ret(); } ASSEMBLER_TEST_RUN(TestAlign0, entry) { typedef int (*TestAlign0)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(0, res); // 0 bytes emitted. } ASSEMBLER_TEST_GENERATE(TestAlign1, assembler) { __ nop(1); __ Align(4, 0); __ movl(EAX, Immediate(assembler->CodeSize())); // Return code size. __ ret(); } ASSEMBLER_TEST_RUN(TestAlign1, entry) { typedef int (*TestAlign1)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(4, res); // 4 bytes emitted. } ASSEMBLER_TEST_GENERATE(TestAlign1Offset1, assembler) { __ nop(1); __ Align(4, 1); __ movl(EAX, Immediate(assembler->CodeSize())); // Return code size. __ ret(); } ASSEMBLER_TEST_RUN(TestAlign1Offset1, entry) { typedef int (*TestAlign1Offset1)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(3, res); // 3 bytes emitted. } ASSEMBLER_TEST_GENERATE(TestAlignLarge, assembler) { __ nop(1); __ Align(16, 0); __ movl(EAX, Immediate(assembler->CodeSize())); // Return code size. __ ret(); } ASSEMBLER_TEST_RUN(TestAlignLarge, entry) { typedef int (*TestAlignLarge)(); int res = reinterpret_cast(entry)(); EXPECT_EQ(16, res); // 16 bytes emitted. } // Called from assembler_test.cc. ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) { __ pushl(CTX); __ movl(CTX, Address(ESP, 2 * kWordSize)); __ movl(EAX, Address(ESP, 3 * kWordSize)); __ movl(ECX, Address(ESP, 4 * kWordSize)); __ pushl(EAX); __ StoreIntoObject(ECX, FieldAddress(ECX, GrowableObjectArray::data_offset()), EAX); __ popl(EAX); __ popl(CTX); __ ret(); } } // namespace dart #endif // defined TARGET_ARCH_IA32