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.
5 #ifndef V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
6 #define V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_
8 #include "src/compiler/generic-node-inl.h"
9 #include "src/compiler/instruction.h"
10 #include "src/compiler/instruction-selector.h"
11 #include "src/compiler/linkage.h"
12 #include "src/macro-assembler.h"
18 // A helper class for the instruction selector that simplifies construction of
19 // Operands. This class implements a base for architecture-specific helpers.
20 class OperandGenerator {
22 explicit OperandGenerator(InstructionSelector* selector)
23 : selector_(selector) {}
25 InstructionOperand* DefineAsRegister(Node* node) {
26 return Define(node, new (zone())
27 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
30 InstructionOperand* DefineSameAsFirst(Node* result) {
31 return Define(result, new (zone())
32 UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT));
35 InstructionOperand* DefineAsFixed(Node* node, Register reg) {
36 return Define(node, new (zone())
37 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
38 Register::ToAllocationIndex(reg)));
41 InstructionOperand* DefineAsFixed(Node* node, DoubleRegister reg) {
42 return Define(node, new (zone())
43 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
44 DoubleRegister::ToAllocationIndex(reg)));
47 InstructionOperand* DefineAsConstant(Node* node) {
48 selector()->MarkAsDefined(node);
49 int virtual_register = selector_->GetVirtualRegister(node);
50 sequence()->AddConstant(virtual_register, ToConstant(node));
51 return ConstantOperand::Create(virtual_register, zone());
54 InstructionOperand* DefineAsLocation(Node* node, LinkageLocation location,
56 return Define(node, ToUnallocatedOperand(location, type));
59 InstructionOperand* Use(Node* node) {
61 node, new (zone()) UnallocatedOperand(
62 UnallocatedOperand::NONE, UnallocatedOperand::USED_AT_START));
65 InstructionOperand* UseRegister(Node* node) {
66 return Use(node, new (zone())
67 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
68 UnallocatedOperand::USED_AT_START));
71 // Use register or operand for the node. If a register is chosen, it won't
72 // alias any temporary or output registers.
73 InstructionOperand* UseUnique(Node* node) {
74 return Use(node, new (zone()) UnallocatedOperand(UnallocatedOperand::NONE));
77 // Use a unique register for the node that does not alias any temporary or
79 InstructionOperand* UseUniqueRegister(Node* node) {
80 return Use(node, new (zone())
81 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
84 InstructionOperand* UseFixed(Node* node, Register reg) {
85 return Use(node, new (zone())
86 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
87 Register::ToAllocationIndex(reg)));
90 InstructionOperand* UseFixed(Node* node, DoubleRegister reg) {
91 return Use(node, new (zone())
92 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
93 DoubleRegister::ToAllocationIndex(reg)));
96 InstructionOperand* UseImmediate(Node* node) {
97 int index = sequence()->AddImmediate(ToConstant(node));
98 return ImmediateOperand::Create(index, zone());
101 InstructionOperand* UseLocation(Node* node, LinkageLocation location,
103 return Use(node, ToUnallocatedOperand(location, type));
106 InstructionOperand* TempRegister() {
107 UnallocatedOperand* op =
108 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
109 UnallocatedOperand::USED_AT_START);
110 op->set_virtual_register(sequence()->NextVirtualRegister());
114 InstructionOperand* TempDoubleRegister() {
115 UnallocatedOperand* op =
116 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
117 UnallocatedOperand::USED_AT_START);
118 op->set_virtual_register(sequence()->NextVirtualRegister());
119 sequence()->MarkAsDouble(op->virtual_register());
123 InstructionOperand* TempRegister(Register reg) {
124 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
125 Register::ToAllocationIndex(reg));
128 InstructionOperand* TempImmediate(int32_t imm) {
129 int index = sequence()->AddImmediate(Constant(imm));
130 return ImmediateOperand::Create(index, zone());
133 InstructionOperand* TempLocation(LinkageLocation location, MachineType type) {
134 UnallocatedOperand* op = ToUnallocatedOperand(location, type);
135 op->set_virtual_register(sequence()->NextVirtualRegister());
139 InstructionOperand* Label(BasicBlock* block) {
140 // TODO(bmeurer): We misuse ImmediateOperand here.
141 return TempImmediate(block->rpo_number());
145 InstructionSelector* selector() const { return selector_; }
146 InstructionSequence* sequence() const { return selector()->sequence(); }
147 Isolate* isolate() const { return zone()->isolate(); }
148 Zone* zone() const { return selector()->instruction_zone(); }
151 static Constant ToConstant(const Node* node) {
152 switch (node->opcode()) {
153 case IrOpcode::kInt32Constant:
154 return Constant(OpParameter<int32_t>(node));
155 case IrOpcode::kInt64Constant:
156 return Constant(OpParameter<int64_t>(node));
157 case IrOpcode::kFloat32Constant:
158 return Constant(OpParameter<float>(node));
159 case IrOpcode::kFloat64Constant:
160 case IrOpcode::kNumberConstant:
161 return Constant(OpParameter<double>(node));
162 case IrOpcode::kExternalConstant:
163 return Constant(OpParameter<ExternalReference>(node));
164 case IrOpcode::kHeapConstant:
165 return Constant(OpParameter<Unique<HeapObject> >(node).handle());
170 return Constant(static_cast<int32_t>(0));
173 UnallocatedOperand* Define(Node* node, UnallocatedOperand* operand) {
174 DCHECK_NOT_NULL(node);
175 DCHECK_NOT_NULL(operand);
176 operand->set_virtual_register(selector_->GetVirtualRegister(node));
177 selector()->MarkAsDefined(node);
181 UnallocatedOperand* Use(Node* node, UnallocatedOperand* operand) {
182 DCHECK_NOT_NULL(node);
183 DCHECK_NOT_NULL(operand);
184 operand->set_virtual_register(selector_->GetVirtualRegister(node));
185 selector()->MarkAsUsed(node);
189 UnallocatedOperand* ToUnallocatedOperand(LinkageLocation location,
191 if (location.location_ == LinkageLocation::ANY_REGISTER) {
193 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER);
195 if (location.location_ < 0) {
196 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
199 if (RepresentationOf(type) == kRepFloat64) {
200 return new (zone()) UnallocatedOperand(
201 UnallocatedOperand::FIXED_DOUBLE_REGISTER, location.location_);
203 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
207 InstructionSelector* selector_;
211 // The flags continuation is a way to combine a branch or a materialization
212 // of a boolean value with an instruction that sets the flags register.
213 // The whole instruction is treated as a unit by the register allocator, and
214 // thus no spills or moves can be introduced between the flags-setting
215 // instruction and the branch or set it should be combined with.
216 class FlagsContinuation FINAL {
218 FlagsContinuation() : mode_(kFlags_none) {}
220 // Creates a new flags continuation from the given condition and true/false
222 FlagsContinuation(FlagsCondition condition, BasicBlock* true_block,
223 BasicBlock* false_block)
224 : mode_(kFlags_branch),
225 condition_(condition),
226 true_block_(true_block),
227 false_block_(false_block) {
228 DCHECK_NOT_NULL(true_block);
229 DCHECK_NOT_NULL(false_block);
232 // Creates a new flags continuation from the given condition and result node.
233 FlagsContinuation(FlagsCondition condition, Node* result)
234 : mode_(kFlags_set), condition_(condition), result_(result) {
235 DCHECK_NOT_NULL(result);
238 bool IsNone() const { return mode_ == kFlags_none; }
239 bool IsBranch() const { return mode_ == kFlags_branch; }
240 bool IsSet() const { return mode_ == kFlags_set; }
241 FlagsCondition condition() const {
245 Node* result() const {
249 BasicBlock* true_block() const {
253 BasicBlock* false_block() const {
260 condition_ = static_cast<FlagsCondition>(condition_ ^ 1);
265 switch (condition_) {
271 case kSignedLessThan:
272 condition_ = kSignedGreaterThan;
274 case kSignedGreaterThanOrEqual:
275 condition_ = kSignedLessThanOrEqual;
277 case kSignedLessThanOrEqual:
278 condition_ = kSignedGreaterThanOrEqual;
280 case kSignedGreaterThan:
281 condition_ = kSignedLessThan;
283 case kUnsignedLessThan:
284 condition_ = kUnsignedGreaterThan;
286 case kUnsignedGreaterThanOrEqual:
287 condition_ = kUnsignedLessThanOrEqual;
289 case kUnsignedLessThanOrEqual:
290 condition_ = kUnsignedGreaterThanOrEqual;
292 case kUnsignedGreaterThan:
293 condition_ = kUnsignedLessThan;
295 case kUnorderedEqual:
296 case kUnorderedNotEqual:
298 case kUnorderedLessThan:
299 condition_ = kUnorderedGreaterThan;
301 case kUnorderedGreaterThanOrEqual:
302 condition_ = kUnorderedLessThanOrEqual;
304 case kUnorderedLessThanOrEqual:
305 condition_ = kUnorderedGreaterThanOrEqual;
307 case kUnorderedGreaterThan:
308 condition_ = kUnorderedLessThan;
314 void OverwriteAndNegateIfEqual(FlagsCondition condition) {
315 bool negate = condition_ == kEqual;
316 condition_ = condition;
317 if (negate) Negate();
320 void SwapBlocks() { std::swap(true_block_, false_block_); }
322 // Encodes this flags continuation into the given opcode.
323 InstructionCode Encode(InstructionCode opcode) {
324 opcode |= FlagsModeField::encode(mode_);
325 if (mode_ != kFlags_none) {
326 opcode |= FlagsConditionField::encode(condition_);
333 FlagsCondition condition_;
334 Node* result_; // Only valid if mode_ == kFlags_set.
335 BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch.
336 BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch.
340 // An internal helper class for generating the operands to calls.
341 // TODO(bmeurer): Get rid of the CallBuffer business and make
342 // InstructionSelector::VisitCall platform independent instead.
344 CallBuffer(Zone* zone, CallDescriptor* descriptor,
345 FrameStateDescriptor* frame_state);
347 CallDescriptor* descriptor;
348 FrameStateDescriptor* frame_state_descriptor;
349 NodeVector output_nodes;
350 InstructionOperandVector outputs;
351 InstructionOperandVector instruction_args;
352 NodeVector pushed_nodes;
354 size_t input_count() const { return descriptor->InputCount(); }
356 size_t frame_state_count() const { return descriptor->FrameStateCount(); }
358 size_t frame_state_value_count() const {
359 return (frame_state_descriptor == NULL)
361 : (frame_state_descriptor->GetTotalSize() +
362 1); // Include deopt id.
366 } // namespace compiler
367 } // namespace internal
370 #endif // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_