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 7namespace v8 { 8namespace internal { 9namespace compiler { 10 11namespace { 12 13template <typename T> 14struct MachInst { 15 T constructor; 16 const char* constructor_name; 17 ArchOpcode arch_opcode; 18 MachineType machine_type; 19}; 20 21typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1; 22typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2; 23 24 25template <typename T> 26std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) { 27 return os << mi.constructor_name; 28} 29 30 31struct Shift { 32 MachInst2 mi; 33 AddressingMode mode; 34}; 35 36 37std::ostream& operator<<(std::ostream& os, const Shift& shift) { 38 return os << shift.mi; 39} 40 41 42// Helper to build Int32Constant or Int64Constant depending on the given 43// machine type. 44Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type, 45 int64_t value) { 46 switch (type.representation()) { 47 case MachineRepresentation::kWord32: 48 return m.Int32Constant(static_cast<int32_t>(value)); 49 break; 50 51 case MachineRepresentation::kWord64: 52 return m.Int64Constant(value); 53 break; 54 55 default: 56 UNIMPLEMENTED(); 57 } 58 return NULL; 59} 60 61 62// ARM64 logical instructions. 63const MachInst2 kLogicalInstructions[] = { 64 {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, 65 MachineType::Int32()}, 66 {&RawMachineAssembler::Word64And, "Word64And", kArm64And, 67 MachineType::Int64()}, 68 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, 69 MachineType::Int32()}, 70 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, 71 MachineType::Int64()}, 72 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32, 73 MachineType::Int32()}, 74 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, 75 MachineType::Int64()}}; 76 77 78// ARM64 logical immediates: contiguous set bits, rotated about a power of two 79// sized block. The block is then duplicated across the word. Below is a random 80// subset of the 32-bit immediates. 81const uint32_t kLogical32Immediates[] = { 82 0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0, 83 0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000, 84 0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000, 85 0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000, 86 0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc, 87 0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe, 88 0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80, 89 0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0, 90 0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff, 91 0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff, 92 0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff, 93 0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff, 94 0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000, 95 0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf, 96 0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff, 97 0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff, 98 0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff}; 99 100 101// Random subset of 64-bit logical immediates. 102const uint64_t kLogical64Immediates[] = { 103 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 104 0x0000000000000070, 0x0000000000000080, 0x0000000000000100, 105 0x00000000000001c0, 0x0000000000000300, 0x0000000000000600, 106 0x00000000000007e0, 0x0000000000003ffc, 0x0000000000007fc0, 107 0x0000000600000000, 0x0000003ffffffffc, 0x000000f000000000, 108 0x000001f800000000, 0x0003fc0000000000, 0x0003fc000003fc00, 109 0x0003ffffffc00000, 0x0003ffffffffffc0, 0x0006000000060000, 110 0x003ffffffffc0000, 0x0180018001800180, 0x01f801f801f801f8, 111 0x0600000000000000, 0x1000000010000000, 0x1000100010001000, 112 0x1010101010101010, 0x1111111111111111, 0x1f001f001f001f00, 113 0x1f1f1f1f1f1f1f1f, 0x1ffffffffffffffe, 0x3ffc3ffc3ffc3ffc, 114 0x5555555555555555, 0x7f7f7f7f7f7f7f7f, 0x8000000000000000, 115 0x8000001f8000001f, 0x8181818181818181, 0x9999999999999999, 116 0x9fff9fff9fff9fff, 0xaaaaaaaaaaaaaaaa, 0xdddddddddddddddd, 117 0xe0000000000001ff, 0xf800000000000000, 0xf8000000000001ff, 118 0xf807f807f807f807, 0xfefefefefefefefe, 0xfffefffefffefffe, 119 0xfffff807fffff807, 0xfffff9fffffff9ff, 0xfffffc0ffffffc0f, 120 0xfffffc0fffffffff, 0xfffffefffffffeff, 0xfffffeffffffffff, 121 0xffffff8000000000, 0xfffffffefffffffe, 0xffffffffefffffff, 122 0xfffffffff9ffffff, 0xffffffffff800000, 0xffffffffffffc0ff, 123 0xfffffffffffffffe}; 124 125 126// ARM64 arithmetic instructions. 127struct AddSub { 128 MachInst2 mi; 129 ArchOpcode negate_arch_opcode; 130}; 131 132 133std::ostream& operator<<(std::ostream& os, const AddSub& op) { 134 return os << op.mi; 135} 136 137 138const AddSub kAddSubInstructions[] = { 139 {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, 140 MachineType::Int32()}, 141 kArm64Sub32}, 142 {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, 143 MachineType::Int64()}, 144 kArm64Sub}, 145 {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, 146 MachineType::Int32()}, 147 kArm64Add32}, 148 {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, 149 MachineType::Int64()}, 150 kArm64Add}}; 151 152 153// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12. 154// Below is a combination of a random subset and some edge values. 155const int32_t kAddSubImmediates[] = { 156 0, 1, 69, 493, 599, 701, 719, 157 768, 818, 842, 945, 1246, 1286, 1429, 158 1669, 2171, 2179, 2182, 2254, 2334, 2338, 159 2343, 2396, 2449, 2610, 2732, 2855, 2876, 160 2944, 3377, 3458, 3475, 3476, 3540, 3574, 161 3601, 3813, 3871, 3917, 4095, 4096, 16384, 162 364544, 462848, 970752, 1523712, 1863680, 2363392, 3219456, 163 3280896, 4247552, 4526080, 4575232, 4960256, 5505024, 5894144, 164 6004736, 6193152, 6385664, 6795264, 7114752, 7233536, 7348224, 165 7499776, 7573504, 7729152, 8634368, 8937472, 9465856, 10354688, 166 10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224, 167 15597568, 15892480, 16773120}; 168 169 170// ARM64 flag setting data processing instructions. 171const MachInst2 kDPFlagSetInstructions[] = { 172 {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, 173 MachineType::Int32()}, 174 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, 175 MachineType::Int32()}, 176 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, 177 MachineType::Int32()}, 178 {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst, 179 MachineType::Int64()}}; 180 181 182// ARM64 arithmetic with overflow instructions. 183const MachInst2 kOvfAddSubInstructions[] = { 184 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow", 185 kArm64Add32, MachineType::Int32()}, 186 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow", 187 kArm64Sub32, MachineType::Int32()}, 188 {&RawMachineAssembler::Int64AddWithOverflow, "Int64AddWithOverflow", 189 kArm64Add, MachineType::Int64()}, 190 {&RawMachineAssembler::Int64SubWithOverflow, "Int64SubWithOverflow", 191 kArm64Sub, MachineType::Int64()}}; 192 193// ARM64 shift instructions. 194const Shift kShiftInstructions[] = { 195 {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, 196 MachineType::Int32()}, 197 kMode_Operand2_R_LSL_I}, 198 {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, 199 MachineType::Int64()}, 200 kMode_Operand2_R_LSL_I}, 201 {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, 202 MachineType::Int32()}, 203 kMode_Operand2_R_LSR_I}, 204 {{&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr, 205 MachineType::Int64()}, 206 kMode_Operand2_R_LSR_I}, 207 {{&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, 208 MachineType::Int32()}, 209 kMode_Operand2_R_ASR_I}, 210 {{&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr, 211 MachineType::Int64()}, 212 kMode_Operand2_R_ASR_I}, 213 {{&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, 214 MachineType::Int32()}, 215 kMode_Operand2_R_ROR_I}, 216 {{&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, 217 MachineType::Int64()}, 218 kMode_Operand2_R_ROR_I}}; 219 220 221// ARM64 Mul/Div instructions. 222const MachInst2 kMulDivInstructions[] = { 223 {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, 224 MachineType::Int32()}, 225 {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, 226 MachineType::Int64()}, 227 {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, 228 MachineType::Int32()}, 229 {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, 230 MachineType::Int64()}, 231 {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32, 232 MachineType::Int32()}, 233 {&RawMachineAssembler::Uint64Div, "Uint64Div", kArm64Udiv, 234 MachineType::Int64()}}; 235 236 237// ARM64 FP arithmetic instructions. 238const MachInst2 kFPArithInstructions[] = { 239 {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add, 240 MachineType::Float64()}, 241 {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub, 242 MachineType::Float64()}, 243 {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul, 244 MachineType::Float64()}, 245 {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div, 246 MachineType::Float64()}}; 247 248 249struct FPCmp { 250 MachInst2 mi; 251 FlagsCondition cond; 252 FlagsCondition commuted_cond; 253}; 254 255 256std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) { 257 return os << cmp.mi; 258} 259 260 261// ARM64 FP comparison instructions. 262const FPCmp kFPCmpInstructions[] = { 263 {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp, 264 MachineType::Float64()}, 265 kEqual, 266 kEqual}, 267 {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", 268 kArm64Float64Cmp, MachineType::Float64()}, 269 kFloatLessThan, 270 kFloatGreaterThan}, 271 {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual", 272 kArm64Float64Cmp, MachineType::Float64()}, 273 kFloatLessThanOrEqual, 274 kFloatGreaterThanOrEqual}, 275 {{&RawMachineAssembler::Float32Equal, "Float32Equal", kArm64Float32Cmp, 276 MachineType::Float32()}, 277 kEqual, 278 kEqual}, 279 {{&RawMachineAssembler::Float32LessThan, "Float32LessThan", 280 kArm64Float32Cmp, MachineType::Float32()}, 281 kFloatLessThan, 282 kFloatGreaterThan}, 283 {{&RawMachineAssembler::Float32LessThanOrEqual, "Float32LessThanOrEqual", 284 kArm64Float32Cmp, MachineType::Float32()}, 285 kFloatLessThanOrEqual, 286 kFloatGreaterThanOrEqual}}; 287 288 289struct Conversion { 290 // The machine_type field in MachInst1 represents the destination type. 291 MachInst1 mi; 292 MachineType src_machine_type; 293}; 294 295 296std::ostream& operator<<(std::ostream& os, const Conversion& conv) { 297 return os << conv.mi; 298} 299 300 301// ARM64 type conversion instructions. 302const Conversion kConversionInstructions[] = { 303 {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64", 304 kArm64Float32ToFloat64, MachineType::Float64()}, 305 MachineType::Float32()}, 306 {{&RawMachineAssembler::TruncateFloat64ToFloat32, 307 "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, 308 MachineType::Float32()}, 309 MachineType::Float64()}, 310 {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64", 311 kArm64Sxtw, MachineType::Int64()}, 312 MachineType::Int32()}, 313 {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64", 314 kArm64Mov32, MachineType::Uint64()}, 315 MachineType::Uint32()}, 316 {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32", 317 kArm64Mov32, MachineType::Int32()}, 318 MachineType::Int64()}, 319 {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64", 320 kArm64Int32ToFloat64, MachineType::Float64()}, 321 MachineType::Int32()}, 322 {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64", 323 kArm64Uint32ToFloat64, MachineType::Float64()}, 324 MachineType::Uint32()}, 325 {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32", 326 kArm64Float64ToInt32, MachineType::Int32()}, 327 MachineType::Float64()}, 328 {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32", 329 kArm64Float64ToUint32, MachineType::Uint32()}, 330 MachineType::Float64()}}; 331 332// ARM64 instructions that clear the top 32 bits of the destination. 333const MachInst2 kCanElideChangeUint32ToUint64[] = { 334 {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, 335 MachineType::Uint32()}, 336 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, 337 MachineType::Uint32()}, 338 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32, 339 MachineType::Uint32()}, 340 {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, 341 MachineType::Uint32()}, 342 {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, 343 MachineType::Uint32()}, 344 {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, 345 MachineType::Uint32()}, 346 {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, 347 MachineType::Uint32()}, 348 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, 349 MachineType::Uint32()}, 350 {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, 351 MachineType::Int32()}, 352 {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow", 353 kArm64Add32, MachineType::Int32()}, 354 {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, 355 MachineType::Int32()}, 356 {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow", 357 kArm64Sub32, MachineType::Int32()}, 358 {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, 359 MachineType::Int32()}, 360 {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, 361 MachineType::Int32()}, 362 {&RawMachineAssembler::Int32Mod, "Int32Mod", kArm64Imod32, 363 MachineType::Int32()}, 364 {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32, 365 MachineType::Int32()}, 366 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual", 367 kArm64Cmp32, MachineType::Int32()}, 368 {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32, 369 MachineType::Uint32()}, 370 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32, 371 MachineType::Uint32()}, 372 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual", 373 kArm64Cmp32, MachineType::Uint32()}, 374 {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kArm64Umod32, 375 MachineType::Uint32()}, 376}; 377 378} // namespace 379 380 381// ----------------------------------------------------------------------------- 382// Logical instructions. 383 384 385typedef InstructionSelectorTestWithParam<MachInst2> 386 InstructionSelectorLogicalTest; 387 388 389TEST_P(InstructionSelectorLogicalTest, Parameter) { 390 const MachInst2 dpi = GetParam(); 391 const MachineType type = dpi.machine_type; 392 StreamBuilder m(this, type, type, type); 393 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); 394 Stream s = m.Build(); 395 ASSERT_EQ(1U, s.size()); 396 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 397 EXPECT_EQ(2U, s[0]->InputCount()); 398 EXPECT_EQ(1U, s[0]->OutputCount()); 399} 400 401 402TEST_P(InstructionSelectorLogicalTest, Immediate) { 403 const MachInst2 dpi = GetParam(); 404 const MachineType type = dpi.machine_type; 405 // TODO(all): Add support for testing 64-bit immediates. 406 if (type == MachineType::Int32()) { 407 // Immediate on the right. 408 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { 409 StreamBuilder m(this, type, type); 410 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); 411 Stream s = m.Build(); 412 ASSERT_EQ(1U, s.size()); 413 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 414 ASSERT_EQ(2U, s[0]->InputCount()); 415 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 416 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 417 EXPECT_EQ(1U, s[0]->OutputCount()); 418 } 419 420 // Immediate on the left; all logical ops should commute. 421 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { 422 StreamBuilder m(this, type, type); 423 m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0))); 424 Stream s = m.Build(); 425 ASSERT_EQ(1U, s.size()); 426 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 427 ASSERT_EQ(2U, s[0]->InputCount()); 428 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 429 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 430 EXPECT_EQ(1U, s[0]->OutputCount()); 431 } 432 } 433} 434 435 436TEST_P(InstructionSelectorLogicalTest, ShiftByImmediate) { 437 const MachInst2 dpi = GetParam(); 438 const MachineType type = dpi.machine_type; 439 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 440 // Only test 64-bit shifted operands with 64-bit instructions. 441 if (shift.mi.machine_type != type) continue; 442 443 TRACED_FORRANGE(int, imm, 0, ((type == MachineType::Int32()) ? 31 : 63)) { 444 StreamBuilder m(this, type, type, type); 445 m.Return((m.*dpi.constructor)( 446 m.Parameter(0), 447 (m.*shift.mi.constructor)(m.Parameter(1), 448 BuildConstant(m, type, imm)))); 449 Stream s = m.Build(); 450 ASSERT_EQ(1U, s.size()); 451 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 452 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 453 EXPECT_EQ(3U, s[0]->InputCount()); 454 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 455 EXPECT_EQ(1U, s[0]->OutputCount()); 456 } 457 458 TRACED_FORRANGE(int, imm, 0, ((type == MachineType::Int32()) ? 31 : 63)) { 459 StreamBuilder m(this, type, type, type); 460 m.Return((m.*dpi.constructor)( 461 (m.*shift.mi.constructor)(m.Parameter(1), 462 BuildConstant(m, type, imm)), 463 m.Parameter(0))); 464 Stream s = m.Build(); 465 ASSERT_EQ(1U, s.size()); 466 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 467 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 468 EXPECT_EQ(3U, s[0]->InputCount()); 469 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 470 EXPECT_EQ(1U, s[0]->OutputCount()); 471 } 472 } 473} 474 475 476INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest, 477 ::testing::ValuesIn(kLogicalInstructions)); 478 479 480// ----------------------------------------------------------------------------- 481// Add and Sub instructions. 482 483typedef InstructionSelectorTestWithParam<AddSub> InstructionSelectorAddSubTest; 484 485 486TEST_P(InstructionSelectorAddSubTest, Parameter) { 487 const AddSub dpi = GetParam(); 488 const MachineType type = dpi.mi.machine_type; 489 StreamBuilder m(this, type, type, type); 490 m.Return((m.*dpi.mi.constructor)(m.Parameter(0), m.Parameter(1))); 491 Stream s = m.Build(); 492 ASSERT_EQ(1U, s.size()); 493 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 494 EXPECT_EQ(2U, s[0]->InputCount()); 495 EXPECT_EQ(1U, s[0]->OutputCount()); 496} 497 498 499TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) { 500 const AddSub dpi = GetParam(); 501 const MachineType type = dpi.mi.machine_type; 502 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 503 StreamBuilder m(this, type, type); 504 m.Return( 505 (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); 506 Stream s = m.Build(); 507 ASSERT_EQ(1U, s.size()); 508 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 509 ASSERT_EQ(2U, s[0]->InputCount()); 510 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 511 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 512 EXPECT_EQ(1U, s[0]->OutputCount()); 513 } 514} 515 516 517TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) { 518 const AddSub dpi = GetParam(); 519 const MachineType type = dpi.mi.machine_type; 520 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 521 if (imm == 0) continue; 522 StreamBuilder m(this, type, type); 523 m.Return( 524 (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, -imm))); 525 Stream s = m.Build(); 526 ASSERT_EQ(1U, s.size()); 527 EXPECT_EQ(dpi.negate_arch_opcode, s[0]->arch_opcode()); 528 ASSERT_EQ(2U, s[0]->InputCount()); 529 ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate()); 530 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 531 EXPECT_EQ(1U, s[0]->OutputCount()); 532 } 533} 534 535 536TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) { 537 const AddSub dpi = GetParam(); 538 const MachineType type = dpi.mi.machine_type; 539 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 540 // Only test 64-bit shifted operands with 64-bit instructions. 541 if (shift.mi.machine_type != type) continue; 542 543 if ((shift.mi.arch_opcode == kArm64Ror32) || 544 (shift.mi.arch_opcode == kArm64Ror)) { 545 // Not supported by add/sub instructions. 546 continue; 547 } 548 549 TRACED_FORRANGE(int, imm, 0, ((type == MachineType::Int32()) ? 31 : 63)) { 550 StreamBuilder m(this, type, type, type); 551 m.Return((m.*dpi.mi.constructor)( 552 m.Parameter(0), 553 (m.*shift.mi.constructor)(m.Parameter(1), 554 BuildConstant(m, type, imm)))); 555 Stream s = m.Build(); 556 ASSERT_EQ(1U, s.size()); 557 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 558 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 559 EXPECT_EQ(3U, s[0]->InputCount()); 560 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 561 EXPECT_EQ(1U, s[0]->OutputCount()); 562 } 563 } 564} 565 566 567TEST_P(InstructionSelectorAddSubTest, UnsignedExtendByte) { 568 const AddSub dpi = GetParam(); 569 const MachineType type = dpi.mi.machine_type; 570 StreamBuilder m(this, type, type, type); 571 m.Return((m.*dpi.mi.constructor)( 572 m.Parameter(0), m.Word32And(m.Parameter(1), m.Int32Constant(0xff)))); 573 Stream s = m.Build(); 574 ASSERT_EQ(1U, s.size()); 575 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 576 EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); 577 ASSERT_EQ(2U, s[0]->InputCount()); 578 ASSERT_EQ(1U, s[0]->OutputCount()); 579} 580 581 582TEST_P(InstructionSelectorAddSubTest, UnsignedExtendHalfword) { 583 const AddSub dpi = GetParam(); 584 const MachineType type = dpi.mi.machine_type; 585 StreamBuilder m(this, type, type, type); 586 m.Return((m.*dpi.mi.constructor)( 587 m.Parameter(0), m.Word32And(m.Parameter(1), m.Int32Constant(0xffff)))); 588 Stream s = m.Build(); 589 ASSERT_EQ(1U, s.size()); 590 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 591 EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); 592 ASSERT_EQ(2U, s[0]->InputCount()); 593 ASSERT_EQ(1U, s[0]->OutputCount()); 594} 595 596 597TEST_P(InstructionSelectorAddSubTest, SignedExtendByte) { 598 const AddSub dpi = GetParam(); 599 const MachineType type = dpi.mi.machine_type; 600 StreamBuilder m(this, type, type, type); 601 m.Return((m.*dpi.mi.constructor)( 602 m.Parameter(0), 603 m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(24)), 604 m.Int32Constant(24)))); 605 Stream s = m.Build(); 606 ASSERT_EQ(1U, s.size()); 607 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 608 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 609 ASSERT_EQ(2U, s[0]->InputCount()); 610 ASSERT_EQ(1U, s[0]->OutputCount()); 611} 612 613 614TEST_P(InstructionSelectorAddSubTest, SignedExtendHalfword) { 615 const AddSub dpi = GetParam(); 616 const MachineType type = dpi.mi.machine_type; 617 StreamBuilder m(this, type, type, type); 618 m.Return((m.*dpi.mi.constructor)( 619 m.Parameter(0), 620 m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(16)), 621 m.Int32Constant(16)))); 622 Stream s = m.Build(); 623 ASSERT_EQ(1U, s.size()); 624 EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); 625 EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); 626 ASSERT_EQ(2U, s[0]->InputCount()); 627 ASSERT_EQ(1U, s[0]->OutputCount()); 628} 629 630 631INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, 632 ::testing::ValuesIn(kAddSubInstructions)); 633 634 635TEST_F(InstructionSelectorTest, AddImmediateOnLeft) { 636 { 637 // 32-bit add. 638 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 639 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 640 m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0))); 641 Stream s = m.Build(); 642 ASSERT_EQ(1U, s.size()); 643 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 644 ASSERT_EQ(2U, s[0]->InputCount()); 645 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 646 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 647 EXPECT_EQ(1U, s[0]->OutputCount()); 648 } 649 } 650 { 651 // 64-bit add. 652 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 653 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 654 m.Return(m.Int64Add(m.Int64Constant(imm), m.Parameter(0))); 655 Stream s = m.Build(); 656 ASSERT_EQ(1U, s.size()); 657 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 658 ASSERT_EQ(2U, s[0]->InputCount()); 659 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 660 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 661 EXPECT_EQ(1U, s[0]->OutputCount()); 662 } 663 } 664} 665 666 667TEST_F(InstructionSelectorTest, SubZeroOnLeft) { 668 { 669 // 32-bit subtract. 670 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 671 MachineType::Int32()); 672 m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0))); 673 Stream s = m.Build(); 674 675 ASSERT_EQ(1U, s.size()); 676 EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode()); 677 ASSERT_EQ(2U, s[0]->InputCount()); 678 EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate()); 679 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(0))); 680 EXPECT_EQ(1U, s[0]->OutputCount()); 681 } 682 { 683 // 64-bit subtract. 684 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 685 MachineType::Int64()); 686 m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0))); 687 Stream s = m.Build(); 688 689 ASSERT_EQ(1U, s.size()); 690 EXPECT_EQ(kArm64Sub, s[0]->arch_opcode()); 691 ASSERT_EQ(2U, s[0]->InputCount()); 692 EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate()); 693 EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(0))); 694 EXPECT_EQ(1U, s[0]->OutputCount()); 695 } 696} 697 698 699TEST_F(InstructionSelectorTest, SubZeroOnLeftWithShift) { 700 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 701 { 702 // Test 32-bit operations. Ignore ROR shifts, as subtract does not 703 // support them. 704 if ((shift.mi.machine_type != MachineType::Int32()) || 705 (shift.mi.arch_opcode == kArm64Ror32) || 706 (shift.mi.arch_opcode == kArm64Ror)) 707 continue; 708 709 TRACED_FORRANGE(int, imm, -32, 63) { 710 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 711 MachineType::Int32()); 712 m.Return(m.Int32Sub( 713 m.Int32Constant(0), 714 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)))); 715 Stream s = m.Build(); 716 717 ASSERT_EQ(1U, s.size()); 718 EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode()); 719 ASSERT_EQ(3U, s[0]->InputCount()); 720 EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate()); 721 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(0))); 722 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 723 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); 724 EXPECT_EQ(1U, s[0]->OutputCount()); 725 } 726 } 727 { 728 // Test 64-bit operations. Ignore ROR shifts, as subtract does not 729 // support them. 730 if ((shift.mi.machine_type != MachineType::Int64()) || 731 (shift.mi.arch_opcode == kArm64Ror32) || 732 (shift.mi.arch_opcode == kArm64Ror)) 733 continue; 734 735 TRACED_FORRANGE(int, imm, -32, 127) { 736 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 737 MachineType::Int64()); 738 m.Return(m.Int64Sub( 739 m.Int64Constant(0), 740 (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)))); 741 Stream s = m.Build(); 742 743 ASSERT_EQ(1U, s.size()); 744 EXPECT_EQ(kArm64Sub, s[0]->arch_opcode()); 745 ASSERT_EQ(3U, s[0]->InputCount()); 746 EXPECT_TRUE(s[0]->InputAt(0)->IsImmediate()); 747 EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(0))); 748 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 749 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); 750 EXPECT_EQ(1U, s[0]->OutputCount()); 751 } 752 } 753 } 754} 755 756 757TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) { 758 { 759 // 32-bit add. 760 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 761 if (imm == 0) continue; 762 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 763 m.Return(m.Int32Add(m.Int32Constant(-imm), m.Parameter(0))); 764 Stream s = m.Build(); 765 766 ASSERT_EQ(1U, s.size()); 767 EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode()); 768 ASSERT_EQ(2U, s[0]->InputCount()); 769 ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate()); 770 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 771 EXPECT_EQ(1U, s[0]->OutputCount()); 772 } 773 } 774 { 775 // 64-bit add. 776 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 777 if (imm == 0) continue; 778 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 779 m.Return(m.Int64Add(m.Int64Constant(-imm), m.Parameter(0))); 780 Stream s = m.Build(); 781 782 ASSERT_EQ(1U, s.size()); 783 EXPECT_EQ(kArm64Sub, s[0]->arch_opcode()); 784 ASSERT_EQ(2U, s[0]->InputCount()); 785 ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate()); 786 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 787 EXPECT_EQ(1U, s[0]->OutputCount()); 788 } 789 } 790} 791 792 793TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) { 794 // 32-bit add. 795 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 796 // Only test relevant shifted operands. 797 if (shift.mi.machine_type != MachineType::Int32()) continue; 798 if (shift.mi.arch_opcode == kArm64Ror32) continue; 799 800 // The available shift operand range is `0 <= imm < 32`, but we also test 801 // that immediates outside this range are handled properly (modulo-32). 802 TRACED_FORRANGE(int, imm, -32, 63) { 803 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 804 MachineType::Int32()); 805 m.Return((m.Int32Add)( 806 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)), 807 m.Parameter(0))); 808 Stream s = m.Build(); 809 ASSERT_EQ(1U, s.size()); 810 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 811 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 812 EXPECT_EQ(3U, s[0]->InputCount()); 813 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 814 EXPECT_EQ(1U, s[0]->OutputCount()); 815 } 816 } 817 818 // 64-bit add. 819 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 820 // Only test relevant shifted operands. 821 if (shift.mi.machine_type != MachineType::Int64()) continue; 822 if (shift.mi.arch_opcode == kArm64Ror) continue; 823 824 // The available shift operand range is `0 <= imm < 64`, but we also test 825 // that immediates outside this range are handled properly (modulo-64). 826 TRACED_FORRANGE(int, imm, -64, 127) { 827 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 828 MachineType::Int64()); 829 m.Return((m.Int64Add)( 830 (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)), 831 m.Parameter(0))); 832 Stream s = m.Build(); 833 ASSERT_EQ(1U, s.size()); 834 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 835 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 836 EXPECT_EQ(3U, s[0]->InputCount()); 837 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 838 EXPECT_EQ(1U, s[0]->OutputCount()); 839 } 840 } 841} 842 843 844TEST_F(InstructionSelectorTest, AddUnsignedExtendByteOnLeft) { 845 { 846 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 847 MachineType::Int32()); 848 m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)), 849 m.Parameter(1))); 850 Stream s = m.Build(); 851 ASSERT_EQ(1U, s.size()); 852 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 853 EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); 854 ASSERT_EQ(2U, s[0]->InputCount()); 855 ASSERT_EQ(1U, s[0]->OutputCount()); 856 } 857 { 858 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(), 859 MachineType::Int64()); 860 m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)), 861 m.Parameter(1))); 862 Stream s = m.Build(); 863 ASSERT_EQ(1U, s.size()); 864 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 865 EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); 866 ASSERT_EQ(2U, s[0]->InputCount()); 867 ASSERT_EQ(1U, s[0]->OutputCount()); 868 } 869} 870 871 872TEST_F(InstructionSelectorTest, AddUnsignedExtendHalfwordOnLeft) { 873 { 874 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 875 MachineType::Int32()); 876 m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)), 877 m.Parameter(1))); 878 Stream s = m.Build(); 879 ASSERT_EQ(1U, s.size()); 880 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 881 EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); 882 ASSERT_EQ(2U, s[0]->InputCount()); 883 ASSERT_EQ(1U, s[0]->OutputCount()); 884 } 885 { 886 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(), 887 MachineType::Int64()); 888 m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)), 889 m.Parameter(1))); 890 Stream s = m.Build(); 891 ASSERT_EQ(1U, s.size()); 892 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 893 EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); 894 ASSERT_EQ(2U, s[0]->InputCount()); 895 ASSERT_EQ(1U, s[0]->OutputCount()); 896 } 897} 898 899 900TEST_F(InstructionSelectorTest, AddSignedExtendByteOnLeft) { 901 { 902 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 903 MachineType::Int32()); 904 m.Return( 905 m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), 906 m.Int32Constant(24)), 907 m.Parameter(1))); 908 Stream s = m.Build(); 909 ASSERT_EQ(1U, s.size()); 910 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 911 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 912 ASSERT_EQ(2U, s[0]->InputCount()); 913 ASSERT_EQ(1U, s[0]->OutputCount()); 914 } 915 { 916 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(), 917 MachineType::Int64()); 918 m.Return( 919 m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), 920 m.Int32Constant(24)), 921 m.Parameter(1))); 922 Stream s = m.Build(); 923 ASSERT_EQ(1U, s.size()); 924 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 925 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 926 ASSERT_EQ(2U, s[0]->InputCount()); 927 ASSERT_EQ(1U, s[0]->OutputCount()); 928 } 929} 930 931 932TEST_F(InstructionSelectorTest, AddSignedExtendHalfwordOnLeft) { 933 { 934 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 935 MachineType::Int32()); 936 m.Return( 937 m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)), 938 m.Int32Constant(16)), 939 m.Parameter(1))); 940 Stream s = m.Build(); 941 ASSERT_EQ(1U, s.size()); 942 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 943 EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); 944 ASSERT_EQ(2U, s[0]->InputCount()); 945 ASSERT_EQ(1U, s[0]->OutputCount()); 946 } 947 { 948 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32(), 949 MachineType::Int64()); 950 m.Return( 951 m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)), 952 m.Int32Constant(16)), 953 m.Parameter(1))); 954 Stream s = m.Build(); 955 ASSERT_EQ(1U, s.size()); 956 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 957 EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); 958 ASSERT_EQ(2U, s[0]->InputCount()); 959 ASSERT_EQ(1U, s[0]->OutputCount()); 960 } 961} 962 963 964// ----------------------------------------------------------------------------- 965// Data processing controlled branches. 966 967 968typedef InstructionSelectorTestWithParam<MachInst2> 969 InstructionSelectorDPFlagSetTest; 970 971 972TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) { 973 const MachInst2 dpi = GetParam(); 974 const MachineType type = dpi.machine_type; 975 StreamBuilder m(this, type, type, type); 976 RawMachineLabel a, b; 977 m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b); 978 m.Bind(&a); 979 m.Return(m.Int32Constant(1)); 980 m.Bind(&b); 981 m.Return(m.Int32Constant(0)); 982 Stream s = m.Build(); 983 ASSERT_EQ(1U, s.size()); 984 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 985 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 986 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 987} 988 989 990INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 991 InstructionSelectorDPFlagSetTest, 992 ::testing::ValuesIn(kDPFlagSetInstructions)); 993 994 995TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnRight) { 996 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { 997 // Skip the cases where the instruction selector would use tbz/tbnz. 998 if (base::bits::CountPopulation32(imm) == 1) continue; 999 1000 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1001 RawMachineLabel a, b; 1002 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b); 1003 m.Bind(&a); 1004 m.Return(m.Int32Constant(1)); 1005 m.Bind(&b); 1006 m.Return(m.Int32Constant(0)); 1007 Stream s = m.Build(); 1008 ASSERT_EQ(1U, s.size()); 1009 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 1010 EXPECT_EQ(4U, s[0]->InputCount()); 1011 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1012 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1013 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1014 } 1015} 1016 1017 1018TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnRight) { 1019 TRACED_FOREACH(int64_t, imm, kLogical64Immediates) { 1020 // Skip the cases where the instruction selector would use tbz/tbnz. 1021 if (base::bits::CountPopulation64(imm) == 1) continue; 1022 1023 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1024 RawMachineLabel a, b; 1025 m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(imm)), &a, &b); 1026 m.Bind(&a); 1027 m.Return(m.Int32Constant(1)); 1028 m.Bind(&b); 1029 m.Return(m.Int32Constant(0)); 1030 Stream s = m.Build(); 1031 ASSERT_EQ(1U, s.size()); 1032 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); 1033 EXPECT_EQ(4U, s[0]->InputCount()); 1034 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1035 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1036 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1037 } 1038} 1039 1040 1041TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) { 1042 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1043 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1044 RawMachineLabel a, b; 1045 m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b); 1046 m.Bind(&a); 1047 m.Return(m.Int32Constant(1)); 1048 m.Bind(&b); 1049 m.Return(m.Int32Constant(0)); 1050 Stream s = m.Build(); 1051 ASSERT_EQ(1U, s.size()); 1052 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 1053 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1054 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1055 } 1056} 1057 1058 1059TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) { 1060 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1061 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1062 RawMachineLabel a, b; 1063 m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b); 1064 m.Bind(&a); 1065 m.Return(m.Int32Constant(1)); 1066 m.Bind(&b); 1067 m.Return(m.Int32Constant(0)); 1068 Stream s = m.Build(); 1069 ASSERT_EQ(1U, s.size()); 1070 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 1071 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1072 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1073 } 1074} 1075 1076 1077TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) { 1078 TRACED_FOREACH(int32_t, imm, kLogical32Immediates) { 1079 // Skip the cases where the instruction selector would use tbz/tbnz. 1080 if (base::bits::CountPopulation32(imm) == 1) continue; 1081 1082 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1083 RawMachineLabel a, b; 1084 m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b); 1085 m.Bind(&a); 1086 m.Return(m.Int32Constant(1)); 1087 m.Bind(&b); 1088 m.Return(m.Int32Constant(0)); 1089 Stream s = m.Build(); 1090 ASSERT_EQ(1U, s.size()); 1091 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 1092 EXPECT_EQ(4U, s[0]->InputCount()); 1093 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1094 ASSERT_LE(1U, s[0]->InputCount()); 1095 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1096 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1097 } 1098} 1099 1100 1101TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnLeft) { 1102 TRACED_FOREACH(int64_t, imm, kLogical64Immediates) { 1103 // Skip the cases where the instruction selector would use tbz/tbnz. 1104 if (base::bits::CountPopulation64(imm) == 1) continue; 1105 1106 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1107 RawMachineLabel a, b; 1108 m.Branch(m.Word64And(m.Int64Constant(imm), m.Parameter(0)), &a, &b); 1109 m.Bind(&a); 1110 m.Return(m.Int32Constant(1)); 1111 m.Bind(&b); 1112 m.Return(m.Int32Constant(0)); 1113 Stream s = m.Build(); 1114 ASSERT_EQ(1U, s.size()); 1115 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); 1116 EXPECT_EQ(4U, s[0]->InputCount()); 1117 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1118 ASSERT_LE(1U, s[0]->InputCount()); 1119 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1120 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1121 } 1122} 1123 1124 1125TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) { 1126 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1127 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1128 RawMachineLabel a, b; 1129 m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b); 1130 m.Bind(&a); 1131 m.Return(m.Int32Constant(1)); 1132 m.Bind(&b); 1133 m.Return(m.Int32Constant(0)); 1134 Stream s = m.Build(); 1135 ASSERT_EQ(1U, s.size()); 1136 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 1137 ASSERT_LE(1U, s[0]->InputCount()); 1138 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1139 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1140 } 1141} 1142 1143 1144TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnRight) { 1145 TRACED_FORRANGE(int, bit, 0, 31) { 1146 uint32_t mask = 1 << bit; 1147 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1148 RawMachineLabel a, b; 1149 m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(mask)), &a, &b); 1150 m.Bind(&a); 1151 m.Return(m.Int32Constant(1)); 1152 m.Bind(&b); 1153 m.Return(m.Int32Constant(0)); 1154 Stream s = m.Build(); 1155 ASSERT_EQ(1U, s.size()); 1156 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); 1157 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1158 EXPECT_EQ(4U, s[0]->InputCount()); 1159 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1160 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1))); 1161 } 1162 1163 TRACED_FORRANGE(int, bit, 0, 31) { 1164 uint32_t mask = 1 << bit; 1165 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1166 RawMachineLabel a, b; 1167 m.Branch( 1168 m.Word32BinaryNot(m.Word32And(m.Parameter(0), m.Int32Constant(mask))), 1169 &a, &b); 1170 m.Bind(&a); 1171 m.Return(m.Int32Constant(1)); 1172 m.Bind(&b); 1173 m.Return(m.Int32Constant(0)); 1174 Stream s = m.Build(); 1175 ASSERT_EQ(1U, s.size()); 1176 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); 1177 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1178 EXPECT_EQ(4U, s[0]->InputCount()); 1179 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1180 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1))); 1181 } 1182} 1183 1184TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnLeft) { 1185 TRACED_FORRANGE(int, bit, 0, 31) { 1186 uint32_t mask = 1 << bit; 1187 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1188 RawMachineLabel a, b; 1189 m.Branch(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), &a, &b); 1190 m.Bind(&a); 1191 m.Return(m.Int32Constant(1)); 1192 m.Bind(&b); 1193 m.Return(m.Int32Constant(0)); 1194 Stream s = m.Build(); 1195 ASSERT_EQ(1U, s.size()); 1196 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); 1197 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1198 EXPECT_EQ(4U, s[0]->InputCount()); 1199 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1200 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1))); 1201 } 1202 1203 TRACED_FORRANGE(int, bit, 0, 31) { 1204 uint32_t mask = 1 << bit; 1205 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1206 RawMachineLabel a, b; 1207 m.Branch( 1208 m.Word32BinaryNot(m.Word32And(m.Int32Constant(mask), m.Parameter(0))), 1209 &a, &b); 1210 m.Bind(&a); 1211 m.Return(m.Int32Constant(1)); 1212 m.Bind(&b); 1213 m.Return(m.Int32Constant(0)); 1214 Stream s = m.Build(); 1215 ASSERT_EQ(1U, s.size()); 1216 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); 1217 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1218 EXPECT_EQ(4U, s[0]->InputCount()); 1219 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1220 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1))); 1221 } 1222} 1223 1224 1225TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) { 1226 TRACED_FORRANGE(int, bit, 0, 63) { 1227 uint64_t mask = 1L << bit; 1228 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1229 RawMachineLabel a, b; 1230 m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b); 1231 m.Bind(&a); 1232 m.Return(m.Int32Constant(1)); 1233 m.Bind(&b); 1234 m.Return(m.Int32Constant(0)); 1235 Stream s = m.Build(); 1236 ASSERT_EQ(1U, s.size()); 1237 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode()); 1238 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1239 EXPECT_EQ(4U, s[0]->InputCount()); 1240 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1241 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); 1242 } 1243} 1244 1245 1246TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) { 1247 TRACED_FORRANGE(int, bit, 0, 63) { 1248 uint64_t mask = 1L << bit; 1249 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1250 RawMachineLabel a, b; 1251 m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b); 1252 m.Bind(&a); 1253 m.Return(m.Int32Constant(1)); 1254 m.Bind(&b); 1255 m.Return(m.Int32Constant(0)); 1256 Stream s = m.Build(); 1257 ASSERT_EQ(1U, s.size()); 1258 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode()); 1259 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1260 EXPECT_EQ(4U, s[0]->InputCount()); 1261 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1262 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); 1263 } 1264} 1265 1266TEST_F(InstructionSelectorTest, Word32EqualZeroAndBranchWithOneBitMask) { 1267 TRACED_FORRANGE(int, bit, 0, 31) { 1268 uint32_t mask = 1 << bit; 1269 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1270 RawMachineLabel a, b; 1271 m.Branch(m.Word32Equal(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), 1272 m.Int32Constant(0)), 1273 &a, &b); 1274 m.Bind(&a); 1275 m.Return(m.Int32Constant(1)); 1276 m.Bind(&b); 1277 m.Return(m.Int32Constant(0)); 1278 Stream s = m.Build(); 1279 ASSERT_EQ(1U, s.size()); 1280 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); 1281 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1282 EXPECT_EQ(4U, s[0]->InputCount()); 1283 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1284 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1))); 1285 } 1286 1287 TRACED_FORRANGE(int, bit, 0, 31) { 1288 uint32_t mask = 1 << bit; 1289 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1290 RawMachineLabel a, b; 1291 m.Branch( 1292 m.Word32NotEqual(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), 1293 m.Int32Constant(0)), 1294 &a, &b); 1295 m.Bind(&a); 1296 m.Return(m.Int32Constant(1)); 1297 m.Bind(&b); 1298 m.Return(m.Int32Constant(0)); 1299 Stream s = m.Build(); 1300 ASSERT_EQ(1U, s.size()); 1301 EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode()); 1302 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1303 EXPECT_EQ(4U, s[0]->InputCount()); 1304 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1305 EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1))); 1306 } 1307} 1308 1309TEST_F(InstructionSelectorTest, Word64EqualZeroAndBranchWithOneBitMask) { 1310 TRACED_FORRANGE(int, bit, 0, 63) { 1311 uint64_t mask = V8_UINT64_C(1) << bit; 1312 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1313 RawMachineLabel a, b; 1314 m.Branch(m.Word64Equal(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), 1315 m.Int64Constant(0)), 1316 &a, &b); 1317 m.Bind(&a); 1318 m.Return(m.Int64Constant(1)); 1319 m.Bind(&b); 1320 m.Return(m.Int64Constant(0)); 1321 Stream s = m.Build(); 1322 ASSERT_EQ(1U, s.size()); 1323 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode()); 1324 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1325 EXPECT_EQ(4U, s[0]->InputCount()); 1326 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1327 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); 1328 } 1329 1330 TRACED_FORRANGE(int, bit, 0, 63) { 1331 uint64_t mask = V8_UINT64_C(1) << bit; 1332 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1333 RawMachineLabel a, b; 1334 m.Branch( 1335 m.Word64NotEqual(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), 1336 m.Int64Constant(0)), 1337 &a, &b); 1338 m.Bind(&a); 1339 m.Return(m.Int64Constant(1)); 1340 m.Bind(&b); 1341 m.Return(m.Int64Constant(0)); 1342 Stream s = m.Build(); 1343 ASSERT_EQ(1U, s.size()); 1344 EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode()); 1345 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1346 EXPECT_EQ(4U, s[0]->InputCount()); 1347 EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 1348 EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); 1349 } 1350} 1351 1352TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) { 1353 { 1354 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1355 RawMachineLabel a, b; 1356 Node* p0 = m.Parameter(0); 1357 m.Branch(p0, &a, &b); 1358 m.Bind(&a); 1359 m.Return(m.Int32Constant(1)); 1360 m.Bind(&b); 1361 m.Return(m.Int32Constant(0)); 1362 Stream s = m.Build(); 1363 ASSERT_EQ(1U, s.size()); 1364 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode()); 1365 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1366 EXPECT_EQ(3U, s[0]->InputCount()); 1367 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1368 } 1369 1370 { 1371 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1372 RawMachineLabel a, b; 1373 Node* p0 = m.Parameter(0); 1374 m.Branch(m.Word32BinaryNot(p0), &a, &b); 1375 m.Bind(&a); 1376 m.Return(m.Int32Constant(1)); 1377 m.Bind(&b); 1378 m.Return(m.Int32Constant(0)); 1379 Stream s = m.Build(); 1380 ASSERT_EQ(1U, s.size()); 1381 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode()); 1382 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1383 EXPECT_EQ(3U, s[0]->InputCount()); 1384 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1385 } 1386} 1387 1388TEST_F(InstructionSelectorTest, EqualZeroAndBranch) { 1389 { 1390 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1391 RawMachineLabel a, b; 1392 Node* p0 = m.Parameter(0); 1393 m.Branch(m.Word32Equal(p0, m.Int32Constant(0)), &a, &b); 1394 m.Bind(&a); 1395 m.Return(m.Int32Constant(1)); 1396 m.Bind(&b); 1397 m.Return(m.Int32Constant(0)); 1398 Stream s = m.Build(); 1399 ASSERT_EQ(1U, s.size()); 1400 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode()); 1401 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1402 EXPECT_EQ(3U, s[0]->InputCount()); 1403 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1404 } 1405 1406 { 1407 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1408 RawMachineLabel a, b; 1409 Node* p0 = m.Parameter(0); 1410 m.Branch(m.Word32NotEqual(p0, m.Int32Constant(0)), &a, &b); 1411 m.Bind(&a); 1412 m.Return(m.Int32Constant(1)); 1413 m.Bind(&b); 1414 m.Return(m.Int32Constant(0)); 1415 Stream s = m.Build(); 1416 ASSERT_EQ(1U, s.size()); 1417 EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode()); 1418 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1419 EXPECT_EQ(3U, s[0]->InputCount()); 1420 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1421 } 1422 1423 { 1424 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1425 RawMachineLabel a, b; 1426 Node* p0 = m.Parameter(0); 1427 m.Branch(m.Word64Equal(p0, m.Int64Constant(0)), &a, &b); 1428 m.Bind(&a); 1429 m.Return(m.Int64Constant(1)); 1430 m.Bind(&b); 1431 m.Return(m.Int64Constant(0)); 1432 Stream s = m.Build(); 1433 ASSERT_EQ(1U, s.size()); 1434 EXPECT_EQ(kArm64CompareAndBranch, s[0]->arch_opcode()); 1435 EXPECT_EQ(kEqual, s[0]->flags_condition()); 1436 EXPECT_EQ(3U, s[0]->InputCount()); 1437 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1438 } 1439 1440 { 1441 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 1442 RawMachineLabel a, b; 1443 Node* p0 = m.Parameter(0); 1444 m.Branch(m.Word64NotEqual(p0, m.Int64Constant(0)), &a, &b); 1445 m.Bind(&a); 1446 m.Return(m.Int64Constant(1)); 1447 m.Bind(&b); 1448 m.Return(m.Int64Constant(0)); 1449 Stream s = m.Build(); 1450 ASSERT_EQ(1U, s.size()); 1451 EXPECT_EQ(kArm64CompareAndBranch, s[0]->arch_opcode()); 1452 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 1453 EXPECT_EQ(3U, s[0]->InputCount()); 1454 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1455 } 1456} 1457 1458// ----------------------------------------------------------------------------- 1459// Add and subtract instructions with overflow. 1460 1461 1462typedef InstructionSelectorTestWithParam<MachInst2> 1463 InstructionSelectorOvfAddSubTest; 1464 1465 1466TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) { 1467 const MachInst2 dpi = GetParam(); 1468 const MachineType type = dpi.machine_type; 1469 StreamBuilder m(this, type, type, type); 1470 m.Return( 1471 m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)))); 1472 Stream s = m.Build(); 1473 ASSERT_EQ(1U, s.size()); 1474 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1475 EXPECT_EQ(2U, s[0]->InputCount()); 1476 EXPECT_LE(1U, s[0]->OutputCount()); 1477 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1478 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1479} 1480 1481 1482TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) { 1483 const MachInst2 dpi = GetParam(); 1484 const MachineType type = dpi.machine_type; 1485 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1486 StreamBuilder m(this, type, type); 1487 m.Return(m.Projection( 1488 1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); 1489 Stream s = m.Build(); 1490 ASSERT_EQ(1U, s.size()); 1491 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1492 ASSERT_EQ(2U, s[0]->InputCount()); 1493 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1494 EXPECT_LE(1U, s[0]->OutputCount()); 1495 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1496 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1497 } 1498} 1499 1500 1501TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) { 1502 const MachInst2 dpi = GetParam(); 1503 const MachineType type = dpi.machine_type; 1504 StreamBuilder m(this, type, type, type); 1505 m.Return( 1506 m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)))); 1507 Stream s = m.Build(); 1508 ASSERT_EQ(1U, s.size()); 1509 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1510 EXPECT_EQ(2U, s[0]->InputCount()); 1511 EXPECT_LE(1U, s[0]->OutputCount()); 1512 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1513} 1514 1515 1516TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) { 1517 const MachInst2 dpi = GetParam(); 1518 const MachineType type = dpi.machine_type; 1519 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1520 StreamBuilder m(this, type, type); 1521 m.Return(m.Projection( 1522 0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)))); 1523 Stream s = m.Build(); 1524 ASSERT_EQ(1U, s.size()); 1525 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1526 ASSERT_EQ(2U, s[0]->InputCount()); 1527 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1528 EXPECT_LE(1U, s[0]->OutputCount()); 1529 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1530 } 1531} 1532 1533 1534TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) { 1535 const MachInst2 dpi = GetParam(); 1536 const MachineType type = dpi.machine_type; 1537 StreamBuilder m(this, type, type, type); 1538 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)); 1539 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); 1540 Stream s = m.Build(); 1541 ASSERT_LE(1U, s.size()); 1542 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1543 EXPECT_EQ(2U, s[0]->InputCount()); 1544 EXPECT_EQ(2U, s[0]->OutputCount()); 1545 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1546 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1547} 1548 1549 1550TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) { 1551 const MachInst2 dpi = GetParam(); 1552 const MachineType type = dpi.machine_type; 1553 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1554 StreamBuilder m(this, type, type); 1555 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); 1556 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); 1557 Stream s = m.Build(); 1558 ASSERT_LE(1U, s.size()); 1559 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1560 ASSERT_EQ(2U, s[0]->InputCount()); 1561 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1562 EXPECT_EQ(2U, s[0]->OutputCount()); 1563 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1564 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1565 } 1566} 1567 1568 1569TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) { 1570 const MachInst2 dpi = GetParam(); 1571 const MachineType type = dpi.machine_type; 1572 StreamBuilder m(this, type, type, type); 1573 RawMachineLabel a, b; 1574 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)); 1575 m.Branch(m.Projection(1, n), &a, &b); 1576 m.Bind(&a); 1577 m.Return(m.Int32Constant(0)); 1578 m.Bind(&b); 1579 m.Return(m.Projection(0, n)); 1580 Stream s = m.Build(); 1581 ASSERT_EQ(1U, s.size()); 1582 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1583 EXPECT_EQ(4U, s[0]->InputCount()); 1584 EXPECT_EQ(1U, s[0]->OutputCount()); 1585 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1586 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1587} 1588 1589 1590TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) { 1591 const MachInst2 dpi = GetParam(); 1592 const MachineType type = dpi.machine_type; 1593 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1594 StreamBuilder m(this, type, type); 1595 RawMachineLabel a, b; 1596 Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)); 1597 m.Branch(m.Projection(1, n), &a, &b); 1598 m.Bind(&a); 1599 m.Return(m.Int32Constant(0)); 1600 m.Bind(&b); 1601 m.Return(m.Projection(0, n)); 1602 Stream s = m.Build(); 1603 ASSERT_EQ(1U, s.size()); 1604 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1605 ASSERT_EQ(4U, s[0]->InputCount()); 1606 EXPECT_EQ(1U, s[0]->OutputCount()); 1607 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1608 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1609 } 1610} 1611 1612TEST_P(InstructionSelectorOvfAddSubTest, RORShift) { 1613 // ADD and SUB do not support ROR shifts, make sure we do not try 1614 // to merge them into the ADD/SUB instruction. 1615 const MachInst2 dpi = GetParam(); 1616 const MachineType type = dpi.machine_type; 1617 auto rotate = &RawMachineAssembler::Word64Ror; 1618 ArchOpcode rotate_opcode = kArm64Ror; 1619 if (type == MachineType::Int32()) { 1620 rotate = &RawMachineAssembler::Word32Ror; 1621 rotate_opcode = kArm64Ror32; 1622 } 1623 TRACED_FORRANGE(int32_t, imm, -32, 63) { 1624 StreamBuilder m(this, type, type, type); 1625 Node* const p0 = m.Parameter(0); 1626 Node* const p1 = m.Parameter(1); 1627 Node* r = (m.*rotate)(p1, m.Int32Constant(imm)); 1628 m.Return((m.*dpi.constructor)(p0, r)); 1629 Stream s = m.Build(); 1630 ASSERT_EQ(2U, s.size()); 1631 EXPECT_EQ(rotate_opcode, s[0]->arch_opcode()); 1632 EXPECT_EQ(dpi.arch_opcode, s[1]->arch_opcode()); 1633 } 1634} 1635 1636INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 1637 InstructionSelectorOvfAddSubTest, 1638 ::testing::ValuesIn(kOvfAddSubInstructions)); 1639 1640 1641TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) { 1642 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1643 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1644 m.Return(m.Projection( 1645 1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)))); 1646 Stream s = m.Build(); 1647 1648 ASSERT_EQ(1U, s.size()); 1649 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 1650 EXPECT_EQ(2U, s[0]->InputCount()); 1651 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1652 EXPECT_LE(1U, s[0]->OutputCount()); 1653 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1654 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1655 } 1656} 1657 1658 1659TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) { 1660 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1661 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1662 m.Return(m.Projection( 1663 0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)))); 1664 Stream s = m.Build(); 1665 1666 ASSERT_EQ(1U, s.size()); 1667 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 1668 ASSERT_EQ(2U, s[0]->InputCount()); 1669 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1670 EXPECT_LE(1U, s[0]->OutputCount()); 1671 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); 1672 } 1673} 1674 1675 1676TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) { 1677 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1678 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1679 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)); 1680 m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n))); 1681 Stream s = m.Build(); 1682 1683 ASSERT_LE(1U, s.size()); 1684 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 1685 ASSERT_EQ(2U, s[0]->InputCount()); 1686 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1687 EXPECT_EQ(2U, s[0]->OutputCount()); 1688 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 1689 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1690 } 1691} 1692 1693 1694TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) { 1695 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 1696 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1697 RawMachineLabel a, b; 1698 Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0)); 1699 m.Branch(m.Projection(1, n), &a, &b); 1700 m.Bind(&a); 1701 m.Return(m.Int32Constant(0)); 1702 m.Bind(&b); 1703 m.Return(m.Projection(0, n)); 1704 Stream s = m.Build(); 1705 1706 ASSERT_EQ(1U, s.size()); 1707 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 1708 ASSERT_EQ(4U, s[0]->InputCount()); 1709 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1710 EXPECT_EQ(1U, s[0]->OutputCount()); 1711 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 1712 EXPECT_EQ(kOverflow, s[0]->flags_condition()); 1713 } 1714} 1715 1716 1717// ----------------------------------------------------------------------------- 1718// Shift instructions. 1719 1720 1721typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest; 1722 1723 1724TEST_P(InstructionSelectorShiftTest, Parameter) { 1725 const Shift shift = GetParam(); 1726 const MachineType type = shift.mi.machine_type; 1727 StreamBuilder m(this, type, type, type); 1728 m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Parameter(1))); 1729 Stream s = m.Build(); 1730 ASSERT_EQ(1U, s.size()); 1731 EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode()); 1732 EXPECT_EQ(2U, s[0]->InputCount()); 1733 EXPECT_EQ(1U, s[0]->OutputCount()); 1734} 1735 1736 1737TEST_P(InstructionSelectorShiftTest, Immediate) { 1738 const Shift shift = GetParam(); 1739 const MachineType type = shift.mi.machine_type; 1740 TRACED_FORRANGE(int32_t, imm, 0, 1741 ((1 << ElementSizeLog2Of(type.representation())) * 8) - 1) { 1742 StreamBuilder m(this, type, type); 1743 m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Int32Constant(imm))); 1744 Stream s = m.Build(); 1745 ASSERT_EQ(1U, s.size()); 1746 EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode()); 1747 EXPECT_EQ(2U, s[0]->InputCount()); 1748 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 1749 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 1750 EXPECT_EQ(1U, s[0]->OutputCount()); 1751 } 1752} 1753 1754 1755INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest, 1756 ::testing::ValuesIn(kShiftInstructions)); 1757 1758 1759TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) { 1760 TRACED_FORRANGE(int64_t, x, 32, 63) { 1761 StreamBuilder m(this, MachineType::Int64(), MachineType::Int32()); 1762 Node* const p0 = m.Parameter(0); 1763 Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x)); 1764 m.Return(n); 1765 Stream s = m.Build(); 1766 ASSERT_EQ(1U, s.size()); 1767 EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode()); 1768 ASSERT_EQ(2U, s[0]->InputCount()); 1769 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1770 EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1))); 1771 ASSERT_EQ(1U, s[0]->OutputCount()); 1772 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1773 } 1774} 1775 1776 1777TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) { 1778 TRACED_FORRANGE(int64_t, x, 32, 63) { 1779 StreamBuilder m(this, MachineType::Int64(), MachineType::Uint32()); 1780 Node* const p0 = m.Parameter(0); 1781 Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x)); 1782 m.Return(n); 1783 Stream s = m.Build(); 1784 ASSERT_EQ(1U, s.size()); 1785 EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode()); 1786 ASSERT_EQ(2U, s[0]->InputCount()); 1787 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 1788 EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1))); 1789 ASSERT_EQ(1U, s[0]->OutputCount()); 1790 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 1791 } 1792} 1793 1794 1795TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) { 1796 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64()); 1797 Node* const p = m.Parameter(0); 1798 Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32))); 1799 m.Return(t); 1800 Stream s = m.Build(); 1801 ASSERT_EQ(1U, s.size()); 1802 EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode()); 1803 ASSERT_EQ(2U, s[0]->InputCount()); 1804 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); 1805 EXPECT_EQ(32, s.ToInt64(s[0]->InputAt(1))); 1806 ASSERT_EQ(1U, s[0]->OutputCount()); 1807 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); 1808} 1809 1810 1811TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) { 1812 TRACED_FORRANGE(int64_t, x, 32, 63) { 1813 StreamBuilder m(this, MachineType::Int32(), MachineType::Int64()); 1814 Node* const p = m.Parameter(0); 1815 Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(x))); 1816 m.Return(t); 1817 Stream s = m.Build(); 1818 ASSERT_EQ(1U, s.size()); 1819 EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode()); 1820 ASSERT_EQ(2U, s[0]->InputCount()); 1821 EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); 1822 EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1))); 1823 ASSERT_EQ(1U, s[0]->OutputCount()); 1824 EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); 1825 } 1826} 1827 1828 1829// ----------------------------------------------------------------------------- 1830// Mul and Div instructions. 1831 1832 1833typedef InstructionSelectorTestWithParam<MachInst2> 1834 InstructionSelectorMulDivTest; 1835 1836 1837TEST_P(InstructionSelectorMulDivTest, Parameter) { 1838 const MachInst2 dpi = GetParam(); 1839 const MachineType type = dpi.machine_type; 1840 StreamBuilder m(this, type, type, type); 1841 m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); 1842 Stream s = m.Build(); 1843 ASSERT_EQ(1U, s.size()); 1844 EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); 1845 EXPECT_EQ(2U, s[0]->InputCount()); 1846 EXPECT_EQ(1U, s[0]->OutputCount()); 1847} 1848 1849 1850INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest, 1851 ::testing::ValuesIn(kMulDivInstructions)); 1852 1853 1854namespace { 1855 1856struct MulDPInst { 1857 const char* mul_constructor_name; 1858 Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*); 1859 Node* (RawMachineAssembler::*add_constructor)(Node*, Node*); 1860 Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*); 1861 ArchOpcode add_arch_opcode; 1862 ArchOpcode sub_arch_opcode; 1863 ArchOpcode neg_arch_opcode; 1864 MachineType machine_type; 1865}; 1866 1867 1868std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) { 1869 return os << inst.mul_constructor_name; 1870} 1871 1872} // namespace 1873 1874 1875static const MulDPInst kMulDPInstructions[] = { 1876 {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add, 1877 &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32, 1878 MachineType::Int32()}, 1879 {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add, 1880 &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg, 1881 MachineType::Int64()}}; 1882 1883 1884typedef InstructionSelectorTestWithParam<MulDPInst> 1885 InstructionSelectorIntDPWithIntMulTest; 1886 1887 1888TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) { 1889 const MulDPInst mdpi = GetParam(); 1890 const MachineType type = mdpi.machine_type; 1891 { 1892 StreamBuilder m(this, type, type, type, type); 1893 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2)); 1894 m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n)); 1895 Stream s = m.Build(); 1896 ASSERT_EQ(1U, s.size()); 1897 EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode()); 1898 EXPECT_EQ(3U, s[0]->InputCount()); 1899 EXPECT_EQ(1U, s[0]->OutputCount()); 1900 } 1901 { 1902 StreamBuilder m(this, type, type, type, type); 1903 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1)); 1904 m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2))); 1905 Stream s = m.Build(); 1906 ASSERT_EQ(1U, s.size()); 1907 EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode()); 1908 EXPECT_EQ(3U, s[0]->InputCount()); 1909 EXPECT_EQ(1U, s[0]->OutputCount()); 1910 } 1911} 1912 1913 1914TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) { 1915 const MulDPInst mdpi = GetParam(); 1916 const MachineType type = mdpi.machine_type; 1917 { 1918 StreamBuilder m(this, type, type, type, type); 1919 Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2)); 1920 m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n)); 1921 Stream s = m.Build(); 1922 ASSERT_EQ(1U, s.size()); 1923 EXPECT_EQ(mdpi.sub_arch_opcode, s[0]->arch_opcode()); 1924 EXPECT_EQ(3U, s[0]->InputCount()); 1925 EXPECT_EQ(1U, s[0]->OutputCount()); 1926 } 1927} 1928 1929 1930TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) { 1931 const MulDPInst mdpi = GetParam(); 1932 const MachineType type = mdpi.machine_type; 1933 { 1934 StreamBuilder m(this, type, type, type); 1935 Node* n = 1936 (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(0)); 1937 m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1))); 1938 Stream s = m.Build(); 1939 ASSERT_EQ(1U, s.size()); 1940 EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode()); 1941 EXPECT_EQ(2U, s[0]->InputCount()); 1942 EXPECT_EQ(1U, s[0]->OutputCount()); 1943 } 1944 { 1945 StreamBuilder m(this, type, type, type); 1946 Node* n = 1947 (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(1)); 1948 m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n)); 1949 Stream s = m.Build(); 1950 ASSERT_EQ(1U, s.size()); 1951 EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode()); 1952 EXPECT_EQ(2U, s[0]->InputCount()); 1953 EXPECT_EQ(1U, s[0]->OutputCount()); 1954 } 1955} 1956 1957 1958INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 1959 InstructionSelectorIntDPWithIntMulTest, 1960 ::testing::ValuesIn(kMulDPInstructions)); 1961 1962 1963TEST_F(InstructionSelectorTest, Int32MulWithImmediate) { 1964 // x * (2^k + 1) -> x + (x << k) 1965 TRACED_FORRANGE(int32_t, k, 1, 30) { 1966 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1967 m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1))); 1968 Stream s = m.Build(); 1969 ASSERT_EQ(1U, s.size()); 1970 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 1971 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 1972 ASSERT_EQ(3U, s[0]->InputCount()); 1973 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 1974 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 1975 EXPECT_EQ(1U, s[0]->OutputCount()); 1976 } 1977 // (2^k + 1) * x -> x + (x << k) 1978 TRACED_FORRANGE(int32_t, k, 1, 30) { 1979 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 1980 m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0))); 1981 Stream s = m.Build(); 1982 ASSERT_EQ(1U, s.size()); 1983 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 1984 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 1985 ASSERT_EQ(3U, s[0]->InputCount()); 1986 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 1987 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 1988 EXPECT_EQ(1U, s[0]->OutputCount()); 1989 } 1990 // x * (2^k + 1) + c -> x + (x << k) + c 1991 TRACED_FORRANGE(int32_t, k, 1, 30) { 1992 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 1993 MachineType::Int32()); 1994 m.Return( 1995 m.Int32Add(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)), 1996 m.Parameter(1))); 1997 Stream s = m.Build(); 1998 ASSERT_EQ(2U, s.size()); 1999 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 2000 EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); 2001 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2002 ASSERT_EQ(3U, s[0]->InputCount()); 2003 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2004 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 2005 EXPECT_EQ(1U, s[0]->OutputCount()); 2006 } 2007 // (2^k + 1) * x + c -> x + (x << k) + c 2008 TRACED_FORRANGE(int32_t, k, 1, 30) { 2009 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2010 MachineType::Int32()); 2011 m.Return( 2012 m.Int32Add(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)), 2013 m.Parameter(1))); 2014 Stream s = m.Build(); 2015 ASSERT_EQ(2U, s.size()); 2016 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 2017 EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); 2018 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2019 ASSERT_EQ(3U, s[0]->InputCount()); 2020 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2021 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 2022 EXPECT_EQ(1U, s[0]->OutputCount()); 2023 } 2024 // c + x * (2^k + 1) -> c + x + (x << k) 2025 TRACED_FORRANGE(int32_t, k, 1, 30) { 2026 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2027 MachineType::Int32()); 2028 m.Return( 2029 m.Int32Add(m.Parameter(0), 2030 m.Int32Mul(m.Parameter(1), m.Int32Constant((1 << k) + 1)))); 2031 Stream s = m.Build(); 2032 ASSERT_EQ(2U, s.size()); 2033 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 2034 EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); 2035 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2036 ASSERT_EQ(3U, s[0]->InputCount()); 2037 EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); 2038 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 2039 EXPECT_EQ(1U, s[0]->OutputCount()); 2040 } 2041 // c + (2^k + 1) * x -> c + x + (x << k) 2042 TRACED_FORRANGE(int32_t, k, 1, 30) { 2043 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2044 MachineType::Int32()); 2045 m.Return( 2046 m.Int32Add(m.Parameter(0), 2047 m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(1)))); 2048 Stream s = m.Build(); 2049 ASSERT_EQ(2U, s.size()); 2050 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 2051 EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); 2052 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2053 ASSERT_EQ(3U, s[0]->InputCount()); 2054 EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); 2055 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 2056 EXPECT_EQ(1U, s[0]->OutputCount()); 2057 } 2058 // c - x * (2^k + 1) -> c - x + (x << k) 2059 TRACED_FORRANGE(int32_t, k, 1, 30) { 2060 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2061 MachineType::Int32()); 2062 m.Return( 2063 m.Int32Sub(m.Parameter(0), 2064 m.Int32Mul(m.Parameter(1), m.Int32Constant((1 << k) + 1)))); 2065 Stream s = m.Build(); 2066 ASSERT_EQ(2U, s.size()); 2067 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 2068 EXPECT_EQ(kArm64Sub32, s[1]->arch_opcode()); 2069 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2070 ASSERT_EQ(3U, s[0]->InputCount()); 2071 EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); 2072 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 2073 EXPECT_EQ(1U, s[0]->OutputCount()); 2074 } 2075 // c - (2^k + 1) * x -> c - x + (x << k) 2076 TRACED_FORRANGE(int32_t, k, 1, 30) { 2077 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2078 MachineType::Int32()); 2079 m.Return( 2080 m.Int32Sub(m.Parameter(0), 2081 m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(1)))); 2082 Stream s = m.Build(); 2083 ASSERT_EQ(2U, s.size()); 2084 EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); 2085 EXPECT_EQ(kArm64Sub32, s[1]->arch_opcode()); 2086 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2087 ASSERT_EQ(3U, s[0]->InputCount()); 2088 EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); 2089 EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); 2090 EXPECT_EQ(1U, s[0]->OutputCount()); 2091 } 2092} 2093 2094 2095TEST_F(InstructionSelectorTest, Int64MulWithImmediate) { 2096 // x * (2^k + 1) -> x + (x << k) 2097 TRACED_FORRANGE(int64_t, k, 1, 62) { 2098 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 2099 m.Return(m.Int64Mul(m.Parameter(0), m.Int64Constant((1L << k) + 1))); 2100 Stream s = m.Build(); 2101 ASSERT_EQ(1U, s.size()); 2102 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2103 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2104 ASSERT_EQ(3U, s[0]->InputCount()); 2105 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2106 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2107 EXPECT_EQ(1U, s[0]->OutputCount()); 2108 } 2109 // (2^k + 1) * x -> x + (x << k) 2110 TRACED_FORRANGE(int64_t, k, 1, 62) { 2111 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 2112 m.Return(m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(0))); 2113 Stream s = m.Build(); 2114 ASSERT_EQ(1U, s.size()); 2115 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2116 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2117 ASSERT_EQ(3U, s[0]->InputCount()); 2118 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2119 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2120 EXPECT_EQ(1U, s[0]->OutputCount()); 2121 } 2122 // x * (2^k + 1) + c -> x + (x << k) + c 2123 TRACED_FORRANGE(int64_t, k, 1, 62) { 2124 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 2125 MachineType::Int64()); 2126 m.Return( 2127 m.Int64Add(m.Int64Mul(m.Parameter(0), m.Int64Constant((1L << k) + 1)), 2128 m.Parameter(1))); 2129 Stream s = m.Build(); 2130 ASSERT_EQ(2U, s.size()); 2131 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2132 EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); 2133 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2134 ASSERT_EQ(3U, s[0]->InputCount()); 2135 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2136 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2137 EXPECT_EQ(1U, s[0]->OutputCount()); 2138 } 2139 // (2^k + 1) * x + c -> x + (x << k) + c 2140 TRACED_FORRANGE(int64_t, k, 1, 62) { 2141 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 2142 MachineType::Int64()); 2143 m.Return( 2144 m.Int64Add(m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(0)), 2145 m.Parameter(1))); 2146 Stream s = m.Build(); 2147 ASSERT_EQ(2U, s.size()); 2148 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2149 EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); 2150 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2151 ASSERT_EQ(3U, s[0]->InputCount()); 2152 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2153 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2154 EXPECT_EQ(1U, s[0]->OutputCount()); 2155 } 2156 // c + x * (2^k + 1) -> c + x + (x << k) 2157 TRACED_FORRANGE(int64_t, k, 1, 62) { 2158 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 2159 MachineType::Int64()); 2160 m.Return( 2161 m.Int64Add(m.Parameter(0), 2162 m.Int64Mul(m.Parameter(1), m.Int64Constant((1L << k) + 1)))); 2163 Stream s = m.Build(); 2164 ASSERT_EQ(2U, s.size()); 2165 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2166 EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); 2167 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2168 ASSERT_EQ(3U, s[0]->InputCount()); 2169 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2170 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2171 EXPECT_EQ(1U, s[0]->OutputCount()); 2172 } 2173 // c + (2^k + 1) * x -> c + x + (x << k) 2174 TRACED_FORRANGE(int64_t, k, 1, 62) { 2175 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 2176 MachineType::Int64()); 2177 m.Return( 2178 m.Int64Add(m.Parameter(0), 2179 m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(1)))); 2180 Stream s = m.Build(); 2181 ASSERT_EQ(2U, s.size()); 2182 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2183 EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); 2184 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2185 ASSERT_EQ(3U, s[0]->InputCount()); 2186 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2187 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2188 EXPECT_EQ(1U, s[0]->OutputCount()); 2189 } 2190 // c - x * (2^k + 1) -> c - x + (x << k) 2191 TRACED_FORRANGE(int64_t, k, 1, 62) { 2192 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 2193 MachineType::Int64()); 2194 m.Return( 2195 m.Int64Sub(m.Parameter(0), 2196 m.Int64Mul(m.Parameter(1), m.Int64Constant((1L << k) + 1)))); 2197 Stream s = m.Build(); 2198 ASSERT_EQ(2U, s.size()); 2199 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2200 EXPECT_EQ(kArm64Sub, s[1]->arch_opcode()); 2201 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2202 ASSERT_EQ(3U, s[0]->InputCount()); 2203 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2204 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2205 EXPECT_EQ(1U, s[0]->OutputCount()); 2206 } 2207 // c - (2^k + 1) * x -> c - x + (x << k) 2208 TRACED_FORRANGE(int64_t, k, 1, 62) { 2209 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64(), 2210 MachineType::Int64()); 2211 m.Return( 2212 m.Int64Sub(m.Parameter(0), 2213 m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(1)))); 2214 Stream s = m.Build(); 2215 ASSERT_EQ(2U, s.size()); 2216 EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); 2217 EXPECT_EQ(kArm64Sub, s[1]->arch_opcode()); 2218 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2219 ASSERT_EQ(3U, s[0]->InputCount()); 2220 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2221 EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); 2222 EXPECT_EQ(1U, s[0]->OutputCount()); 2223 } 2224} 2225 2226 2227// ----------------------------------------------------------------------------- 2228// Floating point instructions. 2229 2230typedef InstructionSelectorTestWithParam<MachInst2> 2231 InstructionSelectorFPArithTest; 2232 2233 2234TEST_P(InstructionSelectorFPArithTest, Parameter) { 2235 const MachInst2 fpa = GetParam(); 2236 StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type); 2237 m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1))); 2238 Stream s = m.Build(); 2239 ASSERT_EQ(1U, s.size()); 2240 EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode()); 2241 EXPECT_EQ(2U, s[0]->InputCount()); 2242 EXPECT_EQ(1U, s[0]->OutputCount()); 2243} 2244 2245 2246INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest, 2247 ::testing::ValuesIn(kFPArithInstructions)); 2248 2249 2250typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest; 2251 2252 2253TEST_P(InstructionSelectorFPCmpTest, Parameter) { 2254 const FPCmp cmp = GetParam(); 2255 StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type, 2256 cmp.mi.machine_type); 2257 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1))); 2258 Stream s = m.Build(); 2259 ASSERT_EQ(1U, s.size()); 2260 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); 2261 EXPECT_EQ(2U, s[0]->InputCount()); 2262 EXPECT_EQ(1U, s[0]->OutputCount()); 2263 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2264 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 2265} 2266 2267 2268TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnRight) { 2269 const FPCmp cmp = GetParam(); 2270 StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type); 2271 if (cmp.mi.machine_type == MachineType::Float64()) { 2272 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float64Constant(0.0))); 2273 } else { 2274 m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Float32Constant(0.0f))); 2275 } 2276 Stream s = m.Build(); 2277 ASSERT_EQ(1U, s.size()); 2278 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); 2279 EXPECT_EQ(2U, s[0]->InputCount()); 2280 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 2281 EXPECT_EQ(1U, s[0]->OutputCount()); 2282 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2283 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 2284} 2285 2286 2287TEST_P(InstructionSelectorFPCmpTest, WithImmediateZeroOnLeft) { 2288 const FPCmp cmp = GetParam(); 2289 StreamBuilder m(this, MachineType::Int32(), cmp.mi.machine_type); 2290 if (cmp.mi.machine_type == MachineType::Float64()) { 2291 m.Return((m.*cmp.mi.constructor)(m.Float64Constant(0.0), m.Parameter(0))); 2292 } else { 2293 m.Return((m.*cmp.mi.constructor)(m.Float32Constant(0.0f), m.Parameter(0))); 2294 } 2295 Stream s = m.Build(); 2296 ASSERT_EQ(1U, s.size()); 2297 EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode()); 2298 EXPECT_EQ(2U, s[0]->InputCount()); 2299 EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); 2300 EXPECT_EQ(1U, s[0]->OutputCount()); 2301 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2302 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); 2303} 2304 2305 2306INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest, 2307 ::testing::ValuesIn(kFPCmpInstructions)); 2308 2309 2310// ----------------------------------------------------------------------------- 2311// Conversions. 2312 2313typedef InstructionSelectorTestWithParam<Conversion> 2314 InstructionSelectorConversionTest; 2315 2316 2317TEST_P(InstructionSelectorConversionTest, Parameter) { 2318 const Conversion conv = GetParam(); 2319 StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type); 2320 m.Return((m.*conv.mi.constructor)(m.Parameter(0))); 2321 Stream s = m.Build(); 2322 ASSERT_EQ(1U, s.size()); 2323 EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode()); 2324 EXPECT_EQ(1U, s[0]->InputCount()); 2325 EXPECT_EQ(1U, s[0]->OutputCount()); 2326} 2327 2328 2329INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 2330 InstructionSelectorConversionTest, 2331 ::testing::ValuesIn(kConversionInstructions)); 2332 2333typedef InstructionSelectorTestWithParam<MachInst2> 2334 InstructionSelectorElidedChangeUint32ToUint64Test; 2335 2336TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) { 2337 const MachInst2 binop = GetParam(); 2338 StreamBuilder m(this, MachineType::Uint64(), binop.machine_type, 2339 binop.machine_type); 2340 m.Return(m.ChangeUint32ToUint64( 2341 (m.*binop.constructor)(m.Parameter(0), m.Parameter(1)))); 2342 Stream s = m.Build(); 2343 // Make sure the `ChangeUint32ToUint64` node turned into a no-op. 2344 ASSERT_EQ(1U, s.size()); 2345 EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode()); 2346 EXPECT_EQ(2U, s[0]->InputCount()); 2347 EXPECT_EQ(1U, s[0]->OutputCount()); 2348} 2349 2350INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 2351 InstructionSelectorElidedChangeUint32ToUint64Test, 2352 ::testing::ValuesIn(kCanElideChangeUint32ToUint64)); 2353 2354TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) { 2355 // For each case, make sure the `ChangeUint32ToUint64` node turned into a 2356 // no-op. 2357 2358 // Ldrb 2359 { 2360 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(), 2361 MachineType::Int32()); 2362 m.Return(m.ChangeUint32ToUint64( 2363 m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1)))); 2364 Stream s = m.Build(); 2365 ASSERT_EQ(1U, s.size()); 2366 EXPECT_EQ(kArm64Ldrb, s[0]->arch_opcode()); 2367 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 2368 EXPECT_EQ(2U, s[0]->InputCount()); 2369 EXPECT_EQ(1U, s[0]->OutputCount()); 2370 } 2371 // Ldrh 2372 { 2373 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(), 2374 MachineType::Int32()); 2375 m.Return(m.ChangeUint32ToUint64( 2376 m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1)))); 2377 Stream s = m.Build(); 2378 ASSERT_EQ(1U, s.size()); 2379 EXPECT_EQ(kArm64Ldrh, s[0]->arch_opcode()); 2380 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 2381 EXPECT_EQ(2U, s[0]->InputCount()); 2382 EXPECT_EQ(1U, s[0]->OutputCount()); 2383 } 2384 // LdrW 2385 { 2386 StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(), 2387 MachineType::Int32()); 2388 m.Return(m.ChangeUint32ToUint64( 2389 m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1)))); 2390 Stream s = m.Build(); 2391 ASSERT_EQ(1U, s.size()); 2392 EXPECT_EQ(kArm64LdrW, s[0]->arch_opcode()); 2393 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 2394 EXPECT_EQ(2U, s[0]->InputCount()); 2395 EXPECT_EQ(1U, s[0]->OutputCount()); 2396 } 2397} 2398 2399// ----------------------------------------------------------------------------- 2400// Memory access instructions. 2401 2402 2403namespace { 2404 2405struct MemoryAccess { 2406 MachineType type; 2407 ArchOpcode ldr_opcode; 2408 ArchOpcode str_opcode; 2409 const int32_t immediates[20]; 2410}; 2411 2412 2413std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { 2414 return os << memacc.type; 2415} 2416 2417} // namespace 2418 2419 2420static const MemoryAccess kMemoryAccesses[] = { 2421 {MachineType::Int8(), 2422 kArm64Ldrsb, 2423 kArm64Strb, 2424 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121, 2425 2442, 4093, 4094, 4095}}, 2426 {MachineType::Uint8(), 2427 kArm64Ldrb, 2428 kArm64Strb, 2429 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121, 2430 2442, 4093, 4094, 4095}}, 2431 {MachineType::Int16(), 2432 kArm64Ldrsh, 2433 kArm64Strh, 2434 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100, 2435 4242, 6786, 8188, 8190}}, 2436 {MachineType::Uint16(), 2437 kArm64Ldrh, 2438 kArm64Strh, 2439 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100, 2440 4242, 6786, 8188, 8190}}, 2441 {MachineType::Int32(), 2442 kArm64LdrW, 2443 kArm64StrW, 2444 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196, 2445 3276, 3280, 16376, 16380}}, 2446 {MachineType::Uint32(), 2447 kArm64LdrW, 2448 kArm64StrW, 2449 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196, 2450 3276, 3280, 16376, 16380}}, 2451 {MachineType::Int64(), 2452 kArm64Ldr, 2453 kArm64Str, 2454 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200, 2455 16384, 16392, 32752, 32760}}, 2456 {MachineType::Uint64(), 2457 kArm64Ldr, 2458 kArm64Str, 2459 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200, 2460 16384, 16392, 32752, 32760}}, 2461 {MachineType::Float32(), 2462 kArm64LdrS, 2463 kArm64StrS, 2464 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196, 2465 3276, 3280, 16376, 16380}}, 2466 {MachineType::Float64(), 2467 kArm64LdrD, 2468 kArm64StrD, 2469 {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200, 2470 16384, 16392, 32752, 32760}}}; 2471 2472 2473typedef InstructionSelectorTestWithParam<MemoryAccess> 2474 InstructionSelectorMemoryAccessTest; 2475 2476 2477TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { 2478 const MemoryAccess memacc = GetParam(); 2479 StreamBuilder m(this, memacc.type, MachineType::Pointer(), 2480 MachineType::Int32()); 2481 m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); 2482 Stream s = m.Build(); 2483 ASSERT_EQ(1U, s.size()); 2484 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); 2485 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 2486 EXPECT_EQ(2U, s[0]->InputCount()); 2487 EXPECT_EQ(1U, s[0]->OutputCount()); 2488} 2489 2490 2491TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) { 2492 const MemoryAccess memacc = GetParam(); 2493 TRACED_FOREACH(int32_t, index, memacc.immediates) { 2494 StreamBuilder m(this, memacc.type, MachineType::Pointer()); 2495 m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); 2496 Stream s = m.Build(); 2497 ASSERT_EQ(1U, s.size()); 2498 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); 2499 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 2500 EXPECT_EQ(2U, s[0]->InputCount()); 2501 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 2502 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); 2503 ASSERT_EQ(1U, s[0]->OutputCount()); 2504 } 2505} 2506 2507 2508TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { 2509 const MemoryAccess memacc = GetParam(); 2510 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), 2511 MachineType::Int32(), memacc.type); 2512 m.Store(memacc.type.representation(), m.Parameter(0), m.Parameter(1), 2513 m.Parameter(2), kNoWriteBarrier); 2514 m.Return(m.Int32Constant(0)); 2515 Stream s = m.Build(); 2516 ASSERT_EQ(1U, s.size()); 2517 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 2518 EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); 2519 EXPECT_EQ(3U, s[0]->InputCount()); 2520 EXPECT_EQ(0U, s[0]->OutputCount()); 2521} 2522 2523 2524TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) { 2525 const MemoryAccess memacc = GetParam(); 2526 TRACED_FOREACH(int32_t, index, memacc.immediates) { 2527 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), 2528 memacc.type); 2529 m.Store(memacc.type.representation(), m.Parameter(0), 2530 m.Int32Constant(index), m.Parameter(1), kNoWriteBarrier); 2531 m.Return(m.Int32Constant(0)); 2532 Stream s = m.Build(); 2533 ASSERT_EQ(1U, s.size()); 2534 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 2535 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 2536 ASSERT_EQ(3U, s[0]->InputCount()); 2537 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind()); 2538 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(2))); 2539 EXPECT_EQ(0U, s[0]->OutputCount()); 2540 } 2541} 2542 2543TEST_P(InstructionSelectorMemoryAccessTest, StoreZero) { 2544 const MemoryAccess memacc = GetParam(); 2545 TRACED_FOREACH(int32_t, index, memacc.immediates) { 2546 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer()); 2547 m.Store(memacc.type.representation(), m.Parameter(0), 2548 m.Int32Constant(index), m.Int32Constant(0), kNoWriteBarrier); 2549 m.Return(m.Int32Constant(0)); 2550 Stream s = m.Build(); 2551 ASSERT_EQ(1U, s.size()); 2552 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 2553 EXPECT_EQ(kMode_MRI, s[0]->addressing_mode()); 2554 ASSERT_EQ(3U, s[0]->InputCount()); 2555 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind()); 2556 EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(2))); 2557 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(0)->kind()); 2558 EXPECT_EQ(0, s.ToInt64(s[0]->InputAt(0))); 2559 EXPECT_EQ(0U, s[0]->OutputCount()); 2560 } 2561} 2562 2563TEST_P(InstructionSelectorMemoryAccessTest, LoadWithShiftedIndex) { 2564 const MemoryAccess memacc = GetParam(); 2565 TRACED_FORRANGE(int, immediate_shift, 0, 4) { 2566 // 32 bit shift 2567 { 2568 StreamBuilder m(this, memacc.type, MachineType::Pointer(), 2569 MachineType::Int32()); 2570 Node* const index = 2571 m.Word32Shl(m.Parameter(1), m.Int32Constant(immediate_shift)); 2572 m.Return(m.Load(memacc.type, m.Parameter(0), index)); 2573 Stream s = m.Build(); 2574 if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) { 2575 ASSERT_EQ(1U, s.size()); 2576 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); 2577 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2578 EXPECT_EQ(3U, s[0]->InputCount()); 2579 EXPECT_EQ(1U, s[0]->OutputCount()); 2580 } else { 2581 // Make sure we haven't merged the shift into the load instruction. 2582 ASSERT_NE(1U, s.size()); 2583 EXPECT_NE(memacc.ldr_opcode, s[0]->arch_opcode()); 2584 EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2585 } 2586 } 2587 // 64 bit shift 2588 { 2589 StreamBuilder m(this, memacc.type, MachineType::Pointer(), 2590 MachineType::Int64()); 2591 Node* const index = 2592 m.Word64Shl(m.Parameter(1), m.Int64Constant(immediate_shift)); 2593 m.Return(m.Load(memacc.type, m.Parameter(0), index)); 2594 Stream s = m.Build(); 2595 if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) { 2596 ASSERT_EQ(1U, s.size()); 2597 EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); 2598 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2599 EXPECT_EQ(3U, s[0]->InputCount()); 2600 EXPECT_EQ(1U, s[0]->OutputCount()); 2601 } else { 2602 // Make sure we haven't merged the shift into the load instruction. 2603 ASSERT_NE(1U, s.size()); 2604 EXPECT_NE(memacc.ldr_opcode, s[0]->arch_opcode()); 2605 EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2606 } 2607 } 2608 } 2609} 2610 2611TEST_P(InstructionSelectorMemoryAccessTest, StoreWithShiftedIndex) { 2612 const MemoryAccess memacc = GetParam(); 2613 TRACED_FORRANGE(int, immediate_shift, 0, 4) { 2614 // 32 bit shift 2615 { 2616 StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(), 2617 MachineType::Int32(), memacc.type); 2618 Node* const index = 2619 m.Word32Shl(m.Parameter(1), m.Int32Constant(immediate_shift)); 2620 m.Store(memacc.type.representation(), m.Parameter(0), index, 2621 m.Parameter(2), kNoWriteBarrier); 2622 m.Return(m.Int32Constant(0)); 2623 Stream s = m.Build(); 2624 if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) { 2625 ASSERT_EQ(1U, s.size()); 2626 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 2627 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2628 EXPECT_EQ(4U, s[0]->InputCount()); 2629 EXPECT_EQ(0U, s[0]->OutputCount()); 2630 } else { 2631 // Make sure we haven't merged the shift into the store instruction. 2632 ASSERT_NE(1U, s.size()); 2633 EXPECT_NE(memacc.str_opcode, s[0]->arch_opcode()); 2634 EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2635 } 2636 } 2637 // 64 bit shift 2638 { 2639 StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(), 2640 MachineType::Int64(), memacc.type); 2641 Node* const index = 2642 m.Word64Shl(m.Parameter(1), m.Int64Constant(immediate_shift)); 2643 m.Store(memacc.type.representation(), m.Parameter(0), index, 2644 m.Parameter(2), kNoWriteBarrier); 2645 m.Return(m.Int64Constant(0)); 2646 Stream s = m.Build(); 2647 if (immediate_shift == ElementSizeLog2Of(memacc.type.representation())) { 2648 ASSERT_EQ(1U, s.size()); 2649 EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); 2650 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2651 EXPECT_EQ(4U, s[0]->InputCount()); 2652 EXPECT_EQ(0U, s[0]->OutputCount()); 2653 } else { 2654 // Make sure we haven't merged the shift into the store instruction. 2655 ASSERT_NE(1U, s.size()); 2656 EXPECT_NE(memacc.str_opcode, s[0]->arch_opcode()); 2657 EXPECT_NE(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); 2658 } 2659 } 2660 } 2661} 2662 2663INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 2664 InstructionSelectorMemoryAccessTest, 2665 ::testing::ValuesIn(kMemoryAccesses)); 2666 2667 2668// ----------------------------------------------------------------------------- 2669// Comparison instructions. 2670 2671static const MachInst2 kComparisonInstructions[] = { 2672 {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, 2673 MachineType::Int32()}, 2674 {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, 2675 MachineType::Int64()}, 2676}; 2677 2678 2679typedef InstructionSelectorTestWithParam<MachInst2> 2680 InstructionSelectorComparisonTest; 2681 2682 2683TEST_P(InstructionSelectorComparisonTest, WithParameters) { 2684 const MachInst2 cmp = GetParam(); 2685 const MachineType type = cmp.machine_type; 2686 StreamBuilder m(this, type, type, type); 2687 m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1))); 2688 Stream s = m.Build(); 2689 ASSERT_EQ(1U, s.size()); 2690 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); 2691 EXPECT_EQ(2U, s[0]->InputCount()); 2692 EXPECT_EQ(1U, s[0]->OutputCount()); 2693 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2694 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2695} 2696 2697 2698TEST_P(InstructionSelectorComparisonTest, WithImmediate) { 2699 const MachInst2 cmp = GetParam(); 2700 const MachineType type = cmp.machine_type; 2701 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 2702 // Compare with 0 are turned into tst instruction. 2703 if (imm == 0) continue; 2704 StreamBuilder m(this, type, type); 2705 m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); 2706 Stream s = m.Build(); 2707 ASSERT_EQ(1U, s.size()); 2708 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); 2709 ASSERT_EQ(2U, s[0]->InputCount()); 2710 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 2711 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 2712 EXPECT_EQ(1U, s[0]->OutputCount()); 2713 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2714 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2715 } 2716 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 2717 // Compare with 0 are turned into tst instruction. 2718 if (imm == 0) continue; 2719 StreamBuilder m(this, type, type); 2720 m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0))); 2721 Stream s = m.Build(); 2722 ASSERT_EQ(1U, s.size()); 2723 EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode()); 2724 ASSERT_EQ(2U, s[0]->InputCount()); 2725 ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); 2726 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); 2727 EXPECT_EQ(1U, s[0]->OutputCount()); 2728 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2729 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2730 } 2731} 2732 2733INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 2734 InstructionSelectorComparisonTest, 2735 ::testing::ValuesIn(kComparisonInstructions)); 2736 2737 2738TEST_F(InstructionSelectorTest, Word32EqualWithZero) { 2739 { 2740 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 2741 m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); 2742 Stream s = m.Build(); 2743 ASSERT_EQ(1U, s.size()); 2744 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 2745 ASSERT_EQ(2U, s[0]->InputCount()); 2746 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2747 EXPECT_EQ(1U, s[0]->OutputCount()); 2748 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2749 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2750 } 2751 { 2752 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 2753 m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); 2754 Stream s = m.Build(); 2755 ASSERT_EQ(1U, s.size()); 2756 EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode()); 2757 ASSERT_EQ(2U, s[0]->InputCount()); 2758 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2759 EXPECT_EQ(1U, s[0]->OutputCount()); 2760 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2761 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2762 } 2763} 2764 2765 2766TEST_F(InstructionSelectorTest, Word64EqualWithZero) { 2767 { 2768 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 2769 m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0))); 2770 Stream s = m.Build(); 2771 ASSERT_EQ(1U, s.size()); 2772 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); 2773 ASSERT_EQ(2U, s[0]->InputCount()); 2774 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2775 EXPECT_EQ(1U, s[0]->OutputCount()); 2776 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2777 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2778 } 2779 { 2780 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 2781 m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0))); 2782 Stream s = m.Build(); 2783 ASSERT_EQ(1U, s.size()); 2784 EXPECT_EQ(kArm64Tst, s[0]->arch_opcode()); 2785 ASSERT_EQ(2U, s[0]->InputCount()); 2786 EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); 2787 EXPECT_EQ(1U, s[0]->OutputCount()); 2788 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 2789 EXPECT_EQ(kEqual, s[0]->flags_condition()); 2790 } 2791} 2792 2793 2794TEST_F(InstructionSelectorTest, Word32EqualWithWord32Shift) { 2795 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 2796 // Skip non 32-bit shifts or ror operations. 2797 if (shift.mi.machine_type != MachineType::Int32() || 2798 shift.mi.arch_opcode == kArm64Ror32) { 2799 continue; 2800 } 2801 2802 TRACED_FORRANGE(int32_t, imm, -32, 63) { 2803 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2804 MachineType::Int32()); 2805 Node* const p0 = m.Parameter(0); 2806 Node* const p1 = m.Parameter(1); 2807 Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm)); 2808 m.Return(m.Word32Equal(p0, r)); 2809 Stream s = m.Build(); 2810 ASSERT_EQ(1U, s.size()); 2811 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2812 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 2813 ASSERT_EQ(3U, s[0]->InputCount()); 2814 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2815 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2816 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); 2817 ASSERT_EQ(1U, s[0]->OutputCount()); 2818 } 2819 TRACED_FORRANGE(int32_t, imm, -32, 63) { 2820 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2821 MachineType::Int32()); 2822 Node* const p0 = m.Parameter(0); 2823 Node* const p1 = m.Parameter(1); 2824 Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm)); 2825 m.Return(m.Word32Equal(r, p0)); 2826 Stream s = m.Build(); 2827 ASSERT_EQ(1U, s.size()); 2828 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2829 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 2830 ASSERT_EQ(3U, s[0]->InputCount()); 2831 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2832 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2833 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); 2834 ASSERT_EQ(1U, s[0]->OutputCount()); 2835 } 2836 } 2837} 2838 2839 2840TEST_F(InstructionSelectorTest, Word32EqualWithUnsignedExtendByte) { 2841 { 2842 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2843 MachineType::Int32()); 2844 Node* const p0 = m.Parameter(0); 2845 Node* const p1 = m.Parameter(1); 2846 Node* r = m.Word32And(p1, m.Int32Constant(0xff)); 2847 m.Return(m.Word32Equal(p0, r)); 2848 Stream s = m.Build(); 2849 ASSERT_EQ(1U, s.size()); 2850 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2851 EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); 2852 ASSERT_EQ(2U, s[0]->InputCount()); 2853 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2854 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2855 ASSERT_EQ(1U, s[0]->OutputCount()); 2856 } 2857 { 2858 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2859 MachineType::Int32()); 2860 Node* const p0 = m.Parameter(0); 2861 Node* const p1 = m.Parameter(1); 2862 Node* r = m.Word32And(p1, m.Int32Constant(0xff)); 2863 m.Return(m.Word32Equal(r, p0)); 2864 Stream s = m.Build(); 2865 ASSERT_EQ(1U, s.size()); 2866 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2867 EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); 2868 ASSERT_EQ(2U, s[0]->InputCount()); 2869 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2870 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2871 ASSERT_EQ(1U, s[0]->OutputCount()); 2872 } 2873} 2874 2875 2876TEST_F(InstructionSelectorTest, Word32EqualWithUnsignedExtendHalfword) { 2877 { 2878 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2879 MachineType::Int32()); 2880 Node* const p0 = m.Parameter(0); 2881 Node* const p1 = m.Parameter(1); 2882 Node* r = m.Word32And(p1, m.Int32Constant(0xffff)); 2883 m.Return(m.Word32Equal(p0, r)); 2884 Stream s = m.Build(); 2885 ASSERT_EQ(1U, s.size()); 2886 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2887 EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); 2888 ASSERT_EQ(2U, s[0]->InputCount()); 2889 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2890 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2891 ASSERT_EQ(1U, s[0]->OutputCount()); 2892 } 2893 { 2894 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2895 MachineType::Int32()); 2896 Node* const p0 = m.Parameter(0); 2897 Node* const p1 = m.Parameter(1); 2898 Node* r = m.Word32And(p1, m.Int32Constant(0xffff)); 2899 m.Return(m.Word32Equal(r, p0)); 2900 Stream s = m.Build(); 2901 ASSERT_EQ(1U, s.size()); 2902 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2903 EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); 2904 ASSERT_EQ(2U, s[0]->InputCount()); 2905 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2906 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2907 ASSERT_EQ(1U, s[0]->OutputCount()); 2908 } 2909} 2910 2911 2912TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendByte) { 2913 { 2914 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2915 MachineType::Int32()); 2916 Node* const p0 = m.Parameter(0); 2917 Node* const p1 = m.Parameter(1); 2918 Node* r = 2919 m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(24)), m.Int32Constant(24)); 2920 m.Return(m.Word32Equal(p0, r)); 2921 Stream s = m.Build(); 2922 ASSERT_EQ(1U, s.size()); 2923 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2924 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 2925 ASSERT_EQ(2U, s[0]->InputCount()); 2926 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2927 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2928 ASSERT_EQ(1U, s[0]->OutputCount()); 2929 } 2930 { 2931 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2932 MachineType::Int32()); 2933 Node* const p0 = m.Parameter(0); 2934 Node* const p1 = m.Parameter(1); 2935 Node* r = 2936 m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(24)), m.Int32Constant(24)); 2937 m.Return(m.Word32Equal(r, p0)); 2938 Stream s = m.Build(); 2939 ASSERT_EQ(1U, s.size()); 2940 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2941 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 2942 ASSERT_EQ(2U, s[0]->InputCount()); 2943 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2944 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2945 ASSERT_EQ(1U, s[0]->OutputCount()); 2946 } 2947} 2948 2949 2950TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendHalfword) { 2951 { 2952 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2953 MachineType::Int32()); 2954 Node* const p0 = m.Parameter(0); 2955 Node* const p1 = m.Parameter(1); 2956 Node* r = 2957 m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(16)), m.Int32Constant(16)); 2958 m.Return(m.Word32Equal(p0, r)); 2959 Stream s = m.Build(); 2960 ASSERT_EQ(1U, s.size()); 2961 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2962 EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); 2963 ASSERT_EQ(2U, s[0]->InputCount()); 2964 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2965 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2966 ASSERT_EQ(1U, s[0]->OutputCount()); 2967 } 2968 { 2969 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2970 MachineType::Int32()); 2971 Node* const p0 = m.Parameter(0); 2972 Node* const p1 = m.Parameter(1); 2973 Node* r = 2974 m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(16)), m.Int32Constant(16)); 2975 m.Return(m.Word32Equal(r, p0)); 2976 Stream s = m.Build(); 2977 ASSERT_EQ(1U, s.size()); 2978 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2979 EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); 2980 ASSERT_EQ(2U, s[0]->InputCount()); 2981 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 2982 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 2983 ASSERT_EQ(1U, s[0]->OutputCount()); 2984 } 2985} 2986 2987 2988TEST_F(InstructionSelectorTest, Word32EqualZeroWithWord32Equal) { 2989 { 2990 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 2991 MachineType::Int32()); 2992 Node* const p0 = m.Parameter(0); 2993 Node* const p1 = m.Parameter(1); 2994 m.Return(m.Word32Equal(m.Word32Equal(p0, p1), m.Int32Constant(0))); 2995 Stream s = m.Build(); 2996 ASSERT_EQ(1U, s.size()); 2997 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 2998 ASSERT_EQ(2U, s[0]->InputCount()); 2999 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3000 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3001 EXPECT_EQ(1U, s[0]->OutputCount()); 3002 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3003 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 3004 } 3005 { 3006 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3007 MachineType::Int32()); 3008 Node* const p0 = m.Parameter(0); 3009 Node* const p1 = m.Parameter(1); 3010 m.Return(m.Word32Equal(m.Int32Constant(0), m.Word32Equal(p0, p1))); 3011 Stream s = m.Build(); 3012 ASSERT_EQ(1U, s.size()); 3013 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 3014 ASSERT_EQ(2U, s[0]->InputCount()); 3015 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3016 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3017 EXPECT_EQ(1U, s[0]->OutputCount()); 3018 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3019 EXPECT_EQ(kNotEqual, s[0]->flags_condition()); 3020 } 3021} 3022 3023namespace { 3024 3025struct IntegerCmp { 3026 MachInst2 mi; 3027 FlagsCondition cond; 3028 FlagsCondition commuted_cond; 3029}; 3030 3031 3032std::ostream& operator<<(std::ostream& os, const IntegerCmp& cmp) { 3033 return os << cmp.mi; 3034} 3035 3036 3037// ARM64 32-bit integer comparison instructions. 3038const IntegerCmp kIntegerCmpInstructions[] = { 3039 {{&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, 3040 MachineType::Int32()}, 3041 kEqual, 3042 kEqual}, 3043 {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kArm64Cmp32, 3044 MachineType::Int32()}, 3045 kSignedLessThan, 3046 kSignedGreaterThan}, 3047 {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual", 3048 kArm64Cmp32, MachineType::Int32()}, 3049 kSignedLessThanOrEqual, 3050 kSignedGreaterThanOrEqual}, 3051 {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kArm64Cmp32, 3052 MachineType::Uint32()}, 3053 kUnsignedLessThan, 3054 kUnsignedGreaterThan}, 3055 {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual", 3056 kArm64Cmp32, MachineType::Uint32()}, 3057 kUnsignedLessThanOrEqual, 3058 kUnsignedGreaterThanOrEqual}}; 3059 3060} // namespace 3061 3062 3063TEST_F(InstructionSelectorTest, Word32CompareNegateWithWord32Shift) { 3064 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3065 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 3066 // Test 32-bit operations. Ignore ROR shifts, as compare-negate does not 3067 // support them. 3068 if (shift.mi.machine_type != MachineType::Int32() || 3069 shift.mi.arch_opcode == kArm64Ror32) { 3070 continue; 3071 } 3072 3073 TRACED_FORRANGE(int32_t, imm, -32, 63) { 3074 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3075 MachineType::Int32()); 3076 Node* const p0 = m.Parameter(0); 3077 Node* const p1 = m.Parameter(1); 3078 Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm)); 3079 m.Return( 3080 (m.*cmp.mi.constructor)(p0, m.Int32Sub(m.Int32Constant(0), r))); 3081 Stream s = m.Build(); 3082 ASSERT_EQ(1U, s.size()); 3083 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 3084 EXPECT_EQ(3U, s[0]->InputCount()); 3085 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 3086 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2))); 3087 EXPECT_EQ(1U, s[0]->OutputCount()); 3088 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3089 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 3090 } 3091 } 3092 } 3093} 3094 3095TEST_F(InstructionSelectorTest, CmpWithImmediateOnLeft) { 3096 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3097 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 3098 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which 3099 // is tested elsewhere. 3100 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; 3101 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3102 Node* const p0 = m.Parameter(0); 3103 RawMachineLabel a, b; 3104 m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), p0), &a, &b); 3105 m.Bind(&a); 3106 m.Return(m.Int32Constant(1)); 3107 m.Bind(&b); 3108 m.Return(m.Int32Constant(0)); 3109 Stream s = m.Build(); 3110 ASSERT_EQ(1U, s.size()); 3111 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 3112 ASSERT_LE(2U, s[0]->InputCount()); 3113 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 3114 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); 3115 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 3116 } 3117 } 3118} 3119 3120TEST_F(InstructionSelectorTest, CmnWithImmediateOnLeft) { 3121 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3122 TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { 3123 // kEqual and kNotEqual trigger the cbz/cbnz optimization, which 3124 // is tested elsewhere. 3125 if (cmp.cond == kEqual || cmp.cond == kNotEqual) continue; 3126 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3127 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); 3128 RawMachineLabel a, b; 3129 m.Branch((m.*cmp.mi.constructor)(m.Int32Constant(imm), sub), &a, &b); 3130 m.Bind(&a); 3131 m.Return(m.Int32Constant(1)); 3132 m.Bind(&b); 3133 m.Return(m.Int32Constant(0)); 3134 Stream s = m.Build(); 3135 ASSERT_EQ(1U, s.size()); 3136 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 3137 ASSERT_LE(2U, s[0]->InputCount()); 3138 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); 3139 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 3140 EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); 3141 } 3142 } 3143} 3144 3145TEST_F(InstructionSelectorTest, CmpSignedExtendByteOnLeft) { 3146 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3147 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3148 MachineType::Int32()); 3149 Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), 3150 m.Int32Constant(24)); 3151 m.Return((m.*cmp.mi.constructor)(extend, m.Parameter(1))); 3152 Stream s = m.Build(); 3153 ASSERT_EQ(1U, s.size()); 3154 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 3155 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3156 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); 3157 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 3158 } 3159} 3160 3161TEST_F(InstructionSelectorTest, CmnSignedExtendByteOnLeft) { 3162 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3163 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3164 MachineType::Int32()); 3165 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); 3166 Node* extend = m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), 3167 m.Int32Constant(24)); 3168 m.Return((m.*cmp.mi.constructor)(extend, sub)); 3169 Stream s = m.Build(); 3170 ASSERT_EQ(1U, s.size()); 3171 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 3172 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3173 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 3174 EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); 3175 } 3176} 3177 3178TEST_F(InstructionSelectorTest, CmpShiftByImmediateOnLeft) { 3179 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3180 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 3181 // Only test relevant shifted operands. 3182 if (shift.mi.machine_type != MachineType::Int32()) continue; 3183 3184 // The available shift operand range is `0 <= imm < 32`, but we also test 3185 // that immediates outside this range are handled properly (modulo-32). 3186 TRACED_FORRANGE(int, imm, -32, 63) { 3187 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3188 MachineType::Int32()); 3189 m.Return((m.*cmp.mi.constructor)( 3190 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)), 3191 m.Parameter(0))); 3192 Stream s = m.Build(); 3193 // Cmp does not support ROR shifts. 3194 if (shift.mi.arch_opcode == kArm64Ror32) { 3195 ASSERT_EQ(2U, s.size()); 3196 continue; 3197 } 3198 ASSERT_EQ(1U, s.size()); 3199 EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); 3200 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 3201 EXPECT_EQ(3U, s[0]->InputCount()); 3202 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 3203 EXPECT_EQ(1U, s[0]->OutputCount()); 3204 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3205 EXPECT_EQ(cmp.commuted_cond, s[0]->flags_condition()); 3206 } 3207 } 3208 } 3209} 3210 3211TEST_F(InstructionSelectorTest, CmnShiftByImmediateOnLeft) { 3212 TRACED_FOREACH(IntegerCmp, cmp, kIntegerCmpInstructions) { 3213 TRACED_FOREACH(Shift, shift, kShiftInstructions) { 3214 // Only test relevant shifted operands. 3215 if (shift.mi.machine_type != MachineType::Int32()) continue; 3216 3217 // The available shift operand range is `0 <= imm < 32`, but we also test 3218 // that immediates outside this range are handled properly (modulo-32). 3219 TRACED_FORRANGE(int, imm, -32, 63) { 3220 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3221 MachineType::Int32()); 3222 Node* sub = m.Int32Sub(m.Int32Constant(0), m.Parameter(0)); 3223 m.Return((m.*cmp.mi.constructor)( 3224 (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)), 3225 sub)); 3226 Stream s = m.Build(); 3227 // Cmn does not support ROR shifts. 3228 if (shift.mi.arch_opcode == kArm64Ror32) { 3229 ASSERT_EQ(2U, s.size()); 3230 continue; 3231 } 3232 ASSERT_EQ(1U, s.size()); 3233 EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); 3234 EXPECT_EQ(shift.mode, s[0]->addressing_mode()); 3235 EXPECT_EQ(3U, s[0]->InputCount()); 3236 EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); 3237 EXPECT_EQ(1U, s[0]->OutputCount()); 3238 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); 3239 EXPECT_EQ(cmp.cond, s[0]->flags_condition()); 3240 } 3241 } 3242 } 3243} 3244 3245 3246// ----------------------------------------------------------------------------- 3247// Miscellaneous 3248 3249 3250static const MachInst2 kLogicalWithNotRHSs[] = { 3251 {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, 3252 MachineType::Int32()}, 3253 {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, 3254 MachineType::Int64()}, 3255 {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, 3256 MachineType::Int32()}, 3257 {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, 3258 MachineType::Int64()}, 3259 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, 3260 MachineType::Int32()}, 3261 {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, 3262 MachineType::Int64()}}; 3263 3264 3265typedef InstructionSelectorTestWithParam<MachInst2> 3266 InstructionSelectorLogicalWithNotRHSTest; 3267 3268 3269TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) { 3270 const MachInst2 inst = GetParam(); 3271 const MachineType type = inst.machine_type; 3272 // Test cases where RHS is Xor(x, -1). 3273 { 3274 StreamBuilder m(this, type, type, type); 3275 if (type == MachineType::Int32()) { 3276 m.Return((m.*inst.constructor)( 3277 m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1)))); 3278 } else { 3279 ASSERT_EQ(MachineType::Int64(), type); 3280 m.Return((m.*inst.constructor)( 3281 m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1)))); 3282 } 3283 Stream s = m.Build(); 3284 ASSERT_EQ(1U, s.size()); 3285 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); 3286 EXPECT_EQ(2U, s[0]->InputCount()); 3287 EXPECT_EQ(1U, s[0]->OutputCount()); 3288 } 3289 { 3290 StreamBuilder m(this, type, type, type); 3291 if (type == MachineType::Int32()) { 3292 m.Return((m.*inst.constructor)( 3293 m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1))); 3294 } else { 3295 ASSERT_EQ(MachineType::Int64(), type); 3296 m.Return((m.*inst.constructor)( 3297 m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1))); 3298 } 3299 Stream s = m.Build(); 3300 ASSERT_EQ(1U, s.size()); 3301 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); 3302 EXPECT_EQ(2U, s[0]->InputCount()); 3303 EXPECT_EQ(1U, s[0]->OutputCount()); 3304 } 3305 // Test cases where RHS is Not(x). 3306 { 3307 StreamBuilder m(this, type, type, type); 3308 if (type == MachineType::Int32()) { 3309 m.Return( 3310 (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1)))); 3311 } else { 3312 ASSERT_EQ(MachineType::Int64(), type); 3313 m.Return( 3314 (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1)))); 3315 } 3316 Stream s = m.Build(); 3317 ASSERT_EQ(1U, s.size()); 3318 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); 3319 EXPECT_EQ(2U, s[0]->InputCount()); 3320 EXPECT_EQ(1U, s[0]->OutputCount()); 3321 } 3322 { 3323 StreamBuilder m(this, type, type, type); 3324 if (type == MachineType::Int32()) { 3325 m.Return( 3326 (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1))); 3327 } else { 3328 ASSERT_EQ(MachineType::Int64(), type); 3329 m.Return( 3330 (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1))); 3331 } 3332 Stream s = m.Build(); 3333 ASSERT_EQ(1U, s.size()); 3334 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); 3335 EXPECT_EQ(2U, s[0]->InputCount()); 3336 EXPECT_EQ(1U, s[0]->OutputCount()); 3337 } 3338} 3339 3340 3341INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, 3342 InstructionSelectorLogicalWithNotRHSTest, 3343 ::testing::ValuesIn(kLogicalWithNotRHSs)); 3344 3345 3346TEST_F(InstructionSelectorTest, Word32NotWithParameter) { 3347 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3348 m.Return(m.Word32Not(m.Parameter(0))); 3349 Stream s = m.Build(); 3350 ASSERT_EQ(1U, s.size()); 3351 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode()); 3352 EXPECT_EQ(1U, s[0]->InputCount()); 3353 EXPECT_EQ(1U, s[0]->OutputCount()); 3354} 3355 3356 3357TEST_F(InstructionSelectorTest, Word64NotWithParameter) { 3358 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3359 m.Return(m.Word64Not(m.Parameter(0))); 3360 Stream s = m.Build(); 3361 ASSERT_EQ(1U, s.size()); 3362 EXPECT_EQ(kArm64Not, s[0]->arch_opcode()); 3363 EXPECT_EQ(1U, s[0]->InputCount()); 3364 EXPECT_EQ(1U, s[0]->OutputCount()); 3365} 3366 3367 3368TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) { 3369 { 3370 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3371 m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1))); 3372 Stream s = m.Build(); 3373 ASSERT_EQ(1U, s.size()); 3374 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode()); 3375 EXPECT_EQ(1U, s[0]->InputCount()); 3376 EXPECT_EQ(1U, s[0]->OutputCount()); 3377 } 3378 { 3379 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3380 m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0))); 3381 Stream s = m.Build(); 3382 ASSERT_EQ(1U, s.size()); 3383 EXPECT_EQ(kArm64Not32, s[0]->arch_opcode()); 3384 EXPECT_EQ(1U, s[0]->InputCount()); 3385 EXPECT_EQ(1U, s[0]->OutputCount()); 3386 } 3387} 3388 3389 3390TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) { 3391 { 3392 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3393 m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1))); 3394 Stream s = m.Build(); 3395 ASSERT_EQ(1U, s.size()); 3396 EXPECT_EQ(kArm64Not, s[0]->arch_opcode()); 3397 EXPECT_EQ(1U, s[0]->InputCount()); 3398 EXPECT_EQ(1U, s[0]->OutputCount()); 3399 } 3400 { 3401 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3402 m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0))); 3403 Stream s = m.Build(); 3404 ASSERT_EQ(1U, s.size()); 3405 EXPECT_EQ(kArm64Not, s[0]->arch_opcode()); 3406 EXPECT_EQ(1U, s[0]->InputCount()); 3407 EXPECT_EQ(1U, s[0]->OutputCount()); 3408 } 3409} 3410 3411 3412TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) { 3413 // The available shift operand range is `0 <= imm < 32`, but we also test 3414 // that immediates outside this range are handled properly (modulo-32). 3415 TRACED_FORRANGE(int32_t, shift, -32, 63) { 3416 int32_t lsb = shift & 0x1f; 3417 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { 3418 uint32_t jnk = rng()->NextInt(); 3419 jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0; 3420 uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; 3421 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3422 m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)), 3423 m.Int32Constant(shift))); 3424 Stream s = m.Build(); 3425 ASSERT_EQ(1U, s.size()); 3426 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); 3427 ASSERT_EQ(3U, s[0]->InputCount()); 3428 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); 3429 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); 3430 } 3431 } 3432 TRACED_FORRANGE(int32_t, shift, -32, 63) { 3433 int32_t lsb = shift & 0x1f; 3434 TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { 3435 uint32_t jnk = rng()->NextInt(); 3436 jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0; 3437 uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; 3438 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3439 m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)), 3440 m.Int32Constant(shift))); 3441 Stream s = m.Build(); 3442 ASSERT_EQ(1U, s.size()); 3443 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); 3444 ASSERT_EQ(3U, s[0]->InputCount()); 3445 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); 3446 EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); 3447 } 3448 } 3449} 3450 3451 3452TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) { 3453 // The available shift operand range is `0 <= imm < 64`, but we also test 3454 // that immediates outside this range are handled properly (modulo-64). 3455 TRACED_FORRANGE(int32_t, shift, -64, 127) { 3456 int32_t lsb = shift & 0x3f; 3457 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) { 3458 uint64_t jnk = rng()->NextInt64(); 3459 jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0; 3460 uint64_t msk = 3461 ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk; 3462 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3463 m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)), 3464 m.Int64Constant(shift))); 3465 Stream s = m.Build(); 3466 ASSERT_EQ(1U, s.size()); 3467 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); 3468 ASSERT_EQ(3U, s[0]->InputCount()); 3469 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1))); 3470 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2))); 3471 } 3472 } 3473 TRACED_FORRANGE(int32_t, shift, -64, 127) { 3474 int32_t lsb = shift & 0x3f; 3475 TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) { 3476 uint64_t jnk = rng()->NextInt64(); 3477 jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0; 3478 uint64_t msk = 3479 ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk; 3480 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3481 m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)), 3482 m.Int64Constant(shift))); 3483 Stream s = m.Build(); 3484 ASSERT_EQ(1U, s.size()); 3485 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); 3486 ASSERT_EQ(3U, s[0]->InputCount()); 3487 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1))); 3488 EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2))); 3489 } 3490 } 3491} 3492 3493 3494TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) { 3495 // The available shift operand range is `0 <= imm < 32`, but we also test 3496 // that immediates outside this range are handled properly (modulo-32). 3497 TRACED_FORRANGE(int32_t, shift, -32, 63) { 3498 int32_t lsb = shift & 0x1f; 3499 TRACED_FORRANGE(int32_t, width, 1, 31) { 3500 uint32_t msk = (1 << width) - 1; 3501 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3502 m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)), 3503 m.Int32Constant(msk))); 3504 Stream s = m.Build(); 3505 ASSERT_EQ(1U, s.size()); 3506 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); 3507 ASSERT_EQ(3U, s[0]->InputCount()); 3508 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); 3509 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width; 3510 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2))); 3511 } 3512 } 3513 TRACED_FORRANGE(int32_t, shift, -32, 63) { 3514 int32_t lsb = shift & 0x1f; 3515 TRACED_FORRANGE(int32_t, width, 1, 31) { 3516 uint32_t msk = (1 << width) - 1; 3517 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3518 m.Return( 3519 m.Word32And(m.Int32Constant(msk), 3520 m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)))); 3521 Stream s = m.Build(); 3522 ASSERT_EQ(1U, s.size()); 3523 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); 3524 ASSERT_EQ(3U, s[0]->InputCount()); 3525 EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1))); 3526 int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width; 3527 EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2))); 3528 } 3529 } 3530} 3531 3532 3533TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) { 3534 // The available shift operand range is `0 <= imm < 64`, but we also test 3535 // that immediates outside this range are handled properly (modulo-64). 3536 TRACED_FORRANGE(int64_t, shift, -64, 127) { 3537 int64_t lsb = shift & 0x3f; 3538 TRACED_FORRANGE(int64_t, width, 1, 63) { 3539 uint64_t msk = (V8_UINT64_C(1) << width) - 1; 3540 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3541 m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(shift)), 3542 m.Int64Constant(msk))); 3543 Stream s = m.Build(); 3544 ASSERT_EQ(1U, s.size()); 3545 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); 3546 ASSERT_EQ(3U, s[0]->InputCount()); 3547 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1))); 3548 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width; 3549 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2))); 3550 } 3551 } 3552 TRACED_FORRANGE(int64_t, shift, -64, 127) { 3553 int64_t lsb = shift & 0x3f; 3554 TRACED_FORRANGE(int64_t, width, 1, 63) { 3555 uint64_t msk = (V8_UINT64_C(1) << width) - 1; 3556 StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); 3557 m.Return( 3558 m.Word64And(m.Int64Constant(msk), 3559 m.Word64Shr(m.Parameter(0), m.Int64Constant(shift)))); 3560 Stream s = m.Build(); 3561 ASSERT_EQ(1U, s.size()); 3562 EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); 3563 ASSERT_EQ(3U, s[0]->InputCount()); 3564 EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1))); 3565 int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width; 3566 EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2))); 3567 } 3568 } 3569} 3570 3571 3572TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) { 3573 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3574 MachineType::Int32()); 3575 Node* const p0 = m.Parameter(0); 3576 Node* const p1 = m.Parameter(1); 3577 Node* const n = m.Int32MulHigh(p0, p1); 3578 m.Return(n); 3579 Stream s = m.Build(); 3580 ASSERT_EQ(2U, s.size()); 3581 EXPECT_EQ(kArm64Smull, s[0]->arch_opcode()); 3582 ASSERT_EQ(2U, s[0]->InputCount()); 3583 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3584 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3585 ASSERT_EQ(1U, s[0]->OutputCount()); 3586 EXPECT_EQ(kArm64Asr, s[1]->arch_opcode()); 3587 ASSERT_EQ(2U, s[1]->InputCount()); 3588 EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); 3589 EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1))); 3590 ASSERT_EQ(1U, s[1]->OutputCount()); 3591 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output())); 3592} 3593 3594 3595TEST_F(InstructionSelectorTest, Int32MulHighWithSar) { 3596 TRACED_FORRANGE(int32_t, shift, -32, 63) { 3597 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3598 MachineType::Int32()); 3599 Node* const p0 = m.Parameter(0); 3600 Node* const p1 = m.Parameter(1); 3601 Node* const n = m.Word32Sar(m.Int32MulHigh(p0, p1), m.Int32Constant(shift)); 3602 m.Return(n); 3603 Stream s = m.Build(); 3604 ASSERT_EQ(2U, s.size()); 3605 EXPECT_EQ(kArm64Smull, s[0]->arch_opcode()); 3606 ASSERT_EQ(2U, s[0]->InputCount()); 3607 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3608 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3609 ASSERT_EQ(1U, s[0]->OutputCount()); 3610 EXPECT_EQ(kArm64Asr, s[1]->arch_opcode()); 3611 ASSERT_EQ(2U, s[1]->InputCount()); 3612 EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); 3613 EXPECT_EQ((shift & 0x1f) + 32, s.ToInt64(s[1]->InputAt(1))); 3614 ASSERT_EQ(1U, s[1]->OutputCount()); 3615 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output())); 3616 } 3617} 3618 3619 3620TEST_F(InstructionSelectorTest, Int32MulHighWithAdd) { 3621 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3622 MachineType::Int32()); 3623 Node* const p0 = m.Parameter(0); 3624 Node* const p1 = m.Parameter(1); 3625 Node* const a = m.Int32Add(m.Int32MulHigh(p0, p1), p0); 3626 // Test only one shift constant here, as we're only interested in it being a 3627 // 32-bit operation; the shift amount is irrelevant. 3628 Node* const n = m.Word32Sar(a, m.Int32Constant(1)); 3629 m.Return(n); 3630 Stream s = m.Build(); 3631 ASSERT_EQ(3U, s.size()); 3632 EXPECT_EQ(kArm64Smull, s[0]->arch_opcode()); 3633 ASSERT_EQ(2U, s[0]->InputCount()); 3634 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3635 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3636 ASSERT_EQ(1U, s[0]->OutputCount()); 3637 EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); 3638 EXPECT_EQ(kMode_Operand2_R_ASR_I, s[1]->addressing_mode()); 3639 ASSERT_EQ(3U, s[1]->InputCount()); 3640 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0))); 3641 EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1))); 3642 EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(2))); 3643 ASSERT_EQ(1U, s[1]->OutputCount()); 3644 EXPECT_EQ(kArm64Asr32, s[2]->arch_opcode()); 3645 ASSERT_EQ(2U, s[2]->InputCount()); 3646 EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(0))); 3647 EXPECT_EQ(1, s.ToInt64(s[2]->InputAt(1))); 3648 ASSERT_EQ(1U, s[2]->OutputCount()); 3649 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[2]->Output())); 3650} 3651 3652 3653TEST_F(InstructionSelectorTest, Uint32MulHighWithShr) { 3654 TRACED_FORRANGE(int32_t, shift, -32, 63) { 3655 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), 3656 MachineType::Int32()); 3657 Node* const p0 = m.Parameter(0); 3658 Node* const p1 = m.Parameter(1); 3659 Node* const n = 3660 m.Word32Shr(m.Uint32MulHigh(p0, p1), m.Int32Constant(shift)); 3661 m.Return(n); 3662 Stream s = m.Build(); 3663 ASSERT_EQ(2U, s.size()); 3664 EXPECT_EQ(kArm64Umull, s[0]->arch_opcode()); 3665 ASSERT_EQ(2U, s[0]->InputCount()); 3666 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3667 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3668 ASSERT_EQ(1U, s[0]->OutputCount()); 3669 EXPECT_EQ(kArm64Lsr, s[1]->arch_opcode()); 3670 ASSERT_EQ(2U, s[1]->InputCount()); 3671 EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); 3672 EXPECT_EQ((shift & 0x1f) + 32, s.ToInt64(s[1]->InputAt(1))); 3673 ASSERT_EQ(1U, s[1]->OutputCount()); 3674 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output())); 3675 } 3676} 3677 3678 3679TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) { 3680 TRACED_FORRANGE(int32_t, shift, 1, 31) { 3681 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3682 Node* const p0 = m.Parameter(0); 3683 Node* const r = m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(shift)), 3684 m.Int32Constant(shift)); 3685 m.Return(r); 3686 Stream s = m.Build(); 3687 ASSERT_EQ(1U, s.size()); 3688 EXPECT_EQ(kArm64Sbfx32, s[0]->arch_opcode()); 3689 ASSERT_EQ(3U, s[0]->InputCount()); 3690 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3691 ASSERT_EQ(1U, s[0]->OutputCount()); 3692 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); 3693 } 3694 TRACED_FORRANGE(int32_t, shift, 1, 31) { 3695 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3696 Node* const p0 = m.Parameter(0); 3697 Node* const r = m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(shift + 32)), 3698 m.Int32Constant(shift + 64)); 3699 m.Return(r); 3700 Stream s = m.Build(); 3701 ASSERT_EQ(1U, s.size()); 3702 EXPECT_EQ(kArm64Sbfx32, s[0]->arch_opcode()); 3703 ASSERT_EQ(3U, s[0]->InputCount()); 3704 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3705 ASSERT_EQ(1U, s[0]->OutputCount()); 3706 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); 3707 } 3708} 3709 3710 3711TEST_F(InstructionSelectorTest, Word32ShrWithWord32Shl) { 3712 TRACED_FORRANGE(int32_t, shift, 1, 31) { 3713 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3714 Node* const p0 = m.Parameter(0); 3715 Node* const r = m.Word32Shr(m.Word32Shl(p0, m.Int32Constant(shift)), 3716 m.Int32Constant(shift)); 3717 m.Return(r); 3718 Stream s = m.Build(); 3719 ASSERT_EQ(1U, s.size()); 3720 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); 3721 ASSERT_EQ(3U, s[0]->InputCount()); 3722 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3723 ASSERT_EQ(1U, s[0]->OutputCount()); 3724 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); 3725 } 3726 TRACED_FORRANGE(int32_t, shift, 1, 31) { 3727 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3728 Node* const p0 = m.Parameter(0); 3729 Node* const r = m.Word32Shr(m.Word32Shl(p0, m.Int32Constant(shift + 32)), 3730 m.Int32Constant(shift + 64)); 3731 m.Return(r); 3732 Stream s = m.Build(); 3733 ASSERT_EQ(1U, s.size()); 3734 EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); 3735 ASSERT_EQ(3U, s[0]->InputCount()); 3736 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3737 ASSERT_EQ(1U, s[0]->OutputCount()); 3738 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); 3739 } 3740} 3741 3742 3743TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) { 3744 TRACED_FORRANGE(int32_t, shift, 1, 30) { 3745 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3746 Node* const p0 = m.Parameter(0); 3747 Node* const r = 3748 m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)), 3749 m.Int32Constant(shift)); 3750 m.Return(r); 3751 Stream s = m.Build(); 3752 ASSERT_EQ(1U, s.size()); 3753 EXPECT_EQ(kArm64Ubfiz32, s[0]->arch_opcode()); 3754 ASSERT_EQ(3U, s[0]->InputCount()); 3755 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3756 ASSERT_EQ(1U, s[0]->OutputCount()); 3757 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); 3758 } 3759 TRACED_FORRANGE(int32_t, shift, 0, 30) { 3760 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 3761 Node* const p0 = m.Parameter(0); 3762 Node* const r = 3763 m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)), 3764 m.Int32Constant(shift + 1)); 3765 m.Return(r); 3766 Stream s = m.Build(); 3767 ASSERT_EQ(1U, s.size()); 3768 EXPECT_EQ(kArm64Lsl32, s[0]->arch_opcode()); 3769 ASSERT_EQ(2U, s[0]->InputCount()); 3770 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3771 ASSERT_EQ(1U, s[0]->OutputCount()); 3772 EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); 3773 } 3774} 3775 3776 3777TEST_F(InstructionSelectorTest, Word32Clz) { 3778 StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32()); 3779 Node* const p0 = m.Parameter(0); 3780 Node* const n = m.Word32Clz(p0); 3781 m.Return(n); 3782 Stream s = m.Build(); 3783 ASSERT_EQ(1U, s.size()); 3784 EXPECT_EQ(kArm64Clz32, s[0]->arch_opcode()); 3785 ASSERT_EQ(1U, s[0]->InputCount()); 3786 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3787 ASSERT_EQ(1U, s[0]->OutputCount()); 3788 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3789} 3790 3791 3792TEST_F(InstructionSelectorTest, Float32Abs) { 3793 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); 3794 Node* const p0 = m.Parameter(0); 3795 Node* const n = m.Float32Abs(p0); 3796 m.Return(n); 3797 Stream s = m.Build(); 3798 ASSERT_EQ(1U, s.size()); 3799 EXPECT_EQ(kArm64Float32Abs, s[0]->arch_opcode()); 3800 ASSERT_EQ(1U, s[0]->InputCount()); 3801 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3802 ASSERT_EQ(1U, s[0]->OutputCount()); 3803 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3804} 3805 3806 3807TEST_F(InstructionSelectorTest, Float64Abs) { 3808 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 3809 Node* const p0 = m.Parameter(0); 3810 Node* const n = m.Float64Abs(p0); 3811 m.Return(n); 3812 Stream s = m.Build(); 3813 ASSERT_EQ(1U, s.size()); 3814 EXPECT_EQ(kArm64Float64Abs, s[0]->arch_opcode()); 3815 ASSERT_EQ(1U, s[0]->InputCount()); 3816 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3817 ASSERT_EQ(1U, s[0]->OutputCount()); 3818 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3819} 3820 3821 3822TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) { 3823 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 3824 Node* const p0 = m.Parameter(0); 3825 Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); 3826 m.Return(n); 3827 Stream s = m.Build(); 3828 ASSERT_EQ(1U, s.size()); 3829 EXPECT_EQ(kArm64Float64Neg, s[0]->arch_opcode()); 3830 ASSERT_EQ(1U, s[0]->InputCount()); 3831 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3832 ASSERT_EQ(1U, s[0]->OutputCount()); 3833 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3834} 3835 3836 3837TEST_F(InstructionSelectorTest, Float32Max) { 3838 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), 3839 MachineType::Float32()); 3840 Node* const p0 = m.Parameter(0); 3841 Node* const p1 = m.Parameter(1); 3842 Node* const n = m.Float32Max(p0, p1); 3843 m.Return(n); 3844 Stream s = m.Build(); 3845 // Float32Max is `(b < a) ? a : b`. 3846 ASSERT_EQ(1U, s.size()); 3847 EXPECT_EQ(kArm64Float32Max, s[0]->arch_opcode()); 3848 ASSERT_EQ(2U, s[0]->InputCount()); 3849 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3850 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3851 ASSERT_EQ(1U, s[0]->OutputCount()); 3852 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3853} 3854 3855 3856TEST_F(InstructionSelectorTest, Float32Min) { 3857 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32(), 3858 MachineType::Float32()); 3859 Node* const p0 = m.Parameter(0); 3860 Node* const p1 = m.Parameter(1); 3861 Node* const n = m.Float32Min(p0, p1); 3862 m.Return(n); 3863 Stream s = m.Build(); 3864 // Float32Min is `(a < b) ? a : b`. 3865 ASSERT_EQ(1U, s.size()); 3866 EXPECT_EQ(kArm64Float32Min, s[0]->arch_opcode()); 3867 ASSERT_EQ(2U, s[0]->InputCount()); 3868 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3869 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3870 ASSERT_EQ(1U, s[0]->OutputCount()); 3871 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3872} 3873 3874 3875TEST_F(InstructionSelectorTest, Float64Max) { 3876 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), 3877 MachineType::Float64()); 3878 Node* const p0 = m.Parameter(0); 3879 Node* const p1 = m.Parameter(1); 3880 Node* const n = m.Float64Max(p0, p1); 3881 m.Return(n); 3882 Stream s = m.Build(); 3883 // Float64Max is `(b < a) ? a : b`. 3884 ASSERT_EQ(1U, s.size()); 3885 EXPECT_EQ(kArm64Float64Max, s[0]->arch_opcode()); 3886 ASSERT_EQ(2U, s[0]->InputCount()); 3887 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3888 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3889 ASSERT_EQ(1U, s[0]->OutputCount()); 3890 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3891} 3892 3893 3894TEST_F(InstructionSelectorTest, Float64Min) { 3895 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64(), 3896 MachineType::Float64()); 3897 Node* const p0 = m.Parameter(0); 3898 Node* const p1 = m.Parameter(1); 3899 Node* const n = m.Float64Min(p0, p1); 3900 m.Return(n); 3901 Stream s = m.Build(); 3902 // Float64Min is `(a < b) ? a : b`. 3903 ASSERT_EQ(1U, s.size()); 3904 EXPECT_EQ(kArm64Float64Min, s[0]->arch_opcode()); 3905 ASSERT_EQ(2U, s[0]->InputCount()); 3906 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3907 EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); 3908 ASSERT_EQ(1U, s[0]->OutputCount()); 3909 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3910} 3911 3912TEST_F(InstructionSelectorTest, Float32Neg) { 3913 StreamBuilder m(this, MachineType::Float32(), MachineType::Float32()); 3914 Node* const p0 = m.Parameter(0); 3915 // Don't use m.Float32Neg() as that generates an explicit sub. 3916 Node* const n = m.AddNode(m.machine()->Float32Neg().op(), m.Parameter(0)); 3917 m.Return(n); 3918 Stream s = m.Build(); 3919 ASSERT_EQ(1U, s.size()); 3920 EXPECT_EQ(kArm64Float32Neg, s[0]->arch_opcode()); 3921 ASSERT_EQ(1U, s[0]->InputCount()); 3922 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3923 ASSERT_EQ(1U, s[0]->OutputCount()); 3924 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3925} 3926 3927TEST_F(InstructionSelectorTest, Float64Neg) { 3928 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 3929 Node* const p0 = m.Parameter(0); 3930 // Don't use m.Float64Neg() as that generates an explicit sub. 3931 Node* const n = m.AddNode(m.machine()->Float64Neg().op(), m.Parameter(0)); 3932 m.Return(n); 3933 Stream s = m.Build(); 3934 ASSERT_EQ(1U, s.size()); 3935 EXPECT_EQ(kArm64Float64Neg, s[0]->arch_opcode()); 3936 ASSERT_EQ(1U, s[0]->InputCount()); 3937 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); 3938 ASSERT_EQ(1U, s[0]->OutputCount()); 3939 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); 3940} 3941 3942} // namespace compiler 3943} // namespace internal 3944} // namespace v8 3945