blob: 9704c2201666167a449409350d96bab1542d31a7 [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->BlankedDisassembly())
#define EXPECT_DISASSEMBLY_ENDS_WITH(expected_arg) \
char* disassembly = test->BlankedDisassembly(); \
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(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+0x...]\n"
"movq rax,[rbp+0x...]\n"
"movq rax,[rax+0x...]\n"
"movq rax,[r10+0x...]\n"
"movq rax,[r12+0x...]\n"
"movq rax,[r13+0x...]\n"
"movq rax,[rsp-0x...]\n"
"movq rax,[rbp-0x...]\n"
"movq rax,[rax-0x...]\n"
"movq rax,[r10-0x...]\n"
"movq rax,[r12-0x...]\n"
"movq rax,[r13-0x...]\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+0x...]\n"
"movq rax,[rax*2+0x...]\n"
"movq rax,[r10*2+0x...]\n"
"movq rax,[r12*2+0x...]\n"
"movq rax,[r13*2+0x...]\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+0x...]\n"
"movq rax,[rax+rax*2+0x...]\n"
"movq rax,[rax+r10*2+0x...]\n"
"movq rax,[rax+r12*2+0x...]\n"
"movq rax,[rax+r13*2+0x...]\n"
"movq rax,[rbp+rbp*2+0x...]\n"
"movq rax,[rbp+rax*2+0x...]\n"
"movq rax,[rbp+r10*2+0x...]\n"
"movq rax,[rbp+r12*2+0x...]\n"
"movq rax,[rbp+r13*2+0x...]\n"
"movq rax,[rsp+rbp*2+0x...]\n"
"movq rax,[rsp+rax*2+0x...]\n"
"movq rax,[rsp+r10*2+0x...]\n"
"movq rax,[rsp+r12*2+0x...]\n"
"movq rax,[rsp+r13*2+0x...]\n"
"movq rax,[r10+rbp*2+0x...]\n"
"movq rax,[r10+rax*2+0x...]\n"
"movq rax,[r10+r10*2+0x...]\n"
"movq rax,[r10+r12*2+0x...]\n"
"movq rax,[r10+r13*2+0x...]\n"
"movq rax,[r12+rbp*2+0x...]\n"
"movq rax,[r12+rax*2+0x...]\n"
"movq rax,[r12+r10*2+0x...]\n"
"movq rax,[r12+r12*2+0x...]\n"
"movq rax,[r12+r13*2+0x...]\n"
"movq rax,[r13+rbp*2+0x...]\n"
"movq rax,[r13+rax*2+0x...]\n"
"movq rax,[r13+r10*2+0x...]\n"
"movq rax,[r13+r12*2+0x...]\n"
"movq rax,[r13+r13*2+0x...]\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 0x................\n"
"jno 0x................\n"
"jc 0x................\n"
"jnc 0x................\n"
"jz 0x................\n"
"jnz 0x................\n"
"jna 0x................\n"
"ja 0x................\n"
"js 0x................\n"
"jns 0x................\n"
"jpe 0x................\n"
"jpo 0x................\n"
"jl 0x................\n"
"jge 0x................\n"
"jle 0x................\n"
"jg 0x................\n"
"jmp 0x................\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 0x................\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 r11,0x........\n"
"push r11\n"
"cmpb [rsp],0x11\n"
"jz 0x................\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 r11,0x........\n"
"push r11\n"
"testb [rsp],0x10\n"
"cmovzq rax,rcx\n"
"testb [rsp],0x20\n"
"jz 0x................\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,0x........\n"
"bsrq rcx,rax\n"
"cmpq rcx,0x1f\n"
"jz 0x................\n"
"int3\n"
"sarq rax,1\n"
"cmpq rax,0x........\n"
"jz 0x................\n"
"int3\n"
"movl rax,0x........\n"
"bsrq rcx,rax\n"
"cmpq rcx,0x1e\n"
"jz 0x................\n"
"int3\n"
"cmpq rax,0x........\n"
"jz 0x................\n"
"int3\n"
"movq rax,0x................\n"
"andl rax,0x........\n"
"cmpq rax,0x........\n"
"jz 0x................\n"
"int3\n"
"movq rcx,0x................\n"
"andl rcx,0x........\n"
"cmpq rcx,0x........\n"
"jz 0x................\n"
"int3\n"
"movl rax,0x........\n"
"bsfq rcx,rax\n"
"cmpq rcx,4\n"
"jz 0x................\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 0x................\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,0x...\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,0x........\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,0x................\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,0x...\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(R11, Immediate(4));
__ imulq(R10, R11);
__ addq(RAX, R10);
__ movq(R15, Immediate(2));
__ imulq(R15, Immediate(4));
__ addq(RAX, R15);
__ popq(R15);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply64, test) {
typedef int64_t (*SignedMultiply64)();
EXPECT_EQ(32, reinterpret_cast<SignedMultiply64>(test->entry())());
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 r11,4\n"
"imulq r10,r11\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,0x................\n"
"movq rcx,0x................\n"
"imulq rax,rcx\n"
"movq r11,0x................\n"
"imulq rcx,r11\n"
"cmpq rax,rcx\n"
"jz 0x................\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,0x........\n"
"movl rcx,0x........\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,0x...\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,0x...\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,-0x........\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,-0x........\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,0x................\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,0x................\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,0x...\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,0x....\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,0x........\n"
"movsxdq rdx,rdx\n"
"movl rax,0x........\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,0x................\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 r11,0x........\n"
"push r11\n"
"push 0x........\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,0x................\n"
"push rax\n"
"addw [rsp],0x....\n"
"subw [rsp+0x2],0x...\n"
"xorw [rsp+0x4],0x...\n"
"andw [rsp+0x6],0x...\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,0x................\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 r11\n"
"pop r11\n"
"pop r11\n"
"pop r11\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 r11\n"
"pop r11\n"
"pop r11\n"
"pop r11\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,0x...\n"
"movl rax,4\n"
"orl rcx,rax\n"
"movl rax,0x....\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 0x................\n"
"movl rcx,0xff\n"
"movl rax,5\n"
"xorq rcx,rax\n"
"cmpq rcx,0xfa\n"
"jnz 0x................\n"
"push 0xff\n"
"movl rcx,5\n"
"xorq [rsp],rcx\n"
"pop rcx\n"
"cmpq rcx,0xfa\n"
"jnz 0x................\n"
"xorq rcx,rcx\n"
"orq rcx,0x...\n"
"movl rax,4\n"
"orq rcx,rax\n"
"movl rax,0x....\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 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rcx,4\n"
"andl rcx,4\n"
"cmpl rcx,0\n"
"jnz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,0\n"
"orl rax,0\n"
"cmpl rax,0\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,4\n"
"orl rax,0\n"
"cmpl rax,0\n"
"jnz 0x................\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 0x................\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 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,2\n"
"shrl rax,1\n"
"cmpl rax,1\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,8\n"
"shrl rax,3\n"
"cmpl rax,1\n"
"jz 0x................\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 0x................\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 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"shlq rax,3\n"
"cmpl rax,8\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,2\n"
"shrq rax,1\n"
"cmpl rax,1\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,8\n"
"shrq rax,3\n"
"cmpl rax,1\n"
"jz 0x................\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 0x................\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 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"shlq rax,31\n"
"shrq rax,3\n"
"cmpq rax,0x........\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,1\n"
"shlq rax,31\n"
"sarl rax,3\n"
"cmpl rax,0x........\n"
"jz 0x................\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,0x........\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rdx,-0x........\n"
"movl r8,-1\n"
"movl rcx,2\n"
"shll rdx,cl\n"
"shldl rdx,r8,2\n"
"cmpl rdx,0x........\n"
"jz 0x................\n"
"int3\n"
"movq rdx,0x................\n"
"movq r8,-1\n"
"movl rcx,2\n"
"shlq rdx,cl\n"
"shldq rdx,r8,2\n"
"movq r11,0x................\n"
"cmpq rdx,r11\n"
"jz 0x................\n"
"int3\n"
"movq rdx,0x................\n"
"movq r8,-1\n"
"movl rcx,2\n"
"shlq rdx,cl\n"
"shldq rdx,r8,cl\n"
"movq r11,0x................\n"
"cmpq rdx,r11\n"
"jz 0x................\n"
"int3\n"
"movq rdx,0x................\n"
"movq r8,-1\n"
"movl rcx,2\n"
"shrq rdx,cl\n"
"shrdq rdx,r8,cl\n"
"movq r11,0x................\n"
"cmpq rdx,r11\n"
"jz 0x................\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 0x................\n"
"int3\n"
"movl rcx,4\n"
"push rcx\n"
"andq rcx,[rsp]\n"
"pop rax\n"
"cmpq rcx,0\n"
"jnz 0x................\n"
"int3\n"
"movl rax,0\n"
"orq rax,0\n"
"cmpq rax,0\n"
"jz 0x................\n"
"int3\n"
"movl rax,4\n"
"orq rax,0\n"
"cmpq rax,0\n"
"jnz 0x................\n"
"int3\n"
"push rax\n"
"movl rax,0xff\n"
"movq [rsp],rax\n"
"cmpq [rsp],0xff\n"
"jz 0x................\n"
"int3\n"
"pop rax\n"
"movl rax,1\n"
"shlq rax,3\n"
"cmpq rax,8\n"
"jz 0x................\n"
"int3\n"
"movl rax,2\n"
"shrq rax,1\n"
"cmpq rax,1\n"
"jz 0x................\n"
"int3\n"
"movl rax,8\n"
"shrq rax,3\n"
"cmpq rax,1\n"
"jz 0x................\n"
"int3\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,cl\n"
"cmpq rax,8\n"
"jz 0x................\n"
"int3\n"
"movl rax,8\n"
"movl rcx,3\n"
"shrq rax,cl\n"
"cmpq rax,1\n"
"jz 0x................\n"
"int3\n"
"movl rax,1\n"
"shlq rax,3\n"
"cmpq rax,8\n"
"jz 0x................\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,2\n"
"shrq rax,1\n"
"cmpq rax,1\n"
"jz 0x................\n"
"int3\n"
"movl rax,8\n"
"shrq rax,3\n"
"cmpq rax,1\n"
"jz 0x................\n"
"int3\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,cl\n"
"cmpq rax,8\n"
"jz 0x................\n"
"int3\n"
"movl rax,8\n"
"movl rcx,3\n"
"shrq rax,cl\n"
"cmpq rax,1\n"
"jz 0x................\n"
"int3\n"
"movl rax,1\n"
"shlq rax,31\n"
"shrq rax,3\n"
"cmpq rax,0x........\n"
"jz 0x................\n"
"int3\n"
"movl rax,1\n"
"shlq rax,63\n"
"sarq rax,3\n"
"movq r11,0x................\n"
"cmpq rax,r11\n"
"jz 0x................\n"
"int3\n"
"movl rax,1\n"
"movl rcx,3\n"
"shlq rax,63\n"
"sarq rax,cl\n"
"movq r11,0x................\n"
"cmpq rax,r11\n"
"jz 0x................\n"
"int3\n"
"push pp\n"
"movq pp,0x................\n"
"andq pp,-1\n"
"movq r11,0x................\n"
"andq pp,r11\n"
"orq pp,2\n"
"movq r11,0x................\n"
"orq pp,r11\n"
"xorq pp,1\n"
"movq r11,0x................\n"
"xorq pp,r11\n"
"movq r11,0x................\n"
"cmpq pp,r11\n"
"jz 0x................\n"
"int3\n"
"andl pp,2\n"
"cmpq pp,2\n"
"jz 0x................\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 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rdx,4\n"
"movl rcx,4\n"
"testl rdx,rcx\n"
"jnz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rax,0\n"
"test al,0\n"
"jz 0x................\n"
"movl rax,0\n"
"movl [rax],rax\n"
"movl rcx,4\n"
"testb rcx,4\n"
"jnz 0x................\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 0x................\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rdx,4\n"
"movl rcx,4\n"
"testq rdx,rcx\n"
"jnz 0x................\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,0\n"
"test al,0\n"
"jz 0x................\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rcx,4\n"
"testb rcx,4\n"
"jnz 0x................\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rcx,0xff\n"
"testb rcx,0xff\n"
"jnz 0x................\n"
"movl rax,0\n"
"movq [rax],rax\n"
"movl rax,0xff\n"
"test al,0xff\n"
"jnz 0x................\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 wor