From owner-cvs-all@FreeBSD.ORG Fri Mar 7 04:26:40 2008 Return-Path: Delivered-To: cvs-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A97861065670; Fri, 7 Mar 2008 04:26:40 +0000 (UTC) (envelope-from brde@optusnet.com.au) Received: from mail17.syd.optusnet.com.au (mail17.syd.optusnet.com.au [211.29.132.198]) by mx1.freebsd.org (Postfix) with ESMTP id 4220F8FC12; Fri, 7 Mar 2008 04:26:40 +0000 (UTC) (envelope-from brde@optusnet.com.au) Received: from c220-239-252-11.carlnfd3.nsw.optusnet.com.au (c220-239-252-11.carlnfd3.nsw.optusnet.com.au [220.239.252.11]) by mail17.syd.optusnet.com.au (8.13.1/8.13.1) with ESMTP id m274QZMf006276 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 7 Mar 2008 15:26:36 +1100 Date: Fri, 7 Mar 2008 15:26:35 +1100 (EST) From: Bruce Evans X-X-Sender: bde@delplex.bde.org To: Colin Percival In-Reply-To: <47CF5AE8.2090101@freebsd.org> Message-ID: <20080307135800.V11489@delplex.bde.org> References: <200803051121.m25BLE03035426@repoman.freebsd.org> <47CE8396.6020803@freebsd.org> <20080306095645.V7605@delplex.bde.org> <47CF5AE8.2090101@freebsd.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Cc: cvs-src@freebsd.org, cvs-all@freebsd.org, src-committers@freebsd.org, Bruce Evans , Bruce Evans Subject: Re: cvs commit: src/sys/i386/include _types.h X-BeenThere: cvs-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: CVS commit messages for the entire tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Mar 2008 04:26:40 -0000 On Wed, 5 Mar 2008, Colin Percival wrote: > Bruce Evans wrote: >> On Wed, 5 Mar 2008, Colin Percival wrote: >>> Bruce Evans wrote: >>>> Change float_t and double_t to long double on i386. >>> >>> Doesn't this have a rather severe performance impact on any code which >>> uses double_t? >> >> No. As mentioned in the commit message, this has no performance effect >> except in cases where it avoids compiler bugs. [...] if you use long double >> for memory variables then you get a severe performance impact and some >> space loss for the load instruction, since loading long doubles is >> much slower than loading doubles (about 4 times slower on Athlons). > > Either I'm misunderstanding something, or you seem to be disagreeing with > yourself here... if I have the following code > > double_t foo, bar, foobar; > foobar = foo + bar; > > then prior to this change the processor loads and stores doubles, while > after this change the processor loads and stores long doubles, with the > associated performance penalty. Low quality code might do that :-). Hmm, I thought that these types were intended to be used to avoid loss of precision in intermediate values, and thus should only be used in code that wants the extra precision at a possible cost in efficiency, but C99 (n869.txt draft) doesn't say exactly this, and a footnote (which is not part of the standard) says that they are trhe most efficient types that are wider than the basic types. It specifies them fully if FLT_EVAL_METHOD is 0, 1 or 2, but weird machines like i386 with 53-bit default precision plus compiler bugs must define FLT_EVAL_METHOD as -1. Then these types are implementation-defined and are not specifically required to be wider than the evaluation method types. I think they should be specifically required to be the most efficient types wider than the evaluation method types. Back to performance penalties... It is extremely unclear what are the most efficient types. Your example is too simple for there to be any stores if double_t is long double: > double_t foo, bar, foobar; > foobar = foo + bar; o Efficiency of double_t for foo and bar depends on where they came from. If they are long doubles in memory initially here, then loading them is slow. If they are in registers initially here, then there is no load to worry about and their type doesn't matter from now on, but their type may have affected previous loads and stores like subsequent use of foobar will (see below). o foo + bar is evaluated in registers (except i386 also allows adds from a value in memory to a value in a register if the memory type is not long double). It essentially has type long double, perhaps rounded to 53-bit or 24-bit precision. o Assignment to foobar requires a conversion from long double to double_t. If double_t is long double, then this conversion is null and foobar normally stays in the register. Otherwise, the conversion is not null, but it won't be done here since all the variables have type double_t and the compiler doesn't really know the type of result of the addition (it thinks that double + double gives double). A C compiler would know that the result is long double and always do the conversion if double_t is only double. o Here is an example of why a conversion is necessary on i386 unless all types are long double: double x = DBL_MAX, y = DBL_MAX, z; z = DBL_MAX + DBL_MAX; // should be +Inf/FE_OVERFLOW but is 2.0L*DBL_MAX z = z - DBL_MAX; // should be +Inf/FE_OVERFLOW but is 1.0L*DBL_MAX The extra range of a long double gives this. 53-bit precision doesn't affect it, and a conversion on assignment is still strictly needed to give the correct results for the intermediate and final z. z = DBL_MAX + DBL_MAX - DBL_MAX; Now both DBL_MAX and +Inf/FE_OVERFLOW are correct results, depending on where double expressions are evaluated with extra range. o Now we have a double_t foobar, reloaded into a register if that is useful, and can probably use it as either a double or a long double at no extra cost, but if double_t is double and the compiler is a C compiler, then converting foobar to a double always cost a lot and usually wasted its extra range if not its extra precision. We should probably have used double_t throughout to avoid this... o .. however, if we use double_t too much, then it will be used for memory variables and the loads and stores for these will cost more than conversions to double and reloads. o However2, someday when 64-bit precision is supported, using double_t will be especially important for memory variables, to prevent unintended loss of precision. Bruce