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 3 // found in the LICENSE file. 4 5 #include "test/unittests/compiler/instruction-selector-unittest.h" 6 7 #include "src/compiler/node-matchers.h" 8 9 namespace v8 { 10 namespace internal { 11 namespace compiler { 12 13 // ----------------------------------------------------------------------------- 14 // Conversions. 15 16 17 TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) { 18 StreamBuilder m(this, MachineType::Float32(), MachineType::Float64()); 19 m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0))); 20 Stream s = m.Build(); 21 ASSERT_EQ(1U, s.size()); 22 EXPECT_EQ(kSSEFloat32ToFloat64, s[0]->arch_opcode()); 23 EXPECT_EQ(1U, s[0]->InputCount()); 24 EXPECT_EQ(1U, s[0]->OutputCount()); 25 } 26 27 28 TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) { 29 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32()); 30 m.Return(m.ChangeInt32ToInt64(m.Parameter(0))); 31 Stream s = m.Build(); 32 ASSERT_EQ(1U, s.size()); 33 EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode()); 34 } 35 36 37 TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) { 38 StreamBuilder m(this, MachineType::Float64(), MachineType::Uint32()); 39 m.Return(m.ChangeUint32ToFloat64(m.Parameter(0))); 40 Stream s = m.Build(); 41 ASSERT_EQ(1U, s.size()); 42 EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode()); 43 } 44 45 46 TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) { 47 StreamBuilder m(this, MachineType::Uint64(), MachineType::Uint32()); 48 m.Return(m.ChangeUint32ToUint64(m.Parameter(0))); 49 Stream s = m.Build(); 50 ASSERT_EQ(1U, s.size()); 51 EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); 52 } 53 54 55 TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) { 56 StreamBuilder m(this, MachineType::Float64(), MachineType::Float32()); 57 m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0))); 58 Stream s = m.Build(); 59 ASSERT_EQ(1U, s.size()); 60 EXPECT_EQ(kSSEFloat64ToFloat32, s[0]->arch_opcode()); 61 EXPECT_EQ(1U, s[0]->InputCount()); 62 EXPECT_EQ(1U, s[0]->OutputCount()); 63 } 64 65 66 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) { 67 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64()); 68 m.Return(m.TruncateInt64ToInt32(m.Parameter(0))); 69 Stream s = m.Build(); 70 ASSERT_EQ(1U, s.size()); 71 EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); 72 } 73 74 75 // ----------------------------------------------------------------------------- 76 // Loads and stores 77 78 79 namespace { 80 81 struct MemoryAccess { 82 MachineType type; 83 ArchOpcode load_opcode; 84 ArchOpcode store_opcode; 85 }; 86 87 88 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { 89 return os << memacc.type; 90 } 91 92 93 static const MemoryAccess kMemoryAccesses[] = { 94 {MachineType::Int8(), kX64Movsxbl, kX64Movb}, 95 {MachineType::Uint8(), kX64Movzxbl, kX64Movb}, 96 {MachineType::Int16(), kX64Movsxwl, kX64Movw}, 97 {MachineType::Uint16(), kX64Movzxwl, kX64Movw}, 98 {MachineType::Int32(), kX64Movl, kX64Movl}, 99 {MachineType::Uint32(), kX64Movl, kX64Movl}, 100 {MachineType::Int64(), kX64Movq, kX64Movq}, 101 {MachineType::Uint64(), kX64Movq, kX64Movq}, 102 {MachineType::Float32(), kX64Movss, kX64Movss}, 103 {MachineType::Float64(), kX64Movsd, kX64Movsd}}; 104 105 } // namespace 106 107 108 typedef InstructionSelectorTestWithParam<MemoryAccess> 109 InstructionSelectorMemoryAccessTest; 110 111 112 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { 113 const MemoryAccess memacc = GetParam(); 114 StreamBuilder m(this, memacc.type, MachineType::Pointer(), 115 MachineType::Int32()); 116 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); 117 Stream s = m.Build(); 118 ASSERT_EQ(1U, s.size()); 119 EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); 120 EXPECT_EQ(2U, s[0]->InputCount()); 121 EXPECT_EQ(1U, s[0]->OutputCount()); 122 } 123 124 125 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { 126 const MemoryAccess memacc = GetParam(); 127 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), 128 MachineType::Int32(), memacc.type); 129 m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1), 130 m.Parameter(2), kNoWriteBarrier); 131 m.Return(m.Int32Constant(0)); 132 Stream s = m.Build(); 133 ASSERT_EQ(1U, s.size()); 134 EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); 135 EXPECT_EQ(3U, s[0]->InputCount()); 136 EXPECT_EQ(0U, s[0]->OutputCount()); 137 } 138 139 140 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 141 InstructionSelectorMemoryAccessTest, 142 ::testing::ValuesIn(kMemoryAccesses)); 143 144 145 // ----------------------------------------------------------------------------- 146 // ChangeUint32ToUint64. 147 148 149 namespace { 150 151 typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*); 152 153 154 struct BinaryOperation { 155 Constructor constructor; 156 const char* constructor_name; 157 }; 158 159 160 std::ostream& operator<<(std::ostream& os, const BinaryOperation& bop) { 161 return os << bop.constructor_name; 162 } 163 164 165 const BinaryOperation kWord32BinaryOperations[] = { 166 {&RawMachineAssembler::Word32And, "Word32And"}, 167 {&RawMachineAssembler::Word32Or, "Word32Or"}, 168 {&RawMachineAssembler::Word32Xor, "Word32Xor"}, 169 {&RawMachineAssembler::Word32Shl, "Word32Shl"}, 170 {&RawMachineAssembler::Word32Shr, "Word32Shr"}, 171 {&RawMachineAssembler::Word32Sar, "Word32Sar"}, 172 {&RawMachineAssembler::Word32Ror, "Word32Ror"}, 173 {&RawMachineAssembler::Word32Equal, "Word32Equal"}, 174 {&RawMachineAssembler::Int32Add, "Int32Add"}, 175 {&RawMachineAssembler::Int32Sub, "Int32Sub"}, 176 {&RawMachineAssembler::Int32Mul, "Int32Mul"}, 177 {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh"}, 178 {&RawMachineAssembler::Int32Div, "Int32Div"}, 179 {&RawMachineAssembler::Int32LessThan, "Int32LessThan"}, 180 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual"}, 181 {&RawMachineAssembler::Int32Mod, "Int32Mod"}, 182 {&RawMachineAssembler::Uint32Div, "Uint32Div"}, 183 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan"}, 184 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual"}, 185 {&RawMachineAssembler::Uint32Mod, "Uint32Mod"}}; 186 187 } // namespace 188 189 190 typedef InstructionSelectorTestWithParam<BinaryOperation> 191 InstructionSelectorChangeUint32ToUint64Test; 192 193 194 TEST_P(InstructionSelectorChangeUint32ToUint64Test, ChangeUint32ToUint64) { 195 const BinaryOperation& bop = GetParam(); 196 StreamBuilder m(this, MachineType::Uint64(), MachineType::Int32(), 197 MachineType::Int32()); 198 Node* const p0 = m.Parameter(0); 199 Node* const p1 = m.Parameter(1); 200 m.Return(m.ChangeUint32ToUint64((m.*bop.constructor)(p0, p1))); 201 Stream s = m.Build(); 202 ASSERT_EQ(1U, s.size()); 203 } 204 205 206 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 207 InstructionSelectorChangeUint32ToUint64Test, 208 ::testing::ValuesIn(kWord32BinaryOperations)); 209 210 211 // ----------------------------------------------------------------------------- 212 // TruncateInt64ToInt32. 213 214 215 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) { 216 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64()); 217 Node* const p = m.Parameter(0); 218 Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32))); 219 m.Return(t); 220 Stream s = m.Build(); 221 ASSERT_EQ(1U, s.size()); 222 EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); 223 ASSERT_EQ(2U, s[0]->InputCount()); 224 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); 225 EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1))); 226 ASSERT_EQ(1U, s[0]->OutputCount()); 227 EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); 228 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); 229 } 230 231 232 TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) { 233 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64()); 234 Node* const p = m.Parameter(0); 235 Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32))); 236 m.Return(t); 237 Stream s = m.Build(); 238 ASSERT_EQ(1U, s.size()); 239 EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); 240 ASSERT_EQ(2U, s[0]->InputCount()); 241 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); 242 EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1))); 243 ASSERT_EQ(1U, s[0]->OutputCount()); 244 EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); 245 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); 246 } 247 248 249 // ----------------------------------------------------------------------------- 250 // Addition. 251 252 253 TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) { 254 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 255 MachineType::Int32()); 256 Node* const p0 = m.Parameter(0); 257 Node* const p1 = m.Parameter(1); 258 Node* const a0 = m.Int32Add(p0, p1); 259 // Additional uses of input to add chooses lea 260 Node* const a1 = m.Int32Div(p0, p1); 261 m.Return(m.Int32Div(a0, a1)); 262 Stream s = m.Build(); 263 ASSERT_EQ(3U, s.size()); 264 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 265 ASSERT_EQ(2U, s[0]->InputCount()); 266 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 267 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 268 } 269 270 271 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) { 272 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 273 Node* const p0 = m.Parameter(0); 274 Node* const c0 = m.Int32Constant(15); 275 // If one of the add's operands is only used once, use an "leal", even though 276 // an "addl" could be used. The "leal" has proven faster--out best guess is 277 // that it gives the register allocation more freedom and it doesn't set 278 // flags, reducing pressure in the CPU's pipeline. If we're lucky with 279 // register allocation, then code generation will select an "addl" later for 280 // the cases that have been measured to be faster. 281 Node* const v0 = m.Int32Add(p0, c0); 282 m.Return(v0); 283 Stream s = m.Build(); 284 ASSERT_EQ(1U, s.size()); 285 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 286 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 287 ASSERT_EQ(2U, s[0]->InputCount()); 288 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 289 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 290 } 291 292 293 TEST_F(InstructionSelectorTest, Int32AddConstantAsAdd) { 294 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 295 Node* const p0 = m.Parameter(0); 296 Node* const c0 = m.Int32Constant(1); 297 // If there is only a single use of an add's input and the immediate constant 298 // for the add is 1, don't use an inc. It is much slower on modern Intel 299 // architectures. 300 m.Return(m.Int32Add(p0, c0)); 301 Stream s = m.Build(); 302 ASSERT_EQ(1U, s.size()); 303 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 304 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 305 ASSERT_EQ(2U, s[0]->InputCount()); 306 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 307 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 308 } 309 310 311 TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) { 312 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 313 Node* const p0 = m.Parameter(0); 314 Node* const c0 = m.Int32Constant(15); 315 // A second use of an add's input uses lea 316 Node* const a0 = m.Int32Add(p0, c0); 317 m.Return(m.Int32Div(a0, p0)); 318 Stream s = m.Build(); 319 ASSERT_EQ(2U, s.size()); 320 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 321 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 322 ASSERT_EQ(2U, s[0]->InputCount()); 323 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 324 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 325 } 326 327 328 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) { 329 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 330 Node* const p0 = m.Parameter(0); 331 Node* const c0 = m.Int32Constant(15); 332 // If one of the add's operands is only used once, use an "leal", even though 333 // an "addl" could be used. The "leal" has proven faster--out best guess is 334 // that it gives the register allocation more freedom and it doesn't set 335 // flags, reducing pressure in the CPU's pipeline. If we're lucky with 336 // register allocation, then code generation will select an "addl" later for 337 // the cases that have been measured to be faster. 338 m.Return(m.Int32Add(c0, p0)); 339 Stream s = m.Build(); 340 ASSERT_EQ(1U, s.size()); 341 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 342 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 343 ASSERT_EQ(2U, s[0]->InputCount()); 344 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 345 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 346 } 347 348 349 TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) { 350 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 351 Node* const p0 = m.Parameter(0); 352 Node* const c0 = m.Int32Constant(15); 353 // A second use of an add's input uses lea 354 Node* const a0 = m.Int32Add(c0, p0); 355 USE(a0); 356 m.Return(m.Int32Div(a0, p0)); 357 Stream s = m.Build(); 358 ASSERT_EQ(2U, s.size()); 359 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 360 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 361 ASSERT_EQ(2U, s[0]->InputCount()); 362 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 363 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 364 } 365 366 367 TEST_F(InstructionSelectorTest, Int32AddSimpleAsAdd) { 368 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 369 MachineType::Int32()); 370 Node* const p0 = m.Parameter(0); 371 Node* const p1 = m.Parameter(1); 372 // If one of the add's operands is only used once, use an "leal", even though 373 // an "addl" could be used. The "leal" has proven faster--out best guess is 374 // that it gives the register allocation more freedom and it doesn't set 375 // flags, reducing pressure in the CPU's pipeline. If we're lucky with 376 // register allocation, then code generation will select an "addl" later for 377 // the cases that have been measured to be faster. 378 m.Return(m.Int32Add(p0, p1)); 379 Stream s = m.Build(); 380 ASSERT_EQ(1U, s.size()); 381 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 382 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); 383 ASSERT_EQ(2U, s[0]->InputCount()); 384 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 385 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 386 } 387 388 389 TEST_F(InstructionSelectorTest, Int32AddSimpleAsLea) { 390 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 391 MachineType::Int32()); 392 Node* const p0 = m.Parameter(0); 393 Node* const p1 = m.Parameter(1); 394 // If all of of the add's operands are used multiple times, use an "leal". 395 Node* const v1 = m.Int32Add(p0, p1); 396 m.Return(m.Int32Add(m.Int32Add(v1, p1), p0)); 397 Stream s = m.Build(); 398 ASSERT_EQ(3U, s.size()); 399 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 400 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); 401 ASSERT_EQ(2U, s[0]->InputCount()); 402 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 403 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 404 } 405 406 407 TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) { 408 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 409 MachineType::Int32()); 410 Node* const p0 = m.Parameter(0); 411 Node* const p1 = m.Parameter(1); 412 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 413 m.Return(m.Int32Add(p0, s0)); 414 Stream s = m.Build(); 415 ASSERT_EQ(1U, s.size()); 416 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 417 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); 418 ASSERT_EQ(2U, s[0]->InputCount()); 419 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 420 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 421 } 422 423 424 TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Mul) { 425 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 426 MachineType::Int32()); 427 Node* const p0 = m.Parameter(0); 428 Node* const p1 = m.Parameter(1); 429 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 430 m.Return(m.Int32Add(s0, p0)); 431 Stream s = m.Build(); 432 ASSERT_EQ(1U, s.size()); 433 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 434 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); 435 ASSERT_EQ(2U, s[0]->InputCount()); 436 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 437 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 438 } 439 440 441 TEST_F(InstructionSelectorTest, Int32AddScaled2Shl) { 442 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 443 MachineType::Int32()); 444 Node* const p0 = m.Parameter(0); 445 Node* const p1 = m.Parameter(1); 446 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1)); 447 m.Return(m.Int32Add(p0, s0)); 448 Stream s = m.Build(); 449 ASSERT_EQ(1U, s.size()); 450 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 451 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); 452 ASSERT_EQ(2U, s[0]->InputCount()); 453 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 454 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 455 } 456 457 458 TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Shl) { 459 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 460 MachineType::Int32()); 461 Node* const p0 = m.Parameter(0); 462 Node* const p1 = m.Parameter(1); 463 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1)); 464 m.Return(m.Int32Add(s0, p0)); 465 Stream s = m.Build(); 466 ASSERT_EQ(1U, s.size()); 467 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 468 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); 469 ASSERT_EQ(2U, s[0]->InputCount()); 470 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 471 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 472 } 473 474 475 TEST_F(InstructionSelectorTest, Int32AddScaled4Mul) { 476 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 477 MachineType::Int32()); 478 Node* const p0 = m.Parameter(0); 479 Node* const p1 = m.Parameter(1); 480 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4)); 481 m.Return(m.Int32Add(p0, s0)); 482 Stream s = m.Build(); 483 ASSERT_EQ(1U, s.size()); 484 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 485 EXPECT_EQ(kMode_MR4, s[0]->addressing_mode()); 486 ASSERT_EQ(2U, s[0]->InputCount()); 487 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 488 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 489 } 490 491 492 TEST_F(InstructionSelectorTest, Int32AddScaled4Shl) { 493 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 494 MachineType::Int32()); 495 Node* const p0 = m.Parameter(0); 496 Node* const p1 = m.Parameter(1); 497 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2)); 498 m.Return(m.Int32Add(p0, s0)); 499 Stream s = m.Build(); 500 ASSERT_EQ(1U, s.size()); 501 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 502 EXPECT_EQ(kMode_MR4, s[0]->addressing_mode()); 503 ASSERT_EQ(2U, s[0]->InputCount()); 504 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 505 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 506 } 507 508 509 TEST_F(InstructionSelectorTest, Int32AddScaled8Mul) { 510 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 511 MachineType::Int32()); 512 Node* const p0 = m.Parameter(0); 513 Node* const p1 = m.Parameter(1); 514 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8)); 515 m.Return(m.Int32Add(p0, s0)); 516 Stream s = m.Build(); 517 ASSERT_EQ(1U, s.size()); 518 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 519 EXPECT_EQ(kMode_MR8, s[0]->addressing_mode()); 520 ASSERT_EQ(2U, s[0]->InputCount()); 521 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 522 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 523 } 524 525 526 TEST_F(InstructionSelectorTest, Int32AddScaled8Shl) { 527 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 528 MachineType::Int32()); 529 Node* const p0 = m.Parameter(0); 530 Node* const p1 = m.Parameter(1); 531 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3)); 532 m.Return(m.Int32Add(p0, s0)); 533 Stream s = m.Build(); 534 ASSERT_EQ(1U, s.size()); 535 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 536 EXPECT_EQ(kMode_MR8, s[0]->addressing_mode()); 537 ASSERT_EQ(2U, s[0]->InputCount()); 538 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 539 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 540 } 541 542 543 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstant) { 544 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 545 MachineType::Int32()); 546 Node* const p0 = m.Parameter(0); 547 Node* const p1 = m.Parameter(1); 548 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 549 Node* const c0 = m.Int32Constant(15); 550 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0))); 551 Stream s = m.Build(); 552 ASSERT_EQ(1U, s.size()); 553 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 554 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 555 ASSERT_EQ(3U, s[0]->InputCount()); 556 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 557 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 558 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 559 } 560 561 562 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle1) { 563 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 564 MachineType::Int32()); 565 Node* const p0 = m.Parameter(0); 566 Node* const p1 = m.Parameter(1); 567 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 568 Node* const c0 = m.Int32Constant(15); 569 m.Return(m.Int32Add(p0, m.Int32Add(s0, c0))); 570 Stream s = m.Build(); 571 ASSERT_EQ(1U, s.size()); 572 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 573 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 574 ASSERT_EQ(3U, s[0]->InputCount()); 575 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 576 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 577 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 578 } 579 580 581 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle2) { 582 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 583 MachineType::Int32()); 584 Node* const p0 = m.Parameter(0); 585 Node* const p1 = m.Parameter(1); 586 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 587 Node* const c0 = m.Int32Constant(15); 588 m.Return(m.Int32Add(s0, m.Int32Add(c0, p0))); 589 Stream s = m.Build(); 590 ASSERT_EQ(1U, s.size()); 591 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 592 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 593 ASSERT_EQ(3U, s[0]->InputCount()); 594 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 595 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 596 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 597 } 598 599 600 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle3) { 601 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 602 MachineType::Int32()); 603 Node* const p0 = m.Parameter(0); 604 Node* const p1 = m.Parameter(1); 605 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 606 Node* const c0 = m.Int32Constant(15); 607 m.Return(m.Int32Add(m.Int32Add(s0, c0), p0)); 608 Stream s = m.Build(); 609 ASSERT_EQ(1U, s.size()); 610 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 611 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 612 ASSERT_EQ(3U, s[0]->InputCount()); 613 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 614 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 615 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 616 } 617 618 619 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle4) { 620 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 621 MachineType::Int32()); 622 Node* const p0 = m.Parameter(0); 623 Node* const p1 = m.Parameter(1); 624 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 625 Node* const c0 = m.Int32Constant(15); 626 m.Return(m.Int32Add(m.Int32Add(c0, p0), s0)); 627 Stream s = m.Build(); 628 ASSERT_EQ(1U, s.size()); 629 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 630 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 631 ASSERT_EQ(3U, s[0]->InputCount()); 632 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 633 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 634 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 635 } 636 637 638 TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle5) { 639 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 640 MachineType::Int32()); 641 Node* const p0 = m.Parameter(0); 642 Node* const p1 = m.Parameter(1); 643 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 644 Node* const c0 = m.Int32Constant(15); 645 m.Return(m.Int32Add(m.Int32Add(p0, s0), c0)); 646 Stream s = m.Build(); 647 ASSERT_EQ(1U, s.size()); 648 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 649 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 650 ASSERT_EQ(3U, s[0]->InputCount()); 651 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 652 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 653 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 654 } 655 656 657 TEST_F(InstructionSelectorTest, Int32AddScaled2ShlWithConstant) { 658 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 659 MachineType::Int32()); 660 Node* const p0 = m.Parameter(0); 661 Node* const p1 = m.Parameter(1); 662 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1)); 663 Node* const c0 = m.Int32Constant(15); 664 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0))); 665 Stream s = m.Build(); 666 ASSERT_EQ(1U, s.size()); 667 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 668 EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode()); 669 ASSERT_EQ(3U, s[0]->InputCount()); 670 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 671 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 672 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 673 } 674 675 676 TEST_F(InstructionSelectorTest, Int32AddScaled4MulWithConstant) { 677 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 678 MachineType::Int32()); 679 Node* const p0 = m.Parameter(0); 680 Node* const p1 = m.Parameter(1); 681 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4)); 682 Node* const c0 = m.Int32Constant(15); 683 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0))); 684 Stream s = m.Build(); 685 ASSERT_EQ(1U, s.size()); 686 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 687 EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode()); 688 ASSERT_EQ(3U, s[0]->InputCount()); 689 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 690 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 691 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 692 } 693 694 695 TEST_F(InstructionSelectorTest, Int32AddScaled4ShlWithConstant) { 696 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 697 MachineType::Int32()); 698 Node* const p0 = m.Parameter(0); 699 Node* const p1 = m.Parameter(1); 700 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2)); 701 Node* const c0 = m.Int32Constant(15); 702 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0))); 703 Stream s = m.Build(); 704 ASSERT_EQ(1U, s.size()); 705 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 706 EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode()); 707 ASSERT_EQ(3U, s[0]->InputCount()); 708 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 709 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 710 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 711 } 712 713 714 TEST_F(InstructionSelectorTest, Int32AddScaled8MulWithConstant) { 715 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 716 MachineType::Int32()); 717 Node* const p0 = m.Parameter(0); 718 Node* const p1 = m.Parameter(1); 719 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8)); 720 Node* const c0 = m.Int32Constant(15); 721 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0))); 722 Stream s = m.Build(); 723 ASSERT_EQ(1U, s.size()); 724 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 725 EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode()); 726 ASSERT_EQ(3U, s[0]->InputCount()); 727 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 728 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 729 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 730 } 731 732 733 TEST_F(InstructionSelectorTest, Int32AddScaled8ShlWithConstant) { 734 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 735 MachineType::Int32()); 736 Node* const p0 = m.Parameter(0); 737 Node* const p1 = m.Parameter(1); 738 Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3)); 739 Node* const c0 = m.Int32Constant(15); 740 m.Return(m.Int32Add(c0, m.Int32Add(p0, s0))); 741 Stream s = m.Build(); 742 ASSERT_EQ(1U, s.size()); 743 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 744 EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode()); 745 ASSERT_EQ(3U, s[0]->InputCount()); 746 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 747 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 748 EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); 749 } 750 751 752 TEST_F(InstructionSelectorTest, Int32SubConstantAsSub) { 753 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 754 Node* const p0 = m.Parameter(0); 755 Node* const c0 = m.Int32Constant(-1); 756 // If there is only a single use of on of the sub's non-constant input, use a 757 // "subl" instruction. 758 m.Return(m.Int32Sub(p0, c0)); 759 Stream s = m.Build(); 760 ASSERT_EQ(1U, s.size()); 761 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 762 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 763 ASSERT_EQ(2U, s[0]->InputCount()); 764 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 765 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 766 } 767 768 769 TEST_F(InstructionSelectorTest, Int32SubConstantAsLea) { 770 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 771 Node* const p0 = m.Parameter(0); 772 Node* const c0 = m.Int32Constant(-1); 773 // If there are multiple uses of on of the sub's non-constant input, use a 774 // "leal" instruction. 775 Node* const v0 = m.Int32Sub(p0, c0); 776 m.Return(m.Int32Div(p0, v0)); 777 Stream s = m.Build(); 778 ASSERT_EQ(2U, s.size()); 779 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 780 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 781 ASSERT_EQ(2U, s[0]->InputCount()); 782 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 783 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 784 } 785 786 787 TEST_F(InstructionSelectorTest, Int32AddScaled2Other) { 788 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 789 MachineType::Int32(), MachineType::Int32()); 790 Node* const p0 = m.Parameter(0); 791 Node* const p1 = m.Parameter(1); 792 Node* const p2 = m.Parameter(2); 793 Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2)); 794 Node* const a0 = m.Int32Add(s0, p2); 795 Node* const a1 = m.Int32Add(p0, a0); 796 m.Return(a1); 797 Stream s = m.Build(); 798 ASSERT_EQ(2U, s.size()); 799 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 800 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); 801 ASSERT_EQ(2U, s[0]->InputCount()); 802 EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0))); 803 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 804 EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0))); 805 ASSERT_EQ(2U, s[1]->InputCount()); 806 EXPECT_EQ(kX64Lea32, s[1]->arch_opcode()); 807 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0))); 808 EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(1))); 809 EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0))); 810 } 811 812 813 // ----------------------------------------------------------------------------- 814 // Multiplication. 815 816 817 TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) { 818 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 819 MachineType::Int32()); 820 Node* const p0 = m.Parameter(0); 821 Node* const p1 = m.Parameter(1); 822 Node* const m0 = m.Int32Mul(p0, p1); 823 m.Return(m.Int32Mul(m0, p0)); 824 Stream s = m.Build(); 825 ASSERT_EQ(2U, s.size()); 826 EXPECT_EQ(kX64Imul32, s[0]->arch_opcode()); 827 ASSERT_EQ(2U, s[0]->InputCount()); 828 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0))); 829 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); 830 ASSERT_EQ(1U, s[0]->OutputCount()); 831 EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[0]->OutputAt(0))); 832 EXPECT_EQ(kX64Imul32, s[1]->arch_opcode()); 833 ASSERT_EQ(2U, s[1]->InputCount()); 834 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0))); 835 EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[1]->InputAt(1))); 836 } 837 838 839 TEST_F(InstructionSelectorTest, Int32MulHigh) { 840 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 841 MachineType::Int32()); 842 Node* const p0 = m.Parameter(0); 843 Node* const p1 = m.Parameter(1); 844 Node* const n = m.Int32MulHigh(p0, p1); 845 m.Return(n); 846 Stream s = m.Build(); 847 ASSERT_EQ(1U, s.size()); 848 EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode()); 849 ASSERT_EQ(2U, s[0]->InputCount()); 850 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 851 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax)); 852 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 853 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); 854 ASSERT_LE(1U, s[0]->OutputCount()); 855 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 856 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx)); 857 } 858 859 860 TEST_F(InstructionSelectorTest, Uint32MulHigh) { 861 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 862 MachineType::Uint32()); 863 Node* const p0 = m.Parameter(0); 864 Node* const p1 = m.Parameter(1); 865 Node* const n = m.Uint32MulHigh(p0, p1); 866 m.Return(n); 867 Stream s = m.Build(); 868 ASSERT_EQ(1U, s.size()); 869 EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode()); 870 ASSERT_EQ(2U, s[0]->InputCount()); 871 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 872 EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax)); 873 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 874 EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); 875 ASSERT_LE(1U, s[0]->OutputCount()); 876 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 877 EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx)); 878 } 879 880 881 TEST_F(InstructionSelectorTest, Int32Mul2BecomesLea) { 882 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 883 MachineType::Uint32()); 884 Node* const p0 = m.Parameter(0); 885 Node* const c1 = m.Int32Constant(2); 886 Node* const n = m.Int32Mul(p0, c1); 887 m.Return(n); 888 Stream s = m.Build(); 889 ASSERT_EQ(1U, s.size()); 890 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 891 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); 892 ASSERT_EQ(2U, s[0]->InputCount()); 893 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 894 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); 895 } 896 897 898 TEST_F(InstructionSelectorTest, Int32Mul3BecomesLea) { 899 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 900 MachineType::Uint32()); 901 Node* const p0 = m.Parameter(0); 902 Node* const c1 = m.Int32Constant(3); 903 Node* const n = m.Int32Mul(p0, c1); 904 m.Return(n); 905 Stream s = m.Build(); 906 ASSERT_EQ(1U, s.size()); 907 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 908 EXPECT_EQ(kMode_MR2, s[0]->addressing_mode()); 909 ASSERT_EQ(2U, s[0]->InputCount()); 910 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 911 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); 912 } 913 914 915 TEST_F(InstructionSelectorTest, Int32Mul4BecomesLea) { 916 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 917 MachineType::Uint32()); 918 Node* const p0 = m.Parameter(0); 919 Node* const c1 = m.Int32Constant(4); 920 Node* const n = m.Int32Mul(p0, c1); 921 m.Return(n); 922 Stream s = m.Build(); 923 ASSERT_EQ(1U, s.size()); 924 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 925 EXPECT_EQ(kMode_M4, s[0]->addressing_mode()); 926 ASSERT_EQ(1U, s[0]->InputCount()); 927 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 928 } 929 930 931 TEST_F(InstructionSelectorTest, Int32Mul5BecomesLea) { 932 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 933 MachineType::Uint32()); 934 Node* const p0 = m.Parameter(0); 935 Node* const c1 = m.Int32Constant(5); 936 Node* const n = m.Int32Mul(p0, c1); 937 m.Return(n); 938 Stream s = m.Build(); 939 ASSERT_EQ(1U, s.size()); 940 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 941 EXPECT_EQ(kMode_MR4, s[0]->addressing_mode()); 942 ASSERT_EQ(2U, s[0]->InputCount()); 943 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 944 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); 945 } 946 947 948 TEST_F(InstructionSelectorTest, Int32Mul8BecomesLea) { 949 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 950 MachineType::Uint32()); 951 Node* const p0 = m.Parameter(0); 952 Node* const c1 = m.Int32Constant(8); 953 Node* const n = m.Int32Mul(p0, c1); 954 m.Return(n); 955 Stream s = m.Build(); 956 ASSERT_EQ(1U, s.size()); 957 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 958 EXPECT_EQ(kMode_M8, s[0]->addressing_mode()); 959 ASSERT_EQ(1U, s[0]->InputCount()); 960 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 961 } 962 963 964 TEST_F(InstructionSelectorTest, Int32Mul9BecomesLea) { 965 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 966 MachineType::Uint32()); 967 Node* const p0 = m.Parameter(0); 968 Node* const c1 = m.Int32Constant(9); 969 Node* const n = m.Int32Mul(p0, c1); 970 m.Return(n); 971 Stream s = m.Build(); 972 ASSERT_EQ(1U, s.size()); 973 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 974 EXPECT_EQ(kMode_MR8, s[0]->addressing_mode()); 975 ASSERT_EQ(2U, s[0]->InputCount()); 976 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 977 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); 978 } 979 980 981 // ----------------------------------------------------------------------------- 982 // Word32Shl. 983 984 985 TEST_F(InstructionSelectorTest, Int32Shl1BecomesLea) { 986 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 987 MachineType::Uint32()); 988 Node* const p0 = m.Parameter(0); 989 Node* const c1 = m.Int32Constant(1); 990 Node* const n = m.Word32Shl(p0, c1); 991 m.Return(n); 992 Stream s = m.Build(); 993 ASSERT_EQ(1U, s.size()); 994 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 995 EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); 996 ASSERT_EQ(2U, s[0]->InputCount()); 997 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 998 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1))); 999 } 1000 1001 1002 TEST_F(InstructionSelectorTest, Int32Shl2BecomesLea) { 1003 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 1004 MachineType::Uint32()); 1005 Node* const p0 = m.Parameter(0); 1006 Node* const c1 = m.Int32Constant(2); 1007 Node* const n = m.Word32Shl(p0, c1); 1008 m.Return(n); 1009 Stream s = m.Build(); 1010 ASSERT_EQ(1U, s.size()); 1011 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 1012 EXPECT_EQ(kMode_M4, s[0]->addressing_mode()); 1013 ASSERT_EQ(1U, s[0]->InputCount()); 1014 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1015 } 1016 1017 1018 TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) { 1019 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32(), 1020 MachineType::Uint32()); 1021 Node* const p0 = m.Parameter(0); 1022 Node* const c1 = m.Int32Constant(3); 1023 Node* const n = m.Word32Shl(p0, c1); 1024 m.Return(n); 1025 Stream s = m.Build(); 1026 ASSERT_EQ(1U, s.size()); 1027 EXPECT_EQ(kX64Lea32, s[0]->arch_opcode()); 1028 EXPECT_EQ(kMode_M8, s[0]->addressing_mode()); 1029 ASSERT_EQ(1U, s[0]->InputCount()); 1030 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1031 } 1032 1033 1034 // ----------------------------------------------------------------------------- 1035 // Floating point operations. 1036 1037 1038 TEST_F(InstructionSelectorTest, Float32Abs) { 1039 { 1040 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); 1041 Node* const p0 = m.Parameter(0); 1042 Node* const n = m.Float32Abs(p0); 1043 m.Return(n); 1044 Stream s = m.Build(); 1045 ASSERT_EQ(1U, s.size()); 1046 EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); 1047 ASSERT_EQ(1U, s[0]->InputCount()); 1048 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1049 ASSERT_EQ(1U, s[0]->OutputCount()); 1050 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); 1051 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1052 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1053 } 1054 { 1055 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); 1056 Node* const p0 = m.Parameter(0); 1057 Node* const n = m.Float32Abs(p0); 1058 m.Return(n); 1059 Stream s = m.Build(AVX); 1060 ASSERT_EQ(1U, s.size()); 1061 EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode()); 1062 ASSERT_EQ(1U, s[0]->InputCount()); 1063 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1064 ASSERT_EQ(1U, s[0]->OutputCount()); 1065 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1066 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1067 } 1068 } 1069 1070 1071 TEST_F(InstructionSelectorTest, Float64Abs) { 1072 { 1073 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 1074 Node* const p0 = m.Parameter(0); 1075 Node* const n = m.Float64Abs(p0); 1076 m.Return(n); 1077 Stream s = m.Build(); 1078 ASSERT_EQ(1U, s.size()); 1079 EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); 1080 ASSERT_EQ(1U, s[0]->InputCount()); 1081 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1082 ASSERT_EQ(1U, s[0]->OutputCount()); 1083 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); 1084 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1085 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1086 } 1087 { 1088 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 1089 Node* const p0 = m.Parameter(0); 1090 Node* const n = m.Float64Abs(p0); 1091 m.Return(n); 1092 Stream s = m.Build(AVX); 1093 ASSERT_EQ(1U, s.size()); 1094 EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode()); 1095 ASSERT_EQ(1U, s[0]->InputCount()); 1096 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1097 ASSERT_EQ(1U, s[0]->OutputCount()); 1098 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1099 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1100 } 1101 } 1102 1103 1104 TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { 1105 { 1106 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), 1107 MachineType::Float64()); 1108 Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1)); 1109 Node* mul = m.Float64Mul(add, m.Parameter(1)); 1110 Node* sub = m.Float64Sub(mul, add); 1111 Node* ret = m.Float64Div(mul, sub); 1112 m.Return(ret); 1113 Stream s = m.Build(AVX); 1114 ASSERT_EQ(4U, s.size()); 1115 EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode()); 1116 EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode()); 1117 EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode()); 1118 EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode()); 1119 } 1120 { 1121 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), 1122 MachineType::Float64()); 1123 Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1)); 1124 Node* mul = m.Float64Mul(add, m.Parameter(1)); 1125 Node* sub = m.Float64Sub(mul, add); 1126 Node* ret = m.Float64Div(mul, sub); 1127 m.Return(ret); 1128 Stream s = m.Build(); 1129 ASSERT_EQ(4U, s.size()); 1130 EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode()); 1131 EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode()); 1132 EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode()); 1133 EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode()); 1134 } 1135 } 1136 1137 1138 TEST_F(InstructionSelectorTest, Float32SubWithMinusZeroAndParameter) { 1139 { 1140 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); 1141 Node* const p0 = m.Parameter(0); 1142 Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); 1143 m.Return(n); 1144 Stream s = m.Build(); 1145 ASSERT_EQ(1U, s.size()); 1146 EXPECT_EQ(kSSEFloat32Neg, s[0]->arch_opcode()); 1147 ASSERT_EQ(1U, s[0]->InputCount()); 1148 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1149 ASSERT_EQ(1U, s[0]->OutputCount()); 1150 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1151 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1152 } 1153 { 1154 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); 1155 Node* const p0 = m.Parameter(0); 1156 Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); 1157 m.Return(n); 1158 Stream s = m.Build(AVX); 1159 ASSERT_EQ(1U, s.size()); 1160 EXPECT_EQ(kAVXFloat32Neg, s[0]->arch_opcode()); 1161 ASSERT_EQ(1U, s[0]->InputCount()); 1162 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1163 ASSERT_EQ(1U, s[0]->OutputCount()); 1164 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1165 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1166 } 1167 } 1168 1169 1170 TEST_F(InstructionSelectorTest, Float64SubWithMinusZeroAndParameter) { 1171 { 1172 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 1173 Node* const p0 = m.Parameter(0); 1174 Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); 1175 m.Return(n); 1176 Stream s = m.Build(); 1177 ASSERT_EQ(1U, s.size()); 1178 EXPECT_EQ(kSSEFloat64Neg, s[0]->arch_opcode()); 1179 ASSERT_EQ(1U, s[0]->InputCount()); 1180 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1181 ASSERT_EQ(1U, s[0]->OutputCount()); 1182 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1183 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1184 } 1185 { 1186 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 1187 Node* const p0 = m.Parameter(0); 1188 Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); 1189 m.Return(n); 1190 Stream s = m.Build(AVX); 1191 ASSERT_EQ(1U, s.size()); 1192 EXPECT_EQ(kAVXFloat64Neg, s[0]->arch_opcode()); 1193 ASSERT_EQ(1U, s[0]->InputCount()); 1194 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1195 ASSERT_EQ(1U, s[0]->OutputCount()); 1196 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1197 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1198 } 1199 } 1200 1201 1202 // ----------------------------------------------------------------------------- 1203 // Miscellaneous. 1204 1205 1206 TEST_F(InstructionSelectorTest, Uint64LessThanWithLoadAndLoadStackPointer) { 1207 StreamBuilder m(this, MachineType::Bool()); 1208 Node* const sl = m.Load( 1209 MachineType::Pointer(), 1210 m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))); 1211 Node* const sp = m.LoadStackPointer(); 1212 Node* const n = m.Uint64LessThan(sl, sp); 1213 m.Return(n); 1214 Stream s = m.Build(); 1215 ASSERT_EQ(1U, s.size()); 1216 EXPECT_EQ(kX64StackCheck, s[0]->arch_opcode()); 1217 ASSERT_EQ(0U, s[0]->InputCount()); 1218 ASSERT_EQ(1U, s[0]->OutputCount()); 1219 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1220 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1221 EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition()); 1222 } 1223 1224 1225 TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) { 1226 TRACED_FORRANGE(int64_t, x, 32, 63) { 1227 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32()); 1228 Node* const p0 = m.Parameter(0); 1229 Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x)); 1230 m.Return(n); 1231 Stream s = m.Build(); 1232 ASSERT_EQ(1U, s.size()); 1233 EXPECT_EQ(kX64Shl, s[0]->arch_opcode()); 1234 ASSERT_EQ(2U, s[0]->InputCount()); 1235 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1236 EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1))); 1237 ASSERT_EQ(1U, s[0]->OutputCount()); 1238 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); 1239 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1240 } 1241 } 1242 1243 1244 TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) { 1245 TRACED_FORRANGE(int64_t, x, 32, 63) { 1246 StreamBuilder m(this, MachineType::Int64(), MachineType::Uint32()); 1247 Node* const p0 = m.Parameter(0); 1248 Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x)); 1249 m.Return(n); 1250 Stream s = m.Build(); 1251 ASSERT_EQ(1U, s.size()); 1252 EXPECT_EQ(kX64Shl, s[0]->arch_opcode()); 1253 ASSERT_EQ(2U, s[0]->InputCount()); 1254 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1255 EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1))); 1256 ASSERT_EQ(1U, s[0]->OutputCount()); 1257 EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); 1258 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1259 } 1260 } 1261 1262 1263 TEST_F(InstructionSelectorTest, Word32AndWith0xff) { 1264 { 1265 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1266 Node* const p0 = m.Parameter(0); 1267 Node* const n = m.Word32And(p0, m.Int32Constant(0xff)); 1268 m.Return(n); 1269 Stream s = m.Build(); 1270 ASSERT_EQ(1U, s.size()); 1271 EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode()); 1272 ASSERT_EQ(1U, s[0]->InputCount()); 1273 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1274 ASSERT_EQ(1U, s[0]->OutputCount()); 1275 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1276 } 1277 { 1278 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1279 Node* const p0 = m.Parameter(0); 1280 Node* const n = m.Word32And(m.Int32Constant(0xff), p0); 1281 m.Return(n); 1282 Stream s = m.Build(); 1283 ASSERT_EQ(1U, s.size()); 1284 EXPECT_EQ(kX64Movzxbl, s[0]->arch_opcode()); 1285 ASSERT_EQ(1U, s[0]->InputCount()); 1286 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1287 ASSERT_EQ(1U, s[0]->OutputCount()); 1288 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1289 } 1290 } 1291 1292 1293 TEST_F(InstructionSelectorTest, Word32AndWith0xffff) { 1294 { 1295 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1296 Node* const p0 = m.Parameter(0); 1297 Node* const n = m.Word32And(p0, m.Int32Constant(0xffff)); 1298 m.Return(n); 1299 Stream s = m.Build(); 1300 ASSERT_EQ(1U, s.size()); 1301 EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode()); 1302 ASSERT_EQ(1U, s[0]->InputCount()); 1303 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1304 ASSERT_EQ(1U, s[0]->OutputCount()); 1305 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1306 } 1307 { 1308 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1309 Node* const p0 = m.Parameter(0); 1310 Node* const n = m.Word32And(m.Int32Constant(0xffff), p0); 1311 m.Return(n); 1312 Stream s = m.Build(); 1313 ASSERT_EQ(1U, s.size()); 1314 EXPECT_EQ(kX64Movzxwl, s[0]->arch_opcode()); 1315 ASSERT_EQ(1U, s[0]->InputCount()); 1316 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1317 ASSERT_EQ(1U, s[0]->OutputCount()); 1318 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1319 } 1320 } 1321 1322 1323 TEST_F(InstructionSelectorTest, Word32Clz) { 1324 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32()); 1325 Node* const p0 = m.Parameter(0); 1326 Node* const n = m.Word32Clz(p0); 1327 m.Return(n); 1328 Stream s = m.Build(); 1329 ASSERT_EQ(1U, s.size()); 1330 EXPECT_EQ(kX64Lzcnt32, s[0]->arch_opcode()); 1331 ASSERT_EQ(1U, s[0]->InputCount()); 1332 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1333 ASSERT_EQ(1U, s[0]->OutputCount()); 1334 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1335 } 1336 1337 } // namespace compiler 1338 } // namespace internal 1339 } // namespace v8 1340