From 3b24ec21079c2c45c0186586ef17632e85875e39 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Mon, 23 Apr 2018 18:17:52 +0300 Subject: Introduce GenCondition --- src/jit/gentree.h | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 3 deletions(-) (limited to 'src/jit/gentree.h') diff --git a/src/jit/gentree.h b/src/jit/gentree.h index c6c5841e98..099e399c10 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -5663,17 +5663,223 @@ struct GenTreeRuntimeLookup final : public GenTreeUnOp } }; +// Represents the condition of a GT_JCC or GT_SETCC node. + +struct GenCondition +{ + // clang-format off + enum Code : unsigned char + { + OperMask = 7, + Unsigned = 8, + Unordered = Unsigned, + Float = 16, + + // 0 would be the encoding of "signed EQ" but since equality is sign insensitive + // we'll use 0 as invalid/uninitialized condition code. This will also leave 1 + // as a spare code. + NONE = 0, + + SLT = 2, + SLE = 3, + SGE = 4, + SGT = 5, + S = 6, + NS = 7, + + EQ = Unsigned | 0, // = 8 + NE = Unsigned | 1, // = 9 + ULT = Unsigned | SLT, // = 10 + ULE = Unsigned | SLE, // = 11 + UGE = Unsigned | SGE, // = 12 + UGT = Unsigned | SGT, // = 13 + C = Unsigned | S, // = 14 + NC = Unsigned | NS, // = 15 + + FEQ = Float | EQ, // = 16 + FNE = Float | NE, // = 17 + FLT = Float | SLT, // = 18 + FLE = Float | SLE, // = 19 + FGE = Float | SGE, // = 20 + FGT = Float | SGT, // = 21 + O = Float | S, // = 22 + NO = Float | NS, // = 23 + + FEQU = Unordered | FEQ, // = 24 + FNEU = Unordered | FNE, // = 25 + FLTU = Unordered | FLT, // = 26 + FLEU = Unordered | FLE, // = 27 + FGEU = Unordered | FGE, // = 28 + FGTU = Unordered | FGT, // = 29 + P = Unordered | O, // = 30 + NP = Unordered | NO, // = 31 + }; + // clang-format on + +private: + Code m_code; + +public: + Code GetCode() const + { + return m_code; + } + + bool IsFlag() const + { + return (m_code & OperMask) >= S; + } + + bool IsUnsigned() const + { + return (ULT <= m_code) && (m_code <= UGT); + } + + bool IsFloat() const + { + return !IsFlag() && (m_code & Float) != 0; + } + + bool IsUnordered() const + { + return !IsFlag() && (m_code & (Float | Unordered)) == (Float | Unordered); + } + + bool Is(Code cond) const + { + return m_code == cond; + } + + template + bool Is(Code c, TRest... rest) const + { + return Is(c) || Is(rest...); + } + + const char* Name() const + { + // clang-format off + static const char* names[] + { + "NONE", "???", "SLT", "SLE", "SGE", "SGT", "S", "NS", + "UEQ", "UNE", "ULT", "ULE", "UGE", "UGT", "C", "NC", + "FEQ", "FNE", "FLT", "FLE", "FGE", "FGT", "O", "NO", + "FEQU", "FNEU", "FLTU", "FLEU", "FGEU", "FGTU", "P", "NP" + }; + // clang-format on + + assert(m_code < _countof(names)); + return names[m_code]; + } + + GenCondition() : m_code() + { + } + + GenCondition(Code cond) : m_code(cond) + { + } + + static_assert((GT_NE - GT_EQ) == (NE & ~Unsigned), "bad relop"); + static_assert((GT_LT - GT_EQ) == SLT, "bad relop"); + static_assert((GT_LE - GT_EQ) == SLE, "bad relop"); + static_assert((GT_GE - GT_EQ) == SGE, "bad relop"); + static_assert((GT_GT - GT_EQ) == SGT, "bad relop"); +#ifndef LEGACY_BACKEND + static_assert((GT_TEST_NE - GT_TEST_EQ) == (NE & ~Unsigned), "bad relop"); +#endif + + static GenCondition FromRelop(GenTree* relop) + { + assert(relop->OperIsCompare()); + + if (varTypeIsFloating(relop->gtGetOp1())) + { + return FromFloatRelop(relop); + } + else + { + return FromIntegralRelop(relop); + } + } + + static GenCondition FromFloatRelop(GenTree* relop) + { + assert(varTypeIsFloating(relop->gtGetOp1()) && varTypeIsFloating(relop->gtGetOp2())); + + return FromFloatRelop(relop->OperGet(), (relop->gtFlags & GTF_RELOP_NAN_UN) != 0); + } + + static GenCondition FromFloatRelop(genTreeOps oper, bool isUnordered) + { + assert(GenTree::OperIsCompare(oper)); + + unsigned code = oper - GT_EQ; + assert(code <= SGT); + code |= Float; + + if (isUnordered) + { + code |= Unordered; + } + + return GenCondition(static_cast(code)); + } + + static GenCondition FromIntegralRelop(GenTree* relop) + { + assert(!varTypeIsFloating(relop->gtGetOp1()) && !varTypeIsFloating(relop->gtGetOp2())); + + return FromIntegralRelop(relop->OperGet(), relop->IsUnsigned()); + } + + static GenCondition FromIntegralRelop(genTreeOps oper, bool isUnsigned) + { + assert(GenTree::OperIsCompare(oper)); + +#ifndef LEGACY_BACKEND + // GT_TEST_EQ/NE are special, they need to be mapped as GT_EQ/NE + unsigned code = oper - ((oper >= GT_TEST_EQ) ? GT_TEST_EQ : GT_EQ); +#else + unsigned code = oper - GT_EQ; +#endif + + if (isUnsigned || (code <= 1)) // EQ/NE are treated as unsigned + { + code |= Unsigned; + } + + return GenCondition(static_cast(code)); + } + + static GenCondition Reverse(GenCondition condition) + { + // clang-format off + static const Code reverse[] + { + // EQ NE LT LE GE GT F NF + NONE, NONE, SGE, SGT, SLT, SLE, NS, S, + NE, EQ, UGE, UGT, ULT, ULE, NC, C, + FNEU, FEQU, FGEU, FGTU, FLTU, FLEU, NO, O, + FNE, FEQ, FGE, FGT, FLT, FGT, NP, P + }; + // clang-format on + + assert(condition.m_code < _countof(reverse)); + return GenCondition(reverse[condition.m_code]); + } +}; + // Represents a GT_JCC or GT_SETCC node. struct GenTreeCC final : public GenTree { - genTreeOps gtCondition; // any relop + GenCondition gtCondition; - GenTreeCC(genTreeOps oper, genTreeOps condition, var_types type = TYP_VOID) + GenTreeCC(genTreeOps oper, GenCondition 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 -- cgit v1.2.3