summaryrefslogtreecommitdiff
path: root/src/jit/codegenarmarch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/codegenarmarch.cpp')
-rw-r--r--src/jit/codegenarmarch.cpp216
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