Skip to content

Commit

Permalink
Merge pull request dotnet#17733 from mikedn/cc-cond2
Browse files Browse the repository at this point in the history
Expand GT_JCC/SETCC condition support
  • Loading branch information
briansull authored Jan 11, 2019
2 parents a2e3393 + 12cfc7f commit 459b58a
Show file tree
Hide file tree
Showing 16 changed files with 562 additions and 935 deletions.
63 changes: 45 additions & 18 deletions src/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,23 +92,6 @@ class CodeGen : public CodeGenInterface
}
}

enum CompareKind
{
CK_SIGNED,
CK_UNSIGNED,
CK_LOGICAL
};
static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind);

// For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array.
// The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the
// 'true' label or a 'false' label.
//
// 'true' label corresponds to jump target of the current basic block i.e. the target to
// branch to on compare condition being true. 'false' label corresponds to the target to
// branch to on condition being false.
static void genJumpKindsForTree(GenTree* cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);

static bool genShouldRoundFP();

GenTreeIndir indirForm(var_types type, GenTree* base);
Expand Down Expand Up @@ -1173,7 +1156,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genCallInstruction(GenTreeCall* call);
void genJmpMethod(GenTree* jmp);
BasicBlock* genCallFinally(BasicBlock* block);
void genCodeForJumpTrue(GenTree* tree);
void genCodeForJumpTrue(GenTreeOp* jtrue);
#ifdef _TARGET_ARM64_
void genCodeForJumpCompare(GenTreeOp* tree);
#endif // _TARGET_ARM64_
Expand Down Expand Up @@ -1393,6 +1376,50 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#ifdef _TARGET_XARCH_
instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
#endif // _TARGET_XARCH_

// Maps a GenCondition code to a sequence of conditional jumps or other conditional instructions
// such as X86's SETcc. A sequence of instructions rather than just a single one is required for
// certain floating point conditions.
// For example, X86's UCOMISS sets ZF to indicate equality but it also sets it, together with PF,
// to indicate an unordered result. So for GenCondition::FEQ we first need to check if PF is 0
// and then jump if ZF is 1:
// JP fallThroughBlock
// JE jumpDestBlock
// fallThroughBlock:
// ...
// jumpDestBlock:
//
// This is very similar to the way shortcircuit evaluation of bool AND and OR operators works so
// in order to make the GenConditionDesc mapping tables easier to read, a bool expression-like
// pattern is used to encode the above:
// { EJ_jnp, GT_AND, EJ_je }
// { EJ_jp, GT_OR, EJ_jne }
//
// For more details check inst_JCC and inst_SETCC functions.
//
struct GenConditionDesc
{
emitJumpKind jumpKind1;
genTreeOps oper;
emitJumpKind jumpKind2;
char padTo4Bytes;

static const GenConditionDesc& Get(GenCondition condition)
{
assert(condition.GetCode() < _countof(map));
const GenConditionDesc& desc = map[condition.GetCode()];
assert(desc.jumpKind1 != EJ_NONE);
assert((desc.oper == GT_NONE) || (desc.oper == GT_AND) || (desc.oper == GT_OR));
assert((desc.oper == GT_NONE) == (desc.jumpKind2 == EJ_NONE));
return desc;
}

private:
static const GenConditionDesc map[32];
};

void inst_JCC(GenCondition condition, BasicBlock* target);
void inst_SETCC(GenCondition condition, var_types type, regNumber dstReg);
};

/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down
77 changes: 10 additions & 67 deletions src/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,7 @@ void CodeGen::genLclHeap(GenTree* tree)
genConsumeRegAndCopy(size, regCnt);
endLabel = genCreateTempLabel();
getEmitter()->emitIns_R_R(INS_TEST, easz, regCnt, regCnt);
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, endLabel);
inst_JMP(EJ_eq, endLabel);
}

stackAdjustment = 0;
Expand Down Expand Up @@ -383,8 +382,7 @@ void CodeGen::genLclHeap(GenTree* tree)
// Note that regCnt is the number of bytes to stack allocate.
assert(genIsValidIntReg(regCnt));
getEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, regCnt, STACK_ALIGN, INS_FLAGS_SET);
emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
inst_JMP(jmpNotEqual, loop);
inst_JMP(EJ_ne, loop);
}
else
{
Expand Down Expand Up @@ -442,8 +440,7 @@ void CodeGen::genLclHeap(GenTree* tree)
getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());

getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
inst_JMP(jmpLTU, done);
inst_JMP(EJ_lo, done);

// Update SP to be at the next page of stack that we will tickle
getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regTmp);
Expand Down Expand Up @@ -1137,7 +1134,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
// Are we evaluating this into a register?
if (targetReg != REG_NA)
{
genSetRegToCond(targetReg, tree);
inst_SETCC(GenCondition::FromRelop(tree), tree->TypeGet(), targetReg);
genProduceReg(tree);
}
}
Expand All @@ -1163,8 +1160,7 @@ void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)

BasicBlock* skipLabel = genCreateTempLabel();

emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, skipLabel);
inst_JMP(EJ_eq, skipLabel);

// emit the call to the EE-helper that stops for GC (or other reasons)

Expand Down Expand Up @@ -1237,54 +1233,6 @@ void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
}
}

//------------------------------------------------------------------------
// genSetRegToCond: Generate code to materialize a condition into a register.
//
// Arguments:
// dstReg - The target register to set to 1 or 0
// tree - The GenTree Relop node that was used to set the Condition codes
//
// Return Value: none
//
// Preconditions:
// The condition codes must already have been appropriately set.
//
void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
{
// Emit code like that:
// ...
// beq True
// bvs True ; this second branch is typically absent
// movs rD, #0
// b Next
// True:
// movs rD, #1
// Next:
// ...

emitJumpKind jumpKind[2];
bool branchToTrueLabel[2];
genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);

BasicBlock* labelTrue = genCreateTempLabel();
getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[0]), labelTrue);

if (jumpKind[1] != EJ_NONE)
{
getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[1]), labelTrue);
}

getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 0);

BasicBlock* labelNext = genCreateTempLabel();
getEmitter()->emitIns_J(INS_b, labelNext);

genDefineTempLabel(labelTrue);
getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 1);
genDefineTempLabel(labelNext);
}

//------------------------------------------------------------------------
// genLongToIntCast: Generate code for long to int casts.
//
// Arguments:
Expand Down Expand Up @@ -1336,17 +1284,14 @@ void CodeGen::genLongToIntCast(GenTree* cast)
BasicBlock* success = genCreateTempLabel();

inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
inst_JMP(JmpNegative, allOne);
inst_JMP(EJ_mi, allOne);
inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
emitJumpKind jmpNotEqualL = genJumpKindForOper(GT_NE, CK_LOGICAL);
genJumpToThrowHlpBlk(jmpNotEqualL, SCK_OVERFLOW);
genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW);
inst_JMP(EJ_jmp, success);

genDefineTempLabel(allOne);
inst_RV_IV(INS_cmp, hiSrcReg, -1, EA_4BYTE);
emitJumpKind jmpNotEqualS = genJumpKindForOper(GT_NE, CK_SIGNED);
genJumpToThrowHlpBlk(jmpNotEqualS, SCK_OVERFLOW);
genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW);

genDefineTempLabel(success);
}
Expand All @@ -1355,13 +1300,11 @@ void CodeGen::genLongToIntCast(GenTree* cast)
if ((srcType == TYP_ULONG) && (dstType == TYP_INT))
{
inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
genJumpToThrowHlpBlk(JmpNegative, SCK_OVERFLOW);
genJumpToThrowHlpBlk(EJ_mi, SCK_OVERFLOW);
}

inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_LOGICAL);
genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW);
}
}

Expand Down
88 changes: 11 additions & 77 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1919,8 +1919,7 @@ void CodeGen::genLclHeap(GenTree* tree)
genConsumeRegAndCopy(size, targetReg);
endLabel = genCreateTempLabel();
getEmitter()->emitIns_R_R(INS_tst, easz, targetReg, targetReg);
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, endLabel);
inst_JMP(EJ_eq, endLabel);

// Compute the size of the block to allocate and perform alignment.
// If compInitMem=true, we can reuse targetReg as regcnt,
Expand Down Expand Up @@ -2040,8 +2039,7 @@ void CodeGen::genLclHeap(GenTree* tree)
// Therefore we need to subtract 16 from regcnt here.
assert(genIsValidIntReg(regCnt));
inst_RV_IV(INS_subs, regCnt, 16, emitActualTypeSize(type));
emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
inst_JMP(jmpNotEqual, loop);
inst_JMP(EJ_ne, loop);
}
else
{
Expand Down Expand Up @@ -2099,8 +2097,7 @@ void CodeGen::genLclHeap(GenTree* tree)
getEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, regTmp, REG_SPBASE, compiler->eeGetPageSize());

getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
inst_JMP(jmpLTU, done);
inst_JMP(EJ_lo, done);

// Update SP to be at the next page of stack that we will tickle
getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, regTmp);
Expand Down Expand Up @@ -2246,17 +2243,15 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree)
{
// Check if the divisor is zero throw a DivideByZeroException
emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
genJumpToThrowHlpBlk(EJ_eq, SCK_DIV_BY_ZERO);
}

if (checkDividend)
{
// Check if the divisor is not -1 branch to 'sdivLabel'
emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);

emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
inst_JMP(jmpNotEqual, sdivLabel);
inst_JMP(EJ_ne, sdivLabel);
// If control flow continues past here the 'divisorReg' is known to be -1

regNumber dividendReg = tree->gtGetOp1()->gtRegNum;
Expand All @@ -2266,7 +2261,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree)
// this will set both the Z and V flags only when dividendReg is MinInt
//
emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
inst_JMP(jmpNotEqual, sdivLabel); // goto sdiv if the Z flag is clear
inst_JMP(EJ_ne, sdivLabel); // goto sdiv if the Z flag is clear
genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
// ArithmeticException

Expand All @@ -2287,8 +2282,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree)
// divisorOp is not a constant, so it could be zero
//
emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
genJumpToThrowHlpBlk(EJ_eq, SCK_DIV_BY_ZERO);
}
genCodeForBinary(tree);
}
Expand Down Expand Up @@ -2998,8 +2992,7 @@ void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)

BasicBlock* skipLabel = genCreateTempLabel();

emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, skipLabel);
inst_JMP(EJ_eq, skipLabel);
// emit the call to the EE-helper that stops for GC (or other reasons)

genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN);
Expand Down Expand Up @@ -3175,63 +3168,6 @@ void CodeGen::genCodeForSwap(GenTreeOp* tree)
gcInfo.gcMarkRegPtrVal(oldOp1Reg, type2);
}

//-------------------------------------------------------------------------------------------
// genSetRegToCond: Set a register 'dstReg' to the appropriate one or zero value
// corresponding to a binary Relational operator result.
//
// Arguments:
// dstReg - The target register to set to 1 or 0
// tree - The GenTree Relop node that was used to set the Condition codes
//
// Return Value: none
//
// Notes:
// A full 64-bit value of either 1 or 0 is setup in the 'dstReg'
//-------------------------------------------------------------------------------------------

void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
{
emitJumpKind jumpKind[2];
bool branchToTrueLabel[2];
genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);
assert(jumpKind[0] != EJ_NONE);

// Set the reg according to the flags
inst_SET(jumpKind[0], dstReg);

// Do we need to use two operation to set the flags?
//
if (jumpKind[1] != EJ_NONE)
{
emitter* emit = getEmitter();
bool ordered = ((tree->gtFlags & GTF_RELOP_NAN_UN) == 0);
insCond secondCond;

// The only ones that require two operations are the
// floating point compare operations of BEQ or BNE.UN
//
if (tree->gtOper == GT_EQ)
{
// This must be an ordered comparison.
assert(ordered);
assert(jumpKind[1] == EJ_vs); // We complement this value
secondCond = INS_COND_VC; // for the secondCond
}
else // gtOper == GT_NE
{
// This must be BNE.UN (unordered comparison)
assert((tree->gtOper == GT_NE) && !ordered);
assert(jumpKind[1] == EJ_lo); // We complement this value
secondCond = INS_COND_HS; // for the secondCond
}

// The second instruction is a 'csinc' instruction that either selects the previous dstReg
// or increments the ZR register, which produces a 1 result.

emit->emitIns_R_R_R_COND(INS_csinc, EA_8BYTE, dstReg, dstReg, REG_ZR, secondCond);
}
}

//------------------------------------------------------------------------
// genIntToFloatCast: Generate code to cast an int/long to float/double
//
Expand Down Expand Up @@ -3424,8 +3360,7 @@ void CodeGen::genCkfinite(GenTree* treeNode)
emit->emitIns_R_I(INS_cmp, EA_4BYTE, intReg, expMask);

// If exponent is all 1's, throw ArithmeticException
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
genJumpToThrowHlpBlk(jmpEqual, SCK_ARITH_EXCPN);
genJumpToThrowHlpBlk(EJ_eq, SCK_ARITH_EXCPN);

// if it is a finite value copy it to targetReg
if (treeNode->gtRegNum != fpReg)
Expand Down Expand Up @@ -3499,7 +3434,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
// Are we evaluating this into a register?
if (targetReg != REG_NA)
{
genSetRegToCond(targetReg, tree);
inst_SETCC(GenCondition::FromRelop(tree), tree->TypeGet(), targetReg);
genProduceReg(tree);
}
}
Expand Down Expand Up @@ -5192,8 +5127,7 @@ void CodeGen::genHWIntrinsicSwitchTable(regNumber swReg,
// Detect and throw out of range exception
getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, swReg, swMax);

emitJumpKind jmpGEU = genJumpKindForOper(GT_GE, CK_UNSIGNED);
genJumpToThrowHlpBlk(jmpGEU, SCK_ARG_RNG_EXCPN);
genJumpToThrowHlpBlk(EJ_hs, SCK_ARG_RNG_EXCPN);

// Calculate switch target
labelFirst->bbFlags |= BBF_JMP_TARGET;
Expand Down
Loading

0 comments on commit 459b58a

Please sign in to comment.