lb and lbu commands accepts 16-bit signed offsets. But GAS accepts larger offsets for these commands. If an offset does not fit in 16-bit range, lb command is translated into lui/lb or lui/addu/lb series. It's interesting that initially LLVM assembler supported this feature, but later it was broken.
This patch restores support for 32-bit offsets. It replaces mem_simm16 operand for LB and LBu definitions by the new mem_simmptr operand. This operand is intended to check that offset fits to the same size as using for pointers. Later we will be able to extend this rule and accepts 64-bit offsets when it is possible.
Some issues remain:
- The regression also affects LD, SD, LH, LHU commands. I'm going to fix them by a separate patch.
- GAS accepts any 32-bit values as an offset. Now LLVM accepts signed 16-bit values and this patch extends the range to signed 32-bit offsets. In other words, the following code accepted by GAS and still triggers an error by LLVM:
lb $4, 0x80000004 # gas lui a0, 0x8000 lb a0, 4(a0)
- In case of 64-bit pointers GAS accepts a 64-bit offset and translates it to the li/dsll/lb series of commands. LLVM still rejects it. Probably this feature has never been implemented in LVVM. This issue is for a separate patch.
lb $4, 0x800000001 # gas li a0, 0x8000 dsll a0, a0, 0x14 lb a0, 4(a0)