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