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_BACKEND_INSTRUCTION_SELECTOR_IMPL_H_
6 #define V8_COMPILER_BACKEND_INSTRUCTION_SELECTOR_IMPL_H_
7 
8 #include "src/codegen/macro-assembler.h"
9 #include "src/compiler/backend/instruction-selector.h"
10 #include "src/compiler/backend/instruction.h"
11 #include "src/compiler/common-operator.h"
12 #include "src/compiler/linkage.h"
13 #include "src/compiler/schedule.h"
14 #include "src/objects/tagged-index.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19 
20 struct CaseInfo {
21   int32_t value;  // The case value.
22   int32_t order;  // The order for lowering to comparisons (less means earlier).
23   BasicBlock* branch;  // The basic blocks corresponding to the case value.
24 };
25 
26 inline bool operator<(const CaseInfo& l, const CaseInfo& r) {
27   return l.order < r.order;
28 }
29 
30 // Helper struct containing data about a table or lookup switch.
31 class SwitchInfo {
32  public:
SwitchInfo(ZoneVector<CaseInfo> const & cases,int32_t min_value,int32_t max_value,BasicBlock * default_branch)33   SwitchInfo(ZoneVector<CaseInfo> const& cases, int32_t min_value,
34              int32_t max_value, BasicBlock* default_branch)
35       : cases_(cases),
36         min_value_(min_value),
37         max_value_(max_value),
38         default_branch_(default_branch) {
39     if (cases.size() != 0) {
40       DCHECK_LE(min_value, max_value);
41       // Note that {value_range} can be 0 if {min_value} is -2^31 and
42       // {max_value} is 2^31-1, so don't assume that it's non-zero below.
43       value_range_ =
44           1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
45     } else {
46       value_range_ = 0;
47     }
48   }
49 
CasesSortedByValue()50   std::vector<CaseInfo> CasesSortedByValue() const {
51     std::vector<CaseInfo> result(cases_.begin(), cases_.end());
52     std::stable_sort(result.begin(), result.end(),
53                      [](CaseInfo a, CaseInfo b) { return a.value < b.value; });
54     return result;
55   }
CasesUnsorted()56   const ZoneVector<CaseInfo>& CasesUnsorted() const { return cases_; }
min_value()57   int32_t min_value() const { return min_value_; }
max_value()58   int32_t max_value() const { return max_value_; }
value_range()59   size_t value_range() const { return value_range_; }
case_count()60   size_t case_count() const { return cases_.size(); }
default_branch()61   BasicBlock* default_branch() const { return default_branch_; }
62 
63  private:
64   const ZoneVector<CaseInfo>& cases_;
65   int32_t min_value_;   // minimum value of {cases_}
66   int32_t max_value_;   // maximum value of {cases_}
67   size_t value_range_;  // |max_value - min_value| + 1
68   BasicBlock* default_branch_;
69 };
70 
71 // A helper class for the instruction selector that simplifies construction of
72 // Operands. This class implements a base for architecture-specific helpers.
73 class OperandGenerator {
74  public:
OperandGenerator(InstructionSelector * selector)75   explicit OperandGenerator(InstructionSelector* selector)
76       : selector_(selector) {}
77 
NoOutput()78   InstructionOperand NoOutput() {
79     return InstructionOperand();  // Generates an invalid operand.
80   }
81 
DefineAsRegister(Node * node)82   InstructionOperand DefineAsRegister(Node* node) {
83     return Define(node,
84                   UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
85                                      GetVReg(node)));
86   }
87 
DefineSameAsInput(Node * node,int input_index)88   InstructionOperand DefineSameAsInput(Node* node, int input_index) {
89     return Define(node, UnallocatedOperand(GetVReg(node), input_index));
90   }
91 
DefineSameAsFirst(Node * node)92   InstructionOperand DefineSameAsFirst(Node* node) {
93     return DefineSameAsInput(node, 0);
94   }
95 
DefineAsFixed(Node * node,Register reg)96   InstructionOperand DefineAsFixed(Node* node, Register reg) {
97     return Define(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
98                                            reg.code(), GetVReg(node)));
99   }
100 
101   template <typename FPRegType>
DefineAsFixed(Node * node,FPRegType reg)102   InstructionOperand DefineAsFixed(Node* node, FPRegType reg) {
103     return Define(node,
104                   UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER,
105                                      reg.code(), GetVReg(node)));
106   }
107 
DefineAsConstant(Node * node)108   InstructionOperand DefineAsConstant(Node* node) {
109     selector()->MarkAsDefined(node);
110     int virtual_register = GetVReg(node);
111     sequence()->AddConstant(virtual_register, ToConstant(node));
112     return ConstantOperand(virtual_register);
113   }
114 
DefineAsLocation(Node * node,LinkageLocation location)115   InstructionOperand DefineAsLocation(Node* node, LinkageLocation location) {
116     return Define(node, ToUnallocatedOperand(location, GetVReg(node)));
117   }
118 
DefineAsDualLocation(Node * node,LinkageLocation primary_location,LinkageLocation secondary_location)119   InstructionOperand DefineAsDualLocation(Node* node,
120                                           LinkageLocation primary_location,
121                                           LinkageLocation secondary_location) {
122     return Define(node,
123                   ToDualLocationUnallocatedOperand(
124                       primary_location, secondary_location, GetVReg(node)));
125   }
126 
Use(Node * node)127   InstructionOperand Use(Node* node) {
128     return Use(node, UnallocatedOperand(UnallocatedOperand::NONE,
129                                         UnallocatedOperand::USED_AT_START,
130                                         GetVReg(node)));
131   }
132 
UseAnyAtEnd(Node * node)133   InstructionOperand UseAnyAtEnd(Node* node) {
134     return Use(node, UnallocatedOperand(UnallocatedOperand::REGISTER_OR_SLOT,
135                                         UnallocatedOperand::USED_AT_END,
136                                         GetVReg(node)));
137   }
138 
UseAny(Node * node)139   InstructionOperand UseAny(Node* node) {
140     return Use(node, UnallocatedOperand(UnallocatedOperand::REGISTER_OR_SLOT,
141                                         UnallocatedOperand::USED_AT_START,
142                                         GetVReg(node)));
143   }
144 
UseRegisterOrSlotOrConstant(Node * node)145   InstructionOperand UseRegisterOrSlotOrConstant(Node* node) {
146     return Use(node, UnallocatedOperand(
147                          UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT,
148                          UnallocatedOperand::USED_AT_START, GetVReg(node)));
149   }
150 
UseUniqueRegisterOrSlotOrConstant(Node * node)151   InstructionOperand UseUniqueRegisterOrSlotOrConstant(Node* node) {
152     return Use(node, UnallocatedOperand(
153                          UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT,
154                          GetVReg(node)));
155   }
156 
UseRegister(Node * node)157   InstructionOperand UseRegister(Node* node) {
158     return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
159                                         UnallocatedOperand::USED_AT_START,
160                                         GetVReg(node)));
161   }
162 
UseUniqueSlot(Node * node)163   InstructionOperand UseUniqueSlot(Node* node) {
164     return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_SLOT,
165                                         GetVReg(node)));
166   }
167 
168   // Use register or operand for the node. If a register is chosen, it won't
169   // alias any temporary or output registers.
UseUnique(Node * node)170   InstructionOperand UseUnique(Node* node) {
171     return Use(node,
172                UnallocatedOperand(UnallocatedOperand::NONE, GetVReg(node)));
173   }
174 
175   // Use a unique register for the node that does not alias any temporary or
176   // output registers.
UseUniqueRegister(Node * node)177   InstructionOperand UseUniqueRegister(Node* node) {
178     return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
179                                         GetVReg(node)));
180   }
181 
182   enum class RegisterUseKind { kUseRegister, kUseUniqueRegister };
UseRegister(Node * node,RegisterUseKind unique_reg)183   InstructionOperand UseRegister(Node* node, RegisterUseKind unique_reg) {
184     if (V8_LIKELY(unique_reg == RegisterUseKind::kUseRegister)) {
185       return UseRegister(node);
186     } else {
187       DCHECK_EQ(unique_reg, RegisterUseKind::kUseUniqueRegister);
188       return UseUniqueRegister(node);
189     }
190   }
191 
UseFixed(Node * node,Register reg)192   InstructionOperand UseFixed(Node* node, Register reg) {
193     return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
194                                         reg.code(), GetVReg(node)));
195   }
196 
197   template <typename FPRegType>
UseFixed(Node * node,FPRegType reg)198   InstructionOperand UseFixed(Node* node, FPRegType reg) {
199     return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER,
200                                         reg.code(), GetVReg(node)));
201   }
202 
UseImmediate(int immediate)203   InstructionOperand UseImmediate(int immediate) {
204     return sequence()->AddImmediate(Constant(immediate));
205   }
206 
UseImmediate(Node * node)207   InstructionOperand UseImmediate(Node* node) {
208     return sequence()->AddImmediate(ToConstant(node));
209   }
210 
UseNegatedImmediate(Node * node)211   InstructionOperand UseNegatedImmediate(Node* node) {
212     return sequence()->AddImmediate(ToNegatedConstant(node));
213   }
214 
UseLocation(Node * node,LinkageLocation location)215   InstructionOperand UseLocation(Node* node, LinkageLocation location) {
216     return Use(node, ToUnallocatedOperand(location, GetVReg(node)));
217   }
218 
219   // Used to force gap moves from the from_location to the to_location
220   // immediately before an instruction.
UsePointerLocation(LinkageLocation to_location,LinkageLocation from_location)221   InstructionOperand UsePointerLocation(LinkageLocation to_location,
222                                         LinkageLocation from_location) {
223     UnallocatedOperand casted_from_operand =
224         UnallocatedOperand::cast(TempLocation(from_location));
225     selector_->Emit(kArchNop, casted_from_operand);
226     return ToUnallocatedOperand(to_location,
227                                 casted_from_operand.virtual_register());
228   }
229 
TempRegister()230   InstructionOperand TempRegister() {
231     return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
232                               UnallocatedOperand::USED_AT_START,
233                               sequence()->NextVirtualRegister());
234   }
235 
AllocateVirtualRegister()236   int AllocateVirtualRegister() { return sequence()->NextVirtualRegister(); }
237 
DefineSameAsFirstForVreg(int vreg)238   InstructionOperand DefineSameAsFirstForVreg(int vreg) {
239     return UnallocatedOperand(UnallocatedOperand::SAME_AS_INPUT, vreg);
240   }
241 
DefineAsRegistertForVreg(int vreg)242   InstructionOperand DefineAsRegistertForVreg(int vreg) {
243     return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg);
244   }
245 
UseRegisterForVreg(int vreg)246   InstructionOperand UseRegisterForVreg(int vreg) {
247     return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
248                               UnallocatedOperand::USED_AT_START, vreg);
249   }
250 
251   // The kind of register generated for memory operands. kRegister is alive
252   // until the start of the operation, kUniqueRegister until the end.
253   enum RegisterMode {
254     kRegister,
255     kUniqueRegister,
256   };
257 
UseRegisterWithMode(Node * node,RegisterMode register_mode)258   InstructionOperand UseRegisterWithMode(Node* node,
259                                          RegisterMode register_mode) {
260     return register_mode == kRegister ? UseRegister(node)
261                                       : UseUniqueRegister(node);
262   }
263 
TempDoubleRegister()264   InstructionOperand TempDoubleRegister() {
265     UnallocatedOperand op = UnallocatedOperand(
266         UnallocatedOperand::MUST_HAVE_REGISTER,
267         UnallocatedOperand::USED_AT_START, sequence()->NextVirtualRegister());
268     sequence()->MarkAsRepresentation(MachineRepresentation::kFloat64,
269                                      op.virtual_register());
270     return op;
271   }
272 
TempSimd128Register()273   InstructionOperand TempSimd128Register() {
274     UnallocatedOperand op = UnallocatedOperand(
275         UnallocatedOperand::MUST_HAVE_REGISTER,
276         UnallocatedOperand::USED_AT_START, sequence()->NextVirtualRegister());
277     sequence()->MarkAsRepresentation(MachineRepresentation::kSimd128,
278                                      op.virtual_register());
279     return op;
280   }
281 
TempRegister(Register reg)282   InstructionOperand TempRegister(Register reg) {
283     return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, reg.code(),
284                               InstructionOperand::kInvalidVirtualRegister);
285   }
286 
287   template <typename FPRegType>
TempFpRegister(FPRegType reg)288   InstructionOperand TempFpRegister(FPRegType reg) {
289     UnallocatedOperand op =
290         UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER, reg.code(),
291                            sequence()->NextVirtualRegister());
292     sequence()->MarkAsRepresentation(MachineRepresentation::kSimd128,
293                                      op.virtual_register());
294     return op;
295   }
296 
TempImmediate(int32_t imm)297   InstructionOperand TempImmediate(int32_t imm) {
298     return sequence()->AddImmediate(Constant(imm));
299   }
300 
TempLocation(LinkageLocation location)301   InstructionOperand TempLocation(LinkageLocation location) {
302     return ToUnallocatedOperand(location, sequence()->NextVirtualRegister());
303   }
304 
Label(BasicBlock * block)305   InstructionOperand Label(BasicBlock* block) {
306     return sequence()->AddImmediate(
307         Constant(RpoNumber::FromInt(block->rpo_number())));
308   }
309 
310  protected:
selector()311   InstructionSelector* selector() const { return selector_; }
sequence()312   InstructionSequence* sequence() const { return selector()->sequence(); }
zone()313   Zone* zone() const { return selector()->instruction_zone(); }
314 
315  private:
GetVReg(Node * node)316   int GetVReg(Node* node) const { return selector_->GetVirtualRegister(node); }
317 
ToConstant(const Node * node)318   static Constant ToConstant(const Node* node) {
319     switch (node->opcode()) {
320       case IrOpcode::kInt32Constant:
321         return Constant(OpParameter<int32_t>(node->op()));
322       case IrOpcode::kInt64Constant:
323         return Constant(OpParameter<int64_t>(node->op()));
324       case IrOpcode::kTaggedIndexConstant: {
325         // Unencoded index value.
326         intptr_t value =
327             static_cast<intptr_t>(OpParameter<int32_t>(node->op()));
328         DCHECK(TaggedIndex::IsValid(value));
329         // Generate it as 32/64-bit constant in a tagged form.
330         Address tagged_index = TaggedIndex::FromIntptr(value).ptr();
331         if (kSystemPointerSize == kInt32Size) {
332           return Constant(static_cast<int32_t>(tagged_index));
333         } else {
334           return Constant(static_cast<int64_t>(tagged_index));
335         }
336       }
337       case IrOpcode::kFloat32Constant:
338         return Constant(OpParameter<float>(node->op()));
339       case IrOpcode::kRelocatableInt32Constant:
340       case IrOpcode::kRelocatableInt64Constant:
341         return Constant(OpParameter<RelocatablePtrConstantInfo>(node->op()));
342       case IrOpcode::kFloat64Constant:
343       case IrOpcode::kNumberConstant:
344         return Constant(OpParameter<double>(node->op()));
345       case IrOpcode::kExternalConstant:
346         return Constant(OpParameter<ExternalReference>(node->op()));
347       case IrOpcode::kComment: {
348         // We cannot use {intptr_t} here, since the Constant constructor would
349         // be ambiguous on some architectures.
350         using ptrsize_int_t =
351             std::conditional<kSystemPointerSize == 8, int64_t, int32_t>::type;
352         return Constant(reinterpret_cast<ptrsize_int_t>(
353             OpParameter<const char*>(node->op())));
354       }
355       case IrOpcode::kHeapConstant:
356         return Constant(HeapConstantOf(node->op()));
357       case IrOpcode::kCompressedHeapConstant:
358         return Constant(HeapConstantOf(node->op()), true);
359       case IrOpcode::kDelayedStringConstant:
360         return Constant(StringConstantBaseOf(node->op()));
361       case IrOpcode::kDeadValue: {
362         switch (DeadValueRepresentationOf(node->op())) {
363           case MachineRepresentation::kBit:
364           case MachineRepresentation::kWord32:
365           case MachineRepresentation::kTagged:
366           case MachineRepresentation::kTaggedSigned:
367           case MachineRepresentation::kTaggedPointer:
368           case MachineRepresentation::kCompressed:
369           case MachineRepresentation::kCompressedPointer:
370             return Constant(static_cast<int32_t>(0));
371           case MachineRepresentation::kWord64:
372             return Constant(static_cast<int64_t>(0));
373           case MachineRepresentation::kFloat64:
374             return Constant(static_cast<double>(0));
375           case MachineRepresentation::kFloat32:
376             return Constant(static_cast<float>(0));
377           default:
378             UNREACHABLE();
379         }
380         break;
381       }
382       default:
383         break;
384     }
385     UNREACHABLE();
386   }
387 
ToNegatedConstant(const Node * node)388   static Constant ToNegatedConstant(const Node* node) {
389     switch (node->opcode()) {
390       case IrOpcode::kInt32Constant:
391         return Constant(-OpParameter<int32_t>(node->op()));
392       case IrOpcode::kInt64Constant:
393         return Constant(-OpParameter<int64_t>(node->op()));
394       default:
395         break;
396     }
397     UNREACHABLE();
398   }
399 
Define(Node * node,UnallocatedOperand operand)400   UnallocatedOperand Define(Node* node, UnallocatedOperand operand) {
401     DCHECK_NOT_NULL(node);
402     DCHECK_EQ(operand.virtual_register(), GetVReg(node));
403     selector()->MarkAsDefined(node);
404     return operand;
405   }
406 
Use(Node * node,UnallocatedOperand operand)407   UnallocatedOperand Use(Node* node, UnallocatedOperand operand) {
408     DCHECK_NOT_NULL(node);
409     DCHECK_EQ(operand.virtual_register(), GetVReg(node));
410     selector()->MarkAsUsed(node);
411     return operand;
412   }
413 
ToDualLocationUnallocatedOperand(LinkageLocation primary_location,LinkageLocation secondary_location,int virtual_register)414   UnallocatedOperand ToDualLocationUnallocatedOperand(
415       LinkageLocation primary_location, LinkageLocation secondary_location,
416       int virtual_register) {
417     // We only support the primary location being a register and the secondary
418     // one a slot.
419     DCHECK(primary_location.IsRegister() &&
420            secondary_location.IsCalleeFrameSlot());
421     int reg_id = primary_location.AsRegister();
422     int slot_id = secondary_location.AsCalleeFrameSlot();
423     return UnallocatedOperand(reg_id, slot_id, virtual_register);
424   }
425 
ToUnallocatedOperand(LinkageLocation location,int virtual_register)426   UnallocatedOperand ToUnallocatedOperand(LinkageLocation location,
427                                           int virtual_register) {
428     if (location.IsAnyRegister()) {
429       // any machine register.
430       return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
431                                 virtual_register);
432     }
433     if (location.IsCallerFrameSlot()) {
434       // a location on the caller frame.
435       return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
436                                 location.AsCallerFrameSlot(), virtual_register);
437     }
438     if (location.IsCalleeFrameSlot()) {
439       // a spill location on this (callee) frame.
440       return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
441                                 location.AsCalleeFrameSlot(), virtual_register);
442     }
443     // a fixed register.
444     if (IsFloatingPoint(location.GetType().representation())) {
445       return UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER,
446                                 location.AsRegister(), virtual_register);
447     }
448     return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
449                               location.AsRegister(), virtual_register);
450   }
451 
452   InstructionSelector* selector_;
453 };
454 
455 }  // namespace compiler
456 }  // namespace internal
457 }  // namespace v8
458 
459 #endif  // V8_COMPILER_BACKEND_INSTRUCTION_SELECTOR_IMPL_H_
460