diff options
Diffstat (limited to 'src/jit/codegenarmarch.cpp')
-rw-r--r-- | src/jit/codegenarmarch.cpp | 216 |
1 files changed, 182 insertions, 34 deletions
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index af9fdfed9c..c541472284 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -212,13 +212,10 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) // We will copy this struct to the stack, possibly using a ldp instruction // Setup loReg and hiReg from the internal registers that we reserved in lower. // - regNumber loReg = REG_NA; - regNumber hiReg = REG_NA; + regNumber loReg = treeNode->ExtractTempReg(); + regNumber hiReg = treeNode->GetSingleTempReg(); regNumber addrReg = REG_NA; - // In lowerArm64/TreeNodeInfoInitPutArgStk we have reserved two internal integer registers - genGetRegPairFromMask(treeNode->gtRsvdRegs, &loReg, &hiReg); - GenTreeLclVarCommon* varNode = nullptr; GenTreePtr addrNode = nullptr; @@ -709,15 +706,9 @@ void CodeGen::genCodeForArrIndex(GenTreeArrIndex* arrIndex) regNumber tgtReg = arrIndex->gtRegNum; noway_assert(tgtReg != REG_NA); - // We will use a temp register to load the lower bound and dimension size values - // - regMaskTP tmpRegsMask = arrIndex->gtRsvdRegs; // there will be two bits set - tmpRegsMask &= ~genRegMask(tgtReg); // remove the bit for 'tgtReg' from 'tmpRegsMask' - - regMaskTP tmpRegMask = genFindLowestBit(tmpRegsMask); // set tmpRegMsk to a one-bit mask - regNumber tmpReg = genRegNumFromMask(tmpRegMask); // set tmpReg from that mask - noway_assert(tmpReg != REG_NA); + // We will use a temp register to load the lower bound and dimension size values. + regNumber tmpReg = arrIndex->GetSingleTempReg(); assert(tgtReg != tmpReg); unsigned dim = arrIndex->gtCurrDim; @@ -773,25 +764,17 @@ void CodeGen::genCodeForArrOffset(GenTreeArrOffs* arrOffset) noway_assert(indexReg != REG_NA); noway_assert(arrReg != REG_NA); - regMaskTP tmpRegMask = arrOffset->gtRsvdRegs; - regNumber tmpReg = genRegNumFromMask(tmpRegMask); - noway_assert(tmpReg != REG_NA); + regNumber tmpReg = arrOffset->GetSingleTempReg(); unsigned dim = arrOffset->gtCurrDim; unsigned rank = arrOffset->gtArrRank; var_types elemType = arrOffset->gtArrElemType; unsigned offset = genOffsetOfMDArrayDimensionSize(elemType, rank, dim); -// Load tmpReg with the dimension size and evaluate -// tgtReg = offsetReg*dim_size + indexReg. -#if defined(_TARGET_ARM_) - emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_4BYTE, tmpReg, arrReg, offset); // a 4 BYTE sign extending load - emit->emitIns_R_R_R(INS_MUL, EA_4BYTE, tgtReg, tmpReg, offsetReg); - emit->emitIns_R_R_R(INS_add, EA_4BYTE, tgtReg, tgtReg, indexReg); -#elif defined(_TARGET_ARM64_) - emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_8BYTE, tmpReg, arrReg, offset); // a 4 BYTE sign extending load - emit->emitIns_R_R_R_R(INS_madd, EA_4BYTE, tgtReg, tmpReg, offsetReg, indexReg); -#endif // _TARGET_* + // Load tmpReg with the dimension size and evaluate + // tgtReg = offsetReg*tmpReg + indexReg. + emit->emitIns_R_R_I(ins_Load(TYP_INT), EA_PTRSIZE, tmpReg, arrReg, offset); + emit->emitIns_R_R_R_R(INS_MULADD, EA_PTRSIZE, tgtReg, tmpReg, offsetReg, indexReg); } else { @@ -1073,12 +1056,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) const regNumber regThis = genGetThisArgReg(call); #if defined(_TARGET_ARM_) - regMaskTP tempMask = genFindLowestBit(call->gtRsvdRegs); - const regNumber tmpReg = genRegNumFromMask(tempMask); - if (genCountBits(call->gtRsvdRegs) > 1) - { - call->gtRsvdRegs &= ~tempMask; - } + const regNumber tmpReg = call->ExtractTempReg(); getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, tmpReg, regThis, 0); #elif defined(_TARGET_ARM64_) getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, regThis, 0); @@ -1239,7 +1217,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) #ifdef _TARGET_ARM_ if (!arm_Valid_Imm_For_BL((ssize_t)addr)) { - regNumber tmpReg = genRegNumFromMask(call->gtRsvdRegs); + regNumber tmpReg = call->GetSingleTempReg(); instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, tmpReg, (ssize_t)addr); genEmitCall(emitter::EC_INDIR_R, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) NULL, retSize, ilOffset, tmpReg); } @@ -1388,7 +1366,7 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode) regNumber sourceReg = castOp->gtRegNum; // For Long to Int conversion we will have a reserved integer register to hold the immediate mask - regNumber tmpReg = (treeNode->gtRsvdRegs == RBM_NONE) ? REG_NA : genRegNumFromMask(treeNode->gtRsvdRegs); + regNumber tmpReg = (treeNode->AvailableTempRegCount() == 0) ? REG_NA : treeNode->GetSingleTempReg(); assert(genIsValidIntReg(targetReg)); assert(genIsValidIntReg(sourceReg)); @@ -1428,7 +1406,20 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode) // we only have to check for any bits set in 'typeMask' noway_assert(castInfo.typeMask != 0); +#if defined(_TARGET_ARM_) + if (arm_Valid_Imm_For_Instr(INS_tst, castInfo.typeMask, INS_FLAGS_DONT_CARE)) + { + emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, castInfo.typeMask); + } + else + { + noway_assert(tmpReg != REG_NA); + instGen_Set_Reg_To_Imm(cmpSize, tmpReg, castInfo.typeMask); + emit->emitIns_R_R(INS_tst, cmpSize, sourceReg, tmpReg); + } +#elif defined(_TARGET_ARM64_) emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, castInfo.typeMask); +#endif // _TARGET_ARM* emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED); genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW); } @@ -1682,6 +1673,163 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface } +//------------------------------------------------------------------------------------------- +// genJumpKindsForTree: Determine the number and kinds of conditional branches +// necessary to implement the given GT_CMP node +// +// Arguments: +// cmpTree - (input) The GenTree node that is used to set the Condition codes +// - The GenTree Relop node that was used to set the Condition codes +// jmpKind[2] - (output) One or two conditional branch instructions +// jmpToTrueLabel[2] - (output) On Arm64 both branches will always branch to the true label +// +// Return Value: +// Sets the proper values into the array elements of jmpKind[] and jmpToTrueLabel[] +// +// Assumptions: +// At least one conditional branch instruction will be returned. +// Typically only one conditional branch is needed +// and the second jmpKind[] value is set to EJ_NONE +// +void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]) +{ + // On ARM both branches will always branch to the true label + jmpToTrueLabel[0] = true; + jmpToTrueLabel[1] = true; + + // For integer comparisons just use genJumpKindForOper + if (!varTypeIsFloating(cmpTree->gtOp.gtOp1->gtEffectiveVal())) + { + CompareKind compareKind = ((cmpTree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED; + jmpKind[0] = genJumpKindForOper(cmpTree->gtOper, compareKind); + jmpKind[1] = EJ_NONE; + } + else // We have a Floating Point Compare operation + { + assert(cmpTree->OperIsCompare()); + + // For details on this mapping, see the ARM Condition Code table + // at section A8.3 in the ARMv7 architecture manual or + // at section C1.2.3 in the ARMV8 architecture manual. + + // We must check the GTF_RELOP_NAN_UN to find out + // if we need to branch when we have a NaN operand. + // + if ((cmpTree->gtFlags & GTF_RELOP_NAN_UN) != 0) + { + // Must branch if we have an NaN, unordered + switch (cmpTree->gtOper) + { + case GT_EQ: + jmpKind[0] = EJ_eq; // branch or set when equal (and no NaN's) + jmpKind[1] = EJ_vs; // branch or set when we have a NaN + break; + + case GT_NE: + jmpKind[0] = EJ_ne; // branch or set when not equal (or have NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_LT: + jmpKind[0] = EJ_lt; // branch or set when less than (or have NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_LE: + jmpKind[0] = EJ_le; // branch or set when less than or equal (or have NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_GT: + jmpKind[0] = EJ_hi; // branch or set when greater than (or have NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_GE: + jmpKind[0] = EJ_hs; // branch or set when greater than or equal (or have NaN's) + jmpKind[1] = EJ_NONE; + break; + + default: + unreached(); + } + } + else // ((cmpTree->gtFlags & GTF_RELOP_NAN_UN) == 0) + { + // Do not branch if we have an NaN, unordered + switch (cmpTree->gtOper) + { + case GT_EQ: + jmpKind[0] = EJ_eq; // branch or set when equal (and no NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_NE: + jmpKind[0] = EJ_gt; // branch or set when greater than (and no NaN's) + jmpKind[1] = EJ_lo; // branch or set when less than (and no NaN's) + break; + + case GT_LT: + jmpKind[0] = EJ_lo; // branch or set when less than (and no NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_LE: + jmpKind[0] = EJ_ls; // branch or set when less than or equal (and no NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_GT: + jmpKind[0] = EJ_gt; // branch or set when greater than (and no NaN's) + jmpKind[1] = EJ_NONE; + break; + + case GT_GE: + jmpKind[0] = EJ_ge; // branch or set when greater than or equal (and no NaN's) + jmpKind[1] = EJ_NONE; + break; + + default: + unreached(); + } + } + } +} + +//------------------------------------------------------------------------ +// genCodeForJumpTrue: Generates code for jmpTrue statement. +// +// Arguments: +// tree - The GT_JTRUE tree node. +// +// Return Value: +// None +// +void CodeGen::genCodeForJumpTrue(GenTreePtr tree) +{ + GenTree* cmp = tree->gtOp.gtOp1->gtEffectiveVal(); + assert(cmp->OperIsCompare()); + assert(compiler->compCurBB->bbJumpKind == BBJ_COND); + + // Get the "kind" and type of the comparison. Note that whether it is an unsigned cmp + // is governed by a flag NOT by the inherent type of the node + emitJumpKind jumpKind[2]; + bool branchToTrueLabel[2]; + genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel); + assert(jumpKind[0] != EJ_NONE); + + // On ARM the branches will always branch to the true label + assert(branchToTrueLabel[0]); + inst_JMP(jumpKind[0], compiler->compCurBB->bbJumpDest); + + if (jumpKind[1] != EJ_NONE) + { + // the second conditional branch always has to be to the true label + assert(branchToTrueLabel[1]); + inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest); + } +} + #endif // _TARGET_ARMARCH_ #endif // !LEGACY_BACKEND |