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 #ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_ 6 #define V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_ 7 8 #include <deque> 9 #include <set> 10 11 #include "src/base/utils/random-number-generator.h" 12 #include "src/compiler/instruction-selector.h" 13 #include "src/compiler/raw-machine-assembler.h" 14 #include "src/macro-assembler.h" 15 #include "test/unittests/test-utils.h" 16 17 namespace v8 { 18 namespace internal { 19 namespace compiler { 20 21 class InstructionSelectorTest : public TestWithContext, 22 public TestWithIsolateAndZone { 23 public: 24 InstructionSelectorTest(); 25 ~InstructionSelectorTest() override; 26 rng()27 base::RandomNumberGenerator* rng() { return &rng_; } 28 29 class Stream; 30 31 enum StreamBuilderMode { 32 kAllInstructions, 33 kTargetInstructions, 34 kAllExceptNopInstructions 35 }; 36 37 class StreamBuilder final : public RawMachineAssembler { 38 public: StreamBuilder(InstructionSelectorTest * test,MachineType return_type)39 StreamBuilder(InstructionSelectorTest* test, MachineType return_type) 40 : RawMachineAssembler(test->isolate(), 41 new (test->zone()) Graph(test->zone()), 42 MakeCallDescriptor(test->zone(), return_type), 43 MachineType::PointerRepresentation(), 44 MachineOperatorBuilder::kAllOptionalOps), 45 test_(test) {} StreamBuilder(InstructionSelectorTest * test,MachineType return_type,MachineType parameter0_type)46 StreamBuilder(InstructionSelectorTest* test, MachineType return_type, 47 MachineType parameter0_type) 48 : RawMachineAssembler( 49 test->isolate(), new (test->zone()) Graph(test->zone()), 50 MakeCallDescriptor(test->zone(), return_type, parameter0_type), 51 MachineType::PointerRepresentation(), 52 MachineOperatorBuilder::kAllOptionalOps), 53 test_(test) {} StreamBuilder(InstructionSelectorTest * test,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type)54 StreamBuilder(InstructionSelectorTest* test, MachineType return_type, 55 MachineType parameter0_type, MachineType parameter1_type) 56 : RawMachineAssembler( 57 test->isolate(), new (test->zone()) Graph(test->zone()), 58 MakeCallDescriptor(test->zone(), return_type, parameter0_type, 59 parameter1_type), 60 MachineType::PointerRepresentation(), 61 MachineOperatorBuilder::kAllOptionalOps), 62 test_(test) {} StreamBuilder(InstructionSelectorTest * test,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type,MachineType parameter2_type)63 StreamBuilder(InstructionSelectorTest* test, MachineType return_type, 64 MachineType parameter0_type, MachineType parameter1_type, 65 MachineType parameter2_type) 66 : RawMachineAssembler( 67 test->isolate(), new (test->zone()) Graph(test->zone()), 68 MakeCallDescriptor(test->zone(), return_type, parameter0_type, 69 parameter1_type, parameter2_type), 70 MachineType::PointerRepresentation(), 71 MachineOperatorBuilder::kAllOptionalOps), 72 test_(test) {} 73 Build(CpuFeature feature)74 Stream Build(CpuFeature feature) { 75 return Build(InstructionSelector::Features(feature)); 76 } Build(CpuFeature feature1,CpuFeature feature2)77 Stream Build(CpuFeature feature1, CpuFeature feature2) { 78 return Build(InstructionSelector::Features(feature1, feature2)); 79 } 80 Stream Build(StreamBuilderMode mode = kTargetInstructions) { 81 return Build(InstructionSelector::Features(), mode); 82 } 83 Stream Build(InstructionSelector::Features features, 84 StreamBuilderMode mode = kTargetInstructions, 85 InstructionSelector::SourcePositionMode source_position_mode = 86 InstructionSelector::kAllSourcePositions); 87 88 const FrameStateFunctionInfo* GetFrameStateFunctionInfo(int parameter_count, 89 int local_count); 90 91 private: MakeCallDescriptor(Zone * zone,MachineType return_type)92 CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) { 93 MachineSignature::Builder builder(zone, 1, 0); 94 builder.AddReturn(return_type); 95 return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); 96 } 97 MakeCallDescriptor(Zone * zone,MachineType return_type,MachineType parameter0_type)98 CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, 99 MachineType parameter0_type) { 100 MachineSignature::Builder builder(zone, 1, 1); 101 builder.AddReturn(return_type); 102 builder.AddParam(parameter0_type); 103 return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); 104 } 105 MakeCallDescriptor(Zone * zone,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type)106 CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, 107 MachineType parameter0_type, 108 MachineType parameter1_type) { 109 MachineSignature::Builder builder(zone, 1, 2); 110 builder.AddReturn(return_type); 111 builder.AddParam(parameter0_type); 112 builder.AddParam(parameter1_type); 113 return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); 114 } 115 MakeCallDescriptor(Zone * zone,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type,MachineType parameter2_type)116 CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, 117 MachineType parameter0_type, 118 MachineType parameter1_type, 119 MachineType parameter2_type) { 120 MachineSignature::Builder builder(zone, 1, 3); 121 builder.AddReturn(return_type); 122 builder.AddParam(parameter0_type); 123 builder.AddParam(parameter1_type); 124 builder.AddParam(parameter2_type); 125 return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); 126 } 127 128 private: 129 InstructionSelectorTest* test_; 130 }; 131 132 class Stream final { 133 public: size()134 size_t size() const { return instructions_.size(); } 135 const Instruction* operator[](size_t index) const { 136 EXPECT_LT(index, size()); 137 return instructions_[index]; 138 } 139 IsDouble(const InstructionOperand * operand)140 bool IsDouble(const InstructionOperand* operand) const { 141 return IsDouble(ToVreg(operand)); 142 } 143 IsDouble(const Node * node)144 bool IsDouble(const Node* node) const { return IsDouble(ToVreg(node)); } 145 IsInteger(const InstructionOperand * operand)146 bool IsInteger(const InstructionOperand* operand) const { 147 return IsInteger(ToVreg(operand)); 148 } 149 IsInteger(const Node * node)150 bool IsInteger(const Node* node) const { return IsInteger(ToVreg(node)); } 151 IsReference(const InstructionOperand * operand)152 bool IsReference(const InstructionOperand* operand) const { 153 return IsReference(ToVreg(operand)); 154 } 155 IsReference(const Node * node)156 bool IsReference(const Node* node) const { 157 return IsReference(ToVreg(node)); 158 } 159 ToFloat32(const InstructionOperand * operand)160 float ToFloat32(const InstructionOperand* operand) const { 161 return ToConstant(operand).ToFloat32(); 162 } 163 ToFloat64(const InstructionOperand * operand)164 double ToFloat64(const InstructionOperand* operand) const { 165 return ToConstant(operand).ToFloat64(); 166 } 167 ToInt32(const InstructionOperand * operand)168 int32_t ToInt32(const InstructionOperand* operand) const { 169 return ToConstant(operand).ToInt32(); 170 } 171 ToInt64(const InstructionOperand * operand)172 int64_t ToInt64(const InstructionOperand* operand) const { 173 return ToConstant(operand).ToInt64(); 174 } 175 ToHeapObject(const InstructionOperand * operand)176 Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const { 177 return ToConstant(operand).ToHeapObject(); 178 } 179 ToVreg(const InstructionOperand * operand)180 int ToVreg(const InstructionOperand* operand) const { 181 if (operand->IsConstant()) { 182 return ConstantOperand::cast(operand)->virtual_register(); 183 } 184 EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind()); 185 return UnallocatedOperand::cast(operand)->virtual_register(); 186 } 187 188 int ToVreg(const Node* node) const; 189 190 bool IsFixed(const InstructionOperand* operand, Register reg) const; 191 bool IsSameAsFirst(const InstructionOperand* operand) const; 192 bool IsUsedAtStart(const InstructionOperand* operand) const; 193 GetFrameStateDescriptor(int deoptimization_id)194 FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) { 195 EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount()); 196 return deoptimization_entries_[deoptimization_id]; 197 } 198 GetFrameStateDescriptorCount()199 int GetFrameStateDescriptorCount() { 200 return static_cast<int>(deoptimization_entries_.size()); 201 } 202 203 private: IsDouble(int virtual_register)204 bool IsDouble(int virtual_register) const { 205 return doubles_.find(virtual_register) != doubles_.end(); 206 } 207 IsInteger(int virtual_register)208 bool IsInteger(int virtual_register) const { 209 return !IsDouble(virtual_register) && !IsReference(virtual_register); 210 } 211 IsReference(int virtual_register)212 bool IsReference(int virtual_register) const { 213 return references_.find(virtual_register) != references_.end(); 214 } 215 ToConstant(const InstructionOperand * operand)216 Constant ToConstant(const InstructionOperand* operand) const { 217 ConstantMap::const_iterator i; 218 if (operand->IsConstant()) { 219 i = constants_.find(ConstantOperand::cast(operand)->virtual_register()); 220 EXPECT_EQ(ConstantOperand::cast(operand)->virtual_register(), i->first); 221 EXPECT_FALSE(constants_.end() == i); 222 } else { 223 EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind()); 224 auto imm = ImmediateOperand::cast(operand); 225 if (imm->type() == ImmediateOperand::INLINE) { 226 return Constant(imm->inline_value()); 227 } 228 i = immediates_.find(imm->indexed_value()); 229 EXPECT_EQ(imm->indexed_value(), i->first); 230 EXPECT_FALSE(immediates_.end() == i); 231 } 232 return i->second; 233 } 234 235 friend class StreamBuilder; 236 237 typedef std::map<int, Constant> ConstantMap; 238 typedef std::map<NodeId, int> VirtualRegisters; 239 240 ConstantMap constants_; 241 ConstantMap immediates_; 242 std::deque<Instruction*> instructions_; 243 std::set<int> doubles_; 244 std::set<int> references_; 245 VirtualRegisters virtual_registers_; 246 std::deque<FrameStateDescriptor*> deoptimization_entries_; 247 }; 248 249 base::RandomNumberGenerator rng_; 250 }; 251 252 253 template <typename T> 254 class InstructionSelectorTestWithParam 255 : public InstructionSelectorTest, 256 public ::testing::WithParamInterface<T> {}; 257 258 } // namespace compiler 259 } // namespace internal 260 } // namespace v8 261 262 #endif // V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_ 263