Files
sdk/runtime/vm/assembler_x64_test.cc
T
Ryan Macnak 877284947b Rename TARGET_OS_* to HOST_OS_*.
Like HOST_ARCH_*, HOST_OS_* describes the OS the VM is running on, which may be different from the OS the VM is generating code for during AOT compilation.

Currently we conflate the two when emitting AOT as assembly, and we get away with it because Flutter only uses assembly for targeting iOS and one can only target iOS from a Mac, but we expect to use assembly for Android as well so native tools can unwind Dart frames.

R=zra@google.com

Review-Url: https://codereview.chromium.org/2750843003 .
2017-03-15 13:11:05 -07:00

3590 lines
96 KiB
C++

// 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_X64)
#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(ReadArgument, assembler) {
__ pushq(CallingConventions::kArg1Reg);
__ movq(RAX, Address(RSP, 0));
__ popq(RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(ReadArgument, test) {
typedef int64_t (*ReadArgumentCode)(int64_t n);
ReadArgumentCode id = reinterpret_cast<ReadArgumentCode>(test->entry());
EXPECT_EQ(42, id(42));
EXPECT_EQ(87, id(87));
static const int64_t kLargeConstant = 0x1234567812345678LL;
EXPECT_EQ(kLargeConstant, id(kLargeConstant));
}
ASSEMBLER_TEST_GENERATE(AddressingModes, assembler) {
__ movq(RAX, Address(RSP, 0));
__ movq(RAX, Address(RBP, 0));
__ movq(RAX, Address(RAX, 0));
__ movq(RAX, Address(R10, 0));
__ movq(RAX, Address(R12, 0));
__ movq(RAX, Address(R13, 0));
__ movq(R10, Address(RAX, 0));
__ movq(RAX, Address(RSP, kWordSize));
__ movq(RAX, Address(RBP, kWordSize));
__ movq(RAX, Address(RAX, kWordSize));
__ movq(RAX, Address(R10, kWordSize));
__ movq(RAX, Address(R12, kWordSize));
__ movq(RAX, Address(R13, kWordSize));
__ movq(RAX, Address(RSP, -kWordSize));
__ movq(RAX, Address(RBP, -kWordSize));
__ movq(RAX, Address(RAX, -kWordSize));
__ movq(RAX, Address(R10, -kWordSize));
__ movq(RAX, Address(R12, -kWordSize));
__ movq(RAX, Address(R13, -kWordSize));
__ movq(RAX, Address(RSP, 256 * kWordSize));
__ movq(RAX, Address(RBP, 256 * kWordSize));
__ movq(RAX, Address(RAX, 256 * kWordSize));
__ movq(RAX, Address(R10, 256 * kWordSize));
__ movq(RAX, Address(R12, 256 * kWordSize));
__ movq(RAX, Address(R13, 256 * kWordSize));
__ movq(RAX, Address(RSP, -256 * kWordSize));
__ movq(RAX, Address(RBP, -256 * kWordSize));
__ movq(RAX, Address(RAX, -256 * kWordSize));
__ movq(RAX, Address(R10, -256 * kWordSize));
__ movq(RAX, Address(R12, -256 * kWordSize));
__ movq(RAX, Address(R13, -256 * kWordSize));
__ movq(RAX, Address(RAX, TIMES_1, 0));
__ movq(RAX, Address(RAX, TIMES_2, 0));
__ movq(RAX, Address(RAX, TIMES_4, 0));
__ movq(RAX, Address(RAX, TIMES_8, 0));
__ movq(RAX, Address(RBP, TIMES_2, 0));
__ movq(RAX, Address(RAX, TIMES_2, 0));
__ movq(RAX, Address(R10, TIMES_2, 0));
__ movq(RAX, Address(R12, TIMES_2, 0));
__ movq(RAX, Address(R13, TIMES_2, 0));
__ movq(RAX, Address(RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, RBP, TIMES_2, 0));
__ movq(RAX, Address(RAX, RAX, TIMES_2, 0));
__ movq(RAX, Address(RAX, R10, TIMES_2, 0));
__ movq(RAX, Address(RAX, R12, TIMES_2, 0));
__ movq(RAX, Address(RAX, R13, TIMES_2, 0));
__ movq(RAX, Address(RBP, RBP, TIMES_2, 0));
__ movq(RAX, Address(RBP, RAX, TIMES_2, 0));
__ movq(RAX, Address(RBP, R10, TIMES_2, 0));
__ movq(RAX, Address(RBP, R12, TIMES_2, 0));
__ movq(RAX, Address(RBP, R13, TIMES_2, 0));
__ movq(RAX, Address(RSP, RBP, TIMES_2, 0));
__ movq(RAX, Address(RSP, RAX, TIMES_2, 0));
__ movq(RAX, Address(RSP, R10, TIMES_2, 0));
__ movq(RAX, Address(RSP, R12, TIMES_2, 0));
__ movq(RAX, Address(RSP, R13, TIMES_2, 0));
__ movq(RAX, Address(R10, RBP, TIMES_2, 0));
__ movq(RAX, Address(R10, RAX, TIMES_2, 0));
__ movq(RAX, Address(R10, R10, TIMES_2, 0));
__ movq(RAX, Address(R10, R12, TIMES_2, 0));
__ movq(RAX, Address(R10, R13, TIMES_2, 0));
__ movq(RAX, Address(R12, RBP, TIMES_2, 0));
__ movq(RAX, Address(R12, RAX, TIMES_2, 0));
__ movq(RAX, Address(R12, R10, TIMES_2, 0));
__ movq(RAX, Address(R12, R12, TIMES_2, 0));
__ movq(RAX, Address(R12, R13, TIMES_2, 0));
__ movq(RAX, Address(R13, RBP, TIMES_2, 0));
__ movq(RAX, Address(R13, RAX, TIMES_2, 0));
__ movq(RAX, Address(R13, R10, TIMES_2, 0));
__ movq(RAX, Address(R13, R12, TIMES_2, 0));
__ movq(RAX, Address(R13, R13, TIMES_2, 0));
__ movq(RAX, Address(RAX, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RSP, 0));
__ movq(RAX, Address::AddressBaseImm32(RBP, 0));
__ movq(RAX, Address::AddressBaseImm32(RAX, 0));
__ movq(RAX, Address::AddressBaseImm32(R10, 0));
__ movq(RAX, Address::AddressBaseImm32(R12, 0));
__ movq(RAX, Address::AddressBaseImm32(R13, 0));
__ movq(R10, Address::AddressBaseImm32(RAX, 0));
__ movq(RAX, Address::AddressBaseImm32(RSP, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RBP, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RAX, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R10, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R12, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R13, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RSP, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RBP, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RAX, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R10, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R12, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R13, -kWordSize));
}
ASSEMBLER_TEST_RUN(AddressingModes, test) {
// 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>(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.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&done);
__ ret();
}
ASSEMBLER_TEST_RUN(JumpAroundCrash, test) {
Instr* instr = Instr::At(test->entry());
EXPECT(!instr->IsBreakPoint());
typedef void (*JumpAroundCrashCode)();
reinterpret_cast<JumpAroundCrashCode>(test->entry())();
}
ASSEMBLER_TEST_GENERATE(SimpleLoop, assembler) {
__ movq(RAX, Immediate(0));
__ movq(RCX, Immediate(0));
Label loop;
__ Bind(&loop);
__ addq(RAX, Immediate(2));
__ incq(RCX);
__ cmpq(RCX, Immediate(87));
__ j(LESS, &loop);
__ ret();
}
ASSEMBLER_TEST_RUN(SimpleLoop, test) {
typedef int (*SimpleLoopCode)();
EXPECT_EQ(2 * 87, reinterpret_cast<SimpleLoopCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(Cmpb, assembler) {
Label done;
__ movq(RAX, Immediate(1));
__ pushq(Immediate(0xffffff11));
__ cmpb(Address(RSP, 0), Immediate(0x11));
__ j(EQUAL, &done, Assembler::kNearJump);
__ movq(RAX, Immediate(0));
__ Bind(&done);
__ popq(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Cmpb, test) {
typedef int (*CmpbCode)();
EXPECT_EQ(1, reinterpret_cast<CmpbCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(Testb, assembler) {
Label done;
__ movq(RAX, Immediate(1));
__ movq(RCX, Immediate(0));
__ pushq(Immediate(0xffffff11));
__ testb(Address(RSP, 0), Immediate(0x10));
// Fail if zero flag set.
__ cmoveq(RAX, RCX);
__ testb(Address(RSP, 0), Immediate(0x20));
// Fail if zero flag not set.
__ j(ZERO, &done);
__ movq(RAX, Immediate(0));
__ Bind(&done);
__ popq(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Testb, test) {
typedef int (*TestbCode)();
EXPECT_EQ(1, reinterpret_cast<TestbCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(Increment, assembler) {
__ movq(RAX, Immediate(0));
__ pushq(RAX);
__ incl(Address(RSP, 0));
__ incq(Address(RSP, 0));
__ movq(RCX, Address(RSP, 0));
__ incq(RCX);
__ popq(RAX);
__ movq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Increment, test) {
typedef int (*IncrementCode)();
EXPECT_EQ(3, reinterpret_cast<IncrementCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(IncrementLong, assembler) {
__ movq(RAX, Immediate(0xffffffff));
__ pushq(RAX);
__ incq(Address(RSP, 0));
__ movq(RCX, Address(RSP, 0));
__ incq(RCX);
__ popq(RAX);
__ movq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(IncrementLong, test) {
typedef int64_t (*IncrementCodeLong)();
EXPECT_EQ(0x100000001, reinterpret_cast<IncrementCodeLong>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(Decrement, assembler) {
__ movq(RAX, Immediate(3));
__ pushq(RAX);
__ decl(Address(RSP, 0));
__ decq(Address(RSP, 0));
__ movq(RCX, Address(RSP, 0));
__ decq(RCX);
__ popq(RAX);
__ movq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Decrement, test) {
typedef int (*DecrementCode)();
EXPECT_EQ(0, reinterpret_cast<DecrementCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(DecrementLong, assembler) {
__ movq(RAX, Immediate(0x100000001));
__ pushq(RAX);
__ decq(Address(RSP, 0));
__ movq(RCX, Address(RSP, 0));
__ decq(RCX);
__ popq(RAX);
__ movq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(DecrementLong, test) {
typedef int64_t (*DecrementCodeLong)();
EXPECT_EQ(0xffffffff, reinterpret_cast<DecrementCodeLong>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SignedMultiply, assembler) {
__ movl(RAX, Immediate(2));
__ movl(RCX, Immediate(4));
__ imull(RAX, RCX);
__ imull(RAX, Immediate(1000));
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply, test) {
typedef int (*SignedMultiply)();
EXPECT_EQ(8000, reinterpret_cast<SignedMultiply>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(UnsignedMultiply, assembler) {
__ movl(RAX, Immediate(-1)); // RAX = 0xFFFFFFFF
__ movl(RCX, Immediate(16)); // RCX = 0x10
__ mull(RCX); // RDX:RAX = RAX * RCX = 0x0FFFFFFFF0
__ movq(RAX, RDX); // Return high32(0x0FFFFFFFF0) == 0x0F
__ ret();
}
ASSEMBLER_TEST_RUN(UnsignedMultiply, test) {
typedef int (*UnsignedMultiply)();
EXPECT_EQ(15, reinterpret_cast<UnsignedMultiply>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SignedMultiply64, assembler) {
__ pushq(R15); // Callee saved.
__ movq(RAX, Immediate(2));
__ movq(RCX, Immediate(4));
__ imulq(RAX, RCX);
__ movq(R8, Immediate(2));
__ movq(R9, Immediate(4));
__ pushq(R9);
__ imulq(R8, Address(RSP, 0));
__ popq(R9);
__ addq(RAX, R8);
__ movq(R10, Immediate(2));
__ movq(R11, Immediate(4));
__ imulq(R10, R11);
__ addq(RAX, R10);
__ movq(R15, Immediate(2));
__ imulq(R15, Immediate(4));
__ addq(RAX, R15);
__ popq(R15);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply64, test) {
typedef int64_t (*SignedMultiply64)();
EXPECT_EQ(32, reinterpret_cast<SignedMultiply64>(test->entry())());
}
static const int64_t kLargeConstant = 0x1234567887654321;
static const int64_t kAnotherLargeConstant = 987654321987654321LL;
static const int64_t kProductLargeConstants = 0x5bbb29a7f52fbbd1;
ASSEMBLER_TEST_GENERATE(SignedMultiplyLong, assembler) {
Label done;
__ movq(RAX, Immediate(kLargeConstant));
__ movq(RCX, Immediate(kAnotherLargeConstant));
__ imulq(RAX, RCX);
__ imulq(RCX, Immediate(kLargeConstant));
__ cmpq(RAX, RCX);
__ j(EQUAL, &done);
__ int3();
__ Bind(&done);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiplyLong, test) {
typedef int64_t (*SignedMultiplyLong)();
EXPECT_EQ(kProductLargeConstants,
reinterpret_cast<SignedMultiplyLong>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(OverflowSignedMultiply, assembler) {
__ movl(RDX, Immediate(0));
__ movl(RAX, Immediate(0x0fffffff));
__ movl(RCX, Immediate(0x0fffffff));
__ imull(RAX, RCX);
__ imull(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(OverflowSignedMultiply, test) {
typedef int (*OverflowSignedMultiply)();
EXPECT_EQ(0, reinterpret_cast<OverflowSignedMultiply>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SignedMultiply1, assembler) {
__ movl(RDX, Immediate(2));
__ movl(RCX, Immediate(4));
__ imull(RDX, RCX);
__ imull(RDX, Immediate(1000));
__ movl(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply1, test) {
typedef int (*SignedMultiply1)();
EXPECT_EQ(8000, reinterpret_cast<SignedMultiply1>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SignedMultiply2, assembler) {
__ pushq(R15); // Callee saved.
__ movl(R15, Immediate(2));
__ imull(R15, Immediate(1000));
__ movl(RAX, R15);
__ popq(R15);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply2, test) {
typedef int (*SignedMultiply2)();
EXPECT_EQ(2000, reinterpret_cast<SignedMultiply2>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(UnsignedMultiplyLong, assembler) {
__ movq(RAX, Immediate(-1)); // RAX = 0xFFFFFFFFFFFFFFFF
__ movq(RCX, Immediate(16)); // RCX = 0x10
__ mulq(RCX); // RDX:RAX = RAX * RCX = 0x0FFFFFFFFFFFFFFFF0
__ movq(RAX, RDX); // Return high64(0x0FFFFFFFFFFFFFFFF0) == 0x0F
__ ret();
}
ASSEMBLER_TEST_RUN(UnsignedMultiplyLong, test) {
typedef int64_t (*UnsignedMultiplyLong)();
EXPECT_EQ(15, reinterpret_cast<UnsignedMultiplyLong>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SignedDivide, assembler) {
__ movl(RAX, Immediate(-87));
__ movl(RDX, Immediate(123));
__ cdq();
__ movl(RCX, Immediate(42));
__ idivl(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedDivide, test) {
typedef int32_t (*SignedDivide)();
EXPECT_EQ(-87 / 42, reinterpret_cast<SignedDivide>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(UnsignedDivide, assembler) {
const int32_t low = 0;
const int32_t high = 0xf0000000;
const int32_t divisor = 0xffffffff;
__ movl(RAX, Immediate(low));
__ movl(RDX, Immediate(high));
__ movl(RCX, Immediate(divisor));
__ divl(RCX); // RAX = RDX:RAX / RCX =
// = 0xf000000000000000 / 0xffffffff = 0xf0000000
__ ret();
}
ASSEMBLER_TEST_RUN(UnsignedDivide, test) {
typedef uint32_t (*UnsignedDivide)();
EXPECT_EQ(0xf0000000, reinterpret_cast<UnsignedDivide>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SignedDivideLong, assembler) {
__ movq(RAX, Immediate(kLargeConstant));
__ movq(RDX, Immediate(123));
__ cqo(); // Clear RDX.
__ movq(RCX, Immediate(42));
__ idivq(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedDivideLong, test) {
typedef int64_t (*SignedDivideLong)();
EXPECT_EQ(kLargeConstant / 42,
reinterpret_cast<SignedDivideLong>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(UnsignedDivideLong, assembler) {
const int64_t low = 0;
const int64_t high = 0xf000000000000000;
const int64_t divisor = 0xffffffffffffffff;
__ movq(RAX, Immediate(low));
__ movq(RDX, Immediate(high));
__ movq(RCX, Immediate(divisor));
__ divq(RCX); // RAX = RDX:RAX / RCX =
// = 0xf0000000000000000000000000000000 /
// 0xffffffffffffffff = 0xf000000000000000
__ ret();
}
ASSEMBLER_TEST_RUN(UnsignedDivideLong, test) {
typedef uint64_t (*UnsignedDivideLong)();
EXPECT_EQ(0xf000000000000000,
reinterpret_cast<UnsignedDivideLong>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(Negate, assembler) {
__ movq(RCX, Immediate(42));
__ negq(RCX);
__ movq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Negate, test) {
typedef int (*Negate)();
EXPECT_EQ(-42, reinterpret_cast<Negate>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(BitScanReverse, assembler) {
__ pushq(CallingConventions::kArg1Reg);
__ movq(RCX, Address(RSP, 0));
__ movq(RAX, Immediate(666)); // Marker for conditional write.
__ bsrq(RAX, RCX);
__ popq(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(BitScanReverse, test) {
typedef int (*Bsr)(int input);
Bsr call = reinterpret_cast<Bsr>(test->entry());
EXPECT_EQ(666, call(0));
EXPECT_EQ(0, call(1));
EXPECT_EQ(1, call(2));
EXPECT_EQ(1, call(3));
EXPECT_EQ(2, call(4));
EXPECT_EQ(5, call(42));
EXPECT_EQ(31, call(-1));
}
ASSEMBLER_TEST_GENERATE(MoveExtend, assembler) {
__ movq(RDX, Immediate(0xffff));
__ movzxb(RAX, RDX); // RAX = 0xff
__ movsxw(R8, RDX); // R8 = -1
__ movzxw(RCX, RDX); // RCX = 0xffff
__ addq(R8, RCX);
__ addq(RAX, R8);
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtend, test) {
typedef int (*MoveExtend)();
EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtend>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(MoveExtend32, assembler) {
__ movq(RDX, Immediate(0xffffffff));
__ movsxd(RDX, RDX);
__ movq(RAX, Immediate(0x7fffffff));
__ movsxd(RAX, RAX);
__ addq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtend32, test) {
typedef intptr_t (*MoveExtend)();
EXPECT_EQ(0x7ffffffe, reinterpret_cast<MoveExtend>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(MoveExtendMemory, assembler) {
__ movq(RDX, Immediate(0x123456781234ffff));
__ pushq(RDX);
__ movzxb(RAX, Address(RSP, 0)); // RAX = 0xff
__ movsxw(R8, Address(RSP, 0)); // R8 = -1
__ movzxw(RCX, Address(RSP, 0)); // RCX = 0xffff
__ addq(RSP, Immediate(kWordSize));
__ addq(R8, RCX);
__ addq(RAX, R8);
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtendMemory, test) {
typedef int (*MoveExtendMemory)();
EXPECT_EQ(0xff - 1 + 0xffff,
reinterpret_cast<MoveExtendMemory>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(MoveExtend32Memory, assembler) {
__ pushq(Immediate(0xffffffff));
__ pushq(Immediate(0x7fffffff));
__ movsxd(RDX, Address(RSP, kWordSize));
__ movsxd(RAX, Address(RSP, 0));
__ addq(RSP, Immediate(kWordSize * 2));
__ addq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtend32Memory, test) {
typedef intptr_t (*MoveExtend)();
EXPECT_EQ(0x7ffffffe, reinterpret_cast<MoveExtend>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(MoveWord, assembler) {
__ xorq(RAX, RAX);
__ pushq(Immediate(0));
__ movq(RAX, RSP);
__ movq(RCX, Immediate(-1));
__ movw(Address(RAX, 0), RCX);
__ movzxw(RAX, Address(RAX, 0)); // RAX = 0xffff
__ addq(RSP, Immediate(kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(MoveWord, test) {
typedef int (*MoveWord)();
EXPECT_EQ(0xffff, reinterpret_cast<MoveWord>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(MoveWordRex, assembler) {
__ pushq(Immediate(0));
__ movq(R8, RSP);
__ movq(R9, Immediate(-1));
__ movw(Address(R8, 0), R9);
__ movzxw(R8, Address(R8, 0)); // 0xffff
__ xorq(RAX, RAX);
__ addq(RAX, R8); // RAX = 0xffff
__ addq(RSP, Immediate(kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(MoveWordRex, test) {
typedef int (*MoveWordRex)();
EXPECT_EQ(0xffff, reinterpret_cast<MoveWordRex>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(LongAddReg, assembler) {
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Address(RSP, 0)); // left low.
__ movl(RDX, Address(RSP, 4)); // left high.
__ movl(RCX, Address(RSP, 8)); // right low.
__ movl(R8, Address(RSP, 12)); // right high
__ addl(RAX, RCX);
__ adcl(RDX, R8);
// Result is in RAX/RDX.
__ movl(Address(RSP, 0), RAX); // result low.
__ movl(Address(RSP, 4), RDX); // result high.
__ popq(RAX);
__ popq(RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(LongAddReg, test) {
typedef int64_t (*LongAddRegCode)(int64_t a, int64_t b);
int64_t a = 12;
int64_t b = 14;
int64_t res = reinterpret_cast<LongAddRegCode>(test->entry())(a, b);
EXPECT_EQ((a + b), res);
a = 2147483647;
b = 600000;
res = reinterpret_cast<LongAddRegCode>(test->entry())(a, b);
EXPECT_EQ((a + b), res);
}
ASSEMBLER_TEST_GENERATE(LongAddImmediate, assembler) {
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Address(RSP, 0)); // left low.
__ movl(RDX, Address(RSP, 4)); // left high.
__ addl(RAX, Immediate(12)); // right low immediate.
__ adcl(RDX, Immediate(11)); // right high immediate.
// Result is in RAX/RDX.
__ movl(Address(RSP, 0), RAX); // result low.
__ movl(Address(RSP, 4), RDX); // result high.
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(LongAddImmediate, test) {
typedef int64_t (*LongAddImmediateCode)(int64_t a);
int64_t a = (13LL << 32) + 14;
int64_t b = (11LL << 32) + 12;
int64_t res = reinterpret_cast<LongAddImmediateCode>(test->entry())(a);
EXPECT_EQ((a + b), res);
a = (13LL << 32) - 1;
res = reinterpret_cast<LongAddImmediateCode>(test->entry())(a);
EXPECT_EQ((a + b), res);
}
ASSEMBLER_TEST_GENERATE(LongAddAddress, assembler) {
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Address(RSP, 0)); // left low.
__ movl(RDX, Address(RSP, 4)); // left high.
__ addl(RAX, Address(RSP, 8)); // low.
__ adcl(RDX, Address(RSP, 12)); // high.
// Result is in RAX/RDX.
__ movl(Address(RSP, 0), RAX); // result low.
__ movl(Address(RSP, 4), RDX); // result high.
__ popq(RAX);
__ popq(RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(LongAddAddress, test) {
typedef int64_t (*LongAddAddressCode)(int64_t a, int64_t b);
int64_t a = 12;
int64_t b = 14;
int64_t res = reinterpret_cast<LongAddAddressCode>(test->entry())(a, b);
EXPECT_EQ((a + b), res);
a = 2147483647;
b = 600000;
res = reinterpret_cast<LongAddAddressCode>(test->entry())(a, b);
EXPECT_EQ((a + b), res);
}
ASSEMBLER_TEST_GENERATE(LongSubReg, assembler) {
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Address(RSP, 0)); // left low.
__ movl(RDX, Address(RSP, 4)); // left high.
__ movl(RCX, Address(RSP, 8)); // right low.
__ movl(R8, Address(RSP, 12)); // right high
__ subl(RAX, RCX);
__ sbbl(RDX, R8);
// Result is in RAX/RDX.
__ movl(Address(RSP, 0), RAX); // result low.
__ movl(Address(RSP, 4), RDX); // result high.
__ popq(RAX);
__ popq(RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(LongSubReg, test) {
typedef int64_t (*LongSubRegCode)(int64_t a, int64_t b);
int64_t a = 12;
int64_t b = 14;
int64_t res = reinterpret_cast<LongSubRegCode>(test->entry())(a, b);
EXPECT_EQ((a - b), res);
a = 600000;
b = 2147483647;
res = reinterpret_cast<LongSubRegCode>(test->entry())(a, b);
EXPECT_EQ((a - b), res);
}
ASSEMBLER_TEST_GENERATE(LongSubImmediate, assembler) {
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Address(RSP, 0)); // left low.
__ movl(RDX, Address(RSP, 4)); // left high.
__ subl(RAX, Immediate(12)); // right low immediate.
__ sbbl(RDX, Immediate(11)); // right high immediate.
// Result is in RAX/RDX.
__ movl(Address(RSP, 0), RAX); // result low.
__ movl(Address(RSP, 4), RDX); // result high.
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(LongSubImmediate, test) {
typedef int64_t (*LongSubImmediateCode)(int64_t a);
int64_t a = (13LL << 32) + 14;
int64_t b = (11LL << 32) + 12;
int64_t res = reinterpret_cast<LongSubImmediateCode>(test->entry())(a);
EXPECT_EQ((a - b), res);
a = (13LL << 32) + 10;
res = reinterpret_cast<LongSubImmediateCode>(test->entry())(a);
EXPECT_EQ((a - b), res);
}
ASSEMBLER_TEST_GENERATE(LongSubAddress, assembler) {
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Address(RSP, 0)); // left low.
__ movl(RDX, Address(RSP, 4)); // left high.
__ subl(RAX, Address(RSP, 8)); // low.
__ sbbl(RDX, Address(RSP, 12)); // high.
// Result is in RAX/RDX.
__ movl(Address(RSP, 0), RAX); // result low.
__ movl(Address(RSP, 4), RDX); // result high.
__ popq(RAX);
__ popq(RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(LongSubAddress, test) {
typedef int64_t (*LongSubAddressCode)(int64_t a, int64_t b);
int64_t a = 12;
int64_t b = 14;
int64_t res = reinterpret_cast<LongSubAddressCode>(test->entry())(a, b);
EXPECT_EQ((a - b), res);
a = 600000;
b = 2147483647;
res = reinterpret_cast<LongSubAddressCode>(test->entry())(a, b);
EXPECT_EQ((a - b), res);
}
ASSEMBLER_TEST_GENERATE(AddReg, assembler) {
__ movq(R10, CallingConventions::kArg1Reg); // al.
__ addq(R10, CallingConventions::kArg3Reg); // bl.
__ movq(RAX, CallingConventions::kArg2Reg); // ah.
__ adcq(RAX, CallingConventions::kArg4Reg); // bh.
// RAX = high64(ah:al + bh:bl).
__ ret();
}
ASSEMBLER_TEST_RUN(AddReg, test) {
typedef int64_t (*AddRegCode)(int64_t al, int64_t ah, int64_t bl, int64_t bh);
int64_t al = 11;
int64_t ah = 12;
int64_t bl = 13;
int64_t bh = 14;
int64_t res = reinterpret_cast<AddRegCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah + bh), res);
al = -1;
res = reinterpret_cast<AddRegCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah + bh + 1), res);
}
ASSEMBLER_TEST_GENERATE(AddImmediate, assembler) {
__ movq(R10, CallingConventions::kArg1Reg); // al.
__ addq(R10, Immediate(13)); // bl.
__ movq(RAX, CallingConventions::kArg2Reg); // ah.
__ adcq(RAX, Immediate(14)); // bh.
// RAX = high64(ah:al + bh:bl).
__ ret();
}
ASSEMBLER_TEST_RUN(AddImmediate, test) {
typedef int64_t (*AddImmediateCode)(int64_t al, int64_t ah);
int64_t al = 11;
int64_t ah = 12;
int64_t bh = 14;
int64_t res = reinterpret_cast<AddImmediateCode>(test->entry())(al, ah);
EXPECT_EQ((ah + bh), res);
al = -1;
res = reinterpret_cast<AddImmediateCode>(test->entry())(al, ah);
EXPECT_EQ((ah + bh + 1), res);
}
ASSEMBLER_TEST_GENERATE(AddAddress, assembler) {
__ pushq(CallingConventions::kArg4Reg);
__ pushq(CallingConventions::kArg3Reg);
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movq(R10, Address(RSP, 0 * kWordSize)); // al.
__ addq(R10, Address(RSP, 2 * kWordSize)); // bl.
__ movq(RAX, Address(RSP, 1 * kWordSize)); // ah.
__ adcq(RAX, Address(RSP, 3 * kWordSize)); // bh.
// RAX = high64(ah:al + bh:bl).
__ Drop(4);
__ ret();
}
ASSEMBLER_TEST_RUN(AddAddress, test) {
typedef int64_t (*AddCode)(int64_t al, int64_t ah, int64_t bl, int64_t bh);
int64_t al = 11;
int64_t ah = 12;
int64_t bl = 13;
int64_t bh = 14;
int64_t res = reinterpret_cast<AddCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah + bh), res);
al = -1;
res = reinterpret_cast<AddCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah + bh + 1), res);
}
ASSEMBLER_TEST_GENERATE(SubReg, assembler) {
__ movq(R10, CallingConventions::kArg1Reg); // al.
__ subq(R10, CallingConventions::kArg3Reg); // bl.
__ movq(RAX, CallingConventions::kArg2Reg); // ah.
__ sbbq(RAX, CallingConventions::kArg4Reg); // bh.
// RAX = high64(ah:al - bh:bl).
__ ret();
}
ASSEMBLER_TEST_RUN(SubReg, test) {
typedef int64_t (*SubRegCode)(int64_t al, int64_t ah, int64_t bl, int64_t bh);
int64_t al = 14;
int64_t ah = 13;
int64_t bl = 12;
int64_t bh = 11;
int64_t res = reinterpret_cast<SubRegCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah - bh), res);
al = 10;
res = reinterpret_cast<SubRegCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah - bh - 1), res);
}
ASSEMBLER_TEST_GENERATE(SubImmediate, assembler) {
__ movq(R10, CallingConventions::kArg1Reg); // al.
__ subq(R10, Immediate(12)); // bl.
__ movq(RAX, CallingConventions::kArg2Reg); // ah.
__ sbbq(RAX, Immediate(11)); // bh.
// RAX = high64(ah:al - bh:bl).
__ ret();
}
ASSEMBLER_TEST_RUN(SubImmediate, test) {
typedef int64_t (*SubImmediateCode)(int64_t al, int64_t ah);
int64_t al = 14;
int64_t ah = 13;
int64_t bh = 11;
int64_t res = reinterpret_cast<SubImmediateCode>(test->entry())(al, ah);
EXPECT_EQ((ah - bh), res);
al = 10;
res = reinterpret_cast<SubImmediateCode>(test->entry())(al, ah);
EXPECT_EQ((ah - bh - 1), res);
}
ASSEMBLER_TEST_GENERATE(SubAddress, assembler) {
__ pushq(CallingConventions::kArg4Reg);
__ pushq(CallingConventions::kArg3Reg);
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movq(R10, Address(RSP, 0 * kWordSize)); // al.
__ subq(R10, Address(RSP, 2 * kWordSize)); // bl.
__ movq(RAX, Address(RSP, 1 * kWordSize)); // ah.
__ sbbq(RAX, Address(RSP, 3 * kWordSize)); // bh.
// RAX = high64(ah:al - bh:bl).
__ Drop(4);
__ ret();
}
ASSEMBLER_TEST_RUN(SubAddress, test) {
typedef int64_t (*SubCode)(int64_t al, int64_t ah, int64_t bl, int64_t bh);
int64_t al = 14;
int64_t ah = 13;
int64_t bl = 12;
int64_t bh = 11;
int64_t res = reinterpret_cast<SubCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah - bh), res);
al = 10;
res = reinterpret_cast<SubCode>(test->entry())(al, ah, bl, bh);
EXPECT_EQ((ah - bh - 1), res);
}
ASSEMBLER_TEST_GENERATE(Bitwise, assembler) {
__ movq(R10, Immediate(-1));
__ orl(Address(CallingConventions::kArg1Reg, 0), R10);
__ orl(Address(CallingConventions::kArg2Reg, 0), R10);
__ movl(RCX, Immediate(42));
__ xorl(RCX, RCX);
__ orl(RCX, Immediate(256));
__ movl(RAX, Immediate(4));
__ orl(RCX, RAX);
__ movl(RAX, Immediate(0xfff0));
__ andl(RCX, RAX);
__ movl(RAX, Immediate(1));
__ orl(RCX, RAX);
__ movl(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Bitwise, test) {
uint64_t f1 = 0;
uint64_t f2 = 0;
typedef int (*Bitwise)(void*, void*);
int result = reinterpret_cast<Bitwise>(test->entry())(&f1, &f2);
EXPECT_EQ(256 + 1, result);
EXPECT_EQ(kMaxUint32, f1);
EXPECT_EQ(kMaxUint32, f2);
}
ASSEMBLER_TEST_GENERATE(Bitwise64, assembler) {
Label error;
__ movq(RAX, Immediate(42));
__ pushq(RAX);
__ xorq(RAX, Address(RSP, 0));
__ popq(RCX);
__ cmpq(RAX, Immediate(0));
__ j(NOT_EQUAL, &error);
__ movq(RCX, Immediate(0xFF));
__ movq(RAX, Immediate(0x5));
__ xorq(RCX, RAX);
__ cmpq(RCX, Immediate(0xFF ^ 0x5));
__ j(NOT_EQUAL, &error);
__ pushq(Immediate(0xFF));
__ movq(RCX, Immediate(0x5));
__ xorq(Address(RSP, 0), RCX);
__ popq(RCX);
__ cmpq(RCX, Immediate(0xFF ^ 0x5));
__ j(NOT_EQUAL, &error);
__ xorq(RCX, RCX);
__ orq(RCX, Immediate(256));
__ movq(RAX, Immediate(4));
__ orq(RCX, RAX);
__ movq(RAX, Immediate(0xfff0));
__ andq(RCX, RAX);
__ movq(RAX, Immediate(1));
__ pushq(RAX);
__ orq(RCX, Address(RSP, 0));
__ xorq(RCX, Immediate(0));
__ popq(RAX);
__ movq(RAX, RCX);
__ ret();
__ Bind(&error);
__ movq(RAX, Immediate(-1));
__ ret();
}
ASSEMBLER_TEST_RUN(Bitwise64, test) {
typedef int (*Bitwise64)();
EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise64>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(LogicalOps, assembler) {
Label donetest1;
__ movl(RAX, Immediate(4));
__ andl(RAX, Immediate(2));
__ cmpl(RAX, Immediate(0));
__ j(EQUAL, &donetest1);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest1);
Label donetest2;
__ movl(RCX, Immediate(4));
__ andl(RCX, Immediate(4));
__ cmpl(RCX, Immediate(0));
__ j(NOT_EQUAL, &donetest2);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest2);
Label donetest3;
__ movl(RAX, Immediate(0));
__ orl(RAX, Immediate(0));
__ cmpl(RAX, Immediate(0));
__ j(EQUAL, &donetest3);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest3);
Label donetest4;
__ movl(RAX, Immediate(4));
__ orl(RAX, Immediate(0));
__ cmpl(RAX, Immediate(0));
__ j(NOT_EQUAL, &donetest4);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest4);
Label donetest5;
__ pushq(RAX);
__ movl(RAX, Immediate(0xff));
__ movl(Address(RSP, 0), RAX);
__ cmpl(Address(RSP, 0), Immediate(0xff));
__ j(EQUAL, &donetest5);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest5);
__ popq(RAX);
Label donetest6;
__ movl(RAX, Immediate(1));
__ shll(RAX, Immediate(3));
__ cmpl(RAX, Immediate(8));
__ j(EQUAL, &donetest6);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest6);
Label donetest7;
__ movl(RAX, Immediate(2));
__ shrl(RAX, Immediate(1));
__ cmpl(RAX, Immediate(1));
__ j(EQUAL, &donetest7);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest7);
Label donetest8;
__ movl(RAX, Immediate(8));
__ shrl(RAX, Immediate(3));
__ cmpl(RAX, Immediate(1));
__ j(EQUAL, &donetest8);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest8);
Label donetest9;
__ movl(RAX, Immediate(1));
__ movl(RCX, Immediate(3));
__ shll(RAX, RCX);
__ cmpl(RAX, Immediate(8));
__ j(EQUAL, &donetest9);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest9);
Label donetest10;
__ movl(RAX, Immediate(8));
__ movl(RCX, Immediate(3));
__ shrl(RAX, RCX);
__ cmpl(RAX, Immediate(1));
__ j(EQUAL, &donetest10);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest10);
Label donetest6a;
__ movl(RAX, Immediate(1));
__ shlq(RAX, Immediate(3));
__ cmpl(RAX, Immediate(8));
__ j(EQUAL, &donetest6a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest6a);
Label donetest7a;
__ movl(RAX, Immediate(2));
__ shrq(RAX, Immediate(1));
__ cmpl(RAX, Immediate(1));
__ j(EQUAL, &donetest7a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest7a);
Label donetest8a;
__ movl(RAX, Immediate(8));
__ shrq(RAX, Immediate(3));
__ cmpl(RAX, Immediate(1));
__ j(EQUAL, &donetest8a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest8a);
Label donetest9a;
__ movl(RAX, Immediate(1));
__ movl(RCX, Immediate(3));
__ shlq(RAX, RCX);
__ cmpl(RAX, Immediate(8));
__ j(EQUAL, &donetest9a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest9a);
Label donetest10a;
__ movl(RAX, Immediate(8));
__ movl(RCX, Immediate(3));
__ shrq(RAX, RCX);
__ cmpl(RAX, Immediate(1));
__ j(EQUAL, &donetest10a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest10a);
Label donetest11a;
__ movl(RAX, Immediate(1));
__ shlq(RAX, Immediate(31));
__ shrq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(0x10000000));
__ j(EQUAL, &donetest11a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest11a);
Label donetest12a;
__ movl(RAX, Immediate(1));
__ shlq(RAX, Immediate(31));
__ sarl(RAX, Immediate(3));
__ cmpl(RAX, Immediate(0xfffffffff0000000));
__ j(EQUAL, &donetest12a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest12a);
Label donetest13a;
__ movl(RAX, Immediate(1));
__ movl(RCX, Immediate(3));
__ shlq(RAX, Immediate(31));
__ sarl(RAX, RCX);
__ cmpl(RAX, Immediate(0xfffffffff0000000));
__ j(EQUAL, &donetest13a);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest13a);
{
Label donetest15a;
const int32_t left = 0xff000000;
const int32_t right = 0xffffffff;
const int32_t shifted = 0xf0000003;
__ movl(RDX, Immediate(left));
__ movl(R8, Immediate(right));
__ movl(RCX, Immediate(2));
__ shll(RDX, RCX); // RDX = 0xff000000 << 2 == 0xfc000000
__ shldl(RDX, R8, Immediate(2));
// RDX = high32(0xfc000000:0xffffffff << 2) == 0xf0000003
__ cmpl(RDX, Immediate(shifted));
__ j(EQUAL, &donetest15a);
__ int3();
__ Bind(&donetest15a);
}
{
Label donetest15b;
const int64_t left = 0xff00000000000000;
const int64_t right = 0xffffffffffffffff;
const int64_t shifted = 0xf000000000000003;
__ movq(RDX, Immediate(left));
__ movq(R8, Immediate(right));
__ movq(RCX, Immediate(2));
__ shlq(RDX, RCX); // RDX = 0xff00000000000000 << 2 == 0xfc00000000000000
__ shldq(RDX, R8, Immediate(2));
// RDX = high64(0xfc00000000000000:0xffffffffffffffff << 2)
// == 0xf000000000000003
__ cmpq(RDX, Immediate(shifted));
__ j(EQUAL, &donetest15b);
__ int3();
__ Bind(&donetest15b);
}
{
Label donetest15c;
const int64_t left = 0xff00000000000000;
const int64_t right = 0xffffffffffffffff;
const int64_t shifted = 0xf000000000000003;
__ movq(RDX, Immediate(left));
__ movq(R8, Immediate(right));
__ movq(RCX, Immediate(2));
__ shlq(RDX, RCX); // RDX = 0xff00000000000000 << 2 == 0xfc00000000000000
__ shldq(RDX, R8, RCX);
// RDX = high64(0xfc00000000000000:0xffffffffffffffff << 2)
// == 0xf000000000000003
__ cmpq(RDX, Immediate(shifted));
__ j(EQUAL, &donetest15c);
__ int3();
__ Bind(&donetest15c);
}
{
Label donetest15d;
const int64_t left = 0xff00000000000000;
const int64_t right = 0xffffffffffffffff;
const int64_t shifted = 0xcff0000000000000;
__ movq(RDX, Immediate(left));
__ movq(R8, Immediate(right));
__ movq(RCX, Immediate(2));
__ shrq(RDX, RCX); // RDX = 0xff00000000000000 >> 2 == 0x3fc0000000000000
__ shrdq(RDX, R8, RCX);
// RDX = low64(0xffffffffffffffff:0x3fc0000000000000 >> 2)
// == 0xcff0000000000000
__ cmpq(RDX, Immediate(shifted));
__ j(EQUAL, &donetest15d);
__ int3();
__ Bind(&donetest15d);
}
__ movl(RAX, Immediate(0));
__ ret();
}
ASSEMBLER_TEST_RUN(LogicalOps, test) {
typedef int (*LogicalOpsCode)();
EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(LogicalOps64, assembler) {
Label donetest1;
__ movq(RAX, Immediate(4));
__ andq(RAX, Immediate(2));
__ cmpq(RAX, Immediate(0));
__ j(EQUAL, &donetest1);
__ int3();
__ Bind(&donetest1);
Label donetest2;
__ movq(RCX, Immediate(4));
__ pushq(RCX);
__ andq(RCX, Address(RSP, 0));
__ popq(RAX);
__ cmpq(RCX, Immediate(0));
__ j(NOT_EQUAL, &donetest2);
__ int3();
__ Bind(&donetest2);
Label donetest3;
__ movq(RAX, Immediate(0));
__ orq(RAX, Immediate(0));
__ cmpq(RAX, Immediate(0));
__ j(EQUAL, &donetest3);
__ int3();
__ Bind(&donetest3);
Label donetest4;
__ movq(RAX, Immediate(4));
__ orq(RAX, Immediate(0));
__ cmpq(RAX, Immediate(0));
__ j(NOT_EQUAL, &donetest4);
__ int3();
__ Bind(&donetest4);
Label donetest5;
__ pushq(RAX);
__ movq(RAX, Immediate(0xff));
__ movq(Address(RSP, 0), RAX);
__ cmpq(Address(RSP, 0), Immediate(0xff));
__ j(EQUAL, &donetest5);
__ int3();
__ Bind(&donetest5);
__ popq(RAX);
Label donetest6;
__ movq(RAX, Immediate(1));
__ shlq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(8));
__ j(EQUAL, &donetest6);
__ int3();
__ Bind(&donetest6);
Label donetest7;
__ movq(RAX, Immediate(2));
__ shrq(RAX, Immediate(1));
__ cmpq(RAX, Immediate(1));
__ j(EQUAL, &donetest7);
__ int3();
__ Bind(&donetest7);
Label donetest8;
__ movq(RAX, Immediate(8));
__ shrq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(1));
__ j(EQUAL, &donetest8);
__ int3();
__ Bind(&donetest8);
Label donetest9;
__ movq(RAX, Immediate(1));
__ movq(RCX, Immediate(3));
__ shlq(RAX, RCX);
__ cmpq(RAX, Immediate(8));
__ j(EQUAL, &donetest9);
__ int3();
__ Bind(&donetest9);
Label donetest10;
__ movq(RAX, Immediate(8));
__ movq(RCX, Immediate(3));
__ shrq(RAX, RCX);
__ cmpq(RAX, Immediate(1));
__ j(EQUAL, &donetest10);
__ int3();
__ Bind(&donetest10);
Label donetest6a;
__ movq(RAX, Immediate(1));
__ shlq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(8));
__ j(EQUAL, &donetest6a);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest6a);
Label donetest7a;
__ movq(RAX, Immediate(2));
__ shrq(RAX, Immediate(1));
__ cmpq(RAX, Immediate(1));
__ j(EQUAL, &donetest7a);
__ int3();
__ Bind(&donetest7a);
Label donetest8a;
__ movq(RAX, Immediate(8));
__ shrq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(1));
__ j(EQUAL, &donetest8a);
__ int3();
__ Bind(&donetest8a);
Label donetest9a;
__ movq(RAX, Immediate(1));
__ movq(RCX, Immediate(3));
__ shlq(RAX, RCX);
__ cmpq(RAX, Immediate(8));
__ j(EQUAL, &donetest9a);
__ int3();
__ Bind(&donetest9a);
Label donetest10a;
__ movq(RAX, Immediate(8));
__ movq(RCX, Immediate(3));
__ shrq(RAX, RCX);
__ cmpq(RAX, Immediate(1));
__ j(EQUAL, &donetest10a);
__ int3();
__ Bind(&donetest10a);
Label donetest11a;
__ movq(RAX, Immediate(1));
__ shlq(RAX, Immediate(31));
__ shrq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(0x10000000));
__ j(EQUAL, &donetest11a);
__ int3();
__ Bind(&donetest11a);
Label donetest12a;
__ movq(RAX, Immediate(1));
__ shlq(RAX, Immediate(63));
__ sarq(RAX, Immediate(3));
__ cmpq(RAX, Immediate(0xf000000000000000));
__ j(EQUAL, &donetest12a);
__ int3();
__ Bind(&donetest12a);
Label donetest13a;
__ movq(RAX, Immediate(1));
__ movq(RCX, Immediate(3));
__ shlq(RAX, Immediate(63));
__ sarq(RAX, RCX);
__ cmpq(RAX, Immediate(0xf000000000000000));
__ j(EQUAL, &donetest13a);
__ int3();
__ Bind(&donetest13a);
Label donetest14, donetest15;
__ pushq(R15); // Callee saved.
__ movq(R15, Immediate(0xf000000000000001));
__ andq(R15, Immediate(-1));
__ andq(R15, Immediate(0x8000000000000001));
__ orq(R15, Immediate(2));
__ orq(R15, Immediate(0xf800000000000000));
__ xorq(R15, Immediate(1));
__ xorq(R15, Immediate(0x0800000000000000));
__ cmpq(R15, Immediate(0xf000000000000002));
__ j(EQUAL, &donetest14);
__ int3();
__ Bind(&donetest14);
__ andq(R15, Immediate(2));
__ cmpq(R15, Immediate(2));
__ j(EQUAL, &donetest15);
__ int3();
__ Bind(&donetest15);
__ popq(R15); // Callee saved.
__ movq(RAX, Immediate(0));
__ ret();
}
ASSEMBLER_TEST_RUN(LogicalOps64, test) {
typedef int (*LogicalOpsCode)();
EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(LogicalTestL, assembler) {
Label donetest1;
__ movl(RAX, Immediate(4));
__ movl(RCX, Immediate(2));
__ testl(RAX, RCX);
__ j(EQUAL, &donetest1);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest1);
Label donetest2;
__ movl(RDX, Immediate(4));
__ movl(RCX, Immediate(4));
__ testl(RDX, RCX);
__ j(NOT_EQUAL, &donetest2);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest2);
Label donetest3;
__ movl(RAX, Immediate(0));
__ testl(RAX, Immediate(0));
__ j(EQUAL, &donetest3);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest3);
Label donetest4;
__ movl(RCX, Immediate(4));
__ testl(RCX, Immediate(4));
__ j(NOT_EQUAL, &donetest4);
// Be sure to skip this crashing code.
__ movl(RAX, Immediate(0));
__ movl(Address(RAX, 0), RAX);
__ Bind(&donetest4);
__ movl(RAX, Immediate(0));
__ ret();
}
ASSEMBLER_TEST_RUN(LogicalTestL, test) {
typedef int (*LogicalTestCode)();
EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(LogicalTestQ, assembler) {
Label donetest1;
__ movq(RAX, Immediate(4));
__ movq(RCX, Immediate(2));
__ testq(RAX, RCX);
__ j(EQUAL, &donetest1);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest1);
Label donetest2;
__ movq(RDX, Immediate(4));
__ movq(RCX, Immediate(4));
__ testq(RDX, RCX);
__ j(NOT_EQUAL, &donetest2);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest2);
Label donetest3;
__ movq(RAX, Immediate(0));
__ testq(RAX, Immediate(0));
__ j(EQUAL, &donetest3);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest3);
Label donetest4;
__ movq(RCX, Immediate(4));
__ testq(RCX, Immediate(4));
__ j(NOT_EQUAL, &donetest4);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest4);
Label donetest5;
__ movq(RCX, Immediate(0xff));
__ testq(RCX, Immediate(0xff));
__ j(NOT_EQUAL, &donetest5);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest5);
Label donetest6;
__ movq(RAX, Immediate(0xff));
__ testq(RAX, Immediate(0xff));
__ j(NOT_EQUAL, &donetest6);
// Be sure to skip this crashing code.
__ movq(RAX, Immediate(0));
__ movq(Address(RAX, 0), RAX);
__ Bind(&donetest6);
__ movq(RAX, Immediate(0));
__ ret();
}
ASSEMBLER_TEST_RUN(LogicalTestQ, test) {
typedef int (*LogicalTestCode)();
EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(CompareSwapEQ, assembler) {
__ movq(RAX, Immediate(0));
__ pushq(RAX);
__ movq(RAX, Immediate(4));
__ movq(RCX, Immediate(0));
__ movq(Address(RSP, 0), RAX);
__ lock_cmpxchgq(Address(RSP, 0), RCX);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapEQ, test) {
typedef int (*CompareSwapEQCode)();
EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(CompareSwapNEQ, assembler) {
__ movq(RAX, Immediate(0));
__ pushq(RAX);
__ movq(RAX, Immediate(2));
__ movq(RCX, Immediate(4));
__ movq(Address(RSP, 0), RCX);
__ lock_cmpxchgq(Address(RSP, 0), RCX);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapNEQ, test) {
typedef int (*CompareSwapNEQCode)();
EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(Exchange, assembler) {
__ movq(RAX, Immediate(kLargeConstant));
__ movq(RDX, Immediate(kAnotherLargeConstant));
__ xchgq(RAX, RDX);
__ subq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(Exchange, test) {
typedef int64_t (*Exchange)();
EXPECT_EQ(kAnotherLargeConstant - kLargeConstant,
reinterpret_cast<Exchange>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(LargeConstant, assembler) {
__ movq(RAX, Immediate(kLargeConstant));
__ ret();
}
ASSEMBLER_TEST_RUN(LargeConstant, test) {
typedef int64_t (*LargeConstantCode)();
EXPECT_EQ(kLargeConstant,
reinterpret_cast<LargeConstantCode>(test->entry())());
}
static int ComputeStackSpaceReservation(int needed, int fixed) {
return (OS::ActivationFrameAlignment() > 1)
? Utils::RoundUp(needed + fixed, OS::ActivationFrameAlignment()) -
fixed
: needed;
}
static int LeafReturn42() {
return 42;
}
static int LeafReturnArgument(int x) {
return x + 87;
}
ASSEMBLER_TEST_GENERATE(CallSimpleLeaf, assembler) {
ExternalLabel call1(reinterpret_cast<uword>(LeafReturn42));
ExternalLabel call2(reinterpret_cast<uword>(LeafReturnArgument));
int space = ComputeStackSpaceReservation(0, 8);
__ subq(RSP, Immediate(space));
__ call(&call1);
__ addq(RSP, Immediate(space));
space = ComputeStackSpaceReservation(0, 8);
__ subq(RSP, Immediate(space));
__ movl(CallingConventions::kArg1Reg, RAX);
__ call(&call2);
__ addq(RSP, Immediate(space));
__ ret();
}
ASSEMBLER_TEST_RUN(CallSimpleLeaf, test) {
typedef int (*CallSimpleLeafCode)();
EXPECT_EQ(42 + 87, reinterpret_cast<CallSimpleLeafCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(JumpSimpleLeaf, assembler) {
ExternalLabel call1(reinterpret_cast<uword>(LeafReturn42));
Label L;
int space = ComputeStackSpaceReservation(0, 8);
__ subq(RSP, Immediate(space));
__ call(&L);
__ addq(RSP, Immediate(space));
__ ret();
__ Bind(&L);
__ jmp(&call1);
}
ASSEMBLER_TEST_RUN(JumpSimpleLeaf, test) {
typedef int (*JumpSimpleLeafCode)();
EXPECT_EQ(42, reinterpret_cast<JumpSimpleLeafCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(JumpIndirect, assembler) {
ExternalLabel call1(reinterpret_cast<uword>(LeafReturn42));
__ movq(Address(CallingConventions::kArg1Reg, 0), Immediate(call1.address()));
__ jmp(Address(CallingConventions::kArg1Reg, 0));
}
ASSEMBLER_TEST_RUN(JumpIndirect, test) {
uword temp = 0;
typedef int (*JumpIndirect)(uword*);
EXPECT_EQ(42, reinterpret_cast<JumpIndirect>(test->entry())(&temp));
}
ASSEMBLER_TEST_GENERATE(SingleFPMoves, assembler) {
__ movq(RAX, Immediate(bit_cast<int32_t, float>(234.0f)));
__ movd(XMM0, RAX);
__ movss(XMM1, XMM0);
__ movss(XMM2, XMM1);
__ movss(XMM3, XMM2);
__ movss(XMM4, XMM3);
__ movss(XMM5, XMM4);
__ movss(XMM6, XMM5);
__ movss(XMM7, XMM6);
__ movss(XMM8, XMM7);
__ movss(XMM9, XMM8);
__ movss(XMM10, XMM9);
__ movss(XMM11, XMM10);
__ movss(XMM12, XMM11);
__ movss(XMM13, XMM12);
__ movss(XMM14, XMM13);
__ movss(XMM15, XMM14);
__ pushq(R15); // Callee saved.
__ pushq(RAX);
__ movq(Address(RSP, 0), Immediate(0));
__ movss(XMM0, Address(RSP, 0));
__ movss(Address(RSP, 0), XMM7);
__ movss(XMM1, Address(RSP, 0));
__ movq(R10, RSP);
__ movss(Address(R10, 0), XMM1);
__ movss(XMM2, Address(R10, 0));
__ movq(R15, RSP);
__ movss(Address(R15, 0), XMM2);
__ movss(XMM3, Address(R15, 0));
__ movq(RAX, RSP);
__ movss(Address(RAX, 0), XMM3);
__ movss(XMM1, Address(RAX, 0));
__ movss(XMM15, Address(RAX, 0));
__ movss(XMM14, XMM15);
__ movss(XMM13, XMM14);
__ movss(XMM12, XMM13);
__ movss(XMM11, XMM12);
__ movss(XMM10, XMM11);
__ movss(XMM9, XMM10);
__ movss(XMM8, XMM9);
__ movss(XMM7, XMM8);
__ movss(XMM6, XMM7);
__ movss(XMM5, XMM6);
__ movss(XMM4, XMM5);
__ movss(XMM3, XMM4);
__ movss(XMM2, XMM3);
__ movss(XMM1, XMM2);
__ movss(XMM0, XMM1);
__ popq(RAX);
__ popq(R15); // Callee saved.
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPMoves, test) {
typedef float (*SingleFPMovesCode)();
EXPECT_EQ(234, reinterpret_cast<SingleFPMovesCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SingleFPMoves2, assembler) {
__ movq(RAX, Immediate(bit_cast<int32_t, float>(234.0f)));
__ movd(XMM0, RAX);
__ movd(XMM8, RAX);
__ movss(XMM1, XMM8);
__ pushq(RAX);
__ movq(Address(RSP, 0), Immediate(0));
__ movss(XMM0, Address(RSP, 0));
__ movss(Address(RSP, 0), XMM1);
__ movss(XMM0, Address(RSP, 0));
__ movq(Address(RSP, 0), Immediate(0));
__ movss(XMM9, XMM8);
__ movss(Address(RSP, 0), XMM9);
__ movss(XMM8, Address(RSP, 0));
__ movss(XMM0, XMM8);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPMoves2, test) {
typedef float (*SingleFPMoves2Code)();
EXPECT_EQ(234, reinterpret_cast<SingleFPMoves2Code>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(PackedDoubleAdd, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {1.0, 2.0};
static const struct ALIGN16 {
double a;
double b;
} constant1 = {3.0, 4.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant1)));
__ movups(XMM11, Address(RAX, 0));
__ addpd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleAdd, test) {
typedef double (*PackedDoubleAdd)();
double res = reinterpret_cast<PackedDoubleAdd>(test->entry())();
EXPECT_FLOAT_EQ(4.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleSub, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {1.0, 2.0};
static const struct ALIGN16 {
double a;
double b;
} constant1 = {3.0, 4.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant1)));
__ movups(XMM11, Address(RAX, 0));
__ subpd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleSub, test) {
typedef double (*PackedDoubleSub)();
double res = reinterpret_cast<PackedDoubleSub>(test->entry())();
EXPECT_FLOAT_EQ(-2.0, res, 0.000001f);
}
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();
}
ASSEMBLER_TEST_GENERATE(PackedDoubleNegate, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {1.0, 2.0};
EnterTestFrame(assembler);
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ negatepd(XMM10);
__ movaps(XMM0, XMM10);
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleNegate, test) {
double res = test->InvokeWithCodeAndThread<double>();
EXPECT_FLOAT_EQ(-1.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleAbsolute, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {-1.0, 2.0};
EnterTestFrame(assembler);
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ abspd(XMM10);
__ movaps(XMM0, XMM10);
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleAbsolute, test) {
double res = test->InvokeWithCodeAndThread<double>();
EXPECT_FLOAT_EQ(1.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleMul, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {3.0, 2.0};
static const struct ALIGN16 {
double a;
double b;
} constant1 = {3.0, 4.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant1)));
__ movups(XMM11, Address(RAX, 0));
__ mulpd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleMul, test) {
typedef double (*PackedDoubleMul)();
double res = reinterpret_cast<PackedDoubleMul>(test->entry())();
EXPECT_FLOAT_EQ(9.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleDiv, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {9.0, 2.0};
static const struct ALIGN16 {
double a;
double b;
} constant1 = {3.0, 4.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant1)));
__ movups(XMM11, Address(RAX, 0));
__ divpd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleDiv, test) {
typedef double (*PackedDoubleDiv)();
double res = reinterpret_cast<PackedDoubleDiv>(test->entry())();
EXPECT_FLOAT_EQ(3.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleSqrt, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {16.0, 2.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ sqrtpd(XMM10);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleSqrt, test) {
typedef double (*PackedDoubleSqrt)();
double res = reinterpret_cast<PackedDoubleSqrt>(test->entry())();
EXPECT_FLOAT_EQ(4.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleMin, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {9.0, 2.0};
static const struct ALIGN16 {
double a;
double b;
} constant1 = {3.0, 4.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant1)));
__ movups(XMM11, Address(RAX, 0));
__ minpd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleMin, test) {
typedef double (*PackedDoubleMin)();
double res = reinterpret_cast<PackedDoubleMin>(test->entry())();
EXPECT_FLOAT_EQ(3.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleMax, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {9.0, 2.0};
static const struct ALIGN16 {
double a;
double b;
} constant1 = {3.0, 4.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant1)));
__ movups(XMM11, Address(RAX, 0));
__ maxpd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleMax, test) {
typedef double (*PackedDoubleMax)();
double res = reinterpret_cast<PackedDoubleMax>(test->entry())();
EXPECT_FLOAT_EQ(9.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleShuffle, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {2.0, 9.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM10, Address(RAX, 0));
// Splat Y across all lanes.
__ shufpd(XMM10, XMM10, Immediate(0x33));
// Splat X across all lanes.
__ shufpd(XMM10, XMM10, Immediate(0x0));
// Set return value.
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleShuffle, test) {
typedef double (*PackedDoubleShuffle)();
double res = reinterpret_cast<PackedDoubleShuffle>(test->entry())();
EXPECT_FLOAT_EQ(9.0, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedDoubleToSingle, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {9.0, 2.0};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM11, Address(RAX, 0));
__ cvtpd2ps(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleToSingle, test) {
typedef float (*PackedDoubleToSingle)();
float res = reinterpret_cast<PackedDoubleToSingle>(test->entry())();
EXPECT_FLOAT_EQ(9.0f, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(PackedSingleToDouble, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {9.0f, 2.0f, 3.0f, 4.0f};
__ movq(RAX, Immediate(reinterpret_cast<uword>(&constant0)));
__ movups(XMM11, Address(RAX, 0));
__ cvtps2pd(XMM10, XMM11);
__ movaps(XMM0, XMM10);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedSingleToDouble, test) {
typedef double (*PackedSingleToDouble)();
double res = reinterpret_cast<PackedSingleToDouble>(test->entry())();
EXPECT_FLOAT_EQ(9.0f, res, 0.000001f);
}
ASSEMBLER_TEST_GENERATE(SingleFPOperations, assembler) {
__ pushq(RBX);
__ pushq(RCX);
__ movq(RBX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, RBX);
__ movd(XMM8, RBX);
__ movq(RCX, Immediate(bit_cast<int32_t, float>(3.4f)));
__ movd(XMM1, RCX);
__ movd(XMM9, RCX);
__ addss(XMM0, XMM1); // 15.7f
__ mulss(XMM0, XMM1); // 53.38f
__ subss(XMM0, XMM1); // 49.98f
__ divss(XMM0, XMM1); // 14.7f
__ addss(XMM8, XMM9); // 15.7f
__ mulss(XMM8, XMM9); // 53.38f
__ subss(XMM8, XMM9); // 49.98f
__ divss(XMM8, XMM9); // 14.7f
__ subss(XMM0, XMM8); // 0.0f
__ popq(RCX);
__ popq(RBX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPOperations, test) {
typedef float (*SingleFPOperationsCode)();
float res = reinterpret_cast<SingleFPOperationsCode>(test->entry())();
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) {
__ movq(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM10, RAX);
__ shufps(XMM10, XMM10, Immediate(0x0));
__ movq(RAX, Immediate(bit_cast<int32_t, float>(3.4f)));
__ movd(XMM9, RAX);
__ shufps(XMM9, XMM9, Immediate(0x0));
__ addps(XMM10, XMM9); // 15.7f
__ mulps(XMM10, XMM9); // 53.38f
__ subps(XMM10, XMM9); // 49.98f
__ divps(XMM10, XMM9); // 14.7f
__ movaps(XMM0, XMM10);
__ shufps(XMM0, XMM0, Immediate(0x55)); // Copy second lane into all 4 lanes.
__ ret();
}
ASSEMBLER_TEST_RUN(PackedFPOperations, test) {
typedef float (*PackedFPOperationsCode)();
float res = reinterpret_cast<PackedFPOperationsCode>(test->entry())();
EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedIntOperations, assembler) {
__ movl(RAX, Immediate(0x2));
__ movd(XMM0, RAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ movl(RAX, Immediate(0x1));
__ movd(XMM1, RAX);
__ shufps(XMM1, XMM1, Immediate(0x0));
__ addpl(XMM0, XMM1); // 0x3
__ addpl(XMM0, XMM0); // 0x6
__ subpl(XMM0, XMM1); // 0x5
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedIntOperations, test) {
typedef uint32_t (*PackedIntOperationsCode)();
uint32_t res = reinterpret_cast<PackedIntOperationsCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x5), res);
}
ASSEMBLER_TEST_GENERATE(PackedIntOperations2, assembler) {
// Note: on Windows 64 XMM6-XMM15 are callee save.
const intptr_t cpu_register_set = 0;
const intptr_t fpu_register_set =
((1 << XMM10) | (1 << XMM11)) & CallingConventions::kVolatileXmmRegisters;
__ PushRegisters(cpu_register_set, fpu_register_set);
__ movl(RAX, Immediate(0x2));
__ movd(XMM10, RAX);
__ shufps(XMM10, XMM10, Immediate(0x0));
__ movl(RAX, Immediate(0x1));
__ movd(XMM11, RAX);
__ shufps(XMM11, XMM11, Immediate(0x0));
__ addpl(XMM10, XMM11); // 0x3
__ addpl(XMM10, XMM10); // 0x6
__ subpl(XMM10, XMM11); // 0x5
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM10);
__ popq(RAX);
__ PopRegisters(cpu_register_set, fpu_register_set);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedIntOperations2, test) {
typedef uint32_t (*PackedIntOperationsCode)();
uint32_t res = reinterpret_cast<PackedIntOperationsCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x5), res);
}
ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
__ movq(RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ movd(XMM0, RAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ movaps(XMM11, XMM0); // Copy XMM0
__ reciprocalps(XMM11); // 0.25
__ sqrtps(XMM11); // 0.5
__ rsqrtps(XMM0); // ~0.5
__ subps(XMM0, XMM11); // ~0.0
__ shufps(XMM0, XMM0, Immediate(0x00)); // Copy second lane into all 4 lanes.
__ ret();
}
ASSEMBLER_TEST_RUN(PackedFPOperations2, test) {
typedef float (*PackedFPOperations2Code)();
float res = reinterpret_cast<PackedFPOperations2Code>(test->entry())();
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppseq(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareEQ, test) {
typedef uint32_t (*PackedCompareEQCode)();
uint32_t res = reinterpret_cast<PackedCompareEQCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
}
ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsneq(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareNEQ, test) {
typedef uint32_t (*PackedCompareNEQCode)();
uint32_t res = reinterpret_cast<PackedCompareNEQCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
}
ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppslt(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareLT, test) {
typedef uint32_t (*PackedCompareLTCode)();
uint32_t res = reinterpret_cast<PackedCompareLTCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
}
ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsle(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareLE, test) {
typedef uint32_t (*PackedCompareLECode)();
uint32_t res = reinterpret_cast<PackedCompareLECode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
}
ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsnlt(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareNLT, test) {
typedef uint32_t (*PackedCompareNLTCode)();
uint32_t res = reinterpret_cast<PackedCompareNLTCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
}
ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsnle(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareNLE, test) {
typedef uint32_t (*PackedCompareNLECode)();
uint32_t res = reinterpret_cast<PackedCompareNLECode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
}
ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
EnterTestFrame(assembler);
__ movl(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, RAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ negateps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedNegate, test) {
float res = test->InvokeWithCodeAndThread<float>();
EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
EnterTestFrame(assembler);
__ movl(RAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
__ movd(XMM0, RAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ absps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
float res = test->InvokeWithCodeAndThread<float>();
EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
EnterTestFrame(assembler);
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ zerowps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0.
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
float res = test->InvokeWithCodeAndThread<float>();
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedMin, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ minps(XMM0, XMM1);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMin, test) {
typedef float (*PackedMinCode)();
float res = reinterpret_cast<PackedMinCode>(test->entry())();
EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedMax, assembler) {
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ maxps(XMM0, XMM1);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMax, test) {
typedef float (*PackedMaxCode)();
float res = reinterpret_cast<PackedMaxCode>(test->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};
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM0, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant2)));
__ movups(XMM1, Address(RAX, 0));
__ orps(XMM0, XMM1);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedLogicalOr, test) {
typedef uint32_t (*PackedLogicalOrCode)();
uint32_t res = reinterpret_cast<PackedLogicalOrCode>(test->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};
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM0, Address(RAX, 0));
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant2)));
__ andps(XMM0, Address(RAX, 0));
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedLogicalAnd, test) {
typedef uint32_t (*PackedLogicalAndCode)();
uint32_t res = reinterpret_cast<PackedLogicalAndCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(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};
EnterTestFrame(assembler);
__ LoadImmediate(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM9, Address(RAX, 0));
__ notps(XMM9);
__ movaps(XMM0, XMM9);
__ pushq(RAX);
__ movss(Address(RSP, 0), XMM0);
__ popq(RAX);
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
uint32_t res = test->InvokeWithCodeAndThread<uint32_t>();
EXPECT_EQ(static_cast<uword>(0x0), res);
}
ASSEMBLER_TEST_GENERATE(PackedMoveHighLow, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {1.0, 2.0, 3.0, 4.0};
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant1 = {5.0, 6.0, 7.0, 8.0};
// XMM9 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant0)));
__ movups(XMM9, Address(RAX, 0));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM1, Address(RAX, 0));
// XMM9 = 7.0f, 8.0f, 3.0f, 4.0f.
__ movhlps(XMM9, XMM1);
__ xorps(XMM1, XMM1);
// XMM1 = 7.0f, 8.0f, 3.0f, 4.0f.
__ movaps(XMM1, XMM9);
__ shufps(XMM9, XMM9, Immediate(0x00)); // 7.0f.
__ shufps(XMM1, XMM1, Immediate(0x55)); // 8.0f.
__ addss(XMM9, XMM1); // 15.0f.
__ movaps(XMM0, XMM9);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMoveHighLow, test) {
typedef float (*PackedMoveHighLow)();
float res = reinterpret_cast<PackedMoveHighLow>(test->entry())();
EXPECT_FLOAT_EQ(15.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedMoveLowHigh, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {1.0, 2.0, 3.0, 4.0};
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant1 = {5.0, 6.0, 7.0, 8.0};
// XMM9 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant0)));
__ movups(XMM9, Address(RAX, 0));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM1, Address(RAX, 0));
// XMM9 = 1.0f, 2.0f, 5.0f, 6.0f
__ movlhps(XMM9, XMM1);
__ xorps(XMM1, XMM1);
// XMM1 = 1.0f, 2.0f, 5.0f, 6.0f
__ movaps(XMM1, XMM9);
__ shufps(XMM9, XMM9, Immediate(0xAA)); // 5.0f.
__ shufps(XMM1, XMM1, Immediate(0xFF)); // 6.0f.
__ addss(XMM9, XMM1); // 11.0f.
__ movaps(XMM0, XMM9);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMoveLowHigh, test) {
typedef float (*PackedMoveLowHigh)();
float res = reinterpret_cast<PackedMoveLowHigh>(test->entry())();
EXPECT_FLOAT_EQ(11.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedUnpackLow, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {1.0, 2.0, 3.0, 4.0};
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant1 = {5.0, 6.0, 7.0, 8.0};
// XMM9 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant0)));
__ movups(XMM9, Address(RAX, 0));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM1, Address(RAX, 0));
// XMM9 = 1.0f, 5.0f, 2.0f, 6.0f.
__ unpcklps(XMM9, XMM1);
// XMM1 = 1.0f, 5.0f, 2.0f, 6.0f.
__ movaps(XMM1, XMM9);
__ shufps(XMM9, XMM9, Immediate(0x55));
__ shufps(XMM1, XMM1, Immediate(0xFF));
__ addss(XMM9, XMM1); // 11.0f.
__ movaps(XMM0, XMM9);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackLow, test) {
typedef float (*PackedUnpackLow)();
float res = reinterpret_cast<PackedUnpackLow>(test->entry())();
EXPECT_FLOAT_EQ(11.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedUnpackHigh, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {1.0, 2.0, 3.0, 4.0};
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant1 = {5.0, 6.0, 7.0, 8.0};
// XMM9 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant0)));
__ movups(XMM9, Address(RAX, 0));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM1, Address(RAX, 0));
// XMM9 = 3.0f, 7.0f, 4.0f, 8.0f.
__ unpckhps(XMM9, XMM1);
// XMM1 = 3.0f, 7.0f, 4.0f, 8.0f.
__ movaps(XMM1, XMM9);
__ shufps(XMM9, XMM9, Immediate(0x00));
__ shufps(XMM1, XMM1, Immediate(0xAA));
__ addss(XMM9, XMM1); // 7.0f.
__ movaps(XMM0, XMM9);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackHigh, test) {
typedef float (*PackedUnpackHigh)();
float res = reinterpret_cast<PackedUnpackHigh>(test->entry())();
EXPECT_FLOAT_EQ(7.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedUnpackLowPair, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {1.0, 2.0, 3.0, 4.0};
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant1 = {5.0, 6.0, 7.0, 8.0};
// XMM9 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant0)));
__ movups(XMM9, Address(RAX, 0));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM1, Address(RAX, 0));
// XMM9 = 1.0f, 2.0f, 5.0f, 6.0f.
__ unpcklpd(XMM9, XMM1);
// XMM1 = 1.0f, 2.0f, 5.0f, 6.0f.
__ movaps(XMM1, XMM9);
__ shufps(XMM9, XMM9, Immediate(0x00));
__ shufps(XMM1, XMM1, Immediate(0xAA));
__ addss(XMM9, XMM1); // 6.0f.
__ movaps(XMM0, XMM9);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackLowPair, test) {
typedef float (*PackedUnpackLowPair)();
float res = reinterpret_cast<PackedUnpackLowPair>(test->entry())();
EXPECT_FLOAT_EQ(6.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(PackedUnpackHighPair, assembler) {
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant0 = {1.0, 2.0, 3.0, 4.0};
static const struct ALIGN16 {
float a;
float b;
float c;
float d;
} constant1 = {5.0, 6.0, 7.0, 8.0};
// XMM9 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant0)));
__ movups(XMM9, Address(RAX, 0));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
__ movups(XMM1, Address(RAX, 0));
// XMM9 = 3.0f, 4.0f, 7.0f, 8.0f.
__ unpckhpd(XMM9, XMM1);
// XMM1 = 3.0f, 4.0f, 7.0f, 8.0f.
__ movaps(XMM1, XMM9);
__ shufps(XMM9, XMM9, Immediate(0x55));
__ shufps(XMM1, XMM1, Immediate(0xFF));
__ addss(XMM9, XMM1); // 12.0f.
__ movaps(XMM0, XMM9);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackHighPair, test) {
typedef float (*PackedUnpackHighPair)();
float res = reinterpret_cast<PackedUnpackHighPair>(test->entry())();
EXPECT_FLOAT_EQ(12.0f, res, 0.001f);
}
ASSEMBLER_TEST_GENERATE(DoubleFPMoves, assembler) {
__ movq(RAX, Immediate(bit_cast<int64_t, double>(1024.67)));
__ pushq(R15); // Callee saved.
__ pushq(RAX);
__ movsd(XMM0, Address(RSP, 0));
__ movsd(XMM1, XMM0);
__ movsd(XMM2, XMM1);
__ movsd(XMM3, XMM2);
__ movsd(XMM4, XMM3);
__ movsd(XMM5, XMM4);
__ movsd(XMM6, XMM5);
__ movsd(XMM7, XMM6);
__ movsd(XMM8, XMM7);
__ movsd(XMM9, XMM8);
__ movsd(XMM10, XMM9);
__ movsd(XMM11, XMM10);
__ movsd(XMM12, XMM11);
__ movsd(XMM13, XMM12);
__ movsd(XMM14, XMM13);
__ movsd(XMM15, XMM14);
__ movq(Address(RSP, 0), Immediate(0));
__ movsd(XMM0, Address(RSP, 0));
__ movsd(Address(RSP, 0), XMM15);
__ movsd(XMM1, Address(RSP, 0));
__ movq(R10, RSP);
__ movsd(Address(R10, 0), XMM1);
__ movsd(XMM2, Address(R10, 0));
__ movq(R15, RSP);
__ movsd(Address(R15, 0), XMM2);
__ movsd(XMM3, Address(R15, 0));
__ movq(RAX, RSP);
__ movsd(Address(RAX, 0), XMM3);
__ movsd(XMM4, Address(RAX, 0));
__ movsd(XMM15, Address(RSP, 0));
__ movaps(XMM14, XMM15);
__ movaps(XMM13, XMM14);
__ movaps(XMM12, XMM13);
__ movaps(XMM11, XMM12);
__ movaps(XMM10, XMM11);
__ movaps(XMM9, XMM10);
__ movaps(XMM8, XMM9);
__ movaps(XMM7, XMM8);
__ movaps(XMM6, XMM7);
__ movaps(XMM5, XMM6);
__ movaps(XMM4, XMM5);
__ movaps(XMM3, XMM4);
__ movaps(XMM2, XMM3);
__ movaps(XMM1, XMM2);
__ movaps(XMM0, XMM1);
__ popq(RAX);
__ popq(R15); // Callee saved.
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleFPMoves, test) {
typedef double (*DoubleFPMovesCode)();
EXPECT_FLOAT_EQ(1024.67, reinterpret_cast<DoubleFPMovesCode>(test->entry())(),
0.001);
}
ASSEMBLER_TEST_GENERATE(DoubleFPOperations, assembler) {
__ movq(RAX, Immediate(bit_cast<int64_t, double>(12.3)));
__ pushq(RAX);
__ movsd(XMM0, Address(RSP, 0));
__ movsd(XMM8, Address(RSP, 0));
__ movq(RAX, Immediate(bit_cast<int64_t, double>(3.4)));
__ movq(Address(RSP, 0), RAX);
__ movsd(XMM12, Address(RSP, 0));
__ addsd(XMM8, XMM12); // 15.7
__ mulsd(XMM8, XMM12); // 53.38
__ subsd(XMM8, XMM12); // 49.98
__ divsd(XMM8, XMM12); // 14.7
__ sqrtsd(XMM8, XMM8); // 3.834
__ movsd(XMM1, Address(RSP, 0));
__ addsd(XMM0, XMM1); // 15.7
__ mulsd(XMM0, XMM1); // 53.38
__ subsd(XMM0, XMM1); // 49.98
__ divsd(XMM0, XMM1); // 14.7
__ sqrtsd(XMM0, XMM0); // 3.834057902
__ addsd(XMM0, XMM8); // 7.6681
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleFPOperations, test) {
typedef double (*SingleFPOperationsCode)();
double res = reinterpret_cast<SingleFPOperationsCode>(test->entry())();
EXPECT_FLOAT_EQ(7.668, res, 0.001);
}
ASSEMBLER_TEST_GENERATE(Int32ToDoubleConversion, assembler) {
// Fill upper bits with garbage.
__ movq(R11, Immediate(0x1111111100000006));
__ cvtsi2sdl(XMM0, R11);
// Fill upper bits with garbage.
__ movq(R11, Immediate(0x2222222200000008));
__ cvtsi2sdl(XMM8, R11);
__ subsd(XMM0, XMM8);
__ ret();
}
ASSEMBLER_TEST_RUN(Int32ToDoubleConversion, test) {
typedef double (*Int32ToDoubleConversion)();
double res = reinterpret_cast<Int32ToDoubleConversion>(test->entry())();
EXPECT_FLOAT_EQ(-2.0, res, 0.001);
}
ASSEMBLER_TEST_GENERATE(Int64ToDoubleConversion, assembler) {
__ movq(RDX, Immediate(12LL << 32));
__ cvtsi2sdq(XMM0, RDX);
__ movsd(XMM15, XMM0); // Move to high register
__ addsd(XMM0, XMM0); // Stomp XMM0
__ movsd(XMM0, XMM15); // Move back to XMM0
__ ret();
}
ASSEMBLER_TEST_RUN(Int64ToDoubleConversion, test) {
typedef double (*Int64ToDoubleConversionCode)();
double res = reinterpret_cast<Int64ToDoubleConversionCode>(test->entry())();
EXPECT_FLOAT_EQ(static_cast<double>(12LL << 32), res, 0.001);
}
ASSEMBLER_TEST_GENERATE(DoubleToInt64Conversion, assembler) {
__ movq(RAX, Immediate(bit_cast<int64_t, double>(12.3)));
__ pushq(RAX);
__ movsd(XMM9, Address(RSP, 0));
__ movsd(XMM6, Address(RSP, 0));
__ popq(RAX);
__ cvttsd2siq(R10, XMM6);
__ cvttsd2siq(RDX, XMM6);
__ cvttsd2siq(R10, XMM9);
__ cvttsd2siq(RDX, XMM9);
__ subq(RDX, R10);
__ movq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleToInt64Conversion, test) {
typedef int64_t (*DoubleToInt64ConversionCode)();
int64_t res = reinterpret_cast<DoubleToInt64ConversionCode>(test->entry())();
EXPECT_EQ(0, res);
}
ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
ObjectStore* object_store = Isolate::Current()->object_store();
const Object& obj = Object::ZoneHandle(object_store->smi_class());
Label fail;
EnterTestFrame(assembler);
__ LoadObject(RAX, obj);
__ CompareObject(RAX, obj);
__ j(NOT_EQUAL, &fail);
__ LoadObject(RCX, obj);
__ CompareObject(RCX, obj);
__ j(NOT_EQUAL, &fail);
const Smi& smi = Smi::ZoneHandle(Smi::New(15));
__ LoadObject(RCX, smi);
__ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ pushq(RAX);
__ StoreObject(Address(RSP, 0), obj);
__ popq(RCX);
__ CompareObject(RCX, obj);
__ j(NOT_EQUAL, &fail);
__ pushq(RAX);
__ StoreObject(Address(RSP, 0), smi);
__ popq(RCX);
__ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ movl(RAX, Immediate(1)); // OK
LeaveTestFrame(assembler);
__ ret();
__ Bind(&fail);
__ movl(RAX, Immediate(0)); // Fail.
LeaveTestFrame(assembler);
__ ret();
}
ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
bool res = test->InvokeWithCodeAndThread<bool>();
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);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
__ ret();
}
ASSEMBLER_TEST_RUN(TestNop, test) {
typedef int (*TestNop)();
int res = reinterpret_cast<TestNop>(test->payload_start())();
EXPECT_EQ(36, res); // 36 nop bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlign0, assembler) {
__ Align(4, 0);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
__ ret();
}
ASSEMBLER_TEST_RUN(TestAlign0, test) {
typedef int (*TestAlign0)();
int res = reinterpret_cast<TestAlign0>(test->payload_start())();
EXPECT_EQ(0, res); // 0 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlign1, assembler) {
__ nop(1);
__ Align(4, 0);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
__ ret();
}
ASSEMBLER_TEST_RUN(TestAlign1, test) {
typedef int (*TestAlign1)();
int res = reinterpret_cast<TestAlign1>(test->payload_start())();
EXPECT_EQ(4, res); // 4 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlign1Offset1, assembler) {
__ nop(1);
__ Align(4, 1);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
__ ret();
}
ASSEMBLER_TEST_RUN(TestAlign1Offset1, test) {
typedef int (*TestAlign1Offset1)();
int res = reinterpret_cast<TestAlign1Offset1>(test->payload_start())();
EXPECT_EQ(3, res); // 3 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAlignLarge, assembler) {
__ nop(1);
__ Align(16, 0);
__ movq(RAX, Immediate(assembler->CodeSize())); // Return code size.
__ ret();
}
ASSEMBLER_TEST_RUN(TestAlignLarge, test) {
typedef int (*TestAlignLarge)();
int res = reinterpret_cast<TestAlignLarge>(test->payload_start())();
EXPECT_EQ(16, res); // 16 bytes emitted.
}
ASSEMBLER_TEST_GENERATE(TestAdds, assembler) {
__ movq(RAX, Immediate(4));
__ pushq(RAX);
__ addq(Address(RSP, 0), Immediate(5));
// TOS: 9
__ addq(Address(RSP, 0), Immediate(-2));
// TOS: 7
__ movq(RCX, Immediate(3));
__ addq(Address(RSP, 0), RCX);
// TOS: 10
__ movq(RAX, Immediate(10));
__ addq(RAX, Address(RSP, 0));
// RAX: 20
__ popq(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(TestAdds, test) {
typedef int (*TestAdds)();
int res = reinterpret_cast<TestAdds>(test->entry())();
EXPECT_EQ(20, res);
}
ASSEMBLER_TEST_GENERATE(TestNot, assembler) {
__ movq(RAX, Immediate(0xFFFFFFFF00000000));
__ notq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(TestNot, test) {
typedef int (*TestNot)();
unsigned int res = reinterpret_cast<TestNot>(test->entry())();
EXPECT_EQ(0xFFFFFFFF, res);
}
ASSEMBLER_TEST_GENERATE(TestNotInt32, assembler) {
__ movq(RAX, Immediate(0x0));
__ notl(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(TestNotInt32, test) {
typedef int (*TestNot)();
unsigned int res = reinterpret_cast<TestNot>(test->entry())();
EXPECT_EQ(0xFFFFFFFF, res);
}
ASSEMBLER_TEST_GENERATE(XorpdZeroing, assembler) {
__ pushq(RAX);
__ movsd(Address(RSP, 0), XMM0);
__ xorpd(XMM0, Address(RSP, 0));
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(XorpdZeroing, test) {
typedef double (*XorpdZeroingCode)(double d);
double res = reinterpret_cast<XorpdZeroingCode>(test->entry())(12.56e3);
EXPECT_FLOAT_EQ(0.0, res, 0.0001);
}
ASSEMBLER_TEST_GENERATE(XorpdZeroing2, assembler) {
Label done;
__ xorpd(XMM15, XMM15);
__ xorpd(XMM0, XMM0);
__ xorpd(XMM0, XMM15);
__ comisd(XMM0, XMM15);
__ j(ZERO, &done);
__ int3();
__ Bind(&done);
__ ret();
}
ASSEMBLER_TEST_RUN(XorpdZeroing2, test) {
typedef double (*XorpdZeroing2Code)(double d);
double res = reinterpret_cast<XorpdZeroing2Code>(test->entry())(12.56e3);
EXPECT_FLOAT_EQ(0.0, res, 0.0001);
}
ASSEMBLER_TEST_GENERATE(Pxor, assembler) {
__ pxor(XMM0, XMM0);
__ ret();
}
ASSEMBLER_TEST_RUN(Pxor, test) {
typedef double (*PxorCode)(double d);
double res = reinterpret_cast<PxorCode>(test->entry())(12.3456e3);
EXPECT_FLOAT_EQ(0.0, res, 0.0);
}
ASSEMBLER_TEST_GENERATE(SquareRootDouble, assembler) {
__ sqrtsd(XMM0, XMM0);
__ ret();
}
ASSEMBLER_TEST_RUN(SquareRootDouble, test) {
typedef double (*SquareRootDoubleCode)(double d);
const double kDoubleConst = .7;
double res =
reinterpret_cast<SquareRootDoubleCode>(test->entry())(kDoubleConst);
EXPECT_FLOAT_EQ(sqrt(kDoubleConst), res, 0.0001);
}
// Called from assembler_test.cc.
ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
__ pushq(CODE_REG);
__ pushq(THR);
__ movq(THR, CallingConventions::kArg3Reg);
__ StoreIntoObject(CallingConventions::kArg2Reg,
FieldAddress(CallingConventions::kArg2Reg,
GrowableObjectArray::data_offset()),
CallingConventions::kArg1Reg);
__ popq(THR);
__ popq(CODE_REG);
__ ret();
}
ASSEMBLER_TEST_GENERATE(DoubleFPUStackMoves, assembler) {
int64_t l = bit_cast<int64_t, double>(1024.67);
__ movq(RAX, Immediate(l));
__ pushq(RAX);
__ fldl(Address(RSP, 0));
__ movq(Address(RSP, 0), Immediate(0));
__ fstpl(Address(RSP, 0));
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleFPUStackMoves, test) {
typedef int64_t (*DoubleFPUStackMovesCode)();
int64_t res = reinterpret_cast<DoubleFPUStackMovesCode>(test->entry())();
EXPECT_FLOAT_EQ(1024.67, (bit_cast<double, int64_t>(res)), 0.001);
}
ASSEMBLER_TEST_GENERATE(Sine, assembler) {
__ pushq(RAX);
__ movsd(Address(RSP, 0), XMM0);
__ fldl(Address(RSP, 0));
__ fsin();
__ fstpl(Address(RSP, 0));
__ movsd(XMM0, Address(RSP, 0));
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(Sine, test) {
typedef double (*SineCode)(double d);
const double kDoubleConst = 0.7;
double res = reinterpret_cast<SineCode>(test->entry())(kDoubleConst);
EXPECT_FLOAT_EQ(sin(kDoubleConst), res, 0.0001);
}
ASSEMBLER_TEST_GENERATE(Cosine, assembler) {
__ pushq(RAX);
__ movsd(Address(RSP, 0), XMM0);
__ fldl(Address(RSP, 0));
__ fcos();
__ fstpl(Address(RSP, 0));
__ movsd(XMM0, Address(RSP, 0));
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(Cosine, test) {
typedef double (*CosineCode)(double f);
const double kDoubleConst = 0.7;
double res = reinterpret_cast<CosineCode>(test->entry())(kDoubleConst);
EXPECT_FLOAT_EQ(cos(kDoubleConst), res, 0.0001);
}
ASSEMBLER_TEST_GENERATE(IntToDoubleConversion, assembler) {
__ movq(RDX, Immediate(6));
__ cvtsi2sdq(XMM0, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(IntToDoubleConversion, test) {
typedef double (*IntToDoubleConversionCode)();
double res = reinterpret_cast<IntToDoubleConversionCode>(test->entry())();
EXPECT_FLOAT_EQ(6.0, res, 0.001);
}
ASSEMBLER_TEST_GENERATE(DoubleToDoubleTrunc, assembler) {
__ roundsd(XMM0, XMM0, Assembler::kRoundToZero);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, test) {
typedef double (*DoubleToDoubleTruncCode)(double d);
double res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(12.3);
EXPECT_EQ(12.0, res);
res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(12.8);
EXPECT_EQ(12.0, res);
res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(-12.3);
EXPECT_EQ(-12.0, res);
res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(-12.8);
EXPECT_EQ(-12.0, res);
}
ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
EnterTestFrame(assembler);
#if defined(HOST_OS_WINDOWS)
// 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);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleAbs, test) {
double val = -12.45;
double res = test->InvokeWithCodeAndThread<double, double>(val);
EXPECT_FLOAT_EQ(-val, res, 0.001);
val = 12.45;
res = test->InvokeWithCodeAndThread<double, double>(val);
EXPECT_FLOAT_EQ(val, res, 0.001);
}
ASSEMBLER_TEST_GENERATE(ExtractSignBits, assembler) {
__ movmskpd(RAX, XMM0);
__ andq(RAX, Immediate(0x1));
__ ret();
}
ASSEMBLER_TEST_RUN(ExtractSignBits, test) {
typedef int (*ExtractSignBits)(double d);
int res = reinterpret_cast<ExtractSignBits>(test->entry())(1.0);
EXPECT_EQ(0, res);
res = reinterpret_cast<ExtractSignBits>(test->entry())(-1.0);
EXPECT_EQ(1, res);
res = reinterpret_cast<ExtractSignBits>(test->entry())(-0.0);
EXPECT_EQ(1, res);
}
ASSEMBLER_TEST_GENERATE(TestSetCC, assembler) {
__ movq(RAX, Immediate(0xFFFFFFFF));
__ cmpq(RAX, RAX);
__ setcc(NOT_EQUAL, AL);
__ ret();
}
ASSEMBLER_TEST_RUN(TestSetCC, test) {
typedef uword (*TestSetCC)();
uword res = reinterpret_cast<TestSetCC>(test->entry())();
EXPECT_EQ(0xFFFFFF00, res);
}
ASSEMBLER_TEST_GENERATE(TestRepMovsBytes, assembler) {
__ pushq(RSI);
__ pushq(RDI);
__ pushq(CallingConventions::kArg1Reg); // from.
__ pushq(CallingConventions::kArg2Reg); // to.
__ pushq(CallingConventions::kArg3Reg); // count.
__ movq(RSI, Address(RSP, 2 * kWordSize)); // from.
__ movq(RDI, Address(RSP, 1 * kWordSize)); // to.
__ movq(RCX, Address(RSP, 0 * kWordSize)); // count.
__ rep_movsb();
// Remove saved arguments.
__ popq(RAX);
__ popq(RAX);
__ popq(RAX);
__ popq(RDI);
__ popq(RSI);
__ ret();
}
ASSEMBLER_TEST_RUN(TestRepMovsBytes, test) {
const char* from = "0123456789";
const char* to = new char[10];
typedef void (*TestRepMovsBytes)(const char* from, const char* to, int count);
reinterpret_cast<TestRepMovsBytes>(test->entry())(from, to, 10);
EXPECT_EQ(to[0], '0');
for (int i = 0; i < 10; i++) {
EXPECT_EQ(from[i], to[i]);
}
delete[] to;
}
ASSEMBLER_TEST_GENERATE(ConditionalMovesCompare, assembler) {
__ cmpq(CallingConventions::kArg1Reg, CallingConventions::kArg2Reg);
__ movq(RDX, Immediate(1)); // Greater equal.
__ movq(RCX, Immediate(-1)); // Less
__ cmovlessq(RAX, RCX);
__ cmovgeq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(ConditionalMovesCompare, test) {
typedef int (*ConditionalMovesCompareCode)(int i, int j);
int res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(10, 5);
EXPECT_EQ(1, res); // Greater equal.
res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(5, 5);
EXPECT_EQ(1, res); // Greater equal.
res = reinterpret_cast<ConditionalMovesCompareCode>(test->entry())(2, 5);
EXPECT_EQ(-1, res); // Less.
}
ASSEMBLER_TEST_GENERATE(BitTest, assembler) {
__ movq(RAX, Immediate(4));
__ movq(R11, Immediate(2));
__ btq(RAX, R11);
Label ok;
__ j(CARRY, &ok);
__ int3();
__ Bind(&ok);
__ movq(RAX, Immediate(1));
__ ret();
}
ASSEMBLER_TEST_RUN(BitTest, test) {
typedef int (*BitTest)();
EXPECT_EQ(1, reinterpret_cast<BitTest>(test->entry())());
}
// Return 1 if equal, 0 if not equal.
ASSEMBLER_TEST_GENERATE(ConditionalMovesEqual, assembler) {
__ movq(RDX, CallingConventions::kArg1Reg);
__ xorq(RAX, RAX);
__ movq(RCX, Immediate(1));
__ cmpq(RDX, Immediate(785));
__ cmoveq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(ConditionalMovesEqual, test) {
typedef int (*ConditionalMovesEqualCode)(int i);
int res = reinterpret_cast<ConditionalMovesEqualCode>(test->entry())(785);
EXPECT_EQ(1, res);
res = reinterpret_cast<ConditionalMovesEqualCode>(test->entry())(-12);
EXPECT_EQ(0, res);
}
// Return 1 if overflow, 0 if no overflow.
ASSEMBLER_TEST_GENERATE(ConditionalMovesNoOverflow, assembler) {
__ movq(RDX, CallingConventions::kArg1Reg);
__ addq(RDX, CallingConventions::kArg2Reg);
__ movq(RAX, Immediate(1));
__ movq(RCX, Immediate(0));
__ cmovnoq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(ConditionalMovesNoOverflow, test) {
typedef int (*ConditionalMovesNoOverflowCode)(int64_t i, int64_t j);
int res = reinterpret_cast<ConditionalMovesNoOverflowCode>(test->entry())(
0x7fffffffffffffff, 2);
EXPECT_EQ(1, res);
res = reinterpret_cast<ConditionalMovesNoOverflowCode>(test->entry())(1, 1);
EXPECT_EQ(0, res);
}
} // namespace dart
#endif // defined TARGET_ARCH_X64