summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/simplified-operator.cc
blob: 62dc8df621a308d48e4011667acbf9b2af613d4c (plain)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// Copyright 2012 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/simplified-operator.h"

#include "src/base/lazy-instance.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
#include "src/types-inl.h"

namespace v8 {
namespace internal {
namespace compiler {

std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
  switch (base_taggedness) {
    case kUntaggedBase:
      return os << "untagged base";
    case kTaggedBase:
      return os << "tagged base";
  }
  UNREACHABLE();
  return os;
}


MachineType BufferAccess::machine_type() const {
  switch (external_array_type_) {
    case kExternalUint8Array:
    case kExternalUint8ClampedArray:
      return kMachUint8;
    case kExternalInt8Array:
      return kMachInt8;
    case kExternalUint16Array:
      return kMachUint16;
    case kExternalInt16Array:
      return kMachInt16;
    case kExternalUint32Array:
      return kMachUint32;
    case kExternalInt32Array:
      return kMachInt32;
    case kExternalFloat32Array:
      return kMachFloat32;
    case kExternalFloat64Array:
      return kMachFloat64;
  }
  UNREACHABLE();
  return kMachNone;
}


bool operator==(BufferAccess lhs, BufferAccess rhs) {
  return lhs.external_array_type() == rhs.external_array_type();
}


bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }


size_t hash_value(BufferAccess access) {
  return base::hash<ExternalArrayType>()(access.external_array_type());
}


std::ostream& operator<<(std::ostream& os, BufferAccess access) {
  switch (access.external_array_type()) {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
  case kExternal##Type##Array:                          \
    return os << #Type;
    TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
  }
  UNREACHABLE();
  return os;
}


BufferAccess const BufferAccessOf(const Operator* op) {
  DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
         op->opcode() == IrOpcode::kStoreBuffer);
  return OpParameter<BufferAccess>(op);
}


bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
  return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
         lhs.machine_type == rhs.machine_type;
}


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


size_t hash_value(FieldAccess const& access) {
  return base::hash_combine(access.base_is_tagged, access.offset,
                            access.machine_type);
}


std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
  os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
#ifdef OBJECT_PRINT
  Handle<Name> name;
  if (access.name.ToHandle(&name)) {
    name->Print(os);
    os << ", ";
  }
#endif
  access.type->PrintTo(os);
  os << ", " << access.machine_type << "]";
  return os;
}


bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
  return lhs.base_is_tagged == rhs.base_is_tagged &&
         lhs.header_size == rhs.header_size &&
         lhs.machine_type == rhs.machine_type;
}


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


size_t hash_value(ElementAccess const& access) {
  return base::hash_combine(access.base_is_tagged, access.header_size,
                            access.machine_type);
}


std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
  os << access.base_is_tagged << ", " << access.header_size << ", ";
  access.type->PrintTo(os);
  os << ", " << access.machine_type;
  return os;
}


const FieldAccess& FieldAccessOf(const Operator* op) {
  DCHECK_NOT_NULL(op);
  DCHECK(op->opcode() == IrOpcode::kLoadField ||
         op->opcode() == IrOpcode::kStoreField);
  return OpParameter<FieldAccess>(op);
}


const ElementAccess& ElementAccessOf(const Operator* op) {
  DCHECK_NOT_NULL(op);
  DCHECK(op->opcode() == IrOpcode::kLoadElement ||
         op->opcode() == IrOpcode::kStoreElement);
  return OpParameter<ElementAccess>(op);
}


#define PURE_OP_LIST(V)                                  \
  V(BooleanNot, Operator::kNoProperties, 1)              \
  V(BooleanToNumber, Operator::kNoProperties, 1)         \
  V(NumberEqual, Operator::kCommutative, 2)              \
  V(NumberLessThan, Operator::kNoProperties, 2)          \
  V(NumberLessThanOrEqual, Operator::kNoProperties, 2)   \
  V(NumberAdd, Operator::kCommutative, 2)                \
  V(NumberSubtract, Operator::kNoProperties, 2)          \
  V(NumberMultiply, Operator::kCommutative, 2)           \
  V(NumberDivide, Operator::kNoProperties, 2)            \
  V(NumberModulus, Operator::kNoProperties, 2)           \
  V(NumberBitwiseOr, Operator::kCommutative, 2)          \
  V(NumberBitwiseXor, Operator::kCommutative, 2)         \
  V(NumberBitwiseAnd, Operator::kCommutative, 2)         \
  V(NumberShiftLeft, Operator::kNoProperties, 2)         \
  V(NumberShiftRight, Operator::kNoProperties, 2)        \
  V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
  V(NumberToInt32, Operator::kNoProperties, 1)           \
  V(NumberToUint32, Operator::kNoProperties, 1)          \
  V(PlainPrimitiveToNumber, Operator::kNoProperties, 1)  \
  V(ChangeTaggedToInt32, Operator::kNoProperties, 1)     \
  V(ChangeTaggedToUint32, Operator::kNoProperties, 1)    \
  V(ChangeTaggedToFloat64, Operator::kNoProperties, 1)   \
  V(ChangeInt32ToTagged, Operator::kNoProperties, 1)     \
  V(ChangeUint32ToTagged, Operator::kNoProperties, 1)    \
  V(ChangeFloat64ToTagged, Operator::kNoProperties, 1)   \
  V(ChangeBoolToBit, Operator::kNoProperties, 1)         \
  V(ChangeBitToBool, Operator::kNoProperties, 1)         \
  V(ObjectIsNumber, Operator::kNoProperties, 1)          \
  V(ObjectIsSmi, Operator::kNoProperties, 1)

#define NO_THROW_OP_LIST(V)                 \
  V(StringEqual, Operator::kCommutative, 2) \
  V(StringLessThan, Operator::kNoThrow, 2)  \
  V(StringLessThanOrEqual, Operator::kNoThrow, 2)

struct SimplifiedOperatorGlobalCache final {
#define PURE(Name, properties, input_count)                                \
  struct Name##Operator final : public Operator {                          \
    Name##Operator()                                                       \
        : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
                   input_count, 0, 0, 1, 0, 0) {}                          \
  };                                                                       \
  Name##Operator k##Name;
  PURE_OP_LIST(PURE)
#undef PURE

#define NO_THROW(Name, properties, input_count)                               \
  struct Name##Operator final : public Operator {                             \
    Name##Operator()                                                          \
        : Operator(IrOpcode::k##Name, Operator::kNoThrow | properties, #Name, \
                   input_count, 1, 1, 1, 1, 0) {}                             \
  };                                                                          \
  Name##Operator k##Name;
  NO_THROW_OP_LIST(NO_THROW)
#undef NO_THROW

#define BUFFER_ACCESS(Type, type, TYPE, ctype, size)                          \
  struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> {  \
    LoadBuffer##Type##Operator()                                              \
        : Operator1<BufferAccess>(IrOpcode::kLoadBuffer,                      \
                                  Operator::kNoThrow | Operator::kNoWrite,    \
                                  "LoadBuffer", 3, 1, 1, 1, 1, 0,             \
                                  BufferAccess(kExternal##Type##Array)) {}    \
  };                                                                          \
  struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
    StoreBuffer##Type##Operator()                                             \
        : Operator1<BufferAccess>(IrOpcode::kStoreBuffer,                     \
                                  Operator::kNoRead | Operator::kNoThrow,     \
                                  "StoreBuffer", 4, 1, 1, 0, 1, 0,            \
                                  BufferAccess(kExternal##Type##Array)) {}    \
  };                                                                          \
  LoadBuffer##Type##Operator kLoadBuffer##Type;                               \
  StoreBuffer##Type##Operator kStoreBuffer##Type;
  TYPED_ARRAYS(BUFFER_ACCESS)
#undef BUFFER_ACCESS
};


static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
    LAZY_INSTANCE_INITIALIZER;


SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
    : cache_(kCache.Get()), zone_(zone) {}


#define GET_FROM_CACHE(Name, properties, input_count) \
  const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
PURE_OP_LIST(GET_FROM_CACHE)
NO_THROW_OP_LIST(GET_FROM_CACHE)
#undef GET_FROM_CACHE


const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
  // TODO(titzer): What about the type parameter?
  return new (zone()) Operator(IrOpcode::kReferenceEqual,
                               Operator::kCommutative | Operator::kPure,
                               "ReferenceEqual", 2, 0, 0, 1, 0, 0);
}


const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
  return new (zone())
      Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow,
                               "Allocate", 1, 1, 1, 1, 1, 0, pretenure);
}


const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
  switch (access.external_array_type()) {
#define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
  case kExternal##Type##Array:                     \
    return &cache_.kLoadBuffer##Type;
    TYPED_ARRAYS(LOAD_BUFFER)
#undef LOAD_BUFFER
  }
  UNREACHABLE();
  return nullptr;
}


const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
  switch (access.external_array_type()) {
#define STORE_BUFFER(Type, type, TYPE, ctype, size) \
  case kExternal##Type##Array:                      \
    return &cache_.kStoreBuffer##Type;
    TYPED_ARRAYS(STORE_BUFFER)
#undef STORE_BUFFER
  }
  UNREACHABLE();
  return nullptr;
}


#define ACCESS_OP_LIST(V)                                    \
  V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1)     \
  V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0)     \
  V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
  V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)


#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
               output_count)                                                   \
  const Operator* SimplifiedOperatorBuilder::Name(const Type& access) {        \
    return new (zone())                                                        \
        Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties,    \
                        #Name, value_input_count, 1, control_input_count,      \
                        output_count, 1, 0, access);                           \
  }
ACCESS_OP_LIST(ACCESS)
#undef ACCESS

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