diff options
Diffstat (limited to 'deps/v8/test/unittests/compiler')
10 files changed, 1827 insertions, 88 deletions
diff --git a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc index 44e3bb457b..bff5697b3f 100644 --- a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -44,11 +44,9 @@ Node* BuildConstant(InstructionSelectorTest::StreamBuilder* m, MachineType type, switch (type.representation()) { case MachineRepresentation::kWord32: return m->Int32Constant(static_cast<int32_t>(value)); - break; case MachineRepresentation::kWord64: return m->Int64Constant(value); - break; default: UNIMPLEMENTED(); @@ -2165,6 +2163,7 @@ struct SIMDMulDPInst { ArchOpcode multiply_add_arch_opcode; ArchOpcode multiply_sub_arch_opcode; MachineType machine_type; + const int lane_size; }; std::ostream& operator<<(std::ostream& os, const SIMDMulDPInst& inst) { @@ -2176,10 +2175,10 @@ std::ostream& operator<<(std::ostream& os, const SIMDMulDPInst& inst) { static const SIMDMulDPInst kSIMDMulDPInstructions[] = { {"I32x4Mul", &MachineOperatorBuilder::I32x4Mul, &MachineOperatorBuilder::I32x4Add, &MachineOperatorBuilder::I32x4Sub, - kArm64I32x4Mla, kArm64I32x4Mls, MachineType::Simd128()}, + kArm64Mla, kArm64Mls, MachineType::Simd128(), 32}, {"I16x8Mul", &MachineOperatorBuilder::I16x8Mul, &MachineOperatorBuilder::I16x8Add, &MachineOperatorBuilder::I16x8Sub, - kArm64I16x8Mla, kArm64I16x8Mls, MachineType::Simd128()}}; + kArm64Mla, kArm64Mls, MachineType::Simd128(), 16}}; using InstructionSelectorSIMDDPWithSIMDMulTest = InstructionSelectorTestWithParam<SIMDMulDPInst>; @@ -2195,6 +2194,7 @@ TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest, AddWithMul) { Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(1U, s[0]->OutputCount()); } @@ -2206,6 +2206,7 @@ TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest, AddWithMul) { Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(1U, s[0]->OutputCount()); } @@ -2222,6 +2223,7 @@ TEST_P(InstructionSelectorSIMDDPWithSIMDMulTest, SubWithMul) { Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(mdpi.multiply_sub_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(1U, s[0]->OutputCount()); } @@ -2231,6 +2233,178 @@ INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorSIMDDPWithSIMDMulTest, ::testing::ValuesIn(kSIMDMulDPInstructions)); +namespace { + +struct SIMDShrAddInst { + const char* shradd_constructor_name; + const Operator* (MachineOperatorBuilder::*shr_s_operator)(); + const Operator* (MachineOperatorBuilder::*shr_u_operator)(); + const Operator* (MachineOperatorBuilder::*add_operator)(); + const int laneSize; +}; + +std::ostream& operator<<(std::ostream& os, const SIMDShrAddInst& inst) { + return os << inst.shradd_constructor_name; +} + +} // namespace + +static const SIMDShrAddInst kSIMDShrAddInstructions[] = { + {"I64x2ShrAdd", &MachineOperatorBuilder::I64x2ShrS, + &MachineOperatorBuilder::I64x2ShrU, &MachineOperatorBuilder::I64x2Add, 64}, + {"I32x4ShrAdd", &MachineOperatorBuilder::I32x4ShrS, + &MachineOperatorBuilder::I32x4ShrU, &MachineOperatorBuilder::I32x4Add, 32}, + {"I16x8ShrAdd", &MachineOperatorBuilder::I16x8ShrS, + &MachineOperatorBuilder::I16x8ShrU, &MachineOperatorBuilder::I16x8Add, 16}, + {"I8x16ShrAdd", &MachineOperatorBuilder::I8x16ShrS, + &MachineOperatorBuilder::I8x16ShrU, &MachineOperatorBuilder::I8x16Add, 8}}; + +using InstructionSelectorSIMDShrAddTest = + InstructionSelectorTestWithParam<SIMDShrAddInst>; + +TEST_P(InstructionSelectorSIMDShrAddTest, ShrAddS) { + const SIMDShrAddInst param = GetParam(); + const MachineType type = MachineType::Simd128(); + { + StreamBuilder m(this, type, type, type); + Node* n = m.AddNode((m.machine()->*param.shr_s_operator)(), m.Parameter(1), + m.Int32Constant(1)); + m.Return( + m.AddNode((m.machine()->*param.add_operator)(), m.Parameter(0), n)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Ssra, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, type, type, type); + Node* n = m.AddNode((m.machine()->*param.shr_s_operator)(), m.Parameter(0), + m.Int32Constant(1)); + m.Return( + m.AddNode((m.machine()->*param.add_operator)(), n, m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Ssra, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_P(InstructionSelectorSIMDShrAddTest, ShrAddU) { + const SIMDShrAddInst param = GetParam(); + const MachineType type = MachineType::Simd128(); + { + StreamBuilder m(this, type, type, type); + Node* n = m.AddNode((m.machine()->*param.shr_u_operator)(), m.Parameter(1), + m.Int32Constant(1)); + m.Return( + m.AddNode((m.machine()->*param.add_operator)(), m.Parameter(0), n)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Usra, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, type, type, type); + Node* n = m.AddNode((m.machine()->*param.shr_u_operator)(), m.Parameter(0), + m.Int32Constant(1)); + m.Return( + m.AddNode((m.machine()->*param.add_operator)(), n, m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Usra, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(param.laneSize, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorSIMDShrAddTest, + ::testing::ValuesIn(kSIMDShrAddInstructions)); + +namespace { +struct SIMDAddExtMulInst { + const char* mul_constructor_name; + const Operator* (MachineOperatorBuilder::*mul_operator)(); + const Operator* (MachineOperatorBuilder::*add_operator)(); + ArchOpcode multiply_add_arch_opcode; + MachineType machine_type; + int lane_size; +}; +} // namespace + +static const SIMDAddExtMulInst kSimdAddExtMulInstructions[] = { + {"I16x8ExtMulLowI8x16S", &MachineOperatorBuilder::I16x8ExtMulLowI8x16S, + &MachineOperatorBuilder::I16x8Add, kArm64Smlal, MachineType::Simd128(), + 16}, + {"I16x8ExtMulHighI8x16S", &MachineOperatorBuilder::I16x8ExtMulHighI8x16S, + &MachineOperatorBuilder::I16x8Add, kArm64Smlal2, MachineType::Simd128(), + 16}, + {"I16x8ExtMulLowI8x16U", &MachineOperatorBuilder::I16x8ExtMulLowI8x16U, + &MachineOperatorBuilder::I16x8Add, kArm64Umlal, MachineType::Simd128(), + 16}, + {"I16x8ExtMulHighI8x16U", &MachineOperatorBuilder::I16x8ExtMulHighI8x16U, + &MachineOperatorBuilder::I16x8Add, kArm64Umlal2, MachineType::Simd128(), + 16}, + {"I32x4ExtMulLowI16x8S", &MachineOperatorBuilder::I32x4ExtMulLowI16x8S, + &MachineOperatorBuilder::I32x4Add, kArm64Smlal, MachineType::Simd128(), + 32}, + {"I32x4ExtMulHighI16x8S", &MachineOperatorBuilder::I32x4ExtMulHighI16x8S, + &MachineOperatorBuilder::I32x4Add, kArm64Smlal2, MachineType::Simd128(), + 32}, + {"I32x4ExtMulLowI16x8U", &MachineOperatorBuilder::I32x4ExtMulLowI16x8U, + &MachineOperatorBuilder::I32x4Add, kArm64Umlal, MachineType::Simd128(), + 32}, + {"I32x4ExtMulHighI16x8U", &MachineOperatorBuilder::I32x4ExtMulHighI16x8U, + &MachineOperatorBuilder::I32x4Add, kArm64Umlal2, MachineType::Simd128(), + 32}}; + +using InstructionSelectorSIMDAddExtMulTest = + InstructionSelectorTestWithParam<SIMDAddExtMulInst>; + +// TODO(zhin): This can be merged with InstructionSelectorSIMDDPWithSIMDMulTest +// once sub+extmul matching is implemented. +TEST_P(InstructionSelectorSIMDAddExtMulTest, AddExtMul) { + const SIMDAddExtMulInst mdpi = GetParam(); + const MachineType type = mdpi.machine_type; + { + // Test Add(x, ExtMul(y, z)). + StreamBuilder m(this, type, type, type, type); + Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(1), + m.Parameter(2)); + m.Return(m.AddNode((m.machine()->*mdpi.add_operator)(), m.Parameter(0), n)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + // Test Add(ExtMul(y, z), x), making sure it's commutative. + StreamBuilder m(this, type, type, type, type); + Node* n = m.AddNode((m.machine()->*mdpi.mul_operator)(), m.Parameter(0), + m.Parameter(1)); + m.Return(m.AddNode((m.machine()->*mdpi.add_operator)(), n, m.Parameter(2))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(mdpi.multiply_add_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(mdpi.lane_size, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorSIMDAddExtMulTest, + ::testing::ValuesIn(kSimdAddExtMulInstructions)); + struct SIMDMulDupInst { const uint8_t shuffle[16]; int32_t lane; @@ -2293,7 +2467,8 @@ TEST_P(InstructionSelectorSimdF32x4MulWithDupTest, MulWithDup) { m.Return(m.AddNode(m.machine()->F32x4Mul(), m.Parameter(2), shuffle)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64F32x4MulElement, s[0]->arch_opcode()); + EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode()); + EXPECT_EQ(32, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2))); EXPECT_EQ(1U, s[0]->OutputCount()); @@ -2309,7 +2484,8 @@ TEST_P(InstructionSelectorSimdF32x4MulWithDupTest, MulWithDup) { m.Return(m.AddNode(m.machine()->F32x4Mul(), shuffle, m.Parameter(2))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64F32x4MulElement, s[0]->arch_opcode()); + EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode()); + EXPECT_EQ(32, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2))); EXPECT_EQ(1U, s[0]->OutputCount()); @@ -2336,7 +2512,8 @@ TEST_F(InstructionSelectorTest, SimdF32x4MulWithDupNegativeTest) { // The shuffle is a i8x16.dup of lane 0. EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode()); EXPECT_EQ(3U, s[0]->InputCount()); - EXPECT_EQ(kArm64F32x4Mul, s[1]->arch_opcode()); + EXPECT_EQ(kArm64FMul, s[1]->arch_opcode()); + EXPECT_EQ(32, LaneSizeField::decode(s[1]->opcode())); EXPECT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(2U, s[1]->InputCount()); EXPECT_EQ(1U, s[1]->OutputCount()); @@ -2379,7 +2556,8 @@ TEST_P(InstructionSelectorSimdF64x2MulWithDupTest, MulWithDup) { m.Return(m.AddNode(m.machine()->F64x2Mul(), m.Parameter(2), shuffle)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64F64x2MulElement, s[0]->arch_opcode()); + EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode()); + EXPECT_EQ(64, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2))); EXPECT_EQ(1U, s[0]->OutputCount()); @@ -2395,7 +2573,8 @@ TEST_P(InstructionSelectorSimdF64x2MulWithDupTest, MulWithDup) { m.Return(m.AddNode(m.machine()->F64x2Mul(), shuffle, m.Parameter(2))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64F64x2MulElement, s[0]->arch_opcode()); + EXPECT_EQ(kArm64FMulElement, s[0]->arch_opcode()); + EXPECT_EQ(64, LaneSizeField::decode(s[0]->opcode())); EXPECT_EQ(3U, s[0]->InputCount()); EXPECT_EQ(param.lane, s.ToInt32(s[0]->InputAt(2))); EXPECT_EQ(1U, s[0]->OutputCount()); @@ -2422,7 +2601,8 @@ TEST_F(InstructionSelectorTest, SimdF64x2MulWithDupNegativeTest) { // The shuffle is a i8x16.dup of lane 0. EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode()); EXPECT_EQ(3U, s[0]->InputCount()); - EXPECT_EQ(kArm64F64x2Mul, s[1]->arch_opcode()); + EXPECT_EQ(kArm64FMul, s[1]->arch_opcode()); + EXPECT_EQ(64, LaneSizeField::decode(s[1]->opcode())); EXPECT_EQ(1U, s[0]->OutputCount()); EXPECT_EQ(2U, s[1]->InputCount()); EXPECT_EQ(1U, s[1]->OutputCount()); diff --git a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc index f4e3ea07b1..e52661fae2 100644 --- a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc @@ -50,8 +50,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( InstructionSelector::kEnableSwitchJumpTable, &tick_counter, nullptr, &max_unoptimized_frame_height, &max_pushed_argument_count, source_position_mode, features, InstructionSelector::kDisableScheduling, - InstructionSelector::kEnableRootsRelativeAddressing, - PoisoningMitigationLevel::kPoisonAll); + InstructionSelector::kEnableRootsRelativeAddressing); selector.SelectInstructions(); if (FLAG_trace_turbo) { StdoutStream{} << "=== Code sequence after instruction selection ===" @@ -452,7 +451,6 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) { EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); size_t num_operands = 1 + // Code object. - 1 + // Poison index 6 + // Frame state deopt id + one input for each value in frame state. 1 + // Function. 1; // Context. @@ -462,23 +460,23 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) { EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); // Deoptimization id. - int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(2)); + int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); FrameStateDescriptor* desc_before = s.GetFrameStateDescriptor(deopt_id_before); EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); EXPECT_EQ(1u, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->stack_count()); - EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(4))); - EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(5))); // This should be a context. + EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(3))); + EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(4))); // This should be a context. // We inserted 0 here. - EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(6))); - EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(7))->IsUndefined(isolate())); + EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(5))); + EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(6))->IsUndefined(isolate())); // Function. - EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(8))); + EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(7))); // Context. - EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(9))); + EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(8))); EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); @@ -559,7 +557,6 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) { EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); size_t num_operands = 1 + // Code object. - 1 + // Poison index. 1 + // Frame state deopt id 5 + // One input for each value in frame state + context. 5 + // One input for each value in the parent frame state + context. @@ -570,7 +567,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) { EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); // Deoptimization id. - int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(2)); + int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); FrameStateDescriptor* desc_before = s.GetFrameStateDescriptor(deopt_id_before); FrameStateDescriptor* desc_before_outer = desc_before->outer_state(); @@ -579,24 +576,24 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) { EXPECT_EQ(1u, desc_before_outer->locals_count()); EXPECT_EQ(1u, desc_before_outer->stack_count()); // Values from parent environment. - EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(4))); + EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(3))); // Context: - EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(5))); - EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(6))); - EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(7))); + EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(4))); + EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(5))); + EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(6))); // Values from the nested frame. EXPECT_EQ(1u, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->stack_count()); - EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(9))); - EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(10))); - EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(11))); - EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(12))); + EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(8))); + EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(9))); + EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(10))); + EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(11))); // Function. - EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(13))); + EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(12))); // Context. - EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(14))); + EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(13))); // Continuation. EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); diff --git a/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc b/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc index 2b76e5289f..03960705e1 100644 --- a/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/effect-control-linearizer-unittest.cc @@ -86,8 +86,7 @@ TEST_F(EffectControlLinearizerTest, SimpleLoad) { // Run the state effect introducer. LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number, @@ -148,8 +147,7 @@ TEST_F(EffectControlLinearizerTest, DiamondLoad) { // Run the state effect introducer. LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); // The effect input to the return should be an effect phi with the // newly introduced effectful change operators. @@ -215,8 +213,7 @@ TEST_F(EffectControlLinearizerTest, LoopLoad) { // Run the state effect introducer. LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); ASSERT_THAT(ret, IsReturn(load, load, if_true)); EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(), @@ -278,8 +275,7 @@ TEST_F(EffectControlLinearizerTest, CloneBranch) { schedule.AddNode(mblock, graph()->end()); LinearizeEffectControl(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); Capture<Node *> branch1_capture, branch2_capture; EXPECT_THAT( @@ -337,8 +333,7 @@ TEST_F(EffectControlLinearizerTest, UnreachableThenBranch) { // Run the state effect linearizer and machine lowering, maintaining the // schedule. LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); ASSERT_THAT(end(), IsEnd(IsThrow())); } @@ -390,8 +385,7 @@ TEST_F(EffectControlLinearizerTest, UnreachableThenDiamond) { // Run the state effect linearizer and machine lowering, maintaining the // schedule. LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); ASSERT_THAT(end(), IsEnd(IsThrow())); } @@ -448,8 +442,7 @@ TEST_F(EffectControlLinearizerTest, UnreachableThenLoop) { // Run the state effect linearizer and machine lowering, maintaining the // schedule. LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); ASSERT_THAT(end(), IsEnd(IsThrow())); } @@ -502,8 +495,7 @@ TEST_F(EffectControlLinearizerTest, UnreachableInChangedBlockThenBranch) { // Run the state effect linearizer and machine lowering, maintaining the // schedule. LowerToMachineSchedule(jsgraph(), &schedule, zone(), source_positions(), - node_origins(), PoisoningMitigationLevel::kDontPoison, - broker()); + node_origins(), broker()); ASSERT_THAT(end(), IsEnd(IsThrow())); } diff --git a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc index f3942b776e..08c16f60c0 100644 --- a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -321,8 +321,8 @@ INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, class AddressingModeUnitTest : public InstructionSelectorTest { public: - AddressingModeUnitTest() : m(NULL) { Reset(); } - ~AddressingModeUnitTest() { delete m; } + AddressingModeUnitTest() : m(nullptr) { Reset(); } + ~AddressingModeUnitTest() override { delete m; } void Run(Node* base, Node* load_index, Node* store_index, AddressingMode mode) { @@ -743,7 +743,7 @@ TEST_F(InstructionSelectorTest, Float32Abs) { m.Return(n); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); + EXPECT_EQ(kFloat32Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -758,7 +758,7 @@ TEST_F(InstructionSelectorTest, Float32Abs) { m.Return(n); Stream s = m.Build(AVX); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode()); + EXPECT_EQ(kFloat32Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -776,7 +776,7 @@ TEST_F(InstructionSelectorTest, Float64Abs) { m.Return(n); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); + EXPECT_EQ(kFloat64Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -791,7 +791,7 @@ TEST_F(InstructionSelectorTest, Float64Abs) { m.Return(n); Stream s = m.Build(AVX); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode()); + EXPECT_EQ(kFloat64Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -812,10 +812,10 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { m.Return(ret); Stream s = m.Build(AVX); ASSERT_EQ(4U, s.size()); - EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode()); - EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode()); - EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode()); - EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode()); + EXPECT_EQ(kFloat64Add, s[0]->arch_opcode()); + EXPECT_EQ(kFloat64Mul, s[1]->arch_opcode()); + EXPECT_EQ(kFloat64Sub, s[2]->arch_opcode()); + EXPECT_EQ(kFloat64Div, s[3]->arch_opcode()); } { StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), @@ -827,10 +827,10 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { m.Return(ret); Stream s = m.Build(); ASSERT_EQ(4U, s.size()); - EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode()); - EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode()); - EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode()); - EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode()); + EXPECT_EQ(kFloat64Add, s[0]->arch_opcode()); + EXPECT_EQ(kFloat64Mul, s[1]->arch_opcode()); + EXPECT_EQ(kFloat64Sub, s[2]->arch_opcode()); + EXPECT_EQ(kFloat64Div, s[3]->arch_opcode()); } } diff --git a/deps/v8/test/unittests/compiler/loong64/instruction-selector-loong64-unittest.cc b/deps/v8/test/unittests/compiler/loong64/instruction-selector-loong64-unittest.cc new file mode 100644 index 0000000000..fa0cd23a86 --- /dev/null +++ b/deps/v8/test/unittests/compiler/loong64/instruction-selector-loong64-unittest.cc @@ -0,0 +1,1564 @@ +// Copyright 2021 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 "src/objects/objects-inl.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" + +namespace v8 { +namespace internal { +namespace compiler { + +namespace { +template <typename T> +struct MachInst { + T constructor; + const char* constructor_name; + ArchOpcode arch_opcode; + MachineType machine_type; +}; + +template <typename T> +std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) { + return os << mi.constructor_name; +} + +using MachInst1 = MachInst<Node* (RawMachineAssembler::*)(Node*)>; +using MachInst2 = MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)>; + +// To avoid duplicated code IntCmp helper structure +// is created. It contains MachInst2 with two nodes and expected_size +// because different cmp instructions have different size. +struct IntCmp { + MachInst2 mi; + uint32_t expected_size; +}; + +struct FPCmp { + MachInst2 mi; + FlagsCondition cond; +}; + +const FPCmp kFPCmpInstructions[] = { + {{&RawMachineAssembler::Float64Equal, "Float64Equal", kLoong64Float64Cmp, + MachineType::Float64()}, + kEqual}, + {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", + kLoong64Float64Cmp, MachineType::Float64()}, + kUnsignedLessThan}, + {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual", + kLoong64Float64Cmp, MachineType::Float64()}, + kUnsignedLessThanOrEqual}, + {{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan", + kLoong64Float64Cmp, MachineType::Float64()}, + kUnsignedLessThan}, + {{&RawMachineAssembler::Float64GreaterThanOrEqual, + "Float64GreaterThanOrEqual", kLoong64Float64Cmp, MachineType::Float64()}, + kUnsignedLessThanOrEqual}}; + +struct Conversion { + // The machine_type field in MachInst1 represents the destination type. + MachInst1 mi; + MachineType src_machine_type; +}; + +// ---------------------------------------------------------------------------- +// Logical instructions. +// ---------------------------------------------------------------------------- + +const MachInst2 kLogicalInstructions[] = { + {&RawMachineAssembler::Word32And, "Word32And", kLoong64And32, + MachineType::Int32()}, + {&RawMachineAssembler::Word64And, "Word64And", kLoong64And, + MachineType::Int64()}, + {&RawMachineAssembler::Word32Or, "Word32Or", kLoong64Or32, + MachineType::Int32()}, + {&RawMachineAssembler::Word64Or, "Word64Or", kLoong64Or, + MachineType::Int64()}, + {&RawMachineAssembler::Word32Xor, "Word32Xor", kLoong64Xor32, + MachineType::Int32()}, + {&RawMachineAssembler::Word64Xor, "Word64Xor", kLoong64Xor, + MachineType::Int64()}}; + +// ---------------------------------------------------------------------------- +// Shift instructions. +// ---------------------------------------------------------------------------- + +const MachInst2 kShiftInstructions[] = { + {&RawMachineAssembler::Word32Shl, "Word32Shl", kLoong64Sll_w, + MachineType::Int32()}, + {&RawMachineAssembler::Word64Shl, "Word64Shl", kLoong64Sll_d, + MachineType::Int64()}, + {&RawMachineAssembler::Word32Shr, "Word32Shr", kLoong64Srl_w, + MachineType::Int32()}, + {&RawMachineAssembler::Word64Shr, "Word64Shr", kLoong64Srl_d, + MachineType::Int64()}, + {&RawMachineAssembler::Word32Sar, "Word32Sar", kLoong64Sra_w, + MachineType::Int32()}, + {&RawMachineAssembler::Word64Sar, "Word64Sar", kLoong64Sra_d, + MachineType::Int64()}, + {&RawMachineAssembler::Word32Ror, "Word32Ror", kLoong64Rotr_w, + MachineType::Int32()}, + {&RawMachineAssembler::Word64Ror, "Word64Ror", kLoong64Rotr_d, + MachineType::Int64()}}; + +// ---------------------------------------------------------------------------- +// MUL/DIV instructions. +// ---------------------------------------------------------------------------- + +const MachInst2 kMulDivInstructions[] = { + {&RawMachineAssembler::Int32Mul, "Int32Mul", kLoong64Mul_w, + MachineType::Int32()}, + {&RawMachineAssembler::Int32Div, "Int32Div", kLoong64Div_w, + MachineType::Int32()}, + {&RawMachineAssembler::Uint32Div, "Uint32Div", kLoong64Div_wu, + MachineType::Uint32()}, + {&RawMachineAssembler::Int64Mul, "Int64Mul", kLoong64Mul_d, + MachineType::Int64()}, + {&RawMachineAssembler::Int64Div, "Int64Div", kLoong64Div_d, + MachineType::Int64()}, + {&RawMachineAssembler::Uint64Div, "Uint64Div", kLoong64Div_du, + MachineType::Uint64()}, + {&RawMachineAssembler::Float64Mul, "Float64Mul", kLoong64Float64Mul, + MachineType::Float64()}, + {&RawMachineAssembler::Float64Div, "Float64Div", kLoong64Float64Div, + MachineType::Float64()}}; + +// ---------------------------------------------------------------------------- +// MOD instructions. +// ---------------------------------------------------------------------------- + +const MachInst2 kModInstructions[] = { + {&RawMachineAssembler::Int32Mod, "Int32Mod", kLoong64Mod_w, + MachineType::Int32()}, + {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kLoong64Mod_wu, + MachineType::Int32()}, + {&RawMachineAssembler::Float64Mod, "Float64Mod", kLoong64Float64Mod, + MachineType::Float64()}}; + +// ---------------------------------------------------------------------------- +// Arithmetic FPU instructions. +// ---------------------------------------------------------------------------- + +const MachInst2 kFPArithInstructions[] = { + {&RawMachineAssembler::Float64Add, "Float64Add", kLoong64Float64Add, + MachineType::Float64()}, + {&RawMachineAssembler::Float64Sub, "Float64Sub", kLoong64Float64Sub, + MachineType::Float64()}}; + +// ---------------------------------------------------------------------------- +// IntArithTest instructions, two nodes. +// ---------------------------------------------------------------------------- + +const MachInst2 kAddSubInstructions[] = { + {&RawMachineAssembler::Int32Add, "Int32Add", kLoong64Add_w, + MachineType::Int32()}, + {&RawMachineAssembler::Int64Add, "Int64Add", kLoong64Add_d, + MachineType::Int64()}, + {&RawMachineAssembler::Int32Sub, "Int32Sub", kLoong64Sub_w, + MachineType::Int32()}, + {&RawMachineAssembler::Int64Sub, "Int64Sub", kLoong64Sub_d, + MachineType::Int64()}}; + +// ---------------------------------------------------------------------------- +// IntArithTest instructions, one node. +// ---------------------------------------------------------------------------- + +const MachInst1 kAddSubOneInstructions[] = { + {&RawMachineAssembler::Int32Neg, "Int32Neg", kLoong64Sub_w, + MachineType::Int32()}, + {&RawMachineAssembler::Int64Neg, "Int64Neg", kLoong64Sub_d, + MachineType::Int64()}}; + +// ---------------------------------------------------------------------------- +// Arithmetic compare instructions. +// ---------------------------------------------------------------------------- + +const IntCmp kCmpInstructions[] = { + {{&RawMachineAssembler::WordEqual, "WordEqual", kLoong64Cmp, + MachineType::Int64()}, + 1U}, + {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kLoong64Cmp, + MachineType::Int64()}, + 1U}, + {{&RawMachineAssembler::Word32Equal, "Word32Equal", kLoong64Cmp, + MachineType::Int32()}, + 1U}, + {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kLoong64Cmp, + MachineType::Int32()}, + 1U}, + {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kLoong64Cmp, + MachineType::Int32()}, + 1U}, + {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual", + kLoong64Cmp, MachineType::Int32()}, + 1U}, + {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kLoong64Cmp, + MachineType::Int32()}, + 1U}, + {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual", + kLoong64Cmp, MachineType::Int32()}, + 1U}, + {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kLoong64Cmp, + MachineType::Uint32()}, + 1U}, + {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual", + kLoong64Cmp, MachineType::Uint32()}, + 1U}}; + +// ---------------------------------------------------------------------------- +// Conversion instructions. +// ---------------------------------------------------------------------------- + +const Conversion kConversionInstructions[] = { + // Conversion instructions are related to machine_operator.h: + // FPU conversions: + // Convert representation of integers between float64 and int32/uint32. + // The precise rounding mode and handling of out of range inputs are *not* + // defined for these operators, since they are intended only for use with + // integers. + {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64", + kLoong64Int32ToFloat64, MachineType::Float64()}, + MachineType::Int32()}, + + {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64", + kLoong64Uint32ToFloat64, MachineType::Float64()}, + MachineType::Int32()}, + + {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32", + kLoong64Float64ToInt32, MachineType::Float64()}, + MachineType::Int32()}, + + {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32", + kLoong64Float64ToUint32, MachineType::Float64()}, + MachineType::Int32()}}; + +// LOONG64 instructions that clear the top 32 bits of the destination. +const MachInst2 kCanElideChangeUint32ToUint64[] = { + {&RawMachineAssembler::Uint32Div, "Uint32Div", kLoong64Div_wu, + MachineType::Uint32()}, + {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kLoong64Mod_wu, + MachineType::Uint32()}, + {&RawMachineAssembler::Uint32MulHigh, "Uint32MulHigh", kLoong64Mulh_wu, + MachineType::Uint32()}}; + +} // namespace + +using InstructionSelectorFPCmpTest = InstructionSelectorTestWithParam<FPCmp>; + +TEST_P(InstructionSelectorFPCmpTest, Parameter) { + const FPCmp cmp = GetParam(); + StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type, + cmp.mi.machine_type); + m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(cmp.cond, s[0]->flags_condition()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest, + ::testing::ValuesIn(kFPCmpInstructions)); + +// ---------------------------------------------------------------------------- +// Arithmetic compare instructions integers +// ---------------------------------------------------------------------------- + +using InstructionSelectorCmpTest = InstructionSelectorTestWithParam<IntCmp>; + +TEST_P(InstructionSelectorCmpTest, Parameter) { + const IntCmp cmp = GetParam(); + const MachineType type = cmp.mi.machine_type; + StreamBuilder m(this, type, type, type); + m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + + ASSERT_EQ(cmp.expected_size, s.size()); + EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorCmpTest, + ::testing::ValuesIn(kCmpInstructions)); + +// ---------------------------------------------------------------------------- +// Shift instructions. +// ---------------------------------------------------------------------------- + +using InstructionSelectorShiftTest = + InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorShiftTest, Immediate) { + const MachInst2 dpi = GetParam(); + const MachineType type = dpi.machine_type; + TRACED_FORRANGE(int32_t, imm, 0, + ((1 << ElementSizeLog2Of(type.representation())) * 8) - 1) { + StreamBuilder m(this, type, type); + 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(2U, s[0]->InputCount()); + EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorShiftTest, + ::testing::ValuesIn(kShiftInstructions)); + +TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) { + // The available shift operand range is `0 <= imm < 32`, but we also test + // that immediates outside this range are handled properly (modulo-32). + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1F; + TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + uint32_t jnk = rng()->NextInt(); + jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0; + uint32_t msk = ((0xFFFFFFFFu >> (32 - width)) << lsb) | jnk; + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)), + m.Int32Constant(shift))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrpick_w, 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, shift, -32, 63) { + int32_t lsb = shift & 0x1F; + TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + uint32_t jnk = rng()->NextInt(); + jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0; + uint32_t msk = ((0xFFFFFFFFu >> (32 - width)) << lsb) | jnk; + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)), + m.Int32Constant(shift))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrpick_w, 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, Word64ShrWithWord64AndWithImmediate) { + // The available shift operand range is `0 <= imm < 64`, but we also test + // that immediates outside this range are handled properly (modulo-64). + TRACED_FORRANGE(int32_t, shift, -64, 127) { + int32_t lsb = shift & 0x3F; + TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) { + uint64_t jnk = rng()->NextInt64(); + jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0; + uint64_t msk = + ((uint64_t{0xFFFFFFFFFFFFFFFF} >> (64 - width)) << lsb) | jnk; + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)), + m.Int64Constant(shift))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrpick_d, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2))); + } + } + TRACED_FORRANGE(int32_t, shift, -64, 127) { + int32_t lsb = shift & 0x3F; + TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) { + uint64_t jnk = rng()->NextInt64(); + jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0; + uint64_t msk = + ((uint64_t{0xFFFFFFFFFFFFFFFF} >> (64 - width)) << lsb) | jnk; + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)), + m.Int64Constant(shift))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrpick_d, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1))); + EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2))); + } + } +} + +TEST_F(InstructionSelectorTest, Word32AndToClearBits) { + TRACED_FORRANGE(int32_t, shift, 1, 31) { + int32_t mask = ~((1 << shift) - 1); + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(mask))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrins_w, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2))); + } + TRACED_FORRANGE(int32_t, shift, 1, 31) { + int32_t mask = ~((1 << shift) - 1); + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32And(m.Int32Constant(mask), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrins_w, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2))); + } +} + +TEST_F(InstructionSelectorTest, Word64AndToClearBits) { + TRACED_FORRANGE(int32_t, shift, 1, 31) { + int64_t mask = ~((1 << shift) - 1); + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64And(m.Parameter(0), m.Int64Constant(mask))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrins_d, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2))); + } + TRACED_FORRANGE(int32_t, shift, 1, 31) { + int64_t mask = ~((1 << shift) - 1); + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64And(m.Int64Constant(mask), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrins_d, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2))); + } +} + +// ---------------------------------------------------------------------------- +// Logical instructions. +// ---------------------------------------------------------------------------- + +using InstructionSelectorLogicalTest = + InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorLogicalTest, Parameter) { + const MachInst2 dpi = GetParam(); + const MachineType type = dpi.machine_type; + StreamBuilder m(this, type, type, type); + 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(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorLogicalTest, + ::testing::ValuesIn(kLogicalInstructions)); + +TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) { + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor32, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor32, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, Word64XorMinusOneWithWord64Or) { + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Xor(m.Word64Or(m.Parameter(0), m.Parameter(0)), + m.Int64Constant(-1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Xor(m.Int64Constant(-1), + m.Word64Or(m.Parameter(0), m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, Word32XorMinusOneWithWord32Or) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Xor(m.Word32Or(m.Parameter(0), m.Parameter(0)), + m.Int32Constant(-1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor32, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Xor(m.Int32Constant(-1), + m.Word32Or(m.Parameter(0), m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Nor32, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) { + // The available shift operand range is `0 <= imm < 32`, but we also test + // that immediates outside this range are handled properly (modulo-32). + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1F; + TRACED_FORRANGE(int32_t, width, 1, 31) { + uint32_t msk = (1 << width) - 1; + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)), + m.Int32Constant(msk))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrpick_w, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width; + EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2))); + } + } + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1F; + TRACED_FORRANGE(int32_t, width, 1, 31) { + uint32_t msk = (1 << width) - 1; + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return( + m.Word32And(m.Int32Constant(msk), + m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Bstrpick_w, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); + int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width; + EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2))); + } + } +} + +TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) { + TRACED_FORRANGE(int32_t, shift, 0, 30) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)), + m.Int32Constant(shift + 1)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Sll_w, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } +} + +TEST_F(InstructionSelectorTest, Word64ShlWithWord64And) { + TRACED_FORRANGE(int32_t, shift, 0, 62) { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word64Shl(m.Word64And(p0, m.Int64Constant((1L << (63 - shift)) - 1)), + m.Int64Constant(shift + 1)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Sll_d, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } +} + +TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ext_w_b, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ext_w_h, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(32)), m.Int32Constant(32)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Sll_w, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } +} + +// ---------------------------------------------------------------------------- +// MUL/DIV instructions. +// ---------------------------------------------------------------------------- + +using InstructionSelectorMulDivTest = + InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorMulDivTest, Parameter) { + const MachInst2 dpi = GetParam(); + const MachineType type = dpi.machine_type; + StreamBuilder m(this, type, type, type); + 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(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorMulDivTest, + ::testing::ValuesIn(kMulDivInstructions)); + +// ---------------------------------------------------------------------------- +// MOD instructions. +// ---------------------------------------------------------------------------- + +using InstructionSelectorModTest = InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorModTest, Parameter) { + const MachInst2 dpi = GetParam(); + const MachineType type = dpi.machine_type; + StreamBuilder m(this, type, type, type); + 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(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, InstructionSelectorModTest, + ::testing::ValuesIn(kModInstructions)); + +// ---------------------------------------------------------------------------- +// Floating point instructions. +// ---------------------------------------------------------------------------- + +using InstructionSelectorFPArithTest = + InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorFPArithTest, Parameter) { + const MachInst2 fpa = GetParam(); + StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type); + m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorFPArithTest, + ::testing::ValuesIn(kFPArithInstructions)); + +// ---------------------------------------------------------------------------- +// Integer arithmetic +// ---------------------------------------------------------------------------- +using InstructionSelectorIntArithTwoTest = + InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorIntArithTwoTest, Parameter) { + const MachInst2 intpa = GetParam(); + StreamBuilder m(this, intpa.machine_type, intpa.machine_type, + intpa.machine_type); + m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorIntArithTwoTest, + ::testing::ValuesIn(kAddSubInstructions)); + +// ---------------------------------------------------------------------------- +// One node. +// ---------------------------------------------------------------------------- + +using InstructionSelectorIntArithOneTest = + InstructionSelectorTestWithParam<MachInst1>; + +TEST_P(InstructionSelectorIntArithOneTest, Parameter) { + const MachInst1 intpa = GetParam(); + StreamBuilder m(this, intpa.machine_type, intpa.machine_type, + intpa.machine_type); + m.Return((m.*intpa.constructor)(m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorIntArithOneTest, + ::testing::ValuesIn(kAddSubOneInstructions)); + +// ---------------------------------------------------------------------------- +// Conversions. +// ---------------------------------------------------------------------------- + +using InstructionSelectorConversionTest = + InstructionSelectorTestWithParam<Conversion>; + +TEST_P(InstructionSelectorConversionTest, Parameter) { + const Conversion conv = GetParam(); + StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type); + m.Return((m.*conv.mi.constructor)(m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorConversionTest, + ::testing::ValuesIn(kConversionInstructions)); + +TEST_F(InstructionSelectorTest, ChangesFromToSmi) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.TruncateInt64ToInt32( + m.Word64Sar(m.Parameter(0), m.Int32Constant(32)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Sra_d, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return( + m.Word64Shl(m.ChangeInt32ToInt64(m.Parameter(0)), m.Int32Constant(32))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Sll_d, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, ChangeFloat64ToInt32OfChangeFloat32ToFloat64) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Float32()); + m.Return(m.ChangeFloat64ToInt32(m.ChangeFloat32ToFloat64(m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kLoong64Float32ToFloat64, s[0]->arch_opcode()); + EXPECT_EQ(kLoong64Float64ToInt32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, + TruncateFloat64ToFloat32OfChangeInt32ToFloat64) { + { + StreamBuilder m(this, MachineType::Float32(), MachineType::Int32()); + m.Return( + m.TruncateFloat64ToFloat32(m.ChangeInt32ToFloat64(m.Parameter(0)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Int32ToFloat32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, CombineShiftsWithMul) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Int32Mul(m.Word64Sar(m.Parameter(0), m.Int32Constant(32)), + m.Word64Sar(m.Parameter(0), m.Int32Constant(32)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Mulh_d, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, CombineShiftsWithDivMod) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Int32Div(m.Word64Sar(m.Parameter(0), m.Int32Constant(32)), + m.Word64Sar(m.Parameter(0), m.Int32Constant(32)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Div_d, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Int32Mod(m.Word64Sar(m.Parameter(0), m.Int32Constant(32)), + m.Word64Sar(m.Parameter(0), m.Int32Constant(32)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Mod_d, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, ChangeInt32ToInt64AfterLoad) { + // For each case, test that the conversion is merged into the load + // operation. + // ChangeInt32ToInt64(Load_Uint8) -> Ld_bu + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeInt32ToInt64( + m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_bu, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // ChangeInt32ToInt64(Load_Int8) -> Ld_b + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeInt32ToInt64( + m.Load(MachineType::Int8(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_b, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // ChangeInt32ToInt64(Load_Uint16) -> Ld_hu + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeInt32ToInt64( + m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_hu, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // ChangeInt32ToInt64(Load_Int16) -> Ld_h + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeInt32ToInt64( + m.Load(MachineType::Int16(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_h, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // ChangeInt32ToInt64(Load_Uint32) -> Ld_w + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeInt32ToInt64( + m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_w, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // ChangeInt32ToInt64(Load_Int32) -> Ld_w + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeInt32ToInt64( + m.Load(MachineType::Int32(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_w, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +using InstructionSelectorElidedChangeUint32ToUint64Test = + InstructionSelectorTestWithParam<MachInst2>; + +TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) { + const MachInst2 binop = GetParam(); + StreamBuilder m(this, MachineType::Uint64(), binop.machine_type, + binop.machine_type); + m.Return(m.ChangeUint32ToUint64( + (m.*binop.constructor)(m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + // Make sure the `ChangeUint32ToUint64` node turned into a no-op. + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kLoong64Bstrpick_d, s[1]->arch_opcode()); + EXPECT_EQ(3U, s[1]->InputCount()); + EXPECT_EQ(1U, s[1]->OutputCount()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorElidedChangeUint32ToUint64Test, + ::testing::ValuesIn(kCanElideChangeUint32ToUint64)); + +TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) { + // For each case, make sure the `ChangeUint32ToUint64` node turned into a + // no-op. + + // Ld_bu + { + StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeUint32ToUint64( + m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_bu, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // Ld_hu + { + StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeUint32ToUint64( + m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_hu, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // Ld_wu + { + StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.ChangeUint32ToUint64( + m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Ld_wu, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +// ---------------------------------------------------------------------------- +// Loads and stores. +// ---------------------------------------------------------------------------- + +namespace { + +struct MemoryAccess { + MachineType type; + ArchOpcode load_opcode; + ArchOpcode store_opcode; +}; + +static const MemoryAccess kMemoryAccesses[] = { + {MachineType::Int8(), kLoong64Ld_b, kLoong64St_b}, + {MachineType::Uint8(), kLoong64Ld_bu, kLoong64St_b}, + {MachineType::Int16(), kLoong64Ld_h, kLoong64St_h}, + {MachineType::Uint16(), kLoong64Ld_hu, kLoong64St_h}, + {MachineType::Int32(), kLoong64Ld_w, kLoong64St_w}, + {MachineType::Float32(), kLoong64Fld_s, kLoong64Fst_s}, + {MachineType::Float64(), kLoong64Fld_d, kLoong64Fst_d}, + {MachineType::Int64(), kLoong64Ld_d, kLoong64St_d}}; + +struct MemoryAccessImm { + MachineType type; + ArchOpcode load_opcode; + ArchOpcode store_opcode; + bool (InstructionSelectorTest::Stream::*val_predicate)( + const InstructionOperand*) const; + const int32_t immediates[40]; +}; + +std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) { + return os << acc.type; +} + +struct MemoryAccessImm1 { + MachineType type; + ArchOpcode load_opcode; + ArchOpcode store_opcode; + bool (InstructionSelectorTest::Stream::*val_predicate)( + const InstructionOperand*) const; + const int32_t immediates[5]; +}; + +std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) { + return os << acc.type; +} + +struct MemoryAccessImm2 { + MachineType type; + ArchOpcode store_opcode; + ArchOpcode store_opcode_unaligned; + bool (InstructionSelectorTest::Stream::*val_predicate)( + const InstructionOperand*) const; + const int32_t immediates[40]; +}; + +// ---------------------------------------------------------------------------- +// Loads and stores immediate values +// ---------------------------------------------------------------------------- + +const MemoryAccessImm kMemoryAccessesImm[] = { + {MachineType::Int8(), + kLoong64Ld_b, + kLoong64St_b, + &InstructionSelectorTest::Stream::IsInteger, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Uint8(), + kLoong64Ld_bu, + kLoong64St_b, + &InstructionSelectorTest::Stream::IsInteger, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Int16(), + kLoong64Ld_h, + kLoong64St_h, + &InstructionSelectorTest::Stream::IsInteger, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Uint16(), + kLoong64Ld_hu, + kLoong64St_h, + &InstructionSelectorTest::Stream::IsInteger, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Int32(), + kLoong64Ld_w, + kLoong64St_w, + &InstructionSelectorTest::Stream::IsInteger, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Float32(), + kLoong64Fld_s, + kLoong64Fst_s, + &InstructionSelectorTest::Stream::IsDouble, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Float64(), + kLoong64Fld_d, + kLoong64Fst_d, + &InstructionSelectorTest::Stream::IsDouble, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {MachineType::Int64(), + kLoong64Ld_d, + kLoong64St_d, + &InstructionSelectorTest::Stream::IsInteger, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, + -89, -87, -86, -82, -44, -23, -3, 0, 7, 10, + 39, 52, 69, 71, 91, 92, 107, 109, 115, 124, + 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}}; + +const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = { + {MachineType::Int8(), + kLoong64Ld_b, + kLoong64St_b, + &InstructionSelectorTest::Stream::IsInteger, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Uint8(), + kLoong64Ld_bu, + kLoong64St_b, + &InstructionSelectorTest::Stream::IsInteger, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Int16(), + kLoong64Ld_h, + kLoong64St_h, + &InstructionSelectorTest::Stream::IsInteger, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Uint16(), + kLoong64Ld_hu, + kLoong64St_h, + &InstructionSelectorTest::Stream::IsInteger, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Int32(), + kLoong64Ld_w, + kLoong64St_w, + &InstructionSelectorTest::Stream::IsInteger, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Float32(), + kLoong64Fld_s, + kLoong64Fst_s, + &InstructionSelectorTest::Stream::IsDouble, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Float64(), + kLoong64Fld_d, + kLoong64Fst_d, + &InstructionSelectorTest::Stream::IsDouble, + {-65000, -55000, 32777, 55000, 65000}}, + {MachineType::Int64(), + kLoong64Ld_d, + kLoong64St_d, + &InstructionSelectorTest::Stream::IsInteger, + {-65000, -55000, 32777, 55000, 65000}}}; + +} // namespace + +using InstructionSelectorMemoryAccessTest = + InstructionSelectorTestWithParam<MemoryAccess>; + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, memacc.type, MachineType::Pointer(), + MachineType::Int32()); + m.Return(m.Load(memacc.type, m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); +} + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), + MachineType::Int32(), memacc.type); + m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1), + kNoWriteBarrier); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessTest, + ::testing::ValuesIn(kMemoryAccesses)); + +// ---------------------------------------------------------------------------- +// Load immediate. +// ---------------------------------------------------------------------------- + +using InstructionSelectorMemoryAccessImmTest = + InstructionSelectorTestWithParam<MemoryAccessImm>; + +TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) { + const MemoryAccessImm memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, memacc.type, MachineType::Pointer()); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output())); + } +} + +// ---------------------------------------------------------------------------- +// Store immediate. +// ---------------------------------------------------------------------------- + +TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) { + const MemoryAccessImm memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), + memacc.type); + m.Store(memacc.type.representation(), m.Parameter(0), + m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + +TEST_P(InstructionSelectorMemoryAccessImmTest, StoreZero) { + const MemoryAccessImm memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer()); + m.Store(memacc.type.representation(), m.Parameter(0), + m.Int32Constant(index), m.Int32Constant(0), kNoWriteBarrier); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind()); + EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessImmTest, + ::testing::ValuesIn(kMemoryAccessesImm)); + +// ---------------------------------------------------------------------------- +// Load/store offsets more than 16 bits. +// ---------------------------------------------------------------------------- + +using InstructionSelectorMemoryAccessImmMoreThan16bitTest = + InstructionSelectorTestWithParam<MemoryAccessImm1>; + +TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest, + LoadWithImmediateIndex) { + const MemoryAccessImm1 memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, memacc.type, MachineType::Pointer()); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest, + StoreWithImmediateIndex) { + const MemoryAccessImm1 memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), + memacc.type); + m.Store(memacc.type.representation(), m.Parameter(0), + m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + +INSTANTIATE_TEST_SUITE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessImmMoreThan16bitTest, + ::testing::ValuesIn(kMemoryAccessImmMoreThan16bit)); + +// ---------------------------------------------------------------------------- +// kLoong64Cmp with zero testing. +// ---------------------------------------------------------------------------- + +TEST_F(InstructionSelectorTest, Word32EqualWithZero) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Cmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_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()); + } + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Cmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_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, Word64EqualWithZero) { + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Cmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_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()); + } + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64Equal(m.Int32Constant(0), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Cmp, s[0]->arch_opcode()); + EXPECT_EQ(kMode_None, s[0]->addressing_mode()); + ASSERT_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, Word32Clz) { + StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32()); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Clz_w, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + +TEST_F(InstructionSelectorTest, Word64Clz) { + StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint64()); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word64Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Clz_d, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + +TEST_F(InstructionSelectorTest, Float32Abs) { + StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Abs(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Float32Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + +TEST_F(InstructionSelectorTest, Float64Abs) { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Abs(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Float64Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + +TEST_F(InstructionSelectorTest, Float64Max) { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const n = m.Float64Max(p0, p1); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Float64Max, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + +TEST_F(InstructionSelectorTest, Float64Min) { + StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), + MachineType::Float64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const n = m.Float64Min(p0, p1); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64Float64Min, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + +TEST_F(InstructionSelectorTest, LoadAndShiftRight) { + { + int32_t immediates[] = {-256, -255, -3, -2, -1, 0, 1, + 2, 3, 255, 256, 260, 4096, 4100, + 8192, 8196, 3276, 3280, 16376, 16380}; + TRACED_FOREACH(int32_t, index, immediates) { + StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer()); + Node* const load = + m.Load(MachineType::Uint64(), m.Parameter(0), m.Int32Constant(index)); + Node* const sar = m.Word64Sar(load, m.Int32Constant(32)); + // Make sure we don't fold the shift into the following add: + m.Return(m.Int64Add(sar, m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kLoong64Ld_w, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index + 4, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + } +} + +TEST_F(InstructionSelectorTest, Word32ReverseBytes) { + { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32ReverseBytes(m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64ByteSwap32, s[0]->arch_opcode()); + EXPECT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +TEST_F(InstructionSelectorTest, Word64ReverseBytes) { + { + StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); + m.Return(m.Word64ReverseBytes(m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kLoong64ByteSwap64, s[0]->arch_opcode()); + EXPECT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc index c432229a35..fa8d45c782 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -3,12 +3,15 @@ // found in the LICENSE file. #include "src/compiler/machine-operator-reducer.h" + #include <limits> + #include "src/base/bits.h" #include "src/base/division-by-constant.h" #include "src/base/ieee754.h" #include "src/base/overflowing-math.h" #include "src/compiler/js-graph.h" +#include "src/compiler/machine-operator.h" #include "src/compiler/typer.h" #include "src/numbers/conversions-inl.h" #include "test/unittests/compiler/graph-unittest.h" @@ -29,7 +32,8 @@ class MachineOperatorReducerTest : public GraphTest { public: explicit MachineOperatorReducerTest(int num_parameters = 2) : GraphTest(num_parameters), - machine_(zone()), + machine_(zone(), MachineType::PointerRepresentation(), + MachineOperatorBuilder::kAllOptionalOps), common_(zone()), javascript_(zone()), jsgraph_(isolate(), graph(), &common_, &javascript_, nullptr, @@ -2880,6 +2884,27 @@ TEST_F(MachineOperatorReducerTest, StoreRepWord16WithWord32SarAndWord32Shl) { } } +TEST_F(MachineOperatorReducerTest, Select) { + static const std::vector<const Operator*> ops = { + machine()->Float32Select().op(), machine()->Float64Select().op(), + machine()->Word32Select().op(), machine()->Word64Select().op()}; + + TRACED_FOREACH(const Operator*, op, ops) { + Node* arg0 = Parameter(0); + Node* arg1 = Parameter(1); + + Node* select_true = graph()->NewNode(op, Int32Constant(1), arg0, arg1); + Reduction r_true = Reduce(select_true); + ASSERT_TRUE(r_true.Changed()); + EXPECT_THAT(r_true.replacement(), IsParameter(0)); + + Node* select_false = graph()->NewNode(op, Int32Constant(0), arg0, arg1); + Reduction r_false = Reduce(select_false); + ASSERT_TRUE(r_false.Changed()); + EXPECT_THAT(r_false.replacement(), IsParameter(1)); + } +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 5305fef574..b449faee8d 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -1150,7 +1150,6 @@ class IsStoreElementMatcher final : public TestNodeMatcher { LOAD_MATCHER(Load) LOAD_MATCHER(UnalignedLoad) -LOAD_MATCHER(PoisonedLoad) LOAD_MATCHER(LoadFromObject) class IsLoadImmutableMatcher final : public TestNodeMatcher { @@ -2103,16 +2102,6 @@ Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, effect_matcher, control_matcher)); } -Matcher<Node*> IsPoisonedLoad(const Matcher<LoadRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher, - const Matcher<Node*>& effect_matcher, - const Matcher<Node*>& control_matcher) { - return MakeMatcher(new IsPoisonedLoadMatcher(rep_matcher, base_matcher, - index_matcher, effect_matcher, - control_matcher)); -} - Matcher<Node*> IsUnalignedLoad(const Matcher<LoadRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, @@ -2366,7 +2355,6 @@ IS_UNOP_MATCHER(Word32Ctz) IS_UNOP_MATCHER(Word32Popcnt) IS_UNOP_MATCHER(Word32ReverseBytes) IS_UNOP_MATCHER(SpeculativeToNumber) -IS_UNOP_MATCHER(TaggedPoisonOnSpeculation) #undef IS_UNOP_MATCHER // Special-case Bitcast operators which are disabled when ENABLE_VERIFY_CSA is diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 0e5e99679c..f727a14c34 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -328,11 +328,6 @@ Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, const Matcher<Node*>& index_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); -Matcher<Node*> IsPoisonedLoad(const Matcher<LoadRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher, - const Matcher<Node*>& effect_matcher, - const Matcher<Node*>& control_matcher); Matcher<Node*> IsUnalignedLoad(const Matcher<LoadRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, @@ -486,7 +481,6 @@ Matcher<Node*> IsNumberToBoolean(const Matcher<Node*>& input_matcher); Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsParameter(const Matcher<int> index_matcher); -Matcher<Node*> IsSpeculationPoison(); Matcher<Node*> IsLoadFramePointer(); Matcher<Node*> IsLoadParentFramePointer(); Matcher<Node*> IsPlainPrimitiveToNumber(const Matcher<Node*>& input_matcher); diff --git a/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc b/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc index 6387f814e1..6eddb961ca 100644 --- a/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc @@ -49,9 +49,8 @@ class SimplifiedLoweringTest : public GraphTest { Linkage* linkage = zone()->New<Linkage>(Linkage::GetJSCallDescriptor( zone(), false, num_parameters_ + 1, CallDescriptor::kCanUseRoots)); - SimplifiedLowering lowering( - jsgraph(), broker(), zone(), source_positions(), node_origins(), - PoisoningMitigationLevel::kDontPoison, tick_counter(), linkage); + SimplifiedLowering lowering(jsgraph(), broker(), zone(), source_positions(), + node_origins(), tick_counter(), linkage); lowering.LowerAllNodes(); } diff --git a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index d2591a52ef..2adac76d66 100644 --- a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -1579,7 +1579,7 @@ TEST_F(InstructionSelectorTest, Float32Abs) { m.Return(n); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); + EXPECT_EQ(kX64Float32Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -1594,7 +1594,7 @@ TEST_F(InstructionSelectorTest, Float32Abs) { m.Return(n); Stream s = m.Build(AVX); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode()); + EXPECT_EQ(kX64Float32Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -1612,7 +1612,7 @@ TEST_F(InstructionSelectorTest, Float64Abs) { m.Return(n); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); + EXPECT_EQ(kX64Float64Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); @@ -1627,7 +1627,7 @@ TEST_F(InstructionSelectorTest, Float64Abs) { m.Return(n); Stream s = m.Build(AVX); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode()); + EXPECT_EQ(kX64Float64Abs, s[0]->arch_opcode()); ASSERT_EQ(1U, s[0]->InputCount()); EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); ASSERT_EQ(1U, s[0]->OutputCount()); |