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.
5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/machine-operator.h"
10 #include "src/compiler/node-properties-inl.h"
11 #include "src/compiler/simplified-operator.h"
17 // The types and representations tracked during representation inference
18 // and change insertion.
19 // TODO(titzer): First, merge MachineType and RepType.
20 // TODO(titzer): Second, Use the real type system instead of RepType.
39 #define REP_TYPE_STRLEN 24
41 typedef uint16_t RepTypeUnion;
44 inline void RenderRepTypeUnion(char* buf, RepTypeUnion info) {
45 base::OS::SNPrintF(buf, REP_TYPE_STRLEN, "{%s%s%s%s%s %s%s%s%s%s%s%s}",
46 (info & rBit) ? "k" : " ", (info & rWord32) ? "w" : " ",
47 (info & rWord64) ? "q" : " ",
48 (info & rFloat64) ? "f" : " ",
49 (info & rTagged) ? "t" : " ", (info & tBool) ? "Z" : " ",
50 (info & tInt32) ? "I" : " ", (info & tUint32) ? "U" : " ",
51 (info & tInt64) ? "L" : " ", (info & tUint64) ? "J" : " ",
52 (info & tNumber) ? "N" : " ", (info & tAny) ? "*" : " ");
56 const RepTypeUnion rMask = rBit | rWord32 | rWord64 | rFloat64 | rTagged;
57 const RepTypeUnion tMask =
58 tBool | tInt32 | tUint32 | tInt64 | tUint64 | tNumber | tAny;
59 const RepType rPtr = kPointerSize == 4 ? rWord32 : rWord64;
61 // Contains logic related to changing the representation of values for constants
62 // and other nodes, as well as lowering Simplified->Machine operators.
63 // Eagerly folds any representation changes for constants.
64 class RepresentationChanger {
66 RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
67 MachineOperatorBuilder* machine, Isolate* isolate)
69 simplified_(simplified),
72 testing_type_errors_(false),
76 Node* GetRepresentationFor(Node* node, RepTypeUnion output_type,
77 RepTypeUnion use_type) {
78 if (!IsPowerOf2(output_type & rMask)) {
79 // There should be only one output representation.
80 return TypeError(node, output_type, use_type);
82 if ((use_type & rMask) == (output_type & rMask)) {
83 // Representations are the same. That's a no-op.
86 if (use_type & rTagged) {
87 return GetTaggedRepresentationFor(node, output_type);
88 } else if (use_type & rFloat64) {
89 return GetFloat64RepresentationFor(node, output_type);
90 } else if (use_type & rWord32) {
91 return GetWord32RepresentationFor(node, output_type);
92 } else if (use_type & rBit) {
93 return GetBitRepresentationFor(node, output_type);
94 } else if (use_type & rWord64) {
95 return GetWord64RepresentationFor(node, output_type);
101 Node* GetTaggedRepresentationFor(Node* node, RepTypeUnion output_type) {
102 // Eagerly fold representation changes for constants.
103 switch (node->opcode()) {
104 case IrOpcode::kNumberConstant:
105 case IrOpcode::kHeapConstant:
106 return node; // No change necessary.
107 case IrOpcode::kInt32Constant:
108 if (output_type & tUint32) {
109 uint32_t value = ValueOf<uint32_t>(node->op());
110 return jsgraph()->Constant(static_cast<double>(value));
111 } else if (output_type & tInt32) {
112 int32_t value = ValueOf<int32_t>(node->op());
113 return jsgraph()->Constant(value);
114 } else if (output_type & rBit) {
115 return ValueOf<int32_t>(node->op()) == 0 ? jsgraph()->FalseConstant()
116 : jsgraph()->TrueConstant();
118 return TypeError(node, output_type, rTagged);
120 case IrOpcode::kFloat64Constant:
121 return jsgraph()->Constant(ValueOf<double>(node->op()));
125 // Select the correct X -> Tagged operator.
127 if (output_type & rBit) {
128 op = simplified()->ChangeBitToBool();
129 } else if (output_type & rWord32) {
130 if (output_type & tUint32) {
131 op = simplified()->ChangeUint32ToTagged();
132 } else if (output_type & tInt32) {
133 op = simplified()->ChangeInt32ToTagged();
135 return TypeError(node, output_type, rTagged);
137 } else if (output_type & rFloat64) {
138 op = simplified()->ChangeFloat64ToTagged();
140 return TypeError(node, output_type, rTagged);
142 return jsgraph()->graph()->NewNode(op, node);
145 Node* GetFloat64RepresentationFor(Node* node, RepTypeUnion output_type) {
146 // Eagerly fold representation changes for constants.
147 switch (node->opcode()) {
148 case IrOpcode::kNumberConstant:
149 return jsgraph()->Float64Constant(ValueOf<double>(node->op()));
150 case IrOpcode::kInt32Constant:
151 if (output_type & tUint32) {
152 uint32_t value = ValueOf<uint32_t>(node->op());
153 return jsgraph()->Float64Constant(static_cast<double>(value));
155 int32_t value = ValueOf<int32_t>(node->op());
156 return jsgraph()->Float64Constant(value);
158 case IrOpcode::kFloat64Constant:
159 return node; // No change necessary.
163 // Select the correct X -> Float64 operator.
165 if (output_type & rWord32) {
166 if (output_type & tUint32) {
167 op = machine()->ChangeUint32ToFloat64();
168 } else if (output_type & tInt32) {
169 op = machine()->ChangeInt32ToFloat64();
171 return TypeError(node, output_type, rFloat64);
173 } else if (output_type & rTagged) {
174 op = simplified()->ChangeTaggedToFloat64();
176 return TypeError(node, output_type, rFloat64);
178 return jsgraph()->graph()->NewNode(op, node);
181 Node* GetWord32RepresentationFor(Node* node, RepTypeUnion output_type) {
182 // Eagerly fold representation changes for constants.
183 switch (node->opcode()) {
184 case IrOpcode::kInt32Constant:
185 return node; // No change necessary.
186 case IrOpcode::kNumberConstant:
187 case IrOpcode::kFloat64Constant: {
188 if (output_type & tUint32) {
189 int32_t value = static_cast<int32_t>(
190 static_cast<uint32_t>(ValueOf<double>(node->op())));
191 return jsgraph()->Int32Constant(value);
192 } else if (output_type & tInt32) {
193 int32_t value = FastD2I(ValueOf<double>(node->op()));
194 return jsgraph()->Int32Constant(value);
196 return TypeError(node, output_type, rWord32);
202 // Select the correct X -> Word32 operator.
204 if (output_type & rFloat64) {
205 if (output_type & tUint32) {
206 op = machine()->ChangeFloat64ToUint32();
207 } else if (output_type & tInt32) {
208 op = machine()->ChangeFloat64ToInt32();
210 return TypeError(node, output_type, rWord32);
212 } else if (output_type & rTagged) {
213 if (output_type & tUint32) {
214 op = simplified()->ChangeTaggedToUint32();
215 } else if (output_type & tInt32) {
216 op = simplified()->ChangeTaggedToInt32();
218 return TypeError(node, output_type, rWord32);
220 } else if (output_type & rBit) {
221 return node; // Sloppy comparison -> word32.
223 return TypeError(node, output_type, rWord32);
225 return jsgraph()->graph()->NewNode(op, node);
228 Node* GetBitRepresentationFor(Node* node, RepTypeUnion output_type) {
229 // Eagerly fold representation changes for constants.
230 switch (node->opcode()) {
231 case IrOpcode::kInt32Constant: {
232 int32_t value = ValueOf<int32_t>(node->op());
233 if (value == 0 || value == 1) return node;
234 return jsgraph()->OneConstant(); // value != 0
236 case IrOpcode::kHeapConstant: {
237 Handle<Object> handle = ValueOf<Handle<Object> >(node->op());
238 DCHECK(*handle == isolate()->heap()->true_value() ||
239 *handle == isolate()->heap()->false_value());
240 return jsgraph()->Int32Constant(
241 *handle == isolate()->heap()->true_value() ? 1 : 0);
246 // Select the correct X -> Bit operator.
248 if (output_type & rWord32) {
249 return node; // No change necessary.
250 } else if (output_type & rWord64) {
251 return node; // TODO(titzer): No change necessary, on 64-bit.
252 } else if (output_type & rTagged) {
253 op = simplified()->ChangeBoolToBit();
255 return TypeError(node, output_type, rBit);
257 return jsgraph()->graph()->NewNode(op, node);
260 Node* GetWord64RepresentationFor(Node* node, RepTypeUnion output_type) {
261 if (output_type & rBit) {
262 return node; // Sloppy comparison -> word64
264 // Can't really convert Word64 to anything else. Purported to be internal.
265 return TypeError(node, output_type, rWord64);
268 static RepType TypeForMachineType(MachineType rep) {
269 // TODO(titzer): merge MachineType and RepType.
279 case kMachineFloat64:
285 return static_cast<RepType>(0);
289 Operator* Int32OperatorFor(IrOpcode::Value opcode) {
291 case IrOpcode::kNumberAdd:
292 return machine()->Int32Add();
293 case IrOpcode::kNumberSubtract:
294 return machine()->Int32Sub();
295 case IrOpcode::kNumberEqual:
296 return machine()->Word32Equal();
297 case IrOpcode::kNumberLessThan:
298 return machine()->Int32LessThan();
299 case IrOpcode::kNumberLessThanOrEqual:
300 return machine()->Int32LessThanOrEqual();
307 Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
309 case IrOpcode::kNumberAdd:
310 return machine()->Int32Add();
311 case IrOpcode::kNumberSubtract:
312 return machine()->Int32Sub();
313 case IrOpcode::kNumberEqual:
314 return machine()->Word32Equal();
315 case IrOpcode::kNumberLessThan:
316 return machine()->Uint32LessThan();
317 case IrOpcode::kNumberLessThanOrEqual:
318 return machine()->Uint32LessThanOrEqual();
325 Operator* Float64OperatorFor(IrOpcode::Value opcode) {
327 case IrOpcode::kNumberAdd:
328 return machine()->Float64Add();
329 case IrOpcode::kNumberSubtract:
330 return machine()->Float64Sub();
331 case IrOpcode::kNumberMultiply:
332 return machine()->Float64Mul();
333 case IrOpcode::kNumberDivide:
334 return machine()->Float64Div();
335 case IrOpcode::kNumberModulus:
336 return machine()->Float64Mod();
337 case IrOpcode::kNumberEqual:
338 return machine()->Float64Equal();
339 case IrOpcode::kNumberLessThan:
340 return machine()->Float64LessThan();
341 case IrOpcode::kNumberLessThanOrEqual:
342 return machine()->Float64LessThanOrEqual();
349 RepType TypeForField(const FieldAccess& access) {
350 RepType tElement = static_cast<RepType>(0); // TODO(titzer)
351 RepType rElement = TypeForMachineType(access.representation);
352 return static_cast<RepType>(tElement | rElement);
355 RepType TypeForElement(const ElementAccess& access) {
356 RepType tElement = static_cast<RepType>(0); // TODO(titzer)
357 RepType rElement = TypeForMachineType(access.representation);
358 return static_cast<RepType>(tElement | rElement);
361 RepType TypeForBasePointer(const FieldAccess& access) {
362 if (access.tag() != 0) return static_cast<RepType>(tAny | rTagged);
363 return kPointerSize == 8 ? rWord64 : rWord32;
366 RepType TypeForBasePointer(const ElementAccess& access) {
367 if (access.tag() != 0) return static_cast<RepType>(tAny | rTagged);
368 return kPointerSize == 8 ? rWord64 : rWord32;
371 RepType TypeFromUpperBound(Type* type) {
372 if (type->Is(Type::None()))
373 return tAny; // TODO(titzer): should be an error
374 if (type->Is(Type::Signed32())) return tInt32;
375 if (type->Is(Type::Unsigned32())) return tUint32;
376 if (type->Is(Type::Number())) return tNumber;
377 if (type->Is(Type::Boolean())) return tBool;
383 SimplifiedOperatorBuilder* simplified_;
384 MachineOperatorBuilder* machine_;
387 friend class RepresentationChangerTester; // accesses the below fields.
389 bool testing_type_errors_; // If {true}, don't abort on a type error.
390 bool type_error_; // Set when a type error is detected.
392 Node* TypeError(Node* node, RepTypeUnion output_type, RepTypeUnion use) {
394 if (!testing_type_errors_) {
395 char buf1[REP_TYPE_STRLEN];
396 char buf2[REP_TYPE_STRLEN];
397 RenderRepTypeUnion(buf1, output_type);
398 RenderRepTypeUnion(buf2, use);
399 V8_Fatal(__FILE__, __LINE__,
400 "RepresentationChangerError: node #%d:%s of rep"
401 "%s cannot be changed to rep%s",
402 node->id(), node->op()->mnemonic(), buf1, buf2);
407 JSGraph* jsgraph() { return jsgraph_; }
408 Isolate* isolate() { return isolate_; }
409 SimplifiedOperatorBuilder* simplified() { return simplified_; }
410 MachineOperatorBuilder* machine() { return machine_; }
414 } // namespace v8::internal::compiler
416 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_