• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15 
operator <<(std::ostream & os,BaseTaggedness base_taggedness)16 std::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 
machine_type() const28 MachineType 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 
operator ==(BufferAccess lhs,BufferAccess rhs)53 bool operator==(BufferAccess lhs, BufferAccess rhs) {
54   return lhs.external_array_type() == rhs.external_array_type();
55 }
56 
57 
operator !=(BufferAccess lhs,BufferAccess rhs)58 bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
59 
60 
hash_value(BufferAccess access)61 size_t hash_value(BufferAccess access) {
62   return base::hash<ExternalArrayType>()(access.external_array_type());
63 }
64 
65 
operator <<(std::ostream & os,BufferAccess access)66 std::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 
BufferAccessOf(const Operator * op)79 BufferAccess const BufferAccessOf(const Operator* op) {
80   DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
81          op->opcode() == IrOpcode::kStoreBuffer);
82   return OpParameter<BufferAccess>(op);
83 }
84 
85 
operator ==(FieldAccess const & lhs,FieldAccess const & rhs)86 bool 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 
operator !=(FieldAccess const & lhs,FieldAccess const & rhs)92 bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
93   return !(lhs == rhs);
94 }
95 
96 
hash_value(FieldAccess const & access)97 size_t hash_value(FieldAccess const& access) {
98   return base::hash_combine(access.base_is_tagged, access.offset,
99                             access.machine_type);
100 }
101 
102 
operator <<(std::ostream & os,FieldAccess const & access)103 std::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 
operator ==(ElementAccess const & lhs,ElementAccess const & rhs)118 bool 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 
operator !=(ElementAccess const & lhs,ElementAccess const & rhs)125 bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
126   return !(lhs == rhs);
127 }
128 
129 
hash_value(ElementAccess const & access)130 size_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 
operator <<(std::ostream & os,ElementAccess const & access)136 std::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 
FieldAccessOf(const Operator * op)144 const 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 
ElementAccessOf(const Operator * op)152 const 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 
197 struct 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 
240 static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
241     LAZY_INSTANCE_INITIALIZER;
242 
243 
SimplifiedOperatorBuilder(Zone * zone)244 SimplifiedOperatorBuilder::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; }
250 PURE_OP_LIST(GET_FROM_CACHE)
NO_THROW_OP_LIST(GET_FROM_CACHE) const251 NO_THROW_OP_LIST(GET_FROM_CACHE)
252 #undef GET_FROM_CACHE
253 
254 
255 const 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 
Allocate(PretenureFlag pretenure)263 const 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 
LoadBuffer(BufferAccess access)270 const 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 
StoreBuffer(BufferAccess access)283 const 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   }
311 ACCESS_OP_LIST(ACCESS)
312 #undef ACCESS
313 
314 }  // namespace compiler
315 }  // namespace internal
316 }  // namespace v8
317