riscv-software-src / riscv-tools

RISC-V Tools (ISA Simulator and Tests)
1.13k stars 446 forks source link

gcc/as not accepting 6 bits immediate for c.lui ?? #182

Open aprnath opened 6 years ago

aprnath commented 6 years ago

Per the spec:

C.LUI loads the non-zero 6-bit immediate field into bits 17–12 of the destination register, clears the bottom 12 bits, and sign-extends bit 17 into all higher bits of the destination. C.LUI is only valid when rd̸={x0, x2}, and when the immediate is not equal to zero. C.LUI expands into lui rd, nzuimm[17:12].

However the assembler flags any case with the 6th bit set as illegal: The following assemble OK:

c.lui x4, 1<<4 
c.lui x4, 31

The following do not assemble:

 c.lui x4, 1<<5 
 c.lui x4, 32
lui.s:4: Error: illegal operands `c.lui x4,1<<5'
lui.s:5: Error: illegal operands `c.lui x4,32'

Is this a known issue?

aswaterman commented 6 years ago

It's a signed immediate, so the valid values are -32 to +31.

aprnath commented 6 years ago

lui.s:4: Error: illegal operandsc.lui x4,-32'`

aswaterman commented 6 years ago

Oops, I forgot the assembler wants nonnegative immediates for LUI. In the mean time, here are three ways to get the desired effect, with the first being by far the best option:

.option rvc

li a0, -1 << 17
c.lui a0, (1<<20) - 32
lui a0, (1<<20) - 32
aswaterman commented 6 years ago

@jim-wilson We can either declare this is how it's supposed to work, or maybe change the assembler so c.lui can accept -32 through -1. I don't think it's a big deal either way, since when hand-writing assembly, it's preferable to just write li and let the assembler choose between addi, lui, c.li, c.lui, etc.

jim-wilson commented 6 years ago

I think there is a potential ambiguity with negative numbers. If we accept -1, then we are also accepting 0xffffffff on a 32-bit host for a 32-bit target, but not on a 64-bit host or for a 64-bit target, and this could be confusing. I think we'd have to be consistent and treat it as a signed or unsigned value always, and if we change this, then we potentially break code that currently relies on the fact that these values are treated as unsigned. I'd have to spend some time studying the issue to figure out it there are any serious risks here.

What happens if someone types "lui 0xffffffff" when they meant to type "li 0xffffffff"? If we accept -1, then it assembles without error and gives an unexpected result. Currently, it is an assembler error, because they specified 32-bits, and lui can only load 20 bits.

Here is another option that works .option rvc c.lui a0, 0xfffe0

aswaterman commented 6 years ago

We certainly shouldn't do anything that breaks existing code, and accepting both [-32, -1] and [0xfffe0, 0x 0xfffff] seems very weird. I lean towards the no-change option.

jim-wilson commented 6 years ago

Another factor to consider here is that c.lui a0, 0xfffe0 is much more user friendly than c.lui a0, -32 It is trivial for a human reading/writing assembly code to figure out what the first instruction does, but the second one requires some arithmetic, which humans aren't very good at. I think that is the best reason to leave things alone.

Instruction encodings and assembly syntax are different issues, with different concerns, and hence assembly syntax doesn't always directly follow from the instruction encodings.

I think the only problem here is lack of assembler documentation to fully explain the assembler syntax. We have a number of other issues asking for better assembler documentation. Someday we need to write a real assembly language manual.