1// Copyright 2012 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/simplified-operator.h"
6
7#include "src/base/lazy-instance.h"
8#include "src/compiler/opcodes.h"
9#include "src/compiler/operator.h"
10#include "src/types-inl.h"
11
12namespace v8 {
13namespace internal {
14namespace compiler {
15
16std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
17  switch (base_taggedness) {
18    case kUntaggedBase:
19      return os << "untagged base";
20    case kTaggedBase:
21      return os << "tagged base";
22  }
23  UNREACHABLE();
24  return os;
25}
26
27
28MachineType BufferAccess::machine_type() const {
29  switch (external_array_type_) {
30    case kExternalUint8Array:
31    case kExternalUint8ClampedArray:
32      return MachineType::Uint8();
33    case kExternalInt8Array:
34      return MachineType::Int8();
35    case kExternalUint16Array:
36      return MachineType::Uint16();
37    case kExternalInt16Array:
38      return MachineType::Int16();
39    case kExternalUint32Array:
40      return MachineType::Uint32();
41    case kExternalInt32Array:
42      return MachineType::Int32();
43    case kExternalFloat32Array:
44      return MachineType::Float32();
45    case kExternalFloat64Array:
46      return MachineType::Float64();
47  }
48  UNREACHABLE();
49  return MachineType::None();
50}
51
52
53bool operator==(BufferAccess lhs, BufferAccess rhs) {
54  return lhs.external_array_type() == rhs.external_array_type();
55}
56
57
58bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
59
60
61size_t hash_value(BufferAccess access) {
62  return base::hash<ExternalArrayType>()(access.external_array_type());
63}
64
65
66std::ostream& operator<<(std::ostream& os, BufferAccess access) {
67  switch (access.external_array_type()) {
68#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
69  case kExternal##Type##Array:                          \
70    return os << #Type;
71    TYPED_ARRAYS(TYPED_ARRAY_CASE)
72#undef TYPED_ARRAY_CASE
73  }
74  UNREACHABLE();
75  return os;
76}
77
78
79BufferAccess const BufferAccessOf(const Operator* op) {
80  DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
81         op->opcode() == IrOpcode::kStoreBuffer);
82  return OpParameter<BufferAccess>(op);
83}
84
85
86bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
87  return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
88         lhs.machine_type == rhs.machine_type;
89}
90
91
92bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
93  return !(lhs == rhs);
94}
95
96
97size_t hash_value(FieldAccess const& access) {
98  return base::hash_combine(access.base_is_tagged, access.offset,
99                            access.machine_type);
100}
101
102
103std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
104  os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
105#ifdef OBJECT_PRINT
106  Handle<Name> name;
107  if (access.name.ToHandle(&name)) {
108    name->Print(os);
109    os << ", ";
110  }
111#endif
112  access.type->PrintTo(os);
113  os << ", " << access.machine_type << "]";
114  return os;
115}
116
117
118bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
119  return lhs.base_is_tagged == rhs.base_is_tagged &&
120         lhs.header_size == rhs.header_size &&
121         lhs.machine_type == rhs.machine_type;
122}
123
124
125bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
126  return !(lhs == rhs);
127}
128
129
130size_t hash_value(ElementAccess const& access) {
131  return base::hash_combine(access.base_is_tagged, access.header_size,
132                            access.machine_type);
133}
134
135
136std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
137  os << access.base_is_tagged << ", " << access.header_size << ", ";
138  access.type->PrintTo(os);
139  os << ", " << access.machine_type;
140  return os;
141}
142
143
144const FieldAccess& FieldAccessOf(const Operator* op) {
145  DCHECK_NOT_NULL(op);
146  DCHECK(op->opcode() == IrOpcode::kLoadField ||
147         op->opcode() == IrOpcode::kStoreField);
148  return OpParameter<FieldAccess>(op);
149}
150
151
152const ElementAccess& ElementAccessOf(const Operator* op) {
153  DCHECK_NOT_NULL(op);
154  DCHECK(op->opcode() == IrOpcode::kLoadElement ||
155         op->opcode() == IrOpcode::kStoreElement);
156  return OpParameter<ElementAccess>(op);
157}
158
159
160#define PURE_OP_LIST(V)                                  \
161  V(BooleanNot, Operator::kNoProperties, 1)              \
162  V(BooleanToNumber, Operator::kNoProperties, 1)         \
163  V(NumberEqual, Operator::kCommutative, 2)              \
164  V(NumberLessThan, Operator::kNoProperties, 2)          \
165  V(NumberLessThanOrEqual, Operator::kNoProperties, 2)   \
166  V(NumberAdd, Operator::kCommutative, 2)                \
167  V(NumberSubtract, Operator::kNoProperties, 2)          \
168  V(NumberMultiply, Operator::kCommutative, 2)           \
169  V(NumberDivide, Operator::kNoProperties, 2)            \
170  V(NumberModulus, Operator::kNoProperties, 2)           \
171  V(NumberBitwiseOr, Operator::kCommutative, 2)          \
172  V(NumberBitwiseXor, Operator::kCommutative, 2)         \
173  V(NumberBitwiseAnd, Operator::kCommutative, 2)         \
174  V(NumberShiftLeft, Operator::kNoProperties, 2)         \
175  V(NumberShiftRight, Operator::kNoProperties, 2)        \
176  V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
177  V(NumberToInt32, Operator::kNoProperties, 1)           \
178  V(NumberToUint32, Operator::kNoProperties, 1)          \
179  V(NumberIsHoleNaN, Operator::kNoProperties, 1)         \
180  V(PlainPrimitiveToNumber, Operator::kNoProperties, 1)  \
181  V(ChangeTaggedToInt32, Operator::kNoProperties, 1)     \
182  V(ChangeTaggedToUint32, Operator::kNoProperties, 1)    \
183  V(ChangeTaggedToFloat64, Operator::kNoProperties, 1)   \
184  V(ChangeInt32ToTagged, Operator::kNoProperties, 1)     \
185  V(ChangeUint32ToTagged, Operator::kNoProperties, 1)    \
186  V(ChangeFloat64ToTagged, Operator::kNoProperties, 1)   \
187  V(ChangeBoolToBit, Operator::kNoProperties, 1)         \
188  V(ChangeBitToBool, Operator::kNoProperties, 1)         \
189  V(ObjectIsNumber, Operator::kNoProperties, 1)          \
190  V(ObjectIsSmi, Operator::kNoProperties, 1)
191
192#define NO_THROW_OP_LIST(V)                 \
193  V(StringEqual, Operator::kCommutative, 2) \
194  V(StringLessThan, Operator::kNoThrow, 2)  \
195  V(StringLessThanOrEqual, Operator::kNoThrow, 2)
196
197struct SimplifiedOperatorGlobalCache final {
198#define PURE(Name, properties, input_count)                                \
199  struct Name##Operator final : public Operator {                          \
200    Name##Operator()                                                       \
201        : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
202                   input_count, 0, 0, 1, 0, 0) {}                          \
203  };                                                                       \
204  Name##Operator k##Name;
205  PURE_OP_LIST(PURE)
206#undef PURE
207
208#define NO_THROW(Name, properties, input_count)                               \
209  struct Name##Operator final : public Operator {                             \
210    Name##Operator()                                                          \
211        : Operator(IrOpcode::k##Name, Operator::kNoThrow | properties, #Name, \
212                   input_count, 1, 1, 1, 1, 0) {}                             \
213  };                                                                          \
214  Name##Operator k##Name;
215  NO_THROW_OP_LIST(NO_THROW)
216#undef NO_THROW
217
218#define BUFFER_ACCESS(Type, type, TYPE, ctype, size)                          \
219  struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> {  \
220    LoadBuffer##Type##Operator()                                              \
221        : Operator1<BufferAccess>(IrOpcode::kLoadBuffer,                      \
222                                  Operator::kNoThrow | Operator::kNoWrite,    \
223                                  "LoadBuffer", 3, 1, 1, 1, 1, 0,             \
224                                  BufferAccess(kExternal##Type##Array)) {}    \
225  };                                                                          \
226  struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
227    StoreBuffer##Type##Operator()                                             \
228        : Operator1<BufferAccess>(IrOpcode::kStoreBuffer,                     \
229                                  Operator::kNoRead | Operator::kNoThrow,     \
230                                  "StoreBuffer", 4, 1, 1, 0, 1, 0,            \
231                                  BufferAccess(kExternal##Type##Array)) {}    \
232  };                                                                          \
233  LoadBuffer##Type##Operator kLoadBuffer##Type;                               \
234  StoreBuffer##Type##Operator kStoreBuffer##Type;
235  TYPED_ARRAYS(BUFFER_ACCESS)
236#undef BUFFER_ACCESS
237};
238
239
240static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
241    LAZY_INSTANCE_INITIALIZER;
242
243
244SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
245    : cache_(kCache.Get()), zone_(zone) {}
246
247
248#define GET_FROM_CACHE(Name, properties, input_count) \
249  const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
250PURE_OP_LIST(GET_FROM_CACHE)
251NO_THROW_OP_LIST(GET_FROM_CACHE)
252#undef GET_FROM_CACHE
253
254
255const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
256  // TODO(titzer): What about the type parameter?
257  return new (zone()) Operator(IrOpcode::kReferenceEqual,
258                               Operator::kCommutative | Operator::kPure,
259                               "ReferenceEqual", 2, 0, 0, 1, 0, 0);
260}
261
262
263const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
264  return new (zone())
265      Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow,
266                               "Allocate", 1, 1, 1, 1, 1, 0, pretenure);
267}
268
269
270const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
271  switch (access.external_array_type()) {
272#define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
273  case kExternal##Type##Array:                     \
274    return &cache_.kLoadBuffer##Type;
275    TYPED_ARRAYS(LOAD_BUFFER)
276#undef LOAD_BUFFER
277  }
278  UNREACHABLE();
279  return nullptr;
280}
281
282
283const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
284  switch (access.external_array_type()) {
285#define STORE_BUFFER(Type, type, TYPE, ctype, size) \
286  case kExternal##Type##Array:                      \
287    return &cache_.kStoreBuffer##Type;
288    TYPED_ARRAYS(STORE_BUFFER)
289#undef STORE_BUFFER
290  }
291  UNREACHABLE();
292  return nullptr;
293}
294
295
296#define ACCESS_OP_LIST(V)                                    \
297  V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1)     \
298  V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0)     \
299  V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
300  V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
301
302
303#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
304               output_count)                                                   \
305  const Operator* SimplifiedOperatorBuilder::Name(const Type& access) {        \
306    return new (zone())                                                        \
307        Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties,    \
308                        #Name, value_input_count, 1, control_input_count,      \
309                        output_count, 1, 0, access);                           \
310  }
311ACCESS_OP_LIST(ACCESS)
312#undef ACCESS
313
314}  // namespace compiler
315}  // namespace internal
316}  // namespace v8
317