[turbofan] Add support for Int32SubWithOverflow.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 1 Aug 2014 12:18:20 +0000 (12:18 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 1 Aug 2014 12:18:20 +0000 (12:18 +0000)
TEST=cctest/test-run-machops,cctest/test-instruction-selector-arm
R=titzer@chromium.org

Review URL: https://codereview.chromium.org/432373002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22791 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

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

index 71c854b..e3c4f9b 100644 (file)
@@ -616,6 +616,11 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kArmSub, kArmRsb);
+}
+
+
 void InstructionSelector::VisitInt32Mul(Node* node) {
   ArmOperandGenerator g(this);
   Int32BinopMatcher m(node);
index 91bbc2d..85a5c58 100644 (file)
@@ -243,7 +243,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ 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);
index 22738a6..5a513a5 100644 (file)
@@ -361,6 +361,11 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kArm64Sub32);
+}
+
+
 void InstructionSelector::VisitInt64Sub(Node* node) {
   VisitSub<int64_t>(this, node, kArm64Sub, kArm64Neg);
 }
index 2ad499a..8685246 100644 (file)
@@ -303,6 +303,11 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kIA32Sub);
+}
+
+
 void InstructionSelector::VisitInt32Mul(Node* node) {
   IA32OperandGenerator g(this);
   Node* left = node->InputAt(0);
index 2b5396d..d7081fe 100644 (file)
@@ -511,6 +511,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitInt32AddWithOverflow(node);
     case IrOpcode::kInt32Sub:
       return VisitInt32Sub(node);
+    case IrOpcode::kInt32SubWithOverflow:
+      return VisitInt32SubWithOverflow(node);
     case IrOpcode::kInt32Mul:
       return VisitInt32Mul(node);
     case IrOpcode::kInt32Div:
index 8daae42..984d394 100644 (file)
@@ -85,6 +85,10 @@ class MachineNodeFactory {
     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) {
     return Load(rep, base, Int32Constant(0));
@@ -198,12 +202,18 @@ class MachineNodeFactory {
   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);
   }
index 84f8f54..d0691d1 100644 (file)
@@ -68,6 +68,7 @@ class MachineOperatorBuilder {
                        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 @@ class MachineOperatorBuilder {
   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); }
index 8c28c61..1cc33e0 100644 (file)
   V(Int32Add)              \
   V(Int32AddWithOverflow)  \
   V(Int32Sub)              \
+  V(Int32SubWithOverflow)  \
   V(Int32Mul)              \
   V(Int32Div)              \
   V(Int32UDiv)             \
index ec68265..fd33f85 100644 (file)
@@ -399,6 +399,11 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  VisitBinopWithOverflow(this, node, kX64Sub32);
+}
+
+
 void InstructionSelector::VisitInt64Sub(Node* node) {
   VisitSub<int64_t>(this, node, kX64Sub, kX64Neg);
 }
index 8d39c7c..1d88df5 100644 (file)
@@ -41,6 +41,26 @@ class DPIs V8_FINAL : public std::list<DPI>, private HandleAndZoneScope {
 };
 
 
+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,356 +245,238 @@ TEST(InstructionSelectorDPIAndShiftImm) {
 }
 
 
-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.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* ovf;
-      m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0), 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* 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(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.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(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, *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(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(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());
     }
   }
 }
 
 
-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());
       }
     }
@@ -582,6 +484,112 @@ TEST(InstructionSelectorInt32AddWithOverflowAndShiftImm) {
 }
 
 
+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) {
   {
     InstructionSelectorTester m;
index d05360d..4fa2938 100644 (file)
@@ -3891,6 +3891,14 @@ static bool sadd_overflow(int32_t x, int32_t y, int32_t* val) {
 }
 
 
+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) {
   int32_t actual_val = -1;
   RawMachineAssemblerTester<int32_t> m;
@@ -3972,4 +3980,86 @@ TEST(RunInt32AddWithOverflowInBranchP) {
   }
 }
 
+
+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