| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 #include "src/compiler/node-properties-inl.h" | 7 #include "src/compiler/node-properties-inl.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 } else { // store [%base + %index], %|#value | 154 } else { // store [%base + %index], %|#value |
| 155 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, | 155 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, |
| 156 g.UseRegister(base), g.UseRegister(index), val); | 156 g.UseRegister(base), g.UseRegister(index), val); |
| 157 } | 157 } |
| 158 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | 158 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] |
| 159 } | 159 } |
| 160 | 160 |
| 161 | 161 |
| 162 // Shared routine for multiple binary operations. | 162 // Shared routine for multiple binary operations. |
| 163 static void VisitBinop(InstructionSelector* selector, Node* node, | 163 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 164 ArchOpcode opcode) { | 164 InstructionCode opcode, FlagsContinuation* cont) { |
| 165 IA32OperandGenerator g(selector); | 165 IA32OperandGenerator g(selector); |
| 166 Int32BinopMatcher m(node); | 166 Int32BinopMatcher m(node); |
| 167 // TODO(turbofan): match complex addressing modes. | 167 InstructionOperand* inputs[4]; |
| 168 // TODO(turbofan): if commutative, pick the non-live-in operand as the left as | |
| 169 // this might be the last use and therefore its register can be reused. | |
| 170 if (g.CanBeImmediate(m.right().node())) { | |
| 171 selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(m.left().node()), | |
| 172 g.UseImmediate(m.right().node())); | |
| 173 } else { | |
| 174 selector->Emit(opcode, g.DefineSameAsFirst(node), | |
| 175 g.UseRegister(m.left().node()), g.Use(m.right().node())); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 | |
| 180 static void VisitBinopWithOverflow(InstructionSelector* selector, Node* node, | |
| 181 InstructionCode opcode) { | |
| 182 IA32OperandGenerator g(selector); | |
| 183 Int32BinopMatcher m(node); | |
| 184 InstructionOperand* inputs[2]; | |
| 185 size_t input_count = 0; | 168 size_t input_count = 0; |
| 186 InstructionOperand* outputs[2]; | 169 InstructionOperand* outputs[2]; |
| 187 size_t output_count = 0; | 170 size_t output_count = 0; |
| 188 | 171 |
| 189 // TODO(turbofan): match complex addressing modes. | 172 // TODO(turbofan): match complex addressing modes. |
| 190 // TODO(turbofan): if commutative, pick the non-live-in operand as the left as | 173 // TODO(turbofan): if commutative, pick the non-live-in operand as the left as |
| 191 // this might be the last use and therefore its register can be reused. | 174 // this might be the last use and therefore its register can be reused. |
| 192 if (g.CanBeImmediate(m.right().node())) { | 175 if (g.CanBeImmediate(m.right().node())) { |
| 193 inputs[input_count++] = g.Use(m.left().node()); | 176 inputs[input_count++] = g.Use(m.left().node()); |
| 194 inputs[input_count++] = g.UseImmediate(m.right().node()); | 177 inputs[input_count++] = g.UseImmediate(m.right().node()); |
| 195 } else { | 178 } else { |
| 196 inputs[input_count++] = g.UseRegister(m.left().node()); | 179 inputs[input_count++] = g.UseRegister(m.left().node()); |
| 197 inputs[input_count++] = g.Use(m.right().node()); | 180 inputs[input_count++] = g.Use(m.right().node()); |
| 198 } | 181 } |
| 199 | 182 |
| 200 // Define outputs depending on the projections. | 183 if (cont->IsBranch()) { |
| 201 Node* projections[2]; | 184 inputs[input_count++] = g.Label(cont->true_block()); |
| 202 node->CollectProjections(ARRAY_SIZE(projections), projections); | 185 inputs[input_count++] = g.Label(cont->false_block()); |
| 203 if (projections[0]) { | |
| 204 outputs[output_count++] = g.DefineSameAsFirst(projections[0]); | |
| 205 } | 186 } |
| 206 if (projections[1]) { | 187 |
| 207 opcode |= FlagsModeField::encode(kFlags_set); | 188 outputs[output_count++] = g.DefineSameAsFirst(node); |
| 208 opcode |= FlagsConditionField::encode(kOverflow); | 189 if (cont->IsSet()) { |
| 209 // TODO(turbofan): Use byte register here. | 190 // TODO(turbofan): Use byte register here. |
| 210 outputs[output_count++] = | 191 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
| 211 (projections[0] ? g.DefineAsRegister(projections[1]) | |
| 212 : g.DefineSameAsFirst(projections[1])); | |
| 213 } | 192 } |
| 214 | 193 |
| 215 ASSERT_NE(0, input_count); | 194 ASSERT_NE(0, input_count); |
| 216 ASSERT_NE(0, output_count); | 195 ASSERT_NE(0, output_count); |
| 217 ASSERT_GE(ARRAY_SIZE(inputs), input_count); | 196 ASSERT_GE(ARRAY_SIZE(inputs), input_count); |
| 218 ASSERT_GE(ARRAY_SIZE(outputs), output_count); | 197 ASSERT_GE(ARRAY_SIZE(outputs), output_count); |
| 219 | 198 |
| 220 selector->Emit(opcode, output_count, outputs, input_count, inputs); | 199 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, |
| 200 outputs, input_count, inputs); |
| 201 if (cont->IsBranch()) instr->MarkAsControl(); |
| 221 } | 202 } |
| 222 | 203 |
| 223 | 204 |
| 205 // Shared routine for multiple binary operations. |
| 206 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 207 InstructionCode opcode) { |
| 208 FlagsContinuation cont; |
| 209 VisitBinop(selector, node, opcode, &cont); |
| 210 } |
| 211 |
| 212 |
| 224 void InstructionSelector::VisitWord32And(Node* node) { | 213 void InstructionSelector::VisitWord32And(Node* node) { |
| 225 VisitBinop(this, node, kIA32And); | 214 VisitBinop(this, node, kIA32And); |
| 226 } | 215 } |
| 227 | 216 |
| 228 | 217 |
| 229 void InstructionSelector::VisitWord32Or(Node* node) { | 218 void InstructionSelector::VisitWord32Or(Node* node) { |
| 230 VisitBinop(this, node, kIA32Or); | 219 VisitBinop(this, node, kIA32Or); |
| 231 } | 220 } |
| 232 | 221 |
| 233 | 222 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 void InstructionSelector::VisitWord32Sar(Node* node) { | 269 void InstructionSelector::VisitWord32Sar(Node* node) { |
| 281 VisitShift(this, node, kIA32Sar); | 270 VisitShift(this, node, kIA32Sar); |
| 282 } | 271 } |
| 283 | 272 |
| 284 | 273 |
| 285 void InstructionSelector::VisitInt32Add(Node* node) { | 274 void InstructionSelector::VisitInt32Add(Node* node) { |
| 286 VisitBinop(this, node, kIA32Add); | 275 VisitBinop(this, node, kIA32Add); |
| 287 } | 276 } |
| 288 | 277 |
| 289 | 278 |
| 290 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { | |
| 291 VisitBinopWithOverflow(this, node, kIA32Add); | |
| 292 } | |
| 293 | |
| 294 | |
| 295 void InstructionSelector::VisitInt32Sub(Node* node) { | 279 void InstructionSelector::VisitInt32Sub(Node* node) { |
| 296 IA32OperandGenerator g(this); | 280 IA32OperandGenerator g(this); |
| 297 Int32BinopMatcher m(node); | 281 Int32BinopMatcher m(node); |
| 298 if (m.left().Is(0)) { | 282 if (m.left().Is(0)) { |
| 299 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); | 283 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); |
| 300 } else { | 284 } else { |
| 301 VisitBinop(this, node, kIA32Sub); | 285 VisitBinop(this, node, kIA32Sub); |
| 302 } | 286 } |
| 303 } | 287 } |
| 304 | 288 |
| 305 | 289 |
| 306 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { | |
| 307 VisitBinopWithOverflow(this, node, kIA32Sub); | |
| 308 } | |
| 309 | |
| 310 | |
| 311 void InstructionSelector::VisitInt32Mul(Node* node) { | 290 void InstructionSelector::VisitInt32Mul(Node* node) { |
| 312 IA32OperandGenerator g(this); | 291 IA32OperandGenerator g(this); |
| 313 Node* left = node->InputAt(0); | 292 Node* left = node->InputAt(0); |
| 314 Node* right = node->InputAt(1); | 293 Node* right = node->InputAt(1); |
| 315 if (g.CanBeImmediate(right)) { | 294 if (g.CanBeImmediate(right)) { |
| 316 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left), | 295 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left), |
| 317 g.UseImmediate(right)); | 296 g.UseImmediate(right)); |
| 318 } else if (g.CanBeImmediate(left)) { | 297 } else if (g.CanBeImmediate(left)) { |
| 319 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right), | 298 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right), |
| 320 g.UseImmediate(left)); | 299 g.UseImmediate(left)); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 | 410 |
| 432 void InstructionSelector::VisitFloat64Mod(Node* node) { | 411 void InstructionSelector::VisitFloat64Mod(Node* node) { |
| 433 IA32OperandGenerator g(this); | 412 IA32OperandGenerator g(this); |
| 434 InstructionOperand* temps[] = {g.TempRegister(eax)}; | 413 InstructionOperand* temps[] = {g.TempRegister(eax)}; |
| 435 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), | 414 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), |
| 436 g.UseDoubleRegister(node->InputAt(0)), | 415 g.UseDoubleRegister(node->InputAt(0)), |
| 437 g.UseDoubleRegister(node->InputAt(1)), 1, temps); | 416 g.UseDoubleRegister(node->InputAt(1)), 1, temps); |
| 438 } | 417 } |
| 439 | 418 |
| 440 | 419 |
| 420 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, |
| 421 FlagsContinuation* cont) { |
| 422 VisitBinop(this, node, kIA32Add, cont); |
| 423 } |
| 424 |
| 425 |
| 426 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, |
| 427 FlagsContinuation* cont) { |
| 428 VisitBinop(this, node, kIA32Sub, cont); |
| 429 } |
| 430 |
| 431 |
| 441 // Shared routine for multiple compare operations. | 432 // Shared routine for multiple compare operations. |
| 442 static inline void VisitCompare(InstructionSelector* selector, | 433 static inline void VisitCompare(InstructionSelector* selector, |
| 443 InstructionCode opcode, | 434 InstructionCode opcode, |
| 444 InstructionOperand* left, | 435 InstructionOperand* left, |
| 445 InstructionOperand* right, | 436 InstructionOperand* right, |
| 446 FlagsContinuation* cont) { | 437 FlagsContinuation* cont) { |
| 447 IA32OperandGenerator g(selector); | 438 IA32OperandGenerator g(selector); |
| 448 if (cont->IsBranch()) { | 439 if (cont->IsBranch()) { |
| 449 selector->Emit(cont->Encode(opcode), NULL, left, right, | 440 selector->Emit(cont->Encode(opcode), NULL, left, right, |
| 450 g.Label(cont->true_block()), | 441 g.Label(cont->true_block()), |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 if (descriptor->kind() == CallDescriptor::kCallAddress && | 551 if (descriptor->kind() == CallDescriptor::kCallAddress && |
| 561 buffer.pushed_count > 0) { | 552 buffer.pushed_count > 0) { |
| 562 ASSERT(deoptimization == NULL && continuation == NULL); | 553 ASSERT(deoptimization == NULL && continuation == NULL); |
| 563 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL); | 554 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL); |
| 564 } | 555 } |
| 565 } | 556 } |
| 566 | 557 |
| 567 } // namespace compiler | 558 } // namespace compiler |
| 568 } // namespace internal | 559 } // namespace internal |
| 569 } // namespace v8 | 560 } // namespace v8 |
| OLD | NEW |