blob: bdcd952b5f703a60aa18a4813325dd2b24ae0f91 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
6#define V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
7
8#include "src/compiler/instruction.h"
9#include "src/compiler/instruction-selector.h"
10#include "src/compiler/linkage.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/macro-assembler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17// A helper class for the instruction selector that simplifies construction of
18// Operands. This class implements a base for architecture-specific helpers.
19class OperandGenerator {
20 public:
21 explicit OperandGenerator(InstructionSelector* selector)
22 : selector_(selector) {}
23
24 InstructionOperand* DefineAsRegister(Node* node) {
25 return Define(node, new (zone())
26 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
27 }
28
29 InstructionOperand* DefineSameAsFirst(Node* result) {
30 return Define(result, new (zone())
31 UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT));
32 }
33
34 InstructionOperand* DefineAsFixed(Node* node, Register reg) {
35 return Define(node, new (zone())
36 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
37 Register::ToAllocationIndex(reg)));
38 }
39
40 InstructionOperand* DefineAsFixed(Node* node, DoubleRegister reg) {
41 return Define(node, new (zone())
42 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
43 DoubleRegister::ToAllocationIndex(reg)));
44 }
45
46 InstructionOperand* DefineAsConstant(Node* node) {
47 selector()->MarkAsDefined(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048 int virtual_register = selector_->GetVirtualRegister(node);
49 sequence()->AddConstant(virtual_register, ToConstant(node));
50 return ConstantOperand::Create(virtual_register, zone());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 }
52
53 InstructionOperand* DefineAsLocation(Node* node, LinkageLocation location,
54 MachineType type) {
55 return Define(node, ToUnallocatedOperand(location, type));
56 }
57
58 InstructionOperand* Use(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040059 return Use(
60 node, new (zone()) UnallocatedOperand(
61 UnallocatedOperand::NONE, UnallocatedOperand::USED_AT_START));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062 }
63
64 InstructionOperand* UseRegister(Node* node) {
65 return Use(node, new (zone())
66 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
67 UnallocatedOperand::USED_AT_START));
68 }
69
70 // Use register or operand for the node. If a register is chosen, it won't
71 // alias any temporary or output registers.
72 InstructionOperand* UseUnique(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040073 return Use(node, new (zone()) UnallocatedOperand(UnallocatedOperand::NONE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 }
75
76 // Use a unique register for the node that does not alias any temporary or
77 // output registers.
78 InstructionOperand* UseUniqueRegister(Node* node) {
79 return Use(node, new (zone())
80 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
81 }
82
83 InstructionOperand* UseFixed(Node* node, Register reg) {
84 return Use(node, new (zone())
85 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
86 Register::ToAllocationIndex(reg)));
87 }
88
89 InstructionOperand* UseFixed(Node* node, DoubleRegister reg) {
90 return Use(node, new (zone())
91 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
92 DoubleRegister::ToAllocationIndex(reg)));
93 }
94
95 InstructionOperand* UseImmediate(Node* node) {
96 int index = sequence()->AddImmediate(ToConstant(node));
97 return ImmediateOperand::Create(index, zone());
98 }
99
100 InstructionOperand* UseLocation(Node* node, LinkageLocation location,
101 MachineType type) {
102 return Use(node, ToUnallocatedOperand(location, type));
103 }
104
105 InstructionOperand* TempRegister() {
106 UnallocatedOperand* op =
107 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
108 UnallocatedOperand::USED_AT_START);
109 op->set_virtual_register(sequence()->NextVirtualRegister());
110 return op;
111 }
112
113 InstructionOperand* TempDoubleRegister() {
114 UnallocatedOperand* op =
115 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
116 UnallocatedOperand::USED_AT_START);
117 op->set_virtual_register(sequence()->NextVirtualRegister());
118 sequence()->MarkAsDouble(op->virtual_register());
119 return op;
120 }
121
122 InstructionOperand* TempRegister(Register reg) {
123 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
124 Register::ToAllocationIndex(reg));
125 }
126
127 InstructionOperand* TempImmediate(int32_t imm) {
128 int index = sequence()->AddImmediate(Constant(imm));
129 return ImmediateOperand::Create(index, zone());
130 }
131
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132 InstructionOperand* TempLocation(LinkageLocation location, MachineType type) {
133 UnallocatedOperand* op = ToUnallocatedOperand(location, type);
134 op->set_virtual_register(sequence()->NextVirtualRegister());
135 return op;
136 }
137
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 InstructionOperand* Label(BasicBlock* block) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400139 int index = sequence()->AddImmediate(Constant(block->GetRpoNumber()));
140 return ImmediateOperand::Create(index, zone());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
142
143 protected:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 InstructionSelector* selector() const { return selector_; }
145 InstructionSequence* sequence() const { return selector()->sequence(); }
146 Isolate* isolate() const { return zone()->isolate(); }
147 Zone* zone() const { return selector()->instruction_zone(); }
148
149 private:
150 static Constant ToConstant(const Node* node) {
151 switch (node->opcode()) {
152 case IrOpcode::kInt32Constant:
153 return Constant(OpParameter<int32_t>(node));
154 case IrOpcode::kInt64Constant:
155 return Constant(OpParameter<int64_t>(node));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400156 case IrOpcode::kFloat32Constant:
157 return Constant(OpParameter<float>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000158 case IrOpcode::kFloat64Constant:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400159 case IrOpcode::kNumberConstant:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 return Constant(OpParameter<double>(node));
161 case IrOpcode::kExternalConstant:
162 return Constant(OpParameter<ExternalReference>(node));
163 case IrOpcode::kHeapConstant:
164 return Constant(OpParameter<Unique<HeapObject> >(node).handle());
165 default:
166 break;
167 }
168 UNREACHABLE();
169 return Constant(static_cast<int32_t>(0));
170 }
171
172 UnallocatedOperand* Define(Node* node, UnallocatedOperand* operand) {
173 DCHECK_NOT_NULL(node);
174 DCHECK_NOT_NULL(operand);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 operand->set_virtual_register(selector_->GetVirtualRegister(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 selector()->MarkAsDefined(node);
177 return operand;
178 }
179
180 UnallocatedOperand* Use(Node* node, UnallocatedOperand* operand) {
181 DCHECK_NOT_NULL(node);
182 DCHECK_NOT_NULL(operand);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400183 operand->set_virtual_register(selector_->GetVirtualRegister(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 selector()->MarkAsUsed(node);
185 return operand;
186 }
187
188 UnallocatedOperand* ToUnallocatedOperand(LinkageLocation location,
189 MachineType type) {
190 if (location.location_ == LinkageLocation::ANY_REGISTER) {
191 return new (zone())
192 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER);
193 }
194 if (location.location_ < 0) {
195 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
196 location.location_);
197 }
198 if (RepresentationOf(type) == kRepFloat64) {
199 return new (zone()) UnallocatedOperand(
200 UnallocatedOperand::FIXED_DOUBLE_REGISTER, location.location_);
201 }
202 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
203 location.location_);
204 }
205
206 InstructionSelector* selector_;
207};
208
209
210// The flags continuation is a way to combine a branch or a materialization
211// of a boolean value with an instruction that sets the flags register.
212// The whole instruction is treated as a unit by the register allocator, and
213// thus no spills or moves can be introduced between the flags-setting
214// instruction and the branch or set it should be combined with.
215class FlagsContinuation FINAL {
216 public:
217 FlagsContinuation() : mode_(kFlags_none) {}
218
219 // Creates a new flags continuation from the given condition and true/false
220 // blocks.
221 FlagsContinuation(FlagsCondition condition, BasicBlock* true_block,
222 BasicBlock* false_block)
223 : mode_(kFlags_branch),
224 condition_(condition),
225 true_block_(true_block),
226 false_block_(false_block) {
227 DCHECK_NOT_NULL(true_block);
228 DCHECK_NOT_NULL(false_block);
229 }
230
231 // Creates a new flags continuation from the given condition and result node.
232 FlagsContinuation(FlagsCondition condition, Node* result)
233 : mode_(kFlags_set), condition_(condition), result_(result) {
234 DCHECK_NOT_NULL(result);
235 }
236
237 bool IsNone() const { return mode_ == kFlags_none; }
238 bool IsBranch() const { return mode_ == kFlags_branch; }
239 bool IsSet() const { return mode_ == kFlags_set; }
240 FlagsCondition condition() const {
241 DCHECK(!IsNone());
242 return condition_;
243 }
244 Node* result() const {
245 DCHECK(IsSet());
246 return result_;
247 }
248 BasicBlock* true_block() const {
249 DCHECK(IsBranch());
250 return true_block_;
251 }
252 BasicBlock* false_block() const {
253 DCHECK(IsBranch());
254 return false_block_;
255 }
256
257 void Negate() {
258 DCHECK(!IsNone());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400259 condition_ = NegateFlagsCondition(condition_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 }
261
262 void Commute() {
263 DCHECK(!IsNone());
264 switch (condition_) {
265 case kEqual:
266 case kNotEqual:
267 case kOverflow:
268 case kNotOverflow:
269 return;
270 case kSignedLessThan:
271 condition_ = kSignedGreaterThan;
272 return;
273 case kSignedGreaterThanOrEqual:
274 condition_ = kSignedLessThanOrEqual;
275 return;
276 case kSignedLessThanOrEqual:
277 condition_ = kSignedGreaterThanOrEqual;
278 return;
279 case kSignedGreaterThan:
280 condition_ = kSignedLessThan;
281 return;
282 case kUnsignedLessThan:
283 condition_ = kUnsignedGreaterThan;
284 return;
285 case kUnsignedGreaterThanOrEqual:
286 condition_ = kUnsignedLessThanOrEqual;
287 return;
288 case kUnsignedLessThanOrEqual:
289 condition_ = kUnsignedGreaterThanOrEqual;
290 return;
291 case kUnsignedGreaterThan:
292 condition_ = kUnsignedLessThan;
293 return;
294 case kUnorderedEqual:
295 case kUnorderedNotEqual:
296 return;
297 case kUnorderedLessThan:
298 condition_ = kUnorderedGreaterThan;
299 return;
300 case kUnorderedGreaterThanOrEqual:
301 condition_ = kUnorderedLessThanOrEqual;
302 return;
303 case kUnorderedLessThanOrEqual:
304 condition_ = kUnorderedGreaterThanOrEqual;
305 return;
306 case kUnorderedGreaterThan:
307 condition_ = kUnorderedLessThan;
308 return;
309 }
310 UNREACHABLE();
311 }
312
313 void OverwriteAndNegateIfEqual(FlagsCondition condition) {
314 bool negate = condition_ == kEqual;
315 condition_ = condition;
316 if (negate) Negate();
317 }
318
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 // Encodes this flags continuation into the given opcode.
320 InstructionCode Encode(InstructionCode opcode) {
321 opcode |= FlagsModeField::encode(mode_);
322 if (mode_ != kFlags_none) {
323 opcode |= FlagsConditionField::encode(condition_);
324 }
325 return opcode;
326 }
327
328 private:
329 FlagsMode mode_;
330 FlagsCondition condition_;
331 Node* result_; // Only valid if mode_ == kFlags_set.
332 BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch.
333 BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch.
334};
335
336
337// An internal helper class for generating the operands to calls.
338// TODO(bmeurer): Get rid of the CallBuffer business and make
339// InstructionSelector::VisitCall platform independent instead.
340struct CallBuffer {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400341 CallBuffer(Zone* zone, const CallDescriptor* descriptor,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 FrameStateDescriptor* frame_state);
343
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 const CallDescriptor* descriptor;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 FrameStateDescriptor* frame_state_descriptor;
346 NodeVector output_nodes;
347 InstructionOperandVector outputs;
348 InstructionOperandVector instruction_args;
349 NodeVector pushed_nodes;
350
351 size_t input_count() const { return descriptor->InputCount(); }
352
353 size_t frame_state_count() const { return descriptor->FrameStateCount(); }
354
355 size_t frame_state_value_count() const {
356 return (frame_state_descriptor == NULL)
357 ? 0
358 : (frame_state_descriptor->GetTotalSize() +
359 1); // Include deopt id.
360 }
361};
362
363} // namespace compiler
364} // namespace internal
365} // namespace v8
366
367#endif // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_