Bug 64718 - [5 Regression] Bad 16-bit bswap replacement
Summary: [5 Regression] Bad 16-bit bswap replacement
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 5.0
: P1 normal
Target Milestone: 5.0
Assignee: Thomas Preud'homme
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-01-21 17:42 UTC by Andrey Zholos
Modified: 2015-02-05 10:09 UTC (History)
3 users (show)

See Also:
Host:
Target: x86
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-01-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Zholos 2015-01-21 17:42:35 UTC
This code is reduced from htons((int)port) on FreeBSD.

The expression gets replaced with a rotation in a 32-bit register
instead of a 16-bit register, so the upper byte is lost.

int swap(int x) {
    return (unsigned short)((unsigned short)x << 8 | (unsigned short)x >> 8);
}

gcc -O2 -S swap.c

swap:
        movl    4(%esp), %eax
        roll    $8, %eax       # should be %ax
        movzwl  %ax, %eax
        ret


Complete program:

#include <stdio.h>

int swap(int x) {
    return (unsigned short)((unsigned short)x << 8 | (unsigned short)x >> 8);
}

int a = 0x1234;
int main() {
    int b = 0x1234;
    printf("%x -> %x\n", a, swap(a));
    printf("%x -> %x\n", b, swap(b));
}

gcc -O2 swap.c && ./a.out

1234 -> 3400
1234 -> 3412
Comment 1 H.J. Lu 2015-01-21 19:47:19 UTC
It is caused by r219256.
Comment 2 H.J. Lu 2015-01-21 19:48:19 UTC
A run-time testcase:

[hjl@gnu-mic-2 gcc-regression]$ cat pr64718.c
int
__attribute__ ((noinline, noclone))
swap(int x)
{
  return (unsigned short)((unsigned short)x << 8 | (unsigned short)x >> 8);
}

int a = 0x1234;

int
main()
{
  int b = 0x1234;
  if (swap (a) != 0x3412)
    __builtin_abort ();
  if (swap (b) != 0x3412)
    __builtin_abort ();
  return 0;
}
[hjl@gnu-mic-2 gcc-regression]$
Comment 3 H.J. Lu 2015-01-21 19:51:31 UTC
Also happens on x86-64.
Comment 4 Thomas Preud'homme 2015-01-22 05:56:41 UTC
The problem comes from:

bswap_type = TREE_TYPE (src); in bswap_replace when dealing with 16-bit bswap. I got a fix for that and testing is underway. Thanks for the testcase.

Best regards.
Comment 5 Thomas Preud'homme 2015-01-28 10:20:51 UTC
Author: thopre01
Date: Wed Jan 28 10:20:19 2015
New Revision: 220203

URL: https://gcc.gnu.org/viewcvs?rev=220203&root=gcc&view=rev
Log:
2015-01-28  Thomas Preud'homme  <thomas.preudhomme@arm.com>

    gcc/
    PR tree-optimization/64718
    * tree-ssa-math-opts.c (pass_optimize_bswap::execute): Make bswap_type
    be a 16bit unsigned integer when n->range is 16.
    (bswap_replace): Convert src to that type if necessary for all bswap
    sizes.  Fix rotation right notation in nearby comment.  Use bswap_type
    set in pass_optimize_bswap::execute ().

    gcc/testsuite/
    PR tree-optimization/64718
    * gcc.c-torture/execute/pr64718.c: New test.

Added:
    trunk/gcc/testsuite/gcc.c-torture/execute/pr64718.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-ssa-math-opts.c
Comment 6 Jakub Jelinek 2015-02-05 10:09:26 UTC
Fixed.