| Index: test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc | 
| diff --git a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc | 
| index 6f0388907c063f010af14b4333387823345c965f..b4c31457182c80476dea307a3d1fe4788c7b24f8 100644 | 
| --- a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc | 
| +++ b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc | 
| @@ -30,6 +30,17 @@ std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) { | 
| } | 
|  | 
|  | 
| +struct Shift { | 
| +  MachInst2 mi; | 
| +  AddressingMode mode; | 
| +}; | 
| + | 
| + | 
| +std::ostream& operator<<(std::ostream& os, const Shift& shift) { | 
| +  return os << shift.mi; | 
| +} | 
| + | 
| + | 
| // Helper to build Int32Constant or Int64Constant depending on the given | 
| // machine type. | 
| Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type, | 
| @@ -139,15 +150,23 @@ static const MachInst2 kOvfAddSubInstructions[] = { | 
|  | 
|  | 
| // ARM64 shift instructions. | 
| -static const MachInst2 kShiftInstructions[] = { | 
| -    {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, kMachInt32}, | 
| -    {&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, kMachInt64}, | 
| -    {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, kMachInt32}, | 
| -    {&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr, kMachInt64}, | 
| -    {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, kMachInt32}, | 
| -    {&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr, kMachInt64}, | 
| -    {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32}, | 
| -    {&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64}}; | 
| +static const Shift kShiftInstructions[] = { | 
| +    {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, kMachInt32}, | 
| +     kMode_Operand2_R_LSL_I}, | 
| +    {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, kMachInt64}, | 
| +     kMode_Operand2_R_LSL_I}, | 
| +    {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, kMachInt32}, | 
| +     kMode_Operand2_R_LSR_I}, | 
| +    {{&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr, kMachInt64}, | 
| +     kMode_Operand2_R_LSR_I}, | 
| +    {{&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, kMachInt32}, | 
| +     kMode_Operand2_R_ASR_I}, | 
| +    {{&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr, kMachInt64}, | 
| +     kMode_Operand2_R_ASR_I}, | 
| +    {{&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32}, | 
| +     kMode_Operand2_R_ROR_I}, | 
| +    {{&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64}, | 
| +     kMode_Operand2_R_ROR_I}}; | 
|  | 
|  | 
| // ARM64 Mul/Div instructions. | 
| @@ -296,6 +315,46 @@ TEST_P(InstructionSelectorLogicalTest, Immediate) { | 
| } | 
|  | 
|  | 
| +TEST_P(InstructionSelectorLogicalTest, ShiftByImmediate) { | 
| +  const MachInst2 dpi = GetParam(); | 
| +  const MachineType type = dpi.machine_type; | 
| +  TRACED_FOREACH(Shift, shift, kShiftInstructions) { | 
| +    // Only test 64-bit shifted operands with 64-bit instructions. | 
| +    if (shift.mi.machine_type != type) continue; | 
| + | 
| +    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) { | 
| +      StreamBuilder m(this, type, type, type); | 
| +      m.Return((m.*dpi.constructor)( | 
| +          m.Parameter(0), | 
| +          (m.*shift.mi.constructor)(m.Parameter(1), | 
| +                                    BuildConstant(m, type, imm)))); | 
| +      Stream s = m.Build(); | 
| +      ASSERT_EQ(1U, s.size()); | 
| +      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | 
| +      EXPECT_EQ(shift.mode, s[0]->addressing_mode()); | 
| +      EXPECT_EQ(3U, s[0]->InputCount()); | 
| +      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); | 
| +      EXPECT_EQ(1U, s[0]->OutputCount()); | 
| +    } | 
| + | 
| +    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) { | 
| +      StreamBuilder m(this, type, type, type); | 
| +      m.Return((m.*dpi.constructor)( | 
| +          (m.*shift.mi.constructor)(m.Parameter(1), | 
| +                                    BuildConstant(m, type, imm)), | 
| +          m.Parameter(0))); | 
| +      Stream s = m.Build(); | 
| +      ASSERT_EQ(1U, s.size()); | 
| +      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | 
| +      EXPECT_EQ(shift.mode, s[0]->addressing_mode()); | 
| +      EXPECT_EQ(3U, s[0]->InputCount()); | 
| +      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); | 
| +      EXPECT_EQ(1U, s[0]->OutputCount()); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest, | 
| ::testing::ValuesIn(kLogicalInstructions)); | 
|  | 
| @@ -356,6 +415,37 @@ TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) { | 
| } | 
|  | 
|  | 
| +TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) { | 
| +  const AddSub dpi = GetParam(); | 
| +  const MachineType type = dpi.mi.machine_type; | 
| +  TRACED_FOREACH(Shift, shift, kShiftInstructions) { | 
| +    // Only test 64-bit shifted operands with 64-bit instructions. | 
| +    if (shift.mi.machine_type != type) continue; | 
| + | 
| +    if ((shift.mi.arch_opcode == kArm64Ror32) || | 
| +        (shift.mi.arch_opcode == kArm64Ror)) { | 
| +      // Not supported by add/sub instructions. | 
| +      continue; | 
| +    } | 
| + | 
| +    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) { | 
| +      StreamBuilder m(this, type, type, type); | 
| +      m.Return((m.*dpi.mi.constructor)( | 
| +          m.Parameter(0), | 
| +          (m.*shift.mi.constructor)(m.Parameter(1), | 
| +                                    BuildConstant(m, type, imm)))); | 
| +      Stream s = m.Build(); | 
| +      ASSERT_EQ(1U, s.size()); | 
| +      EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); | 
| +      EXPECT_EQ(shift.mode, s[0]->addressing_mode()); | 
| +      EXPECT_EQ(3U, s[0]->InputCount()); | 
| +      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); | 
| +      EXPECT_EQ(1U, s[0]->OutputCount()); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, | 
| ::testing::ValuesIn(kAddSubInstructions)); | 
|  | 
| @@ -455,6 +545,51 @@ TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) { | 
| } | 
|  | 
|  | 
| +TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) { | 
| +  // 32-bit add. | 
| +  TRACED_FOREACH(Shift, shift, kShiftInstructions) { | 
| +    // Only test relevant shifted operands. | 
| +    if (shift.mi.machine_type != kMachInt32) continue; | 
| +    if (shift.mi.arch_opcode == kArm64Ror32) continue; | 
| + | 
| +    TRACED_FORRANGE(int, imm, 0, 31) { | 
| +      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); | 
| +      m.Return((m.Int32Add)( | 
| +          (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)), | 
| +          m.Parameter(0))); | 
| +      Stream s = m.Build(); | 
| +      ASSERT_EQ(1U, s.size()); | 
| +      EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); | 
| +      EXPECT_EQ(shift.mode, s[0]->addressing_mode()); | 
| +      EXPECT_EQ(3U, s[0]->InputCount()); | 
| +      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); | 
| +      EXPECT_EQ(1U, s[0]->OutputCount()); | 
| +    } | 
| +  } | 
| + | 
| +  // 64-bit add. | 
| +  TRACED_FOREACH(Shift, shift, kShiftInstructions) { | 
| +    // Only test relevant shifted operands. | 
| +    if (shift.mi.machine_type != kMachInt64) continue; | 
| +    if (shift.mi.arch_opcode == kArm64Ror) continue; | 
| + | 
| +    TRACED_FORRANGE(int, imm, 0, 63) { | 
| +      StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); | 
| +      m.Return((m.Int64Add)( | 
| +          (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)), | 
| +          m.Parameter(0))); | 
| +      Stream s = m.Build(); | 
| +      ASSERT_EQ(1U, s.size()); | 
| +      EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); | 
| +      EXPECT_EQ(shift.mode, s[0]->addressing_mode()); | 
| +      EXPECT_EQ(3U, s[0]->InputCount()); | 
| +      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2))); | 
| +      EXPECT_EQ(1U, s[0]->OutputCount()); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| // ----------------------------------------------------------------------------- | 
| // Data processing controlled branches. | 
|  | 
| @@ -818,32 +953,31 @@ TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) { | 
| // Shift instructions. | 
|  | 
|  | 
| -typedef InstructionSelectorTestWithParam<MachInst2> | 
| -    InstructionSelectorShiftTest; | 
| +typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest; | 
|  | 
|  | 
| TEST_P(InstructionSelectorShiftTest, Parameter) { | 
| -  const MachInst2 dpi = GetParam(); | 
| -  const MachineType type = dpi.machine_type; | 
| +  const Shift shift = GetParam(); | 
| +  const MachineType type = shift.mi.machine_type; | 
| StreamBuilder m(this, type, type, type); | 
| -  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); | 
| +  m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Parameter(1))); | 
| Stream s = m.Build(); | 
| ASSERT_EQ(1U, s.size()); | 
| -  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | 
| +  EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode()); | 
| EXPECT_EQ(2U, s[0]->InputCount()); | 
| EXPECT_EQ(1U, s[0]->OutputCount()); | 
| } | 
|  | 
|  | 
| TEST_P(InstructionSelectorShiftTest, Immediate) { | 
| -  const MachInst2 dpi = GetParam(); | 
| -  const MachineType type = dpi.machine_type; | 
| +  const Shift shift = GetParam(); | 
| +  const MachineType type = shift.mi.machine_type; | 
| TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) { | 
| StreamBuilder m(this, type, type); | 
| -    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))); | 
| +    m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Int32Constant(imm))); | 
| Stream s = m.Build(); | 
| ASSERT_EQ(1U, s.size()); | 
| -    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); | 
| +    EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode()); | 
| EXPECT_EQ(2U, s[0]->InputCount()); | 
| EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); | 
| EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); | 
|  |