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-intrinsics.h" | 7 #include "src/compiler-intrinsics.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 | 114 |
115 static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode, | 115 static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode, |
116 Node* node) { | 116 Node* node) { |
117 ArmOperandGenerator g(selector); | 117 ArmOperandGenerator g(selector); |
118 selector->Emit(opcode, g.DefineAsDoubleRegister(node), | 118 selector->Emit(opcode, g.DefineAsDoubleRegister(node), |
119 g.UseDoubleRegister(node->InputAt(0)), | 119 g.UseDoubleRegister(node->InputAt(0)), |
120 g.UseDoubleRegister(node->InputAt(1))); | 120 g.UseDoubleRegister(node->InputAt(1))); |
121 } | 121 } |
122 | 122 |
123 | 123 |
124 static Instruction* EmitBinop(InstructionSelector* selector, | 124 static bool TryMatchROR(InstructionSelector* selector, |
125 InstructionCode opcode, size_t output_count, | 125 InstructionCode* opcode_return, Node* node, |
126 InstructionOperand** outputs, Node* left, | 126 InstructionOperand** value_return, |
127 Node* right, size_t label_count, | 127 InstructionOperand** shift_return) { |
128 InstructionOperand** labels) { | |
129 ArmOperandGenerator g(selector); | 128 ArmOperandGenerator g(selector); |
130 InstructionOperand* inputs[5]; | 129 if (node->opcode() != IrOpcode::kWord32Or) return false; |
131 size_t input_count = 0; | 130 Int32BinopMatcher m(node); |
132 | 131 Node* shl = m.left().node(); |
133 inputs[input_count++] = g.UseRegister(left); | 132 Node* shr = m.right().node(); |
134 if (g.CanBeImmediate(right, opcode)) { | 133 if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) { |
135 opcode |= AddressingModeField::encode(kMode_Operand2_I); | 134 std::swap(shl, shr); |
136 inputs[input_count++] = g.UseImmediate(right); | 135 } else if (!m.left().IsWord32Shl() || !m.right().IsWord32Shr()) { |
137 } else if (right->opcode() == IrOpcode::kWord32Sar) { | 136 return false; |
138 Int32BinopMatcher mright(right); | |
139 inputs[input_count++] = g.UseRegister(mright.left().node()); | |
140 if (mright.right().IsInRange(1, 32)) { | |
141 opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); | |
142 inputs[input_count++] = g.UseImmediate(mright.right().node()); | |
143 } else { | |
144 opcode |= AddressingModeField::encode(kMode_Operand2_R_ASR_R); | |
145 inputs[input_count++] = g.UseRegister(mright.right().node()); | |
146 } | |
147 } else if (right->opcode() == IrOpcode::kWord32Shl) { | |
148 Int32BinopMatcher mright(right); | |
149 inputs[input_count++] = g.UseRegister(mright.left().node()); | |
150 if (mright.right().IsInRange(0, 31)) { | |
151 opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); | |
152 inputs[input_count++] = g.UseImmediate(mright.right().node()); | |
153 } else { | |
154 opcode |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); | |
155 inputs[input_count++] = g.UseRegister(mright.right().node()); | |
156 } | |
157 } else if (right->opcode() == IrOpcode::kWord32Shr) { | |
158 Int32BinopMatcher mright(right); | |
159 inputs[input_count++] = g.UseRegister(mright.left().node()); | |
160 if (mright.right().IsInRange(1, 32)) { | |
161 opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); | |
162 inputs[input_count++] = g.UseImmediate(mright.right().node()); | |
163 } else { | |
164 opcode |= AddressingModeField::encode(kMode_Operand2_R_LSR_R); | |
165 inputs[input_count++] = g.UseRegister(mright.right().node()); | |
166 } | |
167 } else { | |
168 opcode |= AddressingModeField::encode(kMode_Operand2_R); | |
169 inputs[input_count++] = g.UseRegister(right); | |
170 } | 137 } |
171 | 138 Int32BinopMatcher mshr(shr); |
172 // Append the optional labels. | 139 Int32BinopMatcher mshl(shl); |
173 while (label_count-- != 0) { | 140 Node* value = mshr.left().node(); |
174 inputs[input_count++] = *labels++; | 141 if (value != mshl.left().node()) return false; |
| 142 Node* shift = mshr.right().node(); |
| 143 Int32Matcher mshift(shift); |
| 144 if (mshift.IsInRange(1, 31) && mshl.right().Is(32 - mshift.Value())) { |
| 145 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I); |
| 146 *value_return = g.UseRegister(value); |
| 147 *shift_return = g.UseImmediate(shift); |
| 148 return true; |
175 } | 149 } |
176 | 150 if (mshl.right().IsInt32Sub()) { |
177 ASSERT_NE(0, input_count); | 151 Int32BinopMatcher mshlright(mshl.right().node()); |
178 ASSERT_GE(ARRAY_SIZE(inputs), input_count); | 152 if (!mshlright.left().Is(32)) return false; |
179 ASSERT_NE(kMode_None, AddressingModeField::decode(opcode)); | 153 if (mshlright.right().node() != shift) return false; |
180 | 154 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R); |
181 return selector->Emit(opcode, output_count, outputs, input_count, inputs); | 155 *value_return = g.UseRegister(value); |
| 156 *shift_return = g.UseRegister(shift); |
| 157 return true; |
| 158 } |
| 159 return false; |
182 } | 160 } |
183 | 161 |
184 | 162 |
185 static Instruction* EmitBinop(InstructionSelector* selector, | 163 static inline bool TryMatchASR(InstructionSelector* selector, |
186 InstructionCode opcode, Node* node, Node* left, | 164 InstructionCode* opcode_return, Node* node, |
187 Node* right) { | 165 InstructionOperand** value_return, |
| 166 InstructionOperand** shift_return) { |
188 ArmOperandGenerator g(selector); | 167 ArmOperandGenerator g(selector); |
189 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; | 168 if (node->opcode() != IrOpcode::kWord32Sar) return false; |
190 const size_t output_count = ARRAY_SIZE(outputs); | 169 Int32BinopMatcher m(node); |
191 return EmitBinop(selector, opcode, output_count, outputs, left, right, 0, | 170 *value_return = g.UseRegister(m.left().node()); |
192 NULL); | 171 if (m.right().IsInRange(1, 32)) { |
| 172 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_I); |
| 173 *shift_return = g.UseImmediate(m.right().node()); |
| 174 } else { |
| 175 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R); |
| 176 *shift_return = g.UseRegister(m.right().node()); |
| 177 } |
| 178 return true; |
193 } | 179 } |
194 | 180 |
195 | 181 |
| 182 static inline bool TryMatchLSL(InstructionSelector* selector, |
| 183 InstructionCode* opcode_return, Node* node, |
| 184 InstructionOperand** value_return, |
| 185 InstructionOperand** shift_return) { |
| 186 ArmOperandGenerator g(selector); |
| 187 if (node->opcode() != IrOpcode::kWord32Shl) return false; |
| 188 Int32BinopMatcher m(node); |
| 189 *value_return = g.UseRegister(m.left().node()); |
| 190 if (m.right().IsInRange(0, 31)) { |
| 191 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_I); |
| 192 *shift_return = g.UseImmediate(m.right().node()); |
| 193 } else { |
| 194 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R); |
| 195 *shift_return = g.UseRegister(m.right().node()); |
| 196 } |
| 197 return true; |
| 198 } |
| 199 |
| 200 |
| 201 static inline bool TryMatchLSR(InstructionSelector* selector, |
| 202 InstructionCode* opcode_return, Node* node, |
| 203 InstructionOperand** value_return, |
| 204 InstructionOperand** shift_return) { |
| 205 ArmOperandGenerator g(selector); |
| 206 if (node->opcode() != IrOpcode::kWord32Shr) return false; |
| 207 Int32BinopMatcher m(node); |
| 208 *value_return = g.UseRegister(m.left().node()); |
| 209 if (m.right().IsInRange(1, 32)) { |
| 210 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I); |
| 211 *shift_return = g.UseImmediate(m.right().node()); |
| 212 } else { |
| 213 *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R); |
| 214 *shift_return = g.UseRegister(m.right().node()); |
| 215 } |
| 216 return true; |
| 217 } |
| 218 |
| 219 |
| 220 static inline bool TryMatchImmediateOrShift(InstructionSelector* selector, |
| 221 InstructionCode* opcode_return, |
| 222 Node* node, |
| 223 size_t* input_count_return, |
| 224 InstructionOperand** inputs) { |
| 225 ArmOperandGenerator g(selector); |
| 226 if (g.CanBeImmediate(node, *opcode_return)) { |
| 227 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); |
| 228 inputs[0] = g.UseImmediate(node); |
| 229 *input_count_return = 1; |
| 230 return true; |
| 231 } |
| 232 if (TryMatchASR(selector, opcode_return, node, &inputs[0], &inputs[1]) || |
| 233 TryMatchLSL(selector, opcode_return, node, &inputs[0], &inputs[1]) || |
| 234 TryMatchLSR(selector, opcode_return, node, &inputs[0], &inputs[1]) || |
| 235 TryMatchROR(selector, opcode_return, node, &inputs[0], &inputs[1])) { |
| 236 *input_count_return = 2; |
| 237 return true; |
| 238 } |
| 239 return false; |
| 240 } |
| 241 |
| 242 |
196 // Shared routine for multiple binary operations. | 243 // Shared routine for multiple binary operations. |
197 static void VisitBinop(InstructionSelector* selector, Node* node, | 244 static void VisitBinop(InstructionSelector* selector, Node* node, |
198 InstructionCode opcode, InstructionCode reverse_opcode) { | 245 InstructionCode opcode, InstructionCode reverse_opcode) { |
199 ArmOperandGenerator g(selector); | 246 ArmOperandGenerator g(selector); |
200 Int32BinopMatcher m(node); | 247 Int32BinopMatcher m(node); |
| 248 InstructionOperand* inputs[3]; |
| 249 size_t input_count = 0; |
201 | 250 |
202 Node* left = m.left().node(); | 251 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
203 Node* right = m.right().node(); | 252 &input_count, &inputs[1])) { |
204 if (g.CanBeImmediate(m.left().node(), reverse_opcode) || | 253 inputs[0] = g.UseRegister(m.left().node()); |
205 m.left().IsWord32Sar() || m.left().IsWord32Shl() || | 254 input_count++; |
206 m.left().IsWord32Shr()) { | 255 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, |
| 256 m.left().node(), &input_count, |
| 257 &inputs[1])) { |
| 258 inputs[0] = g.UseRegister(m.right().node()); |
207 opcode = reverse_opcode; | 259 opcode = reverse_opcode; |
208 std::swap(left, right); | 260 input_count++; |
| 261 } else { |
| 262 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
| 263 inputs[input_count++] = g.UseRegister(m.left().node()); |
| 264 inputs[input_count++] = g.UseRegister(m.right().node()); |
209 } | 265 } |
210 | 266 |
211 EmitBinop(selector, opcode, node, left, right); | 267 ASSERT_NE(0, input_count); |
| 268 ASSERT_GE(ARRAY_SIZE(inputs), input_count); |
| 269 ASSERT_NE(kMode_None, AddressingModeField::decode(opcode)); |
| 270 |
| 271 InstructionOperand* outputs[1] = {g.DefineAsRegister(node)}; |
| 272 const size_t output_count = ARRAY_SIZE(outputs); |
| 273 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
212 } | 274 } |
213 | 275 |
214 | 276 |
215 void InstructionSelector::VisitLoad(Node* node) { | 277 void InstructionSelector::VisitLoad(Node* node) { |
216 MachineRepresentation rep = OpParameter<MachineRepresentation>(node); | 278 MachineRepresentation rep = OpParameter<MachineRepresentation>(node); |
217 ArmOperandGenerator g(this); | 279 ArmOperandGenerator g(this); |
218 Node* base = node->InputAt(0); | 280 Node* base = node->InputAt(0); |
219 Node* index = node->InputAt(1); | 281 Node* index = node->InputAt(1); |
220 | 282 |
221 InstructionOperand* result = rep == kMachineFloat64 | 283 InstructionOperand* result = rep == kMachineFloat64 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 } else if (g.CanBeImmediate(base, opcode)) { | 366 } else if (g.CanBeImmediate(base, opcode)) { |
305 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, | 367 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, |
306 g.UseRegister(index), g.UseImmediate(base), val); | 368 g.UseRegister(index), g.UseImmediate(base), val); |
307 } else { | 369 } else { |
308 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL, | 370 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL, |
309 g.UseRegister(base), g.UseRegister(index), val); | 371 g.UseRegister(base), g.UseRegister(index), val); |
310 } | 372 } |
311 } | 373 } |
312 | 374 |
313 | 375 |
| 376 static inline void EmitBic(InstructionSelector* selector, Node* node, |
| 377 Node* left, Node* right) { |
| 378 ArmOperandGenerator g(selector); |
| 379 InstructionCode opcode = kArmBic; |
| 380 InstructionOperand* inputs[3]; |
| 381 size_t input_count = 0; |
| 382 InstructionOperand* outputs[1] = {g.DefineAsRegister(node)}; |
| 383 const size_t output_count = ARRAY_SIZE(outputs); |
| 384 |
| 385 inputs[input_count++] = g.UseRegister(left); |
| 386 if (!TryMatchImmediateOrShift(selector, &opcode, right, &input_count, |
| 387 &inputs[input_count])) { |
| 388 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
| 389 inputs[input_count++] = g.UseRegister(right); |
| 390 } |
| 391 |
| 392 ASSERT_NE(0, input_count); |
| 393 ASSERT_GE(ARRAY_SIZE(inputs), input_count); |
| 394 ASSERT_NE(kMode_None, AddressingModeField::decode(opcode)); |
| 395 |
| 396 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
| 397 } |
| 398 |
| 399 |
314 void InstructionSelector::VisitWord32And(Node* node) { | 400 void InstructionSelector::VisitWord32And(Node* node) { |
315 ArmOperandGenerator g(this); | 401 ArmOperandGenerator g(this); |
316 Int32BinopMatcher m(node); | 402 Int32BinopMatcher m(node); |
317 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { | 403 if (m.left().IsWord32Xor() && CanCover(node, m.left().node())) { |
318 Int32BinopMatcher mleft(m.left().node()); | 404 Int32BinopMatcher mleft(m.left().node()); |
319 if (mleft.right().Is(-1)) { | 405 if (mleft.right().Is(-1)) { |
320 EmitBinop(this, kArmBic, node, m.right().node(), mleft.left().node()); | 406 EmitBic(this, node, m.right().node(), mleft.left().node()); |
321 return; | 407 return; |
322 } | 408 } |
323 } | 409 } |
324 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { | 410 if (m.right().IsWord32Xor() && CanCover(node, m.right().node())) { |
325 Int32BinopMatcher mright(m.right().node()); | 411 Int32BinopMatcher mright(m.right().node()); |
326 if (mright.right().Is(-1)) { | 412 if (mright.right().Is(-1)) { |
327 EmitBinop(this, kArmBic, node, m.left().node(), mright.left().node()); | 413 EmitBic(this, node, m.left().node(), mright.left().node()); |
328 return; | 414 return; |
329 } | 415 } |
330 } | 416 } |
331 if (CpuFeatures::IsSupported(ARMv7) && m.right().HasValue()) { | 417 if (CpuFeatures::IsSupported(ARMv7) && m.right().HasValue()) { |
332 uint32_t value = m.right().Value(); | 418 uint32_t value = m.right().Value(); |
333 uint32_t width = CompilerIntrinsics::CountSetBits(value); | 419 uint32_t width = CompilerIntrinsics::CountSetBits(value); |
334 uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value); | 420 uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value); |
335 if (msb + width == 32) { | 421 if (msb + width == 32) { |
336 ASSERT_EQ(0, CompilerIntrinsics::CountTrailingZeros(value)); | 422 ASSERT_EQ(0, CompilerIntrinsics::CountTrailingZeros(value)); |
337 if (m.left().IsWord32Shr()) { | 423 if (m.left().IsWord32Shr()) { |
(...skipping 17 matching lines...) Expand all Loading... |
355 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), | 441 Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), |
356 g.TempImmediate(lsb), g.TempImmediate(width)); | 442 g.TempImmediate(lsb), g.TempImmediate(width)); |
357 return; | 443 return; |
358 } | 444 } |
359 } | 445 } |
360 VisitBinop(this, node, kArmAnd, kArmAnd); | 446 VisitBinop(this, node, kArmAnd, kArmAnd); |
361 } | 447 } |
362 | 448 |
363 | 449 |
364 void InstructionSelector::VisitWord32Or(Node* node) { | 450 void InstructionSelector::VisitWord32Or(Node* node) { |
| 451 ArmOperandGenerator g(this); |
| 452 InstructionCode opcode = kArmMov; |
| 453 InstructionOperand* value_operand; |
| 454 InstructionOperand* shift_operand; |
| 455 if (TryMatchROR(this, &opcode, node, &value_operand, &shift_operand)) { |
| 456 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); |
| 457 return; |
| 458 } |
365 VisitBinop(this, node, kArmOrr, kArmOrr); | 459 VisitBinop(this, node, kArmOrr, kArmOrr); |
366 } | 460 } |
367 | 461 |
368 | 462 |
369 void InstructionSelector::VisitWord32Xor(Node* node) { | 463 void InstructionSelector::VisitWord32Xor(Node* node) { |
370 ArmOperandGenerator g(this); | 464 ArmOperandGenerator g(this); |
371 Int32BinopMatcher m(node); | 465 Int32BinopMatcher m(node); |
372 if (m.right().Is(-1)) { | 466 if (m.right().Is(-1)) { |
373 Emit(kArmMvn | AddressingModeField::encode(kMode_Operand2_R), | 467 Emit(kArmMvn | AddressingModeField::encode(kMode_Operand2_R), |
374 g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); | 468 g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); |
375 } else { | 469 } else { |
376 VisitBinop(this, node, kArmEor, kArmEor); | 470 VisitBinop(this, node, kArmEor, kArmEor); |
377 } | 471 } |
378 } | 472 } |
379 | 473 |
380 | 474 |
| 475 template <typename TryMatchShift> |
| 476 static inline void VisitShift(InstructionSelector* selector, Node* node, |
| 477 TryMatchShift try_match_shift) { |
| 478 ArmOperandGenerator g(selector); |
| 479 InstructionCode opcode = kArmMov; |
| 480 InstructionOperand* value_operand = NULL; |
| 481 InstructionOperand* shift_operand = NULL; |
| 482 CHECK( |
| 483 try_match_shift(selector, &opcode, node, &value_operand, &shift_operand)); |
| 484 selector->Emit(opcode, g.DefineAsRegister(node), value_operand, |
| 485 shift_operand); |
| 486 } |
| 487 |
| 488 |
381 void InstructionSelector::VisitWord32Shl(Node* node) { | 489 void InstructionSelector::VisitWord32Shl(Node* node) { |
382 ArmOperandGenerator g(this); | 490 VisitShift(this, node, TryMatchLSL); |
383 Int32BinopMatcher m(node); | |
384 if (m.right().IsInRange(0, 31)) { | |
385 Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSL_I), | |
386 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
387 g.UseImmediate(m.right().node())); | |
388 } else { | |
389 Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSL_R), | |
390 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
391 g.UseRegister(m.right().node())); | |
392 } | |
393 } | 491 } |
394 | 492 |
395 | 493 |
396 void InstructionSelector::VisitWord32Shr(Node* node) { | 494 void InstructionSelector::VisitWord32Shr(Node* node) { |
397 ArmOperandGenerator g(this); | 495 ArmOperandGenerator g(this); |
398 Int32BinopMatcher m(node); | 496 Int32BinopMatcher m(node); |
399 if (CpuFeatures::IsSupported(ARMv7) && m.left().IsWord32And() && | 497 if (CpuFeatures::IsSupported(ARMv7) && m.left().IsWord32And() && |
400 m.right().IsInRange(0, 31)) { | 498 m.right().IsInRange(0, 31)) { |
401 int32_t lsb = m.right().Value(); | 499 int32_t lsb = m.right().Value(); |
402 Int32BinopMatcher mleft(m.left().node()); | 500 Int32BinopMatcher mleft(m.left().node()); |
403 if (mleft.right().HasValue()) { | 501 if (mleft.right().HasValue()) { |
404 uint32_t value = (mleft.right().Value() >> lsb) << lsb; | 502 uint32_t value = (mleft.right().Value() >> lsb) << lsb; |
405 uint32_t width = CompilerIntrinsics::CountSetBits(value); | 503 uint32_t width = CompilerIntrinsics::CountSetBits(value); |
406 uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value); | 504 uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value); |
407 if (msb + width + lsb == 32) { | 505 if (msb + width + lsb == 32) { |
408 ASSERT_EQ(lsb, CompilerIntrinsics::CountTrailingZeros(value)); | 506 ASSERT_EQ(lsb, CompilerIntrinsics::CountTrailingZeros(value)); |
409 Emit(kArmUbfx, g.DefineAsRegister(node), | 507 Emit(kArmUbfx, g.DefineAsRegister(node), |
410 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb), | 508 g.UseRegister(mleft.left().node()), g.TempImmediate(lsb), |
411 g.TempImmediate(width)); | 509 g.TempImmediate(width)); |
412 return; | 510 return; |
413 } | 511 } |
414 } | 512 } |
415 } | 513 } |
416 if (m.right().IsInRange(1, 32)) { | 514 VisitShift(this, node, TryMatchLSR); |
417 Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSR_I), | |
418 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
419 g.UseImmediate(m.right().node())); | |
420 return; | |
421 } | |
422 Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_LSR_R), | |
423 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
424 g.UseRegister(m.right().node())); | |
425 } | 515 } |
426 | 516 |
427 | 517 |
428 void InstructionSelector::VisitWord32Sar(Node* node) { | 518 void InstructionSelector::VisitWord32Sar(Node* node) { |
429 ArmOperandGenerator g(this); | 519 VisitShift(this, node, TryMatchASR); |
430 Int32BinopMatcher m(node); | |
431 if (m.right().IsInRange(1, 32)) { | |
432 Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_ASR_I), | |
433 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
434 g.UseImmediate(m.right().node())); | |
435 } else { | |
436 Emit(kArmMov | AddressingModeField::encode(kMode_Operand2_R_ASR_R), | |
437 g.DefineAsRegister(node), g.UseRegister(m.left().node()), | |
438 g.UseRegister(m.right().node())); | |
439 } | |
440 } | 520 } |
441 | 521 |
442 | 522 |
443 void InstructionSelector::VisitInt32Add(Node* node) { | 523 void InstructionSelector::VisitInt32Add(Node* node) { |
444 ArmOperandGenerator g(this); | 524 ArmOperandGenerator g(this); |
445 Int32BinopMatcher m(node); | 525 Int32BinopMatcher m(node); |
446 if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) { | 526 if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) { |
447 Int32BinopMatcher mleft(m.left().node()); | 527 Int32BinopMatcher mleft(m.left().node()); |
448 Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()), | 528 Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()), |
449 g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); | 529 g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node())); |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 } | 784 } |
705 } | 785 } |
706 | 786 |
707 | 787 |
708 // Shared routine for multiple compare operations. | 788 // Shared routine for multiple compare operations. |
709 static void VisitWordCompare(InstructionSelector* selector, Node* node, | 789 static void VisitWordCompare(InstructionSelector* selector, Node* node, |
710 InstructionCode opcode, FlagsContinuation* cont, | 790 InstructionCode opcode, FlagsContinuation* cont, |
711 bool commutative, bool requires_output) { | 791 bool commutative, bool requires_output) { |
712 ArmOperandGenerator g(selector); | 792 ArmOperandGenerator g(selector); |
713 Int32BinopMatcher m(node); | 793 Int32BinopMatcher m(node); |
| 794 InstructionOperand* inputs[5]; |
| 795 size_t input_count = 0; |
| 796 InstructionOperand* outputs[1]; |
| 797 size_t output_count = 0; |
714 | 798 |
715 Node* left = m.left().node(); | 799 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
716 Node* right = m.right().node(); | 800 &input_count, &inputs[1])) { |
717 if (g.CanBeImmediate(m.left().node(), opcode) || m.left().IsWord32Sar() || | 801 inputs[0] = g.UseRegister(m.left().node()); |
718 m.left().IsWord32Shl() || m.left().IsWord32Shr()) { | 802 input_count++; |
| 803 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), |
| 804 &input_count, &inputs[1])) { |
719 if (!commutative) cont->Commute(); | 805 if (!commutative) cont->Commute(); |
720 std::swap(left, right); | 806 inputs[0] = g.UseRegister(m.right().node()); |
| 807 input_count++; |
| 808 } else { |
| 809 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
| 810 inputs[input_count++] = g.UseRegister(m.left().node()); |
| 811 inputs[input_count++] = g.UseRegister(m.right().node()); |
721 } | 812 } |
722 | 813 |
723 opcode = cont->Encode(opcode); | |
724 if (cont->IsBranch()) { | 814 if (cont->IsBranch()) { |
725 InstructionOperand* outputs[1]; | |
726 size_t output_count = 0; | |
727 if (requires_output) { | 815 if (requires_output) { |
728 outputs[output_count++] = g.DefineAsRegister(node); | 816 outputs[output_count++] = g.DefineAsRegister(node); |
729 } | 817 } |
730 InstructionOperand* labels[] = {g.Label(cont->true_block()), | 818 inputs[input_count++] = g.Label(cont->true_block()); |
731 g.Label(cont->false_block())}; | 819 inputs[input_count++] = g.Label(cont->false_block()); |
732 const size_t label_count = ARRAY_SIZE(labels); | |
733 EmitBinop(selector, opcode, output_count, outputs, left, right, label_count, | |
734 labels)->MarkAsControl(); | |
735 } else { | 820 } else { |
736 ASSERT(cont->IsSet()); | 821 ASSERT(cont->IsSet()); |
737 EmitBinop(selector, opcode, cont->result(), left, right); | 822 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
738 } | 823 } |
| 824 |
| 825 ASSERT_NE(0, input_count); |
| 826 ASSERT_GE(ARRAY_SIZE(inputs), input_count); |
| 827 ASSERT_GE(ARRAY_SIZE(outputs), output_count); |
| 828 |
| 829 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, |
| 830 outputs, input_count, inputs); |
| 831 if (cont->IsBranch()) instr->MarkAsControl(); |
739 } | 832 } |
740 | 833 |
741 | 834 |
742 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { | 835 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { |
743 switch (node->opcode()) { | 836 switch (node->opcode()) { |
744 case IrOpcode::kInt32Add: | 837 case IrOpcode::kInt32Add: |
745 return VisitWordCompare(this, node, kArmCmn, cont, true, false); | 838 return VisitWordCompare(this, node, kArmCmn, cont, true, false); |
746 case IrOpcode::kInt32Sub: | 839 case IrOpcode::kInt32Sub: |
747 return VisitWordCompare(this, node, kArmCmp, cont, false, false); | 840 return VisitWordCompare(this, node, kArmCmp, cont, false, false); |
748 case IrOpcode::kWord32And: | 841 case IrOpcode::kWord32And: |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
787 ASSERT(cont->IsSet()); | 880 ASSERT(cont->IsSet()); |
788 Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), | 881 Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()), |
789 g.UseDoubleRegister(m.left().node()), | 882 g.UseDoubleRegister(m.left().node()), |
790 g.UseDoubleRegister(m.right().node())); | 883 g.UseDoubleRegister(m.right().node())); |
791 } | 884 } |
792 } | 885 } |
793 | 886 |
794 } // namespace compiler | 887 } // namespace compiler |
795 } // namespace internal | 888 } // namespace internal |
796 } // namespace v8 | 889 } // namespace v8 |
OLD | NEW |