instruction-selector.h 10 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_INSTRUCTION_SELECTOR_H_
#define V8_COMPILER_INSTRUCTION_SELECTOR_H_

8
#include <map>
9 10 11 12

#include "src/compiler/common-operator.h"
#include "src/compiler/instruction.h"
#include "src/compiler/machine-operator.h"
13
#include "src/compiler/node.h"
14 15 16 17 18 19 20
#include "src/zone-containers.h"

namespace v8 {
namespace internal {
namespace compiler {

// Forward declarations.
21
class BasicBlock;
22 23
struct CallBuffer;  // TODO(bmeurer): Remove this.
class FlagsContinuation;
24
class Linkage;
25
class OperandGenerator;
26
struct SwitchInfo;
27

28 29 30
typedef ZoneVector<InstructionOperand> InstructionOperandVector;


31
// Instruction selection generates an InstructionSequence for a given Schedule.
32
class InstructionSelector final {
33
 public:
34 35 36
  // Forward declarations.
  class Features;

37 38 39 40 41 42 43 44
  enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions };

  InstructionSelector(
      Zone* zone, size_t node_count, Linkage* linkage,
      InstructionSequence* sequence, Schedule* schedule,
      SourcePositionTable* source_positions,
      SourcePositionMode source_position_mode = kCallSourcePositions,
      Features features = SupportedFeatures());
45 46 47 48 49 50 51 52

  // Visit code for the entire graph with the included schedule.
  void SelectInstructions();

  // ===========================================================================
  // ============= Architecture-independent code emission methods. =============
  // ===========================================================================

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    size_t temp_count = 0, InstructionOperand* temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    InstructionOperand a, size_t temp_count = 0,
                    InstructionOperand* temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    InstructionOperand a, InstructionOperand b,
                    size_t temp_count = 0, InstructionOperand* temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    InstructionOperand a, InstructionOperand b,
                    InstructionOperand c, size_t temp_count = 0,
                    InstructionOperand* temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    InstructionOperand a, InstructionOperand b,
                    InstructionOperand c, InstructionOperand d,
                    size_t temp_count = 0, InstructionOperand* temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    InstructionOperand a, InstructionOperand b,
                    InstructionOperand c, InstructionOperand d,
                    InstructionOperand e, size_t temp_count = 0,
                    InstructionOperand* temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand output,
                    InstructionOperand a, InstructionOperand b,
                    InstructionOperand c, InstructionOperand d,
                    InstructionOperand e, InstructionOperand f,
                    size_t temp_count = 0, InstructionOperand* temps = NULL);
79
  Instruction* Emit(InstructionCode opcode, size_t output_count,
80 81 82
                    InstructionOperand* outputs, size_t input_count,
                    InstructionOperand* inputs, size_t temp_count = 0,
                    InstructionOperand* temps = NULL);
83 84
  Instruction* Emit(Instruction* instr);

85 86 87 88
  // ===========================================================================
  // ============== Architecture-independent CPU feature methods. ==============
  // ===========================================================================

89
  class Features final {
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
   public:
    Features() : bits_(0) {}
    explicit Features(unsigned bits) : bits_(bits) {}
    explicit Features(CpuFeature f) : bits_(1u << f) {}
    Features(CpuFeature f1, CpuFeature f2) : bits_((1u << f1) | (1u << f2)) {}

    bool Contains(CpuFeature f) const { return (bits_ & (1u << f)); }

   private:
    unsigned bits_;
  };

  bool IsSupported(CpuFeature feature) const {
    return features_.Contains(feature);
  }

  // Returns the features supported on the target platform.
  static Features SupportedFeatures() {
    return Features(CpuFeatures::SupportedFeatures());
  }

111 112 113
  // TODO(sigurds) This should take a CpuFeatures argument.
  static MachineOperatorBuilder::Flags SupportedMachineOperatorFlags();

114 115 116 117 118 119 120 121 122 123
  // ===========================================================================
  // ============ Architecture-independent graph covering methods. =============
  // ===========================================================================

  // Used in pattern matching during code generation.
  // Check if {node} can be covered while generating code for the current
  // instruction. A node can be covered if the {user} of the node has the only
  // edge and the two are in the same basic block.
  bool CanCover(Node* user, Node* node) const;

124 125 126 127
  // Checks if {node} was already defined, and therefore code was already
  // generated for it.
  bool IsDefined(Node* node) const;

128 129 130 131
  // Checks if {node} has any uses, and therefore code has to be generated for
  // it.
  bool IsUsed(Node* node) const;

132 133 134
  // Checks if {node} is currently live.
  bool IsLive(Node* node) const { return !IsDefined(node) && IsUsed(node); }

135
  int GetVirtualRegister(const Node* node);
136
  const std::map<NodeId, int> GetVirtualRegistersForTesting() const;
137

138 139
  Isolate* isolate() const { return sequence()->isolate(); }

140 141 142
 private:
  friend class OperandGenerator;

143 144 145 146
  void EmitTableSwitch(const SwitchInfo& sw, InstructionOperand& index_operand);
  void EmitLookupSwitch(const SwitchInfo& sw,
                        InstructionOperand& value_operand);

147 148 149
  // Inform the instruction selection that {node} was just defined.
  void MarkAsDefined(Node* node);

150 151 152 153 154 155
  // Inform the instruction selection that {node} has at least one use and we
  // will need to generate code for it.
  void MarkAsUsed(Node* node);

  // Inform the register allocation of the representation of the value produced
  // by {node}.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
  void MarkAsRepresentation(MachineRepresentation rep, Node* node);
  void MarkAsWord32(Node* node) {
    MarkAsRepresentation(MachineRepresentation::kWord32, node);
  }
  void MarkAsWord64(Node* node) {
    MarkAsRepresentation(MachineRepresentation::kWord64, node);
  }
  void MarkAsFloat32(Node* node) {
    MarkAsRepresentation(MachineRepresentation::kFloat32, node);
  }
  void MarkAsFloat64(Node* node) {
    MarkAsRepresentation(MachineRepresentation::kFloat64, node);
  }
  void MarkAsReference(Node* node) {
    MarkAsRepresentation(MachineRepresentation::kTagged, node);
  }
172

173 174
  // Inform the register allocation of the representation of the unallocated
  // operand {op}.
175 176
  void MarkAsRepresentation(MachineRepresentation rep,
                            const InstructionOperand& op);
177

178 179 180 181 182 183 184
  enum CallBufferFlag {
    kCallCodeImmediate = 1u << 0,
    kCallAddressImmediate = 1u << 1,
    kCallTail = 1u << 2
  };
  typedef base::Flags<CallBufferFlag> CallBufferFlags;

185 186 187 188 189 190
  // Initialize the call buffer with the InstructionOperands, nodes, etc,
  // corresponding
  // to the inputs and outputs of the call.
  // {call_code_immediate} to generate immediate operands to calls of code.
  // {call_address_immediate} to generate immediate operands to address calls.
  void InitializeCallBuffer(Node* call, CallBuffer* buffer,
191
                            CallBufferFlags flags, int stack_param_delta = 0);
192
  bool IsTailCallAddressImmediate();
193

194
  FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
195

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  // ===========================================================================
  // ============= Architecture-specific graph covering methods. ===============
  // ===========================================================================

  // Visit nodes in the given block and generate code.
  void VisitBlock(BasicBlock* block);

  // Visit the node for the control flow at the end of the block, generating
  // code if necessary.
  void VisitControl(BasicBlock* block);

  // Visit the node and generate code, if any.
  void VisitNode(Node* node);

#define DECLARE_GENERATOR(x) void Visit##x(Node* node);
  MACHINE_OP_LIST(DECLARE_GENERATOR)
#undef DECLARE_GENERATOR

214
  void VisitFinishRegion(Node* node);
215
  void VisitGuard(Node* node);
216
  void VisitParameter(Node* node);
217
  void VisitIfException(Node* node);
218
  void VisitOsrValue(Node* node);
219 220
  void VisitPhi(Node* node);
  void VisitProjection(Node* node);
221
  void VisitConstant(Node* node);
222 223
  void VisitCall(Node* call, BasicBlock* handler = nullptr);
  void VisitTailCall(Node* call);
224 225
  void VisitGoto(BasicBlock* target);
  void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
226
  void VisitSwitch(Node* node, const SwitchInfo& sw);
227
  void VisitDeoptimize(DeoptimizeKind kind, Node* value);
228
  void VisitReturn(Node* ret);
229 230
  void VisitThrow(Node* value);

231 232 233
  void EmitPrepareArguments(NodeVector* arguments,
                            const CallDescriptor* descriptor, Node* node);

234 235
  // ===========================================================================

236
  Schedule* schedule() const { return schedule_; }
237
  Linkage* linkage() const { return linkage_; }
238 239
  InstructionSequence* sequence() const { return sequence_; }
  Zone* instruction_zone() const { return sequence()->zone(); }
240
  Zone* zone() const { return zone_; }
241 242 243

  // ===========================================================================

244
  Zone* const zone_;
245 246 247
  Linkage* const linkage_;
  InstructionSequence* const sequence_;
  SourcePositionTable* const source_positions_;
248
  SourcePositionMode const source_position_mode_;
249
  Features features_;
250
  Schedule* const schedule_;
251
  BasicBlock* current_block_;
252
  ZoneVector<Instruction*> instructions_;
253
  BoolVector defined_;
254
  BoolVector used_;
255
  IntVector virtual_registers_;
256 257 258 259 260 261 262
};

}  // namespace compiler
}  // namespace internal
}  // namespace v8

#endif  // V8_COMPILER_INSTRUCTION_SELECTOR_H_