From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29526 invoked by alias); 27 Jun 2014 10:30:24 -0000 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 Received: (qmail 29508 invoked by uid 89); 27 Jun 2014 10:30:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL,BAYES_00,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: glazunov.sibelius.xs4all.nl Received: from sibelius.xs4all.nl (HELO glazunov.sibelius.xs4all.nl) (83.163.83.176) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 27 Jun 2014 10:30:21 +0000 Received: from glazunov.sibelius.xs4all.nl (kettenis@localhost [127.0.0.1]) by glazunov.sibelius.xs4all.nl (8.14.5/8.14.3) with ESMTP id s5RAUExN005812; Fri, 27 Jun 2014 12:30:14 +0200 (CEST) Received: (from kettenis@localhost) by glazunov.sibelius.xs4all.nl (8.14.5/8.14.3/Submit) id s5RAUDJo025356; Fri, 27 Jun 2014 12:30:13 +0200 (CEST) Date: Fri, 27 Jun 2014 10:30:00 -0000 Message-Id: <201406271030.s5RAUDJo025356@glazunov.sibelius.xs4all.nl> From: Mark Kettenis To: lgustavo@codesourcery.com CC: gdb-patches@sourceware.org In-reply-to: <53ABB5B3.1070803@codesourcery.com> (message from Luis Machado on Thu, 26 Jun 2014 06:54:59 +0100) Subject: Re: [PATCH] Fix passing/returning of complex data for PowerPC 32-bit References: <53ABB5B3.1070803@codesourcery.com> X-SW-Source: 2014-06/txt/msg00930.txt.bz2 > Date: Thu, 26 Jun 2014 06:54:59 +0100 > From: Luis Machado > > The PowerPC 32-bit unified ABI states that there are two ways of passing > and returning complex type data: > > - Pointer, in a register, to a memory area. > - Data in registers. > > The problem is that it is not clear how to detect which variation a > program is using. GDB currently does a bit of both. It uses the first > mechanism for passing parameters and uses both to return data, depending > on the size of the data type. It is a bit messy because GDB is not > handling complex types explicitly. > > Checking the gdb.base/callfuncs.exp testcase for a PowerPC 32-bit > target, with code built with GCC, showed a few failures related to > complex types. > > This patch steers GDB towards what GCC seems to generate for PowerPC > 32-bit and handles complex type passing/return via general registers > (the second option). All failures are gone. > > The problem here is if some other target/compiler is using the other > variation. So, for those that have a PowerPC 32-bit handy, can you > confirm it works reliably? I'm thinking AIX, Darwin or some other eabi > target. AIX uses its own inplementations (rs6000_push_dummy_call and rs6000_return_value). And we don't support Darwin on PowerPC. > Otherwise, does this look reasonable? I agree that the "System V" support code should support the ATR-PASS-COMPLEX-IN-GPRS ABI Attribute. This is what the Linux ABI uses (it is included in ATR-LINUX) which pretty much is the direct succssor of the System V ABI (which didn't specify anything about complex floating-point support). If somebody really wants to support complex numbers on an embedded system that uses ATR-PASS-COMPLEX-AS-STRUCT, they'll have to implement an osabi sniffer for it and override the appropriate methods. Code generally looks good. Some nits below. The comments are a bit elaborate though. I'd cut them down a bit; see my suggestion below. > 2014-06-26 Luis Machado > > * ppc-sysv-tdep.c (ppc_sysv_abi_push_dummy_call): Explicitly > handle passing of complex arguments. > (do_ppc_sysv_return_value): Explicitly handle return of > complex types. > > diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c > index 1a880a6..2ea7796 100644 > --- a/gdb/ppc-sysv-tdep.c > +++ b/gdb/ppc-sysv-tdep.c > @@ -269,6 +269,57 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, > greg += 4; > } > } > + else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX) > + { > + int lgpr = 11; I'd simply use the constant 11 further down in the code instead of intruducing a new variable here. Matches the existing code better and makes it easier to verify the code. > + int type_size = TYPE_LENGTH (type); > + int ngpr = type_size / tdep->wordsize; > + > + /* The PowerPC Unified 32-bit ABI states that complex types should > + be handled in two different ways. Either they are passed via > + general registers or they are returned as a pointer, in a > + general register, to an area that contains the data. > + > + Unfortunately there is no straightforward way to decide what > + variation a program is using. Therefore we assume the GCC > + mechanism of passing the complex data in general registers. > + > + Float complex uses 2 consecutive GPR's. > + > + Double complex uses 4 consecutive GPR's. > + > + Long Double complex uses 4 or 8 consecutive GPR's, depending on > + whether the long double is represented as a double or as a > + 128-bit entity. > + > + Scalar-based complex types are passed in the same way as their > + floating point counterparts. */ /* The PowerPC Unified 32-bit ABI specifies two mutually conflicting conventions for passing and returning complex floating-point values. These values are either treated as if they were represented as a structure containing an array of size two of the corresponding floating-point types (as identified by the ATR-PASS-COMPLEX-AS-STRUCT ABI attribute) or passed in the GPRs (as identified by the ATR-PASS-COMPLEX-IN-GPRS ABI attribute). Since the latter convention is the default in GCC, and mandated by the Linux ABI, that's what we implement. */ > + > + /* Check if we should pass this parameter in registers or > + stack. */ > + if (ngpr + greg > lgpr) > + { > + /* Pass parameter in the stack. */ > + argoffset = align_up (argoffset, 8); > + if (write_pass) > + write_memory (sp + argoffset, val, len); > + argoffset += len; > + } > + else > + { > + /* Pass the parameter in registers. */ > + if (write_pass) > + { > + int i; > + > + for (i = 0; i < ngpr; i++) > + regcache_cooked_write (regcache, > + tdep->ppc_gp0_regnum + greg + i, > + val + i * 4); > + } > + greg += ngpr; > + } > + } > else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && len <= 8 > && !tdep->soft_float) > { > @@ -724,6 +775,45 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *func_type, > } > return RETURN_VALUE_REGISTER_CONVENTION; > } > + > + /* The PowerPC Unified 32-bit ABI handles return of complex types in two > + different ways. Either they are returned via general registers or they are > + returned as a pointer, in a general register, to an area that contains the > + data. > + > + Unfortunately there is no straightforward way to decide what variation a > + program is using. Therefore we assume the GCC mechanism of returning the > + complex data in general registers. > + > + Float complex uses 2 consecutive GPR's. > + > + Double complex uses 4 consecutive GPR's. > + > + Long Double complex uses 4 or 8 consecutive GPR's, depending on whether the > + long double is represented as a double or as a 128-bit entity. > + > + Scalar-based complex types are returned in the same way as their floating > + point counterparts. */ No real need to repeat all this. I'd say something like: /* The PowerPC Unified 32-bit specifies that complex floating-point values are returned in the GPRs for ATR-PASS-COMPLEX-IN-GPRS. */ is good enough here. > + if (TYPE_CODE (type) == TYPE_CODE_COMPLEX) > + { > + int i, nregs; > + int return_reg = tdep->ppc_gp0_regnum + 3; > + > + nregs = TYPE_LENGTH (type) / tdep->wordsize; > + > + for (i = 0; i < nregs; i++) > + { > + if (readbuf) > + regcache_cooked_read (regcache, return_reg + i, > + readbuf + i * tdep->wordsize); > + if (writebuf) > + regcache_cooked_write (regcache, return_reg + i, > + writebuf + i * tdep->wordsize); > + } > + > + return RETURN_VALUE_REGISTER_CONVENTION; > + } > + > if (TYPE_CODE (type) == TYPE_CODE_FLT > && TYPE_LENGTH (type) == 16 > && !tdep->soft_float