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