[x64] Improve instruction selection for TruncateInt64ToInt32.
authorBenedikt Meurer <bmeurer@chromium.org>
Thu, 19 Feb 2015 09:41:39 +0000 (10:41 +0100)
committerBenedikt Meurer <bmeurer@chromium.org>
Thu, 19 Feb 2015 09:41:53 +0000 (09:41 +0000)
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
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index db2d8cb..0689eb9 100644 (file)
@@ -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));
 }
 
 
index 1f374c0..e524764 100644 (file)
@@ -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)));
+  }
 }