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_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_ 6 #define V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_ 7 8 #include "src/compiler/common-operator.h" 9 #include "src/compiler/instruction-selector.h" 10 #include "src/compiler/linkage.h" 11 #include "src/compiler/machine-operator.h" 12 #include "src/compiler/operator-properties.h" 13 #include "src/compiler/pipeline.h" 14 #include "src/compiler/simplified-operator.h" 15 #include "test/cctest/cctest.h" 16 #include "test/cctest/compiler/call-tester.h" 17 18 namespace v8 { 19 namespace internal { 20 namespace compiler { 21 22 class GraphAndBuilders { 23 public: GraphAndBuilders(Zone * zone)24 explicit GraphAndBuilders(Zone* zone) 25 : main_graph_(new (zone) Graph(zone)), 26 main_common_(zone), 27 main_machine_(zone, MachineType::PointerRepresentation(), 28 InstructionSelector::SupportedMachineOperatorFlags()), 29 main_simplified_(zone) {} 30 graph()31 Graph* graph() const { return main_graph_; } zone()32 Zone* zone() const { return graph()->zone(); } common()33 CommonOperatorBuilder* common() { return &main_common_; } machine()34 MachineOperatorBuilder* machine() { return &main_machine_; } simplified()35 SimplifiedOperatorBuilder* simplified() { return &main_simplified_; } 36 37 protected: 38 // Prefixed with main_ to avoid naming conflicts. 39 Graph* main_graph_; 40 CommonOperatorBuilder main_common_; 41 MachineOperatorBuilder main_machine_; 42 SimplifiedOperatorBuilder main_simplified_; 43 }; 44 45 46 template <typename ReturnType> 47 class GraphBuilderTester : public HandleAndZoneScope, 48 public GraphAndBuilders, 49 public CallHelper<ReturnType> { 50 public: 51 explicit GraphBuilderTester(MachineType p0 = MachineType::None(), 52 MachineType p1 = MachineType::None(), 53 MachineType p2 = MachineType::None(), 54 MachineType p3 = MachineType::None(), 55 MachineType p4 = MachineType::None()) GraphAndBuilders(main_zone ())56 : GraphAndBuilders(main_zone()), 57 CallHelper<ReturnType>( 58 main_isolate(), 59 CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p0, p1, 60 p2, p3, p4)), 61 effect_(NULL), 62 return_(NULL), 63 parameters_(main_zone()->template NewArray<Node*>(parameter_count())) { 64 Begin(static_cast<int>(parameter_count())); 65 InitParameters(); 66 } ~GraphBuilderTester()67 virtual ~GraphBuilderTester() {} 68 GenerateCode()69 void GenerateCode() { Generate(); } Parameter(size_t index)70 Node* Parameter(size_t index) { 71 CHECK_LT(index, parameter_count()); 72 return parameters_[index]; 73 } 74 isolate()75 Isolate* isolate() { return main_isolate(); } factory()76 Factory* factory() { return isolate()->factory(); } 77 78 // Initialize graph and builder. Begin(int num_parameters)79 void Begin(int num_parameters) { 80 CHECK_NULL(graph()->start()); 81 Node* start = graph()->NewNode(common()->Start(num_parameters + 3)); 82 graph()->SetStart(start); 83 effect_ = start; 84 } 85 Return(Node * value)86 void Return(Node* value) { 87 return_ = 88 graph()->NewNode(common()->Return(), value, effect_, graph()->start()); 89 effect_ = NULL; 90 } 91 92 // Close the graph. End()93 void End() { 94 Node* end = graph()->NewNode(common()->End(1), return_); 95 graph()->SetEnd(end); 96 } 97 PointerConstant(void * value)98 Node* PointerConstant(void* value) { 99 intptr_t intptr_value = reinterpret_cast<intptr_t>(value); 100 return kPointerSize == 8 ? NewNode(common()->Int64Constant(intptr_value)) 101 : Int32Constant(static_cast<int>(intptr_value)); 102 } Int32Constant(int32_t value)103 Node* Int32Constant(int32_t value) { 104 return NewNode(common()->Int32Constant(value)); 105 } HeapConstant(Handle<HeapObject> object)106 Node* HeapConstant(Handle<HeapObject> object) { 107 return NewNode(common()->HeapConstant(object)); 108 } 109 BooleanNot(Node * a)110 Node* BooleanNot(Node* a) { return NewNode(simplified()->BooleanNot(), a); } 111 NumberEqual(Node * a,Node * b)112 Node* NumberEqual(Node* a, Node* b) { 113 return NewNode(simplified()->NumberEqual(), a, b); 114 } NumberLessThan(Node * a,Node * b)115 Node* NumberLessThan(Node* a, Node* b) { 116 return NewNode(simplified()->NumberLessThan(), a, b); 117 } NumberLessThanOrEqual(Node * a,Node * b)118 Node* NumberLessThanOrEqual(Node* a, Node* b) { 119 return NewNode(simplified()->NumberLessThanOrEqual(), a, b); 120 } NumberAdd(Node * a,Node * b)121 Node* NumberAdd(Node* a, Node* b) { 122 return NewNode(simplified()->NumberAdd(), a, b); 123 } NumberSubtract(Node * a,Node * b)124 Node* NumberSubtract(Node* a, Node* b) { 125 return NewNode(simplified()->NumberSubtract(), a, b); 126 } NumberMultiply(Node * a,Node * b)127 Node* NumberMultiply(Node* a, Node* b) { 128 return NewNode(simplified()->NumberMultiply(), a, b); 129 } NumberDivide(Node * a,Node * b)130 Node* NumberDivide(Node* a, Node* b) { 131 return NewNode(simplified()->NumberDivide(), a, b); 132 } NumberModulus(Node * a,Node * b)133 Node* NumberModulus(Node* a, Node* b) { 134 return NewNode(simplified()->NumberModulus(), a, b); 135 } NumberToInt32(Node * a)136 Node* NumberToInt32(Node* a) { 137 return NewNode(simplified()->NumberToInt32(), a); 138 } NumberToUint32(Node * a)139 Node* NumberToUint32(Node* a) { 140 return NewNode(simplified()->NumberToUint32(), a); 141 } 142 StringEqual(Node * a,Node * b)143 Node* StringEqual(Node* a, Node* b) { 144 return NewNode(simplified()->StringEqual(), a, b); 145 } StringLessThan(Node * a,Node * b)146 Node* StringLessThan(Node* a, Node* b) { 147 return NewNode(simplified()->StringLessThan(), a, b); 148 } StringLessThanOrEqual(Node * a,Node * b)149 Node* StringLessThanOrEqual(Node* a, Node* b) { 150 return NewNode(simplified()->StringLessThanOrEqual(), a, b); 151 } 152 ChangeTaggedToInt32(Node * a)153 Node* ChangeTaggedToInt32(Node* a) { 154 return NewNode(simplified()->ChangeTaggedToInt32(), a); 155 } ChangeTaggedToUint32(Node * a)156 Node* ChangeTaggedToUint32(Node* a) { 157 return NewNode(simplified()->ChangeTaggedToUint32(), a); 158 } ChangeTaggedToFloat64(Node * a)159 Node* ChangeTaggedToFloat64(Node* a) { 160 return NewNode(simplified()->ChangeTaggedToFloat64(), a); 161 } ChangeInt32ToTagged(Node * a)162 Node* ChangeInt32ToTagged(Node* a) { 163 return NewNode(simplified()->ChangeInt32ToTagged(), a); 164 } ChangeUint32ToTagged(Node * a)165 Node* ChangeUint32ToTagged(Node* a) { 166 return NewNode(simplified()->ChangeUint32ToTagged(), a); 167 } ChangeFloat64ToTagged(Node * a)168 Node* ChangeFloat64ToTagged(Node* a) { 169 return NewNode(simplified()->ChangeFloat64ToTagged(), a); 170 } ChangeBoolToBit(Node * a)171 Node* ChangeBoolToBit(Node* a) { 172 return NewNode(simplified()->ChangeBoolToBit(), a); 173 } ChangeBitToBool(Node * a)174 Node* ChangeBitToBool(Node* a) { 175 return NewNode(simplified()->ChangeBitToBool(), a); 176 } 177 LoadField(const FieldAccess & access,Node * object)178 Node* LoadField(const FieldAccess& access, Node* object) { 179 return NewNode(simplified()->LoadField(access), object); 180 } StoreField(const FieldAccess & access,Node * object,Node * value)181 Node* StoreField(const FieldAccess& access, Node* object, Node* value) { 182 return NewNode(simplified()->StoreField(access), object, value); 183 } LoadElement(const ElementAccess & access,Node * object,Node * index)184 Node* LoadElement(const ElementAccess& access, Node* object, Node* index) { 185 return NewNode(simplified()->LoadElement(access), object, index); 186 } StoreElement(const ElementAccess & access,Node * object,Node * index,Node * value)187 Node* StoreElement(const ElementAccess& access, Node* object, Node* index, 188 Node* value) { 189 return NewNode(simplified()->StoreElement(access), object, index, value); 190 } 191 NewNode(const Operator * op)192 Node* NewNode(const Operator* op) { 193 return MakeNode(op, 0, static_cast<Node**>(NULL)); 194 } 195 NewNode(const Operator * op,Node * n1)196 Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); } 197 NewNode(const Operator * op,Node * n1,Node * n2)198 Node* NewNode(const Operator* op, Node* n1, Node* n2) { 199 Node* buffer[] = {n1, n2}; 200 return MakeNode(op, arraysize(buffer), buffer); 201 } 202 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3)203 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) { 204 Node* buffer[] = {n1, n2, n3}; 205 return MakeNode(op, arraysize(buffer), buffer); 206 } 207 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4)208 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) { 209 Node* buffer[] = {n1, n2, n3, n4}; 210 return MakeNode(op, arraysize(buffer), buffer); 211 } 212 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4,Node * n5)213 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4, 214 Node* n5) { 215 Node* buffer[] = {n1, n2, n3, n4, n5}; 216 return MakeNode(op, arraysize(buffer), buffer); 217 } 218 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4,Node * n5,Node * n6)219 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4, 220 Node* n5, Node* n6) { 221 Node* nodes[] = {n1, n2, n3, n4, n5, n6}; 222 return MakeNode(op, arraysize(nodes), nodes); 223 } 224 NewNode(const Operator * op,int value_input_count,Node ** value_inputs)225 Node* NewNode(const Operator* op, int value_input_count, 226 Node** value_inputs) { 227 return MakeNode(op, value_input_count, value_inputs); 228 } 229 GetCode()230 Handle<Code> GetCode() { 231 Generate(); 232 return code_.ToHandleChecked(); 233 } 234 235 protected: MakeNode(const Operator * op,int value_input_count,Node ** value_inputs)236 Node* MakeNode(const Operator* op, int value_input_count, 237 Node** value_inputs) { 238 CHECK_EQ(op->ValueInputCount(), value_input_count); 239 240 CHECK(!OperatorProperties::HasContextInput(op)); 241 CHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op)); 242 bool has_control = op->ControlInputCount() == 1; 243 bool has_effect = op->EffectInputCount() == 1; 244 245 CHECK_LT(op->ControlInputCount(), 2); 246 CHECK_LT(op->EffectInputCount(), 2); 247 248 Node* result = NULL; 249 if (!has_control && !has_effect) { 250 result = graph()->NewNode(op, value_input_count, value_inputs); 251 } else { 252 int input_count_with_deps = value_input_count; 253 if (has_control) ++input_count_with_deps; 254 if (has_effect) ++input_count_with_deps; 255 Node** buffer = zone()->template NewArray<Node*>(input_count_with_deps); 256 memcpy(buffer, value_inputs, kPointerSize * value_input_count); 257 Node** current_input = buffer + value_input_count; 258 if (has_effect) { 259 *current_input++ = effect_; 260 } 261 if (has_control) { 262 *current_input++ = graph()->start(); 263 } 264 result = graph()->NewNode(op, input_count_with_deps, buffer); 265 if (has_effect) { 266 effect_ = result; 267 } 268 // This graph builder does not support control flow. 269 CHECK_EQ(0, op->ControlOutputCount()); 270 } 271 272 return result; 273 } 274 Generate()275 virtual byte* Generate() { 276 if (code_.is_null()) { 277 Zone* zone = graph()->zone(); 278 CallDescriptor* desc = 279 Linkage::GetSimplifiedCDescriptor(zone, this->csig_); 280 CompilationInfo info("testing", main_isolate(), main_zone()); 281 code_ = Pipeline::GenerateCodeForTesting(&info, desc, graph()); 282 #ifdef ENABLE_DISASSEMBLER 283 if (!code_.is_null() && FLAG_print_opt_code) { 284 OFStream os(stdout); 285 code_.ToHandleChecked()->Disassemble("test code", os); 286 } 287 #endif 288 } 289 return code_.ToHandleChecked()->entry(); 290 } 291 InitParameters()292 void InitParameters() { 293 int param_count = static_cast<int>(parameter_count()); 294 for (int i = 0; i < param_count; ++i) { 295 parameters_[i] = this->NewNode(common()->Parameter(i), graph()->start()); 296 } 297 } 298 parameter_count()299 size_t parameter_count() const { return this->csig_->parameter_count(); } 300 301 private: 302 Node* effect_; 303 Node* return_; 304 Node** parameters_; 305 MaybeHandle<Code> code_; 306 }; 307 308 } // namespace compiler 309 } // namespace internal 310 } // namespace v8 311 312 #endif // V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_ 313