https://gcc.gnu.org/bugzilla/show_bug.cgi?id=74563

            Bug ID: 74563
           Summary: [5 regression] Classic MIPS16 (non-MIPS16e) function
                    return broken
           Product: gcc
           Version: 6.1.1
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ma...@linux-mips.org
                CC: matthew.fortune at imgtec dot com
  Target Milestone: ---
            Target: mips-mti-linux-gnu

This is a regression from GCC 5, present in GCC 6 and in current trunk.

Non-leaf classic MIPS16 (non-MIPS16e) function epilogue uses $7 as the
return register, because there is no hardware instruction available to
load $31 directly from the stack.  This used to work up to GCC 5, but
now function epilogue still loads $7 with the return address, however
it then uses JR $31 to attempt a function return.  This obviously
cannot work as in a non-leaf function typically $31 does not hold the
return address anymore.

To reproduce this simple program can be used:

$ cat jal16.c
void f2(void);

void f1(void)
{
        f2();
}
$ gcc -mips1 -mips16 -O2 -S jal16.c
$ cat jal16.s

With GCC 5 I get this correct result:

        .file   1 "jal16.c"
        .section .mdebug.abi32
        .previous
        .nan    legacy
        .module fp=32
        .module nooddspreg
        .abicalls
        .option pic0
        .text
        .align  2
        .globl  f1
        .set    mips16
        .set    nomicromips
        .ent    f1
        .type   f1, @function
f1:
        .frame  $sp,32,$31              # vars= 0, regs= 1/0, args= 16, gp= 8
        .mask   0x80000000,-4
        .fmask  0x00000000,0
        addiu   $sp,-32
        sw      $31,28($sp)
        jal     f2
        lw      $7,28($sp)
        .set    noreorder
        .set    nomacro
        j       $7
        addiu   $sp,32
        .set    macro
        .set    reorder

        .end    f1
        .size   f1, .-f1
        .ident  "GCC: (GNU) 5.4.1 20160810"

With GCC 6 I get this bad one instead:

        .file   1 "jal16.c"
        .section .mdebug.abi32
        .previous
        .nan    legacy
        .module fp=32
        .module nooddspreg
        .abicalls
        .option pic0
        .text
        .align  2
        .globl  f1
        .set    mips16
        .set    nomicromips
        .ent    f1
        .type   f1, @function
f1:
        .frame  $sp,32,$31              # vars= 0, regs= 1/0, args= 16, gp= 8
        .mask   0x80000000,-4
        .fmask  0x00000000,0
        addiu   $sp,-32
        sw      $31,28($sp)
        jal     f2
        lw      $7,28($sp)
        .set    noreorder
        .set    nomacro
        jr      $31
        addiu   $sp,32
        .set    macro
        .set    reorder

        .end    f1
        .size   f1, .-f1
        .ident  "GCC: (GNU) 6.1.1 20160810"

Notice the difference:

--- jal16-gcc5.s        2016-08-11 14:22:24.996749000 +0100
+++ jal16-gcc6.s        2016-08-11 18:59:38.472543000 +0100
@@ -23,11 +23,11 @@
        lw      $7,28($sp)
        .set    noreorder
        .set    nomacro
-       j       $7
+       jr      $31
        addiu   $sp,32
        .set    macro
        .set    reorder

        .end    f1
        .size   f1, .-f1
-       .ident  "GCC: (GNU) 5.4.1 20160810"
+       .ident  "GCC: (GNU) 6.1.1 20160810"

This is a fatal bug making the MIPS16 compiler unusable and therefore
requiring hightened attention, although only affecting an ISA level
which is not as important these days anymore, so setting severity to
major rather than critical/blocker.

Reply via email to