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" 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 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. 21 class RepresentationChanger { 22 public: RepresentationChanger(JSGraph * jsgraph,SimplifiedOperatorBuilder * simplified,Isolate * isolate)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 GetRepresentationFor(Node * node,MachineTypeUnion output_type,MachineTypeUnion use_type)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 GetTaggedRepresentationFor(Node * node,MachineTypeUnion output_type)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 GetFloat64RepresentationFor(Node * node,MachineTypeUnion output_type)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 GetWord32RepresentationFor(Node * node,MachineTypeUnion output_type,bool use_unsigned)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 GetBitRepresentationFor(Node * node,MachineTypeUnion output_type)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 GetWord64RepresentationFor(Node * node,MachineTypeUnion output_type)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 Int32OperatorFor(IrOpcode::Value opcode)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 Uint32OperatorFor(IrOpcode::Value opcode)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 Float64OperatorFor(IrOpcode::Value opcode)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 TypeForBasePointer(const FieldAccess & access)304 MachineType TypeForBasePointer(const FieldAccess& access) { 305 return access.tag() != 0 ? kMachAnyTagged : kMachPtr; 306 } 307 TypeForBasePointer(const ElementAccess & access)308 MachineType TypeForBasePointer(const ElementAccess& access) { 309 return access.tag() != 0 ? kMachAnyTagged : kMachPtr; 310 } 311 TypeFromUpperBound(Type * type)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 TypeError(Node * node,MachineTypeUnion output_type,MachineTypeUnion use)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 jsgraph()351 JSGraph* jsgraph() { return jsgraph_; } isolate()352 Isolate* isolate() { return isolate_; } simplified()353 SimplifiedOperatorBuilder* simplified() { return simplified_; } machine()354 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } 355 }; 356 } 357 } 358 } // namespace v8::internal::compiler 359 360 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ 361