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/instruction.h"
9 #include "src/compiler/instruction-selector.h"
10 #include "src/compiler/linkage.h"
16 // A helper class for the instruction selector that simplifies construction of
17 // Operands. This class implements a base for architecture-specific helpers.
18 class OperandGenerator {
20 explicit OperandGenerator(InstructionSelector* selector)
21 : selector_(selector) {}
23 InstructionOperand* DefineAsRegister(Node* node) {
24 return Define(node, new (zone())
25 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
28 InstructionOperand* DefineSameAsFirst(Node* result) {
29 return Define(result, new (zone())
30 UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT));
33 InstructionOperand* DefineAsFixed(Node* node, Register reg) {
34 return Define(node, new (zone())
35 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
36 Register::ToAllocationIndex(reg)));
39 InstructionOperand* DefineAsFixed(Node* node, DoubleRegister reg) {
40 return Define(node, new (zone())
41 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
42 DoubleRegister::ToAllocationIndex(reg)));
45 InstructionOperand* DefineAsConstant(Node* node) {
46 selector()->MarkAsDefined(node);
47 sequence()->AddConstant(node->id(), ToConstant(node));
48 return ConstantOperand::Create(node->id(), zone());
51 InstructionOperand* DefineAsLocation(Node* node, LinkageLocation location,
53 return Define(node, ToUnallocatedOperand(location, type));
56 InstructionOperand* Use(Node* node) {
58 new (zone()) UnallocatedOperand(
59 UnallocatedOperand::ANY, UnallocatedOperand::USED_AT_START));
62 InstructionOperand* UseRegister(Node* node) {
63 return Use(node, new (zone())
64 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
65 UnallocatedOperand::USED_AT_START));
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));
74 // Use a unique register for the node that does not alias any temporary or
76 InstructionOperand* UseUniqueRegister(Node* node) {
77 return Use(node, new (zone())
78 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER));
81 InstructionOperand* UseFixed(Node* node, Register reg) {
82 return Use(node, new (zone())
83 UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
84 Register::ToAllocationIndex(reg)));
87 InstructionOperand* UseFixed(Node* node, DoubleRegister reg) {
88 return Use(node, new (zone())
89 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
90 DoubleRegister::ToAllocationIndex(reg)));
93 InstructionOperand* UseImmediate(Node* node) {
94 int index = sequence()->AddImmediate(ToConstant(node));
95 return ImmediateOperand::Create(index, zone());
98 InstructionOperand* UseLocation(Node* node, LinkageLocation location,
100 return Use(node, ToUnallocatedOperand(location, type));
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());
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());
120 InstructionOperand* TempRegister(Register reg) {
121 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
122 Register::ToAllocationIndex(reg));
125 InstructionOperand* TempImmediate(int32_t imm) {
126 int index = sequence()->AddImmediate(Constant(imm));
127 return ImmediateOperand::Create(index, zone());
130 InstructionOperand* Label(BasicBlock* block) {
131 // TODO(bmeurer): We misuse ImmediateOperand here.
132 return TempImmediate(block->id());
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(); }
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());
160 return Constant(static_cast<int32_t>(0));
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);
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);
179 UnallocatedOperand* ToUnallocatedOperand(LinkageLocation location,
181 if (location.location_ == LinkageLocation::ANY_REGISTER) {
183 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER);
185 if (location.location_ < 0) {
186 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
189 if (RepresentationOf(type) == kRepFloat64) {
190 return new (zone()) UnallocatedOperand(
191 UnallocatedOperand::FIXED_DOUBLE_REGISTER, location.location_);
193 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
197 InstructionSelector* selector_;
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.
206 class FlagsContinuation FINAL {
208 FlagsContinuation() : mode_(kFlags_none) {}
210 // Creates a new flags continuation from the given condition and true/false
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);
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);
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 {
235 Node* result() const {
239 BasicBlock* true_block() const {
243 BasicBlock* false_block() const {
250 condition_ = static_cast<FlagsCondition>(condition_ ^ 1);
255 switch (condition_) {
261 case kSignedLessThan:
262 condition_ = kSignedGreaterThan;
264 case kSignedGreaterThanOrEqual:
265 condition_ = kSignedLessThanOrEqual;
267 case kSignedLessThanOrEqual:
268 condition_ = kSignedGreaterThanOrEqual;
270 case kSignedGreaterThan:
271 condition_ = kSignedLessThan;
273 case kUnsignedLessThan:
274 condition_ = kUnsignedGreaterThan;
276 case kUnsignedGreaterThanOrEqual:
277 condition_ = kUnsignedLessThanOrEqual;
279 case kUnsignedLessThanOrEqual:
280 condition_ = kUnsignedGreaterThanOrEqual;
282 case kUnsignedGreaterThan:
283 condition_ = kUnsignedLessThan;
285 case kUnorderedEqual:
286 case kUnorderedNotEqual:
288 case kUnorderedLessThan:
289 condition_ = kUnorderedGreaterThan;
291 case kUnorderedGreaterThanOrEqual:
292 condition_ = kUnorderedLessThanOrEqual;
294 case kUnorderedLessThanOrEqual:
295 condition_ = kUnorderedGreaterThanOrEqual;
297 case kUnorderedGreaterThan:
298 condition_ = kUnorderedLessThan;
304 void OverwriteAndNegateIfEqual(FlagsCondition condition) {
305 bool negate = condition_ == kEqual;
306 condition_ = condition;
307 if (negate) Negate();
310 void SwapBlocks() { std::swap(true_block_, false_block_); }
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_);
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.
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.
334 CallBuffer(Zone* zone, CallDescriptor* descriptor,
335 FrameStateDescriptor* frame_state);
337 CallDescriptor* descriptor;
338 FrameStateDescriptor* frame_state_descriptor;
339 NodeVector output_nodes;
340 InstructionOperandVector outputs;
341 InstructionOperandVector instruction_args;
342 NodeVector pushed_nodes;
344 size_t input_count() const { return descriptor->InputCount(); }
346 size_t frame_state_count() const { return descriptor->FrameStateCount(); }
348 size_t frame_state_value_count() const {
349 return (frame_state_descriptor == NULL)
351 : (frame_state_descriptor->GetTotalSize() +
352 1); // Include deopt id.
356 } // namespace compiler
357 } // namespace internal
360 #endif // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_