From: Bruce Forstall Date: Tue, 2 May 2017 01:35:27 +0000 (-0700) Subject: Refactor compares X-Git-Tag: submit/tizen/20210909.063632~11030^2~7048^2~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=95e818e0979a1a3a3f50b59aa17ec9092a912761;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Refactor compares Commit migrated from https://github.com/dotnet/coreclr/commit/3bb29c3765f23911c3fefc072a11b3bc45a9fd77 --- diff --git a/src/coreclr/src/jit/codegenarm.cpp b/src/coreclr/src/jit/codegenarm.cpp index ea88429..1eaf9ff 100644 --- a/src/coreclr/src/jit/codegenarm.cpp +++ b/src/coreclr/src/jit/codegenarm.cpp @@ -558,76 +558,8 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) case GT_LE: case GT_GE: case GT_GT: - { - // TODO-ARM-CQ: Check if we can use the currently set flags. - // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register - // (signed < or >= where targetReg != REG_NA) - - GenTreeOp* tree = treeNode->AsOp(); - GenTreePtr op1 = tree->gtOp1->gtEffectiveVal(); - GenTreePtr op2 = tree->gtOp2->gtEffectiveVal(); - - genConsumeIfReg(op1); - genConsumeIfReg(op2); - - instruction ins = INS_cmp; - emitAttr cmpAttr; - if (varTypeIsFloating(op1)) - { - assert(op1->TypeGet() == op2->TypeGet()); - ins = INS_vcmp; - cmpAttr = emitTypeSize(op1->TypeGet()); - emit->emitInsBinary(ins, cmpAttr, op1, op2); - // vmrs with register 0xf has special meaning of transferring flags - emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15); - } - else if (varTypeIsLong(op1)) - { -#ifdef DEBUG - // The result of an unlowered long compare on a 32-bit target must either be - // a) materialized into a register, or - // b) unused. - // - // A long compare that has a result that is used but not materialized into a register should - // have been handled by Lowering::LowerCompare. - - LIR::Use use; - assert((treeNode->gtRegNum != REG_NA) || !LIR::AsRange(compiler->compCurBB).TryGetUse(treeNode, &use)); -#endif - genCompareLong(treeNode); - break; - } - else - { - var_types op1Type = op1->TypeGet(); - var_types op2Type = op2->TypeGet(); - assert(!varTypeIsFloating(op2Type)); - ins = INS_cmp; - if (op1Type == op2Type) - { - cmpAttr = emitTypeSize(op1Type); - } - else - { - var_types cmpType = TYP_INT; - bool op1Is64Bit = (varTypeIsLong(op1Type) || op1Type == TYP_REF); - bool op2Is64Bit = (varTypeIsLong(op2Type) || op2Type == TYP_REF); - NYI_IF(op1Is64Bit || op2Is64Bit, "Long compare"); - assert(!op1->isUsedFromMemory() || op1Type == op2Type); - assert(!op2->isUsedFromMemory() || op1Type == op2Type); - cmpAttr = emitTypeSize(cmpType); - } - emit->emitInsBinary(ins, cmpAttr, op1, op2); - } - - // Are we evaluating this into a register? - if (targetReg != REG_NA) - { - genSetRegToCond(targetReg, tree); - genProduceReg(tree); - } - } - break; + genCodeForCompare(treeNode->AsOp()); + break; case GT_JTRUE: genCodeForJumpTrue(treeNode); @@ -1546,6 +1478,86 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) } //------------------------------------------------------------------------ +// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node. +// +// Arguments: +// tree - the node +// +void CodeGen::genCodeForCompare(GenTreeOp* tree) +{ + // TODO-ARM-CQ: Check if we can use the currently set flags. + // TODO-ARM-CQ: Check for the case where we can simply transfer the carry bit to a register + // (signed < or >= where targetReg != REG_NA) + + GenTreePtr op1 = tree->gtOp1->gtEffectiveVal(); + GenTreePtr op2 = tree->gtOp2->gtEffectiveVal(); + + if (varTypeIsLong(op1)) + { +#ifdef DEBUG + // The result of an unlowered long compare on a 32-bit target must either be + // a) materialized into a register, or + // b) unused. + // + // A long compare that has a result that is used but not materialized into a register should + // have been handled by Lowering::LowerCompare. + + LIR::Use use; + assert((tree->gtRegNum != REG_NA) || !LIR::AsRange(compiler->compCurBB).TryGetUse(tree, &use)); +#endif + genCompareLong(tree); + } + else + { + regNumber targetReg = tree->gtRegNum; + emitter* emit = getEmitter(); + emitAttr cmpAttr; + + genConsumeIfReg(op1); + genConsumeIfReg(op2); + + if (varTypeIsFloating(op1)) + { + assert(op1->TypeGet() == op2->TypeGet()); + instruction ins = INS_vcmp; + cmpAttr = emitTypeSize(op1->TypeGet()); + emit->emitInsBinary(ins, cmpAttr, op1, op2); + // vmrs with register 0xf has special meaning of transferring flags + emit->emitIns_R(INS_vmrs, EA_4BYTE, REG_R15); + } + else + { + var_types op1Type = op1->TypeGet(); + var_types op2Type = op2->TypeGet(); + assert(!varTypeIsFloating(op2Type)); + instruction ins = INS_cmp; + if (op1Type == op2Type) + { + cmpAttr = emitTypeSize(op1Type); + } + else + { + var_types cmpType = TYP_INT; + bool op1Is64Bit = (varTypeIsLong(op1Type) || op1Type == TYP_REF); + bool op2Is64Bit = (varTypeIsLong(op2Type) || op2Type == TYP_REF); + NYI_IF(op1Is64Bit || op2Is64Bit, "Long compare"); + assert(!op1->isUsedFromMemory() || op1Type == op2Type); + assert(!op2->isUsedFromMemory() || op1Type == op2Type); + cmpAttr = emitTypeSize(cmpType); + } + emit->emitInsBinary(ins, cmpAttr, op1, op2); + } + + // Are we evaluating this into a register? + if (targetReg != REG_NA) + { + genSetRegToCond(targetReg, tree); + genProduceReg(tree); + } + } +} + +//------------------------------------------------------------------------ // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node. // // Arguments: diff --git a/src/coreclr/src/jit/codegenarm64.cpp b/src/coreclr/src/jit/codegenarm64.cpp index cf3cae8..6a9619a 100644 --- a/src/coreclr/src/jit/codegenarm64.cpp +++ b/src/coreclr/src/jit/codegenarm64.cpp @@ -2345,95 +2345,8 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) case GT_LE: case GT_GE: case GT_GT: - { - // TODO-ARM64-CQ: Check if we can use the currently set flags. - // TODO-ARM64-CQ: Check for the case where we can simply transfer the carry bit to a register - // (signed < or >= where targetReg != REG_NA) - - GenTreeOp* tree = treeNode->AsOp(); - GenTreePtr op1 = tree->gtOp1; - GenTreePtr op2 = tree->gtOp2; - var_types op1Type = op1->TypeGet(); - var_types op2Type = op2->TypeGet(); - - assert(!op1->isUsedFromMemory()); - assert(!op2->isUsedFromMemory()); - - genConsumeOperands(tree); - - emitAttr cmpSize = EA_UNKNOWN; - - if (varTypeIsFloating(op1Type)) - { - assert(varTypeIsFloating(op2Type)); - assert(!op1->isContained()); - assert(op1Type == op2Type); - cmpSize = EA_ATTR(genTypeSize(op1Type)); - - if (op2->IsIntegralConst(0)) - { - emit->emitIns_R_F(INS_fcmp, cmpSize, op1->gtRegNum, 0.0); - } - else - { - assert(!op2->isContained()); - emit->emitIns_R_R(INS_fcmp, cmpSize, op1->gtRegNum, op2->gtRegNum); - } - } - else - { - assert(!varTypeIsFloating(op2Type)); - // We don't support swapping op1 and op2 to generate cmp reg, imm - assert(!op1->isContainedIntOrIImmed()); - - // TODO-ARM64-CQ: the second register argument of a CMP can be sign/zero - // extended as part of the instruction (using "CMP (extended register)"). - // We should use that if possible, swapping operands - // (and reversing the condition) if necessary. - unsigned op1Size = genTypeSize(op1Type); - unsigned op2Size = genTypeSize(op2Type); - - if ((op1Size < 4) || (op1Size < op2Size)) - { - // We need to sign/zero extend op1 up to 32 or 64 bits. - instruction ins = ins_Move_Extend(op1Type, true); - inst_RV_RV(ins, op1->gtRegNum, op1->gtRegNum); - } - - if (!op2->isContainedIntOrIImmed()) - { - if ((op2Size < 4) || (op2Size < op1Size)) - { - // We need to sign/zero extend op2 up to 32 or 64 bits. - instruction ins = ins_Move_Extend(op2Type, true); - inst_RV_RV(ins, op2->gtRegNum, op2->gtRegNum); - } - } - cmpSize = EA_4BYTE; - if ((op1Size == EA_8BYTE) || (op2Size == EA_8BYTE)) - { - cmpSize = EA_8BYTE; - } - - if (op2->isContainedIntOrIImmed()) - { - GenTreeIntConCommon* intConst = op2->AsIntConCommon(); - emit->emitIns_R_I(INS_cmp, cmpSize, op1->gtRegNum, intConst->IconValue()); - } - else - { - emit->emitIns_R_R(INS_cmp, cmpSize, op1->gtRegNum, op2->gtRegNum); - } - } - - // Are we evaluating this into a register? - if (targetReg != REG_NA) - { - genSetRegToCond(targetReg, tree); - genProduceReg(tree); - } - } - break; + genCodeForCompare(treeNode->AsOp()); + break; case GT_JTRUE: genCodeForJumpTrue(treeNode); @@ -4389,6 +4302,104 @@ void CodeGen::genCkfinite(GenTreePtr treeNode) genProduceReg(treeNode); } +//------------------------------------------------------------------------ +// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node. +// +// Arguments: +// tree - the node +// +void CodeGen::genCodeForCompare(GenTreeOp* tree) +{ + regNumber targetReg = tree->gtRegNum; + emitter* emit = getEmitter(); + + // TODO-ARM64-CQ: Check if we can use the currently set flags. + // TODO-ARM64-CQ: Check for the case where we can simply transfer the carry bit to a register + // (signed < or >= where targetReg != REG_NA) + + GenTreePtr op1 = tree->gtOp1; + GenTreePtr op2 = tree->gtOp2; + var_types op1Type = op1->TypeGet(); + var_types op2Type = op2->TypeGet(); + + assert(!op1->isUsedFromMemory()); + assert(!op2->isUsedFromMemory()); + + genConsumeOperands(tree); + + emitAttr cmpSize = EA_UNKNOWN; + + if (varTypeIsFloating(op1Type)) + { + assert(varTypeIsFloating(op2Type)); + assert(!op1->isContained()); + assert(op1Type == op2Type); + cmpSize = EA_ATTR(genTypeSize(op1Type)); + + if (op2->IsIntegralConst(0)) + { + emit->emitIns_R_F(INS_fcmp, cmpSize, op1->gtRegNum, 0.0); + } + else + { + assert(!op2->isContained()); + emit->emitIns_R_R(INS_fcmp, cmpSize, op1->gtRegNum, op2->gtRegNum); + } + } + else + { + assert(!varTypeIsFloating(op2Type)); + // We don't support swapping op1 and op2 to generate cmp reg, imm + assert(!op1->isContainedIntOrIImmed()); + + // TODO-ARM64-CQ: the second register argument of a CMP can be sign/zero + // extended as part of the instruction (using "CMP (extended register)"). + // We should use that if possible, swapping operands + // (and reversing the condition) if necessary. + unsigned op1Size = genTypeSize(op1Type); + unsigned op2Size = genTypeSize(op2Type); + + if ((op1Size < 4) || (op1Size < op2Size)) + { + // We need to sign/zero extend op1 up to 32 or 64 bits. + instruction ins = ins_Move_Extend(op1Type, true); + inst_RV_RV(ins, op1->gtRegNum, op1->gtRegNum); + } + + if (!op2->isContainedIntOrIImmed()) + { + if ((op2Size < 4) || (op2Size < op1Size)) + { + // We need to sign/zero extend op2 up to 32 or 64 bits. + instruction ins = ins_Move_Extend(op2Type, true); + inst_RV_RV(ins, op2->gtRegNum, op2->gtRegNum); + } + } + cmpSize = EA_4BYTE; + if ((op1Size == EA_8BYTE) || (op2Size == EA_8BYTE)) + { + cmpSize = EA_8BYTE; + } + + if (op2->isContainedIntOrIImmed()) + { + GenTreeIntConCommon* intConst = op2->AsIntConCommon(); + emit->emitIns_R_I(INS_cmp, cmpSize, op1->gtRegNum, intConst->IconValue()); + } + else + { + emit->emitIns_R_R(INS_cmp, cmpSize, op1->gtRegNum, op2->gtRegNum); + } + } + + // Are we evaluating this into a register? + if (targetReg != REG_NA) + { + genSetRegToCond(targetReg, tree); + genProduceReg(tree); + } +} + int CodeGenInterface::genSPtoFPdelta() { int delta; diff --git a/src/coreclr/src/jit/codegenlinear.h b/src/coreclr/src/jit/codegenlinear.h index 3b56a9f..57a46c3 100644 --- a/src/coreclr/src/jit/codegenlinear.h +++ b/src/coreclr/src/jit/codegenlinear.h @@ -42,6 +42,8 @@ void genIntToFloatCast(GenTreePtr treeNode); void genCkfinite(GenTreePtr treeNode); +void genCodeForCompare(GenTreeOp* tree); + void genIntrinsic(GenTreePtr treeNode); void genPutArgStk(GenTreePutArgStk* treeNode);