v8/test/cctest/test-assembler-ia32.cc
Maya Lekova 7c7aa4fa94 Revert "Reland "[deoptimizer] Change deopt entries into builtins""
This reverts commit fbfa9bf4ec.

Reason for revert: Seems to break arm64 sim CFI build (please see DeoptExitSizeIfFixed) - https://ci.chromium.org/p/v8/builders/ci/V8%20Linux%20-%20arm64%20-%20sim%20-%20CFI/2808

Original change's description:
> Reland "[deoptimizer] Change deopt entries into builtins"
>
> This is a reland of 7f58ced72e
>
> It fixes the different exit size emitted on x64/Atom CPUs due to
> performance tuning in TurboAssembler::Call. Additionally, add
> cctests to verify the fixed size exits.
>
> Original change's description:
> > [deoptimizer] Change deopt entries into builtins
> >
> > While the overall goal of this commit is to change deoptimization
> > entries into builtins, there are multiple related things happening:
> >
> > - Deoptimization entries, formerly stubs (i.e. Code objects generated
> >   at runtime, guaranteed to be immovable), have been converted into
> >   builtins. The major restriction is that we now need to preserve the
> >   kRootRegister, which was formerly used on most architectures to pass
> >   the deoptimization id. The solution differs based on platform.
> > - Renamed DEOPT_ENTRIES_OR_FOR_TESTING code kind to FOR_TESTING.
> > - Removed heap/ support for immovable Code generation.
> > - Removed the DeserializerData class (no longer needed).
> > - arm64: to preserve 4-byte deopt exits, introduced a new optimization
> >   in which the final jump to the deoptimization entry is generated
> >   once per Code object, and deopt exits can continue to emit a
> >   near-call.
> > - arm,ia32,x64: change to fixed-size deopt exits. This reduces exit
> >   sizes by 4/8, 5, and 5 bytes, respectively.
> >
> > On arm the deopt exit size is reduced from 12 (or 16) bytes to 8 bytes
> > by using the same strategy as on arm64 (recalc deopt id from return
> > address). Before:
> >
> >  e300a002       movw r10, <id>
> >  e59fc024       ldr ip, [pc, <entry offset>]
> >  e12fff3c       blx ip
> >
> > After:
> >
> >  e59acb35       ldr ip, [r10, <entry offset>]
> >  e12fff3c       blx ip
> >
> > On arm64 the deopt exit size remains 4 bytes (or 8 bytes in same cases
> > with CFI). Additionally, up to 4 builtin jumps are emitted per Code
> > object (max 32 bytes added overhead per Code object). Before:
> >
> >  9401cdae       bl <entry offset>
> >
> > After:
> >
> >  # eager deoptimization entry jump.
> >  f95b1f50       ldr x16, [x26, <eager entry offset>]
> >  d61f0200       br x16
> >  # lazy deoptimization entry jump.
> >  f95b2b50       ldr x16, [x26, <lazy entry offset>]
> >  d61f0200       br x16
> >  # the deopt exit.
> >  97fffffc       bl <eager deoptimization entry jump offset>
> >
> > On ia32 the deopt exit size is reduced from 10 to 5 bytes. Before:
> >
> >  bb00000000     mov ebx,<id>
> >  e825f5372b     call <entry>
> >
> > After:
> >
> >  e8ea2256ba     call <entry>
> >
> > On x64 the deopt exit size is reduced from 12 to 7 bytes. Before:
> >
> >  49c7c511000000 REX.W movq r13,<id>
> >  e8ea2f0700     call <entry>
> >
> > After:
> >
> >  41ff9560360000 call [r13+<entry offset>]
> >
> > Bug: v8:8661,v8:8768
> > Change-Id: I13e30aedc360474dc818fecc528ce87c3bfeed42
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2465834
> > Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> > Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> > Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> > Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#70597}
>
> Tbr: ulan@chromium.org, tebbi@chromium.org, rmcilroy@chromium.org
> Bug: v8:8661,v8:8768,chromium:1140165
> Change-Id: Ibcd5c39c58a70bf2b2ac221aa375fc68d495e144
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2485506
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#70655}

TBR=ulan@chromium.org,rmcilroy@chromium.org,jgruber@chromium.org,tebbi@chromium.org

Change-Id: I4739a3475bfd8ee0cfbe4b9a20382f91a6ef1bf0
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:8661
Bug: v8:8768
Bug: chromium:1140165
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2485223
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70658}
2020-10-20 14:14:12 +00:00

1546 lines
42 KiB
C++

// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include "src/init/v8.h"
#include "src/base/platform/platform.h"
#include "src/base/utils/random-number-generator.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/diagnostics/disassembler.h"
#include "src/heap/factory.h"
#include "src/utils/ostreams.h"
#include "test/cctest/cctest.h"
namespace v8 {
namespace internal {
using F0 = int (*)();
using F1 = int (*)(int x);
using F2 = int (*)(int x, int y);
#define __ assm.
TEST(AssemblerIa320) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
__ mov(eax, Operand(esp, 4));
__ add(eax, Operand(esp, 8));
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F2 f = FUNCTION_CAST<F2>(code->entry());
int res = f(3, 4);
::printf("f() = %d\n", res);
CHECK_EQ(7, res);
}
TEST(AssemblerIa321) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
Label L, C;
__ mov(edx, Operand(esp, 4));
__ xor_(eax, eax); // clear eax
__ jmp(&C);
__ bind(&L);
__ add(eax, edx);
__ sub(edx, Immediate(1));
__ bind(&C);
__ test(edx, edx);
__ j(not_zero, &L);
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
int res = f(100);
::printf("f() = %d\n", res);
CHECK_EQ(5050, res);
}
TEST(AssemblerIa322) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
Label L, C;
__ mov(edx, Operand(esp, 4));
__ mov(eax, 1);
__ jmp(&C);
__ bind(&L);
__ imul(eax, edx);
__ sub(edx, Immediate(1));
__ bind(&C);
__ test(edx, edx);
__ j(not_zero, &L);
__ ret(0);
// some relocated stuff here, not executed
__ mov(eax, isolate->factory()->true_value());
__ jmp(kNullAddress, RelocInfo::RUNTIME_ENTRY);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
int res = f(10);
::printf("f() = %d\n", res);
CHECK_EQ(3628800, res);
}
using F3 = int (*)(float x);
TEST(AssemblerIa323) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
__ cvttss2si(eax, Operand(esp, 4));
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
int res = f(static_cast<float>(-3.1415));
::printf("f() = %d\n", res);
CHECK_EQ(-3, res);
}
using F4 = int (*)(double x);
TEST(AssemblerIa324) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
__ cvttsd2si(eax, Operand(esp, 4));
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F4 f = FUNCTION_CAST<F4>(code->entry());
int res = f(2.718281828);
::printf("f() = %d\n", res);
CHECK_EQ(2, res);
}
static int baz = 42;
TEST(AssemblerIa325) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
__ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE));
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
F0 f = FUNCTION_CAST<F0>(code->entry());
int res = f();
CHECK_EQ(42, res);
}
using F5 = double (*)(double x, double y);
TEST(AssemblerIa326) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
__ movsd(xmm0, Operand(esp, 1 * kSystemPointerSize));
__ movsd(xmm1, Operand(esp, 3 * kSystemPointerSize));
__ addsd(xmm0, xmm1);
__ mulsd(xmm0, xmm1);
__ subsd(xmm0, xmm1);
__ divsd(xmm0, xmm1);
// Copy xmm0 to st(0) using eight bytes of stack.
__ sub(esp, Immediate(8));
__ movsd(Operand(esp, 0), xmm0);
__ fld_d(Operand(esp, 0));
__ add(esp, Immediate(8));
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F5 f = FUNCTION_CAST<F5>(code->entry());
double res = f(2.2, 1.1);
::printf("f() = %f\n", res);
CHECK(2.29 < res && res < 2.31);
}
using F6 = double (*)(int x);
TEST(AssemblerIa328) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
__ mov(eax, Operand(esp, 4));
__ cvtsi2sd(xmm0, eax);
// Copy xmm0 to st(0) using eight bytes of stack.
__ sub(esp, Immediate(8));
__ movsd(Operand(esp, 0), xmm0);
__ fld_d(Operand(esp, 0));
__ add(esp, Immediate(8));
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F6 f = FUNCTION_CAST<F6>(code->entry());
double res = f(12);
::printf("f() = %f\n", res);
CHECK(11.99 < res && res < 12.001);
}
TEST(AssemblerIa3210) {
// Test chaining of label usages within instructions (issue 1644).
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label target;
__ j(equal, &target);
__ j(not_equal, &target);
__ bind(&target);
__ nop();
}
TEST(AssemblerMultiByteNop) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[1024];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
__ push(ebx);
__ push(ecx);
__ push(edx);
__ push(edi);
__ push(esi);
__ mov(eax, 1);
__ mov(ebx, 2);
__ mov(ecx, 3);
__ mov(edx, 4);
__ mov(edi, 5);
__ mov(esi, 6);
for (int i = 0; i < 16; i++) {
int before = assm.pc_offset();
__ Nop(i);
CHECK_EQ(assm.pc_offset() - before, i);
}
Label fail;
__ cmp(eax, 1);
__ j(not_equal, &fail);
__ cmp(ebx, 2);
__ j(not_equal, &fail);
__ cmp(ecx, 3);
__ j(not_equal, &fail);
__ cmp(edx, 4);
__ j(not_equal, &fail);
__ cmp(edi, 5);
__ j(not_equal, &fail);
__ cmp(esi, 6);
__ j(not_equal, &fail);
__ mov(eax, 42);
__ pop(esi);
__ pop(edi);
__ pop(edx);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
__ bind(&fail);
__ mov(eax, 13);
__ pop(esi);
__ pop(edi);
__ pop(edx);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
CHECK(code->IsCode());
F0 f = FUNCTION_CAST<F0>(code->entry());
int res = f();
CHECK_EQ(42, res);
}
#ifdef __GNUC__
#define ELEMENT_COUNT 4u
void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
CHECK(args[0]->IsArray());
v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
CHECK_EQ(ELEMENT_COUNT, vec->Length());
v8::internal::byte buffer[256];
Assembler assm(AssemblerOptions{},
ExternalAssemblerBuffer(buffer, sizeof buffer));
// Remove return address from the stack for fix stack frame alignment.
__ pop(ecx);
// Store input vector on the stack.
for (unsigned i = 0; i < ELEMENT_COUNT; ++i) {
__ push(Immediate(
vec->Get(context, i).ToLocalChecked()->Int32Value(context).FromJust()));
}
// Read vector into a xmm register.
__ pxor(xmm0, xmm0);
__ movdqa(xmm0, Operand(esp, 0));
// Create mask and store it in the return register.
__ movmskps(eax, xmm0);
// Remove unused data from the stack.
__ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
// Restore return address.
__ push(ecx);
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
F0 f = FUNCTION_CAST<F0>(code->entry());
int res = f();
args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res));
}
TEST(StackAlignmentForSSE2) {
CcTest::InitializeVM();
CHECK_EQ(0, v8::base::OS::ActivationFrameAlignment() % 16);
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
global_template->Set(v8_str("do_sse2"),
v8::FunctionTemplate::New(isolate, DoSSE2));
LocalContext env(nullptr, global_template);
CompileRun(
"function foo(vec) {"
" return do_sse2(vec);"
"}");
v8::Local<v8::Object> global_object = env->Global();
v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
global_object->Get(env.local(), v8_str("foo")).ToLocalChecked());
int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
for (unsigned i = 0; i < ELEMENT_COUNT; i++) {
v8_vec->Set(env.local(), i, v8_num(vec[i])).FromJust();
}
v8::Local<v8::Value> args[] = { v8_vec };
v8::Local<v8::Value> result =
foo->Call(env.local(), global_object, 1, args).ToLocalChecked();
// The mask should be 0b1000.
CHECK_EQ(8, result->Int32Value(env.local()).FromJust());
}
#undef ELEMENT_COUNT
#endif // __GNUC__
TEST(AssemblerIa32Extractps) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(SSE4_1)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{ CpuFeatureScope fscope41(&assm, SSE4_1);
__ movsd(xmm1, Operand(esp, 4));
__ extractps(eax, xmm1, 0x1);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F4 f = FUNCTION_CAST<F4>(code->entry());
uint64_t value1 = 0x1234'5678'8765'4321;
CHECK_EQ(0x12345678, f(uint64_to_double(value1)));
uint64_t value2 = 0x8765'4321'1234'5678;
CHECK_EQ(static_cast<int>(0x87654321), f(uint64_to_double(value2)));
}
using F8 = int (*)(float x, float y);
TEST(AssemblerIa32SSE) {
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
__ movss(xmm0, Operand(esp, kSystemPointerSize));
__ movss(xmm1, Operand(esp, 2 * kSystemPointerSize));
__ shufps(xmm0, xmm0, 0x0);
__ shufps(xmm1, xmm1, 0x0);
__ movaps(xmm2, xmm1);
__ addps(xmm2, xmm0);
__ mulps(xmm2, xmm1);
__ subps(xmm2, xmm0);
__ divps(xmm2, xmm1);
__ cvttss2si(eax, xmm2);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F8 f = FUNCTION_CAST<F8>(code->entry());
CHECK_EQ(2, f(1.0, 2.0));
}
TEST(AssemblerIa32SSE3) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(SSE3)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, SSE3);
__ movss(xmm0, Operand(esp, kSystemPointerSize));
__ movss(xmm1, Operand(esp, 2 * kSystemPointerSize));
__ shufps(xmm0, xmm0, 0x0);
__ shufps(xmm1, xmm1, 0x0);
__ haddps(xmm1, xmm0);
__ cvttss2si(eax, xmm1);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F8 f = FUNCTION_CAST<F8>(code->entry());
CHECK_EQ(4, f(1.0, 2.0));
}
using F9 = int (*)(double x, double y, double z);
TEST(AssemblerX64FMA_sd) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(FMA3)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[1024];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, FMA3);
Label exit;
__ movsd(xmm0, Operand(esp, 1 * kSystemPointerSize));
__ movsd(xmm1, Operand(esp, 3 * kSystemPointerSize));
__ movsd(xmm2, Operand(esp, 5 * kSystemPointerSize));
// argument in xmm0, xmm1 and xmm2
// xmm0 * xmm1 + xmm2
__ movaps(xmm3, xmm0);
__ mulsd(xmm3, xmm1);
__ addsd(xmm3, xmm2); // Expected result in xmm3
__ AllocateStackSpace(kDoubleSize); // For memory operand
// vfmadd132sd
__ mov(eax, Immediate(1)); // Test number
__ movaps(xmm4, xmm0);
__ vfmadd132sd(xmm4, xmm2, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfmadd213sd(xmm4, xmm0, xmm2);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfmadd231sd(xmm4, xmm0, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movsd(Operand(esp, 0), xmm1);
__ vfmadd132sd(xmm4, xmm2, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movsd(Operand(esp, 0), xmm2);
__ vfmadd213sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movsd(Operand(esp, 0), xmm1);
__ vfmadd231sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// xmm0 * xmm1 - xmm2
__ movaps(xmm3, xmm0);
__ mulsd(xmm3, xmm1);
__ subsd(xmm3, xmm2); // Expected result in xmm3
// vfmsub132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ vfmsub132sd(xmm4, xmm2, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfmsub213sd(xmm4, xmm0, xmm2);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfmsub231sd(xmm4, xmm0, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movsd(Operand(esp, 0), xmm1);
__ vfmsub132sd(xmm4, xmm2, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movsd(Operand(esp, 0), xmm2);
__ vfmsub213sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movsd(Operand(esp, 0), xmm1);
__ vfmsub231sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// - xmm0 * xmm1 + xmm2
__ movaps(xmm3, xmm0);
__ mulsd(xmm3, xmm1);
__ Move(xmm4, (uint64_t)1 << 63);
__ xorpd(xmm3, xmm4);
__ addsd(xmm3, xmm2); // Expected result in xmm3
// vfnmadd132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ vfnmadd132sd(xmm4, xmm2, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfnmadd213sd(xmm4, xmm0, xmm2);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfnmadd231sd(xmm4, xmm0, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movsd(Operand(esp, 0), xmm1);
__ vfnmadd132sd(xmm4, xmm2, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movsd(Operand(esp, 0), xmm2);
__ vfnmadd213sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movsd(Operand(esp, 0), xmm1);
__ vfnmadd231sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// - xmm0 * xmm1 - xmm2
__ movaps(xmm3, xmm0);
__ mulsd(xmm3, xmm1);
__ Move(xmm4, (uint64_t)1 << 63);
__ xorpd(xmm3, xmm4);
__ subsd(xmm3, xmm2); // Expected result in xmm3
// vfnmsub132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ vfnmsub132sd(xmm4, xmm2, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfnmsub213sd(xmm4, xmm0, xmm2);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfnmsub231sd(xmm4, xmm0, xmm1);
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub132sd
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movsd(Operand(esp, 0), xmm1);
__ vfnmsub132sd(xmm4, xmm2, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub213sd
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movsd(Operand(esp, 0), xmm2);
__ vfnmsub213sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub231sd
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movsd(Operand(esp, 0), xmm1);
__ vfnmsub231sd(xmm4, xmm0, Operand(esp, 0));
__ ucomisd(xmm4, xmm3);
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ add(esp, Immediate(kDoubleSize));
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F9 f = FUNCTION_CAST<F9>(code->entry());
CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
}
using F10 = int (*)(float x, float y, float z);
TEST(AssemblerX64FMA_ss) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(FMA3)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[1024];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, FMA3);
Label exit;
__ movss(xmm0, Operand(esp, 1 * kSystemPointerSize));
__ movss(xmm1, Operand(esp, 2 * kSystemPointerSize));
__ movss(xmm2, Operand(esp, 3 * kSystemPointerSize));
// arguments in xmm0, xmm1 and xmm2
// xmm0 * xmm1 + xmm2
__ movaps(xmm3, xmm0);
__ mulss(xmm3, xmm1);
__ addss(xmm3, xmm2); // Expected result in xmm3
__ AllocateStackSpace(kDoubleSize); // For memory operand
// vfmadd132ss
__ mov(eax, Immediate(1)); // Test number
__ movaps(xmm4, xmm0);
__ vfmadd132ss(xmm4, xmm2, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfmadd213ss(xmm4, xmm0, xmm2);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfmadd231ss(xmm4, xmm0, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movss(Operand(esp, 0), xmm1);
__ vfmadd132ss(xmm4, xmm2, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movss(Operand(esp, 0), xmm2);
__ vfmadd213ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movss(Operand(esp, 0), xmm1);
__ vfmadd231ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// xmm0 * xmm1 - xmm2
__ movaps(xmm3, xmm0);
__ mulss(xmm3, xmm1);
__ subss(xmm3, xmm2); // Expected result in xmm3
// vfmsub132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ vfmsub132ss(xmm4, xmm2, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfmsub213ss(xmm4, xmm0, xmm2);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfmsub231ss(xmm4, xmm0, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movss(Operand(esp, 0), xmm1);
__ vfmsub132ss(xmm4, xmm2, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movss(Operand(esp, 0), xmm2);
__ vfmsub213ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movss(Operand(esp, 0), xmm1);
__ vfmsub231ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// - xmm0 * xmm1 + xmm2
__ movaps(xmm3, xmm0);
__ mulss(xmm3, xmm1);
__ Move(xmm4, (uint32_t)1 << 31);
__ xorps(xmm3, xmm4);
__ addss(xmm3, xmm2); // Expected result in xmm3
// vfnmadd132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ vfnmadd132ss(xmm4, xmm2, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmadd213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfnmadd213ss(xmm4, xmm0, xmm2);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfnmadd231ss(xmm4, xmm0, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movss(Operand(esp, 0), xmm1);
__ vfnmadd132ss(xmm4, xmm2, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movss(Operand(esp, 0), xmm2);
__ vfnmadd213ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmadd231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movss(Operand(esp, 0), xmm1);
__ vfnmadd231ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// - xmm0 * xmm1 - xmm2
__ movaps(xmm3, xmm0);
__ mulss(xmm3, xmm1);
__ Move(xmm4, (uint32_t)1 << 31);
__ xorps(xmm3, xmm4);
__ subss(xmm3, xmm2); // Expected result in xmm3
// vfnmsub132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ vfnmsub132ss(xmm4, xmm2, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfmsub213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ vfnmsub213ss(xmm4, xmm0, xmm2);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ vfnmsub231ss(xmm4, xmm0, xmm1);
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub132ss
__ inc(eax);
__ movaps(xmm4, xmm0);
__ movss(Operand(esp, 0), xmm1);
__ vfnmsub132ss(xmm4, xmm2, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub213ss
__ inc(eax);
__ movaps(xmm4, xmm1);
__ movss(Operand(esp, 0), xmm2);
__ vfnmsub213ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
// vfnmsub231ss
__ inc(eax);
__ movaps(xmm4, xmm2);
__ movss(Operand(esp, 0), xmm1);
__ vfnmsub231ss(xmm4, xmm0, Operand(esp, 0));
__ ucomiss(xmm4, xmm3);
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ add(esp, Immediate(kDoubleSize));
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F10 f = FUNCTION_CAST<F10>(code->entry());
CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
}
TEST(AssemblerIa32BMI1) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(BMI1)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[1024];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, BMI1);
Label exit;
__ push(ebx); // save ebx
__ mov(ecx, Immediate(0x55667788u)); // source operand
__ push(ecx); // For memory operand
// andn
__ mov(edx, Immediate(0x20000000u));
__ mov(eax, Immediate(1)); // Test number
__ andn(ebx, edx, ecx);
__ cmp(ebx, Immediate(0x55667788u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ andn(ebx, edx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x55667788u)); // expected result
__ j(not_equal, &exit);
// bextr
__ mov(edx, Immediate(0x00002808u));
__ inc(eax);
__ bextr(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x00556677u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ bextr(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x00556677u)); // expected result
__ j(not_equal, &exit);
// blsi
__ inc(eax);
__ blsi(ebx, ecx);
__ cmp(ebx, Immediate(0x00000008u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ blsi(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x00000008u)); // expected result
__ j(not_equal, &exit);
// blsmsk
__ inc(eax);
__ blsmsk(ebx, ecx);
__ cmp(ebx, Immediate(0x0000000Fu)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ blsmsk(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x0000000Fu)); // expected result
__ j(not_equal, &exit);
// blsr
__ inc(eax);
__ blsr(ebx, ecx);
__ cmp(ebx, Immediate(0x55667780u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ blsr(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x55667780u)); // expected result
__ j(not_equal, &exit);
// tzcnt
__ inc(eax);
__ tzcnt(ebx, ecx);
__ cmp(ebx, Immediate(3)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ tzcnt(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(3)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32LZCNT) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(LZCNT)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, LZCNT);
Label exit;
__ push(ebx); // save ebx
__ mov(ecx, Immediate(0x55667788u)); // source operand
__ push(ecx); // For memory operand
__ mov(eax, Immediate(1)); // Test number
__ lzcnt(ebx, ecx);
__ cmp(ebx, Immediate(1)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ lzcnt(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(1)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32POPCNT) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(POPCNT)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, POPCNT);
Label exit;
__ push(ebx); // save ebx
__ mov(ecx, Immediate(0x11111100u)); // source operand
__ push(ecx); // For memory operand
__ mov(eax, Immediate(1)); // Test number
__ popcnt(ebx, ecx);
__ cmp(ebx, Immediate(6)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ popcnt(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(6)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32BMI2) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(BMI2)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[2048];
MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes,
ExternalAssemblerBuffer(buffer, sizeof(buffer)));
{
CpuFeatureScope fscope(&assm, BMI2);
Label exit;
__ push(ebx); // save ebx
__ push(esi); // save esi
__ mov(ecx, Immediate(0x55667788u)); // source operand
__ push(ecx); // For memory operand
// bzhi
__ mov(edx, Immediate(9));
__ mov(eax, Immediate(1)); // Test number
__ bzhi(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x00000188u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ bzhi(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x00000188u)); // expected result
__ j(not_equal, &exit);
// mulx
__ mov(edx, Immediate(0x00001000u));
__ inc(eax);
__ mulx(ebx, esi, ecx);
__ cmp(ebx, Immediate(0x00000556u)); // expected result
__ j(not_equal, &exit);
__ cmp(esi, Immediate(0x67788000u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ mulx(ebx, esi, Operand(esp, 0));
__ cmp(ebx, Immediate(0x00000556u)); // expected result
__ j(not_equal, &exit);
__ cmp(esi, Immediate(0x67788000u)); // expected result
__ j(not_equal, &exit);
// pdep
__ mov(edx, Immediate(0xFFFFFFF0u));
__ inc(eax);
__ pdep(ebx, edx, ecx);
__ cmp(ebx, Immediate(0x55667400u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ pdep(ebx, edx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x55667400u)); // expected result
__ j(not_equal, &exit);
// pext
__ mov(edx, Immediate(0xFFFFFFF0u));
__ inc(eax);
__ pext(ebx, edx, ecx);
__ cmp(ebx, Immediate(0x0000FFFEu)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ pext(ebx, edx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x0000FFFEu)); // expected result
__ j(not_equal, &exit);
// sarx
__ mov(edx, Immediate(4));
__ inc(eax);
__ sarx(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ sarx(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
// shlx
__ mov(edx, Immediate(4));
__ inc(eax);
__ shlx(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x56677880u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ shlx(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x56677880u)); // expected result
__ j(not_equal, &exit);
// shrx
__ mov(edx, Immediate(4));
__ inc(eax);
__ shrx(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ shrx(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
// rorx
__ inc(eax);
__ rorx(ebx, ecx, 0x4);
__ cmp(ebx, Immediate(0x85566778u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ rorx(ebx, Operand(esp, 0), 0x4);
__ cmp(ebx, Immediate(0x85566778u)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(esi);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32JumpTables1) {
// Test jump tables with forward jumps.
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
const int kNumCases = 512;
int values[kNumCases];
isolate->random_number_generator()->NextBytes(values, sizeof(values));
Label labels[kNumCases];
Label done, table;
__ mov(eax, Operand(esp, 4));
__ jmp(Operand::JumpTable(eax, times_system_pointer_size, &table));
__ ud2();
__ bind(&table);
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ mov(eax, Immediate(values[i]));
__ jmp(&done);
}
__ bind(&done);
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
int res = f(i);
::printf("f(%d) = %d\n", i, res);
CHECK_EQ(values[i], res);
}
}
TEST(AssemblerIa32JumpTables2) {
// Test jump tables with backward jumps.
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
const int kNumCases = 512;
int values[kNumCases];
isolate->random_number_generator()->NextBytes(values, sizeof(values));
Label labels[kNumCases];
Label done, table;
__ mov(eax, Operand(esp, 4));
__ jmp(Operand::JumpTable(eax, times_system_pointer_size, &table));
__ ud2();
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ mov(eax, Immediate(values[i]));
__ jmp(&done);
}
__ bind(&table);
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
__ bind(&done);
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
int res = f(i);
::printf("f(%d) = %d\n", i, res);
CHECK_EQ(values[i], res);
}
}
TEST(Regress621926) {
// Bug description:
// The opcodes for cmpw r/m16, r16 and cmpw r16, r/m16 were swapped.
// This was causing non-commutative comparisons to produce the wrong result.
CcTest::InitializeVM();
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
uint16_t a = 42;
Label fail;
__ push(ebx);
__ mov(ebx, Immediate(reinterpret_cast<intptr_t>(&a)));
__ mov(eax, Immediate(41));
__ cmpw(eax, Operand(ebx, 0));
__ j(above_equal, &fail);
__ cmpw(Operand(ebx, 0), eax);
__ j(below_equal, &fail);
__ mov(eax, 1);
__ pop(ebx);
__ ret(0);
__ bind(&fail);
__ mov(eax, 0);
__ pop(ebx);
__ ret(0);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = Factory::CodeBuilder(
isolate, desc, CodeKind::DEOPT_ENTRIES_OR_FOR_TESTING)
.Build();
#ifdef OBJECT_PRINT
StdoutStream os;
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(1, f());
}
#undef __
} // namespace internal
} // namespace v8