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: 33 explicit OperandGenerator(InstructionSelector* selector) 34 : selector_(selector) {} 35 36 InstructionOperand NoOutput() { 37 return InstructionOperand(); // Generates an invalid operand. 38 } 39 40 InstructionOperand DefineAsRegister(Node* node) { 41 return Define(node, 42 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 43 GetVReg(node))); 44 } 45 46 InstructionOperand DefineSameAsFirst(Node* node) { 47 return Define(node, 48 UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT, 49 GetVReg(node))); 50 } 51 52 InstructionOperand DefineAsFixed(Node* node, Register reg) { 53 return Define(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 54 reg.code(), GetVReg(node))); 55 } 56 57 template <typename FPRegType> 58 InstructionOperand DefineAsFixed(Node* node, FPRegType reg) { 59 return Define(node, 60 UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER, 61 reg.code(), GetVReg(node))); 62 } 63 64 InstructionOperand DefineAsConstant(Node* node) { 65 return DefineAsConstant(node, ToConstant(node)); 66 } 67 68 InstructionOperand DefineAsConstant(Node* node, Constant constant) { 69 selector()->MarkAsDefined(node); 70 int virtual_register = GetVReg(node); 71 sequence()->AddConstant(virtual_register, constant); 72 return ConstantOperand(virtual_register); 73 } 74 75 InstructionOperand DefineAsLocation(Node* node, LinkageLocation location) { 76 return Define(node, ToUnallocatedOperand(location, GetVReg(node))); 77 } 78 79 InstructionOperand DefineAsDualLocation(Node* node, 80 LinkageLocation primary_location, 81 LinkageLocation secondary_location) { 82 return Define(node, 83 ToDualLocationUnallocatedOperand( 84 primary_location, secondary_location, GetVReg(node))); 85 } 86 87 InstructionOperand Use(Node* node) { 88 return Use(node, UnallocatedOperand(UnallocatedOperand::NONE, 89 UnallocatedOperand::USED_AT_START, 90 GetVReg(node))); 91 } 92 93 InstructionOperand UseAnyAtEnd(Node* node) { 94 return Use(node, UnallocatedOperand(UnallocatedOperand::ANY, 95 UnallocatedOperand::USED_AT_END, 96 GetVReg(node))); 97 } 98 99 InstructionOperand UseAny(Node* node) { 100 return Use(node, UnallocatedOperand(UnallocatedOperand::ANY, 101 UnallocatedOperand::USED_AT_START, 102 GetVReg(node))); 103 } 104 105 InstructionOperand UseRegister(Node* node) { 106 return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 107 UnallocatedOperand::USED_AT_START, 108 GetVReg(node))); 109 } 110 111 InstructionOperand UseUniqueSlot(Node* node) { 112 return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_SLOT, 113 GetVReg(node))); 114 } 115 116 // Use register or operand for the node. If a register is chosen, it won't 117 // alias any temporary or output registers. 118 InstructionOperand UseUnique(Node* node) { 119 return Use(node, 120 UnallocatedOperand(UnallocatedOperand::NONE, GetVReg(node))); 121 } 122 123 // Use a unique register for the node that does not alias any temporary or 124 // output registers. 125 InstructionOperand UseUniqueRegister(Node* node) { 126 return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 127 GetVReg(node))); 128 } 129 130 InstructionOperand UseFixed(Node* node, Register reg) { 131 return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 132 reg.code(), GetVReg(node))); 133 } 134 135 template <typename FPRegType> 136 InstructionOperand UseFixed(Node* node, FPRegType reg) { 137 return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER, 138 reg.code(), GetVReg(node))); 139 } 140 141 InstructionOperand UseExplicit(LinkageLocation location) { 142 MachineRepresentation rep = InstructionSequence::DefaultRepresentation(); 143 if (location.IsRegister()) { 144 return ExplicitOperand(LocationOperand::REGISTER, rep, 145 location.AsRegister()); 146 } else { 147 return ExplicitOperand(LocationOperand::STACK_SLOT, rep, 148 location.GetLocation()); 149 } 150 } 151 152 InstructionOperand UseImmediate(int immediate) { 153 return sequence()->AddImmediate(Constant(immediate)); 154 } 155 156 InstructionOperand UseImmediate(Node* node) { 157 return sequence()->AddImmediate(ToConstant(node)); 158 } 159 160 InstructionOperand UseNegatedImmediate(Node* node) { 161 return sequence()->AddImmediate(ToNegatedConstant(node)); 162 } 163 164 InstructionOperand UseLocation(Node* node, LinkageLocation location) { 165 return Use(node, ToUnallocatedOperand(location, GetVReg(node))); 166 } 167 168 // Used to force gap moves from the from_location to the to_location 169 // immediately before an instruction. 170 InstructionOperand UsePointerLocation(LinkageLocation to_location, 171 LinkageLocation from_location) { 172 UnallocatedOperand casted_from_operand = 173 UnallocatedOperand::cast(TempLocation(from_location)); 174 selector_->Emit(kArchNop, casted_from_operand); 175 return ToUnallocatedOperand(to_location, 176 casted_from_operand.virtual_register()); 177 } 178 179 InstructionOperand TempRegister() { 180 return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 181 UnallocatedOperand::USED_AT_START, 182 sequence()->NextVirtualRegister()); 183 } 184 185 InstructionOperand TempDoubleRegister() { 186 UnallocatedOperand op = UnallocatedOperand( 187 UnallocatedOperand::MUST_HAVE_REGISTER, 188 UnallocatedOperand::USED_AT_START, sequence()->NextVirtualRegister()); 189 sequence()->MarkAsRepresentation(MachineRepresentation::kFloat64, 190 op.virtual_register()); 191 return op; 192 } 193 194 InstructionOperand TempRegister(Register reg) { 195 return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, reg.code(), 196 InstructionOperand::kInvalidVirtualRegister); 197 } 198 199 InstructionOperand TempImmediate(int32_t imm) { 200 return sequence()->AddImmediate(Constant(imm)); 201 } 202 203 InstructionOperand TempLocation(LinkageLocation location) { 204 return ToUnallocatedOperand(location, sequence()->NextVirtualRegister()); 205 } 206 207 InstructionOperand Label(BasicBlock* block) { 208 return sequence()->AddImmediate( 209 Constant(RpoNumber::FromInt(block->rpo_number()))); 210 } 211 212 protected: 213 InstructionSelector* selector() const { return selector_; } 214 InstructionSequence* sequence() const { return selector()->sequence(); } 215 Zone* zone() const { return selector()->instruction_zone(); } 216 217 private: 218 int GetVReg(Node* node) const { return selector_->GetVirtualRegister(node); } 219 220 static Constant ToConstant(const Node* node) { 221 switch (node->opcode()) { 222 case IrOpcode::kInt32Constant: 223 return Constant(OpParameter<int32_t>(node)); 224 case IrOpcode::kInt64Constant: 225 return Constant(OpParameter<int64_t>(node)); 226 case IrOpcode::kFloat32Constant: 227 return Constant(OpParameter<float>(node)); 228 case IrOpcode::kRelocatableInt32Constant: 229 case IrOpcode::kRelocatableInt64Constant: 230 return Constant(OpParameter<RelocatablePtrConstantInfo>(node)); 231 case IrOpcode::kFloat64Constant: 232 case IrOpcode::kNumberConstant: 233 return Constant(OpParameter<double>(node)); 234 case IrOpcode::kExternalConstant: 235 case IrOpcode::kComment: 236 return Constant(OpParameter<ExternalReference>(node)); 237 case IrOpcode::kHeapConstant: 238 return Constant(OpParameter<Handle<HeapObject>>(node)); 239 default: 240 break; 241 } 242 UNREACHABLE(); 243 return Constant(static_cast<int32_t>(0)); 244 } 245 246 static Constant ToNegatedConstant(const Node* node) { 247 switch (node->opcode()) { 248 case IrOpcode::kInt32Constant: 249 return Constant(-OpParameter<int32_t>(node)); 250 case IrOpcode::kInt64Constant: 251 return Constant(-OpParameter<int64_t>(node)); 252 default: 253 break; 254 } 255 UNREACHABLE(); 256 return Constant(static_cast<int32_t>(0)); 257 } 258 259 UnallocatedOperand Define(Node* node, UnallocatedOperand operand) { 260 DCHECK_NOT_NULL(node); 261 DCHECK_EQ(operand.virtual_register(), GetVReg(node)); 262 selector()->MarkAsDefined(node); 263 return operand; 264 } 265 266 UnallocatedOperand Use(Node* node, UnallocatedOperand operand) { 267 DCHECK_NOT_NULL(node); 268 DCHECK_EQ(operand.virtual_register(), GetVReg(node)); 269 selector()->MarkAsUsed(node); 270 return operand; 271 } 272 273 UnallocatedOperand ToDualLocationUnallocatedOperand( 274 LinkageLocation primary_location, LinkageLocation secondary_location, 275 int virtual_register) { 276 // We only support the primary location being a register and the secondary 277 // one a slot. 278 DCHECK(primary_location.IsRegister() && 279 secondary_location.IsCalleeFrameSlot()); 280 int reg_id = primary_location.AsRegister(); 281 int slot_id = secondary_location.AsCalleeFrameSlot(); 282 return UnallocatedOperand(reg_id, slot_id, virtual_register); 283 } 284 285 UnallocatedOperand ToUnallocatedOperand(LinkageLocation location, 286 int virtual_register) { 287 if (location.IsAnyRegister()) { 288 // any machine register. 289 return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 290 virtual_register); 291 } 292 if (location.IsCallerFrameSlot()) { 293 // a location on the caller frame. 294 return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT, 295 location.AsCallerFrameSlot(), virtual_register); 296 } 297 if (location.IsCalleeFrameSlot()) { 298 // a spill location on this (callee) frame. 299 return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT, 300 location.AsCalleeFrameSlot(), virtual_register); 301 } 302 // a fixed register. 303 if (IsFloatingPoint(location.GetType().representation())) { 304 return UnallocatedOperand(UnallocatedOperand::FIXED_FP_REGISTER, 305 location.AsRegister(), virtual_register); 306 } 307 return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 308 location.AsRegister(), virtual_register); 309 } 310 311 InstructionSelector* selector_; 312 }; 313 314 315 // The flags continuation is a way to combine a branch or a materialization 316 // of a boolean value with an instruction that sets the flags register. 317 // The whole instruction is treated as a unit by the register allocator, and 318 // thus no spills or moves can be introduced between the flags-setting 319 // instruction and the branch or set it should be combined with. 320 class FlagsContinuation final { 321 public: 322 FlagsContinuation() : mode_(kFlags_none) {} 323 324 // Creates a new flags continuation from the given condition and true/false 325 // blocks. 326 FlagsContinuation(FlagsCondition condition, BasicBlock* true_block, 327 BasicBlock* false_block) 328 : mode_(kFlags_branch), 329 condition_(condition), 330 true_block_(true_block), 331 false_block_(false_block) { 332 DCHECK_NOT_NULL(true_block); 333 DCHECK_NOT_NULL(false_block); 334 } 335 336 // Creates a new flags continuation for an eager deoptimization exit. 337 static FlagsContinuation ForDeoptimize(FlagsCondition condition, 338 DeoptimizeReason reason, 339 Node* frame_state) { 340 return FlagsContinuation(condition, reason, frame_state); 341 } 342 343 // Creates a new flags continuation for a boolean value. 344 static FlagsContinuation ForSet(FlagsCondition condition, Node* result) { 345 return FlagsContinuation(condition, result); 346 } 347 348 bool IsNone() const { return mode_ == kFlags_none; } 349 bool IsBranch() const { return mode_ == kFlags_branch; } 350 bool IsDeoptimize() const { return mode_ == kFlags_deoptimize; } 351 bool IsSet() const { return mode_ == kFlags_set; } 352 FlagsCondition condition() const { 353 DCHECK(!IsNone()); 354 return condition_; 355 } 356 DeoptimizeReason reason() const { 357 DCHECK(IsDeoptimize()); 358 return reason_; 359 } 360 Node* frame_state() const { 361 DCHECK(IsDeoptimize()); 362 return frame_state_or_result_; 363 } 364 Node* result() const { 365 DCHECK(IsSet()); 366 return frame_state_or_result_; 367 } 368 BasicBlock* true_block() const { 369 DCHECK(IsBranch()); 370 return true_block_; 371 } 372 BasicBlock* false_block() const { 373 DCHECK(IsBranch()); 374 return false_block_; 375 } 376 377 void Negate() { 378 DCHECK(!IsNone()); 379 condition_ = NegateFlagsCondition(condition_); 380 } 381 382 void Commute() { 383 DCHECK(!IsNone()); 384 condition_ = CommuteFlagsCondition(condition_); 385 } 386 387 void Overwrite(FlagsCondition condition) { condition_ = condition; } 388 389 void OverwriteAndNegateIfEqual(FlagsCondition condition) { 390 DCHECK(condition_ == kEqual || condition_ == kNotEqual); 391 bool negate = condition_ == kEqual; 392 condition_ = condition; 393 if (negate) Negate(); 394 } 395 396 void OverwriteUnsignedIfSigned() { 397 switch (condition_) { 398 case kSignedLessThan: 399 condition_ = kUnsignedLessThan; 400 break; 401 case kSignedLessThanOrEqual: 402 condition_ = kUnsignedLessThanOrEqual; 403 break; 404 case kSignedGreaterThan: 405 condition_ = kUnsignedGreaterThan; 406 break; 407 case kSignedGreaterThanOrEqual: 408 condition_ = kUnsignedGreaterThanOrEqual; 409 break; 410 default: 411 break; 412 } 413 } 414 415 // Encodes this flags continuation into the given opcode. 416 InstructionCode Encode(InstructionCode opcode) { 417 opcode |= FlagsModeField::encode(mode_); 418 if (mode_ != kFlags_none) { 419 opcode |= FlagsConditionField::encode(condition_); 420 } 421 return opcode; 422 } 423 424 private: 425 FlagsContinuation(FlagsCondition condition, DeoptimizeReason reason, 426 Node* frame_state) 427 : mode_(kFlags_deoptimize), 428 condition_(condition), 429 reason_(reason), 430 frame_state_or_result_(frame_state) { 431 DCHECK_NOT_NULL(frame_state); 432 } 433 FlagsContinuation(FlagsCondition condition, Node* result) 434 : mode_(kFlags_set), 435 condition_(condition), 436 frame_state_or_result_(result) { 437 DCHECK_NOT_NULL(result); 438 } 439 440 FlagsMode const mode_; 441 FlagsCondition condition_; 442 DeoptimizeReason reason_; // Only value if mode_ == kFlags_deoptimize 443 Node* frame_state_or_result_; // Only valid if mode_ == kFlags_deoptimize 444 // or mode_ == kFlags_set. 445 BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch. 446 BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch. 447 }; 448 449 } // namespace compiler 450 } // namespace internal 451 } // namespace v8 452 453 #endif // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_ 454