• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H_
6 #define V8_COMPILER_INSTRUCTION_SELECTOR_H_
7 
8 #include <map>
9 
10 #include "src/compiler/common-operator.h"
11 #include "src/compiler/instruction-scheduler.h"
12 #include "src/compiler/instruction.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/machine-operator.h"
15 #include "src/compiler/node.h"
16 #include "src/globals.h"
17 #include "src/zone/zone-containers.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22 
23 // Forward declarations.
24 class BasicBlock;
25 struct CallBuffer;  // TODO(bmeurer): Remove this.
26 class Linkage;
27 class OperandGenerator;
28 class SwitchInfo;
29 class StateObjectDeduplicator;
30 
31 // The flags continuation is a way to combine a branch or a materialization
32 // of a boolean value with an instruction that sets the flags register.
33 // The whole instruction is treated as a unit by the register allocator, and
34 // thus no spills or moves can be introduced between the flags-setting
35 // instruction and the branch or set it should be combined with.
36 class FlagsContinuation final {
37  public:
FlagsContinuation()38   FlagsContinuation() : mode_(kFlags_none) {}
39 
40   // Creates a new flags continuation from the given condition and true/false
41   // blocks.
ForBranch(FlagsCondition condition,BasicBlock * true_block,BasicBlock * false_block)42   static FlagsContinuation ForBranch(FlagsCondition condition,
43                                      BasicBlock* true_block,
44                                      BasicBlock* false_block) {
45     return FlagsContinuation(kFlags_branch, condition, true_block, false_block);
46   }
47 
ForBranchAndPoison(FlagsCondition condition,BasicBlock * true_block,BasicBlock * false_block)48   static FlagsContinuation ForBranchAndPoison(FlagsCondition condition,
49                                               BasicBlock* true_block,
50                                               BasicBlock* false_block) {
51     return FlagsContinuation(kFlags_branch_and_poison, condition, true_block,
52                              false_block);
53   }
54 
55   // Creates a new flags continuation for an eager deoptimization exit.
ForDeoptimize(FlagsCondition condition,DeoptimizeKind kind,DeoptimizeReason reason,VectorSlotPair const & feedback,Node * frame_state)56   static FlagsContinuation ForDeoptimize(FlagsCondition condition,
57                                          DeoptimizeKind kind,
58                                          DeoptimizeReason reason,
59                                          VectorSlotPair const& feedback,
60                                          Node* frame_state) {
61     return FlagsContinuation(kFlags_deoptimize, condition, kind, reason,
62                              feedback, frame_state);
63   }
64 
65   // Creates a new flags continuation for an eager deoptimization exit.
ForDeoptimizeAndPoison(FlagsCondition condition,DeoptimizeKind kind,DeoptimizeReason reason,VectorSlotPair const & feedback,Node * frame_state)66   static FlagsContinuation ForDeoptimizeAndPoison(
67       FlagsCondition condition, DeoptimizeKind kind, DeoptimizeReason reason,
68       VectorSlotPair const& feedback, Node* frame_state) {
69     return FlagsContinuation(kFlags_deoptimize_and_poison, condition, kind,
70                              reason, feedback, frame_state);
71   }
72 
73   // Creates a new flags continuation for a boolean value.
ForSet(FlagsCondition condition,Node * result)74   static FlagsContinuation ForSet(FlagsCondition condition, Node* result) {
75     return FlagsContinuation(condition, result);
76   }
77 
78   // Creates a new flags continuation for a wasm trap.
ForTrap(FlagsCondition condition,TrapId trap_id,Node * result)79   static FlagsContinuation ForTrap(FlagsCondition condition, TrapId trap_id,
80                                    Node* result) {
81     return FlagsContinuation(condition, trap_id, result);
82   }
83 
IsNone()84   bool IsNone() const { return mode_ == kFlags_none; }
IsBranch()85   bool IsBranch() const {
86     return mode_ == kFlags_branch || mode_ == kFlags_branch_and_poison;
87   }
IsDeoptimize()88   bool IsDeoptimize() const {
89     return mode_ == kFlags_deoptimize || mode_ == kFlags_deoptimize_and_poison;
90   }
IsPoisoned()91   bool IsPoisoned() const {
92     return mode_ == kFlags_branch_and_poison ||
93            mode_ == kFlags_deoptimize_and_poison;
94   }
IsSet()95   bool IsSet() const { return mode_ == kFlags_set; }
IsTrap()96   bool IsTrap() const { return mode_ == kFlags_trap; }
condition()97   FlagsCondition condition() const {
98     DCHECK(!IsNone());
99     return condition_;
100   }
kind()101   DeoptimizeKind kind() const {
102     DCHECK(IsDeoptimize());
103     return kind_;
104   }
reason()105   DeoptimizeReason reason() const {
106     DCHECK(IsDeoptimize());
107     return reason_;
108   }
feedback()109   VectorSlotPair const& feedback() const {
110     DCHECK(IsDeoptimize());
111     return feedback_;
112   }
frame_state()113   Node* frame_state() const {
114     DCHECK(IsDeoptimize());
115     return frame_state_or_result_;
116   }
result()117   Node* result() const {
118     DCHECK(IsSet());
119     return frame_state_or_result_;
120   }
trap_id()121   TrapId trap_id() const {
122     DCHECK(IsTrap());
123     return trap_id_;
124   }
true_block()125   BasicBlock* true_block() const {
126     DCHECK(IsBranch());
127     return true_block_;
128   }
false_block()129   BasicBlock* false_block() const {
130     DCHECK(IsBranch());
131     return false_block_;
132   }
133 
Negate()134   void Negate() {
135     DCHECK(!IsNone());
136     condition_ = NegateFlagsCondition(condition_);
137   }
138 
Commute()139   void Commute() {
140     DCHECK(!IsNone());
141     condition_ = CommuteFlagsCondition(condition_);
142   }
143 
Overwrite(FlagsCondition condition)144   void Overwrite(FlagsCondition condition) { condition_ = condition; }
145 
OverwriteAndNegateIfEqual(FlagsCondition condition)146   void OverwriteAndNegateIfEqual(FlagsCondition condition) {
147     DCHECK(condition_ == kEqual || condition_ == kNotEqual);
148     bool negate = condition_ == kEqual;
149     condition_ = condition;
150     if (negate) Negate();
151   }
152 
OverwriteUnsignedIfSigned()153   void OverwriteUnsignedIfSigned() {
154     switch (condition_) {
155       case kSignedLessThan:
156         condition_ = kUnsignedLessThan;
157         break;
158       case kSignedLessThanOrEqual:
159         condition_ = kUnsignedLessThanOrEqual;
160         break;
161       case kSignedGreaterThan:
162         condition_ = kUnsignedGreaterThan;
163         break;
164       case kSignedGreaterThanOrEqual:
165         condition_ = kUnsignedGreaterThanOrEqual;
166         break;
167       default:
168         break;
169     }
170   }
171 
172   // Encodes this flags continuation into the given opcode.
Encode(InstructionCode opcode)173   InstructionCode Encode(InstructionCode opcode) {
174     opcode |= FlagsModeField::encode(mode_);
175     if (mode_ != kFlags_none) {
176       opcode |= FlagsConditionField::encode(condition_);
177     }
178     return opcode;
179   }
180 
181  private:
FlagsContinuation(FlagsMode mode,FlagsCondition condition,BasicBlock * true_block,BasicBlock * false_block)182   FlagsContinuation(FlagsMode mode, FlagsCondition condition,
183                     BasicBlock* true_block, BasicBlock* false_block)
184       : mode_(mode),
185         condition_(condition),
186         true_block_(true_block),
187         false_block_(false_block) {
188     DCHECK(mode == kFlags_branch || mode == kFlags_branch_and_poison);
189     DCHECK_NOT_NULL(true_block);
190     DCHECK_NOT_NULL(false_block);
191   }
192 
FlagsContinuation(FlagsMode mode,FlagsCondition condition,DeoptimizeKind kind,DeoptimizeReason reason,VectorSlotPair const & feedback,Node * frame_state)193   FlagsContinuation(FlagsMode mode, FlagsCondition condition,
194                     DeoptimizeKind kind, DeoptimizeReason reason,
195                     VectorSlotPair const& feedback, Node* frame_state)
196       : mode_(mode),
197         condition_(condition),
198         kind_(kind),
199         reason_(reason),
200         feedback_(feedback),
201         frame_state_or_result_(frame_state) {
202     DCHECK(mode == kFlags_deoptimize || mode == kFlags_deoptimize_and_poison);
203     DCHECK_NOT_NULL(frame_state);
204   }
205 
FlagsContinuation(FlagsCondition condition,Node * result)206   FlagsContinuation(FlagsCondition condition, Node* result)
207       : mode_(kFlags_set),
208         condition_(condition),
209         frame_state_or_result_(result) {
210     DCHECK_NOT_NULL(result);
211   }
212 
FlagsContinuation(FlagsCondition condition,TrapId trap_id,Node * result)213   FlagsContinuation(FlagsCondition condition, TrapId trap_id, Node* result)
214       : mode_(kFlags_trap),
215         condition_(condition),
216         frame_state_or_result_(result),
217         trap_id_(trap_id) {
218     DCHECK_NOT_NULL(result);
219   }
220 
221   FlagsMode const mode_;
222   FlagsCondition condition_;
223   DeoptimizeKind kind_;          // Only valid if mode_ == kFlags_deoptimize*
224   DeoptimizeReason reason_;      // Only valid if mode_ == kFlags_deoptimize*
225   VectorSlotPair feedback_;      // Only valid if mode_ == kFlags_deoptimize*
226   Node* frame_state_or_result_;  // Only valid if mode_ == kFlags_deoptimize*
227                                  // or mode_ == kFlags_set.
228   BasicBlock* true_block_;       // Only valid if mode_ == kFlags_branch*.
229   BasicBlock* false_block_;      // Only valid if mode_ == kFlags_branch*.
230   TrapId trap_id_;               // Only valid if mode_ == kFlags_trap.
231 };
232 
233 // This struct connects nodes of parameters which are going to be pushed on the
234 // call stack with their parameter index in the call descriptor of the callee.
235 struct PushParameter {
236   PushParameter(Node* n = nullptr,
237                 LinkageLocation l = LinkageLocation::ForAnyRegister())
nodePushParameter238       : node(n), location(l) {}
239 
240   Node* node;
241   LinkageLocation location;
242 };
243 
244 enum class FrameStateInputKind { kAny, kStackSlot };
245 
246 // Instruction selection generates an InstructionSequence for a given Schedule.
247 class V8_EXPORT_PRIVATE InstructionSelector final {
248  public:
249   // Forward declarations.
250   class Features;
251 
252   enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions };
253   enum EnableScheduling { kDisableScheduling, kEnableScheduling };
254   enum EnableRootsRelativeAddressing {
255     kDisableRootsRelativeAddressing,
256     kEnableRootsRelativeAddressing
257   };
258   enum EnableSwitchJumpTable {
259     kDisableSwitchJumpTable,
260     kEnableSwitchJumpTable
261   };
262   enum EnableTraceTurboJson { kDisableTraceTurboJson, kEnableTraceTurboJson };
263 
264   InstructionSelector(
265       Zone* zone, size_t node_count, Linkage* linkage,
266       InstructionSequence* sequence, Schedule* schedule,
267       SourcePositionTable* source_positions, Frame* frame,
268       EnableSwitchJumpTable enable_switch_jump_table,
269       SourcePositionMode source_position_mode = kCallSourcePositions,
270       Features features = SupportedFeatures(),
271       EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling
272                                                ? kEnableScheduling
273                                                : kDisableScheduling,
274       EnableRootsRelativeAddressing enable_roots_relative_addressing =
275           kDisableRootsRelativeAddressing,
276       PoisoningMitigationLevel poisoning_level =
277           PoisoningMitigationLevel::kDontPoison,
278       EnableTraceTurboJson trace_turbo = kDisableTraceTurboJson);
279 
280   // Visit code for the entire graph with the included schedule.
281   bool SelectInstructions();
282 
283   void StartBlock(RpoNumber rpo);
284   void EndBlock(RpoNumber rpo);
285   void AddInstruction(Instruction* instr);
286   void AddTerminator(Instruction* instr);
287 
288   // ===========================================================================
289   // ============= Architecture-independent code emission methods. =============
290   // ===========================================================================
291 
292   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
293                     size_t temp_count = 0, InstructionOperand* temps = nullptr);
294   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
295                     InstructionOperand a, size_t temp_count = 0,
296                     InstructionOperand* temps = nullptr);
297   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
298                     InstructionOperand a, InstructionOperand b,
299                     size_t temp_count = 0, InstructionOperand* temps = nullptr);
300   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
301                     InstructionOperand a, InstructionOperand b,
302                     InstructionOperand c, size_t temp_count = 0,
303                     InstructionOperand* temps = nullptr);
304   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
305                     InstructionOperand a, InstructionOperand b,
306                     InstructionOperand c, InstructionOperand d,
307                     size_t temp_count = 0, InstructionOperand* temps = nullptr);
308   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
309                     InstructionOperand a, InstructionOperand b,
310                     InstructionOperand c, InstructionOperand d,
311                     InstructionOperand e, size_t temp_count = 0,
312                     InstructionOperand* temps = nullptr);
313   Instruction* Emit(InstructionCode opcode, InstructionOperand output,
314                     InstructionOperand a, InstructionOperand b,
315                     InstructionOperand c, InstructionOperand d,
316                     InstructionOperand e, InstructionOperand f,
317                     size_t temp_count = 0, InstructionOperand* temps = nullptr);
318   Instruction* Emit(InstructionCode opcode, size_t output_count,
319                     InstructionOperand* outputs, size_t input_count,
320                     InstructionOperand* inputs, size_t temp_count = 0,
321                     InstructionOperand* temps = nullptr);
322   Instruction* Emit(Instruction* instr);
323 
324   // [0-3] operand instructions with no output, uses labels for true and false
325   // blocks of the continuation.
326   Instruction* EmitWithContinuation(InstructionCode opcode,
327                                     FlagsContinuation* cont);
328   Instruction* EmitWithContinuation(InstructionCode opcode,
329                                     InstructionOperand a,
330                                     FlagsContinuation* cont);
331   Instruction* EmitWithContinuation(InstructionCode opcode,
332                                     InstructionOperand a, InstructionOperand b,
333                                     FlagsContinuation* cont);
334   Instruction* EmitWithContinuation(InstructionCode opcode,
335                                     InstructionOperand a, InstructionOperand b,
336                                     InstructionOperand c,
337                                     FlagsContinuation* cont);
338   Instruction* EmitWithContinuation(InstructionCode opcode, size_t output_count,
339                                     InstructionOperand* outputs,
340                                     size_t input_count,
341                                     InstructionOperand* inputs,
342                                     FlagsContinuation* cont);
343 
344   // ===========================================================================
345   // ===== Architecture-independent deoptimization exit emission methods. ======
346   // ===========================================================================
347   Instruction* EmitDeoptimize(InstructionCode opcode, size_t output_count,
348                               InstructionOperand* outputs, size_t input_count,
349                               InstructionOperand* inputs, DeoptimizeKind kind,
350                               DeoptimizeReason reason,
351                               VectorSlotPair const& feedback,
352                               Node* frame_state);
353 
354   // ===========================================================================
355   // ============== Architecture-independent CPU feature methods. ==============
356   // ===========================================================================
357 
358   class Features final {
359    public:
Features()360     Features() : bits_(0) {}
Features(unsigned bits)361     explicit Features(unsigned bits) : bits_(bits) {}
Features(CpuFeature f)362     explicit Features(CpuFeature f) : bits_(1u << f) {}
Features(CpuFeature f1,CpuFeature f2)363     Features(CpuFeature f1, CpuFeature f2) : bits_((1u << f1) | (1u << f2)) {}
364 
Contains(CpuFeature f)365     bool Contains(CpuFeature f) const { return (bits_ & (1u << f)); }
366 
367    private:
368     unsigned bits_;
369   };
370 
IsSupported(CpuFeature feature)371   bool IsSupported(CpuFeature feature) const {
372     return features_.Contains(feature);
373   }
374 
375   // Returns the features supported on the target platform.
SupportedFeatures()376   static Features SupportedFeatures() {
377     return Features(CpuFeatures::SupportedFeatures());
378   }
379 
380   // TODO(sigurds) This should take a CpuFeatures argument.
381   static MachineOperatorBuilder::Flags SupportedMachineOperatorFlags();
382 
383   static MachineOperatorBuilder::AlignmentRequirements AlignmentRequirements();
384 
385   bool NeedsPoisoning(IsSafetyCheck safety_check) const;
386 
387   // ===========================================================================
388   // ============ Architecture-independent graph covering methods. =============
389   // ===========================================================================
390 
391   // Used in pattern matching during code generation.
392   // Check if {node} can be covered while generating code for the current
393   // instruction. A node can be covered if the {user} of the node has the only
394   // edge and the two are in the same basic block.
395   bool CanCover(Node* user, Node* node) const;
396 
397   // Used in pattern matching during code generation.
398   // This function checks that {node} and {user} are in the same basic block,
399   // and that {user} is the only user of {node} in this basic block.  This
400   // check guarantees that there are no users of {node} scheduled between
401   // {node} and {user}, and thus we can select a single instruction for both
402   // nodes, if such an instruction exists. This check can be used for example
403   // when selecting instructions for:
404   //   n = Int32Add(a, b)
405   //   c = Word32Compare(n, 0, cond)
406   //   Branch(c, true_label, false_label)
407   // Here we can generate a flag-setting add instruction, even if the add has
408   // uses in other basic blocks, since the flag-setting add instruction will
409   // still generate the result of the addition and not just set the flags.
410   // However, if we had uses of the add in the same basic block, we could have:
411   //   n = Int32Add(a, b)
412   //   o = OtherOp(n, ...)
413   //   c = Word32Compare(n, 0, cond)
414   //   Branch(c, true_label, false_label)
415   // where we cannot select the add and the compare together.  If we were to
416   // select a flag-setting add instruction for Word32Compare and Int32Add while
417   // visiting Word32Compare, we would then have to select an instruction for
418   // OtherOp *afterwards*, which means we would attempt to use the result of
419   // the add before we have defined it.
420   bool IsOnlyUserOfNodeInSameBlock(Node* user, Node* node) const;
421 
422   // Checks if {node} was already defined, and therefore code was already
423   // generated for it.
424   bool IsDefined(Node* node) const;
425 
426   // Checks if {node} has any uses, and therefore code has to be generated for
427   // it.
428   bool IsUsed(Node* node) const;
429 
430   // Checks if {node} is currently live.
IsLive(Node * node)431   bool IsLive(Node* node) const { return !IsDefined(node) && IsUsed(node); }
432 
433   // Gets the effect level of {node}.
434   int GetEffectLevel(Node* node) const;
435 
436   int GetVirtualRegister(const Node* node);
437   const std::map<NodeId, int> GetVirtualRegistersForTesting() const;
438 
439   // Check if we can generate loads and stores of ExternalConstants relative
440   // to the roots register.
441   bool CanAddressRelativeToRootsRegister() const;
442   // Check if we can use the roots register to access GC roots.
443   bool CanUseRootsRegister() const;
444 
isolate()445   Isolate* isolate() const { return sequence()->isolate(); }
446 
instr_origins()447   const ZoneVector<std::pair<int, int>>& instr_origins() const {
448     return instr_origins_;
449   }
450 
451   // Expose these SIMD helper functions for testing.
CanonicalizeShuffleForTesting(bool inputs_equal,uint8_t * shuffle,bool * needs_swap,bool * is_swizzle)452   static void CanonicalizeShuffleForTesting(bool inputs_equal, uint8_t* shuffle,
453                                             bool* needs_swap,
454                                             bool* is_swizzle) {
455     CanonicalizeShuffle(inputs_equal, shuffle, needs_swap, is_swizzle);
456   }
457 
TryMatchIdentityForTesting(const uint8_t * shuffle)458   static bool TryMatchIdentityForTesting(const uint8_t* shuffle) {
459     return TryMatchIdentity(shuffle);
460   }
461   template <int LANES>
TryMatchDupForTesting(const uint8_t * shuffle,int * index)462   static bool TryMatchDupForTesting(const uint8_t* shuffle, int* index) {
463     return TryMatchDup<LANES>(shuffle, index);
464   }
TryMatch32x4ShuffleForTesting(const uint8_t * shuffle,uint8_t * shuffle32x4)465   static bool TryMatch32x4ShuffleForTesting(const uint8_t* shuffle,
466                                             uint8_t* shuffle32x4) {
467     return TryMatch32x4Shuffle(shuffle, shuffle32x4);
468   }
TryMatch16x8ShuffleForTesting(const uint8_t * shuffle,uint8_t * shuffle16x8)469   static bool TryMatch16x8ShuffleForTesting(const uint8_t* shuffle,
470                                             uint8_t* shuffle16x8) {
471     return TryMatch16x8Shuffle(shuffle, shuffle16x8);
472   }
TryMatchConcatForTesting(const uint8_t * shuffle,uint8_t * offset)473   static bool TryMatchConcatForTesting(const uint8_t* shuffle,
474                                        uint8_t* offset) {
475     return TryMatchConcat(shuffle, offset);
476   }
TryMatchBlendForTesting(const uint8_t * shuffle)477   static bool TryMatchBlendForTesting(const uint8_t* shuffle) {
478     return TryMatchBlend(shuffle);
479   }
480 
481  private:
482   friend class OperandGenerator;
483 
UseInstructionScheduling()484   bool UseInstructionScheduling() const {
485     return (enable_scheduling_ == kEnableScheduling) &&
486            InstructionScheduler::SchedulerSupported();
487   }
488 
489   void AppendDeoptimizeArguments(InstructionOperandVector* args,
490                                  DeoptimizeKind kind, DeoptimizeReason reason,
491                                  VectorSlotPair const& feedback,
492                                  Node* frame_state);
493 
494   void EmitTableSwitch(const SwitchInfo& sw, InstructionOperand& index_operand);
495   void EmitLookupSwitch(const SwitchInfo& sw,
496                         InstructionOperand& value_operand);
497   void EmitBinarySearchSwitch(const SwitchInfo& sw,
498                               InstructionOperand& value_operand);
499 
500   void TryRename(InstructionOperand* op);
501   int GetRename(int virtual_register);
502   void SetRename(const Node* node, const Node* rename);
503   void UpdateRenames(Instruction* instruction);
504   void UpdateRenamesInPhi(PhiInstruction* phi);
505 
506   // Inform the instruction selection that {node} was just defined.
507   void MarkAsDefined(Node* node);
508 
509   // Inform the instruction selection that {node} has at least one use and we
510   // will need to generate code for it.
511   void MarkAsUsed(Node* node);
512 
513   // Sets the effect level of {node}.
514   void SetEffectLevel(Node* node, int effect_level);
515 
516   // Inform the register allocation of the representation of the value produced
517   // by {node}.
518   void MarkAsRepresentation(MachineRepresentation rep, Node* node);
MarkAsWord32(Node * node)519   void MarkAsWord32(Node* node) {
520     MarkAsRepresentation(MachineRepresentation::kWord32, node);
521   }
MarkAsWord64(Node * node)522   void MarkAsWord64(Node* node) {
523     MarkAsRepresentation(MachineRepresentation::kWord64, node);
524   }
MarkAsFloat32(Node * node)525   void MarkAsFloat32(Node* node) {
526     MarkAsRepresentation(MachineRepresentation::kFloat32, node);
527   }
MarkAsFloat64(Node * node)528   void MarkAsFloat64(Node* node) {
529     MarkAsRepresentation(MachineRepresentation::kFloat64, node);
530   }
MarkAsSimd128(Node * node)531   void MarkAsSimd128(Node* node) {
532     MarkAsRepresentation(MachineRepresentation::kSimd128, node);
533   }
MarkAsReference(Node * node)534   void MarkAsReference(Node* node) {
535     MarkAsRepresentation(MachineRepresentation::kTagged, node);
536   }
537 
538   // Inform the register allocation of the representation of the unallocated
539   // operand {op}.
540   void MarkAsRepresentation(MachineRepresentation rep,
541                             const InstructionOperand& op);
542 
543   enum CallBufferFlag {
544     kCallCodeImmediate = 1u << 0,
545     kCallAddressImmediate = 1u << 1,
546     kCallTail = 1u << 2,
547     kCallFixedTargetRegister = 1u << 3,
548   };
549   typedef base::Flags<CallBufferFlag> CallBufferFlags;
550 
551   // Initialize the call buffer with the InstructionOperands, nodes, etc,
552   // corresponding
553   // to the inputs and outputs of the call.
554   // {call_code_immediate} to generate immediate operands to calls of code.
555   // {call_address_immediate} to generate immediate operands to address calls.
556   void InitializeCallBuffer(Node* call, CallBuffer* buffer,
557                             CallBufferFlags flags, bool is_tail_call,
558                             int stack_slot_delta = 0);
559   bool IsTailCallAddressImmediate();
560   int GetTempsCountForTailCallFromJSFunction();
561 
562   FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
563   size_t AddInputsToFrameStateDescriptor(FrameStateDescriptor* descriptor,
564                                          Node* state, OperandGenerator* g,
565                                          StateObjectDeduplicator* deduplicator,
566                                          InstructionOperandVector* inputs,
567                                          FrameStateInputKind kind, Zone* zone);
568   size_t AddOperandToStateValueDescriptor(StateValueList* values,
569                                           InstructionOperandVector* inputs,
570                                           OperandGenerator* g,
571                                           StateObjectDeduplicator* deduplicator,
572                                           Node* input, MachineType type,
573                                           FrameStateInputKind kind, Zone* zone);
574 
575   // ===========================================================================
576   // ============= Architecture-specific graph covering methods. ===============
577   // ===========================================================================
578 
579   // Visit nodes in the given block and generate code.
580   void VisitBlock(BasicBlock* block);
581 
582   // Visit the node for the control flow at the end of the block, generating
583   // code if necessary.
584   void VisitControl(BasicBlock* block);
585 
586   // Visit the node and generate code, if any.
587   void VisitNode(Node* node);
588 
589   // Visit the node and generate code for IEEE 754 functions.
590   void VisitFloat64Ieee754Binop(Node*, InstructionCode code);
591   void VisitFloat64Ieee754Unop(Node*, InstructionCode code);
592 
593 #define DECLARE_GENERATOR(x) void Visit##x(Node* node);
594   MACHINE_OP_LIST(DECLARE_GENERATOR)
595   MACHINE_SIMD_OP_LIST(DECLARE_GENERATOR)
596 #undef DECLARE_GENERATOR
597 
598   void VisitFinishRegion(Node* node);
599   void VisitParameter(Node* node);
600   void VisitIfException(Node* node);
601   void VisitOsrValue(Node* node);
602   void VisitPhi(Node* node);
603   void VisitProjection(Node* node);
604   void VisitConstant(Node* node);
605   void VisitCall(Node* call, BasicBlock* handler = nullptr);
606   void VisitCallWithCallerSavedRegisters(Node* call,
607                                          BasicBlock* handler = nullptr);
608   void VisitDeoptimizeIf(Node* node);
609   void VisitDeoptimizeUnless(Node* node);
610   void VisitTrapIf(Node* node, TrapId trap_id);
611   void VisitTrapUnless(Node* node, TrapId trap_id);
612   void VisitTailCall(Node* call);
613   void VisitGoto(BasicBlock* target);
614   void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
615   void VisitSwitch(Node* node, const SwitchInfo& sw);
616   void VisitDeoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
617                        VectorSlotPair const& feedback, Node* value);
618   void VisitReturn(Node* ret);
619   void VisitThrow(Node* node);
620   void VisitRetain(Node* node);
621   void VisitUnreachable(Node* node);
622   void VisitDeadValue(Node* node);
623 
624   void VisitWordCompareZero(Node* user, Node* value, FlagsContinuation* cont);
625 
626   void EmitWordPoisonOnSpeculation(Node* node);
627 
628   void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments,
629                             const CallDescriptor* call_descriptor, Node* node);
630   void EmitPrepareResults(ZoneVector<compiler::PushParameter>* results,
631                           const CallDescriptor* call_descriptor, Node* node);
632 
633   void EmitIdentity(Node* node);
634   bool CanProduceSignalingNaN(Node* node);
635 
636   // ===========================================================================
637   // ============= Vector instruction (SIMD) helper fns. =======================
638   // ===========================================================================
639 
640   // Converts a shuffle into canonical form, meaning that the first lane index
641   // is in the range [0 .. 15]. Set |inputs_equal| true if this is an explicit
642   // swizzle. Returns canonicalized |shuffle|, |needs_swap|, and |is_swizzle|.
643   // If |needs_swap| is true, inputs must be swapped. If |is_swizzle| is true,
644   // the second input can be ignored.
645   static void CanonicalizeShuffle(bool inputs_equal, uint8_t* shuffle,
646                                   bool* needs_swap, bool* is_swizzle);
647 
648   // Canonicalize shuffles to make pattern matching simpler. Returns the shuffle
649   // indices, and a boolean indicating if the shuffle is a swizzle (one input).
650   void CanonicalizeShuffle(Node* node, uint8_t* shuffle, bool* is_swizzle);
651 
652   // Swaps the two first input operands of the node, to help match shuffles
653   // to specific architectural instructions.
654   void SwapShuffleInputs(Node* node);
655 
656   // Tries to match an 8x16 byte shuffle to the identity shuffle, which is
657   // [0 1 ... 15]. This should be called after canonicalizing the shuffle, so
658   // the second identity shuffle, [16 17 .. 31] is converted to the first one.
659   static bool TryMatchIdentity(const uint8_t* shuffle);
660 
661   // Tries to match a byte shuffle to a scalar splat operation. Returns the
662   // index of the lane if successful.
663   template <int LANES>
TryMatchDup(const uint8_t * shuffle,int * index)664   static bool TryMatchDup(const uint8_t* shuffle, int* index) {
665     const int kBytesPerLane = kSimd128Size / LANES;
666     // Get the first lane's worth of bytes and check that indices start at a
667     // lane boundary and are consecutive.
668     uint8_t lane0[kBytesPerLane];
669     lane0[0] = shuffle[0];
670     if (lane0[0] % kBytesPerLane != 0) return false;
671     for (int i = 1; i < kBytesPerLane; ++i) {
672       lane0[i] = shuffle[i];
673       if (lane0[i] != lane0[0] + i) return false;
674     }
675     // Now check that the other lanes are identical to lane0.
676     for (int i = 1; i < LANES; ++i) {
677       for (int j = 0; j < kBytesPerLane; ++j) {
678         if (lane0[j] != shuffle[i * kBytesPerLane + j]) return false;
679       }
680     }
681     *index = lane0[0] / kBytesPerLane;
682     return true;
683   }
684 
685   // Tries to match an 8x16 byte shuffle to an equivalent 32x4 shuffle. If
686   // successful, it writes the 32x4 shuffle word indices. E.g.
687   // [0 1 2 3 8 9 10 11 4 5 6 7 12 13 14 15] == [0 2 1 3]
688   static bool TryMatch32x4Shuffle(const uint8_t* shuffle, uint8_t* shuffle32x4);
689 
690   // Tries to match an 8x16 byte shuffle to an equivalent 16x8 shuffle. If
691   // successful, it writes the 16x8 shuffle word indices. E.g.
692   // [0 1 8 9 2 3 10 11 4 5 12 13 6 7 14 15] == [0 4 1 5 2 6 3 7]
693   static bool TryMatch16x8Shuffle(const uint8_t* shuffle, uint8_t* shuffle16x8);
694 
695   // Tries to match a byte shuffle to a concatenate operation, formed by taking
696   // 16 bytes from the 32 byte concatenation of the inputs.  If successful, it
697   // writes the byte offset. E.g. [4 5 6 7 .. 16 17 18 19] concatenates both
698   // source vectors with offset 4. The shuffle should be canonicalized.
699   static bool TryMatchConcat(const uint8_t* shuffle, uint8_t* offset);
700 
701   // Tries to match a byte shuffle to a blend operation, which is a shuffle
702   // where no lanes change position. E.g. [0 9 2 11 .. 14 31] interleaves the
703   // even lanes of the first source with the odd lanes of the second.  The
704   // shuffle should be canonicalized.
705   static bool TryMatchBlend(const uint8_t* shuffle);
706 
707   // Packs 4 bytes of shuffle into a 32 bit immediate.
708   static int32_t Pack4Lanes(const uint8_t* shuffle);
709 
710   // ===========================================================================
711 
schedule()712   Schedule* schedule() const { return schedule_; }
linkage()713   Linkage* linkage() const { return linkage_; }
sequence()714   InstructionSequence* sequence() const { return sequence_; }
instruction_zone()715   Zone* instruction_zone() const { return sequence()->zone(); }
zone()716   Zone* zone() const { return zone_; }
717 
set_instruction_selection_failed()718   void set_instruction_selection_failed() {
719     instruction_selection_failed_ = true;
720   }
instruction_selection_failed()721   bool instruction_selection_failed() { return instruction_selection_failed_; }
722 
723   void MarkPairProjectionsAsWord32(Node* node);
724   bool IsSourcePositionUsed(Node* node);
725   void VisitWord32AtomicBinaryOperation(Node* node, ArchOpcode int8_op,
726                                         ArchOpcode uint8_op,
727                                         ArchOpcode int16_op,
728                                         ArchOpcode uint16_op,
729                                         ArchOpcode word32_op);
730   void VisitWord64AtomicBinaryOperation(Node* node, ArchOpcode uint8_op,
731                                         ArchOpcode uint16_op,
732                                         ArchOpcode uint32_op,
733                                         ArchOpcode uint64_op);
734   void VisitWord64AtomicNarrowBinop(Node* node, ArchOpcode uint8_op,
735                                     ArchOpcode uint16_op, ArchOpcode uint32_op);
736 
737   // ===========================================================================
738 
739   Zone* const zone_;
740   Linkage* const linkage_;
741   InstructionSequence* const sequence_;
742   SourcePositionTable* const source_positions_;
743   SourcePositionMode const source_position_mode_;
744   Features features_;
745   Schedule* const schedule_;
746   BasicBlock* current_block_;
747   ZoneVector<Instruction*> instructions_;
748   InstructionOperandVector continuation_inputs_;
749   InstructionOperandVector continuation_outputs_;
750   BoolVector defined_;
751   BoolVector used_;
752   IntVector effect_level_;
753   IntVector virtual_registers_;
754   IntVector virtual_register_rename_;
755   InstructionScheduler* scheduler_;
756   EnableScheduling enable_scheduling_;
757   EnableRootsRelativeAddressing enable_roots_relative_addressing_;
758   EnableSwitchJumpTable enable_switch_jump_table_;
759 
760   PoisoningMitigationLevel poisoning_level_;
761   Frame* frame_;
762   bool instruction_selection_failed_;
763   ZoneVector<std::pair<int, int>> instr_origins_;
764   EnableTraceTurboJson trace_turbo_;
765 };
766 
767 }  // namespace compiler
768 }  // namespace internal
769 }  // namespace v8
770 
771 #endif  // V8_COMPILER_INSTRUCTION_SELECTOR_H_
772