Skip to content

Commit

Permalink
Introduce GenCondition
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedn committed Oct 5, 2017
1 parent 076a61e commit 049992a
Show file tree
Hide file tree
Showing 7 changed files with 455 additions and 45 deletions.
2 changes: 2 additions & 0 deletions src/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void instGen(instruction ins);
#ifdef _TARGET_XARCH_
void instNop(unsigned size);
void instJcc(instruction ins, BasicBlock* target);
void instSetcc(instruction ins, regNumber reg);
#endif

void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
Expand Down
74 changes: 64 additions & 10 deletions src/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3334,20 +3334,74 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
}
}

struct GenConditionDesc
{
instruction ins[2];
};

static const GenConditionDesc& GetConditionDesc(GenCondition condition)
{
// clang-format off
static constexpr GenConditionDesc map[32]
{
{ { INS_beq, INS_invalid } }, // EQ
{ { INS_bne, INS_invalid } }, // NE
{ { INS_blt, INS_invalid } }, // SLT
{ { INS_ble, INS_invalid } }, // SLE
{ { INS_bge, INS_invalid } }, // SGE
{ { INS_bgt, INS_invalid } }, // SGT
{ { INS_bmi, INS_invalid } }, // S
{ { INS_bpl, INS_invalid } }, // NS

{ { INS_beq, INS_invalid } }, // EQ
{ { INS_bne, INS_invalid } }, // NE
{ { INS_blo, INS_invalid } }, // ULT
{ { INS_bls, INS_invalid } }, // ULE
{ { INS_bhs, INS_invalid } }, // UGE
{ { INS_bhi, INS_invalid } }, // UGT
{ { INS_bhs, INS_invalid } }, // C
{ { INS_blo, INS_invalid } }, // NC

{ { INS_beq, INS_invalid } }, // FEQ
{ { INS_bgt, INS_blo } }, // FNE
{ { INS_blo, INS_invalid } }, // FLT
{ { INS_bls, INS_invalid } }, // FLE
{ { INS_blo, INS_invalid } }, // FGE
{ { INS_bls, INS_invalid } }, // FGT
{ { INS_bvs, INS_invalid } }, // O
{ { INS_bvc, INS_invalid } }, // NO

{ { INS_beq, INS_bvs } }, // FEQU
{ { INS_bne, INS_invalid } }, // FNEU
{ { INS_blt, INS_invalid } }, // FLTU
{ { INS_ble, INS_invalid } }, // FLEU
{ { INS_bhs, INS_invalid } }, // FGEU
{ { INS_bhi, INS_invalid } }, // FGTU
{ }, // P
{ }, // NP
};
// clang-format on

assert(condition.Value() < COUNTOF(map));
const GenConditionDesc& desc = map[condition.Value()];
assert(desc.ins[0] != INS_invalid);
return desc;
}

//------------------------------------------------------------------------
// genCodeForJcc: Produce code for a GT_JCC node.
//
// Arguments:
// tree - the node
//
void CodeGen::genCodeForJcc(GenTreeCC* tree)
void CodeGen::genCodeForJcc(GenTreeCC* jcc)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);

CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
emitJumpKind jumpKind = genJumpKindForOper(tree->gtCondition, compareKind);
const GenConditionDesc& desc = GetConditionDesc(jcc->gtCondition);

inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
getEmitter()->emitIns_J(desc.ins[0], compiler->compCurBB->bbJumpDest);
assert(desc.ins[1] == INS_invalid);
}

//------------------------------------------------------------------------
Expand All @@ -3365,16 +3419,15 @@ void CodeGen::genCodeForJcc(GenTreeCC* tree)

void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
{
regNumber dstReg = setcc->gtRegNum;
CompareKind compareKind = setcc->IsUnsigned() ? CK_UNSIGNED : CK_SIGNED;
emitJumpKind jumpKind = genJumpKindForOper(setcc->gtCondition, compareKind);
regNumber dstReg = setcc->gtRegNum;
const GenConditionDesc& desc = GetConditionDesc(setcc->gtCondition);

assert(genIsValidIntReg(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);

#ifdef _TARGET_ARM64_
inst_SET(jumpKind, dstReg);
getEmitter()->emitIns_R_COND(INS_cset, EA_8BYTE, dstReg, static_cast<insCond>(desc.ins[0] - INS_beq));
assert(desc.ins[1] == INS_invalid);
#else
// Emit code like that:
// ...
Expand All @@ -3387,7 +3440,8 @@ void CodeGen::genCodeForSetcc(GenTreeCC* setcc)
// ...

BasicBlock* labelTrue = genCreateTempLabel();
getEmitter()->emitIns_J(emitter::emitJumpKindToIns(jumpKind), labelTrue);
getEmitter()->emitIns_J(desc.ins[0], labelTrue);
assert(desc.ins[1] == INS_invalid);

getEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(setcc->TypeGet()), dstReg, 0);

Expand Down
173 changes: 154 additions & 19 deletions src/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1558,20 +1558,153 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
}
}

struct GenConditionDesc
{
instruction ins[2];
bool jmpToTrueLabel[2];
};

static const GenConditionDesc& GetConditionDesc(GenCondition condition)
{
// clang-format off
static const GenConditionDesc map[32]
{
{ { INS_je, INS_invalid }, { true, true } }, // EQ
{ { INS_jne, INS_invalid }, { true, true } }, // NE
{ { INS_jl, INS_invalid }, { true, true } }, // SLT
{ { INS_jle, INS_invalid }, { true, true } }, // SLE
{ { INS_jge, INS_invalid }, { true, true } }, // SGE
{ { INS_jg, INS_invalid }, { true, true } }, // SGT
{ { INS_js, INS_invalid }, { true, true } }, // S
{ { INS_jns, INS_invalid }, { true, true } }, // NS

{ { INS_je, INS_invalid }, { true, true } }, // EQ
{ { INS_jne, INS_invalid }, { true, true } }, // NE
{ { INS_jb, INS_invalid }, { true, true } }, // ULT
{ { INS_jbe, INS_invalid }, { true, true } }, // ULE
{ { INS_jae, INS_invalid }, { true, true } }, // UGE
{ { INS_ja, INS_invalid }, { true, true } }, // UGT
{ { INS_jb, INS_invalid }, { true, true } }, // C
{ { INS_jae, INS_invalid }, { true, true } }, // NC

{ { INS_jpe, INS_je }, { false, true } }, // FEQ
{ { INS_jne, INS_invalid }, { true, true } }, // FNE
{ }, // FLT
{ }, // FLE
{ { INS_jae, INS_invalid }, { true, true } }, // FGE
{ { INS_ja, INS_invalid }, { true, true } }, // FGT
{ { INS_jo, INS_invalid }, { true, true } }, // O
{ { INS_jno, INS_invalid }, { true, true } }, // NO

{ { INS_je, INS_invalid }, { true, true } }, // FEQU
{ { INS_jpe, INS_jne }, { true, true } }, // FNEU
{ { INS_jb, INS_invalid }, { true, true } }, // FLTU
{ { INS_jbe, INS_invalid }, { true, true } }, // FLEU
{ }, // FGEU
{ }, // FGTU
{ { INS_jpe, INS_invalid }, { true, true } }, // P
{ { INS_jpo, INS_invalid }, { true, true } }, // NP
};
// clang-format on

assert(condition.Value() < COUNTOF(map));
const GenConditionDesc& desc = map[condition.Value()];
assert(desc.ins[0] != INS_invalid);
return desc;
}

static instruction ReverseJcc(instruction jcc)
{
static const instruction reverse[]{
INS_jno, // INS_jo
INS_jo, // INS_jno
INS_jae, // INS_jb
INS_jb, // INS_jae
INS_jne, // INS_je
INS_je, // INS_jne
INS_ja, // INS_jbe
INS_jbe, // INS_ja
INS_jns, // INS_js
INS_js, // INS_jns
INS_jpo, // INS_jpe
INS_jpe, // INS_jpo
INS_jge, // INS_jl
INS_jl, // INS_jge
INS_jg, // INS_jle
INS_jle // INS_jg
};

assert((INS_jo <= jcc) && (jcc <= INS_jg));
return reverse[jcc - INS_jo];
}

void CodeGen::instJcc(instruction jcc, BasicBlock* target)
{
assert((INS_jo <= jcc) && (jcc <= INS_jg));

#if !FEATURE_FIXED_OUT_ARGS
// On the x86 we are pushing (and changing the stack level), but on x64 and other archs we have
// a fixed outgoing args area that we store into and we never change the stack level when calling methods.
//
// Thus only on x86 do we need to assert that the stack level at the target block matches the current stack level.
//
CLANG_FORMAT_COMMENT_ANCHOR;

#ifdef UNIX_X86_ABI
// bbTgtStkDepth is a (pure) argument count (stack alignment padding should be excluded).
assert((target->bbTgtStkDepth * sizeof(int) == (genStackLevel - curNestedAlignment)) || isFramePointerUsed());
#else
assert((target->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed());
#endif
#endif // !FEATURE_FIXED_OUT_ARGS

getEmitter()->emitIns_J(jcc, target);
}

void CodeGen::instSetcc(instruction jcc, regNumber reg)
{
assert((INS_jo <= jcc) && (jcc <= INS_jg));
assert(genIsValidIntReg(reg));
assert(isByteReg(reg));

getEmitter()->emitIns_R(static_cast<instruction>((jcc - INS_jo) + INS_seto), EA_1BYTE, reg);
}

//------------------------------------------------------------------------
// genCodeForJcc: Produce code for a GT_JCC node.
//
// Arguments:
// tree - the node
// jcc - the JCC node
//
void CodeGen::genCodeForJcc(GenTreeCC* tree)
void CodeGen::genCodeForJcc(GenTreeCC* jcc)
{
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);

CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
emitJumpKind jumpKind = genJumpKindForOper(tree->gtCondition, compareKind);
const GenConditionDesc& desc = GetConditionDesc(jcc->gtCondition);

if (desc.ins[1] == INS_invalid)
{
instJcc(desc.ins[0], compiler->compCurBB->bbJumpDest);
}
else
{
BasicBlock* jmpTarget = compiler->compCurBB->bbJumpDest;
BasicBlock* skipLabel = nullptr;

if (!desc.jmpToTrueLabel[0])
{
skipLabel = genCreateTempLabel();
jmpTarget = skipLabel;
}

inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
instJcc(desc.ins[0], jmpTarget);
instJcc(desc.ins[1], compiler->compCurBB->bbJumpDest);

if (skipLabel != nullptr)
{
genDefineTempLabel(skipLabel);
}
}
}

//------------------------------------------------------------------------
Expand All @@ -1580,25 +1713,27 @@ void CodeGen::genCodeForJcc(GenTreeCC* tree)
// 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);
regNumber dstReg = setcc->gtRegNum;

const GenConditionDesc& desc = GetConditionDesc(setcc->gtCondition);

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);
if (desc.ins[1] == INS_invalid)
{
instSetcc(desc.ins[0], dstReg);
}
else
{
instSetcc(desc.jmpToTrueLabel[0] ? desc.ins[0] : ReverseJcc(desc.ins[0]), dstReg);
BasicBlock* skipLabel = genCreateTempLabel();
instJcc(desc.ins[0], skipLabel);
instSetcc(desc.ins[1], dstReg);
genDefineTempLabel(skipLabel);
}

inst_SET(jumpKind, dstReg);
inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), dstReg, dstReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
getEmitter()->emitIns_R_R(INS_movzx, EA_1BYTE, dstReg, dstReg);
genProduceReg(setcc);
}

Expand Down
5 changes: 2 additions & 3 deletions src/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2548,8 +2548,7 @@ GenTreePtr Compiler::gtReverseCond(GenTree* tree)
}
else if (tree->OperIs(GT_JCC, GT_SETCC))
{
GenTreeCC* cc = tree->AsCC();
cc->gtCondition = GenTree::ReverseRelop(cc->gtCondition);
tree->AsCC()->gtCondition.Reverse();
}
else if (tree->OperIs(GT_JCMP))
{
Expand Down Expand Up @@ -10815,7 +10814,7 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)

case GT_JCC:
case GT_SETCC:
printf(" cond=%s", GenTree::OpName(tree->AsCC()->gtCondition));
printf(" cond=%s", tree->AsCC()->gtCondition.Name());
break;
case GT_JCMP:
printf(" cond=%s%s", (tree->gtFlags & GTF_JCMP_TST) ? "TEST_" : "",
Expand Down
Loading

0 comments on commit 049992a

Please sign in to comment.