From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by sourceware.org (Postfix) with ESMTPS id 2FE313858D28 for ; Tue, 17 Jan 2023 11:04:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2FE313858D28 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 156D66853E; Tue, 17 Jan 2023 11:04:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1673953464; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Ez/qOlGjX0Hs9DOzSDebB8Rm7UEso1noG08Z+qsfgCY=; b=DZ2QSi5IC3Gy9u4ubfcKsvpyEQ7ooxUsAgm6096TwqDEp509JJtI01F5mIMy1cnsI+rC7y IKZ7E8POsF8li0WMaM8qObsOlddK7JhmFtj/QCmnDyd7Iy7IwVRYq1yNa9B1+u/AN/qN7q D4F69a14+PYZc//LLTkrivSqIQz3/gY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1673953464; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Ez/qOlGjX0Hs9DOzSDebB8Rm7UEso1noG08Z+qsfgCY=; b=MVhubPr8a/ALbwEBx6zIPspVV7FhelslWjaPOymAU0ewlc/PXqLYt1ClvzEHnyu8KRZO8x D9vZof5cyupikmDg== Received: from wotan.suse.de (wotan.suse.de [10.160.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 026252C141; Tue, 17 Jan 2023 11:04:24 +0000 (UTC) Date: Tue, 17 Jan 2023 11:04:23 +0000 (UTC) From: Richard Biener To: Jakub Jelinek cc: Aldy Hernandez , Andrew MacLeod , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] forwprop: Fix up rotate pattern matching [PR106523] In-Reply-To: Message-ID: References: User-Agent: Alpine 2.22 (LSU 394 2020-01-19) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-5.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Tue, 17 Jan 2023, Jakub Jelinek wrote: > Hi! > > The comment above simplify_rotate roughly describes what patterns > are matched into what: > We are looking for X with unsigned type T with bitsize B, OP being > +, | or ^, some type T2 wider than T. For: > (X << CNT1) OP (X >> CNT2) iff CNT1 + CNT2 == B > ((T) ((T2) X << CNT1)) OP ((T) ((T2) X >> CNT2)) iff CNT1 + CNT2 == B > > transform these into: > X r<< CNT1 > > Or for: > (X << Y) OP (X >> (B - Y)) > (X << (int) Y) OP (X >> (int) (B - Y)) > ((T) ((T2) X << Y)) OP ((T) ((T2) X >> (B - Y))) > ((T) ((T2) X << (int) Y)) OP ((T) ((T2) X >> (int) (B - Y))) > (X << Y) | (X >> ((-Y) & (B - 1))) > (X << (int) Y) | (X >> (int) ((-Y) & (B - 1))) > ((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1)))) > ((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1)))) > > transform these into (last 2 only if ranger can prove Y < B): > X r<< Y > > Or for: > (X << (Y & (B - 1))) | (X >> ((-Y) & (B - 1))) > (X << (int) (Y & (B - 1))) | (X >> (int) ((-Y) & (B - 1))) > ((T) ((T2) X << (Y & (B - 1)))) | ((T) ((T2) X >> ((-Y) & (B - 1)))) > ((T) ((T2) X << (int) (Y & (B - 1)))) \ > | ((T) ((T2) X >> (int) ((-Y) & (B - 1)))) > > transform these into: > X r<< (Y & (B - 1)) > The following testcase shows that 2 of these are problematic. > If T2 is wider than T, then the 2 which yse (-Y) & (B - 1) on one > of the shift counts but Y on the can do something different from > rotate. E.g.: > __attribute__((noipa)) unsigned char > f7 (unsigned char x, unsigned int y) > { > unsigned int t = x; > return (t << y) | (t >> ((-y) & 7)); > } > if y is [0, 7], then it is a normal rotate, and if y is in [32, ~0U] > then it is UB, but for y in [9, 31] the left shift in this case > will never leave any bits in the result, while in a rotate they are > left there. Say for y 5 and x 0xaa the expression gives > 0x55 which is the same thing as rotate, while for y 19 and x 0xaa > 0x5, which is different. > Now, I believe the > ((T) ((T2) X << Y)) OP ((T) ((T2) X >> (B - Y))) > ((T) ((T2) X << (int) Y)) OP ((T) ((T2) X >> (int) (B - Y))) > forms are ok, because B - Y still needs to be a valid shift count, > and if Y > B then B - Y should be either negative or very large > positive (for unsigned types). > And similarly the last 2 cases above which use & (B - 1) on both > shift operands are definitely ok. > > The following patch disables the > ((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1)))) > ((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1)))) > unless ranger says Y is not in [B, B2 - 1] range. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk > (for now)? OK. Richard. > > Aldy/Andrew, is the ranger query ok or should I use something different > when check_range_stmt is non-NULL and I know on which statement to ask? > > And, looking at it again this morning, actually the Y equal to B > case is still fine, if Y is equal to 0, then it is > (T) (((T2) X << 0) | ((T2) X >> 0)) > and so X, for Y == B it is > (T) (((T2) X << B) | ((T2) X >> 0)) > which is the same as > (T) (0 | ((T2) X >> 0)) > which is also X. So instead of the [B, B2 - 1] range we could use > [B + 1, B2 - 1]. And, if we wanted to go further, even multiplies > of B are ok if they are smaller than B2, so we could construct a detailed > int_range_max if we wanted. > > 2023-01-17 Jakub Jelinek > > PR tree-optimization/106523 > * tree-ssa-forwprop.cc (simplify_rotate): For the > patterns with (-Y) & (B - 1) in one operand's shift > count and Y in another, if T2 has wider precision than T, > punt if Y could have a value in [B, B2 - 1] range. > > * c-c++-common/rotate-2.c (f5, f6, f7, f8, f13, f14, f15, f16, > f37, f38, f39, f40, f45, f46, f47, f48): Add assertions using > __builtin_unreachable about shift count. > * c-c++-common/rotate-2b.c: New test. > * c-c++-common/rotate-4.c (f5, f6, f7, f8, f13, f14, f15, f16, > f37, f38, f39, f40, f45, f46, f47, f48): Add assertions using > __builtin_unreachable about shift count. > * c-c++-common/rotate-4b.c: New test. > * gcc.c-torture/execute/pr106523.c: New test. > > --- gcc/tree-ssa-forwprop.cc.jj 2023-01-02 09:32:26.000000000 +0100 > +++ gcc/tree-ssa-forwprop.cc 2023-01-16 18:18:43.524443879 +0100 > @@ -1837,7 +1837,7 @@ defcodefor_name (tree name, enum tree_co > ((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1)))) > ((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1)))) > > - transform these into: > + transform these into (last 2 only if ranger can prove Y < B): > X r<< Y > > Or for: > @@ -1866,6 +1866,8 @@ simplify_rotate (gimple_stmt_iterator *g > int i; > bool swapped_p = false; > gimple *g; > + gimple *def_arg_stmt[2] = { NULL, NULL }; > + int wider_prec = 0; > > arg[0] = gimple_assign_rhs1 (stmt); > arg[1] = gimple_assign_rhs2 (stmt); > @@ -1878,7 +1880,11 @@ simplify_rotate (gimple_stmt_iterator *g > return false; > > for (i = 0; i < 2; i++) > - defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]); > + { > + defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]); > + if (TREE_CODE (arg[i]) == SSA_NAME) > + def_arg_stmt[i] = SSA_NAME_DEF_STMT (arg[i]); > + } > > /* Look through narrowing (or same precision) conversions. */ > if (CONVERT_EXPR_CODE_P (def_code[0]) > @@ -1891,10 +1897,13 @@ simplify_rotate (gimple_stmt_iterator *g > && has_single_use (arg[0]) > && has_single_use (arg[1])) > { > + wider_prec = TYPE_PRECISION (TREE_TYPE (def_arg1[0])); > for (i = 0; i < 2; i++) > { > arg[i] = def_arg1[i]; > defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]); > + if (TREE_CODE (arg[i]) == SSA_NAME) > + def_arg_stmt[i] = SSA_NAME_DEF_STMT (arg[i]); > } > } > else > @@ -1910,6 +1919,8 @@ simplify_rotate (gimple_stmt_iterator *g > { > arg[i] = def_arg1[i]; > defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]); > + if (TREE_CODE (arg[i]) == SSA_NAME) > + def_arg_stmt[i] = SSA_NAME_DEF_STMT (arg[i]); > } > } > > @@ -1983,6 +1994,9 @@ simplify_rotate (gimple_stmt_iterator *g > { > tree cdef_arg1[2], cdef_arg2[2], def_arg2_alt[2]; > enum tree_code cdef_code[2]; > + gimple *def_arg_alt_stmt[2] = { NULL, NULL }; > + bool check_range = false; > + gimple *check_range_stmt = NULL; > /* Look through conversion of the shift count argument. > The C/C++ FE cast any shift count argument to integer_type_node. > The only problem might be if the shift count type maximum value > @@ -1999,9 +2013,13 @@ simplify_rotate (gimple_stmt_iterator *g > && type_has_mode_precision_p (TREE_TYPE (cdef_arg1[i]))) > { > def_arg2_alt[i] = cdef_arg1[i]; > + if (TREE_CODE (def_arg2[i]) == SSA_NAME) > + def_arg_alt_stmt[i] = SSA_NAME_DEF_STMT (def_arg2[i]); > defcodefor_name (def_arg2_alt[i], &cdef_code[i], > &cdef_arg1[i], &cdef_arg2[i]); > } > + else > + def_arg_alt_stmt[i] = def_arg_stmt[i]; > } > for (i = 0; i < 2; i++) > /* Check for one shift count being Y and the other B - Y, > @@ -2024,7 +2042,7 @@ simplify_rotate (gimple_stmt_iterator *g > if (CONVERT_EXPR_CODE_P (code) > && INTEGRAL_TYPE_P (TREE_TYPE (tem)) > && TYPE_PRECISION (TREE_TYPE (tem)) > - > floor_log2 (TYPE_PRECISION (rtype)) > + > floor_log2 (TYPE_PRECISION (rtype)) > && type_has_mode_precision_p (TREE_TYPE (tem)) > && (tem == def_arg2[1 - i] > || tem == def_arg2_alt[1 - i])) > @@ -2053,7 +2071,7 @@ simplify_rotate (gimple_stmt_iterator *g > if (CONVERT_EXPR_CODE_P (code) > && INTEGRAL_TYPE_P (TREE_TYPE (tem)) > && TYPE_PRECISION (TREE_TYPE (tem)) > - > floor_log2 (TYPE_PRECISION (rtype)) > + > floor_log2 (TYPE_PRECISION (rtype)) > && type_has_mode_precision_p (TREE_TYPE (tem))) > defcodefor_name (tem, &code, &tem, NULL); > > @@ -2062,6 +2080,11 @@ simplify_rotate (gimple_stmt_iterator *g > if (tem == def_arg2[1 - i] || tem == def_arg2_alt[1 - i]) > { > rotcnt = tem; > + check_range = true; > + if (tem == def_arg2[1 - i]) > + check_range_stmt = def_arg_stmt[1 - i]; > + else > + check_range_stmt = def_arg_alt_stmt[1 - i]; > break; > } > tree tem2; > @@ -2076,6 +2099,11 @@ simplify_rotate (gimple_stmt_iterator *g > || tem2 == def_arg2_alt[1 - i]) > { > rotcnt = tem2; > + check_range = true; > + if (tem2 == def_arg2[1 - i]) > + check_range_stmt = def_arg_stmt[1 - i]; > + else > + check_range_stmt = def_arg_alt_stmt[1 - i]; > break; > } > } > @@ -2111,6 +2139,23 @@ simplify_rotate (gimple_stmt_iterator *g > } > } > } > + if (check_range && wider_prec > TYPE_PRECISION (rtype)) > + { > + if (TREE_CODE (rotcnt) != SSA_NAME) > + return false; > + int_range_max r; > + if (!get_global_range_query ()->range_of_expr (r, rotcnt, > + check_range_stmt)) > + return false; > + int prec = TYPE_PRECISION (TREE_TYPE (rotcnt)); > + signop sign = TYPE_SIGN (TREE_TYPE (rotcnt)); > + wide_int min = wide_int::from (TYPE_PRECISION (rtype), prec, sign); > + wide_int max = wide_int::from (wider_prec - 1, prec, sign); > + int_range<2> r2 (TREE_TYPE (rotcnt), min, max); > + r.intersect (r2); > + if (!r.undefined_p ()) > + return false; > + } > if (rotcnt == NULL_TREE) > return false; > swapped_p = i != 1; > --- gcc/testsuite/c-c++-common/rotate-2.c.jj 2020-01-12 11:54:37.023404206 +0100 > +++ gcc/testsuite/c-c++-common/rotate-2.c 2023-01-16 17:53:49.459329241 +0100 > @@ -32,24 +32,32 @@ f4 (unsigned int x, int y __attribute__( > unsigned short int > f5 (unsigned short int x, unsigned int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned short int > f6 (unsigned short int x, unsigned long int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned char > f7 (unsigned char x, unsigned int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > } > > unsigned char > f8 (unsigned char x, unsigned long int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > } > > @@ -80,24 +88,32 @@ f12 (unsigned int x, int y __attribute__ > unsigned short int > f13 (unsigned short int x, unsigned int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned short int > f14 (unsigned short int x, unsigned long int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned char > f15 (unsigned char x, unsigned int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > unsigned char > f16 (unsigned char x, unsigned long int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > @@ -224,24 +240,32 @@ f36 (unsigned int x, int y __attribute__ > unsigned short int > f37 (unsigned short int x, unsigned int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned short int > f38 (unsigned short int x, unsigned long int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned char > f39 (unsigned char x, unsigned int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > } > > unsigned char > f40 (unsigned char x, unsigned long int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > } > > @@ -272,24 +296,32 @@ f44 (unsigned int x, int y __attribute__ > unsigned short int > f45 (unsigned short int x, unsigned int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned short int > f46 (unsigned short int x, unsigned long int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned char > f47 (unsigned char x, unsigned int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > unsigned char > f48 (unsigned char x, unsigned long int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > --- gcc/testsuite/c-c++-common/rotate-2b.c.jj 2023-01-16 18:25:08.359787649 +0100 > +++ gcc/testsuite/c-c++-common/rotate-2b.c 2023-01-16 18:25:04.078850569 +0100 > @@ -0,0 +1,100 @@ > +/* Check rotate pattern detection. */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */ > +/* { dg-final { scan-tree-dump-not "r\[<>]\[<>]" "optimized" } } */ > + > +unsigned short int > +f5 (unsigned short int x, unsigned int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned short int > +f6 (unsigned short int x, unsigned long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned char > +f7 (unsigned char x, unsigned int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned char > +f8 (unsigned char x, unsigned long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned short int > +f13 (unsigned short int x, unsigned int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned short int > +f14 (unsigned short int x, unsigned long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned char > +f15 (unsigned char x, unsigned int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > + > +unsigned char > +f16 (unsigned char x, unsigned long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > + > +unsigned short int > +f37 (unsigned short int x, unsigned int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned short int > +f38 (unsigned short int x, unsigned long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned char > +f39 (unsigned char x, unsigned int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned char > +f40 (unsigned char x, unsigned long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned short int > +f45 (unsigned short int x, unsigned int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned short int > +f46 (unsigned short int x, unsigned long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned char > +f47 (unsigned char x, unsigned int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > + > +unsigned char > +f48 (unsigned char x, unsigned long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > --- gcc/testsuite/c-c++-common/rotate-4.c.jj 2020-01-12 11:54:37.023404206 +0100 > +++ gcc/testsuite/c-c++-common/rotate-4.c 2023-01-16 18:01:04.161979907 +0100 > @@ -32,24 +32,32 @@ f4 (unsigned int x, int y __attribute__( > unsigned short int > f5 (unsigned short int x, int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned short int > f6 (unsigned short int x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned char > f7 (unsigned char x, int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > } > > unsigned char > f8 (unsigned char x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > } > > @@ -80,24 +88,32 @@ f12 (unsigned int x, int y __attribute__ > unsigned short int > f13 (unsigned short int x, int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned short int > f14 (unsigned short int x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned char > f15 (unsigned char x, int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > unsigned char > f16 (unsigned char x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__) > + __builtin_unreachable (); > return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > @@ -224,24 +240,32 @@ f36 (unsigned int x, int y __attribute__ > unsigned short int > f37 (unsigned short int x, int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned short int > f38 (unsigned short int x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > } > > unsigned char > f39 (unsigned char x, int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > } > > unsigned char > f40 (unsigned char x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > } > > @@ -272,24 +296,32 @@ f44 (unsigned int x, int y __attribute__ > unsigned short int > f45 (unsigned short int x, int y) > { > + if (y >= __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned short int > f46 (unsigned short int x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__ * __SIZEOF_SHORT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > } > > unsigned char > f47 (unsigned char x, int y) > { > + if (y >= __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > unsigned char > f48 (unsigned char x, long int y) > { > + if (y >= 0UL + __CHAR_BIT__) > + __builtin_unreachable (); > return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > } > > --- gcc/testsuite/c-c++-common/rotate-4b.c.jj 2023-01-16 18:25:19.645621784 +0100 > +++ gcc/testsuite/c-c++-common/rotate-4b.c 2023-01-16 18:27:26.237761150 +0100 > @@ -0,0 +1,100 @@ > +/* Check rotate pattern detection. */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */ > +/* { dg-final { scan-tree-dump-not "r\[<>]\[<>]" "optimized" } } */ > + > +unsigned short int > +f5 (unsigned short int x, int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned short int > +f6 (unsigned short int x, long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned char > +f7 (unsigned char x, int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned char > +f8 (unsigned char x, long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned short int > +f13 (unsigned short int x, int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned short int > +f14 (unsigned short int x, long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned char > +f15 (unsigned char x, int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > + > +unsigned char > +f16 (unsigned char x, long int y) > +{ > + return (x << y) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > + > +unsigned short int > +f37 (unsigned short int x, int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned short int > +f38 (unsigned short int x, long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))); > +} > + > +unsigned char > +f39 (unsigned char x, int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned char > +f40 (unsigned char x, long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ - 1))); > +} > + > +unsigned short int > +f45 (unsigned short int x, int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned short int > +f46 (unsigned short int x, long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))); > +} > + > +unsigned char > +f47 (unsigned char x, int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > + > +unsigned char > +f48 (unsigned char x, long int y) > +{ > + return (x >> y) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))); > +} > --- gcc/testsuite/gcc.c-torture/execute/pr106523.c.jj 2023-01-16 18:37:42.208726762 +0100 > +++ gcc/testsuite/gcc.c-torture/execute/pr106523.c 2023-01-16 18:37:31.898877393 +0100 > @@ -0,0 +1,22 @@ > +/* PR tree-optimization/106523 */ > + > +__attribute__((noipa)) unsigned char > +f7 (unsigned char x, unsigned int y) > +{ > + unsigned int t = x; > + return (t << y) | (t >> ((-y) & 7)); > +} > + > +int > +main () > +{ > + if (__CHAR_BIT__ != 8 || __SIZEOF_INT__ != 4) > + return 0; > + > + volatile unsigned char x = 152; > + volatile unsigned int y = 19; > + if (f7 (x, y) != 4) > + __builtin_abort (); > + > + return 0; > +} > > Jakub > > -- Richard Biener SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman; HRB 36809 (AG Nuernberg)