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"
11 #include "src/macro-assembler.h"
17 // A helper class for the instruction selector that simplifies construction of
18 // Operands. This class implements a base for architecture-specific helpers.
19 class OperandGenerator {
21 explicit OperandGenerator(InstructionSelector* selector)
22 : selector_(selector) {}
24 InstructionOperand NoOutput() {
25 return InstructionOperand(); // Generates an invalid operand.
28 InstructionOperand DefineAsRegister(Node* node) {
30 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
34 InstructionOperand DefineSameAsFirst(Node* node) {
36 UnallocatedOperand(UnallocatedOperand::SAME_AS_FIRST_INPUT,
40 InstructionOperand DefineAsFixed(Node* node, Register reg) {
41 return Define(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
42 Register::ToAllocationIndex(reg),
46 InstructionOperand DefineAsFixed(Node* node, DoubleRegister reg) {
48 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
49 DoubleRegister::ToAllocationIndex(reg),
53 InstructionOperand DefineAsConstant(Node* node) {
54 selector()->MarkAsDefined(node);
55 int virtual_register = GetVReg(node);
56 sequence()->AddConstant(virtual_register, ToConstant(node));
57 return ConstantOperand(virtual_register);
60 InstructionOperand DefineAsLocation(Node* node, LinkageLocation location,
62 return Define(node, ToUnallocatedOperand(location, type, GetVReg(node)));
65 InstructionOperand Use(Node* node) {
66 return Use(node, UnallocatedOperand(UnallocatedOperand::NONE,
67 UnallocatedOperand::USED_AT_START,
71 InstructionOperand UseRegister(Node* node) {
72 return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
73 UnallocatedOperand::USED_AT_START,
77 // Use register or operand for the node. If a register is chosen, it won't
78 // alias any temporary or output registers.
79 InstructionOperand UseUnique(Node* node) {
81 UnallocatedOperand(UnallocatedOperand::NONE, GetVReg(node)));
84 // Use a unique register for the node that does not alias any temporary or
86 InstructionOperand UseUniqueRegister(Node* node) {
87 return Use(node, UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
91 InstructionOperand UseFixed(Node* node, Register reg) {
92 return Use(node, UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
93 Register::ToAllocationIndex(reg),
97 InstructionOperand UseFixed(Node* node, DoubleRegister reg) {
99 UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
100 DoubleRegister::ToAllocationIndex(reg),
104 InstructionOperand UseImmediate(Node* node) {
105 int index = sequence()->AddImmediate(ToConstant(node));
106 return ImmediateOperand(index);
109 InstructionOperand UseLocation(Node* node, LinkageLocation location,
111 return Use(node, ToUnallocatedOperand(location, type, GetVReg(node)));
114 InstructionOperand TempRegister() {
115 return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
116 UnallocatedOperand::USED_AT_START,
117 sequence()->NextVirtualRegister());
120 InstructionOperand TempDoubleRegister() {
121 UnallocatedOperand op = UnallocatedOperand(
122 UnallocatedOperand::MUST_HAVE_REGISTER,
123 UnallocatedOperand::USED_AT_START, sequence()->NextVirtualRegister());
124 sequence()->MarkAsDouble(op.virtual_register());
128 InstructionOperand TempRegister(Register reg) {
129 return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
130 Register::ToAllocationIndex(reg),
131 InstructionOperand::kInvalidVirtualRegister);
134 InstructionOperand TempImmediate(int32_t imm) {
135 int index = sequence()->AddImmediate(Constant(imm));
136 return ImmediateOperand(index);
139 InstructionOperand TempLocation(LinkageLocation location, MachineType type) {
140 return ToUnallocatedOperand(location, type,
141 sequence()->NextVirtualRegister());
144 InstructionOperand Label(BasicBlock* block) {
145 int index = sequence()->AddImmediate(Constant(block->GetRpoNumber()));
146 return ImmediateOperand(index);
150 InstructionSelector* selector() const { return selector_; }
151 InstructionSequence* sequence() const { return selector()->sequence(); }
152 Zone* zone() const { return selector()->instruction_zone(); }
155 int GetVReg(Node* node) const { return selector_->GetVirtualRegister(node); }
157 static Constant ToConstant(const Node* node) {
158 switch (node->opcode()) {
159 case IrOpcode::kInt32Constant:
160 return Constant(OpParameter<int32_t>(node));
161 case IrOpcode::kInt64Constant:
162 return Constant(OpParameter<int64_t>(node));
163 case IrOpcode::kFloat32Constant:
164 return Constant(OpParameter<float>(node));
165 case IrOpcode::kFloat64Constant:
166 case IrOpcode::kNumberConstant:
167 return Constant(OpParameter<double>(node));
168 case IrOpcode::kExternalConstant:
169 return Constant(OpParameter<ExternalReference>(node));
170 case IrOpcode::kHeapConstant:
171 return Constant(OpParameter<Unique<HeapObject> >(node).handle());
176 return Constant(static_cast<int32_t>(0));
179 UnallocatedOperand Define(Node* node, UnallocatedOperand operand) {
180 DCHECK_NOT_NULL(node);
181 DCHECK_EQ(operand.virtual_register(), GetVReg(node));
182 selector()->MarkAsDefined(node);
186 UnallocatedOperand Use(Node* node, UnallocatedOperand operand) {
187 DCHECK_NOT_NULL(node);
188 DCHECK_EQ(operand.virtual_register(), GetVReg(node));
189 selector()->MarkAsUsed(node);
193 UnallocatedOperand ToUnallocatedOperand(LinkageLocation location,
195 int virtual_register) {
196 if (location.location_ == LinkageLocation::ANY_REGISTER) {
197 // any machine register.
198 return UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER,
201 if (location.location_ < 0) {
202 // a location on the caller frame.
203 return UnallocatedOperand(UnallocatedOperand::FIXED_SLOT,
204 location.location_, virtual_register);
206 if (location.location_ > LinkageLocation::ANY_REGISTER) {
207 // a spill location on this (callee) frame.
208 return UnallocatedOperand(
209 UnallocatedOperand::FIXED_SLOT,
210 location.location_ - LinkageLocation::ANY_REGISTER - 1,
214 if (RepresentationOf(type) == kRepFloat64) {
215 return UnallocatedOperand(UnallocatedOperand::FIXED_DOUBLE_REGISTER,
216 location.location_, virtual_register);
218 return UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER,
219 location.location_, virtual_register);
222 InstructionSelector* selector_;
226 // The flags continuation is a way to combine a branch or a materialization
227 // of a boolean value with an instruction that sets the flags register.
228 // The whole instruction is treated as a unit by the register allocator, and
229 // thus no spills or moves can be introduced between the flags-setting
230 // instruction and the branch or set it should be combined with.
231 class FlagsContinuation FINAL {
233 FlagsContinuation() : mode_(kFlags_none) {}
235 // Creates a new flags continuation from the given condition and true/false
237 FlagsContinuation(FlagsCondition condition, BasicBlock* true_block,
238 BasicBlock* false_block)
239 : mode_(kFlags_branch),
240 condition_(condition),
241 true_block_(true_block),
242 false_block_(false_block) {
243 DCHECK_NOT_NULL(true_block);
244 DCHECK_NOT_NULL(false_block);
247 // Creates a new flags continuation from the given condition and result node.
248 FlagsContinuation(FlagsCondition condition, Node* result)
249 : mode_(kFlags_set), condition_(condition), result_(result) {
250 DCHECK_NOT_NULL(result);
253 bool IsNone() const { return mode_ == kFlags_none; }
254 bool IsBranch() const { return mode_ == kFlags_branch; }
255 bool IsSet() const { return mode_ == kFlags_set; }
256 FlagsCondition condition() const {
260 Node* result() const {
264 BasicBlock* true_block() const {
268 BasicBlock* false_block() const {
275 condition_ = NegateFlagsCondition(condition_);
280 switch (condition_) {
286 case kSignedLessThan:
287 condition_ = kSignedGreaterThan;
289 case kSignedGreaterThanOrEqual:
290 condition_ = kSignedLessThanOrEqual;
292 case kSignedLessThanOrEqual:
293 condition_ = kSignedGreaterThanOrEqual;
295 case kSignedGreaterThan:
296 condition_ = kSignedLessThan;
298 case kUnsignedLessThan:
299 condition_ = kUnsignedGreaterThan;
301 case kUnsignedGreaterThanOrEqual:
302 condition_ = kUnsignedLessThanOrEqual;
304 case kUnsignedLessThanOrEqual:
305 condition_ = kUnsignedGreaterThanOrEqual;
307 case kUnsignedGreaterThan:
308 condition_ = kUnsignedLessThan;
310 case kUnorderedEqual:
311 case kUnorderedNotEqual:
317 void OverwriteAndNegateIfEqual(FlagsCondition condition) {
318 bool negate = condition_ == kEqual;
319 condition_ = condition;
320 if (negate) Negate();
323 // Encodes this flags continuation into the given opcode.
324 InstructionCode Encode(InstructionCode opcode) {
325 opcode |= FlagsModeField::encode(mode_);
326 if (mode_ != kFlags_none) {
327 opcode |= FlagsConditionField::encode(condition_);
334 FlagsCondition condition_;
335 Node* result_; // Only valid if mode_ == kFlags_set.
336 BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch.
337 BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch.
341 // An internal helper class for generating the operands to calls.
342 // TODO(bmeurer): Get rid of the CallBuffer business and make
343 // InstructionSelector::VisitCall platform independent instead.
345 CallBuffer(Zone* zone, const CallDescriptor* descriptor,
346 FrameStateDescriptor* frame_state);
348 const CallDescriptor* descriptor;
349 FrameStateDescriptor* frame_state_descriptor;
350 NodeVector output_nodes;
351 InstructionOperandVector outputs;
352 InstructionOperandVector instruction_args;
353 NodeVector pushed_nodes;
355 size_t input_count() const { return descriptor->InputCount(); }
357 size_t frame_state_count() const { return descriptor->FrameStateCount(); }
359 size_t frame_state_value_count() const {
360 return (frame_state_descriptor == NULL)
362 : (frame_state_descriptor->GetTotalSize() +
363 1); // Include deopt id.
367 } // namespace compiler
368 } // namespace internal
371 #endif // V8_COMPILER_INSTRUCTION_SELECTOR_IMPL_H_