Revision: 22791
Author:   [email protected]
Date:     Fri Aug  1 12:18:20 2014 UTC
Log:      [turbofan] Add support for Int32SubWithOverflow.

TEST=cctest/test-run-machops,cctest/test-instruction-selector-arm
[email protected]

Review URL: https://codereview.chromium.org/432373002
http://code.google.com/p/v8/source/detail?r=22791

Modified:
 /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc
 /branches/bleeding_edge/src/compiler/arm64/code-generator-arm64.cc
 /branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
 /branches/bleeding_edge/src/compiler/ia32/instruction-selector-ia32.cc
 /branches/bleeding_edge/src/compiler/instruction-selector.cc
 /branches/bleeding_edge/src/compiler/machine-node-factory.h
 /branches/bleeding_edge/src/compiler/machine-operator.h
 /branches/bleeding_edge/src/compiler/opcodes.h
 /branches/bleeding_edge/src/compiler/x64/instruction-selector-x64.cc
/branches/bleeding_edge/test/cctest/compiler/test-instruction-selector-arm.cc
 /branches/bleeding_edge/test/cctest/compiler/test-run-machops.cc

=======================================
--- /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc Fri Aug 1 11:14:47 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm/instruction-selector-arm.cc Fri Aug 1 12:18:20 2014 UTC
@@ -614,6 +614,11 @@
   }
   VisitBinop(this, node, kArmSub, kArmRsb);
 }
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kArmSub, kArmRsb);
+}


 void InstructionSelector::VisitInt32Mul(Node* node) {
=======================================
--- /branches/bleeding_edge/src/compiler/arm64/code-generator-arm64.cc Fri Aug 1 09:32:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm64/code-generator-arm64.cc Fri Aug 1 12:18:20 2014 UTC
@@ -243,7 +243,12 @@
       __ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
       break;
     case kArm64Sub32:
- __ Sub(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      if (FlagsModeField::decode(opcode) != kFlags_none) {
+        __ Subs(i.OutputRegister32(), i.InputRegister32(0),
+                i.InputOperand32(1));
+      } else {
+ __ Sub(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      }
       break;
     case kArm64Shl:
       ASSEMBLE_SHIFT(Lsl, 64);
=======================================
--- /branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc Fri Aug 1 12:18:20 2014 UTC
@@ -359,6 +359,11 @@
 void InstructionSelector::VisitInt32Sub(Node* node) {
   VisitSub<int32_t>(this, node, kArm64Sub32, kArm64Neg32);
 }
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kArm64Sub32);
+}


 void InstructionSelector::VisitInt64Sub(Node* node) {
=======================================
--- /branches/bleeding_edge/src/compiler/ia32/instruction-selector-ia32.cc Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/ia32/instruction-selector-ia32.cc Fri Aug 1 12:18:20 2014 UTC
@@ -301,6 +301,11 @@
     VisitBinop(this, node, kIA32Sub);
   }
 }
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kIA32Sub);
+}


 void InstructionSelector::VisitInt32Mul(Node* node) {
=======================================
--- /branches/bleeding_edge/src/compiler/instruction-selector.cc Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/instruction-selector.cc Fri Aug 1 12:18:20 2014 UTC
@@ -511,6 +511,8 @@
       return VisitInt32AddWithOverflow(node);
     case IrOpcode::kInt32Sub:
       return VisitInt32Sub(node);
+    case IrOpcode::kInt32SubWithOverflow:
+      return VisitInt32SubWithOverflow(node);
     case IrOpcode::kInt32Mul:
       return VisitInt32Mul(node);
     case IrOpcode::kInt32Div:
=======================================
--- /branches/bleeding_edge/src/compiler/machine-node-factory.h Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/machine-node-factory.h Fri Aug 1 12:18:20 2014 UTC
@@ -84,6 +84,10 @@
         PrintableUnique<Object>::CreateUninitialized(ZONE(), object);
     return NEW_NODE_0(COMMON()->HeapConstant(val));
   }
+
+  Node* Projection(int index, Node* a) {
+    return NEW_NODE_1(COMMON()->Projection(index), a);
+  }

   // Memory Operations.
   Node* Load(MachineRepresentation rep, Node* base) {
@@ -198,12 +202,18 @@
   void Int32AddWithOverflow(Node* a, Node* b, Node** val_return,
                             Node** ovf_return) {
     Node* add = NEW_NODE_2(MACHINE()->Int32AddWithOverflow(), a, b);
-    if (val_return) *val_return = NEW_NODE_1(COMMON()->Projection(0), add);
-    if (ovf_return) *ovf_return = NEW_NODE_1(COMMON()->Projection(1), add);
+    if (val_return) *val_return = Projection(0, add);
+    if (ovf_return) *ovf_return = Projection(1, add);
   }
   Node* Int32Sub(Node* a, Node* b) {
     return NEW_NODE_2(MACHINE()->Int32Sub(), a, b);
   }
+  void Int32SubWithOverflow(Node* a, Node* b, Node** val_return,
+                            Node** ovf_return) {
+    Node* add = NEW_NODE_2(MACHINE()->Int32SubWithOverflow(), a, b);
+    if (val_return) *val_return = Projection(0, add);
+    if (ovf_return) *ovf_return = Projection(1, add);
+  }
   Node* Int32Mul(Node* a, Node* b) {
     return NEW_NODE_2(MACHINE()->Int32Mul(), a, b);
   }
=======================================
--- /branches/bleeding_edge/src/compiler/machine-operator.h Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/machine-operator.h Fri Aug 1 12:18:20 2014 UTC
@@ -68,6 +68,7 @@
                        inputs, outputs, #name, pname)

 #define BINOP(name) SIMPLE(name, Operator::kPure, 2, 1)
+#define BINOP_O(name) SIMPLE(name, Operator::kPure, 2, 2)
 #define BINOP_C(name) \
   SIMPLE(name, Operator::kCommutative | Operator::kPure, 2, 1)
#define BINOP_AC(name) \
@@ -119,6 +120,7 @@
   Operator* Int32Add() { BINOP_AC(Int32Add); }
   Operator* Int32AddWithOverflow() { BINOP_ACO(Int32AddWithOverflow); }
   Operator* Int32Sub() { BINOP(Int32Sub); }
+  Operator* Int32SubWithOverflow() { BINOP_O(Int32SubWithOverflow); }
   Operator* Int32Mul() { BINOP_AC(Int32Mul); }
   Operator* Int32Div() { BINOP(Int32Div); }
   Operator* Int32UDiv() { BINOP(Int32UDiv); }
=======================================
--- /branches/bleeding_edge/src/compiler/opcodes.h Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/opcodes.h Fri Aug 1 12:18:20 2014 UTC
@@ -175,6 +175,7 @@
   V(Int32Add)              \
   V(Int32AddWithOverflow)  \
   V(Int32Sub)              \
+  V(Int32SubWithOverflow)  \
   V(Int32Mul)              \
   V(Int32Div)              \
   V(Int32UDiv)             \
=======================================
--- /branches/bleeding_edge/src/compiler/x64/instruction-selector-x64.cc Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/src/compiler/x64/instruction-selector-x64.cc Fri Aug 1 12:18:20 2014 UTC
@@ -397,6 +397,11 @@
 void InstructionSelector::VisitInt32Sub(Node* node) {
   VisitSub<int32_t>(this, node, kX64Sub32, kX64Neg32);
 }
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kX64Sub32);
+}


 void InstructionSelector::VisitInt64Sub(Node* node) {
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/test-instruction-selector-arm.cc Fri Aug 1 11:14:47 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/test-instruction-selector-arm.cc Fri Aug 1 12:18:20 2014 UTC
@@ -41,6 +41,26 @@
 };


+struct ODPI {
+  Operator* op;
+  ArchOpcode arch_opcode;
+  ArchOpcode reverse_arch_opcode;
+};
+
+
+// ARM data processing instructions with overflow.
+class ODPIs V8_FINAL : public std::list<ODPI>, private HandleAndZoneScope {
+ public:
+  ODPIs() {
+    MachineOperatorBuilder machine(main_zone());
+    ODPI add = {machine.Int32AddWithOverflow(), kArmAdd, kArmAdd};
+    push_back(add);
+    ODPI sub = {machine.Int32SubWithOverflow(), kArmSub, kArmRsb};
+    push_back(sub);
+  }
+};
+
+
 // ARM immediates.
 class Immediates V8_FINAL : public std::list<int32_t> {
  public:
@@ -225,361 +245,349 @@
 }


-TEST(InstructionSelectorInt32AddWithOverflowP) {
-  {
-    InstructionSelectorTester m;
-    Node* ovf;
-    m.Int32AddWithOverflow(m.Parameter(0), m.Parameter(1), NULL, &ovf);
-    m.Return(ovf);
-    m.SelectInstructions();
-    CHECK_EQ(1, m.code.size());
-    CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-    CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
-    CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-    CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-    CHECK_EQ(2, m.code[0]->InputCount());
-    CHECK_EQ(1, m.code[0]->OutputCount());
-  }
-  {
-    InstructionSelectorTester m;
-    Node* val;
-    m.Int32AddWithOverflow(m.Parameter(0), m.Parameter(1), &val, NULL);
-    m.Return(val);
-    m.SelectInstructions();
-    CHECK_EQ(1, m.code.size());
-    CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-    CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
-    CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
-    CHECK_EQ(2, m.code[0]->InputCount());
-    CHECK_EQ(1, m.code[0]->OutputCount());
-  }
-  {
-    InstructionSelectorTester m;
-    Node* val, *ovf;
-    m.Int32AddWithOverflow(m.Parameter(0), m.Parameter(1), &val, &ovf);
-    m.Return(m.Word32Equal(val, ovf));
-    m.SelectInstructions();
-    CHECK_LE(1, m.code.size());
-    CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-    CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
-    CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-    CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-    CHECK_EQ(2, m.code[0]->InputCount());
-    CHECK_EQ(2, m.code[0]->OutputCount());
-  }
-}
-
-
-TEST(InstructionSelectorInt32AddWithOverflowImm) {
-  Immediates immediates;
- for (Immediates::const_iterator i = immediates.begin(); i != immediates.end();
-       ++i) {
-    int32_t imm = *i;
+TEST(InstructionSelectorODPIP) {
+  ODPIs odpis;
+  for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) {
+    ODPI odpi = *i;
     {
       InstructionSelectorTester m;
-      Node* ovf;
- m.Int32AddWithOverflow(m.Parameter(0), m.Int32Constant(imm), NULL, &ovf);
-      m.Return(ovf);
+      m.Return(
+ m.Projection(1, m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1))));
       m.SelectInstructions();
       CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+      CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
       CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
       CHECK_EQ(kOverflow, m.code[0]->flags_condition());
       CHECK_EQ(2, m.code[0]->InputCount());
-      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
       CHECK_EQ(1, m.code[0]->OutputCount());
     }
     {
       InstructionSelectorTester m;
-      Node* ovf;
- m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0), NULL, &ovf);
-      m.Return(ovf);
+      m.Return(
+ m.Projection(0, m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1))));
       m.SelectInstructions();
       CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-      CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-      CHECK_EQ(2, m.code[0]->InputCount());
-      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
-      CHECK_EQ(1, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* val;
- m.Int32AddWithOverflow(m.Parameter(0), m.Int32Constant(imm), &val, NULL);
-      m.Return(val);
-      m.SelectInstructions();
-      CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+      CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
       CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
       CHECK_EQ(2, m.code[0]->InputCount());
-      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
       CHECK_EQ(1, m.code[0]->OutputCount());
     }
     {
       InstructionSelectorTester m;
-      Node* val;
- m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0), &val, NULL);
-      m.Return(val);
-      m.SelectInstructions();
-      CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
-      CHECK_EQ(2, m.code[0]->InputCount());
-      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
-      CHECK_EQ(1, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* val, *ovf;
- m.Int32AddWithOverflow(m.Parameter(0), m.Int32Constant(imm), &val, &ovf);
-      m.Return(m.Word32Equal(val, ovf));
+      Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1));
+ m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
       m.SelectInstructions();
       CHECK_LE(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+      CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+      CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode());
       CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
       CHECK_EQ(kOverflow, m.code[0]->flags_condition());
       CHECK_EQ(2, m.code[0]->InputCount());
-      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
       CHECK_EQ(2, m.code[0]->OutputCount());
     }
-    {
-      InstructionSelectorTester m;
-      Node* val, *ovf;
- m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0), &val, &ovf);
-      m.Return(m.Word32Equal(val, ovf));
-      m.SelectInstructions();
-      CHECK_LE(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-      CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-      CHECK_EQ(2, m.code[0]->InputCount());
-      CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
-      CHECK_EQ(2, m.code[0]->OutputCount());
-    }
   }
 }


-TEST(InstructionSelectorInt32AddWithOverflowAndShiftP) {
-  Shifts shifts;
-  for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
-    Shift shift = *i;
-    {
-      InstructionSelectorTester m;
-      Node* ovf;
-      m.Int32AddWithOverflow(
- m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)),
-          NULL, &ovf);
-      m.Return(ovf);
-      m.SelectInstructions();
-      CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-      CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-      CHECK_EQ(3, m.code[0]->InputCount());
-      CHECK_EQ(1, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* ovf;
-      m.Int32AddWithOverflow(
- m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), m.Parameter(2),
-          NULL, &ovf);
-      m.Return(ovf);
-      m.SelectInstructions();
-      CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-      CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-      CHECK_EQ(3, m.code[0]->InputCount());
-      CHECK_EQ(1, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* val;
-      m.Int32AddWithOverflow(
- m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)),
-          &val, NULL);
-      m.Return(val);
-      m.SelectInstructions();
-      CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
-      CHECK_EQ(3, m.code[0]->InputCount());
-      CHECK_EQ(1, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* val;
-      m.Int32AddWithOverflow(
- m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), m.Parameter(2),
-          &val, NULL);
-      m.Return(val);
-      m.SelectInstructions();
-      CHECK_EQ(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
-      CHECK_EQ(3, m.code[0]->InputCount());
-      CHECK_EQ(1, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* val, *ovf;
-      m.Int32AddWithOverflow(
- m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)),
-          &val, &ovf);
-      m.Return(m.Word32Equal(val, ovf));
-      m.SelectInstructions();
-      CHECK_LE(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-      CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-      CHECK_EQ(3, m.code[0]->InputCount());
-      CHECK_EQ(2, m.code[0]->OutputCount());
-    }
-    {
-      InstructionSelectorTester m;
-      Node* val, *ovf;
-      m.Int32AddWithOverflow(
- m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), m.Parameter(2),
-          &val, &ovf);
-      m.Return(m.Word32Equal(val, ovf));
-      m.SelectInstructions();
-      CHECK_LE(1, m.code.size());
-      CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-      CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
-      CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
-      CHECK_EQ(kOverflow, m.code[0]->flags_condition());
-      CHECK_EQ(3, m.code[0]->InputCount());
-      CHECK_EQ(2, m.code[0]->OutputCount());
+TEST(InstructionSelectorODPIImm) {
+  ODPIs odpis;
+  Immediates immediates;
+  for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) {
+    ODPI odpi = *i;
+    for (Immediates::const_iterator j = immediates.begin();
+         j != immediates.end(); ++j) {
+      int32_t imm = *j;
+      {
+        InstructionSelectorTester m;
+        m.Return(m.Projection(
+            1, m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm))));
+        m.SelectInstructions();
+        CHECK_EQ(1, m.code.size());
+        CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+        CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+        CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+        CHECK_EQ(2, m.code[0]->InputCount());
+        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+        CHECK_EQ(1, m.code[0]->OutputCount());
+      }
+      {
+        InstructionSelectorTester m;
+        m.Return(m.Projection(
+            1, m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0))));
+        m.SelectInstructions();
+        CHECK_EQ(1, m.code.size());
+        CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+        CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+        CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+        CHECK_EQ(2, m.code[0]->InputCount());
+        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+        CHECK_EQ(1, m.code[0]->OutputCount());
+      }
+      {
+        InstructionSelectorTester m;
+        m.Return(m.Projection(
+            0, m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm))));
+        m.SelectInstructions();
+        CHECK_EQ(1, m.code.size());
+        CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+        CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
+        CHECK_EQ(2, m.code[0]->InputCount());
+        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+        CHECK_EQ(1, m.code[0]->OutputCount());
+      }
+      {
+        InstructionSelectorTester m;
+        m.Return(m.Projection(
+            0, m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0))));
+        m.SelectInstructions();
+        CHECK_EQ(1, m.code.size());
+        CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+        CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
+        CHECK_EQ(2, m.code[0]->InputCount());
+        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+        CHECK_EQ(1, m.code[0]->OutputCount());
+      }
+      {
+        InstructionSelectorTester m;
+ Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
+        m.SelectInstructions();
+        CHECK_LE(1, m.code.size());
+        CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+        CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+        CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+        CHECK_EQ(2, m.code[0]->InputCount());
+        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+        CHECK_EQ(2, m.code[0]->OutputCount());
+      }
+      {
+        InstructionSelectorTester m;
+ Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
+        m.SelectInstructions();
+        CHECK_LE(1, m.code.size());
+        CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode());
+        CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+        CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+        CHECK_EQ(2, m.code[0]->InputCount());
+        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1)));
+        CHECK_EQ(2, m.code[0]->OutputCount());
+      }
     }
   }
 }


-TEST(InstructionSelectorInt32AddWithOverflowAndShiftImm) {
+TEST(InstructionSelectorODPIAndShiftP) {
+  ODPIs odpis;
   Shifts shifts;
-  for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) {
-    Shift shift = *i;
-    for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) {
+  for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) {
+    ODPI odpi = *i;
+ for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) {
+      Shift shift = *j;
       {
         InstructionSelectorTester m;
-        Node* ovf;
-        m.Int32AddWithOverflow(
-            m.Parameter(0),
- m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)), NULL,
-            &ovf);
-        m.Return(ovf);
+        m.Return(m.Projection(
+            1, m.NewNode(odpi.op, m.Parameter(0),
+ m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)))));
         m.SelectInstructions();
         CHECK_EQ(1, m.code.size());
-        CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-        CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+        CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
         CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
         CHECK_EQ(kOverflow, m.code[0]->flags_condition());
         CHECK_EQ(3, m.code[0]->InputCount());
-        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
         CHECK_EQ(1, m.code[0]->OutputCount());
       }
       {
         InstructionSelectorTester m;
-        Node* ovf;
-        m.Int32AddWithOverflow(
-            m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)),
-            m.Parameter(1), NULL, &ovf);
-        m.Return(ovf);
+        m.Return(m.Projection(
+            1, m.NewNode(odpi.op,
+ m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)),
+                         m.Parameter(2))));
         m.SelectInstructions();
         CHECK_EQ(1, m.code.size());
-        CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-        CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+        CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
         CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
         CHECK_EQ(kOverflow, m.code[0]->flags_condition());
         CHECK_EQ(3, m.code[0]->InputCount());
-        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
         CHECK_EQ(1, m.code[0]->OutputCount());
       }
       {
         InstructionSelectorTester m;
-        Node* val;
-        m.Int32AddWithOverflow(
-            m.Parameter(0),
- m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)), &val,
-            NULL);
-        m.Return(val);
+        m.Return(m.Projection(
+            0, m.NewNode(odpi.op, m.Parameter(0),
+ m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)))));
         m.SelectInstructions();
         CHECK_EQ(1, m.code.size());
-        CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-        CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+        CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
         CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
         CHECK_EQ(3, m.code[0]->InputCount());
-        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
         CHECK_EQ(1, m.code[0]->OutputCount());
       }
       {
         InstructionSelectorTester m;
-        Node* val;
-        m.Int32AddWithOverflow(
-            m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)),
-            m.Parameter(1), &val, NULL);
-        m.Return(val);
+        m.Return(m.Projection(
+            0, m.NewNode(odpi.op,
+ m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)),
+                         m.Parameter(2))));
         m.SelectInstructions();
         CHECK_EQ(1, m.code.size());
-        CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-        CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+        CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
         CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
         CHECK_EQ(3, m.code[0]->InputCount());
-        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
         CHECK_EQ(1, m.code[0]->OutputCount());
       }
       {
         InstructionSelectorTester m;
-        Node* val, *ovf;
-        m.Int32AddWithOverflow(
-            m.Parameter(0),
- m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)), &val,
-            &ovf);
-        m.Return(m.Word32Equal(val, ovf));
+        Node* node =
+            m.NewNode(odpi.op, m.Parameter(0),
+                      m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)));
+ m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
         m.SelectInstructions();
         CHECK_LE(1, m.code.size());
-        CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-        CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+        CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
         CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
         CHECK_EQ(kOverflow, m.code[0]->flags_condition());
         CHECK_EQ(3, m.code[0]->InputCount());
-        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
         CHECK_EQ(2, m.code[0]->OutputCount());
       }
       {
         InstructionSelectorTester m;
-        Node* val, *ovf;
-        m.Int32AddWithOverflow(
-            m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)),
-            m.Parameter(1), &val, &ovf);
-        m.Return(m.Word32Equal(val, ovf));
+        Node* node = m.NewNode(
+            odpi.op, m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)),
+            m.Parameter(2));
+ m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
         m.SelectInstructions();
         CHECK_LE(1, m.code.size());
-        CHECK_EQ(kArmAdd, m.code[0]->arch_opcode());
-        CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+        CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+        CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode());
         CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
         CHECK_EQ(kOverflow, m.code[0]->flags_condition());
         CHECK_EQ(3, m.code[0]->InputCount());
-        CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
         CHECK_EQ(2, m.code[0]->OutputCount());
       }
     }
   }
 }
+
+
+TEST(InstructionSelectorODPIAndShiftImm) {
+  ODPIs odpis;
+  Shifts shifts;
+  for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) {
+    ODPI odpi = *i;
+ for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) {
+      Shift shift = *j;
+      for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) {
+        {
+          InstructionSelectorTester m;
+          m.Return(m.Projection(1, m.NewNode(odpi.op, m.Parameter(0),
+ m.NewNode(shift.op, m.Parameter(1), + m.Int32Constant(imm)))));
+          m.SelectInstructions();
+          CHECK_EQ(1, m.code.size());
+          CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+          CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+          CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+          CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+          CHECK_EQ(3, m.code[0]->InputCount());
+          CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
+          CHECK_EQ(1, m.code[0]->OutputCount());
+        }
+        {
+          InstructionSelectorTester m;
+          m.Return(m.Projection(
+              1, m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0),
+                                              m.Int32Constant(imm)),
+                           m.Parameter(1))));
+          m.SelectInstructions();
+          CHECK_EQ(1, m.code.size());
+          CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+          CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+          CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+          CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+          CHECK_EQ(3, m.code[0]->InputCount());
+          CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
+          CHECK_EQ(1, m.code[0]->OutputCount());
+        }
+        {
+          InstructionSelectorTester m;
+          m.Return(m.Projection(0, m.NewNode(odpi.op, m.Parameter(0),
+ m.NewNode(shift.op, m.Parameter(1), + m.Int32Constant(imm)))));
+          m.SelectInstructions();
+          CHECK_EQ(1, m.code.size());
+          CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+          CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+          CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
+          CHECK_EQ(3, m.code[0]->InputCount());
+          CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
+          CHECK_EQ(1, m.code[0]->OutputCount());
+        }
+        {
+          InstructionSelectorTester m;
+          m.Return(m.Projection(
+              0, m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0),
+                                              m.Int32Constant(imm)),
+                           m.Parameter(1))));
+          m.SelectInstructions();
+          CHECK_EQ(1, m.code.size());
+          CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+          CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+          CHECK_EQ(kFlags_none, m.code[0]->flags_mode());
+          CHECK_EQ(3, m.code[0]->InputCount());
+          CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
+          CHECK_EQ(1, m.code[0]->OutputCount());
+        }
+        {
+          InstructionSelectorTester m;
+          Node* node = m.NewNode(
+              odpi.op, m.Parameter(0),
+              m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)));
+ m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
+          m.SelectInstructions();
+          CHECK_LE(1, m.code.size());
+          CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode());
+          CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+          CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+          CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+          CHECK_EQ(3, m.code[0]->InputCount());
+          CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
+          CHECK_EQ(2, m.code[0]->OutputCount());
+        }
+        {
+          InstructionSelectorTester m;
+ Node* node = m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0),
+                                                    m.Int32Constant(imm)),
+                                 m.Parameter(1));
+ m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node)));
+          m.SelectInstructions();
+          CHECK_LE(1, m.code.size());
+          CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode());
+          CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode());
+          CHECK_EQ(kFlags_set, m.code[0]->flags_mode());
+          CHECK_EQ(kOverflow, m.code[0]->flags_condition());
+          CHECK_EQ(3, m.code[0]->InputCount());
+          CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2)));
+          CHECK_EQ(2, m.code[0]->OutputCount());
+        }
+      }
+    }
+  }
+}


 TEST(InstructionSelectorWord32AndAndWord32XorWithMinus1P) {
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/test-run-machops.cc Fri Aug 1 10:54:58 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/test-run-machops.cc Fri Aug 1 12:18:20 2014 UTC
@@ -3889,6 +3889,14 @@
   *val = v;
   return (((v ^ x) & (v ^ y)) >> 31) & 1;
 }
+
+
+static bool ssub_overflow(int32_t x, int32_t y, int32_t* val) {
+  int32_t v =
+ static_cast<int32_t>(static_cast<uint32_t>(x) - static_cast<uint32_t>(y));
+  *val = v;
+  return (((v ^ x) & (v ^ ~y)) >> 31) & 1;
+}


 TEST(RunInt32AddWithOverflowP) {
@@ -3971,5 +3979,87 @@
     }
   }
 }
+
+
+TEST(RunInt32SubWithOverflowP) {
+  int32_t actual_val = -1;
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  Node* val, *ovf;
+  m.Int32SubWithOverflow(bt.param0, bt.param1, &val, &ovf);
+  m.StoreToPointer(&actual_val, kMachineWord32, val);
+  bt.AddReturn(ovf);
+  FOR_INT32_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      int32_t expected_val;
+      int expected_ovf = ssub_overflow(*i, *j, &expected_val);
+      CHECK_EQ(expected_ovf, bt.call(*i, *j));
+      CHECK_EQ(expected_val, actual_val);
+    }
+  }
+}
+
+
+TEST(RunInt32SubWithOverflowImm) {
+  int32_t actual_val = -1, expected_val = 0;
+  FOR_INT32_INPUTS(i) {
+    {
+      RawMachineAssemblerTester<int32_t> m(kMachineWord32);
+      Node* val, *ovf;
+ m.Int32SubWithOverflow(m.Int32Constant(*i), m.Parameter(0), &val, &ovf);
+      m.StoreToPointer(&actual_val, kMachineWord32, val);
+      m.Return(ovf);
+      FOR_INT32_INPUTS(j) {
+        int expected_ovf = ssub_overflow(*i, *j, &expected_val);
+        CHECK_EQ(expected_ovf, m.Call(*j));
+        CHECK_EQ(expected_val, actual_val);
+      }
+    }
+    {
+      RawMachineAssemblerTester<int32_t> m(kMachineWord32);
+      Node* val, *ovf;
+ m.Int32SubWithOverflow(m.Parameter(0), m.Int32Constant(*i), &val, &ovf);
+      m.StoreToPointer(&actual_val, kMachineWord32, val);
+      m.Return(ovf);
+      FOR_INT32_INPUTS(j) {
+        int expected_ovf = ssub_overflow(*j, *i, &expected_val);
+        CHECK_EQ(expected_ovf, m.Call(*j));
+        CHECK_EQ(expected_val, actual_val);
+      }
+    }
+    FOR_INT32_INPUTS(j) {
+      RawMachineAssemblerTester<int32_t> m;
+      Node* val, *ovf;
+ m.Int32SubWithOverflow(m.Int32Constant(*i), m.Int32Constant(*j), &val,
+                             &ovf);
+      m.StoreToPointer(&actual_val, kMachineWord32, val);
+      m.Return(ovf);
+      int expected_ovf = ssub_overflow(*i, *j, &expected_val);
+      CHECK_EQ(expected_ovf, m.Call());
+      CHECK_EQ(expected_val, actual_val);
+    }
+  }
+}
+
+
+TEST(RunInt32SubWithOverflowInBranchP) {
+  MLabel blocka, blockb;
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  Node* val, *ovf;
+  m.Int32SubWithOverflow(bt.param0, bt.param1, &val, &ovf);
+  m.Branch(ovf, &blocka, &blockb);
+  m.Bind(&blocka);
+  bt.AddReturn(m.Word32Not(val));
+  m.Bind(&blockb);
+  bt.AddReturn(val);
+  FOR_UINT32_INPUTS(i) {
+    FOR_UINT32_INPUTS(j) {
+      int32_t expected;
+      if (ssub_overflow(*i, *j, &expected)) expected = ~expected;
+      CHECK_EQ(expected, bt.call(*i, *j));
+    }
+  }
+}

 #endif  // V8_TURBOFAN_TARGET

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to