Commit 33022426 authored by Kanghua Yu's avatar Kanghua Yu Committed by Commit Bot

Reland "[turbofan][x64] Reduce compare-zero followed by flags-setting binop"

On IA architecture, arithmetic and shifting operations set the flags
according to the computation result.

    subl rsi,0x1
    REX.W movq rbx,[rbx+0x17]
    cmpl rsi, 0                       <-- TO BE REDUCED
    jnz 0x3f54d2dcef0
==>
    REX.W movq rbx,[rbx+0x17]
    subl rsi,0x1
    jnz 0x3f54d2dcef0
&
    orl rdx,rbx
    cmpl rdx,0x0                      <-- TO BE REDUCED
    jnz 0x3f54d22b0f5
==>
    orl rdx,rbx
    jnz 0x3f54d22b0f5

Bug: chromium:842497, chromium:842501
Change-Id: I4e2c40861b76ac3f508b01ee27249e85eab3222f
Reviewed-on: https://chromium-review.googlesource.com/1057351Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Kanghua Yu <kanghua.yu@intel.com>
Cr-Commit-Position: refs/heads/master@{#53171}
parent 0e8b67ce
......@@ -589,6 +589,28 @@ void VisitWord64Shift(InstructionSelector* selector, Node* node,
}
}
// Shared routine for multiple shift operations with continuation.
template <typename BinopMatcher, int Bits>
bool TryVisitWordShift(InstructionSelector* selector, Node* node,
ArchOpcode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector);
BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
// If the shift count is 0, the flags are not affected.
if (!g.CanBeImmediate(right) ||
(g.GetImmediateIntegerValue(right) & (Bits - 1)) == 0) {
return false;
}
InstructionOperand output = g.DefineSameAsFirst(node);
InstructionOperand inputs[2];
inputs[0] = g.UseRegister(left);
inputs[1] = g.UseImmediate(right);
selector->EmitWithContinuation(opcode, 1, &output, 2, inputs, cont);
return true;
}
void EmitLea(InstructionSelector* selector, InstructionCode opcode,
Node* result, Node* index, int scale, Node* base,
Node* displacement, DisplacementMode displacement_mode) {
......@@ -1722,11 +1744,55 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
VisitWordCompare(selector, node, kX64Cmp, cont);
}
// Shared routine for comparison with zero.
void VisitCompareZero(InstructionSelector* selector, Node* node,
void VisitCompareZero(InstructionSelector* selector, Node* user, Node* node,
InstructionCode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector);
if (cont->IsBranch() &&
(cont->condition() == kNotEqual || cont->condition() == kEqual)) {
switch (node->opcode()) {
#define FLAGS_SET_BINOP_LIST(V) \
V(kInt32Add, VisitBinop, kX64Add32) \
V(kInt32Sub, VisitBinop, kX64Sub32) \
V(kWord32And, VisitBinop, kX64And32) \
V(kWord32Or, VisitBinop, kX64Or32) \
V(kInt64Add, VisitBinop, kX64Add) \
V(kInt64Sub, VisitBinop, kX64Sub) \
V(kWord64And, VisitBinop, kX64And) \
V(kWord64Or, VisitBinop, kX64Or)
#define FLAGS_SET_BINOP(opcode, Visit, archOpcode) \
case IrOpcode::opcode: \
if (selector->IsOnlyUserOfNodeInSameBlock(user, node)) { \
return Visit(selector, node, archOpcode, cont); \
} \
break;
FLAGS_SET_BINOP_LIST(FLAGS_SET_BINOP)
#undef FLAGS_SET_BINOP_LIST
#undef FLAGS_SET_BINOP
#define TRY_VISIT_WORD32_SHIFT TryVisitWordShift<Int32BinopMatcher, 32>
#define TRY_VISIT_WORD64_SHIFT TryVisitWordShift<Int64BinopMatcher, 64>
// Skip Word64Sar/Word32Sar since no instruction reduction in most cases.
#define FLAGS_SET_SHIFT_LIST(V) \
V(kWord32Shl, TRY_VISIT_WORD32_SHIFT, kX64Shl32) \
V(kWord32Shr, TRY_VISIT_WORD32_SHIFT, kX64Shr32) \
V(kWord64Shl, TRY_VISIT_WORD64_SHIFT, kX64Shl) \
V(kWord64Shr, TRY_VISIT_WORD64_SHIFT, kX64Shr)
#define FLAGS_SET_SHIFT(opcode, TryVisit, archOpcode) \
case IrOpcode::opcode: \
if (selector->IsOnlyUserOfNodeInSameBlock(user, node)) { \
if (TryVisit(selector, node, archOpcode, cont)) return; \
} \
break;
FLAGS_SET_SHIFT_LIST(FLAGS_SET_SHIFT)
#undef TRY_VISIT_WORD32_SHIFT
#undef TRY_VISIT_WORD64_SHIFT
#undef FLAGS_SET_SHIFT_LIST
#undef FLAGS_SET_SHIFT
default:
break;
}
}
VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont);
}
......@@ -1897,7 +1963,7 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
break;
}
}
return VisitCompareZero(this, value, kX64Cmp, cont);
return VisitCompareZero(this, user, value, kX64Cmp, cont);
}
return VisitWord64Compare(this, value, cont);
}
......@@ -1992,7 +2058,7 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
}
// Branch could not be combined with a compare, emit compare against 0.
VisitCompareZero(this, value, kX64Cmp32, cont);
VisitCompareZero(this, user, value, kX64Cmp32, cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
......
......@@ -3199,6 +3199,54 @@ TEST(RunWord32ShrP) {
}
}
TEST(RunWordShiftInBranch) {
static const uint32_t constant = 987654321;
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<uint32_t> m(MachineType::Uint32());
RawMachineLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Shl(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
uint32_t expected = ((*i << shift) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i));
}
}
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<uint32_t> m(MachineType::Uint32());
RawMachineLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_UINT32_INPUTS(i) {
uint32_t expected = ((*i >> shift) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i));
}
}
FOR_UINT32_SHIFTS(shift) {
RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
RawMachineLabel blocka, blockb;
m.Branch(m.Word32Equal(m.Word32Sar(m.Parameter(0), m.Int32Constant(shift)),
m.Int32Constant(0)),
&blocka, &blockb);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
m.Bind(&blockb);
m.Return(m.Int32Constant(0 - constant));
FOR_INT32_INPUTS(i) {
int32_t expected = ((*i >> shift) == 0) ? constant : 0 - constant;
CHECK_EQ(expected, m.Call(*i));
}
}
}
TEST(RunWord32ShrInComparison) {
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment