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

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

Issue 2696343002: s390: optimize for compares (Closed)
Patch Set: add todo Created 3 years, 10 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 27bb6c6f10933ac3313dc8ec7e0904e870cf58f8..a0fed62be331a2aa09d911fa4992dc6075848d22 100644
--- a/src/compiler/s390/instruction-selector-s390.cc
+++ b/src/compiler/s390/instruction-selector-s390.cc
@@ -21,6 +21,7 @@ enum class OperandMode : uint32_t {
kInt32Imm_Negate = 1u << 3,
kUint32Imm = 1u << 4,
kInt20Imm = 1u << 5,
+ kUint12Imm = 1u << 6,
// Instr format
kAllowRRR = 1u << 7,
kAllowRM = 1u << 8,
@@ -83,6 +84,13 @@ class S390OperandGenerator final : public OperandGenerator {
return UseRegister(node);
}
+ InstructionOperand UseAnyExceptImmediate(Node* node) {
+ if (NodeProperties::IsConstant(node))
+ return UseRegister(node);
+ else
+ return Use(node);
+ }
+
int64_t GetImmediate(Node* node) {
if (node->opcode() == IrOpcode::kInt32Constant)
return OpParameter<int32_t>(node);
@@ -117,10 +125,38 @@ class S390OperandGenerator final : public OperandGenerator {
return is_uint32(value);
else if (mode & OperandMode::kInt20Imm)
return is_int20(value);
+ else if (mode & OperandMode::kUint12Imm)
+ return is_uint12(value);
else
return false;
}
+ bool CanBeMemoryOperand(InstructionCode opcode, Node* user, Node* input,
+ int effect_level) {
+ if (input->opcode() != IrOpcode::kLoad ||
+ !selector()->CanCover(user, input)) {
+ return false;
+ }
+
+ if (effect_level != selector()->GetEffectLevel(input)) {
+ return false;
+ }
+
+ MachineRepresentation rep =
+ LoadRepresentationOf(input->op()).representation();
+ switch (opcode) {
+ case kS390_Cmp64:
+ case kS390_LoadAndTestWord64:
+ return rep == MachineRepresentation::kWord64 || IsAnyTagged(rep);
+ case kS390_LoadAndTestWord32:
+ case kS390_Cmp32:
+ return rep == MachineRepresentation::kWord32;
+ default:
+ break;
+ }
+ return false;
+ }
+
AddressingMode GenerateMemoryOperandInputs(Node* index, Node* base,
Node* displacement,
DisplacementMode displacement_mode,
@@ -164,9 +200,9 @@ class S390OperandGenerator final : public OperandGenerator {
return mode;
}
- AddressingMode GetEffectiveAddressMemoryOperand(Node* operand,
- InstructionOperand inputs[],
- size_t* input_count) {
+ AddressingMode GetEffectiveAddressMemoryOperand(
+ Node* operand, InstructionOperand inputs[], size_t* input_count,
+ OperandModes immediate_mode = OperandMode::kInt20Imm) {
#if V8_TARGET_ARCH_S390X
BaseWithIndexAndDisplacement64Matcher m(operand,
AddressOption::kAllowInputSwap);
@@ -176,7 +212,7 @@ class S390OperandGenerator final : public OperandGenerator {
#endif
DCHECK(m.matches());
if ((m.displacement() == nullptr ||
- CanBeImmediate(m.displacement(), OperandMode::kInt20Imm))) {
+ CanBeImmediate(m.displacement(), immediate_mode))) {
DCHECK(m.scale() == 0);
return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(),
m.displacement_mode(), inputs,
@@ -203,6 +239,25 @@ class S390OperandGenerator final : public OperandGenerator {
namespace {
+bool S390OpcodeOnlySupport12BitDisp(ArchOpcode opcode) {
+ switch (opcode) {
+ case kS390_CmpFloat:
+ case kS390_CmpDouble:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool S390OpcodeOnlySupport12BitDisp(InstructionCode op) {
+ ArchOpcode opcode = ArchOpcodeField::decode(op);
+ return S390OpcodeOnlySupport12BitDisp(opcode);
+}
+
+#define OpcodeImmMode(op) \
+ (S390OpcodeOnlySupport12BitDisp(op) ? OperandMode::kUint12Imm \
+ : OperandMode::kInt20Imm)
+
ArchOpcode SelectLoadOpcode(Node* node) {
NodeMatcher m(node);
DCHECK(m.IsLoad());
@@ -1741,25 +1796,87 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
}
}
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+ Node* value, InstructionCode opcode,
+ FlagsContinuation* cont);
+
+void VisitLoadAndTest(InstructionSelector* selector, InstructionCode opcode,
+ Node* node, Node* value, FlagsContinuation* cont,
+ bool discard_output = false);
+
// Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont,
- bool commutative, OperandModes immediate_mode) {
+ OperandModes immediate_mode) {
S390OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
- // Match immediates on left or right side of comparison.
- if (g.CanBeImmediate(right, immediate_mode)) {
- VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
- cont);
- } else if (g.CanBeImmediate(left, immediate_mode)) {
- if (!commutative) cont->Commute();
- VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
- cont);
+ DCHECK(IrOpcode::IsComparisonOpcode(node->opcode()) ||
+ node->opcode() == IrOpcode::kInt32Sub ||
+ node->opcode() == IrOpcode::kInt64Sub);
+
+ InstructionOperand inputs[8];
+ InstructionOperand outputs[1];
+ size_t input_count = 0;
+ size_t output_count = 0;
+
+ // If one of the two inputs is an immediate, make sure it's on the right, or
+ // if one of the two inputs is a memory operand, make sure it's on the left.
+ int effect_level = selector->GetEffectLevel(node);
+ if (cont->IsBranch()) {
+ effect_level = selector->GetEffectLevel(
+ cont->true_block()->PredecessorAt(0)->control_input());
+ }
+
+ if ((!g.CanBeImmediate(right, immediate_mode) &&
+ g.CanBeImmediate(left, immediate_mode)) ||
+ (!g.CanBeMemoryOperand(opcode, node, right, effect_level) &&
+ g.CanBeMemoryOperand(opcode, node, left, effect_level))) {
+ if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
+ std::swap(left, right);
+ }
+
+ // check if compare with 0
+ if (g.CanBeImmediate(right, immediate_mode) && g.GetImmediate(right) == 0) {
+ DCHECK(opcode == kS390_Cmp32 || opcode == kS390_Cmp64);
+ ArchOpcode load_and_test = (opcode == kS390_Cmp32)
+ ? kS390_LoadAndTestWord32
+ : kS390_LoadAndTestWord64;
+ return VisitLoadAndTest(selector, load_and_test, node, left, cont, true);
+ }
+
+ inputs[input_count++] = g.UseRegister(left);
+ if (g.CanBeMemoryOperand(opcode, node, right, effect_level)) {
+ // generate memory operand
+ AddressingMode addressing_mode = g.GetEffectiveAddressMemoryOperand(
+ right, inputs, &input_count, OpcodeImmMode(opcode));
+ opcode |= AddressingModeField::encode(addressing_mode);
+ } else if (g.CanBeImmediate(right, immediate_mode)) {
+ inputs[input_count++] = g.UseImmediate(right);
+ } else {
+ inputs[input_count++] = g.UseAnyExceptImmediate(right);
+ }
+
+ opcode = cont->Encode(opcode);
+ if (cont->IsBranch()) {
+ inputs[input_count++] = g.Label(cont->true_block());
+ inputs[input_count++] = g.Label(cont->false_block());
+ } else if (cont->IsSet()) {
+ outputs[output_count++] = g.DefineAsRegister(cont->result());
+ } else if (cont->IsTrap()) {
+ inputs[input_count++] = g.UseImmediate(cont->trap_id());
} else {
- VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
- cont);
+ DCHECK(cont->IsDeoptimize());
+ // nothing to do
+ }
+
+ DCHECK(input_count <= 8 && output_count <= 1);
+ if (cont->IsDeoptimize()) {
+ selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
+ cont->reason(), cont->frame_state());
+ } else {
+ selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
}
@@ -1767,7 +1884,7 @@ void VisitWord32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
OperandModes mode =
(CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm);
- VisitWordCompare(selector, node, kS390_Cmp32, cont, false, mode);
+ VisitWordCompare(selector, node, kS390_Cmp32, cont, mode);
}
#if V8_TARGET_ARCH_S390X
@@ -1775,28 +1892,97 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
OperandModes mode =
(CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm);
- VisitWordCompare(selector, node, kS390_Cmp64, cont, false, mode);
+ VisitWordCompare(selector, node, kS390_Cmp64, cont, mode);
}
#endif
// Shared routine for multiple float32 compare operations.
void VisitFloat32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
- S390OperandGenerator g(selector);
- Node* left = node->InputAt(0);
- Node* right = node->InputAt(1);
- VisitCompare(selector, kS390_CmpFloat, g.UseRegister(left),
- g.UseRegister(right), cont);
+ VisitWordCompare(selector, node, kS390_CmpFloat, cont, OperandMode::kNone);
}
// Shared routine for multiple float64 compare operations.
void VisitFloat64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
+ VisitWordCompare(selector, node, kS390_CmpDouble, cont, OperandMode::kNone);
+}
+
+void VisitTestUnderMask(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ DCHECK(node->opcode() == IrOpcode::kWord32And ||
+ node->opcode() == IrOpcode::kWord64And);
+ ArchOpcode opcode =
+ (node->opcode() == IrOpcode::kWord32And) ? kS390_Tst32 : kS390_Tst64;
S390OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
- VisitCompare(selector, kS390_CmpDouble, g.UseRegister(left),
- g.UseRegister(right), cont);
+ if (!g.CanBeImmediate(right, OperandMode::kUint32Imm) &&
+ g.CanBeImmediate(left, OperandMode::kUint32Imm)) {
+ std::swap(left, right);
+ }
+ VisitCompare(selector, opcode, g.UseRegister(left),
+ g.UseOperand(right, OperandMode::kUint32Imm), cont);
+}
+
+void VisitLoadAndTest(InstructionSelector* selector, InstructionCode opcode,
+ Node* node, Node* value, FlagsContinuation* cont,
+ bool discard_output) {
+ static_assert(kS390_LoadAndTestFloat64 - kS390_LoadAndTestWord32 == 3,
+ "LoadAndTest Opcode shouldn't contain other opcodes.");
+
+ // TODO(john.yan): Add support for Float32/Float64.
+ DCHECK(opcode >= kS390_LoadAndTestWord32 ||
+ opcode <= kS390_LoadAndTestWord64);
+
+ S390OperandGenerator g(selector);
+ InstructionOperand inputs[8];
+ InstructionOperand outputs[2];
+ size_t input_count = 0;
+ size_t output_count = 0;
+ bool use_value = false;
+
+ int effect_level = selector->GetEffectLevel(node);
+ if (cont->IsBranch()) {
+ effect_level = selector->GetEffectLevel(
+ cont->true_block()->PredecessorAt(0)->control_input());
+ }
+
+ if (g.CanBeMemoryOperand(opcode, node, value, effect_level)) {
+ // generate memory operand
+ AddressingMode addressing_mode =
+ g.GetEffectiveAddressMemoryOperand(value, inputs, &input_count);
+ opcode |= AddressingModeField::encode(addressing_mode);
+ } else {
+ inputs[input_count++] = g.UseAnyExceptImmediate(value);
+ use_value = true;
+ }
+
+ if (!discard_output && !use_value) {
+ outputs[output_count++] = g.DefineAsRegister(value);
+ }
+
+ opcode = cont->Encode(opcode);
+ if (cont->IsBranch()) {
+ inputs[input_count++] = g.Label(cont->true_block());
+ inputs[input_count++] = g.Label(cont->false_block());
+ } else if (cont->IsSet()) {
+ outputs[output_count++] = g.DefineAsRegister(cont->result());
+ } else if (cont->IsTrap()) {
+ inputs[input_count++] = g.UseImmediate(cont->trap_id());
+ } else {
+ DCHECK(cont->IsDeoptimize());
+ // nothing to do
+ }
+
+ DCHECK(input_count <= 8 && output_count <= 2);
+ 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);
+ }
}
// Shared routine for word comparisons against zero.
@@ -1814,6 +2000,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
cont->Negate();
}
+ FlagsCondition fc = cont->condition();
if (selector->CanCover(user, value)) {
switch (value->opcode()) {
case IrOpcode::kWord32Equal: {
@@ -1828,8 +2015,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kInt32Sub:
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kWord32And:
- return VisitWordCompare(selector, value, kS390_Tst64, cont,
- true, OperandMode::kUint32Imm);
+ return VisitTestUnderMask(selector, value, cont);
default:
break;
}
@@ -1862,8 +2048,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kInt64Sub:
return VisitWord64Compare(selector, value, cont);
case IrOpcode::kWord64And:
- return VisitWordCompare(selector, value, kS390_Tst64, cont,
- true, OperandMode::kUint32Imm);
+ return VisitTestUnderMask(selector, value, cont);
default:
break;
}
@@ -1947,53 +2132,77 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
}
break;
case IrOpcode::kInt32Sub:
- return VisitWord32Compare(selector, value, cont);
+ if (fc == kNotEqual || fc == kEqual)
+ return VisitWord32Compare(selector, value, cont);
+ break;
case IrOpcode::kWord32And:
- return VisitWordCompare(selector, value, kS390_Tst32, cont, true,
- OperandMode::kUint32Imm);
-// TODO(mbrandy): Handle?
-// case IrOpcode::kInt32Add:
-// case IrOpcode::kWord32Or:
-// case IrOpcode::kWord32Xor:
-// case IrOpcode::kWord32Sar:
-// case IrOpcode::kWord32Shl:
-// case IrOpcode::kWord32Shr:
-// case IrOpcode::kWord32Ror:
+ return VisitTestUnderMask(selector, value, cont);
+ case IrOpcode::kLoad: {
+ LoadRepresentation load_rep = LoadRepresentationOf(value->op());
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kWord32:
+ if (opcode == kS390_LoadAndTestWord32) {
+ return VisitLoadAndTest(selector, opcode, user, value, cont);
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case IrOpcode::kInt32Add:
+ // can't handle overflow case.
+ break;
+ case IrOpcode::kWord32Or:
+ return VisitBin32op(selector, value, kS390_Or32, OrOperandMode, cont);
+ case IrOpcode::kWord32Xor:
+ return VisitBin32op(selector, value, kS390_Xor32, XorOperandMode, cont);
+ case IrOpcode::kWord32Sar:
+ case IrOpcode::kWord32Shl:
+ case IrOpcode::kWord32Shr:
+ case IrOpcode::kWord32Ror:
+ // doesn't generate cc, so ignore.
+ break;
#if V8_TARGET_ARCH_S390X
case IrOpcode::kInt64Sub:
- return VisitWord64Compare(selector, value, cont);
+ if (fc == kNotEqual || fc == kEqual)
+ return VisitWord64Compare(selector, value, cont);
+ break;
case IrOpcode::kWord64And:
- return VisitWordCompare(selector, value, kS390_Tst64, cont, true,
- OperandMode::kUint32Imm);
-// TODO(mbrandy): Handle?
-// case IrOpcode::kInt64Add:
-// case IrOpcode::kWord64Or:
-// case IrOpcode::kWord64Xor:
-// case IrOpcode::kWord64Sar:
-// case IrOpcode::kWord64Shl:
-// case IrOpcode::kWord64Shr:
-// case IrOpcode::kWord64Ror:
+ return VisitTestUnderMask(selector, value, cont);
+ case IrOpcode::kInt64Add:
+ // can't handle overflow case.
+ break;
+ case IrOpcode::kWord64Or:
+ // TODO(john.yan): need to handle
+ break;
+ case IrOpcode::kWord64Xor:
+ // TODO(john.yan): need to handle
+ break;
+ case IrOpcode::kWord64Sar:
+ case IrOpcode::kWord64Shl:
+ case IrOpcode::kWord64Shr:
+ case IrOpcode::kWord64Ror:
+ // doesn't generate cc, so ignore
+ break;
#endif
default:
break;
}
}
- // Branch could not be combined with a compare, emit compare against 0.
- S390OperandGenerator g(selector);
- VisitCompare(selector, opcode, g.UseRegister(value), g.TempImmediate(0),
- cont);
+ // Branch could not be combined with a compare, emit LoadAndTest
+ VisitLoadAndTest(selector, opcode, user, value, cont, true);
}
void VisitWord32CompareZero(InstructionSelector* selector, Node* user,
Node* value, FlagsContinuation* cont) {
- VisitWordCompareZero(selector, user, value, kS390_Cmp32, cont);
+ VisitWordCompareZero(selector, user, value, kS390_LoadAndTestWord32, cont);
}
#if V8_TARGET_ARCH_S390X
void VisitWord64CompareZero(InstructionSelector* selector, Node* user,
Node* value, FlagsContinuation* cont) {
- VisitWordCompareZero(selector, user, value, kS390_Cmp64, cont);
+ VisitWordCompareZero(selector, user, value, kS390_LoadAndTestWord64, cont);
}
#endif
« 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