v8/test/cctest/test-assembler-s390.cc
Jakob Gruber c7cb9beca1 Reland "Reland "[deoptimizer] Change deopt entries into builtins""
This is a reland of fbfa9bf4ec

The arm64 was missing proper codegen for CFI, thus sizes were off.

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, tebbi@chromium.org, rmcilroy@chromium.org
Bug: v8:8661
Bug: v8:8768
Bug: chromium:1140165
Change-Id: I471cc94fc085e527dc9bfb5a84b96bd907c2333f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2488682
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70672}
2020-10-21 06:01:38 +00:00

1071 lines
30 KiB
C++

// Copyright 2014 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 "src/init/v8.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/s390/assembler-s390-inl.h"
#include "src/diagnostics/disassembler.h"
#include "src/execution/simulator.h"
#include "src/heap/factory.h"
#include "test/cctest/cctest.h"
#include "test/common/assembler-tester.h"
namespace v8 {
namespace internal {
// Define these function prototypes to match JSEntryFunction in execution.cc.
// TODO(s390): Refine these signatures per test case.
using F1 = void*(int x, int p1, int p2, int p3, int p4);
using F2 = void*(int x, int y, int p2, int p3, int p4);
using F3 = void*(void* p0, int p1, int p2, int p3, int p4);
using F4 = void*(void* p0, void* p1, int p2, int p3, int p4);
#define __ assm.
// Simple add parameter 1 to parameter 2 and return
TEST(0) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
__ lhi(r1, Operand(3)); // test 4-byte instr
__ llilf(r2, Operand(4)); // test 6-byte instr
__ lgr(r2, r2); // test 2-byte opcode
__ ar(r2, r1); // test 2-byte instr
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F2>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(3, 4, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(7, static_cast<int>(res));
}
// Loop 100 times, adding loop counter to result
TEST(1) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label L, C;
#if defined(_AIX)
__ function_descriptor();
#endif
__ lr(r3, r2);
__ lhi(r2, Operand(0, RelocInfo::NONE));
__ b(&C);
__ bind(&L);
__ ar(r2, r3);
__ ahi(r3, Operand(-1 & 0xFFFF));
__ bind(&C);
__ cfi(r3, Operand(0, RelocInfo::NONE));
__ bne(&L);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(100, 0, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(5050, static_cast<int>(res));
}
TEST(2) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
// Create a function that accepts &t, and loads, manipulates, and stores
// the doubles and floats.
Assembler assm(AssemblerOptions{});
Label L, C;
#if defined(_AIX)
__ function_descriptor();
#endif
__ lgr(r3, r2);
__ lhi(r2, Operand(1));
__ b(&C);
__ bind(&L);
__ lr(r5, r2); // Set up muliplicant in R4:R5
__ mr_z(r4, r3); // this is actually R4:R5 = R5 * R2
__ lr(r2, r5);
__ ahi(r3, Operand(-1 & 0xFFFF));
__ bind(&C);
__ cfi(r3, Operand(0, RelocInfo::NONE));
__ bne(&L);
__ b(r14);
// some relocated stuff here, not executed
__ RecordComment("dead code, just testing relocations");
__ iilf(r0, Operand(isolate->factory()->true_value()));
__ RecordComment("dead code, just testing immediate operands");
__ iilf(r0, Operand(-1));
__ iilf(r0, Operand(0xFF000000));
__ iilf(r0, Operand(0xF0F0F0F0));
__ iilf(r0, Operand(0xFFF0FFFF));
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(10, 0, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(3628800, static_cast<int>(res));
}
TEST(3) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
__ ar(r14, r13);
__ sr(r14, r13);
__ mr_z(r14, r13);
__ dr(r14, r13);
__ or_z(r14, r13);
__ nr(r14, r13);
__ xr(r14, r13);
__ agr(r14, r13);
__ sgr(r14, r13);
__ ogr(r14, r13);
__ ngr(r14, r13);
__ xgr(r14, r13);
__ ahi(r13, Operand(123));
__ aghi(r13, Operand(123));
__ stm(r1, r2, MemOperand(r3, r0, 123));
__ slag(r1, r2, Operand(123));
__ lay(r1, MemOperand(r2, r3, -123));
__ a(r13, MemOperand(r1, r2, 123));
__ ay(r13, MemOperand(r1, r2, 123));
__ brc(Condition(14), Operand(123));
__ brc(Condition(14), Operand(-123));
__ brcl(Condition(14), Operand(123));
__ brcl(Condition(14), Operand(-123));
__ iilf(r13, Operand(123456789));
__ iihf(r13, Operand(-123456789));
__ mvc(MemOperand(r0, 123), MemOperand(r4, 567), Operand(88));
__ sll(r13, Operand(10));
v8::internal::byte* bufPos = assm.buffer_pos();
::printf("buffer position = %p", static_cast<void*>(bufPos));
::fflush(stdout);
// OS::DebugBreak();
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
USE(code);
::exit(0);
}
#if 0
TEST(4) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label L2, L3, L4;
__ chi(r2, Operand(10));
__ ble(&L2);
__ lr(r2, r4);
__ ar(r2, r3);
__ b(&L3);
__ bind(&L2);
__ chi(r2, Operand(5));
__ bgt(&L4);
__ lhi(r2, Operand::Zero());
__ b(&L3);
__ bind(&L4);
__ lr(r2, r3);
__ sr(r2, r4);
__ bind(&L3);
__ lgfr(r2, r3);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, CodeKind::FOR_TESTING, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F2>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(
f.Call(3, 4, 3, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(4, static_cast<int>(res));
}
// Test ExtractBitRange
TEST(5) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
__ mov(r2, Operand(0x12345678));
__ ExtractBitRange(r3, r2, 3, 2);
__ lgfr(r2, r3);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, CodeKind::FOR_TESTING, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F2>::FromCode(*code);
intptr_t res =
reinterpret_cast<intptr_t>(f.Call(3, 4, 3, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(2, static_cast<int>(res));
}
// Test JumpIfSmi
TEST(6) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label yes;
__ mov(r2, Operand(0x12345678));
__ JumpIfSmi(r2, &yes);
__ beq(&yes);
__ Load(r2, Operand::Zero());
__ b(r14);
__ bind(&yes);
__ Load(r2, Operand(1));
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, CodeKind::FOR_TESTING, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F2>::FromCode(*code);
intptr_t res =
reinterpret_cast<intptr_t>(f.Call(3, 4, 3, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(1, static_cast<int>(res));
}
// Test fix<->floating point conversion.
TEST(7) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label yes;
__ mov(r3, Operand(0x1234));
__ cdfbr(d1, r3);
__ ldr(d2, d1);
__ adbr(d1, d2);
__ cfdbr(Condition(0), r2, d1);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, CodeKind::FOR_TESTING, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F2>::FromCode(*code);
intptr_t res =
reinterpret_cast<intptr_t>(f.Call(3, 4, 3, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(0x2468, static_cast<int>(res));
}
// Test DSGR
TEST(8) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
// Zero upper bits of r3/r4
__ llihf(r3, Operand::Zero());
__ llihf(r4, Operand::Zero());
__ mov(r3, Operand(0x0002));
__ mov(r4, Operand(0x0002));
__ dsgr(r2, r4);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, CodeKind::FOR_TESTING, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res =
reinterpret_cast<intptr_t>(f.Call(100, 0,
0, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// Test LZDR
TEST(9) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
__ lzdr(d4);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, CodeKind::FOR_TESTING, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res =
reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
}
#endif
// Test msrkc and msgrkc
TEST(10) {
if (!CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
return;
}
::printf("MISC_INSTR_EXT2 is enabled.\n");
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label ok, failed;
{ // test 1: msrkc
__ lgfi(r2, Operand(3));
__ lgfi(r3, Operand(4));
__ msrkc(r1, r2, r3); // 3 * 4
__ b(static_cast<Condition>(le | overflow), &failed); // test failed.
__ chi(r1, Operand(12));
__ bne(&failed); // test failed.
__ lgfi(r2, Operand(-3));
__ lgfi(r3, Operand(4));
__ msrkc(r1, r2, r3); // -3 * 4
__ b(static_cast<Condition>(ge | overflow), &failed); // test failed.
__ chi(r1, Operand(-12));
__ bne(&failed); // test failed.
__ iilf(r2, Operand(0x80000000));
__ lgfi(r3, Operand(-1));
__ msrkc(r1, r2, r3); // INT_MIN * -1
__ b(nooverflow, &failed); // test failed.
__ cfi(r1, Operand(0x80000000));
__ bne(&failed); // test failed.
}
{ // test 1: msgrkc
__ lgfi(r2, Operand(3));
__ lgfi(r3, Operand(4));
__ msgrkc(r1, r2, r3); // 3 * 4
__ b(static_cast<Condition>(le | overflow), &failed); // test failed.
__ chi(r1, Operand(12));
__ bne(&failed); // test failed.
__ lgfi(r2, Operand(-3));
__ lgfi(r3, Operand(4));
__ msgrkc(r1, r2, r3); // -3 * 4
__ b(static_cast<Condition>(ge | overflow), &failed); // test failed.
__ chi(r1, Operand(-12));
__ bne(&failed); // test failed.
__ lgfi(r2, Operand::Zero());
__ iihf(r2, Operand(0x80000000));
__ lgfi(r3, Operand(-1));
__ msgrkc(r1, r2, r3); // INT_MIN * -1
__ b(nooverflow, &failed); // test failed.
__ cgr(r1, r2);
__ bne(&failed); // test failed.
}
__ bind(&ok);
__ lgfi(r2, Operand::Zero());
__ b(r14); // test done.
__ bind(&failed);
__ lgfi(r2, Operand(1));
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F2>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(3, 4, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// brxh
TEST(11) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label ok, failed, continue1, continue2;
// r1 - operand; r3 - inc / test val
__ lgfi(r1, Operand(1));
__ lgfi(r3, Operand(1));
__ brxh(r1, r3, &continue1);
__ b(&failed);
__ bind(&continue1);
__ lgfi(r1, Operand(-2));
__ lgfi(r3, Operand(1));
__ brxh(r1, r3, &failed);
__ brxh(r1, r3, &failed);
__ brxh(r1, r3, &failed);
__ brxh(r1, r3, &continue2);
__ b(&failed);
//r1 - operand; r4 - inc; r5 - test val
__ bind(&continue2);
__ lgfi(r1, Operand(-2));
__ lgfi(r4, Operand(1));
__ lgfi(r5, Operand(-1));
__ brxh(r1, r4, &failed);
__ brxh(r1, r4, &ok);
__ b(&failed);
__ bind(&ok);
__ lgfi(r2, Operand::Zero());
__ b(r14); // test done.
__ bind(&failed);
__ lgfi(r2, Operand(1));
__ b(r14); // test done.
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// brxhg
TEST(12) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label ok, failed, continue1, continue2;
// r1 - operand; r3 - inc / test val
__ lgfi(r1, Operand(1));
__ lgfi(r3, Operand(1));
__ brxhg(r1, r3, &continue1);
__ b(&failed);
__ bind(&continue1);
__ lgfi(r1, Operand(-2));
__ lgfi(r3, Operand(1));
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &continue2);
__ b(&failed);
//r1 - operand; r4 - inc; r5 - test val
__ bind(&continue2);
__ lgfi(r1, Operand(-2));
__ lgfi(r4, Operand(1));
__ lgfi(r5, Operand(-1));
__ brxhg(r1, r4, &failed);
__ brxhg(r1, r4, &ok);
__ b(&failed);
__ bind(&ok);
__ lgfi(r2, Operand::Zero());
__ b(r14); // test done.
__ bind(&failed);
__ lgfi(r2, Operand(1));
__ b(r14); // test done.
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// vector basics
TEST(13) {
// check if the VECTOR_FACILITY is supported
if (!CpuFeatures::IsSupported(VECTOR_FACILITY)) {
return;
}
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label done, error;
// vector loads, replicate, and arithmetics
__ vrepi(d2, Operand(100), Condition(2));
__ lay(sp, MemOperand(sp, -4));
__ sty(r3, MemOperand(sp));
__ vlrep(d3, MemOperand(sp), Condition(2));
__ lay(sp, MemOperand(sp, 4));
__ vlvg(d4, r2, MemOperand(r0, 2), Condition(2));
__ vrep(d4, d4, Operand(2), Condition(2));
__ lay(sp, MemOperand(sp, -kSimd128Size));
__ vst(d4, MemOperand(sp), Condition(0));
__ va(d2, d2, d3, Condition(0), Condition(0), Condition(2));
__ vl(d3, MemOperand(sp), Condition(0));
__ lay(sp, MemOperand(sp, kSimd128Size));
__ vs(d2, d2, d3, Condition(0), Condition(0), Condition(2));
__ vml(d3, d3, d2, Condition(0), Condition(0), Condition(2));
__ lay(sp, MemOperand(sp, -4));
__ vstef(d3, MemOperand(sp), Condition(3));
__ vlef(d2, MemOperand(sp), Condition(0));
__ lay(sp, MemOperand(sp, 4));
__ vlgv(r2, d2, MemOperand(r0, 0), Condition(2));
__ cfi(r2, Operand(15000));
__ bne(&error);
__ vrepi(d2, Operand(-30), Condition(3));
__ vlc(d2, d2, Condition(0), Condition(0), Condition(3));
__ vlgv(r2, d2, MemOperand(r0, 1), Condition(3));
__ lgfi(r1, Operand(-30));
__ lcgr(r1, r1);
__ cgr(r1, r2);
__ bne(&error);
__ lgfi(r2, Operand(0));
__ b(&done);
__ bind(&error);
__ lgfi(r2, Operand(1));
__ bind(&done);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(50, 250, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// vector sum, packs, unpacks
TEST(14) {
// check if the VECTOR_FACILITY is supported
if (!CpuFeatures::IsSupported(VECTOR_FACILITY)) {
return;
}
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label done, error;
// vector sum word and doubleword
__ vrepi(d2, Operand(100), Condition(2));
__ vsumg(d1, d2, d2, Condition(0), Condition(0), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(3));
__ cfi(r2, Operand(300));
__ bne(&error);
__ vrepi(d1, Operand(0), Condition(1));
__ vrepi(d2, Operand(75), Condition(1));
__ vsum(d1, d2, d1, Condition(0), Condition(0), Condition(1));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(2));
__ cfi(r2, Operand(150));
__ bne(&error);
// vector packs
__ vrepi(d1, Operand(200), Condition(2));
__ vpk(d1, d1, d1, Condition(0), Condition(0), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 5), Condition(1));
__ cfi(r2, Operand(200));
__ bne(&error);
__ vrepi(d2, Operand(30), Condition(1));
__ vpks(d1, d1, d2, Condition(0), Condition(1));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(0));
__ vlgv(r3, d1, MemOperand(r0, 8), Condition(0));
__ ar(r2, r3);
__ cfi(r2, Operand(157));
__ bne(&error);
__ vrepi(d1, Operand(270), Condition(1));
__ vrepi(d2, Operand(-30), Condition(1));
__ vpkls(d1, d1, d2, Condition(0), Condition(1));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(0));
__ vlgv(r3, d1, MemOperand(r0, 8), Condition(0));
__ cfi(r2, Operand(255));
__ bne(&error);
__ cfi(r3, Operand(255));
__ bne(&error);
// vector unpacks
__ vrepi(d1, Operand(50), Condition(2));
__ lgfi(r1, Operand(10));
__ lgfi(r2, Operand(20));
__ vlvg(d1, r1, MemOperand(r0, 0), Condition(2));
__ vlvg(d1, r2, MemOperand(r0, 2), Condition(2));
__ vuph(d2, d1, Condition(0), Condition(0), Condition(2));
__ vupl(d1, d1, Condition(0), Condition(0), Condition(2));
__ va(d1, d1, d2, Condition(0), Condition(0), Condition(3));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(3));
__ vlgv(r3, d1, MemOperand(r0, 1), Condition(3));
__ ar(r2, r3);
__ cfi(r2, Operand(130));
__ bne(&error);
__ vrepi(d1, Operand(-100), Condition(2));
__ vuplh(d2, d1, Condition(0), Condition(0), Condition(2));
__ vupll(d1, d1, Condition(0), Condition(0), Condition(2));
__ va(d1, d1, d1, Condition(0), Condition(0), Condition(3));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(3));
__ cfi(r2, Operand(0x1ffffff38));
__ bne(&error);
__ lgfi(r2, Operand(0));
__ b(&done);
__ bind(&error);
__ lgfi(r2, Operand(1));
__ bind(&done);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// vector comparisons
TEST(15) {
// check if the VECTOR_FACILITY is supported
if (!CpuFeatures::IsSupported(VECTOR_FACILITY)) {
return;
}
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label done, error;
// vector max and min
__ vrepi(d2, Operand(-50), Condition(2));
__ vrepi(d3, Operand(40), Condition(2));
__ vmx(d1, d2, d3, Condition(0), Condition(0), Condition(2));
__ vlgv(r1, d1, MemOperand(r0, 0), Condition(2));
__ vmnl(d1, d2, d3, Condition(0), Condition(0), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(2));
__ cgr(r1, r2);
__ vmxl(d1, d2, d3, Condition(0), Condition(0), Condition(2));
__ vlgv(r1, d1, MemOperand(r0, 0), Condition(2));
__ vmn(d1, d2, d3, Condition(0), Condition(0), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(2));
__ cgr(r1, r2);
__ bne(&error);
// vector comparisons
__ vlr(d4, d3, Condition(0), Condition(0), Condition(0));
__ vceq(d1, d3, d4, Condition(0), Condition(2));
__ vlgv(r1, d1, MemOperand(r0, 0), Condition(2));
__ vch(d1, d2, d3, Condition(0), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(2));
__ vchl(d1, d2, d3, Condition(0), Condition(2));
__ vlgv(r3, d1, MemOperand(r0, 0), Condition(2));
__ ar(r2, r3);
__ cgr(r1, r2);
__ bne(&error);
// vector bitwise ops
__ vrepi(d2, Operand(0), Condition(2));
__ vn(d1, d2, d3, Condition(0), Condition(0), Condition(0));
__ vceq(d1, d1, d2, Condition(0), Condition(2));
__ vlgv(r1, d1, MemOperand(r0, 0), Condition(2));
__ vo(d1, d2, d3, Condition(0), Condition(0), Condition(0));
__ vx(d1, d1, d2, Condition(0), Condition(0), Condition(0));
__ vceq(d1, d1, d3, Condition(0), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(2));
__ cgr(r1, r2);
__ bne(&error);
// vector bitwise shift
__ vceq(d1, d1, d1, Condition(0), Condition(2));
__ vesra(d1, d1, MemOperand(r0, 5), Condition(2));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(2));
__ cgr(r3, r2);
__ bne(&error);
__ lgfi(r1, Operand(0xfffff895));
__ vlvg(d1, r1, MemOperand(r0, 0), Condition(3));
__ vrep(d1, d1, Operand(0), Condition(3));
__ slag(r1, r1, Operand(10));
__ vesl(d1, d1, MemOperand(r0, 10), Condition(3));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(3));
__ cgr(r1, r2);
__ bne(&error);
__ srlg(r1, r1, Operand(10));
__ vesrl(d1, d1, MemOperand(r0, 10), Condition(3));
__ vlgv(r2, d1, MemOperand(r0, 0), Condition(3));
__ cgr(r1, r2);
__ bne(&error);
__ lgfi(r2, Operand(0));
__ b(&done);
__ bind(&error);
__ lgfi(r2, Operand(1));
__ bind(&done);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// vector select and test mask
TEST(16) {
// check if the VECTOR_FACILITY is supported
if (!CpuFeatures::IsSupported(VECTOR_FACILITY)) {
return;
}
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label done, error;
// vector select
__ vrepi(d1, Operand(0x1011), Condition(1));
__ vrepi(d2, Operand(0x4343), Condition(1));
__ vrepi(d3, Operand(0x3434), Condition(1));
__ vsel(d1, d2, d3, d1, Condition(0), Condition(0));
__ vlgv(r2, d1, MemOperand(r0, 2), Condition(1));
__ cfi(r2, Operand(0x2425));
__ bne(&error);
// vector test mask
__ vtm(d2, d1, Condition(0), Condition(0), Condition(0));
__ b(Condition(0x1), &error);
__ b(Condition(0x8), &error);
__ lgfi(r2, Operand(0));
__ b(&done);
__ bind(&error);
__ lgfi(r2, Operand(1));
__ bind(&done);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// vector fp instructions
TEST(17) {
// check if the VECTOR_FACILITY is supported
if (!CpuFeatures::IsSupported(VECTOR_FACILITY)) {
return;
}
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label done, error;
// vector fp arithmetics
__ cdgbr(d1, r3);
__ ldr(d2, d1);
__ vfa(d1, d1, d2, Condition(0), Condition(0), Condition(3));
__ cdgbr(d3, r2);
__ vfm(d1, d1, d3, Condition(0), Condition(0), Condition(3));
__ vfs(d1, d1, d2, Condition(0), Condition(0), Condition(3));
__ vfd(d1, d1, d3, Condition(0), Condition(0), Condition(3));
__ vfsq(d1, d1, Condition(0), Condition(0), Condition(3));
__ cgdbr(Condition(4), r2, d1);
__ cgfi(r2, Operand(0x8));
__ bne(&error);
// vector fp comparisons
__ cdgbra(Condition(4), d1, r3);
__ ldr(d2, d1);
__ vfa(d1, d1, d2, Condition(0), Condition(0), Condition(3));
#ifdef VECTOR_ENHANCE_FACILITY_1
__ vfmin(d3, d1, d2, Condition(1), Condition(0), Condition(3));
__ vfmax(d4, d1, d2, Condition(1), Condition(0), Condition(3));
#else
__ vlr(d3, d2, Condition(0), Condition(0), Condition(0));
__ vlr(d4, d1, Condition(0), Condition(0), Condition(0));
#endif
__ vfch(d5, d4, d3, Condition(0), Condition(0), Condition(3));
__ vfche(d3, d3, d4, Condition(0), Condition(0), Condition(3));
__ vfce(d4, d1, d4, Condition(0), Condition(0), Condition(3));
__ va(d3, d3, d4, Condition(0), Condition(0), Condition(3));
__ vs(d3, d3, d5, Condition(0), Condition(0), Condition(3));
__ vlgv(r2, d3, MemOperand(r0, 0), Condition(3));
// vector fp sign ops
__ lgfi(r1, Operand(-0x50));
__ cdgbra(Condition(4), d1, r1);
__ vfpso(d1, d1, Condition(0), Condition(0), Condition(3));
__ vfi(d1, d1, Condition(5), Condition(0), Condition(3));
__ vlgv(r1, d1, MemOperand(r0, 0), Condition(3));
__ agr(r2, r1);
__ srlg(r2, r2, Operand(32));
__ cgfi(r2, Operand(0x40540000));
__ bne(&error);
__ lgfi(r2, Operand(0));
__ b(&done);
__ bind(&error);
__ lgfi(r2, Operand(1));
__ bind(&done);
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0x2, 0x30, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
//TMHH, TMHL
TEST(18) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(AssemblerOptions{});
Label done, error;
Label continue1, continue2, continue3, continue4;
Label continue5, continue6, continue7, continue8, continue9;
// selected bits all 0
__ lgfi(r1, Operand(0));
__ tmhh(r1, Operand(1));
__ beq(&continue1); //8
__ b(&error);
__ bind(&continue1);
__ tmhl(r1, Operand(1));
__ beq(&continue2); //8
__ b(&error);
// mask = 0
__ bind(&continue2);
__ lgfi(r1, Operand(-1));
__ tmhh(r1, Operand(0));
__ beq(&continue3); //8
__ b(&error);
__ bind(&continue3);
__ tmhh(r1, Operand(0));
__ beq(&continue4); //8
__ b(&error);
// selected bits all 1
__ bind(&continue4);
__ tmhh(r1, Operand(1));
__ b(Condition(1), &continue5); //1
__ b(&error);
__ bind(&continue5);
__ tmhl(r1, Operand(1));
__ b(Condition(1), &continue6); //1
__ b(&error);
// leftmost = 1
__ bind(&continue6);
__ lgfi(r1, Operand(0xF000F000));
__ slag(r2, r1, Operand(32));
__ tmhh(r2, Operand(0xFFFF));
__ b(Condition(2), &done); //2
__ b(&error);
__ bind(&continue7);
__ tmhl(r1, Operand(0xFFFF));
__ b(Condition(2), &continue8); //2
__ b(&error);
// leftmost = 0
__ bind(&continue8);
__ lgfi(r1, Operand(0x0FF00FF0));
__ slag(r2, r1, Operand(32));
__ tmhh(r2, Operand(0xFFFF));
__ b(Condition(4), &done); //4
__ b(&error);
__ bind(&continue9);
__ tmhl(r1, Operand(0xFFFF));
__ b(Condition(4), &done); //4
__ b(&error);
__ bind(&error);
__ lgfi(r2, Operand(1));
__ b(r14);
__ bind(&done);
__ lgfi(r2, Operand::Zero());
__ b(r14);
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
// f.Call(reg2, reg3, reg4, reg5, reg6) -> set the register value
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIxPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
#undef __
} // namespace internal
} // namespace v8