| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/simplified-lowering.h" | 5 #include "src/compiler/simplified-lowering.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 // 1. During propagation, the use info is used to inform the input node | 65 // 1. During propagation, the use info is used to inform the input node |
| 66 // about what part of the input is used (we call this truncation) and what | 66 // about what part of the input is used (we call this truncation) and what |
| 67 // is the preferred representation. | 67 // is the preferred representation. |
| 68 // | 68 // |
| 69 // 2. During lowering, the use info is used to properly convert the input | 69 // 2. During lowering, the use info is used to properly convert the input |
| 70 // to the preferred representation. The preferred representation might be | 70 // to the preferred representation. The preferred representation might be |
| 71 // insufficient to do the conversion (e.g. word32->float64 conv), so we also | 71 // insufficient to do the conversion (e.g. word32->float64 conv), so we also |
| 72 // need the signedness information to produce the correct value. | 72 // need the signedness information to produce the correct value. |
| 73 class UseInfo { | 73 class UseInfo { |
| 74 public: | 74 public: |
| 75 // Constructors | 75 UseInfo(MachineType preferred, Truncation truncation) |
| 76 // ================================================================ | 76 : preferred_(preferred), truncation_(truncation) { |
| 77 | 77 DCHECK(preferred == (preferred & kRepMask)); |
| 78 // Uses truncating to the preferred representation. | 78 } |
| 79 static UseInfo TruncatingWord32() { | 79 static UseInfo TruncatingWord32() { |
| 80 return UseInfo(kTypeInt32 | kTypeUint32 | kRepWord32); | 80 return UseInfo(kRepWord32, Truncation::Word32()); |
| 81 } | 81 } |
| 82 static UseInfo TruncatingWord64() { | 82 static UseInfo TruncatingWord64() { |
| 83 return UseInfo(kTypeInt64 | kTypeUint64 | kRepWord64); | 83 return UseInfo(kRepWord64, Truncation::Word64()); |
| 84 } | 84 } |
| 85 static UseInfo Bool() { return UseInfo(kMachBool); } | 85 static UseInfo Bool() { return UseInfo(kRepBit, Truncation::Bool()); } |
| 86 static UseInfo Float32() { return UseInfo(kMachFloat32); } | 86 static UseInfo Float32() { |
| 87 static UseInfo Float64() { return UseInfo(kMachFloat64); } | 87 return UseInfo(kRepFloat32, Truncation::Float32()); |
| 88 } |
| 89 static UseInfo Float64() { |
| 90 return UseInfo(kRepFloat64, Truncation::Float64()); |
| 91 } |
| 88 static UseInfo PointerInt() { | 92 static UseInfo PointerInt() { |
| 89 return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64(); | 93 return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64(); |
| 90 } | 94 } |
| 95 static UseInfo AnyTagged() { return UseInfo(kRepTagged, Truncation::Any()); } |
| 91 | 96 |
| 92 // Non-truncating uses. | 97 // Undetermined representation. |
| 93 static UseInfo AnyTagged() { return UseInfo(kMachAnyTagged); } | 98 static UseInfo Any() { return UseInfo(kMachNone, Truncation::Any()); } |
| 94 static UseInfo Any() { return UseInfo(kTypeAny); } | 99 static UseInfo None() { return UseInfo(kMachNone, Truncation::None()); } |
| 95 | 100 |
| 96 // Ignored-value 'use'. | 101 // Truncation to a representation that is smaller than the preferred |
| 97 static UseInfo None() { return UseInfo(kMachNone); } | |
| 98 | |
| 99 // Truncating to a representation that is smaller than the preferred | |
| 100 // one. | 102 // one. |
| 101 static UseInfo Float64TruncatingToWord32() { | 103 static UseInfo Float64TruncatingToWord32() { |
| 102 return UseInfo(kRepFloat64 | kTypeInt32 | kTypeUint32); | 104 return UseInfo(kRepFloat64, Truncation::Word32()); |
| 103 } | 105 } |
| 104 static UseInfo Word64TruncatingToWord32() { | 106 static UseInfo Word64TruncatingToWord32() { |
| 105 return UseInfo(kRepWord64 | kTypeInt32 | kTypeUint32); | 107 return UseInfo(kRepWord64, Truncation::Word32()); |
| 106 } | 108 } |
| 107 static UseInfo AnyTruncatingToBool() { return UseInfo(kTypeBool); } | 109 static UseInfo AnyTruncatingToBool() { |
| 108 | 110 return UseInfo(kMachNone, Truncation::Bool()); |
| 109 UseInfo(MachineTypeUnion representation, MachineTypeUnion truncation) | |
| 110 : type_(representation | truncation) { | |
| 111 DCHECK(base::bits::CountPopulation32(representation & kRepMask) == 1); | |
| 112 DCHECK((representation & kTypeMask) == 0); | |
| 113 DCHECK((truncation & kRepMask) == 0); | |
| 114 // TODO(jarin) Check/normalize truncation? | |
| 115 } | 111 } |
| 116 | 112 |
| 117 // Queries | 113 MachineType preferred() const { return preferred_; } |
| 118 // ================================================================ | 114 Truncation truncation() const { return truncation_; } |
| 119 MachineType GetRepresentation() const { | |
| 120 return static_cast<MachineType>(type_ & kRepMask); | |
| 121 } | |
| 122 | |
| 123 // This should only be used by the Enqueue method. | |
| 124 MachineTypeUnion machine_type() const { return type_; } | |
| 125 | 115 |
| 126 private: | 116 private: |
| 127 explicit UseInfo(MachineTypeUnion type) : type_(type) {} | 117 MachineType preferred_; |
| 128 | 118 Truncation truncation_; |
| 129 MachineTypeUnion type_; | |
| 130 }; | 119 }; |
| 131 | 120 |
| 132 | 121 |
| 133 UseInfo UseInfoFromMachineType(MachineType type) { | 122 UseInfo UseInfoFromMachineType(MachineType type) { |
| 134 MachineTypeUnion rep = RepresentationOf(type); | 123 MachineTypeUnion rep = RepresentationOf(type); |
| 135 DCHECK((rep & kTypeMask) == 0); | 124 DCHECK((rep & kTypeMask) == 0); |
| 125 |
| 136 if (rep & kRepTagged) return UseInfo::AnyTagged(); | 126 if (rep & kRepTagged) return UseInfo::AnyTagged(); |
| 137 if (rep & kRepFloat64) { | 127 if (rep & kRepFloat64) { |
| 138 DCHECK((rep & kRepWord64) == 0); | 128 DCHECK((rep & kRepWord64) == 0); |
| 139 return UseInfo::Float64(); | 129 return UseInfo::Float64(); |
| 140 } | 130 } |
| 141 if (rep & kRepFloat32) { | 131 if (rep & kRepFloat32) { |
| 142 if (rep == kRepFloat32) return UseInfo::Float32(); | 132 if (rep == kRepFloat32) return UseInfo::Float32(); |
| 143 return UseInfo::AnyTagged(); | 133 return UseInfo::AnyTagged(); |
| 144 } | 134 } |
| 145 if (rep & kRepWord64) { | 135 if (rep & kRepWord64) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 162 UseInfo UseInfoForBasePointer(const ElementAccess& access) { | 152 UseInfo UseInfoForBasePointer(const ElementAccess& access) { |
| 163 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt(); | 153 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt(); |
| 164 } | 154 } |
| 165 | 155 |
| 166 } // namespace | 156 } // namespace |
| 167 | 157 |
| 168 | 158 |
| 169 class RepresentationSelector { | 159 class RepresentationSelector { |
| 170 public: | 160 public: |
| 171 // Information for each node tracked during the fixpoint. | 161 // Information for each node tracked during the fixpoint. |
| 172 struct NodeInfo { | 162 class NodeInfo { |
| 173 MachineTypeUnion use : 15; // Union of all usages for the node. | 163 public: |
| 174 bool queued : 1; // Bookkeeping for the traversal. | 164 // Adds new use to the node. Returns true if something has changed |
| 175 bool visited : 1; // Bookkeeping for the traversal. | 165 // and the node has to be requeued. |
| 176 MachineTypeUnion output : 15; // Output type of the node. | 166 bool AddUse(UseInfo info) { |
| 167 Truncation old_truncation = truncation_; |
| 168 truncation_ = Truncation::Generalize(truncation_, info.truncation()); |
| 169 return truncation_ != old_truncation; |
| 170 } |
| 171 |
| 172 void set_queued(bool value) { queued_ = value; } |
| 173 bool queued() const { return queued_; } |
| 174 void set_visited() { visited_ = true; } |
| 175 bool visited() const { return visited_; } |
| 176 Truncation truncation() const { return truncation_; } |
| 177 void set_output_type(MachineTypeUnion type) { output_ = type; } |
| 178 MachineTypeUnion output_type() const { return output_; } |
| 179 |
| 180 private: |
| 181 bool queued_ = false; // Bookkeeping for the traversal. |
| 182 bool visited_ = false; // Bookkeeping for the traversal. |
| 183 MachineTypeUnion output_ = kMachNone; // Output type of the node. |
| 184 Truncation truncation_ = Truncation::None(); // Information about uses. |
| 177 }; | 185 }; |
| 178 | 186 |
| 179 RepresentationSelector(JSGraph* jsgraph, Zone* zone, | 187 RepresentationSelector(JSGraph* jsgraph, Zone* zone, |
| 180 RepresentationChanger* changer, | 188 RepresentationChanger* changer, |
| 181 SourcePositionTable* source_positions) | 189 SourcePositionTable* source_positions) |
| 182 : jsgraph_(jsgraph), | 190 : jsgraph_(jsgraph), |
| 183 count_(jsgraph->graph()->NodeCount()), | 191 count_(jsgraph->graph()->NodeCount()), |
| 184 info_(zone->NewArray<NodeInfo>(count_)), | 192 info_(count_, zone), |
| 185 nodes_(zone), | 193 nodes_(zone), |
| 186 replacements_(zone), | 194 replacements_(zone), |
| 187 phase_(PROPAGATE), | 195 phase_(PROPAGATE), |
| 188 changer_(changer), | 196 changer_(changer), |
| 189 queue_(zone), | 197 queue_(zone), |
| 190 source_positions_(source_positions) { | 198 source_positions_(source_positions) { |
| 191 memset(info_, 0, sizeof(NodeInfo) * count_); | |
| 192 | |
| 193 safe_int_additive_range_ = | 199 safe_int_additive_range_ = |
| 194 Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone); | 200 Type::Range(-std::pow(2.0, 52.0), std::pow(2.0, 52.0), zone); |
| 195 } | 201 } |
| 196 | 202 |
| 197 void Run(SimplifiedLowering* lowering) { | 203 void Run(SimplifiedLowering* lowering) { |
| 198 // Run propagation phase to a fixpoint. | 204 // Run propagation phase to a fixpoint. |
| 199 TRACE("--{Propagation phase}--\n"); | 205 TRACE("--{Propagation phase}--\n"); |
| 200 phase_ = PROPAGATE; | 206 phase_ = PROPAGATE; |
| 201 Enqueue(jsgraph_->graph()->end()); | 207 Enqueue(jsgraph_->graph()->end()); |
| 202 // Process nodes from the queue until it is empty. | 208 // Process nodes from the queue until it is empty. |
| 203 while (!queue_.empty()) { | 209 while (!queue_.empty()) { |
| 204 Node* node = queue_.front(); | 210 Node* node = queue_.front(); |
| 205 NodeInfo* info = GetInfo(node); | 211 NodeInfo* info = GetInfo(node); |
| 206 queue_.pop(); | 212 queue_.pop(); |
| 207 info->queued = false; | 213 info->set_queued(false); |
| 208 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic()); | 214 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic()); |
| 209 VisitNode(node, info->use, NULL); | 215 VisitNode(node, info->truncation(), NULL); |
| 210 TRACE(" ==> output "); | 216 TRACE(" ==> output "); |
| 211 PrintInfo(info->output); | 217 PrintInfo(info->output_type()); |
| 212 TRACE("\n"); | 218 TRACE("\n"); |
| 213 } | 219 } |
| 214 | 220 |
| 215 // Run lowering and change insertion phase. | 221 // Run lowering and change insertion phase. |
| 216 TRACE("--{Simplified lowering phase}--\n"); | 222 TRACE("--{Simplified lowering phase}--\n"); |
| 217 phase_ = LOWER; | 223 phase_ = LOWER; |
| 218 // Process nodes from the collected {nodes_} vector. | 224 // Process nodes from the collected {nodes_} vector. |
| 219 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) { | 225 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) { |
| 220 Node* node = *i; | 226 Node* node = *i; |
| 227 NodeInfo* info = GetInfo(node); |
| 221 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic()); | 228 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic()); |
| 222 // Reuse {VisitNode()} so the representation rules are in one place. | 229 // Reuse {VisitNode()} so the representation rules are in one place. |
| 223 SourcePositionTable::Scope scope( | 230 SourcePositionTable::Scope scope( |
| 224 source_positions_, source_positions_->GetSourcePosition(node)); | 231 source_positions_, source_positions_->GetSourcePosition(node)); |
| 225 VisitNode(node, GetUseInfo(node), lowering); | 232 VisitNode(node, info->truncation(), lowering); |
| 226 } | 233 } |
| 227 | 234 |
| 228 // Perform the final replacements. | 235 // Perform the final replacements. |
| 229 for (NodeVector::iterator i = replacements_.begin(); | 236 for (NodeVector::iterator i = replacements_.begin(); |
| 230 i != replacements_.end(); ++i) { | 237 i != replacements_.end(); ++i) { |
| 231 Node* node = *i; | 238 Node* node = *i; |
| 232 Node* replacement = *(++i); | 239 Node* replacement = *(++i); |
| 233 node->ReplaceUses(replacement); | 240 node->ReplaceUses(replacement); |
| 234 // We also need to replace the node in the rest of the vector. | 241 // We also need to replace the node in the rest of the vector. |
| 235 for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) { | 242 for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) { |
| 236 ++j; | 243 ++j; |
| 237 if (*j == node) *j = replacement; | 244 if (*j == node) *j = replacement; |
| 238 } | 245 } |
| 239 } | 246 } |
| 240 } | 247 } |
| 241 | 248 |
| 242 // Enqueue {node} if the {use} contains new information for that node. | 249 // Enqueue {node} if the {use} contains new information for that node. |
| 243 // Add {node} to {nodes_} if this is the first time it's been visited. | 250 // Add {node} to {nodes_} if this is the first time it's been visited. |
| 244 void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) { | 251 void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) { |
| 245 MachineTypeUnion use = use_info.machine_type(); | |
| 246 | |
| 247 if (phase_ != PROPAGATE) return; | 252 if (phase_ != PROPAGATE) return; |
| 248 NodeInfo* info = GetInfo(node); | 253 NodeInfo* info = GetInfo(node); |
| 249 if (!info->visited) { | 254 if (!info->visited()) { |
| 250 // First visit of this node. | 255 // First visit of this node. |
| 251 info->visited = true; | 256 info->set_visited(); |
| 252 info->queued = true; | 257 info->set_queued(true); |
| 253 nodes_.push_back(node); | 258 nodes_.push_back(node); |
| 254 queue_.push(node); | 259 queue_.push(node); |
| 255 TRACE(" initial: "); | 260 TRACE(" initial: "); |
| 256 info->use |= use; | 261 info->AddUse(use_info); |
| 257 PrintUseInfo(node); | 262 PrintTruncation(info->truncation()); |
| 258 return; | 263 return; |
| 259 } | 264 } |
| 260 TRACE(" queue?: "); | 265 TRACE(" queue?: "); |
| 261 PrintUseInfo(node); | 266 PrintTruncation(info->truncation()); |
| 262 if ((info->use & use) != use) { | 267 if (info->AddUse(use_info)) { |
| 263 // New usage information for the node is available. | 268 // New usage information for the node is available. |
| 264 if (!info->queued) { | 269 if (!info->queued()) { |
| 265 queue_.push(node); | 270 queue_.push(node); |
| 266 info->queued = true; | 271 info->set_queued(true); |
| 267 TRACE(" added: "); | 272 TRACE(" added: "); |
| 268 } else { | 273 } else { |
| 269 TRACE(" inqueue: "); | 274 TRACE(" inqueue: "); |
| 270 } | 275 } |
| 271 info->use |= use; | 276 PrintTruncation(info->truncation()); |
| 272 PrintUseInfo(node); | |
| 273 } | 277 } |
| 274 } | 278 } |
| 275 | 279 |
| 276 bool lower() { return phase_ == LOWER; } | 280 bool lower() { return phase_ == LOWER; } |
| 277 | 281 |
| 278 void SetOutput(Node* node, MachineTypeUnion output) { | 282 void SetOutput(Node* node, MachineTypeUnion output) { |
| 279 // Every node should have at most one output representation. Note that | 283 // Every node should have at most one output representation. Note that |
| 280 // phis can have 0, if they have not been used in a representation-inducing | 284 // phis can have 0, if they have not been used in a representation-inducing |
| 281 // instruction. | 285 // instruction. |
| 282 DCHECK((output & kRepMask) == 0 || | 286 DCHECK((output & kRepMask) == 0 || |
| 283 base::bits::IsPowerOfTwo32(output & kRepMask)); | 287 base::bits::IsPowerOfTwo32(output & kRepMask)); |
| 284 GetInfo(node)->output = output; | 288 GetInfo(node)->set_output_type(output); |
| 285 } | 289 } |
| 286 | 290 |
| 287 bool BothInputsAre(Node* node, Type* type) { | 291 bool BothInputsAre(Node* node, Type* type) { |
| 288 DCHECK_EQ(2, node->InputCount()); | 292 DCHECK_EQ(2, node->InputCount()); |
| 289 return NodeProperties::GetType(node->InputAt(0))->Is(type) && | 293 return NodeProperties::GetType(node->InputAt(0))->Is(type) && |
| 290 NodeProperties::GetType(node->InputAt(1))->Is(type); | 294 NodeProperties::GetType(node->InputAt(1))->Is(type); |
| 291 } | 295 } |
| 292 | 296 |
| 293 void ProcessTruncateWord32Input(Node* node, int index) { | 297 void ProcessTruncateWord32Input(Node* node, int index) { |
| 294 Node* input = node->InputAt(index); | 298 Node* input = node->InputAt(index); |
| 295 if (phase_ == PROPAGATE) { | 299 if (phase_ == PROPAGATE) { |
| 296 // In the propagate phase, propagate the usage information backward. | 300 // In the propagate phase, propagate the usage information backward. |
| 297 Enqueue(input, UseInfo::TruncatingWord32()); | 301 Enqueue(input, UseInfo::TruncatingWord32()); |
| 298 } else { | 302 } else { |
| 299 // In the change phase, insert a change before the use if necessary. | 303 // In the change phase, insert a change before the use if necessary. |
| 300 MachineTypeUnion output = GetInfo(input)->output; | 304 MachineTypeUnion output = GetInfo(input)->output_type(); |
| 301 if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) { | 305 if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) { |
| 302 // Output representation doesn't match usage. | 306 // Output representation doesn't match usage. |
| 303 TRACE(" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(), | 307 TRACE(" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(), |
| 304 node->op()->mnemonic(), index, input->id(), | 308 node->op()->mnemonic(), index, input->id(), |
| 305 input->op()->mnemonic()); | 309 input->op()->mnemonic()); |
| 306 TRACE(" from "); | 310 TRACE(" from "); |
| 307 PrintInfo(output); | 311 PrintInfo(output); |
| 308 TRACE("\n"); | 312 TRACE("\n"); |
| 309 Node* n = changer_->GetTruncatedWord32For(input, output); | 313 Node* n = changer_->GetTruncatedWord32For(input, output); |
| 310 node->ReplaceInput(index, n); | 314 node->ReplaceInput(index, n); |
| 311 } | 315 } |
| 312 } | 316 } |
| 313 } | 317 } |
| 314 | 318 |
| 315 void EnqueueInputUse(Node* node, int index, UseInfo use) { | 319 void EnqueueInputUse(Node* node, int index, UseInfo use) { |
| 316 Enqueue(node->InputAt(index), use); | 320 Enqueue(node->InputAt(index), use); |
| 317 } | 321 } |
| 318 | 322 |
| 319 void ConvertInput(Node* node, int index, UseInfo use) { | 323 void ConvertInput(Node* node, int index, UseInfo use) { |
| 320 Node* input = node->InputAt(index); | 324 Node* input = node->InputAt(index); |
| 321 // In the change phase, insert a change before the use if necessary. | 325 // In the change phase, insert a change before the use if necessary. |
| 322 if (use.GetRepresentation() == kMachNone) | 326 if (use.preferred() == kMachNone) |
| 323 return; // No input requirement on the use. | 327 return; // No input requirement on the use. |
| 324 MachineTypeUnion output = GetInfo(input)->output; | 328 MachineTypeUnion output = GetInfo(input)->output_type(); |
| 325 if ((output & kRepMask) != use.GetRepresentation()) { | 329 if ((output & kRepMask) != use.preferred()) { |
| 326 // Output representation doesn't match usage. | 330 // Output representation doesn't match usage. |
| 327 TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(), | 331 TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(), |
| 328 index, input->id(), input->op()->mnemonic()); | 332 index, input->id(), input->op()->mnemonic()); |
| 329 TRACE(" from "); | 333 TRACE(" from "); |
| 330 PrintInfo(output); | 334 PrintInfo(output); |
| 331 TRACE(" to "); | 335 TRACE(" to "); |
| 332 PrintUseInfo(use); | 336 PrintUseInfo(use); |
| 333 TRACE("\n"); | 337 TRACE("\n"); |
| 334 Node* n = | 338 Node* n = changer_->GetRepresentationFor(input, output, use.preferred(), |
| 335 changer_->GetRepresentationFor(input, output, use.machine_type()); | 339 use.truncation()); |
| 336 node->ReplaceInput(index, n); | 340 node->ReplaceInput(index, n); |
| 337 } | 341 } |
| 338 } | 342 } |
| 339 | 343 |
| 340 void ProcessInput(Node* node, int index, UseInfo use) { | 344 void ProcessInput(Node* node, int index, UseInfo use) { |
| 341 if (phase_ == PROPAGATE) { | 345 if (phase_ == PROPAGATE) { |
| 342 EnqueueInputUse(node, index, use); | 346 EnqueueInputUse(node, index, use); |
| 343 } else { | 347 } else { |
| 344 ConvertInput(node, index, use); | 348 ConvertInput(node, index, use); |
| 345 } | 349 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 VisitBinop(node, UseInfo::TruncatingWord32(), kMachBool); | 437 VisitBinop(node, UseInfo::TruncatingWord32(), kMachBool); |
| 434 } | 438 } |
| 435 void VisitInt64Cmp(Node* node) { | 439 void VisitInt64Cmp(Node* node) { |
| 436 VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool); | 440 VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool); |
| 437 } | 441 } |
| 438 void VisitUint64Cmp(Node* node) { | 442 void VisitUint64Cmp(Node* node) { |
| 439 VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool); | 443 VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool); |
| 440 } | 444 } |
| 441 | 445 |
| 442 // Infer representation for phi-like nodes. | 446 // Infer representation for phi-like nodes. |
| 443 static MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) { | 447 static MachineType GetRepresentationForPhi(Node* node, Truncation use) { |
| 444 // Phis adapt to the output representation their uses demand. | 448 // Phis adapt to the output representation their uses demand. |
| 445 Type* upper = NodeProperties::GetType(node); | 449 Type* upper = NodeProperties::GetType(node); |
| 446 if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) { | 450 if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) { |
| 447 // We are within 32 bits range => pick kRepWord32. | 451 // We are within 32 bits range => pick kRepWord32. |
| 448 return kRepWord32; | 452 return kRepWord32; |
| 449 } else if (!CanObserveNonWord32(use)) { | 453 } else if (use.TruncatesToWord32()) { |
| 450 // We only use 32 bits. | 454 // We only use 32 bits. |
| 451 return kRepWord32; | 455 return kRepWord32; |
| 452 } else if (upper->Is(Type::Boolean())) { | 456 } else if (upper->Is(Type::Boolean())) { |
| 453 // multiple uses => pick kRepBit. | 457 // multiple uses => pick kRepBit. |
| 454 return kRepBit; | 458 return kRepBit; |
| 455 } else if (upper->Is(Type::Number())) { | 459 } else if (upper->Is(Type::Number())) { |
| 456 // multiple uses => pick kRepFloat64. | 460 // multiple uses => pick kRepFloat64. |
| 457 return kRepFloat64; | 461 return kRepFloat64; |
| 458 } else if (upper->Is(Type::Internal())) { | 462 } else if (upper->Is(Type::Internal())) { |
| 459 return kMachPtr; | 463 return kMachPtr; |
| 460 } | 464 } |
| 461 return kRepTagged; | 465 return kRepTagged; |
| 462 } | 466 } |
| 463 | 467 |
| 464 // Helper for handling selects. | 468 // Helper for handling selects. |
| 465 void VisitSelect(Node* node, MachineTypeUnion use, | 469 void VisitSelect(Node* node, Truncation truncation, |
| 466 SimplifiedLowering* lowering) { | 470 SimplifiedLowering* lowering) { |
| 467 ProcessInput(node, 0, UseInfo::Bool()); | 471 ProcessInput(node, 0, UseInfo::Bool()); |
| 468 MachineType output = GetRepresentationForPhi(node, use); | 472 MachineType output = GetRepresentationForPhi(node, truncation); |
| 469 | 473 |
| 470 Type* upper = NodeProperties::GetType(node); | 474 Type* upper = NodeProperties::GetType(node); |
| 471 MachineType output_type = | 475 MachineType output_type = |
| 472 static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output); | 476 static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output); |
| 473 SetOutput(node, output_type); | 477 SetOutput(node, output_type); |
| 474 | 478 |
| 475 if (lower()) { | 479 if (lower()) { |
| 476 // Update the select operator. | 480 // Update the select operator. |
| 477 SelectParameters p = SelectParametersOf(node->op()); | 481 SelectParameters p = SelectParametersOf(node->op()); |
| 478 MachineType type = static_cast<MachineType>(output_type); | 482 MachineType type = static_cast<MachineType>(output_type); |
| 479 if (type != p.type()) { | 483 if (type != p.type()) { |
| 480 NodeProperties::ChangeOp(node, | 484 NodeProperties::ChangeOp(node, |
| 481 lowering->common()->Select(type, p.hint())); | 485 lowering->common()->Select(type, p.hint())); |
| 482 } | 486 } |
| 483 } | 487 } |
| 484 // Convert inputs to the output representation of this phi, pass the | 488 // Convert inputs to the output representation of this phi, pass the |
| 485 // use truncation along. | 489 // truncation truncation along. |
| 486 UseInfo input_use(output, use & kTypeMask); | 490 UseInfo input_use(output, truncation); |
| 487 ProcessInput(node, 1, input_use); | 491 ProcessInput(node, 1, input_use); |
| 488 ProcessInput(node, 2, input_use); | 492 ProcessInput(node, 2, input_use); |
| 489 } | 493 } |
| 490 | 494 |
| 491 // Helper for handling phis. | 495 // Helper for handling phis. |
| 492 void VisitPhi(Node* node, MachineTypeUnion use, | 496 void VisitPhi(Node* node, Truncation truncation, |
| 493 SimplifiedLowering* lowering) { | 497 SimplifiedLowering* lowering) { |
| 494 MachineType output = GetRepresentationForPhi(node, use); | 498 MachineType output = GetRepresentationForPhi(node, truncation); |
| 495 | 499 |
| 496 Type* upper = NodeProperties::GetType(node); | 500 Type* upper = NodeProperties::GetType(node); |
| 497 MachineType output_type = | 501 MachineType output_type = |
| 498 static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output); | 502 static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output); |
| 499 SetOutput(node, output_type); | 503 SetOutput(node, output_type); |
| 500 | 504 |
| 501 int values = node->op()->ValueInputCount(); | 505 int values = node->op()->ValueInputCount(); |
| 502 | 506 |
| 503 if (lower()) { | 507 if (lower()) { |
| 504 // Update the phi operator. | 508 // Update the phi operator. |
| 505 MachineType type = static_cast<MachineType>(output_type); | 509 MachineType type = static_cast<MachineType>(output_type); |
| 506 if (type != OpParameter<MachineType>(node)) { | 510 if (type != OpParameter<MachineType>(node)) { |
| 507 NodeProperties::ChangeOp(node, lowering->common()->Phi(type, values)); | 511 NodeProperties::ChangeOp(node, lowering->common()->Phi(type, values)); |
| 508 } | 512 } |
| 509 } | 513 } |
| 510 | 514 |
| 511 // Convert inputs to the output representation of this phi, pass the | 515 // Convert inputs to the output representation of this phi, pass the |
| 512 // use truncation along. | 516 // truncation truncation along. |
| 513 UseInfo input_use(output, use & kTypeMask); | 517 UseInfo input_use(output, truncation); |
| 514 for (int i = 0; i < node->InputCount(); i++) { | 518 for (int i = 0; i < node->InputCount(); i++) { |
| 515 ProcessInput(node, i, i < values ? input_use : UseInfo::None()); | 519 ProcessInput(node, i, i < values ? input_use : UseInfo::None()); |
| 516 } | 520 } |
| 517 } | 521 } |
| 518 | 522 |
| 519 void VisitCall(Node* node, SimplifiedLowering* lowering) { | 523 void VisitCall(Node* node, SimplifiedLowering* lowering) { |
| 520 const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op()); | 524 const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op()); |
| 521 const MachineSignature* sig = desc->GetMachineSignature(); | 525 const MachineSignature* sig = desc->GetMachineSignature(); |
| 522 int params = static_cast<int>(sig->parameter_count()); | 526 int params = static_cast<int>(sig->parameter_count()); |
| 523 // Propagate representation information from call descriptor. | 527 // Propagate representation information from call descriptor. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 543 if (phase_ == PROPAGATE) { | 547 if (phase_ == PROPAGATE) { |
| 544 for (int i = 0; i < node->InputCount(); i++) { | 548 for (int i = 0; i < node->InputCount(); i++) { |
| 545 Enqueue(node->InputAt(i), UseInfo::Any()); | 549 Enqueue(node->InputAt(i), UseInfo::Any()); |
| 546 } | 550 } |
| 547 } else { | 551 } else { |
| 548 Zone* zone = jsgraph_->zone(); | 552 Zone* zone = jsgraph_->zone(); |
| 549 ZoneVector<MachineType>* types = | 553 ZoneVector<MachineType>* types = |
| 550 new (zone->New(sizeof(ZoneVector<MachineType>))) | 554 new (zone->New(sizeof(ZoneVector<MachineType>))) |
| 551 ZoneVector<MachineType>(node->InputCount(), zone); | 555 ZoneVector<MachineType>(node->InputCount(), zone); |
| 552 for (int i = 0; i < node->InputCount(); i++) { | 556 for (int i = 0; i < node->InputCount(); i++) { |
| 553 MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output; | 557 MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output_type(); |
| 554 (*types)[i] = static_cast<MachineType>(input_type); | 558 (*types)[i] = static_cast<MachineType>(input_type); |
| 555 } | 559 } |
| 556 NodeProperties::ChangeOp(node, | 560 NodeProperties::ChangeOp(node, |
| 557 jsgraph_->common()->TypedStateValues(types)); | 561 jsgraph_->common()->TypedStateValues(types)); |
| 558 } | 562 } |
| 559 SetOutput(node, kMachAnyTagged); | 563 SetOutput(node, kMachAnyTagged); |
| 560 } | 564 } |
| 561 | 565 |
| 562 const Operator* Int32Op(Node* node) { | 566 const Operator* Int32Op(Node* node) { |
| 563 return changer_->Int32OperatorFor(node->opcode()); | 567 return changer_->Int32OperatorFor(node->opcode()); |
| 564 } | 568 } |
| 565 | 569 |
| 566 const Operator* Uint32Op(Node* node) { | 570 const Operator* Uint32Op(Node* node) { |
| 567 return changer_->Uint32OperatorFor(node->opcode()); | 571 return changer_->Uint32OperatorFor(node->opcode()); |
| 568 } | 572 } |
| 569 | 573 |
| 570 const Operator* Float64Op(Node* node) { | 574 const Operator* Float64Op(Node* node) { |
| 571 return changer_->Float64OperatorFor(node->opcode()); | 575 return changer_->Float64OperatorFor(node->opcode()); |
| 572 } | 576 } |
| 573 | 577 |
| 574 bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) { | 578 bool CanLowerToInt32Binop(Node* node, Truncation use) { |
| 575 return BothInputsAre(node, Type::Signed32()) && | 579 return BothInputsAre(node, Type::Signed32()) && |
| 576 (!CanObserveNonWord32(use) || | 580 (use.TruncatesToWord32() || |
| 577 NodeProperties::GetType(node)->Is(Type::Signed32())); | 581 NodeProperties::GetType(node)->Is(Type::Signed32())); |
| 578 } | 582 } |
| 579 | 583 |
| 580 bool CanLowerToWord32AdditiveBinop(Node* node, MachineTypeUnion use) { | 584 bool CanLowerToWord32AdditiveBinop(Node* node, Truncation use) { |
| 581 return BothInputsAre(node, safe_int_additive_range_) && | 585 return BothInputsAre(node, safe_int_additive_range_) && |
| 582 !CanObserveNonWord32(use); | 586 use.TruncatesToWord32(); |
| 583 } | |
| 584 | |
| 585 bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) { | |
| 586 return BothInputsAre(node, Type::Unsigned32()) && | |
| 587 (!CanObserveNonWord32(use) || | |
| 588 NodeProperties::GetType(node)->Is(Type::Unsigned32())); | |
| 589 } | |
| 590 | |
| 591 static bool CanObserveNonWord32(MachineTypeUnion use) { | |
| 592 return (use & kTypeMask & ~(kTypeInt32 | kTypeUint32)) != 0; | |
| 593 } | |
| 594 | |
| 595 static bool CanObserveNaN(MachineTypeUnion use) { | |
| 596 return (use & (kTypeNumber | kTypeAny)) != 0; | |
| 597 } | 587 } |
| 598 | 588 |
| 599 // Dispatching routine for visiting the node {node} with the usage {use}. | 589 // Dispatching routine for visiting the node {node} with the usage {use}. |
| 600 // Depending on the operator, propagate new usage info to the inputs. | 590 // Depending on the operator, propagate new usage info to the inputs. |
| 601 void VisitNode(Node* node, MachineTypeUnion use, | 591 void VisitNode(Node* node, Truncation truncation, |
| 602 SimplifiedLowering* lowering) { | 592 SimplifiedLowering* lowering) { |
| 603 switch (node->opcode()) { | 593 switch (node->opcode()) { |
| 604 //------------------------------------------------------------------ | 594 //------------------------------------------------------------------ |
| 605 // Common operators. | 595 // Common operators. |
| 606 //------------------------------------------------------------------ | 596 //------------------------------------------------------------------ |
| 607 case IrOpcode::kStart: | 597 case IrOpcode::kStart: |
| 608 case IrOpcode::kDead: | 598 case IrOpcode::kDead: |
| 609 return VisitLeaf(node, 0); | 599 return VisitLeaf(node, 0); |
| 610 case IrOpcode::kParameter: { | 600 case IrOpcode::kParameter: { |
| 611 // TODO(titzer): use representation from linkage. | 601 // TODO(titzer): use representation from linkage. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 631 | 621 |
| 632 case IrOpcode::kBranch: | 622 case IrOpcode::kBranch: |
| 633 ProcessInput(node, 0, UseInfo::Bool()); | 623 ProcessInput(node, 0, UseInfo::Bool()); |
| 634 Enqueue(NodeProperties::GetControlInput(node, 0)); | 624 Enqueue(NodeProperties::GetControlInput(node, 0)); |
| 635 break; | 625 break; |
| 636 case IrOpcode::kSwitch: | 626 case IrOpcode::kSwitch: |
| 637 ProcessInput(node, 0, UseInfo::TruncatingWord32()); | 627 ProcessInput(node, 0, UseInfo::TruncatingWord32()); |
| 638 Enqueue(NodeProperties::GetControlInput(node, 0)); | 628 Enqueue(NodeProperties::GetControlInput(node, 0)); |
| 639 break; | 629 break; |
| 640 case IrOpcode::kSelect: | 630 case IrOpcode::kSelect: |
| 641 return VisitSelect(node, use, lowering); | 631 return VisitSelect(node, truncation, lowering); |
| 642 case IrOpcode::kPhi: | 632 case IrOpcode::kPhi: |
| 643 return VisitPhi(node, use, lowering); | 633 return VisitPhi(node, truncation, lowering); |
| 644 case IrOpcode::kCall: | 634 case IrOpcode::kCall: |
| 645 return VisitCall(node, lowering); | 635 return VisitCall(node, lowering); |
| 646 | 636 |
| 647 //------------------------------------------------------------------ | 637 //------------------------------------------------------------------ |
| 648 // JavaScript operators. | 638 // JavaScript operators. |
| 649 //------------------------------------------------------------------ | 639 //------------------------------------------------------------------ |
| 650 // For now, we assume that all JS operators were too complex to lower | 640 // For now, we assume that all JS operators were too complex to lower |
| 651 // to Simplified and that they will always require tagged value inputs | 641 // to Simplified and that they will always require tagged value inputs |
| 652 // and produce tagged value outputs. | 642 // and produce tagged value outputs. |
| 653 // TODO(turbofan): it might be possible to lower some JSOperators here, | 643 // TODO(turbofan): it might be possible to lower some JSOperators here, |
| 654 // but that responsibility really lies in the typed lowering phase. | 644 // but that responsibility really lies in the typed lowering phase. |
| 655 #define DEFINE_JS_CASE(x) case IrOpcode::k##x: | 645 #define DEFINE_JS_CASE(x) case IrOpcode::k##x: |
| 656 JS_OP_LIST(DEFINE_JS_CASE) | 646 JS_OP_LIST(DEFINE_JS_CASE) |
| 657 #undef DEFINE_JS_CASE | 647 #undef DEFINE_JS_CASE |
| 658 VisitInputs(node); | 648 VisitInputs(node); |
| 659 return SetOutput(node, kRepTagged); | 649 return SetOutput(node, kRepTagged); |
| 660 | 650 |
| 661 //------------------------------------------------------------------ | 651 //------------------------------------------------------------------ |
| 662 // Simplified operators. | 652 // Simplified operators. |
| 663 //------------------------------------------------------------------ | 653 //------------------------------------------------------------------ |
| 664 case IrOpcode::kBooleanNot: { | 654 case IrOpcode::kBooleanNot: { |
| 665 if (lower()) { | 655 if (lower()) { |
| 666 MachineTypeUnion input = GetInfo(node->InputAt(0))->output; | 656 MachineTypeUnion input = GetInfo(node->InputAt(0))->output_type(); |
| 667 if (input & kRepBit) { | 657 if (input & kRepBit) { |
| 668 // BooleanNot(x: kRepBit) => Word32Equal(x, #0) | 658 // BooleanNot(x: kRepBit) => Word32Equal(x, #0) |
| 669 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0)); | 659 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0)); |
| 670 NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal()); | 660 NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal()); |
| 671 } else { | 661 } else { |
| 672 // BooleanNot(x: kRepTagged) => WordEqual(x, #false) | 662 // BooleanNot(x: kRepTagged) => WordEqual(x, #false) |
| 673 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant()); | 663 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant()); |
| 674 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); | 664 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); |
| 675 } | 665 } |
| 676 } else { | 666 } else { |
| 677 // No input representation requirement; adapt during lowering. | 667 // No input representation requirement; adapt during lowering. |
| 678 ProcessInput(node, 0, UseInfo::AnyTruncatingToBool()); | 668 ProcessInput(node, 0, UseInfo::AnyTruncatingToBool()); |
| 679 SetOutput(node, kRepBit); | 669 SetOutput(node, kRepBit); |
| 680 } | 670 } |
| 681 break; | 671 break; |
| 682 } | 672 } |
| 683 case IrOpcode::kBooleanToNumber: { | 673 case IrOpcode::kBooleanToNumber: { |
| 684 if (lower()) { | 674 if (lower()) { |
| 685 MachineTypeUnion input = GetInfo(node->InputAt(0))->output; | 675 MachineTypeUnion input = GetInfo(node->InputAt(0))->output_type(); |
| 686 if (input & kRepBit) { | 676 if (input & kRepBit) { |
| 687 // BooleanToNumber(x: kRepBit) => x | 677 // BooleanToNumber(x: kRepBit) => x |
| 688 DeferReplacement(node, node->InputAt(0)); | 678 DeferReplacement(node, node->InputAt(0)); |
| 689 } else { | 679 } else { |
| 690 // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true) | 680 // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true) |
| 691 node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant()); | 681 node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant()); |
| 692 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); | 682 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); |
| 693 } | 683 } |
| 694 } else { | 684 } else { |
| 695 // No input representation requirement; adapt during lowering. | 685 // No input representation requirement; adapt during lowering. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 714 // => Float64Cmp | 704 // => Float64Cmp |
| 715 VisitFloat64Cmp(node); | 705 VisitFloat64Cmp(node); |
| 716 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); | 706 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); |
| 717 } | 707 } |
| 718 break; | 708 break; |
| 719 } | 709 } |
| 720 case IrOpcode::kNumberAdd: | 710 case IrOpcode::kNumberAdd: |
| 721 case IrOpcode::kNumberSubtract: { | 711 case IrOpcode::kNumberSubtract: { |
| 722 // Add and subtract reduce to Int32Add/Sub if the inputs | 712 // Add and subtract reduce to Int32Add/Sub if the inputs |
| 723 // are already integers and all uses are truncating. | 713 // are already integers and all uses are truncating. |
| 724 if (CanLowerToWord32AdditiveBinop(node, use)) { | 714 if (CanLowerToWord32AdditiveBinop(node, truncation)) { |
| 725 // => signed Int32Add/Sub | 715 // => signed Int32Add/Sub |
| 726 VisitInt32Binop(node); | 716 VisitInt32Binop(node); |
| 727 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); | 717 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); |
| 728 } else { | 718 } else { |
| 729 // => Float64Add/Sub | 719 // => Float64Add/Sub |
| 730 VisitFloat64Binop(node); | 720 VisitFloat64Binop(node); |
| 731 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); | 721 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); |
| 732 } | 722 } |
| 733 break; | 723 break; |
| 734 } | 724 } |
| 735 case IrOpcode::kNumberMultiply: { | 725 case IrOpcode::kNumberMultiply: { |
| 736 NumberMatcher right(node->InputAt(1)); | 726 NumberMatcher right(node->InputAt(1)); |
| 737 if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa. | 727 if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa. |
| 738 if (CanLowerToInt32Binop(node, use)) { | 728 if (CanLowerToInt32Binop(node, truncation)) { |
| 739 // => signed Int32Mul | 729 // => signed Int32Mul |
| 740 VisitInt32Binop(node); | 730 VisitInt32Binop(node); |
| 741 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); | 731 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); |
| 742 break; | 732 break; |
| 743 } | 733 } |
| 744 } | 734 } |
| 745 // => Float64Mul | 735 // => Float64Mul |
| 746 VisitFloat64Binop(node); | 736 VisitFloat64Binop(node); |
| 747 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); | 737 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); |
| 748 break; | 738 break; |
| 749 } | 739 } |
| 750 case IrOpcode::kNumberDivide: { | 740 case IrOpcode::kNumberDivide: { |
| 751 if (CanLowerToInt32Binop(node, use)) { | 741 if (CanLowerToInt32Binop(node, truncation)) { |
| 752 // => signed Int32Div | 742 // => signed Int32Div |
| 753 VisitInt32Binop(node); | 743 VisitInt32Binop(node); |
| 754 if (lower()) DeferReplacement(node, lowering->Int32Div(node)); | 744 if (lower()) DeferReplacement(node, lowering->Int32Div(node)); |
| 755 break; | 745 break; |
| 756 } | 746 } |
| 757 if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) { | 747 if (BothInputsAre(node, Type::Unsigned32()) && |
| 748 truncation.TruncatesNaNToZero()) { |
| 758 // => unsigned Uint32Div | 749 // => unsigned Uint32Div |
| 759 VisitUint32Binop(node); | 750 VisitUint32Binop(node); |
| 760 if (lower()) DeferReplacement(node, lowering->Uint32Div(node)); | 751 if (lower()) DeferReplacement(node, lowering->Uint32Div(node)); |
| 761 break; | 752 break; |
| 762 } | 753 } |
| 763 // => Float64Div | 754 // => Float64Div |
| 764 VisitFloat64Binop(node); | 755 VisitFloat64Binop(node); |
| 765 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); | 756 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); |
| 766 break; | 757 break; |
| 767 } | 758 } |
| 768 case IrOpcode::kNumberModulus: { | 759 case IrOpcode::kNumberModulus: { |
| 769 if (CanLowerToInt32Binop(node, use)) { | 760 if (CanLowerToInt32Binop(node, truncation)) { |
| 770 // => signed Int32Mod | 761 // => signed Int32Mod |
| 771 VisitInt32Binop(node); | 762 VisitInt32Binop(node); |
| 772 if (lower()) DeferReplacement(node, lowering->Int32Mod(node)); | 763 if (lower()) DeferReplacement(node, lowering->Int32Mod(node)); |
| 773 break; | 764 break; |
| 774 } | 765 } |
| 775 if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) { | 766 if (BothInputsAre(node, Type::Unsigned32()) && |
| 767 truncation.TruncatesNaNToZero()) { |
| 776 // => unsigned Uint32Mod | 768 // => unsigned Uint32Mod |
| 777 VisitUint32Binop(node); | 769 VisitUint32Binop(node); |
| 778 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node)); | 770 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node)); |
| 779 break; | 771 break; |
| 780 } | 772 } |
| 781 // => Float64Mod | 773 // => Float64Mod |
| 782 VisitFloat64Binop(node); | 774 VisitFloat64Binop(node); |
| 783 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); | 775 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); |
| 784 break; | 776 break; |
| 785 } | 777 } |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 ProcessRemainingInputs(node, 2); | 886 ProcessRemainingInputs(node, 2); |
| 895 SetOutput(node, 0); | 887 SetOutput(node, 0); |
| 896 break; | 888 break; |
| 897 } | 889 } |
| 898 case IrOpcode::kLoadBuffer: { | 890 case IrOpcode::kLoadBuffer: { |
| 899 BufferAccess access = BufferAccessOf(node->op()); | 891 BufferAccess access = BufferAccessOf(node->op()); |
| 900 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer | 892 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer |
| 901 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset | 893 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset |
| 902 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length | 894 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length |
| 903 ProcessRemainingInputs(node, 3); | 895 ProcessRemainingInputs(node, 3); |
| 904 // Tagged overrides everything if we have to do a typed array bounds | 896 |
| 905 // check, because we may need to return undefined then. | |
| 906 MachineType output_type; | 897 MachineType output_type; |
| 907 if (use & kRepTagged) { | 898 if (truncation.TruncatesUndefinedToZeroOrNaN()) { |
| 908 output_type = kMachAnyTagged; | 899 if (truncation.TruncatesNaNToZero()) { |
| 909 } else if (use & kRepFloat64) { | 900 // If undefined is truncated to a non-NaN number, we can use |
| 910 if (access.machine_type() & kRepFloat32) { | 901 // the load's representation. |
| 911 output_type = access.machine_type(); | 902 output_type = access.machine_type(); |
| 912 } else { | 903 } else { |
| 913 output_type = kMachFloat64; | 904 // If undefined is truncated to a number, but the use can |
| 905 // observe NaN, we need to output at least the float32 |
| 906 // representation. |
| 907 if (access.machine_type() & kRepFloat32) { |
| 908 output_type = access.machine_type(); |
| 909 } else { |
| 910 output_type = kMachFloat64; |
| 911 } |
| 914 } | 912 } |
| 915 } else if (use & kRepFloat32) { | |
| 916 output_type = kMachFloat32; | |
| 917 } else { | 913 } else { |
| 918 output_type = access.machine_type(); | 914 // If undefined is not truncated away, we need to have the tagged |
| 915 // representation. |
| 916 output_type = kMachAnyTagged; |
| 919 } | 917 } |
| 920 SetOutput(node, output_type); | 918 SetOutput(node, output_type); |
| 921 if (lower()) lowering->DoLoadBuffer(node, output_type, changer_); | 919 if (lower()) lowering->DoLoadBuffer(node, output_type, changer_); |
| 922 break; | 920 break; |
| 923 } | 921 } |
| 924 case IrOpcode::kStoreBuffer: { | 922 case IrOpcode::kStoreBuffer: { |
| 925 BufferAccess access = BufferAccessOf(node->op()); | 923 BufferAccess access = BufferAccessOf(node->op()); |
| 926 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer | 924 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer |
| 927 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset | 925 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset |
| 928 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length | 926 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1118 break; | 1116 break; |
| 1119 } | 1117 } |
| 1120 } | 1118 } |
| 1121 | 1119 |
| 1122 void DeferReplacement(Node* node, Node* replacement) { | 1120 void DeferReplacement(Node* node, Node* replacement) { |
| 1123 TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(), | 1121 TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(), |
| 1124 node->op()->mnemonic(), replacement->id(), | 1122 node->op()->mnemonic(), replacement->id(), |
| 1125 replacement->op()->mnemonic()); | 1123 replacement->op()->mnemonic()); |
| 1126 | 1124 |
| 1127 if (replacement->id() < count_ && | 1125 if (replacement->id() < count_ && |
| 1128 GetInfo(replacement)->output == GetInfo(node)->output) { | 1126 GetInfo(replacement)->output_type() == GetInfo(node)->output_type()) { |
| 1129 // Replace with a previously existing node eagerly only if the type is the | 1127 // Replace with a previously existing node eagerly only if the type is the |
| 1130 // same. | 1128 // same. |
| 1131 node->ReplaceUses(replacement); | 1129 node->ReplaceUses(replacement); |
| 1132 } else { | 1130 } else { |
| 1133 // Otherwise, we are replacing a node with a representation change. | 1131 // Otherwise, we are replacing a node with a representation change. |
| 1134 // Such a substitution must be done after all lowering is done, because | 1132 // Such a substitution must be done after all lowering is done, because |
| 1135 // changing the type could confuse the representation change | 1133 // changing the type could confuse the representation change |
| 1136 // insertion for uses of the node. | 1134 // insertion for uses of the node. |
| 1137 replacements_.push_back(node); | 1135 replacements_.push_back(node); |
| 1138 replacements_.push_back(replacement); | 1136 replacements_.push_back(replacement); |
| 1139 } | 1137 } |
| 1140 node->NullAllInputs(); // Node is now dead. | 1138 node->NullAllInputs(); // Node is now dead. |
| 1141 } | 1139 } |
| 1142 | 1140 |
| 1143 void PrintUseInfo(Node* node) { | |
| 1144 TRACE("#%d:%-20s ", node->id(), node->op()->mnemonic()); | |
| 1145 PrintInfo(GetUseInfo(node)); | |
| 1146 TRACE("\n"); | |
| 1147 } | |
| 1148 | |
| 1149 void PrintInfo(MachineTypeUnion info) { | 1141 void PrintInfo(MachineTypeUnion info) { |
| 1150 if (FLAG_trace_representation) { | 1142 if (FLAG_trace_representation) { |
| 1151 OFStream os(stdout); | 1143 OFStream os(stdout); |
| 1152 os << static_cast<MachineType>(info); | 1144 os << static_cast<MachineType>(info); |
| 1153 } | 1145 } |
| 1154 } | 1146 } |
| 1155 | 1147 |
| 1148 void PrintTruncation(Truncation truncation) { |
| 1149 if (FLAG_trace_representation) { |
| 1150 OFStream os(stdout); |
| 1151 os << truncation.description(); |
| 1152 } |
| 1153 } |
| 1154 |
| 1156 void PrintUseInfo(UseInfo info) { | 1155 void PrintUseInfo(UseInfo info) { |
| 1157 if (FLAG_trace_representation) { | 1156 if (FLAG_trace_representation) { |
| 1158 OFStream os(stdout); | 1157 OFStream os(stdout); |
| 1159 os << static_cast<MachineType>(info.machine_type()); | 1158 os << info.preferred() << ":" << info.truncation().description(); |
| 1160 } | 1159 } |
| 1161 } | 1160 } |
| 1162 | 1161 |
| 1163 private: | 1162 private: |
| 1164 JSGraph* jsgraph_; | 1163 JSGraph* jsgraph_; |
| 1165 size_t const count_; // number of nodes in the graph | 1164 size_t const count_; // number of nodes in the graph |
| 1166 NodeInfo* info_; // node id -> usage information | 1165 ZoneVector<NodeInfo> info_; // node id -> usage information |
| 1167 NodeVector nodes_; // collected nodes | 1166 NodeVector nodes_; // collected nodes |
| 1168 NodeVector replacements_; // replacements to be done after lowering | 1167 NodeVector replacements_; // replacements to be done after lowering |
| 1169 Phase phase_; // current phase of algorithm | 1168 Phase phase_; // current phase of algorithm |
| 1170 RepresentationChanger* changer_; // for inserting representation changes | 1169 RepresentationChanger* changer_; // for inserting representation changes |
| 1171 ZoneQueue<Node*> queue_; // queue for traversing the graph | 1170 ZoneQueue<Node*> queue_; // queue for traversing the graph |
| 1172 // TODO(danno): RepresentationSelector shouldn't know anything about the | 1171 // TODO(danno): RepresentationSelector shouldn't know anything about the |
| 1173 // source positions table, but must for now since there currently is no other | 1172 // source positions table, but must for now since there currently is no other |
| 1174 // way to pass down source position information to nodes created during | 1173 // way to pass down source position information to nodes created during |
| 1175 // lowering. Once this phase becomes a vanilla reducer, it should get source | 1174 // lowering. Once this phase becomes a vanilla reducer, it should get source |
| 1176 // position information via the SourcePositionWrapper like all other reducers. | 1175 // position information via the SourcePositionWrapper like all other reducers. |
| 1177 SourcePositionTable* source_positions_; | 1176 SourcePositionTable* source_positions_; |
| 1178 Type* safe_int_additive_range_; | 1177 Type* safe_int_additive_range_; |
| 1179 | 1178 |
| 1180 NodeInfo* GetInfo(Node* node) { | 1179 NodeInfo* GetInfo(Node* node) { |
| 1181 DCHECK(node->id() >= 0); | 1180 DCHECK(node->id() >= 0); |
| 1182 DCHECK(node->id() < count_); | 1181 DCHECK(node->id() < count_); |
| 1183 return &info_[node->id()]; | 1182 return &info_[node->id()]; |
| 1184 } | 1183 } |
| 1185 | |
| 1186 MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; } | |
| 1187 }; | 1184 }; |
| 1188 | 1185 |
| 1189 | 1186 |
| 1190 SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone, | 1187 SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone, |
| 1191 SourcePositionTable* source_positions) | 1188 SourcePositionTable* source_positions) |
| 1192 : jsgraph_(jsgraph), | 1189 : jsgraph_(jsgraph), |
| 1193 zone_(zone), | 1190 zone_(zone), |
| 1194 zero_thirtyone_range_(Type::Range(0, 31, zone)), | 1191 zero_thirtyone_range_(Type::Range(0, 31, zone)), |
| 1195 source_positions_(source_positions) {} | 1192 source_positions_(source_positions) {} |
| 1196 | 1193 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1219 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset) | 1216 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset) |
| 1220 : offset; | 1217 : offset; |
| 1221 | 1218 |
| 1222 Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length); | 1219 Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length); |
| 1223 Node* branch = | 1220 Node* branch = |
| 1224 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); | 1221 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1225 | 1222 |
| 1226 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); | 1223 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1227 Node* etrue = | 1224 Node* etrue = |
| 1228 graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true); | 1225 graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true); |
| 1229 Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type); | 1226 Node* vtrue = changer->GetRepresentationFor( |
| 1227 etrue, type, RepresentationOf(output_type), Truncation::None()); |
| 1230 | 1228 |
| 1231 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | 1229 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1232 Node* efalse = effect; | 1230 Node* efalse = effect; |
| 1233 Node* vfalse; | 1231 Node* vfalse; |
| 1234 if (output_type & kRepTagged) { | 1232 if (output_type & kRepTagged) { |
| 1235 vfalse = jsgraph()->UndefinedConstant(); | 1233 vfalse = jsgraph()->UndefinedConstant(); |
| 1236 } else if (output_type & kRepFloat64) { | 1234 } else if (output_type & kRepFloat64) { |
| 1237 vfalse = | 1235 vfalse = |
| 1238 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN()); | 1236 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN()); |
| 1239 } else if (output_type & kRepFloat32) { | 1237 } else if (output_type & kRepFloat32) { |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1621 ReplaceEffectUses(node, comparison); | 1619 ReplaceEffectUses(node, comparison); |
| 1622 node->ReplaceInput(0, comparison); | 1620 node->ReplaceInput(0, comparison); |
| 1623 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); | 1621 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); |
| 1624 node->TrimInputCount(2); | 1622 node->TrimInputCount(2); |
| 1625 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); | 1623 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); |
| 1626 } | 1624 } |
| 1627 | 1625 |
| 1628 } // namespace compiler | 1626 } // namespace compiler |
| 1629 } // namespace internal | 1627 } // namespace internal |
| 1630 } // namespace v8 | 1628 } // namespace v8 |
| OLD | NEW |