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/compiler/schedule.h"
12 #include "src/macro-assembler.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 // Helper struct containing data about a table or lookup switch.
19 struct SwitchInfo {
20   int32_t min_value;           // minimum value of {case_values}
21   int32_t max_value;           // maximum value of {case_values}
22   size_t value_range;          // |max_value - min_value| + 1
23   size_t case_count;           // number of cases
24   int32_t* case_values;        // actual case values, unsorted
25   BasicBlock** case_branches;  // basic blocks corresponding to case values
26   BasicBlock* default_branch;  // default branch target
27 };
28 
29 // A helper class for the instruction selector that simplifies construction of
30 // Operands. This class implements a base for architecture-specific helpers.
31 class OperandGenerator {
32  public:
OperandGenerator(InstructionSelector * selector)33   explicit OperandGenerator(InstructionSelector* selector)
34       : selector_(selector) {}
35 
NoOutput()36   InstructionOperand NoOutput() {
37     return InstructionOperand();  // Generates an invalid operand.
38   }
39 
DefineAsRegister(Node * node)40   InstructionOperand DefineAsRegister(Node* node) {
41     return Define(node,
42                   UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
43                                      GetVReg(node)));
44   }
45 
DefineSameAsFirst(Node * node)46   InstructionOperand DefineSameAsFirst(Node* node) {
47     return Define(node,
48                   UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT,
49                                      GetVReg(node)));
50   }
51 
DefineAsFixed(Node * node,Register reg)52   InstructionOperand DefineAsFixed(Node* node, Register reg) {
53     return Define(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
54                                            reg.code(), GetVReg(node)));
55   }
56 
DefineAsFixed(Node * node,DoubleRegister reg)57   InstructionOperand DefineAsFixed(Node* node, DoubleRegister reg) {
58     return Define(node,
59                   UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
60                                      reg.code(), GetVReg(node)));
61   }
62 
DefineAsConstant(Node * node)63   InstructionOperand DefineAsConstant(Node* node) {
64     selector()->MarkAsDefined(node);
65     int virtual_register = GetVReg(node);
66     sequence()->AddConstant(virtual_register, ToConstant(node));
67     return ConstantOperand(virtual_register);
68   }
69 
DefineAsLocation(Node * node,LinkageLocation location,MachineRepresentation rep)70   InstructionOperand DefineAsLocation(Node* node, LinkageLocation location,
71                                       MachineRepresentation rep) {
72     return Define(node, ToUnallocatedOperand(location, rep, GetVReg(node)));
73   }
74 
DefineAsDualLocation(Node * node,LinkageLocation primary_location,LinkageLocation secondary_location)75   InstructionOperand DefineAsDualLocation(Node* node,
76                                           LinkageLocation primary_location,
77                                           LinkageLocation secondary_location) {
78     return Define(node,
79                   ToDualLocationUnallocatedOperand(
80                       primary_location, secondary_location, GetVReg(node)));
81   }
82 
Use(Node * node)83   InstructionOperand Use(Node* node) {
84     return Use(node, UnallocatedOperand(UnallocatedOperand::NONE,
85                                         UnallocatedOperand::USED_AT_START,
86                                         GetVReg(node)));
87   }
88 
UseAny(Node * node)89   InstructionOperand UseAny(Node* node) {
90     return Use(node, UnallocatedOperand(UnallocatedOperand::ANY,
91                                         UnallocatedOperand::USED_AT_START,
92                                         GetVReg(node)));
93   }
94 
UseRegister(Node * node)95   InstructionOperand UseRegister(Node* node) {
96     return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
97                                         UnallocatedOperand::USED_AT_START,
98                                         GetVReg(node)));
99   }
100 
UseUniqueSlot(Node * node)101   InstructionOperand UseUniqueSlot(Node* node) {
102     return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_SLOT,
103                                         GetVReg(node)));
104   }
105 
106   // Use register or operand for the node. If a register is chosen, it won't
107   // alias any temporary or output registers.
UseUnique(Node * node)108   InstructionOperand UseUnique(Node* node) {
109     return Use(node,
110                UnallocatedOperand(UnallocatedOperand::NONE, GetVReg(node)));
111   }
112 
113   // Use a unique register for the node that does not alias any temporary or
114   // output registers.
UseUniqueRegister(Node * node)115   InstructionOperand UseUniqueRegister(Node* node) {
116     return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
117                                         GetVReg(node)));
118   }
119 
UseFixed(Node * node,Register reg)120   InstructionOperand UseFixed(Node* node, Register reg) {
121     return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
122                                         reg.code(), GetVReg(node)));
123   }
124 
UseFixed(Node * node,DoubleRegister reg)125   InstructionOperand UseFixed(Node* node, DoubleRegister reg) {
126     return Use(node,
127                UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
128                                   reg.code(), GetVReg(node)));
129   }
130 
UseExplicit(LinkageLocation location)131   InstructionOperand UseExplicit(LinkageLocation location) {
132     MachineRepresentation rep = InstructionSequence::DefaultRepresentation();
133     if (location.IsRegister()) {
134       return ExplicitOperand(LocationOperand::REGISTER, rep,
135                              location.AsRegister());
136     } else {
137       return ExplicitOperand(LocationOperand::STACK_SLOT, rep,
138                              location.GetLocation());
139     }
140   }
141 
UseImmediate(Node * node)142   InstructionOperand UseImmediate(Node* node) {
143     return sequence()->AddImmediate(ToConstant(node));
144   }
145 
UseLocation(Node * node,LinkageLocation location,MachineRepresentation rep)146   InstructionOperand UseLocation(Node* node, LinkageLocation location,
147                                  MachineRepresentation rep) {
148     return Use(node, ToUnallocatedOperand(location, rep, GetVReg(node)));
149   }
150 
151   // Used to force gap moves from the from_location to the to_location
152   // immediately before an instruction.
UsePointerLocation(LinkageLocation to_location,LinkageLocation from_location)153   InstructionOperand UsePointerLocation(LinkageLocation to_location,
154                                         LinkageLocation from_location) {
155     MachineRepresentation rep = MachineType::PointerRepresentation();
156     UnallocatedOperand casted_from_operand =
157         UnallocatedOperand::cast(TempLocation(from_location, rep));
158     selector_->Emit(kArchNop, casted_from_operand);
159     return ToUnallocatedOperand(to_location, rep,
160                                 casted_from_operand.virtual_register());
161   }
162 
TempRegister()163   InstructionOperand TempRegister() {
164     return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
165                               UnallocatedOperand::USED_AT_START,
166                               sequence()->NextVirtualRegister());
167   }
168 
TempDoubleRegister()169   InstructionOperand TempDoubleRegister() {
170     UnallocatedOperand op = UnallocatedOperand(
171         UnallocatedOperand::MUST_HAVE_REGISTER,
172         UnallocatedOperand::USED_AT_START, sequence()->NextVirtualRegister());
173     sequence()->MarkAsRepresentation(MachineRepresentation::kFloat64,
174                                      op.virtual_register());
175     return op;
176   }
177 
TempRegister(Register reg)178   InstructionOperand TempRegister(Register reg) {
179     return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, reg.code(),
180                               InstructionOperand::kInvalidVirtualRegister);
181   }
182 
TempImmediate(int32_t imm)183   InstructionOperand TempImmediate(int32_t imm) {
184     return sequence()->AddImmediate(Constant(imm));
185   }
186 
TempLocation(LinkageLocation location,MachineRepresentation rep)187   InstructionOperand TempLocation(LinkageLocation location,
188                                   MachineRepresentation rep) {
189     return ToUnallocatedOperand(location, rep,
190                                 sequence()->NextVirtualRegister());
191   }
192 
Label(BasicBlock * block)193   InstructionOperand Label(BasicBlock* block) {
194     return sequence()->AddImmediate(
195         Constant(RpoNumber::FromInt(block->rpo_number())));
196   }
197 
198  protected:
selector()199   InstructionSelector* selector() const { return selector_; }
sequence()200   InstructionSequence* sequence() const { return selector()->sequence(); }
zone()201   Zone* zone() const { return selector()->instruction_zone(); }
202 
203  private:
GetVReg(Node * node)204   int GetVReg(Node* node) const { return selector_->GetVirtualRegister(node); }
205 
ToConstant(const Node * node)206   static Constant ToConstant(const Node* node) {
207     switch (node->opcode()) {
208       case IrOpcode::kInt32Constant:
209         return Constant(OpParameter<int32_t>(node));
210       case IrOpcode::kInt64Constant:
211         return Constant(OpParameter<int64_t>(node));
212       case IrOpcode::kFloat32Constant:
213         return Constant(OpParameter<float>(node));
214       case IrOpcode::kFloat64Constant:
215       case IrOpcode::kNumberConstant:
216         return Constant(OpParameter<double>(node));
217       case IrOpcode::kExternalConstant:
218         return Constant(OpParameter<ExternalReference>(node));
219       case IrOpcode::kHeapConstant:
220         return Constant(OpParameter<Handle<HeapObject>>(node));
221       default:
222         break;
223     }
224     UNREACHABLE();
225     return Constant(static_cast<int32_t>(0));
226   }
227 
Define(Node * node,UnallocatedOperand operand)228   UnallocatedOperand Define(Node* node, UnallocatedOperand operand) {
229     DCHECK_NOT_NULL(node);
230     DCHECK_EQ(operand.virtual_register(), GetVReg(node));
231     selector()->MarkAsDefined(node);
232     return operand;
233   }
234 
Use(Node * node,UnallocatedOperand operand)235   UnallocatedOperand Use(Node* node, UnallocatedOperand operand) {
236     DCHECK_NOT_NULL(node);
237     DCHECK_EQ(operand.virtual_register(), GetVReg(node));
238     selector()->MarkAsUsed(node);
239     return operand;
240   }
241 
ToDualLocationUnallocatedOperand(LinkageLocation primary_location,LinkageLocation secondary_location,int virtual_register)242   UnallocatedOperand ToDualLocationUnallocatedOperand(
243       LinkageLocation primary_location, LinkageLocation secondary_location,
244       int virtual_register) {
245     // We only support the primary location being a register and the secondary
246     // one a slot.
247     DCHECK(primary_location.IsRegister() &&
248            secondary_location.IsCalleeFrameSlot());
249     int reg_id = primary_location.AsRegister();
250     int slot_id = secondary_location.AsCalleeFrameSlot();
251     return UnallocatedOperand(reg_id, slot_id, virtual_register);
252   }
253 
ToUnallocatedOperand(LinkageLocation location,MachineRepresentation rep,int virtual_register)254   UnallocatedOperand ToUnallocatedOperand(LinkageLocation location,
255                                           MachineRepresentation rep,
256                                           int virtual_register) {
257     if (location.IsAnyRegister()) {
258       // any machine register.
259       return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
260                                 virtual_register);
261     }
262     if (location.IsCallerFrameSlot()) {
263       // a location on the caller frame.
264       return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
265                                 location.AsCallerFrameSlot(), virtual_register);
266     }
267     if (location.IsCalleeFrameSlot()) {
268       // a spill location on this (callee) frame.
269       return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
270                                 location.AsCalleeFrameSlot(), virtual_register);
271     }
272     // a fixed register.
273     if (IsFloatingPoint(rep)) {
274       return UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
275                                 location.AsRegister(), virtual_register);
276     }
277     return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
278                               location.AsRegister(), virtual_register);
279   }
280 
281   InstructionSelector* selector_;
282 };
283 
284 
285 // The flags continuation is a way to combine a branch or a materialization
286 // of a boolean value with an instruction that sets the flags register.
287 // The whole instruction is treated as a unit by the register allocator, and
288 // thus no spills or moves can be introduced between the flags-setting
289 // instruction and the branch or set it should be combined with.
290 class FlagsContinuation final {
291  public:
FlagsContinuation()292   FlagsContinuation() : mode_(kFlags_none) {}
293 
294   // Creates a new flags continuation from the given condition and true/false
295   // blocks.
FlagsContinuation(FlagsCondition condition,BasicBlock * true_block,BasicBlock * false_block)296   FlagsContinuation(FlagsCondition condition, BasicBlock* true_block,
297                     BasicBlock* false_block)
298       : mode_(kFlags_branch),
299         condition_(condition),
300         true_block_(true_block),
301         false_block_(false_block) {
302     DCHECK_NOT_NULL(true_block);
303     DCHECK_NOT_NULL(false_block);
304   }
305 
306   // Creates a new flags continuation from the given condition and result node.
FlagsContinuation(FlagsCondition condition,Node * result)307   FlagsContinuation(FlagsCondition condition, Node* result)
308       : mode_(kFlags_set), condition_(condition), result_(result) {
309     DCHECK_NOT_NULL(result);
310   }
311 
IsNone()312   bool IsNone() const { return mode_ == kFlags_none; }
IsBranch()313   bool IsBranch() const { return mode_ == kFlags_branch; }
IsSet()314   bool IsSet() const { return mode_ == kFlags_set; }
condition()315   FlagsCondition condition() const {
316     DCHECK(!IsNone());
317     return condition_;
318   }
result()319   Node* result() const {
320     DCHECK(IsSet());
321     return result_;
322   }
true_block()323   BasicBlock* true_block() const {
324     DCHECK(IsBranch());
325     return true_block_;
326   }
false_block()327   BasicBlock* false_block() const {
328     DCHECK(IsBranch());
329     return false_block_;
330   }
331 
Negate()332   void Negate() {
333     DCHECK(!IsNone());
334     condition_ = NegateFlagsCondition(condition_);
335   }
336 
Commute()337   void Commute() {
338     DCHECK(!IsNone());
339     condition_ = CommuteFlagsCondition(condition_);
340   }
341 
OverwriteAndNegateIfEqual(FlagsCondition condition)342   void OverwriteAndNegateIfEqual(FlagsCondition condition) {
343     bool negate = condition_ == kEqual;
344     condition_ = condition;
345     if (negate) Negate();
346   }
347 
348   // Encodes this flags continuation into the given opcode.
Encode(InstructionCode opcode)349   InstructionCode Encode(InstructionCode opcode) {
350     opcode |= FlagsModeField::encode(mode_);
351     if (mode_ != kFlags_none) {
352       opcode |= FlagsConditionField::encode(condition_);
353     }
354     return opcode;
355   }
356 
357  private:
358   FlagsMode mode_;
359   FlagsCondition condition_;
360   Node* result_;             // Only valid if mode_ == kFlags_set.
361   BasicBlock* true_block_;   // Only valid if mode_ == kFlags_branch.
362   BasicBlock* false_block_;  // Only valid if mode_ == kFlags_branch.
363 };
364 
365 }  // namespace compiler
366 }  // namespace internal
367 }  // namespace v8
368 
369 #endif  // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
370