summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Sullivan <briansul@microsoft.com>2017-04-28 10:57:50 -0700
committerGitHub <noreply@github.com>2017-04-28 10:57:50 -0700
commitaabe04b262546c93421a7e0164c4f0f4aaeedbf3 (patch)
treeb55d6ffcb59c4b3dd987684eefc8ee974f2c0c7d
parent6bfd4789a274c92f7839796f9ba7acfa1cc1e634 (diff)
parent136b32f6b7148b9d8541cfd5f3ed0d7e141fd32b (diff)
downloadcoreclr-aabe04b262546c93421a7e0164c4f0f4aaeedbf3.tar.gz
coreclr-aabe04b262546c93421a7e0164c4f0f4aaeedbf3.tar.bz2
coreclr-aabe04b262546c93421a7e0164c4f0f4aaeedbf3.zip
Merge pull request #11268 from sdmaclea/PR-ARM64-two-gc-attributes
[Arm64] Support two GC attributes in pair forms
-rw-r--r--src/jit/codegenarm64.cpp46
-rw-r--r--src/jit/codegenarmarch.cpp17
-rw-r--r--src/jit/emit.cpp4
-rw-r--r--src/jit/emit.h26
-rw-r--r--src/jit/emitarm64.cpp54
-rw-r--r--src/jit/emitarm64.h3
6 files changed, 83 insertions, 67 deletions
diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp
index c075c0ac18..a8c92c2fba 100644
--- a/src/jit/codegenarm64.cpp
+++ b/src/jit/codegenarm64.cpp
@@ -3487,31 +3487,29 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
// If we can prove it's on the stack we don't need to use the write barrier.
if (dstOnStack)
{
- for (unsigned i = 0; i < slots; ++i)
+ unsigned i = 0;
+ // Check if two or more remaining slots and use a ldp/stp sequence
+ while (i < slots - 1)
{
- emitAttr attr = EA_8BYTE;
- if (gcPtrs[i] == GCT_GCREF)
- attr = EA_GCREF;
- else if (gcPtrs[i] == GCT_BYREF)
- attr = EA_BYREF;
-
- // Check if two or more remaining slots and use a ldp/stp sequence
- // TODO-ARM64-CQ: Current limitations only allows using ldp/stp when both of the GC types match
- if ((i + 1 < slots) && (gcPtrs[i] == gcPtrs[i + 1]))
- {
- emit->emitIns_R_R_R_I(INS_ldp, attr, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF,
- 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
- emit->emitIns_R_R_R_I(INS_stp, attr, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF,
- 2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
- ++i; // extra increment of i, since we are copying two items
- }
- else
- {
- emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
- INS_OPTS_POST_INDEX);
- emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
- INS_OPTS_POST_INDEX);
- }
+ emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
+ emitAttr attr1 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 1]));
+
+ emit->emitIns_R_R_R_I(INS_ldp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, 2 * TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX, attr1);
+ emit->emitIns_R_R_R_I(INS_stp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF, 2 * TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX, attr1);
+ i += 2;
+ }
+
+ // Use a ldr/str sequence for the last remainder
+ if (i < slots)
+ {
+ emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
+
+ emit->emitIns_R_R_I(INS_ldr, attr0, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX);
+ emit->emitIns_R_R_I(INS_str, attr0, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
+ INS_OPTS_POST_INDEX);
}
}
else
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index 4a79ad1bba..0888e83963 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -356,20 +356,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
assert(loReg != addrReg);
noway_assert((remainingSize == 2 * TARGET_POINTER_SIZE) || (hiReg != addrReg));
- // Use a ldp instruction if types match
- // TODO-ARM64-CQ: Current limitations only allows using ldp/stp when both of the GC types match
- if (type0 == type1)
- {
- // Load from our address expression source
- emit->emitIns_R_R_R_I(INS_ldp, emitTypeSize(type0), loReg, hiReg, addrReg, structOffset);
- }
- else
- {
- // Load from our address expression source
- emit->emitIns_R_R_I(ins_Load(type0), emitTypeSize(type0), loReg, addrReg, structOffset);
- emit->emitIns_R_R_I(ins_Load(type1), emitTypeSize(type1), hiReg, addrReg,
- structOffset + TARGET_POINTER_SIZE);
- }
+ // Load from our address expression source
+ emit->emitIns_R_R_R_I(INS_ldp, emitTypeSize(type0), loReg, hiReg, addrReg, structOffset,
+ INS_OPTS_NONE, emitTypeSize(type0));
}
// Emit two store instructions to store the two registers into the outgoing argument area
diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp
index d2aa29fd7a..ff2475a4f0 100644
--- a/src/jit/emit.cpp
+++ b/src/jit/emit.cpp
@@ -1381,6 +1381,10 @@ void* emitter::emitAllocInstr(size_t sz, emitAttr opsz)
id->idOpSize(EA_SIZE(opsz));
}
+#ifdef _TARGET_ARM64_
+ id->idGCrefReg2(GCT_NONE);
+#endif
+
// Amd64: ip-relative addressing is supported even when not generating relocatable ngen code
if (EA_IS_DSP_RELOC(opsz)
#ifndef _TARGET_AMD64_
diff --git a/src/jit/emit.h b/src/jit/emit.h
index e1c924f467..a63242f0b0 100644
--- a/src/jit/emit.h
+++ b/src/jit/emit.h
@@ -655,6 +655,9 @@ protected:
// unnecessarily since the GC-ness of the second register is only needed for call instructions.
// The instrDescCGCA struct's member keeping the GC-ness of the first return register is _idcSecondRetRegGCType.
GCtype _idGCref : 2; // GCref operand? (value is a "GCtype")
+#ifdef _TARGET_ARM64_
+ GCtype _idGCref2 : 2;
+#endif
// Note that we use the _idReg1 and _idReg2 fields to hold
// the live gcrefReg mask for the call instructions on x86/x64
@@ -668,7 +671,7 @@ protected:
// x86: 30 bits
// amd64: 38 bits
// arm: 32 bits
- // arm64: 30 bits
+ // arm64: 32 bits
CLANG_FORMAT_COMMENT_ANCHOR;
#if HAS_TINY_DESC
@@ -718,8 +721,8 @@ protected:
#define ID_EXTRA_BITFIELD_BITS (16)
#elif defined(_TARGET_ARM64_)
-// For Arm64, we have used 15 bits from the second DWORD.
-#define ID_EXTRA_BITFIELD_BITS (16)
+// For Arm64, we have used 18 bits from the second DWORD.
+#define ID_EXTRA_BITFIELD_BITS (18)
#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
// For xarch !LEGACY_BACKEND, we have used 14 bits from the second DWORD.
#define ID_EXTRA_BITFIELD_BITS (14)
@@ -735,7 +738,7 @@ protected:
// x86: 38 bits // if HAS_TINY_DESC is not defined (which it is)
// amd64: 46 bits
// arm: 48 bits
- // arm64: 48 bits
+ // arm64: 50 bits
CLANG_FORMAT_COMMENT_ANCHOR;
unsigned _idCnsReloc : 1; // LargeCns is an RVA and needs reloc tag
@@ -748,7 +751,7 @@ protected:
// x86: 40 bits
// amd64: 48 bits
// arm: 50 bits
- // arm64: 50 bits
+ // arm64: 52 bits
CLANG_FORMAT_COMMENT_ANCHOR;
#define ID_EXTRA_BITS (ID_EXTRA_RELOC_BITS + ID_EXTRA_BITFIELD_BITS)
@@ -764,7 +767,7 @@ protected:
// x86: 24 bits
// amd64: 16 bits
// arm: 14 bits
- // arm64: 14 bits
+ // arm64: 12 bits
unsigned _idSmallCns : ID_BIT_SMALL_CNS;
@@ -1072,6 +1075,17 @@ protected:
assert(reg == _idReg1);
}
+#ifdef _TARGET_ARM64_
+ GCtype idGCrefReg2() const
+ {
+ return (GCtype)_idGCref2;
+ }
+ void idGCrefReg2(GCtype gctype)
+ {
+ _idGCref2 = gctype;
+ }
+#endif // _TARGET_ARM64_
+
regNumber idReg2() const
{
return _idReg2;
diff --git a/src/jit/emitarm64.cpp b/src/jit/emitarm64.cpp
index 1a56e863e5..e2a1ae14ec 100644
--- a/src/jit/emitarm64.cpp
+++ b/src/jit/emitarm64.cpp
@@ -5072,7 +5072,8 @@ void emitter::emitIns_R_R_R_I(instruction ins,
regNumber reg2,
regNumber reg3,
ssize_t imm,
- insOpts opt /* = INS_OPTS_NONE */)
+ insOpts opt /* = INS_OPTS_NONE */,
+ emitAttr attrReg2 /* = EA_UNKNOWN */)
{
emitAttr size = EA_SIZE(attr);
emitAttr elemsize = EA_UNKNOWN;
@@ -5347,6 +5348,23 @@ void emitter::emitIns_R_R_R_I(instruction ins,
id->idReg2(reg2);
id->idReg3(reg3);
+ if (attrReg2 != EA_UNKNOWN)
+ {
+ assert((fmt == IF_LS_3B) || (fmt == IF_LS_3C));
+ if (EA_IS_GCREF(attrReg2))
+ {
+ /* A special value indicates a GCref pointer value */
+
+ id->idGCrefReg2(GCT_GCREF);
+ }
+ else if (EA_IS_BYREF(attrReg2))
+ {
+ /* A special value indicates a Byref pointer value */
+
+ id->idGCrefReg2(GCT_BYREF);
+ }
+ }
+
dispIns(id);
appendToCurIG(id);
}
@@ -9324,35 +9342,27 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
// for stores, but we ignore those cases here.)
if (emitInsMayWriteToGCReg(id)) // True if "id->idIns()" writes to a register than can hold GC ref.
{
- // If we ever generate instructions that write to multiple registers,
- // then we'd need to more work here to ensure that changes in the status of GC refs are
- // tracked properly.
- if (emitInsMayWriteMultipleRegs(id))
+ // We assume that "idReg1" is the primary destination register for all instructions
+ if (id->idGCref() != GCT_NONE)
{
- // INS_ldp etc...
- // We assume that "idReg1" and "idReg2" are the destination register for all instructions
- // TODO-ARM64-CQ: Current limitations only allows using ldp/stp when both of the GC types match
- if (id->idGCref() != GCT_NONE)
- {
- emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
- emitGCregLiveUpd(id->idGCref(), id->idReg2(), dst);
- }
- else
- {
- emitGCregDeadUpd(id->idReg1(), dst);
- emitGCregDeadUpd(id->idReg2(), dst);
- }
+ emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
}
else
{
- // We assume that "idReg1" is the destination register for all instructions
- if (id->idGCref() != GCT_NONE)
+ emitGCregDeadUpd(id->idReg1(), dst);
+ }
+
+ if (emitInsMayWriteMultipleRegs(id))
+ {
+ // INS_ldp etc...
+ // "idReg2" is the secondary destination register
+ if (id->idGCrefReg2() != GCT_NONE)
{
- emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
+ emitGCregLiveUpd(id->idGCrefReg2(), id->idReg2(), dst);
}
else
{
- emitGCregDeadUpd(id->idReg1(), dst);
+ emitGCregDeadUpd(id->idReg2(), dst);
}
}
}
diff --git a/src/jit/emitarm64.h b/src/jit/emitarm64.h
index 6a8e42b86f..8dcb3286bb 100644
--- a/src/jit/emitarm64.h
+++ b/src/jit/emitarm64.h
@@ -724,7 +724,8 @@ void emitIns_R_R_R_I(instruction ins,
regNumber reg2,
regNumber reg3,
ssize_t imm,
- insOpts opt = INS_OPTS_NONE);
+ insOpts opt = INS_OPTS_NONE,
+ emitAttr attrReg2 = EA_UNKNOWN);
void emitIns_R_R_R_Ext(instruction ins,
emitAttr attr,