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

Commit cb2ab8a

Browse files
committed
Address some CR feedback
1 parent 4b5b426 commit cb2ab8a

File tree

2 files changed

+69
-31
lines changed

2 files changed

+69
-31
lines changed

src/jit/codegenxarch.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,21 @@ static const GenConditionDesc& GetConditionDesc(GenCondition condition)
16021602
return desc;
16031603
}
16041604

1605+
inline instruction ins_CMOV(emitJumpKind kind)
1606+
{
1607+
assert((kind >= EJ_jo) && (kind <= EJ_jg));
1608+
1609+
// Spot check some EJ_/INS_ values to make sure they're ordered correctly.
1610+
static_assert_no_msg((EJ_jo - EJ_jo) + INS_cmovo == INS_cmovo);
1611+
static_assert_no_msg((EJ_jae - EJ_jo) + INS_cmovo == INS_cmovae);
1612+
static_assert_no_msg((EJ_jl - EJ_jo) + INS_cmovo == INS_cmovl);
1613+
static_assert_no_msg((EJ_jg - EJ_jo) + INS_cmovo == INS_cmovg);
1614+
1615+
instruction ins = static_cast<instruction>((kind - EJ_jo) + INS_cmovo);
1616+
assert(insIsCMOV(ins));
1617+
return ins;
1618+
}
1619+
16051620
//------------------------------------------------------------------------
16061621
// genCodeForJcc: Produce code for a GT_JCC node.
16071622
//
@@ -1712,23 +1727,16 @@ void CodeGen::genCodeForSelCC(GenTreeOpCC* selcc)
17121727
if (compiler->opts.compUseCMOV)
17131728
{
17141729
const GenConditionDesc& desc = GetConditionDesc(selcc->gtCondition);
1715-
assert(desc.ins[1] == EJ_NONE);
1716-
1717-
constexpr instruction EJtoCMOV[]{INS_nop, INS_nop, INS_cmovo, INS_cmovno, INS_cmovb, INS_cmovae,
1718-
INS_cmove, INS_cmovne, INS_cmovbe, INS_cmova, INS_cmovs, INS_cmovns,
1719-
INS_cmovpe, INS_cmovpo, INS_cmovl, INS_cmovge, INS_cmovle, INS_cmovg};
1720-
noway_assert((unsigned)desc.ins[0] < _countof(EJtoCMOV));
1721-
instruction ins = EJtoCMOV[desc.ins[0]];
1722-
noway_assert(insIsCMOV(ins));
1730+
assert(desc.ins[1] == EJ_NONE); // Floating point conditions are not yet supported
17231731

1724-
getEmitter()->emitInsBinary(ins, emitTypeSize(dstType), op1, op2);
1732+
getEmitter()->emitInsBinary(ins_CMOV(desc.ins[0]), emitTypeSize(dstType), op1, op2);
17251733
}
17261734
else
17271735
{
17281736
GenCondition condition = selcc->gtCondition;
17291737
condition.Reverse();
17301738
const GenConditionDesc& desc = GetConditionDesc(condition);
1731-
assert(desc.ins[1] == EJ_NONE);
1739+
assert(desc.ins[1] == EJ_NONE); // Floating point conditions are not yet supported
17321740

17331741
BasicBlock* label = genCreateTempLabel();
17341742
inst_JMP(desc.ins[0], label);

src/jit/lower.cpp

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,36 +3126,49 @@ class IfConversion
31263126
m_falseBlock = m_block->bbNext;
31273127
m_trueBlock = m_block->bbJumpDest;
31283128

3129-
BasicBlock* joinBlock = SingleSuccessorBlock(m_falseBlock);
3129+
assert(m_falseBlock != m_block); // m_block can't fall through to itself
31303130

3131-
if (joinBlock == m_block->bbJumpDest)
3131+
if (m_trueBlock == m_falseBlock)
31323132
{
3133-
if (LastInstruction(m_falseBlock) == nullptr)
3133+
// Reject degenerate full hammocks, fg optimizations should have taken care of this.
3134+
// They may end up passing as genuine full hammocks and cause various problems
3135+
// (e.g. decrement the ref count of a lclvar twice).
3136+
return HammockKind::None;
3137+
}
3138+
3139+
if (((m_trueBlock->bbFlags & BBF_RUN_RARELY) == 0) && ((m_block->bbFlags & BBF_RUN_RARELY) != 0))
3140+
{
3141+
// fall through from not-run-rarerly to run-rarely
3142+
return HammockKind::None;
3143+
}
3144+
3145+
if (m_trueBlock == m_block)
3146+
{
3147+
// Reject some back edges. A half hammock may be formed if "falseBlock" jumps back to
3148+
// "block" but that would be an infinite loop and it's not exactly common (and likely
3149+
// there's no test coverage for).
3150+
return HammockKind::None;
3151+
}
3152+
3153+
m_joinBlock = SingleSuccessorBlock(m_falseBlock);
3154+
3155+
if (m_joinBlock == m_trueBlock)
3156+
{
3157+
if (m_comp->fgInDifferentRegions(m_block, m_falseBlock))
31343158
{
3135-
// The block is empty, fg optimizations should have taken care of this.
31363159
return HammockKind::None;
31373160
}
31383161

3139-
if (m_comp->fgInDifferentRegions(m_block, m_falseBlock) || !BasicBlock::sameEHRegion(m_block, m_falseBlock))
3162+
if (!BasicBlock::sameEHRegion(m_block, m_falseBlock))
31403163
{
31413164
return HammockKind::None;
31423165
}
31433166

31443167
// We have something like "if (cond) { falseBlock: ... } joinBlock: ..."
3145-
3146-
m_joinBlock = joinBlock;
31473168
return HammockKind::Half;
31483169
}
31493170
else
31503171
{
3151-
if ((LastInstruction(m_falseBlock) == nullptr) || (LastInstruction(m_trueBlock) == nullptr))
3152-
{
3153-
// Either or both blocks are empty, fg optimizations should have taken care of this.
3154-
// If only one block is empty we actually have a half hammock but to keep things
3155-
// simple this special case is not handled.
3156-
return HammockKind::None;
3157-
}
3158-
31593172
if ((m_falseBlock->bbJumpKind == BBJ_RETURN) && (m_trueBlock->bbJumpKind == BBJ_RETURN))
31603173
{
31613174
#ifdef JIT32_GCENCODER
@@ -3165,14 +3178,26 @@ class IfConversion
31653178
// limit imposed by the x86 GC encoding.
31663179
return HammockKind::None;
31673180
#endif
3168-
m_joinBlock = nullptr;
3181+
// SingleSuccessorBlock should have returned null for a BBJ_RETURN block
3182+
assert(m_joinBlock == nullptr);
31693183
}
3170-
else if ((joinBlock != nullptr) && (joinBlock == SingleSuccessorBlock(m_trueBlock)))
3184+
else if ((m_joinBlock == nullptr) || (m_joinBlock != SingleSuccessorBlock(m_trueBlock)))
31713185
{
3172-
m_joinBlock = joinBlock;
3186+
return HammockKind::None;
31733187
}
3174-
else
3188+
else if (m_joinBlock == m_block)
3189+
{
3190+
// Reject full hammocks where both "false" and "true" blocks jump back to "block".
3191+
// That would be an infinite infinite loop and it's not exactly common (and likely
3192+
// there's no test coverage for).
3193+
return HammockKind::None;
3194+
}
3195+
3196+
if (!m_block->isRunRarely() && m_trueBlock->isRunRarely())
31753197
{
3198+
// If we're jumping from a normal block to a rarely run block then it means we have
3199+
// a rarely taken branch and it's likely not beneficial to convert it.
3200+
// TODO What about fall through?
31763201
return HammockKind::None;
31773202
}
31783203

@@ -3188,7 +3213,6 @@ class IfConversion
31883213
}
31893214

31903215
// We have something like "if (cond) { falseBlock: ... } else { trueBlock: ... } joinBlock: ..."
3191-
31923216
return HammockKind::Full;
31933217
}
31943218
}
@@ -3221,12 +3245,18 @@ class IfConversion
32213245

32223246
GenTree* op = LastInstruction(m_block);
32233247

3248+
if (op == nullptr)
3249+
{
3250+
// The block is empty, fg optimizations should have taken care of this.
3251+
return false;
3252+
}
3253+
32243254
if ((kind == HammockKind::Half) && op->OperIs(GT_RETURN))
32253255
{
32263256
return false;
32273257
}
32283258

3229-
if ((op == nullptr) || !op->OperIs(GT_STORE_LCL_VAR, GT_RETURN))
3259+
if (!op->OperIs(GT_STORE_LCL_VAR, GT_RETURN))
32303260
{
32313261
// TODO Indirs would also work provided that both blocks store to the same address.
32323262
// How to detect that?

0 commit comments

Comments
 (0)