2022-08-22 15:42:07 +00:00
|
|
|
// Copyright 2022 the V8 project authors. All rights reserved.
|
2014-07-30 13:54:45 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2022-08-22 15:42:07 +00:00
|
|
|
#ifndef V8_UNITTESTS_COMPILER_CODEGEN_TESTER_H_
|
|
|
|
#define V8_UNITTESTS_COMPILER_CODEGEN_TESTER_H_
|
2014-07-30 13:54:45 +00:00
|
|
|
|
2022-07-07 11:52:08 +00:00
|
|
|
#include "src/codegen/assembler.h"
|
2018-04-04 20:30:34 +00:00
|
|
|
#include "src/codegen/optimized-compilation-info.h"
|
2018-11-12 14:12:52 +00:00
|
|
|
#include "src/compiler/backend/instruction-selector.h"
|
2014-07-30 13:54:45 +00:00
|
|
|
#include "src/compiler/pipeline.h"
|
2015-07-07 15:02:39 +00:00
|
|
|
#include "src/compiler/raw-machine-assembler.h"
|
2022-07-07 11:52:08 +00:00
|
|
|
#include "src/objects/code-inl.h"
|
2022-08-22 15:42:07 +00:00
|
|
|
#include "test/common/call-tester.h"
|
2014-07-30 13:54:45 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
2015-05-29 14:05:39 +00:00
|
|
|
template <typename ReturnType>
|
2022-08-22 15:42:07 +00:00
|
|
|
class RawMachineAssemblerTester : public CallHelper<ReturnType>,
|
2015-05-29 14:05:39 +00:00
|
|
|
public RawMachineAssembler {
|
2014-07-30 13:54:45 +00:00
|
|
|
public:
|
2018-01-11 11:54:33 +00:00
|
|
|
template <typename... ParamMachTypes>
|
2022-08-22 15:42:07 +00:00
|
|
|
explicit RawMachineAssemblerTester(Isolate* isolate, Zone* zone,
|
|
|
|
ParamMachTypes... p)
|
|
|
|
: CallHelper<ReturnType>(
|
|
|
|
isolate,
|
|
|
|
CSignature::New(zone, MachineTypeForC<ReturnType>(), p...)),
|
2015-05-29 14:05:39 +00:00
|
|
|
RawMachineAssembler(
|
2022-08-22 15:42:07 +00:00
|
|
|
isolate, zone->template New<Graph>(zone),
|
2015-07-21 15:54:16 +00:00
|
|
|
Linkage::GetSimplifiedCDescriptor(
|
2022-08-22 15:42:07 +00:00
|
|
|
zone,
|
|
|
|
CSignature::New(zone, MachineTypeForC<ReturnType>(), p...),
|
2019-07-31 09:40:06 +00:00
|
|
|
CallDescriptor::kInitializeRootRegister),
|
2015-12-10 09:03:30 +00:00
|
|
|
MachineType::PointerRepresentation(),
|
2016-07-22 20:55:03 +00:00
|
|
|
InstructionSelector::SupportedMachineOperatorFlags(),
|
2022-08-22 15:42:07 +00:00
|
|
|
InstructionSelector::AlignmentRequirements()),
|
|
|
|
isolate_(isolate),
|
|
|
|
zone_(zone) {}
|
2014-07-30 13:54:45 +00:00
|
|
|
|
2018-10-02 13:02:12 +00:00
|
|
|
template <typename... ParamMachTypes>
|
2022-08-22 15:42:07 +00:00
|
|
|
RawMachineAssemblerTester(Isolate* isolate, Zone* zone, CodeKind kind,
|
|
|
|
ParamMachTypes... p)
|
|
|
|
: CallHelper<ReturnType>(
|
|
|
|
isolate,
|
|
|
|
CSignature::New(zone, MachineTypeForC<ReturnType>(), p...)),
|
2018-10-02 13:02:12 +00:00
|
|
|
RawMachineAssembler(
|
2022-08-22 15:42:07 +00:00
|
|
|
isolate, zone->template New<Graph>(zone),
|
2018-10-02 13:02:12 +00:00
|
|
|
Linkage::GetSimplifiedCDescriptor(
|
2022-08-22 15:42:07 +00:00
|
|
|
zone,
|
|
|
|
CSignature::New(zone, MachineTypeForC<ReturnType>(), p...),
|
2019-07-31 09:40:06 +00:00
|
|
|
CallDescriptor::kInitializeRootRegister),
|
2018-10-02 13:02:12 +00:00
|
|
|
MachineType::PointerRepresentation(),
|
|
|
|
InstructionSelector::SupportedMachineOperatorFlags(),
|
|
|
|
InstructionSelector::AlignmentRequirements()),
|
2022-08-22 15:42:07 +00:00
|
|
|
isolate_(isolate),
|
|
|
|
zone_(zone),
|
2018-10-02 13:02:12 +00:00
|
|
|
kind_(kind) {}
|
|
|
|
|
2018-09-17 11:30:48 +00:00
|
|
|
~RawMachineAssemblerTester() override = default;
|
2016-02-02 12:26:38 +00:00
|
|
|
|
2018-12-25 00:19:47 +00:00
|
|
|
void CheckNumber(double expected, Object number) {
|
2014-07-30 13:54:45 +00:00
|
|
|
CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
|
|
|
|
}
|
|
|
|
|
2018-12-25 00:19:47 +00:00
|
|
|
void CheckString(const char* expected, Object string) {
|
2014-07-30 13:54:45 +00:00
|
|
|
CHECK(
|
|
|
|
this->isolate()->factory()->InternalizeUtf8String(expected)->SameValue(
|
|
|
|
string));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GenerateCode() { Generate(); }
|
|
|
|
|
2023-01-17 13:39:32 +00:00
|
|
|
Handle<InstructionStream> GetInstructionStream() {
|
2023-01-18 14:16:01 +00:00
|
|
|
return handle(GetCode()->instruction_stream(), isolate_);
|
2015-10-01 17:11:34 +00:00
|
|
|
}
|
|
|
|
|
2023-01-18 14:16:01 +00:00
|
|
|
Handle<Code> GetCode() {
|
|
|
|
Generate();
|
|
|
|
return code_.ToHandleChecked();
|
|
|
|
}
|
2021-12-15 10:51:04 +00:00
|
|
|
|
2014-07-30 13:54:45 +00:00
|
|
|
protected:
|
2018-09-14 15:41:32 +00:00
|
|
|
Address Generate() override {
|
2023-01-18 14:16:01 +00:00
|
|
|
if (code_.is_null()) {
|
2023-01-17 13:39:32 +00:00
|
|
|
Schedule* schedule = ExportForTest();
|
2022-08-22 15:42:07 +00:00
|
|
|
OptimizedCompilationInfo info(base::ArrayVector("testing"), zone_, kind_);
|
2023-01-18 14:16:01 +00:00
|
|
|
code_ = Pipeline::GenerateCodeForTesting(
|
2023-01-17 13:39:32 +00:00
|
|
|
&info, isolate_, call_descriptor(), graph(),
|
2022-08-22 15:42:07 +00:00
|
|
|
AssemblerOptions::Default(isolate_), schedule);
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
2023-01-18 14:16:01 +00:00
|
|
|
return code_.ToHandleChecked()->instruction_stream().entry();
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
|
|
|
|
2022-08-22 15:42:07 +00:00
|
|
|
Zone* zone() { return zone_; }
|
|
|
|
|
2014-07-30 13:54:45 +00:00
|
|
|
private:
|
2022-08-22 15:42:07 +00:00
|
|
|
Isolate* isolate_;
|
|
|
|
Zone* zone_;
|
Reland "Reland "[deoptimizer] Change deopt entries into builtins""
This is a reland of fbfa9bf4ec72b1b73a96b70ccb68cd98c321511b
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 7f58ced72eb65b6b5530ccabaf2eaebe45bf9d33
>
> 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 05:12:25 +00:00
|
|
|
CodeKind kind_ = CodeKind::FOR_TESTING;
|
2023-01-18 14:16:01 +00:00
|
|
|
MaybeHandle<Code> code_;
|
2014-07-30 13:54:45 +00:00
|
|
|
};
|
|
|
|
|
2015-10-30 21:32:35 +00:00
|
|
|
template <typename ReturnType>
|
|
|
|
class BufferedRawMachineAssemblerTester
|
|
|
|
: public RawMachineAssemblerTester<int32_t> {
|
|
|
|
public:
|
2018-01-11 11:54:33 +00:00
|
|
|
template <typename... ParamMachTypes>
|
2022-08-22 15:42:07 +00:00
|
|
|
explicit BufferedRawMachineAssemblerTester(Isolate* isolate, Zone* zone,
|
|
|
|
ParamMachTypes... p)
|
2018-01-11 11:54:33 +00:00
|
|
|
: RawMachineAssemblerTester<int32_t>(
|
2022-08-22 15:42:07 +00:00
|
|
|
isolate, zone, MachineType::Pointer(),
|
|
|
|
((void)p, MachineType::Pointer())...),
|
2018-01-11 11:54:33 +00:00
|
|
|
test_graph_signature_(
|
2022-08-22 15:42:07 +00:00
|
|
|
CSignature::New(this->zone(), MachineType::Int32(), p...)),
|
2018-01-11 11:54:33 +00:00
|
|
|
return_parameter_index_(sizeof...(p)) {
|
|
|
|
static_assert(sizeof...(p) <= arraysize(parameter_nodes_),
|
|
|
|
"increase parameter_nodes_ array");
|
2018-01-16 15:43:38 +00:00
|
|
|
std::array<MachineType, sizeof...(p)> p_arr{{p...}};
|
2018-01-11 11:54:33 +00:00
|
|
|
for (size_t i = 0; i < p_arr.size(); ++i) {
|
|
|
|
parameter_nodes_[i] = Load(p_arr[i], RawMachineAssembler::Parameter(i));
|
|
|
|
}
|
|
|
|
}
|
2015-10-30 21:32:35 +00:00
|
|
|
|
2018-04-13 22:28:05 +00:00
|
|
|
Address Generate() override { return RawMachineAssemblerTester::Generate(); }
|
2015-10-30 21:32:35 +00:00
|
|
|
|
|
|
|
// The BufferedRawMachineAssemblerTester does not pass parameters directly
|
|
|
|
// to the constructed IR graph. Instead it passes a pointer to the parameter
|
|
|
|
// to the IR graph, and adds Load nodes to the IR graph to load the
|
|
|
|
// parameters from memory. Thereby it is possible to pass 64 bit parameters
|
|
|
|
// to the IR graph.
|
|
|
|
Node* Parameter(size_t index) {
|
2018-01-11 11:54:33 +00:00
|
|
|
CHECK_GT(arraysize(parameter_nodes_), index);
|
2015-10-30 21:32:35 +00:00
|
|
|
return parameter_nodes_[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
// The BufferedRawMachineAssemblerTester adds a Store node to the IR graph
|
|
|
|
// to store the graph's return value in memory. The memory address for the
|
|
|
|
// Store node is provided as a parameter. By storing the return value in
|
|
|
|
// memory it is possible to return 64 bit values.
|
|
|
|
void Return(Node* input) {
|
2019-03-06 10:24:13 +00:00
|
|
|
if (COMPRESS_POINTERS_BOOL && MachineTypeForC<ReturnType>().IsTagged()) {
|
|
|
|
// Since we are returning values via storing to off-heap location
|
|
|
|
// generate full-word store here.
|
|
|
|
Store(MachineType::PointerRepresentation(),
|
|
|
|
RawMachineAssembler::Parameter(return_parameter_index_),
|
|
|
|
BitcastTaggedToWord(input), kNoWriteBarrier);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
Store(MachineTypeForC<ReturnType>().representation(),
|
|
|
|
RawMachineAssembler::Parameter(return_parameter_index_), input,
|
|
|
|
kNoWriteBarrier);
|
|
|
|
}
|
2015-10-30 21:32:35 +00:00
|
|
|
RawMachineAssembler::Return(Int32Constant(1234));
|
|
|
|
}
|
|
|
|
|
2018-01-11 11:54:33 +00:00
|
|
|
template <typename... Params>
|
|
|
|
ReturnType Call(Params... p) {
|
2019-02-11 15:31:20 +00:00
|
|
|
uintptr_t zap_data[] = {kZapValue, kZapValue};
|
2015-10-30 21:32:35 +00:00
|
|
|
ReturnType return_value;
|
2022-05-13 09:19:09 +00:00
|
|
|
static_assert(sizeof(return_value) <= sizeof(zap_data));
|
2019-02-11 15:31:20 +00:00
|
|
|
MemCopy(&return_value, &zap_data, sizeof(return_value));
|
2018-01-11 11:54:33 +00:00
|
|
|
CSignature::VerifyParams<Params...>(test_graph_signature_);
|
|
|
|
CallHelper<int32_t>::Call(reinterpret_cast<void*>(&p)...,
|
2015-10-30 21:32:35 +00:00
|
|
|
reinterpret_cast<void*>(&return_value));
|
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
CSignature* test_graph_signature_;
|
|
|
|
Node* parameter_nodes_[4];
|
|
|
|
uint32_t return_parameter_index_;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
class BufferedRawMachineAssemblerTester<void>
|
|
|
|
: public RawMachineAssemblerTester<void> {
|
|
|
|
public:
|
2018-01-11 11:54:33 +00:00
|
|
|
template <typename... ParamMachTypes>
|
2022-08-22 15:42:07 +00:00
|
|
|
explicit BufferedRawMachineAssemblerTester(Isolate* isolate, Zone* zone,
|
|
|
|
ParamMachTypes... p)
|
|
|
|
: RawMachineAssemblerTester<void>(isolate, zone,
|
|
|
|
((void)p, MachineType::Pointer())...),
|
2015-10-30 21:32:35 +00:00
|
|
|
test_graph_signature_(
|
2022-08-22 15:42:07 +00:00
|
|
|
CSignature::New(this->zone(), MachineType::None(), p...)) {
|
2018-01-11 11:54:33 +00:00
|
|
|
static_assert(sizeof...(p) <= arraysize(parameter_nodes_),
|
|
|
|
"increase parameter_nodes_ array");
|
2018-01-16 15:43:38 +00:00
|
|
|
std::array<MachineType, sizeof...(p)> p_arr{{p...}};
|
2018-01-11 11:54:33 +00:00
|
|
|
for (size_t i = 0; i < p_arr.size(); ++i) {
|
|
|
|
parameter_nodes_[i] = Load(p_arr[i], RawMachineAssembler::Parameter(i));
|
|
|
|
}
|
2015-10-30 21:32:35 +00:00
|
|
|
}
|
|
|
|
|
2018-04-13 22:28:05 +00:00
|
|
|
Address Generate() override { return RawMachineAssemblerTester::Generate(); }
|
2016-02-02 12:26:38 +00:00
|
|
|
|
2015-10-30 21:32:35 +00:00
|
|
|
// The BufferedRawMachineAssemblerTester does not pass parameters directly
|
|
|
|
// to the constructed IR graph. Instead it passes a pointer to the parameter
|
|
|
|
// to the IR graph, and adds Load nodes to the IR graph to load the
|
|
|
|
// parameters from memory. Thereby it is possible to pass 64 bit parameters
|
|
|
|
// to the IR graph.
|
|
|
|
Node* Parameter(size_t index) {
|
2018-01-11 11:54:33 +00:00
|
|
|
CHECK_GT(arraysize(parameter_nodes_), index);
|
2015-10-30 21:32:35 +00:00
|
|
|
return parameter_nodes_[index];
|
|
|
|
}
|
|
|
|
|
2018-01-11 11:54:33 +00:00
|
|
|
template <typename... Params>
|
|
|
|
void Call(Params... p) {
|
|
|
|
CSignature::VerifyParams<Params...>(test_graph_signature_);
|
|
|
|
CallHelper<void>::Call(reinterpret_cast<void*>(&p)...);
|
2015-10-30 21:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
CSignature* test_graph_signature_;
|
|
|
|
Node* parameter_nodes_[4];
|
|
|
|
};
|
2018-01-11 11:54:33 +00:00
|
|
|
|
2014-07-30 13:54:45 +00:00
|
|
|
static const bool USE_RESULT_BUFFER = true;
|
|
|
|
static const bool USE_RETURN_REGISTER = false;
|
2014-07-31 09:30:16 +00:00
|
|
|
static const int32_t CHECK_VALUE = 0x99BEEDCE;
|
|
|
|
|
2014-07-30 13:54:45 +00:00
|
|
|
// TODO(titzer): use the C-style calling convention, or any register-based
|
|
|
|
// calling convention for binop tests.
|
2015-12-10 09:03:30 +00:00
|
|
|
template <typename CType, bool use_result_buffer>
|
2014-07-30 13:54:45 +00:00
|
|
|
class BinopTester {
|
|
|
|
public:
|
2015-12-10 09:03:30 +00:00
|
|
|
explicit BinopTester(RawMachineAssemblerTester<int32_t>* tester,
|
2019-05-10 10:10:34 +00:00
|
|
|
MachineType type)
|
2014-07-30 13:54:45 +00:00
|
|
|
: T(tester),
|
2019-05-10 10:10:34 +00:00
|
|
|
param0(T->LoadFromPointer(&p0, type)),
|
|
|
|
param1(T->LoadFromPointer(&p1, type)),
|
|
|
|
type(type),
|
2014-07-30 13:54:45 +00:00
|
|
|
p0(static_cast<CType>(0)),
|
|
|
|
p1(static_cast<CType>(0)),
|
|
|
|
result(static_cast<CType>(0)) {}
|
|
|
|
|
|
|
|
RawMachineAssemblerTester<int32_t>* T;
|
|
|
|
Node* param0;
|
|
|
|
Node* param1;
|
|
|
|
|
|
|
|
CType call(CType a0, CType a1) {
|
|
|
|
p0 = a0;
|
|
|
|
p1 = a1;
|
|
|
|
if (use_result_buffer) {
|
|
|
|
CHECK_EQ(CHECK_VALUE, T->Call());
|
|
|
|
return result;
|
|
|
|
} else {
|
2015-03-30 07:33:46 +00:00
|
|
|
return static_cast<CType>(T->Call());
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddReturn(Node* val) {
|
|
|
|
if (use_result_buffer) {
|
2019-05-10 10:10:34 +00:00
|
|
|
T->Store(type.representation(), T->PointerConstant(&result),
|
2015-12-11 15:34:00 +00:00
|
|
|
T->Int32Constant(0), val, kNoWriteBarrier);
|
2014-07-30 13:54:45 +00:00
|
|
|
T->Return(T->Int32Constant(CHECK_VALUE));
|
|
|
|
} else {
|
|
|
|
T->Return(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-31 07:44:29 +00:00
|
|
|
template <typename Ci, typename Cj, typename Fn>
|
|
|
|
void Run(const Ci& ci, const Cj& cj, const Fn& fn) {
|
|
|
|
typename Ci::const_iterator i;
|
|
|
|
typename Cj::const_iterator j;
|
|
|
|
for (i = ci.begin(); i != ci.end(); ++i) {
|
|
|
|
for (j = cj.begin(); j != cj.end(); ++j) {
|
|
|
|
CHECK_EQ(fn(*i, *j), this->call(*i, *j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-30 13:54:45 +00:00
|
|
|
protected:
|
2019-05-10 10:10:34 +00:00
|
|
|
MachineType type;
|
2014-07-30 13:54:45 +00:00
|
|
|
CType p0;
|
|
|
|
CType p1;
|
|
|
|
CType result;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A helper class for testing code sequences that take two int parameters and
|
|
|
|
// return an int value.
|
2015-12-10 09:03:30 +00:00
|
|
|
class Int32BinopTester : public BinopTester<int32_t, USE_RETURN_REGISTER> {
|
2014-07-30 13:54:45 +00:00
|
|
|
public:
|
|
|
|
explicit Int32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
2015-12-10 09:03:30 +00:00
|
|
|
: BinopTester<int32_t, USE_RETURN_REGISTER>(tester,
|
|
|
|
MachineType::Int32()) {}
|
2014-08-14 09:19:54 +00:00
|
|
|
};
|
|
|
|
|
2015-12-24 18:50:37 +00:00
|
|
|
// A helper class for testing code sequences that take two int parameters and
|
|
|
|
// return an int value.
|
|
|
|
class Int64BinopTester : public BinopTester<int64_t, USE_RETURN_REGISTER> {
|
|
|
|
public:
|
|
|
|
explicit Int64BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
|
|
|
: BinopTester<int64_t, USE_RETURN_REGISTER>(tester,
|
|
|
|
MachineType::Int64()) {}
|
|
|
|
};
|
|
|
|
|
2014-08-14 09:19:54 +00:00
|
|
|
// A helper class for testing code sequences that take two uint parameters and
|
|
|
|
// return an uint value.
|
2015-12-10 09:03:30 +00:00
|
|
|
class Uint32BinopTester : public BinopTester<uint32_t, USE_RETURN_REGISTER> {
|
2014-08-14 09:19:54 +00:00
|
|
|
public:
|
|
|
|
explicit Uint32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
2015-12-10 09:03:30 +00:00
|
|
|
: BinopTester<uint32_t, USE_RETURN_REGISTER>(tester,
|
|
|
|
MachineType::Uint32()) {}
|
2014-07-30 13:54:45 +00:00
|
|
|
|
2014-08-14 09:19:54 +00:00
|
|
|
uint32_t call(uint32_t a0, uint32_t a1) {
|
|
|
|
p0 = a0;
|
|
|
|
p1 = a1;
|
|
|
|
return static_cast<uint32_t>(T->Call());
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-03-30 07:33:46 +00:00
|
|
|
// A helper class for testing code sequences that take two float parameters and
|
|
|
|
// return a float value.
|
2015-12-10 09:03:30 +00:00
|
|
|
class Float32BinopTester : public BinopTester<float, USE_RESULT_BUFFER> {
|
2015-03-30 07:33:46 +00:00
|
|
|
public:
|
|
|
|
explicit Float32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
2015-12-10 09:03:30 +00:00
|
|
|
: BinopTester<float, USE_RESULT_BUFFER>(tester, MachineType::Float32()) {}
|
2015-03-30 07:33:46 +00:00
|
|
|
};
|
|
|
|
|
2014-07-30 13:54:45 +00:00
|
|
|
// A helper class for testing code sequences that take two double parameters and
|
|
|
|
// return a double value.
|
2015-12-10 09:03:30 +00:00
|
|
|
class Float64BinopTester : public BinopTester<double, USE_RESULT_BUFFER> {
|
2014-07-30 13:54:45 +00:00
|
|
|
public:
|
|
|
|
explicit Float64BinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
2015-12-10 09:03:30 +00:00
|
|
|
: BinopTester<double, USE_RESULT_BUFFER>(tester, MachineType::Float64()) {
|
|
|
|
}
|
2014-07-30 13:54:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// A helper class for testing code sequences that take two pointer parameters
|
|
|
|
// and return a pointer value.
|
|
|
|
// TODO(titzer): pick word size of pointers based on V8_TARGET.
|
|
|
|
template <typename Type>
|
2018-04-27 11:55:34 +00:00
|
|
|
class PointerBinopTester : public BinopTester<Type, USE_RETURN_REGISTER> {
|
2014-07-30 13:54:45 +00:00
|
|
|
public:
|
|
|
|
explicit PointerBinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
2018-04-27 11:55:34 +00:00
|
|
|
: BinopTester<Type, USE_RETURN_REGISTER>(tester, MachineType::Pointer()) {
|
|
|
|
}
|
2014-07-30 13:54:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// A helper class for testing code sequences that take two tagged parameters and
|
|
|
|
// return a tagged value.
|
|
|
|
template <typename Type>
|
2018-04-27 11:55:34 +00:00
|
|
|
class TaggedBinopTester : public BinopTester<Type, USE_RETURN_REGISTER> {
|
2014-07-30 13:54:45 +00:00
|
|
|
public:
|
|
|
|
explicit TaggedBinopTester(RawMachineAssemblerTester<int32_t>* tester)
|
2018-04-27 11:55:34 +00:00
|
|
|
: BinopTester<Type, USE_RETURN_REGISTER>(tester,
|
|
|
|
MachineType::AnyTagged()) {}
|
2014-07-30 13:54:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// A helper class for testing compares. Wraps a machine opcode and provides
|
|
|
|
// evaluation routines and the operators.
|
|
|
|
class CompareWrapper {
|
|
|
|
public:
|
|
|
|
explicit CompareWrapper(IrOpcode::Value op) : opcode(op) {}
|
|
|
|
|
|
|
|
Node* MakeNode(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
|
2015-09-23 09:08:15 +00:00
|
|
|
return m->AddNode(op(m->machine()), a, b);
|
2014-07-30 13:54:45 +00:00
|
|
|
}
|
|
|
|
|
2014-09-10 12:23:45 +00:00
|
|
|
const Operator* op(MachineOperatorBuilder* machine) {
|
2014-07-30 13:54:45 +00:00
|
|
|
switch (opcode) {
|
|
|
|
case IrOpcode::kWord32Equal:
|
|
|
|
return machine->Word32Equal();
|
|
|
|
case IrOpcode::kInt32LessThan:
|
|
|
|
return machine->Int32LessThan();
|
|
|
|
case IrOpcode::kInt32LessThanOrEqual:
|
|
|
|
return machine->Int32LessThanOrEqual();
|
|
|
|
case IrOpcode::kUint32LessThan:
|
|
|
|
return machine->Uint32LessThan();
|
|
|
|
case IrOpcode::kUint32LessThanOrEqual:
|
|
|
|
return machine->Uint32LessThanOrEqual();
|
|
|
|
case IrOpcode::kFloat64Equal:
|
|
|
|
return machine->Float64Equal();
|
|
|
|
case IrOpcode::kFloat64LessThan:
|
|
|
|
return machine->Float64LessThan();
|
|
|
|
case IrOpcode::kFloat64LessThanOrEqual:
|
|
|
|
return machine->Float64LessThanOrEqual();
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Int32Compare(int32_t a, int32_t b) {
|
|
|
|
switch (opcode) {
|
|
|
|
case IrOpcode::kWord32Equal:
|
|
|
|
return a == b;
|
|
|
|
case IrOpcode::kInt32LessThan:
|
|
|
|
return a < b;
|
|
|
|
case IrOpcode::kInt32LessThanOrEqual:
|
|
|
|
return a <= b;
|
|
|
|
case IrOpcode::kUint32LessThan:
|
|
|
|
return static_cast<uint32_t>(a) < static_cast<uint32_t>(b);
|
|
|
|
case IrOpcode::kUint32LessThanOrEqual:
|
|
|
|
return static_cast<uint32_t>(a) <= static_cast<uint32_t>(b);
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Float64Compare(double a, double b) {
|
|
|
|
switch (opcode) {
|
|
|
|
case IrOpcode::kFloat64Equal:
|
|
|
|
return a == b;
|
|
|
|
case IrOpcode::kFloat64LessThan:
|
|
|
|
return a < b;
|
|
|
|
case IrOpcode::kFloat64LessThanOrEqual:
|
|
|
|
return a <= b;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IrOpcode::Value opcode;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A small closure class to generate code for a function of two inputs that
|
|
|
|
// produces a single output so that it can be used in many different contexts.
|
|
|
|
// The {expected()} method should compute the expected output for a given
|
|
|
|
// pair of inputs.
|
|
|
|
template <typename T>
|
|
|
|
class BinopGen {
|
|
|
|
public:
|
|
|
|
virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) = 0;
|
|
|
|
virtual T expected(T a, T b) = 0;
|
2018-09-17 11:30:48 +00:00
|
|
|
virtual ~BinopGen() = default;
|
2014-07-30 13:54:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// A helper class to generate various combination of input shape combinations
|
|
|
|
// and run the generated code to ensure it produces the correct results.
|
|
|
|
class Int32BinopInputShapeTester {
|
|
|
|
public:
|
2022-08-22 15:42:07 +00:00
|
|
|
explicit Int32BinopInputShapeTester(Isolate* isolate, Zone* zone,
|
|
|
|
BinopGen<int32_t>* g)
|
|
|
|
: isolate_(isolate), zone_(zone), gen(g), input_a(0), input_b(0) {}
|
2014-07-30 13:54:45 +00:00
|
|
|
|
|
|
|
void TestAllInputShapes();
|
|
|
|
|
|
|
|
private:
|
2022-08-22 15:42:07 +00:00
|
|
|
Isolate* isolate_;
|
|
|
|
Zone* zone_;
|
2014-07-30 13:54:45 +00:00
|
|
|
BinopGen<int32_t>* gen;
|
|
|
|
int32_t input_a;
|
|
|
|
int32_t input_b;
|
|
|
|
|
|
|
|
void Run(RawMachineAssemblerTester<int32_t>* m);
|
|
|
|
void RunLeft(RawMachineAssemblerTester<int32_t>* m);
|
|
|
|
void RunRight(RawMachineAssemblerTester<int32_t>* m);
|
|
|
|
};
|
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|
|
|
|
|
2022-08-22 15:42:07 +00:00
|
|
|
#endif // V8_UNITTESTS_COMPILER_CODEGEN_TESTER_H_
|