From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2522 invoked by alias); 13 Nov 2012 14:10:50 -0000 Received: (qmail 2508 invoked by uid 22791); 13 Nov 2012 14:10:47 -0000 X-SWARE-Spam-Status: No, hits=-4.2 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,RP_MATCHES_RCVD,TW_CP X-Spam-Check-By: sourceware.org Received: from mms3.broadcom.com (HELO mms3.broadcom.com) (216.31.210.19) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 13 Nov 2012 14:10:15 +0000 Received: from [10.9.200.133] by mms3.broadcom.com with ESMTP (Broadcom SMTP Relay (Email Firewall v6.5)); Tue, 13 Nov 2012 06:06:06 -0800 X-Server-Uuid: B86B6450-0931-4310-942E-F00ED04CA7AF Received: from mail-irva-13.broadcom.com (10.11.16.103) by IRVEXCHHUB02.corp.ad.broadcom.com (10.9.200.133) with Microsoft SMTP Server id 8.2.247.2; Tue, 13 Nov 2012 06:09:41 -0800 Received: from [10.177.72.87] (unknown [10.177.72.87]) by mail-irva-13.broadcom.com (Postfix) with ESMTP id BB7504103F for ; Tue, 13 Nov 2012 06:10:06 -0800 (PST) Message-ID: <50A254C0.1030901@broadcom.com> Date: Tue, 13 Nov 2012 14:10:00 -0000 From: "Andrew Burgess" User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20121026 Thunderbird/16.0.2 MIME-Version: 1.0 To: "gdb-patches@sourceware.org" Subject: [PATCH] Vector to scalar casting and widening Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-11/txt/msg00312.txt.bz2 I'd like to change the way gdb handles scalar to vector widening. I believe that the changes I propose will bring gdb expression evaluation into line with how gcc handles these things; this seems a good thing to me, but I'd be interested to hear why anyone things we should stick with the current scheme. The problem I have is the current behaviour when casting from scalar to vector. We first cast the scalar to the element type of the vector, then replicate the (truncated) scalar to fill each element of the vector. The gcc behaviour is to only allow casting from scalar to vector, and from vector to vector when the lengths of the scalar and the vector, or the two vectors, match. On my local target I have instructions that process registers as though they were vectors of different sizes, so an instruction might treat the register as a single 64-bit value, two 32-bit values, four 16-bit values, and so on. We have types for each different vector size, and it's not uncommon to cast a register between types. You'll notice the gcc behaviour matches this perfectly while the gdb behaviour can truncate values when casting between types. One place where gcc does replicate scalars to create vectors is in binary operations on vectors, so you can have "vector + scalar", this will then add 'scalar' to each element of 'vector'. This seems like a good thing, and seems to be something a lot of vector supporting targets actually have in hardware. gcc restricts the scalar to vector replication within binary operations to only expanding the type to avoid loosing significant bits. So a vector of type 'int' could for example be added to a scalar 'short' or 'char', but not to a 'long long'. I've included a simple test file and gdb command script which shows the current behaviour of gdb. The patch does the following: 1. Casting scalar to vector or vector to vector is only allowed when the lengths of the two types are equal. 2. Binary operations on a vector and a scalar will first create a temporary vector by replicating scalar, then perform the operation on the two vectors. We will error if casting the scalar to the element type of the vector causes truncation of the value. OK to commit? Thanks, Andrew ##### EXAMPLE FILES ##### /* File: vec.c I'm using gcc 4.7.2 on GNU/Linux (RHEL 5.7) on x86-64. Compile using: gcc -DBROKEN -g -o vec vec.c to test constructs that will not compile. Compile using: gcc -g -o vec vec.c to test only constructs that do compile. */ #include #define VEC_TYPE(btype, count) \ typedef btype btype ## count \ __attribute__ ((vector_size (count * sizeof (btype)))); \ void print_ ## btype ## count ( const char *name, btype ## count var ) \ { \ int i; \ printf ("%s = { %lld", name, var[0]); \ for (i = 1; i < count; ++i) \ { \ printf (", %lld", var[i]); \ } \ printf (" }\n"); \ } VEC_TYPE (char, 4) VEC_TYPE (char, 8) VEC_TYPE (int, 2) VEC_TYPE (int, 4) int ia = 1; short sa = 1; long long lla = 1; void breakpt () { /* Breakpt */ } int main () { char4 c4a = { 1, 2, 3, 4}; char4 c4b = (char4) 1; #if BROKEN char4 c4c = 1; char4 c4d = ia; char4 c4e = sa; char4 c4f = lla; #endif char4 c4g = (char4) ia; #if BROKEN char4 c4h = (char4) sa; char4 c4i = (char4) lla; #endif int4 i4a = { 1, 2, 3, 4}; int2 i2a = { 1, 2}; int2 i2b = (int2) lla; #if BROKEN char4 c4j = i4a; char4 c4k = (char4) i4a; char8 c8a = i2a; #endif char8 c8b = (char8) i2a; print_char4 ("c4b", c4b); print_int4 ("i4a", i4a); print_char8 ("c8b", c8b); print_int2 ("i2b", i2b); return 0; /* Break Here */ } /* END: vec.c */ # START: vec.gdb set height 0 set trace-commands 1 break 81 run print c4b print (char4) 1 print i2b print lla print (int2) lla # The following don't compile # under gcc 4.7.2 print (char4) sa print (char4) lla print (char4) i4a quit # END: vec.gdb ##### PATCH ##### gdb/ChangeLog 2012-11-13 Andrew Burgess * valarith.c (vector_widen): New function for replicating a scalar into a vector. (value_binop): Use vector_widen to convert scalar to vector rather than value_cast. * valops.c (value_casst): Update logic for casting between vector types, and for casting from scalar to vector. diff --git a/gdb/valarith.c b/gdb/valarith.c index c457f4a..81d6868 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -1347,6 +1347,47 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) return val; } +/* Widen a scalar value SCALAR_VALUE to vector type VECTOR_TYPE by + replicating SCALAR_VALUE for each element of the vector. Only scalar + types that can be cast to the type of one element of the vector are + acceptable. The newly created vector value is returned upon success, + otherwise an error is thrown. */ + +static struct value * +vector_widen (struct value *scalar_value, struct type *vector_type) +{ + /* Widen the scalar to a vector. */ + struct type *eltype, *scalar_type; + struct value *val, *elval; + LONGEST low_bound, high_bound; + int i; + + gdb_assert (TYPE_CODE (check_typedef (vector_type)) == TYPE_CODE_ARRAY); + gdb_assert (TYPE_VECTOR (vector_type)); + + if (!get_array_bounds (vector_type, &low_bound, &high_bound)) + error (_("Could not determine the vector bounds")); + + eltype = check_typedef (TYPE_TARGET_TYPE (vector_type)); + elval = value_cast (eltype, scalar_value); + + scalar_type = check_typedef (value_type (scalar_value)); + + /* If we reduced the length of the scalar then check we didn't loose any + important bits. */ + if (TYPE_LENGTH (eltype) < TYPE_LENGTH (scalar_type) + && !value_equal (elval, scalar_value)) + error (_("conversion of scalar to vector involves truncation")); + + val = allocate_value (vector_type); + for (i = 0; i < high_bound - low_bound + 1; i++) + /* Duplicate the contents of elval into the destination vector. */ + memcpy (value_contents_writeable (val) + (i * TYPE_LENGTH (eltype)), + value_contents_all (elval), TYPE_LENGTH (eltype)); + + return val; +} + /* Performs a binary operation on two vector operands by calling scalar_binop for each pair of vector components. */ @@ -1426,7 +1467,9 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) && !is_integral_type (t)) error (_("Argument to operation not a number or boolean.")); - *v = value_cast (t1_is_vec ? type1 : type2, *v); + /* Replicate the scalar value to make a vector value. */ + *v = vector_widen (*v, t1_is_vec ? type1 : type2); + val = vector_binop (arg1, arg2, op); } diff --git a/gdb/valops.c b/gdb/valops.c index 502fb0d..c8d7c8b 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -546,29 +546,14 @@ value_cast (struct type *type, struct value *arg2) minus one, instead of biasing the normal case. */ return value_from_longest (type, -1); } - else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) && scalar) - { - /* Widen the scalar to a vector. */ - struct type *eltype; - struct value *val; - LONGEST low_bound, high_bound; - int i; - - if (!get_array_bounds (type, &low_bound, &high_bound)) - error (_("Could not determine the vector bounds")); - - eltype = check_typedef (TYPE_TARGET_TYPE (type)); - arg2 = value_cast (eltype, arg2); - val = allocate_value (type); - - for (i = 0; i < high_bound - low_bound + 1; i++) - { - /* Duplicate the contents of arg2 into the destination vector. */ - memcpy (value_contents_writeable (val) + (i * TYPE_LENGTH (eltype)), - value_contents_all (arg2), TYPE_LENGTH (eltype)); - } - return val; - } + else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) + && code2 == TYPE_CODE_ARRAY && TYPE_VECTOR (type2) + && TYPE_LENGTH (type) != TYPE_LENGTH (type2)) + error (_("can't convert between vector values of different size")); + else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) + && scalar + && TYPE_LENGTH (type) != TYPE_LENGTH (type2)) + error (_("can only cast scalar to vector of same size")); else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2)) { if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) gdb/testsuite/ChangeLog 2012-11-13 Andrew Burgess * gdb.base/gnu_vector.c: New variable for use in tests. * gdb.base/gnu_vector.exp: Update and extend tests to reflect changes in scalar to vector casting and widening. * gdb.python/py-type.c: New variables for use in tests. * gdb.python/py-type.exp: Update vector related tests to reflect changes in scalar to vector casting and widening. diff --git a/gdb/testsuite/gdb.base/gnu_vector.c b/gdb/testsuite/gdb.base/gnu_vector.c index a2a218f..5b7c98b 100644 --- a/gdb/testsuite/gdb.base/gnu_vector.c +++ b/gdb/testsuite/gdb.base/gnu_vector.c @@ -31,6 +31,7 @@ int ia = 2; int ib = 1; float fa = 2; float fb = 1; +long long lla = 0x0000000100000001ll; char4 c4 = {1, 2, 3, 4}; int4 i4a = {2, 4, 8, 16}; int4 i4b = {1, 2, 8, 4}; diff --git a/gdb/testsuite/gdb.base/gnu_vector.exp b/gdb/testsuite/gdb.base/gnu_vector.exp index baba119..eaba6f2 100644 --- a/gdb/testsuite/gdb.base/gnu_vector.exp +++ b/gdb/testsuite/gdb.base/gnu_vector.exp @@ -82,32 +82,52 @@ gdb_test "print f4a / f4b" "\\\$$decimal = \\{2, 2, 1, 4\\}" gdb_test "print +f4a" "\\\$$decimal = \\{2, 4, 8, 16\\}" gdb_test "print -f4a" "\\\$$decimal = \\{-2, -4, -8, -16\\}" -# Test scalar to vector widening -gdb_test "print (int2) 1" "\\\$$decimal = \\{1, 1\\}" -gdb_test "print (longlong2) 2" "\\\$$decimal = \\{2, 2\\}" -gdb_test "print (float2) 3" "\\\$$decimal = \\{3, 3\\}" -gdb_test "print (double2) 4" "\\\$$decimal = \\{4, 4\\}" -gdb_test "print (char4) 12" "\\\$$decimal = \\{12, 12, 12, 12\\}" -gdb_test "print (uint4) ia" "\\\$$decimal = \\{2, 2, 2, 2\\}" -gdb_test "print (int4) -3" "\\\$$decimal = \\{-3, -3, -3, -3\\}" -gdb_test "print (float4) 4" "\\\$$decimal = \\{4, 4, 4, 4\\}" - +# When casting to vector the input type must have the same length as +# the total length of the vector. +gdb_test "print (char4) 0x01010101" "\\\$$decimal = \\{1, 1, 1, 1\\}" +gdb_test "print (char4) ia" "\\\$$decimal = \\{2, 0, 0, 0\\}" +gdb_test "print (int2) lla" "\\\$$decimal = \\{1, 1\\}" + +gdb_test "print (int2) 1" "can only cast scalar to vector of same size" +gdb_test "print (longlong2) 2" "can only cast scalar to vector of same size" +gdb_test "print (float2) 3" "can only cast scalar to vector of same size" +gdb_test "print (double2) 4" "can only cast scalar to vector of same size" +gdb_test "print (uint4) ia" "can only cast scalar to vector of same size" +gdb_test "print (int4) -3" "can only cast scalar to vector of same size" +gdb_test "print (float4) 4" "can only cast scalar to vector of same size" + +gdb_test "print i4b = ia" "can only cast scalar to vector of same size" +gdb_test "print i4a = 3" "can only cast scalar to vector of same size" +gdb_test "print f4a = fb" "can only cast scalar to vector of same size" +gdb_test "print f4b = 2" "can only cast scalar to vector of same size" + +gdb_test "print c4 + lla" "conversion of scalar to vector involves truncation" +gdb_test "print i4a + lla" "conversion of scalar to vector involves truncation" +gdb_test "print lla + c4" "conversion of scalar to vector involves truncation" +gdb_test "print lla + i4a" "conversion of scalar to vector involves truncation" + +gdb_test "print c4 + ib" "\\\$$decimal = \\{2, 3, 4, 5\\}" gdb_test "print i4a + ib" "\\\$$decimal = \\{3, 5, 9, 17\\}" +gdb_test "print i4a + 1" "\\\$$decimal = \\{3, 5, 9, 17\\}" +gdb_test "print 1 + i4a" "\\\$$decimal = \\{3, 5, 9, 17\\}" gdb_test "print fa - f4b" "\\\$$decimal = \\{1, 0, -6, -2\\}" +gdb_test "print 2 - f4b" "\\\$$decimal = \\{1, 0, -6, -2\\}" gdb_test "print f4a * fb" "\\\$$decimal = \\{2, 4, 8, 16\\}" +gdb_test "print f4a * 1" "\\\$$decimal = \\{2, 4, 8, 16\\}" gdb_test "print ia / i4b" "\\\$$decimal = \\{2, 1, 0, 0\\}" +gdb_test "print 2 / i4b" "\\\$$decimal = \\{2, 1, 0, 0\\}" gdb_test "print i4a % ib" "\\\$$decimal = \\{0, 0, 0, 0\\}" - +gdb_test "print i4a % 1" "\\\$$decimal = \\{0, 0, 0, 0\\}" gdb_test "print ia & i4b" "\\\$$decimal = \\{0, 2, 0, 0\\}" +gdb_test "print 2 & i4b" "\\\$$decimal = \\{0, 2, 0, 0\\}" gdb_test "print i4a | ib" "\\\$$decimal = \\{3, 5, 9, 17\\}" +gdb_test "print i4a | 1" "\\\$$decimal = \\{3, 5, 9, 17\\}" gdb_test "print ia ^ i4b" "\\\$$decimal = \\{3, 0, 10, 6\\}" +gdb_test "print 2 ^ i4b" "\\\$$decimal = \\{3, 0, 10, 6\\}" gdb_test "print i4a << ib" "\\\$$decimal = \\{4, 8, 16, 32\\}" +gdb_test "print i4a << 1" "\\\$$decimal = \\{4, 8, 16, 32\\}" gdb_test "print i4a >> ib" "\\\$$decimal = \\{1, 2, 4, 8\\}" - -gdb_test "print i4b = ia" "\\\$$decimal = \\{2, 2, 2, 2\\}" -gdb_test "print i4a = 3" "\\\$$decimal = \\{3, 3, 3, 3\\}" -gdb_test "print f4a = fb" "\\\$$decimal = \\{1, 1, 1, 1\\}" -gdb_test "print f4b = 2" "\\\$$decimal = \\{2, 2, 2, 2\\}" +gdb_test "print i4a >> 1" "\\\$$decimal = \\{1, 2, 4, 8\\}" gdb_test "print i4a = \{2, 4, 8, 16\}" "\\\$$decimal = \\{2, 4, 8, 16\\}" gdb_test "print i4a <<= ib" "\\\$$decimal = \\{4, 8, 16, 32\\}" diff --git a/gdb/testsuite/gdb.python/py-type.c b/gdb/testsuite/gdb.python/py-type.c index bf39443..c57a2e8 100644 --- a/gdb/testsuite/gdb.python/py-type.c +++ b/gdb/testsuite/gdb.python/py-type.c @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include + struct s { int a; @@ -50,6 +52,9 @@ enum E { v1, v2, v3 }; +uint64_t vec_data_1 = 0x0000000100000001ull; +uint64_t vec_data_2 = 0x0000000100000002ull; + int main () { diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp index b997c51..5791bb6 100644 --- a/gdb/testsuite/gdb.python/py-type.exp +++ b/gdb/testsuite/gdb.python/py-type.exp @@ -125,15 +125,18 @@ proc test_fields {lang} { # Test gdb.Type.vector. # Note: vectors cast differently than arrays. Here ar[0] is replicated # for the size of the vector. - gdb_py_test_silent_cmd \ - "python vec1 = ar\[0\].cast(ar\[0\].type.vector(1))" "set vec1" 1 + gdb_py_test_silent_cmd "print vec_data_1" "print value (vec_data_1)" 1 + gdb_py_test_silent_cmd "python vec_data_1 = gdb.history (0)" "get value (vec_data_1) from history" 1 + + gdb_py_test_silent_cmd "print vec_data_2" "print value (vec_data_2)" 1 + gdb_py_test_silent_cmd "python vec_data_2 = gdb.history (0)" "get value (vec_data_2) from history" 1 + + gdb_py_test_silent_cmd "python vec1 = vec_data_1.cast(ar\[0\].type.vector(1))" "set vec1" 1 gdb_test "python print vec1" ".1, 1." "cast to vector with one argument" - gdb_py_test_silent_cmd \ - "python vec2 = ar\[0\].cast(ar\[0\].type.vector(0, 1))" "set vec2" 1 + gdb_py_test_silent_cmd "python vec2 = vec_data_1.cast(ar\[0\].type.vector(0, 1))" "set vec2" 1 gdb_test "python print vec2" ".1, 1." "cast to vector with two arguments" gdb_test "python print vec1 == vec2" "True" - gdb_py_test_silent_cmd \ - "python vec3 = ar\[1\].cast(ar\[1\].type.vector(1))" "set vec3" 1 + gdb_py_test_silent_cmd "python vec3 = vec_data_2.cast(ar\[0\].type.vector(1))" "set vec3" 1 gdb_test "python print vec1 == vec3" "False" }