From f4b5224ae9b463423e58bf9082f0280f9efe84fb Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Thu, 14 Aug 2014 06:33:50 +0000 Subject: [PATCH] [turbofan] Refactor the InstructionSelector tests. Also fix some issues and improve test coverage. TEST=compiler-unittests BUG=v8:3489 LOG=y R=jarin@chromium.org Review URL: https://codereview.chromium.org/469743002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23111 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler/arm/instruction-selector-arm.cc | 21 +- src/compiler/machine-node-factory.h | 15 + test/cctest/cctest.gyp | 4 - .../compiler/test-instruction-selector-arm.cc | 1863 -------------------- .../compiler/test-instruction-selector-arm64.cc | 157 -- .../compiler/test-instruction-selector-ia32.cc | 66 - test/cctest/compiler/test-instruction-selector.cc | 22 - test/compiler-unittests/DEPS | 2 +- .../arm/instruction-selector-arm-unittest.cc | 1711 +++++++++++++++++- .../arm64/instruction-selector-arm64-unittest.cc | 133 ++ .../compiler-unittests/change-lowering-unittest.cc | 1 - test/compiler-unittests/compiler-unittests.gyp | 10 + test/compiler-unittests/compiler-unittests.h | 2 +- .../ia32/instruction-selector-ia32-unittest.cc | 78 + .../instruction-selector-unittest.cc | 15 +- .../instruction-selector-unittest.h | 38 +- testing/gtest-support.h | 58 + testing/gtest-type-names.h | 34 - testing/gtest.gyp | 2 +- 19 files changed, 2069 insertions(+), 2163 deletions(-) delete mode 100644 test/cctest/compiler/test-instruction-selector-arm.cc delete mode 100644 test/cctest/compiler/test-instruction-selector-arm64.cc delete mode 100644 test/cctest/compiler/test-instruction-selector-ia32.cc delete mode 100644 test/cctest/compiler/test-instruction-selector.cc create mode 100644 test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc create mode 100644 test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc create mode 100644 testing/gtest-support.h delete mode 100644 testing/gtest-type-names.h diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index 029d6e3..22af55f 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc @@ -141,11 +141,22 @@ static bool TryMatchROR(InstructionSelector* selector, if (value != mshl.left().node()) return false; Node* shift = mshr.right().node(); Int32Matcher mshift(shift); - if (mshift.IsInRange(1, 31) && mshl.right().Is(32 - mshift.Value())) { - *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); - *value_return = g.UseRegister(value); - *shift_return = g.UseImmediate(shift); - return true; + if (mshift.IsInRange(1, 31)) { + if (mshl.right().Is(32 - mshift.Value())) { + *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); + *value_return = g.UseRegister(value); + *shift_return = g.UseImmediate(shift); + return true; + } + if (mshl.right().IsInt32Sub()) { + Int32BinopMatcher mshlright(mshl.right().node()); + if (mshlright.left().Is(32) && mshlright.right().Is(mshift.Value())) { + *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); + *value_return = g.UseRegister(value); + *shift_return = g.UseImmediate(shift); + return true; + } + } } if (mshl.right().IsInt32Sub()) { Int32BinopMatcher mshlright(mshl.right().node()); diff --git a/src/compiler/machine-node-factory.h b/src/compiler/machine-node-factory.h index faee93e..721b1ff 100644 --- a/src/compiler/machine-node-factory.h +++ b/src/compiler/machine-node-factory.h @@ -118,6 +118,13 @@ class MachineNodeFactory { Node* WordSar(Node* a, Node* b) { return NEW_NODE_2(MACHINE()->WordSar(), a, b); } + Node* WordRor(Node* a, Node* b) { + if (MACHINE()->is32()) { + return Word32Ror(a, b); + } else { + return Word64Ror(a, b); + } + } Node* WordEqual(Node* a, Node* b) { return NEW_NODE_2(MACHINE()->WordEqual(), a, b); } @@ -157,6 +164,10 @@ class MachineNodeFactory { Node* Word32Sar(Node* a, Node* b) { return NEW_NODE_2(MACHINE()->Word32Sar(), a, b); } + Node* Word32Ror(Node* a, Node* b) { + return Word32Or(Word32Shl(a, Int32Sub(Int32Constant(32), b)), + Word32Shr(a, b)); + } Node* Word32Equal(Node* a, Node* b) { return NEW_NODE_2(MACHINE()->Word32Equal(), a, b); } @@ -184,6 +195,10 @@ class MachineNodeFactory { Node* Word64Sar(Node* a, Node* b) { return NEW_NODE_2(MACHINE()->Word64Sar(), a, b); } + Node* Word64Ror(Node* a, Node* b) { + return Word64Or(Word64Shl(a, Int64Sub(Int64Constant(64), b)), + Word64Shr(a, b)); + } Node* Word64Equal(Node* a, Node* b) { return NEW_NODE_2(MACHINE()->Word64Equal(), a, b); } diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index 5e0005d..559dd6b 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -57,7 +57,6 @@ 'compiler/test-codegen-deopt.cc', 'compiler/test-gap-resolver.cc', 'compiler/test-graph-reducer.cc', - 'compiler/test-instruction-selector.cc', 'compiler/test-instruction.cc', 'compiler/test-js-context-specialization.cc', 'compiler/test-js-constant-cache.cc', @@ -167,7 +166,6 @@ 'conditions': [ ['v8_target_arch=="ia32"', { 'sources': [ ### gcmole(arch:ia32) ### - 'compiler/test-instruction-selector-ia32.cc', 'test-assembler-ia32.cc', 'test-code-stubs.cc', 'test-code-stubs-ia32.cc', @@ -188,7 +186,6 @@ }], ['v8_target_arch=="arm"', { 'sources': [ ### gcmole(arch:arm) ### - 'compiler/test-instruction-selector-arm.cc', 'test-assembler-arm.cc', 'test-code-stubs.cc', 'test-code-stubs-arm.cc', @@ -198,7 +195,6 @@ }], ['v8_target_arch=="arm64"', { 'sources': [ ### gcmole(arch:arm64) ### - 'compiler/test-instruction-selector-arm64.cc', 'test-utils-arm64.cc', 'test-assembler-arm64.cc', 'test-code-stubs.cc', diff --git a/test/cctest/compiler/test-instruction-selector-arm.cc b/test/cctest/compiler/test-instruction-selector-arm.cc deleted file mode 100644 index f62e09f..0000000 --- a/test/cctest/compiler/test-instruction-selector-arm.cc +++ /dev/null @@ -1,1863 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "test/cctest/compiler/instruction-selector-tester.h" -#include "test/cctest/compiler/value-helper.h" - -using namespace v8::internal; -using namespace v8::internal::compiler; - -namespace { - -typedef RawMachineAssembler::Label MLabel; - -struct DPI { - Operator* op; - ArchOpcode arch_opcode; - ArchOpcode reverse_arch_opcode; - ArchOpcode test_arch_opcode; -}; - - -// ARM data processing instructions. -class DPIs V8_FINAL : public std::list, private HandleAndZoneScope { - public: - DPIs() { - MachineOperatorBuilder machine(main_zone()); - DPI and_ = {machine.Word32And(), kArmAnd, kArmAnd, kArmTst}; - push_back(and_); - DPI or_ = {machine.Word32Or(), kArmOrr, kArmOrr, kArmOrr}; - push_back(or_); - DPI xor_ = {machine.Word32Xor(), kArmEor, kArmEor, kArmTeq}; - push_back(xor_); - DPI add = {machine.Int32Add(), kArmAdd, kArmAdd, kArmCmn}; - push_back(add); - DPI sub = {machine.Int32Sub(), kArmSub, kArmRsb, kArmCmp}; - push_back(sub); - } -}; - - -struct ODPI { - Operator* op; - ArchOpcode arch_opcode; - ArchOpcode reverse_arch_opcode; -}; - - -// ARM data processing instructions with overflow. -class ODPIs V8_FINAL : public std::list, private HandleAndZoneScope { - public: - ODPIs() { - MachineOperatorBuilder machine(main_zone()); - ODPI add = {machine.Int32AddWithOverflow(), kArmAdd, kArmAdd}; - push_back(add); - ODPI sub = {machine.Int32SubWithOverflow(), kArmSub, kArmRsb}; - push_back(sub); - } -}; - - -// ARM immediates. -class Immediates V8_FINAL : public std::list { - public: - Immediates() { - for (uint32_t imm8 = 0; imm8 < 256; ++imm8) { - for (uint32_t rot4 = 0; rot4 < 32; rot4 += 2) { - int32_t imm = (imm8 >> rot4) | (imm8 << (32 - rot4)); - CHECK(Assembler::ImmediateFitsAddrMode1Instruction(imm)); - push_back(imm); - } - } - } -}; - - -struct Shift { - Operator* op; - int32_t i_low; // lowest possible immediate - int32_t i_high; // highest possible immediate - AddressingMode i_mode; // Operand2_R__I - AddressingMode r_mode; // Operand2_R__R -}; - - -// ARM shifts. -class Shifts V8_FINAL : public std::list, private HandleAndZoneScope { - public: - Shifts() { - MachineOperatorBuilder machine(main_zone()); - Shift sar = {machine.Word32Sar(), 1, 32, kMode_Operand2_R_ASR_I, - kMode_Operand2_R_ASR_R}; - Shift shl = {machine.Word32Shl(), 0, 31, kMode_Operand2_R_LSL_I, - kMode_Operand2_R_LSL_R}; - Shift shr = {machine.Word32Shr(), 1, 32, kMode_Operand2_R_LSR_I, - kMode_Operand2_R_LSR_R}; - push_back(sar); - push_back(shl); - push_back(shr); - } -}; - -} // namespace - - -TEST(InstructionSelectorDPIP) { - DPIs dpis; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } -} - - -TEST(InstructionSelectorDPIImm) { - DPIs dpis; - Immediates immediates; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - for (Immediates::const_iterator j = immediates.begin(); - j != immediates.end(); ++j) { - int32_t imm = *j; - { - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - } - } - } -} - - -TEST(InstructionSelectorDPIAndShiftP) { - DPIs dpis; - Shifts shifts; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { - Shift shift = *j; - { - InstructionSelectorTester m; - m.Return( - m.NewNode(dpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, - m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), - m.Parameter(2))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - } - } -} - - -TEST(InstructionSelectorDPIAndRotateRightP) { - DPIs dpis; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - { - InstructionSelectorTester m; - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = m.Word32Or( - m.Word32Shr(value, shift), - m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); - m.Return(m.NewNode(dpi.op, m.Parameter(0), ror)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = - m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), - m.Word32Shr(value, shift)); - m.Return(m.NewNode(dpi.op, m.Parameter(0), ror)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = m.Word32Or( - m.Word32Shr(value, shift), - m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); - m.Return(m.NewNode(dpi.op, ror, m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = - m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), - m.Word32Shr(value, shift)); - m.Return(m.NewNode(dpi.op, ror, m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - } - } -} - - -TEST(InstructionSelectorDPIAndShiftImm) { - DPIs dpis; - Shifts shifts; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { - Shift shift = *j; - for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { - { - InstructionSelectorTester m; - m.Return(m.NewNode( - dpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.NewNode( - dpi.op, m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)), - m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - } - } - } - } -} - - -TEST(InstructionSelectorODPIP) { - ODPIs odpis; - for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { - ODPI odpi = *i; - { - InstructionSelectorTester m; - m.Return( - m.Projection(1, m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return( - m.Projection(0, m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - } -} - - -TEST(InstructionSelectorODPIImm) { - ODPIs odpis; - Immediates immediates; - for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { - ODPI odpi = *i; - for (Immediates::const_iterator j = immediates.begin(); - j != immediates.end(); ++j) { - int32_t imm = *j; - { - InstructionSelectorTester m; - m.Return(m.Projection( - 1, m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 1, m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 0, m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 0, m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - } - } -} - - -TEST(InstructionSelectorODPIAndShiftP) { - ODPIs odpis; - Shifts shifts; - for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { - ODPI odpi = *i; - for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { - Shift shift = *j; - { - InstructionSelectorTester m; - m.Return(m.Projection( - 1, m.NewNode(odpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 1, m.NewNode(odpi.op, - m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), - m.Parameter(2)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 0, m.NewNode(odpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 0, m.NewNode(odpi.op, - m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), - m.Parameter(2)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = - m.NewNode(odpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = m.NewNode( - odpi.op, m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), - m.Parameter(2)); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - } - } -} - - -TEST(InstructionSelectorODPIAndShiftImm) { - ODPIs odpis; - Shifts shifts; - for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { - ODPI odpi = *i; - for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { - Shift shift = *j; - for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { - { - InstructionSelectorTester m; - m.Return(m.Projection(1, m.NewNode(odpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), - m.Int32Constant(imm))))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 1, m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0), - m.Int32Constant(imm)), - m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection(0, m.NewNode(odpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), - m.Int32Constant(imm))))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - m.Return(m.Projection( - 0, m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0), - m.Int32Constant(imm)), - m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); - CHECK_LE(1, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = m.NewNode( - odpi.op, m.Parameter(0), - m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm))); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - { - InstructionSelectorTester m; - Node* node = m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0), - m.Int32Constant(imm)), - m.Parameter(1)); - m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); - m.SelectInstructions(); - CHECK_LE(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); - CHECK_EQ(2, m.code[0]->OutputCount()); - } - } - } - } -} - - -TEST(InstructionSelectorWord32AndAndWord32XorWithMinus1P) { - { - InstructionSelectorTester m; - m.Return(m.Word32And(m.Parameter(0), - m.Word32Xor(m.Int32Constant(-1), m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32And(m.Parameter(0), - m.Word32Xor(m.Parameter(1), m.Int32Constant(-1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32And(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)), - m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32And(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), - m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } -} - - -TEST(InstructionSelectorWord32AndAndWord32XorWithMinus1AndShiftP) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - { - InstructionSelectorTester m; - m.Return(m.Word32And( - m.Parameter(0), - m.Word32Xor(m.Int32Constant(-1), - m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32And( - m.Parameter(0), - m.Word32Xor(m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)), - m.Int32Constant(-1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32And( - m.Word32Xor(m.Int32Constant(-1), - m.NewNode(shift.op, m.Parameter(0), m.Parameter(1))), - m.Parameter(2))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32And( - m.Word32Xor(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), - m.Int32Constant(-1)), - m.Parameter(2))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - } -} - - -TEST(InstructionSelectorWord32XorWithMinus1P) { - { - InstructionSelectorTester m; - m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - } -} - - -TEST(InstructionSelectorWord32XorWithMinus1AndShiftP) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - { - InstructionSelectorTester m; - m.Return( - m.Word32Xor(m.Int32Constant(-1), - m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Xor(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), - m.Int32Constant(-1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - } - } -} - - -TEST(InstructionSelectorShiftP) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - InstructionSelectorTester m; - m.Return(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - } -} - - -TEST(InstructionSelectorShiftImm) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { - InstructionSelectorTester m; - m.Return(m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - } -} - - -TEST(InstructionSelectorRotateRightP) { - { - InstructionSelectorTester m; - Node* value = m.Parameter(0); - Node* shift = m.Parameter(1); - m.Return( - m.Word32Or(m.Word32Shr(value, shift), - m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - } - { - InstructionSelectorTester m; - Node* value = m.Parameter(0); - Node* shift = m.Parameter(1); - m.Return( - m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), - m.Word32Shr(value, shift))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - } -} - - -TEST(InstructionSelectorRotateRightImm) { - FOR_INPUTS(uint32_t, ror, i) { - uint32_t shift = *i; - { - InstructionSelectorTester m; - Node* value = m.Parameter(0); - m.Return(m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)), - m.Word32Shl(value, m.Int32Constant(32 - shift)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(1))); - } - { - InstructionSelectorTester m; - Node* value = m.Parameter(0); - m.Return(m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)), - m.Word32Shr(value, m.Int32Constant(shift)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(1))); - } - } -} - - -TEST(InstructionSelectorInt32MulP) { - InstructionSelectorTester m; - m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMul, m.code[0]->arch_opcode()); -} - - -TEST(InstructionSelectorInt32MulImm) { - // x * (2^k + 1) -> (x >> k) + x - for (int k = 1; k < 31; ++k) { - InstructionSelectorTester m; - m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmAdd, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); - } - // (2^k + 1) * x -> (x >> k) + x - for (int k = 1; k < 31; ++k) { - InstructionSelectorTester m; - m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmAdd, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); - } - // x * (2^k - 1) -> (x >> k) - x - for (int k = 3; k < 31; ++k) { - InstructionSelectorTester m; - m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmRsb, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); - } - // (2^k - 1) * x -> (x >> k) - x - for (int k = 3; k < 31; ++k) { - InstructionSelectorTester m; - m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmRsb, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); - } -} - - -TEST(InstructionSelectorWord32AndImm_ARMv7) { - for (uint32_t width = 1; width <= 32; ++width) { - InstructionSelectorTester m; - m.Return(m.Word32And(m.Parameter(0), - m.Int32Constant(0xffffffffu >> (32 - width)))); - m.SelectInstructions(ARMv7); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(0, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); - } - for (uint32_t lsb = 0; lsb <= 31; ++lsb) { - for (uint32_t width = 1; width < 32 - lsb; ++width) { - uint32_t msk = ~((0xffffffffu >> (32 - width)) << lsb); - InstructionSelectorTester m; - m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(msk))); - m.SelectInstructions(ARMv7); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmBfc, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK(UnallocatedOperand::cast(m.code[0]->Output()) - ->HasSameAsInputPolicy()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); - } - } -} - - -TEST(InstructionSelectorWord32AndAndWord32ShrImm_ARMv7) { - for (uint32_t lsb = 0; lsb <= 31; ++lsb) { - for (uint32_t width = 1; width <= 32 - lsb; ++width) { - { - InstructionSelectorTester m; - m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)), - m.Int32Constant(0xffffffffu >> (32 - width)))); - m.SelectInstructions(ARMv7); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); - } - { - InstructionSelectorTester m; - m.Return( - m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), - m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)))); - m.SelectInstructions(ARMv7); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); - } - } - } -} - - -TEST(InstructionSelectorWord32ShrAndWord32AndImm_ARMv7) { - for (uint32_t lsb = 0; lsb <= 31; ++lsb) { - for (uint32_t width = 1; width <= 32 - lsb; ++width) { - uint32_t max = 1 << lsb; - if (max > static_cast(kMaxInt)) max -= 1; - uint32_t jnk = CcTest::random_number_generator()->NextInt(max); - uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; - { - InstructionSelectorTester m; - m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)), - m.Int32Constant(lsb))); - m.SelectInstructions(ARMv7); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)), - m.Int32Constant(lsb))); - m.SelectInstructions(ARMv7); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); - CHECK_EQ(3, m.code[0]->InputCount()); - CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); - CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); - } - } - } -} - - -TEST(InstructionSelectorInt32SubAndInt32MulP) { - InstructionSelectorTester m; - m.Return( - m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); - m.SelectInstructions(); - CHECK_EQ(2, m.code.size()); - CHECK_EQ(kArmMul, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(kArmSub, m.code[1]->arch_opcode()); - CHECK_EQ(2, m.code[1]->InputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(1)); -} - - -TEST(InstructionSelectorInt32SubAndInt32MulP_MLS) { - InstructionSelectorTester m; - m.Return( - m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); - m.SelectInstructions(MLS); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmMls, m.code[0]->arch_opcode()); -} - - -TEST(InstructionSelectorInt32DivP) { - InstructionSelectorTester m; - m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(4, m.code.size()); - CHECK_EQ(kArmVcvtF64S32, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(kArmVcvtF64S32, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); - CHECK_EQ(2, m.code[2]->InputCount()); - CHECK_EQ(1, m.code[2]->OutputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); - CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); - CHECK_EQ(kArmVcvtS32F64, m.code[3]->arch_opcode()); - CHECK_EQ(1, m.code[3]->InputCount()); - CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); -} - - -TEST(InstructionSelectorInt32DivP_SUDIV) { - InstructionSelectorTester m; - m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(SUDIV); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode()); -} - - -TEST(InstructionSelectorInt32UDivP) { - InstructionSelectorTester m; - m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(4, m.code.size()); - CHECK_EQ(kArmVcvtF64U32, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(kArmVcvtF64U32, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); - CHECK_EQ(2, m.code[2]->InputCount()); - CHECK_EQ(1, m.code[2]->OutputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); - CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); - CHECK_EQ(kArmVcvtU32F64, m.code[3]->arch_opcode()); - CHECK_EQ(1, m.code[3]->InputCount()); - CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); -} - - -TEST(InstructionSelectorInt32UDivP_SUDIV) { - InstructionSelectorTester m; - m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(SUDIV); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode()); -} - - -TEST(InstructionSelectorInt32ModP) { - InstructionSelectorTester m; - m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(6, m.code.size()); - CHECK_EQ(kArmVcvtF64S32, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(kArmVcvtF64S32, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); - CHECK_EQ(2, m.code[2]->InputCount()); - CHECK_EQ(1, m.code[2]->OutputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); - CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); - CHECK_EQ(kArmVcvtS32F64, m.code[3]->arch_opcode()); - CHECK_EQ(1, m.code[3]->InputCount()); - CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); - CHECK_EQ(kArmMul, m.code[4]->arch_opcode()); - CHECK_EQ(1, m.code[4]->OutputCount()); - CHECK_EQ(2, m.code[4]->InputCount()); - CheckSameVreg(m.code[3]->Output(), m.code[4]->InputAt(0)); - CheckSameVreg(m.code[1]->InputAt(0), m.code[4]->InputAt(1)); - CHECK_EQ(kArmSub, m.code[5]->arch_opcode()); - CHECK_EQ(1, m.code[5]->OutputCount()); - CHECK_EQ(2, m.code[5]->InputCount()); - CheckSameVreg(m.code[0]->InputAt(0), m.code[5]->InputAt(0)); - CheckSameVreg(m.code[4]->Output(), m.code[5]->InputAt(1)); -} - - -TEST(InstructionSelectorInt32ModP_SUDIV) { - InstructionSelectorTester m; - m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(SUDIV); - CHECK_EQ(3, m.code.size()); - CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(kArmMul, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(2, m.code[1]->InputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); - CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); - CHECK_EQ(kArmSub, m.code[2]->arch_opcode()); - CHECK_EQ(1, m.code[2]->OutputCount()); - CHECK_EQ(2, m.code[2]->InputCount()); - CheckSameVreg(m.code[0]->InputAt(0), m.code[2]->InputAt(0)); - CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); -} - - -TEST(InstructionSelectorInt32ModP_MLS_SUDIV) { - InstructionSelectorTester m; - m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(MLS, SUDIV); - CHECK_EQ(2, m.code.size()); - CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(kArmMls, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(3, m.code[1]->InputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); - CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); - CheckSameVreg(m.code[0]->InputAt(0), m.code[1]->InputAt(2)); -} - - -TEST(InstructionSelectorInt32UModP) { - InstructionSelectorTester m; - m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(6, m.code.size()); - CHECK_EQ(kArmVcvtF64U32, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(kArmVcvtF64U32, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); - CHECK_EQ(2, m.code[2]->InputCount()); - CHECK_EQ(1, m.code[2]->OutputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); - CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); - CHECK_EQ(kArmVcvtU32F64, m.code[3]->arch_opcode()); - CHECK_EQ(1, m.code[3]->InputCount()); - CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); - CHECK_EQ(kArmMul, m.code[4]->arch_opcode()); - CHECK_EQ(1, m.code[4]->OutputCount()); - CHECK_EQ(2, m.code[4]->InputCount()); - CheckSameVreg(m.code[3]->Output(), m.code[4]->InputAt(0)); - CheckSameVreg(m.code[1]->InputAt(0), m.code[4]->InputAt(1)); - CHECK_EQ(kArmSub, m.code[5]->arch_opcode()); - CHECK_EQ(1, m.code[5]->OutputCount()); - CHECK_EQ(2, m.code[5]->InputCount()); - CheckSameVreg(m.code[0]->InputAt(0), m.code[5]->InputAt(0)); - CheckSameVreg(m.code[4]->Output(), m.code[5]->InputAt(1)); -} - - -TEST(InstructionSelectorInt32UModP_SUDIV) { - InstructionSelectorTester m; - m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(SUDIV); - CHECK_EQ(3, m.code.size()); - CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(kArmMul, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(2, m.code[1]->InputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); - CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); - CHECK_EQ(kArmSub, m.code[2]->arch_opcode()); - CHECK_EQ(1, m.code[2]->OutputCount()); - CHECK_EQ(2, m.code[2]->InputCount()); - CheckSameVreg(m.code[0]->InputAt(0), m.code[2]->InputAt(0)); - CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); -} - - -TEST(InstructionSelectorInt32UModP_MLS_SUDIV) { - InstructionSelectorTester m; - m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(MLS, SUDIV); - CHECK_EQ(2, m.code.size()); - CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(kArmMls, m.code[1]->arch_opcode()); - CHECK_EQ(1, m.code[1]->OutputCount()); - CHECK_EQ(3, m.code[1]->InputCount()); - CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); - CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); - CheckSameVreg(m.code[0]->InputAt(0), m.code[1]->InputAt(2)); -} - - -TEST(InstructionSelectorWord32EqualP) { - InstructionSelectorTester m; - m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); -} - - -TEST(InstructionSelectorWord32EqualImm) { - Immediates immediates; - for (Immediates::const_iterator i = immediates.begin(); i != immediates.end(); - ++i) { - int32_t imm = *i; - { - InstructionSelectorTester m; - m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - if (imm == 0) { - CHECK_EQ(kArmTst, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CheckSameVreg(m.code[0]->InputAt(0), m.code[0]->InputAt(1)); - } else { - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - } - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - if (imm == 0) { - CHECK_EQ(kArmTst, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CheckSameVreg(m.code[0]->InputAt(0), m.code[0]->InputAt(1)); - } else { - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - } - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } -} - - -TEST(InstructionSelectorWord32EqualAndDPIP) { - DPIs dpis; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - { - InstructionSelectorTester m; - m.Return(m.Word32Equal(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), - m.Int32Constant(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - m.Return( - m.Word32Equal(m.Int32Constant(0), - m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } -} - - -TEST(InstructionSelectorWord32EqualAndDPIImm) { - DPIs dpis; - Immediates immediates; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - for (Immediates::const_iterator j = immediates.begin(); - j != immediates.end(); ++j) { - int32_t imm = *j; - { - InstructionSelectorTester m; - m.Return(m.Word32Equal( - m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm)), - m.Int32Constant(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Equal( - m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0)), - m.Int32Constant(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Equal( - m.Int32Constant(0), - m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Equal( - m.Int32Constant(0), - m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } - } -} - - -TEST(InstructionSelectorWord32EqualAndShiftP) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - { - InstructionSelectorTester m; - m.Return(m.Word32Equal( - m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - m.Return(m.Word32Equal( - m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), m.Parameter(2))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } -} - - -TEST(InstructionSelectorBranchWithWord32EqualAndShiftP) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch(m.Word32Equal(m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), - m.Parameter(2))), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch( - m.Word32Equal(m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)), - m.Parameter(0)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } -} - - -TEST(InstructionSelectorBranchWithWord32EqualAndShiftImm) { - Shifts shifts; - for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { - Shift shift = *i; - for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch( - m.Word32Equal(m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), - m.Int32Constant(imm))), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch(m.Word32Equal( - m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)), - m.Parameter(0)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } - } -} - - -TEST(InstructionSelectorBranchWithWord32EqualAndRotateRightP) { - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = - m.Word32Or(m.Word32Shr(value, shift), - m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); - m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = - m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), - m.Word32Shr(value, shift)); - m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = - m.Word32Or(m.Word32Shr(value, shift), - m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); - m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* shift = m.Parameter(2); - Node* ror = - m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), - m.Word32Shr(value, shift)); - m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } -} - - -TEST(InstructionSelectorBranchWithWord32EqualAndRotateRightImm) { - FOR_INPUTS(uint32_t, ror, i) { - uint32_t shift = *i; - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* ror = m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)), - m.Word32Shl(value, m.Int32Constant(32 - shift))); - m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - CHECK_LE(3, m.code[0]->InputCount()); - CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* ror = m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)), - m.Word32Shr(value, m.Int32Constant(shift))); - m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - CHECK_LE(3, m.code[0]->InputCount()); - CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* ror = m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)), - m.Word32Shl(value, m.Int32Constant(32 - shift))); - m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - CHECK_LE(3, m.code[0]->InputCount()); - CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* input = m.Parameter(0); - Node* value = m.Parameter(1); - Node* ror = m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)), - m.Word32Shr(value, m.Int32Constant(shift))); - m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - CHECK_LE(3, m.code[0]->InputCount()); - CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); - } - } -} - - -TEST(InstructionSelectorBranchWithDPIP) { - DPIs dpis; - for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { - DPI dpi = *i; - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), &blocka, - &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kNotEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch(m.Word32Equal(m.Int32Constant(0), - m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - m.Branch(m.Word32Equal(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), - m.Int32Constant(0)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(1)); - m.Bind(&blockb); - m.Return(m.Int32Constant(0)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kEqual, m.code[0]->flags_condition()); - } - } -} - - -TEST(InstructionSelectorBranchWithODPIP) { - ODPIs odpis; - for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { - ODPI odpi = *i; - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); - m.Branch(m.Projection(1, node), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); - m.Branch(m.Word32Equal(m.Projection(1, node), m.Int32Constant(0)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); - m.Branch(m.Word32Equal(m.Int32Constant(0), m.Projection(1, node)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); - } - } -} - - -TEST(InstructionSelectorBranchWithODPIImm) { - ODPIs odpis; - Immediates immediates; - for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { - ODPI odpi = *i; - for (Immediates::const_iterator j = immediates.begin(); - j != immediates.end(); ++j) { - int32_t imm = *j; - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); - m.Branch(m.Projection(1, node), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_LE(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); - m.Branch(m.Projection(1, node), &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kOverflow, m.code[0]->flags_condition()); - CHECK_LE(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); - m.Branch(m.Word32Equal(m.Projection(1, node), m.Int32Constant(0)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); - CHECK_LE(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - { - InstructionSelectorTester m; - MLabel blocka, blockb; - Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); - m.Branch(m.Word32Equal(m.Projection(1, node), m.Int32Constant(0)), - &blocka, &blockb); - m.Bind(&blocka); - m.Return(m.Int32Constant(0)); - m.Bind(&blockb); - m.Return(m.Projection(0, node)); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); - CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); - CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); - CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); - CHECK_LE(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - } - } -} diff --git a/test/cctest/compiler/test-instruction-selector-arm64.cc b/test/cctest/compiler/test-instruction-selector-arm64.cc deleted file mode 100644 index 095064a..0000000 --- a/test/cctest/compiler/test-instruction-selector-arm64.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "test/cctest/compiler/instruction-selector-tester.h" - -using namespace v8::internal; -using namespace v8::internal::compiler; - -namespace { - -struct DPI { - Operator* op; - ArchOpcode arch_opcode; -}; - - -// ARM64 Logical instructions. -class LogicalInstructions V8_FINAL : public std::list, - private HandleAndZoneScope { - public: - LogicalInstructions() { - MachineOperatorBuilder machine(main_zone()); - DPI and32 = {machine.Word32And(), kArm64And32}; - push_back(and32); - DPI and64 = {machine.Word64And(), kArm64And}; - push_back(and64); - DPI or32 = {machine.Word32Or(), kArm64Or32}; - push_back(or32); - DPI or64 = {machine.Word64Or(), kArm64Or}; - push_back(or64); - DPI xor32 = {machine.Word32Xor(), kArm64Xor32}; - push_back(xor32); - DPI xor64 = {machine.Word64Xor(), kArm64Xor}; - push_back(xor64); - } -}; - - -// ARM64 Arithmetic instructions. -class AddSubInstructions V8_FINAL : public std::list, - private HandleAndZoneScope { - public: - AddSubInstructions() { - MachineOperatorBuilder machine(main_zone()); - DPI add32 = {machine.Int32Add(), kArm64Add32}; - push_back(add32); - DPI add64 = {machine.Int64Add(), kArm64Add}; - push_back(add64); - DPI sub32 = {machine.Int32Sub(), kArm64Sub32}; - push_back(sub32); - DPI sub64 = {machine.Int64Sub(), kArm64Sub}; - push_back(sub64); - } -}; - - -// ARM64 Add/Sub immediates. -class AddSubImmediates V8_FINAL : public std::list { - public: - AddSubImmediates() { - for (int32_t imm12 = 0; imm12 < 4096; ++imm12) { - CHECK(Assembler::IsImmAddSub(imm12)); - CHECK(Assembler::IsImmAddSub(imm12 << 12)); - push_back(imm12); - push_back(imm12 << 12); - } - } -}; - - -// ARM64 Arithmetic instructions. -class MulDivInstructions V8_FINAL : public std::list, - private HandleAndZoneScope { - public: - MulDivInstructions() { - MachineOperatorBuilder machine(main_zone()); - DPI mul32 = {machine.Int32Mul(), kArm64Mul32}; - push_back(mul32); - DPI mul64 = {machine.Int64Mul(), kArm64Mul}; - push_back(mul64); - DPI sdiv32 = {machine.Int32Div(), kArm64Idiv32}; - push_back(sdiv32); - DPI sdiv64 = {machine.Int64Div(), kArm64Idiv}; - push_back(sdiv64); - DPI udiv32 = {machine.Int32UDiv(), kArm64Udiv32}; - push_back(udiv32); - DPI udiv64 = {machine.Int64UDiv(), kArm64Udiv}; - push_back(udiv64); - } -}; - -} // namespace - - -TEST(InstructionSelectorLogicalP) { - LogicalInstructions instructions; - for (LogicalInstructions::const_iterator i = instructions.begin(); - i != instructions.end(); ++i) { - DPI dpi = *i; - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - } -} - - -TEST(InstructionSelectorAddSubP) { - AddSubInstructions instructions; - for (AddSubInstructions::const_iterator i = instructions.begin(); - i != instructions.end(); ++i) { - DPI dpi = *i; - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - } -} - - -TEST(InstructionSelectorAddSubImm) { - AddSubInstructions instructions; - AddSubImmediates immediates; - for (AddSubInstructions::const_iterator i = instructions.begin(); - i != instructions.end(); ++i) { - DPI dpi = *i; - for (AddSubImmediates::const_iterator j = immediates.begin(); - j != immediates.end(); ++j) { - int32_t imm = *j; - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - CHECK(m.code[0]->InputAt(1)->IsImmediate()); - } - } -} - - -TEST(InstructionSelectorMulDivP) { - MulDivInstructions instructions; - for (MulDivInstructions::const_iterator i = instructions.begin(); - i != instructions.end(); ++i) { - DPI dpi = *i; - InstructionSelectorTester m; - m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); - } -} diff --git a/test/cctest/compiler/test-instruction-selector-ia32.cc b/test/cctest/compiler/test-instruction-selector-ia32.cc deleted file mode 100644 index b650958..0000000 --- a/test/cctest/compiler/test-instruction-selector-ia32.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "test/cctest/compiler/instruction-selector-tester.h" -#include "test/cctest/compiler/value-helper.h" - -using namespace v8::internal; -using namespace v8::internal::compiler; - -TEST(InstructionSelectorInt32AddP) { - InstructionSelectorTester m; - m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kIA32Add, m.code[0]->arch_opcode()); -} - - -TEST(InstructionSelectorInt32AddImm) { - FOR_INT32_INPUTS(i) { - int32_t imm = *i; - { - InstructionSelectorTester m; - m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kIA32Add, m.code[0]->arch_opcode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - { - InstructionSelectorTester m; - m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kIA32Add, m.code[0]->arch_opcode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } - } -} - - -TEST(InstructionSelectorInt32SubP) { - InstructionSelectorTester m; - m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kIA32Sub, m.code[0]->arch_opcode()); - CHECK_EQ(1, m.code[0]->OutputCount()); -} - - -TEST(InstructionSelectorInt32SubImm) { - FOR_INT32_INPUTS(i) { - int32_t imm = *i; - InstructionSelectorTester m; - m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm))); - m.SelectInstructions(); - CHECK_EQ(1, m.code.size()); - CHECK_EQ(kIA32Sub, m.code[0]->arch_opcode()); - CHECK_EQ(2, m.code[0]->InputCount()); - CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); - } -} diff --git a/test/cctest/compiler/test-instruction-selector.cc b/test/cctest/compiler/test-instruction-selector.cc deleted file mode 100644 index e594064..0000000 --- a/test/cctest/compiler/test-instruction-selector.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "test/cctest/compiler/instruction-selector-tester.h" - -using namespace v8::internal; -using namespace v8::internal::compiler; - -#if V8_TURBOFAN_TARGET - -TEST(InstructionSelectionReturnZero) { - InstructionSelectorTester m; - m.Return(m.Int32Constant(0)); - m.SelectInstructions(InstructionSelectorTester::kInternalMode); - CHECK_EQ(2, static_cast(m.code.size())); - CHECK_EQ(kArchNop, m.code[0]->opcode()); - CHECK_EQ(kArchRet, m.code[1]->opcode()); - CHECK_EQ(1, static_cast(m.code[1]->InputCount())); -} - -#endif // !V8_TURBOFAN_TARGET diff --git a/test/compiler-unittests/DEPS b/test/compiler-unittests/DEPS index 8aa0239..0dd664e 100644 --- a/test/compiler-unittests/DEPS +++ b/test/compiler-unittests/DEPS @@ -1,6 +1,6 @@ include_rules = [ "+src", "+testing/gtest", - "+testing/gtest-type-names.h", + "+testing/gtest-support.h", "+testing/gmock", ] diff --git a/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc b/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc index b781ac8..7db1d6e 100644 --- a/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc +++ b/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc @@ -8,20 +8,1723 @@ namespace v8 { namespace internal { namespace compiler { -class InstructionSelectorARMTest : public InstructionSelectorTest {}; +namespace { +typedef RawMachineAssembler::Label MLabel; +typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*); -TARGET_TEST_F(InstructionSelectorARMTest, Int32AddP) { + +// Data processing instructions. +struct DPI { + Constructor constructor; + const char* constructor_name; + ArchOpcode arch_opcode; + ArchOpcode reverse_arch_opcode; + ArchOpcode test_arch_opcode; +}; + + +std::ostream& operator<<(std::ostream& os, const DPI& dpi) { + return os << dpi.constructor_name; +} + + +static const DPI kDPIs[] = { + {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmAnd, kArmTst}, + {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr, kArmOrr}, + {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmEor, kArmTeq}, + {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmAdd, kArmCmn}, + {&RawMachineAssembler::Int32Sub, "Int32Sub", kArmSub, kArmRsb, kArmCmp}}; + + +// Data processing instructions with overflow. +struct ODPI { + Constructor constructor; + const char* constructor_name; + ArchOpcode arch_opcode; + ArchOpcode reverse_arch_opcode; +}; + + +std::ostream& operator<<(std::ostream& os, const ODPI& odpi) { + return os << odpi.constructor_name; +} + + +static const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow, + "Int32AddWithOverflow", kArmAdd, kArmAdd}, + {&RawMachineAssembler::Int32SubWithOverflow, + "Int32SubWithOverflow", kArmSub, kArmRsb}}; + + +// Shifts. +struct Shift { + Constructor constructor; + const char* constructor_name; + int32_t i_low; // lowest possible immediate + int32_t i_high; // highest possible immediate + AddressingMode i_mode; // Operand2_R__I + AddressingMode r_mode; // Operand2_R__R +}; + + +std::ostream& operator<<(std::ostream& os, const Shift& shift) { + return os << shift.constructor_name; +} + + +static const Shift kShifts[] = { + {&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32, + kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R}, + {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31, + kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R}, + {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32, + kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R}, + {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31, + kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}}; + + +// Immediates (random subset). +static const int32_t kImmediates[] = { + -2147483617, -2147483606, -2113929216, -2080374784, -1996488704, + -1879048192, -1459617792, -1358954496, -1342177265, -1275068414, + -1073741818, -1073741777, -855638016, -805306368, -402653184, + -268435444, -16777216, 0, 35, 61, + 105, 116, 171, 245, 255, + 692, 1216, 1248, 1520, 1600, + 1888, 3744, 4080, 5888, 8384, + 9344, 9472, 9792, 13312, 15040, + 15360, 20736, 22272, 23296, 32000, + 33536, 37120, 45824, 47872, 56320, + 59392, 65280, 72704, 101376, 147456, + 161792, 164864, 167936, 173056, 195584, + 209920, 212992, 356352, 655360, 704512, + 716800, 851968, 901120, 1044480, 1523712, + 2572288, 3211264, 3588096, 3833856, 3866624, + 4325376, 5177344, 6488064, 7012352, 7471104, + 14090240, 16711680, 19398656, 22282240, 28573696, + 30408704, 30670848, 43253760, 54525952, 55312384, + 56623104, 68157440, 115343360, 131072000, 187695104, + 188743680, 195035136, 197132288, 203423744, 218103808, + 267386880, 268435470, 285212672, 402653185, 415236096, + 595591168, 603979776, 603979778, 629145600, 1073741835, + 1073741855, 1073741861, 1073741884, 1157627904, 1476395008, + 1476395010, 1610612741, 2030043136, 2080374785, 2097152000}; + +} // namespace + + +// ----------------------------------------------------------------------------- +// Data processing instructions. + + +typedef InstructionSelectorTestWithParam InstructionSelectorDPITest; + + +TEST_P(InstructionSelectorDPITest, Parameters) { + const DPI dpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorDPITest, Immediate) { + const DPI dpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorDPITest, ShiftByParameter) { + const DPI dpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return((m.*dpi.constructor)( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return((m.*dpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorDPITest, ShiftByImmediate) { + const DPI dpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + } + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + } +} + + +TEST_P(InstructionSelectorDPITest, BranchWithParameters) { + const DPI dpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorDPITest, BranchWithImmediate) { + const DPI dpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), &a, + &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), &a, + &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorDPITest, BranchWithShiftByParameter) { + const DPI dpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), + m.Parameter(2)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorDPITest, BranchWithShiftByImmediate) { + const DPI dpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)(m.Parameter(0), + (m.*shift.constructor)( + m.Parameter(1), m.Int32Constant(imm))), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(5U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } + } + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch((m.*dpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)), + m.Parameter(1)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(5U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } + } +} + + +TEST_P(InstructionSelectorDPITest, BranchIfZeroWithParameters) { + const DPI dpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch(m.Word32Equal((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), + m.Int32Constant(0)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithParameters) { + const DPI dpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch( + m.Word32NotEqual((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), + m.Int32Constant(0)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorDPITest, BranchIfZeroWithImmediate) { + const DPI dpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch(m.Word32Equal( + (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), + m.Int32Constant(0)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch(m.Word32Equal( + (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), + m.Int32Constant(0)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithImmediate) { + const DPI dpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch(m.Word32NotEqual( + (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), + m.Int32Constant(0)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + m.Branch(m.Word32NotEqual( + (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), + m.Int32Constant(0)), + &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(1)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotEqual, s[0]->flags_condition()); + } +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest, + ::testing::ValuesIn(kDPIs)); + + +// ----------------------------------------------------------------------------- +// Data processing instructions with overflow. + + +typedef InstructionSelectorTestWithParam InstructionSelectorODPITest; + + +TEST_P(InstructionSelectorODPITest, OvfWithParameters) { + const ODPI odpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return( + m.Projection(1, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorODPITest, OvfWithImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 1, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 1, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorODPITest, OvfWithShiftByParameter) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Projection( + 1, (m.*odpi.constructor)( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Projection( + 1, (m.*odpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), + m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorODPITest, OvfWithShiftByImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 1, (m.*odpi.constructor)(m.Parameter(0), + (m.*shift.constructor)( + m.Parameter(1), m.Int32Constant(imm))))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + } + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 1, (m.*odpi.constructor)( + (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)), + m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + } +} + + +TEST_P(InstructionSelectorODPITest, ValWithParameters) { + const ODPI odpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return( + m.Projection(0, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); +} + + +TEST_P(InstructionSelectorODPITest, ValWithImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 0, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 0, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } +} + + +TEST_P(InstructionSelectorODPITest, ValWithShiftByParameter) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Projection( + 0, (m.*odpi.constructor)( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Projection( + 0, (m.*odpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), + m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } +} + + +TEST_P(InstructionSelectorODPITest, ValWithShiftByImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 0, (m.*odpi.constructor)(m.Parameter(0), + (m.*shift.constructor)( + m.Parameter(1), m.Int32Constant(imm))))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + } + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Projection( + 0, (m.*odpi.constructor)( + (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)), + m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_LE(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + } +} + + +TEST_P(InstructionSelectorODPITest, BothWithParameters) { + const ODPI odpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1)); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorODPITest, BothWithImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0)); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorODPITest, BothWithShiftByParameter) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + Node* n = (m.*odpi.constructor)( + m.Parameter(0), (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + TRACED_FOREACH(Shift, shift, kShifts) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + Node* n = (m.*odpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), m.Parameter(2)); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorODPITest, BothWithShiftByImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + Node* n = (m.*odpi.constructor)( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + } + TRACED_FOREACH(Shift, shift, kShifts) { + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + Node* n = (m.*odpi.constructor)( + (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)), + m.Parameter(1)); + m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); + Stream s = m.Build(); + ASSERT_LE(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(2U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + } +} + + +TEST_P(InstructionSelectorODPITest, BranchWithParameters) { + const ODPI odpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1)); + m.Branch(m.Projection(1, n), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(0)); + m.Bind(&b); + m.Return(m.Projection(0, n)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(4U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorODPITest, BranchWithImmediate) { + const ODPI odpi = GetParam(); + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); + m.Branch(m.Projection(1, n), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(0)); + m.Bind(&b); + m.Return(m.Projection(0, n)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(4U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + MLabel a, b; + Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0)); + m.Branch(m.Projection(1, n), &a, &b); + m.Bind(&a); + m.Return(m.Int32Constant(0)); + m.Bind(&b); + m.Return(m.Projection(0, n)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(4U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorODPITest, BranchIfZeroWithParameters) { + const ODPI odpi = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + MLabel a, b; + Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1)); + m.Branch(m.Word32Equal(m.Projection(1, n), m.Int32Constant(0)), &a, &b); + m.Bind(&a); + m.Return(m.Projection(0, n)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(4U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kNotOverflow, s[0]->flags_condition()); +} + + +TEST_P(InstructionSelectorODPITest, BranchIfNotZeroWithParameters) { + const ODPI odpi = GetParam(); StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); - m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1))); + MLabel a, b; + Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1)); + m.Branch(m.Word32NotEqual(m.Projection(1, n), m.Int32Constant(0)), &a, &b); + m.Bind(&a); + m.Return(m.Projection(0, n)); + m.Bind(&b); + m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArmAdd, s[0]->arch_opcode()); + EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode()); EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(4U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); + EXPECT_EQ(kOverflow, s[0]->flags_condition()); +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorODPITest, + ::testing::ValuesIn(kODPIs)); + + +// ----------------------------------------------------------------------------- +// Shifts. + + +typedef InstructionSelectorTestWithParam InstructionSelectorShiftTest; + + +TEST_P(InstructionSelectorShiftTest, Parameters) { + const Shift shift = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*shift.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMov, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); EXPECT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(1U, s[0]->OutputCount()); } + +TEST_P(InstructionSelectorShiftTest, Immediate) { + const Shift shift = GetParam(); + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return((m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMov, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameter) { + const Shift shift = GetParam(); + { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Word32Equal(m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } + { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Word32Equal((m.*shift.constructor)(m.Parameter(1), m.Parameter(2)), + m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameterAndImmediate) { + const Shift shift = GetParam(); + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal( + (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)), + m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal( + m.Parameter(0), + (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } +} + + +TEST_P(InstructionSelectorShiftTest, Word32NotWithParameters) { + const Shift shift = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32Not((m.*shift.constructor)(m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMvn, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorShiftTest, Word32NotWithImmediate) { + const Shift shift = GetParam(); + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Not( + (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMvn, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithParameters) { + const Shift shift = GetParam(); + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32And(m.Parameter(0), m.Word32Not((m.*shift.constructor)( + m.Parameter(1), m.Parameter(2))))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmBic, s[0]->arch_opcode()); + EXPECT_EQ(shift.r_mode, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithImmediate) { + const Shift shift = GetParam(); + TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Parameter(0), + m.Word32Not((m.*shift.constructor)( + m.Parameter(1), m.Int32Constant(imm))))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmBic, s[0]->arch_opcode()); + EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest, + ::testing::ValuesIn(kShifts)); + + +// ----------------------------------------------------------------------------- +// Miscellaneous. + + +TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) { + { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMla, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Add(m.Int32Mul(m.Parameter(1), m.Parameter(2)), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMla, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, Int32DivWithParameters) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(4U, s.size()); + EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode()); + ASSERT_EQ(2U, s[2]->InputCount()); + ASSERT_EQ(1U, s[2]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1))); + EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode()); + ASSERT_EQ(1U, s[3]->InputCount()); + EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0))); +} + + +TEST_F(InstructionSelectorTest, Int32DivWithParametersForSUDIV) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(SUDIV); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmSdiv, s[0]->arch_opcode()); +} + + +TEST_F(InstructionSelectorTest, Int32ModWithParameters) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(6U, s.size()); + EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode()); + ASSERT_EQ(2U, s[2]->InputCount()); + ASSERT_EQ(1U, s[2]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1))); + EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode()); + ASSERT_EQ(1U, s[3]->InputCount()); + EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0))); + EXPECT_EQ(kArmMul, s[4]->arch_opcode()); + ASSERT_EQ(1U, s[4]->OutputCount()); + ASSERT_EQ(2U, s[4]->InputCount()); + EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1))); + EXPECT_EQ(kArmSub, s[5]->arch_opcode()); + ASSERT_EQ(1U, s[5]->OutputCount()); + ASSERT_EQ(2U, s[5]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1))); +} + + +TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIV) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(SUDIV); + ASSERT_EQ(3U, s.size()); + EXPECT_EQ(kArmSdiv, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(kArmMul, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + ASSERT_EQ(2U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1))); + EXPECT_EQ(kArmSub, s[2]->arch_opcode()); + ASSERT_EQ(1U, s[2]->OutputCount()); + ASSERT_EQ(2U, s[2]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1))); +} + + +TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIVAndMLS) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(MLS, SUDIV); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArmSdiv, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(kArmMls, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + ASSERT_EQ(3U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2))); +} + + +TEST_F(InstructionSelectorTest, Int32MulWithParameters) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMul, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_F(InstructionSelectorTest, Int32MulWithImmediate) { + // x * (2^k + 1) -> x + (x >> k) + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmAdd, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // x * (2^k - 1) -> -x + (x >> k) + TRACED_FORRANGE(int32_t, k, 3, 30) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmRsb, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // (2^k + 1) * x -> x + (x >> k) + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmAdd, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // x * (2^k - 1) -> -x + (x >> k) + TRACED_FORRANGE(int32_t, k, 3, 30) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmRsb, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArmMul, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArmSub, s[1]->arch_opcode()); + ASSERT_EQ(2U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1))); +} + + +TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + Stream s = m.Build(MLS); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMls, s[0]->arch_opcode()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(3U, s[0]->InputCount()); +} + + +TEST_F(InstructionSelectorTest, Int32UDivWithParameters) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(4U, s.size()); + EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode()); + ASSERT_EQ(2U, s[2]->InputCount()); + ASSERT_EQ(1U, s[2]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1))); + EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode()); + ASSERT_EQ(1U, s[3]->InputCount()); + EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0))); +} + + +TEST_F(InstructionSelectorTest, Int32UDivWithParametersForSUDIV) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(SUDIV); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUdiv, s[0]->arch_opcode()); +} + + +TEST_F(InstructionSelectorTest, Int32UModWithParameters) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(6U, s.size()); + EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode()); + ASSERT_EQ(2U, s[2]->InputCount()); + ASSERT_EQ(1U, s[2]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1))); + EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode()); + ASSERT_EQ(1U, s[3]->InputCount()); + EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0))); + EXPECT_EQ(kArmMul, s[4]->arch_opcode()); + ASSERT_EQ(1U, s[4]->OutputCount()); + ASSERT_EQ(2U, s[4]->InputCount()); + EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1))); + EXPECT_EQ(kArmSub, s[5]->arch_opcode()); + ASSERT_EQ(1U, s[5]->OutputCount()); + ASSERT_EQ(2U, s[5]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1))); +} + + +TEST_F(InstructionSelectorTest, Int32UModWithParametersForSUDIV) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(SUDIV); + ASSERT_EQ(3U, s.size()); + EXPECT_EQ(kArmUdiv, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(kArmMul, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + ASSERT_EQ(2U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1))); + EXPECT_EQ(kArmSub, s[2]->arch_opcode()); + ASSERT_EQ(1U, s[2]->OutputCount()); + ASSERT_EQ(2U, s[2]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1))); +} + + +TEST_F(InstructionSelectorTest, Int32UModWithParametersForSUDIVAndMLS) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(MLS, SUDIV); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArmUdiv, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(kArmMls, s[1]->arch_opcode()); + ASSERT_EQ(1U, s[1]->OutputCount()); + ASSERT_EQ(3U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2))); +} + + +TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { + TRACED_FORRANGE(int32_t, width, 1, 32) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Parameter(0), + m.Int32Constant(0xffffffffu >> (32 - width)))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + TRACED_FORRANGE(int32_t, width, 1, 32) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), + m.Parameter(0))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } +} + + +TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) { + TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, width, 1, (32 - lsb) - 1) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32And( + m.Parameter(0), + m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmBfc, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + } + TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, width, 1, (32 - lsb) - 1) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return( + m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)), + m.Parameter(0))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmBfc, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE( + UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + } +} + + +TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) { + TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + uint32_t max = 1 << lsb; + if (max > static_cast(kMaxInt)) max -= 1; + uint32_t jnk = rng()->NextInt(max); + uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)), + m.Int32Constant(lsb))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + } + TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + uint32_t max = 1 << lsb; + if (max > static_cast(kMaxInt)) max -= 1; + uint32_t jnk = rng()->NextInt(max); + uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)), + m.Int32Constant(lsb))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + } +} + + +TEST_F(InstructionSelectorTest, Word32AndWithWord32Not) { + { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Parameter(0), m.Word32Not(m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmBic, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Word32Not(m.Parameter(0)), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmBic, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithParameters) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithImmediate) { + TRACED_FOREACH(int32_t, imm, kImmediates) { + if (imm == 0) continue; + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } + TRACED_FOREACH(int32_t, imm, kImmediates) { + if (imm == 0) continue; + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithZero) { + { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmTst, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } + { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmTst, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kEqual, s[0]->flags_condition()); + } +} + + +TEST_F(InstructionSelectorTest, Word32NotWithParameter) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32Not(m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmMvn, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + EXPECT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { + TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)), + m.Int32Constant(0xffffffffu >> (32 - width)))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + } + TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), + m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); + } + } +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc b/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc new file mode 100644 index 0000000..68f0b9f --- /dev/null +++ b/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc @@ -0,0 +1,133 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "test/compiler-unittests/instruction-selector-unittest.h" + +#include "test/cctest/compiler/instruction-selector-tester.h" + +namespace v8 { +namespace internal { +namespace compiler { + +namespace { + +typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*); + +struct DPI { + Constructor constructor; + const char* constructor_name; + ArchOpcode arch_opcode; +}; + + +std::ostream& operator<<(std::ostream& os, const DPI& dpi) { + return os << dpi.constructor_name; +} + + +// ARM64 Logical instructions. +static const DPI kLogicalInstructions[] = { + {&RawMachineAssembler::Word32And, "Word32And", kArm64And32}, + {&RawMachineAssembler::Word64And, "Word64And", kArm64And}, + {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32}, + {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or}, + {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Xor32}, + {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Xor}}; + + +// ARM64 Arithmetic instructions. +static const DPI kAddSubInstructions[] = { + {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32}, + {&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add}, + {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32}, + {&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub}}; + + +// ARM64 Add/Sub immediates. +// TODO(all): Test only a subset of the immediates, similar to what we do for +// arm. Unit tests should be really fast! +class AddSubImmediates V8_FINAL : public std::list { + public: + AddSubImmediates() { + for (int32_t imm12 = 0; imm12 < 4096; ++imm12) { + CHECK(Assembler::IsImmAddSub(imm12)); + CHECK(Assembler::IsImmAddSub(imm12 << 12)); + push_back(imm12); + push_back(imm12 << 12); + } + } +}; + + +// ARM64 Mul/Div instructions. +static const DPI kMulDivInstructions[] = { + {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32}, + {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul}, + {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32}, + {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv}, + {&RawMachineAssembler::Int32UDiv, "Int32UDiv", kArm64Udiv32}, + {&RawMachineAssembler::Int64UDiv, "Int64UDiv", kArm64Udiv}}; + +} // namespace + + +// TODO(all): Use TEST_P, see instruction-selector-arm-unittest.cc. +TEST_F(InstructionSelectorTest, LogicalWithParameter) { + TRACED_FOREACH(DPI, dpi, kLogicalInstructions) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + } +} + + +// TODO(all): Use TEST_P, see instruction-selector-arm-unittest.cc. +TEST_F(InstructionSelectorTest, AddSubWithParameter) { + TRACED_FOREACH(DPI, dpi, kAddSubInstructions) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + } +} + + +// TODO(all): Use TEST_P, see instruction-selector-arm-unittest.cc. +TEST_F(InstructionSelectorTest, AddSubWithImmediate) { + AddSubImmediates immediates; + TRACED_FOREACH(DPI, dpi, kAddSubInstructions) { + for (AddSubImmediates::const_iterator j = immediates.begin(); + j != immediates.end(); ++j) { + int32_t imm = *j; + SCOPED_TRACE(::testing::Message() << "imm = " << imm); + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); + } + } +} + + +// TODO(all): Use TEST_P, see instruction-selector-arm-unittest.cc. +TEST_F(InstructionSelectorTest, MulDivWithParameter) { + TRACED_FOREACH(DPI, dpi, kMulDivInstructions) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); + } +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/test/compiler-unittests/change-lowering-unittest.cc b/test/compiler-unittests/change-lowering-unittest.cc index 68de480..96d29e2 100644 --- a/test/compiler-unittests/change-lowering-unittest.cc +++ b/test/compiler-unittests/change-lowering-unittest.cc @@ -10,7 +10,6 @@ #include "src/factory.h" #include "test/compiler-unittests/compiler-unittests.h" #include "test/compiler-unittests/node-matchers.h" -#include "testing/gtest-type-names.h" using testing::_; diff --git a/test/compiler-unittests/compiler-unittests.gyp b/test/compiler-unittests/compiler-unittests.gyp index c1de0c4..f257e54 100644 --- a/test/compiler-unittests/compiler-unittests.gyp +++ b/test/compiler-unittests/compiler-unittests.gyp @@ -32,6 +32,16 @@ 'arm/instruction-selector-arm-unittest.cc', ], }], + ['v8_target_arch=="arm64"', { + 'sources': [ ### gcmole(arch:arm64) ### + 'arm64/instruction-selector-arm64-unittest.cc', + ], + }], + ['v8_target_arch=="ia32"', { + 'sources': [ ### gcmole(arch:ia32) ### + 'ia32/instruction-selector-ia32-unittest.cc', + ], + }], ['component=="shared_library"', { # compiler-unittests can't be built against a shared library, so we # need to depend on the underlying static target in that case. diff --git a/test/compiler-unittests/compiler-unittests.h b/test/compiler-unittests/compiler-unittests.h index 091b137..f0955a6 100644 --- a/test/compiler-unittests/compiler-unittests.h +++ b/test/compiler-unittests/compiler-unittests.h @@ -7,7 +7,7 @@ #include "include/v8.h" #include "src/zone.h" -#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest-support.h" namespace v8 { namespace internal { diff --git a/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc b/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc new file mode 100644 index 0000000..bb53bd5 --- /dev/null +++ b/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc @@ -0,0 +1,78 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "test/compiler-unittests/instruction-selector-unittest.h" + +namespace v8 { +namespace internal { +namespace compiler { + +namespace { + +// Immediates (random subset). +static const int32_t kImmediates[] = { + kMinInt, -42, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt}; + +} // namespace + + +TEST_F(InstructionSelectorTest, Int32AddWithParameter) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32Add, s[0]->arch_opcode()); +} + + +TEST_F(InstructionSelectorTest, Int32AddWithImmediate) { + TRACED_FOREACH(int32_t, imm, kImmediates) { + { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32Add, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + } + { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32Add, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + } + } +} + + +TEST_F(InstructionSelectorTest, Int32SubWithParameter) { + StreamBuilder m(this, kMachineWord32, kMachineWord32, kMachineWord32); + m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32Sub, s[0]->arch_opcode()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_F(InstructionSelectorTest, Int32SubWithImmediate) { + TRACED_FOREACH(int32_t, imm, kImmediates) { + StreamBuilder m(this, kMachineWord32, kMachineWord32); + m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32Sub, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + } +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/test/compiler-unittests/instruction-selector-unittest.cc b/test/compiler-unittests/instruction-selector-unittest.cc index 7018652..725c431 100644 --- a/test/compiler-unittests/instruction-selector-unittest.cc +++ b/test/compiler-unittests/instruction-selector-unittest.cc @@ -4,14 +4,23 @@ #include "test/compiler-unittests/instruction-selector-unittest.h" +#include "src/flags.h" + namespace v8 { namespace internal { namespace compiler { +InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {} + + InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( InstructionSelector::Features features, InstructionSelectorTest::StreamBuilderMode mode) { Schedule* schedule = Export(); + if (FLAG_trace_turbo) { + OFStream out(stdout); + out << "=== Schedule before instruction selection ===" << endl << *schedule; + } EXPECT_NE(0, graph()->NodeCount()); CompilationInfo info(test_->isolate(), test_->zone()); Linkage linkage(&info, call_descriptor()); @@ -21,7 +30,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( selector.SelectInstructions(); if (FLAG_trace_turbo) { OFStream out(stdout); - out << "--- Code sequence after instruction selection ---" << endl + out << "=== Code sequence after instruction selection ===" << endl << sequence; } Stream s; @@ -62,7 +71,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( } -TARGET_TEST_F(InstructionSelectorTest, ReturnP) { +TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { StreamBuilder m(this, kMachineWord32, kMachineWord32); m.Return(m.Parameter(0)); Stream s = m.Build(kAllInstructions); @@ -74,7 +83,7 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnP) { } -TARGET_TEST_F(InstructionSelectorTest, ReturnImm) { +TARGET_TEST_F(InstructionSelectorTest, ReturnZero) { StreamBuilder m(this, kMachineWord32); m.Return(m.Int32Constant(0)); Stream s = m.Build(kAllInstructions); diff --git a/test/compiler-unittests/instruction-selector-unittest.h b/test/compiler-unittests/instruction-selector-unittest.h index 3a7b590..5a4273f 100644 --- a/test/compiler-unittests/instruction-selector-unittest.h +++ b/test/compiler-unittests/instruction-selector-unittest.h @@ -6,7 +6,9 @@ #define V8_COMPILER_UNITTESTS_INSTRUCTION_SELECTOR_UNITTEST_H_ #include +#include // NOLINT(readability/streams) +#include "src/base/utils/random-number-generator.h" #include "src/compiler/instruction-selector.h" #include "src/compiler/raw-machine-assembler.h" #include "test/compiler-unittests/compiler-unittests.h" @@ -17,9 +19,11 @@ namespace compiler { class InstructionSelectorTest : public CompilerTest { public: - InstructionSelectorTest() {} + InstructionSelectorTest(); virtual ~InstructionSelectorTest() {} + base::RandomNumberGenerator* rng() { return &rng_; } + protected: class Stream; @@ -44,6 +48,14 @@ class InstructionSelectorTest : public CompilerTest { CallDescriptorBuilder(test->zone(), return_type, parameter0_type, parameter1_type)), test_(test) {} + StreamBuilder(InstructionSelectorTest* test, MachineType return_type, + MachineType parameter0_type, MachineType parameter1_type, + MachineType parameter2_type) + : RawMachineAssembler( + new (test->zone()) Graph(test->zone()), + CallDescriptorBuilder(test->zone(), return_type, parameter0_type, + parameter1_type, parameter2_type)), + test_(test) {} Stream Build(CpuFeature feature) { return Build(InstructionSelector::Features(feature)); @@ -81,6 +93,17 @@ class InstructionSelectorTest : public CompilerTest { MachineCallDescriptorBuilder(return_type, 2, parameter_types); } + MachineCallDescriptorBuilder* CallDescriptorBuilder( + Zone* zone, MachineType return_type, MachineType parameter0_type, + MachineType parameter1_type, MachineType parameter2_type) { + MachineType* parameter_types = zone->NewArray(3); + parameter_types[0] = parameter0_type; + parameter_types[1] = parameter1_type; + parameter_types[2] = parameter2_type; + return new (zone) + MachineCallDescriptorBuilder(return_type, 3, parameter_types); + } + private: InstructionSelectorTest* test_; }; @@ -97,6 +120,11 @@ class InstructionSelectorTest : public CompilerTest { return ToConstant(operand).ToInt32(); } + int ToVreg(const InstructionOperand* operand) const { + EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind()); + return UnallocatedOperand::cast(operand)->virtual_register(); + } + private: Constant ToConstant(const InstructionOperand* operand) const { ConstantMap::const_iterator i; @@ -120,8 +148,16 @@ class InstructionSelectorTest : public CompilerTest { ConstantMap immediates_; std::deque instructions_; }; + + base::RandomNumberGenerator rng_; }; + +template +class InstructionSelectorTestWithParam + : public InstructionSelectorTest, + public ::testing::WithParamInterface {}; + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/testing/gtest-support.h b/testing/gtest-support.h new file mode 100644 index 0000000..de09c21 --- /dev/null +++ b/testing/gtest-support.h @@ -0,0 +1,58 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_TESTING_GTEST_SUPPORT_H_ +#define V8_TESTING_GTEST_SUPPORT_H_ + +#include "include/v8stdint.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace testing { +namespace internal { + +#define GET_TYPE_NAME(type) \ + template <> \ + inline std::string GetTypeName() { \ + return #type; \ + } +GET_TYPE_NAME(int8_t) +GET_TYPE_NAME(uint8_t) +GET_TYPE_NAME(int16_t) +GET_TYPE_NAME(uint16_t) +GET_TYPE_NAME(int32_t) +GET_TYPE_NAME(uint32_t) +GET_TYPE_NAME(int64_t) +GET_TYPE_NAME(uint64_t) +GET_TYPE_NAME(float) +GET_TYPE_NAME(double) +#undef GET_TYPE_NAME + + +// TRACED_FOREACH(type, var, array) expands to a loop that assigns |var| every +// item in the |array| and adds a SCOPED_TRACE() message for the |var| while +// inside the loop body. +// TODO(bmeurer): Migrate to C++11 once we're ready. +#define TRACED_FOREACH(_type, _var, _array) \ + for (size_t _i = 0; _i < ARRAY_SIZE(_array); ++_i) \ + for (bool _done = false; !_done;) \ + for (const _type _var = _array[_i]; !_done;) \ + for (SCOPED_TRACE(::testing::Message() << #_var << " = " << _var); \ + !_done; _done = true) + + +// TRACED_FORRANGE(type, var, low, high) expands to a loop that assigns |var| +// every value in the range |low| to (including) |high| and adds a +// SCOPED_TRACE() message for the |var| while inside the loop body. +// TODO(bmeurer): Migrate to C++11 once we're ready. +#define TRACED_FORRANGE(_type, _var, _low, _high) \ + for (_type _i = _low; _i <= _high; ++_i) \ + for (bool _done = false; !_done;) \ + for (const _type _var = _i; !_done;) \ + for (SCOPED_TRACE(::testing::Message() << #_var << " = " << _var); \ + !_done; _done = true) + +} // namespace internal +} // namespace testing + +#endif // V8_TESTING_GTEST_SUPPORT_H_ diff --git a/testing/gtest-type-names.h b/testing/gtest-type-names.h deleted file mode 100644 index ba900dd..0000000 --- a/testing/gtest-type-names.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_TESTING_GTEST_TYPE_NAMES_H_ -#define V8_TESTING_GTEST_TYPE_NAMES_H_ - -#include "include/v8stdint.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace testing { -namespace internal { - -#define GET_TYPE_NAME(type) \ - template <> \ - std::string GetTypeName() { \ - return #type; \ - } -GET_TYPE_NAME(int8_t) -GET_TYPE_NAME(uint8_t) -GET_TYPE_NAME(int16_t) -GET_TYPE_NAME(uint16_t) -GET_TYPE_NAME(int32_t) -GET_TYPE_NAME(uint32_t) -GET_TYPE_NAME(int64_t) -GET_TYPE_NAME(uint64_t) -GET_TYPE_NAME(float) -GET_TYPE_NAME(double) -#undef GET_TYPE_NAME - -} // namespace internal -} // namespace testing - -#endif // V8_TESTING_GTEST_TYPE_NAMES_H_ diff --git a/testing/gtest.gyp b/testing/gtest.gyp index 5d068d0..d766210 100644 --- a/testing/gtest.gyp +++ b/testing/gtest.gyp @@ -37,7 +37,7 @@ 'gtest/src/gtest-test-part.cc', 'gtest/src/gtest-typed-test.cc', 'gtest/src/gtest.cc', - 'gtest-type-names.h', + 'gtest-support.h', ], 'sources!': [ 'gtest/src/gtest-all.cc', # Not needed by our build. -- 2.7.4