blob: c0acbff882821da048163dd7ae08543a5b8fe0dd [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_X64)
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/backend/locations.h"
#include "vm/cpu.h"
#include "vm/os.h"
#include "vm/unit_test.h"
#include "vm/virtual_memory.h"
namespace dart {
namespace compiler {
#define __ assembler->
#if defined(PRODUCT)
#define EXPECT_DISASSEMBLY(expected)
#define EXPECT_DISASSEMBLY_ENDS_WITH(expected)
#define EXPECT_DISASSEMBLY_NOT_WINDOWS(expected)
#define EXPECT_DISASSEMBLY_NOT_WINDOWS_ENDS_WITH(expected)
#else
#define EXPECT_DISASSEMBLY(expected) \
EXPECT_STREQ(expected, test->RelativeDisassembly())
#define EXPECT_DISASSEMBLY_ENDS_WITH(expected_arg) \
char* disassembly = test->RelativeDisassembly(); \
const char* expected = expected_arg; \
intptr_t dis_len = strlen(disassembly); \
intptr_t exp_len = strlen(expected); \
EXPECT_GT(dis_len, exp_len); \
EXPECT_STREQ(expected, disassembly + dis_len - exp_len);
#if defined(DART_TARGET_OS_WINDOWS)
// Windows has different calling conventions on x64, which means the
// disassembly looks different on some tests. We skip testing the
// disassembly output for those tests on Windows.
#define EXPECT_DISASSEMBLY_NOT_WINDOWS(expected)
#define EXPECT_DISASSEMBLY_NOT_WINDOWS_ENDS_WITH(expected)
#else
#define EXPECT_DISASSEMBLY_NOT_WINDOWS(expected) EXPECT_DISASSEMBLY(expected)
#define EXPECT_DISASSEMBLY_NOT_WINDOWS_ENDS_WITH(expected) \
EXPECT_DISASSEMBLY_ENDS_WITH(expected)
#endif
#endif
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));
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rdi\n"
"movq rax,[rsp]\n"
"pop rdx\n"
"ret\n");
}
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, target::kWordSize));
__ movq(RAX, Address(RBP, target::kWordSize));
__ movq(RAX, Address(RAX, target::kWordSize));
__ movq(RAX, Address(R10, target::kWordSize));
__ movq(RAX, Address(R12, target::kWordSize));
__ movq(RAX, Address(R13, target::kWordSize));
__ movq(RAX, Address(RSP, -target::kWordSize));
__ movq(RAX, Address(RBP, -target::kWordSize));
__ movq(RAX, Address(RAX, -target::kWordSize));
__ movq(RAX, Address(R10, -target::kWordSize));
__ movq(RAX, Address(R12, -target::kWordSize));
__ movq(RAX, Address(R13, -target::kWordSize));
__ movq(RAX, Address(RSP, 256 * target::kWordSize));
__ movq(RAX, Address(RBP, 256 * target::kWordSize));
__ movq(RAX, Address(RAX, 256 * target::kWordSize));
__ movq(RAX, Address(R10, 256 * target::kWordSize));
__ movq(RAX, Address(R12, 256 * target::kWordSize));
__ movq(RAX, Address(R13, 256 * target::kWordSize));
__ movq(RAX, Address(RSP, -256 * target::kWordSize));
__ movq(RAX, Address(RBP, -256 * target::kWordSize));
__ movq(RAX, Address(RAX, -256 * target::kWordSize));
__ movq(RAX, Address(R10, -256 * target::kWordSize));
__ movq(RAX, Address(R12, -256 * target::kWordSize));
__ movq(RAX, Address(R13, -256 * target::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, target::kWordSize));
__ movq(RAX, Address(RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R13, TIMES_2, 256 * target::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, target::kWordSize));
__ movq(RAX, Address(RAX, RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RAX, R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RAX, R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RAX, R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RBP, RBP, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RBP, RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RBP, R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RBP, R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RBP, R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RSP, RBP, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RSP, RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RSP, R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RSP, R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RSP, R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R10, RBP, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R10, RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R10, R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R10, R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R10, R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R12, RBP, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R12, RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R12, R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R12, R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R12, R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R13, RBP, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R13, RAX, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R13, R10, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R13, R12, TIMES_2, target::kWordSize));
__ movq(RAX, Address(R13, R13, TIMES_2, target::kWordSize));
__ movq(RAX, Address(RAX, RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RAX, RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RAX, R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RAX, R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RAX, R13, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RBP, RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RBP, RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RBP, R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RBP, R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RBP, R13, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RSP, RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RSP, RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RSP, R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RSP, R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(RSP, R13, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R10, RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R10, RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R10, R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R10, R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R10, R13, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R12, RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R12, RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R12, R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R12, R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R12, R13, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R13, RBP, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R13, RAX, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R13, R10, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R13, R12, TIMES_2, 256 * target::kWordSize));
__ movq(RAX, Address(R13, R13, TIMES_2, 256 * target::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, target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RBP, target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RAX, target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R10, target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R12, target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R13, target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RSP, -target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RBP, -target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RAX, -target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R10, -target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R12, -target::kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R13, -target::kWordSize));
}
ASSEMBLER_TEST_RUN(AddressingModes, test) {
// Avoid running the code since it is constructed to lead to crashes.
EXPECT_DISASSEMBLY(
"movq rax,[rsp]\n"
"movq rax,[rbp+0]\n"
"movq rax,[rax]\n"
"movq rax,[r10]\n"
"movq rax,[r12]\n"
"movq rax,[r13+0]\n"
"movq r10,[rax]\n"
"movq rax,[rsp+0x8]\n"
"movq rax,[rbp+0x8]\n"
"movq rax,[rax+0x8]\n"
"movq rax,[r10+0x8]\n"
"movq rax,[r12+0x8]\n"
"movq rax,[r13+0x8]\n"
"movq rax,[rsp-0x8]\n"
"movq rax,[rbp-0x8]\n"
"movq rax,[rax-0x8]\n"
"movq rax,[r10-0x8]\n"
"movq rax,[r12-0x8]\n"
"movq rax,[r13-0x8]\n"
"movq rax,[rsp+0x800]\n"
"movq rax,[rbp+0x800]\n"
"movq rax,[rax+0x800]\n"
"movq rax,[r10+0x800]\n"
"movq rax,[r12+0x800]\n"
"movq rax,[r13+0x800]\n"
"movq rax,[rsp-0x800]\n"
"movq rax,[rbp-0x800]\n"
"movq rax,[rax-0x800]\n"
"movq rax,[r10-0x800]\n"
"movq rax,[r12-0x800]\n"
"movq rax,[r13-0x800]\n"
"movq rax,[rax*1+0]\n"
"movq rax,[rax*2+0]\n"
"movq rax,[rax*4+0]\n"
"movq rax,[rax*8+0]\n"
"movq rax,[rbp*2+0]\n"
"movq rax,[rax*2+0]\n"
"movq rax,[r10*2+0]\n"
"movq rax,[r12*2+0]\n"
"movq rax,[r13*2+0]\n"
"movq rax,[rbp*2+0x8]\n"
"movq rax,[rax*2+0x8]\n"
"movq rax,[r10*2+0x8]\n"
"movq rax,[r12*2+0x8]\n"
"movq rax,[r13*2+0x8]\n"
"movq rax,[rbp*2+0x800]\n"
"movq rax,[rax*2+0x800]\n"
"movq rax,[r10*2+0x800]\n"
"movq rax,[r12*2+0x800]\n"
"movq rax,[r13*2+0x800]\n"
"movq rax,[rax+rbp*2]\n"
"movq rax,[rax+rax*2]\n"
"movq rax,[rax+r10*2]\n"
"movq rax,[rax+r12*2]\n"
"movq rax,[rax+r13*2]\n"
"movq rax,[rbp+rbp*2+0]\n"
"movq rax,[rbp+rax*2+0]\n"
"movq rax,[rbp+r10*2+0]\n"
"movq rax,[rbp+r12*2+0]\n"
"movq rax,[rbp+r13*2+0]\n"
"movq rax,[rsp+rbp*2]\n"
"movq rax,[rsp+rax*2]\n"
"movq rax,[rsp+r10*2]\n"
"movq rax,[rsp+r12*2]\n"
"movq rax,[rsp+r13*2]\n"
"movq rax,[r10+rbp*2]\n"
"movq rax,[r10+rax*2]\n"
"movq rax,[r10+r10*2]\n"
"movq rax,[r10+r12*2]\n"
"movq rax,[r10+r13*2]\n"
"movq rax,[r12+rbp*2]\n"
"movq rax,[r12+rax*2]\n"
"movq rax,[r12+r10*2]\n"
"movq rax,[r12+r12*2]\n"
"movq rax,[r12+r13*2]\n"
"movq rax,[r13+rbp*2+0]\n"
"movq rax,[r13+rax*2+0]\n"
"movq rax,[r13+r10*2+0]\n"
"movq rax,[r13+r12*2+0]\n"
"movq rax,[r13+r13*2+0]\n"
"movq rax,[rax+rbp*2+0x8]\n"
"movq rax,[rax+rax*2+0x8]\n"
"movq rax,[rax+r10*2+0x8]\n"
"movq rax,[rax+r12*2+0x8]\n"
"movq rax,[rax+r13*2+0x8]\n"
"movq rax,[rbp+rbp*2+0x8]\n"
"movq rax,[rbp+rax*2+0x8]\n"
"movq rax,[rbp+r10*2+0x8]\n"
"movq rax,[rbp+r12*2+0x8]\n"
"movq rax,[rbp+r13*2+0x8]\n"
"movq rax,[rsp+rbp*2+0x8]\n"
"movq rax,[rsp+rax*2+0x8]\n"
"movq rax,[rsp+r10*2+0x8]\n"
"movq rax,[rsp+r12*2+0x8]\n"
"movq rax,[rsp+r13*2+0x8]\n"
"movq rax,[r10+rbp*2+0x8]\n"
"movq rax,[r10+rax*2+0x8]\n"
"movq rax,[r10+r10*2+0x8]\n"
"movq rax,[r10+r12*2+0x8]\n"
"movq rax,[r10+r13*2+0x8]\n"
"movq rax,[r12+rbp*2+0x8]\n"
"movq rax,[r12+rax*2+0x8]\n"
"movq rax,[r12+r10*2+0x8]\n"
"movq rax,[r12+r12*2+0x8]\n"
"movq rax,[r12+r13*2+0x8]\n"
"movq rax,[r13+rbp*2+0x8]\n"
"movq rax,[r13+rax*2+0x8]\n"
"movq rax,[r13+r10*2+0x8]\n"
"movq rax,[r13+r12*2+0x8]\n"
"movq rax,[r13+r13*2+0x8]\n"
"movq rax,[rax+rbp*2+0x800]\n"
"movq rax,[rax+rax*2+0x800]\n"
"movq rax,[rax+r10*2+0x800]\n"
"movq rax,[rax+r12*2+0x800]\n"
"movq rax,[rax+r13*2+0x800]\n"
"movq rax,[rbp+rbp*2+0x800]\n"
"movq rax,[rbp+rax*2+0x800]\n"
"movq rax,[rbp+r10*2+0x800]\n"
"movq rax,[rbp+r12*2+0x800]\n"
"movq rax,[rbp+r13*2+0x800]\n"
"movq rax,[rsp+rbp*2+0x800]\n"
"movq rax,[rsp+rax*2+0x800]\n"
"movq rax,[rsp+r10*2+0x800]\n"
"movq rax,[rsp+r12*2+0x800]\n"
"movq rax,[rsp+r13*2+0x800]\n"
"movq rax,[r10+rbp*2+0x800]\n"
"movq rax,[r10+rax*2+0x800]\n"
"movq rax,[r10+r10*2+0x800]\n"
"movq rax,[r10+r12*2+0x800]\n"
"movq rax,[r10+r13*2+0x800]\n"
"movq rax,[r12+rbp*2+0x800]\n"
"movq rax,[r12+rax*2+0x800]\n"
"movq rax,[r12+r10*2+0x800]\n"
"movq rax,[r12+r12*2+0x800]\n"
"movq rax,[r12+r13*2+0x800]\n"
"movq rax,[r13+rbp*2+0x800]\n"
"movq rax,[r13+rax*2+0x800]\n"
"movq rax,[r13+r10*2+0x800]\n"
"movq rax,[r13+r12*2+0x800]\n"
"movq rax,[r13+r13*2+0x800]\n"
"movq rax,[rsp+0]\n"
"movq rax,[rbp+0]\n"
"movq rax,[rax+0]\n"
"movq rax,[r10+0]\n"
"movq rax,[r12+0]\n"
"movq rax,[r13+0]\n"
"movq r10,[rax+0]\n"
"movq rax,[rsp+0x8]\n"
"movq rax,[rbp+0x8]\n"
"movq rax,[rax+0x8]\n"
"movq rax,[r10+0x8]\n"
"movq rax,[r12+0x8]\n"
"movq rax,[r13+0x8]\n"
"movq rax,[rsp-0x8]\n"
"movq rax,[rbp-0x8]\n"
"movq rax,[rax-0x8]\n"
"movq rax,[r10-0x8]\n"
"movq rax,[r12-0x8]\n"
"movq rax,[r13-0x8]\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.
__ 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())();
EXPECT_DISASSEMBLY(
"jo +109\n"
"jno +103\n"
"jc +97\n"
"jnc +91\n"
"jz +85\n"
"jnz +79\n"
"jna +73\n"
"ja +67\n"
"js +61\n"
"jns +55\n"
"jpe +49\n"
"jpo +43\n"
"jl +37\n"
"jge +31\n"
"jle +25\n"
"jg +19\n"
"jmp +13\n"
"movl rax,0\n"
"movq [rax],rax\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,0\n"
"movl rcx,0\n"
"addq rax,2\n"
"incq rcx\n"
"cmpq rcx,0x57\n"
"jl -11\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,1\n"
"movl tmp,0xffffff11\n"
"push tmp\n"
"cmpb [rsp],0x11\n"
"jz +7\n"
"movl rax,0\n"
"pop rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,1\n"
"movl rcx,0\n"
"movl tmp,0xffffff11\n"
"push tmp\n"
"testb [rsp],0x10\n"
"cmovzq rax,rcx\n"
"testb [rsp],0x20\n"
"jz +11\n"
"movl rax,0\n"
"pop rcx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Testb2, assembler) {
Label done, ok1, ok2, ok3, ok4, ok5, ok6, ok7;
__ movq(RAX, Immediate(0xffffefff));
__ bsrq(RCX, RAX);
__ cmpq(RCX, Immediate(31));
__ j(EQUAL, &ok1);
__ int3();
__ Bind(&ok1);
__ sarq(RAX, Immediate(1));
__ cmpq(RAX, Immediate(0x7ffff7ff));
__ j(EQUAL, &ok2);
__ int3();
__ Bind(&ok2);
__ movq(RAX, Immediate(0x7fffffff));
__ bsrq(RCX, RAX);
__ cmpq(RCX, Immediate(30));
__ j(EQUAL, &ok3);
__ int3();
__ Bind(&ok3);
__ cmpq(RAX, Immediate(0x7fffffff));
__ j(EQUAL, &ok4);
__ int3();
__ Bind(&ok4);
__ movq(RAX, Immediate(0x101020408));
__ andq(RAX, Immediate(0xffffffff));
__ cmpq(RAX, Immediate(0x1020408));
__ j(EQUAL, &ok5);
__ int3();
__ Bind(&ok5);
__ movq(RCX, Immediate(0x101020408));
__ andq(RCX, Immediate(0xffffffff));
__ cmpq(RCX, Immediate(0x1020408));
__ j(EQUAL, &ok6);
__ int3();
__ Bind(&ok6);
__ movq(RAX, Immediate(0x0fffeff0));
__ bsfq(RCX, RAX);
__ cmpq(RCX, Immediate(4));
__ j(EQUAL, &ok7);
__ int3();
__ Bind(&ok7);
__ movq(RAX, Immediate(42));
__ ret();
}
ASSEMBLER_TEST_RUN(Testb2, test) {
typedef int64_t (*Testb2Code)();
EXPECT_EQ(42, reinterpret_cast<Testb2Code>(test->entry())());
EXPECT_DISASSEMBLY(
"movl rax,0xffffefff\n"
"bsrq rcx,rax\n"
"cmpq rcx,0x1f\n"
"jz +7\n"
"int3\n"
"sarq rax,1\n"
"cmpq rax,0x7ffff7ff\n"
"jz +7\n"
"int3\n"
"movl rax,0x7fffffff\n"
"bsrq rcx,rax\n"
"cmpq rcx,0x1e\n"
"jz +7\n"
"int3\n"
"cmpq rax,0x7fffffff\n"
"jz +7\n"
"int3\n"
"movq rax,0x0000000101020408\n"
"andl rax,0xffffffff\n"
"cmpq rax,0x01020408\n"
"jz +7\n"
"int3\n"
"movq rcx,0x0000000101020408\n"
"andl rcx,0xffffffff\n"
"cmpq rcx,0x01020408\n"
"jz +7\n"
"int3\n"
"movl rax,0x0fffeff0\n"
"bsfq rcx,rax\n"
"cmpq rcx,4\n"
"jz +7\n"
"int3\n"
"movl rax,0x2a\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Testb3, assembler) {
Label zero;
__ pushq(CallingConventions::kArg1Reg);
__ movq(RDX, Immediate(0x10));
__ testb(Address(RSP, 0), RDX);
__ j(ZERO, &zero);
__ movq(RAX, Immediate(1));
__ popq(RCX);
__ ret();
__ Bind(&zero);
__ movq(RAX, Immediate(0));
__ popq(RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Testb3, test) {
typedef int (*TestbCode)(int);
EXPECT_EQ(1, reinterpret_cast<TestbCode>(test->entry())(0x11));
EXPECT_EQ(0, reinterpret_cast<TestbCode>(test->entry())(0x101));
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rdi\n"
"movl rdx,0x10\n"
"testb rdx,[rsp]\n"
"jz +13\n"
"movl rax,1\n"
"pop rcx\n"
"ret\n"
"movl rax,0\n"
"pop rcx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Popcnt, assembler) {
__ movq(RCX, Immediate(-1));
__ popcntq(RAX, RCX);
__ movq(RCX, Immediate(0xf));
__ popcntq(RCX, RCX);
__ addq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Popcnt, test) {
if (!HostCPUFeatures::popcnt_supported()) {
return;
}
typedef int64_t (*PopcntCode)();
EXPECT_EQ(68, reinterpret_cast<PopcntCode>(test->entry())());
EXPECT_DISASSEMBLY(
"movq rcx,-1\n"
"popcntq rax,rcx\n"
"movl rcx,0xf\n"
"popcntq rcx,rcx\n"
"addq rax,rcx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Lzcnt, assembler) {
__ movq(RCX, Immediate(0x0f00));
__ lzcntq(RAX, RCX);
__ movq(RCX, Immediate(0x00f0));
__ lzcntq(RCX, RCX);
__ addq(RAX, RCX);
__ ret();
}
ASSEMBLER_TEST_RUN(Lzcnt, test) {
if (!HostCPUFeatures::abm_supported()) {
return;
}
typedef int64_t (*LzcntCode)();
EXPECT_EQ(108, reinterpret_cast<LzcntCode>(test->entry())());
EXPECT_DISASSEMBLY(
"movl rcx,0xf00\n"
"lzcntq rax,rcx\n"
"movl rcx,0xf0\n"
"lzcntq rcx,rcx\n"
"addq rax,rcx\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) {
__ jmp(Address(CallingConventions::kArg1Reg, OFFSET_OF(JumpAddress, target)));
__ int3();
__ int3();
__ int3();
__ int3();
__ int3();
jump_address_offset = __ CodeSize();
__ movl(RAX, 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_NOT_WINDOWS(
"jmp [rdi+0x28]\n"
"int3\n"
"int3\n"
"int3\n"
"int3\n"
"int3\n"
"movl rax,0x2a\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,0\n"
"push rax\n"
"incl [rsp]\n"
"incq [rsp]\n"
"movq rcx,[rsp]\n"
"incq rcx\n"
"pop rax\n"
"movq rax,rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,0xffffffff\n"
"push rax\n"
"incq [rsp]\n"
"movq rcx,[rsp]\n"
"incq rcx\n"
"pop rax\n"
"movq rax,rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,3\n"
"push rax\n"
"decl [rsp]\n"
"decq [rsp]\n"
"movq rcx,[rsp]\n"
"decq rcx\n"
"pop rax\n"
"movq rax,rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movq rax,0x0000000100000001\n"
"push rax\n"
"decq [rsp]\n"
"movq rcx,[rsp]\n"
"decq rcx\n"
"pop rax\n"
"movq rax,rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,2\n"
"movl rcx,4\n"
"imull rax,rcx\n"
"imull rax,rax,0x3e8\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,-1\n"
"movl rcx,0x10\n"
"mull (rax,rdx),rcx\n"
"movq rax,rdx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SignedMultiply64Implicit, assembler) {
__ movq(RAX, Immediate(7));
__ movq(RDX, Immediate(-3));
__ imulq(RDX); // // RDX:RAX = -21
__ addq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply64Implicit, test) {
typedef int (*SignedMultiply64Implicit)();
EXPECT_EQ(-22, reinterpret_cast<SignedMultiply64Implicit>(test->entry())());
EXPECT_DISASSEMBLY(
"movl rax,7\n"
"movq rdx,-3\n"
"imulq (rax,rdx),rdx\n"
"addq rax,rdx\n"
"ret\n");
}
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(TMP, Immediate(4));
__ imulq(R10, TMP);
__ 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())());
EXPECT_DISASSEMBLY(
"push pp\n"
"movl rax,2\n"
"movl rcx,4\n"
"imulq rax,rcx\n"
"movl r8,2\n"
"movl r9,4\n"
"push r9\n"
"imulq r8,[rsp]\n"
"pop r9\n"
"addq rax,r8\n"
"movl r10,2\n"
"movl tmp,4\n"
"imulq r10,tmp\n"
"addq rax,r10\n"
"movl pp,2\n"
"imulq pp,pp,4\n"
"addq rax,pp\n"
"pop pp\n"
"ret\n");
}
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);
__ MulImmediate(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())());
EXPECT_DISASSEMBLY(
"movq rax,0x1234567887654321\n"
"movq rcx,0x0db4da5f7ef412b1\n"
"imulq rax,rcx\n"
"movq tmp,0x1234567887654321\n"
"imulq rcx,tmp\n"
"cmpq rax,rcx\n"
"jz +7\n"
"int3\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rdx,0\n"
"movl rax,0x0fffffff\n"
"movl rcx,0x0fffffff\n"
"imull rax,rcx\n"
"imull rax,rdx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rdx,2\n"
"movl rcx,4\n"
"imull rdx,rcx\n"
"imull rdx,rdx,0x3e8\n"
"movl rax,rdx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"push pp\n"
"movl pp,2\n"
"imull pp,pp,0x3e8\n"
"movl rax,pp\n"
"pop pp\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movq rax,-1\n"
"movl rcx,0x10\n"
"mulq (rax,rdx),rcx\n"
"movq rax,rdx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,-0x00000057\n"
"movl rdx,0x7b\n"
"cdq\n"
"movl rcx,0x2a\n"
"idivl (rax,rdx),rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,0\n"
"movl rdx,-0x10000000\n"
"movl rcx,-1\n"
"divl (rax,rdx),rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movq rax,0x1234567887654321\n"
"movl rdx,0x7b\n"
"cqo\n"
"movl rcx,0x2a\n"
"idivq (rax,rdx),rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,0\n"
"movq rdx,0xf000000000000000\n"
"movq rcx,-1\n"
"divq (rax,rdx),rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rcx,0x2a\n"
"negq rcx\n"
"movq rax,rcx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(BitScanReverseTest, 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(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_NOT_WINDOWS(
"push rdi\n"
"movq rcx,[rsp]\n"
"movl rax,0x29a\n"
"bsrq rax,rcx\n"
"pop rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rdx,0xffff\n"
"movzxbq rax,rdx\n"
"movsxwq r8,rdx\n"
"movzxwq rcx,rdx\n"
"addq r8,rcx\n"
"addq rax,r8\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rdx,0xffffffff\n"
"movsxdq rdx,rdx\n"
"movl rax,0x7fffffff\n"
"movsxdq rax,rax\n"
"addq rax,rdx\n"
"ret\n");
}
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(target::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())());
EXPECT_DISASSEMBLY(
"movq rdx,0x123456781234ffff\n"
"push rdx\n"
"movzxbq rax,[rsp]\n"
"movsxwq r8,[rsp]\n"
"movzxwq rcx,[rsp]\n"
"addq rsp,8\n"
"addq r8,rcx\n"
"addq rax,r8\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(MoveExtend32Memory, assembler) {
__ pushq(Immediate(0xffffffff));
__ pushq(Immediate(0x7fffffff));
__ movsxd(RDX, Address(RSP, target::kWordSize));
__ movsxd(RAX, Address(RSP, 0));
__ addq(RSP, Immediate(target::kWordSize * 2));
__ addq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(MoveExtend32Memory, test) {
typedef intptr_t (*MoveExtend)();
EXPECT_EQ(0x7ffffffe, reinterpret_cast<MoveExtend>(test->entry())());
EXPECT_DISASSEMBLY(
"movl tmp,0xffffffff\n"
"push tmp\n"
"push 0x7fffffff\n"
"movsxdq rdx,[rsp+0x8]\n"
"movsxdq rax,[rsp]\n"
"addq rsp,0x10\n"
"addq rax,rdx\n"
"ret\n");
}
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(target::kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(MoveWord, test) {
typedef int (*MoveWord)();
EXPECT_EQ(0xffff, reinterpret_cast<MoveWord>(test->entry())());
EXPECT_DISASSEMBLY(
"xorq rax,rax\n"
"push 0\n"
"movq rax,rsp\n"
"movq rcx,-1\n"
"movw [rax],rcx\n"
"movzxwq rax,[rax]\n"
"addq rsp,8\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(WordOps, assembler) {
__ movq(RAX, Immediate(0x0102030405060708));
__ pushq(RAX);
__ addw(Address(RSP, 0), Immediate(-0x201));
__ subw(Address(RSP, 2), Immediate(0x201));
__ xorw(Address(RSP, 4), Immediate(0x201));
__ andw(Address(RSP, 6), Immediate(0x301));
__ andw(Address(RSP, 0), Immediate(-1));
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(WordOps, test) {
typedef int64_t (*WordOps)();
EXPECT_EQ(0x0100010503050507, reinterpret_cast<WordOps>(test->entry())());
EXPECT_DISASSEMBLY(
"movq rax,0x0102030405060708\n"
"push rax\n"
"addw [rsp],0xfdff\n"
"subw [rsp+0x2],0x201\n"
"xorw [rsp+0x4],0x201\n"
"andw [rsp+0x6],0x301\n"
"andw [rsp],-1\n"
"pop rax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(ByteOps, assembler) {
__ movq(RAX, Immediate(0x0102030405060708));
__ pushq(RAX);
__ addb(Address(RSP, 0), Immediate(0xff));
__ subb(Address(RSP, 2), Immediate(1));
__ xorb(Address(RSP, 4), Immediate(1));
__ andb(Address(RSP, 6), Immediate(1));
__ andb(Address(RSP, 0), Immediate(-1));
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(ByteOps, test) {
typedef int64_t (*ByteOps)();
EXPECT_EQ(0x0100030505050707, reinterpret_cast<ByteOps>(test->entry())());
EXPECT_DISASSEMBLY(
"movq rax,0x0102030405060708\n"
"push rax\n"
"addb [rsp],-1\n"
"subb [rsp+0x2],1\n"
"xorb [rsp+0x4],1\n"
"andb [rsp+0x6],1\n"
"andb [rsp],-1\n"
"pop rax\n"
"ret\n");
}
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(target::kWordSize));
__ ret();
}
ASSEMBLER_TEST_RUN(MoveWordRex, test) {
typedef int (*MoveWordRex)();
EXPECT_EQ(0xffff, reinterpret_cast<MoveWordRex>(test->entry())());
EXPECT_DISASSEMBLY(
"push 0\n"
"movq r8,rsp\n"
"movq r9,-1\n"
"movw [r8],r9\n"
"movzxwq r8,[r8]\n"
"xorq rax,rax\n"
"addq rax,r8\n"
"addq rsp,8\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rsi\n"
"push rdi\n"
"movl rax,[rsp]\n"
"movl rdx,[rsp+0x4]\n"
"movl rcx,[rsp+0x8]\n"
"movl r8,[rsp+0xc]\n"
"addl rax,rcx\n"
"adcl rdx,r8\n"
"movl [rsp],rax\n"
"movl [rsp+0x4],rdx\n"
"pop rax\n"
"pop rdx\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rdi\n"
"movl rax,[rsp]\n"
"movl rdx,[rsp+0x4]\n"
"addl rax,0xc\n"
"adcl rdx,0xb\n"
"movl [rsp],rax\n"
"movl [rsp+0x4],rdx\n"
"pop rax\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rsi\n"
"push rdi\n"
"movl rax,[rsp]\n"
"movl rdx,[rsp+0x4]\n"
"addl rax,[rsp+0x8]\n"
"adcl rdx,[rsp+0xc]\n"
"movl [rsp],rax\n"
"movl [rsp+0x4],rdx\n"
"pop rax\n"
"pop rdx\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rsi\n"
"push rdi\n"
"movl rax,[rsp]\n"
"movl rdx,[rsp+0x4]\n"
"movl rcx,[rsp+0x8]\n"
"movl r8,[rsp+0xc]\n"
"subl rax,rcx\n"
"sbbl rdx,r8\n"
"movl [rsp],rax\n"
"movl [rsp+0x4],rdx\n"
"pop rax\n"
"pop rdx\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(LongSubImmediate, assembler) {
__ pushq(CallingConventions::kArg1Reg);
__ movl(RAX, Immediate(0));
__ subl(
RAX,
Immediate(1)); // Set the carry flag so we can test that subl ignores it.
__ 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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rdi\n"
"movl rax,0\n"
"subl rax,1\n"
"movl rax,[rsp]\n"
"movl rdx,[rsp+0x4]\n"
"subl rax,0xc\n"
"sbbl rdx,0xb\n"
"movl [rsp],rax\n"
"movl [rsp+0x4],rdx\n"
"pop rax\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rsi\n"
"push rdi\n"
"movl rax,[rsp]\n"
"movl rdx,[rsp+0x4]\n"
"subl rax,[rsp+0x8]\n"
"sbbl rdx,[rsp+0xc]\n"
"movl [rsp],rax\n"
"movl [rsp+0x4],rdx\n"
"pop rax\n"
"pop rdx\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"movq r10,rdi\n"
"addq r10,rdx\n"
"movq rax,rsi\n"
"adcq rax,rcx\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"movq r10,rdi\n"
"addq r10,0xd\n"
"movq rax,rsi\n"
"adcq rax,0xe\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(AddAddress, assembler) {
__ pushq(CallingConventions::kArg4Reg);
__ pushq(CallingConventions::kArg3Reg);
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movq(R10, Address(RSP, 0 * target::kWordSize)); // al.
__ addq(R10, Address(RSP, 2 * target::kWordSize)); // bl.
__ movq(RAX, Address(RSP, 1 * target::kWordSize)); // ah.
__ adcq(RAX, Address(RSP, 3 * target::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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rcx\n"
"push rdx\n"
"push rsi\n"
"push rdi\n"
"movq r10,[rsp]\n"
"addq r10,[rsp+0x10]\n"
"movq rax,[rsp+0x8]\n"
"adcq rax,[rsp+0x18]\n"
"pop tmp\n"
"pop tmp\n"
"pop tmp\n"
"pop tmp\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"movq r10,rdi\n"
"subq r10,rdx\n"
"movq rax,rsi\n"
"sbbq rax,rcx\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"movq r10,rdi\n"
"subq r10,0xc\n"
"movq rax,rsi\n"
"sbbq rax,0xb\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(SubAddress, assembler) {
__ pushq(CallingConventions::kArg4Reg);
__ pushq(CallingConventions::kArg3Reg);
__ pushq(CallingConventions::kArg2Reg);
__ pushq(CallingConventions::kArg1Reg);
__ movq(R10, Address(RSP, 0 * target::kWordSize)); // al.
__ subq(R10, Address(RSP, 2 * target::kWordSize)); // bl.
__ movq(RAX, Address(RSP, 1 * target::kWordSize)); // ah.
__ sbbq(RAX, Address(RSP, 3 * target::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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"push rcx\n"
"push rdx\n"
"push rsi\n"
"push rdi\n"
"movq r10,[rsp]\n"
"subq r10,[rsp+0x10]\n"
"movq rax,[rsp+0x8]\n"
"sbbq rax,[rsp+0x18]\n"
"pop tmp\n"
"pop tmp\n"
"pop tmp\n"
"pop tmp\n"
"ret\n");
}
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);
EXPECT_DISASSEMBLY_NOT_WINDOWS(
"movq r10,-1\n"
"orl [rdi],r10\n"
"orl [rsi],r10\n"
"movl rcx,0x2a\n"
"xorl rcx,rcx\n"
"orl rcx,0x100\n"
"movl rax,4\n"
"orl rcx,rax\n"
"movl rax,0xfff0\n"
"andl rcx,rax\n"
"movl rax,1\n"
"orl rcx,rax\n"
"movl rax,rcx\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,0x2a\n"
"push rax\n"
"xorq rax,[rsp]\n"
"pop rcx\n"
"cmpq rax,0\n"
"jnz +105\n"
"movl rcx,0xff\n"
"movl rax,5\n"
"xorq rcx,rax\n"
"cmpq rcx,0xfa\n"
"jnz +79\n"
"push 0xff\n"
"movl rcx,5\n"
"xorq [rsp],rcx\n"
"pop rcx\n"
"cmpq rcx,0xfa\n"
"jnz +51\n"
"xorq rcx,rcx\n"
"orq rcx,0x100\n"
"movl rax,4\n"
"orq rcx,rax\n"
"movl rax,0xfff0\n"
"andq rcx,rax\n"
"movl rax,1\n"
"push rax\n"
"orq rcx,[rsp]\n"
"xorq rcx,0\n"
"pop rax\n"
"movq rax,rcx\n"
"ret\n"
"movq rax,-1\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,4\n"
"andl rax,2\n"
"cmpl rax,0\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rcx,4\n"
"andl rcx,4\n"
"cmpl rcx,0\n"
"jnz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,0\n"
"orl rax,0\n"
"cmpl rax,0\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,4\n"
"orl rax,0\n"
"cmpl rax,0\n"
"jnz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"push rax\n"
"movl rax,0xff\n"
"movl [rsp],rax\n"
"cmpl [rsp],0xff\n"
"jz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"pop rax\n"
"movl rax,1\n"
"shll rax,3\n"
"cmpl rax,8\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,2\n"
"shrl rax,1\n"
"cmpl rax,1\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,8\n"
"shrl rax,3\n"
"cmpl rax,1\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"movl rcx,3\n"
"shll rax,cl\n"
"cmpl rax,8\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,8\n"
"movl rcx,3\n"
"shrl rax,cl\n"
"cmpl rax,1\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"shlq rax,3\n"
"cmpl rax,8\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,2\n"
"shrq rax,1\n"
"cmpl rax,1\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,8\n"
"shrq rax,3\n"
"cmpl rax,1\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,cl\n"
"cmpl rax,8\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,8\n"
"movl rcx,3\n"
"shrq rax,cl\n"
"cmpl rax,1\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"shlq rax,31\n"
"shrq rax,3\n"
"cmpq rax,0x10000000\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"shlq rax,31\n"
"sarl rax,3\n"
"cmpl rax,0xf0000000\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,31\n"
"sarl rax,cl\n"
"cmpl rax,0xf0000000\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rdx,-0x01000000\n"
"movl r8,-1\n"
"movl rcx,2\n"
"shll rdx,cl\n"
"shldl rdx,r8,2\n"
"cmpl rdx,0xf0000003\n"
"jz +7\n"
"int3\n"
"movq rdx,0xff00000000000000\n"
"movq r8,-1\n"
"movl rcx,2\n"
"shlq rdx,cl\n"
"shldq rdx,r8,2\n"
"movq tmp,0xf000000000000003\n"
"cmpq rdx,tmp\n"
"jz +7\n"
"int3\n"
"movq rdx,0xff00000000000000\n"
"movq r8,-1\n"
"movl rcx,2\n"
"shlq rdx,cl\n"
"shldq rdx,r8,cl\n"
"movq tmp,0xf000000000000003\n"
"cmpq rdx,tmp\n"
"jz +7\n"
"int3\n"
"movq rdx,0xff00000000000000\n"
"movq r8,-1\n"
"movl rcx,2\n"
"shrq rdx,cl\n"
"shrdq rdx,r8,cl\n"
"movq tmp,0xcff0000000000000\n"
"cmpq rdx,tmp\n"
"jz +7\n"
"int3\n"
"movl rax,0\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,4\n"
"andl rax,2\n"
"cmpq rax,0\n"
"jz +7\n"
"int3\n"
"movl rcx,4\n"
"push rcx\n"
"andq rcx,[rsp]\n"
"pop rax\n"
"cmpq rcx,0\n"
"jnz +7\n"
"int3\n"
"movl rax,0\n"
"orq rax,0\n"
"cmpq rax,0\n"
"jz +7\n"
"int3\n"
"movl rax,4\n"
"orq rax,0\n"
"cmpq rax,0\n"
"jnz +7\n"
"int3\n"
"push rax\n"
"movl rax,0xff\n"
"movq [rsp],rax\n"
"cmpq [rsp],0xff\n"
"jz +7\n"
"int3\n"
"pop rax\n"
"movl rax,1\n"
"shlq rax,3\n"
"cmpq rax,8\n"
"jz +7\n"
"int3\n"
"movl rax,2\n"
"shrq rax,1\n"
"cmpq rax,1\n"
"jz +7\n"
"int3\n"
"movl rax,8\n"
"shrq rax,3\n"
"cmpq rax,1\n"
"jz +7\n"
"int3\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,cl\n"
"cmpq rax,8\n"
"jz +7\n"
"int3\n"
"movl rax,8\n"
"movl rcx,3\n"
"shrq rax,cl\n"
"cmpq rax,1\n"
"jz +7\n"
"int3\n"
"movl rax,1\n"
"shlq rax,3\n"
"cmpq rax,8\n"
"jz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,2\n"
"shrq rax,1\n"
"cmpq rax,1\n"
"jz +7\n"
"int3\n"
"movl rax,8\n"
"shrq rax,3\n"
"cmpq rax,1\n"
"jz +7\n"
"int3\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,cl\n"
"cmpq rax,8\n"
"jz +7\n"
"int3\n"
"movl rax,8\n"
"movl rcx,3\n"
"shrq rax,cl\n"
"cmpq rax,1\n"
"jz +7\n"
"int3\n"
"movl rax,1\n"
"shlq rax,31\n"
"shrq rax,3\n"
"cmpq rax,0x10000000\n"
"jz +7\n"
"int3\n"
"movl rax,1\n"
"shlq rax,63\n"
"sarq rax,3\n"
"movq tmp,0xf000000000000000\n"
"cmpq rax,tmp\n"
"jz +7\n"
"int3\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,63\n"
"sarq rax,cl\n"
"movq tmp,0xf000000000000000\n"
"cmpq rax,tmp\n"
"jz +7\n"
"int3\n"
"push pp\n"
"movq pp,0xf000000000000001\n"
"andq pp,-1\n"
"movq tmp,0x8000000000000001\n"
"andq pp,tmp\n"
"orq pp,2\n"
"movq tmp,0xf800000000000000\n"
"orq pp,tmp\n"
"xorq pp,1\n"
"movq tmp,0x0800000000000000\n"
"xorq pp,tmp\n"
"movq tmp,0xf000000000000002\n"
"cmpq pp,tmp\n"
"jz +7\n"
"int3\n"
"andl pp,2\n"
"cmpq pp,2\n"
"jz +7\n"
"int3\n"
"pop pp\n"
"movl rax,0\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,4\n"
"movl rcx,2\n"
"testl rax,rcx\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rdx,4\n"
"movl rcx,4\n"
"testl rdx,rcx\n"
"jnz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,0\n"
"test al,0\n"
"jz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rcx,4\n"
"testb rcx,4\n"
"jnz +14\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,0\n"
"ret\n");
}
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())());
EXPECT_DISASSEMBLY(
"movl rax,4\n"
"movl rcx,2\n"
"testq rax,rcx\n"
"jz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rdx,4\n"
"movl rcx,4\n"
"testq rdx,rcx\n"
"jnz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,0\n"
"test al,0\n"
"jz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rcx,4\n"
"testb rcx,4\n"
"jnz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rcx,0xff\n"
"testb rcx,0xff\n"
"jnz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,0xff\n"
"test al,0xff\n"
"jnz +14\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,0\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(CompareSwapEQ, assembler) {
__ movq(RAX, Immediate(0));
__ pushq(RAX);
__ movq(RAX, Immediate(4));
__ movq(RCX, Immediate(0));
__ movq(Address(RSP, 0), RAX);
__ LockCmpxchgq(Address(RSP, 0), RCX);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapEQ, test) {
typedef int (*CompareSwapEQCode)();
EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(test->entry())());
EXPECT_DISASSEMBLY(
"movl rax,0\n"
"push rax\n"
"movl rax,4\n"
"movl rcx,0\n"
"movq [rsp],rax\n"
"lock cmpxchgq rcx,[rsp]\n"
"pop rax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(CompareSwapNEQ, assembler) {
__ movq(RAX, Immediate(0));
__ pushq(RAX);
__ movq(RAX, Immediate(2));
__ movq(RCX, Immediate(4));
__ movq(Address(RSP, 0), RCX);
__ LockCmpxchgq(Address(RSP, 0), RCX);
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapNEQ, test) {
typedef int (*CompareSwapNEQCode)();
EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(test->entry())());
EXPECT_DISASSEMBLY(
"movl rax,0\n"
"push rax\n"
"movl rax,2\n"
"movl rcx,4\n"
"movq [rsp],rcx\n"
"lock cmpxchgq rcx,[rsp]\n"
"pop rax\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(CompareSwapEQ32, assembler) {
__ movq(RAX, Immediate(0x100000000));
__ pushq(RAX);
__ movq(RAX, Immediate(4));
__ movq(RCX, Immediate(0));
// 32 bit store of 4.
__ movl(Address(RSP, 0), RAX);
// Compare 32 bit memory location with RAX (4) and write 0.
__ LockCmpxchgl(Address(RSP, 0), RCX);
// Pop unchanged high word and zeroed out low word.
__ popq(RAX);
__ ret();
}
ASSEMBLER_TEST_RUN(CompareSwapEQ32<