https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126555

            Bug ID: 126555
           Summary: [AArch64] wrong-code: SUBP used for subtraction of
                    zero-extended 56-bit integers
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kareem.h.omar at gmail dot com
  Target Milestone: ---

Keywords: AArch64, wrong-code, memtag, subp, backend

The AArch64 backend incorrectly emits SUBP for subtraction of two unsigned
64-bit values after each value has been masked to 56 bits when the 'memtag'
instruction set extensions are enabled (i.e. -mcpu=cortex-a150 or
-mcpu=neoverse-n2).

Minimal repro:

unsigned long f(unsigned long a, unsigned long b)
{
    return (a & 0xFFFFFFFFFFFFFF) - (b & 0xFFFFFFFFFFFFFF);
}

Compile:

gcc -O3 -mcpu=neoverse-n2

Codegen:

subp x0, x0, x1
ret

View it live:
https://godbolt.org/z/6vxYz37de

The bug:

SUBP performs *sign*-extension of its operands from 56 to 64 bits, not
*zero*-extension, producing an incorrect result for some inputs.

This is of particular importance in cryptographic code which somewhat commonly
manipulates 56-bit limbs of multiprecision integers, and is how this bug was
encountered in the wild.

Expected behavior:

The subtraction must be performed on zero-extended, not sign-extended,
operands.

Versions:

All versions from gcc10.3 to current gcc trunk (10.3 is earliest I can find
with support for -mcpu=neoverse-n2).

Workaround:

Appending +nomemtag to the -mcpu string prevents the generation of the SUBP
instruction.

Reply via email to