From 64a2717529e2197f3a789adabf86ca36f5eb764c Mon Sep 17 00:00:00 2001 From: Benedikt Meurer Date: Thu, 19 Feb 2015 10:41:39 +0100 Subject: [PATCH] [x64] Improve instruction selection for TruncateInt64ToInt32. R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/936323004 Cr-Commit-Position: refs/heads/master@{#26739} --- src/compiler/x64/instruction-selector-x64.cc | 22 +++++-- .../x64/instruction-selector-x64-unittest.cc | 73 +++++++++++----------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index db2d8cb..0689eb9 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -812,12 +812,22 @@ void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) { Node* value = node->InputAt(0); if (CanCover(node, value)) { switch (value->opcode()) { - case IrOpcode::kWord64Sar: - case IrOpcode::kWord64Shr: { + case IrOpcode::kWord64Sar: { Int64BinopMatcher m(value); - if (m.right().Is(32)) { + if (m.right().IsInRange(1, 32)) { Emit(kX64Shr, g.DefineSameAsFirst(node), - g.UseRegister(m.left().node()), g.TempImmediate(32)); + g.UseRegister(m.left().node()), + g.UseImmediate(m.right().node())); + return; + } + break; + } + case IrOpcode::kWord64Shl: { + Int64BinopMatcher m(value); + if (m.right().IsInRange(1, 31)) { + Emit(kX64Shl32, g.DefineSameAsFirst(node), + g.UseRegister(m.left().node()), + g.UseImmediate(m.right().node())); return; } break; @@ -826,7 +836,9 @@ void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) { break; } } - Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value)); + // Otherwise truncation from 64-bit to 32-bit is a no-nop, as 32-bit + // operations just ignore the upper 64-bit. + Emit(kArchNop, g.DefineAsRegister(node), g.Use(value)); } diff --git a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index 1f374c0..e524764 100644 --- a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -63,15 +63,6 @@ TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) { } -TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) { - StreamBuilder m(this, kMachInt32, kMachInt64); - m.Return(m.TruncateInt64ToInt32(m.Parameter(0))); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); -} - - // ----------------------------------------------------------------------------- // Loads and stores @@ -206,37 +197,49 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, // TruncateInt64ToInt32. -TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) { +TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) { StreamBuilder m(this, kMachInt32, kMachInt64); - Node* const p = m.Parameter(0); - Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32))); - m.Return(t); + m.Return(m.TruncateInt64ToInt32(m.Parameter(0))); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); - ASSERT_EQ(2U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); - EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); + ASSERT_EQ(0U, s.size()); } -TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) { - StreamBuilder m(this, kMachInt32, kMachInt64); - Node* const p = m.Parameter(0); - Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32))); - m.Return(t); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); - ASSERT_EQ(2U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); - EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); +TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) { + TRACED_FORRANGE(int32_t, k, 1, 32) { + StreamBuilder m(this, kMachInt32, kMachInt64); + Node* const p = m.Parameter(0); + Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(k))); + m.Return(t); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Shr, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); + EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); + } +} + + +TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shl) { + TRACED_FORRANGE(int32_t, k, 1, 31) { + StreamBuilder m(this, kMachInt32, kMachInt64); + Node* const p = m.Parameter(0); + Node* const t = m.TruncateInt64ToInt32(m.Word64Shl(p, m.Int64Constant(k))); + m.Return(t); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Shl32, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0))); + EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0))); + } } -- 2.7.4