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 <list> 6 7 #include "src/compiler/instruction-selector-unittest.h" 8 9 namespace v8 { 10 namespace internal { 11 namespace compiler { 12 13 namespace { 14 15 typedef RawMachineAssembler::Label MLabel; 16 17 template <typename T> 18 struct MachInst { 19 T constructor; 20 const char* constructor_name; 21 ArchOpcode arch_opcode; 22 MachineType machine_type; 23 }; 24 25 typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1; 26 typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2; 27 28 29 template <typename T> 30 std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) { 31 return os << mi.constructor_name; 32 } 33 34 35 // Helper to build Int32Constant or Int64Constant depending on the given 36 // machine type. 37 Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type, 38 int64_t value) { 39 switch (type) { 40 case kMachInt32: 41 return m.Int32Constant(value); 42 break; 43 44 case kMachInt64: 45 return m.Int64Constant(value); 46 break; 47 48 default: 49 UNIMPLEMENTED(); 50 } 51 return NULL; 52 } 53 54 55 // ARM64 logical instructions. 56 static const MachInst2 kLogicalInstructions[] = { 57 {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32}, 58 {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64}, 59 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32}, 60 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64}, 61 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Xor32, kMachInt32}, 62 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Xor, kMachInt64}}; 63 64 65 // ARM64 logical immediates: contiguous set bits, rotated about a power of two 66 // sized block. The block is then duplicated across the word. Below is a random 67 // subset of the 32-bit immediates. 68 static const uint32_t kLogicalImmediates[] = { 69 0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0, 70 0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000, 71 0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000, 72 0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000, 73 0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc, 74 0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe, 75 0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80, 76 0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0, 77 0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff, 78 0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff, 79 0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff, 80 0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff, 81 0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000, 82 0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf, 83 0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff, 84 0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff, 85 0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff}; 86 87 88 // ARM64 arithmetic instructions. 89 static const MachInst2 kAddSubInstructions[] = { 90 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32}, 91 {&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64}, 92 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32}, 93 {&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64}}; 94 95 96 // ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12. 97 // Below is a combination of a random subset and some edge values. 98 static const int32_t kAddSubImmediates[] = { 99 0, 1, 69, 493, 599, 701, 719, 100 768, 818, 842, 945, 1246, 1286, 1429, 101 1669, 2171, 2179, 2182, 2254, 2334, 2338, 102 2343, 2396, 2449, 2610, 2732, 2855, 2876, 103 2944, 3377, 3458, 3475, 3476, 3540, 3574, 104 3601, 3813, 3871, 3917, 4095, 4096, 16384, 105 364544, 462848, 970752, 1523712, 1863680, 2363392, 3219456, 106 3280896, 4247552, 4526080, 4575232, 4960256, 5505024, 5894144, 107 6004736, 6193152, 6385664, 6795264, 7114752, 7233536, 7348224, 108 7499776, 7573504, 7729152, 8634368, 8937472, 9465856, 10354688, 109 10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224, 110 15597568, 15892480, 16773120}; 111 112 113 // ARM64 flag setting data processing instructions. 114 static const MachInst2 kDPFlagSetInstructions[] = { 115 {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32}, 116 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32}, 117 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32}}; 118 119 120 // ARM64 arithmetic with overflow instructions. 121 static const MachInst2 kOvfAddSubInstructions[] = { 122 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow", 123 kArm64Add32, kMachInt32}, 124 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow", 125 kArm64Sub32, kMachInt32}}; 126 127 128 // ARM64 shift instructions. 129 static const MachInst2 kShiftInstructions[] = { 130 {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32}, 131 {&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Shl, kMachInt64}, 132 {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Shr32, kMachInt32}, 133 {&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Shr, kMachInt64}, 134 {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Sar32, kMachInt32}, 135 {&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Sar, kMachInt64}, 136 {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32}, 137 {&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64}}; 138 139 140 // ARM64 Mul/Div instructions. 141 static const MachInst2 kMulDivInstructions[] = { 142 {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32}, 143 {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64}, 144 {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32}, 145 {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64}, 146 {&RawMachineAssembler::Int32UDiv, "Int32UDiv", kArm64Udiv32, kMachInt32}, 147 {&RawMachineAssembler::Int64UDiv, "Int64UDiv", kArm64Udiv, kMachInt64}}; 148 149 150 // ARM64 FP arithmetic instructions. 151 static const MachInst2 kFPArithInstructions[] = { 152 {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add, 153 kMachFloat64}, 154 {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub, 155 kMachFloat64}, 156 {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul, 157 kMachFloat64}, 158 {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div, 159 kMachFloat64}}; 160 161 162 struct FPCmp { 163 MachInst2 mi; 164 FlagsCondition cond; 165 }; 166 167 168 std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) { 169 return os << cmp.mi; 170 } 171 172 173 // ARM64 FP comparison instructions. 174 static const FPCmp kFPCmpInstructions[] = { 175 {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp, 176 kMachFloat64}, 177 kUnorderedEqual}, 178 {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", 179 kArm64Float64Cmp, kMachFloat64}, 180 kUnorderedLessThan}, 181 {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual", 182 kArm64Float64Cmp, kMachFloat64}, 183 kUnorderedLessThanOrEqual}}; 184 185 186 struct Conversion { 187 // The machine_type field in MachInst1 represents the destination type. 188 MachInst1 mi; 189 MachineType src_machine_type; 190 }; 191 192 193 std::ostream& operator<<(std::ostream& os, const Conversion& conv) { 194 return os << conv.mi; 195 } 196 197 198 // ARM64 type conversion instructions. 199 static const Conversion kConversionInstructions[] = { 200 {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64", 201 kArm64Sxtw, kMachInt64}, 202 kMachInt32}, 203 {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64", 204 kArm64Mov32, kMachUint64}, 205 kMachUint32}, 206 {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32", 207 kArm64Mov32, kMachInt32}, 208 kMachInt64}, 209 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64", 210 kArm64Int32ToFloat64, kMachFloat64}, 211 kMachInt32}, 212 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64", 213 kArm64Uint32ToFloat64, kMachFloat64}, 214 kMachUint32}, 215 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32", 216 kArm64Float64ToInt32, kMachInt32}, 217 kMachFloat64}, 218 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32", 219 kArm64Float64ToUint32, kMachUint32}, 220 kMachFloat64}}; 221 222 } // namespace 223 224 225 // ----------------------------------------------------------------------------- 226 // Logical instructions. 227 228 229 typedef InstructionSelectorTestWithParam<MachInst2> 230 InstructionSelectorLogicalTest; 231 232 233 TEST_P(InstructionSelectorLogicalTest, Parameter) { 234 const MachInst2 dpi = GetParam(); 235 const MachineType type = dpi.machine_type; 236 StreamBuilder m(this, type, type, type); 237 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); 238 Stream s = m.Build(); 239 ASSERT_EQ(1U, s.size()); 240 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 241 EXPECT_EQ(2U, s[0]->InputCount()); 242 EXPECT_EQ(1U, s[0]->OutputCount()); 243 } 244 245 246 TEST_P(InstructionSelectorLogicalTest, Immediate) { 247 const MachInst2 dpi = GetParam(); 248 const MachineType type = dpi.machine_type; 249 // TODO(all): Add support for testing 64-bit immediates. 250 if (type == kMachInt32) { 251 // Immediate on the right. 252 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { 253 StreamBuilder m(this, type, type); 254 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); 255 Stream s = m.Build(); 256 ASSERT_EQ(1U, s.size()); 257 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 258 ASSERT_EQ(2U, s[0]->InputCount()); 259 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 260 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 261 EXPECT_EQ(1U, s[0]->OutputCount()); 262 } 263 264 // Immediate on the left; all logical ops should commute. 265 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { 266 StreamBuilder m(this, type, type); 267 m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0))); 268 Stream s = m.Build(); 269 ASSERT_EQ(1U, s.size()); 270 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 271 ASSERT_EQ(2U, s[0]->InputCount()); 272 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 273 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 274 EXPECT_EQ(1U, s[0]->OutputCount()); 275 } 276 } 277 } 278 279 280 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest, 281 ::testing::ValuesIn(kLogicalInstructions)); 282 283 284 // ----------------------------------------------------------------------------- 285 // Add and Sub instructions. 286 287 typedef InstructionSelectorTestWithParam<MachInst2> 288 InstructionSelectorAddSubTest; 289 290 291 TEST_P(InstructionSelectorAddSubTest, Parameter) { 292 const MachInst2 dpi = GetParam(); 293 const MachineType type = dpi.machine_type; 294 StreamBuilder m(this, type, type, type); 295 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); 296 Stream s = m.Build(); 297 ASSERT_EQ(1U, s.size()); 298 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 299 EXPECT_EQ(2U, s[0]->InputCount()); 300 EXPECT_EQ(1U, s[0]->OutputCount()); 301 } 302 303 304 TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) { 305 const MachInst2 dpi = GetParam(); 306 const MachineType type = dpi.machine_type; 307 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 308 StreamBuilder m(this, type, type); 309 m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); 310 Stream s = m.Build(); 311 ASSERT_EQ(1U, s.size()); 312 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 313 ASSERT_EQ(2U, s[0]->InputCount()); 314 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 315 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 316 EXPECT_EQ(1U, s[0]->OutputCount()); 317 } 318 } 319 320 321 TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) { 322 const MachInst2 dpi = GetParam(); 323 const MachineType type = dpi.machine_type; 324 325 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 326 StreamBuilder m(this, type, type); 327 m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0))); 328 Stream s = m.Build(); 329 330 // Add can support an immediate on the left by commuting, but Sub can't 331 // commute. We test zero-on-left Sub later. 332 if (strstr(dpi.constructor_name, "Add") != NULL) { 333 ASSERT_EQ(1U, s.size()); 334 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 335 ASSERT_EQ(2U, s[0]->InputCount()); 336 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 337 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 338 EXPECT_EQ(1U, s[0]->OutputCount()); 339 } 340 } 341 } 342 343 344 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, 345 ::testing::ValuesIn(kAddSubInstructions)); 346 347 348 TEST_F(InstructionSelectorTest, SubZeroOnLeft) { 349 // Subtraction with zero on the left maps to Neg. 350 { 351 // 32-bit subtract. 352 StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); 353 m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0))); 354 Stream s = m.Build(); 355 356 ASSERT_EQ(1U, s.size()); 357 EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode()); 358 EXPECT_EQ(1U, s[0]->InputCount()); 359 EXPECT_EQ(1U, s[0]->OutputCount()); 360 } 361 { 362 // 64-bit subtract. 363 StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); 364 m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0))); 365 Stream s = m.Build(); 366 367 ASSERT_EQ(1U, s.size()); 368 EXPECT_EQ(kArm64Neg, s[0]->arch_opcode()); 369 EXPECT_EQ(1U, s[0]->InputCount()); 370 EXPECT_EQ(1U, s[0]->OutputCount()); 371 } 372 } 373 374 375 // ----------------------------------------------------------------------------- 376 // Data processing controlled branches. 377 378 379 typedef InstructionSelectorTestWithParam<MachInst2> 380 InstructionSelectorDPFlagSetTest; 381 382 383 TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) { 384 const MachInst2 dpi = GetParam(); 385 const MachineType type = dpi.machine_type; 386 StreamBuilder m(this, type, type, type); 387 MLabel a, b; 388 m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b); 389 m.Bind(&a); 390 m.Return(m.Int32Constant(1)); 391 m.Bind(&b); 392 m.Return(m.Int32Constant(0)); 393 Stream s = m.Build(); 394 ASSERT_EQ(1U, s.size()); 395 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 396 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 397 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 398 } 399 400 401 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 402 InstructionSelectorDPFlagSetTest, 403 ::testing::ValuesIn(kDPFlagSetInstructions)); 404 405 406 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) { 407 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { 408 StreamBuilder m(this, kMachInt32, kMachInt32); 409 MLabel a, b; 410 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b); 411 m.Bind(&a); 412 m.Return(m.Int32Constant(1)); 413 m.Bind(&b); 414 m.Return(m.Int32Constant(0)); 415 Stream s = m.Build(); 416 ASSERT_EQ(1U, s.size()); 417 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 418 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 419 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 420 } 421 } 422 423 424 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) { 425 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 426 StreamBuilder m(this, kMachInt32, kMachInt32); 427 MLabel a, b; 428 m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b); 429 m.Bind(&a); 430 m.Return(m.Int32Constant(1)); 431 m.Bind(&b); 432 m.Return(m.Int32Constant(0)); 433 Stream s = m.Build(); 434 ASSERT_EQ(1U, s.size()); 435 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 436 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 437 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 438 } 439 } 440 441 442 TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) { 443 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 444 StreamBuilder m(this, kMachInt32, kMachInt32); 445 MLabel a, b; 446 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b); 447 m.Bind(&a); 448 m.Return(m.Int32Constant(1)); 449 m.Bind(&b); 450 m.Return(m.Int32Constant(0)); 451 Stream s = m.Build(); 452 ASSERT_EQ(1U, s.size()); 453 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 454 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 455 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 456 } 457 } 458 459 460 TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) { 461 TRACED_FOREACH(int32_t, imm, kLogicalImmediates) { 462 StreamBuilder m(this, kMachInt32, kMachInt32); 463 MLabel a, b; 464 m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b); 465 m.Bind(&a); 466 m.Return(m.Int32Constant(1)); 467 m.Bind(&b); 468 m.Return(m.Int32Constant(0)); 469 Stream s = m.Build(); 470 ASSERT_EQ(1U, s.size()); 471 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 472 ASSERT_LE(1U, s[0]->InputCount()); 473 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 474 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 475 } 476 } 477 478 479 TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) { 480 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 481 StreamBuilder m(this, kMachInt32, kMachInt32); 482 MLabel a, b; 483 m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b); 484 m.Bind(&a); 485 m.Return(m.Int32Constant(1)); 486 m.Bind(&b); 487 m.Return(m.Int32Constant(0)); 488 Stream s = m.Build(); 489 ASSERT_EQ(1U, s.size()); 490 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 491 ASSERT_LE(1U, s[0]->InputCount()); 492 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 493 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 494 } 495 } 496 497 498 // ----------------------------------------------------------------------------- 499 // Add and subtract instructions with overflow. 500 501 502 typedef InstructionSelectorTestWithParam<MachInst2> 503 InstructionSelectorOvfAddSubTest; 504 505 506 TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) { 507 const MachInst2 dpi = GetParam(); 508 const MachineType type = dpi.machine_type; 509 StreamBuilder m(this, type, type, type); 510 m.Return( 511 m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)))); 512 Stream s = m.Build(); 513 ASSERT_EQ(1U, s.size()); 514 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 515 EXPECT_EQ(2U, s[0]->InputCount()); 516 EXPECT_LE(1U, s[0]->OutputCount()); 517 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 518 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 519 } 520 521 522 TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) { 523 const MachInst2 dpi = GetParam(); 524 const MachineType type = dpi.machine_type; 525 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 526 StreamBuilder m(this, type, type); 527 m.Return(m.Projection( 528 1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); 529 Stream s = m.Build(); 530 ASSERT_EQ(1U, s.size()); 531 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 532 ASSERT_EQ(2U, s[0]->InputCount()); 533 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 534 EXPECT_LE(1U, s[0]->OutputCount()); 535 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 536 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 537 } 538 } 539 540 541 TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) { 542 const MachInst2 dpi = GetParam(); 543 const MachineType type = dpi.machine_type; 544 StreamBuilder m(this, type, type, type); 545 m.Return( 546 m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)))); 547 Stream s = m.Build(); 548 ASSERT_EQ(1U, s.size()); 549 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 550 EXPECT_EQ(2U, s[0]->InputCount()); 551 EXPECT_LE(1U, s[0]->OutputCount()); 552 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 553 } 554 555 556 TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) { 557 const MachInst2 dpi = GetParam(); 558 const MachineType type = dpi.machine_type; 559 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 560 StreamBuilder m(this, type, type); 561 m.Return(m.Projection( 562 0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); 563 Stream s = m.Build(); 564 ASSERT_EQ(1U, s.size()); 565 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 566 ASSERT_EQ(2U, s[0]->InputCount()); 567 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 568 EXPECT_LE(1U, s[0]->OutputCount()); 569 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 570 } 571 } 572 573 574 TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) { 575 const MachInst2 dpi = GetParam(); 576 const MachineType type = dpi.machine_type; 577 StreamBuilder m(this, type, type, type); 578 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)); 579 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); 580 Stream s = m.Build(); 581 ASSERT_LE(1U, s.size()); 582 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 583 EXPECT_EQ(2U, s[0]->InputCount()); 584 EXPECT_EQ(2U, s[0]->OutputCount()); 585 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 586 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 587 } 588 589 590 TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) { 591 const MachInst2 dpi = GetParam(); 592 const MachineType type = dpi.machine_type; 593 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 594 StreamBuilder m(this, type, type); 595 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); 596 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); 597 Stream s = m.Build(); 598 ASSERT_LE(1U, s.size()); 599 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 600 ASSERT_EQ(2U, s[0]->InputCount()); 601 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 602 EXPECT_EQ(2U, s[0]->OutputCount()); 603 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 604 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 605 } 606 } 607 608 609 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) { 610 const MachInst2 dpi = GetParam(); 611 const MachineType type = dpi.machine_type; 612 StreamBuilder m(this, type, type, type); 613 MLabel a, b; 614 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)); 615 m.Branch(m.Projection(1, n), &a, &b); 616 m.Bind(&a); 617 m.Return(m.Int32Constant(0)); 618 m.Bind(&b); 619 m.Return(m.Projection(0, n)); 620 Stream s = m.Build(); 621 ASSERT_EQ(1U, s.size()); 622 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 623 EXPECT_EQ(4U, s[0]->InputCount()); 624 EXPECT_EQ(1U, s[0]->OutputCount()); 625 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 626 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 627 } 628 629 630 TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) { 631 const MachInst2 dpi = GetParam(); 632 const MachineType type = dpi.machine_type; 633 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 634 StreamBuilder m(this, type, type); 635 MLabel a, b; 636 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); 637 m.Branch(m.Projection(1, n), &a, &b); 638 m.Bind(&a); 639 m.Return(m.Int32Constant(0)); 640 m.Bind(&b); 641 m.Return(m.Projection(0, n)); 642 Stream s = m.Build(); 643 ASSERT_EQ(1U, s.size()); 644 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 645 ASSERT_EQ(4U, s[0]->InputCount()); 646 EXPECT_EQ(1U, s[0]->OutputCount()); 647 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 648 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 649 } 650 } 651 652 653 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 654 InstructionSelectorOvfAddSubTest, 655 ::testing::ValuesIn(kOvfAddSubInstructions)); 656 657 658 TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) { 659 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 660 StreamBuilder m(this, kMachInt32, kMachInt32); 661 m.Return(m.Projection( 662 1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)))); 663 Stream s = m.Build(); 664 665 ASSERT_EQ(1U, s.size()); 666 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 667 EXPECT_EQ(2U, s[0]->InputCount()); 668 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 669 EXPECT_LE(1U, s[0]->OutputCount()); 670 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 671 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 672 } 673 } 674 675 676 TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) { 677 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 678 StreamBuilder m(this, kMachInt32, kMachInt32); 679 m.Return(m.Projection( 680 0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)))); 681 Stream s = m.Build(); 682 683 ASSERT_EQ(1U, s.size()); 684 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 685 ASSERT_EQ(2U, s[0]->InputCount()); 686 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 687 EXPECT_LE(1U, s[0]->OutputCount()); 688 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 689 } 690 } 691 692 693 TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) { 694 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 695 StreamBuilder m(this, kMachInt32, kMachInt32); 696 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)); 697 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); 698 Stream s = m.Build(); 699 700 ASSERT_LE(1U, s.size()); 701 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 702 ASSERT_EQ(2U, s[0]->InputCount()); 703 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 704 EXPECT_EQ(2U, s[0]->OutputCount()); 705 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 706 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 707 } 708 } 709 710 711 TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) { 712 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 713 StreamBuilder m(this, kMachInt32, kMachInt32); 714 MLabel a, b; 715 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)); 716 m.Branch(m.Projection(1, n), &a, &b); 717 m.Bind(&a); 718 m.Return(m.Int32Constant(0)); 719 m.Bind(&b); 720 m.Return(m.Projection(0, n)); 721 Stream s = m.Build(); 722 723 ASSERT_EQ(1U, s.size()); 724 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 725 ASSERT_EQ(4U, s[0]->InputCount()); 726 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 727 EXPECT_EQ(1U, s[0]->OutputCount()); 728 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 729 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 730 } 731 } 732 733 734 // ----------------------------------------------------------------------------- 735 // Shift instructions. 736 737 738 typedef InstructionSelectorTestWithParam<MachInst2> 739 InstructionSelectorShiftTest; 740 741 742 TEST_P(InstructionSelectorShiftTest, Parameter) { 743 const MachInst2 dpi = GetParam(); 744 const MachineType type = dpi.machine_type; 745 StreamBuilder m(this, type, type, type); 746 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); 747 Stream s = m.Build(); 748 ASSERT_EQ(1U, s.size()); 749 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 750 EXPECT_EQ(2U, s[0]->InputCount()); 751 EXPECT_EQ(1U, s[0]->OutputCount()); 752 } 753 754 755 TEST_P(InstructionSelectorShiftTest, Immediate) { 756 const MachInst2 dpi = GetParam(); 757 const MachineType type = dpi.machine_type; 758 TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) { 759 StreamBuilder m(this, type, type); 760 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); 761 Stream s = m.Build(); 762 ASSERT_EQ(1U, s.size()); 763 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 764 EXPECT_EQ(2U, s[0]->InputCount()); 765 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 766 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 767 EXPECT_EQ(1U, s[0]->OutputCount()); 768 } 769 } 770 771 772 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest, 773 ::testing::ValuesIn(kShiftInstructions)); 774 775 776 // ----------------------------------------------------------------------------- 777 // Mul and Div instructions. 778 779 780 typedef InstructionSelectorTestWithParam<MachInst2> 781 InstructionSelectorMulDivTest; 782 783 784 TEST_P(InstructionSelectorMulDivTest, Parameter) { 785 const MachInst2 dpi = GetParam(); 786 const MachineType type = dpi.machine_type; 787 StreamBuilder m(this, type, type, type); 788 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); 789 Stream s = m.Build(); 790 ASSERT_EQ(1U, s.size()); 791 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 792 EXPECT_EQ(2U, s[0]->InputCount()); 793 EXPECT_EQ(1U, s[0]->OutputCount()); 794 } 795 796 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest, 797 ::testing::ValuesIn(kMulDivInstructions)); 798 799 800 // ----------------------------------------------------------------------------- 801 // Floating point instructions. 802 803 typedef InstructionSelectorTestWithParam<MachInst2> 804 InstructionSelectorFPArithTest; 805 806 807 TEST_P(InstructionSelectorFPArithTest, Parameter) { 808 const MachInst2 fpa = GetParam(); 809 StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type); 810 m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1))); 811 Stream s = m.Build(); 812 ASSERT_EQ(1U, s.size()); 813 EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode()); 814 EXPECT_EQ(2U, s[0]->InputCount()); 815 EXPECT_EQ(1U, s[0]->OutputCount()); 816 } 817 818 819 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest, 820 ::testing::ValuesIn(kFPArithInstructions)); 821 822 823 typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest; 824 825 826 TEST_P(InstructionSelectorFPCmpTest, Parameter) { 827 const FPCmp cmp = GetParam(); 828 StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type); 829 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1))); 830 Stream s = m.Build(); 831 ASSERT_EQ(1U, s.size()); 832 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); 833 EXPECT_EQ(2U, s[0]->InputCount()); 834 EXPECT_EQ(1U, s[0]->OutputCount()); 835 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 836 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 837 } 838 839 840 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest, 841 ::testing::ValuesIn(kFPCmpInstructions)); 842 843 844 // ----------------------------------------------------------------------------- 845 // Conversions. 846 847 typedef InstructionSelectorTestWithParam<Conversion> 848 InstructionSelectorConversionTest; 849 850 851 TEST_P(InstructionSelectorConversionTest, Parameter) { 852 const Conversion conv = GetParam(); 853 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type); 854 m.Return((m.*conv.mi.constructor)(m.Parameter(0))); 855 Stream s = m.Build(); 856 ASSERT_EQ(1U, s.size()); 857 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode()); 858 EXPECT_EQ(1U, s[0]->InputCount()); 859 EXPECT_EQ(1U, s[0]->OutputCount()); 860 } 861 862 863 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 864 InstructionSelectorConversionTest, 865 ::testing::ValuesIn(kConversionInstructions)); 866 867 868 // ----------------------------------------------------------------------------- 869 // Memory access instructions. 870 871 872 namespace { 873 874 struct MemoryAccess { 875 MachineType type; 876 ArchOpcode ldr_opcode; 877 ArchOpcode str_opcode; 878 const int32_t immediates[20]; 879 }; 880 881 882 std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { 883 OStringStream ost; 884 ost << memacc.type; 885 return os << ost.c_str(); 886 } 887 888 } // namespace 889 890 891 static const MemoryAccess kMemoryAccesses[] = { 892 {kMachInt8, kArm64Ldrsb, kArm64Strb, 893 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 894 2121, 2442, 4093, 4094, 4095}}, 895 {kMachUint8, kArm64Ldrb, kArm64Strb, 896 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 897 2121, 2442, 4093, 4094, 4095}}, 898 {kMachInt16, kArm64Ldrsh, kArm64Strh, 899 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 900 4100, 4242, 6786, 8188, 8190}}, 901 {kMachUint16, kArm64Ldrh, kArm64Strh, 902 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 903 4100, 4242, 6786, 8188, 8190}}, 904 {kMachInt32, kArm64LdrW, kArm64StrW, 905 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 906 8196, 3276, 3280, 16376, 16380}}, 907 {kMachUint32, kArm64LdrW, kArm64StrW, 908 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 909 8196, 3276, 3280, 16376, 16380}}, 910 {kMachInt64, kArm64Ldr, kArm64Str, 911 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 912 8200, 16384, 16392, 32752, 32760}}, 913 {kMachUint64, kArm64Ldr, kArm64Str, 914 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 915 8200, 16384, 16392, 32752, 32760}}, 916 {kMachFloat32, kArm64LdrS, kArm64StrS, 917 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 918 8196, 3276, 3280, 16376, 16380}}, 919 {kMachFloat64, kArm64LdrD, kArm64StrD, 920 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 921 8200, 16384, 16392, 32752, 32760}}}; 922 923 924 typedef InstructionSelectorTestWithParam<MemoryAccess> 925 InstructionSelectorMemoryAccessTest; 926 927 928 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { 929 const MemoryAccess memacc = GetParam(); 930 StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); 931 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); 932 Stream s = m.Build(); 933 ASSERT_EQ(1U, s.size()); 934 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); 935 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 936 EXPECT_EQ(2U, s[0]->InputCount()); 937 EXPECT_EQ(1U, s[0]->OutputCount()); 938 } 939 940 941 TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) { 942 const MemoryAccess memacc = GetParam(); 943 TRACED_FOREACH(int32_t, index, memacc.immediates) { 944 StreamBuilder m(this, memacc.type, kMachPtr); 945 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); 946 Stream s = m.Build(); 947 ASSERT_EQ(1U, s.size()); 948 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); 949 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 950 EXPECT_EQ(2U, s[0]->InputCount()); 951 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 952 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); 953 ASSERT_EQ(1U, s[0]->OutputCount()); 954 } 955 } 956 957 958 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { 959 const MemoryAccess memacc = GetParam(); 960 StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); 961 m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); 962 m.Return(m.Int32Constant(0)); 963 Stream s = m.Build(); 964 ASSERT_EQ(1U, s.size()); 965 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 966 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 967 EXPECT_EQ(3U, s[0]->InputCount()); 968 EXPECT_EQ(0U, s[0]->OutputCount()); 969 } 970 971 972 TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) { 973 const MemoryAccess memacc = GetParam(); 974 TRACED_FOREACH(int32_t, index, memacc.immediates) { 975 StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type); 976 m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index), 977 m.Parameter(1)); 978 m.Return(m.Int32Constant(0)); 979 Stream s = m.Build(); 980 ASSERT_EQ(1U, s.size()); 981 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 982 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 983 ASSERT_EQ(3U, s[0]->InputCount()); 984 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 985 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); 986 EXPECT_EQ(0U, s[0]->OutputCount()); 987 } 988 } 989 990 991 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 992 InstructionSelectorMemoryAccessTest, 993 ::testing::ValuesIn(kMemoryAccesses)); 994 995 996 // ----------------------------------------------------------------------------- 997 // Comparison instructions. 998 999 static const MachInst2 kComparisonInstructions[] = { 1000 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32}, 1001 {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64}, 1002 }; 1003 1004 1005 typedef InstructionSelectorTestWithParam<MachInst2> 1006 InstructionSelectorComparisonTest; 1007 1008 1009 TEST_P(InstructionSelectorComparisonTest, WithParameters) { 1010 const MachInst2 cmp = GetParam(); 1011 const MachineType type = cmp.machine_type; 1012 StreamBuilder m(this, type, type, type); 1013 m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1))); 1014 Stream s = m.Build(); 1015 ASSERT_EQ(1U, s.size()); 1016 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); 1017 EXPECT_EQ(2U, s[0]->InputCount()); 1018 EXPECT_EQ(1U, s[0]->OutputCount()); 1019 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1020 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1021 } 1022 1023 1024 TEST_P(InstructionSelectorComparisonTest, WithImmediate) { 1025 const MachInst2 cmp = GetParam(); 1026 const MachineType type = cmp.machine_type; 1027 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1028 // Compare with 0 are turned into tst instruction. 1029 if (imm == 0) continue; 1030 StreamBuilder m(this, type, type); 1031 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); 1032 Stream s = m.Build(); 1033 ASSERT_EQ(1U, s.size()); 1034 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); 1035 ASSERT_EQ(2U, s[0]->InputCount()); 1036 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1037 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 1038 EXPECT_EQ(1U, s[0]->OutputCount()); 1039 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1040 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1041 } 1042 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1043 // Compare with 0 are turned into tst instruction. 1044 if (imm == 0) continue; 1045 StreamBuilder m(this, type, type); 1046 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); 1047 Stream s = m.Build(); 1048 ASSERT_EQ(1U, s.size()); 1049 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); 1050 ASSERT_EQ(2U, s[0]->InputCount()); 1051 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1052 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 1053 EXPECT_EQ(1U, s[0]->OutputCount()); 1054 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1055 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1056 } 1057 } 1058 1059 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 1060 InstructionSelectorComparisonTest, 1061 ::testing::ValuesIn(kComparisonInstructions)); 1062 1063 1064 TEST_F(InstructionSelectorTest, Word32EqualWithZero) { 1065 { 1066 StreamBuilder m(this, kMachInt32, kMachInt32); 1067 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); 1068 Stream s = m.Build(); 1069 ASSERT_EQ(1U, s.size()); 1070 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 1071 ASSERT_EQ(2U, s[0]->InputCount()); 1072 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 1073 EXPECT_EQ(1U, s[0]->OutputCount()); 1074 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1075 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1076 } 1077 { 1078 StreamBuilder m(this, kMachInt32, kMachInt32); 1079 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); 1080 Stream s = m.Build(); 1081 ASSERT_EQ(1U, s.size()); 1082 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 1083 ASSERT_EQ(2U, s[0]->InputCount()); 1084 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 1085 EXPECT_EQ(1U, s[0]->OutputCount()); 1086 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1087 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1088 } 1089 } 1090 1091 1092 TEST_F(InstructionSelectorTest, Word64EqualWithZero) { 1093 { 1094 StreamBuilder m(this, kMachInt64, kMachInt64); 1095 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0))); 1096 Stream s = m.Build(); 1097 ASSERT_EQ(1U, s.size()); 1098 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); 1099 ASSERT_EQ(2U, s[0]->InputCount()); 1100 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 1101 EXPECT_EQ(1U, s[0]->OutputCount()); 1102 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1103 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1104 } 1105 { 1106 StreamBuilder m(this, kMachInt64, kMachInt64); 1107 m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0))); 1108 Stream s = m.Build(); 1109 ASSERT_EQ(1U, s.size()); 1110 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); 1111 ASSERT_EQ(2U, s[0]->InputCount()); 1112 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 1113 EXPECT_EQ(1U, s[0]->OutputCount()); 1114 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1115 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1116 } 1117 } 1118 1119 } // namespace compiler 1120 } // namespace internal 1121 } // namespace v8 1122