@@ -4683,32 +4683,49 @@ void CodeGen::genCodeForCCMP(GenTreeCCMP* ccmp)
46834683}
46844684
46854685//------------------------------------------------------------------------
4686- // genCodeForSelect: Produce code for a GT_SELECT node.
4686+ // genCodeForSelect: Produce code for a GT_SELECT/GT_SELECT_INV/GT_SELECT_NEG node.
46874687//
46884688// Arguments:
46894689// tree - the node
46904690//
46914691void CodeGen::genCodeForSelect(GenTreeOp* tree)
46924692{
4693- assert(tree->OperIs(GT_SELECT, GT_SELECTCC));
4694- GenTree* opcond = nullptr;
4695- if (tree->OperIs(GT_SELECT))
4693+ assert(tree->OperIs(GT_SELECT, GT_SELECTCC, GT_SELECT_INC, GT_SELECT_INCCC, GT_SELECT_INV, GT_SELECT_INVCC,
4694+ GT_SELECT_NEG, GT_SELECT_NEGCC));
4695+ GenTree* opcond = nullptr;
4696+ instruction ins = INS_csel;
4697+ GenTree* op1 = tree->gtOp1;
4698+ GenTree* op2 = tree->gtOp2;
4699+
4700+ if (tree->OperIs(GT_SELECT_INV, GT_SELECT_INVCC))
4701+ {
4702+ ins = (op2 == nullptr) ? INS_cinv : INS_csinv;
4703+ }
4704+ else if (tree->OperIs(GT_SELECT_NEG, GT_SELECT_NEGCC))
4705+ {
4706+ ins = (op2 == nullptr) ? INS_cneg : INS_csneg;
4707+ }
4708+ else if (tree->OperIs(GT_SELECT_INC, GT_SELECT_INCCC))
4709+ {
4710+ ins = (op2 == nullptr) ? INS_cinc : INS_csinc;
4711+ }
4712+
4713+ if (tree->OperIs(GT_SELECT, GT_SELECT_INV, GT_SELECT_NEG))
46964714 {
46974715 opcond = tree->AsConditional()->gtCond;
46984716 genConsumeRegs(opcond);
46994717 }
47004718
4701- emitter* emit = GetEmitter();
4702-
4703- GenTree* op1 = tree->gtOp1;
4704- GenTree* op2 = tree->gtOp2;
4705- var_types op1Type = genActualType(op1);
4706- var_types op2Type = genActualType(op2);
4707- emitAttr attr = emitActualTypeSize(tree);
4719+ if (op2 != nullptr)
4720+ {
4721+ var_types op1Type = genActualType(op1);
4722+ var_types op2Type = genActualType(op2);
4723+ assert(genTypeSize(op1Type) == genTypeSize(op2Type));
4724+ }
47084725
47094726 assert(!op1->isUsedFromMemory());
4710- assert(genTypeSize(op1Type) == genTypeSize(op2Type));
47114727
4728+ emitter* emit = GetEmitter();
47124729 GenCondition cond;
47134730
47144731 if (opcond != nullptr)
@@ -4719,92 +4736,62 @@ void CodeGen::genCodeForSelect(GenTreeOp* tree)
47194736 }
47204737 else
47214738 {
4722- assert(tree->OperIs(GT_SELECTCC));
4739+ assert(tree->OperIs(GT_SELECTCC, GT_SELECT_INCCC, GT_SELECT_INVCC, GT_SELECT_NEGCC ));
47234740 cond = tree->AsOpCC()->gtCondition;
47244741 }
47254742
47264743 assert(!op1->isContained() || op1->IsIntegralConst(0));
4727- assert(!op2->isContained() || op2->IsIntegralConst(0));
4744+ assert(op2 == nullptr || !op2->isContained() || op2->IsIntegralConst(0));
47284745
47294746 regNumber targetReg = tree->GetRegNum();
47304747 regNumber srcReg1 = op1->IsIntegralConst(0) ? REG_ZR : genConsumeReg(op1);
4731- regNumber srcReg2 = op2->IsIntegralConst(0) ? REG_ZR : genConsumeReg(op2);
47324748 const GenConditionDesc& prevDesc = GenConditionDesc::Get(cond);
4749+ emitAttr attr = emitActualTypeSize(tree);
4750+ regNumber srcReg2;
47334751
4734- emit->emitIns_R_R_R_COND(INS_csel, attr, targetReg, srcReg1, srcReg2, JumpKindToInsCond(prevDesc.jumpKind1));
4735-
4736- // Some conditions require an additional condition check.
4737- if (prevDesc.oper == GT_OR)
4738- {
4739- emit->emitIns_R_R_R_COND(INS_csel, attr, targetReg, srcReg1, targetReg, JumpKindToInsCond(prevDesc.jumpKind2));
4740- }
4741- else if (prevDesc.oper == GT_AND)
4742- {
4743- emit->emitIns_R_R_R_COND(INS_csel, attr, targetReg, targetReg, srcReg2, JumpKindToInsCond(prevDesc.jumpKind2));
4744- }
4745-
4746- regSet.verifyRegUsed(targetReg);
4747- genProduceReg(tree);
4748- }
4749-
4750- //------------------------------------------------------------------------
4751- // genCodeForCinc: Produce code for a GT_CINC/GT_CINCCC node.
4752- //
4753- // Arguments:
4754- // tree - the node
4755- //
4756- void CodeGen::genCodeForCinc(GenTreeOp* cinc)
4757- {
4758- assert(cinc->OperIs(GT_CINC, GT_CINCCC));
4759-
4760- GenTree* opcond = nullptr;
4761- GenTree* op = cinc->gtOp1;
4762- if (cinc->OperIs(GT_CINC))
4752+ if (op2 == nullptr)
47634753 {
4764- opcond = cinc->gtOp1;
4765- op = cinc->gtOp2;
4766- genConsumeRegs(opcond);
4767- }
4768-
4769- emitter* emit = GetEmitter();
4770- var_types opType = genActualType(op->TypeGet());
4771- emitAttr attr = emitActualTypeSize(cinc->TypeGet());
4772-
4773- assert(!op->isUsedFromMemory());
4774- genConsumeRegs(op);
4775-
4776- GenCondition cond;
4777-
4778- if (cinc->OperIs(GT_CINC))
4779- {
4780- assert(!opcond->isContained());
4781- // Condition has been generated into a register - move it into flags.
4782- emit->emitIns_R_I(INS_cmp, emitActualTypeSize(opcond), opcond->GetRegNum(), 0);
4783- cond = GenCondition::NE;
4754+ srcReg2 = srcReg1;
4755+ emit->emitIns_R_R_COND(ins, attr, targetReg, srcReg1, JumpKindToInsCond(prevDesc.jumpKind1));
47844756 }
47854757 else
47864758 {
4787- assert(cinc->OperIs(GT_CINCCC ));
4788- cond = cinc->AsOpCC()->gtCondition ;
4759+ srcReg2 = (op2->IsIntegralConst(0) ? REG_ZR : genConsumeReg(op2 ));
4760+ emit->emitIns_R_R_R_COND(ins, attr, targetReg, srcReg1, srcReg2, JumpKindToInsCond(prevDesc.jumpKind1)) ;
47894761 }
4790- const GenConditionDesc& prevDesc = GenConditionDesc::Get(cond);
4791- regNumber targetReg = cinc->GetRegNum();
4792- regNumber srcReg;
47934762
4794- if (op->isContained())
4763+ // Some floating point comparision conditions require an additional condition check.
4764+ // These checks are emitted as a subsequent check using GT_AND or GT_OR nodes.
4765+ // e.g., using GT_OR => `dest = (cond1 || cond2) ? src1 : src2`
4766+ // GT_AND => `dest = (cond1 && cond2) ? src1 : src2`
4767+ // The GT_OR case results in emitting the following sequence of two csel instructions.
4768+ // csel dest, src1, src2, cond1 # emitted previously
4769+ // csel dest, src1, dest, cond2
4770+ //
4771+ if (prevDesc.oper == GT_AND)
47954772 {
4796- assert(op->IsIntegralConst(0));
4797- srcReg = REG_ZR;
4773+ // To ensure correctness with invert and negate variants of conditional select, the second instruction needs to
4774+ // be csinv or csneg respectively.
4775+ // dest = (cond1 && cond2) ? src1 : ~src2
4776+ // csinv dest, src1, src2, cond1
4777+ // csinv dest, dest, src2, cond2
4778+ //
4779+ // However, the other variants - increment and select, the second instruction needs to be csel.
4780+ // dest = (cond1 && cond2) ? src1 : src2++
4781+ // csinc dest, src1, src2, cond1
4782+ // csel dest, dest, src1 cond2
4783+ ins = ((ins == INS_csinv) || (ins == INS_csneg)) ? ins : INS_csel;
4784+ emit->emitIns_R_R_R_COND(ins, attr, targetReg, targetReg, srcReg2, JumpKindToInsCond(prevDesc.jumpKind2));
47984785 }
4799- else
4786+ else if (prevDesc.oper == GT_OR)
48004787 {
4801- srcReg = op->GetRegNum();
4788+ // Similarly, the second instruction needs to be csinc while emitting conditional increment.
4789+ ins = (ins == INS_csinc) ? ins : INS_csel;
4790+ emit->emitIns_R_R_R_COND(ins, attr, targetReg, srcReg1, targetReg, JumpKindToInsCond(prevDesc.jumpKind2));
48024791 }
48034792
4804- assert(prevDesc.oper != GT_OR && prevDesc.oper != GT_AND);
4805- emit->emitIns_R_R_COND(INS_cinc, attr, targetReg, srcReg, JumpKindToInsCond(prevDesc.jumpKind1));
48064793 regSet.verifyRegUsed(targetReg);
4807- genProduceReg(cinc );
4794+ genProduceReg(tree );
48084795}
48094796
48104797//------------------------------------------------------------------------
@@ -10365,53 +10352,6 @@ void CodeGen::genCodeForBfiz(GenTreeOp* tree)
1036510352 genProduceReg(tree);
1036610353}
1036710354
10368- //------------------------------------------------------------------------
10369- // genCodeForCond: Generates the code sequence for a GenTree node that
10370- // represents a conditional instruction.
10371- //
10372- // Arguments:
10373- // tree - conditional op
10374- //
10375- void CodeGen::genCodeForCond(GenTreeOp* tree)
10376- {
10377- assert(tree->OperIs(GT_CSNEG_MI, GT_CNEG_LT));
10378- assert(!(tree->gtFlags & GTF_SET_FLAGS));
10379- genConsumeOperands(tree);
10380-
10381- switch (tree->OperGet())
10382- {
10383- case GT_CSNEG_MI:
10384- {
10385- instruction ins = INS_csneg;
10386- insCond cond = INS_COND_MI;
10387-
10388- regNumber dstReg = tree->GetRegNum();
10389- regNumber op1Reg = tree->gtGetOp1()->GetRegNum();
10390- regNumber op2Reg = tree->gtGetOp2()->GetRegNum();
10391-
10392- GetEmitter()->emitIns_R_R_R_COND(ins, emitActualTypeSize(tree), dstReg, op1Reg, op2Reg, cond);
10393- break;
10394- }
10395-
10396- case GT_CNEG_LT:
10397- {
10398- instruction ins = INS_cneg;
10399- insCond cond = INS_COND_LT;
10400-
10401- regNumber dstReg = tree->GetRegNum();
10402- regNumber op1Reg = tree->gtGetOp1()->GetRegNum();
10403-
10404- GetEmitter()->emitIns_R_R_COND(ins, emitActualTypeSize(tree), dstReg, op1Reg, cond);
10405- break;
10406- }
10407-
10408- default:
10409- unreached();
10410- }
10411-
10412- genProduceReg(tree);
10413- }
10414-
1041510355//------------------------------------------------------------------------
1041610356// JumpKindToInsCond: Convert a Jump Kind to a condition.
1041710357//
0 commit comments