summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/codegenarmarch.cpp4
-rw-r--r--src/jit/codegenlinear.h3
-rw-r--r--src/jit/codegenxarch.cpp43
-rw-r--r--src/jit/gentree.cpp12
-rw-r--r--src/jit/gentree.h11
-rw-r--r--src/jit/gtlist.h12
-rw-r--r--src/jit/gtstructs.h2
-rw-r--r--src/jit/lower.cpp2
-rw-r--r--src/jit/lowerxarch.cpp5
-rw-r--r--src/jit/lsra.cpp2
-rw-r--r--src/jit/lsraxarch.cpp15
-rw-r--r--src/jit/rationalize.cpp4
12 files changed, 86 insertions, 29 deletions
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index 40fb746ed0..f7edec1bfc 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -240,7 +240,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
#ifdef _TARGET_ARM_
case GT_JCC:
- genCodeForJcc(treeNode->AsJumpCC());
+ genCodeForJcc(treeNode->AsCC());
break;
#endif // _TARGET_ARM_
@@ -2568,7 +2568,7 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
// Arguments:
// tree - the node
//
-void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
+void CodeGen::genCodeForJcc(GenTreeCC* tree)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h
index ffcc1d6015..c91d2e76b0 100644
--- a/src/jit/codegenlinear.h
+++ b/src/jit/codegenlinear.h
@@ -172,7 +172,8 @@ void genCodeForLclFld(GenTreeLclFld* tree);
void genCodeForStoreLclFld(GenTreeLclFld* tree);
void genCodeForStoreLclVar(GenTreeLclVar* tree);
void genCodeForReturnTrap(GenTreeOp* tree);
-void genCodeForJcc(GenTreeJumpCC* tree);
+void genCodeForJcc(GenTreeCC* tree);
+void genCodeForSetcc(GenTreeCC* setcc);
void genCodeForStoreInd(GenTreeStoreInd* tree);
void genCodeForSwap(GenTreeOp* tree);
void genCodeForCpObj(GenTreeObj* cpObjNode);
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index e64928e195..21da989ef1 100644
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -1410,14 +1410,14 @@ void CodeGen::genReturn(GenTreePtr treeNode)
}
//------------------------------------------------------------------------
-// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT/GT_TEST_EQ/GT_TEST_NE node.
+// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT/GT_TEST_EQ/GT_TEST_NE/GT_CMP node.
//
// Arguments:
// tree - the node
//
void CodeGen::genCodeForCompare(GenTreeOp* tree)
{
- assert(tree->OperIs(GT_EQ, GT_NE, GT_LT, GT_LE, GT_GE, GT_GT, GT_TEST_EQ, GT_TEST_NE));
+ assert(tree->OperIs(GT_EQ, GT_NE, GT_LT, GT_LE, GT_GE, GT_GT, GT_TEST_EQ, GT_TEST_NE, GT_CMP));
// TODO-XArch-CQ: Check if we can use the currently set flags.
// TODO-XArch-CQ: Check for the case where we can simply transfer the carry bit to a register
@@ -1520,7 +1520,7 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
// Arguments:
// tree - the node
//
-void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
+void CodeGen::genCodeForJcc(GenTreeCC* tree)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
@@ -1531,6 +1531,34 @@ void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
}
//------------------------------------------------------------------------
+// genCodeForSetcc: Generates a setcc instruction for a GT_SETCC node.
+//
+// Arguments:
+// tree - the GT_SETCC node
+//
+// Assumptions:
+// The condition represents an integer comparison. This code doesn't
+// have the necessary logic to deal with floating point comparisons,
+// in fact it doesn't even know if the comparison is integer or floating
+// point because SETCC nodes do not have any operands.
+//
+
+void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
+{
+ regNumber dstReg = setcc->gtRegNum;
+ CompareKind compareKind = setcc->IsUnsigned() ? CK_UNSIGNED : CK_SIGNED;
+ emitJumpKind jumpKind = genJumpKindForOper(setcc->gtCondition, compareKind);
+
+ assert(genIsValidIntReg(dstReg) && isByteReg(dstReg));
+ // Make sure nobody is setting GTF_RELOP_NAN_UN on this node as it is ignored.
+ assert((setcc->gtFlags & GTF_RELOP_NAN_UN) == 0);
+
+ inst_SET(jumpKind, dstReg);
+ inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), dstReg, dstReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
+ genProduceReg(setcc);
+}
+
+//------------------------------------------------------------------------
// genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
//
// Arguments:
@@ -1771,6 +1799,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
case GT_GT:
case GT_TEST_EQ:
case GT_TEST_NE:
+ case GT_CMP:
genCodeForCompare(treeNode->AsOp());
break;
@@ -1779,7 +1808,11 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
break;
case GT_JCC:
- genCodeForJcc(treeNode->AsJumpCC());
+ genCodeForJcc(treeNode->AsCC());
+ break;
+
+ case GT_SETCC:
+ genCodeForSetcc(treeNode->AsCC());
break;
case GT_RETURNTRAP:
@@ -6287,7 +6320,7 @@ void CodeGen::genCompareFloat(GenTreePtr treeNode)
// None.
void CodeGen::genCompareInt(GenTreePtr treeNode)
{
- assert(treeNode->OperIsCompare());
+ assert(treeNode->OperIsCompare() || treeNode->OperIs(GT_CMP));
GenTreeOp* tree = treeNode->AsOp();
GenTreePtr op1 = tree->gtOp1;
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index 2f09590c01..551dcfc91e 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -366,7 +366,7 @@ void GenTree::InitNodeSize()
static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeRegVar) <= TREE_NODE_SZ_SMALL);
- static_assert_no_msg(sizeof(GenTreeJumpCC) <= TREE_NODE_SZ_SMALL);
+ static_assert_no_msg(sizeof(GenTreeCC) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node
static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node
@@ -3447,10 +3447,10 @@ GenTreePtr Compiler::gtReverseCond(GenTree* tree)
tree->gtFlags ^= GTF_RELOP_NAN_UN;
}
}
- else if (tree->OperGet() == GT_JCC)
+ else if (tree->OperIs(GT_JCC, GT_SETCC))
{
- GenTreeJumpCC* jcc = tree->AsJumpCC();
- jcc->gtCondition = GenTree::ReverseRelop(jcc->gtCondition);
+ GenTreeCC* cc = tree->AsCC();
+ cc->gtCondition = GenTree::ReverseRelop(cc->gtCondition);
}
else
{
@@ -9200,6 +9200,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
case GT_MEMORYBARRIER:
case GT_JMP:
case GT_JCC:
+ case GT_SETCC:
case GT_NO_OP:
case GT_START_NONGC:
case GT_PROF_HOOK:
@@ -11182,7 +11183,8 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
break;
case GT_JCC:
- printf(" cond=%s", GenTree::NodeName(tree->AsJumpCC()->gtCondition));
+ case GT_SETCC:
+ printf(" cond=%s", GenTree::NodeName(tree->AsCC()->gtCondition));
break;
default:
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index d99a05f3ff..65ee25aad1 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -4981,18 +4981,21 @@ struct GenTreeAllocObj final : public GenTreeUnOp
#endif
};
-struct GenTreeJumpCC final : public GenTree
+// Represents a GT_JCC or GT_SETCC node.
+
+struct GenTreeCC final : public GenTree
{
genTreeOps gtCondition; // any relop
- GenTreeJumpCC(genTreeOps condition)
- : GenTree(GT_JCC, TYP_VOID DEBUGARG(/*largeNode*/ FALSE)), gtCondition(condition)
+ GenTreeCC(genTreeOps oper, genTreeOps condition, var_types type = TYP_VOID)
+ : GenTree(oper, type DEBUGARG(/*largeNode*/ FALSE)), gtCondition(condition)
{
+ assert(OperIs(GT_JCC, GT_SETCC));
assert(OperIsCompare(condition));
}
#if DEBUGGABLE_GENTREE
- GenTreeJumpCC() : GenTree()
+ GenTreeCC() : GenTree()
{
}
#endif // DEBUGGABLE_GENTREE
diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h
index 5af2f5bb78..cba2d71a3b 100644
--- a/src/jit/gtlist.h
+++ b/src/jit/gtlist.h
@@ -214,11 +214,21 @@ GTNODE(SIMD , "simd" ,GenTreeSIMD ,0,GTK_BINOP|GTK_EX
#endif // FEATURE_SIMD
//-----------------------------------------------------------------------------
+// LIR specific compare and conditional branch/set nodes:
+//-----------------------------------------------------------------------------
+
+GTNODE(CMP , "cmp" ,GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // Sets the condition flags according to the compare result.
+ // N.B. Not a relop, it does not produce a value and it cannot be reversed.
+GTNODE(JCC , "jcc" ,GenTreeCC ,0,GTK_LEAF|GTK_NOVALUE) // Checks the condition flags and branch if the condition specified
+ // by GenTreeCC::gtCondition is true.
+GTNODE(SETCC , "setcc" ,GenTreeCC ,0,GTK_LEAF) // Checks the condition flags and produces 1 if the condition specified
+ // by GenTreeCC::gtCondition is true and 0 otherwise.
+
+//-----------------------------------------------------------------------------
// Other nodes that look like unary/binary operators:
//-----------------------------------------------------------------------------
GTNODE(JTRUE , "jmpTrue" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE)
-GTNODE(JCC , "jcc" ,GenTreeJumpCC ,0,GTK_LEAF|GTK_NOVALUE)
GTNODE(LIST , "<list>" ,GenTreeArgList ,0,GTK_BINOP|GTK_NOVALUE)
GTNODE(FIELD_LIST , "<fldList>" ,GenTreeFieldList ,0,GTK_BINOP) // List of fields of a struct, when passed as an argument
diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h
index c4a4f73e37..898aeec002 100644
--- a/src/jit/gtstructs.h
+++ b/src/jit/gtstructs.h
@@ -101,7 +101,7 @@ GTSTRUCT_1(PhysReg , GT_PHYSREG)
GTSTRUCT_1(SIMD , GT_SIMD)
#endif // FEATURE_SIMD
GTSTRUCT_1(AllocObj , GT_ALLOCOBJ)
-GTSTRUCT_1(JumpCC , GT_JCC)
+GTSTRUCT_2(CC , GT_JCC, GT_SETCC)
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
GTSTRUCT_1(MulLong , GT_MUL_LONG)
#endif
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index 3f3dbc101e..c043b03566 100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -2217,7 +2217,7 @@ void Lowering::LowerCompare(GenTree* cmp)
BasicBlock* newBlock2 = comp->fgSplitBlockAtEnd(newBlock);
- GenTree* hiJcc = new (comp, GT_JCC) GenTreeJumpCC(hiCmpOper);
+ GenTree* hiJcc = new (comp, GT_JCC) GenTreeCC(GT_JCC, hiCmpOper);
hiJcc->gtFlags = cmp->gtFlags;
LIR::AsRange(newBlock).InsertAfter(nullptr, hiJcc);
diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp
index f887a2a330..cda563479f 100644
--- a/src/jit/lowerxarch.cpp
+++ b/src/jit/lowerxarch.cpp
@@ -1012,7 +1012,7 @@ bool Lowering::isRMWRegOper(GenTreePtr tree)
// For now, We assume that most binary operators are of the RMW form.
assert(tree->OperIsBinary());
- if (tree->OperIsCompare())
+ if (tree->OperIsCompare() || tree->OperIs(GT_CMP))
{
return false;
}
@@ -1086,7 +1086,7 @@ bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode)
GenTree* Lowering::PreferredRegOptionalOperand(GenTree* tree)
{
assert(GenTree::OperIsBinary(tree->OperGet()));
- assert(tree->OperIsCommutative() || tree->OperIsCompare());
+ assert(tree->OperIsCommutative() || tree->OperIsCompare() || tree->OperIs(GT_CMP));
GenTree* op1 = tree->gtGetOp1();
GenTree* op2 = tree->gtGetOp2();
@@ -1161,7 +1161,6 @@ GenTree* Lowering::PreferredRegOptionalOperand(GenTree* tree)
else
{
preferredOp = op1;
- ;
}
}
else if (op1->OperGet() == GT_LCL_VAR)
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 1f86325fe3..03f383bda5 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -3419,7 +3419,7 @@ static int ComputeOperandDstCount(GenTree* operand)
// If an operand has no destination registers but does have source registers, it must be a store
// or a compare.
assert(operand->OperIsStore() || operand->OperIsBlkOp() || operand->OperIsPutArgStk() ||
- operand->OperIsCompare() || operand->IsSIMDEqualityOrInequality());
+ operand->OperIsCompare() || operand->OperIs(GT_CMP) || operand->IsSIMDEqualityOrInequality());
return 0;
}
else if (!operand->OperIsFieldListHead() && (operand->OperIsStore() || operand->TypeGet() == TYP_VOID))
diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp
index 56f1bd26d6..3fa85cf211 100644
--- a/src/jit/lsraxarch.cpp
+++ b/src/jit/lsraxarch.cpp
@@ -335,6 +335,14 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
info->dstCount = 0;
break;
+ case GT_SETCC:
+ info->srcCount = 0;
+ info->dstCount = 1;
+#ifdef _TARGET_X86_
+ info->setDstCandidates(m_lsra, RBM_BYTE_REGS);
+#endif // _TARGET_X86_
+ break;
+
case GT_JMP:
info->srcCount = 0;
info->dstCount = 0;
@@ -523,6 +531,7 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
case GT_GT:
case GT_TEST_EQ:
case GT_TEST_NE:
+ case GT_CMP:
TreeNodeInfoInitCmp(tree);
break;
@@ -3026,12 +3035,12 @@ void Lowering::TreeNodeInfoInitIndir(GenTreePtr indirTree)
//
void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree)
{
- assert(tree->OperIsCompare());
+ assert(tree->OperIsCompare() || tree->OperIs(GT_CMP));
TreeNodeInfo* info = &(tree->gtLsraInfo);
info->srcCount = 2;
- info->dstCount = 1;
+ info->dstCount = tree->OperIs(GT_CMP) ? 0 : 1;
#ifdef _TARGET_X86_
// If the compare is used by a jump, we just need to set the condition codes. If not, then we need
@@ -3561,7 +3570,7 @@ bool Lowering::ExcludeNonByteableRegisters(GenTree* tree)
{
return true;
}
- else if (tree->OperIsCompare())
+ else if (tree->OperIsCompare() || tree->OperIs(GT_CMP))
{
GenTree* op1 = tree->gtGetOp1();
GenTree* op2 = tree->gtGetOp2();
diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp
index c0fb92486c..adf01f9e29 100644
--- a/src/jit/rationalize.cpp
+++ b/src/jit/rationalize.cpp
@@ -951,8 +951,8 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStack<G
#endif // FEATURE_SIMD
default:
- // JCC nodes should not be present in HIR.
- assert(node->OperGet() != GT_JCC);
+ // CMP, SETCC and JCC nodes should not be present in HIR.
+ assert(!node->OperIs(GT_CMP, GT_SETCC, GT_JCC));
break;
}