| 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/base/bits.h" | 5 #include "src/base/bits.h" |
| 6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
| 7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
| 8 #include "src/compiler/node-properties.h" | 8 #include "src/compiler/node-properties.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 selector->Emit(opcode, g.DefineAsRegister(node), | 92 selector->Emit(opcode, g.DefineAsRegister(node), |
| 93 g.UseRegister(node->InputAt(0)), | 93 g.UseRegister(node->InputAt(0)), |
| 94 g.UseRegister(node->InputAt(1))); | 94 g.UseRegister(node->InputAt(1))); |
| 95 } | 95 } |
| 96 | 96 |
| 97 | 97 |
| 98 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax, | 98 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax, |
| 99 AddressingMode kImmMode, AddressingMode kRegMode> | 99 AddressingMode kImmMode, AddressingMode kRegMode> |
| 100 bool TryMatchShift(InstructionSelector* selector, | 100 bool TryMatchShift(InstructionSelector* selector, |
| 101 InstructionCode* opcode_return, Node* node, | 101 InstructionCode* opcode_return, Node* node, |
| 102 InstructionOperand** value_return, | 102 InstructionOperand* value_return, |
| 103 InstructionOperand** shift_return) { | 103 InstructionOperand* shift_return) { |
| 104 ArmOperandGenerator g(selector); | 104 ArmOperandGenerator g(selector); |
| 105 if (node->opcode() == kOpcode) { | 105 if (node->opcode() == kOpcode) { |
| 106 Int32BinopMatcher m(node); | 106 Int32BinopMatcher m(node); |
| 107 *value_return = g.UseRegister(m.left().node()); | 107 *value_return = g.UseRegister(m.left().node()); |
| 108 if (m.right().IsInRange(kImmMin, kImmMax)) { | 108 if (m.right().IsInRange(kImmMin, kImmMax)) { |
| 109 *opcode_return |= AddressingModeField::encode(kImmMode); | 109 *opcode_return |= AddressingModeField::encode(kImmMode); |
| 110 *shift_return = g.UseImmediate(m.right().node()); | 110 *shift_return = g.UseImmediate(m.right().node()); |
| 111 } else { | 111 } else { |
| 112 *opcode_return |= AddressingModeField::encode(kRegMode); | 112 *opcode_return |= AddressingModeField::encode(kRegMode); |
| 113 *shift_return = g.UseRegister(m.right().node()); | 113 *shift_return = g.UseRegister(m.right().node()); |
| 114 } | 114 } |
| 115 return true; | 115 return true; |
| 116 } | 116 } |
| 117 return false; | 117 return false; |
| 118 } | 118 } |
| 119 | 119 |
| 120 | 120 |
| 121 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return, | 121 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return, |
| 122 Node* node, InstructionOperand** value_return, | 122 Node* node, InstructionOperand* value_return, |
| 123 InstructionOperand** shift_return) { | 123 InstructionOperand* shift_return) { |
| 124 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I, | 124 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I, |
| 125 kMode_Operand2_R_ROR_R>(selector, opcode_return, node, | 125 kMode_Operand2_R_ROR_R>(selector, opcode_return, node, |
| 126 value_return, shift_return); | 126 value_return, shift_return); |
| 127 } | 127 } |
| 128 | 128 |
| 129 | 129 |
| 130 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return, | 130 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return, |
| 131 Node* node, InstructionOperand** value_return, | 131 Node* node, InstructionOperand* value_return, |
| 132 InstructionOperand** shift_return) { | 132 InstructionOperand* shift_return) { |
| 133 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I, | 133 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I, |
| 134 kMode_Operand2_R_ASR_R>(selector, opcode_return, node, | 134 kMode_Operand2_R_ASR_R>(selector, opcode_return, node, |
| 135 value_return, shift_return); | 135 value_return, shift_return); |
| 136 } | 136 } |
| 137 | 137 |
| 138 | 138 |
| 139 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return, | 139 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return, |
| 140 Node* node, InstructionOperand** value_return, | 140 Node* node, InstructionOperand* value_return, |
| 141 InstructionOperand** shift_return) { | 141 InstructionOperand* shift_return) { |
| 142 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I, | 142 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I, |
| 143 kMode_Operand2_R_LSL_R>(selector, opcode_return, node, | 143 kMode_Operand2_R_LSL_R>(selector, opcode_return, node, |
| 144 value_return, shift_return); | 144 value_return, shift_return); |
| 145 } | 145 } |
| 146 | 146 |
| 147 | 147 |
| 148 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return, | 148 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return, |
| 149 Node* node, InstructionOperand** value_return, | 149 Node* node, InstructionOperand* value_return, |
| 150 InstructionOperand** shift_return) { | 150 InstructionOperand* shift_return) { |
| 151 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I, | 151 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I, |
| 152 kMode_Operand2_R_LSR_R>(selector, opcode_return, node, | 152 kMode_Operand2_R_LSR_R>(selector, opcode_return, node, |
| 153 value_return, shift_return); | 153 value_return, shift_return); |
| 154 } | 154 } |
| 155 | 155 |
| 156 | 156 |
| 157 bool TryMatchShift(InstructionSelector* selector, | 157 bool TryMatchShift(InstructionSelector* selector, |
| 158 InstructionCode* opcode_return, Node* node, | 158 InstructionCode* opcode_return, Node* node, |
| 159 InstructionOperand** value_return, | 159 InstructionOperand* value_return, |
| 160 InstructionOperand** shift_return) { | 160 InstructionOperand* shift_return) { |
| 161 return ( | 161 return ( |
| 162 TryMatchASR(selector, opcode_return, node, value_return, shift_return) || | 162 TryMatchASR(selector, opcode_return, node, value_return, shift_return) || |
| 163 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) || | 163 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) || |
| 164 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) || | 164 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) || |
| 165 TryMatchROR(selector, opcode_return, node, value_return, shift_return)); | 165 TryMatchROR(selector, opcode_return, node, value_return, shift_return)); |
| 166 } | 166 } |
| 167 | 167 |
| 168 | 168 |
| 169 bool TryMatchImmediateOrShift(InstructionSelector* selector, | 169 bool TryMatchImmediateOrShift(InstructionSelector* selector, |
| 170 InstructionCode* opcode_return, Node* node, | 170 InstructionCode* opcode_return, Node* node, |
| 171 size_t* input_count_return, | 171 size_t* input_count_return, |
| 172 InstructionOperand** inputs) { | 172 InstructionOperand* inputs) { |
| 173 ArmOperandGenerator g(selector); | 173 ArmOperandGenerator g(selector); |
| 174 if (g.CanBeImmediate(node, *opcode_return)) { | 174 if (g.CanBeImmediate(node, *opcode_return)) { |
| 175 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); | 175 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); |
| 176 inputs[0] = g.UseImmediate(node); | 176 inputs[0] = g.UseImmediate(node); |
| 177 *input_count_return = 1; | 177 *input_count_return = 1; |
| 178 return true; | 178 return true; |
| 179 } | 179 } |
| 180 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) { | 180 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) { |
| 181 *input_count_return = 2; | 181 *input_count_return = 2; |
| 182 return true; | 182 return true; |
| 183 } | 183 } |
| 184 return false; | 184 return false; |
| 185 } | 185 } |
| 186 | 186 |
| 187 | 187 |
| 188 void VisitBinop(InstructionSelector* selector, Node* node, | 188 void VisitBinop(InstructionSelector* selector, Node* node, |
| 189 InstructionCode opcode, InstructionCode reverse_opcode, | 189 InstructionCode opcode, InstructionCode reverse_opcode, |
| 190 FlagsContinuation* cont) { | 190 FlagsContinuation* cont) { |
| 191 ArmOperandGenerator g(selector); | 191 ArmOperandGenerator g(selector); |
| 192 Int32BinopMatcher m(node); | 192 Int32BinopMatcher m(node); |
| 193 InstructionOperand* inputs[5]; | 193 InstructionOperand inputs[5]; |
| 194 size_t input_count = 0; | 194 size_t input_count = 0; |
| 195 InstructionOperand* outputs[2]; | 195 InstructionOperand outputs[2]; |
| 196 size_t output_count = 0; | 196 size_t output_count = 0; |
| 197 | 197 |
| 198 if (m.left().node() == m.right().node()) { | 198 if (m.left().node() == m.right().node()) { |
| 199 // If both inputs refer to the same operand, enforce allocating a register | 199 // If both inputs refer to the same operand, enforce allocating a register |
| 200 // for both of them to ensure that we don't end up generating code like | 200 // for both of them to ensure that we don't end up generating code like |
| 201 // this: | 201 // this: |
| 202 // | 202 // |
| 203 // mov r0, r1, asr #16 | 203 // mov r0, r1, asr #16 |
| 204 // adds r0, r0, r1, asr #16 | 204 // adds r0, r0, r1, asr #16 |
| 205 // bvs label | 205 // bvs label |
| 206 InstructionOperand* const input = g.UseRegister(m.left().node()); | 206 InstructionOperand const input = g.UseRegister(m.left().node()); |
| 207 opcode |= AddressingModeField::encode(kMode_Operand2_R); | 207 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
| 208 inputs[input_count++] = input; | 208 inputs[input_count++] = input; |
| 209 inputs[input_count++] = input; | 209 inputs[input_count++] = input; |
| 210 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 210 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
| 211 &input_count, &inputs[1])) { | 211 &input_count, &inputs[1])) { |
| 212 inputs[0] = g.UseRegister(m.left().node()); | 212 inputs[0] = g.UseRegister(m.left().node()); |
| 213 input_count++; | 213 input_count++; |
| 214 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, | 214 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, |
| 215 m.left().node(), &input_count, | 215 m.left().node(), &input_count, |
| 216 &inputs[1])) { | 216 &inputs[1])) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 Node* index = node->InputAt(1); | 302 Node* index = node->InputAt(1); |
| 303 Node* value = node->InputAt(2); | 303 Node* value = node->InputAt(2); |
| 304 | 304 |
| 305 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 305 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
| 306 MachineType rep = RepresentationOf(store_rep.machine_type()); | 306 MachineType rep = RepresentationOf(store_rep.machine_type()); |
| 307 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 307 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
| 308 DCHECK(rep == kRepTagged); | 308 DCHECK(rep == kRepTagged); |
| 309 // TODO(dcarney): refactor RecordWrite function to take temp registers | 309 // TODO(dcarney): refactor RecordWrite function to take temp registers |
| 310 // and pass them here instead of using fixed regs | 310 // and pass them here instead of using fixed regs |
| 311 // TODO(dcarney): handle immediate indices. | 311 // TODO(dcarney): handle immediate indices. |
| 312 InstructionOperand* temps[] = {g.TempRegister(r5), g.TempRegister(r6)}; | 312 InstructionOperand temps[] = {g.TempRegister(r5), g.TempRegister(r6)}; |
| 313 Emit(kArmStoreWriteBarrier, NULL, g.UseFixed(base, r4), | 313 Emit(kArmStoreWriteBarrier, g.NoOutput(), g.UseFixed(base, r4), |
| 314 g.UseFixed(index, r5), g.UseFixed(value, r6), arraysize(temps), | 314 g.UseFixed(index, r5), g.UseFixed(value, r6), arraysize(temps), temps); |
| 315 temps); | |
| 316 return; | 315 return; |
| 317 } | 316 } |
| 318 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 317 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| 319 | 318 |
| 320 ArchOpcode opcode; | 319 ArchOpcode opcode; |
| 321 switch (rep) { | 320 switch (rep) { |
| 322 case kRepFloat32: | 321 case kRepFloat32: |
| 323 opcode = kArmVstrF32; | 322 opcode = kArmVstrF32; |
| 324 break; | 323 break; |
| 325 case kRepFloat64: | 324 case kRepFloat64: |
| 326 opcode = kArmVstrF64; | 325 opcode = kArmVstrF64; |
| 327 break; | 326 break; |
| 328 case kRepBit: // Fall through. | 327 case kRepBit: // Fall through. |
| 329 case kRepWord8: | 328 case kRepWord8: |
| 330 opcode = kArmStrb; | 329 opcode = kArmStrb; |
| 331 break; | 330 break; |
| 332 case kRepWord16: | 331 case kRepWord16: |
| 333 opcode = kArmStrh; | 332 opcode = kArmStrh; |
| 334 break; | 333 break; |
| 335 case kRepTagged: // Fall through. | 334 case kRepTagged: // Fall through. |
| 336 case kRepWord32: | 335 case kRepWord32: |
| 337 opcode = kArmStr; | 336 opcode = kArmStr; |
| 338 break; | 337 break; |
| 339 default: | 338 default: |
| 340 UNREACHABLE(); | 339 UNREACHABLE(); |
| 341 return; | 340 return; |
| 342 } | 341 } |
| 343 | 342 |
| 344 if (g.CanBeImmediate(index, opcode)) { | 343 if (g.CanBeImmediate(index, opcode)) { |
| 345 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, | 344 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(), |
| 346 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); | 345 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); |
| 347 } else { | 346 } else { |
| 348 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL, | 347 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), |
| 349 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); | 348 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); |
| 350 } | 349 } |
| 351 } | 350 } |
| 352 | 351 |
| 353 | 352 |
| 354 void InstructionSelector::VisitCheckedLoad(Node* node) { | 353 void InstructionSelector::VisitCheckedLoad(Node* node) { |
| 355 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 354 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 356 MachineType typ = TypeOf(OpParameter<MachineType>(node)); | 355 MachineType typ = TypeOf(OpParameter<MachineType>(node)); |
| 357 ArmOperandGenerator g(this); | 356 ArmOperandGenerator g(this); |
| 358 Node* const buffer = node->InputAt(0); | 357 Node* const buffer = node->InputAt(0); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 372 case kRepFloat32: | 371 case kRepFloat32: |
| 373 opcode = kCheckedLoadFloat32; | 372 opcode = kCheckedLoadFloat32; |
| 374 break; | 373 break; |
| 375 case kRepFloat64: | 374 case kRepFloat64: |
| 376 opcode = kCheckedLoadFloat64; | 375 opcode = kCheckedLoadFloat64; |
| 377 break; | 376 break; |
| 378 default: | 377 default: |
| 379 UNREACHABLE(); | 378 UNREACHABLE(); |
| 380 return; | 379 return; |
| 381 } | 380 } |
| 382 InstructionOperand* offset_operand = g.UseRegister(offset); | 381 InstructionOperand offset_operand = g.UseRegister(offset); |
| 383 InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp) | 382 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) |
| 384 ? g.UseImmediate(length) | 383 ? g.UseImmediate(length) |
| 385 : g.UseRegister(length); | 384 : g.UseRegister(length); |
| 386 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), | 385 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), |
| 387 g.DefineAsRegister(node), offset_operand, length_operand, | 386 g.DefineAsRegister(node), offset_operand, length_operand, |
| 388 g.UseRegister(buffer), offset_operand); | 387 g.UseRegister(buffer), offset_operand); |
| 389 } | 388 } |
| 390 | 389 |
| 391 | 390 |
| 392 void InstructionSelector::VisitCheckedStore(Node* node) { | 391 void InstructionSelector::VisitCheckedStore(Node* node) { |
| 393 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 392 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
| 394 ArmOperandGenerator g(this); | 393 ArmOperandGenerator g(this); |
| 395 Node* const buffer = node->InputAt(0); | 394 Node* const buffer = node->InputAt(0); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 410 case kRepFloat32: | 409 case kRepFloat32: |
| 411 opcode = kCheckedStoreFloat32; | 410 opcode = kCheckedStoreFloat32; |
| 412 break; | 411 break; |
| 413 case kRepFloat64: | 412 case kRepFloat64: |
| 414 opcode = kCheckedStoreFloat64; | 413 opcode = kCheckedStoreFloat64; |
| 415 break; | 414 break; |
| 416 default: | 415 default: |
| 417 UNREACHABLE(); | 416 UNREACHABLE(); |
| 418 return; | 417 return; |
| 419 } | 418 } |
| 420 InstructionOperand* offset_operand = g.UseRegister(offset); | 419 InstructionOperand offset_operand = g.UseRegister(offset); |
| 421 InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp) | 420 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) |
| 422 ? g.UseImmediate(length) | 421 ? g.UseImmediate(length) |
| 423 : g.UseRegister(length); | 422 : g.UseRegister(length); |
| 424 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), nullptr, | 423 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), |
| 425 offset_operand, length_operand, g.UseRegister(value), | 424 offset_operand, length_operand, g.UseRegister(value), |
| 426 g.UseRegister(buffer), offset_operand); | 425 g.UseRegister(buffer), offset_operand); |
| 427 } | 426 } |
| 428 | 427 |
| 429 | 428 |
| 430 namespace { | 429 namespace { |
| 431 | 430 |
| 432 void EmitBic(InstructionSelector* selector, Node* node, Node* left, | 431 void EmitBic(InstructionSelector* selector, Node* node, Node* left, |
| 433 Node* right) { | 432 Node* right) { |
| 434 ArmOperandGenerator g(selector); | 433 ArmOperandGenerator g(selector); |
| 435 InstructionCode opcode = kArmBic; | 434 InstructionCode opcode = kArmBic; |
| 436 InstructionOperand* value_operand; | 435 InstructionOperand value_operand; |
| 437 InstructionOperand* shift_operand; | 436 InstructionOperand shift_operand; |
| 438 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) { | 437 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) { |
| 439 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), | 438 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), |
| 440 value_operand, shift_operand); | 439 value_operand, shift_operand); |
| 441 return; | 440 return; |
| 442 } | 441 } |
| 443 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), | 442 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), |
| 444 g.DefineAsRegister(node), g.UseRegister(left), | 443 g.DefineAsRegister(node), g.UseRegister(left), |
| 445 g.UseRegister(right)); | 444 g.UseRegister(right)); |
| 446 } | 445 } |
| 447 | 446 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 void InstructionSelector::VisitWord32Or(Node* node) { | 527 void InstructionSelector::VisitWord32Or(Node* node) { |
| 529 VisitBinop(this, node, kArmOrr, kArmOrr); | 528 VisitBinop(this, node, kArmOrr, kArmOrr); |
| 530 } | 529 } |
| 531 | 530 |
| 532 | 531 |
| 533 void InstructionSelector::VisitWord32Xor(Node* node) { | 532 void InstructionSelector::VisitWord32Xor(Node* node) { |
| 534 ArmOperandGenerator g(this); | 533 ArmOperandGenerator g(this); |
| 535 Int32BinopMatcher m(node); | 534 Int32BinopMatcher m(node); |
| 536 if (m.right().Is(-1)) { | 535 if (m.right().Is(-1)) { |
| 537 InstructionCode opcode = kArmMvn; | 536 InstructionCode opcode = kArmMvn; |
| 538 InstructionOperand* value_operand; | 537 InstructionOperand value_operand; |
| 539 InstructionOperand* shift_operand; | 538 InstructionOperand shift_operand; |
| 540 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand, | 539 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand, |
| 541 &shift_operand)) { | 540 &shift_operand)) { |
| 542 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); | 541 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); |
| 543 return; | 542 return; |
| 544 } | 543 } |
| 545 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), | 544 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), |
| 546 g.DefineAsRegister(node), g.UseRegister(m.left().node())); | 545 g.DefineAsRegister(node), g.UseRegister(m.left().node())); |
| 547 return; | 546 return; |
| 548 } | 547 } |
| 549 VisitBinop(this, node, kArmEor, kArmEor); | 548 VisitBinop(this, node, kArmEor, kArmEor); |
| 550 } | 549 } |
| 551 | 550 |
| 552 | 551 |
| 553 namespace { | 552 namespace { |
| 554 | 553 |
| 555 template <typename TryMatchShift> | 554 template <typename TryMatchShift> |
| 556 void VisitShift(InstructionSelector* selector, Node* node, | 555 void VisitShift(InstructionSelector* selector, Node* node, |
| 557 TryMatchShift try_match_shift, FlagsContinuation* cont) { | 556 TryMatchShift try_match_shift, FlagsContinuation* cont) { |
| 558 ArmOperandGenerator g(selector); | 557 ArmOperandGenerator g(selector); |
| 559 InstructionCode opcode = kArmMov; | 558 InstructionCode opcode = kArmMov; |
| 560 InstructionOperand* inputs[4]; | 559 InstructionOperand inputs[4]; |
| 561 size_t input_count = 2; | 560 size_t input_count = 2; |
| 562 InstructionOperand* outputs[2]; | 561 InstructionOperand outputs[2]; |
| 563 size_t output_count = 0; | 562 size_t output_count = 0; |
| 564 | 563 |
| 565 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1])); | 564 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1])); |
| 566 | 565 |
| 567 if (cont->IsBranch()) { | 566 if (cont->IsBranch()) { |
| 568 inputs[input_count++] = g.Label(cont->true_block()); | 567 inputs[input_count++] = g.Label(cont->true_block()); |
| 569 inputs[input_count++] = g.Label(cont->false_block()); | 568 inputs[input_count++] = g.Label(cont->false_block()); |
| 570 } | 569 } |
| 571 | 570 |
| 572 outputs[output_count++] = g.DefineAsRegister(node); | 571 outputs[output_count++] = g.DefineAsRegister(node); |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 | 801 |
| 803 void InstructionSelector::VisitInt32MulHigh(Node* node) { | 802 void InstructionSelector::VisitInt32MulHigh(Node* node) { |
| 804 ArmOperandGenerator g(this); | 803 ArmOperandGenerator g(this); |
| 805 Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), | 804 Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), |
| 806 g.UseRegister(node->InputAt(1))); | 805 g.UseRegister(node->InputAt(1))); |
| 807 } | 806 } |
| 808 | 807 |
| 809 | 808 |
| 810 void InstructionSelector::VisitUint32MulHigh(Node* node) { | 809 void InstructionSelector::VisitUint32MulHigh(Node* node) { |
| 811 ArmOperandGenerator g(this); | 810 ArmOperandGenerator g(this); |
| 812 InstructionOperand* outputs[] = {g.TempRegister(), g.DefineAsRegister(node)}; | 811 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)}; |
| 813 InstructionOperand* inputs[] = {g.UseRegister(node->InputAt(0)), | 812 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)), |
| 814 g.UseRegister(node->InputAt(1))}; | 813 g.UseRegister(node->InputAt(1))}; |
| 815 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs); | 814 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs); |
| 816 } | 815 } |
| 817 | 816 |
| 818 | 817 |
| 819 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, | 818 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, |
| 820 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, | 819 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, |
| 821 InstructionOperand* result_operand, | 820 InstructionOperand result_operand, |
| 822 InstructionOperand* left_operand, | 821 InstructionOperand left_operand, |
| 823 InstructionOperand* right_operand) { | 822 InstructionOperand right_operand) { |
| 824 ArmOperandGenerator g(selector); | 823 ArmOperandGenerator g(selector); |
| 825 if (selector->IsSupported(SUDIV)) { | 824 if (selector->IsSupported(SUDIV)) { |
| 826 selector->Emit(div_opcode, result_operand, left_operand, right_operand); | 825 selector->Emit(div_opcode, result_operand, left_operand, right_operand); |
| 827 return; | 826 return; |
| 828 } | 827 } |
| 829 InstructionOperand* left_double_operand = g.TempDoubleRegister(); | 828 InstructionOperand left_double_operand = g.TempDoubleRegister(); |
| 830 InstructionOperand* right_double_operand = g.TempDoubleRegister(); | 829 InstructionOperand right_double_operand = g.TempDoubleRegister(); |
| 831 InstructionOperand* result_double_operand = g.TempDoubleRegister(); | 830 InstructionOperand result_double_operand = g.TempDoubleRegister(); |
| 832 selector->Emit(f64i32_opcode, left_double_operand, left_operand); | 831 selector->Emit(f64i32_opcode, left_double_operand, left_operand); |
| 833 selector->Emit(f64i32_opcode, right_double_operand, right_operand); | 832 selector->Emit(f64i32_opcode, right_double_operand, right_operand); |
| 834 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, | 833 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, |
| 835 right_double_operand); | 834 right_double_operand); |
| 836 selector->Emit(i32f64_opcode, result_operand, result_double_operand); | 835 selector->Emit(i32f64_opcode, result_operand, result_double_operand); |
| 837 } | 836 } |
| 838 | 837 |
| 839 | 838 |
| 840 static void VisitDiv(InstructionSelector* selector, Node* node, | 839 static void VisitDiv(InstructionSelector* selector, Node* node, |
| 841 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, | 840 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 856 void InstructionSelector::VisitUint32Div(Node* node) { | 855 void InstructionSelector::VisitUint32Div(Node* node) { |
| 857 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); | 856 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); |
| 858 } | 857 } |
| 859 | 858 |
| 860 | 859 |
| 861 static void VisitMod(InstructionSelector* selector, Node* node, | 860 static void VisitMod(InstructionSelector* selector, Node* node, |
| 862 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, | 861 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, |
| 863 ArchOpcode i32f64_opcode) { | 862 ArchOpcode i32f64_opcode) { |
| 864 ArmOperandGenerator g(selector); | 863 ArmOperandGenerator g(selector); |
| 865 Int32BinopMatcher m(node); | 864 Int32BinopMatcher m(node); |
| 866 InstructionOperand* div_operand = g.TempRegister(); | 865 InstructionOperand div_operand = g.TempRegister(); |
| 867 InstructionOperand* result_operand = g.DefineAsRegister(node); | 866 InstructionOperand result_operand = g.DefineAsRegister(node); |
| 868 InstructionOperand* left_operand = g.UseRegister(m.left().node()); | 867 InstructionOperand left_operand = g.UseRegister(m.left().node()); |
| 869 InstructionOperand* right_operand = g.UseRegister(m.right().node()); | 868 InstructionOperand right_operand = g.UseRegister(m.right().node()); |
| 870 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, | 869 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, |
| 871 left_operand, right_operand); | 870 left_operand, right_operand); |
| 872 if (selector->IsSupported(MLS)) { | 871 if (selector->IsSupported(MLS)) { |
| 873 selector->Emit(kArmMls, result_operand, div_operand, right_operand, | 872 selector->Emit(kArmMls, result_operand, div_operand, right_operand, |
| 874 left_operand); | 873 left_operand); |
| 875 return; | 874 return; |
| 876 } | 875 } |
| 877 InstructionOperand* mul_operand = g.TempRegister(); | 876 InstructionOperand mul_operand = g.TempRegister(); |
| 878 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); | 877 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); |
| 879 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); | 878 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); |
| 880 } | 879 } |
| 881 | 880 |
| 882 | 881 |
| 883 void InstructionSelector::VisitInt32Mod(Node* node) { | 882 void InstructionSelector::VisitInt32Mod(Node* node) { |
| 884 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); | 883 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); |
| 885 } | 884 } |
| 886 | 885 |
| 887 | 886 |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1034 // Compute InstructionOperands for inputs and outputs. | 1033 // Compute InstructionOperands for inputs and outputs. |
| 1035 // TODO(turbofan): on ARM64 it's probably better to use the code object in a | 1034 // TODO(turbofan): on ARM64 it's probably better to use the code object in a |
| 1036 // register if there are multiple uses of it. Improve constant pool and the | 1035 // register if there are multiple uses of it. Improve constant pool and the |
| 1037 // heuristics in the register allocator for where to emit constants. | 1036 // heuristics in the register allocator for where to emit constants. |
| 1038 InitializeCallBuffer(node, &buffer, true, false); | 1037 InitializeCallBuffer(node, &buffer, true, false); |
| 1039 | 1038 |
| 1040 // TODO(dcarney): might be possible to use claim/poke instead | 1039 // TODO(dcarney): might be possible to use claim/poke instead |
| 1041 // Push any stack arguments. | 1040 // Push any stack arguments. |
| 1042 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); | 1041 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); |
| 1043 ++i) { | 1042 ++i) { |
| 1044 Emit(kArmPush, nullptr, g.UseRegister(*i)); | 1043 Emit(kArmPush, g.NoOutput(), g.UseRegister(*i)); |
| 1045 } | 1044 } |
| 1046 | 1045 |
| 1047 // Select the appropriate opcode based on the call type. | 1046 // Select the appropriate opcode based on the call type. |
| 1048 InstructionCode opcode; | 1047 InstructionCode opcode; |
| 1049 switch (descriptor->kind()) { | 1048 switch (descriptor->kind()) { |
| 1050 case CallDescriptor::kCallCodeObject: { | 1049 case CallDescriptor::kCallCodeObject: { |
| 1051 opcode = kArchCallCodeObject; | 1050 opcode = kArchCallCodeObject; |
| 1052 break; | 1051 break; |
| 1053 } | 1052 } |
| 1054 case CallDescriptor::kCallJSFunction: | 1053 case CallDescriptor::kCallJSFunction: |
| 1055 opcode = kArchCallJSFunction; | 1054 opcode = kArchCallJSFunction; |
| 1056 break; | 1055 break; |
| 1057 default: | 1056 default: |
| 1058 UNREACHABLE(); | 1057 UNREACHABLE(); |
| 1059 return; | 1058 return; |
| 1060 } | 1059 } |
| 1061 opcode |= MiscField::encode(descriptor->flags()); | 1060 opcode |= MiscField::encode(descriptor->flags()); |
| 1062 | 1061 |
| 1063 // Emit the call instruction. | 1062 // Emit the call instruction. |
| 1064 InstructionOperand** first_output = | 1063 InstructionOperand* first_output = |
| 1065 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; | 1064 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; |
| 1066 Instruction* call_instr = | 1065 Instruction* call_instr = |
| 1067 Emit(opcode, buffer.outputs.size(), first_output, | 1066 Emit(opcode, buffer.outputs.size(), first_output, |
| 1068 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 1067 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
| 1069 call_instr->MarkAsCall(); | 1068 call_instr->MarkAsCall(); |
| 1070 } | 1069 } |
| 1071 | 1070 |
| 1072 | 1071 |
| 1073 namespace { | 1072 namespace { |
| 1074 | 1073 |
| 1075 // Shared routine for multiple float compare operations. | 1074 // Shared routine for multiple float compare operations. |
| 1076 void VisitFloat64Compare(InstructionSelector* selector, Node* node, | 1075 void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
| 1077 FlagsContinuation* cont) { | 1076 FlagsContinuation* cont) { |
| 1078 ArmOperandGenerator g(selector); | 1077 ArmOperandGenerator g(selector); |
| 1079 Float64BinopMatcher m(node); | 1078 Float64BinopMatcher m(node); |
| 1080 InstructionOperand* rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node()) | 1079 InstructionOperand rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node()) |
| 1081 : g.UseRegister(m.right().node()); | 1080 : g.UseRegister(m.right().node()); |
| 1082 if (cont->IsBranch()) { | 1081 if (cont->IsBranch()) { |
| 1083 selector->Emit(cont->Encode(kArmVcmpF64), nullptr, | 1082 selector->Emit(cont->Encode(kArmVcmpF64), g.NoOutput(), |
| 1084 g.UseRegister(m.left().node()), rhs, | 1083 g.UseRegister(m.left().node()), rhs, |
| 1085 g.Label(cont->true_block()), | 1084 g.Label(cont->true_block()), |
| 1086 g.Label(cont->false_block()))->MarkAsControl(); | 1085 g.Label(cont->false_block()))->MarkAsControl(); |
| 1087 } else { | 1086 } else { |
| 1088 DCHECK(cont->IsSet()); | 1087 DCHECK(cont->IsSet()); |
| 1089 selector->Emit(cont->Encode(kArmVcmpF64), | 1088 selector->Emit(cont->Encode(kArmVcmpF64), |
| 1090 g.DefineAsRegister(cont->result()), | 1089 g.DefineAsRegister(cont->result()), |
| 1091 g.UseRegister(m.left().node()), rhs); | 1090 g.UseRegister(m.left().node()), rhs); |
| 1092 } | 1091 } |
| 1093 } | 1092 } |
| 1094 | 1093 |
| 1095 | 1094 |
| 1096 // Shared routine for multiple word compare operations. | 1095 // Shared routine for multiple word compare operations. |
| 1097 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1096 void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 1098 InstructionCode opcode, FlagsContinuation* cont) { | 1097 InstructionCode opcode, FlagsContinuation* cont) { |
| 1099 ArmOperandGenerator g(selector); | 1098 ArmOperandGenerator g(selector); |
| 1100 Int32BinopMatcher m(node); | 1099 Int32BinopMatcher m(node); |
| 1101 InstructionOperand* inputs[5]; | 1100 InstructionOperand inputs[5]; |
| 1102 size_t input_count = 0; | 1101 size_t input_count = 0; |
| 1103 InstructionOperand* outputs[1]; | 1102 InstructionOperand outputs[1]; |
| 1104 size_t output_count = 0; | 1103 size_t output_count = 0; |
| 1105 | 1104 |
| 1106 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 1105 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
| 1107 &input_count, &inputs[1])) { | 1106 &input_count, &inputs[1])) { |
| 1108 inputs[0] = g.UseRegister(m.left().node()); | 1107 inputs[0] = g.UseRegister(m.left().node()); |
| 1109 input_count++; | 1108 input_count++; |
| 1110 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), | 1109 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), |
| 1111 &input_count, &inputs[1])) { | 1110 &input_count, &inputs[1])) { |
| 1112 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1111 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
| 1113 inputs[0] = g.UseRegister(m.right().node()); | 1112 inputs[0] = g.UseRegister(m.right().node()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1227 default: | 1226 default: |
| 1228 break; | 1227 break; |
| 1229 } | 1228 } |
| 1230 break; | 1229 break; |
| 1231 } | 1230 } |
| 1232 | 1231 |
| 1233 // Continuation could not be combined with a compare, emit compare against 0. | 1232 // Continuation could not be combined with a compare, emit compare against 0. |
| 1234 ArmOperandGenerator g(selector); | 1233 ArmOperandGenerator g(selector); |
| 1235 InstructionCode const opcode = | 1234 InstructionCode const opcode = |
| 1236 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); | 1235 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); |
| 1237 InstructionOperand* const value_operand = g.UseRegister(value); | 1236 InstructionOperand const value_operand = g.UseRegister(value); |
| 1238 if (cont->IsBranch()) { | 1237 if (cont->IsBranch()) { |
| 1239 selector->Emit(opcode, nullptr, value_operand, value_operand, | 1238 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand, |
| 1240 g.Label(cont->true_block()), | 1239 g.Label(cont->true_block()), |
| 1241 g.Label(cont->false_block()))->MarkAsControl(); | 1240 g.Label(cont->false_block()))->MarkAsControl(); |
| 1242 } else { | 1241 } else { |
| 1243 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, | 1242 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, |
| 1244 value_operand); | 1243 value_operand); |
| 1245 } | 1244 } |
| 1246 } | 1245 } |
| 1247 | 1246 |
| 1248 } // namespace | 1247 } // namespace |
| 1249 | 1248 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1339 MachineOperatorBuilder::kFloat64Ceil | | 1338 MachineOperatorBuilder::kFloat64Ceil | |
| 1340 MachineOperatorBuilder::kFloat64RoundTruncate | | 1339 MachineOperatorBuilder::kFloat64RoundTruncate | |
| 1341 MachineOperatorBuilder::kFloat64RoundTiesAway; | 1340 MachineOperatorBuilder::kFloat64RoundTiesAway; |
| 1342 } | 1341 } |
| 1343 return flags; | 1342 return flags; |
| 1344 } | 1343 } |
| 1345 | 1344 |
| 1346 } // namespace compiler | 1345 } // namespace compiler |
| 1347 } // namespace internal | 1346 } // namespace internal |
| 1348 } // namespace v8 | 1347 } // namespace v8 |
| OLD | NEW |