Line data Source code
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/base/utils/random-number-generator.h"
6 : #include "src/compiler/pipeline.h"
7 : #include "test/unittests/compiler/instruction-sequence-unittest.h"
8 : #include "test/unittests/test-utils.h"
9 : #include "testing/gmock/include/gmock/gmock.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 : namespace compiler {
14 :
15 : static const char*
16 : general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
17 : static const char*
18 : double_register_names_[RegisterConfiguration::kMaxFPRegisters];
19 : static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
20 : RegisterConfiguration::kMaxFPRegisters)];
21 :
22 : namespace {
23 : static int allocatable_codes[InstructionSequenceTest::kDefaultNRegs] = {
24 : 0, 1, 2, 3, 4, 5, 6, 7};
25 : }
26 :
27 52 : static void InitializeRegisterNames() {
28 : char* loc = register_names_;
29 1716 : for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
30 1664 : general_register_names_[i] = loc;
31 1664 : loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
32 1664 : *loc++ = 0;
33 : }
34 1664 : for (int i = 0; i < RegisterConfiguration::kMaxFPRegisters; ++i) {
35 1664 : double_register_names_[i] = loc;
36 1664 : loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
37 1664 : *loc++ = 0;
38 : }
39 52 : }
40 :
41 52 : InstructionSequenceTest::InstructionSequenceTest()
42 : : sequence_(nullptr),
43 : num_general_registers_(kDefaultNRegs),
44 : num_double_registers_(kDefaultNRegs),
45 : instruction_blocks_(zone()),
46 : current_block_(nullptr),
47 104 : block_returns_(false) {
48 52 : InitializeRegisterNames();
49 52 : }
50 :
51 :
52 3 : void InstructionSequenceTest::SetNumRegs(int num_general_registers,
53 : int num_double_registers) {
54 3 : CHECK(!config_);
55 3 : CHECK(instructions_.empty());
56 3 : CHECK(instruction_blocks_.empty());
57 3 : num_general_registers_ = num_general_registers;
58 3 : num_double_registers_ = num_double_registers;
59 3 : }
60 :
61 258 : int InstructionSequenceTest::GetNumRegs(MachineRepresentation rep) {
62 258 : switch (rep) {
63 : case MachineRepresentation::kFloat32:
64 30 : return config()->num_float_registers();
65 : case MachineRepresentation::kFloat64:
66 34 : return config()->num_double_registers();
67 : case MachineRepresentation::kSimd128:
68 31 : return config()->num_simd128_registers();
69 : default:
70 163 : return config()->num_general_registers();
71 : }
72 : }
73 :
74 8 : int InstructionSequenceTest::GetAllocatableCode(int index,
75 : MachineRepresentation rep) {
76 8 : switch (rep) {
77 : case MachineRepresentation::kFloat32:
78 4 : return config()->GetAllocatableFloatCode(index);
79 : case MachineRepresentation::kFloat64:
80 4 : return config()->GetAllocatableDoubleCode(index);
81 : case MachineRepresentation::kSimd128:
82 4 : return config()->GetAllocatableSimd128Code(index);
83 : default:
84 4 : return config()->GetAllocatableGeneralCode(index);
85 : }
86 : }
87 :
88 360 : const RegisterConfiguration* InstructionSequenceTest::config() {
89 360 : if (!config_) {
90 : config_.reset(new RegisterConfiguration(
91 : num_general_registers_, num_double_registers_, num_general_registers_,
92 : num_double_registers_, allocatable_codes, allocatable_codes,
93 : kSimpleFPAliasing ? RegisterConfiguration::OVERLAP
94 : : RegisterConfiguration::COMBINE,
95 : general_register_names_,
96 : double_register_names_, // float register names
97 : double_register_names_,
98 52 : double_register_names_)); // SIMD 128 register names
99 : }
100 360 : return config_.get();
101 : }
102 :
103 :
104 1217 : InstructionSequence* InstructionSequenceTest::sequence() {
105 1217 : if (sequence_ == nullptr) {
106 : sequence_ = new (zone())
107 104 : InstructionSequence(isolate(), zone(), &instruction_blocks_);
108 : sequence_->SetRegisterConfigurationForTesting(
109 52 : InstructionSequenceTest::config());
110 : }
111 1217 : return sequence_;
112 : }
113 :
114 :
115 3 : void InstructionSequenceTest::StartLoop(int loop_blocks) {
116 3 : CHECK_NULL(current_block_);
117 3 : if (!loop_blocks_.empty()) {
118 0 : CHECK(!loop_blocks_.back().loop_header_.IsValid());
119 : }
120 3 : LoopData loop_data = {Rpo::Invalid(), loop_blocks};
121 3 : loop_blocks_.push_back(loop_data);
122 3 : }
123 :
124 :
125 3 : void InstructionSequenceTest::EndLoop() {
126 3 : CHECK_NULL(current_block_);
127 3 : CHECK(!loop_blocks_.empty());
128 3 : CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
129 : loop_blocks_.pop_back();
130 3 : }
131 :
132 :
133 122 : void InstructionSequenceTest::StartBlock(bool deferred) {
134 122 : block_returns_ = false;
135 122 : NewBlock(deferred);
136 122 : }
137 :
138 :
139 122 : Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) {
140 : Instruction* result = nullptr;
141 122 : if (block_returns_) {
142 16 : CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
143 16 : completion.type_ = kBlockEnd;
144 : }
145 122 : switch (completion.type_) {
146 : case kBlockEnd:
147 : break;
148 : case kFallThrough:
149 17 : result = EmitJump();
150 17 : break;
151 : case kJump:
152 33 : CHECK(!block_returns_);
153 33 : result = EmitJump();
154 33 : break;
155 : case kBranch:
156 22 : CHECK(!block_returns_);
157 22 : result = EmitBranch(completion.op_);
158 22 : break;
159 : }
160 122 : completions_.push_back(completion);
161 122 : CHECK_NOT_NULL(current_block_);
162 122 : sequence()->EndBlock(current_block_->rpo_number());
163 122 : current_block_ = nullptr;
164 122 : return result;
165 : }
166 :
167 :
168 11 : InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
169 11 : return TestOperand(kImmediate, imm);
170 : }
171 :
172 :
173 87 : InstructionSequenceTest::VReg InstructionSequenceTest::Define(
174 87 : TestOperand output_op) {
175 87 : VReg vreg = NewReg(output_op);
176 87 : InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)};
177 87 : Emit(kArchNop, 1, outputs);
178 87 : return vreg;
179 : }
180 :
181 16 : Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) {
182 16 : block_returns_ = true;
183 16 : InstructionOperand inputs[1]{ConvertInputOp(input_op_0)};
184 16 : return Emit(kArchRet, 0, nullptr, 1, inputs);
185 : }
186 :
187 :
188 49 : PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
189 : VReg incoming_vreg_1,
190 : VReg incoming_vreg_2,
191 : VReg incoming_vreg_3) {
192 : VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
193 49 : incoming_vreg_3};
194 : size_t input_count = 0;
195 138 : for (; input_count < arraysize(inputs); ++input_count) {
196 138 : if (inputs[input_count].value_ == kNoValue) break;
197 : }
198 49 : CHECK_LT(0, input_count);
199 98 : auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, input_count);
200 138 : for (size_t i = 0; i < input_count; ++i) {
201 89 : SetInput(phi, i, inputs[i]);
202 : }
203 49 : current_block_->AddPhi(phi);
204 49 : return phi;
205 : }
206 :
207 :
208 5 : PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
209 : size_t input_count) {
210 10 : auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, input_count);
211 5 : SetInput(phi, 0, incoming_vreg_0);
212 5 : current_block_->AddPhi(phi);
213 5 : return phi;
214 : }
215 :
216 :
217 99 : void InstructionSequenceTest::SetInput(PhiInstruction* phi, size_t input,
218 : VReg vreg) {
219 99 : CHECK_NE(kNoValue, vreg.value_);
220 99 : phi->SetInput(input, vreg.value_);
221 99 : }
222 :
223 :
224 62 : InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
225 : int32_t imm) {
226 62 : VReg vreg = NewReg();
227 124 : sequence()->AddConstant(vreg.value_, Constant(imm));
228 62 : InstructionOperand outputs[1]{ConstantOperand(vreg.value_)};
229 62 : Emit(kArchNop, 1, outputs);
230 62 : return vreg;
231 : }
232 :
233 :
234 9 : Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); }
235 :
236 :
237 : static size_t CountInputs(size_t size,
238 : InstructionSequenceTest::TestOperand* inputs) {
239 : size_t i = 0;
240 78 : for (; i < size; ++i) {
241 136 : if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break;
242 : }
243 : return i;
244 : }
245 :
246 :
247 38 : Instruction* InstructionSequenceTest::EmitI(size_t input_size,
248 : TestOperand* inputs) {
249 38 : InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
250 38 : return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs);
251 : }
252 :
253 :
254 38 : Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0,
255 : TestOperand input_op_1,
256 : TestOperand input_op_2,
257 : TestOperand input_op_3) {
258 38 : TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
259 38 : return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
260 : }
261 :
262 :
263 19 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
264 19 : TestOperand output_op, size_t input_size, TestOperand* inputs) {
265 19 : VReg output_vreg = NewReg(output_op);
266 19 : InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
267 19 : InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
268 19 : Emit(kArchNop, 1, outputs, input_size, mapped_inputs);
269 19 : return output_vreg;
270 : }
271 :
272 :
273 16 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
274 : TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
275 : TestOperand input_op_2, TestOperand input_op_3) {
276 16 : TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
277 16 : return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs);
278 : }
279 :
280 :
281 1 : InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
282 2 : TestOperand output_op_0, TestOperand output_op_1, size_t input_size,
283 : TestOperand* inputs) {
284 : VRegPair output_vregs =
285 3 : std::make_pair(NewReg(output_op_0), NewReg(output_op_1));
286 : InstructionOperand outputs[2]{
287 : ConvertOutputOp(output_vregs.first, output_op_0),
288 1 : ConvertOutputOp(output_vregs.second, output_op_1)};
289 1 : InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
290 1 : Emit(kArchNop, 2, outputs, input_size, mapped_inputs);
291 1 : return output_vregs;
292 : }
293 :
294 :
295 1 : InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
296 : TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0,
297 : TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) {
298 1 : TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
299 : return EmitOOI(output_op_0, output_op_1,
300 1 : CountInputs(arraysize(inputs), inputs), inputs);
301 : }
302 :
303 :
304 10 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
305 10 : TestOperand output_op, size_t input_size, TestOperand* inputs) {
306 10 : VReg output_vreg = NewReg(output_op);
307 10 : InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
308 10 : CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy());
309 10 : InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
310 : Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr,
311 10 : true);
312 10 : return output_vreg;
313 : }
314 :
315 :
316 7 : InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
317 : TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
318 : TestOperand input_op_2, TestOperand input_op_3) {
319 7 : TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
320 7 : return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs);
321 : }
322 :
323 :
324 22 : Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) {
325 : InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
326 88 : ConvertInputOp(Imm()), ConvertInputOp(Imm())};
327 : InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
328 : FlagsConditionField::encode(kEqual);
329 22 : auto instruction = NewInstruction(opcode, 0, nullptr, 4, inputs);
330 22 : return AddInstruction(instruction);
331 : }
332 :
333 :
334 0 : Instruction* InstructionSequenceTest::EmitFallThrough() {
335 0 : auto instruction = NewInstruction(kArchNop, 0, nullptr);
336 0 : return AddInstruction(instruction);
337 : }
338 :
339 :
340 50 : Instruction* InstructionSequenceTest::EmitJump() {
341 50 : InstructionOperand inputs[1]{ConvertInputOp(Imm())};
342 50 : auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs);
343 50 : return AddInstruction(instruction);
344 : }
345 :
346 :
347 314 : Instruction* InstructionSequenceTest::NewInstruction(
348 : InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
349 : size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
350 : InstructionOperand* temps) {
351 314 : CHECK(current_block_);
352 : return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
353 314 : inputs, temps_size, temps);
354 : }
355 :
356 :
357 0 : InstructionOperand InstructionSequenceTest::Unallocated(
358 : TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
359 0 : return UnallocatedOperand(policy, op.vreg_.value_);
360 : }
361 :
362 :
363 0 : InstructionOperand InstructionSequenceTest::Unallocated(
364 : TestOperand op, UnallocatedOperand::ExtendedPolicy policy,
365 : UnallocatedOperand::Lifetime lifetime) {
366 0 : return UnallocatedOperand(policy, lifetime, op.vreg_.value_);
367 : }
368 :
369 :
370 0 : InstructionOperand InstructionSequenceTest::Unallocated(
371 : TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) {
372 0 : return UnallocatedOperand(policy, index, op.vreg_.value_);
373 : }
374 :
375 :
376 0 : InstructionOperand InstructionSequenceTest::Unallocated(
377 : TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) {
378 0 : return UnallocatedOperand(policy, index, op.vreg_.value_);
379 : }
380 :
381 :
382 68 : InstructionOperand* InstructionSequenceTest::ConvertInputs(
383 : size_t input_size, TestOperand* inputs) {
384 : InstructionOperand* mapped_inputs =
385 68 : zone()->NewArray<InstructionOperand>(static_cast<int>(input_size));
386 200 : for (size_t i = 0; i < input_size; ++i) {
387 132 : mapped_inputs[i] = ConvertInputOp(inputs[i]);
388 : }
389 68 : return mapped_inputs;
390 : }
391 :
392 :
393 286 : InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) {
394 286 : if (op.type_ == kImmediate) {
395 127 : CHECK_EQ(op.vreg_.value_, kNoValue);
396 127 : return ImmediateOperand(ImmediateOperand::INLINE, op.value_);
397 : }
398 159 : CHECK_NE(op.vreg_.value_, kNoValue);
399 159 : switch (op.type_) {
400 : case kNone:
401 : return Unallocated(op, UnallocatedOperand::NONE,
402 : UnallocatedOperand::USED_AT_START);
403 : case kUnique:
404 : return Unallocated(op, UnallocatedOperand::NONE);
405 : case kUniqueRegister:
406 : return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
407 : case kRegister:
408 : return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
409 : UnallocatedOperand::USED_AT_START);
410 : case kSlot:
411 : return Unallocated(op, UnallocatedOperand::MUST_HAVE_SLOT,
412 : UnallocatedOperand::USED_AT_START);
413 : case kFixedRegister: {
414 : MachineRepresentation rep = GetCanonicalRep(op);
415 37 : CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
416 37 : if (DoesRegisterAllocation()) {
417 : auto extended_policy = IsFloatingPoint(rep)
418 : ? UnallocatedOperand::FIXED_FP_REGISTER
419 37 : : UnallocatedOperand::FIXED_REGISTER;
420 : return Unallocated(op, extended_policy, op.value_);
421 : } else {
422 0 : return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
423 : }
424 : }
425 : case kFixedSlot:
426 12 : if (DoesRegisterAllocation()) {
427 : return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
428 : } else {
429 : return AllocatedOperand(LocationOperand::STACK_SLOT,
430 : GetCanonicalRep(op), op.value_);
431 : }
432 : default:
433 : break;
434 : }
435 0 : CHECK(false);
436 : return InstructionOperand();
437 : }
438 :
439 :
440 118 : InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg,
441 : TestOperand op) {
442 118 : CHECK_EQ(op.vreg_.value_, kNoValue);
443 118 : op.vreg_ = vreg;
444 118 : switch (op.type_) {
445 : case kSameAsFirst:
446 : return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
447 : case kRegister:
448 : return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
449 : case kFixedSlot:
450 39 : if (DoesRegisterAllocation()) {
451 : return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
452 : } else {
453 : return AllocatedOperand(LocationOperand::STACK_SLOT,
454 0 : GetCanonicalRep(op), op.value_);
455 : }
456 : case kFixedRegister: {
457 : MachineRepresentation rep = GetCanonicalRep(op);
458 55 : CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
459 55 : if (DoesRegisterAllocation()) {
460 : auto extended_policy = IsFloatingPoint(rep)
461 : ? UnallocatedOperand::FIXED_FP_REGISTER
462 53 : : UnallocatedOperand::FIXED_REGISTER;
463 : return Unallocated(op, extended_policy, op.value_);
464 : } else {
465 2 : return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
466 : }
467 : }
468 : default:
469 : break;
470 : }
471 0 : CHECK(false);
472 : return InstructionOperand();
473 : }
474 :
475 :
476 174 : InstructionBlock* InstructionSequenceTest::NewBlock(bool deferred) {
477 174 : CHECK_NULL(current_block_);
478 348 : Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size()));
479 : Rpo loop_header = Rpo::Invalid();
480 : Rpo loop_end = Rpo::Invalid();
481 174 : if (!loop_blocks_.empty()) {
482 : auto& loop_data = loop_blocks_.back();
483 : // This is a loop header.
484 4 : if (!loop_data.loop_header_.IsValid()) {
485 3 : loop_end = Rpo::FromInt(rpo.ToInt() + loop_data.expected_blocks_);
486 3 : loop_data.expected_blocks_--;
487 3 : loop_data.loop_header_ = rpo;
488 : } else {
489 : // This is a loop body.
490 1 : CHECK_NE(0, loop_data.expected_blocks_);
491 : // TODO(dcarney): handle nested loops.
492 1 : loop_data.expected_blocks_--;
493 1 : loop_header = loop_data.loop_header_;
494 : }
495 : }
496 : // Construct instruction block.
497 : auto instruction_block = new (zone())
498 348 : InstructionBlock(zone(), rpo, loop_header, loop_end, deferred, false);
499 174 : instruction_blocks_.push_back(instruction_block);
500 174 : current_block_ = instruction_block;
501 174 : sequence()->StartBlock(rpo);
502 174 : return instruction_block;
503 : }
504 :
505 :
506 52 : void InstructionSequenceTest::WireBlocks() {
507 52 : CHECK(!current_block());
508 206 : CHECK(instruction_blocks_.size() == completions_.size());
509 52 : CHECK(loop_blocks_.empty());
510 : // Wire in end block to look like a scheduler produced cfg.
511 52 : auto end_block = NewBlock();
512 52 : current_block_ = nullptr;
513 52 : sequence()->EndBlock(end_block->rpo_number());
514 : size_t offset = 0;
515 226 : for (const auto& completion : completions_) {
516 122 : switch (completion.type_) {
517 : case kBlockEnd: {
518 50 : auto block = instruction_blocks_[offset];
519 100 : block->successors().push_back(end_block->rpo_number());
520 100 : end_block->predecessors().push_back(block->rpo_number());
521 50 : break;
522 : }
523 : case kFallThrough: // Fallthrough.
524 : case kJump:
525 50 : WireBlock(offset, completion.offset_0_);
526 50 : break;
527 : case kBranch:
528 22 : WireBlock(offset, completion.offset_0_);
529 22 : WireBlock(offset, completion.offset_1_);
530 22 : break;
531 : }
532 122 : ++offset;
533 : }
534 52 : }
535 :
536 :
537 94 : void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
538 94 : size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
539 188 : CHECK(block_offset < instruction_blocks_.size());
540 94 : CHECK(target_block_offset < instruction_blocks_.size());
541 94 : auto block = instruction_blocks_[block_offset];
542 94 : auto target = instruction_blocks_[target_block_offset];
543 188 : block->successors().push_back(target->rpo_number());
544 188 : target->predecessors().push_back(block->rpo_number());
545 94 : }
546 :
547 :
548 242 : Instruction* InstructionSequenceTest::Emit(
549 : InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
550 : size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
551 : InstructionOperand* temps, bool is_call) {
552 : auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
553 242 : inputs, temps_size, temps);
554 242 : if (is_call) instruction->MarkAsCall();
555 242 : return AddInstruction(instruction);
556 : }
557 :
558 :
559 0 : Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) {
560 314 : sequence()->AddInstruction(instruction);
561 0 : return instruction;
562 : }
563 :
564 : } // namespace compiler
565 : } // namespace internal
566 7893 : } // namespace v8
|