Open
Description
Consider the addition operator for Int128:
/// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_Addition(TSelf, TOther)" />
public static Int128 operator +(Int128 left, Int128 right)
{
// For unsigned addition, we can detect overflow by checking `(x + y) < x`
// This gives us the carry to add to upper to compute the correct result
ulong lower = left._lower + right._lower;
ulong carry = (lower < left._lower) ? 1UL : 0UL;
ulong upper = left._upper + right._upper + carry;
return new Int128(upper, lower);
}
This compiles to:
ldp x0, x1, [fp, #0x18] // [V42 tmp41], [V43 tmp42]
ldp x20, x21, [fp, #0x28] // [V34 tmp33], [V35 tmp34]
add x19, x20, x0
cmp x19, x20
cset x0, lo
mov w0, w0
add x1, x21, x1
add x20, x1, x0
movz x0, #0xA610
movk x0, #0x75F3 LSL #16
movk x0, #0xECE6 LSL #32
bl CORINFO_HELP_NEWSFAST
stp x19, x20, [x0, #0x08]
Instead add with carry should be used to remove the compare:
ldp x0, x1, [fp, #0x18] // [V42 tmp41], [V43 tmp42]
ldp x20, x21, [fp, #0x28] // [V34 tmp33], [V35 tmp34]
adds x19, x20, x0
addc x20, x21, x1
movz x0, #0xA610
movk x0, #0x75F3 LSL #16
movk x0, #0xECE6 LSL #32
bl CORINFO_HELP_NEWSFAST
stp x19, x20, [x0, #0x08]
This should be expanded for uses of SUBC and NEGC.
This could either be done by matching a standard IR pattern or if it's too big/fragile, then via intrinsics. There is an initial discussion here: #68028 (comment)