OLD | NEW |
(Empty) | |
| 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/v8.h" |
| 6 #include "test/cctest/cctest.h" |
| 7 |
| 8 #include "src/compiler/code-generator.h" |
| 9 #include "src/compiler/common-operator.h" |
| 10 #include "src/compiler/graph.h" |
| 11 #include "src/compiler/instruction.h" |
| 12 #include "src/compiler/machine-operator.h" |
| 13 #include "src/compiler/node.h" |
| 14 #include "src/compiler/operator.h" |
| 15 #include "src/compiler/schedule.h" |
| 16 #include "src/compiler/scheduler.h" |
| 17 #include "src/lithium.h" |
| 18 |
| 19 using namespace v8::internal; |
| 20 using namespace v8::internal::compiler; |
| 21 |
| 22 typedef v8::internal::compiler::Instruction TestInstr; |
| 23 typedef v8::internal::compiler::InstructionSequence TestInstrSeq; |
| 24 |
| 25 // A testing helper for the register code abstraction. |
| 26 class InstructionTester : public HandleAndZoneScope { |
| 27 public: // We're all friends here. |
| 28 explicit InstructionTester() |
| 29 : isolate(main_isolate()), |
| 30 graph(zone()), |
| 31 schedule(zone()), |
| 32 info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()), |
| 33 linkage(&info), |
| 34 common(zone()), |
| 35 machine(zone(), kMachineWord32), |
| 36 code(NULL) {} |
| 37 |
| 38 Isolate* isolate; |
| 39 Graph graph; |
| 40 Schedule schedule; |
| 41 CompilationInfoWithZone info; |
| 42 Linkage linkage; |
| 43 CommonOperatorBuilder common; |
| 44 MachineOperatorBuilder machine; |
| 45 TestInstrSeq* code; |
| 46 |
| 47 Zone* zone() { return main_zone(); } |
| 48 |
| 49 void allocCode() { |
| 50 if (schedule.rpo_order()->size() == 0) { |
| 51 // Compute the RPO order. |
| 52 Scheduler scheduler(zone(), &graph, &schedule); |
| 53 scheduler.ComputeSpecialRPO(); |
| 54 ASSERT(schedule.rpo_order()->size() > 0); |
| 55 } |
| 56 code = new TestInstrSeq(&linkage, &graph, &schedule); |
| 57 } |
| 58 |
| 59 Node* Int32Constant(int32_t val) { |
| 60 Node* node = graph.NewNode(common.Int32Constant(val)); |
| 61 schedule.AddNode(schedule.entry(), node); |
| 62 return node; |
| 63 } |
| 64 |
| 65 Node* Float64Constant(double val) { |
| 66 Node* node = graph.NewNode(common.Float64Constant(val)); |
| 67 schedule.AddNode(schedule.entry(), node); |
| 68 return node; |
| 69 } |
| 70 |
| 71 Node* Parameter(int32_t which) { |
| 72 Node* node = graph.NewNode(common.Parameter(which)); |
| 73 schedule.AddNode(schedule.entry(), node); |
| 74 return node; |
| 75 } |
| 76 |
| 77 Node* NewNode(BasicBlock* block) { |
| 78 Node* node = graph.NewNode(common.Int32Constant(111)); |
| 79 schedule.AddNode(block, node); |
| 80 return node; |
| 81 } |
| 82 |
| 83 int NewInstr(BasicBlock* block) { |
| 84 InstructionCode opcode = static_cast<InstructionCode>(110); |
| 85 TestInstr* instr = TestInstr::New(zone(), opcode); |
| 86 return code->AddInstruction(instr, block); |
| 87 } |
| 88 |
| 89 UnallocatedOperand* NewUnallocated(int vreg) { |
| 90 UnallocatedOperand* unallocated = |
| 91 new (zone()) UnallocatedOperand(UnallocatedOperand::ANY); |
| 92 unallocated->set_virtual_register(vreg); |
| 93 return unallocated; |
| 94 } |
| 95 }; |
| 96 |
| 97 |
| 98 TEST(InstructionBasic) { |
| 99 InstructionTester R; |
| 100 |
| 101 for (int i = 0; i < 10; i++) { |
| 102 R.Int32Constant(i); // Add some nodes to the graph. |
| 103 } |
| 104 |
| 105 BasicBlock* last = R.schedule.entry(); |
| 106 for (int i = 0; i < 5; i++) { |
| 107 BasicBlock* block = R.schedule.NewBasicBlock(); |
| 108 R.schedule.AddGoto(last, block); |
| 109 last = block; |
| 110 } |
| 111 |
| 112 R.allocCode(); |
| 113 |
| 114 CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount()); |
| 115 |
| 116 BasicBlockVector* blocks = R.schedule.rpo_order(); |
| 117 CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount()); |
| 118 |
| 119 int index = 0; |
| 120 for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end(); |
| 121 i++, index++) { |
| 122 BasicBlock* block = *i; |
| 123 CHECK_EQ(block, R.code->BlockAt(index)); |
| 124 CHECK_EQ(-1, R.code->GetLoopEnd(block)); |
| 125 } |
| 126 } |
| 127 |
| 128 |
| 129 TEST(InstructionGetBasicBlock) { |
| 130 InstructionTester R; |
| 131 |
| 132 BasicBlock* b0 = R.schedule.entry(); |
| 133 BasicBlock* b1 = R.schedule.NewBasicBlock(); |
| 134 BasicBlock* b2 = R.schedule.NewBasicBlock(); |
| 135 BasicBlock* b3 = R.schedule.exit(); |
| 136 |
| 137 R.schedule.AddGoto(b0, b1); |
| 138 R.schedule.AddGoto(b1, b2); |
| 139 R.schedule.AddGoto(b2, b3); |
| 140 |
| 141 R.allocCode(); |
| 142 |
| 143 R.code->StartBlock(b0); |
| 144 int i0 = R.NewInstr(b0); |
| 145 int i1 = R.NewInstr(b0); |
| 146 R.code->EndBlock(b0); |
| 147 R.code->StartBlock(b1); |
| 148 int i2 = R.NewInstr(b1); |
| 149 int i3 = R.NewInstr(b1); |
| 150 int i4 = R.NewInstr(b1); |
| 151 int i5 = R.NewInstr(b1); |
| 152 R.code->EndBlock(b1); |
| 153 R.code->StartBlock(b2); |
| 154 int i6 = R.NewInstr(b2); |
| 155 int i7 = R.NewInstr(b2); |
| 156 int i8 = R.NewInstr(b2); |
| 157 R.code->EndBlock(b2); |
| 158 R.code->StartBlock(b3); |
| 159 R.code->EndBlock(b3); |
| 160 |
| 161 CHECK_EQ(b0, R.code->GetBasicBlock(i0)); |
| 162 CHECK_EQ(b0, R.code->GetBasicBlock(i1)); |
| 163 |
| 164 CHECK_EQ(b1, R.code->GetBasicBlock(i2)); |
| 165 CHECK_EQ(b1, R.code->GetBasicBlock(i3)); |
| 166 CHECK_EQ(b1, R.code->GetBasicBlock(i4)); |
| 167 CHECK_EQ(b1, R.code->GetBasicBlock(i5)); |
| 168 |
| 169 CHECK_EQ(b2, R.code->GetBasicBlock(i6)); |
| 170 CHECK_EQ(b2, R.code->GetBasicBlock(i7)); |
| 171 CHECK_EQ(b2, R.code->GetBasicBlock(i8)); |
| 172 |
| 173 CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index())); |
| 174 CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index())); |
| 175 |
| 176 CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index())); |
| 177 CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index())); |
| 178 |
| 179 CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index())); |
| 180 CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index())); |
| 181 |
| 182 CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index())); |
| 183 CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index())); |
| 184 } |
| 185 |
| 186 |
| 187 TEST(InstructionIsGapAt) { |
| 188 InstructionTester R; |
| 189 |
| 190 BasicBlock* b0 = R.schedule.entry(); |
| 191 R.schedule.AddReturn(b0, R.Int32Constant(1)); |
| 192 |
| 193 R.allocCode(); |
| 194 TestInstr* i0 = TestInstr::New(R.zone(), 100); |
| 195 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); |
| 196 R.code->StartBlock(b0); |
| 197 R.code->AddInstruction(i0, b0); |
| 198 R.code->AddInstruction(g, b0); |
| 199 R.code->EndBlock(b0); |
| 200 |
| 201 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart()); |
| 202 |
| 203 CHECK_EQ(true, R.code->IsGapAt(0)); // Label |
| 204 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap |
| 205 CHECK_EQ(false, R.code->IsGapAt(2)); // i0 |
| 206 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap |
| 207 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap |
| 208 CHECK_EQ(false, R.code->IsGapAt(5)); // g |
| 209 } |
| 210 |
| 211 |
| 212 TEST(InstructionIsGapAt2) { |
| 213 InstructionTester R; |
| 214 |
| 215 BasicBlock* b0 = R.schedule.entry(); |
| 216 BasicBlock* b1 = R.schedule.exit(); |
| 217 R.schedule.AddGoto(b0, b1); |
| 218 R.schedule.AddReturn(b1, R.Int32Constant(1)); |
| 219 |
| 220 R.allocCode(); |
| 221 TestInstr* i0 = TestInstr::New(R.zone(), 100); |
| 222 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); |
| 223 R.code->StartBlock(b0); |
| 224 R.code->AddInstruction(i0, b0); |
| 225 R.code->AddInstruction(g, b0); |
| 226 R.code->EndBlock(b0); |
| 227 |
| 228 TestInstr* i1 = TestInstr::New(R.zone(), 102); |
| 229 TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl(); |
| 230 R.code->StartBlock(b1); |
| 231 R.code->AddInstruction(i1, b1); |
| 232 R.code->AddInstruction(g1, b1); |
| 233 R.code->EndBlock(b1); |
| 234 |
| 235 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart()); |
| 236 |
| 237 CHECK_EQ(true, R.code->IsGapAt(0)); // Label |
| 238 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap |
| 239 CHECK_EQ(false, R.code->IsGapAt(2)); // i0 |
| 240 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap |
| 241 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap |
| 242 CHECK_EQ(false, R.code->IsGapAt(5)); // g |
| 243 |
| 244 CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart()); |
| 245 |
| 246 CHECK_EQ(true, R.code->IsGapAt(6)); // Label |
| 247 CHECK_EQ(true, R.code->IsGapAt(7)); // Gap |
| 248 CHECK_EQ(false, R.code->IsGapAt(8)); // i1 |
| 249 CHECK_EQ(true, R.code->IsGapAt(9)); // Gap |
| 250 CHECK_EQ(true, R.code->IsGapAt(10)); // Gap |
| 251 CHECK_EQ(false, R.code->IsGapAt(11)); // g1 |
| 252 } |
| 253 |
| 254 |
| 255 TEST(InstructionAddGapMove) { |
| 256 InstructionTester R; |
| 257 |
| 258 BasicBlock* b0 = R.schedule.entry(); |
| 259 R.schedule.AddReturn(b0, R.Int32Constant(1)); |
| 260 |
| 261 R.allocCode(); |
| 262 TestInstr* i0 = TestInstr::New(R.zone(), 100); |
| 263 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); |
| 264 R.code->StartBlock(b0); |
| 265 R.code->AddInstruction(i0, b0); |
| 266 R.code->AddInstruction(g, b0); |
| 267 R.code->EndBlock(b0); |
| 268 |
| 269 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart()); |
| 270 |
| 271 CHECK_EQ(true, R.code->IsGapAt(0)); // Label |
| 272 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap |
| 273 CHECK_EQ(false, R.code->IsGapAt(2)); // i0 |
| 274 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap |
| 275 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap |
| 276 CHECK_EQ(false, R.code->IsGapAt(5)); // g |
| 277 |
| 278 int indexes[] = {0, 1, 3, 4, -1}; |
| 279 for (int i = 0; indexes[i] >= 0; i++) { |
| 280 int index = indexes[i]; |
| 281 |
| 282 UnallocatedOperand* op1 = R.NewUnallocated(index + 6); |
| 283 UnallocatedOperand* op2 = R.NewUnallocated(index + 12); |
| 284 |
| 285 R.code->AddGapMove(index, op1, op2); |
| 286 GapInstruction* gap = R.code->GapAt(index); |
| 287 ParallelMove* move = gap->GetParallelMove(GapInstruction::START); |
| 288 CHECK_NE(NULL, move); |
| 289 const ZoneList<MoveOperands>* move_operands = move->move_operands(); |
| 290 CHECK_EQ(1, move_operands->length()); |
| 291 MoveOperands* cur = &move_operands->at(0); |
| 292 CHECK_EQ(op1, cur->source()); |
| 293 CHECK_EQ(op2, cur->destination()); |
| 294 } |
| 295 } |
| 296 |
| 297 |
| 298 TEST(InstructionOperands) { |
| 299 Zone zone(CcTest::InitIsolateOnce()); |
| 300 |
| 301 { |
| 302 TestInstr* i = TestInstr::New(&zone, 101); |
| 303 CHECK_EQ(0, i->OutputCount()); |
| 304 CHECK_EQ(0, i->InputCount()); |
| 305 CHECK_EQ(0, i->TempCount()); |
| 306 } |
| 307 |
| 308 InstructionOperand* outputs[] = { |
| 309 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 310 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 311 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 312 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)}; |
| 313 |
| 314 InstructionOperand* inputs[] = { |
| 315 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 316 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 317 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 318 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)}; |
| 319 |
| 320 InstructionOperand* temps[] = { |
| 321 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 322 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 323 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), |
| 324 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)}; |
| 325 |
| 326 for (size_t i = 0; i < ARRAY_SIZE(outputs); i++) { |
| 327 for (size_t j = 0; j < ARRAY_SIZE(inputs); j++) { |
| 328 for (size_t k = 0; k < ARRAY_SIZE(temps); k++) { |
| 329 TestInstr* m = |
| 330 TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps); |
| 331 CHECK(i == m->OutputCount()); |
| 332 CHECK(j == m->InputCount()); |
| 333 CHECK(k == m->TempCount()); |
| 334 |
| 335 for (size_t z = 0; z < i; z++) { |
| 336 CHECK_EQ(outputs[z], m->OutputAt(z)); |
| 337 } |
| 338 |
| 339 for (size_t z = 0; z < j; z++) { |
| 340 CHECK_EQ(inputs[z], m->InputAt(z)); |
| 341 } |
| 342 |
| 343 for (size_t z = 0; z < k; z++) { |
| 344 CHECK_EQ(temps[z], m->TempAt(z)); |
| 345 } |
| 346 } |
| 347 } |
| 348 } |
| 349 } |
OLD | NEW |