| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 1 | // Copyright 2015 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 | #include "src/compiler/effect-control-linearizer.h" |
| 6 | |
| 7 | #include "src/code-factory.h" |
| 8 | #include "src/compiler/access-builder.h" |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 9 | #include "src/compiler/compiler-source-position-table.h" |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 10 | #include "src/compiler/js-graph.h" |
| 11 | #include "src/compiler/linkage.h" |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 12 | #include "src/compiler/node-matchers.h" |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 13 | #include "src/compiler/node-properties.h" |
| 14 | #include "src/compiler/node.h" |
| 15 | #include "src/compiler/schedule.h" |
| 16 | |
| 17 | namespace v8 { |
| 18 | namespace internal { |
| 19 | namespace compiler { |
| 20 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 21 | EffectControlLinearizer::EffectControlLinearizer( |
| 22 | JSGraph* js_graph, Schedule* schedule, Zone* temp_zone, |
| 23 | SourcePositionTable* source_positions) |
| 24 | : js_graph_(js_graph), |
| 25 | schedule_(schedule), |
| 26 | temp_zone_(temp_zone), |
| 27 | source_positions_(source_positions) {} |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 28 | |
| 29 | Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); } |
| 30 | CommonOperatorBuilder* EffectControlLinearizer::common() const { |
| 31 | return js_graph_->common(); |
| 32 | } |
| 33 | SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const { |
| 34 | return js_graph_->simplified(); |
| 35 | } |
| 36 | MachineOperatorBuilder* EffectControlLinearizer::machine() const { |
| 37 | return js_graph_->machine(); |
| 38 | } |
| 39 | |
| 40 | namespace { |
| 41 | |
| 42 | struct BlockEffectControlData { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 43 | Node* current_effect = nullptr; // New effect. |
| 44 | Node* current_control = nullptr; // New control. |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 45 | Node* current_frame_state = nullptr; // New frame state. |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 46 | }; |
| 47 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 48 | class BlockEffectControlMap { |
| 49 | public: |
| 50 | explicit BlockEffectControlMap(Zone* temp_zone) : map_(temp_zone) {} |
| 51 | |
| 52 | BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) { |
| 53 | return map_[std::make_pair(from->rpo_number(), to->rpo_number())]; |
| 54 | } |
| 55 | |
| 56 | const BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) const { |
| 57 | return map_.at(std::make_pair(from->rpo_number(), to->rpo_number())); |
| 58 | } |
| 59 | |
| 60 | private: |
| 61 | typedef std::pair<int32_t, int32_t> Key; |
| 62 | typedef ZoneMap<Key, BlockEffectControlData> Map; |
| 63 | |
| 64 | Map map_; |
| 65 | }; |
| 66 | |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 67 | // Effect phis that need to be updated after the first pass. |
| 68 | struct PendingEffectPhi { |
| 69 | Node* effect_phi; |
| 70 | BasicBlock* block; |
| 71 | |
| 72 | PendingEffectPhi(Node* effect_phi, BasicBlock* block) |
| 73 | : effect_phi(effect_phi), block(block) {} |
| 74 | }; |
| 75 | |
| 76 | void UpdateEffectPhi(Node* node, BasicBlock* block, |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 77 | BlockEffectControlMap* block_effects) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 78 | // Update all inputs to an effect phi with the effects from the given |
| 79 | // block->effect map. |
| 80 | DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 81 | DCHECK_EQ(static_cast<size_t>(node->op()->EffectInputCount()), |
| 82 | block->PredecessorCount()); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 83 | for (int i = 0; i < node->op()->EffectInputCount(); i++) { |
| 84 | Node* input = node->InputAt(i); |
| 85 | BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 86 | const BlockEffectControlData& block_effect = |
| 87 | block_effects->For(predecessor, block); |
| 88 | if (input != block_effect.current_effect) { |
| 89 | node->ReplaceInput(i, block_effect.current_effect); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 90 | } |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | void UpdateBlockControl(BasicBlock* block, |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 95 | BlockEffectControlMap* block_effects) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 96 | Node* control = block->NodeAt(0); |
| 97 | DCHECK(NodeProperties::IsControl(control)); |
| 98 | |
| 99 | // Do not rewire the end node. |
| 100 | if (control->opcode() == IrOpcode::kEnd) return; |
| 101 | |
| 102 | // Update all inputs to the given control node with the correct control. |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 103 | DCHECK(control->opcode() == IrOpcode::kMerge || |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 104 | static_cast<size_t>(control->op()->ControlInputCount()) == |
| 105 | block->PredecessorCount()); |
| 106 | if (static_cast<size_t>(control->op()->ControlInputCount()) != |
| 107 | block->PredecessorCount()) { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 108 | return; // We already re-wired the control inputs of this node. |
| 109 | } |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 110 | for (int i = 0; i < control->op()->ControlInputCount(); i++) { |
| 111 | Node* input = NodeProperties::GetControlInput(control, i); |
| 112 | BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i)); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 113 | const BlockEffectControlData& block_effect = |
| 114 | block_effects->For(predecessor, block); |
| 115 | if (input != block_effect.current_control) { |
| 116 | NodeProperties::ReplaceControlInput(control, block_effect.current_control, |
| 117 | i); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 118 | } |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | bool HasIncomingBackEdges(BasicBlock* block) { |
| 123 | for (BasicBlock* pred : block->predecessors()) { |
| 124 | if (pred->rpo_number() >= block->rpo_number()) { |
| 125 | return true; |
| 126 | } |
| 127 | } |
| 128 | return false; |
| 129 | } |
| 130 | |
| 131 | void RemoveRegionNode(Node* node) { |
| 132 | DCHECK(IrOpcode::kFinishRegion == node->opcode() || |
| 133 | IrOpcode::kBeginRegion == node->opcode()); |
| 134 | // Update the value/context uses to the value input of the finish node and |
| 135 | // the effect uses to the effect input. |
| 136 | for (Edge edge : node->use_edges()) { |
| 137 | DCHECK(!edge.from()->IsDead()); |
| 138 | if (NodeProperties::IsEffectEdge(edge)) { |
| 139 | edge.UpdateTo(NodeProperties::GetEffectInput(node)); |
| 140 | } else { |
| 141 | DCHECK(!NodeProperties::IsControlEdge(edge)); |
| 142 | DCHECK(!NodeProperties::IsFrameStateEdge(edge)); |
| 143 | edge.UpdateTo(node->InputAt(0)); |
| 144 | } |
| 145 | } |
| 146 | node->Kill(); |
| 147 | } |
| 148 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 149 | void TryCloneBranch(Node* node, BasicBlock* block, Graph* graph, |
| 150 | CommonOperatorBuilder* common, |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 151 | BlockEffectControlMap* block_effects, |
| 152 | SourcePositionTable* source_positions) { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 153 | DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
| 154 | |
| 155 | // This optimization is a special case of (super)block cloning. It takes an |
| 156 | // input graph as shown below and clones the Branch node for every predecessor |
| 157 | // to the Merge, essentially removing the Merge completely. This avoids |
| 158 | // materializing the bit for the Phi and may offer potential for further |
| 159 | // branch folding optimizations (i.e. because one or more inputs to the Phi is |
| 160 | // a constant). Note that there may be more Phi nodes hanging off the Merge, |
| 161 | // but we can only a certain subset of them currently (actually only Phi and |
| 162 | // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control |
| 163 | // input). |
| 164 | |
| 165 | // Control1 ... ControlN |
| 166 | // ^ ^ |
| 167 | // | | Cond1 ... CondN |
| 168 | // +----+ +----+ ^ ^ |
| 169 | // | | | | |
| 170 | // | | +----+ | |
| 171 | // Merge<--+ | +------------+ |
| 172 | // ^ \|/ |
| 173 | // | Phi |
| 174 | // | | |
| 175 | // Branch----+ |
| 176 | // ^ |
| 177 | // | |
| 178 | // +-----+-----+ |
| 179 | // | | |
| 180 | // IfTrue IfFalse |
| 181 | // ^ ^ |
| 182 | // | | |
| 183 | |
| 184 | // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this: |
| 185 | |
| 186 | // Control1 Cond1 ... ControlN CondN |
| 187 | // ^ ^ ^ ^ |
| 188 | // \ / \ / |
| 189 | // Branch ... Branch |
| 190 | // ^ ^ |
| 191 | // | | |
| 192 | // +---+---+ +---+----+ |
| 193 | // | | | | |
| 194 | // IfTrue IfFalse ... IfTrue IfFalse |
| 195 | // ^ ^ ^ ^ |
| 196 | // | | | | |
| 197 | // +--+ +-------------+ | |
| 198 | // | | +--------------+ +--+ |
| 199 | // | | | | |
| 200 | // Merge Merge |
| 201 | // ^ ^ |
| 202 | // | | |
| 203 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 204 | SourcePositionTable::Scope scope(source_positions, |
| 205 | source_positions->GetSourcePosition(node)); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 206 | Node* branch = node; |
| 207 | Node* cond = NodeProperties::GetValueInput(branch, 0); |
| 208 | if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return; |
| 209 | Node* merge = NodeProperties::GetControlInput(branch); |
| 210 | if (merge->opcode() != IrOpcode::kMerge || |
| 211 | NodeProperties::GetControlInput(cond) != merge) { |
| 212 | return; |
| 213 | } |
| 214 | // Grab the IfTrue/IfFalse projections of the Branch. |
| 215 | BranchMatcher matcher(branch); |
| 216 | // Check/collect other Phi/EffectPhi nodes hanging off the Merge. |
| 217 | NodeVector phis(graph->zone()); |
| 218 | for (Node* const use : merge->uses()) { |
| 219 | if (use == branch || use == cond) continue; |
| 220 | // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the |
| 221 | // Merge. Ideally, we would just clone the nodes (and everything that |
| 222 | // depends on it to some distant join point), but that requires knowledge |
| 223 | // about dominance/post-dominance. |
| 224 | if (!NodeProperties::IsPhi(use)) return; |
| 225 | for (Edge edge : use->use_edges()) { |
| 226 | // Right now we can only handle Phi/EffectPhi nodes whose uses are |
| 227 | // directly control-dependend on either the IfTrue or the IfFalse |
| 228 | // successor, because we know exactly how to update those uses. |
| 229 | if (edge.from()->op()->ControlInputCount() != 1) return; |
| 230 | Node* control = NodeProperties::GetControlInput(edge.from()); |
| 231 | if (NodeProperties::IsPhi(edge.from())) { |
| 232 | control = NodeProperties::GetControlInput(control, edge.index()); |
| 233 | } |
| 234 | if (control != matcher.IfTrue() && control != matcher.IfFalse()) return; |
| 235 | } |
| 236 | phis.push_back(use); |
| 237 | } |
| 238 | BranchHint const hint = BranchHintOf(branch->op()); |
| 239 | int const input_count = merge->op()->ControlInputCount(); |
| 240 | DCHECK_LE(1, input_count); |
| 241 | Node** const inputs = graph->zone()->NewArray<Node*>(2 * input_count); |
| 242 | Node** const merge_true_inputs = &inputs[0]; |
| 243 | Node** const merge_false_inputs = &inputs[input_count]; |
| 244 | for (int index = 0; index < input_count; ++index) { |
| 245 | Node* cond1 = NodeProperties::GetValueInput(cond, index); |
| 246 | Node* control1 = NodeProperties::GetControlInput(merge, index); |
| 247 | Node* branch1 = graph->NewNode(common->Branch(hint), cond1, control1); |
| 248 | merge_true_inputs[index] = graph->NewNode(common->IfTrue(), branch1); |
| 249 | merge_false_inputs[index] = graph->NewNode(common->IfFalse(), branch1); |
| 250 | } |
| 251 | Node* const merge_true = matcher.IfTrue(); |
| 252 | Node* const merge_false = matcher.IfFalse(); |
| 253 | merge_true->TrimInputCount(0); |
| 254 | merge_false->TrimInputCount(0); |
| 255 | for (int i = 0; i < input_count; ++i) { |
| 256 | merge_true->AppendInput(graph->zone(), merge_true_inputs[i]); |
| 257 | merge_false->AppendInput(graph->zone(), merge_false_inputs[i]); |
| 258 | } |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 259 | DCHECK_EQ(2u, block->SuccessorCount()); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 260 | NodeProperties::ChangeOp(matcher.IfTrue(), common->Merge(input_count)); |
| 261 | NodeProperties::ChangeOp(matcher.IfFalse(), common->Merge(input_count)); |
| 262 | int const true_index = |
| 263 | block->SuccessorAt(0)->NodeAt(0) == matcher.IfTrue() ? 0 : 1; |
| 264 | BlockEffectControlData* true_block_data = |
| 265 | &block_effects->For(block, block->SuccessorAt(true_index)); |
| 266 | BlockEffectControlData* false_block_data = |
| 267 | &block_effects->For(block, block->SuccessorAt(true_index ^ 1)); |
| 268 | for (Node* const phi : phis) { |
| 269 | for (int index = 0; index < input_count; ++index) { |
| 270 | inputs[index] = phi->InputAt(index); |
| 271 | } |
| 272 | inputs[input_count] = merge_true; |
| 273 | Node* phi_true = graph->NewNode(phi->op(), input_count + 1, inputs); |
| 274 | inputs[input_count] = merge_false; |
| 275 | Node* phi_false = graph->NewNode(phi->op(), input_count + 1, inputs); |
| 276 | if (phi->UseCount() == 0) { |
| 277 | DCHECK_EQ(phi->opcode(), IrOpcode::kEffectPhi); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 278 | } else { |
| 279 | for (Edge edge : phi->use_edges()) { |
| 280 | Node* control = NodeProperties::GetControlInput(edge.from()); |
| 281 | if (NodeProperties::IsPhi(edge.from())) { |
| 282 | control = NodeProperties::GetControlInput(control, edge.index()); |
| 283 | } |
| 284 | DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse()); |
| 285 | edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false); |
| 286 | } |
| 287 | } |
| 288 | if (phi->opcode() == IrOpcode::kEffectPhi) { |
| 289 | true_block_data->current_effect = phi_true; |
| 290 | false_block_data->current_effect = phi_false; |
| 291 | } |
| 292 | phi->Kill(); |
| 293 | } |
| 294 | // Fix up IfTrue and IfFalse and kill all dead nodes. |
| 295 | if (branch == block->control_input()) { |
| 296 | true_block_data->current_control = merge_true; |
| 297 | false_block_data->current_control = merge_false; |
| 298 | } |
| 299 | branch->Kill(); |
| 300 | cond->Kill(); |
| 301 | merge->Kill(); |
| 302 | } |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 303 | } // namespace |
| 304 | |
| 305 | void EffectControlLinearizer::Run() { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 306 | BlockEffectControlMap block_effects(temp_zone()); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 307 | ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone()); |
| 308 | ZoneVector<BasicBlock*> pending_block_controls(temp_zone()); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 309 | NodeVector inputs_buffer(temp_zone()); |
| 310 | |
| 311 | for (BasicBlock* block : *(schedule()->rpo_order())) { |
| 312 | size_t instr = 0; |
| 313 | |
| 314 | // The control node should be the first. |
| 315 | Node* control = block->NodeAt(instr); |
| 316 | DCHECK(NodeProperties::IsControl(control)); |
| 317 | // Update the control inputs. |
| 318 | if (HasIncomingBackEdges(block)) { |
| 319 | // If there are back edges, we need to update later because we have not |
| 320 | // computed the control yet. This should only happen for loops. |
| 321 | DCHECK_EQ(IrOpcode::kLoop, control->opcode()); |
| 322 | pending_block_controls.push_back(block); |
| 323 | } else { |
| 324 | // If there are no back edges, we can update now. |
| 325 | UpdateBlockControl(block, &block_effects); |
| 326 | } |
| 327 | instr++; |
| 328 | |
| 329 | // Iterate over the phis and update the effect phis. |
| 330 | Node* effect = nullptr; |
| 331 | Node* terminate = nullptr; |
| 332 | for (; instr < block->NodeCount(); instr++) { |
| 333 | Node* node = block->NodeAt(instr); |
| 334 | // Only go through the phis and effect phis. |
| 335 | if (node->opcode() == IrOpcode::kEffectPhi) { |
| 336 | // There should be at most one effect phi in a block. |
| 337 | DCHECK_NULL(effect); |
| 338 | // IfException blocks should not have effect phis. |
| 339 | DCHECK_NE(IrOpcode::kIfException, control->opcode()); |
| 340 | effect = node; |
| 341 | |
| 342 | // Make sure we update the inputs to the incoming blocks' effects. |
| 343 | if (HasIncomingBackEdges(block)) { |
| 344 | // In case of loops, we do not update the effect phi immediately |
| 345 | // because the back predecessor has not been handled yet. We just |
| 346 | // record the effect phi for later processing. |
| 347 | pending_effect_phis.push_back(PendingEffectPhi(node, block)); |
| 348 | } else { |
| 349 | UpdateEffectPhi(node, block, &block_effects); |
| 350 | } |
| 351 | } else if (node->opcode() == IrOpcode::kPhi) { |
| 352 | // Just skip phis. |
| 353 | } else if (node->opcode() == IrOpcode::kTerminate) { |
| 354 | DCHECK(terminate == nullptr); |
| 355 | terminate = node; |
| 356 | } else { |
| 357 | break; |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | if (effect == nullptr) { |
| 362 | // There was no effect phi. |
| 363 | DCHECK(!HasIncomingBackEdges(block)); |
| 364 | if (block == schedule()->start()) { |
| 365 | // Start block => effect is start. |
| 366 | DCHECK_EQ(graph()->start(), control); |
| 367 | effect = graph()->start(); |
| 368 | } else if (control->opcode() == IrOpcode::kEnd) { |
| 369 | // End block is just a dummy, no effect needed. |
| 370 | DCHECK_EQ(BasicBlock::kNone, block->control()); |
| 371 | DCHECK_EQ(1u, block->size()); |
| 372 | effect = nullptr; |
| 373 | } else { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 374 | // If all the predecessors have the same effect, we can use it as our |
| 375 | // current effect. |
| 376 | effect = |
| 377 | block_effects.For(block->PredecessorAt(0), block).current_effect; |
| 378 | for (size_t i = 1; i < block->PredecessorCount(); ++i) { |
| 379 | if (block_effects.For(block->PredecessorAt(i), block) |
| 380 | .current_effect != effect) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 381 | effect = nullptr; |
| 382 | break; |
| 383 | } |
| 384 | } |
| 385 | if (effect == nullptr) { |
| 386 | DCHECK_NE(IrOpcode::kIfException, control->opcode()); |
| 387 | // The input blocks do not have the same effect. We have |
| 388 | // to create an effect phi node. |
| 389 | inputs_buffer.clear(); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 390 | inputs_buffer.resize(block->PredecessorCount(), jsgraph()->Dead()); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 391 | inputs_buffer.push_back(control); |
| 392 | effect = graph()->NewNode( |
| 393 | common()->EffectPhi(static_cast<int>(block->PredecessorCount())), |
| 394 | static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front())); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 395 | // For loops, we update the effect phi node later to break cycles. |
| 396 | if (control->opcode() == IrOpcode::kLoop) { |
| 397 | pending_effect_phis.push_back(PendingEffectPhi(effect, block)); |
| 398 | } else { |
| 399 | UpdateEffectPhi(effect, block, &block_effects); |
| 400 | } |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 401 | } else if (control->opcode() == IrOpcode::kIfException) { |
| 402 | // The IfException is connected into the effect chain, so we need |
| 403 | // to update the effect here. |
| 404 | NodeProperties::ReplaceEffectInput(control, effect); |
| 405 | effect = control; |
| 406 | } |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | // Fixup the Terminate node. |
| 411 | if (terminate != nullptr) { |
| 412 | NodeProperties::ReplaceEffectInput(terminate, effect); |
| 413 | } |
| 414 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 415 | // The frame state at block entry is determined by the frame states leaving |
| 416 | // all predecessors. In case there is no frame state dominating this block, |
| 417 | // we can rely on a checkpoint being present before the next deoptimization. |
| 418 | // TODO(mstarzinger): Eventually we will need to go hunt for a frame state |
| 419 | // once deoptimizing nodes roam freely through the schedule. |
| 420 | Node* frame_state = nullptr; |
| 421 | if (block != schedule()->start()) { |
| 422 | // If all the predecessors have the same effect, we can use it |
| 423 | // as our current effect. |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 424 | frame_state = |
| 425 | block_effects.For(block->PredecessorAt(0), block).current_frame_state; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 426 | for (size_t i = 1; i < block->PredecessorCount(); i++) { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 427 | if (block_effects.For(block->PredecessorAt(i), block) |
| 428 | .current_frame_state != frame_state) { |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 429 | frame_state = nullptr; |
| 430 | break; |
| 431 | } |
| 432 | } |
| 433 | } |
| 434 | |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 435 | // Process the ordinary instructions. |
| 436 | for (; instr < block->NodeCount(); instr++) { |
| 437 | Node* node = block->NodeAt(instr); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 438 | ProcessNode(node, &frame_state, &effect, &control); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 439 | } |
| 440 | |
| 441 | switch (block->control()) { |
| 442 | case BasicBlock::kGoto: |
| 443 | case BasicBlock::kNone: |
| 444 | break; |
| 445 | |
| 446 | case BasicBlock::kCall: |
| 447 | case BasicBlock::kTailCall: |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 448 | case BasicBlock::kSwitch: |
| 449 | case BasicBlock::kReturn: |
| 450 | case BasicBlock::kDeoptimize: |
| 451 | case BasicBlock::kThrow: |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 452 | ProcessNode(block->control_input(), &frame_state, &effect, &control); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 453 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 454 | |
| 455 | case BasicBlock::kBranch: |
| 456 | ProcessNode(block->control_input(), &frame_state, &effect, &control); |
| 457 | TryCloneBranch(block->control_input(), block, graph(), common(), |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 458 | &block_effects, source_positions_); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 459 | break; |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 460 | } |
| 461 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 462 | // Store the effect, control and frame state for later use. |
| 463 | for (BasicBlock* successor : block->successors()) { |
| 464 | BlockEffectControlData* data = &block_effects.For(block, successor); |
| 465 | if (data->current_effect == nullptr) { |
| 466 | data->current_effect = effect; |
| 467 | } |
| 468 | if (data->current_control == nullptr) { |
| 469 | data->current_control = control; |
| 470 | } |
| 471 | data->current_frame_state = frame_state; |
| 472 | } |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 473 | } |
| 474 | |
| 475 | // Update the incoming edges of the effect phis that could not be processed |
| 476 | // during the first pass (because they could have incoming back edges). |
| 477 | for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) { |
| 478 | UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block, |
| 479 | &block_effects); |
| 480 | } |
| 481 | for (BasicBlock* pending_block_control : pending_block_controls) { |
| 482 | UpdateBlockControl(pending_block_control, &block_effects); |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | namespace { |
| 487 | |
| 488 | void TryScheduleCallIfSuccess(Node* node, Node** control) { |
| 489 | // Schedule the call's IfSuccess node if there is no exception use. |
| 490 | if (!NodeProperties::IsExceptionalCall(node)) { |
| 491 | for (Edge edge : node->use_edges()) { |
| 492 | if (NodeProperties::IsControlEdge(edge) && |
| 493 | edge.from()->opcode() == IrOpcode::kIfSuccess) { |
| 494 | *control = edge.from(); |
| 495 | } |
| 496 | } |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | } // namespace |
| 501 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 502 | void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state, |
| 503 | Node** effect, Node** control) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 504 | SourcePositionTable::Scope scope(source_positions_, |
| 505 | source_positions_->GetSourcePosition(node)); |
| 506 | |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 507 | // If the node needs to be wired into the effect/control chain, do this |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 508 | // here. Pass current frame state for lowering to eager deoptimization. |
| 509 | if (TryWireInStateEffect(node, *frame_state, effect, control)) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 510 | return; |
| 511 | } |
| 512 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 513 | // If the node has a visible effect, then there must be a checkpoint in the |
| 514 | // effect chain before we are allowed to place another eager deoptimization |
| 515 | // point. We zap the frame state to ensure this invariant is maintained. |
| 516 | if (region_observability_ == RegionObservability::kObservable && |
| 517 | !node->op()->HasProperty(Operator::kNoWrite)) { |
| 518 | *frame_state = nullptr; |
| 519 | } |
| 520 | |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 521 | // Remove the end markers of 'atomic' allocation region because the |
| 522 | // region should be wired-in now. |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 523 | if (node->opcode() == IrOpcode::kFinishRegion) { |
| 524 | // Reset the current region observability. |
| 525 | region_observability_ = RegionObservability::kObservable; |
| 526 | // Update the value uses to the value input of the finish node and |
| 527 | // the effect uses to the effect input. |
| 528 | return RemoveRegionNode(node); |
| 529 | } |
| 530 | if (node->opcode() == IrOpcode::kBeginRegion) { |
| 531 | // Determine the observability for this region and use that for all |
| 532 | // nodes inside the region (i.e. ignore the absence of kNoWrite on |
| 533 | // StoreField and other operators). |
| 534 | DCHECK_NE(RegionObservability::kNotObservable, region_observability_); |
| 535 | region_observability_ = RegionObservabilityOf(node->op()); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 536 | // Update the value uses to the value input of the finish node and |
| 537 | // the effect uses to the effect input. |
| 538 | return RemoveRegionNode(node); |
| 539 | } |
| 540 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 541 | // Special treatment for checkpoint nodes. |
| 542 | if (node->opcode() == IrOpcode::kCheckpoint) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 543 | // Unlink the check point; effect uses will be updated to the incoming |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 544 | // effect that is passed. The frame state is preserved for lowering. |
| 545 | DCHECK_EQ(RegionObservability::kObservable, region_observability_); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 546 | *frame_state = NodeProperties::GetFrameStateInput(node); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 547 | return; |
| 548 | } |
| 549 | |
| 550 | if (node->opcode() == IrOpcode::kIfSuccess) { |
| 551 | // We always schedule IfSuccess with its call, so skip it here. |
| 552 | DCHECK_EQ(IrOpcode::kCall, node->InputAt(0)->opcode()); |
| 553 | // The IfSuccess node should not belong to an exceptional call node |
| 554 | // because such IfSuccess nodes should only start a basic block (and |
| 555 | // basic block start nodes are not handled in the ProcessNode method). |
| 556 | DCHECK(!NodeProperties::IsExceptionalCall(node->InputAt(0))); |
| 557 | return; |
| 558 | } |
| 559 | |
| 560 | // If the node takes an effect, replace with the current one. |
| 561 | if (node->op()->EffectInputCount() > 0) { |
| 562 | DCHECK_EQ(1, node->op()->EffectInputCount()); |
| 563 | Node* input_effect = NodeProperties::GetEffectInput(node); |
| 564 | |
| 565 | if (input_effect != *effect) { |
| 566 | NodeProperties::ReplaceEffectInput(node, *effect); |
| 567 | } |
| 568 | |
| 569 | // If the node produces an effect, update our current effect. (However, |
| 570 | // ignore new effect chains started with ValueEffect.) |
| 571 | if (node->op()->EffectOutputCount() > 0) { |
| 572 | DCHECK_EQ(1, node->op()->EffectOutputCount()); |
| 573 | *effect = node; |
| 574 | } |
| 575 | } else { |
| 576 | // New effect chain is only started with a Start or ValueEffect node. |
| 577 | DCHECK(node->op()->EffectOutputCount() == 0 || |
| 578 | node->opcode() == IrOpcode::kStart); |
| 579 | } |
| 580 | |
| 581 | // Rewire control inputs. |
| 582 | for (int i = 0; i < node->op()->ControlInputCount(); i++) { |
| 583 | NodeProperties::ReplaceControlInput(node, *control, i); |
| 584 | } |
| 585 | // Update the current control and wire IfSuccess right after calls. |
| 586 | if (node->op()->ControlOutputCount() > 0) { |
| 587 | *control = node; |
| 588 | if (node->opcode() == IrOpcode::kCall) { |
| 589 | // Schedule the call's IfSuccess node (if there is no exception use). |
| 590 | TryScheduleCallIfSuccess(node, control); |
| 591 | } |
| 592 | } |
| 593 | } |
| 594 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 595 | bool EffectControlLinearizer::TryWireInStateEffect(Node* node, |
| 596 | Node* frame_state, |
| 597 | Node** effect, |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 598 | Node** control) { |
| 599 | ValueEffectControl state(nullptr, nullptr, nullptr); |
| 600 | switch (node->opcode()) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 601 | case IrOpcode::kChangeBitToTagged: |
| 602 | state = LowerChangeBitToTagged(node, *effect, *control); |
| 603 | break; |
| 604 | case IrOpcode::kChangeInt31ToTaggedSigned: |
| 605 | state = LowerChangeInt31ToTaggedSigned(node, *effect, *control); |
| 606 | break; |
| 607 | case IrOpcode::kChangeInt32ToTagged: |
| 608 | state = LowerChangeInt32ToTagged(node, *effect, *control); |
| 609 | break; |
| 610 | case IrOpcode::kChangeUint32ToTagged: |
| 611 | state = LowerChangeUint32ToTagged(node, *effect, *control); |
| 612 | break; |
| 613 | case IrOpcode::kChangeFloat64ToTagged: |
| 614 | state = LowerChangeFloat64ToTagged(node, *effect, *control); |
| 615 | break; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 616 | case IrOpcode::kChangeFloat64ToTaggedPointer: |
| 617 | state = LowerChangeFloat64ToTaggedPointer(node, *effect, *control); |
| 618 | break; |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 619 | case IrOpcode::kChangeTaggedSignedToInt32: |
| 620 | state = LowerChangeTaggedSignedToInt32(node, *effect, *control); |
| 621 | break; |
| 622 | case IrOpcode::kChangeTaggedToBit: |
| 623 | state = LowerChangeTaggedToBit(node, *effect, *control); |
| 624 | break; |
| 625 | case IrOpcode::kChangeTaggedToInt32: |
| 626 | state = LowerChangeTaggedToInt32(node, *effect, *control); |
| 627 | break; |
| 628 | case IrOpcode::kChangeTaggedToUint32: |
| 629 | state = LowerChangeTaggedToUint32(node, *effect, *control); |
| 630 | break; |
| 631 | case IrOpcode::kChangeTaggedToFloat64: |
| 632 | state = LowerChangeTaggedToFloat64(node, *effect, *control); |
| 633 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 634 | case IrOpcode::kTruncateTaggedToBit: |
| 635 | state = LowerTruncateTaggedToBit(node, *effect, *control); |
| 636 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 637 | case IrOpcode::kTruncateTaggedToFloat64: |
| 638 | state = LowerTruncateTaggedToFloat64(node, *effect, *control); |
| 639 | break; |
| 640 | case IrOpcode::kCheckBounds: |
| 641 | state = LowerCheckBounds(node, frame_state, *effect, *control); |
| 642 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 643 | case IrOpcode::kCheckMaps: |
| 644 | state = LowerCheckMaps(node, frame_state, *effect, *control); |
| 645 | break; |
| 646 | case IrOpcode::kCheckNumber: |
| 647 | state = LowerCheckNumber(node, frame_state, *effect, *control); |
| 648 | break; |
| 649 | case IrOpcode::kCheckString: |
| 650 | state = LowerCheckString(node, frame_state, *effect, *control); |
| 651 | break; |
| 652 | case IrOpcode::kCheckIf: |
| 653 | state = LowerCheckIf(node, frame_state, *effect, *control); |
| 654 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 655 | case IrOpcode::kCheckedInt32Add: |
| 656 | state = LowerCheckedInt32Add(node, frame_state, *effect, *control); |
| 657 | break; |
| 658 | case IrOpcode::kCheckedInt32Sub: |
| 659 | state = LowerCheckedInt32Sub(node, frame_state, *effect, *control); |
| 660 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 661 | case IrOpcode::kCheckedInt32Div: |
| 662 | state = LowerCheckedInt32Div(node, frame_state, *effect, *control); |
| 663 | break; |
| 664 | case IrOpcode::kCheckedInt32Mod: |
| 665 | state = LowerCheckedInt32Mod(node, frame_state, *effect, *control); |
| 666 | break; |
| 667 | case IrOpcode::kCheckedUint32Div: |
| 668 | state = LowerCheckedUint32Div(node, frame_state, *effect, *control); |
| 669 | break; |
| 670 | case IrOpcode::kCheckedUint32Mod: |
| 671 | state = LowerCheckedUint32Mod(node, frame_state, *effect, *control); |
| 672 | break; |
| 673 | case IrOpcode::kCheckedInt32Mul: |
| 674 | state = LowerCheckedInt32Mul(node, frame_state, *effect, *control); |
| 675 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 676 | case IrOpcode::kCheckedInt32ToTaggedSigned: |
| 677 | state = |
| 678 | LowerCheckedInt32ToTaggedSigned(node, frame_state, *effect, *control); |
| 679 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 680 | case IrOpcode::kCheckedUint32ToInt32: |
| 681 | state = LowerCheckedUint32ToInt32(node, frame_state, *effect, *control); |
| 682 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 683 | case IrOpcode::kCheckedUint32ToTaggedSigned: |
| 684 | state = LowerCheckedUint32ToTaggedSigned(node, frame_state, *effect, |
| 685 | *control); |
| 686 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 687 | case IrOpcode::kCheckedFloat64ToInt32: |
| 688 | state = LowerCheckedFloat64ToInt32(node, frame_state, *effect, *control); |
| 689 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 690 | case IrOpcode::kCheckedTaggedSignedToInt32: |
| 691 | state = |
| 692 | LowerCheckedTaggedSignedToInt32(node, frame_state, *effect, *control); |
| 693 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 694 | case IrOpcode::kCheckedTaggedToInt32: |
| 695 | state = LowerCheckedTaggedToInt32(node, frame_state, *effect, *control); |
| 696 | break; |
| 697 | case IrOpcode::kCheckedTaggedToFloat64: |
| 698 | state = LowerCheckedTaggedToFloat64(node, frame_state, *effect, *control); |
| 699 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 700 | case IrOpcode::kCheckedTaggedToTaggedSigned: |
| 701 | state = LowerCheckedTaggedToTaggedSigned(node, frame_state, *effect, |
| 702 | *control); |
| 703 | break; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 704 | case IrOpcode::kCheckedTaggedToTaggedPointer: |
| 705 | state = LowerCheckedTaggedToTaggedPointer(node, frame_state, *effect, |
| 706 | *control); |
| 707 | break; |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 708 | case IrOpcode::kTruncateTaggedToWord32: |
| 709 | state = LowerTruncateTaggedToWord32(node, *effect, *control); |
| 710 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 711 | case IrOpcode::kCheckedTruncateTaggedToWord32: |
| 712 | state = LowerCheckedTruncateTaggedToWord32(node, frame_state, *effect, |
| 713 | *control); |
| 714 | break; |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 715 | case IrOpcode::kObjectIsCallable: |
| 716 | state = LowerObjectIsCallable(node, *effect, *control); |
| 717 | break; |
| 718 | case IrOpcode::kObjectIsNumber: |
| 719 | state = LowerObjectIsNumber(node, *effect, *control); |
| 720 | break; |
| 721 | case IrOpcode::kObjectIsReceiver: |
| 722 | state = LowerObjectIsReceiver(node, *effect, *control); |
| 723 | break; |
| 724 | case IrOpcode::kObjectIsSmi: |
| 725 | state = LowerObjectIsSmi(node, *effect, *control); |
| 726 | break; |
| 727 | case IrOpcode::kObjectIsString: |
| 728 | state = LowerObjectIsString(node, *effect, *control); |
| 729 | break; |
| 730 | case IrOpcode::kObjectIsUndetectable: |
| 731 | state = LowerObjectIsUndetectable(node, *effect, *control); |
| 732 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 733 | case IrOpcode::kArrayBufferWasNeutered: |
| 734 | state = LowerArrayBufferWasNeutered(node, *effect, *control); |
| 735 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 736 | case IrOpcode::kStringFromCharCode: |
| 737 | state = LowerStringFromCharCode(node, *effect, *control); |
| 738 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 739 | case IrOpcode::kStringFromCodePoint: |
| 740 | state = LowerStringFromCodePoint(node, *effect, *control); |
| 741 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 742 | case IrOpcode::kStringCharCodeAt: |
| 743 | state = LowerStringCharCodeAt(node, *effect, *control); |
| 744 | break; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 745 | case IrOpcode::kStringEqual: |
| 746 | state = LowerStringEqual(node, *effect, *control); |
| 747 | break; |
| 748 | case IrOpcode::kStringLessThan: |
| 749 | state = LowerStringLessThan(node, *effect, *control); |
| 750 | break; |
| 751 | case IrOpcode::kStringLessThanOrEqual: |
| 752 | state = LowerStringLessThanOrEqual(node, *effect, *control); |
| 753 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 754 | case IrOpcode::kCheckFloat64Hole: |
| 755 | state = LowerCheckFloat64Hole(node, frame_state, *effect, *control); |
| 756 | break; |
| 757 | case IrOpcode::kCheckTaggedHole: |
| 758 | state = LowerCheckTaggedHole(node, frame_state, *effect, *control); |
| 759 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 760 | case IrOpcode::kConvertTaggedHoleToUndefined: |
| 761 | state = LowerConvertTaggedHoleToUndefined(node, *effect, *control); |
| 762 | break; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 763 | case IrOpcode::kPlainPrimitiveToNumber: |
| 764 | state = LowerPlainPrimitiveToNumber(node, *effect, *control); |
| 765 | break; |
| 766 | case IrOpcode::kPlainPrimitiveToWord32: |
| 767 | state = LowerPlainPrimitiveToWord32(node, *effect, *control); |
| 768 | break; |
| 769 | case IrOpcode::kPlainPrimitiveToFloat64: |
| 770 | state = LowerPlainPrimitiveToFloat64(node, *effect, *control); |
| 771 | break; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 772 | case IrOpcode::kEnsureWritableFastElements: |
| 773 | state = LowerEnsureWritableFastElements(node, *effect, *control); |
| 774 | break; |
| 775 | case IrOpcode::kMaybeGrowFastElements: |
| 776 | state = LowerMaybeGrowFastElements(node, frame_state, *effect, *control); |
| 777 | break; |
| 778 | case IrOpcode::kTransitionElementsKind: |
| 779 | state = LowerTransitionElementsKind(node, *effect, *control); |
| 780 | break; |
| 781 | case IrOpcode::kLoadTypedElement: |
| 782 | state = LowerLoadTypedElement(node, *effect, *control); |
| 783 | break; |
| 784 | case IrOpcode::kStoreTypedElement: |
| 785 | state = LowerStoreTypedElement(node, *effect, *control); |
| 786 | break; |
| 787 | case IrOpcode::kFloat64RoundUp: |
| 788 | state = LowerFloat64RoundUp(node, *effect, *control); |
| 789 | break; |
| 790 | case IrOpcode::kFloat64RoundDown: |
| 791 | state = LowerFloat64RoundDown(node, *effect, *control); |
| 792 | break; |
| 793 | case IrOpcode::kFloat64RoundTruncate: |
| 794 | state = LowerFloat64RoundTruncate(node, *effect, *control); |
| 795 | break; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 796 | case IrOpcode::kFloat64RoundTiesEven: |
| 797 | state = LowerFloat64RoundTiesEven(node, *effect, *control); |
| 798 | break; |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 799 | default: |
| 800 | return false; |
| 801 | } |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 802 | NodeProperties::ReplaceUses(node, state.value, state.effect, state.control); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 803 | *effect = state.effect; |
| 804 | *control = state.control; |
| 805 | return true; |
| 806 | } |
| 807 | |
| 808 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 809 | EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node, Node* effect, |
| 810 | Node* control) { |
| 811 | Node* value = node->InputAt(0); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 812 | return AllocateHeapNumberWithValue(value, effect, control); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 813 | } |
| 814 | |
| 815 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 816 | EffectControlLinearizer::LowerChangeFloat64ToTaggedPointer(Node* node, |
| 817 | Node* effect, |
| 818 | Node* control) { |
| 819 | Node* value = node->InputAt(0); |
| 820 | return AllocateHeapNumberWithValue(value, effect, control); |
| 821 | } |
| 822 | |
| 823 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 824 | EffectControlLinearizer::LowerChangeBitToTagged(Node* node, Node* effect, |
| 825 | Node* control) { |
| 826 | Node* value = node->InputAt(0); |
| 827 | |
| 828 | Node* branch = graph()->NewNode(common()->Branch(), value, control); |
| 829 | |
| 830 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 831 | Node* vtrue = jsgraph()->TrueConstant(); |
| 832 | |
| 833 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 834 | Node* vfalse = jsgraph()->FalseConstant(); |
| 835 | |
| 836 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 837 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 838 | vtrue, vfalse, control); |
| 839 | |
| 840 | return ValueEffectControl(value, effect, control); |
| 841 | } |
| 842 | |
| 843 | EffectControlLinearizer::ValueEffectControl |
| 844 | EffectControlLinearizer::LowerChangeInt31ToTaggedSigned(Node* node, |
| 845 | Node* effect, |
| 846 | Node* control) { |
| 847 | Node* value = node->InputAt(0); |
| 848 | value = ChangeInt32ToSmi(value); |
| 849 | return ValueEffectControl(value, effect, control); |
| 850 | } |
| 851 | |
| 852 | EffectControlLinearizer::ValueEffectControl |
| 853 | EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node, Node* effect, |
| 854 | Node* control) { |
| 855 | Node* value = node->InputAt(0); |
| 856 | |
| 857 | if (machine()->Is64()) { |
| 858 | return ValueEffectControl(ChangeInt32ToSmi(value), effect, control); |
| 859 | } |
| 860 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 861 | Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value, |
| 862 | control); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 863 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 864 | Node* ovf = graph()->NewNode(common()->Projection(1), add, control); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 865 | Node* branch = |
| 866 | graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control); |
| 867 | |
| 868 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 869 | ValueEffectControl alloc = |
| 870 | AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), effect, if_true); |
| 871 | |
| 872 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 873 | Node* vfalse = graph()->NewNode(common()->Projection(0), add, if_false); |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 874 | |
| 875 | Node* merge = graph()->NewNode(common()->Merge(2), alloc.control, if_false); |
| 876 | Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 877 | alloc.value, vfalse, merge); |
| 878 | Node* ephi = |
| 879 | graph()->NewNode(common()->EffectPhi(2), alloc.effect, effect, merge); |
| 880 | |
| 881 | return ValueEffectControl(phi, ephi, merge); |
| 882 | } |
| 883 | |
| 884 | EffectControlLinearizer::ValueEffectControl |
| 885 | EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node, Node* effect, |
| 886 | Node* control) { |
| 887 | Node* value = node->InputAt(0); |
| 888 | |
| 889 | Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, |
| 890 | SmiMaxValueConstant()); |
| 891 | Node* branch = |
| 892 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 893 | |
| 894 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 895 | Node* vtrue = ChangeUint32ToSmi(value); |
| 896 | |
| 897 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 898 | ValueEffectControl alloc = AllocateHeapNumberWithValue( |
| 899 | ChangeUint32ToFloat64(value), effect, if_false); |
| 900 | |
| 901 | Node* merge = graph()->NewNode(common()->Merge(2), if_true, alloc.control); |
| 902 | Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 903 | vtrue, alloc.value, merge); |
| 904 | Node* ephi = |
| 905 | graph()->NewNode(common()->EffectPhi(2), effect, alloc.effect, merge); |
| 906 | |
| 907 | return ValueEffectControl(phi, ephi, merge); |
| 908 | } |
| 909 | |
| 910 | EffectControlLinearizer::ValueEffectControl |
| 911 | EffectControlLinearizer::LowerChangeTaggedSignedToInt32(Node* node, |
| 912 | Node* effect, |
| 913 | Node* control) { |
| 914 | Node* value = node->InputAt(0); |
| 915 | value = ChangeSmiToInt32(value); |
| 916 | return ValueEffectControl(value, effect, control); |
| 917 | } |
| 918 | |
| 919 | EffectControlLinearizer::ValueEffectControl |
| 920 | EffectControlLinearizer::LowerChangeTaggedToBit(Node* node, Node* effect, |
| 921 | Node* control) { |
| 922 | Node* value = node->InputAt(0); |
| 923 | value = graph()->NewNode(machine()->WordEqual(), value, |
| 924 | jsgraph()->TrueConstant()); |
| 925 | return ValueEffectControl(value, effect, control); |
| 926 | } |
| 927 | |
| 928 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 929 | EffectControlLinearizer::LowerTruncateTaggedToBit(Node* node, Node* effect, |
| 930 | Node* control) { |
| 931 | Node* value = node->InputAt(0); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 932 | Node* zero = jsgraph()->Int32Constant(0); |
| 933 | Node* fzero = jsgraph()->Float64Constant(0.0); |
| 934 | |
| 935 | // Collect effect/control/value triples. |
| 936 | int count = 0; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 937 | Node* values[6]; |
| 938 | Node* effects[6]; |
| 939 | Node* controls[5]; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 940 | |
| 941 | // Check if {value} is a Smi. |
| 942 | Node* check_smi = ObjectIsSmi(value); |
| 943 | Node* branch_smi = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 944 | check_smi, control); |
| 945 | |
| 946 | // If {value} is a Smi, then we only need to check that it's not zero. |
| 947 | Node* if_smi = graph()->NewNode(common()->IfTrue(), branch_smi); |
| 948 | Node* esmi = effect; |
| 949 | { |
| 950 | controls[count] = if_smi; |
| 951 | effects[count] = esmi; |
| 952 | values[count] = |
| 953 | graph()->NewNode(machine()->Word32Equal(), |
| 954 | graph()->NewNode(machine()->WordEqual(), value, |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 955 | jsgraph()->IntPtrConstant(0)), |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 956 | zero); |
| 957 | count++; |
| 958 | } |
| 959 | control = graph()->NewNode(common()->IfFalse(), branch_smi); |
| 960 | |
| 961 | // Load the map instance type of {value}. |
| 962 | Node* value_map = effect = graph()->NewNode( |
| 963 | simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control); |
| 964 | Node* value_instance_type = effect = graph()->NewNode( |
| 965 | simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map, |
| 966 | effect, control); |
| 967 | |
| 968 | // Check if {value} is an Oddball. |
| 969 | Node* check_oddball = |
| 970 | graph()->NewNode(machine()->Word32Equal(), value_instance_type, |
| 971 | jsgraph()->Int32Constant(ODDBALL_TYPE)); |
| 972 | Node* branch_oddball = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 973 | check_oddball, control); |
| 974 | |
| 975 | // The only Oddball {value} that is trueish is true itself. |
| 976 | Node* if_oddball = graph()->NewNode(common()->IfTrue(), branch_oddball); |
| 977 | Node* eoddball = effect; |
| 978 | { |
| 979 | controls[count] = if_oddball; |
| 980 | effects[count] = eoddball; |
| 981 | values[count] = graph()->NewNode(machine()->WordEqual(), value, |
| 982 | jsgraph()->TrueConstant()); |
| 983 | count++; |
| 984 | } |
| 985 | control = graph()->NewNode(common()->IfFalse(), branch_oddball); |
| 986 | |
| 987 | // Check if {value} is a String. |
| 988 | Node* check_string = |
| 989 | graph()->NewNode(machine()->Int32LessThan(), value_instance_type, |
| 990 | jsgraph()->Int32Constant(FIRST_NONSTRING_TYPE)); |
| 991 | Node* branch_string = |
| 992 | graph()->NewNode(common()->Branch(), check_string, control); |
| 993 | |
| 994 | // For String {value}, we need to check that the length is not zero. |
| 995 | Node* if_string = graph()->NewNode(common()->IfTrue(), branch_string); |
| 996 | Node* estring = effect; |
| 997 | { |
| 998 | // Load the {value} length. |
| 999 | Node* value_length = estring = graph()->NewNode( |
| 1000 | simplified()->LoadField(AccessBuilder::ForStringLength()), value, |
| 1001 | estring, if_string); |
| 1002 | |
| 1003 | controls[count] = if_string; |
| 1004 | effects[count] = estring; |
| 1005 | values[count] = |
| 1006 | graph()->NewNode(machine()->Word32Equal(), |
| 1007 | graph()->NewNode(machine()->WordEqual(), value_length, |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 1008 | jsgraph()->IntPtrConstant(0)), |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1009 | zero); |
| 1010 | count++; |
| 1011 | } |
| 1012 | control = graph()->NewNode(common()->IfFalse(), branch_string); |
| 1013 | |
| 1014 | // Check if {value} is a HeapNumber. |
| 1015 | Node* check_heapnumber = |
| 1016 | graph()->NewNode(machine()->Word32Equal(), value_instance_type, |
| 1017 | jsgraph()->Int32Constant(HEAP_NUMBER_TYPE)); |
| 1018 | Node* branch_heapnumber = |
| 1019 | graph()->NewNode(common()->Branch(), check_heapnumber, control); |
| 1020 | |
| 1021 | // For HeapNumber {value}, just check that its value is not 0.0, -0.0 or NaN. |
| 1022 | Node* if_heapnumber = graph()->NewNode(common()->IfTrue(), branch_heapnumber); |
| 1023 | Node* eheapnumber = effect; |
| 1024 | { |
| 1025 | // Load the raw value of {value}. |
| 1026 | Node* value_value = eheapnumber = graph()->NewNode( |
| 1027 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1028 | eheapnumber, if_heapnumber); |
| 1029 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 1030 | // Check if {value} is not one of 0, -0, or NaN. |
| 1031 | controls[count] = if_heapnumber; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1032 | effects[count] = eheapnumber; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 1033 | values[count] = graph()->NewNode( |
| 1034 | machine()->Float64LessThan(), fzero, |
| 1035 | graph()->NewNode(machine()->Float64Abs(), value_value)); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1036 | count++; |
| 1037 | } |
| 1038 | control = graph()->NewNode(common()->IfFalse(), branch_heapnumber); |
| 1039 | |
| 1040 | // The {value} is either a JSReceiver, a Symbol or some Simd128Value. In |
| 1041 | // those cases we can just the undetectable bit on the map, which will only |
| 1042 | // be set for certain JSReceivers, i.e. document.all. |
| 1043 | { |
| 1044 | // Load the {value} map bit field. |
| 1045 | Node* value_map_bitfield = effect = graph()->NewNode( |
| 1046 | simplified()->LoadField(AccessBuilder::ForMapBitField()), value_map, |
| 1047 | effect, control); |
| 1048 | |
| 1049 | controls[count] = control; |
| 1050 | effects[count] = effect; |
| 1051 | values[count] = graph()->NewNode( |
| 1052 | machine()->Word32Equal(), |
| 1053 | graph()->NewNode(machine()->Word32And(), value_map_bitfield, |
| 1054 | jsgraph()->Int32Constant(1 << Map::kIsUndetectable)), |
| 1055 | zero); |
| 1056 | count++; |
| 1057 | } |
| 1058 | |
| 1059 | // Merge the different controls. |
| 1060 | control = graph()->NewNode(common()->Merge(count), count, controls); |
| 1061 | effects[count] = control; |
| 1062 | effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects); |
| 1063 | values[count] = control; |
| 1064 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, count), |
| 1065 | count + 1, values); |
| 1066 | |
| 1067 | return ValueEffectControl(value, effect, control); |
| 1068 | } |
| 1069 | |
| 1070 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 1071 | EffectControlLinearizer::LowerChangeTaggedToInt32(Node* node, Node* effect, |
| 1072 | Node* control) { |
| 1073 | Node* value = node->InputAt(0); |
| 1074 | |
| 1075 | Node* check = ObjectIsSmi(value); |
| 1076 | Node* branch = |
| 1077 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1078 | |
| 1079 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1080 | Node* etrue = effect; |
| 1081 | Node* vtrue = ChangeSmiToInt32(value); |
| 1082 | |
| 1083 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1084 | Node* efalse = effect; |
| 1085 | Node* vfalse; |
| 1086 | { |
| 1087 | STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); |
| 1088 | vfalse = efalse = graph()->NewNode( |
| 1089 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1090 | efalse, if_false); |
| 1091 | vfalse = graph()->NewNode(machine()->ChangeFloat64ToInt32(), vfalse); |
| 1092 | } |
| 1093 | |
| 1094 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1095 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1096 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 1097 | vtrue, vfalse, control); |
| 1098 | |
| 1099 | return ValueEffectControl(value, effect, control); |
| 1100 | } |
| 1101 | |
| 1102 | EffectControlLinearizer::ValueEffectControl |
| 1103 | EffectControlLinearizer::LowerChangeTaggedToUint32(Node* node, Node* effect, |
| 1104 | Node* control) { |
| 1105 | Node* value = node->InputAt(0); |
| 1106 | |
| 1107 | Node* check = ObjectIsSmi(value); |
| 1108 | Node* branch = |
| 1109 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1110 | |
| 1111 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1112 | Node* etrue = effect; |
| 1113 | Node* vtrue = ChangeSmiToInt32(value); |
| 1114 | |
| 1115 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1116 | Node* efalse = effect; |
| 1117 | Node* vfalse; |
| 1118 | { |
| 1119 | STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); |
| 1120 | vfalse = efalse = graph()->NewNode( |
| 1121 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1122 | efalse, if_false); |
| 1123 | vfalse = graph()->NewNode(machine()->ChangeFloat64ToUint32(), vfalse); |
| 1124 | } |
| 1125 | |
| 1126 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1127 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1128 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 1129 | vtrue, vfalse, control); |
| 1130 | |
| 1131 | return ValueEffectControl(value, effect, control); |
| 1132 | } |
| 1133 | |
| 1134 | EffectControlLinearizer::ValueEffectControl |
| 1135 | EffectControlLinearizer::LowerChangeTaggedToFloat64(Node* node, Node* effect, |
| 1136 | Node* control) { |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1137 | return LowerTruncateTaggedToFloat64(node, effect, control); |
| 1138 | } |
| 1139 | |
| 1140 | EffectControlLinearizer::ValueEffectControl |
| 1141 | EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node, Node* effect, |
| 1142 | Node* control) { |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 1143 | Node* value = node->InputAt(0); |
| 1144 | |
| 1145 | Node* check = ObjectIsSmi(value); |
| 1146 | Node* branch = |
| 1147 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1148 | |
| 1149 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1150 | Node* etrue = effect; |
| 1151 | Node* vtrue; |
| 1152 | { |
| 1153 | vtrue = ChangeSmiToInt32(value); |
| 1154 | vtrue = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue); |
| 1155 | } |
| 1156 | |
| 1157 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1158 | Node* efalse = effect; |
| 1159 | Node* vfalse; |
| 1160 | { |
| 1161 | STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); |
| 1162 | vfalse = efalse = graph()->NewNode( |
| 1163 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1164 | efalse, if_false); |
| 1165 | } |
| 1166 | |
| 1167 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1168 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1169 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 1170 | vtrue, vfalse, control); |
| 1171 | |
| 1172 | return ValueEffectControl(value, effect, control); |
| 1173 | } |
| 1174 | |
| 1175 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1176 | EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state, |
| 1177 | Node* effect, Node* control) { |
| 1178 | Node* index = node->InputAt(0); |
| 1179 | Node* limit = node->InputAt(1); |
| 1180 | |
| 1181 | Node* check = graph()->NewNode(machine()->Uint32LessThan(), index, limit); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1182 | control = effect = graph()->NewNode( |
| 1183 | common()->DeoptimizeUnless(DeoptimizeReason::kOutOfBounds), check, |
| 1184 | frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1185 | |
| 1186 | return ValueEffectControl(index, effect, control); |
| 1187 | } |
| 1188 | |
| 1189 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1190 | EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state, |
| 1191 | Node* effect, Node* control) { |
| 1192 | Node* value = node->InputAt(0); |
| 1193 | |
| 1194 | // Load the current map of the {value}. |
| 1195 | Node* value_map = effect = graph()->NewNode( |
| 1196 | simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control); |
| 1197 | |
| 1198 | int const map_count = node->op()->ValueInputCount() - 1; |
| 1199 | Node** controls = temp_zone()->NewArray<Node*>(map_count); |
| 1200 | Node** effects = temp_zone()->NewArray<Node*>(map_count + 1); |
| 1201 | |
| 1202 | for (int i = 0; i < map_count; ++i) { |
| 1203 | Node* map = node->InputAt(1 + i); |
| 1204 | |
| 1205 | Node* check = graph()->NewNode(machine()->WordEqual(), value_map, map); |
| 1206 | if (i == map_count - 1) { |
| 1207 | controls[i] = effects[i] = graph()->NewNode( |
| 1208 | common()->DeoptimizeUnless(DeoptimizeReason::kWrongMap), check, |
| 1209 | frame_state, effect, control); |
| 1210 | } else { |
| 1211 | control = graph()->NewNode(common()->Branch(), check, control); |
| 1212 | controls[i] = graph()->NewNode(common()->IfTrue(), control); |
| 1213 | control = graph()->NewNode(common()->IfFalse(), control); |
| 1214 | effects[i] = effect; |
| 1215 | } |
| 1216 | } |
| 1217 | |
| 1218 | control = graph()->NewNode(common()->Merge(map_count), map_count, controls); |
| 1219 | effects[map_count] = control; |
| 1220 | effect = |
| 1221 | graph()->NewNode(common()->EffectPhi(map_count), map_count + 1, effects); |
| 1222 | |
| 1223 | return ValueEffectControl(value, effect, control); |
| 1224 | } |
| 1225 | |
| 1226 | EffectControlLinearizer::ValueEffectControl |
| 1227 | EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state, |
| 1228 | Node* effect, Node* control) { |
| 1229 | Node* value = node->InputAt(0); |
| 1230 | |
| 1231 | Node* check0 = ObjectIsSmi(value); |
| 1232 | Node* branch0 = |
| 1233 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 1234 | |
| 1235 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1236 | Node* etrue0 = effect; |
| 1237 | |
| 1238 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1239 | Node* efalse0 = effect; |
| 1240 | { |
| 1241 | Node* value_map = efalse0 = |
| 1242 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1243 | value, efalse0, if_false0); |
| 1244 | Node* check1 = graph()->NewNode(machine()->WordEqual(), value_map, |
| 1245 | jsgraph()->HeapNumberMapConstant()); |
| 1246 | if_false0 = efalse0 = graph()->NewNode( |
| 1247 | common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber), check1, |
| 1248 | frame_state, efalse0, if_false0); |
| 1249 | } |
| 1250 | |
| 1251 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 1252 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 1253 | |
| 1254 | return ValueEffectControl(value, effect, control); |
| 1255 | } |
| 1256 | |
| 1257 | EffectControlLinearizer::ValueEffectControl |
| 1258 | EffectControlLinearizer::LowerCheckString(Node* node, Node* frame_state, |
| 1259 | Node* effect, Node* control) { |
| 1260 | Node* value = node->InputAt(0); |
| 1261 | |
| 1262 | Node* check0 = ObjectIsSmi(value); |
| 1263 | control = effect = |
| 1264 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kSmi), check0, |
| 1265 | frame_state, effect, control); |
| 1266 | |
| 1267 | Node* value_map = effect = graph()->NewNode( |
| 1268 | simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control); |
| 1269 | Node* value_instance_type = effect = graph()->NewNode( |
| 1270 | simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map, |
| 1271 | effect, control); |
| 1272 | |
| 1273 | Node* check1 = |
| 1274 | graph()->NewNode(machine()->Uint32LessThan(), value_instance_type, |
| 1275 | jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); |
| 1276 | control = effect = graph()->NewNode( |
| 1277 | common()->DeoptimizeUnless(DeoptimizeReason::kWrongInstanceType), check1, |
| 1278 | frame_state, effect, control); |
| 1279 | |
| 1280 | return ValueEffectControl(value, effect, control); |
| 1281 | } |
| 1282 | |
| 1283 | EffectControlLinearizer::ValueEffectControl |
| 1284 | EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state, |
| 1285 | Node* effect, Node* control) { |
| 1286 | Node* value = node->InputAt(0); |
| 1287 | |
| 1288 | control = effect = |
| 1289 | graph()->NewNode(common()->DeoptimizeUnless(DeoptimizeReason::kNoReason), |
| 1290 | value, frame_state, effect, control); |
| 1291 | |
| 1292 | return ValueEffectControl(value, effect, control); |
| 1293 | } |
| 1294 | |
| 1295 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1296 | EffectControlLinearizer::LowerCheckedInt32Add(Node* node, Node* frame_state, |
| 1297 | Node* effect, Node* control) { |
| 1298 | Node* lhs = node->InputAt(0); |
| 1299 | Node* rhs = node->InputAt(1); |
| 1300 | |
| 1301 | Node* value = |
| 1302 | graph()->NewNode(machine()->Int32AddWithOverflow(), lhs, rhs, control); |
| 1303 | |
| 1304 | Node* check = graph()->NewNode(common()->Projection(1), value, control); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1305 | control = effect = |
| 1306 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow), |
| 1307 | check, frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1308 | |
| 1309 | value = graph()->NewNode(common()->Projection(0), value, control); |
| 1310 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1311 | return ValueEffectControl(value, effect, control); |
| 1312 | } |
| 1313 | |
| 1314 | EffectControlLinearizer::ValueEffectControl |
| 1315 | EffectControlLinearizer::LowerCheckedInt32Sub(Node* node, Node* frame_state, |
| 1316 | Node* effect, Node* control) { |
| 1317 | Node* lhs = node->InputAt(0); |
| 1318 | Node* rhs = node->InputAt(1); |
| 1319 | |
| 1320 | Node* value = |
| 1321 | graph()->NewNode(machine()->Int32SubWithOverflow(), lhs, rhs, control); |
| 1322 | |
| 1323 | Node* check = graph()->NewNode(common()->Projection(1), value, control); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1324 | control = effect = |
| 1325 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow), |
| 1326 | check, frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1327 | |
| 1328 | value = graph()->NewNode(common()->Projection(0), value, control); |
| 1329 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1330 | return ValueEffectControl(value, effect, control); |
| 1331 | } |
| 1332 | |
| 1333 | EffectControlLinearizer::ValueEffectControl |
| 1334 | EffectControlLinearizer::LowerCheckedInt32Div(Node* node, Node* frame_state, |
| 1335 | Node* effect, Node* control) { |
| 1336 | Node* zero = jsgraph()->Int32Constant(0); |
| 1337 | Node* minusone = jsgraph()->Int32Constant(-1); |
| 1338 | Node* minint = jsgraph()->Int32Constant(std::numeric_limits<int32_t>::min()); |
| 1339 | |
| 1340 | Node* lhs = node->InputAt(0); |
| 1341 | Node* rhs = node->InputAt(1); |
| 1342 | |
| 1343 | // Check if {rhs} is positive (and not zero). |
| 1344 | Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs); |
| 1345 | Node* branch0 = |
| 1346 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 1347 | |
| 1348 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1349 | Node* etrue0 = effect; |
| 1350 | Node* vtrue0; |
| 1351 | { |
| 1352 | // Fast case, no additional checking required. |
| 1353 | vtrue0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0); |
| 1354 | } |
| 1355 | |
| 1356 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1357 | Node* efalse0 = effect; |
| 1358 | Node* vfalse0; |
| 1359 | { |
| 1360 | // Check if {rhs} is zero. |
| 1361 | Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero); |
| 1362 | if_false0 = efalse0 = graph()->NewNode( |
| 1363 | common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check, |
| 1364 | frame_state, efalse0, if_false0); |
| 1365 | |
| 1366 | // Check if {lhs} is zero, as that would produce minus zero. |
| 1367 | check = graph()->NewNode(machine()->Word32Equal(), lhs, zero); |
| 1368 | if_false0 = efalse0 = |
| 1369 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero), |
| 1370 | check, frame_state, efalse0, if_false0); |
| 1371 | |
| 1372 | // Check if {lhs} is kMinInt and {rhs} is -1, in which case we'd have |
| 1373 | // to return -kMinInt, which is not representable. |
| 1374 | Node* check1 = graph()->NewNode(machine()->Word32Equal(), lhs, minint); |
| 1375 | Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 1376 | check1, if_false0); |
| 1377 | |
| 1378 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1379 | Node* etrue1 = efalse0; |
| 1380 | { |
| 1381 | // Check if {rhs} is -1. |
| 1382 | Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, minusone); |
| 1383 | if_true1 = etrue1 = |
| 1384 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow), |
| 1385 | check, frame_state, etrue1, if_true1); |
| 1386 | } |
| 1387 | |
| 1388 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 1389 | Node* efalse1 = efalse0; |
| 1390 | |
| 1391 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 1392 | efalse0 = |
| 1393 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
| 1394 | |
| 1395 | // Perform the actual integer division. |
| 1396 | vfalse0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_false0); |
| 1397 | } |
| 1398 | |
| 1399 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 1400 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 1401 | Node* value = |
| 1402 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue0, |
| 1403 | vfalse0, control); |
| 1404 | |
| 1405 | // Check if the remainder is non-zero. |
| 1406 | Node* check = |
| 1407 | graph()->NewNode(machine()->Word32Equal(), lhs, |
| 1408 | graph()->NewNode(machine()->Int32Mul(), rhs, value)); |
| 1409 | control = effect = graph()->NewNode( |
| 1410 | common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), check, |
| 1411 | frame_state, effect, control); |
| 1412 | |
| 1413 | return ValueEffectControl(value, effect, control); |
| 1414 | } |
| 1415 | |
| 1416 | EffectControlLinearizer::ValueEffectControl |
| 1417 | EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, Node* frame_state, |
| 1418 | Node* effect, Node* control) { |
| 1419 | Node* zero = jsgraph()->Int32Constant(0); |
| 1420 | Node* one = jsgraph()->Int32Constant(1); |
| 1421 | |
| 1422 | // General case for signed integer modulus, with optimization for (unknown) |
| 1423 | // power of 2 right hand side. |
| 1424 | // |
| 1425 | // if rhs <= 0 then |
| 1426 | // rhs = -rhs |
| 1427 | // deopt if rhs == 0 |
| 1428 | // if lhs < 0 then |
| 1429 | // let res = lhs % rhs in |
| 1430 | // deopt if res == 0 |
| 1431 | // res |
| 1432 | // else |
| 1433 | // let msk = rhs - 1 in |
| 1434 | // if rhs & msk == 0 then |
| 1435 | // lhs & msk |
| 1436 | // else |
| 1437 | // lhs % rhs |
| 1438 | // |
| 1439 | Node* lhs = node->InputAt(0); |
| 1440 | Node* rhs = node->InputAt(1); |
| 1441 | |
| 1442 | // Check if {rhs} is not strictly positive. |
| 1443 | Node* check0 = graph()->NewNode(machine()->Int32LessThanOrEqual(), rhs, zero); |
| 1444 | Node* branch0 = |
| 1445 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); |
| 1446 | |
| 1447 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 1448 | Node* etrue0 = effect; |
| 1449 | Node* vtrue0; |
| 1450 | { |
| 1451 | // Negate {rhs}, might still produce a negative result in case of |
| 1452 | // -2^31, but that is handled safely below. |
| 1453 | vtrue0 = graph()->NewNode(machine()->Int32Sub(), zero, rhs); |
| 1454 | |
| 1455 | // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. |
| 1456 | Node* check = graph()->NewNode(machine()->Word32Equal(), vtrue0, zero); |
| 1457 | if_true0 = etrue0 = graph()->NewNode( |
| 1458 | common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check, |
| 1459 | frame_state, etrue0, if_true0); |
| 1460 | } |
| 1461 | |
| 1462 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 1463 | Node* efalse0 = effect; |
| 1464 | Node* vfalse0 = rhs; |
| 1465 | |
| 1466 | // At this point {rhs} is either greater than zero or -2^31, both are |
| 1467 | // fine for the code that follows. |
| 1468 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 1469 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 1470 | rhs = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 1471 | vtrue0, vfalse0, control); |
| 1472 | |
| 1473 | // Check if {lhs} is negative. |
| 1474 | Node* check1 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero); |
| 1475 | Node* branch1 = |
| 1476 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); |
| 1477 | |
| 1478 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 1479 | Node* etrue1 = effect; |
| 1480 | Node* vtrue1; |
| 1481 | { |
| 1482 | // Compute the remainder using {lhs % msk}. |
| 1483 | vtrue1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1); |
| 1484 | |
| 1485 | // Check if we would have to return -0. |
| 1486 | Node* check = graph()->NewNode(machine()->Word32Equal(), vtrue1, zero); |
| 1487 | if_true1 = etrue1 = |
| 1488 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero), |
| 1489 | check, frame_state, etrue1, if_true1); |
| 1490 | } |
| 1491 | |
| 1492 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 1493 | Node* efalse1 = effect; |
| 1494 | Node* vfalse1; |
| 1495 | { |
| 1496 | Node* msk = graph()->NewNode(machine()->Int32Sub(), rhs, one); |
| 1497 | |
| 1498 | // Check if {rhs} minus one is a valid mask. |
| 1499 | Node* check2 = graph()->NewNode( |
| 1500 | machine()->Word32Equal(), |
| 1501 | graph()->NewNode(machine()->Word32And(), rhs, msk), zero); |
| 1502 | Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1); |
| 1503 | |
| 1504 | // Compute the remainder using {lhs & msk}. |
| 1505 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 1506 | Node* vtrue2 = graph()->NewNode(machine()->Word32And(), lhs, msk); |
| 1507 | |
| 1508 | // Compute the remainder using the generic {lhs % rhs}. |
| 1509 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 1510 | Node* vfalse2 = |
| 1511 | graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_false2); |
| 1512 | |
| 1513 | if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
| 1514 | vfalse1 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 1515 | vtrue2, vfalse2, if_false1); |
| 1516 | } |
| 1517 | |
| 1518 | control = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 1519 | effect = graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, control); |
| 1520 | Node* value = |
| 1521 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue1, |
| 1522 | vfalse1, control); |
| 1523 | |
| 1524 | return ValueEffectControl(value, effect, control); |
| 1525 | } |
| 1526 | |
| 1527 | EffectControlLinearizer::ValueEffectControl |
| 1528 | EffectControlLinearizer::LowerCheckedUint32Div(Node* node, Node* frame_state, |
| 1529 | Node* effect, Node* control) { |
| 1530 | Node* zero = jsgraph()->Int32Constant(0); |
| 1531 | |
| 1532 | Node* lhs = node->InputAt(0); |
| 1533 | Node* rhs = node->InputAt(1); |
| 1534 | |
| 1535 | // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. |
| 1536 | Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero); |
| 1537 | control = effect = graph()->NewNode( |
| 1538 | common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check, |
| 1539 | frame_state, effect, control); |
| 1540 | |
| 1541 | // Perform the actual unsigned integer division. |
| 1542 | Node* value = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, control); |
| 1543 | |
| 1544 | // Check if the remainder is non-zero. |
| 1545 | check = graph()->NewNode(machine()->Word32Equal(), lhs, |
| 1546 | graph()->NewNode(machine()->Int32Mul(), rhs, value)); |
| 1547 | control = effect = graph()->NewNode( |
| 1548 | common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), check, |
| 1549 | frame_state, effect, control); |
| 1550 | |
| 1551 | return ValueEffectControl(value, effect, control); |
| 1552 | } |
| 1553 | |
| 1554 | EffectControlLinearizer::ValueEffectControl |
| 1555 | EffectControlLinearizer::LowerCheckedUint32Mod(Node* node, Node* frame_state, |
| 1556 | Node* effect, Node* control) { |
| 1557 | Node* zero = jsgraph()->Int32Constant(0); |
| 1558 | |
| 1559 | Node* lhs = node->InputAt(0); |
| 1560 | Node* rhs = node->InputAt(1); |
| 1561 | |
| 1562 | // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. |
| 1563 | Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero); |
| 1564 | control = effect = graph()->NewNode( |
| 1565 | common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check, |
| 1566 | frame_state, effect, control); |
| 1567 | |
| 1568 | // Perform the actual unsigned integer modulus. |
| 1569 | Node* value = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, control); |
| 1570 | |
| 1571 | return ValueEffectControl(value, effect, control); |
| 1572 | } |
| 1573 | |
| 1574 | EffectControlLinearizer::ValueEffectControl |
| 1575 | EffectControlLinearizer::LowerCheckedInt32Mul(Node* node, Node* frame_state, |
| 1576 | Node* effect, Node* control) { |
| 1577 | CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op()); |
| 1578 | Node* zero = jsgraph()->Int32Constant(0); |
| 1579 | Node* lhs = node->InputAt(0); |
| 1580 | Node* rhs = node->InputAt(1); |
| 1581 | |
| 1582 | Node* projection = |
| 1583 | graph()->NewNode(machine()->Int32MulWithOverflow(), lhs, rhs, control); |
| 1584 | |
| 1585 | Node* check = graph()->NewNode(common()->Projection(1), projection, control); |
| 1586 | control = effect = |
| 1587 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow), |
| 1588 | check, frame_state, effect, control); |
| 1589 | |
| 1590 | Node* value = graph()->NewNode(common()->Projection(0), projection, control); |
| 1591 | |
| 1592 | if (mode == CheckForMinusZeroMode::kCheckForMinusZero) { |
| 1593 | Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value, zero); |
| 1594 | Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 1595 | check_zero, control); |
| 1596 | |
| 1597 | Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero); |
| 1598 | Node* e_if_zero = effect; |
| 1599 | { |
| 1600 | // We may need to return negative zero. |
| 1601 | Node* or_inputs = graph()->NewNode(machine()->Word32Or(), lhs, rhs); |
| 1602 | Node* check_or = |
| 1603 | graph()->NewNode(machine()->Int32LessThan(), or_inputs, zero); |
| 1604 | if_zero = e_if_zero = |
| 1605 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero), |
| 1606 | check_or, frame_state, e_if_zero, if_zero); |
| 1607 | } |
| 1608 | |
| 1609 | Node* if_not_zero = graph()->NewNode(common()->IfFalse(), branch_zero); |
| 1610 | Node* e_if_not_zero = effect; |
| 1611 | |
| 1612 | control = graph()->NewNode(common()->Merge(2), if_zero, if_not_zero); |
| 1613 | effect = graph()->NewNode(common()->EffectPhi(2), e_if_zero, e_if_not_zero, |
| 1614 | control); |
| 1615 | } |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1616 | |
| 1617 | return ValueEffectControl(value, effect, control); |
| 1618 | } |
| 1619 | |
| 1620 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1621 | EffectControlLinearizer::LowerCheckedInt32ToTaggedSigned(Node* node, |
| 1622 | Node* frame_state, |
| 1623 | Node* effect, |
| 1624 | Node* control) { |
| 1625 | DCHECK(SmiValuesAre31Bits()); |
| 1626 | Node* value = node->InputAt(0); |
| 1627 | |
| 1628 | Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value, |
| 1629 | control); |
| 1630 | |
| 1631 | Node* check = graph()->NewNode(common()->Projection(1), add, control); |
| 1632 | control = effect = |
| 1633 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow), |
| 1634 | check, frame_state, effect, control); |
| 1635 | |
| 1636 | value = graph()->NewNode(common()->Projection(0), add, control); |
| 1637 | |
| 1638 | return ValueEffectControl(value, effect, control); |
| 1639 | } |
| 1640 | |
| 1641 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1642 | EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node, |
| 1643 | Node* frame_state, |
| 1644 | Node* effect, |
| 1645 | Node* control) { |
| 1646 | Node* value = node->InputAt(0); |
| 1647 | Node* max_int = jsgraph()->Int32Constant(std::numeric_limits<int32_t>::max()); |
| 1648 | Node* is_safe = |
| 1649 | graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, max_int); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1650 | control = effect = graph()->NewNode( |
| 1651 | common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), is_safe, |
| 1652 | frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1653 | |
| 1654 | return ValueEffectControl(value, effect, control); |
| 1655 | } |
| 1656 | |
| 1657 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1658 | EffectControlLinearizer::LowerCheckedUint32ToTaggedSigned(Node* node, |
| 1659 | Node* frame_state, |
| 1660 | Node* effect, |
| 1661 | Node* control) { |
| 1662 | Node* value = node->InputAt(0); |
| 1663 | Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, |
| 1664 | SmiMaxValueConstant()); |
| 1665 | control = effect = graph()->NewNode( |
| 1666 | common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), check, |
| 1667 | frame_state, effect, control); |
| 1668 | value = ChangeUint32ToSmi(value); |
| 1669 | |
| 1670 | return ValueEffectControl(value, effect, control); |
| 1671 | } |
| 1672 | |
| 1673 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1674 | EffectControlLinearizer::BuildCheckedFloat64ToInt32(CheckForMinusZeroMode mode, |
| 1675 | Node* value, |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1676 | Node* frame_state, |
| 1677 | Node* effect, |
| 1678 | Node* control) { |
| 1679 | Node* value32 = graph()->NewNode(machine()->RoundFloat64ToInt32(), value); |
| 1680 | Node* check_same = graph()->NewNode( |
| 1681 | machine()->Float64Equal(), value, |
| 1682 | graph()->NewNode(machine()->ChangeInt32ToFloat64(), value32)); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1683 | control = effect = graph()->NewNode( |
| 1684 | common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecisionOrNaN), |
| 1685 | check_same, frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1686 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1687 | if (mode == CheckForMinusZeroMode::kCheckForMinusZero) { |
| 1688 | // Check if {value} is -0. |
| 1689 | Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value32, |
| 1690 | jsgraph()->Int32Constant(0)); |
| 1691 | Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 1692 | check_zero, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1693 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1694 | Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero); |
| 1695 | Node* if_notzero = graph()->NewNode(common()->IfFalse(), branch_zero); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1696 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1697 | // In case of 0, we need to check the high bits for the IEEE -0 pattern. |
| 1698 | Node* check_negative = graph()->NewNode( |
| 1699 | machine()->Int32LessThan(), |
| 1700 | graph()->NewNode(machine()->Float64ExtractHighWord32(), value), |
| 1701 | jsgraph()->Int32Constant(0)); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1702 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1703 | Node* deopt_minus_zero = |
| 1704 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero), |
| 1705 | check_negative, frame_state, effect, if_zero); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1706 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1707 | control = |
| 1708 | graph()->NewNode(common()->Merge(2), deopt_minus_zero, if_notzero); |
| 1709 | effect = graph()->NewNode(common()->EffectPhi(2), deopt_minus_zero, effect, |
| 1710 | control); |
| 1711 | } |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1712 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1713 | return ValueEffectControl(value32, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1714 | } |
| 1715 | |
| 1716 | EffectControlLinearizer::ValueEffectControl |
| 1717 | EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node, |
| 1718 | Node* frame_state, |
| 1719 | Node* effect, |
| 1720 | Node* control) { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1721 | CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op()); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1722 | Node* value = node->InputAt(0); |
| 1723 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1724 | return BuildCheckedFloat64ToInt32(mode, value, frame_state, effect, control); |
| 1725 | } |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1726 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1727 | EffectControlLinearizer::ValueEffectControl |
| 1728 | EffectControlLinearizer::LowerCheckedTaggedSignedToInt32(Node* node, |
| 1729 | Node* frame_state, |
| 1730 | Node* effect, |
| 1731 | Node* control) { |
| 1732 | Node* value = node->InputAt(0); |
| 1733 | |
| 1734 | Node* check = ObjectIsSmi(value); |
| 1735 | control = effect = |
| 1736 | graph()->NewNode(common()->DeoptimizeUnless(DeoptimizeReason::kNotASmi), |
| 1737 | check, frame_state, effect, control); |
| 1738 | value = ChangeSmiToInt32(value); |
| 1739 | |
| 1740 | return ValueEffectControl(value, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1741 | } |
| 1742 | |
| 1743 | EffectControlLinearizer::ValueEffectControl |
| 1744 | EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node, |
| 1745 | Node* frame_state, |
| 1746 | Node* effect, |
| 1747 | Node* control) { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1748 | CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op()); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1749 | Node* value = node->InputAt(0); |
| 1750 | |
| 1751 | Node* check = ObjectIsSmi(value); |
| 1752 | Node* branch = |
| 1753 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1754 | |
| 1755 | // In the Smi case, just convert to int32. |
| 1756 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1757 | Node* etrue = effect; |
| 1758 | Node* vtrue = ChangeSmiToInt32(value); |
| 1759 | |
| 1760 | // In the non-Smi case, check the heap numberness, load the number and convert |
| 1761 | // to int32. |
| 1762 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1763 | Node* efalse = effect; |
| 1764 | Node* vfalse; |
| 1765 | { |
| 1766 | Node* value_map = efalse = |
| 1767 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1768 | value, efalse, if_false); |
| 1769 | Node* check = graph()->NewNode(machine()->WordEqual(), value_map, |
| 1770 | jsgraph()->HeapNumberMapConstant()); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1771 | if_false = efalse = graph()->NewNode( |
| 1772 | common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber), check, |
| 1773 | frame_state, efalse, if_false); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1774 | vfalse = efalse = graph()->NewNode( |
| 1775 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1776 | efalse, if_false); |
| 1777 | ValueEffectControl state = |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1778 | BuildCheckedFloat64ToInt32(mode, vfalse, frame_state, efalse, if_false); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1779 | if_false = state.control; |
| 1780 | efalse = state.effect; |
| 1781 | vfalse = state.value; |
| 1782 | } |
| 1783 | |
| 1784 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1785 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1786 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 1787 | vtrue, vfalse, control); |
| 1788 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1789 | return ValueEffectControl(value, effect, control); |
| 1790 | } |
| 1791 | |
| 1792 | EffectControlLinearizer::ValueEffectControl |
| 1793 | EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64( |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1794 | CheckTaggedInputMode mode, Node* value, Node* frame_state, Node* effect, |
| 1795 | Node* control) { |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1796 | Node* value_map = effect = graph()->NewNode( |
| 1797 | simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1798 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1799 | Node* check_number = graph()->NewNode(machine()->WordEqual(), value_map, |
| 1800 | jsgraph()->HeapNumberMapConstant()); |
| 1801 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1802 | switch (mode) { |
| 1803 | case CheckTaggedInputMode::kNumber: { |
| 1804 | control = effect = graph()->NewNode( |
| 1805 | common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber), |
| 1806 | check_number, frame_state, effect, control); |
| 1807 | break; |
| 1808 | } |
| 1809 | case CheckTaggedInputMode::kNumberOrOddball: { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1810 | Node* branch = |
| 1811 | graph()->NewNode(common()->Branch(), check_number, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1812 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1813 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1814 | Node* etrue = effect; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1815 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1816 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1817 | // For oddballs also contain the numeric value, let us just check that |
| 1818 | // we have an oddball here. |
| 1819 | Node* efalse = effect; |
| 1820 | Node* instance_type = efalse = graph()->NewNode( |
| 1821 | simplified()->LoadField(AccessBuilder::ForMapInstanceType()), |
| 1822 | value_map, efalse, if_false); |
| 1823 | Node* check_oddball = |
| 1824 | graph()->NewNode(machine()->Word32Equal(), instance_type, |
| 1825 | jsgraph()->Int32Constant(ODDBALL_TYPE)); |
| 1826 | if_false = efalse = graph()->NewNode( |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 1827 | common()->DeoptimizeUnless(DeoptimizeReason::kNotANumberOrOddball), |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1828 | check_oddball, frame_state, efalse, if_false); |
| 1829 | STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1830 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1831 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1832 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1833 | break; |
| 1834 | } |
| 1835 | } |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1836 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1837 | value = effect = graph()->NewNode( |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1838 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1839 | effect, control); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1840 | return ValueEffectControl(value, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1841 | } |
| 1842 | |
| 1843 | EffectControlLinearizer::ValueEffectControl |
| 1844 | EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node, |
| 1845 | Node* frame_state, |
| 1846 | Node* effect, |
| 1847 | Node* control) { |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1848 | CheckTaggedInputMode mode = CheckTaggedInputModeOf(node->op()); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1849 | Node* value = node->InputAt(0); |
| 1850 | |
| 1851 | Node* check = ObjectIsSmi(value); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1852 | Node* branch = graph()->NewNode(common()->Branch(), check, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1853 | |
| 1854 | // In the Smi case, just convert to int32 and then float64. |
| 1855 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1856 | Node* etrue = effect; |
| 1857 | Node* vtrue = ChangeSmiToInt32(value); |
| 1858 | vtrue = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue); |
| 1859 | |
| 1860 | // Otherwise, check heap numberness and load the number. |
| 1861 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1862 | ValueEffectControl number_state = BuildCheckedHeapNumberOrOddballToFloat64( |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1863 | mode, value, frame_state, effect, if_false); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1864 | |
| 1865 | Node* merge = |
| 1866 | graph()->NewNode(common()->Merge(2), if_true, number_state.control); |
| 1867 | Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue, |
| 1868 | number_state.effect, merge); |
| 1869 | Node* result = |
| 1870 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), vtrue, |
| 1871 | number_state.value, merge); |
| 1872 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1873 | return ValueEffectControl(result, effect_phi, merge); |
| 1874 | } |
| 1875 | |
| 1876 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1877 | EffectControlLinearizer::LowerCheckedTaggedToTaggedSigned(Node* node, |
| 1878 | Node* frame_state, |
| 1879 | Node* effect, |
| 1880 | Node* control) { |
| 1881 | Node* value = node->InputAt(0); |
| 1882 | |
| 1883 | Node* check = ObjectIsSmi(value); |
| 1884 | control = effect = |
| 1885 | graph()->NewNode(common()->DeoptimizeUnless(DeoptimizeReason::kNotASmi), |
| 1886 | check, frame_state, effect, control); |
| 1887 | |
| 1888 | return ValueEffectControl(value, effect, control); |
| 1889 | } |
| 1890 | |
| 1891 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 1892 | EffectControlLinearizer::LowerCheckedTaggedToTaggedPointer(Node* node, |
| 1893 | Node* frame_state, |
| 1894 | Node* effect, |
| 1895 | Node* control) { |
| 1896 | Node* value = node->InputAt(0); |
| 1897 | |
| 1898 | Node* check = ObjectIsSmi(value); |
| 1899 | control = effect = |
| 1900 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kSmi), check, |
| 1901 | frame_state, effect, control); |
| 1902 | |
| 1903 | return ValueEffectControl(value, effect, control); |
| 1904 | } |
| 1905 | |
| 1906 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 1907 | EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node, Node* effect, |
| 1908 | Node* control) { |
| 1909 | Node* value = node->InputAt(0); |
| 1910 | |
| 1911 | Node* check = ObjectIsSmi(value); |
| 1912 | Node* branch = |
| 1913 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1914 | |
| 1915 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1916 | Node* etrue = effect; |
| 1917 | Node* vtrue = ChangeSmiToInt32(value); |
| 1918 | |
| 1919 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1920 | Node* efalse = effect; |
| 1921 | Node* vfalse; |
| 1922 | { |
| 1923 | STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset); |
| 1924 | vfalse = efalse = graph()->NewNode( |
| 1925 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value, |
| 1926 | efalse, if_false); |
| 1927 | vfalse = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse); |
| 1928 | } |
| 1929 | |
| 1930 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1931 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1932 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 1933 | vtrue, vfalse, control); |
| 1934 | |
| 1935 | return ValueEffectControl(value, effect, control); |
| 1936 | } |
| 1937 | |
| 1938 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 1939 | EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(Node* node, |
| 1940 | Node* frame_state, |
| 1941 | Node* effect, |
| 1942 | Node* control) { |
| 1943 | Node* value = node->InputAt(0); |
| 1944 | |
| 1945 | Node* check = ObjectIsSmi(value); |
| 1946 | Node* branch = |
| 1947 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 1948 | |
| 1949 | // In the Smi case, just convert to int32. |
| 1950 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1951 | Node* etrue = effect; |
| 1952 | Node* vtrue = ChangeSmiToInt32(value); |
| 1953 | |
| 1954 | // Otherwise, check that it's a heap number or oddball and truncate the value |
| 1955 | // to int32. |
| 1956 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1957 | ValueEffectControl false_state = BuildCheckedHeapNumberOrOddballToFloat64( |
| 1958 | CheckTaggedInputMode::kNumberOrOddball, value, frame_state, effect, |
| 1959 | if_false); |
| 1960 | false_state.value = |
| 1961 | graph()->NewNode(machine()->TruncateFloat64ToWord32(), false_state.value); |
| 1962 | |
| 1963 | Node* merge = |
| 1964 | graph()->NewNode(common()->Merge(2), if_true, false_state.control); |
| 1965 | Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue, |
| 1966 | false_state.effect, merge); |
| 1967 | Node* result = |
| 1968 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue, |
| 1969 | false_state.value, merge); |
| 1970 | |
| 1971 | return ValueEffectControl(result, effect_phi, merge); |
| 1972 | } |
| 1973 | |
| 1974 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 1975 | EffectControlLinearizer::LowerObjectIsCallable(Node* node, Node* effect, |
| 1976 | Node* control) { |
| 1977 | Node* value = node->InputAt(0); |
| 1978 | |
| 1979 | Node* check = ObjectIsSmi(value); |
| 1980 | Node* branch = |
| 1981 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 1982 | |
| 1983 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1984 | Node* etrue = effect; |
| 1985 | Node* vtrue = jsgraph()->Int32Constant(0); |
| 1986 | |
| 1987 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1988 | Node* efalse = effect; |
| 1989 | Node* vfalse; |
| 1990 | { |
| 1991 | Node* value_map = efalse = |
| 1992 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1993 | value, efalse, if_false); |
| 1994 | Node* value_bit_field = efalse = graph()->NewNode( |
| 1995 | simplified()->LoadField(AccessBuilder::ForMapBitField()), value_map, |
| 1996 | efalse, if_false); |
| 1997 | vfalse = graph()->NewNode( |
| 1998 | machine()->Word32Equal(), |
| 1999 | jsgraph()->Int32Constant(1 << Map::kIsCallable), |
| 2000 | graph()->NewNode( |
| 2001 | machine()->Word32And(), value_bit_field, |
| 2002 | jsgraph()->Int32Constant((1 << Map::kIsCallable) | |
| 2003 | (1 << Map::kIsUndetectable)))); |
| 2004 | } |
| 2005 | |
| 2006 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 2007 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 2008 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue, |
| 2009 | vfalse, control); |
| 2010 | |
| 2011 | return ValueEffectControl(value, effect, control); |
| 2012 | } |
| 2013 | |
| 2014 | EffectControlLinearizer::ValueEffectControl |
| 2015 | EffectControlLinearizer::LowerObjectIsNumber(Node* node, Node* effect, |
| 2016 | Node* control) { |
| 2017 | Node* value = node->InputAt(0); |
| 2018 | |
| 2019 | Node* check = ObjectIsSmi(value); |
| 2020 | Node* branch = graph()->NewNode(common()->Branch(), check, control); |
| 2021 | |
| 2022 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 2023 | Node* etrue = effect; |
| 2024 | Node* vtrue = jsgraph()->Int32Constant(1); |
| 2025 | |
| 2026 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 2027 | Node* efalse = effect; |
| 2028 | Node* vfalse; |
| 2029 | { |
| 2030 | Node* value_map = efalse = |
| 2031 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 2032 | value, efalse, if_false); |
| 2033 | vfalse = graph()->NewNode(machine()->WordEqual(), value_map, |
| 2034 | jsgraph()->HeapNumberMapConstant()); |
| 2035 | } |
| 2036 | |
| 2037 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 2038 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 2039 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue, |
| 2040 | vfalse, control); |
| 2041 | |
| 2042 | return ValueEffectControl(value, effect, control); |
| 2043 | } |
| 2044 | |
| 2045 | EffectControlLinearizer::ValueEffectControl |
| 2046 | EffectControlLinearizer::LowerObjectIsReceiver(Node* node, Node* effect, |
| 2047 | Node* control) { |
| 2048 | Node* value = node->InputAt(0); |
| 2049 | |
| 2050 | Node* check = ObjectIsSmi(value); |
| 2051 | Node* branch = |
| 2052 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 2053 | |
| 2054 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 2055 | Node* etrue = effect; |
| 2056 | Node* vtrue = jsgraph()->Int32Constant(0); |
| 2057 | |
| 2058 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 2059 | Node* efalse = effect; |
| 2060 | Node* vfalse; |
| 2061 | { |
| 2062 | STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 2063 | Node* value_map = efalse = |
| 2064 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 2065 | value, efalse, if_false); |
| 2066 | Node* value_instance_type = efalse = graph()->NewNode( |
| 2067 | simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map, |
| 2068 | efalse, if_false); |
| 2069 | vfalse = graph()->NewNode(machine()->Uint32LessThanOrEqual(), |
| 2070 | jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE), |
| 2071 | value_instance_type); |
| 2072 | } |
| 2073 | |
| 2074 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 2075 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 2076 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue, |
| 2077 | vfalse, control); |
| 2078 | |
| 2079 | return ValueEffectControl(value, effect, control); |
| 2080 | } |
| 2081 | |
| 2082 | EffectControlLinearizer::ValueEffectControl |
| 2083 | EffectControlLinearizer::LowerObjectIsSmi(Node* node, Node* effect, |
| 2084 | Node* control) { |
| 2085 | Node* value = node->InputAt(0); |
| 2086 | value = ObjectIsSmi(value); |
| 2087 | return ValueEffectControl(value, effect, control); |
| 2088 | } |
| 2089 | |
| 2090 | EffectControlLinearizer::ValueEffectControl |
| 2091 | EffectControlLinearizer::LowerObjectIsString(Node* node, Node* effect, |
| 2092 | Node* control) { |
| 2093 | Node* value = node->InputAt(0); |
| 2094 | |
| 2095 | Node* check = ObjectIsSmi(value); |
| 2096 | Node* branch = |
| 2097 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 2098 | |
| 2099 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 2100 | Node* etrue = effect; |
| 2101 | Node* vtrue = jsgraph()->Int32Constant(0); |
| 2102 | |
| 2103 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 2104 | Node* efalse = effect; |
| 2105 | Node* vfalse; |
| 2106 | { |
| 2107 | Node* value_map = efalse = |
| 2108 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 2109 | value, efalse, if_false); |
| 2110 | Node* value_instance_type = efalse = graph()->NewNode( |
| 2111 | simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map, |
| 2112 | efalse, if_false); |
| 2113 | vfalse = graph()->NewNode(machine()->Uint32LessThan(), value_instance_type, |
| 2114 | jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); |
| 2115 | } |
| 2116 | |
| 2117 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 2118 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 2119 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue, |
| 2120 | vfalse, control); |
| 2121 | |
| 2122 | return ValueEffectControl(value, effect, control); |
| 2123 | } |
| 2124 | |
| 2125 | EffectControlLinearizer::ValueEffectControl |
| 2126 | EffectControlLinearizer::LowerObjectIsUndetectable(Node* node, Node* effect, |
| 2127 | Node* control) { |
| 2128 | Node* value = node->InputAt(0); |
| 2129 | |
| 2130 | Node* check = ObjectIsSmi(value); |
| 2131 | Node* branch = |
| 2132 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 2133 | |
| 2134 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 2135 | Node* etrue = effect; |
| 2136 | Node* vtrue = jsgraph()->Int32Constant(0); |
| 2137 | |
| 2138 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 2139 | Node* efalse = effect; |
| 2140 | Node* vfalse; |
| 2141 | { |
| 2142 | Node* value_map = efalse = |
| 2143 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 2144 | value, efalse, if_false); |
| 2145 | Node* value_bit_field = efalse = graph()->NewNode( |
| 2146 | simplified()->LoadField(AccessBuilder::ForMapBitField()), value_map, |
| 2147 | efalse, if_false); |
| 2148 | vfalse = graph()->NewNode( |
| 2149 | machine()->Word32Equal(), |
| 2150 | graph()->NewNode( |
| 2151 | machine()->Word32Equal(), jsgraph()->Int32Constant(0), |
| 2152 | graph()->NewNode( |
| 2153 | machine()->Word32And(), value_bit_field, |
| 2154 | jsgraph()->Int32Constant(1 << Map::kIsUndetectable))), |
| 2155 | jsgraph()->Int32Constant(0)); |
| 2156 | } |
| 2157 | |
| 2158 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 2159 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 2160 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue, |
| 2161 | vfalse, control); |
| 2162 | |
| 2163 | return ValueEffectControl(value, effect, control); |
| 2164 | } |
| 2165 | |
| 2166 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 2167 | EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node, Node* effect, |
| 2168 | Node* control) { |
| 2169 | Node* value = node->InputAt(0); |
| 2170 | |
| 2171 | Node* value_bit_field = effect = graph()->NewNode( |
| 2172 | simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), value, |
| 2173 | effect, control); |
| 2174 | value = graph()->NewNode( |
| 2175 | machine()->Word32Equal(), |
| 2176 | graph()->NewNode(machine()->Word32Equal(), |
| 2177 | graph()->NewNode(machine()->Word32And(), value_bit_field, |
| 2178 | jsgraph()->Int32Constant( |
| 2179 | JSArrayBuffer::WasNeutered::kMask)), |
| 2180 | jsgraph()->Int32Constant(0)), |
| 2181 | jsgraph()->Int32Constant(0)); |
| 2182 | |
| 2183 | return ValueEffectControl(value, effect, control); |
| 2184 | } |
| 2185 | |
| 2186 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2187 | EffectControlLinearizer::LowerStringCharCodeAt(Node* node, Node* effect, |
| 2188 | Node* control) { |
| 2189 | Node* subject = node->InputAt(0); |
| 2190 | Node* index = node->InputAt(1); |
| 2191 | |
| 2192 | // We may need to loop several times for ConsString/SlicedString {subject}s. |
| 2193 | Node* loop = |
| 2194 | graph()->NewNode(common()->Loop(4), control, control, control, control); |
| 2195 | Node* lsubject = |
| 2196 | graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 4), |
| 2197 | subject, subject, subject, subject, loop); |
| 2198 | Node* lindex = |
| 2199 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 4), index, |
| 2200 | index, index, index, loop); |
| 2201 | Node* leffect = graph()->NewNode(common()->EffectPhi(4), effect, effect, |
| 2202 | effect, effect, loop); |
| 2203 | |
| 2204 | control = loop; |
| 2205 | effect = leffect; |
| 2206 | |
| 2207 | // Determine the instance type of {lsubject}. |
| 2208 | Node* lsubject_map = effect = |
| 2209 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 2210 | lsubject, effect, control); |
| 2211 | Node* lsubject_instance_type = effect = graph()->NewNode( |
| 2212 | simplified()->LoadField(AccessBuilder::ForMapInstanceType()), |
| 2213 | lsubject_map, effect, control); |
| 2214 | |
| 2215 | // Check if {lsubject} is a SeqString. |
| 2216 | Node* check0 = graph()->NewNode( |
| 2217 | machine()->Word32Equal(), |
| 2218 | graph()->NewNode(machine()->Word32And(), lsubject_instance_type, |
| 2219 | jsgraph()->Int32Constant(kStringRepresentationMask)), |
| 2220 | jsgraph()->Int32Constant(kSeqStringTag)); |
| 2221 | Node* branch0 = graph()->NewNode(common()->Branch(), check0, control); |
| 2222 | |
| 2223 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 2224 | Node* etrue0 = effect; |
| 2225 | Node* vtrue0; |
| 2226 | { |
| 2227 | // Check if the {lsubject} is a TwoByteSeqString or a OneByteSeqString. |
| 2228 | Node* check1 = graph()->NewNode( |
| 2229 | machine()->Word32Equal(), |
| 2230 | graph()->NewNode(machine()->Word32And(), lsubject_instance_type, |
| 2231 | jsgraph()->Int32Constant(kStringEncodingMask)), |
| 2232 | jsgraph()->Int32Constant(kTwoByteStringTag)); |
| 2233 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0); |
| 2234 | |
| 2235 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 2236 | Node* etrue1 = etrue0; |
| 2237 | Node* vtrue1 = etrue1 = |
| 2238 | graph()->NewNode(simplified()->LoadElement( |
| 2239 | AccessBuilder::ForSeqTwoByteStringCharacter()), |
| 2240 | lsubject, lindex, etrue1, if_true1); |
| 2241 | |
| 2242 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 2243 | Node* efalse1 = etrue0; |
| 2244 | Node* vfalse1 = efalse1 = |
| 2245 | graph()->NewNode(simplified()->LoadElement( |
| 2246 | AccessBuilder::ForSeqOneByteStringCharacter()), |
| 2247 | lsubject, lindex, efalse1, if_false1); |
| 2248 | |
| 2249 | if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 2250 | etrue0 = |
| 2251 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
| 2252 | vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 2253 | vtrue1, vfalse1, if_true0); |
| 2254 | } |
| 2255 | |
| 2256 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 2257 | Node* efalse0 = effect; |
| 2258 | Node* vfalse0; |
| 2259 | { |
| 2260 | // Check if the {lsubject} is a ConsString. |
| 2261 | Node* check1 = graph()->NewNode( |
| 2262 | machine()->Word32Equal(), |
| 2263 | graph()->NewNode(machine()->Word32And(), lsubject_instance_type, |
| 2264 | jsgraph()->Int32Constant(kStringRepresentationMask)), |
| 2265 | jsgraph()->Int32Constant(kConsStringTag)); |
| 2266 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); |
| 2267 | |
| 2268 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 2269 | Node* etrue1 = efalse0; |
| 2270 | { |
| 2271 | // Load the right hand side of the {lsubject} ConsString. |
| 2272 | Node* lsubject_second = etrue1 = graph()->NewNode( |
| 2273 | simplified()->LoadField(AccessBuilder::ForConsStringSecond()), |
| 2274 | lsubject, etrue1, if_true1); |
| 2275 | |
| 2276 | // Check whether the right hand side is the empty string (i.e. if |
| 2277 | // this is really a flat string in a cons string). If that is not |
| 2278 | // the case we flatten the string first. |
| 2279 | Node* check2 = graph()->NewNode(machine()->WordEqual(), lsubject_second, |
| 2280 | jsgraph()->EmptyStringConstant()); |
| 2281 | Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 2282 | check2, if_true1); |
| 2283 | |
| 2284 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 2285 | Node* etrue2 = etrue1; |
| 2286 | Node* vtrue2 = etrue2 = graph()->NewNode( |
| 2287 | simplified()->LoadField(AccessBuilder::ForConsStringFirst()), |
| 2288 | lsubject, etrue2, if_true2); |
| 2289 | |
| 2290 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 2291 | Node* efalse2 = etrue1; |
| 2292 | Node* vfalse2; |
| 2293 | { |
| 2294 | // Flatten the {lsubject} ConsString first. |
| 2295 | Operator::Properties properties = |
| 2296 | Operator::kNoDeopt | Operator::kNoThrow; |
| 2297 | Runtime::FunctionId id = Runtime::kFlattenString; |
| 2298 | CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor( |
| 2299 | graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags); |
| 2300 | vfalse2 = efalse2 = graph()->NewNode( |
| 2301 | common()->Call(desc), jsgraph()->CEntryStubConstant(1), lsubject, |
| 2302 | jsgraph()->ExternalConstant(ExternalReference(id, isolate())), |
| 2303 | jsgraph()->Int32Constant(1), jsgraph()->NoContextConstant(), |
| 2304 | efalse2, if_false2); |
| 2305 | } |
| 2306 | |
| 2307 | // Retry the {loop} with the new subject. |
| 2308 | loop->ReplaceInput(1, if_true2); |
| 2309 | lindex->ReplaceInput(1, lindex); |
| 2310 | leffect->ReplaceInput(1, etrue2); |
| 2311 | lsubject->ReplaceInput(1, vtrue2); |
| 2312 | loop->ReplaceInput(2, if_false2); |
| 2313 | lindex->ReplaceInput(2, lindex); |
| 2314 | leffect->ReplaceInput(2, efalse2); |
| 2315 | lsubject->ReplaceInput(2, vfalse2); |
| 2316 | } |
| 2317 | |
| 2318 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 2319 | Node* efalse1 = efalse0; |
| 2320 | Node* vfalse1; |
| 2321 | { |
| 2322 | // Check if the {lsubject} is an ExternalString. |
| 2323 | Node* check2 = graph()->NewNode( |
| 2324 | machine()->Word32Equal(), |
| 2325 | graph()->NewNode(machine()->Word32And(), lsubject_instance_type, |
| 2326 | jsgraph()->Int32Constant(kStringRepresentationMask)), |
| 2327 | jsgraph()->Int32Constant(kExternalStringTag)); |
| 2328 | Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 2329 | check2, if_false1); |
| 2330 | |
| 2331 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 2332 | Node* etrue2 = efalse1; |
| 2333 | Node* vtrue2; |
| 2334 | { |
| 2335 | // Check if the {lsubject} is a short external string. |
| 2336 | Node* check3 = graph()->NewNode( |
| 2337 | machine()->Word32Equal(), |
| 2338 | graph()->NewNode( |
| 2339 | machine()->Word32And(), lsubject_instance_type, |
| 2340 | jsgraph()->Int32Constant(kShortExternalStringMask)), |
| 2341 | jsgraph()->Int32Constant(0)); |
| 2342 | Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 2343 | check3, if_true2); |
| 2344 | |
| 2345 | Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); |
| 2346 | Node* etrue3 = etrue2; |
| 2347 | Node* vtrue3; |
| 2348 | { |
| 2349 | // Load the actual resource data from the {lsubject}. |
| 2350 | Node* lsubject_resource_data = etrue3 = graph()->NewNode( |
| 2351 | simplified()->LoadField( |
| 2352 | AccessBuilder::ForExternalStringResourceData()), |
| 2353 | lsubject, etrue3, if_true3); |
| 2354 | |
| 2355 | // Check if the {lsubject} is a TwoByteExternalString or a |
| 2356 | // OneByteExternalString. |
| 2357 | Node* check4 = graph()->NewNode( |
| 2358 | machine()->Word32Equal(), |
| 2359 | graph()->NewNode(machine()->Word32And(), lsubject_instance_type, |
| 2360 | jsgraph()->Int32Constant(kStringEncodingMask)), |
| 2361 | jsgraph()->Int32Constant(kTwoByteStringTag)); |
| 2362 | Node* branch4 = |
| 2363 | graph()->NewNode(common()->Branch(), check4, if_true3); |
| 2364 | |
| 2365 | Node* if_true4 = graph()->NewNode(common()->IfTrue(), branch4); |
| 2366 | Node* etrue4 = etrue3; |
| 2367 | Node* vtrue4 = etrue4 = graph()->NewNode( |
| 2368 | simplified()->LoadElement( |
| 2369 | AccessBuilder::ForExternalTwoByteStringCharacter()), |
| 2370 | lsubject_resource_data, lindex, etrue4, if_true4); |
| 2371 | |
| 2372 | Node* if_false4 = graph()->NewNode(common()->IfFalse(), branch4); |
| 2373 | Node* efalse4 = etrue3; |
| 2374 | Node* vfalse4 = efalse4 = graph()->NewNode( |
| 2375 | simplified()->LoadElement( |
| 2376 | AccessBuilder::ForExternalOneByteStringCharacter()), |
| 2377 | lsubject_resource_data, lindex, efalse4, if_false4); |
| 2378 | |
| 2379 | if_true3 = graph()->NewNode(common()->Merge(2), if_true4, if_false4); |
| 2380 | etrue3 = graph()->NewNode(common()->EffectPhi(2), etrue4, efalse4, |
| 2381 | if_true3); |
| 2382 | vtrue3 = |
| 2383 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 2384 | vtrue4, vfalse4, if_true3); |
| 2385 | } |
| 2386 | |
| 2387 | Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3); |
| 2388 | Node* efalse3 = etrue2; |
| 2389 | Node* vfalse3; |
| 2390 | { |
| 2391 | // The {lsubject} might be compressed, call the runtime. |
| 2392 | Operator::Properties properties = |
| 2393 | Operator::kNoDeopt | Operator::kNoThrow; |
| 2394 | Runtime::FunctionId id = Runtime::kExternalStringGetChar; |
| 2395 | CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor( |
| 2396 | graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags); |
| 2397 | vfalse3 = efalse3 = graph()->NewNode( |
| 2398 | common()->Call(desc), jsgraph()->CEntryStubConstant(1), lsubject, |
| 2399 | ChangeInt32ToSmi(lindex), |
| 2400 | jsgraph()->ExternalConstant(ExternalReference(id, isolate())), |
| 2401 | jsgraph()->Int32Constant(2), jsgraph()->NoContextConstant(), |
| 2402 | efalse3, if_false3); |
| 2403 | vfalse3 = ChangeSmiToInt32(vfalse3); |
| 2404 | } |
| 2405 | |
| 2406 | if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3); |
| 2407 | etrue2 = |
| 2408 | graph()->NewNode(common()->EffectPhi(2), etrue3, efalse3, if_true2); |
| 2409 | vtrue2 = |
| 2410 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 2411 | vtrue3, vfalse3, if_true2); |
| 2412 | } |
| 2413 | |
| 2414 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 2415 | Node* efalse2 = efalse1; |
| 2416 | { |
| 2417 | // The {lsubject} is a SlicedString, continue with its parent. |
| 2418 | Node* lsubject_parent = efalse2 = graph()->NewNode( |
| 2419 | simplified()->LoadField(AccessBuilder::ForSlicedStringParent()), |
| 2420 | lsubject, efalse2, if_false2); |
| 2421 | Node* lsubject_offset = efalse2 = graph()->NewNode( |
| 2422 | simplified()->LoadField(AccessBuilder::ForSlicedStringOffset()), |
| 2423 | lsubject, efalse2, if_false2); |
| 2424 | Node* lsubject_index = graph()->NewNode( |
| 2425 | machine()->Int32Add(), lindex, ChangeSmiToInt32(lsubject_offset)); |
| 2426 | |
| 2427 | // Retry the {loop} with the parent subject. |
| 2428 | loop->ReplaceInput(3, if_false2); |
| 2429 | leffect->ReplaceInput(3, efalse2); |
| 2430 | lindex->ReplaceInput(3, lsubject_index); |
| 2431 | lsubject->ReplaceInput(3, lsubject_parent); |
| 2432 | } |
| 2433 | |
| 2434 | if_false1 = if_true2; |
| 2435 | efalse1 = etrue2; |
| 2436 | vfalse1 = vtrue2; |
| 2437 | } |
| 2438 | |
| 2439 | if_false0 = if_false1; |
| 2440 | efalse0 = efalse1; |
| 2441 | vfalse0 = vfalse1; |
| 2442 | } |
| 2443 | |
| 2444 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 2445 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 2446 | Node* value = |
| 2447 | graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue0, |
| 2448 | vfalse0, control); |
| 2449 | |
| 2450 | return ValueEffectControl(value, effect, control); |
| 2451 | } |
| 2452 | |
| 2453 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2454 | EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect, |
| 2455 | Node* control) { |
| 2456 | Node* value = node->InputAt(0); |
| 2457 | |
| 2458 | // Compute the character code. |
| 2459 | Node* code = |
| 2460 | graph()->NewNode(machine()->Word32And(), value, |
| 2461 | jsgraph()->Int32Constant(String::kMaxUtf16CodeUnit)); |
| 2462 | |
| 2463 | // Check if the {code} is a one-byte char code. |
| 2464 | Node* check0 = |
| 2465 | graph()->NewNode(machine()->Int32LessThanOrEqual(), code, |
| 2466 | jsgraph()->Int32Constant(String::kMaxOneByteCharCode)); |
| 2467 | Node* branch0 = |
| 2468 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 2469 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2470 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 2471 | Node* efalse0 = effect; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 2472 | |
| 2473 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 2474 | Node* etrue0 = effect; |
| 2475 | |
| 2476 | // Load the isolate wide single character string cache. |
| 2477 | Node* cache = |
| 2478 | jsgraph()->HeapConstant(factory()->single_character_string_cache()); |
| 2479 | |
| 2480 | // Compute the {cache} index for {code}. |
| 2481 | Node* index = machine()->Is32() |
| 2482 | ? code |
| 2483 | : graph()->NewNode(machine()->ChangeUint32ToUint64(), code); |
| 2484 | |
| 2485 | // Check if we have an entry for the {code} in the single character string |
| 2486 | // cache already. |
| 2487 | Node* entry = etrue0 = graph()->NewNode( |
| 2488 | simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), cache, |
| 2489 | index, etrue0, if_true0); |
| 2490 | |
| 2491 | Node* check1 = graph()->NewNode(machine()->WordEqual(), entry, |
| 2492 | jsgraph()->UndefinedConstant()); |
| 2493 | Node* branch1 = |
| 2494 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_true0); |
| 2495 | |
| 2496 | // Use the {entry} from the {cache}. |
| 2497 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 2498 | Node* efalse1 = etrue0; |
| 2499 | Node* vfalse1 = entry; |
| 2500 | |
| 2501 | // Let %StringFromCharCode handle this case. |
| 2502 | // TODO(turbofan): At some point we may consider adding a stub for this |
| 2503 | // deferred case, so that we don't need to call to C++ here. |
| 2504 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 2505 | Node* etrue1 = etrue0; |
| 2506 | Node* vtrue1; |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2507 | { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 2508 | if_true1 = graph()->NewNode(common()->Merge(2), if_true1, if_false0); |
| 2509 | etrue1 = |
| 2510 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse0, if_true1); |
| 2511 | Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow; |
| 2512 | Runtime::FunctionId id = Runtime::kStringCharFromCode; |
| 2513 | CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor( |
| 2514 | graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags); |
| 2515 | vtrue1 = etrue1 = graph()->NewNode( |
| 2516 | common()->Call(desc), jsgraph()->CEntryStubConstant(1), |
| 2517 | ChangeInt32ToSmi(code), |
| 2518 | jsgraph()->ExternalConstant(ExternalReference(id, isolate())), |
| 2519 | jsgraph()->Int32Constant(1), jsgraph()->NoContextConstant(), etrue1, |
| 2520 | if_true1); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2521 | } |
| 2522 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 2523 | control = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 2524 | effect = graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2525 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 2526 | vtrue1, vfalse1, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2527 | |
| 2528 | return ValueEffectControl(value, effect, control); |
| 2529 | } |
| 2530 | |
| 2531 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 2532 | EffectControlLinearizer::LowerStringFromCodePoint(Node* node, Node* effect, |
| 2533 | Node* control) { |
| 2534 | Node* value = node->InputAt(0); |
| 2535 | Node* code = value; |
| 2536 | |
| 2537 | Node* etrue0 = effect; |
| 2538 | Node* vtrue0; |
| 2539 | |
| 2540 | // Check if the {code} is a single code unit |
| 2541 | Node* check0 = graph()->NewNode(machine()->Uint32LessThanOrEqual(), code, |
| 2542 | jsgraph()->Uint32Constant(0xFFFF)); |
| 2543 | Node* branch0 = |
| 2544 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 2545 | |
| 2546 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 2547 | { |
| 2548 | // Check if the {code} is a one byte character |
| 2549 | Node* check1 = graph()->NewNode( |
| 2550 | machine()->Uint32LessThanOrEqual(), code, |
| 2551 | jsgraph()->Uint32Constant(String::kMaxOneByteCharCode)); |
| 2552 | Node* branch1 = |
| 2553 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); |
| 2554 | |
| 2555 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 2556 | Node* etrue1 = etrue0; |
| 2557 | Node* vtrue1; |
| 2558 | { |
| 2559 | // Load the isolate wide single character string cache. |
| 2560 | Node* cache = |
| 2561 | jsgraph()->HeapConstant(factory()->single_character_string_cache()); |
| 2562 | |
| 2563 | // Compute the {cache} index for {code}. |
| 2564 | Node* index = |
| 2565 | machine()->Is32() |
| 2566 | ? code |
| 2567 | : graph()->NewNode(machine()->ChangeUint32ToUint64(), code); |
| 2568 | |
| 2569 | // Check if we have an entry for the {code} in the single character string |
| 2570 | // cache already. |
| 2571 | Node* entry = etrue1 = graph()->NewNode( |
| 2572 | simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), |
| 2573 | cache, index, etrue1, if_true1); |
| 2574 | |
| 2575 | Node* check2 = graph()->NewNode(machine()->WordEqual(), entry, |
| 2576 | jsgraph()->UndefinedConstant()); |
| 2577 | Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 2578 | check2, if_true1); |
| 2579 | |
| 2580 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 2581 | Node* etrue2 = etrue1; |
| 2582 | Node* vtrue2; |
| 2583 | { |
| 2584 | // Allocate a new SeqOneByteString for {code}. |
| 2585 | vtrue2 = etrue2 = graph()->NewNode( |
| 2586 | simplified()->Allocate(NOT_TENURED), |
| 2587 | jsgraph()->Int32Constant(SeqOneByteString::SizeFor(1)), etrue2, |
| 2588 | if_true2); |
| 2589 | etrue2 = graph()->NewNode( |
| 2590 | simplified()->StoreField(AccessBuilder::ForMap()), vtrue2, |
| 2591 | jsgraph()->HeapConstant(factory()->one_byte_string_map()), etrue2, |
| 2592 | if_true2); |
| 2593 | etrue2 = graph()->NewNode( |
| 2594 | simplified()->StoreField(AccessBuilder::ForNameHashField()), vtrue2, |
| 2595 | jsgraph()->IntPtrConstant(Name::kEmptyHashField), etrue2, if_true2); |
| 2596 | etrue2 = graph()->NewNode( |
| 2597 | simplified()->StoreField(AccessBuilder::ForStringLength()), vtrue2, |
| 2598 | jsgraph()->SmiConstant(1), etrue2, if_true2); |
| 2599 | etrue2 = graph()->NewNode( |
| 2600 | machine()->Store(StoreRepresentation(MachineRepresentation::kWord8, |
| 2601 | kNoWriteBarrier)), |
| 2602 | vtrue2, jsgraph()->IntPtrConstant(SeqOneByteString::kHeaderSize - |
| 2603 | kHeapObjectTag), |
| 2604 | code, etrue2, if_true2); |
| 2605 | |
| 2606 | // Remember it in the {cache}. |
| 2607 | etrue2 = graph()->NewNode( |
| 2608 | simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), |
| 2609 | cache, index, vtrue2, etrue2, if_true2); |
| 2610 | } |
| 2611 | |
| 2612 | // Use the {entry} from the {cache}. |
| 2613 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 2614 | Node* efalse2 = etrue0; |
| 2615 | Node* vfalse2 = entry; |
| 2616 | |
| 2617 | if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
| 2618 | etrue1 = |
| 2619 | graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_true1); |
| 2620 | vtrue1 = |
| 2621 | graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 2622 | vtrue2, vfalse2, if_true1); |
| 2623 | } |
| 2624 | |
| 2625 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 2626 | Node* efalse1 = effect; |
| 2627 | Node* vfalse1; |
| 2628 | { |
| 2629 | // Allocate a new SeqTwoByteString for {code}. |
| 2630 | vfalse1 = efalse1 = graph()->NewNode( |
| 2631 | simplified()->Allocate(NOT_TENURED), |
| 2632 | jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(1)), efalse1, |
| 2633 | if_false1); |
| 2634 | efalse1 = graph()->NewNode( |
| 2635 | simplified()->StoreField(AccessBuilder::ForMap()), vfalse1, |
| 2636 | jsgraph()->HeapConstant(factory()->string_map()), efalse1, if_false1); |
| 2637 | efalse1 = graph()->NewNode( |
| 2638 | simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse1, |
| 2639 | jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse1, if_false1); |
| 2640 | efalse1 = graph()->NewNode( |
| 2641 | simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse1, |
| 2642 | jsgraph()->SmiConstant(1), efalse1, if_false1); |
| 2643 | efalse1 = graph()->NewNode( |
| 2644 | machine()->Store(StoreRepresentation(MachineRepresentation::kWord16, |
| 2645 | kNoWriteBarrier)), |
| 2646 | vfalse1, jsgraph()->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| 2647 | kHeapObjectTag), |
| 2648 | code, efalse1, if_false1); |
| 2649 | } |
| 2650 | |
| 2651 | if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 2652 | etrue0 = |
| 2653 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
| 2654 | vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 2655 | vtrue1, vfalse1, if_true0); |
| 2656 | } |
| 2657 | |
| 2658 | // Generate surrogate pair string |
| 2659 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 2660 | Node* efalse0 = effect; |
| 2661 | Node* vfalse0; |
| 2662 | { |
| 2663 | switch (UnicodeEncodingOf(node->op())) { |
| 2664 | case UnicodeEncoding::UTF16: |
| 2665 | break; |
| 2666 | |
| 2667 | case UnicodeEncoding::UTF32: { |
| 2668 | // Convert UTF32 to UTF16 code units, and store as a 32 bit word. |
| 2669 | Node* lead_offset = jsgraph()->Int32Constant(0xD800 - (0x10000 >> 10)); |
| 2670 | |
| 2671 | // lead = (codepoint >> 10) + LEAD_OFFSET |
| 2672 | Node* lead = |
| 2673 | graph()->NewNode(machine()->Int32Add(), |
| 2674 | graph()->NewNode(machine()->Word32Shr(), code, |
| 2675 | jsgraph()->Int32Constant(10)), |
| 2676 | lead_offset); |
| 2677 | |
| 2678 | // trail = (codepoint & 0x3FF) + 0xDC00; |
| 2679 | Node* trail = |
| 2680 | graph()->NewNode(machine()->Int32Add(), |
| 2681 | graph()->NewNode(machine()->Word32And(), code, |
| 2682 | jsgraph()->Int32Constant(0x3FF)), |
| 2683 | jsgraph()->Int32Constant(0xDC00)); |
| 2684 | |
| 2685 | // codpoint = (trail << 16) | lead; |
| 2686 | code = graph()->NewNode(machine()->Word32Or(), |
| 2687 | graph()->NewNode(machine()->Word32Shl(), trail, |
| 2688 | jsgraph()->Int32Constant(16)), |
| 2689 | lead); |
| 2690 | break; |
| 2691 | } |
| 2692 | } |
| 2693 | |
| 2694 | // Allocate a new SeqTwoByteString for {code}. |
| 2695 | vfalse0 = efalse0 = |
| 2696 | graph()->NewNode(simplified()->Allocate(NOT_TENURED), |
| 2697 | jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(2)), |
| 2698 | efalse0, if_false0); |
| 2699 | efalse0 = graph()->NewNode( |
| 2700 | simplified()->StoreField(AccessBuilder::ForMap()), vfalse0, |
| 2701 | jsgraph()->HeapConstant(factory()->string_map()), efalse0, if_false0); |
| 2702 | efalse0 = graph()->NewNode( |
| 2703 | simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse0, |
| 2704 | jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse0, if_false0); |
| 2705 | efalse0 = graph()->NewNode( |
| 2706 | simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse0, |
| 2707 | jsgraph()->SmiConstant(2), efalse0, if_false0); |
| 2708 | efalse0 = graph()->NewNode( |
| 2709 | machine()->Store(StoreRepresentation(MachineRepresentation::kWord32, |
| 2710 | kNoWriteBarrier)), |
| 2711 | vfalse0, jsgraph()->IntPtrConstant(SeqTwoByteString::kHeaderSize - |
| 2712 | kHeapObjectTag), |
| 2713 | code, efalse0, if_false0); |
| 2714 | } |
| 2715 | |
| 2716 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 2717 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 2718 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 2719 | vtrue0, vfalse0, control); |
| 2720 | |
| 2721 | return ValueEffectControl(value, effect, control); |
| 2722 | } |
| 2723 | |
| 2724 | EffectControlLinearizer::ValueEffectControl |
| 2725 | EffectControlLinearizer::LowerStringComparison(Callable const& callable, |
| 2726 | Node* node, Node* effect, |
| 2727 | Node* control) { |
| 2728 | Operator::Properties properties = Operator::kEliminatable; |
| 2729 | CallDescriptor::Flags flags = CallDescriptor::kNoFlags; |
| 2730 | CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 2731 | isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties); |
| 2732 | node->InsertInput(graph()->zone(), 0, |
| 2733 | jsgraph()->HeapConstant(callable.code())); |
| 2734 | node->AppendInput(graph()->zone(), jsgraph()->NoContextConstant()); |
| 2735 | node->AppendInput(graph()->zone(), effect); |
| 2736 | NodeProperties::ChangeOp(node, common()->Call(desc)); |
| 2737 | return ValueEffectControl(node, node, control); |
| 2738 | } |
| 2739 | |
| 2740 | EffectControlLinearizer::ValueEffectControl |
| 2741 | EffectControlLinearizer::LowerStringEqual(Node* node, Node* effect, |
| 2742 | Node* control) { |
| 2743 | return LowerStringComparison(CodeFactory::StringEqual(isolate()), node, |
| 2744 | effect, control); |
| 2745 | } |
| 2746 | |
| 2747 | EffectControlLinearizer::ValueEffectControl |
| 2748 | EffectControlLinearizer::LowerStringLessThan(Node* node, Node* effect, |
| 2749 | Node* control) { |
| 2750 | return LowerStringComparison(CodeFactory::StringLessThan(isolate()), node, |
| 2751 | effect, control); |
| 2752 | } |
| 2753 | |
| 2754 | EffectControlLinearizer::ValueEffectControl |
| 2755 | EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node, Node* effect, |
| 2756 | Node* control) { |
| 2757 | return LowerStringComparison(CodeFactory::StringLessThanOrEqual(isolate()), |
| 2758 | node, effect, control); |
| 2759 | } |
| 2760 | |
| 2761 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2762 | EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state, |
| 2763 | Node* effect, Node* control) { |
| 2764 | // If we reach this point w/o eliminating the {node} that's marked |
| 2765 | // with allow-return-hole, we cannot do anything, so just deoptimize |
| 2766 | // in case of the hole NaN (similar to Crankshaft). |
| 2767 | Node* value = node->InputAt(0); |
| 2768 | Node* check = graph()->NewNode( |
| 2769 | machine()->Word32Equal(), |
| 2770 | graph()->NewNode(machine()->Float64ExtractHighWord32(), value), |
| 2771 | jsgraph()->Int32Constant(kHoleNanUpper32)); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2772 | control = effect = |
| 2773 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), check, |
| 2774 | frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2775 | |
| 2776 | return ValueEffectControl(value, effect, control); |
| 2777 | } |
| 2778 | |
| 2779 | EffectControlLinearizer::ValueEffectControl |
| 2780 | EffectControlLinearizer::LowerCheckTaggedHole(Node* node, Node* frame_state, |
| 2781 | Node* effect, Node* control) { |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2782 | Node* value = node->InputAt(0); |
| 2783 | Node* check = graph()->NewNode(machine()->WordEqual(), value, |
| 2784 | jsgraph()->TheHoleConstant()); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2785 | control = effect = |
| 2786 | graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), check, |
| 2787 | frame_state, effect, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2788 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2789 | return ValueEffectControl(value, effect, control); |
| 2790 | } |
| 2791 | |
| 2792 | EffectControlLinearizer::ValueEffectControl |
| 2793 | EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node, |
| 2794 | Node* effect, |
| 2795 | Node* control) { |
| 2796 | Node* value = node->InputAt(0); |
| 2797 | Node* check = graph()->NewNode(machine()->WordEqual(), value, |
| 2798 | jsgraph()->TheHoleConstant()); |
| 2799 | Node* branch = |
| 2800 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 2801 | |
| 2802 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 2803 | Node* vtrue = jsgraph()->UndefinedConstant(); |
| 2804 | |
| 2805 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 2806 | Node* vfalse = value; |
| 2807 | |
| 2808 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 2809 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 2810 | vtrue, vfalse, control); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2811 | |
| 2812 | return ValueEffectControl(value, effect, control); |
| 2813 | } |
| 2814 | |
| 2815 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 2816 | EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value, Node* effect, |
| 2817 | Node* control) { |
| 2818 | Node* result = effect = graph()->NewNode( |
| 2819 | simplified()->Allocate(NOT_TENURED), |
| 2820 | jsgraph()->Int32Constant(HeapNumber::kSize), effect, control); |
| 2821 | effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), |
| 2822 | result, jsgraph()->HeapNumberMapConstant(), effect, |
| 2823 | control); |
| 2824 | effect = graph()->NewNode( |
| 2825 | simplified()->StoreField(AccessBuilder::ForHeapNumberValue()), result, |
| 2826 | value, effect, control); |
| 2827 | return ValueEffectControl(result, effect, control); |
| 2828 | } |
| 2829 | |
| 2830 | Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) { |
| 2831 | if (machine()->Is64()) { |
| 2832 | value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value); |
| 2833 | } |
| 2834 | return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()); |
| 2835 | } |
| 2836 | |
| 2837 | Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) { |
| 2838 | if (machine()->Is64()) { |
| 2839 | value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value); |
| 2840 | } |
| 2841 | return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()); |
| 2842 | } |
| 2843 | |
| 2844 | Node* EffectControlLinearizer::ChangeInt32ToFloat64(Node* value) { |
| 2845 | return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value); |
| 2846 | } |
| 2847 | |
| 2848 | Node* EffectControlLinearizer::ChangeUint32ToFloat64(Node* value) { |
| 2849 | return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value); |
| 2850 | } |
| 2851 | |
| 2852 | Node* EffectControlLinearizer::ChangeSmiToInt32(Node* value) { |
| 2853 | value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant()); |
| 2854 | if (machine()->Is64()) { |
| 2855 | value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value); |
| 2856 | } |
| 2857 | return value; |
| 2858 | } |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 2859 | Node* EffectControlLinearizer::ObjectIsSmi(Node* value) { |
| 2860 | return graph()->NewNode( |
| 2861 | machine()->WordEqual(), |
| 2862 | graph()->NewNode(machine()->WordAnd(), value, |
| 2863 | jsgraph()->IntPtrConstant(kSmiTagMask)), |
| 2864 | jsgraph()->IntPtrConstant(kSmiTag)); |
| 2865 | } |
| 2866 | |
| 2867 | Node* EffectControlLinearizer::SmiMaxValueConstant() { |
| 2868 | return jsgraph()->Int32Constant(Smi::kMaxValue); |
| 2869 | } |
| 2870 | |
| 2871 | Node* EffectControlLinearizer::SmiShiftBitsConstant() { |
| 2872 | return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); |
| 2873 | } |
| 2874 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2875 | EffectControlLinearizer::ValueEffectControl |
| 2876 | EffectControlLinearizer::LowerPlainPrimitiveToNumber(Node* node, Node* effect, |
| 2877 | Node* control) { |
| 2878 | Node* value = node->InputAt(0); |
| 2879 | Node* result = effect = |
| 2880 | graph()->NewNode(ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2881 | value, jsgraph()->NoContextConstant(), effect); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2882 | return ValueEffectControl(result, effect, control); |
| 2883 | } |
| 2884 | |
| 2885 | EffectControlLinearizer::ValueEffectControl |
| 2886 | EffectControlLinearizer::LowerPlainPrimitiveToWord32(Node* node, Node* effect, |
| 2887 | Node* control) { |
| 2888 | Node* value = node->InputAt(0); |
| 2889 | |
| 2890 | Node* check0 = ObjectIsSmi(value); |
| 2891 | Node* branch0 = |
| 2892 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 2893 | |
| 2894 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 2895 | Node* etrue0 = effect; |
| 2896 | Node* vtrue0 = ChangeSmiToInt32(value); |
| 2897 | |
| 2898 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 2899 | Node* efalse0 = effect; |
| 2900 | Node* vfalse0; |
| 2901 | { |
| 2902 | vfalse0 = efalse0 = graph()->NewNode( |
| 2903 | ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value, |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2904 | jsgraph()->NoContextConstant(), efalse0); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2905 | |
| 2906 | Node* check1 = ObjectIsSmi(vfalse0); |
| 2907 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); |
| 2908 | |
| 2909 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 2910 | Node* etrue1 = efalse0; |
| 2911 | Node* vtrue1 = ChangeSmiToInt32(vfalse0); |
| 2912 | |
| 2913 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 2914 | Node* efalse1 = efalse0; |
| 2915 | Node* vfalse1; |
| 2916 | { |
| 2917 | vfalse1 = efalse1 = graph()->NewNode( |
| 2918 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0, |
| 2919 | efalse1, if_false1); |
| 2920 | vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1); |
| 2921 | } |
| 2922 | |
| 2923 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 2924 | efalse0 = |
| 2925 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
| 2926 | vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 2927 | vtrue1, vfalse1, if_false0); |
| 2928 | } |
| 2929 | |
| 2930 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 2931 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 2932 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
| 2933 | vtrue0, vfalse0, control); |
| 2934 | return ValueEffectControl(value, effect, control); |
| 2935 | } |
| 2936 | |
| 2937 | EffectControlLinearizer::ValueEffectControl |
| 2938 | EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node, Node* effect, |
| 2939 | Node* control) { |
| 2940 | Node* value = node->InputAt(0); |
| 2941 | |
| 2942 | Node* check0 = ObjectIsSmi(value); |
| 2943 | Node* branch0 = |
| 2944 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 2945 | |
| 2946 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 2947 | Node* etrue0 = effect; |
| 2948 | Node* vtrue0; |
| 2949 | { |
| 2950 | vtrue0 = ChangeSmiToInt32(value); |
| 2951 | vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0); |
| 2952 | } |
| 2953 | |
| 2954 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 2955 | Node* efalse0 = effect; |
| 2956 | Node* vfalse0; |
| 2957 | { |
| 2958 | vfalse0 = efalse0 = graph()->NewNode( |
| 2959 | ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value, |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2960 | jsgraph()->NoContextConstant(), efalse0); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 2961 | |
| 2962 | Node* check1 = ObjectIsSmi(vfalse0); |
| 2963 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); |
| 2964 | |
| 2965 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 2966 | Node* etrue1 = efalse0; |
| 2967 | Node* vtrue1; |
| 2968 | { |
| 2969 | vtrue1 = ChangeSmiToInt32(vfalse0); |
| 2970 | vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1); |
| 2971 | } |
| 2972 | |
| 2973 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 2974 | Node* efalse1 = efalse0; |
| 2975 | Node* vfalse1; |
| 2976 | { |
| 2977 | vfalse1 = efalse1 = graph()->NewNode( |
| 2978 | simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0, |
| 2979 | efalse1, if_false1); |
| 2980 | } |
| 2981 | |
| 2982 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 2983 | efalse0 = |
| 2984 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
| 2985 | vfalse0 = |
| 2986 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 2987 | vtrue1, vfalse1, if_false0); |
| 2988 | } |
| 2989 | |
| 2990 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 2991 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 2992 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 2993 | vtrue0, vfalse0, control); |
| 2994 | return ValueEffectControl(value, effect, control); |
| 2995 | } |
| 2996 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 2997 | EffectControlLinearizer::ValueEffectControl |
| 2998 | EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node, |
| 2999 | Node* effect, |
| 3000 | Node* control) { |
| 3001 | Node* object = node->InputAt(0); |
| 3002 | Node* elements = node->InputAt(1); |
| 3003 | |
| 3004 | // Load the current map of {elements}. |
| 3005 | Node* elements_map = effect = |
| 3006 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 3007 | elements, effect, control); |
| 3008 | |
| 3009 | // Check if {elements} is not a copy-on-write FixedArray. |
| 3010 | Node* check = graph()->NewNode(machine()->WordEqual(), elements_map, |
| 3011 | jsgraph()->FixedArrayMapConstant()); |
| 3012 | Node* branch = |
| 3013 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 3014 | |
| 3015 | // Nothing to do if the {elements} are not copy-on-write. |
| 3016 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 3017 | Node* etrue = effect; |
| 3018 | Node* vtrue = elements; |
| 3019 | |
| 3020 | // We need to take a copy of the {elements} and set them up for {object}. |
| 3021 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 3022 | Node* efalse = effect; |
| 3023 | Node* vfalse; |
| 3024 | { |
| 3025 | // We need to create a copy of the {elements} for {object}. |
| 3026 | Operator::Properties properties = Operator::kEliminatable; |
| 3027 | Callable callable = CodeFactory::CopyFastSmiOrObjectElements(isolate()); |
| 3028 | CallDescriptor::Flags flags = CallDescriptor::kNoFlags; |
| 3029 | CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
| 3030 | isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
| 3031 | properties); |
| 3032 | vfalse = efalse = graph()->NewNode( |
| 3033 | common()->Call(desc), jsgraph()->HeapConstant(callable.code()), object, |
| 3034 | jsgraph()->NoContextConstant(), efalse); |
| 3035 | } |
| 3036 | |
| 3037 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 3038 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 3039 | Node* value = graph()->NewNode( |
| 3040 | common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control); |
| 3041 | |
| 3042 | return ValueEffectControl(value, effect, control); |
| 3043 | } |
| 3044 | |
| 3045 | EffectControlLinearizer::ValueEffectControl |
| 3046 | EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node, |
| 3047 | Node* frame_state, |
| 3048 | Node* effect, |
| 3049 | Node* control) { |
| 3050 | GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); |
| 3051 | Node* object = node->InputAt(0); |
| 3052 | Node* elements = node->InputAt(1); |
| 3053 | Node* index = node->InputAt(2); |
| 3054 | Node* length = node->InputAt(3); |
| 3055 | |
| 3056 | Node* check0 = graph()->NewNode((flags & GrowFastElementsFlag::kHoleyElements) |
| 3057 | ? machine()->Uint32LessThanOrEqual() |
| 3058 | : machine()->Word32Equal(), |
| 3059 | length, index); |
| 3060 | Node* branch0 = graph()->NewNode(common()->Branch(), check0, control); |
| 3061 | |
| 3062 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 3063 | Node* etrue0 = effect; |
| 3064 | Node* vtrue0 = elements; |
| 3065 | { |
| 3066 | // Load the length of the {elements} backing store. |
| 3067 | Node* elements_length = etrue0 = graph()->NewNode( |
| 3068 | simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), elements, |
| 3069 | etrue0, if_true0); |
| 3070 | elements_length = ChangeSmiToInt32(elements_length); |
| 3071 | |
| 3072 | // Check if we need to grow the {elements} backing store. |
| 3073 | Node* check1 = |
| 3074 | graph()->NewNode(machine()->Uint32LessThan(), index, elements_length); |
| 3075 | Node* branch1 = |
| 3076 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); |
| 3077 | |
| 3078 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3079 | Node* etrue1 = etrue0; |
| 3080 | Node* vtrue1 = vtrue0; |
| 3081 | |
| 3082 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3083 | Node* efalse1 = etrue0; |
| 3084 | Node* vfalse1 = vtrue0; |
| 3085 | { |
| 3086 | // We need to grow the {elements} for {object}. |
| 3087 | Operator::Properties properties = Operator::kEliminatable; |
| 3088 | Callable callable = |
| 3089 | (flags & GrowFastElementsFlag::kDoubleElements) |
| 3090 | ? CodeFactory::GrowFastDoubleElements(isolate()) |
| 3091 | : CodeFactory::GrowFastSmiOrObjectElements(isolate()); |
| 3092 | CallDescriptor::Flags flags = CallDescriptor::kNoFlags; |
| 3093 | CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
| 3094 | isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
| 3095 | properties); |
| 3096 | vfalse1 = efalse1 = graph()->NewNode( |
| 3097 | common()->Call(desc), jsgraph()->HeapConstant(callable.code()), |
| 3098 | object, ChangeInt32ToSmi(index), jsgraph()->NoContextConstant(), |
| 3099 | efalse1); |
| 3100 | |
| 3101 | // Ensure that we were able to grow the {elements}. |
| 3102 | // TODO(turbofan): We use kSmi as reason here similar to Crankshaft, |
| 3103 | // but maybe we should just introduce a reason that makes sense. |
| 3104 | efalse1 = if_false1 = graph()->NewNode( |
| 3105 | common()->DeoptimizeIf(DeoptimizeReason::kSmi), ObjectIsSmi(vfalse1), |
| 3106 | frame_state, efalse1, if_false1); |
| 3107 | } |
| 3108 | |
| 3109 | if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3110 | etrue0 = |
| 3111 | graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
| 3112 | vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 3113 | vtrue1, vfalse1, if_true0); |
| 3114 | |
| 3115 | // For JSArray {object}s we also need to update the "length". |
| 3116 | if (flags & GrowFastElementsFlag::kArrayObject) { |
| 3117 | // Compute the new {length}. |
| 3118 | Node* object_length = ChangeInt32ToSmi(graph()->NewNode( |
| 3119 | machine()->Int32Add(), index, jsgraph()->Int32Constant(1))); |
| 3120 | |
| 3121 | // Update the "length" property of the {object}. |
| 3122 | etrue0 = |
| 3123 | graph()->NewNode(simplified()->StoreField( |
| 3124 | AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 3125 | object, object_length, etrue0, if_true0); |
| 3126 | } |
| 3127 | } |
| 3128 | |
| 3129 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 3130 | Node* efalse0 = effect; |
| 3131 | Node* vfalse0 = elements; |
| 3132 | { |
| 3133 | // In case of non-holey {elements}, we need to verify that the {index} is |
| 3134 | // in-bounds, otherwise for holey {elements}, the check above already |
| 3135 | // guards the index (and the operator forces {index} to be unsigned). |
| 3136 | if (!(flags & GrowFastElementsFlag::kHoleyElements)) { |
| 3137 | Node* check1 = |
| 3138 | graph()->NewNode(machine()->Uint32LessThan(), index, length); |
| 3139 | efalse0 = if_false0 = graph()->NewNode( |
| 3140 | common()->DeoptimizeUnless(DeoptimizeReason::kOutOfBounds), check1, |
| 3141 | frame_state, efalse0, if_false0); |
| 3142 | } |
| 3143 | } |
| 3144 | |
| 3145 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 3146 | effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 3147 | Node* value = |
| 3148 | graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0, |
| 3149 | vfalse0, control); |
| 3150 | |
| 3151 | return ValueEffectControl(value, effect, control); |
| 3152 | } |
| 3153 | |
| 3154 | EffectControlLinearizer::ValueEffectControl |
| 3155 | EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect, |
| 3156 | Node* control) { |
| 3157 | ElementsTransition const transition = ElementsTransitionOf(node->op()); |
| 3158 | Node* object = node->InputAt(0); |
| 3159 | Node* source_map = node->InputAt(1); |
| 3160 | Node* target_map = node->InputAt(2); |
| 3161 | |
| 3162 | // Load the current map of {object}. |
| 3163 | Node* object_map = effect = |
| 3164 | graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, |
| 3165 | effect, control); |
| 3166 | |
| 3167 | // Check if {object_map} is the same as {source_map}. |
| 3168 | Node* check = |
| 3169 | graph()->NewNode(machine()->WordEqual(), object_map, source_map); |
| 3170 | Node* branch = |
| 3171 | graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 3172 | |
| 3173 | // Migrate the {object} from {source_map} to {target_map}. |
| 3174 | Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 3175 | Node* etrue = effect; |
| 3176 | { |
| 3177 | switch (transition) { |
| 3178 | case ElementsTransition::kFastTransition: { |
| 3179 | // In-place migration of {object}, just store the {target_map}. |
| 3180 | etrue = |
| 3181 | graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), |
| 3182 | object, target_map, etrue, if_true); |
| 3183 | break; |
| 3184 | } |
| 3185 | case ElementsTransition::kSlowTransition: { |
| 3186 | // Instance migration, call out to the runtime for {object}. |
| 3187 | Operator::Properties properties = |
| 3188 | Operator::kNoDeopt | Operator::kNoThrow; |
| 3189 | Runtime::FunctionId id = Runtime::kTransitionElementsKind; |
| 3190 | CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor( |
| 3191 | graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags); |
| 3192 | etrue = graph()->NewNode( |
| 3193 | common()->Call(desc), jsgraph()->CEntryStubConstant(1), object, |
| 3194 | target_map, |
| 3195 | jsgraph()->ExternalConstant(ExternalReference(id, isolate())), |
| 3196 | jsgraph()->Int32Constant(2), jsgraph()->NoContextConstant(), etrue, |
| 3197 | if_true); |
| 3198 | break; |
| 3199 | } |
| 3200 | } |
| 3201 | } |
| 3202 | |
| 3203 | // Nothing to do if the {object} doesn't have the {source_map}. |
| 3204 | Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 3205 | Node* efalse = effect; |
| 3206 | |
| 3207 | control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 3208 | effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 3209 | |
| 3210 | return ValueEffectControl(nullptr, effect, control); |
| 3211 | } |
| 3212 | |
| 3213 | EffectControlLinearizer::ValueEffectControl |
| 3214 | EffectControlLinearizer::LowerLoadTypedElement(Node* node, Node* effect, |
| 3215 | Node* control) { |
| 3216 | ExternalArrayType array_type = ExternalArrayTypeOf(node->op()); |
| 3217 | Node* buffer = node->InputAt(0); |
| 3218 | Node* base = node->InputAt(1); |
| 3219 | Node* external = node->InputAt(2); |
| 3220 | Node* index = node->InputAt(3); |
| 3221 | |
| 3222 | // We need to keep the {buffer} alive so that the GC will not release the |
| 3223 | // ArrayBuffer (if there's any) as long as we are still operating on it. |
| 3224 | effect = graph()->NewNode(common()->Retain(), buffer, effect); |
| 3225 | |
| 3226 | // Compute the effective storage pointer. |
| 3227 | Node* storage = effect = graph()->NewNode(machine()->UnsafePointerAdd(), base, |
| 3228 | external, effect, control); |
| 3229 | |
| 3230 | // Perform the actual typed element access. |
| 3231 | Node* value = effect = graph()->NewNode( |
| 3232 | simplified()->LoadElement( |
| 3233 | AccessBuilder::ForTypedArrayElement(array_type, true)), |
| 3234 | storage, index, effect, control); |
| 3235 | |
| 3236 | return ValueEffectControl(value, effect, control); |
| 3237 | } |
| 3238 | |
| 3239 | EffectControlLinearizer::ValueEffectControl |
| 3240 | EffectControlLinearizer::LowerStoreTypedElement(Node* node, Node* effect, |
| 3241 | Node* control) { |
| 3242 | ExternalArrayType array_type = ExternalArrayTypeOf(node->op()); |
| 3243 | Node* buffer = node->InputAt(0); |
| 3244 | Node* base = node->InputAt(1); |
| 3245 | Node* external = node->InputAt(2); |
| 3246 | Node* index = node->InputAt(3); |
| 3247 | Node* value = node->InputAt(4); |
| 3248 | |
| 3249 | // We need to keep the {buffer} alive so that the GC will not release the |
| 3250 | // ArrayBuffer (if there's any) as long as we are still operating on it. |
| 3251 | effect = graph()->NewNode(common()->Retain(), buffer, effect); |
| 3252 | |
| 3253 | // Compute the effective storage pointer. |
| 3254 | Node* storage = effect = graph()->NewNode(machine()->UnsafePointerAdd(), base, |
| 3255 | external, effect, control); |
| 3256 | |
| 3257 | // Perform the actual typed element access. |
| 3258 | effect = graph()->NewNode( |
| 3259 | simplified()->StoreElement( |
| 3260 | AccessBuilder::ForTypedArrayElement(array_type, true)), |
| 3261 | storage, index, value, effect, control); |
| 3262 | |
| 3263 | return ValueEffectControl(nullptr, effect, control); |
| 3264 | } |
| 3265 | |
| 3266 | EffectControlLinearizer::ValueEffectControl |
| 3267 | EffectControlLinearizer::LowerFloat64RoundUp(Node* node, Node* effect, |
| 3268 | Node* control) { |
| 3269 | // Nothing to be done if a fast hardware instruction is available. |
| 3270 | if (machine()->Float64RoundUp().IsSupported()) { |
| 3271 | return ValueEffectControl(node, effect, control); |
| 3272 | } |
| 3273 | |
| 3274 | Node* const one = jsgraph()->Float64Constant(1.0); |
| 3275 | Node* const zero = jsgraph()->Float64Constant(0.0); |
| 3276 | Node* const minus_zero = jsgraph()->Float64Constant(-0.0); |
| 3277 | Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0); |
| 3278 | Node* const minus_two_52 = jsgraph()->Float64Constant(-4503599627370496.0E0); |
| 3279 | Node* const input = node->InputAt(0); |
| 3280 | |
| 3281 | // General case for ceil. |
| 3282 | // |
| 3283 | // if 0.0 < input then |
| 3284 | // if 2^52 <= input then |
| 3285 | // input |
| 3286 | // else |
| 3287 | // let temp1 = (2^52 + input) - 2^52 in |
| 3288 | // if temp1 < input then |
| 3289 | // temp1 + 1 |
| 3290 | // else |
| 3291 | // temp1 |
| 3292 | // else |
| 3293 | // if input == 0 then |
| 3294 | // input |
| 3295 | // else |
| 3296 | // if input <= -2^52 then |
| 3297 | // input |
| 3298 | // else |
| 3299 | // let temp1 = -0 - input in |
| 3300 | // let temp2 = (2^52 + temp1) - 2^52 in |
| 3301 | // let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in |
| 3302 | // -0 - temp3 |
| 3303 | // |
| 3304 | // Note: We do not use the Diamond helper class here, because it really hurts |
| 3305 | // readability with nested diamonds. |
| 3306 | |
| 3307 | Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input); |
| 3308 | Node* branch0 = |
| 3309 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 3310 | |
| 3311 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 3312 | Node* vtrue0; |
| 3313 | { |
| 3314 | Node* check1 = |
| 3315 | graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input); |
| 3316 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0); |
| 3317 | |
| 3318 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3319 | Node* vtrue1 = input; |
| 3320 | |
| 3321 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3322 | Node* vfalse1; |
| 3323 | { |
| 3324 | Node* temp1 = graph()->NewNode( |
| 3325 | machine()->Float64Sub(), |
| 3326 | graph()->NewNode(machine()->Float64Add(), two_52, input), two_52); |
| 3327 | vfalse1 = graph()->NewNode( |
| 3328 | common()->Select(MachineRepresentation::kFloat64), |
| 3329 | graph()->NewNode(machine()->Float64LessThan(), temp1, input), |
| 3330 | graph()->NewNode(machine()->Float64Add(), temp1, one), temp1); |
| 3331 | } |
| 3332 | |
| 3333 | if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3334 | vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3335 | vtrue1, vfalse1, if_true0); |
| 3336 | } |
| 3337 | |
| 3338 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 3339 | Node* vfalse0; |
| 3340 | { |
| 3341 | Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero); |
| 3342 | Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 3343 | check1, if_false0); |
| 3344 | |
| 3345 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3346 | Node* vtrue1 = input; |
| 3347 | |
| 3348 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3349 | Node* vfalse1; |
| 3350 | { |
| 3351 | Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(), |
| 3352 | input, minus_two_52); |
| 3353 | Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 3354 | check2, if_false1); |
| 3355 | |
| 3356 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 3357 | Node* vtrue2 = input; |
| 3358 | |
| 3359 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 3360 | Node* vfalse2; |
| 3361 | { |
| 3362 | Node* temp1 = |
| 3363 | graph()->NewNode(machine()->Float64Sub(), minus_zero, input); |
| 3364 | Node* temp2 = graph()->NewNode( |
| 3365 | machine()->Float64Sub(), |
| 3366 | graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52); |
| 3367 | Node* temp3 = graph()->NewNode( |
| 3368 | common()->Select(MachineRepresentation::kFloat64), |
| 3369 | graph()->NewNode(machine()->Float64LessThan(), temp1, temp2), |
| 3370 | graph()->NewNode(machine()->Float64Sub(), temp2, one), temp2); |
| 3371 | vfalse2 = graph()->NewNode(machine()->Float64Sub(), minus_zero, temp3); |
| 3372 | } |
| 3373 | |
| 3374 | if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
| 3375 | vfalse1 = |
| 3376 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3377 | vtrue2, vfalse2, if_false1); |
| 3378 | } |
| 3379 | |
| 3380 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3381 | vfalse0 = |
| 3382 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3383 | vtrue1, vfalse1, if_false0); |
| 3384 | } |
| 3385 | |
| 3386 | Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 3387 | Node* value = |
| 3388 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3389 | vtrue0, vfalse0, merge0); |
| 3390 | return ValueEffectControl(value, effect, merge0); |
| 3391 | } |
| 3392 | |
| 3393 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3394 | EffectControlLinearizer::BuildFloat64RoundDown(Node* value, Node* effect, |
| 3395 | Node* control) { |
| 3396 | if (machine()->Float64RoundDown().IsSupported()) { |
| 3397 | value = graph()->NewNode(machine()->Float64RoundDown().op(), value); |
| 3398 | } else { |
| 3399 | Node* const one = jsgraph()->Float64Constant(1.0); |
| 3400 | Node* const zero = jsgraph()->Float64Constant(0.0); |
| 3401 | Node* const minus_one = jsgraph()->Float64Constant(-1.0); |
| 3402 | Node* const minus_zero = jsgraph()->Float64Constant(-0.0); |
| 3403 | Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0); |
| 3404 | Node* const minus_two_52 = |
| 3405 | jsgraph()->Float64Constant(-4503599627370496.0E0); |
| 3406 | Node* const input = value; |
| 3407 | |
| 3408 | // General case for floor. |
| 3409 | // |
| 3410 | // if 0.0 < input then |
| 3411 | // if 2^52 <= input then |
| 3412 | // input |
| 3413 | // else |
| 3414 | // let temp1 = (2^52 + input) - 2^52 in |
| 3415 | // if input < temp1 then |
| 3416 | // temp1 - 1 |
| 3417 | // else |
| 3418 | // temp1 |
| 3419 | // else |
| 3420 | // if input == 0 then |
| 3421 | // input |
| 3422 | // else |
| 3423 | // if input <= -2^52 then |
| 3424 | // input |
| 3425 | // else |
| 3426 | // let temp1 = -0 - input in |
| 3427 | // let temp2 = (2^52 + temp1) - 2^52 in |
| 3428 | // if temp2 < temp1 then |
| 3429 | // -1 - temp2 |
| 3430 | // else |
| 3431 | // -0 - temp2 |
| 3432 | // |
| 3433 | // Note: We do not use the Diamond helper class here, because it really |
| 3434 | // hurts |
| 3435 | // readability with nested diamonds. |
| 3436 | |
| 3437 | Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input); |
| 3438 | Node* branch0 = |
| 3439 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 3440 | |
| 3441 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 3442 | Node* vtrue0; |
| 3443 | { |
| 3444 | Node* check1 = |
| 3445 | graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input); |
| 3446 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0); |
| 3447 | |
| 3448 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3449 | Node* vtrue1 = input; |
| 3450 | |
| 3451 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3452 | Node* vfalse1; |
| 3453 | { |
| 3454 | Node* temp1 = graph()->NewNode( |
| 3455 | machine()->Float64Sub(), |
| 3456 | graph()->NewNode(machine()->Float64Add(), two_52, input), two_52); |
| 3457 | vfalse1 = graph()->NewNode( |
| 3458 | common()->Select(MachineRepresentation::kFloat64), |
| 3459 | graph()->NewNode(machine()->Float64LessThan(), input, temp1), |
| 3460 | graph()->NewNode(machine()->Float64Sub(), temp1, one), temp1); |
| 3461 | } |
| 3462 | |
| 3463 | if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3464 | vtrue0 = |
| 3465 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3466 | vtrue1, vfalse1, if_true0); |
| 3467 | } |
| 3468 | |
| 3469 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 3470 | Node* vfalse0; |
| 3471 | { |
| 3472 | Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero); |
| 3473 | Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 3474 | check1, if_false0); |
| 3475 | |
| 3476 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3477 | Node* vtrue1 = input; |
| 3478 | |
| 3479 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3480 | Node* vfalse1; |
| 3481 | { |
| 3482 | Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(), |
| 3483 | input, minus_two_52); |
| 3484 | Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 3485 | check2, if_false1); |
| 3486 | |
| 3487 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 3488 | Node* vtrue2 = input; |
| 3489 | |
| 3490 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 3491 | Node* vfalse2; |
| 3492 | { |
| 3493 | Node* temp1 = |
| 3494 | graph()->NewNode(machine()->Float64Sub(), minus_zero, input); |
| 3495 | Node* temp2 = graph()->NewNode( |
| 3496 | machine()->Float64Sub(), |
| 3497 | graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52); |
| 3498 | vfalse2 = graph()->NewNode( |
| 3499 | common()->Select(MachineRepresentation::kFloat64), |
| 3500 | graph()->NewNode(machine()->Float64LessThan(), temp2, temp1), |
| 3501 | graph()->NewNode(machine()->Float64Sub(), minus_one, temp2), |
| 3502 | graph()->NewNode(machine()->Float64Sub(), minus_zero, temp2)); |
| 3503 | } |
| 3504 | |
| 3505 | if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
| 3506 | vfalse1 = |
| 3507 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3508 | vtrue2, vfalse2, if_false1); |
| 3509 | } |
| 3510 | |
| 3511 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3512 | vfalse0 = |
| 3513 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3514 | vtrue1, vfalse1, if_false0); |
| 3515 | } |
| 3516 | |
| 3517 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 3518 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3519 | vtrue0, vfalse0, control); |
| 3520 | } |
| 3521 | return ValueEffectControl(value, effect, control); |
| 3522 | } |
| 3523 | |
| 3524 | EffectControlLinearizer::ValueEffectControl |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3525 | EffectControlLinearizer::LowerFloat64RoundDown(Node* node, Node* effect, |
| 3526 | Node* control) { |
| 3527 | // Nothing to be done if a fast hardware instruction is available. |
| 3528 | if (machine()->Float64RoundDown().IsSupported()) { |
| 3529 | return ValueEffectControl(node, effect, control); |
| 3530 | } |
| 3531 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3532 | Node* const input = node->InputAt(0); |
| 3533 | return BuildFloat64RoundDown(input, effect, control); |
| 3534 | } |
| 3535 | |
| 3536 | EffectControlLinearizer::ValueEffectControl |
| 3537 | EffectControlLinearizer::LowerFloat64RoundTiesEven(Node* node, Node* effect, |
| 3538 | Node* control) { |
| 3539 | // Nothing to be done if a fast hardware instruction is available. |
| 3540 | if (machine()->Float64RoundTiesEven().IsSupported()) { |
| 3541 | return ValueEffectControl(node, effect, control); |
| 3542 | } |
| 3543 | |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3544 | Node* const one = jsgraph()->Float64Constant(1.0); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3545 | Node* const two = jsgraph()->Float64Constant(2.0); |
| 3546 | Node* const half = jsgraph()->Float64Constant(0.5); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3547 | Node* const zero = jsgraph()->Float64Constant(0.0); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3548 | Node* const input = node->InputAt(0); |
| 3549 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3550 | // Generate case for round ties to even: |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3551 | // |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3552 | // let value = floor(input) in |
| 3553 | // let temp1 = input - value in |
| 3554 | // if temp1 < 0.5 then |
| 3555 | // value |
| 3556 | // else if 0.5 < temp1 then |
| 3557 | // value + 1.0 |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3558 | // else |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3559 | // let temp2 = value % 2.0 in |
| 3560 | // if temp2 == 0.0 then |
| 3561 | // value |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3562 | // else |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3563 | // value + 1.0 |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3564 | // |
| 3565 | // Note: We do not use the Diamond helper class here, because it really hurts |
| 3566 | // readability with nested diamonds. |
| 3567 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3568 | ValueEffectControl continuation = |
| 3569 | BuildFloat64RoundDown(input, effect, control); |
| 3570 | Node* value = continuation.value; |
| 3571 | effect = continuation.effect; |
| 3572 | control = continuation.control; |
| 3573 | |
| 3574 | Node* temp1 = graph()->NewNode(machine()->Float64Sub(), input, value); |
| 3575 | |
| 3576 | Node* check0 = graph()->NewNode(machine()->Float64LessThan(), temp1, half); |
| 3577 | Node* branch0 = graph()->NewNode(common()->Branch(), check0, control); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3578 | |
| 3579 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3580 | Node* vtrue0 = value; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3581 | |
| 3582 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 3583 | Node* vfalse0; |
| 3584 | { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3585 | Node* check1 = graph()->NewNode(machine()->Float64LessThan(), half, temp1); |
| 3586 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3587 | |
| 3588 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3589 | Node* vtrue1 = graph()->NewNode(machine()->Float64Add(), value, one); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3590 | |
| 3591 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3592 | Node* vfalse1; |
| 3593 | { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3594 | Node* temp2 = graph()->NewNode(machine()->Float64Mod(), value, two); |
| 3595 | |
| 3596 | Node* check2 = graph()->NewNode(machine()->Float64Equal(), temp2, zero); |
| 3597 | Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3598 | |
| 3599 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3600 | Node* vtrue2 = value; |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3601 | |
| 3602 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3603 | Node* vfalse2 = graph()->NewNode(machine()->Float64Add(), value, one); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3604 | |
| 3605 | if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
| 3606 | vfalse1 = |
| 3607 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3608 | vtrue2, vfalse2, if_false1); |
| 3609 | } |
| 3610 | |
| 3611 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3612 | vfalse0 = |
| 3613 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3614 | vtrue1, vfalse1, if_false0); |
| 3615 | } |
| 3616 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame^] | 3617 | control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 3618 | value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3619 | vtrue0, vfalse0, control); |
| 3620 | |
| 3621 | return ValueEffectControl(value, effect, control); |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3622 | } |
| 3623 | |
| 3624 | EffectControlLinearizer::ValueEffectControl |
| 3625 | EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node, Node* effect, |
| 3626 | Node* control) { |
| 3627 | // Nothing to be done if a fast hardware instruction is available. |
| 3628 | if (machine()->Float64RoundTruncate().IsSupported()) { |
| 3629 | return ValueEffectControl(node, effect, control); |
| 3630 | } |
| 3631 | |
| 3632 | Node* const one = jsgraph()->Float64Constant(1.0); |
| 3633 | Node* const zero = jsgraph()->Float64Constant(0.0); |
| 3634 | Node* const minus_zero = jsgraph()->Float64Constant(-0.0); |
| 3635 | Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0); |
| 3636 | Node* const minus_two_52 = jsgraph()->Float64Constant(-4503599627370496.0E0); |
| 3637 | Node* const input = node->InputAt(0); |
| 3638 | |
| 3639 | // General case for trunc. |
| 3640 | // |
| 3641 | // if 0.0 < input then |
| 3642 | // if 2^52 <= input then |
| 3643 | // input |
| 3644 | // else |
| 3645 | // let temp1 = (2^52 + input) - 2^52 in |
| 3646 | // if input < temp1 then |
| 3647 | // temp1 - 1 |
| 3648 | // else |
| 3649 | // temp1 |
| 3650 | // else |
| 3651 | // if input == 0 then |
| 3652 | // input |
| 3653 | // else |
| 3654 | // if input <= -2^52 then |
| 3655 | // input |
| 3656 | // else |
| 3657 | // let temp1 = -0 - input in |
| 3658 | // let temp2 = (2^52 + temp1) - 2^52 in |
| 3659 | // let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in |
| 3660 | // -0 - temp3 |
| 3661 | // |
| 3662 | // Note: We do not use the Diamond helper class here, because it really hurts |
| 3663 | // readability with nested diamonds. |
| 3664 | |
| 3665 | Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input); |
| 3666 | Node* branch0 = |
| 3667 | graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 3668 | |
| 3669 | Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 3670 | Node* vtrue0; |
| 3671 | { |
| 3672 | Node* check1 = |
| 3673 | graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input); |
| 3674 | Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0); |
| 3675 | |
| 3676 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3677 | Node* vtrue1 = input; |
| 3678 | |
| 3679 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3680 | Node* vfalse1; |
| 3681 | { |
| 3682 | Node* temp1 = graph()->NewNode( |
| 3683 | machine()->Float64Sub(), |
| 3684 | graph()->NewNode(machine()->Float64Add(), two_52, input), two_52); |
| 3685 | vfalse1 = graph()->NewNode( |
| 3686 | common()->Select(MachineRepresentation::kFloat64), |
| 3687 | graph()->NewNode(machine()->Float64LessThan(), input, temp1), |
| 3688 | graph()->NewNode(machine()->Float64Sub(), temp1, one), temp1); |
| 3689 | } |
| 3690 | |
| 3691 | if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3692 | vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3693 | vtrue1, vfalse1, if_true0); |
| 3694 | } |
| 3695 | |
| 3696 | Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 3697 | Node* vfalse0; |
| 3698 | { |
| 3699 | Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero); |
| 3700 | Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 3701 | check1, if_false0); |
| 3702 | |
| 3703 | Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 3704 | Node* vtrue1 = input; |
| 3705 | |
| 3706 | Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 3707 | Node* vfalse1; |
| 3708 | { |
| 3709 | Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(), |
| 3710 | input, minus_two_52); |
| 3711 | Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 3712 | check2, if_false1); |
| 3713 | |
| 3714 | Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 3715 | Node* vtrue2 = input; |
| 3716 | |
| 3717 | Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
| 3718 | Node* vfalse2; |
| 3719 | { |
| 3720 | Node* temp1 = |
| 3721 | graph()->NewNode(machine()->Float64Sub(), minus_zero, input); |
| 3722 | Node* temp2 = graph()->NewNode( |
| 3723 | machine()->Float64Sub(), |
| 3724 | graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52); |
| 3725 | Node* temp3 = graph()->NewNode( |
| 3726 | common()->Select(MachineRepresentation::kFloat64), |
| 3727 | graph()->NewNode(machine()->Float64LessThan(), temp1, temp2), |
| 3728 | graph()->NewNode(machine()->Float64Sub(), temp2, one), temp2); |
| 3729 | vfalse2 = graph()->NewNode(machine()->Float64Sub(), minus_zero, temp3); |
| 3730 | } |
| 3731 | |
| 3732 | if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
| 3733 | vfalse1 = |
| 3734 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3735 | vtrue2, vfalse2, if_false1); |
| 3736 | } |
| 3737 | |
| 3738 | if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 3739 | vfalse0 = |
| 3740 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3741 | vtrue1, vfalse1, if_false0); |
| 3742 | } |
| 3743 | |
| 3744 | Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 3745 | Node* value = |
| 3746 | graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
| 3747 | vtrue0, vfalse0, merge0); |
| 3748 | return ValueEffectControl(value, effect, merge0); |
| 3749 | } |
| 3750 | |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 3751 | Factory* EffectControlLinearizer::factory() const { |
| 3752 | return isolate()->factory(); |
| 3753 | } |
| 3754 | |
| 3755 | Isolate* EffectControlLinearizer::isolate() const { |
| 3756 | return jsgraph()->isolate(); |
| 3757 | } |
| 3758 | |
| 3759 | Operator const* EffectControlLinearizer::ToNumberOperator() { |
| 3760 | if (!to_number_operator_.is_set()) { |
| 3761 | Callable callable = CodeFactory::ToNumber(isolate()); |
| 3762 | CallDescriptor::Flags flags = CallDescriptor::kNoFlags; |
| 3763 | CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 3764 | isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
| Ben Murdoch | f91f061 | 2016-11-29 16:50:11 +0000 | [diff] [blame] | 3765 | Operator::kEliminatable); |
| Ben Murdoch | 13e2dad | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 3766 | to_number_operator_.set(common()->Call(desc)); |
| 3767 | } |
| 3768 | return to_number_operator_.get(); |
| 3769 | } |
| 3770 | |
| Ben Murdoch | bcf72ee | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 3771 | } // namespace compiler |
| 3772 | } // namespace internal |
| 3773 | } // namespace v8 |