Index: src/compiler/s390/instruction-selector-s390.cc |
diff --git a/src/compiler/s390/instruction-selector-s390.cc b/src/compiler/s390/instruction-selector-s390.cc |
index 00e747856823c0d4bff3231c56513e6c803231b5..b2b3a4fe4a65cc8e2c5e00ee5735de420784380d 100644 |
--- a/src/compiler/s390/instruction-selector-s390.cc |
+++ b/src/compiler/s390/instruction-selector-s390.cc |
@@ -317,50 +317,49 @@ ArchOpcode SelectLoadOpcode(Node* node) { |
return opcode; |
} |
-bool AutoZeroExtendsWord32ToWord64(Node* node) { |
+#define RESULT_IS_WORD32_LIST(V) \ |
+ /* Float unary op*/ \ |
+ V(BitcastFloat32ToInt32) \ |
+ /* V(TruncateFloat64ToWord32) */ \ |
+ /* V(RoundFloat64ToInt32) */ \ |
+ /* V(TruncateFloat32ToInt32) */ \ |
+ /* V(TruncateFloat32ToUint32) */ \ |
+ /* V(TruncateFloat64ToUint32) */ \ |
+ /* V(ChangeFloat64ToInt32) */ \ |
+ /* V(ChangeFloat64ToUint32) */ \ |
+ /* Word32 unary op */ \ |
+ V(Word32Clz) \ |
+ V(Word32Popcnt) \ |
+ /* Word32 bin op */ \ |
+ V(Int32Add) \ |
+ V(Int32Sub) \ |
+ V(Int32Mul) \ |
+ V(Int32AddWithOverflow) \ |
+ V(Int32SubWithOverflow) \ |
+ V(Int32MulWithOverflow) \ |
+ V(Int32MulHigh) \ |
+ V(Uint32MulHigh) \ |
+ V(Int32Div) \ |
+ V(Uint32Div) \ |
+ V(Int32Mod) \ |
+ V(Uint32Mod) \ |
+ V(Word32Ror) \ |
+ V(Word32And) \ |
+ V(Word32Or) \ |
+ V(Word32Xor) \ |
+ V(Word32Shl) \ |
+ V(Word32Shr) \ |
+ V(Word32Sar) |
+ |
+bool ProduceWord32Result(Node* node) { |
#if !V8_TARGET_ARCH_S390X |
return true; |
#else |
switch (node->opcode()) { |
- case IrOpcode::kInt32Div: |
- case IrOpcode::kUint32Div: |
- case IrOpcode::kInt32MulHigh: |
- case IrOpcode::kUint32MulHigh: |
- case IrOpcode::kInt32Mod: |
- case IrOpcode::kUint32Mod: |
- case IrOpcode::kWord32Clz: |
- case IrOpcode::kWord32Popcnt: |
- case IrOpcode::kChangeUint32ToUint64: |
- return true; |
- default: |
- return false; |
- } |
- return false; |
-#endif |
-} |
- |
-bool ZeroExtendsWord32ToWord64(Node* node) { |
-#if !V8_TARGET_ARCH_S390X |
- return true; |
-#else |
- switch (node->opcode()) { |
- case IrOpcode::kInt32Add: |
- case IrOpcode::kInt32Sub: |
- case IrOpcode::kWord32And: |
- case IrOpcode::kWord32Or: |
- case IrOpcode::kWord32Xor: |
- case IrOpcode::kWord32Shl: |
- case IrOpcode::kWord32Shr: |
- case IrOpcode::kWord32Sar: |
- case IrOpcode::kInt32Mul: |
- case IrOpcode::kWord32Ror: |
- case IrOpcode::kInt32Div: |
- case IrOpcode::kUint32Div: |
- case IrOpcode::kInt32MulHigh: |
- case IrOpcode::kInt32Mod: |
- case IrOpcode::kUint32Mod: |
- case IrOpcode::kWord32Popcnt: |
- return true; |
+#define VISITOR(name) case IrOpcode::k##name: |
+ RESULT_IS_WORD32_LIST(VISITOR) |
+#undef VISITOR |
+ return true; |
// TODO(john.yan): consider the following case to be valid |
// case IrOpcode::kWord32Equal: |
// case IrOpcode::kInt32LessThan: |
@@ -398,10 +397,12 @@ bool ZeroExtendsWord32ToWord64(Node* node) { |
#endif |
} |
-void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { |
- S390OperandGenerator g(selector); |
- selector->Emit(opcode, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
+static inline bool DoZeroExtForResult(Node* node) { |
+#if V8_TARGET_ARCH_S390X |
+ return ProduceWord32Result(node); |
+#else |
+ return false; |
+#endif |
} |
// TODO(john.yan): Create VisiteShift to match dst = src shift (R+I) |
@@ -503,51 +504,59 @@ void VisitBinOp(InstructionSelector* selector, Node* node, |
InstructionCode opcode, OperandModes operand_mode, |
FlagsContinuation* cont, CanCombineWithLoad canCombineWithLoad); |
-#define VISIT_OP_LIST(V) \ |
- V(Word64, Unary, \ |
- [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \ |
- V(Word64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \ |
- V(Float32, Unary, \ |
- [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ |
- V(Float64, Unary, \ |
- [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) \ |
- V(Float32, Bin, \ |
- [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ |
+// Generate The following variations: |
+// VisitWord32UnaryOp, VisitWord32BinOp, |
+// VisitWord64UnaryOp, VisitWord64BinOp, |
+// VisitFloat32UnaryOp, VisitFloat32BinOp, |
+// VisitFloat64UnaryOp, VisitFloat64BinOp |
+#define VISIT_OP_LIST_32(V) \ |
+ V(Word32, Unary, [](ArchOpcode opcode) { \ |
+ return opcode == kS390_LoadWordS32 || opcode == kS390_LoadWordU32; \ |
+ }) \ |
+ V(Float32, Unary, \ |
+ [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ |
+ V(Float64, Unary, \ |
+ [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) \ |
+ V(Word32, Bin, [](ArchOpcode opcode) { \ |
+ return opcode == kS390_LoadWordS32 || opcode == kS390_LoadWordU32; \ |
+ }) \ |
+ V(Float32, Bin, \ |
+ [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ |
V(Float64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) |
+#if V8_TARGET_ARCH_S390X |
+#define VISIT_OP_LIST(V) \ |
+ VISIT_OP_LIST_32(V) \ |
+ V(Word64, Unary, \ |
+ [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \ |
+ V(Word64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) |
+#else |
+#define VISIT_OP_LIST VISIT_OP_LIST_32 |
+#endif |
+ |
#define DECLARE_VISIT_HELPER_FUNCTIONS(type1, type2, canCombineWithLoad) \ |
- void Visit##type1##type2##Op( \ |
+ static inline void Visit##type1##type2##Op( \ |
InstructionSelector* selector, Node* node, InstructionCode opcode, \ |
OperandModes operand_mode, FlagsContinuation* cont) { \ |
Visit##type2##Op(selector, node, opcode, operand_mode, cont, \ |
canCombineWithLoad); \ |
} \ |
- void Visit##type1##type2##Op(InstructionSelector* selector, Node* node, \ |
- InstructionCode opcode, \ |
- OperandModes operand_mode) { \ |
+ static inline void Visit##type1##type2##Op( \ |
+ InstructionSelector* selector, Node* node, InstructionCode opcode, \ |
+ OperandModes operand_mode) { \ |
FlagsContinuation cont; \ |
Visit##type1##type2##Op(selector, node, opcode, operand_mode, &cont); \ |
} |
VISIT_OP_LIST(DECLARE_VISIT_HELPER_FUNCTIONS); |
#undef DECLARE_VISIT_HELPER_FUNCTIONS |
+#undef VISIT_OP_LIST_32 |
+#undef VISIT_OP_LIST |
template <class CanCombineWithLoad> |
void VisitUnaryOp(InstructionSelector* selector, Node* node, |
InstructionCode opcode, OperandModes operand_mode, |
FlagsContinuation* cont, |
CanCombineWithLoad canCombineWithLoad) { |
-// Just to get rid of unused function warning |
-#define USE_VISITOR(type1, type2, canCombineWithLoad) \ |
- { \ |
- VisiterType dummy = Visit##type1##type2##Op; \ |
- USE(dummy); \ |
- } |
- typedef void (*VisiterType)(InstructionSelector * selector, Node * node, |
- InstructionCode opcode, |
- OperandModes operand_mode); |
- VISIT_OP_LIST(USE_VISITOR); |
-#undef USE_VISITOR |
- |
S390OperandGenerator g(selector); |
InstructionOperand inputs[8]; |
size_t input_count = 0; |
@@ -558,6 +567,16 @@ void VisitUnaryOp(InstructionSelector* selector, Node* node, |
GenerateRightOperands(selector, node, input, opcode, operand_mode, inputs, |
input_count, canCombineWithLoad); |
+ bool input_is_word32 = ProduceWord32Result(input); |
+ |
+ bool doZeroExt = DoZeroExtForResult(node); |
+ bool canEliminateZeroExt = input_is_word32; |
+ |
+ if (doZeroExt) { |
+ // Add zero-ext indication |
+ inputs[input_count++] = g.TempImmediate(!canEliminateZeroExt); |
+ } |
+ |
if (cont->IsBranch()) { |
inputs[input_count++] = g.Label(cont->true_block()); |
inputs[input_count++] = g.Label(cont->false_block()); |
@@ -567,7 +586,12 @@ void VisitUnaryOp(InstructionSelector* selector, Node* node, |
// If we can deoptimize as a result of the binop, we need to make sure |
// that the deopt inputs are not overwritten by the binop result. One way |
// to achieve that is to declare the output register as same-as-first. |
- outputs[output_count++] = g.DefineAsRegister(node); |
+ if (doZeroExt && canEliminateZeroExt) { |
+ // we have to make sure result and left use the same register |
+ outputs[output_count++] = g.DefineSameAsFirst(node); |
+ } else { |
+ outputs[output_count++] = g.DefineAsRegister(node); |
+ } |
} else { |
outputs[output_count++] = g.DefineSameAsFirst(node); |
} |
@@ -617,102 +641,32 @@ void VisitBinOp(InstructionSelector* selector, Node* node, |
GenerateBinOpOperands(selector, node, left, right, opcode, operand_mode, |
inputs, input_count, canCombineWithLoad); |
- if (cont->IsBranch()) { |
- inputs[input_count++] = g.Label(cont->true_block()); |
- inputs[input_count++] = g.Label(cont->false_block()); |
- } |
- |
- if ((operand_mode & OperandMode::kAllowDistinctOps) && |
- // If we can deoptimize as a result of the binop, we need to make sure |
- // that the deopt inputs are not overwritten by the binop result. One way |
- // to achieve that is to declare the output register as same-as-first. |
- !cont->IsDeoptimize()) { |
- outputs[output_count++] = g.DefineAsRegister(node); |
- } else { |
- outputs[output_count++] = g.DefineSameAsFirst(node); |
- } |
- |
- if (cont->IsSet()) { |
- outputs[output_count++] = g.DefineAsRegister(cont->result()); |
- } |
- |
- DCHECK_NE(0u, input_count); |
- DCHECK_NE(0u, output_count); |
- DCHECK_GE(arraysize(inputs), input_count); |
- DCHECK_GE(arraysize(outputs), output_count); |
- |
- opcode = cont->Encode(opcode); |
- |
- if (cont->IsDeoptimize()) { |
- selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, |
- cont->kind(), cont->reason(), cont->frame_state()); |
- } else if (cont->IsTrap()) { |
- inputs[input_count++] = g.UseImmediate(cont->trap_id()); |
- selector->Emit(opcode, output_count, outputs, input_count, inputs); |
- } else { |
- selector->Emit(opcode, output_count, outputs, input_count, inputs); |
- } |
-} |
- |
-void VisitBin32op(InstructionSelector* selector, Node* node, |
- InstructionCode opcode, OperandModes operand_mode, |
- FlagsContinuation* cont) { |
- S390OperandGenerator g(selector); |
- Int32BinopMatcher m(node); |
- Node* left = m.left().node(); |
- Node* right = m.right().node(); |
- InstructionOperand inputs[8]; |
- size_t input_count = 0; |
- InstructionOperand outputs[2]; |
- size_t output_count = 0; |
+ bool left_is_word32 = ProduceWord32Result(left); |
- // match left of TruncateInt64ToInt32 |
- if (m.left().IsTruncateInt64ToInt32() && selector->CanCover(node, left)) { |
- left = left->InputAt(0); |
- } |
- // match right of TruncateInt64ToInt32 |
- if (m.right().IsTruncateInt64ToInt32() && selector->CanCover(node, right)) { |
- right = right->InputAt(0); |
- } |
+ bool doZeroExt = DoZeroExtForResult(node); |
+ bool canEliminateZeroExt = left_is_word32; |
-#if V8_TARGET_ARCH_S390X |
- if ((ZeroExtendsWord32ToWord64(right) || g.CanBeBetterLeftOperand(right)) && |
- node->op()->HasProperty(Operator::kCommutative) && |
- !g.CanBeImmediate(right, operand_mode)) { |
- std::swap(left, right); |
+ if (doZeroExt) { |
+ // Add zero-ext indication |
+ inputs[input_count++] = g.TempImmediate(!canEliminateZeroExt); |
} |
-#else |
- if (node->op()->HasProperty(Operator::kCommutative) && |
- !g.CanBeImmediate(right, operand_mode) && |
- (g.CanBeBetterLeftOperand(right))) { |
- std::swap(left, right); |
- } |
-#endif |
- |
- GenerateBinOpOperands(selector, node, left, right, opcode, operand_mode, |
- inputs, input_count, [](ArchOpcode opcode) { |
- return opcode == kS390_LoadWordU32 || |
- opcode == kS390_LoadWordS32; |
- }); |
- |
- bool doZeroExt = |
- AutoZeroExtendsWord32ToWord64(node) || !ZeroExtendsWord32ToWord64(left); |
- |
- inputs[input_count++] = |
- g.TempImmediate(doZeroExt && (!AutoZeroExtendsWord32ToWord64(node))); |
if (cont->IsBranch()) { |
inputs[input_count++] = g.Label(cont->true_block()); |
inputs[input_count++] = g.Label(cont->false_block()); |
} |
- if (doZeroExt && (operand_mode & OperandMode::kAllowDistinctOps) && |
+ if ((operand_mode & OperandMode::kAllowDistinctOps) && |
// If we can deoptimize as a result of the binop, we need to make sure |
- // that |
- // the deopt inputs are not overwritten by the binop result. One way |
+ // that the deopt inputs are not overwritten by the binop result. One way |
// to achieve that is to declare the output register as same-as-first. |
!cont->IsDeoptimize()) { |
- outputs[output_count++] = g.DefineAsRegister(node); |
+ if (doZeroExt && canEliminateZeroExt) { |
+ // we have to make sure result and left use the same register |
+ outputs[output_count++] = g.DefineSameAsFirst(node); |
+ } else { |
+ outputs[output_count++] = g.DefineAsRegister(node); |
+ } |
} else { |
outputs[output_count++] = g.DefineSameAsFirst(node); |
} |
@@ -739,13 +693,6 @@ void VisitBin32op(InstructionSelector* selector, Node* node, |
} |
} |
-void VisitBin32op(InstructionSelector* selector, Node* node, ArchOpcode opcode, |
- OperandModes operand_mode) { |
- FlagsContinuation cont; |
- VisitBin32op(selector, node, opcode, operand_mode, &cont); |
-} |
-#undef VISIT_OP_LIST |
- |
} // namespace |
void InstructionSelector::VisitLoad(Node* node) { |
@@ -1013,23 +960,6 @@ static inline bool IsContiguousMask64(uint64_t value, int* mb, int* me) { |
} |
#endif |
-// TODO(john.yan): use list to simplify general instructions |
-#define WORD32_BIN_OP_LIST(V) \ |
- /* V(name, ArchOpcode, OperandModes) */ \ |
- V(Word32And, kS390_And32, And32OperandMode) \ |
- V(Word32Or, kS390_Or32, Or32OperandMode) \ |
- V(Word32Xor, kS390_Xor32, Xor32OperandMode) \ |
- V(Word32Shl, kS390_ShiftLeft32, Shift32OperandMode) \ |
- V(Word32Shr, kS390_ShiftRight32, Shift32OperandMode) |
- |
-#define VISITOR(name, op, mode) \ |
- void InstructionSelector::Visit##name(Node* node) { \ |
- VisitBin32op(this, node, op, mode); \ |
- } |
-WORD32_BIN_OP_LIST(VISITOR); |
-#undef VISITOR |
-#undef WORD32_BIN_OP_LIST |
- |
#if V8_TARGET_ARCH_S390X |
void InstructionSelector::VisitWord64And(Node* node) { |
S390OperandGenerator g(this); |
@@ -1082,14 +1012,6 @@ void InstructionSelector::VisitWord64And(Node* node) { |
VisitWord64BinOp(this, node, kS390_And64, And64OperandMode); |
} |
-void InstructionSelector::VisitWord64Or(Node* node) { |
- VisitWord64BinOp(this, node, kS390_Or64, Or64OperandMode); |
-} |
- |
-void InstructionSelector::VisitWord64Xor(Node* node) { |
- VisitWord64BinOp(this, node, kS390_Xor64, Xor64OperandMode); |
-} |
- |
void InstructionSelector::VisitWord64Shl(Node* node) { |
S390OperandGenerator g(this); |
Int64BinopMatcher m(node); |
@@ -1171,27 +1093,31 @@ void InstructionSelector::VisitWord64Shr(Node* node) { |
} |
#endif |
-void InstructionSelector::VisitWord32Sar(Node* node) { |
- S390OperandGenerator g(this); |
+static inline bool TryMatchSignExtInt16OrInt8FromWord32Sar( |
+ InstructionSelector* selector, Node* node) { |
+ S390OperandGenerator g(selector); |
Int32BinopMatcher m(node); |
- // Replace with sign extension for (x << K) >> K where K is 16 or 24. |
- if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) { |
+ if (selector->CanCover(node, m.left().node()) && m.left().IsWord32Shl()) { |
Int32BinopMatcher mleft(m.left().node()); |
if (mleft.right().Is(16) && m.right().Is(16)) { |
- bool doZeroExt = !ZeroExtendsWord32ToWord64(mleft.left().node()); |
- Emit(kS390_ExtendSignWord16, |
- doZeroExt ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node), |
- g.UseRegister(mleft.left().node()), g.TempImmediate(doZeroExt)); |
- return; |
+ bool canEliminateZeroExt = ProduceWord32Result(mleft.left().node()); |
+ selector->Emit(kS390_ExtendSignWord16, |
+ canEliminateZeroExt ? g.DefineSameAsFirst(node) |
+ : g.DefineAsRegister(node), |
+ g.UseRegister(mleft.left().node()), |
+ g.TempImmediate(!canEliminateZeroExt)); |
+ return true; |
} else if (mleft.right().Is(24) && m.right().Is(24)) { |
- bool doZeroExt = !ZeroExtendsWord32ToWord64(mleft.left().node()); |
- Emit(kS390_ExtendSignWord8, |
- doZeroExt ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node), |
- g.UseRegister(mleft.left().node()), g.TempImmediate(doZeroExt)); |
- return; |
+ bool canEliminateZeroExt = ProduceWord32Result(mleft.left().node()); |
+ selector->Emit(kS390_ExtendSignWord8, |
+ canEliminateZeroExt ? g.DefineSameAsFirst(node) |
+ : g.DefineAsRegister(node), |
+ g.UseRegister(mleft.left().node()), |
+ g.TempImmediate(!canEliminateZeroExt)); |
+ return true; |
} |
} |
- VisitBin32op(this, node, kS390_ShiftRightArith32, Shift32OperandMode); |
+ return false; |
} |
#if !V8_TARGET_ARCH_S390X |
@@ -1302,51 +1228,6 @@ void InstructionSelector::VisitWord32PairSar(Node* node) { |
} |
#endif |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitWord64Sar(Node* node) { |
- VisitWord64BinOp(this, node, kS390_ShiftRightArith64, Shift64OperandMode); |
-} |
-#endif |
- |
-void InstructionSelector::VisitWord32Ror(Node* node) { |
- // TODO(john): match dst = ror(src1, src2 + imm) |
- VisitBin32op(this, node, kS390_RotRight32, |
- OperandMode::kAllowRI | OperandMode::kAllowRRR | |
- OperandMode::kAllowRRI | OperandMode::kShift32Imm); |
-} |
- |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitWord64Ror(Node* node) { |
- VisitWord64BinOp(this, node, kS390_RotRight64, Shift64OperandMode); |
-} |
-#endif |
- |
-void InstructionSelector::VisitWord32Clz(Node* node) { |
- VisitRR(this, kS390_Cntlz32, node); |
-} |
- |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitWord64Clz(Node* node) { |
- S390OperandGenerator g(this); |
- Emit(kS390_Cntlz64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
-} |
-#endif |
- |
-void InstructionSelector::VisitWord32Popcnt(Node* node) { |
- S390OperandGenerator g(this); |
- Node* value = node->InputAt(0); |
- Emit(kS390_Popcnt32, g.DefineAsRegister(node), g.UseRegister(value)); |
-} |
- |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitWord64Popcnt(Node* node) { |
- S390OperandGenerator g(this); |
- Emit(kS390_Popcnt64, g.DefineAsRegister(node), |
- g.UseRegister(node->InputAt(0))); |
-} |
-#endif |
- |
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } |
#if V8_TARGET_ARCH_S390X |
@@ -1384,222 +1265,329 @@ void InstructionSelector::VisitWord32ReverseBytes(Node* node) { |
g.UseRegister(node->InputAt(0))); |
} |
-void InstructionSelector::VisitInt32Add(Node* node) { |
- VisitBin32op(this, node, kS390_Add32, AddOperandMode); |
-} |
- |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitInt64Add(Node* node) { |
- VisitWord64BinOp(this, node, kS390_Add64, AddOperandMode); |
-} |
-#endif |
- |
-void InstructionSelector::VisitInt32Sub(Node* node) { |
- S390OperandGenerator g(this); |
- Int32BinopMatcher m(node); |
- if (m.left().Is(0)) { |
- Node* right = m.right().node(); |
- bool doZeroExt = ZeroExtendsWord32ToWord64(right); |
- Emit(kS390_Neg32, g.DefineAsRegister(node), g.UseRegister(right), |
- g.TempImmediate(doZeroExt)); |
- } else { |
- VisitBin32op(this, node, kS390_Sub32, SubOperandMode); |
- } |
-} |
- |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitInt64Sub(Node* node) { |
- S390OperandGenerator g(this); |
- Int64BinopMatcher m(node); |
+template <class Matcher, ArchOpcode neg_opcode> |
+static inline bool TryMatchNegFromSub(InstructionSelector* selector, |
+ Node* node) { |
+ S390OperandGenerator g(selector); |
+ Matcher m(node); |
+ static_assert(neg_opcode == kS390_Neg32 || neg_opcode == kS390_Neg64, |
+ "Provided opcode is not a Neg opcode."); |
if (m.left().Is(0)) { |
- Emit(kS390_Neg64, g.DefineAsRegister(node), |
- g.UseRegister(m.right().node())); |
- } else { |
- VisitWord64BinOp(this, node, kS390_Sub64, SubOperandMode); |
- } |
-} |
-#endif |
- |
-void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { |
- if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); |
- return VisitBin32op(this, node, kS390_Mul32WithOverflow, |
- OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, |
- &cont); |
- } |
- VisitBin32op(this, node, kS390_Mul32, MulOperandMode); |
-} |
- |
-void InstructionSelector::VisitInt32Mul(Node* node) { |
- S390OperandGenerator g(this); |
- Int32BinopMatcher m(node); |
- Node* left = m.left().node(); |
- Node* right = m.right().node(); |
- if (g.CanBeImmediate(right, OperandMode::kInt32Imm) && |
- base::bits::IsPowerOfTwo32(g.GetImmediate(right))) { |
- int power = 31 - base::bits::CountLeadingZeros32(g.GetImmediate(right)); |
- bool doZeroExt = !ZeroExtendsWord32ToWord64(left); |
- InstructionOperand dst = |
- (doZeroExt && CpuFeatures::IsSupported(DISTINCT_OPS)) |
- ? g.DefineAsRegister(node) |
- : g.DefineSameAsFirst(node); |
- |
- Emit(kS390_ShiftLeft32, dst, g.UseRegister(left), g.UseImmediate(power), |
- g.TempImmediate(doZeroExt)); |
- return; |
+ Node* value = m.right().node(); |
+ bool doZeroExt = DoZeroExtForResult(node); |
+ bool canEliminateZeroExt = ProduceWord32Result(value); |
+ if (doZeroExt) { |
+ selector->Emit(neg_opcode, |
+ canEliminateZeroExt ? g.DefineSameAsFirst(node) |
+ : g.DefineAsRegister(node), |
+ g.UseRegister(value), |
+ g.TempImmediate(!canEliminateZeroExt)); |
+ } else { |
+ selector->Emit(neg_opcode, g.DefineAsRegister(node), |
+ g.UseRegister(value)); |
+ } |
+ return true; |
} |
- VisitBin32op(this, node, kS390_Mul32, MulOperandMode); |
+ return false; |
} |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitInt64Mul(Node* node) { |
- S390OperandGenerator g(this); |
- Int64BinopMatcher m(node); |
+template <class Matcher, ArchOpcode shift_op> |
+bool TryMatchShiftFromMul(InstructionSelector* selector, Node* node) { |
+ S390OperandGenerator g(selector); |
+ Matcher m(node); |
Node* left = m.left().node(); |
Node* right = m.right().node(); |
if (g.CanBeImmediate(right, OperandMode::kInt32Imm) && |
base::bits::IsPowerOfTwo64(g.GetImmediate(right))) { |
int power = 63 - base::bits::CountLeadingZeros64(g.GetImmediate(right)); |
- Emit(kS390_ShiftLeft64, g.DefineSameAsFirst(node), g.UseRegister(left), |
- g.UseImmediate(power)); |
- return; |
+ bool doZeroExt = DoZeroExtForResult(node); |
+ bool canEliminateZeroExt = ProduceWord32Result(left); |
+ InstructionOperand dst = (doZeroExt && !canEliminateZeroExt && |
+ CpuFeatures::IsSupported(DISTINCT_OPS)) |
+ ? g.DefineAsRegister(node) |
+ : g.DefineSameAsFirst(node); |
+ |
+ if (doZeroExt) { |
+ selector->Emit(shift_op, dst, g.UseRegister(left), g.UseImmediate(power), |
+ g.TempImmediate(!canEliminateZeroExt)); |
+ } else { |
+ selector->Emit(shift_op, dst, g.UseRegister(left), g.UseImmediate(power)); |
+ } |
+ return true; |
} |
- VisitWord64BinOp(this, node, kS390_Mul64, MulOperandMode); |
-} |
-#endif |
- |
-void InstructionSelector::VisitInt32MulHigh(Node* node) { |
- VisitBin32op(this, node, kS390_MulHigh32, |
- OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps); |
-} |
- |
-void InstructionSelector::VisitUint32MulHigh(Node* node) { |
- VisitBin32op(this, node, kS390_MulHighU32, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
-} |
- |
-void InstructionSelector::VisitInt32Div(Node* node) { |
- VisitBin32op(this, node, kS390_Div32, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+ return false; |
} |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitInt64Div(Node* node) { |
- VisitWord64BinOp(this, node, kS390_Div64, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+template <ArchOpcode opcode> |
+static inline bool TryMatchInt32OpWithOverflow(InstructionSelector* selector, |
+ Node* node, OperandModes mode) { |
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
+ VisitWord32BinOp(selector, node, opcode, mode, &cont); |
+ return true; |
+ } |
+ return false; |
} |
-#endif |
-void InstructionSelector::VisitUint32Div(Node* node) { |
- VisitBin32op(this, node, kS390_DivU32, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+static inline bool TryMatchInt32AddWithOverflow(InstructionSelector* selector, |
+ Node* node) { |
+ return TryMatchInt32OpWithOverflow<kS390_Add32>(selector, node, |
+ AddOperandMode); |
} |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitUint64Div(Node* node) { |
- VisitWord64BinOp(this, node, kS390_DivU64, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+static inline bool TryMatchInt32SubWithOverflow(InstructionSelector* selector, |
+ Node* node) { |
+ return TryMatchInt32OpWithOverflow<kS390_Sub32>(selector, node, |
+ SubOperandMode); |
} |
-#endif |
-void InstructionSelector::VisitInt32Mod(Node* node) { |
- VisitBin32op(this, node, kS390_Mod32, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+static inline bool TryMatchInt32MulWithOverflow(InstructionSelector* selector, |
+ Node* node) { |
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); |
+ VisitWord32BinOp(selector, node, kS390_Mul32WithOverflow, |
+ OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, |
+ &cont); |
+ return true; |
+ } |
+ return TryMatchShiftFromMul<Int32BinopMatcher, kS390_ShiftLeft32>(selector, |
+ node); |
} |
#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitInt64Mod(Node* node) { |
- VisitWord64BinOp(this, node, kS390_Mod64, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+template <ArchOpcode opcode> |
+static inline bool TryMatchInt64OpWithOverflow(InstructionSelector* selector, |
+ Node* node, OperandModes mode) { |
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
+ VisitWord64BinOp(selector, node, opcode, mode, &cont); |
+ return true; |
+ } |
+ return false; |
} |
-#endif |
-void InstructionSelector::VisitUint32Mod(Node* node) { |
- VisitBin32op(this, node, kS390_ModU32, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+static inline bool TryMatchInt64AddWithOverflow(InstructionSelector* selector, |
+ Node* node) { |
+ return TryMatchInt64OpWithOverflow<kS390_Add64>(selector, node, |
+ AddOperandMode); |
} |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitUint64Mod(Node* node) { |
- VisitWord64BinOp(this, node, kS390_ModU64, |
- OperandMode::kAllowRRM | OperandMode::kAllowRRR); |
+static inline bool TryMatchInt64SubWithOverflow(InstructionSelector* selector, |
+ Node* node) { |
+ return TryMatchInt64OpWithOverflow<kS390_Sub64>(selector, node, |
+ SubOperandMode); |
} |
#endif |
+#define null ([]() { return false; }) |
// TODO(john.yan): place kAllowRM where available |
-#define VISIT_FLOAT_UNARY_OP_LIST(V) \ |
+#define FLOAT_UNARY_OP_LIST_32(V) \ |
V(Float32, ChangeFloat32ToFloat64, kS390_Float32ToDouble, \ |
- OperandMode::kAllowRM) \ |
+ OperandMode::kAllowRM, null) \ |
V(Float32, BitcastFloat32ToInt32, kS390_BitcastFloat32ToInt32, \ |
- OperandMode::kNone) \ |
+ OperandMode::kNone, null) \ |
V(Float64, TruncateFloat64ToFloat32, kS390_DoubleToFloat32, \ |
- OperandMode::kNone) \ |
+ OperandMode::kNone, null) \ |
V(Float64, TruncateFloat64ToWord32, kArchTruncateDoubleToI, \ |
- OperandMode::kNone) \ |
- V(Float64, RoundFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone) \ |
- V(Float32, TruncateFloat32ToInt32, kS390_Float32ToInt32, OperandMode::kNone) \ |
+ OperandMode::kNone, null) \ |
+ V(Float64, RoundFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone, \ |
+ null) \ |
+ V(Float32, TruncateFloat32ToInt32, kS390_Float32ToInt32, OperandMode::kNone, \ |
+ null) \ |
V(Float32, TruncateFloat32ToUint32, kS390_Float32ToUint32, \ |
- OperandMode::kNone) \ |
- V(Float64, ChangeFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone) \ |
- V(Float64, ChangeFloat64ToUint32, kS390_DoubleToUint32, OperandMode::kNone) \ |
+ OperandMode::kNone, null) \ |
V(Float64, TruncateFloat64ToUint32, kS390_DoubleToUint32, \ |
- OperandMode::kNone) \ |
- V(Float64, Float64SilenceNaN, kS390_Float64SilenceNaN, OperandMode::kNone) \ |
- V(Float32, Float32Abs, kS390_AbsFloat, OperandMode::kNone) \ |
- V(Float64, Float64Abs, kS390_AbsDouble, OperandMode::kNone) \ |
- V(Float32, Float32Sqrt, kS390_SqrtFloat, OperandMode::kNone) \ |
- V(Float64, Float64Sqrt, kS390_SqrtDouble, OperandMode::kNone) \ |
- V(Float32, Float32RoundDown, kS390_FloorFloat, OperandMode::kNone) \ |
- V(Float64, Float64RoundDown, kS390_FloorDouble, OperandMode::kNone) \ |
- V(Float32, Float32RoundUp, kS390_CeilFloat, OperandMode::kNone) \ |
- V(Float64, Float64RoundUp, kS390_CeilDouble, OperandMode::kNone) \ |
- V(Float32, Float32RoundTruncate, kS390_TruncateFloat, OperandMode::kNone) \ |
- V(Float64, Float64RoundTruncate, kS390_TruncateDouble, OperandMode::kNone) \ |
- V(Float64, Float64RoundTiesAway, kS390_RoundDouble, OperandMode::kNone) \ |
- V(Float32, Float32Neg, kS390_NegFloat, OperandMode::kNone) \ |
- V(Float64, Float64Neg, kS390_NegDouble, OperandMode::kNone) |
- |
-#define VISIT_WORD64_UNARY_OP_LIST(V) \ |
- V(Word64, TruncateInt64ToInt32, kS390_Int64ToInt32, OperandMode::kNone) \ |
- V(Word64, RoundInt64ToFloat32, kS390_Int64ToFloat32, OperandMode::kNone) \ |
- V(Word64, RoundInt64ToFloat64, kS390_Int64ToDouble, OperandMode::kNone) \ |
- V(Word64, RoundUint64ToFloat32, kS390_Uint64ToFloat32, OperandMode::kNone) \ |
- V(Word64, RoundUint64ToFloat64, kS390_Uint64ToDouble, OperandMode::kNone) \ |
- V(Word64, BitcastInt64ToFloat64, kS390_BitcastInt64ToDouble, \ |
- OperandMode::kNone) \ |
- V(Float64, BitcastFloat64ToInt64, kS390_BitcastDoubleToInt64, \ |
- OperandMode::kNone) |
+ OperandMode::kNone, null) \ |
+ V(Float64, ChangeFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone, \ |
+ null) \ |
+ V(Float64, ChangeFloat64ToUint32, kS390_DoubleToUint32, OperandMode::kNone, \ |
+ null) \ |
+ V(Float64, Float64SilenceNaN, kS390_Float64SilenceNaN, OperandMode::kNone, \ |
+ null) \ |
+ V(Float32, Float32Abs, kS390_AbsFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64Abs, kS390_AbsDouble, OperandMode::kNone, null) \ |
+ V(Float32, Float32Sqrt, kS390_SqrtFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64Sqrt, kS390_SqrtDouble, OperandMode::kNone, null) \ |
+ V(Float32, Float32RoundDown, kS390_FloorFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64RoundDown, kS390_FloorDouble, OperandMode::kNone, null) \ |
+ V(Float32, Float32RoundUp, kS390_CeilFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64RoundUp, kS390_CeilDouble, OperandMode::kNone, null) \ |
+ V(Float32, Float32RoundTruncate, kS390_TruncateFloat, OperandMode::kNone, \ |
+ null) \ |
+ V(Float64, Float64RoundTruncate, kS390_TruncateDouble, OperandMode::kNone, \ |
+ null) \ |
+ V(Float64, Float64RoundTiesAway, kS390_RoundDouble, OperandMode::kNone, \ |
+ null) \ |
+ V(Float32, Float32Neg, kS390_NegFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64Neg, kS390_NegDouble, OperandMode::kNone, null) |
+ |
+#define FLOAT_BIN_OP_LIST(V) \ |
+ V(Float32, Float32Add, kS390_AddFloat, OperandMode::kAllowRM, null) \ |
+ V(Float64, Float64Add, kS390_AddDouble, OperandMode::kAllowRM, null) \ |
+ V(Float32, Float32Sub, kS390_SubFloat, OperandMode::kAllowRM, null) \ |
+ V(Float64, Float64Sub, kS390_SubDouble, OperandMode::kAllowRM, null) \ |
+ V(Float32, Float32Mul, kS390_MulFloat, OperandMode::kAllowRM, null) \ |
+ V(Float64, Float64Mul, kS390_MulDouble, OperandMode::kAllowRM, null) \ |
+ V(Float32, Float32Div, kS390_DivFloat, OperandMode::kAllowRM, null) \ |
+ V(Float64, Float64Div, kS390_DivDouble, OperandMode::kAllowRM, null) \ |
+ V(Float32, Float32Max, kS390_MaxFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64Max, kS390_MaxDouble, OperandMode::kNone, null) \ |
+ V(Float32, Float32Min, kS390_MinFloat, OperandMode::kNone, null) \ |
+ V(Float64, Float64Min, kS390_MinDouble, OperandMode::kNone, null) |
+ |
+#define WORD32_UNARY_OP_LIST_32(V) \ |
+ V(Word32, Word32Clz, kS390_Cntlz32, OperandMode::kNone, null) \ |
+ V(Word32, Word32Popcnt, kS390_Popcnt32, OperandMode::kNone, null) \ |
+ V(Word32, RoundInt32ToFloat32, kS390_Int32ToFloat32, OperandMode::kNone, \ |
+ null) \ |
+ V(Word32, RoundUint32ToFloat32, kS390_Uint32ToFloat32, OperandMode::kNone, \ |
+ null) \ |
+ V(Word32, ChangeInt32ToFloat64, kS390_Int32ToDouble, OperandMode::kNone, \ |
+ null) \ |
+ V(Word32, ChangeUint32ToFloat64, kS390_Uint32ToDouble, OperandMode::kNone, \ |
+ null) \ |
+ V(Word32, BitcastInt32ToFloat32, kS390_BitcastInt32ToFloat32, \ |
+ OperandMode::kNone, null) |
+ |
+#ifdef V8_TARGET_ARCH_S390X |
+#define FLOAT_UNARY_OP_LIST(V) \ |
+ FLOAT_UNARY_OP_LIST_32(V) \ |
+ V(Float64, ChangeFloat64ToUint64, kS390_DoubleToUint64, OperandMode::kNone, \ |
+ null) \ |
+ V(Float64, BitcastFloat64ToInt64, kS390_BitcastDoubleToInt64, \ |
+ OperandMode::kNone, null) |
+#define WORD32_UNARY_OP_LIST(V) \ |
+ WORD32_UNARY_OP_LIST_32(V) \ |
+ V(Word32, ChangeInt32ToInt64, kS390_ExtendSignWord32, OperandMode::kNone, \ |
+ null) \ |
+ V(Word32, ChangeUint32ToUint64, kS390_Uint32ToUint64, OperandMode::kNone, \ |
+ [&]() -> bool { \ |
+ if (ProduceWord32Result(node->InputAt(0))) { \ |
+ EmitIdentity(node); \ |
+ return true; \ |
+ } \ |
+ return false; \ |
+ }) |
-#define DECLARE_UNARY_OP(type, name, op, mode) \ |
- void InstructionSelector::Visit##name(Node* node) { \ |
- Visit##type##UnaryOp(this, node, op, mode); \ |
- } |
+#else |
+#define FLOAT_UNARY_OP_LIST(V) FLOAT_UNARY_OP_LIST_32(V) |
+#define WORD32_UNARY_OP_LIST(V) WORD32_UNARY_OP_LIST_32(V) |
+#endif |
-VISIT_FLOAT_UNARY_OP_LIST(DECLARE_UNARY_OP); |
+#define WORD32_BIN_OP_LIST(V) \ |
+ V(Word32, Int32Add, kS390_Add32, AddOperandMode, null) \ |
+ V(Word32, Int32Sub, kS390_Sub32, SubOperandMode, ([&]() { \ |
+ return TryMatchNegFromSub<Int32BinopMatcher, kS390_Neg32>(this, node); \ |
+ })) \ |
+ V(Word32, Int32Mul, kS390_Mul32, MulOperandMode, ([&]() { \ |
+ return TryMatchShiftFromMul<Int32BinopMatcher, kS390_ShiftLeft32>(this, \ |
+ node); \ |
+ })) \ |
+ V(Word32, Int32AddWithOverflow, kS390_Add32, AddOperandMode, \ |
+ ([&]() { return TryMatchInt32AddWithOverflow(this, node); })) \ |
+ V(Word32, Int32SubWithOverflow, kS390_Sub32, SubOperandMode, \ |
+ ([&]() { return TryMatchInt32SubWithOverflow(this, node); })) \ |
+ V(Word32, Int32MulWithOverflow, kS390_Mul32, MulOperandMode, \ |
+ ([&]() { return TryMatchInt32MulWithOverflow(this, node); })) \ |
+ V(Word32, Int32MulHigh, kS390_MulHigh32, \ |
+ OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, null) \ |
+ V(Word32, Uint32MulHigh, kS390_MulHighU32, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word32, Int32Div, kS390_Div32, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word32, Uint32Div, kS390_DivU32, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word32, Int32Mod, kS390_Mod32, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word32, Uint32Mod, kS390_ModU32, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word32, Word32Ror, kS390_RotRight32, \ |
+ OperandMode::kAllowRI | OperandMode::kAllowRRR | OperandMode::kAllowRRI | \ |
+ OperandMode::kShift32Imm, \ |
+ null) \ |
+ V(Word32, Word32And, kS390_And32, And32OperandMode, null) \ |
+ V(Word32, Word32Or, kS390_Or32, Or32OperandMode, null) \ |
+ V(Word32, Word32Xor, kS390_Xor32, Xor32OperandMode, null) \ |
+ V(Word32, Word32Shl, kS390_ShiftLeft32, Shift32OperandMode, null) \ |
+ V(Word32, Word32Shr, kS390_ShiftRight32, Shift32OperandMode, null) \ |
+ V(Word32, Word32Sar, kS390_ShiftRightArith32, Shift32OperandMode, \ |
+ [&]() { return TryMatchSignExtInt16OrInt8FromWord32Sar(this, node); }) |
+ |
+#define WORD64_UNARY_OP_LIST(V) \ |
+ V(Word64, Word64Popcnt, kS390_Popcnt64, OperandMode::kNone, null) \ |
+ V(Word64, Word64Clz, kS390_Cntlz64, OperandMode::kNone, null) \ |
+ V(Word64, TruncateInt64ToInt32, kS390_Int64ToInt32, OperandMode::kNone, \ |
+ null) \ |
+ V(Word64, RoundInt64ToFloat32, kS390_Int64ToFloat32, OperandMode::kNone, \ |
+ null) \ |
+ V(Word64, RoundInt64ToFloat64, kS390_Int64ToDouble, OperandMode::kNone, \ |
+ null) \ |
+ V(Word64, RoundUint64ToFloat32, kS390_Uint64ToFloat32, OperandMode::kNone, \ |
+ null) \ |
+ V(Word64, RoundUint64ToFloat64, kS390_Uint64ToDouble, OperandMode::kNone, \ |
+ null) \ |
+ V(Word64, BitcastInt64ToFloat64, kS390_BitcastInt64ToDouble, \ |
+ OperandMode::kNone, null) |
+ |
+#define WORD64_BIN_OP_LIST(V) \ |
+ V(Word64, Int64Add, kS390_Add64, AddOperandMode, null) \ |
+ V(Word64, Int64Sub, kS390_Sub64, SubOperandMode, ([&]() { \ |
+ return TryMatchNegFromSub<Int64BinopMatcher, kS390_Neg64>(this, node); \ |
+ })) \ |
+ V(Word64, Int64AddWithOverflow, kS390_Add64, AddOperandMode, \ |
+ ([&]() { return TryMatchInt64AddWithOverflow(this, node); })) \ |
+ V(Word64, Int64SubWithOverflow, kS390_Sub64, SubOperandMode, \ |
+ ([&]() { return TryMatchInt64SubWithOverflow(this, node); })) \ |
+ V(Word64, Int64Mul, kS390_Mul64, MulOperandMode, ([&]() { \ |
+ return TryMatchShiftFromMul<Int64BinopMatcher, kS390_ShiftLeft64>(this, \ |
+ node); \ |
+ })) \ |
+ V(Word64, Int64Div, kS390_Div64, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word64, Uint64Div, kS390_DivU64, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word64, Int64Mod, kS390_Mod64, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word64, Uint64Mod, kS390_ModU64, \ |
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
+ V(Word64, Word64Sar, kS390_ShiftRightArith64, Shift64OperandMode, null) \ |
+ V(Word64, Word64Ror, kS390_RotRight64, Shift64OperandMode, null) \ |
+ V(Word64, Word64Or, kS390_Or64, Or64OperandMode, null) \ |
+ V(Word64, Word64Xor, kS390_Xor64, Xor64OperandMode, null) |
+ |
+#define DECLARE_UNARY_OP(type, name, op, mode, try_extra) \ |
+ void InstructionSelector::Visit##name(Node* node) { \ |
+ if (std::function<bool()>(try_extra)()) return; \ |
+ Visit##type##UnaryOp(this, node, op, mode); \ |
+ } |
+ |
+#define DECLARE_BIN_OP(type, name, op, mode, try_extra) \ |
+ void InstructionSelector::Visit##name(Node* node) { \ |
+ if (std::function<bool()>(try_extra)()) return; \ |
+ Visit##type##BinOp(this, node, op, mode); \ |
+ } |
+ |
+WORD32_BIN_OP_LIST(DECLARE_BIN_OP); |
+WORD32_UNARY_OP_LIST(DECLARE_UNARY_OP); |
+FLOAT_UNARY_OP_LIST(DECLARE_UNARY_OP); |
+FLOAT_BIN_OP_LIST(DECLARE_BIN_OP); |
#if V8_TARGET_ARCH_S390X |
-VISIT_WORD64_UNARY_OP_LIST(DECLARE_UNARY_OP) |
+WORD64_UNARY_OP_LIST(DECLARE_UNARY_OP) |
+WORD64_BIN_OP_LIST(DECLARE_BIN_OP) |
#endif |
+#undef DECLARE_BIN_OP |
#undef DECLARE_UNARY_OP |
-#undef VISIT_WORD64_UNARY_OP_LIST |
-#undef VISIT_FLOAT_UNARY_OP_LIST |
- |
-void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) { |
- VisitRR(this, kS390_Int32ToFloat32, node); |
-} |
- |
-void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) { |
- VisitRR(this, kS390_Uint32ToFloat32, node); |
-} |
- |
-void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { |
- VisitRR(this, kS390_Int32ToDouble, node); |
-} |
- |
-void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { |
- VisitRR(this, kS390_Uint32ToDouble, node); |
-} |
+#undef WORD64_BIN_OP_LIST |
+#undef WORD64_UNARY_OP_LIST |
+#undef WORD32_BIN_OP_LIST |
+#undef WORD32_UNARY_OP_LIST |
+#undef FLOAT_UNARY_OP_LIST |
+#undef WORD32_UNARY_OP_LIST_32 |
+#undef FLOAT_BIN_OP_LIST |
+#undef FLOAT_BIN_OP_LIST_32 |
+#undef null |
#if V8_TARGET_ARCH_S390X |
void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) { |
@@ -1618,66 +1606,8 @@ void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) { |
VisitTryTruncateDouble(this, kS390_DoubleToUint64, node); |
} |
-void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { |
- // TODO(mbrandy): inspect input to see if nop is appropriate. |
- VisitRR(this, kS390_ExtendSignWord32, node); |
-} |
- |
-void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { |
- S390OperandGenerator g(this); |
- Node* value = node->InputAt(0); |
- if (ZeroExtendsWord32ToWord64(value)) { |
- // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the |
- // zero-extension is a no-op. |
- return EmitIdentity(node); |
- } |
- VisitRR(this, kS390_Uint32ToUint64, node); |
-} |
- |
-void InstructionSelector::VisitChangeFloat64ToUint64(Node* node) { |
- VisitRR(this, kS390_DoubleToUint64, node); |
-} |
#endif |
-void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) { |
- VisitRR(this, kS390_BitcastInt32ToFloat32, node); |
-} |
- |
-void InstructionSelector::VisitFloat32Add(Node* node) { |
- return VisitFloat32BinOp(this, node, kS390_AddFloat, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat64Add(Node* node) { |
- // TODO(mbrandy): detect multiply-add |
- return VisitFloat64BinOp(this, node, kS390_AddDouble, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat32Sub(Node* node) { |
- return VisitFloat32BinOp(this, node, kS390_SubFloat, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat64Sub(Node* node) { |
- // TODO(mbrandy): detect multiply-subtract |
- return VisitFloat64BinOp(this, node, kS390_SubDouble, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat32Mul(Node* node) { |
- return VisitFloat32BinOp(this, node, kS390_MulFloat, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat64Mul(Node* node) { |
- // TODO(mbrandy): detect negate |
- return VisitFloat64BinOp(this, node, kS390_MulDouble, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat32Div(Node* node) { |
- return VisitFloat32BinOp(this, node, kS390_DivFloat, OperandMode::kAllowRM); |
-} |
- |
-void InstructionSelector::VisitFloat64Div(Node* node) { |
- return VisitFloat64BinOp(this, node, kS390_DivDouble, OperandMode::kAllowRM); |
-} |
- |
void InstructionSelector::VisitFloat64Mod(Node* node) { |
S390OperandGenerator g(this); |
Emit(kS390_ModDouble, g.DefineAsFixed(node, d1), |
@@ -1685,22 +1615,6 @@ void InstructionSelector::VisitFloat64Mod(Node* node) { |
->MarkAsCall(); |
} |
-void InstructionSelector::VisitFloat32Max(Node* node) { |
- return VisitFloat32BinOp(this, node, kS390_MaxFloat, OperandMode::kNone); |
-} |
- |
-void InstructionSelector::VisitFloat64Max(Node* node) { |
- return VisitFloat64BinOp(this, node, kS390_MaxDouble, OperandMode::kNone); |
-} |
- |
-void InstructionSelector::VisitFloat32Min(Node* node) { |
- return VisitFloat32BinOp(this, node, kS390_MinFloat, OperandMode::kNone); |
-} |
- |
-void InstructionSelector::VisitFloat64Min(Node* node) { |
- return VisitFloat64BinOp(this, node, kS390_MinDouble, OperandMode::kNone); |
-} |
- |
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node, |
InstructionCode opcode) { |
S390OperandGenerator g(this); |
@@ -1724,44 +1638,6 @@ void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { |
UNREACHABLE(); |
} |
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
- OperandModes mode = AddOperandMode; |
- if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
- return VisitBin32op(this, node, kS390_Add32, mode, &cont); |
- } |
- FlagsContinuation cont; |
- VisitBin32op(this, node, kS390_Add32, mode, &cont); |
-} |
- |
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
- OperandModes mode = SubOperandMode; |
- if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
- return VisitBin32op(this, node, kS390_Sub32, mode, &cont); |
- } |
- FlagsContinuation cont; |
- VisitBin32op(this, node, kS390_Sub32, mode, &cont); |
-} |
- |
-#if V8_TARGET_ARCH_S390X |
-void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { |
- if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
- return VisitWord64BinOp(this, node, kS390_Add64, AddOperandMode, &cont); |
- } |
- VisitWord64BinOp(this, node, kS390_Add64, AddOperandMode); |
-} |
- |
-void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { |
- if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
- return VisitWord64BinOp(this, node, kS390_Sub64, SubOperandMode, &cont); |
- } |
- VisitWord64BinOp(this, node, kS390_Sub64, SubOperandMode); |
-} |
-#endif |
- |
static bool CompareLogical(FlagsContinuation* cont) { |
switch (cont->condition()) { |
case kUnsignedLessThan: |
@@ -2105,15 +1981,15 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
switch (node->opcode()) { |
case IrOpcode::kInt32AddWithOverflow: |
cont->OverwriteAndNegateIfEqual(kOverflow); |
- return VisitBin32op(selector, node, kS390_Add32, AddOperandMode, |
- cont); |
+ return VisitWord32BinOp(selector, node, kS390_Add32, |
+ AddOperandMode, cont); |
case IrOpcode::kInt32SubWithOverflow: |
cont->OverwriteAndNegateIfEqual(kOverflow); |
- return VisitBin32op(selector, node, kS390_Sub32, SubOperandMode, |
- cont); |
+ return VisitWord32BinOp(selector, node, kS390_Sub32, |
+ SubOperandMode, cont); |
case IrOpcode::kInt32MulWithOverflow: |
cont->OverwriteAndNegateIfEqual(kNotEqual); |
- return VisitBin32op( |
+ return VisitWord32BinOp( |
selector, node, kS390_Mul32WithOverflow, |
OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, |
cont); |
@@ -2156,13 +2032,13 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
break; |
case IrOpcode::kWord32Or: |
if (fc == kNotEqual || fc == kEqual) |
- return VisitBin32op(selector, value, kS390_Or32, Or32OperandMode, |
- cont); |
+ return VisitWord32BinOp(selector, value, kS390_Or32, Or32OperandMode, |
+ cont); |
break; |
case IrOpcode::kWord32Xor: |
if (fc == kNotEqual || fc == kEqual) |
- return VisitBin32op(selector, value, kS390_Xor32, Xor32OperandMode, |
- cont); |
+ return VisitWord32BinOp(selector, value, kS390_Xor32, |
+ Xor32OperandMode, cont); |
break; |
case IrOpcode::kWord32Sar: |
case IrOpcode::kWord32Shl: |