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/opcodes.h" 6 #include "src/compiler/operator.h" 7 #include "src/compiler/operator-properties.h" 8 #include "src/compiler/simplified-operator.h" 9 #include "src/types-inl.h" 10 #include "test/unittests/test-utils.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace compiler { 15 16 // ----------------------------------------------------------------------------- 17 // Pure operators. 18 19 20 namespace { 21 22 struct PureOperator { 23 const Operator* (SimplifiedOperatorBuilder::*constructor)(); 24 IrOpcode::Value opcode; 25 Operator::Properties properties; 26 int value_input_count; 27 }; 28 29 30 std::ostream& operator<<(std::ostream& os, const PureOperator& pop) { 31 return os << IrOpcode::Mnemonic(pop.opcode); 32 } 33 34 35 const PureOperator kPureOperators[] = { 36 #define PURE(Name, properties, input_count) \ 37 { \ 38 &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \ 39 Operator::kPure | properties, input_count \ 40 } 41 PURE(BooleanNot, Operator::kNoProperties, 1), 42 PURE(BooleanToNumber, Operator::kNoProperties, 1), 43 PURE(NumberEqual, Operator::kCommutative, 2), 44 PURE(NumberLessThan, Operator::kNoProperties, 2), 45 PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2), 46 PURE(NumberAdd, Operator::kCommutative, 2), 47 PURE(NumberSubtract, Operator::kNoProperties, 2), 48 PURE(NumberMultiply, Operator::kCommutative, 2), 49 PURE(NumberDivide, Operator::kNoProperties, 2), 50 PURE(NumberModulus, Operator::kNoProperties, 2), 51 PURE(NumberBitwiseOr, Operator::kCommutative, 2), 52 PURE(NumberBitwiseXor, Operator::kCommutative, 2), 53 PURE(NumberBitwiseAnd, Operator::kCommutative, 2), 54 PURE(NumberShiftLeft, Operator::kNoProperties, 2), 55 PURE(NumberShiftRight, Operator::kNoProperties, 2), 56 PURE(NumberShiftRightLogical, Operator::kNoProperties, 2), 57 PURE(NumberToInt32, Operator::kNoProperties, 1), 58 PURE(NumberToUint32, Operator::kNoProperties, 1), 59 PURE(PlainPrimitiveToNumber, Operator::kNoProperties, 1), 60 PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1), 61 PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1), 62 PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1), 63 PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1), 64 PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1), 65 PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1), 66 PURE(ChangeBoolToBit, Operator::kNoProperties, 1), 67 PURE(ChangeBitToBool, Operator::kNoProperties, 1), 68 PURE(ObjectIsSmi, Operator::kNoProperties, 1) 69 #undef PURE 70 }; 71 72 } // namespace 73 74 75 class SimplifiedPureOperatorTest 76 : public TestWithZone, 77 public ::testing::WithParamInterface<PureOperator> {}; 78 79 80 TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) { 81 const PureOperator& pop = GetParam(); 82 SimplifiedOperatorBuilder simplified1(zone()); 83 SimplifiedOperatorBuilder simplified2(zone()); 84 EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)()); 85 } 86 87 88 TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) { 89 SimplifiedOperatorBuilder simplified(zone()); 90 const PureOperator& pop = GetParam(); 91 const Operator* op = (simplified.*pop.constructor)(); 92 93 EXPECT_EQ(pop.value_input_count, op->ValueInputCount()); 94 EXPECT_EQ(0, op->EffectInputCount()); 95 EXPECT_EQ(0, op->ControlInputCount()); 96 EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op)); 97 98 EXPECT_EQ(1, op->ValueOutputCount()); 99 EXPECT_EQ(0, op->EffectOutputCount()); 100 EXPECT_EQ(0, op->ControlOutputCount()); 101 } 102 103 104 TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) { 105 SimplifiedOperatorBuilder simplified(zone()); 106 const PureOperator& pop = GetParam(); 107 const Operator* op = (simplified.*pop.constructor)(); 108 EXPECT_EQ(pop.opcode, op->opcode()); 109 } 110 111 112 TEST_P(SimplifiedPureOperatorTest, Properties) { 113 SimplifiedOperatorBuilder simplified(zone()); 114 const PureOperator& pop = GetParam(); 115 const Operator* op = (simplified.*pop.constructor)(); 116 EXPECT_EQ(pop.properties, op->properties() & pop.properties); 117 } 118 119 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest, 120 ::testing::ValuesIn(kPureOperators)); 121 122 123 // ----------------------------------------------------------------------------- 124 // Buffer access operators. 125 126 127 namespace { 128 129 const ExternalArrayType kExternalArrayTypes[] = { 130 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array, 131 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array, 132 kExternalFloat32Array, kExternalFloat64Array}; 133 134 } // namespace 135 136 137 class SimplifiedBufferAccessOperatorTest 138 : public TestWithZone, 139 public ::testing::WithParamInterface<ExternalArrayType> {}; 140 141 142 TEST_P(SimplifiedBufferAccessOperatorTest, InstancesAreGloballyShared) { 143 BufferAccess const access(GetParam()); 144 SimplifiedOperatorBuilder simplified1(zone()); 145 SimplifiedOperatorBuilder simplified2(zone()); 146 EXPECT_EQ(simplified1.LoadBuffer(access), simplified2.LoadBuffer(access)); 147 EXPECT_EQ(simplified1.StoreBuffer(access), simplified2.StoreBuffer(access)); 148 } 149 150 151 TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) { 152 SimplifiedOperatorBuilder simplified(zone()); 153 BufferAccess const access(GetParam()); 154 const Operator* op = simplified.LoadBuffer(access); 155 156 EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode()); 157 EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties()); 158 EXPECT_EQ(access, BufferAccessOf(op)); 159 160 EXPECT_EQ(3, op->ValueInputCount()); 161 EXPECT_EQ(1, op->EffectInputCount()); 162 EXPECT_EQ(1, op->ControlInputCount()); 163 EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op)); 164 165 EXPECT_EQ(1, op->ValueOutputCount()); 166 EXPECT_EQ(1, op->EffectOutputCount()); 167 EXPECT_EQ(0, op->ControlOutputCount()); 168 } 169 170 171 TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) { 172 SimplifiedOperatorBuilder simplified(zone()); 173 BufferAccess const access(GetParam()); 174 const Operator* op = simplified.StoreBuffer(access); 175 176 EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode()); 177 EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties()); 178 EXPECT_EQ(access, BufferAccessOf(op)); 179 180 EXPECT_EQ(4, op->ValueInputCount()); 181 EXPECT_EQ(1, op->EffectInputCount()); 182 EXPECT_EQ(1, op->ControlInputCount()); 183 EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op)); 184 185 EXPECT_EQ(0, op->ValueOutputCount()); 186 EXPECT_EQ(1, op->EffectOutputCount()); 187 EXPECT_EQ(0, op->ControlOutputCount()); 188 } 189 190 191 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, 192 SimplifiedBufferAccessOperatorTest, 193 ::testing::ValuesIn(kExternalArrayTypes)); 194 195 196 // ----------------------------------------------------------------------------- 197 // Element access operators. 198 199 200 namespace { 201 202 const ElementAccess kElementAccesses[] = { 203 {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), 204 MachineType::AnyTagged()}, 205 {kUntaggedBase, 0, Type::Any(), MachineType::Int8()}, 206 {kUntaggedBase, 0, Type::Any(), MachineType::Int16()}, 207 {kUntaggedBase, 0, Type::Any(), MachineType::Int32()}, 208 {kUntaggedBase, 0, Type::Any(), MachineType::Uint8()}, 209 {kUntaggedBase, 0, Type::Any(), MachineType::Uint16()}, 210 {kUntaggedBase, 0, Type::Any(), MachineType::Uint32()}, 211 {kUntaggedBase, 0, Type::Signed32(), MachineType::Int8()}, 212 {kUntaggedBase, 0, Type::Unsigned32(), MachineType::Uint8()}, 213 {kUntaggedBase, 0, Type::Signed32(), MachineType::Int16()}, 214 {kUntaggedBase, 0, Type::Unsigned32(), MachineType::Uint16()}, 215 {kUntaggedBase, 0, Type::Signed32(), MachineType::Int32()}, 216 {kUntaggedBase, 0, Type::Unsigned32(), MachineType::Uint32()}, 217 {kUntaggedBase, 0, Type::Number(), 218 MachineType(MachineRepresentation::kFloat32, MachineSemantic::kNone)}, 219 {kUntaggedBase, 0, Type::Number(), 220 MachineType(MachineRepresentation::kFloat64, MachineSemantic::kNone)}, 221 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(), 222 MachineType::Int8()}, 223 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(), 224 MachineType::Uint8()}, 225 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(), 226 MachineType::Int16()}, 227 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(), 228 MachineType::Uint16()}, 229 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(), 230 MachineType::Int32()}, 231 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(), 232 MachineType::Uint32()}, 233 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(), 234 MachineType(MachineRepresentation::kFloat32, MachineSemantic::kNone)}, 235 {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(), 236 MachineType(MachineRepresentation::kFloat32, MachineSemantic::kNone)}}; 237 238 } // namespace 239 240 241 class SimplifiedElementAccessOperatorTest 242 : public TestWithZone, 243 public ::testing::WithParamInterface<ElementAccess> {}; 244 245 246 TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) { 247 SimplifiedOperatorBuilder simplified(zone()); 248 const ElementAccess& access = GetParam(); 249 const Operator* op = simplified.LoadElement(access); 250 251 EXPECT_EQ(IrOpcode::kLoadElement, op->opcode()); 252 EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties()); 253 EXPECT_EQ(access, ElementAccessOf(op)); 254 255 EXPECT_EQ(2, op->ValueInputCount()); 256 EXPECT_EQ(1, op->EffectInputCount()); 257 EXPECT_EQ(1, op->ControlInputCount()); 258 EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op)); 259 260 EXPECT_EQ(1, op->ValueOutputCount()); 261 EXPECT_EQ(1, op->EffectOutputCount()); 262 EXPECT_EQ(0, op->ControlOutputCount()); 263 } 264 265 266 TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) { 267 SimplifiedOperatorBuilder simplified(zone()); 268 const ElementAccess& access = GetParam(); 269 const Operator* op = simplified.StoreElement(access); 270 271 EXPECT_EQ(IrOpcode::kStoreElement, op->opcode()); 272 EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties()); 273 EXPECT_EQ(access, ElementAccessOf(op)); 274 275 EXPECT_EQ(3, op->ValueInputCount()); 276 EXPECT_EQ(1, op->EffectInputCount()); 277 EXPECT_EQ(1, op->ControlInputCount()); 278 EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op)); 279 280 EXPECT_EQ(0, op->ValueOutputCount()); 281 EXPECT_EQ(1, op->EffectOutputCount()); 282 EXPECT_EQ(0, op->ControlOutputCount()); 283 } 284 285 286 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, 287 SimplifiedElementAccessOperatorTest, 288 ::testing::ValuesIn(kElementAccesses)); 289 290 } // namespace compiler 291 } // namespace internal 292 } // namespace v8 293