t.S:3:11: error: immediate must be an integer in range [0, 65535].
movz x0, #thing
^
t.S:4:14: error: expected compatible register, symbol or integer in range [0, 4095]
add x0, x0, #thing
^
t.S:5:14: error: expected compatible register or logical immediate
eor x0, x0, #thing
^
t.S:6:15: error: index must be an integer in range [-256, 255].
ldr x0, [x1, #thing]
^
t.S:7:19: error: invalid operand for instruction
ldp x0, x1, [x2, #thing]
^
t.S:8:15: error: index must be an integer in range [-256, 255].
ldr q0, [x0, #thing]
^
t.S:9:19: error: invalid operand for instruction
ldp q0, q1, [x0, #thing]
^
The errors for ldp are unhelpfully vague, but the caret position hints
that assembler is objecting to the immediate operand. The eor error
is a little unhelpful, but I understand that it's hard to characterize the
acceptable ARM64 logical immediate values. The other messages are
simply incorrect: it's clear that thing has the value 16, which is
easily in range.
GNU as accepts the following (https://gcc.godbolt.org/z/e1fed5vhM)
```assembler
.text
proc:
movz x0, #thing
add x0, x0, #thing
eor x0, x0, #thing
ldr x0, [x1, #thing]
ldp x0, x1, [x2, #thing]
ldr q0, [x0, #thing]
ldp q0, q1, [x0, #thing]
ret
.balign 16
base:
.skip 16
thing = . - base
.skip 16
```
and produces
```
0000000000000000 <proc>:
0: d2800200 mov x0, #0x10 // #16
4: 91004000 add x0, x0, #0x10
8: d27c0000 eor x0, x0, #0x10
c: f9400820 ldr x0, [x1, #16]
10: a9410440 ldp x0, x1, [x2, #16]
14: 3dc00400 ldr q0, [x0, #16]
18: ad408400 ldp q0, q1, [x0, #16]
1c: d65f03c0 ret
```
as I expect.
Clang rejects this (https://gcc.godbolt.org/z/W8PTq9aqG), reporting
```
t.S:3:11: error: immediate must be an integer in range [0, 65535].
movz x0, #thing
^
t.S:4:14: error: expected compatible register, symbol or integer in range [0, 4095]
add x0, x0, #thing
^
t.S:5:14: error: expected compatible register or logical immediate
eor x0, x0, #thing
^
t.S:6:15: error: index must be an integer in range [-256, 255].
ldr x0, [x1, #thing]
^
t.S:7:19: error: invalid operand for instruction
ldp x0, x1, [x2, #thing]
^
t.S:8:15: error: index must be an integer in range [-256, 255].
ldr q0, [x0, #thing]
^
t.S:9:19: error: invalid operand for instruction
ldp q0, q1, [x0, #thing]
^
```
The errors for `ldp` are unhelpfully vague, but the caret position hints
that assembler is objecting to the immediate operand. The `eor` error
is a little unhelpful, but I understand that it's hard to characterize the
acceptable ARM64 logical immediate values. The other messages are
simply incorrect: it's clear that `thing` has the value 16, which is
easily in range.
It doesn't help to float the data definition above the code which
references it (https://gcc.godbolt.org/z/sejn5frx9); nor does it help to
replace the expressions with their literal values
(https://gcc.godbolt.org/z/v9GKnf8b8). However, doing _both_ of these
things is successful (https://gcc.godbolt.org/z/Gjrjc6a7M).
```assembler
.text
.balign 16
base:
.skip 16
thing = 16 // . - base
.skip 16
proc:
movz x0, #thing
add x0, x0, #thing
eor x0, x0, #thing
ldr x0, [x1, #thing]
ldp x0, x1, [x2, #thing]
ldr q0, [x0, #thing]
ldp q0, q1, [x0, #thing]
ret
```
I guess, therefore, that there are at least two underlying bugs:
* the assembler tries to resolve immediate values in the first
pass; and
* the assembler doesn't understand that the difference between two
defined symbols in the same section is a plain integer.
ARM64 is where I tripped over this, but it seems that other targets are
affected also. For example, the ARM32 fragment
```assembler
.text
.arch armv7-a
.fpu neon
proc:
mov r0, #thing
add r0, r0, #thing
eor r0, r0, #thing
ldr r0, [r1, #thing]
ldrd r0, r1, [r2, #thing]
vldr d0, [r0, #thing]
bx r14
.balign 16
base:
.skip 16
thing = . - base
.skip 16
```
is acceptable to GNU as (https://gcc.godbolt.org/z/G454KvrE6) but Clang
objects to the `mov`, `ldrd`, and `vldr` instructions
(https://gcc.godbolt.org/z/es33YqrfM).
GNU as accepts the following (https://gcc.godbolt.org/z/e1fed5vhM)
and produces
as I expect.
Clang rejects this (https://gcc.godbolt.org/z/W8PTq9aqG), reporting
The errors for
ldp
are unhelpfully vague, but the caret position hints that assembler is objecting to the immediate operand. Theeor
error is a little unhelpful, but I understand that it's hard to characterize the acceptable ARM64 logical immediate values. The other messages are simply incorrect: it's clear thatthing
has the value 16, which is easily in range.It doesn't help to float the data definition above the code which references it (https://gcc.godbolt.org/z/sejn5frx9); nor does it help to replace the expressions with their literal values (https://gcc.godbolt.org/z/v9GKnf8b8). However, doing both of these things is successful (https://gcc.godbolt.org/z/Gjrjc6a7M).
I guess, therefore, that there are at least two underlying bugs:
the assembler tries to resolve immediate values in the first pass; and
the assembler doesn't understand that the difference between two defined symbols in the same section is a plain integer.
ARM64 is where I tripped over this, but it seems that other targets are affected also. For example, the ARM32 fragment
is acceptable to GNU as (https://gcc.godbolt.org/z/G454KvrE6) but Clang objects to the
mov
,ldrd
, andvldr
instructions (https://gcc.godbolt.org/z/es33YqrfM).