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 12namespace v8 { 13namespace internal { 14namespace compiler { 15 16// A helper class for the instruction selector that simplifies construction of 17// Operands. This class implements a base for architecture-specific helpers. 18class OperandGenerator { 19 public: 20 explicit OperandGenerator(InstructionSelector* selector) 21 : selector_(selector) {} 22 23 InstructionOperand* DefineAsRegister(Node* node) { 24 return Define(node, new (zone()) 25 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)); 26 } 27 28 InstructionOperand* DefineSameAsFirst(Node* result) { 29 return Define(result, new (zone()) 30 UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT)); 31 } 32 33 InstructionOperand* DefineAsFixed(Node* node, Register reg) { 34 return Define(node, new (zone()) 35 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 36 Register::ToAllocationIndex(reg))); 37 } 38 39 InstructionOperand* DefineAsFixed(Node* node, DoubleRegister reg) { 40 return Define(node, new (zone()) 41 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER, 42 DoubleRegister::ToAllocationIndex(reg))); 43 } 44 45 InstructionOperand* DefineAsConstant(Node* node) { 46 selector()->MarkAsDefined(node); 47 sequence()->AddConstant(node->id(), ToConstant(node)); 48 return ConstantOperand::Create(node->id(), zone()); 49 } 50 51 InstructionOperand* DefineAsLocation(Node* node, LinkageLocation location, 52 MachineType type) { 53 return Define(node, ToUnallocatedOperand(location, type)); 54 } 55 56 InstructionOperand* Use(Node* node) { 57 return Use(node, 58 new (zone()) UnallocatedOperand( 59 UnallocatedOperand::ANY, UnallocatedOperand::USED_AT_START)); 60 } 61 62 InstructionOperand* UseRegister(Node* node) { 63 return Use(node, new (zone()) 64 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 65 UnallocatedOperand::USED_AT_START)); 66 } 67 68 // Use register or operand for the node. If a register is chosen, it won't 69 // alias any temporary or output registers. 70 InstructionOperand* UseUnique(Node* node) { 71 return Use(node, new (zone()) UnallocatedOperand(UnallocatedOperand::ANY)); 72 } 73 74 // Use a unique register for the node that does not alias any temporary or 75 // output registers. 76 InstructionOperand* UseUniqueRegister(Node* node) { 77 return Use(node, new (zone()) 78 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)); 79 } 80 81 InstructionOperand* UseFixed(Node* node, Register reg) { 82 return Use(node, new (zone()) 83 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 84 Register::ToAllocationIndex(reg))); 85 } 86 87 InstructionOperand* UseFixed(Node* node, DoubleRegister reg) { 88 return Use(node, new (zone()) 89 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER, 90 DoubleRegister::ToAllocationIndex(reg))); 91 } 92 93 InstructionOperand* UseImmediate(Node* node) { 94 int index = sequence()->AddImmediate(ToConstant(node)); 95 return ImmediateOperand::Create(index, zone()); 96 } 97 98 InstructionOperand* UseLocation(Node* node, LinkageLocation location, 99 MachineType type) { 100 return Use(node, ToUnallocatedOperand(location, type)); 101 } 102 103 InstructionOperand* TempRegister() { 104 UnallocatedOperand* op = 105 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 106 UnallocatedOperand::USED_AT_START); 107 op->set_virtual_register(sequence()->NextVirtualRegister()); 108 return op; 109 } 110 111 InstructionOperand* TempDoubleRegister() { 112 UnallocatedOperand* op = 113 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, 114 UnallocatedOperand::USED_AT_START); 115 op->set_virtual_register(sequence()->NextVirtualRegister()); 116 sequence()->MarkAsDouble(op->virtual_register()); 117 return op; 118 } 119 120 InstructionOperand* TempRegister(Register reg) { 121 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 122 Register::ToAllocationIndex(reg)); 123 } 124 125 InstructionOperand* TempImmediate(int32_t imm) { 126 int index = sequence()->AddImmediate(Constant(imm)); 127 return ImmediateOperand::Create(index, zone()); 128 } 129 130 InstructionOperand* Label(BasicBlock* block) { 131 // TODO(bmeurer): We misuse ImmediateOperand here. 132 return TempImmediate(block->id()); 133 } 134 135 protected: 136 Graph* graph() const { return selector()->graph(); } 137 InstructionSelector* selector() const { return selector_; } 138 InstructionSequence* sequence() const { return selector()->sequence(); } 139 Isolate* isolate() const { return zone()->isolate(); } 140 Zone* zone() const { return selector()->instruction_zone(); } 141 142 private: 143 static Constant ToConstant(const Node* node) { 144 switch (node->opcode()) { 145 case IrOpcode::kInt32Constant: 146 return Constant(OpParameter<int32_t>(node)); 147 case IrOpcode::kInt64Constant: 148 return Constant(OpParameter<int64_t>(node)); 149 case IrOpcode::kNumberConstant: 150 case IrOpcode::kFloat64Constant: 151 return Constant(OpParameter<double>(node)); 152 case IrOpcode::kExternalConstant: 153 return Constant(OpParameter<ExternalReference>(node)); 154 case IrOpcode::kHeapConstant: 155 return Constant(OpParameter<Unique<HeapObject> >(node).handle()); 156 default: 157 break; 158 } 159 UNREACHABLE(); 160 return Constant(static_cast<int32_t>(0)); 161 } 162 163 UnallocatedOperand* Define(Node* node, UnallocatedOperand* operand) { 164 DCHECK_NOT_NULL(node); 165 DCHECK_NOT_NULL(operand); 166 operand->set_virtual_register(node->id()); 167 selector()->MarkAsDefined(node); 168 return operand; 169 } 170 171 UnallocatedOperand* Use(Node* node, UnallocatedOperand* operand) { 172 DCHECK_NOT_NULL(node); 173 DCHECK_NOT_NULL(operand); 174 operand->set_virtual_register(node->id()); 175 selector()->MarkAsUsed(node); 176 return operand; 177 } 178 179 UnallocatedOperand* ToUnallocatedOperand(LinkageLocation location, 180 MachineType type) { 181 if (location.location_ == LinkageLocation::ANY_REGISTER) { 182 return new (zone()) 183 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER); 184 } 185 if (location.location_ < 0) { 186 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_SLOT, 187 location.location_); 188 } 189 if (RepresentationOf(type) == kRepFloat64) { 190 return new (zone()) UnallocatedOperand( 191 UnallocatedOperand::FIXED_DOUBLE_REGISTER, location.location_); 192 } 193 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, 194 location.location_); 195 } 196 197 InstructionSelector* selector_; 198}; 199 200 201// The flags continuation is a way to combine a branch or a materialization 202// of a boolean value with an instruction that sets the flags register. 203// The whole instruction is treated as a unit by the register allocator, and 204// thus no spills or moves can be introduced between the flags-setting 205// instruction and the branch or set it should be combined with. 206class FlagsContinuation FINAL { 207 public: 208 FlagsContinuation() : mode_(kFlags_none) {} 209 210 // Creates a new flags continuation from the given condition and true/false 211 // blocks. 212 FlagsContinuation(FlagsCondition condition, BasicBlock* true_block, 213 BasicBlock* false_block) 214 : mode_(kFlags_branch), 215 condition_(condition), 216 true_block_(true_block), 217 false_block_(false_block) { 218 DCHECK_NOT_NULL(true_block); 219 DCHECK_NOT_NULL(false_block); 220 } 221 222 // Creates a new flags continuation from the given condition and result node. 223 FlagsContinuation(FlagsCondition condition, Node* result) 224 : mode_(kFlags_set), condition_(condition), result_(result) { 225 DCHECK_NOT_NULL(result); 226 } 227 228 bool IsNone() const { return mode_ == kFlags_none; } 229 bool IsBranch() const { return mode_ == kFlags_branch; } 230 bool IsSet() const { return mode_ == kFlags_set; } 231 FlagsCondition condition() const { 232 DCHECK(!IsNone()); 233 return condition_; 234 } 235 Node* result() const { 236 DCHECK(IsSet()); 237 return result_; 238 } 239 BasicBlock* true_block() const { 240 DCHECK(IsBranch()); 241 return true_block_; 242 } 243 BasicBlock* false_block() const { 244 DCHECK(IsBranch()); 245 return false_block_; 246 } 247 248 void Negate() { 249 DCHECK(!IsNone()); 250 condition_ = static_cast<FlagsCondition>(condition_ ^ 1); 251 } 252 253 void Commute() { 254 DCHECK(!IsNone()); 255 switch (condition_) { 256 case kEqual: 257 case kNotEqual: 258 case kOverflow: 259 case kNotOverflow: 260 return; 261 case kSignedLessThan: 262 condition_ = kSignedGreaterThan; 263 return; 264 case kSignedGreaterThanOrEqual: 265 condition_ = kSignedLessThanOrEqual; 266 return; 267 case kSignedLessThanOrEqual: 268 condition_ = kSignedGreaterThanOrEqual; 269 return; 270 case kSignedGreaterThan: 271 condition_ = kSignedLessThan; 272 return; 273 case kUnsignedLessThan: 274 condition_ = kUnsignedGreaterThan; 275 return; 276 case kUnsignedGreaterThanOrEqual: 277 condition_ = kUnsignedLessThanOrEqual; 278 return; 279 case kUnsignedLessThanOrEqual: 280 condition_ = kUnsignedGreaterThanOrEqual; 281 return; 282 case kUnsignedGreaterThan: 283 condition_ = kUnsignedLessThan; 284 return; 285 case kUnorderedEqual: 286 case kUnorderedNotEqual: 287 return; 288 case kUnorderedLessThan: 289 condition_ = kUnorderedGreaterThan; 290 return; 291 case kUnorderedGreaterThanOrEqual: 292 condition_ = kUnorderedLessThanOrEqual; 293 return; 294 case kUnorderedLessThanOrEqual: 295 condition_ = kUnorderedGreaterThanOrEqual; 296 return; 297 case kUnorderedGreaterThan: 298 condition_ = kUnorderedLessThan; 299 return; 300 } 301 UNREACHABLE(); 302 } 303 304 void OverwriteAndNegateIfEqual(FlagsCondition condition) { 305 bool negate = condition_ == kEqual; 306 condition_ = condition; 307 if (negate) Negate(); 308 } 309 310 void SwapBlocks() { std::swap(true_block_, false_block_); } 311 312 // Encodes this flags continuation into the given opcode. 313 InstructionCode Encode(InstructionCode opcode) { 314 opcode |= FlagsModeField::encode(mode_); 315 if (mode_ != kFlags_none) { 316 opcode |= FlagsConditionField::encode(condition_); 317 } 318 return opcode; 319 } 320 321 private: 322 FlagsMode mode_; 323 FlagsCondition condition_; 324 Node* result_; // Only valid if mode_ == kFlags_set. 325 BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch. 326 BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch. 327}; 328 329 330// An internal helper class for generating the operands to calls. 331// TODO(bmeurer): Get rid of the CallBuffer business and make 332// InstructionSelector::VisitCall platform independent instead. 333struct CallBuffer { 334 CallBuffer(Zone* zone, CallDescriptor* descriptor, 335 FrameStateDescriptor* frame_state); 336 337 CallDescriptor* descriptor; 338 FrameStateDescriptor* frame_state_descriptor; 339 NodeVector output_nodes; 340 InstructionOperandVector outputs; 341 InstructionOperandVector instruction_args; 342 NodeVector pushed_nodes; 343 344 size_t input_count() const { return descriptor->InputCount(); } 345 346 size_t frame_state_count() const { return descriptor->FrameStateCount(); } 347 348 size_t frame_state_value_count() const { 349 return (frame_state_descriptor == NULL) 350 ? 0 351 : (frame_state_descriptor->GetTotalSize() + 352 1); // Include deopt id. 353 } 354}; 355 356} // namespace compiler 357} // namespace internal 358} // namespace v8 359 360#endif // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_ 361