Skip to content

Commit 459b58a

Browse files
authored
Merge pull request dotnet#17733 from mikedn/cc-cond2
Expand GT_JCC/SETCC condition support
2 parents a2e3393 + 12cfc7f commit 459b58a

16 files changed

+562
-935
lines changed

src/jit/codegen.h

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,23 +92,6 @@ class CodeGen : public CodeGenInterface
9292
}
9393
}
9494

95-
enum CompareKind
96-
{
97-
CK_SIGNED,
98-
CK_UNSIGNED,
99-
CK_LOGICAL
100-
};
101-
static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind);
102-
103-
// For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array.
104-
// The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the
105-
// 'true' label or a 'false' label.
106-
//
107-
// 'true' label corresponds to jump target of the current basic block i.e. the target to
108-
// branch to on compare condition being true. 'false' label corresponds to the target to
109-
// branch to on condition being false.
110-
static void genJumpKindsForTree(GenTree* cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
111-
11295
static bool genShouldRoundFP();
11396

11497
GenTreeIndir indirForm(var_types type, GenTree* base);
@@ -1173,7 +1156,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11731156
void genCallInstruction(GenTreeCall* call);
11741157
void genJmpMethod(GenTree* jmp);
11751158
BasicBlock* genCallFinally(BasicBlock* block);
1176-
void genCodeForJumpTrue(GenTree* tree);
1159+
void genCodeForJumpTrue(GenTreeOp* jtrue);
11771160
#ifdef _TARGET_ARM64_
11781161
void genCodeForJumpCompare(GenTreeOp* tree);
11791162
#endif // _TARGET_ARM64_
@@ -1393,6 +1376,50 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13931376
#ifdef _TARGET_XARCH_
13941377
instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
13951378
#endif // _TARGET_XARCH_
1379+
1380+
// Maps a GenCondition code to a sequence of conditional jumps or other conditional instructions
1381+
// such as X86's SETcc. A sequence of instructions rather than just a single one is required for
1382+
// certain floating point conditions.
1383+
// For example, X86's UCOMISS sets ZF to indicate equality but it also sets it, together with PF,
1384+
// to indicate an unordered result. So for GenCondition::FEQ we first need to check if PF is 0
1385+
// and then jump if ZF is 1:
1386+
// JP fallThroughBlock
1387+
// JE jumpDestBlock
1388+
// fallThroughBlock:
1389+
// ...
1390+
// jumpDestBlock:
1391+
//
1392+
// This is very similar to the way shortcircuit evaluation of bool AND and OR operators works so
1393+
// in order to make the GenConditionDesc mapping tables easier to read, a bool expression-like
1394+
// pattern is used to encode the above:
1395+
// { EJ_jnp, GT_AND, EJ_je }
1396+
// { EJ_jp, GT_OR, EJ_jne }
1397+
//
1398+
// For more details check inst_JCC and inst_SETCC functions.
1399+
//
1400+
struct GenConditionDesc
1401+
{
1402+
emitJumpKind jumpKind1;
1403+
genTreeOps oper;
1404+
emitJumpKind jumpKind2;
1405+
char padTo4Bytes;
1406+
1407+
static const GenConditionDesc& Get(GenCondition condition)
1408+
{
1409+
assert(condition.GetCode() < _countof(map));
1410+
const GenConditionDesc& desc = map[condition.GetCode()];
1411+
assert(desc.jumpKind1 != EJ_NONE);
1412+
assert((desc.oper == GT_NONE) || (desc.oper == GT_AND) || (desc.oper == GT_OR));
1413+
assert((desc.oper == GT_NONE) == (desc.jumpKind2 == EJ_NONE));
1414+
return desc;
1415+
}
1416+
1417+
private:
1418+
static const GenConditionDesc map[32];
1419+
};
1420+
1421+
void inst_JCC(GenCondition condition, BasicBlock* target);
1422+
void inst_SETCC(GenCondition condition, var_types type, regNumber dstReg);
13961423
};
13971424

13981425
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

src/jit/codegenarm.cpp

Lines changed: 10 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,7 @@ void CodeGen::genLclHeap(GenTree* tree)
301301
genConsumeRegAndCopy(size, regCnt);
302302
endLabel = genCreateTempLabel();
303303
getEmitter()->emitIns_R_R(INS_TEST, easz, regCnt, regCnt);
304-
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
305-
inst_JMP(jmpEqual, endLabel);
304+
inst_JMP(EJ_eq, endLabel);
306305
}
307306

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

444442
getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
445-
emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
446-
inst_JMP(jmpLTU, done);
443+
inst_JMP(EJ_lo, done);
447444

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

11641161
BasicBlock* skipLabel = genCreateTempLabel();
11651162

1166-
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1167-
inst_JMP(jmpEqual, skipLabel);
1163+
inst_JMP(EJ_eq, skipLabel);
11681164

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

@@ -1237,54 +1233,6 @@ void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
12371233
}
12381234
}
12391235

1240-
//------------------------------------------------------------------------
1241-
// genSetRegToCond: Generate code to materialize a condition into a register.
1242-
//
1243-
// Arguments:
1244-
// dstReg - The target register to set to 1 or 0
1245-
// tree - The GenTree Relop node that was used to set the Condition codes
1246-
//
1247-
// Return Value: none
1248-
//
1249-
// Preconditions:
1250-
// The condition codes must already have been appropriately set.
1251-
//
1252-
void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
1253-
{
1254-
// Emit code like that:
1255-
// ...
1256-
// beq True
1257-
// bvs True ; this second branch is typically absent
1258-
// movs rD, #0
1259-
// b Next
1260-
// True:
1261-
// movs rD, #1
1262-
// Next:
1263-
// ...
1264-
1265-
emitJumpKind jumpKind[2];
1266-
bool branchToTrueLabel[2];
1267-
genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);
1268-
1269-
BasicBlock* labelTrue = genCreateTempLabel();
1270-
getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[0]), labelTrue);
1271-
1272-
if (jumpKind[1] != EJ_NONE)
1273-
{
1274-
getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind[1]), labelTrue);
1275-
}
1276-
1277-
getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 0);
1278-
1279-
BasicBlock* labelNext = genCreateTempLabel();
1280-
getEmitter()->emitIns_J(INS_b, labelNext);
1281-
1282-
genDefineTempLabel(labelTrue);
1283-
getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(tree->gtType), dstReg, 1);
1284-
genDefineTempLabel(labelNext);
1285-
}
1286-
1287-
//------------------------------------------------------------------------
12881236
// genLongToIntCast: Generate code for long to int casts.
12891237
//
12901238
// Arguments:
@@ -1336,17 +1284,14 @@ void CodeGen::genLongToIntCast(GenTree* cast)
13361284
BasicBlock* success = genCreateTempLabel();
13371285

13381286
inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1339-
emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1340-
inst_JMP(JmpNegative, allOne);
1287+
inst_JMP(EJ_mi, allOne);
13411288
inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1342-
emitJumpKind jmpNotEqualL = genJumpKindForOper(GT_NE, CK_LOGICAL);
1343-
genJumpToThrowHlpBlk(jmpNotEqualL, SCK_OVERFLOW);
1289+
genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW);
13441290
inst_JMP(EJ_jmp, success);
13451291

13461292
genDefineTempLabel(allOne);
13471293
inst_RV_IV(INS_cmp, hiSrcReg, -1, EA_4BYTE);
1348-
emitJumpKind jmpNotEqualS = genJumpKindForOper(GT_NE, CK_SIGNED);
1349-
genJumpToThrowHlpBlk(jmpNotEqualS, SCK_OVERFLOW);
1294+
genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW);
13501295

13511296
genDefineTempLabel(success);
13521297
}
@@ -1355,13 +1300,11 @@ void CodeGen::genLongToIntCast(GenTree* cast)
13551300
if ((srcType == TYP_ULONG) && (dstType == TYP_INT))
13561301
{
13571302
inst_RV_RV(INS_tst, loSrcReg, loSrcReg, TYP_INT, EA_4BYTE);
1358-
emitJumpKind JmpNegative = genJumpKindForOper(GT_LT, CK_LOGICAL);
1359-
genJumpToThrowHlpBlk(JmpNegative, SCK_OVERFLOW);
1303+
genJumpToThrowHlpBlk(EJ_mi, SCK_OVERFLOW);
13601304
}
13611305

13621306
inst_RV_RV(INS_tst, hiSrcReg, hiSrcReg, TYP_INT, EA_4BYTE);
1363-
emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_LOGICAL);
1364-
genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
1307+
genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW);
13651308
}
13661309
}
13671310

src/jit/codegenarm64.cpp

Lines changed: 11 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,8 +1919,7 @@ void CodeGen::genLclHeap(GenTree* tree)
19191919
genConsumeRegAndCopy(size, targetReg);
19201920
endLabel = genCreateTempLabel();
19211921
getEmitter()->emitIns_R_R(INS_tst, easz, targetReg, targetReg);
1922-
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
1923-
inst_JMP(jmpEqual, endLabel);
1922+
inst_JMP(EJ_eq, endLabel);
19241923

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

21012099
getEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, regTmp, regCnt);
2102-
emitJumpKind jmpLTU = genJumpKindForOper(GT_LT, CK_UNSIGNED);
2103-
inst_JMP(jmpLTU, done);
2100+
inst_JMP(EJ_lo, done);
21042101

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

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

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

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

@@ -2287,8 +2282,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree)
22872282
// divisorOp is not a constant, so it could be zero
22882283
//
22892284
emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
2290-
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
2291-
genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
2285+
genJumpToThrowHlpBlk(EJ_eq, SCK_DIV_BY_ZERO);
22922286
}
22932287
genCodeForBinary(tree);
22942288
}
@@ -2998,8 +2992,7 @@ void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
29982992

29992993
BasicBlock* skipLabel = genCreateTempLabel();
30002994

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

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

3178-
//-------------------------------------------------------------------------------------------
3179-
// genSetRegToCond: Set a register 'dstReg' to the appropriate one or zero value
3180-
// corresponding to a binary Relational operator result.
3181-
//
3182-
// Arguments:
3183-
// dstReg - The target register to set to 1 or 0
3184-
// tree - The GenTree Relop node that was used to set the Condition codes
3185-
//
3186-
// Return Value: none
3187-
//
3188-
// Notes:
3189-
// A full 64-bit value of either 1 or 0 is setup in the 'dstReg'
3190-
//-------------------------------------------------------------------------------------------
3191-
3192-
void CodeGen::genSetRegToCond(regNumber dstReg, GenTree* tree)
3193-
{
3194-
emitJumpKind jumpKind[2];
3195-
bool branchToTrueLabel[2];
3196-
genJumpKindsForTree(tree, jumpKind, branchToTrueLabel);
3197-
assert(jumpKind[0] != EJ_NONE);
3198-
3199-
// Set the reg according to the flags
3200-
inst_SET(jumpKind[0], dstReg);
3201-
3202-
// Do we need to use two operation to set the flags?
3203-
//
3204-
if (jumpKind[1] != EJ_NONE)
3205-
{
3206-
emitter* emit = getEmitter();
3207-
bool ordered = ((tree->gtFlags & GTF_RELOP_NAN_UN) == 0);
3208-
insCond secondCond;
3209-
3210-
// The only ones that require two operations are the
3211-
// floating point compare operations of BEQ or BNE.UN
3212-
//
3213-
if (tree->gtOper == GT_EQ)
3214-
{
3215-
// This must be an ordered comparison.
3216-
assert(ordered);
3217-
assert(jumpKind[1] == EJ_vs); // We complement this value
3218-
secondCond = INS_COND_VC; // for the secondCond
3219-
}
3220-
else // gtOper == GT_NE
3221-
{
3222-
// This must be BNE.UN (unordered comparison)
3223-
assert((tree->gtOper == GT_NE) && !ordered);
3224-
assert(jumpKind[1] == EJ_lo); // We complement this value
3225-
secondCond = INS_COND_HS; // for the secondCond
3226-
}
3227-
3228-
// The second instruction is a 'csinc' instruction that either selects the previous dstReg
3229-
// or increments the ZR register, which produces a 1 result.
3230-
3231-
emit->emitIns_R_R_R_COND(INS_csinc, EA_8BYTE, dstReg, dstReg, REG_ZR, secondCond);
3232-
}
3233-
}
3234-
32353171
//------------------------------------------------------------------------
32363172
// genIntToFloatCast: Generate code to cast an int/long to float/double
32373173
//
@@ -3424,8 +3360,7 @@ void CodeGen::genCkfinite(GenTree* treeNode)
34243360
emit->emitIns_R_I(INS_cmp, EA_4BYTE, intReg, expMask);
34253361

34263362
// If exponent is all 1's, throw ArithmeticException
3427-
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
3428-
genJumpToThrowHlpBlk(jmpEqual, SCK_ARITH_EXCPN);
3363+
genJumpToThrowHlpBlk(EJ_eq, SCK_ARITH_EXCPN);
34293364

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

5195-
emitJumpKind jmpGEU = genJumpKindForOper(GT_GE, CK_UNSIGNED);
5196-
genJumpToThrowHlpBlk(jmpGEU, SCK_ARG_RNG_EXCPN);
5130+
genJumpToThrowHlpBlk(EJ_hs, SCK_ARG_RNG_EXCPN);
51975131

51985132
// Calculate switch target
51995133
labelFirst->bbFlags |= BBF_JMP_TARGET;

0 commit comments

Comments
 (0)