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