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