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