blob: aaa248eab86f65e29e8284ab091500d4f29abbc7 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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"
9#include "src/compiler/js-graph.h"
10#include "src/compiler/machine-operator.h"
11#include "src/compiler/node-properties-inl.h"
12#include "src/compiler/simplified-operator.h"
13
14namespace v8 {
15namespace internal {
16namespace 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.
21class RepresentationChanger {
22 public:
23 RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
24 Isolate* isolate)
25 : jsgraph_(jsgraph),
26 simplified_(simplified),
27 isolate_(isolate),
28 testing_type_errors_(false),
29 type_error_(false) {}
30
31 // TODO(titzer): should Word64 also be implicitly convertable to others?
32 static const MachineTypeUnion rWord =
33 kRepBit | kRepWord8 | kRepWord16 | kRepWord32;
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 & kRepFloat64) {
55 return GetFloat64RepresentationFor(node, output_type);
56 } else if (use_type & kRepFloat32) {
57 return TypeError(node, output_type, use_type); // TODO(titzer): handle
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 default:
92 break;
93 }
94 // Select the correct X -> Tagged operator.
95 const Operator* op;
96 if (output_type & kRepBit) {
97 op = simplified()->ChangeBitToBool();
98 } else if (output_type & rWord) {
99 if (output_type & kTypeUint32) {
100 op = simplified()->ChangeUint32ToTagged();
101 } else if (output_type & kTypeInt32) {
102 op = simplified()->ChangeInt32ToTagged();
103 } else {
104 return TypeError(node, output_type, kRepTagged);
105 }
106 } else if (output_type & kRepFloat64) {
107 op = simplified()->ChangeFloat64ToTagged();
108 } else {
109 return TypeError(node, output_type, kRepTagged);
110 }
111 return jsgraph()->graph()->NewNode(op, node);
112 }
113
114 Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
115 // Eagerly fold representation changes for constants.
116 switch (node->opcode()) {
117 case IrOpcode::kNumberConstant:
118 return jsgraph()->Float64Constant(OpParameter<double>(node));
119 case IrOpcode::kInt32Constant:
120 if (output_type & kTypeUint32) {
121 uint32_t value = OpParameter<uint32_t>(node);
122 return jsgraph()->Float64Constant(static_cast<double>(value));
123 } else {
124 int32_t value = OpParameter<int32_t>(node);
125 return jsgraph()->Float64Constant(value);
126 }
127 case IrOpcode::kFloat64Constant:
128 return node; // No change necessary.
129 default:
130 break;
131 }
132 // Select the correct X -> Float64 operator.
133 const Operator* op;
134 if (output_type & kRepBit) {
135 return TypeError(node, output_type, kRepFloat64);
136 } else if (output_type & rWord) {
137 if (output_type & kTypeUint32) {
138 op = machine()->ChangeUint32ToFloat64();
139 } else {
140 op = machine()->ChangeInt32ToFloat64();
141 }
142 } else if (output_type & kRepTagged) {
143 op = simplified()->ChangeTaggedToFloat64();
144 } else {
145 return TypeError(node, output_type, kRepFloat64);
146 }
147 return jsgraph()->graph()->NewNode(op, node);
148 }
149
150 Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
151 bool use_unsigned) {
152 // Eagerly fold representation changes for constants.
153 switch (node->opcode()) {
154 case IrOpcode::kInt32Constant:
155 return node; // No change necessary.
156 case IrOpcode::kNumberConstant:
157 case IrOpcode::kFloat64Constant: {
158 double value = OpParameter<double>(node);
159 if (value < 0) {
160 DCHECK(IsInt32Double(value));
161 int32_t iv = static_cast<int32_t>(value);
162 return jsgraph()->Int32Constant(iv);
163 } else {
164 DCHECK(IsUint32Double(value));
165 int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
166 return jsgraph()->Int32Constant(iv);
167 }
168 }
169 default:
170 break;
171 }
172 // Select the correct X -> Word32 operator.
173 const Operator* op = NULL;
174 if (output_type & kRepFloat64) {
175 if (output_type & kTypeUint32 || use_unsigned) {
176 op = machine()->ChangeFloat64ToUint32();
177 } else {
178 op = machine()->ChangeFloat64ToInt32();
179 }
180 } else if (output_type & kRepTagged) {
181 if (output_type & kTypeUint32 || use_unsigned) {
182 op = simplified()->ChangeTaggedToUint32();
183 } else {
184 op = simplified()->ChangeTaggedToInt32();
185 }
186 } else {
187 return TypeError(node, output_type, kRepWord32);
188 }
189 return jsgraph()->graph()->NewNode(op, node);
190 }
191
192 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) {
193 // Eagerly fold representation changes for constants.
194 switch (node->opcode()) {
195 case IrOpcode::kInt32Constant: {
196 int32_t value = OpParameter<int32_t>(node);
197 if (value == 0 || value == 1) return node;
198 return jsgraph()->OneConstant(); // value != 0
199 }
200 case IrOpcode::kHeapConstant: {
201 Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
202 DCHECK(*handle == isolate()->heap()->true_value() ||
203 *handle == isolate()->heap()->false_value());
204 return jsgraph()->Int32Constant(
205 *handle == isolate()->heap()->true_value() ? 1 : 0);
206 }
207 default:
208 break;
209 }
210 // Select the correct X -> Bit operator.
211 const Operator* op;
212 if (output_type & rWord) {
213 return node; // No change necessary.
214 } else if (output_type & kRepWord64) {
215 return node; // TODO(titzer): No change necessary, on 64-bit.
216 } else if (output_type & kRepTagged) {
217 op = simplified()->ChangeBoolToBit();
218 } else {
219 return TypeError(node, output_type, kRepBit);
220 }
221 return jsgraph()->graph()->NewNode(op, node);
222 }
223
224 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
225 if (output_type & kRepBit) {
226 return node; // Sloppy comparison -> word64
227 }
228 // Can't really convert Word64 to anything else. Purported to be internal.
229 return TypeError(node, output_type, kRepWord64);
230 }
231
232 const Operator* Int32OperatorFor(IrOpcode::Value opcode) {
233 switch (opcode) {
234 case IrOpcode::kNumberAdd:
235 return machine()->Int32Add();
236 case IrOpcode::kNumberSubtract:
237 return machine()->Int32Sub();
238 case IrOpcode::kNumberMultiply:
239 return machine()->Int32Mul();
240 case IrOpcode::kNumberDivide:
241 return machine()->Int32Div();
242 case IrOpcode::kNumberModulus:
243 return machine()->Int32Mod();
244 case IrOpcode::kNumberEqual:
245 return machine()->Word32Equal();
246 case IrOpcode::kNumberLessThan:
247 return machine()->Int32LessThan();
248 case IrOpcode::kNumberLessThanOrEqual:
249 return machine()->Int32LessThanOrEqual();
250 default:
251 UNREACHABLE();
252 return NULL;
253 }
254 }
255
256 const Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
257 switch (opcode) {
258 case IrOpcode::kNumberAdd:
259 return machine()->Int32Add();
260 case IrOpcode::kNumberSubtract:
261 return machine()->Int32Sub();
262 case IrOpcode::kNumberMultiply:
263 return machine()->Int32Mul();
264 case IrOpcode::kNumberDivide:
265 return machine()->Int32UDiv();
266 case IrOpcode::kNumberModulus:
267 return machine()->Int32UMod();
268 case IrOpcode::kNumberEqual:
269 return machine()->Word32Equal();
270 case IrOpcode::kNumberLessThan:
271 return machine()->Uint32LessThan();
272 case IrOpcode::kNumberLessThanOrEqual:
273 return machine()->Uint32LessThanOrEqual();
274 default:
275 UNREACHABLE();
276 return NULL;
277 }
278 }
279
280 const Operator* Float64OperatorFor(IrOpcode::Value opcode) {
281 switch (opcode) {
282 case IrOpcode::kNumberAdd:
283 return machine()->Float64Add();
284 case IrOpcode::kNumberSubtract:
285 return machine()->Float64Sub();
286 case IrOpcode::kNumberMultiply:
287 return machine()->Float64Mul();
288 case IrOpcode::kNumberDivide:
289 return machine()->Float64Div();
290 case IrOpcode::kNumberModulus:
291 return machine()->Float64Mod();
292 case IrOpcode::kNumberEqual:
293 return machine()->Float64Equal();
294 case IrOpcode::kNumberLessThan:
295 return machine()->Float64LessThan();
296 case IrOpcode::kNumberLessThanOrEqual:
297 return machine()->Float64LessThanOrEqual();
298 default:
299 UNREACHABLE();
300 return NULL;
301 }
302 }
303
304 MachineType TypeForBasePointer(const FieldAccess& access) {
305 return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
306 }
307
308 MachineType TypeForBasePointer(const ElementAccess& access) {
309 return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
310 }
311
312 MachineType TypeFromUpperBound(Type* type) {
313 if (type->Is(Type::None()))
314 return kTypeAny; // TODO(titzer): should be an error
315 if (type->Is(Type::Signed32())) return kTypeInt32;
316 if (type->Is(Type::Unsigned32())) return kTypeUint32;
317 if (type->Is(Type::Number())) return kTypeNumber;
318 if (type->Is(Type::Boolean())) return kTypeBool;
319 return kTypeAny;
320 }
321
322 private:
323 JSGraph* jsgraph_;
324 SimplifiedOperatorBuilder* simplified_;
325 Isolate* isolate_;
326
327 friend class RepresentationChangerTester; // accesses the below fields.
328
329 bool testing_type_errors_; // If {true}, don't abort on a type error.
330 bool type_error_; // Set when a type error is detected.
331
332 Node* TypeError(Node* node, MachineTypeUnion output_type,
333 MachineTypeUnion use) {
334 type_error_ = true;
335 if (!testing_type_errors_) {
336 OStringStream out_str;
337 out_str << static_cast<MachineType>(output_type);
338
339 OStringStream use_str;
340 use_str << static_cast<MachineType>(use);
341
342 V8_Fatal(__FILE__, __LINE__,
343 "RepresentationChangerError: node #%d:%s of "
344 "%s cannot be changed to %s",
345 node->id(), node->op()->mnemonic(), out_str.c_str(),
346 use_str.c_str());
347 }
348 return node;
349 }
350
351 JSGraph* jsgraph() { return jsgraph_; }
352 Isolate* isolate() { return isolate_; }
353 SimplifiedOperatorBuilder* simplified() { return simplified_; }
354 MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
355};
356}
357}
358} // namespace v8::internal::compiler
359
360#endif // V8_COMPILER_REPRESENTATION_CHANGE_H_