Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Simplify some relop/jtrue related optimizations #14027

Merged
merged 4 commits into from
Oct 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3298,40 +3298,6 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
assert(!op1->isUsedFromMemory());
assert(!op2->isUsedFromMemory());

// Case of op1 == 0 or op1 != 0:
// Optimize generation of 'test' instruction if op1 sets flags.
//
// This behavior is designed to match the unexpected behavior
// of XARCH genCompareInt();
//
// TODO-Cleanup Review GTF_USE_FLAGS usage
// https://github.com/dotnet/coreclr/issues/14093
if ((tree->gtFlags & GTF_USE_FLAGS) != 0)
{
// op1 must set flags
assert(op1->gtSetFlags());

// Must be compare against zero.
assert(!tree->OperIs(GT_TEST_EQ, GT_TEST_NE));
assert(op2->IsIntegralConst(0));
assert(op2->isContained());

// Just consume the operands
genConsumeOperands(tree);

// No need to generate compare instruction since
// op1 sets flags

// Are we evaluating this into a register?
if (targetReg != REG_NA)
{
genSetRegToCond(targetReg, tree);
genProduceReg(tree);
}

return;
}

genConsumeOperands(tree);

emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
Expand Down
63 changes: 2 additions & 61 deletions src/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,8 @@ void CodeGen::genCodeForBinary(GenTree* treeNode)
}

// try to use an inc or dec
if (oper == GT_ADD && !varTypeIsFloating(treeNode) && src->isContainedIntOrIImmed() && !treeNode->gtOverflowEx())
if (oper == GT_ADD && !varTypeIsFloating(treeNode) && src->isContainedIntOrIImmed() && !treeNode->gtOverflowEx() &&
!treeNode->gtSetFlags())
{
if (src->IsIntegralConst(1))
{
Expand Down Expand Up @@ -6243,66 +6244,6 @@ void CodeGen::genCompareInt(GenTreePtr treeNode)
var_types op2Type = op2->TypeGet();
regNumber targetReg = tree->gtRegNum;

// Case of op1 == 0 or op1 != 0:
// Optimize generation of 'test' instruction if op1 sets flags.
//
// TODO-Cleanup Review GTF_USE_FLAGS usage
// https://github.com/dotnet/coreclr/issues/14093
//
// Note that if LSRA has inserted any GT_RELOAD/GT_COPY before
// op1, it will not modify the flags set by codegen of op1.
// Similarly op1 could also be reg-optional at its use and
// it was spilled after producing its result in a register.
// Spill code too will not modify the flags set by op1.
GenTree* realOp1 = op1->gtSkipReloadOrCopy();
if ((tree->gtFlags & GTF_USE_FLAGS) != 0)
{
// op1 must set ZF and SF flags
assert(realOp1->gtSetZSFlags());
assert(realOp1->gtSetFlags());

// Must be (in)equality against zero.
assert(tree->OperIs(GT_EQ, GT_NE));
assert(op2->IsIntegralConst(0));
assert(op2->isContained());

// Just consume the operands
genConsumeOperands(tree);

// No need to generate test instruction since
// op1 sets flags

// Are we evaluating this into a register?
if (targetReg != REG_NA)
{
genSetRegToCond(targetReg, tree);
genProduceReg(tree);
}

return;
}

#ifdef FEATURE_SIMD
// If we have GT_JTRUE(GT_EQ/NE(GT_SIMD((in)Equality, v1, v2), true/false)),
// then we don't need to generate code for GT_EQ/GT_NE, since SIMD (in)Equality intrinsic
// would set or clear Zero flag.
if ((targetReg == REG_NA) && tree->OperIs(GT_EQ, GT_NE))
{
// Is it a SIMD (in)Equality that doesn't need to materialize result into a register?
if ((op1->gtRegNum == REG_NA) && op1->IsSIMDEqualityOrInequality())
{
// Must be comparing against true or false.
assert(op2->IsIntegralConst(0) || op2->IsIntegralConst(1));
assert(op2->isContainedIntOrIImmed());

// In this case SIMD (in)Equality will set or clear
// Zero flag, based on which GT_JTRUE would generate
// the right conditional jump.
return;
}
}
#endif // FEATURE_SIMD

genConsumeOperands(tree);

assert(!op1->isContainedIntOrIImmed());
Expand Down
2 changes: 1 addition & 1 deletion src/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9781,11 +9781,11 @@ int cTreeFlagsIR(Compiler* comp, GenTree* tree)
{
chars += printf("[SPILLED_OP2]");
}
#endif
if (tree->gtFlags & GTF_ZSF_SET)
{
chars += printf("[ZSF_SET]");
}
#endif
#if FEATURE_SET_FLAGS
if (tree->gtFlags & GTF_SET_FLAGS)
{
Expand Down
4 changes: 3 additions & 1 deletion src/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -856,11 +856,11 @@ struct GenTree
#ifdef LEGACY_BACKEND
#define GTF_SPILLED_OPER 0x00000100 // op1 has been spilled
#define GTF_SPILLED_OP2 0x00000200 // op2 has been spilled
#define GTF_ZSF_SET 0x00000400 // the zero(ZF) and sign(SF) flags set to the operand
#else // !LEGACY_BACKEND
#define GTF_NOREG_AT_USE 0x00000100 // tree node is in memory at the point of use
#endif // !LEGACY_BACKEND

#define GTF_ZSF_SET 0x00000400 // the zero(ZF) and sign(SF) flags set to the operand
#define GTF_SET_FLAGS 0x00000800 // Requires that codegen for this node set the flags. Use gtSetFlags() to check this flag.
#define GTF_USE_FLAGS 0x00001000 // Indicates that this node uses the flags bits.

Expand Down Expand Up @@ -2126,12 +2126,14 @@ struct GenTree
bool gtSetFlags() const;
bool gtRequestSetFlags();

#ifdef LEGACY_BACKEND
// Returns true if the codegen of this tree node
// sets ZF and SF flags.
bool gtSetZSFlags() const
{
return (gtFlags & GTF_ZSF_SET) != 0;
}
#endif

#ifdef DEBUG
bool gtIsValid64RsltMul();
Expand Down
Loading