1 // Copyright 2013 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 #ifndef V8_COMPILER_MACHINE_OPERATOR_H_
6 #define V8_COMPILER_MACHINE_OPERATOR_H_
7 
8 #include "src/base/flags.h"
9 #include "src/machine-type.h"
10 
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14 
15 // Forward declarations.
16 struct MachineOperatorGlobalCache;
17 class Operator;
18 
19 
20 // For operators that are not supported on all platforms.
21 class OptionalOperator final {
22  public:
OptionalOperator(const Operator * op)23   explicit OptionalOperator(const Operator* op) : op_(op) {}
24 
IsSupported()25   bool IsSupported() const { return op_ != nullptr; }
op()26   const Operator* op() const {
27     DCHECK_NOT_NULL(op_);
28     return op_;
29   }
30 
31  private:
32   const Operator* const op_;
33 };
34 
35 
36 // Supported float64 to int32 truncation modes.
37 enum class TruncationMode : uint8_t {
38   kJavaScript,  // ES6 section 7.1.5
39   kRoundToZero  // Round towards zero. Implementation defined for NaN and ovf.
40 };
41 
hash_value(TruncationMode mode)42 V8_INLINE size_t hash_value(TruncationMode mode) {
43   return static_cast<uint8_t>(mode);
44 }
45 
46 std::ostream& operator<<(std::ostream&, TruncationMode);
47 
48 TruncationMode TruncationModeOf(Operator const*);
49 
50 
51 // Supported write barrier modes.
52 enum WriteBarrierKind {
53   kNoWriteBarrier,
54   kMapWriteBarrier,
55   kPointerWriteBarrier,
56   kFullWriteBarrier
57 };
58 
59 std::ostream& operator<<(std::ostream& os, WriteBarrierKind);
60 
61 
62 // A Load needs a MachineType.
63 typedef MachineType LoadRepresentation;
64 
65 LoadRepresentation LoadRepresentationOf(Operator const*);
66 
67 // A Store needs a MachineType and a WriteBarrierKind in order to emit the
68 // correct write barrier.
69 class StoreRepresentation final {
70  public:
StoreRepresentation(MachineRepresentation representation,WriteBarrierKind write_barrier_kind)71   StoreRepresentation(MachineRepresentation representation,
72                       WriteBarrierKind write_barrier_kind)
73       : representation_(representation),
74         write_barrier_kind_(write_barrier_kind) {}
75 
representation()76   MachineRepresentation representation() const { return representation_; }
write_barrier_kind()77   WriteBarrierKind write_barrier_kind() const { return write_barrier_kind_; }
78 
79  private:
80   MachineRepresentation representation_;
81   WriteBarrierKind write_barrier_kind_;
82 };
83 
84 bool operator==(StoreRepresentation, StoreRepresentation);
85 bool operator!=(StoreRepresentation, StoreRepresentation);
86 
87 size_t hash_value(StoreRepresentation);
88 
89 std::ostream& operator<<(std::ostream&, StoreRepresentation);
90 
91 StoreRepresentation const& StoreRepresentationOf(Operator const*);
92 
93 
94 // A CheckedLoad needs a MachineType.
95 typedef MachineType CheckedLoadRepresentation;
96 
97 CheckedLoadRepresentation CheckedLoadRepresentationOf(Operator const*);
98 
99 
100 // A CheckedStore needs a MachineType.
101 typedef MachineRepresentation CheckedStoreRepresentation;
102 
103 CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const*);
104 
105 
106 // Interface for building machine-level operators. These operators are
107 // machine-level but machine-independent and thus define a language suitable
108 // for generating code to run on architectures such as ia32, x64, arm, etc.
109 class MachineOperatorBuilder final : public ZoneObject {
110  public:
111   // Flags that specify which operations are available. This is useful
112   // for operations that are unsupported by some back-ends.
113   enum Flag {
114     kNoFlags = 0u,
115     // Note that Float*Max behaves like `(b < a) ? a : b`, not like Math.max().
116     // Note that Float*Min behaves like `(a < b) ? a : b`, not like Math.min().
117     kFloat32Max = 1u << 0,
118     kFloat32Min = 1u << 1,
119     kFloat64Max = 1u << 2,
120     kFloat64Min = 1u << 3,
121     kFloat32RoundDown = 1u << 4,
122     kFloat64RoundDown = 1u << 5,
123     kFloat32RoundUp = 1u << 6,
124     kFloat64RoundUp = 1u << 7,
125     kFloat32RoundTruncate = 1u << 8,
126     kFloat64RoundTruncate = 1u << 9,
127     kFloat32RoundTiesEven = 1u << 10,
128     kFloat64RoundTiesEven = 1u << 11,
129     kFloat64RoundTiesAway = 1u << 12,
130     kInt32DivIsSafe = 1u << 13,
131     kUint32DivIsSafe = 1u << 14,
132     kWord32ShiftIsSafe = 1u << 15,
133     kWord32Ctz = 1u << 16,
134     kWord64Ctz = 1u << 17,
135     kWord32Popcnt = 1u << 18,
136     kWord64Popcnt = 1u << 19,
137     kAllOptionalOps = kFloat32Max | kFloat32Min | kFloat64Max | kFloat64Min |
138                       kFloat32RoundDown | kFloat64RoundDown | kFloat32RoundUp |
139                       kFloat64RoundUp | kFloat32RoundTruncate |
140                       kFloat64RoundTruncate | kFloat64RoundTiesAway |
141                       kFloat32RoundTiesEven | kFloat64RoundTiesEven |
142                       kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt
143   };
144   typedef base::Flags<Flag, unsigned> Flags;
145 
146   explicit MachineOperatorBuilder(
147       Zone* zone,
148       MachineRepresentation word = MachineType::PointerRepresentation(),
149       Flags supportedOperators = kNoFlags);
150 
151   const Operator* Word32And();
152   const Operator* Word32Or();
153   const Operator* Word32Xor();
154   const Operator* Word32Shl();
155   const Operator* Word32Shr();
156   const Operator* Word32Sar();
157   const Operator* Word32Ror();
158   const Operator* Word32Equal();
159   const Operator* Word32Clz();
160   const OptionalOperator Word32Ctz();
161   const OptionalOperator Word32Popcnt();
162   const OptionalOperator Word64Popcnt();
Word32ShiftIsSafe()163   bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
164 
165   const Operator* Word64And();
166   const Operator* Word64Or();
167   const Operator* Word64Xor();
168   const Operator* Word64Shl();
169   const Operator* Word64Shr();
170   const Operator* Word64Sar();
171   const Operator* Word64Ror();
172   const Operator* Word64Clz();
173   const OptionalOperator Word64Ctz();
174   const Operator* Word64Equal();
175 
176   const Operator* Int32Add();
177   const Operator* Int32AddWithOverflow();
178   const Operator* Int32Sub();
179   const Operator* Int32SubWithOverflow();
180   const Operator* Int32Mul();
181   const Operator* Int32MulHigh();
182   const Operator* Int32Div();
183   const Operator* Int32Mod();
184   const Operator* Int32LessThan();
185   const Operator* Int32LessThanOrEqual();
186   const Operator* Uint32Div();
187   const Operator* Uint32LessThan();
188   const Operator* Uint32LessThanOrEqual();
189   const Operator* Uint32Mod();
190   const Operator* Uint32MulHigh();
Int32DivIsSafe()191   bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; }
Uint32DivIsSafe()192   bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; }
193 
194   const Operator* Int64Add();
195   const Operator* Int64AddWithOverflow();
196   const Operator* Int64Sub();
197   const Operator* Int64SubWithOverflow();
198   const Operator* Int64Mul();
199   const Operator* Int64Div();
200   const Operator* Int64Mod();
201   const Operator* Int64LessThan();
202   const Operator* Int64LessThanOrEqual();
203   const Operator* Uint64Div();
204   const Operator* Uint64LessThan();
205   const Operator* Uint64LessThanOrEqual();
206   const Operator* Uint64Mod();
207 
208   // These operators change the representation of numbers while preserving the
209   // value of the number. Narrowing operators assume the input is representable
210   // in the target type and are *not* defined for other inputs.
211   // Use narrowing change operators only when there is a static guarantee that
212   // the input value is representable in the target value.
213   const Operator* ChangeFloat32ToFloat64();
214   const Operator* ChangeFloat64ToInt32();   // narrowing
215   const Operator* ChangeFloat64ToUint32();  // narrowing
216   const Operator* TryTruncateFloat32ToInt64();
217   const Operator* TryTruncateFloat64ToInt64();
218   const Operator* TryTruncateFloat32ToUint64();
219   const Operator* TryTruncateFloat64ToUint64();
220   const Operator* ChangeInt32ToFloat64();
221   const Operator* ChangeInt32ToInt64();
222   const Operator* ChangeUint32ToFloat64();
223   const Operator* ChangeUint32ToUint64();
224 
225   // These operators truncate or round numbers, both changing the representation
226   // of the number and mapping multiple input values onto the same output value.
227   const Operator* TruncateFloat64ToFloat32();
228   const Operator* TruncateFloat64ToInt32(TruncationMode);
229   const Operator* TruncateInt64ToInt32();
230   const Operator* RoundInt64ToFloat32();
231   const Operator* RoundInt64ToFloat64();
232   const Operator* RoundUint64ToFloat32();
233   const Operator* RoundUint64ToFloat64();
234 
235   // These operators reinterpret the bits of a floating point number as an
236   // integer and vice versa.
237   const Operator* BitcastFloat32ToInt32();
238   const Operator* BitcastFloat64ToInt64();
239   const Operator* BitcastInt32ToFloat32();
240   const Operator* BitcastInt64ToFloat64();
241 
242   // Floating point operators always operate with IEEE 754 round-to-nearest
243   // (single-precision).
244   const Operator* Float32Add();
245   const Operator* Float32Sub();
246   const Operator* Float32Mul();
247   const Operator* Float32Div();
248   const Operator* Float32Sqrt();
249 
250   // Floating point operators always operate with IEEE 754 round-to-nearest
251   // (double-precision).
252   const Operator* Float64Add();
253   const Operator* Float64Sub();
254   const Operator* Float64Mul();
255   const Operator* Float64Div();
256   const Operator* Float64Mod();
257   const Operator* Float64Sqrt();
258 
259   // Floating point comparisons complying to IEEE 754 (single-precision).
260   const Operator* Float32Equal();
261   const Operator* Float32LessThan();
262   const Operator* Float32LessThanOrEqual();
263 
264   // Floating point comparisons complying to IEEE 754 (double-precision).
265   const Operator* Float64Equal();
266   const Operator* Float64LessThan();
267   const Operator* Float64LessThanOrEqual();
268 
269   // Floating point min/max complying to IEEE 754 (single-precision).
270   const OptionalOperator Float32Max();
271   const OptionalOperator Float32Min();
272 
273   // Floating point min/max complying to IEEE 754 (double-precision).
274   const OptionalOperator Float64Max();
275   const OptionalOperator Float64Min();
276 
277   // Floating point abs complying to IEEE 754 (single-precision).
278   const Operator* Float32Abs();
279 
280   // Floating point abs complying to IEEE 754 (double-precision).
281   const Operator* Float64Abs();
282 
283   // Floating point rounding.
284   const OptionalOperator Float32RoundDown();
285   const OptionalOperator Float64RoundDown();
286   const OptionalOperator Float32RoundUp();
287   const OptionalOperator Float64RoundUp();
288   const OptionalOperator Float32RoundTruncate();
289   const OptionalOperator Float64RoundTruncate();
290   const OptionalOperator Float64RoundTiesAway();
291   const OptionalOperator Float32RoundTiesEven();
292   const OptionalOperator Float64RoundTiesEven();
293 
294   // Floating point bit representation.
295   const Operator* Float64ExtractLowWord32();
296   const Operator* Float64ExtractHighWord32();
297   const Operator* Float64InsertLowWord32();
298   const Operator* Float64InsertHighWord32();
299 
300   // load [base + index]
301   const Operator* Load(LoadRepresentation rep);
302 
303   // store [base + index], value
304   const Operator* Store(StoreRepresentation rep);
305 
306   // Access to the machine stack.
307   const Operator* LoadStackPointer();
308   const Operator* LoadFramePointer();
309 
310   // checked-load heap, index, length
311   const Operator* CheckedLoad(CheckedLoadRepresentation);
312   // checked-store heap, index, length, value
313   const Operator* CheckedStore(CheckedStoreRepresentation);
314 
315   // Target machine word-size assumed by this builder.
Is32()316   bool Is32() const { return word() == MachineRepresentation::kWord32; }
Is64()317   bool Is64() const { return word() == MachineRepresentation::kWord64; }
word()318   MachineRepresentation word() const { return word_; }
319 
320 // Pseudo operators that translate to 32/64-bit operators depending on the
321 // word-size of the target machine assumed by this builder.
322 #define PSEUDO_OP_LIST(V) \
323   V(Word, And)            \
324   V(Word, Or)             \
325   V(Word, Xor)            \
326   V(Word, Shl)            \
327   V(Word, Shr)            \
328   V(Word, Sar)            \
329   V(Word, Ror)            \
330   V(Word, Equal)          \
331   V(Int, Add)             \
332   V(Int, Sub)             \
333   V(Int, Mul)             \
334   V(Int, Div)             \
335   V(Int, Mod)             \
336   V(Int, LessThan)        \
337   V(Int, LessThanOrEqual) \
338   V(Uint, Div)            \
339   V(Uint, LessThan)       \
340   V(Uint, Mod)
341 #define PSEUDO_OP(Prefix, Suffix)                                \
342   const Operator* Prefix##Suffix() {                             \
343     return Is32() ? Prefix##32##Suffix() : Prefix##64##Suffix(); \
344   }
345   PSEUDO_OP_LIST(PSEUDO_OP)
346 #undef PSEUDO_OP
347 #undef PSEUDO_OP_LIST
348 
349  private:
350   MachineOperatorGlobalCache const& cache_;
351   MachineRepresentation const word_;
352   Flags const flags_;
353 
354   DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder);
355 };
356 
357 
358 DEFINE_OPERATORS_FOR_FLAGS(MachineOperatorBuilder::Flags)
359 
360 }  // namespace compiler
361 }  // namespace internal
362 }  // namespace v8
363 
364 #endif  // V8_COMPILER_MACHINE_OPERATOR_H_
365