Bug 85344 - Constant constraint check sign extends unsigned constant input operands
Summary: Constant constraint check sign extends unsigned constant input operands
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 8.0.1
: P3 normal
Target Milestone: ---
Assignee: Thomas Preud'homme
URL:
Keywords: ice-on-valid-code, wrong-code
Depends on:
Blocks:
 
Reported: 2018-04-11 11:57 UTC by Thomas Preud'homme
Modified: 2018-04-13 22:08 UTC (History)
0 users

See Also:
Host:
Target: arm-none-eabi
Build:
Known to work:
Known to fail: 6.4.1, 7.3.1, 8.0.1
Last reconfirmed: 2018-04-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Preud'homme 2018-04-11 11:57:05 UTC
Hi,

Compiling the following piece of code with -mthumb -mcpu=cortex-m0 generates an "impossible constraint in 'asm' error"

void
foo (void)
{
  __asm( "%0" :: "I" ((unsigned char) 0x80));
}

It appears that although the operand is unsigned, it gets sign extended to perform the constraint check.
Comment 1 Thomas Preud'homme 2018-04-11 12:01:51 UTC
It believe that the problem is in expand_asm_stmt (). The code calls into expand for the operand which will create a const_int of -128 with the assumption that an outer RTX will tell how to interpret that constant (eg. zero_extend:SI (const_int -128)). However the code uses that value directly calling INTVAL on it. It should instead extend it according to the signedness of the operand so that INTVAL returns the initial value.
Comment 2 Thomas Preud'homme 2018-04-11 12:14:53 UTC
I have a patch, starting testing.
Comment 3 Thomas Preud'homme 2018-04-11 12:26:55 UTC
More worrying is that this code compiles without error when it should error out:

void
foo (void)
{
  __asm( "%0" :: "J" ((unsigned char) 0x80));
}
Comment 4 Thomas Preud'homme 2018-04-11 12:28:10 UTC
(In reply to Thomas Preud'homme from comment #3)
> More worrying is that this code compiles without error when it should error
> out:
> 
> void
> foo (void)
> {
>   __asm( "%0" :: "J" ((unsigned char) 0x80));
> }

In which case we end up with #-128 in the assembly which is not what the user wrote. Thus adding wrong-code tag.
Comment 5 Thomas Preud'homme 2018-04-13 22:08:11 UTC
(In reply to Thomas Preud'homme from comment #4)
> (In reply to Thomas Preud'homme from comment #3)
> > More worrying is that this code compiles without error when it should error
> > out:
> > 
> > void
> > foo (void)
> > {
> >   __asm( "%0" :: "J" ((unsigned char) 0x80));
> > }
> 
> In which case we end up with #-128 in the assembly which is not what the
> user wrote. Thus adding wrong-code tag.

I have difficulty to make up my mind about what is the expected behavior for constant input in inline asm, esp. for immediate constraint. But first let's look at register constraint:

asm ("mov %0, %0" : "=r"(result) : "0"((signed char) -128));

will put 0x00000080 in the register holding result. It basically set the register in the mode of the immediate, so QImode here. I would have expected for a 32bit register to have the immediate as 2-complement 32bit value, ie 0xFFFFFF80 in this case. The documentation says that a general register should be used which is true in both case.

Now what about asm ("%0" :: "i"((unsigned char) 128));

This gives -128 in the assembly code, on at least ARM and x86_64 targets but I would expect likewise on all targets. Likewise:

asm ("%0" :: "i"(0x80000000));

gives #-2147483648 in assembly for the similar reason. Here my expectation is that provided that the constant can be represented in a const_int its value as a C level constant is what should be printed in assembly and the constraint check (eg for constraint I in ARM backend) should be based on that value as well.

Thoughts?