blob: 43c481880e1897071510219751b21a99693dff57 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if defined(TARGET_ARCH_IA32)
#include "vm/compiler/assembler/assembler.h"
#include "vm/cpu.h"
#include "vm/os.h"
#include "vm/unit_test.h"
#include "vm/virtual_memory.h"
#if defined(PRODUCT)
#define EXPECT_DISASSEMBLY(expected)
#else
#define EXPECT_DISASSEMBLY(expected) \
EXPECT_STREQ(expected, test->RelativeDisassembly())
#endif
namespace dart {
namespace compiler {
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Simple, assembler) {
__ movl(EAX, Immediate(42));
__ ret();
}
ASSEMBLER_TEST_RUN(Simple, test) {
typedef int (*SimpleCode)();
EXPECT_EQ(42, reinterpret_cast<SimpleCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0x2a\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(ReadArgument, assembler) {
__ movl(EAX, Address(ESP, target::kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(ReadArgument, test) {
typedef int (*ReadArgumentCode)(int n);
EXPECT_EQ(42, reinterpret_cast<ReadArgumentCode>(test->entry())(42));
EXPECT_EQ(87, reinterpret_cast<ReadArgumentCode>(test->entry())(87));
EXPECT_DISASSEMBLY(
"mov eax,[esp+0x4]\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(AddressingModes, assembler) {
__ movl(EAX, Address(ESP, 0));
__ movl(EAX, Address(EBP, 0));
__ movl(EAX, Address(EAX, 0));
__ movl(EAX, Address(ESP, target::kWordSize));
__ movl(EAX, Address(EBP, target::kWordSize));
__ movl(EAX, Address(EAX, target::kWordSize));
__ movl(EAX, Address(ESP, -target::kWordSize));
__ movl(EAX, Address(EBP, -target::kWordSize));
__ movl(EAX, Address(EAX, -target::kWordSize));
__ movl(EAX, Address(ESP, 256 * target::kWordSize));
__ movl(EAX, Address(EBP, 256 * target::kWordSize));
__ movl(EAX, Address(EAX, 256 * target::kWordSize));
__ movl(EAX, Address(ESP, -256 * target::kWordSize));
__ movl(EAX, Address(EBP, -256 * target::kWordSize));
__ movl(EAX, Address(EAX, -256 * target::kWordSize));
__ movl(EAX, Address(EAX, TIMES_1));
__ movl(EAX, Address(EAX, TIMES_2));
__ movl(EAX, Address(EAX, TIMES_4));
__ movl(EAX, Address(EAX, TIMES_8));
__ movl(EAX, Address(EBP, TIMES_2));
__ movl(EAX, Address(EAX, TIMES_2));
__ movl(EAX, Address(EBP, TIMES_2, target::kWordSize));
__ movl(EAX, Address(EAX, TIMES_2, target::kWordSize));
__ movl(EAX, Address(EBP, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(EAX, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(EAX, EBP, TIMES_2, 0));
__ movl(EAX, Address(EAX, EAX, TIMES_2, 0));
__ movl(EAX, Address(EBP, EBP, TIMES_2, 0));
__ movl(EAX, Address(EBP, EAX, TIMES_2, 0));
__ movl(EAX, Address(ESP, EBP, TIMES_2, 0));
__ movl(EAX, Address(ESP, EAX, TIMES_2, 0));
__ movl(EAX, Address(EAX, EBP, TIMES_2, target::kWordSize));
__ movl(EAX, Address(EAX, EAX, TIMES_2, target::kWordSize));
__ movl(EAX, Address(EBP, EBP, TIMES_2, target::kWordSize));
__ movl(EAX, Address(EBP, EAX, TIMES_2, target::kWordSize));
__ movl(EAX, Address(ESP, EBP, TIMES_2, target::kWordSize));
__ movl(EAX, Address(ESP, EAX, TIMES_2, target::kWordSize));
__ movl(EAX, Address(EAX, EBP, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(EAX, EAX, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(EBP, EBP, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(EBP, EAX, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(ESP, EBP, TIMES_2, 256 * target::kWordSize));
__ movl(EAX, Address(ESP, EAX, TIMES_2, 256 * target::kWordSize));
}
ASSEMBLER_TEST_RUN(AddressingModes, test) {
// Avoid running the code since it is constructed to lead to crashes.
EXPECT_DISASSEMBLY(
"mov eax,[esp]\n"
"mov eax,[ebp+0]\n"
"mov eax,[eax]\n"
"mov eax,[esp+0x4]\n"
"mov eax,[ebp+0x4]\n"
"mov eax,[eax+0x4]\n"
"mov eax,[esp-0x4]\n"
"mov eax,[ebp-0x4]\n"
"mov eax,[eax-0x4]\n"
"mov eax,[esp+0x400]\n"
"mov eax,[ebp+0x400]\n"
"mov eax,[eax+0x400]\n"
"mov eax,[esp-0x400]\n"
"mov eax,[ebp-0x400]\n"
"mov eax,[eax-0x400]\n"
"mov eax,[eax]\n"
"mov eax,[eax+0x1]\n"
"mov eax,[eax+0x2]\n"
"mov eax,[eax+0x3]\n"
"mov eax,[ebp+0x1]\n"
"mov eax,[eax+0x1]\n"
"mov eax,[ebp*2+0x4]\n"
"mov eax,[eax*2+0x4]\n"
"mov eax,[ebp*2+0x400]\n"
"mov eax,[eax*2+0x400]\n"
"mov eax,[eax+ebp*2]\n"
"mov eax,[eax+eax*2]\n"
"mov eax,[ebp+ebp*2+0]\n"
"mov eax,[ebp+eax*2+0]\n"
"mov eax,[esp+ebp*2]\n"
"mov eax,[esp+eax*2]\n"
"mov eax,[eax+ebp*2+0x4]\n"
"mov eax,[eax+eax*2+0x4]\n"
"mov eax,[ebp+ebp*2+0x4]\n"
"mov eax,[ebp+eax*2+0x4]\n"
"mov eax,[esp+ebp*2+0x4]\n"
"mov eax,[esp+eax*2+0x4]\n"
"mov eax,[eax+ebp*2+0x400]\n"
"mov eax,[eax+eax*2+0x400]\n"
"mov eax,[ebp+ebp*2+0x400]\n"
"mov eax,[ebp+eax*2+0x400]\n"
"mov eax,[esp+ebp*2+0x400]\n"
"mov eax,[esp+eax*2+0x400]\n");
}
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.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ 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())();
EXPECT_DISASSEMBLY(
"jo +108\n"
"jno +102\n"
"jc +96\n"
"jnc +90\n"
"jz +84\n"
"jnz +78\n"
"jna +72\n"
"ja +66\n"
"js +60\n"
"jns +54\n"
"jpe +48\n"
"jpo +42\n"
"jl +36\n"
"jge +30\n"
"jle +24\n"
"jg +18\n"
"jmp +12\n"
"mov eax,0\n"
"mov [eax],eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(NearJumpAroundCrash, 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, Assembler::kNearJump);
}
// This isn't strictly necessary, but we do an unconditional
// jump around the crashing code anyway.
__ jmp(&done, Assembler::kNearJump);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&done);
__ ret();
}
ASSEMBLER_TEST_RUN(NearJumpAroundCrash, test) {
typedef void (*NearJumpAroundCrashCode)();
reinterpret_cast<NearJumpAroundCrashCode>(test->entry())();
EXPECT_DISASSEMBLY(
"jo +41\n"
"jno +39\n"
"jc +37\n"
"jnc +35\n"
"jz +33\n"
"jnz +31\n"
"jna +29\n"
"ja +27\n"
"js +25\n"
"jns +23\n"
"jpe +21\n"
"jpo +19\n"
"jl +17\n"
"jge +15\n"
"jle +13\n"
"jg +11\n"
"jmp +9\n"
"mov eax,0\n"
"mov [eax],eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SimpleLoop, assembler) {
__ movl(EAX, Immediate(0));
__ movl(ECX, Immediate(0));
Label loop;
__ Bind(&loop);
__ addl(EAX, Immediate(2));
__ incl(ECX);
__ cmpl(ECX, Immediate(87));
__ j(LESS, &loop);
__ ret();
}
ASSEMBLER_TEST_RUN(SimpleLoop, test) {
typedef int (*SimpleLoopCode)();
EXPECT_EQ(2 * 87, reinterpret_cast<SimpleLoopCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0\n"
"mov ecx,0\n"
"add eax,2\n"
"inc ecx\n"
"cmp ecx,0x57\n"
"jl -7\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Cmpb, assembler) {
Label done;
__ movl(EAX, Immediate(1));
__ pushl(Immediate(0xffffff11));
__ cmpb(Address(ESP, 0), Immediate(0x11));
__ j(EQUAL, &done, Assembler::kNearJump);
__ movl(EAX, Immediate(0));
__ Bind(&done);
__ popl(ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Cmpb, test) {
typedef int (*CmpbCode)();
EXPECT_EQ(1, reinterpret_cast<CmpbCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,1\n"
"push 0xffffff11\n"
"cmpb [esp],0x11\n"
"jz +7\n"
"mov eax,0\n"
"pop ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Testb, assembler) {
__ movl(EAX, Immediate(1));
__ movl(ECX, Immediate(0));
__ pushl(Immediate(0xffffff11));
__ testb(Address(ESP, 0), Immediate(0x10));
// Fail if zero flag set.
__ cmove(EAX, ECX);
__ testb(Address(ESP, 0), Immediate(0x20));
// Fail if zero flag not set.
__ cmovne(EAX, ECX);
__ popl(ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Testb, test) {
typedef int (*TestbCode)();
EXPECT_EQ(1, reinterpret_cast<TestbCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,1\n"
"mov ecx,0\n"
"push 0xffffff11\n"
"testb [esp],0x10\n"
"cmovz eax,ecx\n"
"testb [esp],0x20\n"
"cmovnz eax,ecx\n"
"pop ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Bsf, assembler) {
__ movl(ECX, Immediate(12));
__ bsfl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Bsf, test) {
typedef int (*BsfCode)();
EXPECT_EQ(2, reinterpret_cast<BsfCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov ecx,0xc\n"
"bsf eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Bsr, assembler) {
__ movl(ECX, Immediate(12));
__ bsrl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Bsr, test) {
typedef int (*BsrCode)();
EXPECT_EQ(3, reinterpret_cast<BsrCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov ecx,0xc\n"
"bsr eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Popcnt, assembler) {
__ movl(ECX, Immediate(-1));
__ popcntl(EAX, ECX);
__ movl(ECX, Immediate(0xf));
__ popcntl(ECX, ECX);
__ addl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Popcnt, test) {
if (!HostCPUFeatures::popcnt_supported()) {
return;
}
typedef int (*PopcntCode)();
EXPECT_EQ(36, reinterpret_cast<PopcntCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov ecx,0xffffffff\n"
"popcnt eax,ecx\n"
"mov ecx,0xf\n"
"popcnt ecx,ecx\n"
"add eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Lzcnt, assembler) {
__ movl(ECX, Immediate(0x0f00));
__ lzcntl(EAX, ECX);
__ movl(ECX, Immediate(0x00f0));
__ lzcntl(ECX, ECX);
__ addl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Lzcnt, test) {
if (!HostCPUFeatures::abm_supported()) {
return;
}
typedef int (*LzcntCode)();
EXPECT_EQ(44, reinterpret_cast<LzcntCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov ecx,0xf00\n"
"lzcnt eax,ecx\n"
"mov ecx,0xf0\n"
"lzcnt ecx,ecx\n"
"add eax,ecx\n"
"ret\n");
}
struct JumpAddress {
uword filler1;
uword filler2;
uword filler3;
uword filler4;
uword filler5;
uword target;
uword filler6;
uword filler7;
uword filler8;
};
static JumpAddress jump_address;
static uword jump_address_offset;
ASSEMBLER_TEST_GENERATE(JumpAddress, assembler) {
__ movl(EAX, Address(ESP, 4));
__ jmp(Address(EAX, OFFSET_OF(JumpAddress, target)));
__ int3();
__ int3();
__ int3();
__ int3();
__ int3();
jump_address_offset = __ CodeSize();
__ movl(EAX, Immediate(42));
__ ret();
}
ASSEMBLER_TEST_RUN(JumpAddress, test) {
memset(&jump_address, 0, sizeof(jump_address));
jump_address.target = test->entry() + jump_address_offset;
typedef int (*TestCode)(void*);
EXPECT_EQ(42, reinterpret_cast<TestCode>(test->entry())(&jump_address));
EXPECT_DISASSEMBLY(
"mov eax,[esp+0x4]\n"
"jmp [eax+0x14]\n"
"int3\n"
"int3\n"
"int3\n"
"int3\n"
"int3\n"
"mov eax,0x2a\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Increment, assembler) {
__ movl(EAX, Immediate(0));
__ pushl(EAX);
__ incl(Address(ESP, 0));
__ movl(ECX, Address(ESP, 0));
__ incl(ECX);
__ popl(EAX);
__ movl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Increment, test) {
typedef int (*IncrementCode)();
EXPECT_EQ(2, reinterpret_cast<IncrementCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0\n"
"push eax\n"
"inc [esp]\n"
"mov ecx,[esp]\n"
"inc ecx\n"
"pop eax\n"
"mov eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Decrement, assembler) {
__ movl(EAX, Immediate(2));
__ pushl(EAX);
__ decl(Address(ESP, 0));
__ movl(ECX, Address(ESP, 0));
__ decl(ECX);
__ popl(EAX);
__ movl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Decrement, test) {
typedef int (*DecrementCode)();
EXPECT_EQ(0, reinterpret_cast<DecrementCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,2\n"
"push eax\n"
"dec [esp]\n"
"mov ecx,[esp]\n"
"dec ecx\n"
"pop eax\n"
"mov eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(AddressBinOp, assembler) {
__ movl(EAX, Address(ESP, target::kWordSize));
__ addl(EAX, Address(ESP, target::kWordSize));
__ incl(EAX);
__ subl(EAX, Address(ESP, target::kWordSize));
__ imull(EAX, Address(ESP, target::kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(AddressBinOp, test) {
typedef int (*AddressBinOpCode)(int a);
EXPECT_EQ((2 + 2 + 1 - 2) * 2,
reinterpret_cast<AddressBinOpCode>(test->entry())(2));
EXPECT_DISASSEMBLY(
"mov eax,[esp+0x4]\n"
"add eax,[esp+0x4]\n"
"inc eax\n"
"sub eax,[esp+0x4]\n"
"imul eax,[esp+0x4]\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SignedMultiply, assembler) {
__ movl(EAX, Immediate(2));
__ movl(ECX, Immediate(4));
__ imull(EAX, ECX);
__ imull(EAX, Immediate(1000));
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply, test) {
typedef int (*SignedMultiply)();
EXPECT_EQ(8000, reinterpret_cast<SignedMultiply>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,2\n"
"mov ecx,4\n"
"imul eax,ecx\n"
"imul eax,eax,0x3e8\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(OverflowSignedMultiply, assembler) {
__ movl(EDX, Immediate(0));
__ movl(EAX, Immediate(0x0fffffff));
__ movl(ECX, Immediate(0x0fffffff));
__ imull(EAX, ECX);
__ imull(EAX, EDX);
__ ret();
}
ASSEMBLER_TEST_RUN(OverflowSignedMultiply, test) {
typedef int (*OverflowSignedMultiply)();
EXPECT_EQ(0, reinterpret_cast<OverflowSignedMultiply>(test->entry())());
EXPECT_DISASSEMBLY(
"mov edx,0\n"
"mov eax,0x0fffffff\n"
"mov ecx,0x0fffffff\n"
"imul eax,ecx\n"
"imul eax,edx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SignedMultiply1, assembler) {
__ pushl(EBX); // preserve EBX.
__ movl(EBX, Immediate(2));
__ movl(ECX, Immediate(4));
__ imull(EBX, ECX);
__ imull(EBX, Immediate(1000));
__ movl(EAX, EBX);
__ popl(EBX); // restore EBX.
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply1, test) {
typedef int (*SignedMultiply1)();
EXPECT_EQ(8000, reinterpret_cast<SignedMultiply1>(test->entry())());
EXPECT_DISASSEMBLY(
"push ebx\n"
"mov ebx,2\n"
"mov ecx,4\n"
"imul ebx,ecx\n"
"imul ebx,ebx,0x3e8\n"
"mov eax,ebx\n"
"pop ebx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Negate, assembler) {
__ movl(ECX, Immediate(42));
__ negl(ECX);
__ movl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Negate, test) {
typedef int (*Negate)();
EXPECT_EQ(-42, reinterpret_cast<Negate>(test->entry())());
EXPECT_DISASSEMBLY(
"mov ecx,0x2a\n"
"neg ecx\n"
"mov eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(BitScanReverseTest, assembler) {
__ movl(ECX, Address(ESP, target::kWordSize));
__ movl(EAX, Immediate(666)); // Marker for conditional write.
__ bsrl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(BitScanReverseTest, 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));
EXPECT_DISASSEMBLY(
"mov ecx,[esp+0x4]\n"
"mov eax,0x29a\n"
"bsr eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(MoveExtend, assembler) {
__ pushl(EBX); // preserve EBX.
__ movl(EDX, Immediate(0x1234ffff));
__ movzxb(EAX, DL); // EAX = 0xff
__ movsxw(EBX, EDX); // EBX = -1
__ movzxw(ECX, EDX); // ECX = 0xffff
__ addl(EBX, ECX);
__ addl(EAX, EBX);
__ popl(EBX); // restore EBX.
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtend, test) {
typedef int (*MoveExtend)();
EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtend>(test->entry())());
EXPECT_DISASSEMBLY(
"push ebx\n"
"mov edx,0x1234ffff\n"
"movzxb eax,edx\n"
"movsxw ebx,edx\n"
"movzxw ecx,edx\n"
"add ebx,ecx\n"
"add eax,ebx\n"
"pop ebx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(MoveExtendMemory, assembler) {
__ pushl(EBX); // preserve EBX.
__ movl(EDX, Immediate(0x1234ffff));
__ pushl(EDX);
__ movzxb(EAX, Address(ESP, 0)); // EAX = 0xff
__ movsxw(EBX, Address(ESP, 0)); // EBX = -1
__ movzxw(ECX, Address(ESP, 0)); // ECX = 0xffff
__ addl(ESP, Immediate(target::kWordSize));
__ addl(EBX, ECX);
__ addl(EAX, EBX);
__ popl(EBX); // restore EBX.
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtendMemory, test) {
typedef int (*MoveExtendMemory)();
EXPECT_EQ(0xff - 1 + 0xffff,
reinterpret_cast<MoveExtendMemory>(test->entry())());
EXPECT_DISASSEMBLY(
"push ebx\n"
"mov edx,0x1234ffff\n"
"push edx\n"
"movzxb eax,[esp]\n"
"movsxw ebx,[esp]\n"
"movzxw ecx,[esp]\n"
"add esp,4\n"
"add ebx,ecx\n"
"add eax,ebx\n"
"pop ebx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Bitwise, assembler) {
__ movl(ECX, Immediate(42));
__ xorl(ECX, ECX);
__ orl(ECX, Immediate(0x100));
__ movl(EAX, Immediate(0x648));
__ orl(ECX, EAX); // 0x748.
__ movl(EAX, Immediate(0xfff0));
__ andl(ECX, EAX); // 0x740.
__ pushl(Immediate(0xF6FF));
__ andl(ECX, Address(ESP, 0)); // 0x640.
__ popl(EAX); // Discard.
__ movl(EAX, Immediate(1));
__ orl(ECX, EAX); // 0x641.
__ pushl(Immediate(0x7));
__ orl(ECX, Address(ESP, 0)); // 0x647.
__ popl(EAX); // Discard.
__ xorl(ECX, Immediate(0)); // 0x647.
__ pushl(Immediate(0x1C));
__ xorl(ECX, Address(ESP, 0)); // 0x65B.
__ popl(EAX); // Discard.
__ movl(EAX, Address(ESP, target::kWordSize));
__ movl(EDX, Immediate(0xB0));
__ orl(Address(EAX, 0), EDX);
__ movl(EAX, ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(Bitwise, test) {
typedef int (*Bitwise)(int* value);
int value = 0xA;
const int result = reinterpret_cast<Bitwise>(test->entry())(&value);
EXPECT_EQ(0x65B, result);
EXPECT_EQ(0xBA, value);
EXPECT_DISASSEMBLY(
"mov ecx,0x2a\n"
"xor ecx,ecx\n"
"or ecx,0x100\n"
"mov eax,0x648\n"
"or ecx,eax\n"
"mov eax,0xfff0\n"
"and ecx,eax\n"
"push 0xf6ff\n"
"and ecx,[esp]\n"
"pop eax\n"
"mov eax,1\n"
"or ecx,eax\n"
"push 7\n"
"or ecx,[esp]\n"
"pop eax\n"
"xor ecx,0\n"
"push 0x1c\n"
"xor ecx,[esp]\n"
"pop eax\n"
"mov eax,[esp+0x4]\n"
"mov edx,0xb0\n"
"or [eax],edx\n"
"mov eax,ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(LogicalOps, assembler) {
Label donetest1;
__ movl(EAX, Immediate(4));
__ andl(EAX, Immediate(2));
__ cmpl(EAX, Immediate(0));
__ j(EQUAL, &donetest1);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest1);
Label donetest2;
__ movl(ECX, Immediate(4));
__ andl(ECX, Immediate(4));
__ cmpl(ECX, Immediate(0));
__ j(NOT_EQUAL, &donetest2);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest2);
Label donetest3;
__ movl(EAX, Immediate(0));
__ orl(EAX, Immediate(0));
__ cmpl(EAX, Immediate(0));
__ j(EQUAL, &donetest3);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest3);
Label donetest4;
__ movl(EAX, Immediate(4));
__ orl(EAX, Immediate(0));
__ cmpl(EAX, Immediate(0));
__ j(NOT_EQUAL, &donetest4);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest4);
Label donetest5;
__ movl(EAX, Immediate(1));
__ shll(EAX, Immediate(1));
__ cmpl(EAX, Immediate(2));
__ j(EQUAL, &donetest5);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest5);
Label donetest6;
__ movl(EAX, Immediate(1));
__ shll(EAX, Immediate(3));
__ cmpl(EAX, Immediate(8));
__ j(EQUAL, &donetest6);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest6);
Label donetest7;
__ movl(EAX, Immediate(2));
__ shrl(EAX, Immediate(1));
__ cmpl(EAX, Immediate(1));
__ j(EQUAL, &donetest7);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest7);
Label donetest8;
__ movl(EAX, Immediate(8));
__ shrl(EAX, Immediate(3));
__ cmpl(EAX, Immediate(1));
__ j(EQUAL, &donetest8);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest8);
Label donetest9;
__ movl(EAX, Immediate(1));
__ movl(ECX, Immediate(3));
__ shll(EAX, ECX);
__ cmpl(EAX, Immediate(8));
__ j(EQUAL, &donetest9);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest9);
Label donetest10;
__ movl(EAX, Immediate(8));
__ movl(ECX, Immediate(3));
__ shrl(EAX, ECX);
__ cmpl(EAX, Immediate(1));
__ j(EQUAL, &donetest10);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest10);
Label donetest11;
__ movl(EAX, Immediate(1));
__ shll(EAX, Immediate(31));
__ shrl(EAX, Immediate(3));
__ cmpl(EAX, Immediate(0x10000000));
__ j(EQUAL, &donetest11);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest11);
Label donetest12;
__ movl(EAX, Immediate(1));
__ shll(EAX, Immediate(31));
__ sarl(EAX, Immediate(3));
__ cmpl(EAX, Immediate(0xf0000000));
__ j(EQUAL, &donetest12);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest12);
Label donetest13;
__ movl(EAX, Immediate(1));
__ movl(ECX, Immediate(3));
__ shll(EAX, Immediate(31));
__ sarl(EAX, ECX);
__ cmpl(EAX, Immediate(0xf0000000));
__ j(EQUAL, &donetest13);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest13);
Label donetest14;
__ subl(ESP, Immediate(target::kWordSize));
__ movl(Address(ESP, 0), Immediate(0x80000000));
__ movl(EAX, Immediate(0));
__ movl(ECX, Immediate(3));
__ sarl(Address(ESP, 0), ECX);
__ shrdl(Address(ESP, 0), EAX, ECX);
__ cmpl(Address(ESP, 0), Immediate(0x1e000000));
__ j(EQUAL, &donetest14);
__ int3();
__ Bind(&donetest14);
__ addl(ESP, Immediate(target::kWordSize));
Label donetest15;
__ subl(ESP, Immediate(target::kWordSize));
__ movl(Address(ESP, 0), Immediate(0xFF000000));
__ movl(EAX, Immediate(-1));
__ movl(ECX, Immediate(2));
__ shll(Address(ESP, 0), ECX);
__ shldl(Address(ESP, 0), EAX, ECX);
__ cmpl(Address(ESP, 0), Immediate(0xF0000003));
__ j(EQUAL, &donetest15);
__ int3();
__ Bind(&donetest15);
__ addl(ESP, Immediate(target::kWordSize));
Label donetest16;
__ movl(EDX, Immediate(0x80000000));
__ movl(EAX, Immediate(0));
__ movl(ECX, Immediate(3));
__ sarl(EDX, Immediate(3));
__ shrdl(EDX, EAX, Immediate(3));
__ cmpl(EDX, Immediate(0x1e000000));
__ j(EQUAL, &donetest16);
__ int3();
__ Bind(&donetest16);
Label donetest17;
__ movl(EDX, Immediate(0xFF000000));
__ movl(EAX, Immediate(-1));
__ shll(EDX, Immediate(2));
__ shldl(EDX, EAX, Immediate(2));
__ cmpl(EDX, Immediate(0xF0000003));
__ j(EQUAL, &donetest17);
__ int3();
__ Bind(&donetest17);
__ movl(EAX, Immediate(0));
__ ret();
}
ASSEMBLER_TEST_RUN(LogicalOps, test) {
typedef int (*LogicalOpsCode)();
EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,4\n"
"and eax,2\n"
"cmp eax,0\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov ecx,4\n"
"and ecx,4\n"
"cmp ecx,0\n"
"jnz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,0\n"
"or eax,0\n"
"cmp eax,0\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,4\n"
"or eax,0\n"
"cmp eax,0\n"
"jnz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,1\n"
"shl eax,1\n"
"cmp eax,2\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,1\n"
"shl eax,3\n"
"cmp eax,8\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,2\n"
"shr eax,1\n"
"cmp eax,1\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,8\n"
"shr eax,3\n"
"cmp eax,1\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,1\n"
"mov ecx,3\n"
"shl eax,cl\n"
"cmp eax,8\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,8\n"
"mov ecx,3\n"
"shr eax,cl\n"
"cmp eax,1\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,1\n"
"shl eax,31\n"
"shr eax,3\n"
"cmp eax,0x10000000\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,1\n"
"shl eax,31\n"
"sar eax,3\n"
"cmp eax,0xf0000000\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,1\n"
"mov ecx,3\n"
"shl eax,31\n"
"sar eax,cl\n"
"cmp eax,0xf0000000\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"sub esp,4\n"
"mov [esp],-0x80000000\n"
"mov eax,0\n"
"mov ecx,3\n"
"sar [esp],cl\n"
"shrd [esp],eax,cl\n"
"cmp [esp],0x1e000000\n"
"jz +7\n"
"int3\n"
"add esp,4\n"
"sub esp,4\n"
"mov [esp],-0x01000000\n"
"mov eax,0xffffffff\n"
"mov ecx,2\n"
"shl [esp],cl\n"
"shld [esp],eax,cl\n"
"cmp [esp],0xf0000003\n"
"jz +7\n"
"int3\n"
"add esp,4\n"
"mov edx,0x80000000\n"
"mov eax,0\n"
"mov ecx,3\n"
"sar edx,3\n"
"shrd edx,eax,3\n"
"cmp edx,0x1e000000\n"
"jz +7\n"
"int3\n"
"mov edx,0xff000000\n"
"mov eax,0xffffffff\n"
"shl edx,2\n"
"shld edx,eax,2\n"
"cmp edx,0xf0000003\n"
"jz +7\n"
"int3\n"
"mov eax,0\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(LogicalTest, assembler) {
__ pushl(EBX); // save EBX.
Label donetest1;
__ movl(EAX, Immediate(4));
__ movl(ECX, Immediate(2));
__ testl(EAX, ECX);
__ j(EQUAL, &donetest1);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest1);
Label donetest2;
__ movl(EDX, Immediate(4));
__ movl(ECX, Immediate(4));
__ testl(EDX, ECX);
__ j(NOT_EQUAL, &donetest2);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest2);
Label donetest3;
__ movl(EAX, Immediate(0));
__ testl(EAX, Immediate(0));
__ j(EQUAL, &donetest3);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest3);
Label donetest4;
__ movl(EBX, Immediate(4));
__ testl(EBX, Immediate(4));
__ j(NOT_EQUAL, &donetest4);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest4);
Label donetest5;
__ movl(EBX, Immediate(0xff));
__ testl(EBX, Immediate(0xff));
__ j(NOT_EQUAL, &donetest5);
// Be sure to skip this crashing code.
__ movl(EAX, Immediate(0));
__ movl(Address(EAX, 0), EAX);
__ Bind(&donetest5);
__ movl(EAX, Immediate(0));
__ popl(EBX); // restore EBX.
__ ret();
}
ASSEMBLER_TEST_RUN(LogicalTest, test) {
typedef int (*LogicalTestCode)();
EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(test->entry())());
EXPECT_DISASSEMBLY(
"push ebx\n"
"mov eax,4\n"
"mov ecx,2\n"
"test eax,ecx\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov edx,4\n"
"mov ecx,4\n"
"test edx,ecx\n"
"jnz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,0\n"
"test al,0\n"
"jz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov ebx,4\n"
"testb ebx,4\n"
"jnz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov ebx,0xff\n"
"testb ebx,0xff\n"
"jnz +13\n"
"mov eax,0\n"
"mov [eax],eax\n"
"mov eax,0\n"
"pop ebx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(CompareSwapEQ, assembler) {
__ movl(EAX, Immediate(0));
__ pushl(EAX);
__ movl(EAX, Immediate(4));
__ movl(ECX, Immediate(0));
__ movl(Address(ESP, 0), EAX);
__ LockCmpxchgl(Address(ESP, 0), ECX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapEQ, test) {
typedef int (*CompareSwapEQCode)();
EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0\n"
"push eax\n"
"mov eax,4\n"
"mov ecx,0\n"
"mov [esp],eax\n"
"lock cmpxchg ecx,[esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(CompareSwapNEQ, assembler) {
__ movl(EAX, Immediate(0));
__ pushl(EAX);
__ movl(EAX, Immediate(2));
__ movl(ECX, Immediate(4));
__ movl(Address(ESP, 0), ECX);
__ LockCmpxchgl(Address(ESP, 0), ECX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapNEQ, test) {
typedef int (*CompareSwapNEQCode)();
EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0\n"
"push eax\n"
"mov eax,2\n"
"mov ecx,4\n"
"mov [esp],ecx\n"
"lock cmpxchg ecx,[esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SignedDivide, assembler) {
__ movl(EAX, Immediate(-87));
__ movl(EDX, Immediate(123));
__ cdq();
__ movl(ECX, Immediate(42));
__ idivl(ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedDivide, test) {
typedef int (*SignedDivide)();
EXPECT_EQ(-87 / 42, reinterpret_cast<SignedDivide>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0xffffffa9\n"
"mov edx,0x7b\n"
"cdq\n"
"mov ecx,0x2a\n"
"idiv (eax,edx),ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(UnsignedDivide, assembler) {
__ movl(EAX, Immediate(0xffffffbe));
__ movl(EDX, Immediate(0x41));
__ movl(ECX, Immediate(-1));
__ divl(ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(UnsignedDivide, test) {
typedef int (*UnsignedDivide)();
EXPECT_EQ(0x42, reinterpret_cast<UnsignedDivide>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0xffffffbe\n"
"mov edx,0x41\n"
"mov ecx,0xffffffff\n"
"div (eax,edx),ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Exchange, assembler) {
__ movl(EAX, Immediate(123456789));
__ movl(EDX, Immediate(987654321));
__ xchgl(EAX, EDX);
__ subl(EAX, EDX);
__ ret();
}
ASSEMBLER_TEST_RUN(Exchange, test) {
typedef int (*Exchange)();
EXPECT_EQ(987654321 - 123456789, reinterpret_cast<Exchange>(test->entry())());
EXPECT_DISASSEMBLY(
"mov eax,0x075bcd15\n"
"mov edx,0x3ade68b1\n"
"xchg eax,edx\n"
"sub eax,edx\n"
"ret\n");
}
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, 4);
__ AddImmediate(ESP, Immediate(-space));
__ call(&call1);
__ AddImmediate(ESP, Immediate(space));
space = ComputeStackSpaceReservation(4, 4);
__ AddImmediate(ESP, Immediate(-space));
__ movl(Address(ESP, 0), EAX);
__ call(&call2);
__ AddImmediate(ESP, Immediate(space));
__ ret();
}
ASSEMBLER_TEST_RUN(CallSimpleLeaf, 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, 4);
__ AddImmediate(ESP, Immediate(-space));
__ call(&L);
__ AddImmediate(ESP, 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(JumpConditionalSimpleLeaf, assembler) {
ExternalLabel call1(reinterpret_cast<uword>(LeafReturn42));
Label L;
int space = ComputeStackSpaceReservation(0, 4);
__ AddImmediate(ESP, Immediate(-space));
__ call(&L);
__ AddImmediate(ESP, Immediate(space));
__ ret();
__ Bind(&L);
__ cmpl(EAX, EAX);
__ j(EQUAL, &call1);
__ int3();
}
ASSEMBLER_TEST_RUN(JumpConditionalSimpleLeaf, test) {
typedef int (*JumpConditionalSimpleLeafCode)();
EXPECT_EQ(42,
reinterpret_cast<JumpConditionalSimpleLeafCode>(test->entry())());
}
ASSEMBLER_TEST_GENERATE(SingleFPMoves, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(234.0f)));
__ movd(XMM0, EAX);
__ movss(XMM1, XMM0);
__ movss(XMM2, XMM1);
__ movss(XMM3, XMM2);
__ movss(XMM4, XMM3);
__ movss(XMM5, XMM4);
__ movss(XMM6, XMM5);
__ movss(XMM7, XMM6);
__ pushl(EAX);
__ movl(Address(ESP, 0), Immediate(0));
__ movss(Address(ESP, 0), XMM7);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPMoves, test) {
typedef float (*SingleFPMovesCode)();
float res = reinterpret_cast<SingleFPMovesCode>(test->entry())();
EXPECT_EQ(234.0f, res);
EXPECT_DISASSEMBLY(
"mov eax,0x436a0000\n"
"movd xmm0,eax\n"
"movss ecx,xmm0\n"
"movss edx,xmm1\n"
"movss ebx,xmm2\n"
"movss esp,xmm3\n"
"movss ebp,xmm4\n"
"movss esi,xmm5\n"
"movss edi,xmm6\n"
"push eax\n"
"mov [esp],0\n"
"movss [esp],xmm7\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SingleFPMoves2, assembler) {
__ pushl(EBX); // preserve EBX.
__ pushl(ECX); // preserve ECX.
__ movl(EBX, Immediate(bit_cast<int32_t, float>(234.0f)));
__ movd(XMM0, EBX);
__ movss(XMM1, XMM0);
__ movd(ECX, XMM1);
__ pushl(ECX);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ popl(ECX);
__ popl(EBX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPMoves2, test) {
typedef float (*SingleFPMoves2Code)();
float res = reinterpret_cast<SingleFPMoves2Code>(test->entry())();
EXPECT_EQ(234.0f, res);
EXPECT_DISASSEMBLY(
"push ebx\n"
"push ecx\n"
"mov ebx,0x436a0000\n"
"movd xmm0,ebx\n"
"movss ecx,xmm0\n"
"movd ecx,xmm1\n"
"push ecx\n"
"fld_s [esp]\n"
"pop eax\n"
"pop ecx\n"
"pop ebx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SingleFPUStackMoves, assembler) {
__ movl(EAX, Immediate(1131020288)); // 234.0f
__ pushl(EAX);
__ flds(Address(ESP, 0));
__ xorl(ECX, ECX);
__ pushl(ECX);
__ fstps(Address(ESP, 0));
__ popl(EAX);
__ popl(ECX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPUStackMoves, test) {
typedef int (*SingleFPUStackMovesCode)();
int res = reinterpret_cast<SingleFPUStackMovesCode>(test->entry())();
EXPECT_EQ(234.0f, (bit_cast<float, int>(res)));
EXPECT_DISASSEMBLY(
"mov eax,0x436a0000\n"
"push eax\n"
"fld_s [esp]\n"
"xor ecx,ecx\n"
"push ecx\n"
"fstp_s [esp]\n"
"pop eax\n"
"pop ecx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SingleFPOperations, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, EAX);
__ movl(EAX, Immediate(bit_cast<int32_t, float>(3.4f)));
__ movd(XMM1, EAX);
__ addss(XMM0, XMM1); // 15.7f
__ mulss(XMM0, XMM1); // 53.38f
__ subss(XMM0, XMM1); // 49.98f
__ divss(XMM0, XMM1); // 14.7f
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPOperations, test) {
typedef float (*SingleFPOperationsCode)();
float res = reinterpret_cast<SingleFPOperationsCode>(test->entry())();
EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x4144cccd\n"
"movd xmm0,eax\n"
"mov eax,0x4059999a\n"
"movd xmm1,eax\n"
"addss xmm0,xmm1\n"
"mulss xmm0,xmm1\n"
"subss xmm0,xmm1\n"
"divss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, EAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ movl(EAX, Immediate(bit_cast<int32_t, float>(3.4f)));
__ movd(XMM1, EAX);
__ shufps(XMM1, XMM1, Immediate(0x0));
__ addps(XMM0, XMM1); // 15.7f
__ mulps(XMM0, XMM1); // 53.38f
__ subps(XMM0, XMM1); // 49.98f
__ divps(XMM0, XMM1); // 14.7f
__ shufps(XMM0, XMM0, Immediate(0x55)); // Copy second lane into all 4 lanes.
__ pushl(EAX);
// Copy the low lane at ESP.
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedFPOperations, test) {
typedef float (*PackedFPOperationsCode)();
float res = reinterpret_cast<PackedFPOperationsCode>(test->entry())();
EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x4144cccd\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x4059999a\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"addps xmm0,xmm1\n"
"mulps xmm0,xmm1\n"
"subps xmm0,xmm1\n"
"divps xmm0,xmm1\n"
"shufps xmm0,xmm0 [55]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedIntOperations, assembler) {
__ movl(EAX, Immediate(0x2));
__ movd(XMM0, EAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ movl(EAX, Immediate(0x1));
__ movd(XMM1, EAX);
__ shufps(XMM1, XMM1, Immediate(0x0));
__ addpl(XMM0, XMM1); // 0x3
__ addpl(XMM0, XMM0); // 0x6
__ subpl(XMM0, XMM1); // 0x5
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ popl(EAX);
__ 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);
EXPECT_DISASSEMBLY(
"mov eax,2\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,1\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"paddd xmm0,xmm1\n"
"paddd xmm0,xmm0\n"
"psubd xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ movd(XMM0, EAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ movaps(XMM1, XMM0); // Copy XMM0
__ reciprocalps(XMM1); // 0.25
__ sqrtps(XMM1); // 0.5
__ rsqrtps(XMM0); // ~0.5
__ subps(XMM0, XMM1); // ~0.0
__ shufps(XMM0, XMM0, Immediate(0x00)); // Copy second lane into all 4 lanes.
__ pushl(EAX);
// Copy the low lane at ESP.
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedFPOperations2, test) {
typedef float (*PackedFPOperations2Code)();
float res = reinterpret_cast<PackedFPOperations2Code>(test->entry())();
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x40800000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"movaps xmm1,xmm0\n"
"rcpps xmm1,xmm1\n"
"sqrtps xmm1,xmm1\n"
"rsqrtps xmm0,xmm0\n"
"subps xmm0,xmm1\n"
"shufps xmm0,xmm0 [0]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppseq(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareEQ, test) {
typedef uint32_t (*PackedCompareEQCode)();
uint32_t res = reinterpret_cast<PackedCompareEQCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"cmpps xmm0,xmm1 [eq]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsneq(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareNEQ, test) {
typedef uint32_t (*PackedCompareNEQCode)();
uint32_t res = reinterpret_cast<PackedCompareNEQCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"cmpps xmm0,xmm1 [neq]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppslt(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareLT, test) {
typedef uint32_t (*PackedCompareLTCode)();
uint32_t res = reinterpret_cast<PackedCompareLTCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"cmpps xmm0,xmm1 [lt]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsle(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareLE, test) {
typedef uint32_t (*PackedCompareLECode)();
uint32_t res = reinterpret_cast<PackedCompareLECode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"cmpps xmm0,xmm1 [le]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsnlt(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareNLT, test) {
typedef uint32_t (*PackedCompareNLTCode)();
uint32_t res = reinterpret_cast<PackedCompareNLTCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"cmpps xmm0,xmm1 [nlt]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ cmppsnle(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedCompareNLE, test) {
typedef uint32_t (*PackedCompareNLECode)();
uint32_t res = reinterpret_cast<PackedCompareNLECode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"cmpps xmm0,xmm1 [nle]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, EAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ negateps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
__ pushl(EAX);
// Copy the low lane at ESP.
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedNegate, test) {
typedef float (*PackedNegateCode)();
float res = reinterpret_cast<PackedNegateCode>(test->entry())();
EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x4144cccd\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"xorps xmm0,[0x.......]\n"
"shufps xmm0,xmm0 [aa]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
__ movd(XMM0, EAX);
__ shufps(XMM0, XMM0, Immediate(0x0));
__ absps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
typedef float (*PackedAbsoluteCode)();
float res = reinterpret_cast<PackedAbsoluteCode>(test->entry())();
EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0xc174cccd\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"andps xmm0,[0x.......]\n"
"shufps xmm0,xmm0 [aa]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ zerowps(XMM0);
__ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0.
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
typedef float (*PackedSetWZeroCode)();
float res = reinterpret_cast<PackedSetWZeroCode>(test->entry())();
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x4144cccd\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"andps xmm0,[0x.......]\n"
"shufps xmm0,xmm0 [ff]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedMin, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ minps(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMin, test) {
typedef float (*PackedMinCode)();
float res = reinterpret_cast<PackedMinCode>(test->entry())();
EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"minps xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedMax, assembler) {
__ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
__ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
__ maxps(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMax, test) {
typedef float (*PackedMaxCode)();
float res = reinterpret_cast<PackedMaxCode>(test->entry())();
EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x40000000\n"
"movd xmm0,eax\n"
"shufps xmm0,xmm0 [0]\n"
"mov eax,0x40800000\n"
"movd xmm1,eax\n"
"shufps xmm1,xmm1 [0]\n"
"maxps xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedLogicalOr, assembler) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} constant1 = {0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0};
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} constant2 = {0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant2)));
__ orps(XMM0, XMM1);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedLogicalOr, test) {
typedef uint32_t (*PackedLogicalOrCode)();
uint32_t res = reinterpret_cast<PackedLogicalOrCode>(test->entry())();
EXPECT_EQ(0xFFFFFFFF, res);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"orps xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedLogicalAnd, assembler) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} constant1 = {0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0};
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} constant2 = {0x0F0FFF0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ andps(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant2)));
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedLogicalAnd, test) {
typedef uint32_t (*PackedLogicalAndCode)();
uint32_t res = reinterpret_cast<PackedLogicalAndCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0000F000), res);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"andps xmm0,[0x.......]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
static const struct ALIGN16 {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} constant1 = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ notps(XMM0);
// Copy the low lane at ESP.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
typedef uint32_t (*PackedLogicalNotCode)();
uint32_t res = reinterpret_cast<PackedLogicalNotCode>(test->entry())();
EXPECT_EQ(static_cast<uword>(0x0), res);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"xorps xmm0,[0x.......]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
// XMM0 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
// XMM0 = 7.0f, 8.0f, 3.0f, 4.0f.
__ movhlps(XMM0, XMM1);
__ xorps(XMM1, XMM1);
// XMM1 = 7.0f, 8.0f, 3.0f, 4.0f.
__ movaps(XMM1, XMM0);
__ shufps(XMM0, XMM0, Immediate(0x00)); // 7.0f.
__ shufps(XMM1, XMM1, Immediate(0x55)); // 8.0f.
__ addss(XMM0, XMM1); // 15.0f.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMoveHighLow, test) {
typedef float (*PackedMoveHighLow)();
float res = reinterpret_cast<PackedMoveHighLow>(test->entry())();
EXPECT_FLOAT_EQ(15.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"movhlps xmm0,xmm1\n"
"xorps xmm1,xmm1\n"
"movaps xmm1,xmm0\n"
"shufps xmm0,xmm0 [0]\n"
"shufps xmm1,xmm1 [55]\n"
"addss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
// XMM0 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
// XMM0 = 1.0f, 2.0f, 5.0f, 6.0f
__ movlhps(XMM0, XMM1);
__ xorps(XMM1, XMM1);
// XMM1 = 1.0f, 2.0f, 5.0f, 6.0f
__ movaps(XMM1, XMM0);
__ shufps(XMM0, XMM0, Immediate(0xAA)); // 5.0f.
__ shufps(XMM1, XMM1, Immediate(0xFF)); // 6.0f.
__ addss(XMM0, XMM1); // 11.0f.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedMoveLowHigh, test) {
typedef float (*PackedMoveLowHigh)();
float res = reinterpret_cast<PackedMoveLowHigh>(test->entry())();
EXPECT_FLOAT_EQ(11.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"movlhps xmm0,xmm1\n"
"xorps xmm1,xmm1\n"
"movaps xmm1,xmm0\n"
"shufps xmm0,xmm0 [aa]\n"
"shufps xmm1,xmm1 [ff]\n"
"addss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
// XMM0 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
// XMM0 = 1.0f, 5.0f, 2.0f, 6.0f.
__ unpcklps(XMM0, XMM1);
// XMM1 = 1.0f, 5.0f, 2.0f, 6.0f.
__ movaps(XMM1, XMM0);
__ shufps(XMM0, XMM0, Immediate(0x55));
__ shufps(XMM1, XMM1, Immediate(0xFF));
__ addss(XMM0, XMM1); // 11.0f.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackLow, test) {
typedef float (*PackedUnpackLow)();
float res = reinterpret_cast<PackedUnpackLow>(test->entry())();
EXPECT_FLOAT_EQ(11.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"unpcklps xmm0,xmm1\n"
"movaps xmm1,xmm0\n"
"shufps xmm0,xmm0 [55]\n"
"shufps xmm1,xmm1 [ff]\n"
"addss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
// XMM0 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
// XMM0 = 3.0f, 7.0f, 4.0f, 8.0f.
__ unpckhps(XMM0, XMM1);
// XMM1 = 3.0f, 7.0f, 4.0f, 8.0f.
__ movaps(XMM1, XMM0);
__ shufps(XMM0, XMM0, Immediate(0x00));
__ shufps(XMM1, XMM1, Immediate(0xAA));
__ addss(XMM0, XMM1); // 7.0f.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackHigh, test) {
typedef float (*PackedUnpackHigh)();
float res = reinterpret_cast<PackedUnpackHigh>(test->entry())();
EXPECT_FLOAT_EQ(7.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"unpckhps xmm0,xmm1\n"
"movaps xmm1,xmm0\n"
"shufps xmm0,xmm0 [0]\n"
"shufps xmm1,xmm1 [aa]\n"
"addss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
// XMM0 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
// XMM0 = 1.0f, 2.0f, 5.0f, 6.0f.
__ unpcklpd(XMM0, XMM1);
// XMM1 = 1.0f, 2.0f, 5.0f, 6.0f.
__ movaps(XMM1, XMM0);
__ shufps(XMM0, XMM0, Immediate(0x00));
__ shufps(XMM1, XMM1, Immediate(0xAA));
__ addss(XMM0, XMM1); // 6.0f.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackLowPair, test) {
typedef float (*PackedUnpackLowPair)();
float res = reinterpret_cast<PackedUnpackLowPair>(test->entry())();
EXPECT_FLOAT_EQ(6.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"unpcklpd xmm0,xmm1\n"
"movaps xmm1,xmm0\n"
"shufps xmm0,xmm0 [0]\n"
"shufps xmm1,xmm1 [aa]\n"
"addss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
// XMM0 = 1.0f, 2.0f, 3.0f, 4.0f.
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// XMM1 = 5.0f, 6.0f, 7.0f, 8.0f.
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
// XMM0 = 3.0f, 4.0f, 7.0f, 8.0f.
__ unpckhpd(XMM0, XMM1);
// XMM1 = 3.0f, 4.0f, 7.0f, 8.0f.
__ movaps(XMM1, XMM0);
__ shufps(XMM0, XMM0, Immediate(0x55));
__ shufps(XMM1, XMM1, Immediate(0xFF));
__ addss(XMM0, XMM1); // 12.0f.
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedUnpackHighPair, test) {
typedef float (*PackedUnpackHighPair)();
float res = reinterpret_cast<PackedUnpackHighPair>(test->entry())();
EXPECT_FLOAT_EQ(12.0f, res, 0.001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"unpckhpd xmm0,xmm1\n"
"movaps xmm1,xmm0\n"
"shufps xmm0,xmm0 [55]\n"
"shufps xmm1,xmm1 [ff]\n"
"addss xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ addpd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleAdd, test) {
typedef double (*PackedDoubleAdd)();
double res = reinterpret_cast<PackedDoubleAdd>(test->entry())();
EXPECT_FLOAT_EQ(4.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"addpd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ subpd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleSub, test) {
typedef double (*PackedDoubleSub)();
double res = reinterpret_cast<PackedDoubleSub>(test->entry())();
EXPECT_FLOAT_EQ(-2.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"subpd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedDoubleNegate, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {1.0, 2.0};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ negatepd(XMM0);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleNegate, test) {
typedef double (*PackedDoubleNegate)();
double res = reinterpret_cast<PackedDoubleNegate>(test->entry())();
EXPECT_FLOAT_EQ(-1.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"xorpd xmm0,[0x.......]\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedDoubleAbsolute, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {-1.0, 2.0};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ abspd(XMM0);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleAbsolute, test) {
typedef double (*PackedDoubleAbsolute)();
double res = reinterpret_cast<PackedDoubleAbsolute>(test->entry())();
EXPECT_FLOAT_EQ(1.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"andpd xmm0,[0x.......]\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ mulpd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleMul, test) {
typedef double (*PackedDoubleMul)();
double res = reinterpret_cast<PackedDoubleMul>(test->entry())();
EXPECT_FLOAT_EQ(9.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"mulpd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ divpd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleDiv, test) {
typedef double (*PackedDoubleDiv)();
double res = reinterpret_cast<PackedDoubleDiv>(test->entry())();
EXPECT_FLOAT_EQ(3.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"divpd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedDoubleSqrt, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {16.0, 2.0};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ sqrtpd(XMM0);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleSqrt, test) {
typedef double (*PackedDoubleSqrt)();
double res = reinterpret_cast<PackedDoubleSqrt>(test->entry())();
EXPECT_FLOAT_EQ(4.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"sqrtpd xmm0,xmm0\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ minpd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleMin, test) {
typedef double (*PackedDoubleMin)();
double res = reinterpret_cast<PackedDoubleMin>(test->entry())();
EXPECT_FLOAT_EQ(3.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"minpd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant1)));
__ maxpd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleMax, test) {
typedef double (*PackedDoubleMax)();
double res = reinterpret_cast<PackedDoubleMax>(test->entry())();
EXPECT_FLOAT_EQ(9.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"movups xmm1,[0x.......]\n"
"maxpd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedDoubleShuffle, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {2.0, 9.0};
__ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant0)));
// Splat Y across all lanes.
__ shufpd(XMM0, XMM0, Immediate(0x33));
// Splat X across all lanes.
__ shufpd(XMM0, XMM0, Immediate(0x0));
// Set return value.
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleShuffle, test) {
typedef double (*PackedDoubleShuffle)();
double res = reinterpret_cast<PackedDoubleShuffle>(test->entry())();
EXPECT_FLOAT_EQ(9.0, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm0,[0x.......]\n"
"shufpd xmm0, xmm0 [33]\n"
"shufpd xmm0, xmm0 [0]\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(PackedDoubleToSingle, assembler) {
static const struct ALIGN16 {
double a;
double b;
} constant0 = {9.0, 2.0};
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ cvtpd2ps(XMM0, XMM1);
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedDoubleToSingle, test) {
typedef float (*PackedDoubleToSingle)();
float res = reinterpret_cast<PackedDoubleToSingle>(test->entry())();
EXPECT_FLOAT_EQ(9.0f, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm1,[0x.......]\n"
"cvtpd2ps xmm0,xmm1\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
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};
__ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant0)));
__ cvtps2pd(XMM0, XMM1);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(PackedSingleToDouble, test) {
typedef double (*PackedSingleToDouble)();
double res = reinterpret_cast<PackedSingleToDouble>(test->entry())();
EXPECT_FLOAT_EQ(9.0f, res, 0.000001f);
EXPECT_DISASSEMBLY(
"movups xmm1,[0x.......]\n"
"cvtps2pd xmm0,xmm1\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SingleFPOperationsStack, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, EAX);
__ addss(XMM0, Address(ESP, target::kWordSize)); // 15.7f
__ mulss(XMM0, Address(ESP, target::kWordSize)); // 53.38f
__ subss(XMM0, Address(ESP, target::kWordSize)); // 49.98f
__ divss(XMM0, Address(ESP, target::kWordSize)); // 14.7f
__ pushl(EAX);
__ movss(Address(ESP, 0), XMM0);
__ flds(Address(ESP, 0));
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(SingleFPOperationsStack, test) {
typedef float (*SingleFPOperationsStackCode)(float f);
float res = reinterpret_cast<SingleFPOperationsStackCode>(test->entry())(3.4);
EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
EXPECT_DISASSEMBLY(
"mov eax,0x4144cccd\n"
"movd xmm0,eax\n"
"addss xmm0,[esp+0x4]\n"
"mulss xmm0,[esp+0x4]\n"
"subss xmm0,[esp+0x4]\n"
"divss xmm0,[esp+0x4]\n"
"push eax\n"
"movss [esp],xmm0\n"
"fld_s [esp]\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(DoubleFPMoves, assembler) {
int64_t l = bit_cast<int64_t, double>(1024.67);
__ movl(EAX, Immediate(Utils::High32Bits(l)));
__ pushl(EAX);
__ movl(EAX, Immediate(Utils::Low32Bits(l)));
__ pushl(EAX);
__ movsd(XMM0, Address(ESP, 0));
__ movsd(XMM1, XMM0);
__ movsd(XMM2, XMM1);
__ movsd(XMM3, XMM2);
__ movsd(XMM4, XMM3);
__ movsd(XMM5, XMM4);
__ movsd(XMM6, XMM5);
__ movsd(XMM7, XMM6);
__ movl(Address(ESP, 0), Immediate(0));
__ movl(Address(ESP, target::kWordSize), Immediate(0));
__ movsd(XMM0, Address(ESP, 0));
__ movsd(Address(ESP, 0), XMM7);
__ movsd(XMM7, Address(ESP, 0));
__ movaps(XMM6, XMM7);
__ movaps(XMM5, XMM6);
__ movaps(XMM4, XMM5);
__ movaps(XMM3, XMM4);
__ movaps(XMM2, XMM3);
__ movaps(XMM1, XMM2);
__ movaps(XMM0, XMM1);
__ movl(Address(ESP, 0), Immediate(0));
__ movl(Address(ESP, target::kWordSize), Immediate(0));
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleFPMoves, test) {
typedef double (*DoubleFPMovesCode)();
double res = reinterpret_cast<DoubleFPMovesCode>(test->entry())();
EXPECT_FLOAT_EQ(1024.67, res, 0.0001);
EXPECT_DISASSEMBLY(
"mov eax,0x409002ae\n"
"push eax\n"
"mov eax,0x147ae148\n"
"push eax\n"
"movsd xmm0,[esp]\n"
"movsd xmm1,xmm0\n"
"movsd xmm2,xmm1\n"
"movsd xmm3,xmm2\n"
"movsd xmm4,xmm3\n"
"movsd xmm5,xmm4\n"
"movsd xmm6,xmm5\n"
"movsd xmm7,xmm6\n"
"mov [esp],0\n"
"mov [esp+0x4],0\n"
"movsd xmm0,[esp]\n"
"movsd [esp],xmm7\n"
"movsd xmm7,[esp]\n"
"movaps xmm6,xmm7\n"
"movaps xmm5,xmm6\n"
"movaps xmm4,xmm5\n"
"movaps xmm3,xmm4\n"
"movaps xmm2,xmm3\n"
"movaps xmm1,xmm2\n"
"movaps xmm0,xmm1\n"
"mov [esp],0\n"
"mov [esp+0x4],0\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(DoubleFPUStackMoves, assembler) {
int64_t l = bit_cast<int64_t, double>(1024.67);
__ movl(EAX, Immediate(Utils::High32Bits(l)));
__ pushl(EAX);
__ movl(EAX, Immediate(Utils::Low32Bits(l)));
__ pushl(EAX);
__ fldl(Address(ESP, 0));
__ movl(Address(ESP, 0), Immediate(0));
__ movl(Address(ESP, target::kWordSize), Immediate(0));
__ fstpl(Address(ESP, 0));
__ popl(EAX);
__ popl(EDX);
__ 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);
EXPECT_DISASSEMBLY(
"mov eax,0x409002ae\n"
"push eax\n"
"mov eax,0x147ae148\n"
"push eax\n"
"fld_d [esp]\n"
"mov [esp],0\n"
"mov [esp+0x4],0\n"
"fstp_d [esp]\n"
"pop eax\n"
"pop edx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(DoubleFPOperations, assembler) {
int64_t l = bit_cast<int64_t, double>(12.3);
__ movl(EAX, Immediate(Utils::High32Bits(l)));
__ pushl(EAX);
__ movl(EAX, Immediate(Utils::Low32Bits(l)));
__ pushl(EAX);
__ movsd(XMM0, Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
l = bit_cast<int64_t, double>(3.4);
__ movl(EAX, Immediate(Utils::High32Bits(l)));
__ pushl(EAX);
__ movl(EAX, Immediate(Utils::Low32Bits(l)));
__ pushl(EAX);
__ movsd(XMM1, Address(ESP, 0));
__ addsd(XMM0, XMM1); // 15.7
__ mulsd(XMM0, XMM1); // 53.38
__ subsd(XMM0, XMM1); // 49.98
__ divsd(XMM0, XMM1); // 14.7
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleFPOperations, test) {
typedef double (*DoubleFPOperationsCode)();
double res = reinterpret_cast<DoubleFPOperationsCode>(test->entry())();
EXPECT_FLOAT_EQ(14.7, res, 0.001);
EXPECT_DISASSEMBLY(
"mov eax,0x40289999\n"
"push eax\n"
"mov eax,0x9999999a\n"
"push eax\n"
"movsd xmm0,[esp]\n"
"pop eax\n"
"pop eax\n"
"mov eax,0x400b3333\n"
"push eax\n"
"mov eax,0x33333333\n"
"push eax\n"
"movsd xmm1,[esp]\n"
"addsd xmm0,xmm1\n"
"mulsd xmm0,xmm1\n"
"subsd xmm0,xmm1\n"
"divsd xmm0,xmm1\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(DoubleFPOperationsStack, assembler) {
int64_t l = bit_cast<int64_t, double>(12.3);
__ movl(EAX, Immediate(Utils::High32Bits(l)));
__ pushl(EAX);
__ movl(EAX, Immediate(Utils::Low32Bits(l)));
__ pushl(EAX);
__ movsd(XMM0, Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ addsd(XMM0, Address(ESP, target::kWordSize)); // 15.7
__ mulsd(XMM0, Address(ESP, target::kWordSize)); // 53.38
__ subsd(XMM0, Address(ESP, target::kWordSize)); // 49.98
__ divsd(XMM0, Address(ESP, target::kWordSize)); // 14.7
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM0);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(DoubleFPOperationsStack, test) {
typedef double (*DoubleFPOperationsStackCode)(double d);
double res =
reinterpret_cast<DoubleFPOperationsStackCode>(test->entry())(3.4);
EXPECT_FLOAT_EQ(14.7, res, 0.001);
EXPECT_DISASSEMBLY(
"mov eax,0x40289999\n"
"push eax\n"
"mov eax,0x9999999a\n"
"push eax\n"
"movsd xmm0,[esp]\n"
"pop eax\n"
"pop eax\n"
"addsd xmm0,[esp+0x4]\n"
"mulsd xmm0,[esp+0x4]\n"
"subsd xmm0,[esp+0x4]\n"
"divsd xmm0,[esp+0x4]\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm0\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(IntToDoubleConversion, assembler) {
__ movl(EDX, Immediate(6));
__ cvtsi2sd(XMM1, EDX);
__ pushl(EAX);
__ pushl(EAX);
__ movsd(Address(ESP, 0), XMM1);
__ fldl(Address(ESP, 0));
__ popl(EAX);
__ popl(EAX);
__ ret();
}
ASSEMBLER_TEST_RUN(IntToDoubleConversion, test) {
typedef double (*IntToDoubleConversionCode)();
double res = reinterpret_cast<IntToDoubleConversionCode>(test->entry())();
EXPECT_FLOAT_EQ(6.0, res, 0.001);
EXPECT_DISASSEMBLY(
"mov edx,6\n"
"cvtsi2sd xmm1,edx\n"
"push eax\n"
"push eax\n"
"movsd [esp],xmm1\n"
"fld_d [esp]\n"
"pop eax\n"
"pop eax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(IntToDoubleConversion2, assembler) {
__ filds(Address(ESP, target::kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(IntToDoubleConversion2, test) {
typedef double (*IntToDoubleConversion2Code)(int i);
double res = reinterpret_cast<IntToDoubleConversion2Code>(test->entry())(3);
EXPECT_FLOAT_EQ(3.0, res, 0.001);
EXPECT_DISASSEMBLY(
"fild_s [esp+0x4]\n"