Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Unified Diff: src/compiler/s390/instruction-selector-s390.cc

Issue 2649113007: s390: TF Codegen Optimization (Closed)
Patch Set: remove 2 unnecessary unreachables Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/s390/instruction-scheduler-s390.cc ('k') | src/s390/assembler-s390.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 b469415d2e98b5e7d10ec6de33159202f56cf956..d5d5e079fa09546219ff74bbaa4a8cbfffc2c4f4 100644
--- a/src/compiler/s390/instruction-selector-s390.cc
+++ b/src/compiler/s390/instruction-selector-s390.cc
@@ -12,23 +12,61 @@ namespace v8 {
namespace internal {
namespace compiler {
-enum ImmediateMode {
- kShift32Imm,
- kShift64Imm,
- kInt32Imm,
- kInt32Imm_Negate,
- kUint32Imm,
- kInt20Imm,
- kNoImmediate
+enum class OperandMode : uint32_t {
+ kNone = 0u,
+ // Immediate mode
+ kShift32Imm = 1u << 0,
+ kShift64Imm = 1u << 1,
+ kInt32Imm = 1u << 2,
+ kInt32Imm_Negate = 1u << 3,
+ kUint32Imm = 1u << 4,
+ kInt20Imm = 1u << 5,
+ // Instr format
+ kAllowRRR = 1u << 7,
+ kAllowRM = 1u << 8,
+ kAllowRI = 1u << 9,
+ kAllowRRI = 1u << 10,
+ kAllowRRM = 1u << 11,
+ // Useful combination
+ kAllowImmediate = kAllowRI | kAllowRRI,
+ kAllowMemoryOperand = kAllowRM | kAllowRRM,
+ kAllowDistinctOps = kAllowRRR | kAllowRRI | kAllowRRM,
+ kBitWiseCommonMode = kAllowRI | kUint32Imm,
+ kArithmeticCommonMode = kAllowRM | kAllowRI
};
+typedef base::Flags<OperandMode, uint32_t> OperandModes;
+DEFINE_OPERATORS_FOR_FLAGS(OperandModes);
+OperandModes immediateModeMask =
+ OperandMode::kShift32Imm | OperandMode::kShift64Imm |
+ OperandMode::kInt32Imm | OperandMode::kInt32Imm_Negate |
+ OperandMode::kUint32Imm | OperandMode::kInt20Imm;
+
+#define BitWiseOperandMode \
+ ((OperandMode::kBitWiseCommonMode | \
+ (CpuFeatures::IsSupported(DISTINCT_OPS) \
+ ? OperandMode::kAllowRRR \
+ : OperandMode::kBitWiseCommonMode)))
+#define AddOperandMode \
+ ((OperandMode::kArithmeticCommonMode | OperandMode::kInt32Imm | \
+ (CpuFeatures::IsSupported(DISTINCT_OPS) \
+ ? (OperandMode::kAllowRRR | OperandMode::kAllowRRI) \
+ : OperandMode::kArithmeticCommonMode)))
+#define SubOperandMode \
+ ((OperandMode::kArithmeticCommonMode | OperandMode::kInt32Imm_Negate | \
+ (CpuFeatures::IsSupported(DISTINCT_OPS) \
+ ? (OperandMode::kAllowRRR | OperandMode::kAllowRRI) \
+ : OperandMode::kArithmeticCommonMode)))
+#define MulOperandMode \
+ (OperandMode::kArithmeticCommonMode | OperandMode::kInt32Imm)
+
// Adds S390-specific methods for generating operands.
class S390OperandGenerator final : public OperandGenerator {
public:
explicit S390OperandGenerator(InstructionSelector* selector)
: OperandGenerator(selector) {}
- InstructionOperand UseOperand(Node* node, ImmediateMode mode) {
+ InstructionOperand UseOperand(Node* node, OperandModes mode) {
if (CanBeImmediate(node, mode)) {
return UseImmediate(node);
}
@@ -45,7 +83,7 @@ class S390OperandGenerator final : public OperandGenerator {
return 0L;
}
- bool CanBeImmediate(Node* node, ImmediateMode mode) {
+ bool CanBeImmediate(Node* node, OperandModes mode) {
int64_t value;
if (node->opcode() == IrOpcode::kInt32Constant)
value = OpParameter<int32_t>(node);
@@ -56,24 +94,21 @@ class S390OperandGenerator final : public OperandGenerator {
return CanBeImmediate(value, mode);
}
- bool CanBeImmediate(int64_t value, ImmediateMode mode) {
- switch (mode) {
- case kShift32Imm:
- return 0 <= value && value < 32;
- case kShift64Imm:
- return 0 <= value && value < 64;
- case kInt32Imm:
- return is_int32(value);
- case kInt32Imm_Negate:
- return is_int32(-value);
- case kUint32Imm:
- return is_uint32(value);
- case kInt20Imm:
- return is_int20(value);
- case kNoImmediate:
- return false;
- }
- return false;
+ bool CanBeImmediate(int64_t value, OperandModes mode) {
+ if (mode & OperandMode::kShift32Imm)
+ return 0 <= value && value < 32;
+ else if (mode & OperandMode::kShift64Imm)
+ return 0 <= value && value < 64;
+ else if (mode & OperandMode::kInt32Imm)
+ return is_int32(value);
+ else if (mode & OperandMode::kInt32Imm_Negate)
+ return is_int32(-value);
+ else if (mode & OperandMode::kUint32Imm)
+ return is_uint32(value);
+ else if (mode & OperandMode::kInt20Imm)
+ return is_int20(value);
+ else
+ return false;
}
AddressingMode GenerateMemoryOperandInputs(Node* index, Node* base,
@@ -131,7 +166,7 @@ class S390OperandGenerator final : public OperandGenerator {
#endif
DCHECK(m.matches());
if ((m.displacement() == nullptr ||
- CanBeImmediate(m.displacement(), kInt20Imm))) {
+ CanBeImmediate(m.displacement(), OperandMode::kInt20Imm))) {
DCHECK(m.scale() == 0);
return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(),
m.displacement_mode(), inputs,
@@ -158,6 +193,127 @@ class S390OperandGenerator final : public OperandGenerator {
namespace {
+ArchOpcode SelectLoadOpcode(Node* node) {
+ NodeMatcher m(node);
+ DCHECK(m.IsLoad());
+ LoadRepresentation load_rep = LoadRepresentationOf(node->op());
+ ArchOpcode opcode = kArchNop;
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kFloat32:
+ opcode = kS390_LoadFloat32;
+ break;
+ case MachineRepresentation::kFloat64:
+ opcode = kS390_LoadDouble;
+ break;
+ case MachineRepresentation::kBit: // Fall through.
+ case MachineRepresentation::kWord8:
+ opcode = load_rep.IsSigned() ? kS390_LoadWordS8 : kS390_LoadWordU8;
+ break;
+ case MachineRepresentation::kWord16:
+ opcode = load_rep.IsSigned() ? kS390_LoadWordS16 : kS390_LoadWordU16;
+ break;
+#if !V8_TARGET_ARCH_S390X
+ case MachineRepresentation::kTaggedSigned: // Fall through.
+ case MachineRepresentation::kTaggedPointer: // Fall through.
+ case MachineRepresentation::kTagged: // Fall through.
+#endif
+ case MachineRepresentation::kWord32:
+ opcode = kS390_LoadWordU32;
+ break;
+#if V8_TARGET_ARCH_S390X
+ case MachineRepresentation::kTaggedSigned: // Fall through.
+ case MachineRepresentation::kTaggedPointer: // Fall through.
+ case MachineRepresentation::kTagged: // Fall through.
+ case MachineRepresentation::kWord64:
+ opcode = kS390_LoadWord64;
+ break;
+#else
+ case MachineRepresentation::kWord64: // Fall through.
+#endif
+ case MachineRepresentation::kSimd128: // Fall through.
+ case MachineRepresentation::kNone:
+ default:
+ UNREACHABLE();
+ }
+ return opcode;
+}
+
+bool AutoZeroExtendsWord32ToWord64(Node* node) {
+#if !V8_TARGET_ARCH_S390X
+ return true;
+#else
+ switch (node->opcode()) {
+ case IrOpcode::kInt32Div:
+ case IrOpcode::kUint32Div:
+ case IrOpcode::kInt32MulHigh:
+ case IrOpcode::kInt32Mod:
+ case IrOpcode::kUint32Mod:
+ 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:
+ return true;
+ // TODO(john.yan): consider the following case to be valid
+ // case IrOpcode::kWord32Equal:
+ // case IrOpcode::kInt32LessThan:
+ // case IrOpcode::kInt32LessThanOrEqual:
+ // case IrOpcode::kUint32LessThan:
+ // case IrOpcode::kUint32LessThanOrEqual:
+ // case IrOpcode::kUint32MulHigh:
+ // // These 32-bit operations implicitly zero-extend to 64-bit on x64, so
+ // the
+ // // zero-extension is a no-op.
+ // return true;
+ // case IrOpcode::kProjection: {
+ // Node* const value = node->InputAt(0);
+ // switch (value->opcode()) {
+ // case IrOpcode::kInt32AddWithOverflow:
+ // case IrOpcode::kInt32SubWithOverflow:
+ // case IrOpcode::kInt32MulWithOverflow:
+ // return true;
+ // default:
+ // return false;
+ // }
+ // }
+ case IrOpcode::kLoad: {
+ LoadRepresentation load_rep = LoadRepresentationOf(node->op());
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kWord32:
+ return true;
+ default:
+ return false;
+ }
+ }
+ default:
+ return false;
+ }
+#endif
+}
+
void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
S390OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsRegister(node),
@@ -171,15 +327,15 @@ void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
g.UseRegister(node->InputAt(1)));
}
+#if V8_TARGET_ARCH_S390X
void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node,
- ImmediateMode operand_mode) {
+ OperandModes operand_mode) {
S390OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)),
g.UseOperand(node->InputAt(1), operand_mode));
}
-#if V8_TARGET_ARCH_S390X
void VisitTryTruncateDouble(InstructionSelector* selector, ArchOpcode opcode,
Node* node) {
S390OperandGenerator g(selector);
@@ -200,7 +356,7 @@ void VisitTryTruncateDouble(InstructionSelector* selector, ArchOpcode opcode,
// Shared routine for multiple binary operations.
template <typename Matcher>
void VisitBinop(InstructionSelector* selector, Node* node,
- InstructionCode opcode, ImmediateMode operand_mode,
+ InstructionCode opcode, OperandModes operand_mode,
FlagsContinuation* cont) {
S390OperandGenerator g(selector);
Matcher m(node);
@@ -269,54 +425,149 @@ void VisitBinop(InstructionSelector* selector, Node* node,
// Shared routine for multiple binary operations.
template <typename Matcher>
void VisitBinop(InstructionSelector* selector, Node* node, ArchOpcode opcode,
- ImmediateMode operand_mode) {
+ OperandModes operand_mode) {
FlagsContinuation cont;
VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
}
-} // namespace
+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;
+
+ // 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);
+ }
-void InstructionSelector::VisitLoad(Node* node) {
- LoadRepresentation load_rep = LoadRepresentationOf(node->op());
- S390OperandGenerator g(this);
- ArchOpcode opcode = kArchNop;
- switch (load_rep.representation()) {
- case MachineRepresentation::kFloat32:
- opcode = kS390_LoadFloat32;
- break;
- case MachineRepresentation::kFloat64:
- opcode = kS390_LoadDouble;
- break;
- case MachineRepresentation::kBit: // Fall through.
- case MachineRepresentation::kWord8:
- opcode = load_rep.IsSigned() ? kS390_LoadWordS8 : kS390_LoadWordU8;
- break;
- case MachineRepresentation::kWord16:
- opcode = load_rep.IsSigned() ? kS390_LoadWordS16 : kS390_LoadWordU16;
- break;
-#if !V8_TARGET_ARCH_S390X
- case MachineRepresentation::kTaggedSigned: // Fall through.
- case MachineRepresentation::kTaggedPointer: // Fall through.
- case MachineRepresentation::kTagged: // Fall through.
-#endif
- case MachineRepresentation::kWord32:
- opcode = kS390_LoadWordU32;
- break;
#if V8_TARGET_ARCH_S390X
- case MachineRepresentation::kTaggedSigned: // Fall through.
- case MachineRepresentation::kTaggedPointer: // Fall through.
- case MachineRepresentation::kTagged: // Fall through.
- case MachineRepresentation::kWord64:
- opcode = kS390_LoadWord64;
- break;
+ if ((ZeroExtendsWord32ToWord64(right) || g.CanBeBetterLeftOperand(right)) &&
+ node->op()->HasProperty(Operator::kCommutative) &&
+ !g.CanBeImmediate(right, operand_mode)) {
+ std::swap(left, right);
+ }
#else
- case MachineRepresentation::kWord64: // Fall through.
+ if (node->op()->HasProperty(Operator::kCommutative) &&
+ !g.CanBeImmediate(right, operand_mode) &&
+ (g.CanBeBetterLeftOperand(right))) {
+ std::swap(left, right);
+ }
#endif
- case MachineRepresentation::kSimd128: // Fall through.
- case MachineRepresentation::kNone:
+
+ // left is always register
+ InstructionOperand const left_input = g.UseRegister(left);
+ inputs[input_count++] = left_input;
+
+ // TODO(turbofan): match complex addressing modes.
+ if (left == right) {
+ // If both inputs refer to the same operand, enforce allocating a register
+ // for both of them to ensure that we don't end up generating code like
+ // this:
+ //
+ // mov rax, [rbp-0x10]
+ // add rax, [rbp-0x10]
+ // jo label
+ inputs[input_count++] = left_input;
+ // Can only be RR or RRR
+ operand_mode &= OperandMode::kAllowRRR;
+ } else if ((operand_mode & OperandMode::kAllowImmediate) &&
+ g.CanBeImmediate(right, operand_mode)) {
+ inputs[input_count++] = g.UseImmediate(right);
+ // Can only be RI or RRI
+ operand_mode &= OperandMode::kAllowImmediate;
+ } else if (operand_mode & OperandMode::kAllowMemoryOperand) {
+ NodeMatcher mright(right);
+ if (mright.IsLoad() && selector->CanCover(node, right) &&
+ SelectLoadOpcode(right) == kS390_LoadWordU32) {
+ AddressingMode mode =
+ g.GetEffectiveAddressMemoryOperand(right, inputs, &input_count);
+ opcode |= AddressingModeField::encode(mode);
+ operand_mode &= ~OperandMode::kAllowImmediate;
+ if (operand_mode & OperandMode::kAllowRM)
+ operand_mode &= ~OperandMode::kAllowDistinctOps;
+ } else if (operand_mode & OperandMode::kAllowRM) {
+ DCHECK(!(operand_mode & OperandMode::kAllowRRM));
+ inputs[input_count++] = g.Use(right);
+ // Can not be Immediate
+ operand_mode &=
+ ~OperandMode::kAllowImmediate & ~OperandMode::kAllowDistinctOps;
+ } else if (operand_mode & OperandMode::kAllowRRM) {
+ DCHECK(!(operand_mode & OperandMode::kAllowRM));
+ inputs[input_count++] = g.Use(right);
+ // Can not be Immediate
+ operand_mode &= ~OperandMode::kAllowImmediate;
+ } else {
UNREACHABLE();
- return;
+ }
+ } else {
+ inputs[input_count++] = g.UseRegister(right);
+ // Can only be RR or RRR
+ operand_mode &= OperandMode::kAllowRRR;
+ }
+
+ 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 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->reason(), cont->frame_state());
+ } else {
+ selector->Emit(opcode, output_count, outputs, input_count, inputs);
+ }
+}
+
+void VisitBin32op(InstructionSelector* selector, Node* node, ArchOpcode opcode,
+ OperandModes operand_mode) {
+ FlagsContinuation cont;
+ VisitBin32op(selector, node, opcode, operand_mode, &cont);
+}
+
+} // namespace
+
+void InstructionSelector::VisitLoad(Node* node) {
+ S390OperandGenerator g(this);
+ ArchOpcode opcode = SelectLoadOpcode(node);
InstructionOperand outputs[1];
outputs[0] = g.DefineAsRegister(node);
InstructionOperand inputs[3];
@@ -350,7 +601,7 @@ void InstructionSelector::VisitStore(Node* node) {
inputs[input_count++] = g.UseUniqueRegister(base);
// OutOfLineRecordWrite uses the offset in an 'AddP' instruction as well as
// for the store itself, so we must check compatibility with both.
- if (g.CanBeImmediate(offset, kInt20Imm)) {
+ if (g.CanBeImmediate(offset, OperandMode::kInt20Imm)) {
inputs[input_count++] = g.UseImmediate(offset);
addressing_mode = kMode_MRI;
} else {
@@ -494,7 +745,7 @@ void InstructionSelector::VisitCheckedLoad(Node* node) {
AddressingMode addressingMode = kMode_MRR;
Emit(opcode | AddressingModeField::encode(addressingMode),
g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(offset),
- g.UseOperand(length, kUint32Imm));
+ g.UseOperand(length, OperandMode::kUint32Imm));
}
void InstructionSelector::VisitCheckedStore(Node* node) {
@@ -541,7 +792,7 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
AddressingMode addressingMode = kMode_MRR;
Emit(opcode | AddressingModeField::encode(addressingMode), g.NoOutput(),
g.UseRegister(base), g.UseRegister(offset),
- g.UseOperand(length, kUint32Imm), g.UseRegister(value));
+ g.UseOperand(length, OperandMode::kUint32Imm), g.UseRegister(value));
}
#if 0
@@ -571,7 +822,8 @@ static inline bool IsContiguousMask64(uint64_t value, int* mb, int* me) {
#endif
void InstructionSelector::VisitWord32And(Node* node) {
- VisitBinop<Int32BinopMatcher>(this, node, kS390_And32, kUint32Imm);
+ VisitBin32op(this, node, kS390_And32,
+ BitWiseOperandMode | OperandMode::kAllowRM);
}
#if V8_TARGET_ARCH_S390X
@@ -623,46 +875,38 @@ void InstructionSelector::VisitWord64And(Node* node) {
}
}
}
- VisitBinop<Int64BinopMatcher>(this, node, kS390_And64, kUint32Imm);
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_And64,
+ OperandMode::kUint32Imm);
}
#endif
void InstructionSelector::VisitWord32Or(Node* node) {
- Int32BinopMatcher m(node);
- VisitBinop<Int32BinopMatcher>(this, node, kS390_Or32, kUint32Imm);
+ VisitBin32op(this, node, kS390_Or32,
+ BitWiseOperandMode | OperandMode::kAllowRM);
}
#if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitWord64Or(Node* node) {
Int64BinopMatcher m(node);
- VisitBinop<Int64BinopMatcher>(this, node, kS390_Or64, kUint32Imm);
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_Or64,
+ OperandMode::kUint32Imm);
}
#endif
void InstructionSelector::VisitWord32Xor(Node* node) {
- S390OperandGenerator g(this);
- Int32BinopMatcher m(node);
- if (m.right().Is(-1)) {
- Emit(kS390_Not32, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
- } else {
- VisitBinop<Int32BinopMatcher>(this, node, kS390_Xor32, kUint32Imm);
- }
+ VisitBin32op(this, node, kS390_Xor32,
+ BitWiseOperandMode | OperandMode::kAllowRM);
}
#if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitWord64Xor(Node* node) {
- S390OperandGenerator g(this);
- Int64BinopMatcher m(node);
- if (m.right().Is(-1)) {
- Emit(kS390_Not64, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
- } else {
- VisitBinop<Int64BinopMatcher>(this, node, kS390_Xor64, kUint32Imm);
- }
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_Xor64,
+ OperandMode::kUint32Imm);
}
#endif
void InstructionSelector::VisitWord32Shl(Node* node) {
- VisitRRO(this, kS390_ShiftLeft32, node, kShift32Imm);
+ VisitBin32op(this, node, kS390_ShiftLeft32, BitWiseOperandMode);
}
#if V8_TARGET_ARCH_S390X
@@ -705,12 +949,12 @@ void InstructionSelector::VisitWord64Shl(Node* node) {
}
}
}
- VisitRRO(this, kS390_ShiftLeft64, node, kShift64Imm);
+ VisitRRO(this, kS390_ShiftLeft64, node, OperandMode::kShift64Imm);
}
#endif
void InstructionSelector::VisitWord32Shr(Node* node) {
- VisitRRO(this, kS390_ShiftRight32, node, kShift32Imm);
+ VisitBin32op(this, node, kS390_ShiftRight32, BitWiseOperandMode);
}
#if V8_TARGET_ARCH_S390X
@@ -749,7 +993,7 @@ void InstructionSelector::VisitWord64Shr(Node* node) {
}
}
}
- VisitRRO(this, kS390_ShiftRight64, node, kShift64Imm);
+ VisitRRO(this, kS390_ShiftRight64, node, OperandMode::kShift64Imm);
}
#endif
@@ -760,16 +1004,20 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().Is(16) && m.right().Is(16)) {
- Emit(kS390_ExtendSignWord16, g.DefineAsRegister(node),
- g.UseRegister(mleft.left().node()));
+ 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;
} else if (mleft.right().Is(24) && m.right().Is(24)) {
- Emit(kS390_ExtendSignWord8, g.DefineAsRegister(node),
- g.UseRegister(mleft.left().node()));
+ 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;
}
}
- VisitRRO(this, kS390_ShiftRightArith32, node, kShift32Imm);
+ VisitBin32op(this, node, kS390_ShiftRightArith32, BitWiseOperandMode);
}
#if !V8_TARGET_ARCH_S390X
@@ -795,7 +1043,7 @@ void VisitPairBinop(InstructionSelector* selector, InstructionCode opcode,
// instruction.
selector->Emit(opcode2, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)),
- g.UseRegister(node->InputAt(2)));
+ g.UseRegister(node->InputAt(2)), g.TempImmediate(0));
}
}
@@ -825,7 +1073,8 @@ void InstructionSelector::VisitInt32PairMul(Node* node) {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kS390_Mul32, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(2)));
+ g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(2)),
+ g.TempImmediate(0));
}
}
@@ -881,17 +1130,20 @@ void InstructionSelector::VisitWord32PairSar(Node* node) {
#if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitWord64Sar(Node* node) {
- VisitRRO(this, kS390_ShiftRightArith64, node, kShift64Imm);
+ VisitRRO(this, kS390_ShiftRightArith64, node, OperandMode::kShift64Imm);
}
#endif
void InstructionSelector::VisitWord32Ror(Node* node) {
- VisitRRO(this, kS390_RotRight32, node, kShift32Imm);
+ // 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) {
- VisitRRO(this, kS390_RotRight64, node, kShift64Imm);
+ VisitRRO(this, kS390_RotRight64, node, OperandMode::kShift64Imm);
}
#endif
@@ -961,12 +1213,13 @@ void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
}
void InstructionSelector::VisitInt32Add(Node* node) {
- VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt32Imm);
+ VisitBin32op(this, node, kS390_Add32, AddOperandMode);
}
#if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitInt64Add(Node* node) {
- VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt32Imm);
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64,
+ OperandMode::kInt32Imm);
}
#endif
@@ -974,10 +1227,12 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
S390OperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.left().Is(0)) {
- Emit(kS390_Neg32, g.DefineAsRegister(node),
- g.UseRegister(m.right().node()));
+ Node* right = m.right().node();
+ bool doZeroExt = ZeroExtendsWord32ToWord64(right);
+ Emit(kS390_Neg32, g.DefineAsRegister(node), g.UseRegister(right),
+ g.TempImmediate(doZeroExt));
} else {
- VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32, kInt32Imm_Negate);
+ VisitBin32op(this, node, kS390_Sub32, SubOperandMode);
}
}
@@ -989,7 +1244,8 @@ void InstructionSelector::VisitInt64Sub(Node* node) {
Emit(kS390_Neg64, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
- VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64, kInt32Imm_Negate);
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64,
+ OperandMode::kInt32Imm_Negate);
}
}
#endif
@@ -999,35 +1255,14 @@ namespace {
void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont);
-void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
- FlagsContinuation* cont) {
- S390OperandGenerator g(selector);
- Int32BinopMatcher m(node);
- InstructionOperand result_operand = g.DefineAsRegister(node);
- InstructionOperand high32_operand = g.TempRegister();
- InstructionOperand temp_operand = g.TempRegister();
- {
- InstructionOperand outputs[] = {result_operand, high32_operand};
- InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
- g.UseRegister(m.right().node())};
- selector->Emit(kS390_Mul32WithHigh32, 2, outputs, 2, inputs);
- }
- {
- InstructionOperand shift_31 = g.UseImmediate(31);
- InstructionOperand outputs[] = {temp_operand};
- InstructionOperand inputs[] = {result_operand, shift_31};
- selector->Emit(kS390_ShiftRightArith32, 1, outputs, 2, inputs);
- }
-
- VisitCompare(selector, kS390_Cmp32, high32_operand, temp_operand, cont);
-}
+#if V8_TARGET_ARCH_S390X
void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
S390OperandGenerator g(selector);
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
- if (g.CanBeImmediate(right, kInt32Imm)) {
+ if (g.CanBeImmediate(right, OperandMode::kInt32Imm)) {
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
g.UseImmediate(right));
} else {
@@ -1038,17 +1273,18 @@ void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
g.Use(right));
}
}
+#endif
} // namespace
void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
- return EmitInt32MulWithOverflow(this, node, &cont);
+ return VisitBin32op(this, node, kS390_Mul32WithOverflow,
+ OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps,
+ &cont);
}
- VisitMul(this, node, kS390_Mul32);
- // FlagsContinuation cont;
- // EmitInt32MulWithOverflow(this, node, &cont);
+ VisitBin32op(this, node, kS390_Mul32, MulOperandMode);
}
void InstructionSelector::VisitInt32Mul(Node* node) {
@@ -1056,14 +1292,20 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
- if (g.CanBeImmediate(right, kInt32Imm) &&
+ if (g.CanBeImmediate(right, OperandMode::kInt32Imm) &&
base::bits::IsPowerOfTwo32(g.GetImmediate(right))) {
int power = 31 - base::bits::CountLeadingZeros32(g.GetImmediate(right));
- Emit(kS390_ShiftLeft32, g.DefineSameAsFirst(node), g.UseRegister(left),
- g.UseImmediate(power));
+ 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;
}
- VisitMul(this, node, kS390_Mul32);
+ VisitBin32op(this, node, kS390_Mul32, MulOperandMode);
}
#if V8_TARGET_ARCH_S390X
@@ -1072,7 +1314,7 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
Int64BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
- if (g.CanBeImmediate(right, kInt32Imm) &&
+ 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),
@@ -1084,15 +1326,8 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
#endif
void InstructionSelector::VisitInt32MulHigh(Node* node) {
- S390OperandGenerator g(this);
- Int32BinopMatcher m(node);
- Node* left = m.left().node();
- Node* right = m.right().node();
- if (g.CanBeBetterLeftOperand(right)) {
- std::swap(left, right);
- }
- Emit(kS390_MulHigh32, g.DefineAsRegister(node), g.UseRegister(left),
- g.Use(right));
+ VisitBin32op(this, node, kS390_MulHigh32,
+ OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps);
}
void InstructionSelector::VisitUint32MulHigh(Node* node) {
@@ -1108,7 +1343,8 @@ void InstructionSelector::VisitUint32MulHigh(Node* node) {
}
void InstructionSelector::VisitInt32Div(Node* node) {
- VisitRRR(this, kS390_Div32, node);
+ VisitBin32op(this, node, kS390_Div32,
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR);
}
#if V8_TARGET_ARCH_S390X
@@ -1118,7 +1354,8 @@ void InstructionSelector::VisitInt64Div(Node* node) {
#endif
void InstructionSelector::VisitUint32Div(Node* node) {
- VisitRRR(this, kS390_DivU32, node);
+ VisitBin32op(this, node, kS390_DivU32,
+ OperandMode::kAllowRRM | OperandMode::kAllowRRR);
}
#if V8_TARGET_ARCH_S390X
@@ -1202,7 +1439,13 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
}
void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
- // TODO(mbrandy): inspect input to see if nop is appropriate.
+ 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);
}
#endif
@@ -1408,46 +1651,46 @@ void InstructionSelector::VisitFloat64Neg(Node* node) {
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+ OperandModes mode = AddOperandMode;
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
- return VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt32Imm,
- &cont);
+ return VisitBin32op(this, node, kS390_Add32, mode, &cont);
}
FlagsContinuation cont;
- VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt32Imm, &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 VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32,
- kInt32Imm_Negate, &cont);
+ return VisitBin32op(this, node, kS390_Sub32, mode, &cont);
}
FlagsContinuation cont;
- VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32, kInt32Imm_Negate,
- &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 VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt32Imm,
- &cont);
+ return VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64,
+ OperandMode::kInt32Imm, &cont);
}
FlagsContinuation cont;
- VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt32Imm, &cont);
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, OperandMode::kInt32Imm,
+ &cont);
}
void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64,
- kInt32Imm_Negate, &cont);
+ OperandMode::kInt32Imm_Negate, &cont);
}
FlagsContinuation cont;
- VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64, kInt32Imm_Negate,
- &cont);
+ VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64,
+ OperandMode::kInt32Imm_Negate, &cont);
}
#endif
@@ -1488,7 +1731,7 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
// Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont,
- bool commutative, ImmediateMode immediate_mode) {
+ bool commutative, OperandModes immediate_mode) {
S390OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
@@ -1509,14 +1752,16 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
void VisitWord32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
- ImmediateMode mode = (CompareLogical(cont) ? kUint32Imm : kInt32Imm);
+ OperandModes mode =
+ (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm);
VisitWordCompare(selector, node, kS390_Cmp32, cont, false, mode);
}
#if V8_TARGET_ARCH_S390X
void VisitWord64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
- ImmediateMode mode = (CompareLogical(cont) ? kUint32Imm : kUint32Imm);
+ OperandModes mode =
+ (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm);
VisitWordCompare(selector, node, kS390_Cmp64, cont, false, mode);
}
#endif
@@ -1571,7 +1816,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kWord32And:
return VisitWordCompare(selector, value, kS390_Tst64, cont,
- true, kUint32Imm);
+ true, OperandMode::kUint32Imm);
default:
break;
}
@@ -1605,7 +1850,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
return VisitWord64Compare(selector, value, cont);
case IrOpcode::kWord64And:
return VisitWordCompare(selector, value, kS390_Tst64, cont,
- true, kUint32Imm);
+ true, OperandMode::kUint32Imm);
default:
break;
}
@@ -1659,24 +1904,28 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
- return VisitBinop<Int32BinopMatcher>(
- selector, node, kS390_Add32, kInt32Imm, cont);
+ return VisitBin32op(selector, node, kS390_Add32, AddOperandMode,
+ cont);
case IrOpcode::kInt32SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
- return VisitBinop<Int32BinopMatcher>(
- selector, node, kS390_Sub32, kInt32Imm_Negate, cont);
+ return VisitBin32op(selector, node, kS390_Sub32, SubOperandMode,
+ cont);
case IrOpcode::kInt32MulWithOverflow:
cont->OverwriteAndNegateIfEqual(kNotEqual);
- return EmitInt32MulWithOverflow(selector, node, cont);
+ return VisitBin32op(
+ selector, node, kS390_Mul32WithOverflow,
+ OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps,
+ cont);
#if V8_TARGET_ARCH_S390X
case IrOpcode::kInt64AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int64BinopMatcher>(
- selector, node, kS390_Add64, kInt32Imm, cont);
+ selector, node, kS390_Add64, OperandMode::kInt32Imm, cont);
case IrOpcode::kInt64SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int64BinopMatcher>(
- selector, node, kS390_Sub64, kInt32Imm_Negate, cont);
+ selector, node, kS390_Sub64, OperandMode::kInt32Imm_Negate,
+ cont);
#endif
default:
break;
@@ -1688,7 +1937,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kWord32And:
return VisitWordCompare(selector, value, kS390_Tst32, cont, true,
- kUint32Imm);
+ OperandMode::kUint32Imm);
// TODO(mbrandy): Handle?
// case IrOpcode::kInt32Add:
// case IrOpcode::kWord32Or:
@@ -1702,7 +1951,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
return VisitWord64Compare(selector, value, cont);
case IrOpcode::kWord64And:
return VisitWordCompare(selector, value, kS390_Tst64, cont, true,
- kUint32Imm);
+ OperandMode::kUint32Imm);
// TODO(mbrandy): Handle?
// case IrOpcode::kInt64Add:
// case IrOpcode::kWord64Or:
@@ -1780,9 +2029,14 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand index_operand = value_operand;
if (sw.min_value) {
index_operand = g.TempRegister();
- Emit(kS390_Sub32, index_operand, value_operand,
- g.TempImmediate(sw.min_value));
+ Emit(kS390_Lay | AddressingModeField::encode(kMode_MRI), index_operand,
+ value_operand, g.TempImmediate(-sw.min_value));
}
+#if V8_TARGET_ARCH_S390X
+ InstructionOperand index_operand_zero_ext = g.TempRegister();
+ Emit(kS390_Uint32ToUint64, index_operand_zero_ext, index_operand);
+ index_operand = index_operand_zero_ext;
+#endif
// Generate a table lookup.
return EmitTableSwitch(sw, index_operand);
}
« no previous file with comments | « src/compiler/s390/instruction-scheduler-s390.cc ('k') | src/s390/assembler-s390.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698