Bug 52408 - Incorrect assembler generated for zvdep_imm64
Summary: Incorrect assembler generated for zvdep_imm64
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.6.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-28 03:43 UTC by John David Anglin
Modified: 2012-03-04 21:41 UTC (History)
1 user (show)

See Also:
Host: hppa64-*-*
Target: hppa64-*-*
Build: hppa64-*-*
Known to work:
Known to fail:
Last reconfirmed:


Attachments
pa.md.d (410 bytes, patch)
2012-02-29 01:44 UTC, dave.anglin
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description John David Anglin 2012-02-28 03:43:32 UTC
Created attachment 26776 [details]
pa.md.d

The following testcase is miscompiled at -O1:

typedef unsigned long long loff_t;
typedef unsigned long long blkcnt_t;
typedef unsigned long long u64;
#define MAX_LFS_FILESIZE        0x7fffffffffffffffULL

loff_t ext4_max_size(int blkbits, int has_huge_files)
{
	loff_t res;
	loff_t upper_limit = MAX_LFS_FILESIZE;

	if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
		upper_limit = (1LL << 32) - 1;

		upper_limit >>= (blkbits - 9);
		upper_limit <<= blkbits;
	}

	res = (1LL << 32) - 1;
	res <<= blkbits;

	if (res > upper_limit)
		res = upper_limit;

	return res;
}

int main(void)
{
	printf("res = 0x%lx\n", ext4_max_size(12, 0));
	return 0;
}

Wrong code is generated for the "res <<= blkbits;" operation.
We have the following rtl:

(insn 27 26 65 (set (reg/v:DI 31 %r31 [orig:71 res ] [71])
        (ashift:DI (const_int 4294967295 [0xffffffff])
            (minus:DI (const_int 63 [0x3f])
                (reg:DI 60 SAR [82])))) ext4.c:21 230 {zvdep_imm64}
     (expr_list:REG_DEAD (reg:DI 60 SAR [82])
        (expr_list:REG_EQUAL (ashift:DI (const_int 4294967295 [0xffffffff])
                (reg/v:DI 31 %r31 [orig:75 blkbits+-4 ] [75]))
            (nil))))

The pattern for zvdep_imm64 is:

(define_insn "zvdep_imm64"
  [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (match_operand:DI 1 "lhs_lshift_cint_operand" "")
                   (minus:DI (const_int 63)
                             (match_operand:DI 2 "register_operand" "q"))))]
  "TARGET_64BIT"
  "*
{
  int x = INTVAL (operands[1]);
  operands[2] = GEN_INT (4 + exact_log2 ((x >> 4) + 1));
  operands[1] = GEN_INT ((x & 0x1f) - 0x20);
  return \"depdi,z %1,%%sar,%2,%0\";
}"
  [(set_attr "type" "shift")
   (set_attr "length" "4")])

The lhs_lshift_cint_operand predicate allows the unsigned long long
value 0xffffffff, but it is truncated when assigned to x. As a result,
the call to exact_log2 fails and returns -1.  This results in the following
incorrect instruction:

       depdi,z -1,%sar,3,%r31
 
There appear to be a few more instances with the same problem...

The problem has been present for years and affects all active versions.
Comment 1 dave.anglin 2012-02-29 01:44:09 UTC
Attached is patch which I am testing.

--
John David Anglin	dave.anglin@bell.net
Comment 2 John David Anglin 2012-03-01 19:31:16 UTC
Author: danglin
Date: Thu Mar  1 19:31:03 2012
New Revision: 184757

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184757
Log:
	PR target/52408
	* config/pa/pa.md (zvdep_imm32): Change type of variable x from int to
	unsigned HOST_WIDE_INT.
	(zvdep_imm64): Likewise.
	(vdepi_ior): Change type of variable x from int to HOST_WIDE_INT.
	(vdepi_and): Likewise.
	Likewise for unamed 64-bit patterns.
	* config/pa/predicates.md (lhs_lshift_cint_operand): Update comment.


Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/pa/pa.md
    trunk/gcc/config/pa/predicates.md
Comment 3 John David Anglin 2012-03-04 16:23:39 UTC
Author: danglin
Date: Sun Mar  4 16:23:26 2012
New Revision: 184888

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184888
Log:
	Backport from mainline
	2012-03-01  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>

	PR target/52408
	* config/pa/pa.md (zvdep_imm32): Change type of variable x from int to
	unsigned HOST_WIDE_INT.
	(zvdep_imm64): Likewise.
	(vdepi_ior): Change type of variable x from int to HOST_WIDE_INT.
	(vdepi_and): Likewise.
	Likewise for unamed 64-bit patterns.
	* config/pa/predicates.md (lhs_lshift_cint_operand): Update comment.


Modified:
    branches/gcc-4_6-branch/gcc/ChangeLog
    branches/gcc-4_6-branch/gcc/config/pa/pa.md
    branches/gcc-4_6-branch/gcc/config/pa/predicates.md
Comment 4 John David Anglin 2012-03-04 17:17:18 UTC
Author: danglin
Date: Sun Mar  4 17:17:11 2012
New Revision: 184889

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184889
Log:
	Backport from mainline
	2012-03-01  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>

	PR target/52408
	* config/pa/pa.md (zvdep_imm32): Change type of variable x from int to
	unsigned HOST_WIDE_INT.
	(zvdep_imm64): Likewise.
	(vdepi_ior): Change type of variable x from int to HOST_WIDE_INT.
	(vdepi_and): Likewise.
	Likewise for unamed 64-bit patterns.
	* config/pa/predicates.md (lhs_lshift_cint_operand): Update comment.


Modified:
    branches/gcc-4_4-branch/gcc/ChangeLog
    branches/gcc-4_4-branch/gcc/config/pa/pa.md
    branches/gcc-4_4-branch/gcc/config/pa/predicates.md
Comment 5 John David Anglin 2012-03-04 21:31:29 UTC
Author: danglin
Date: Sun Mar  4 21:31:25 2012
New Revision: 184902

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184902
Log:
	Backport from mainline
	2012-03-01  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>

	PR target/52408
	* config/pa/pa.md (zvdep_imm32): Change type of variable x from int to
	unsigned HOST_WIDE_INT.
	(zvdep_imm64): Likewise.
	(vdepi_ior): Change type of variable x from int to HOST_WIDE_INT.
	(vdepi_and): Likewise.
	Likewise for unamed 64-bit patterns.
	* config/pa/predicates.md (lhs_lshift_cint_operand): Update comment.


Modified:
    branches/gcc-4_5-branch/gcc/ChangeLog
    branches/gcc-4_5-branch/gcc/config/pa/pa.md
    branches/gcc-4_5-branch/gcc/config/pa/predicates.md
Comment 6 John David Anglin 2012-03-04 21:41:57 UTC
Fixed.