Bug 27075 - [MIPS] Gas adds useless delay-slot nops to r6 compact branches, which have no delay slots
Summary: [MIPS] Gas adds useless delay-slot nops to r6 compact branches, which have no...
Status: RESOLVED NOTABUG
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.35
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-12-15 19:21 UTC by Luca Saiu
Modified: 2022-06-22 06:29 UTC (History)
1 user (show)

See Also:
Host: mips-unknown-linux-gnu (mips32r6)
Target:
Build: x86_64-unknown-linux-gnu
Last reconfirmed:


Attachments
interaction showing my test case and the tool output (1.13 KB, text/plain)
2020-12-15 19:21 UTC, Luca Saiu
Details
test case (580 bytes, text/plain)
2020-12-15 19:25 UTC, Luca Saiu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Luca Saiu 2020-12-15 19:21:23 UTC
Created attachment 13052 [details]
interaction showing my test case and the tool output

While adding support for MIPS release 6 to my software I noticed a
bizarre behaviour related to compact branch instructions, in particular
conditionals.

Gas adds a useless nop instruction (sll $0,$0,0x0) after most but not
all compact branches, unless the instruction following the branch looks
like a "plausible" delay-slot instructions (more details in the test
case).

For example, this:

        .set arch=mips32r6
foo:
        bnezc $3, foo
        bltzc $3, foo
        bgtzc $3, foo
        blezc $3, foo
        bgezc $3, foo


disassembles to:

00000000 <foo>:
   0:	f87fffff 	bnezc	$3,0 <foo>
   4:	00000000 	sll	$0,$0,0x0
   8:	5c63fffd 	bltzc	$3,0 <foo>
   c:	00000000 	sll	$0,$0,0x0
  10:	5c03fffb 	bgtzc	$3,0 <foo>
  14:	00000000 	sll	$0,$0,0x0
  18:	5803fff9 	blezc	$3,0 <foo>
  1c:	00000000 	sll	$0,$0,0x0
  20:	5863fff7 	bgezc	$3,0 <foo>
	...

This, while not technically assembling incorrect code, does not make
sense: the instruction following the compact branch is *not* executed
when the branch is taken, which is the entire point of compact branches.
This should be independent from what instruction follows the branch,
since at least as far as I understand there is no restriction on what
instructions are allowed in that position.

The balc instruction is not affected.
The bc instruction is not affected.
The jalrc instruction is not affected.
The jic instruction is not affected.

Every conditional compact branch I have tried *is* affected.  I have not
tested the linking versions, but on the other hand every conditional
branch seems affected: on zero, on sign, on magnitude.  This includes
for example beqzc, bltzc, bgtzc, bltc.

I am using inline asm from GNU C, from which it is not practical to work
around the misbehaviour with
  .set noreorder
, since the last instruction before I switch back to
  .set reorder
will be "completed" with a useless nop, unless the following instruction
appears to be suitable to fill the (not actually existing) delay slot.

I am attaching a distilled test case along with what the tools show me.

Tested with Binutils 2.35.1 (on a cross configuration to big-endian
32-bit MIPS), compiled with crosstool but using stock source tarballs
downloaded from ftp.gnu.org, with no patches.

Binutils 2.35.1, compiled via crosstool-ng with no patches:
m6[luca@moore ~/repos/jitter/_build/cross-mips32r6]$ mips-unknown-linux-gnu-as --version
GNU assembler (crosstool-NG 1.23.0.942_5fbcd4b) 2.35.1
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `mips-unknown-linux-gnu'.

m6[luca@moore ~/repos/jitter/_build/cross-mips32r6]$ mips-unknown-linux-gnu-gcc --version
mips-unknown-linux-gnu-gcc (crosstool-NG 1.23.0.942_5fbcd4b) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

m6[luca@moore ~/repos/jitter/_build/cross-mips32r6]$ mips-unknown-linux-gnu-gcc -v -c testcase-beqzc.s
Using built-in specs.
COLLECT_GCC=mips-unknown-linux-gnu-gcc
Target: mips-unknown-linux-gnu
Configured with: /home/luca/cross-scratch/mips32r6/.build/mips-unknown-linux-gnu/src/gcc/configure --build=x86_64-build_pc-linux-gnu --host=x86_64-build_pc-linux-gnu --target=mips-unknown-linux-gnu --prefix=/home/luca/usr-cross-mips32r6 --with-sysroot=/home/luca/usr-cross-mips32r6/mips-unknown-linux-gnu/sysroot --enable-languages=c,c++ --with-arch=mips32r6 --with-abi=32 --with-float=hard --with-pkgversion='crosstool-NG 1.23.0.942_5fbcd4b' --enable-__cxa_atexit --disable-libmudflap --disable-libgomp --disable-libssp --disable-libquadmath --disable-libquadmath-support --disable-libsanitizer --disable-libmpx --with-gmp=/home/luca/cross-scratch/mips32r6/.build/mips-unknown-linux-gnu/buildtools --with-mpfr=/home/luca/cross-scratch/mips32r6/.build/mips-unknown-linux-gnu/buildtools --with-mpc=/home/luca/cross-scratch/mips32r6/.build/mips-unknown-linux-gnu/buildtools --with-isl=/home/luca/cross-scratch/mips32r6/.build/mips-unknown-linux-gnu/buildtools --disable-lto --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --enable-threads=posix --enable-target-optspace --enable-plugin --disable-nls --disable-multilib --with-local-prefix=/home/luca/usr-cross-mips32r6/mips-unknown-linux-gnu/sysroot --enable-long-long
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (crosstool-NG 1.23.0.942_5fbcd4b) 
COLLECT_GCC_OPTIONS='-v' '-c' '-march=mips32r6' '-mabi=32' '-mhard-float' '-mllsc' '-mips32r6' '-mnan=2008' '-mno-shared' '-EB'
 /home/luca/usr-cross-mips32r6/lib/gcc/mips-unknown-linux-gnu/10.2.0/../../../../mips-unknown-linux-gnu/bin/as -v -EB -mips32r6 -O1 -mabi=32 -march=mips32r6 -mnan=2008 -mno-shared -mhard-float -KPIC -o testcase-beqzc.o testcase-beqzc.s
GNU assembler version 2.35.1 (mips-unknown-linux-gnu) using BFD version (crosstool-NG 1.23.0.942_5fbcd4b) 2.35.1
COMPILER_PATH=/home/luca/usr-cross-mips32r6/libexec/gcc/mips-unknown-linux-gnu/10.2.0/:/home/luca/usr-cross-mips32r6/libexec/gcc/mips-unknown-linux-gnu/10.2.0/:/home/luca/usr-cross-mips32r6/libexec/gcc/mips-unknown-linux-gnu/:/home/luca/usr-cross-mips32r6/lib/gcc/mips-unknown-linux-gnu/10.2.0/:/home/luca/usr-cross-mips32r6/lib/gcc/mips-unknown-linux-gnu/:/home/luca/usr-cross-mips32r6/lib/gcc/mips-unknown-linux-gnu/10.2.0/../../../../mips-unknown-linux-gnu/bin/
LIBRARY_PATH=/home/luca/usr-cross-mips32r6/lib/gcc/mips-unknown-linux-gnu/10.2.0/:/home/luca/usr-cross-mips32r6/lib/gcc/mips-unknown-linux-gnu/10.2.0/../../../../mips-unknown-linux-gnu/lib/:/home/luca/usr-cross-mips32r6/mips-unknown-linux-gnu/sysroot/lib/:/home/luca/usr-cross-mips32r6/mips-unknown-linux-gnu/sysroot/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-c' '-march=mips32r6' '-mabi=32' '-mhard-float' '-mllsc' '-mips32r6' '-mnan=2008' '-mno-shared' '-EB'

Thank you very much for your work on the Binutils.
Best regards,

-- 
Luca Saiu
* My personal web site:  http://ageinghacker.net
* Jitter:                http://ageinghacker.net/projects/jitter
* GNU epsilon:           http://www.gnu.org/software/epsilon

I support everyone's freedom of mocking any opinion or belief, no
matter how deeply held, with open disrespect and the same unrelented
enthusiasm of a toddler who has just learned the word "poo".
Comment 1 Luca Saiu 2020-12-15 19:22:31 UTC
On 2020-12-15 at 18:03 +0100, Luca Saiu wrote:

> This, while not technically assembling incorrect code, does not make
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

One more remark: I was not able to reproduce this behaviour with compact
branches, but it is possible that in some cases Gas' rewrite machinery
might actually move a previous instruction past the branch instead of
inserting a nop.  That would in fact be incorrect code with compact
branches.

For example (using a traditional MIPS branch with delay slot) this:

        addu  $10, $11, $12
        beq   $13, $14, foo

may turn into:

   0:	11aeffff 	beq	$13,$14,0x0
   4:	016c5021 	addu	$10,$11,$12

If that happened with compact branches it would be a disaster.
Comment 2 Luca Saiu 2020-12-15 19:25:10 UTC
Created attachment 13053 [details]
test case
Comment 3 Luca Saiu 2020-12-15 19:51:03 UTC
I wrote:
> This should be independent from what instruction follows the branch,
> since at least as far as I understand there is no restriction on what
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> instructions are allowed in that position.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Reading the specification again I noticed that I was wrong: r6 forbidden slots.
Gas' behavior is correct, also with respect to unconditional branches requiring no special treatment.  I apologise for the noise.

-- 
Luca Saiu
Comment 4 Luca Saiu 2020-12-15 19:53:26 UTC
Gas' behaviour is in fact correct: it avoids some instructions, such as other branches, in r6 forbidden slots.  Unconditional branches have no forbidden slots.