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.
4
5#include "src/compiler/common-operator.h"
6
7#include "src/assembler.h"
8#include "src/base/lazy-instance.h"
9#include "src/compiler/linkage.h"
10#include "src/unique.h"
11#include "src/zone.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17namespace {
18
19// TODO(turbofan): Use size_t instead of int here.
20class ControlOperator : public Operator1<int> {
21 public:
22  ControlOperator(IrOpcode::Value opcode, Properties properties, int inputs,
23                  int outputs, int controls, const char* mnemonic)
24      : Operator1<int>(opcode, properties, inputs, outputs, mnemonic,
25                       controls) {}
26
27  virtual OStream& PrintParameter(OStream& os) const FINAL { return os; }
28};
29
30}  // namespace
31
32
33// Specialization for static parameters of type {ExternalReference}.
34template <>
35struct StaticParameterTraits<ExternalReference> {
36  static OStream& PrintTo(OStream& os, ExternalReference reference) {
37    os << reference.address();
38    // TODO(bmeurer): Move to operator<<(os, ExternalReference)
39    const Runtime::Function* function =
40        Runtime::FunctionForEntry(reference.address());
41    if (function) {
42      os << " <" << function->name << ".entry>";
43    }
44    return os;
45  }
46  static int HashCode(ExternalReference reference) {
47    return bit_cast<int>(static_cast<uint32_t>(
48        reinterpret_cast<uintptr_t>(reference.address())));
49  }
50  static bool Equals(ExternalReference lhs, ExternalReference rhs) {
51    return lhs == rhs;
52  }
53};
54
55
56#define SHARED_OP_LIST(V)               \
57  V(Dead, Operator::kFoldable, 0, 0)    \
58  V(End, Operator::kFoldable, 0, 1)     \
59  V(Branch, Operator::kFoldable, 1, 1)  \
60  V(IfTrue, Operator::kFoldable, 0, 1)  \
61  V(IfFalse, Operator::kFoldable, 0, 1) \
62  V(Throw, Operator::kFoldable, 1, 1)   \
63  V(Return, Operator::kNoProperties, 1, 1)
64
65
66struct CommonOperatorBuilderImpl FINAL {
67#define SHARED(Name, properties, value_input_count, control_input_count)       \
68  struct Name##Operator FINAL : public ControlOperator {                       \
69    Name##Operator()                                                           \
70        : ControlOperator(IrOpcode::k##Name, properties, value_input_count, 0, \
71                          control_input_count, #Name) {}                       \
72  };                                                                           \
73  Name##Operator k##Name##Operator;
74  SHARED_OP_LIST(SHARED)
75#undef SHARED
76
77  struct ControlEffectOperator FINAL : public SimpleOperator {
78    ControlEffectOperator()
79        : SimpleOperator(IrOpcode::kControlEffect, Operator::kPure, 0, 0,
80                         "ControlEffect") {}
81  };
82  ControlEffectOperator kControlEffectOperator;
83};
84
85
86static base::LazyInstance<CommonOperatorBuilderImpl>::type kImpl =
87    LAZY_INSTANCE_INITIALIZER;
88
89
90CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone)
91    : impl_(kImpl.Get()), zone_(zone) {}
92
93
94#define SHARED(Name, properties, value_input_count, control_input_count) \
95  const Operator* CommonOperatorBuilder::Name() {                        \
96    return &impl_.k##Name##Operator;                                     \
97  }
98SHARED_OP_LIST(SHARED)
99#undef SHARED
100
101
102const Operator* CommonOperatorBuilder::Start(int num_formal_parameters) {
103  // Outputs are formal parameters, plus context, receiver, and JSFunction.
104  const int value_output_count = num_formal_parameters + 3;
105  return new (zone()) ControlOperator(IrOpcode::kStart, Operator::kFoldable, 0,
106                                      value_output_count, 0, "Start");
107}
108
109
110const Operator* CommonOperatorBuilder::Merge(int controls) {
111  return new (zone()) ControlOperator(IrOpcode::kMerge, Operator::kFoldable, 0,
112                                      0, controls, "Merge");
113}
114
115
116const Operator* CommonOperatorBuilder::Loop(int controls) {
117  return new (zone()) ControlOperator(IrOpcode::kLoop, Operator::kFoldable, 0,
118                                      0, controls, "Loop");
119}
120
121
122const Operator* CommonOperatorBuilder::Parameter(int index) {
123  return new (zone()) Operator1<int>(IrOpcode::kParameter, Operator::kPure, 1,
124                                     1, "Parameter", index);
125}
126
127
128const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) {
129  return new (zone()) Operator1<int32_t>(
130      IrOpcode::kInt32Constant, Operator::kPure, 0, 1, "Int32Constant", value);
131}
132
133
134const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) {
135  return new (zone()) Operator1<int64_t>(
136      IrOpcode::kInt64Constant, Operator::kPure, 0, 1, "Int64Constant", value);
137}
138
139
140const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) {
141  return new (zone())
142      Operator1<float>(IrOpcode::kFloat32Constant, Operator::kPure, 0, 1,
143                       "Float32Constant", value);
144}
145
146
147const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) {
148  return new (zone())
149      Operator1<double>(IrOpcode::kFloat64Constant, Operator::kPure, 0, 1,
150                        "Float64Constant", value);
151}
152
153
154const Operator* CommonOperatorBuilder::ExternalConstant(
155    const ExternalReference& value) {
156  return new (zone())
157      Operator1<ExternalReference>(IrOpcode::kExternalConstant, Operator::kPure,
158                                   0, 1, "ExternalConstant", value);
159}
160
161
162const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) {
163  return new (zone())
164      Operator1<double>(IrOpcode::kNumberConstant, Operator::kPure, 0, 1,
165                        "NumberConstant", value);
166}
167
168
169const Operator* CommonOperatorBuilder::HeapConstant(
170    const Unique<Object>& value) {
171  return new (zone()) Operator1<Unique<Object> >(
172      IrOpcode::kHeapConstant, Operator::kPure, 0, 1, "HeapConstant", value);
173}
174
175
176const Operator* CommonOperatorBuilder::Phi(MachineType type, int arguments) {
177  DCHECK(arguments > 0);  // Disallow empty phis.
178  return new (zone()) Operator1<MachineType>(IrOpcode::kPhi, Operator::kPure,
179                                             arguments, 1, "Phi", type);
180}
181
182
183const Operator* CommonOperatorBuilder::EffectPhi(int arguments) {
184  DCHECK(arguments > 0);  // Disallow empty phis.
185  return new (zone()) Operator1<int>(IrOpcode::kEffectPhi, Operator::kPure, 0,
186                                     0, "EffectPhi", arguments);
187}
188
189
190const Operator* CommonOperatorBuilder::ControlEffect() {
191  return &impl_.kControlEffectOperator;
192}
193
194
195const Operator* CommonOperatorBuilder::ValueEffect(int arguments) {
196  DCHECK(arguments > 0);  // Disallow empty value effects.
197  return new (zone()) SimpleOperator(IrOpcode::kValueEffect, Operator::kPure,
198                                     arguments, 0, "ValueEffect");
199}
200
201
202const Operator* CommonOperatorBuilder::Finish(int arguments) {
203  DCHECK(arguments > 0);  // Disallow empty finishes.
204  return new (zone()) Operator1<int>(IrOpcode::kFinish, Operator::kPure, 1, 1,
205                                     "Finish", arguments);
206}
207
208
209const Operator* CommonOperatorBuilder::StateValues(int arguments) {
210  return new (zone()) Operator1<int>(IrOpcode::kStateValues, Operator::kPure,
211                                     arguments, 1, "StateValues", arguments);
212}
213
214
215const Operator* CommonOperatorBuilder::FrameState(
216    FrameStateType type, BailoutId bailout_id,
217    OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
218  return new (zone()) Operator1<FrameStateCallInfo>(
219      IrOpcode::kFrameState, Operator::kPure, 4, 1, "FrameState",
220      FrameStateCallInfo(type, bailout_id, state_combine, jsfunction));
221}
222
223
224const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
225  class CallOperator FINAL : public Operator1<const CallDescriptor*> {
226   public:
227    // TODO(titzer): Operator still uses int, whereas CallDescriptor uses
228    // size_t.
229    CallOperator(const CallDescriptor* descriptor, const char* mnemonic)
230        : Operator1<const CallDescriptor*>(
231              IrOpcode::kCall, descriptor->properties(),
232              static_cast<int>(descriptor->InputCount() +
233                               descriptor->FrameStateCount()),
234              static_cast<int>(descriptor->ReturnCount()), mnemonic,
235              descriptor) {}
236
237    virtual OStream& PrintParameter(OStream& os) const OVERRIDE {
238      return os << "[" << *parameter() << "]";
239    }
240  };
241  return new (zone()) CallOperator(descriptor, "Call");
242}
243
244
245const Operator* CommonOperatorBuilder::Projection(size_t index) {
246  return new (zone()) Operator1<size_t>(IrOpcode::kProjection, Operator::kPure,
247                                        1, 1, "Projection", index);
248}
249
250}  // namespace compiler
251}  // namespace internal
252}  // namespace v8
253