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