common-operator.cc 8.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// 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.

#include "src/compiler/common-operator.h"

#include "src/assembler.h"
#include "src/base/lazy-instance.h"
#include "src/compiler/linkage.h"
#include "src/unique.h"
#include "src/zone.h"

namespace v8 {
namespace internal {
namespace compiler {

namespace {

// TODO(turbofan): Use size_t instead of int here.
class ControlOperator : public Operator1<int> {
 public:
  ControlOperator(IrOpcode::Value opcode, Properties properties, int inputs,
                  int outputs, int controls, const char* mnemonic)
      : Operator1<int>(opcode, properties, inputs, outputs, mnemonic,
                       controls) {}

27
  virtual void PrintParameter(std::ostream& os) const FINAL {}
28 29 30 31 32
};

}  // namespace


33 34 35 36 37 38 39 40 41 42 43 44
size_t hash_value(OutputFrameStateCombine const& sc) {
  return base::hash_combine(sc.kind_, sc.parameter_);
}


std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
  switch (sc.kind_) {
    case OutputFrameStateCombine::kPushOutput:
      if (sc.parameter_ == 0) return os << "Ignore";
      return os << "Push(" << sc.parameter_ << ")";
    case OutputFrameStateCombine::kPokeAt:
      return os << "PokeAt(" << sc.parameter_ << ")";
45
  }
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  UNREACHABLE();
  return os;
}


bool operator==(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
  return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
         lhs.state_combine() == rhs.state_combine();
}


bool operator!=(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
  return !(lhs == rhs);
}


size_t hash_value(FrameStateCallInfo const& info) {
  return base::hash_combine(info.type(), info.bailout_id(),
                            info.state_combine());
}


std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
  return os << info.type() << ", " << info.bailout_id() << ", "
            << info.state_combine();
}
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150


#define SHARED_OP_LIST(V)               \
  V(Dead, Operator::kFoldable, 0, 0)    \
  V(End, Operator::kFoldable, 0, 1)     \
  V(Branch, Operator::kFoldable, 1, 1)  \
  V(IfTrue, Operator::kFoldable, 0, 1)  \
  V(IfFalse, Operator::kFoldable, 0, 1) \
  V(Throw, Operator::kFoldable, 1, 1)   \
  V(Return, Operator::kNoProperties, 1, 1)


struct CommonOperatorBuilderImpl FINAL {
#define SHARED(Name, properties, value_input_count, control_input_count)       \
  struct Name##Operator FINAL : public ControlOperator {                       \
    Name##Operator()                                                           \
        : ControlOperator(IrOpcode::k##Name, properties, value_input_count, 0, \
                          control_input_count, #Name) {}                       \
  };                                                                           \
  Name##Operator k##Name##Operator;
  SHARED_OP_LIST(SHARED)
#undef SHARED
};


static base::LazyInstance<CommonOperatorBuilderImpl>::type kImpl =
    LAZY_INSTANCE_INITIALIZER;


CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone)
    : impl_(kImpl.Get()), zone_(zone) {}


#define SHARED(Name, properties, value_input_count, control_input_count) \
  const Operator* CommonOperatorBuilder::Name() {                        \
    return &impl_.k##Name##Operator;                                     \
  }
SHARED_OP_LIST(SHARED)
#undef SHARED


const Operator* CommonOperatorBuilder::Start(int num_formal_parameters) {
  // Outputs are formal parameters, plus context, receiver, and JSFunction.
  const int value_output_count = num_formal_parameters + 3;
  return new (zone()) ControlOperator(IrOpcode::kStart, Operator::kFoldable, 0,
                                      value_output_count, 0, "Start");
}


const Operator* CommonOperatorBuilder::Merge(int controls) {
  return new (zone()) ControlOperator(IrOpcode::kMerge, Operator::kFoldable, 0,
                                      0, controls, "Merge");
}


const Operator* CommonOperatorBuilder::Loop(int controls) {
  return new (zone()) ControlOperator(IrOpcode::kLoop, Operator::kFoldable, 0,
                                      0, controls, "Loop");
}


const Operator* CommonOperatorBuilder::Parameter(int index) {
  return new (zone()) Operator1<int>(IrOpcode::kParameter, Operator::kPure, 1,
                                     1, "Parameter", index);
}


const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) {
  return new (zone()) Operator1<int32_t>(
      IrOpcode::kInt32Constant, Operator::kPure, 0, 1, "Int32Constant", value);
}


const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) {
  return new (zone()) Operator1<int64_t>(
      IrOpcode::kInt64Constant, Operator::kPure, 0, 1, "Int64Constant", value);
}


151 152
const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) {
  return new (zone())
153 154 155
      Operator1<float, base::bit_equal_to<float>, base::bit_hash<float>>(
          IrOpcode::kFloat32Constant, Operator::kPure, 0, 1, "Float32Constant",
          value);
156 157 158
}


159 160
const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) {
  return new (zone())
161 162 163
      Operator1<double, base::bit_equal_to<double>, base::bit_hash<double>>(
          IrOpcode::kFloat64Constant, Operator::kPure, 0, 1, "Float64Constant",
          value);
164 165 166 167 168 169 170 171 172 173 174 175 176
}


const Operator* CommonOperatorBuilder::ExternalConstant(
    const ExternalReference& value) {
  return new (zone())
      Operator1<ExternalReference>(IrOpcode::kExternalConstant, Operator::kPure,
                                   0, 1, "ExternalConstant", value);
}


const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) {
  return new (zone())
177 178 179
      Operator1<double, base::bit_equal_to<double>, base::bit_hash<double>>(
          IrOpcode::kNumberConstant, Operator::kPure, 0, 1, "NumberConstant",
          value);
180 181 182 183
}


const Operator* CommonOperatorBuilder::HeapConstant(
184 185
    const Unique<HeapObject>& value) {
  return new (zone()) Operator1<Unique<HeapObject>>(
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
      IrOpcode::kHeapConstant, Operator::kPure, 0, 1, "HeapConstant", value);
}


const Operator* CommonOperatorBuilder::Phi(MachineType type, int arguments) {
  DCHECK(arguments > 0);  // Disallow empty phis.
  return new (zone()) Operator1<MachineType>(IrOpcode::kPhi, Operator::kPure,
                                             arguments, 1, "Phi", type);
}


const Operator* CommonOperatorBuilder::EffectPhi(int arguments) {
  DCHECK(arguments > 0);  // Disallow empty phis.
  return new (zone()) Operator1<int>(IrOpcode::kEffectPhi, Operator::kPure, 0,
                                     0, "EffectPhi", arguments);
}


const Operator* CommonOperatorBuilder::ValueEffect(int arguments) {
  DCHECK(arguments > 0);  // Disallow empty value effects.
206 207
  return new (zone()) Operator1<int>(IrOpcode::kValueEffect, Operator::kPure,
                                     arguments, 0, "ValueEffect", arguments);
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
}


const Operator* CommonOperatorBuilder::Finish(int arguments) {
  DCHECK(arguments > 0);  // Disallow empty finishes.
  return new (zone()) Operator1<int>(IrOpcode::kFinish, Operator::kPure, 1, 1,
                                     "Finish", arguments);
}


const Operator* CommonOperatorBuilder::StateValues(int arguments) {
  return new (zone()) Operator1<int>(IrOpcode::kStateValues, Operator::kPure,
                                     arguments, 1, "StateValues", arguments);
}


const Operator* CommonOperatorBuilder::FrameState(
225 226
    FrameStateType type, BailoutId bailout_id,
    OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
227 228
  return new (zone()) Operator1<FrameStateCallInfo>(
      IrOpcode::kFrameState, Operator::kPure, 4, 1, "FrameState",
229
      FrameStateCallInfo(type, bailout_id, state_combine, jsfunction));
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
}


const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
  class CallOperator FINAL : public Operator1<const CallDescriptor*> {
   public:
    // TODO(titzer): Operator still uses int, whereas CallDescriptor uses
    // size_t.
    CallOperator(const CallDescriptor* descriptor, const char* mnemonic)
        : Operator1<const CallDescriptor*>(
              IrOpcode::kCall, descriptor->properties(),
              static_cast<int>(descriptor->InputCount() +
                               descriptor->FrameStateCount()),
              static_cast<int>(descriptor->ReturnCount()), mnemonic,
              descriptor) {}

246 247
    virtual void PrintParameter(std::ostream& os) const OVERRIDE {
      os << "[" << *parameter() << "]";
248 249 250 251 252 253 254 255 256 257 258 259 260 261
    }
  };
  return new (zone()) CallOperator(descriptor, "Call");
}


const Operator* CommonOperatorBuilder::Projection(size_t index) {
  return new (zone()) Operator1<size_t>(IrOpcode::kProjection, Operator::kPure,
                                        1, 1, "Projection", index);
}

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