V8 Project
representation-change.h
Go to the documentation of this file.
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 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_
7 
8 #include "src/base/bits.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 // Contains logic related to changing the representation of values for constants
19 // and other nodes, as well as lowering Simplified->Machine operators.
20 // Eagerly folds any representation changes for constants.
22  public:
23  RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
25  : jsgraph_(jsgraph),
29  type_error_(false) {}
30 
31  // TODO(titzer): should Word64 also be implicitly convertable to others?
32  static const MachineTypeUnion rWord =
34 
35  Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type,
36  MachineTypeUnion use_type) {
37  if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
38  // There should be only one output representation.
39  return TypeError(node, output_type, use_type);
40  }
41  if ((use_type & kRepMask) == (output_type & kRepMask)) {
42  // Representations are the same. That's a no-op.
43  return node;
44  }
45  if ((use_type & rWord) && (output_type & rWord)) {
46  // Both are words less than or equal to 32-bits.
47  // Since loads of integers from memory implicitly sign or zero extend the
48  // value to the full machine word size and stores implicitly truncate,
49  // no representation change is necessary.
50  return node;
51  }
52  if (use_type & kRepTagged) {
53  return GetTaggedRepresentationFor(node, output_type);
54  } else if (use_type & kRepFloat32) {
55  return GetFloat32RepresentationFor(node, output_type);
56  } else if (use_type & kRepFloat64) {
57  return GetFloat64RepresentationFor(node, output_type);
58  } else if (use_type & kRepBit) {
59  return GetBitRepresentationFor(node, output_type);
60  } else if (use_type & rWord) {
61  return GetWord32RepresentationFor(node, output_type,
62  use_type & kTypeUint32);
63  } else if (use_type & kRepWord64) {
64  return GetWord64RepresentationFor(node, output_type);
65  } else {
66  return node;
67  }
68  }
69 
70  Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) {
71  // Eagerly fold representation changes for constants.
72  switch (node->opcode()) {
73  case IrOpcode::kNumberConstant:
74  case IrOpcode::kHeapConstant:
75  return node; // No change necessary.
76  case IrOpcode::kInt32Constant:
77  if (output_type & kTypeUint32) {
78  uint32_t value = OpParameter<uint32_t>(node);
79  return jsgraph()->Constant(static_cast<double>(value));
80  } else if (output_type & kTypeInt32) {
81  int32_t value = OpParameter<int32_t>(node);
82  return jsgraph()->Constant(value);
83  } else if (output_type & kRepBit) {
84  return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
85  : jsgraph()->TrueConstant();
86  } else {
87  return TypeError(node, output_type, kRepTagged);
88  }
89  case IrOpcode::kFloat64Constant:
90  return jsgraph()->Constant(OpParameter<double>(node));
91  case IrOpcode::kFloat32Constant:
92  return jsgraph()->Constant(OpParameter<float>(node));
93  default:
94  break;
95  }
96  // Select the correct X -> Tagged operator.
97  const Operator* op;
98  if (output_type & kRepBit) {
99  op = simplified()->ChangeBitToBool();
100  } else if (output_type & rWord) {
101  if (output_type & kTypeUint32) {
102  op = simplified()->ChangeUint32ToTagged();
103  } else if (output_type & kTypeInt32) {
104  op = simplified()->ChangeInt32ToTagged();
105  } else {
106  return TypeError(node, output_type, kRepTagged);
107  }
108  } else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged
109  node = InsertChangeFloat32ToFloat64(node);
110  op = simplified()->ChangeFloat64ToTagged();
111  } else if (output_type & kRepFloat64) {
112  op = simplified()->ChangeFloat64ToTagged();
113  } else {
114  return TypeError(node, output_type, kRepTagged);
115  }
116  return jsgraph()->graph()->NewNode(op, node);
117  }
118 
119  Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type) {
120  // Eagerly fold representation changes for constants.
121  switch (node->opcode()) {
122  case IrOpcode::kFloat64Constant:
123  case IrOpcode::kNumberConstant:
124  return jsgraph()->Float32Constant(
125  DoubleToFloat32(OpParameter<double>(node)));
126  case IrOpcode::kInt32Constant:
127  if (output_type & kTypeUint32) {
128  uint32_t value = OpParameter<uint32_t>(node);
129  return jsgraph()->Float32Constant(static_cast<float>(value));
130  } else {
131  int32_t value = OpParameter<int32_t>(node);
132  return jsgraph()->Float32Constant(static_cast<float>(value));
133  }
134  case IrOpcode::kFloat32Constant:
135  return node; // No change necessary.
136  default:
137  break;
138  }
139  // Select the correct X -> Float32 operator.
140  const Operator* op;
141  if (output_type & kRepBit) {
142  return TypeError(node, output_type, kRepFloat32);
143  } else if (output_type & rWord) {
144  if (output_type & kTypeUint32) {
145  op = machine()->ChangeUint32ToFloat64();
146  } else {
147  op = machine()->ChangeInt32ToFloat64();
148  }
149  // int32 -> float64 -> float32
150  node = jsgraph()->graph()->NewNode(op, node);
151  op = machine()->TruncateFloat64ToFloat32();
152  } else if (output_type & kRepTagged) {
153  op = simplified()
154  ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32
155  node = jsgraph()->graph()->NewNode(op, node);
156  op = machine()->TruncateFloat64ToFloat32();
157  } else if (output_type & kRepFloat64) {
158  op = machine()->ChangeFloat32ToFloat64();
159  } else {
160  return TypeError(node, output_type, kRepFloat32);
161  }
162  return jsgraph()->graph()->NewNode(op, node);
163  }
164 
165  Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
166  // Eagerly fold representation changes for constants.
167  switch (node->opcode()) {
168  case IrOpcode::kNumberConstant:
169  return jsgraph()->Float64Constant(OpParameter<double>(node));
170  case IrOpcode::kInt32Constant:
171  if (output_type & kTypeUint32) {
172  uint32_t value = OpParameter<uint32_t>(node);
173  return jsgraph()->Float64Constant(static_cast<double>(value));
174  } else {
175  int32_t value = OpParameter<int32_t>(node);
176  return jsgraph()->Float64Constant(value);
177  }
178  case IrOpcode::kFloat64Constant:
179  return node; // No change necessary.
180  case IrOpcode::kFloat32Constant:
181  return jsgraph()->Float64Constant(OpParameter<float>(node));
182  default:
183  break;
184  }
185  // Select the correct X -> Float64 operator.
186  const Operator* op;
187  if (output_type & kRepBit) {
188  return TypeError(node, output_type, kRepFloat64);
189  } else if (output_type & rWord) {
190  if (output_type & kTypeUint32) {
191  op = machine()->ChangeUint32ToFloat64();
192  } else {
193  op = machine()->ChangeInt32ToFloat64();
194  }
195  } else if (output_type & kRepTagged) {
196  op = simplified()->ChangeTaggedToFloat64();
197  } else if (output_type & kRepFloat32) {
198  op = machine()->ChangeFloat32ToFloat64();
199  } else {
200  return TypeError(node, output_type, kRepFloat64);
201  }
202  return jsgraph()->graph()->NewNode(op, node);
203  }
204 
205  Node* MakeInt32Constant(double value) {
206  if (value < 0) {
207  DCHECK(IsInt32Double(value));
208  int32_t iv = static_cast<int32_t>(value);
209  return jsgraph()->Int32Constant(iv);
210  } else {
211  DCHECK(IsUint32Double(value));
212  int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
213  return jsgraph()->Int32Constant(iv);
214  }
215  }
216 
217  Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
218  bool use_unsigned) {
219  // Eagerly fold representation changes for constants.
220  switch (node->opcode()) {
221  case IrOpcode::kInt32Constant:
222  return node; // No change necessary.
223  case IrOpcode::kFloat32Constant:
224  return MakeInt32Constant(OpParameter<float>(node));
225  case IrOpcode::kNumberConstant:
226  case IrOpcode::kFloat64Constant:
227  return MakeInt32Constant(OpParameter<double>(node));
228  default:
229  break;
230  }
231  // Select the correct X -> Word32 operator.
232  const Operator* op = NULL;
233  if (output_type & kRepFloat64) {
234  if (output_type & kTypeUint32 || use_unsigned) {
235  op = machine()->ChangeFloat64ToUint32();
236  } else {
237  op = machine()->ChangeFloat64ToInt32();
238  }
239  } else if (output_type & kRepFloat32) {
240  node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32
241  if (output_type & kTypeUint32 || use_unsigned) {
242  op = machine()->ChangeFloat64ToUint32();
243  } else {
244  op = machine()->ChangeFloat64ToInt32();
245  }
246  } else if (output_type & kRepTagged) {
247  if (output_type & kTypeUint32 || use_unsigned) {
248  op = simplified()->ChangeTaggedToUint32();
249  } else {
250  op = simplified()->ChangeTaggedToInt32();
251  }
252  } else {
253  return TypeError(node, output_type, kRepWord32);
254  }
255  return jsgraph()->graph()->NewNode(op, node);
256  }
257 
258  Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) {
259  // Eagerly fold representation changes for constants.
260  switch (node->opcode()) {
261  case IrOpcode::kInt32Constant: {
262  int32_t value = OpParameter<int32_t>(node);
263  if (value == 0 || value == 1) return node;
264  return jsgraph()->OneConstant(); // value != 0
265  }
266  case IrOpcode::kHeapConstant: {
267  Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
268  DCHECK(*handle == isolate()->heap()->true_value() ||
269  *handle == isolate()->heap()->false_value());
270  return jsgraph()->Int32Constant(
271  *handle == isolate()->heap()->true_value() ? 1 : 0);
272  }
273  default:
274  break;
275  }
276  // Select the correct X -> Bit operator.
277  const Operator* op;
278  if (output_type & rWord) {
279  return node; // No change necessary.
280  } else if (output_type & kRepWord64) {
281  return node; // TODO(titzer): No change necessary, on 64-bit.
282  } else if (output_type & kRepTagged) {
283  op = simplified()->ChangeBoolToBit();
284  } else {
285  return TypeError(node, output_type, kRepBit);
286  }
287  return jsgraph()->graph()->NewNode(op, node);
288  }
289 
290  Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
291  if (output_type & kRepBit) {
292  return node; // Sloppy comparison -> word64
293  }
294  // Can't really convert Word64 to anything else. Purported to be internal.
295  return TypeError(node, output_type, kRepWord64);
296  }
297 
299  switch (opcode) {
300  case IrOpcode::kNumberAdd:
301  return machine()->Int32Add();
302  case IrOpcode::kNumberSubtract:
303  return machine()->Int32Sub();
304  case IrOpcode::kNumberMultiply:
305  return machine()->Int32Mul();
306  case IrOpcode::kNumberDivide:
307  return machine()->Int32Div();
308  case IrOpcode::kNumberModulus:
309  return machine()->Int32Mod();
310  case IrOpcode::kNumberEqual:
311  return machine()->Word32Equal();
312  case IrOpcode::kNumberLessThan:
313  return machine()->Int32LessThan();
314  case IrOpcode::kNumberLessThanOrEqual:
315  return machine()->Int32LessThanOrEqual();
316  default:
317  UNREACHABLE();
318  return NULL;
319  }
320  }
321 
323  switch (opcode) {
324  case IrOpcode::kNumberAdd:
325  return machine()->Int32Add();
326  case IrOpcode::kNumberSubtract:
327  return machine()->Int32Sub();
328  case IrOpcode::kNumberMultiply:
329  return machine()->Int32Mul();
330  case IrOpcode::kNumberDivide:
331  return machine()->Int32UDiv();
332  case IrOpcode::kNumberModulus:
333  return machine()->Int32UMod();
334  case IrOpcode::kNumberEqual:
335  return machine()->Word32Equal();
336  case IrOpcode::kNumberLessThan:
337  return machine()->Uint32LessThan();
338  case IrOpcode::kNumberLessThanOrEqual:
339  return machine()->Uint32LessThanOrEqual();
340  default:
341  UNREACHABLE();
342  return NULL;
343  }
344  }
345 
347  switch (opcode) {
348  case IrOpcode::kNumberAdd:
349  return machine()->Float64Add();
350  case IrOpcode::kNumberSubtract:
351  return machine()->Float64Sub();
352  case IrOpcode::kNumberMultiply:
353  return machine()->Float64Mul();
354  case IrOpcode::kNumberDivide:
355  return machine()->Float64Div();
356  case IrOpcode::kNumberModulus:
357  return machine()->Float64Mod();
358  case IrOpcode::kNumberEqual:
359  return machine()->Float64Equal();
360  case IrOpcode::kNumberLessThan:
361  return machine()->Float64LessThan();
362  case IrOpcode::kNumberLessThanOrEqual:
363  return machine()->Float64LessThanOrEqual();
364  default:
365  UNREACHABLE();
366  return NULL;
367  }
368  }
369 
371  return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
372  }
373 
375  return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
376  }
377 
379  if (type->Is(Type::None()))
380  return kTypeAny; // TODO(titzer): should be an error
381  if (type->Is(Type::Signed32())) return kTypeInt32;
382  if (type->Is(Type::Unsigned32())) return kTypeUint32;
383  if (type->Is(Type::Number())) return kTypeNumber;
384  if (type->Is(Type::Boolean())) return kTypeBool;
385  return kTypeAny;
386  }
387 
388  private:
390  SimplifiedOperatorBuilder* simplified_;
392 
393  friend class RepresentationChangerTester; // accesses the below fields.
394 
395  bool testing_type_errors_; // If {true}, don't abort on a type error.
396  bool type_error_; // Set when a type error is detected.
397 
398  Node* TypeError(Node* node, MachineTypeUnion output_type,
400  type_error_ = true;
401  if (!testing_type_errors_) {
402  OStringStream out_str;
403  out_str << static_cast<MachineType>(output_type);
404 
405  OStringStream use_str;
406  use_str << static_cast<MachineType>(use);
407 
408  V8_Fatal(__FILE__, __LINE__,
409  "RepresentationChangerError: node #%d:%s of "
410  "%s cannot be changed to %s",
411  node->id(), node->op()->mnemonic(), out_str.c_str(),
412  use_str.c_str());
413  }
414  return node;
415  }
416 
417  Node* InsertChangeFloat32ToFloat64(Node* node) {
418  return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
419  node);
420  }
421 
422  JSGraph* jsgraph() { return jsgraph_; }
423  Isolate* isolate() { return isolate_; }
424  SimplifiedOperatorBuilder* simplified() { return simplified_; }
425  MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
426 };
427 
428 } // namespace compiler
429 } // namespace internal
430 } // namespace v8
431 
432 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_
const char * c_str() const
Definition: ostreams.h:84
bool Is(TypeImpl *that)
Definition: types.h:390
Node * NewNode(const Operator *op, int input_count, Node **inputs)
Definition: graph.cc:24
Node * Float32Constant(float value)
Definition: js-graph.cc:168
MachineOperatorBuilder * machine()
Definition: js-graph.h:88
Node * Float64Constant(double value)
Definition: js-graph.cc:174
Node * Constant(Handle< Object > value)
Definition: js-graph.cc:115
Node * Int32Constant(int32_t value)
Definition: js-graph.cc:150
const Operator * Float64OperatorFor(IrOpcode::Value opcode)
Node * GetTaggedRepresentationFor(Node *node, MachineTypeUnion output_type)
Node * GetFloat32RepresentationFor(Node *node, MachineTypeUnion output_type)
Node * GetRepresentationFor(Node *node, MachineTypeUnion output_type, MachineTypeUnion use_type)
Node * GetWord32RepresentationFor(Node *node, MachineTypeUnion output_type, bool use_unsigned)
Node * TypeError(Node *node, MachineTypeUnion output_type, MachineTypeUnion use)
const Operator * Int32OperatorFor(IrOpcode::Value opcode)
MachineType TypeForBasePointer(const FieldAccess &access)
Node * GetBitRepresentationFor(Node *node, MachineTypeUnion output_type)
Node * GetWord64RepresentationFor(Node *node, MachineTypeUnion output_type)
const Operator * Uint32OperatorFor(IrOpcode::Value opcode)
Node * GetFloat64RepresentationFor(Node *node, MachineTypeUnion output_type)
MachineType TypeForBasePointer(const ElementAccess &access)
RepresentationChanger(JSGraph *jsgraph, SimplifiedOperatorBuilder *simplified, Isolate *isolate)
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to use(in kBytes)") DEFINE_INT(max_stack_trace_source_length
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
void V8_Fatal(const char *file, int line, const char *format,...)
Definition: logging.cc:75
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
int int32_t
Definition: unicode.cc:24
bool IsPowerOfTwo32(uint32_t value)
Definition: bits.h:77
const MachineTypeUnion kRepMask
Definition: machine-type.h:62
static bool IsUint32Double(double value)
Definition: conversions.h:180
static bool IsInt32Double(double value)
Definition: conversions.h:169
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
float DoubleToFloat32(double x)
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
@ None
Definition: v8.h:2211