Description
These 2 instructions were said to be completed in #68028 but I writing tests for them and found the following issue. See #111796 for the full tests.
Compare these 2 c# functions taken from the tests in the PR above. Both of them take 2 numbers shift 1 of them and compare it to the other or the negative in the CmnLargeShift64Bit case. If they are equal return true else return false.
static bool CmnLargeShift64Bit(long a, long b)
{
if (a == -(b<<247))
{
return true;
}
return false;
}
static bool CmpLargeShift64Bit(long a, long b)
{
if (a == (b<<119))
{
return true;
}
return false;
}
The disassembly of both functions respectively.
cmn x0, x1, LSL #55
cset x0, eq
lsl x1, x1, #55
cmp x0, x1
cset x0, eq
Section of nodes just before lowering for each function respectively.
N003 ( 3, 4) [000003] -----+----- t3 = * LSH long $140
/--* t3 long
N004 ( 4, 5) [000004] -----+----- t4 = * NEG long $82
N005 ( 1, 1) [000000] -----+----- t0 = LCL_VAR long V00 arg0 u:1 (last use) $80
/--* t4 long
+--* t0 long
N006 ( 6, 7) [000005] N----+-N-U- t5 = * NE int $180
N004 ( 3, 4) [000003] -----+----- t3 = * LSH long $140
/--* t0 long
+--* t3 long
N005 ( 5, 6) [000004] N----+-N-U- t4 = * NE int $180
After the lowering phase the LSH in CmnLargeShift64Bit has been contained and will produce the shifted register version of cmn.
In CmpLargeShift64Bit the LSH is not contained.
In lowerarmarch.cpp function IsContainableUnaryOrBinaryOp line 272 we have this check
const ssize_t shiftAmount = shiftAmountNode->AsIntCon()->IconValue();
const ssize_t maxShift = (static_cast<ssize_t>(genTypeSize(parentNode)) * BITS_PER_BYTE) - 1;
if ((shiftAmount < 0x01) || (shiftAmount > maxShift))
{
// Cannot contain if the shift amount is less than 1 or greater than maxShift
return false;
}
Which says if the shift amount is greater than the max shift return false. When checking the LSH Cmp the parent node is the NE whereas Cmn's parent node is NEG. The type size of NE node is 4 bytes and the NEG node is 8 bytes which gets a maxShift of 31 & 63 for NE & NEG.
In the Cmp case the shift amount of 55 is > 31 and it returns false.
In the Cmn case the shift amount of 55 is not > 63 and it continues the function and further down returns true to say it is containable.
The same thing happens for ands.