Bug#800318: gcc-5: [mips,mipsel] regression: miscompilation caused by -fexpensive-optimizations

Andreas Cadhalpun <[email protected]>
Newsgroups gmane.linux.debian.devel.bugs.general,gmane.linux.debian.ports.mips
Message-ID <[email protected]>
Hi Aurelien,

On 28.09.2015 14:48, Aurelien Jarno wrote:
> On 2015-09-27 23:43, Andreas Cadhalpun wrote:
>> A slightly larger test case for mips is compiling ffmpeg...
> 
> It what I did to test if the failure is due to the above changes.
> ffmpeg builds fine with gcc version 5.2.1-17 and -march=mips2
> -mtune=mips32 (instead of the new default -march=mips32r2), and passes
> the testsuite. I'll see if I can isolate a smaller testcase so that we
> can understand the problem.

Attached is a testcase for mips, but it works fine for mipsel.

One more peculiarity I noticed is that adding 'c->A = 1;' to
an unused code path inverts the behavior: It works with
-fexpensive-optimizations, but fails with -fno-expensive-optimizations.

Best regards,
Andreas
main.c (text/x-csrc, 524 B)
#include <inttypes.h>
#include <stdio.h>

typedef struct Context {
    int64_t out;
    int64_t A;
    int64_t B;
    int C;
} Context;

void init_tables(Context *c, int *table, int brightness, int contrast, int saturation);

int main()
{
    Context c = { 0 };
    int table[3] = {104597, 132201, 25675};
    init_tables(&c, table, 0, 65536, 65536);

    fprintf(stderr, "TEST: 0x%"PRIX64"\n", c.out);
    if (c.out == 0x12a15) {
        printf("working\n");
        return 0;
    }
    printf("broken\n");
    return 1;
}
Makefile (text/plain, 600 B)
CFLAGS += -fPIC -O2
LDFLAGS += -shared

all: working broken
	LD_LIBRARY_PATH=. ./working || true
	LD_LIBRARY_PATH=. ./broken || true

working.o:
	$(CC) $(CFLAGS) -fno-expensive-optimizations -c -o working.o test.c

broken.o:
	$(CC) $(CFLAGS) -c -o broken.o test.c

libworking.so: working.o
	$(CC) $(LDFLAGS) -o libworking.so working.o

libbroken.so: broken.o
	$(CC) $(LDFLAGS) -o libbroken.so broken.o

working: libworking.so
	$(CC) -o working main.c -L. -lworking

broken: libbroken.so
	$(CC) -o broken main.c -L. -lbroken

clean:
	rm -f working.o libworking.so working broken.o libbroken.so broken
test.c (text/x-csrc, 3.6 KB)
#include <inttypes.h>

typedef struct Context {
    int64_t out;
    int64_t A;
    int64_t B;
    int C;
} Context;

static uint8_t clip_uint8_c(int a)
{
    if (a&(~0xFF)) return (-a)>>31;
    else return a;
}
static void fill_table(uint8_t* table[256 + 2*256], const int elemsize,
                       const int64_t inc, void *y_tab)
{
    int i;
    uint8_t *y_table = y_tab;
    y_table -= elemsize * (inc >> 9);
    for (i = 0; i < 256 + 2*256; i++) {
        int64_t cb = clip_uint8_c(i-256)*inc;
        table[i] = y_table + elemsize * (cb >> 16);
    }
}
static void fill_gv_table(int table[256 + 2*256], const int elemsize, const int64_t inc)
{
    int i;
    int off = -(inc >> 9);
    for (i = 0; i < 256 + 2*256; i++) {
        int64_t cb = clip_uint8_c(i-256)*inc;
        table[i] = elemsize * (off + (cb >> 16));
    }
}
static uint16_t roundToInt16(int64_t f)
{
    int r = (f + (1 << 15)) >> 16;
    if (r < -0x7FFF)
        return 0x8000;
    else if (r > 0x7FFF)
        return 0x7FFF;
    else
        return r;
}

uint8_t yuvTable[1024];
int table_gV[256 + 2*256];
uint8_t *table_rV[256 + 2*256];
uint8_t *table_gU[256 + 2*256];
uint8_t *table_bU[256 + 2*256];
int64_t loc1;
int64_t loc2;
int64_t loc3;
int loc4;

__attribute__((cold)) void init_tables(Context *c, int *table, int brightness, int contrast, int saturation)
{
    int i;
    const int bpp = c->C;
    const int yoffs = brightness ? 384 : 326;
    int64_t crv = table[0];
    int64_t cbu = table[1];
    int64_t cgu = -table[0];
    int64_t cgv = -table[2];
    int64_t cy = 1 << 16;
    int64_t TEST = 1 << 16;
    int64_t oy = 0;
    int64_t yb = 0;
    if (!brightness) {
        cy = (cy * 255) / 219;
        TEST = (TEST * 255) / 219;
        oy = 16 << 16;
    } else {
        crv = (crv * 224) / 255;
        cbu = (cbu * 224) / 255;
        cgu = (cgu * 224) / 255;
        cgv = (cgv * 224) / 255;
    }
    cy = (cy * contrast) >> 16;
//    c->out = TEST;
    TEST = (TEST * contrast) >> 16;
    c->out = TEST;

    crv = (crv * contrast * saturation) >> 32;
    cbu = (cbu * contrast * saturation) >> 32;
    cgu = (cgu * contrast * saturation) >> 32;
    cgv = (cgv * contrast * saturation) >> 32;
    oy -= 256 * brightness;
    c->A = 1;
    c->B = roundToInt16(cy * 8192) + roundToInt16(crv * 8192);
    loc1 = roundToInt16(cgv * 8192);
    loc2 = roundToInt16(cgu * 8192);
    loc3 = roundToInt16(oy * 8);
    loc4 = roundToInt16(cy << 13) + roundToInt16(oy) + roundToInt16(crv << 13) 
           + roundToInt16(cgv << 13) + roundToInt16(cgu << 13) + roundToInt16(cbu << 13);
    crv = ((crv << 16) + 0x8000) / ((cy) > (1) ? (cy) : (1));
    cbu = ((cbu << 16) + 0x8000) / ((cy) > (1) ? (cy) : (1));
    cgu = ((cgu << 16) + 0x8000) / ((cy) > (1) ? (cy) : (1));
    cgv = ((cgv << 16) + 0x8000) / ((cy) > (1) ? (cy) : (1));
    switch (bpp) {
    case 0:
        yb = -(384 << 16) - oy;
        for (i = 0; i < 1024; i++) {
            yuvTable[i] = clip_uint8_c(yb >> 16);
            yb += cy;
        }
        fill_table(table_rV, 1, crv, yuvTable);
        fill_table(table_gU, 1, cgu, yuvTable);
        fill_table(table_bU, 1, cbu, yuvTable);
        fill_gv_table(table_gV, 1, cgv);
        break;
    case 1:
        yb = -(384 << 16) - oy;
        for (i = 0; i < 1024; i++) {
            yuvTable[i] = clip_uint8_c(yb >> 16);
            yb += cy;
        }
//        c->A = 1; // uncomment to change broken/working
        fill_table(table_rV, 1, crv, yuvTable);
        fill_table(table_gU, 1, cgu, yuvTable);
        fill_table(table_bU, 1, cbu, yuvTable + yoffs);
        fill_gv_table(table_gV, 1, cgv);
        break;
    }
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.