1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/simplified-operator.h"
6 
7 #include "src/compiler/operator-properties-inl.h"
8 #include "src/test/test-utils.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13 
14 // TODO(bmeurer): Drop once we use std::ostream instead of our OStream.
operator <<(std::ostream & os,const ElementAccess & access)15 inline std::ostream& operator<<(std::ostream& os, const ElementAccess& access) {
16   OStringStream ost;
17   ost << access;
18   return os << ost.c_str();
19 }
20 
21 
22 // -----------------------------------------------------------------------------
23 // Pure operators.
24 
25 
26 namespace {
27 
28 struct PureOperator {
29   const Operator* (SimplifiedOperatorBuilder::*constructor)();
30   IrOpcode::Value opcode;
31   Operator::Properties properties;
32   int value_input_count;
33 };
34 
35 
operator <<(std::ostream & os,const PureOperator & pop)36 std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
37   return os << IrOpcode::Mnemonic(pop.opcode);
38 }
39 
40 
41 const PureOperator kPureOperators[] = {
42 #define PURE(Name, properties, input_count)              \
43   {                                                      \
44     &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
45         Operator::kPure | properties, input_count        \
46   }
47     PURE(BooleanNot, Operator::kNoProperties, 1),
48     PURE(NumberEqual, Operator::kCommutative, 2),
49     PURE(NumberLessThan, Operator::kNoProperties, 2),
50     PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2),
51     PURE(NumberAdd, Operator::kCommutative, 2),
52     PURE(NumberSubtract, Operator::kNoProperties, 2),
53     PURE(NumberMultiply, Operator::kCommutative, 2),
54     PURE(NumberDivide, Operator::kNoProperties, 2),
55     PURE(NumberModulus, Operator::kNoProperties, 2),
56     PURE(NumberToInt32, Operator::kNoProperties, 1),
57     PURE(NumberToUint32, Operator::kNoProperties, 1),
58     PURE(StringEqual, Operator::kCommutative, 2),
59     PURE(StringLessThan, Operator::kNoProperties, 2),
60     PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
61     PURE(StringAdd, Operator::kNoProperties, 2),
62     PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
63     PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
64     PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),
65     PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1),
66     PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1),
67     PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1),
68     PURE(ChangeBoolToBit, Operator::kNoProperties, 1),
69     PURE(ChangeBitToBool, Operator::kNoProperties, 1)
70 #undef PURE
71 };
72 
73 }  // namespace
74 
75 
76 class SimplifiedPureOperatorTest
77     : public TestWithZone,
78       public ::testing::WithParamInterface<PureOperator> {};
79 
80 
TEST_P(SimplifiedPureOperatorTest,InstancesAreGloballyShared)81 TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) {
82   const PureOperator& pop = GetParam();
83   SimplifiedOperatorBuilder simplified1(zone());
84   SimplifiedOperatorBuilder simplified2(zone());
85   EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)());
86 }
87 
88 
TEST_P(SimplifiedPureOperatorTest,NumberOfInputsAndOutputs)89 TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) {
90   SimplifiedOperatorBuilder simplified(zone());
91   const PureOperator& pop = GetParam();
92   const Operator* op = (simplified.*pop.constructor)();
93 
94   EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op));
95   EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
96   EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
97   EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
98 
99   EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
100   EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
101   EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
102 }
103 
104 
TEST_P(SimplifiedPureOperatorTest,OpcodeIsCorrect)105 TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) {
106   SimplifiedOperatorBuilder simplified(zone());
107   const PureOperator& pop = GetParam();
108   const Operator* op = (simplified.*pop.constructor)();
109   EXPECT_EQ(pop.opcode, op->opcode());
110 }
111 
112 
TEST_P(SimplifiedPureOperatorTest,Properties)113 TEST_P(SimplifiedPureOperatorTest, Properties) {
114   SimplifiedOperatorBuilder simplified(zone());
115   const PureOperator& pop = GetParam();
116   const Operator* op = (simplified.*pop.constructor)();
117   EXPECT_EQ(pop.properties, op->properties() & pop.properties);
118 }
119 
120 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
121                         ::testing::ValuesIn(kPureOperators));
122 
123 
124 // -----------------------------------------------------------------------------
125 // Element access operators.
126 
127 namespace {
128 
129 const ElementAccess kElementAccesses[] = {
130     {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
131     {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
132      kMachInt8},
133     {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
134      kMachInt16},
135     {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
136      kMachInt32},
137     {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
138      kMachUint8},
139     {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
140      kMachUint16},
141     {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
142      kMachUint32},
143     {kUntaggedBase, 0, Type::Signed32(), kMachInt8},
144     {kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
145     {kUntaggedBase, 0, Type::Signed32(), kMachInt16},
146     {kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
147     {kUntaggedBase, 0, Type::Signed32(), kMachInt32},
148     {kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
149     {kUntaggedBase, 0, Type::Number(), kRepFloat32},
150     {kUntaggedBase, 0, Type::Number(), kRepFloat64},
151     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
152      kMachInt8},
153     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
154      kMachUint8},
155     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
156      kMachInt16},
157     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
158      kMachUint16},
159     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
160      kMachInt32},
161     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
162      kMachUint32},
163     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
164      kRepFloat32},
165     {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
166      kRepFloat64}};
167 
168 }  // namespace
169 
170 
171 class SimplifiedElementAccessOperatorTest
172     : public TestWithZone,
173       public ::testing::WithParamInterface<ElementAccess> {};
174 
175 
TEST_P(SimplifiedElementAccessOperatorTest,LoadElement)176 TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
177   SimplifiedOperatorBuilder simplified(zone());
178   const ElementAccess& access = GetParam();
179   const Operator* op = simplified.LoadElement(access);
180 
181   EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
182   EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
183   EXPECT_EQ(access, ElementAccessOf(op));
184 
185   EXPECT_EQ(3, OperatorProperties::GetValueInputCount(op));
186   EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
187   EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
188   EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
189 
190   EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
191   EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
192   EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
193 }
194 
195 
TEST_P(SimplifiedElementAccessOperatorTest,StoreElement)196 TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
197   SimplifiedOperatorBuilder simplified(zone());
198   const ElementAccess& access = GetParam();
199   const Operator* op = simplified.StoreElement(access);
200 
201   EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
202   EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
203   EXPECT_EQ(access, ElementAccessOf(op));
204 
205   EXPECT_EQ(4, OperatorProperties::GetValueInputCount(op));
206   EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
207   EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
208   EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
209 
210   EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
211   EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
212   EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
213 }
214 
215 
216 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
217                         SimplifiedElementAccessOperatorTest,
218                         ::testing::ValuesIn(kElementAccesses));
219 
220 }  // namespace compiler
221 }  // namespace internal
222 }  // namespace v8
223