summaryrefslogtreecommitdiff
path: root/src/jit/codegenarmarch.cpp
diff options
context:
space:
mode:
authorCarol Eidt <carol.eidt@microsoft.com>2018-08-29 14:58:10 -0700
committerCarol Eidt <carol.eidt@microsoft.com>2018-09-12 07:53:20 -0700
commit6d58642cd13e639501fcb3c1289af3ac9cc40c34 (patch)
tree6f4a88a411172ca3c4f7d2cde597ec19b29b81d9 /src/jit/codegenarmarch.cpp
parent598fca6348cbedc9cadb92aabf00b0f6f181bf83 (diff)
downloadcoreclr-6d58642cd13e639501fcb3c1289af3ac9cc40c34.tar.gz
coreclr-6d58642cd13e639501fcb3c1289af3ac9cc40c34.tar.bz2
coreclr-6d58642cd13e639501fcb3c1289af3ac9cc40c34.zip
Arm: Correctly handle multi-reg COPY
Fix #19448
Diffstat (limited to 'src/jit/codegenarmarch.cpp')
-rw-r--r--src/jit/codegenarmarch.cpp107
1 files changed, 63 insertions, 44 deletions
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index 746636a69d..e59bf359a1 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -2059,56 +2059,30 @@ void CodeGen::genCodeForStoreOffset(instruction ins, emitAttr size, regNumber sr
}
//------------------------------------------------------------------------
-// genRegCopy: Generate a register copy.
+// genRegCopy: Produce code for a GT_COPY node.
+//
+// Arguments:
+// tree - the GT_COPY node
+//
+// Notes:
+// This will copy the register(s) produced by this node's source, to
+// the register(s) allocated to this GT_COPY node.
+// It has some special handling for these cases:
+// - when the source and target registers are in different register files
+// (note that this is *not* a conversion).
+// - when the source is a lclVar whose home location is being moved to a new
+// register (rather than just being copied for temporary use).
//
void CodeGen::genRegCopy(GenTree* treeNode)
{
assert(treeNode->OperGet() == GT_COPY);
+ GenTree* op1 = treeNode->gtOp.gtOp1;
- var_types targetType = treeNode->TypeGet();
- regNumber targetReg = treeNode->gtRegNum;
- assert(targetReg != REG_NA);
-
- GenTree* op1 = treeNode->gtOp.gtOp1;
regNumber sourceReg = genConsumeReg(op1);
- // Check whether this node and the node from which we're copying the value have the same
- // register type.
- // This can happen if (currently iff) we have a SIMD vector type that fits in an integer
- // register, in which case it is passed as an argument, or returned from a call,
- // in an integer register and must be copied if it's in an xmm register.
-
- if (varTypeIsFloating(treeNode) != varTypeIsFloating(op1))
- {
-#ifdef _TARGET_ARM64_
- inst_RV_RV(INS_fmov, targetReg, sourceReg, targetType);
-#else // !_TARGET_ARM64_
- if (varTypeIsFloating(treeNode))
- {
- // GT_COPY from 'int' to 'float' currently can't happen. Maybe if ARM SIMD is implemented
- // it will happen, according to the comment above?
- NYI_ARM("genRegCopy from 'int' to 'float'");
- }
- else
- {
- assert(varTypeIsFloating(op1));
-
- if (op1->TypeGet() == TYP_FLOAT)
- {
- inst_RV_RV(INS_vmov_f2i, targetReg, genConsumeReg(op1), targetType);
- }
- else
- {
- regNumber otherReg = (regNumber)treeNode->AsCopyOrReload()->gtOtherRegs[0];
- assert(otherReg != REG_NA);
- inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, genConsumeReg(op1), EA_8BYTE);
- }
- }
-#endif // !_TARGET_ARM64_
- }
- else if (targetType == TYP_STRUCT)
+ if (op1->IsMultiRegNode())
{
- noway_assert(op1->IsMultiRegNode() && !op1->IsCopyOrReload());
+ noway_assert(!op1->IsCopyOrReload());
unsigned regCount = op1->GetMultiRegCount();
for (unsigned i = 0; i < regCount; i++)
{
@@ -2120,7 +2094,51 @@ void CodeGen::genRegCopy(GenTree* treeNode)
}
else
{
- inst_RV_RV(ins_Copy(targetType), targetReg, sourceReg, targetType);
+ var_types targetType = treeNode->TypeGet();
+ regNumber targetReg = treeNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ assert(targetType != TYP_STRUCT);
+
+ // Check whether this node and the node from which we're copying the value have the same
+ // register type.
+ // This can happen if (currently iff) we have a SIMD vector type that fits in an integer
+ // register, in which case it is passed as an argument, or returned from a call,
+ // in an integer register and must be copied if it's in a floating point register.
+
+ bool srcFltReg = (varTypeIsFloating(op1) || varTypeIsSIMD(op1));
+ bool tgtFltReg = (varTypeIsFloating(treeNode) || varTypeIsSIMD(treeNode));
+ if (srcFltReg != tgtFltReg)
+ {
+#ifdef _TARGET_ARM64_
+ inst_RV_RV(INS_fmov, targetReg, sourceReg, targetType);
+#else // !_TARGET_ARM64_
+ if (varTypeIsFloating(treeNode))
+ {
+ // GT_COPY from 'int' to 'float' currently can't happen. Maybe if ARM SIMD is implemented
+ // it will happen, according to the comment above?
+ NYI_ARM("genRegCopy from 'int' to 'float'");
+ }
+ else
+ {
+ assert(varTypeIsFloating(op1));
+
+ if (op1->TypeGet() == TYP_FLOAT)
+ {
+ inst_RV_RV(INS_vmov_f2i, targetReg, genConsumeReg(op1), targetType);
+ }
+ else
+ {
+ regNumber otherReg = (regNumber)treeNode->AsCopyOrReload()->gtOtherRegs[0];
+ assert(otherReg != REG_NA);
+ inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, genConsumeReg(op1), EA_8BYTE);
+ }
+ }
+#endif // !_TARGET_ARM64_
+ }
+ else
+ {
+ inst_RV_RV(ins_Copy(targetType), targetReg, sourceReg, targetType);
+ }
}
if (op1->IsLocal())
@@ -2258,7 +2276,8 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
#endif // _TARGET_*
}
- // Either gtControlExpr != null or gtCallAddr != null or it is a direct non-virtual call to a user or helper method.
+ // Either gtControlExpr != null or gtCallAddr != null or it is a direct non-virtual call to a user or helper
+ // method.
CORINFO_METHOD_HANDLE methHnd;
GenTree* target = call->gtControlExpr;
if (callType == CT_INDIRECT)