| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/utils/random-number-generator.h" | 5 #include "src/base/utils/random-number-generator.h" |
| 6 #include "src/compiler/pipeline.h" | 6 #include "src/compiler/pipeline.h" |
| 7 #include "test/unittests/compiler/instruction-sequence-unittest.h" | 7 #include "test/unittests/compiler/instruction-sequence-unittest.h" |
| 8 #include "test/unittests/test-utils.h" | 8 #include "test/unittests/test-utils.h" |
| 9 #include "testing/gmock/include/gmock/gmock.h" | 9 #include "testing/gmock/include/gmock/gmock.h" |
| 10 | 10 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 *loc++ = 0; | 33 *loc++ = 0; |
| 34 } | 34 } |
| 35 } | 35 } |
| 36 | 36 |
| 37 | 37 |
| 38 InstructionSequenceTest::InstructionSequenceTest() | 38 InstructionSequenceTest::InstructionSequenceTest() |
| 39 : sequence_(nullptr), | 39 : sequence_(nullptr), |
| 40 num_general_registers_(kDefaultNRegs), | 40 num_general_registers_(kDefaultNRegs), |
| 41 num_double_registers_(kDefaultNRegs), | 41 num_double_registers_(kDefaultNRegs), |
| 42 instruction_blocks_(zone()), | 42 instruction_blocks_(zone()), |
| 43 current_instruction_index_(-1), | |
| 44 current_block_(nullptr), | 43 current_block_(nullptr), |
| 45 block_returns_(false) { | 44 block_returns_(false) { |
| 46 InitializeRegisterNames(); | 45 InitializeRegisterNames(); |
| 47 } | 46 } |
| 48 | 47 |
| 49 | 48 |
| 50 void InstructionSequenceTest::SetNumRegs(int num_general_registers, | 49 void InstructionSequenceTest::SetNumRegs(int num_general_registers, |
| 51 int num_double_registers) { | 50 int num_double_registers) { |
| 52 CHECK(config_.is_empty()); | 51 CHECK(config_.is_empty()); |
| 53 CHECK(instructions_.empty()); | 52 CHECK(instructions_.empty()); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 loop_blocks_.pop_back(); | 92 loop_blocks_.pop_back(); |
| 94 } | 93 } |
| 95 | 94 |
| 96 | 95 |
| 97 void InstructionSequenceTest::StartBlock() { | 96 void InstructionSequenceTest::StartBlock() { |
| 98 block_returns_ = false; | 97 block_returns_ = false; |
| 99 NewBlock(); | 98 NewBlock(); |
| 100 } | 99 } |
| 101 | 100 |
| 102 | 101 |
| 103 int InstructionSequenceTest::EndBlock(BlockCompletion completion) { | 102 Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) { |
| 104 int instruction_index = kMinInt; | 103 Instruction* result = nullptr; |
| 105 if (block_returns_) { | 104 if (block_returns_) { |
| 106 CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough); | 105 CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough); |
| 107 completion.type_ = kBlockEnd; | 106 completion.type_ = kBlockEnd; |
| 108 } | 107 } |
| 109 switch (completion.type_) { | 108 switch (completion.type_) { |
| 110 case kBlockEnd: | 109 case kBlockEnd: |
| 111 break; | 110 break; |
| 112 case kFallThrough: | 111 case kFallThrough: |
| 113 instruction_index = EmitFallThrough(); | 112 result = EmitFallThrough(); |
| 114 break; | 113 break; |
| 115 case kJump: | 114 case kJump: |
| 116 CHECK(!block_returns_); | 115 CHECK(!block_returns_); |
| 117 instruction_index = EmitJump(); | 116 result = EmitJump(); |
| 118 break; | 117 break; |
| 119 case kBranch: | 118 case kBranch: |
| 120 CHECK(!block_returns_); | 119 CHECK(!block_returns_); |
| 121 instruction_index = EmitBranch(completion.op_); | 120 result = EmitBranch(completion.op_); |
| 122 break; | 121 break; |
| 123 } | 122 } |
| 124 completions_.push_back(completion); | 123 completions_.push_back(completion); |
| 125 CHECK(current_block_ != nullptr); | 124 CHECK(current_block_ != nullptr); |
| 126 sequence()->EndBlock(current_block_->rpo_number()); | 125 sequence()->EndBlock(current_block_->rpo_number()); |
| 127 current_block_ = nullptr; | 126 current_block_ = nullptr; |
| 128 return instruction_index; | 127 return result; |
| 129 } | 128 } |
| 130 | 129 |
| 131 | 130 |
| 132 InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) { | 131 InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) { |
| 133 int index = sequence()->AddImmediate(Constant(imm)); | 132 int index = sequence()->AddImmediate(Constant(imm)); |
| 134 return TestOperand(kImmediate, index); | 133 return TestOperand(kImmediate, index); |
| 135 } | 134 } |
| 136 | 135 |
| 137 | 136 |
| 138 InstructionSequenceTest::VReg InstructionSequenceTest::Define( | 137 InstructionSequenceTest::VReg InstructionSequenceTest::Define( |
| 139 TestOperand output_op) { | 138 TestOperand output_op) { |
| 140 VReg vreg = NewReg(); | 139 VReg vreg = NewReg(); |
| 141 InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)}; | 140 InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)}; |
| 142 Emit(vreg.value_, kArchNop, 1, outputs); | 141 Emit(kArchNop, 1, outputs); |
| 143 return vreg; | 142 return vreg; |
| 144 } | 143 } |
| 145 | 144 |
| 146 | 145 |
| 147 int InstructionSequenceTest::Return(TestOperand input_op_0) { | 146 Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) { |
| 148 block_returns_ = true; | 147 block_returns_ = true; |
| 149 InstructionOperand inputs[1]{ConvertInputOp(input_op_0)}; | 148 InstructionOperand inputs[1]{ConvertInputOp(input_op_0)}; |
| 150 return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs); | 149 return Emit(kArchRet, 0, nullptr, 1, inputs); |
| 151 } | 150 } |
| 152 | 151 |
| 153 | 152 |
| 154 PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0, | 153 PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0, |
| 155 VReg incoming_vreg_1, | 154 VReg incoming_vreg_1, |
| 156 VReg incoming_vreg_2, | 155 VReg incoming_vreg_2, |
| 157 VReg incoming_vreg_3) { | 156 VReg incoming_vreg_3) { |
| 158 VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2, | 157 VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2, |
| 159 incoming_vreg_3}; | 158 incoming_vreg_3}; |
| 160 size_t input_count = 0; | 159 size_t input_count = 0; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 185 CHECK(vreg.value_ != kNoValue); | 184 CHECK(vreg.value_ != kNoValue); |
| 186 phi->SetInput(input, vreg.value_); | 185 phi->SetInput(input, vreg.value_); |
| 187 } | 186 } |
| 188 | 187 |
| 189 | 188 |
| 190 InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant( | 189 InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant( |
| 191 int32_t imm) { | 190 int32_t imm) { |
| 192 VReg vreg = NewReg(); | 191 VReg vreg = NewReg(); |
| 193 sequence()->AddConstant(vreg.value_, Constant(imm)); | 192 sequence()->AddConstant(vreg.value_, Constant(imm)); |
| 194 InstructionOperand outputs[1]{ConstantOperand(vreg.value_)}; | 193 InstructionOperand outputs[1]{ConstantOperand(vreg.value_)}; |
| 195 Emit(vreg.value_, kArchNop, 1, outputs); | 194 Emit(kArchNop, 1, outputs); |
| 196 return vreg; | 195 return vreg; |
| 197 } | 196 } |
| 198 | 197 |
| 199 | 198 |
| 200 int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); } | 199 Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); } |
| 201 | 200 |
| 202 | 201 |
| 203 static size_t CountInputs(size_t size, | 202 static size_t CountInputs(size_t size, |
| 204 InstructionSequenceTest::TestOperand* inputs) { | 203 InstructionSequenceTest::TestOperand* inputs) { |
| 205 size_t i = 0; | 204 size_t i = 0; |
| 206 for (; i < size; ++i) { | 205 for (; i < size; ++i) { |
| 207 if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break; | 206 if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break; |
| 208 } | 207 } |
| 209 return i; | 208 return i; |
| 210 } | 209 } |
| 211 | 210 |
| 212 | 211 |
| 213 int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) { | 212 Instruction* InstructionSequenceTest::EmitI(size_t input_size, |
| 213 TestOperand* inputs) { |
| 214 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); | 214 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); |
| 215 return Emit(NewIndex(), kArchNop, 0, nullptr, input_size, mapped_inputs); | 215 return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs); |
| 216 } | 216 } |
| 217 | 217 |
| 218 | 218 |
| 219 int InstructionSequenceTest::EmitI(TestOperand input_op_0, | 219 Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0, |
| 220 TestOperand input_op_1, | 220 TestOperand input_op_1, |
| 221 TestOperand input_op_2, | 221 TestOperand input_op_2, |
| 222 TestOperand input_op_3) { | 222 TestOperand input_op_3) { |
| 223 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; | 223 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; |
| 224 return EmitI(CountInputs(arraysize(inputs), inputs), inputs); | 224 return EmitI(CountInputs(arraysize(inputs), inputs), inputs); |
| 225 } | 225 } |
| 226 | 226 |
| 227 | 227 |
| 228 InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( | 228 InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( |
| 229 TestOperand output_op, size_t input_size, TestOperand* inputs) { | 229 TestOperand output_op, size_t input_size, TestOperand* inputs) { |
| 230 VReg output_vreg = NewReg(); | 230 VReg output_vreg = NewReg(); |
| 231 InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)}; | 231 InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)}; |
| 232 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); | 232 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); |
| 233 Emit(output_vreg.value_, kArchNop, 1, outputs, input_size, mapped_inputs); | 233 Emit(kArchNop, 1, outputs, input_size, mapped_inputs); |
| 234 return output_vreg; | 234 return output_vreg; |
| 235 } | 235 } |
| 236 | 236 |
| 237 | 237 |
| 238 InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( | 238 InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( |
| 239 TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, | 239 TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, |
| 240 TestOperand input_op_2, TestOperand input_op_3) { | 240 TestOperand input_op_2, TestOperand input_op_3) { |
| 241 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; | 241 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; |
| 242 return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs); | 242 return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs); |
| 243 } | 243 } |
| 244 | 244 |
| 245 | 245 |
| 246 InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( |
| 247 TestOperand output_op_0, TestOperand output_op_1, size_t input_size, |
| 248 TestOperand* inputs) { |
| 249 VRegPair output_vregs = std::make_pair(NewReg(), NewReg()); |
| 250 InstructionOperand outputs[2]{ |
| 251 ConvertOutputOp(output_vregs.first, output_op_0), |
| 252 ConvertOutputOp(output_vregs.second, output_op_1)}; |
| 253 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); |
| 254 Emit(kArchNop, 2, outputs, input_size, mapped_inputs); |
| 255 return output_vregs; |
| 256 } |
| 257 |
| 258 |
| 259 InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( |
| 260 TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0, |
| 261 TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) { |
| 262 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; |
| 263 return EmitOOI(output_op_0, output_op_1, |
| 264 CountInputs(arraysize(inputs), inputs), inputs); |
| 265 } |
| 266 |
| 267 |
| 246 InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( | 268 InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( |
| 247 TestOperand output_op, size_t input_size, TestOperand* inputs) { | 269 TestOperand output_op, size_t input_size, TestOperand* inputs) { |
| 248 VReg output_vreg = NewReg(); | 270 VReg output_vreg = NewReg(); |
| 249 InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)}; | 271 InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)}; |
| 250 CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy()); | 272 CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy()); |
| 251 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); | 273 InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); |
| 252 Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size, | 274 Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr, |
| 253 mapped_inputs, 0, nullptr, true); | 275 true); |
| 254 return output_vreg; | 276 return output_vreg; |
| 255 } | 277 } |
| 256 | 278 |
| 257 | 279 |
| 258 InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( | 280 InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( |
| 259 TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, | 281 TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, |
| 260 TestOperand input_op_2, TestOperand input_op_3) { | 282 TestOperand input_op_2, TestOperand input_op_3) { |
| 261 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; | 283 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; |
| 262 return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs); | 284 return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs); |
| 263 } | 285 } |
| 264 | 286 |
| 265 | 287 |
| 266 const Instruction* InstructionSequenceTest::GetInstruction( | 288 Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) { |
| 267 int instruction_index) { | |
| 268 auto it = instructions_.find(instruction_index); | |
| 269 CHECK(it != instructions_.end()); | |
| 270 return it->second; | |
| 271 } | |
| 272 | |
| 273 | |
| 274 int InstructionSequenceTest::EmitBranch(TestOperand input_op) { | |
| 275 InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()), | 289 InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()), |
| 276 ConvertInputOp(Imm()), ConvertInputOp(Imm())}; | 290 ConvertInputOp(Imm()), ConvertInputOp(Imm())}; |
| 277 InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) | | 291 InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) | |
| 278 FlagsConditionField::encode(kEqual); | 292 FlagsConditionField::encode(kEqual); |
| 279 auto instruction = | 293 auto instruction = |
| 280 NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl(); | 294 NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl(); |
| 281 return AddInstruction(NewIndex(), instruction); | 295 return AddInstruction(instruction); |
| 282 } | 296 } |
| 283 | 297 |
| 284 | 298 |
| 285 int InstructionSequenceTest::EmitFallThrough() { | 299 Instruction* InstructionSequenceTest::EmitFallThrough() { |
| 286 auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl(); | 300 auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl(); |
| 287 return AddInstruction(NewIndex(), instruction); | 301 return AddInstruction(instruction); |
| 288 } | 302 } |
| 289 | 303 |
| 290 | 304 |
| 291 int InstructionSequenceTest::EmitJump() { | 305 Instruction* InstructionSequenceTest::EmitJump() { |
| 292 InstructionOperand inputs[1]{ConvertInputOp(Imm())}; | 306 InstructionOperand inputs[1]{ConvertInputOp(Imm())}; |
| 293 auto instruction = | 307 auto instruction = |
| 294 NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl(); | 308 NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl(); |
| 295 return AddInstruction(NewIndex(), instruction); | 309 return AddInstruction(instruction); |
| 296 } | 310 } |
| 297 | 311 |
| 298 | 312 |
| 299 Instruction* InstructionSequenceTest::NewInstruction( | 313 Instruction* InstructionSequenceTest::NewInstruction( |
| 300 InstructionCode code, size_t outputs_size, InstructionOperand* outputs, | 314 InstructionCode code, size_t outputs_size, InstructionOperand* outputs, |
| 301 size_t inputs_size, InstructionOperand* inputs, size_t temps_size, | 315 size_t inputs_size, InstructionOperand* inputs, size_t temps_size, |
| 302 InstructionOperand* temps) { | 316 InstructionOperand* temps) { |
| 303 CHECK(current_block_); | 317 CHECK(current_block_); |
| 304 return Instruction::New(zone(), code, outputs_size, outputs, inputs_size, | 318 return Instruction::New(zone(), code, outputs_size, outputs, inputs_size, |
| 305 inputs, temps_size, temps); | 319 inputs, temps_size, temps); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset); | 465 size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset); |
| 452 CHECK(block_offset < instruction_blocks_.size()); | 466 CHECK(block_offset < instruction_blocks_.size()); |
| 453 CHECK(target_block_offset < instruction_blocks_.size()); | 467 CHECK(target_block_offset < instruction_blocks_.size()); |
| 454 auto block = instruction_blocks_[block_offset]; | 468 auto block = instruction_blocks_[block_offset]; |
| 455 auto target = instruction_blocks_[target_block_offset]; | 469 auto target = instruction_blocks_[target_block_offset]; |
| 456 block->successors().push_back(target->rpo_number()); | 470 block->successors().push_back(target->rpo_number()); |
| 457 target->predecessors().push_back(block->rpo_number()); | 471 target->predecessors().push_back(block->rpo_number()); |
| 458 } | 472 } |
| 459 | 473 |
| 460 | 474 |
| 461 int InstructionSequenceTest::Emit(int instruction_index, InstructionCode code, | 475 Instruction* InstructionSequenceTest::Emit( |
| 462 size_t outputs_size, | 476 InstructionCode code, size_t outputs_size, InstructionOperand* outputs, |
| 463 InstructionOperand* outputs, | 477 size_t inputs_size, InstructionOperand* inputs, size_t temps_size, |
| 464 size_t inputs_size, | 478 InstructionOperand* temps, bool is_call) { |
| 465 InstructionOperand* inputs, size_t temps_size, | |
| 466 InstructionOperand* temps, bool is_call) { | |
| 467 auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size, | 479 auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size, |
| 468 inputs, temps_size, temps); | 480 inputs, temps_size, temps); |
| 469 if (is_call) instruction->MarkAsCall(); | 481 if (is_call) instruction->MarkAsCall(); |
| 470 return AddInstruction(instruction_index, instruction); | 482 return AddInstruction(instruction); |
| 471 } | 483 } |
| 472 | 484 |
| 473 | 485 |
| 474 int InstructionSequenceTest::AddInstruction(int instruction_index, | 486 Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) { |
| 475 Instruction* instruction) { | |
| 476 sequence()->AddInstruction(instruction); | 487 sequence()->AddInstruction(instruction); |
| 477 return instruction_index; | 488 return instruction; |
| 478 } | 489 } |
| 479 | 490 |
| 480 } // namespace compiler | 491 } // namespace compiler |
| 481 } // namespace internal | 492 } // namespace internal |
| 482 } // namespace v8 | 493 } // namespace v8 |
| OLD | NEW |