From patchwork Tue Jan 29 20:00:17 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 216646 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 2F3C62C0096 for ; Wed, 30 Jan 2013 07:00:38 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1360094439; h=Comment: DomainKey-Signature:Received:Received:Received:Received: Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject: References:In-Reply-To:Content-Type:Mailing-List:Precedence: List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=ntcmc4aHbHz9wWYabfZ2WUkTCFE=; b=U0ZelEhHLqmuqa7 rPfJbWWyvNGWyDpCA+lxll9MrLIPO8Ing6kjqXvh67UevZ5S6XI1LQrfT8Utp8By Bm88NAH2gWalYSWKNprTqqrqPuzjm+lvtC7poKK8msm25ajHvkHyRTfHXS+UsMxj xa+97MM5Ql/neVFJGOWLue+/ioZc= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:X-RZG-AUTH:X-RZG-CLASS-ID:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=O6EyxfIIceNuTZpeV3GMCMac+swK+XaM0vmH5pmVQob7ohp1KfmADEQ4JMsPZU lxN3qAC30uFFCtputFCsD7UJsx0VdlM8BcqiI9xBW6rpzqRNfz8+qVe/kO5Do/gf 15lvrspFBzOuanPsaec/JnnIF1w0rsp/yrUpI4g5jpVhs=; Received: (qmail 31038 invoked by alias); 29 Jan 2013 20:00:29 -0000 Received: (qmail 31019 invoked by uid 22791); 29 Jan 2013 20:00:26 -0000 X-SWARE-Spam-Status: No, hits=-0.8 required=5.0 tests=AWL, BAYES_50, KHOP_SPAMHAUS_DROP, KHOP_THREADED, RCVD_IN_DNSWL_NONE, TW_CP X-Spam-Check-By: sourceware.org Received: from mo-p00-ob.rzone.de (HELO mo-p00-ob.rzone.de) (81.169.146.161) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 29 Jan 2013 20:00:19 +0000 X-RZG-AUTH: :LXoWVUeid/7A29J/hMvvT2k715jHQaJercGObUOFkj18odoYNahU4Q== X-RZG-CLASS-ID: mo00 Received: from [192.168.0.22] (business-188-111-022-002.static.arcor-ip.net [188.111.22.2]) by smtp.strato.de (jored mo29) (RZmta 31.14 AUTH) with ESMTPA id u02cadp0TJGTqW ; Tue, 29 Jan 2013 21:00:17 +0100 (CET) Message-ID: <51082A51.9010501@gjlay.de> Date: Tue, 29 Jan 2013 21:00:17 +0100 From: Georg-Johann Lay User-Agent: Thunderbird 2.0.0.24 (X11/20100302) MIME-Version: 1.0 To: Richard Biener CC: gcc-patches@gcc.gnu.org Subject: Re: [Patch] PR56064: Fold VIEW_CONVERT_EXPR with FIXED_CST, Take #2 References: <50FD4297.1090107@gjlay.de> In-Reply-To: X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Richard Biener wrote: > Georg-Johann Lay wrote: >> This is tentative patch as discussed in >> >> http://gcc.gnu.org/ml/gcc/2013-01/msg00187.html >> >> fold-const.c gets 2 new function native_encode_fixed and >> native_interpret_fixed. Code common with the integer case is factored out and >> moved to the new constructor-like function double_int::from_buffer. >> >> The code bootstraps fine on x86-linux-gnu and I have test coverage from >> avr-unknown-none. >> >> Ok to apply? > > Ok. > > Thanks, > Richard. Let me drop this, I don't like the name "const_fixed_from_double_int". It's bad and I think "fixed_from_double_int" is better. Other constructor-like functions for FIXED_VALUE_TYPE use fixed_from_* whereas const_fixed_* returns a CONST_FIXED rtx. This is less confusing and fits better the naming convention. The new patch also adds const_fixed_from_double_int that actually returns a CONST_FIXED rtx. It's unused, but I would use it in the avr back. Okay with that rename? (Or, at your option, without const_fixed_from_double_int). Johann PR tree-optimization/56064 * fixed-value.c (fixed_from_double_int): New function. * fixed-value.h (fixed_from_double_int): New prototype. (const_fixed_from_double_int): New static inline function. * fold-const.c (native_interpret_fixed): New static function. (native_interpret_expr) : Use it. (can_native_interpret_type_p) : Return true. (native_encode_fixed): New static function. (native_encode_expr) : Use it. (native_interpret_int): Move double_int worker code to... * double-int.c (double_int::from_buffer): ...this new static method. * double-int.h (double_int::from_buffer): Prototype it. testsuite/ PR tree-optimization/56064 * gcc.dg/fixed-point/view-convert.c: New test. > >> There are less intrusive solutions that only handle the int <-> fixed cases, >> for example fold-const.c:fold_view_convert_expr() could test for these cases >> and use double_int directly without serializing / deserializing through a >> memory buffer. >> >> Johann >> >> >> PR tree-optimization/56064 >> * fixed-value.c (const_fixed_from_double_int): New function. >> * fixed-value.h (const_fixed_from_double_int): New prototype. >> * fold-const.c (native_interpret_fixed): New static function. >> (native_interpret_expr) : Use it. >> (can_native_interpret_type_p) : Return true. >> (native_encode_fixed): New static function. >> (native_encode_expr) : Use it. >> (native_interpret_int): Move double_int worker code to... >> * double-int.c (double_int::from_buffer): ...this new static method. >> * double-int.h (double_int::from_buffer): Prototype it. >> >> testsuite/ >> PR tree-optimization/56064 >> * gcc.dg/fixed-point/view-convert.c: New test. > Index: fixed-value.c =================================================================== --- fixed-value.c (revision 195514) +++ fixed-value.c (working copy) @@ -81,6 +81,24 @@ check_real_for_fixed_mode (REAL_VALUE_TY return FIXED_OK; } + +/* Construct a CONST_FIXED from a bit payload and machine mode MODE. + The bits in PAYLOAD are used verbatim. */ + +FIXED_VALUE_TYPE +fixed_from_double_int (double_int payload, enum machine_mode mode) +{ + FIXED_VALUE_TYPE value; + + gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT); + + value.data = payload; + value.mode = mode; + + return value; +} + + /* Initialize from a decimal or hexadecimal string. */ void Index: fixed-value.h =================================================================== --- fixed-value.h (revision 195514) +++ fixed-value.h (working copy) @@ -49,6 +49,22 @@ extern FIXED_VALUE_TYPE fconst1[MAX_FCON const_fixed_from_fixed_value (r, m) extern rtx const_fixed_from_fixed_value (FIXED_VALUE_TYPE, enum machine_mode); +/* Construct a FIXED_VALUE from a bit payload and machine mode MODE. + The bits in PAYLOAD are used verbatim. */ +extern FIXED_VALUE_TYPE fixed_from_double_int (double_int, + enum machine_mode); + +/* Return a CONST_FIXED from a bit payload and machine mode MODE. + The bits in PAYLOAD are used verbatim. */ +static inline rtx +const_fixed_from_double_int (double_int payload, + enum machine_mode mode) +{ + return + const_fixed_from_fixed_value (fixed_from_double_int (payload, mode), + mode); +} + /* Initialize from a decimal or hexadecimal string. */ extern void fixed_from_string (FIXED_VALUE_TYPE *, const char *, enum machine_mode); Index: fold-const.c =================================================================== --- fold-const.c (revision 195514) +++ fold-const.c (working copy) @@ -7200,6 +7200,36 @@ native_encode_int (const_tree expr, unsi } +/* Subroutine of native_encode_expr. Encode the FIXED_CST + specified by EXPR into the buffer PTR of length LEN bytes. + Return the number of bytes placed in the buffer, or zero + upon failure. */ + +static int +native_encode_fixed (const_tree expr, unsigned char *ptr, int len) +{ + tree type = TREE_TYPE (expr); + enum machine_mode mode = TYPE_MODE (type); + int total_bytes = GET_MODE_SIZE (mode); + FIXED_VALUE_TYPE value; + tree i_value, i_type; + + if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) + return 0; + + i_type = lang_hooks.types.type_for_size (GET_MODE_BITSIZE (mode), 1); + + if (NULL_TREE == i_type + || TYPE_PRECISION (i_type) != total_bytes) + return 0; + + value = TREE_FIXED_CST (expr); + i_value = double_int_to_tree (i_type, value.data); + + return native_encode_int (i_value, ptr, len); +} + + /* Subroutine of native_encode_expr. Encode the REAL_CST specified by EXPR into the buffer PTR of length LEN bytes. Return the number of bytes placed in the buffer, or zero @@ -7345,6 +7375,9 @@ native_encode_expr (const_tree expr, uns case REAL_CST: return native_encode_real (expr, ptr, len); + case FIXED_CST: + return native_encode_fixed (expr, ptr, len); + case COMPLEX_CST: return native_encode_complex (expr, ptr, len); @@ -7368,44 +7401,37 @@ static tree native_interpret_int (tree type, const unsigned char *ptr, int len) { int total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); - int byte, offset, word, words; - unsigned char value; double_int result; - if (total_bytes > len) - return NULL_TREE; - if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) + if (total_bytes > len + || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) return NULL_TREE; - result = double_int_zero; - words = total_bytes / UNITS_PER_WORD; + result = double_int::from_buffer (ptr, total_bytes); - for (byte = 0; byte < total_bytes; byte++) - { - int bitpos = byte * BITS_PER_UNIT; - if (total_bytes > UNITS_PER_WORD) - { - word = byte / UNITS_PER_WORD; - if (WORDS_BIG_ENDIAN) - word = (words - 1) - word; - offset = word * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); - else - offset += byte % UNITS_PER_WORD; - } - else - offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte; - value = ptr[offset]; + return double_int_to_tree (type, result); +} - if (bitpos < HOST_BITS_PER_WIDE_INT) - result.low |= (unsigned HOST_WIDE_INT) value << bitpos; - else - result.high |= (unsigned HOST_WIDE_INT) value - << (bitpos - HOST_BITS_PER_WIDE_INT); - } - return double_int_to_tree (type, result); +/* Subroutine of native_interpret_expr. Interpret the contents of + the buffer PTR of length LEN as a FIXED_CST of type TYPE. + If the buffer cannot be interpreted, return NULL_TREE. */ + +static tree +native_interpret_fixed (tree type, const unsigned char *ptr, int len) +{ + int total_bytes = GET_MODE_SIZE (TYPE_MODE (type)); + double_int result; + FIXED_VALUE_TYPE fixed_value; + + if (total_bytes > len + || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT) + return NULL_TREE; + + result = double_int::from_buffer (ptr, total_bytes); + fixed_value = fixed_from_double_int (result, TYPE_MODE (type)); + + return build_fixed (type, fixed_value); } @@ -7533,6 +7559,9 @@ native_interpret_expr (tree type, const case REAL_TYPE: return native_interpret_real (type, ptr, len); + case FIXED_POINT_TYPE: + return native_interpret_fixed (type, ptr, len); + case COMPLEX_TYPE: return native_interpret_complex (type, ptr, len); @@ -7557,6 +7586,7 @@ can_native_interpret_type_p (tree type) case BOOLEAN_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: + case FIXED_POINT_TYPE: case REAL_TYPE: case COMPLEX_TYPE: case VECTOR_TYPE: Index: double-int.c =================================================================== --- double-int.c (revision 195514) +++ double-int.c (working copy) @@ -641,6 +641,54 @@ div_and_round_double (unsigned code, int return overflow; } + +/* Construct from a buffer of length LEN. BUFFER will be read according + to byte endianess and word endianess. Only the lower LEN bytes + of the result are set; the remaining high bytes are cleared. */ + +double_int +double_int::from_buffer (const unsigned char *buffer, int len) +{ + double_int result = double_int_zero; + int words = len / UNITS_PER_WORD; + + gcc_assert (len * BITS_PER_UNIT <= HOST_BITS_PER_DOUBLE_INT); + + for (int byte = 0; byte < len; byte++) + { + int offset; + int bitpos = byte * BITS_PER_UNIT; + unsigned HOST_WIDE_INT value; + + if (len > UNITS_PER_WORD) + { + int word = byte / UNITS_PER_WORD; + + if (WORDS_BIG_ENDIAN) + word = (words - 1) - word; + + offset = word * UNITS_PER_WORD; + + if (BYTES_BIG_ENDIAN) + offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD); + else + offset += byte % UNITS_PER_WORD; + } + else + offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte; + + value = (unsigned HOST_WIDE_INT) buffer[offset]; + + if (bitpos < HOST_BITS_PER_WIDE_INT) + result.low |= value << bitpos; + else + result.high |= value << (bitpos - HOST_BITS_PER_WIDE_INT); + } + + return result; +} + + /* Returns mask for PREC bits. */ double_int Index: double-int.h =================================================================== --- double-int.h (revision 195514) +++ double-int.h (working copy) @@ -59,6 +59,10 @@ struct double_int static double_int from_shwi (HOST_WIDE_INT cst); static double_int from_pair (HOST_WIDE_INT high, unsigned HOST_WIDE_INT low); + /* Construct from a fuffer of length LEN. BUFFER will be read according + to byte endianess and word endianess. */ + static double_int from_buffer (const unsigned char *buffer, int len); + /* No copy assignment operator or destructor to keep the type a POD. */ /* There are some special value-creation static member functions. */ Index: testsuite/gcc.dg/fixed-point/view-convert.c =================================================================== --- testsuite/gcc.dg/fixed-point/view-convert.c (revision 0) +++ testsuite/gcc.dg/fixed-point/view-convert.c (revision 0) @@ -0,0 +1,122 @@ +/* PR tree-optimization/56064 */ +/* { dg-do run } */ +/* { dg-options "-std=gnu99 -O2 -fno-builtin-memcpy" } */ + +extern void abort (void); +extern void *memcpy (void*, const void*, __SIZE_TYPE__); + +#define f_pun_i(F, I, VAL) \ + { \ + I i1 = VAL; \ + I i2 = VAL; \ + F q1, q2; \ + memcpy (&q1, &i1, sizeof (I)); \ + __builtin_memcpy (&q2, &i2, sizeof (I)); \ + if (q1 != q2) \ + abort(); \ + } + +#define i_pun_f(I, F, VAL) \ + { \ + F q1 = VAL; \ + F q2 = VAL; \ + I i1, i2; \ + memcpy (&i1, &q1, sizeof (I)); \ + __builtin_memcpy (&i2, &q2, sizeof (I)); \ + if (i1 != i2) \ + abort(); \ + } + + +void __attribute__((noinline)) +test8 (void) +{ +#ifdef __INT8_TYPE__ + if (sizeof (__INT8_TYPE__) == sizeof (short _Fract)) + { +#define TEST(X) f_pun_i (short _Fract, __INT8_TYPE__, __INT8_C (X)) + TEST (123); + TEST (-123); +#undef TEST + +#define TEST(X) i_pun_f (__INT8_TYPE__, short _Fract, X ## hr) + TEST (0.1234); + TEST (-0.987); +#undef TEST + } +#endif /* __INT8_TYPE__ */ +} + + +void __attribute__((noinline)) +test16 (void) +{ +#ifdef __INT16_TYPE__ + + if (sizeof (__INT16_TYPE__) == sizeof (_Fract)) + { +#define TEST(X) f_pun_i (_Fract, __INT16_TYPE__, __INT16_C (X)) + TEST (0x4321); + TEST (-0x4321); + TEST (0x8000); +#undef TEST + +#define TEST(X) i_pun_f (__INT16_TYPE__, _Fract, X ## r) + TEST (0.12345); + TEST (-0.98765); +#undef TEST + } +#endif /* __INT16_TYPE__ */ +} + + +void __attribute__((noinline)) +test32 (void) +{ +#ifdef __INT32_TYPE__ + if (sizeof (__INT32_TYPE__) == sizeof (_Accum)) + { +#define TEST(X) f_pun_i (_Accum, __INT32_TYPE__, __INT32_C (X)) + TEST (0x76543219); + TEST (-0x76543219); + TEST (0x80000000); +#undef TEST + +#define TEST(X) i_pun_f (__INT32_TYPE__, _Accum, X ## k) + TEST (123.456789); + TEST (-123.456789); +#undef TEST + } +#endif /* __INT32_TYPE__ */ +} + + +void __attribute__((noinline)) +test64 (void) +{ +#ifdef __INT64_TYPE__ + if (sizeof (__INT64_TYPE__) == sizeof (long _Accum)) + { +#define TEST(X) f_pun_i (long _Accum, __INT64_TYPE__, __INT64_C (X)) + TEST (0x12345678abcdef01); + TEST (-0x12345678abcdef01); + TEST (0x8000000000000000); +#undef TEST + +#define TEST(X) i_pun_f (__INT64_TYPE__, long _Accum, X ## lk) + TEST (123.456789); + TEST (-123.456789); +#undef TEST + } +#endif /* __INT64_TYPE__ */ +} + +int main() +{ + test8(); + test16(); + test32(); + test64(); + + return 0; +}