Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Feb 2017 12:15:43 +0200
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   Re: svn commit: r314087 - head/sys/x86/x86
Message-ID:  <20170225101543.GC2092@kib.kiev.ua>
In-Reply-To: <20170225130549.C1026@besplex.bde.org>
References:  <201702220707.v1M7764i020598@repo.freebsd.org> <20170223053954.J1044@besplex.bde.org> <20170224125335.GV2092@kib.kiev.ua> <20170225130549.C1026@besplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Feb 25, 2017 at 02:17:23PM +1100, Bruce Evans wrote:
> On Fri, 24 Feb 2017, Konstantin Belousov wrote:
> 
> > On Thu, Feb 23, 2017 at 06:33:43AM +1100, Bruce Evans wrote:
> >> On Wed, 22 Feb 2017, Konstantin Belousov wrote:
> >>
> >>> Log:
> >>>  More fixes for regression in r313898 on i386.
> >>>  Use long long constants where needed.
> >>
> >> The long long abomination is never needed, and is always a style bug.
> > I never saw any explanation behind this claim.  Esp. the first part
> > of it, WRT 'never needed'.
> 
> I hope I wrote enough about this in log messages when I cleaned up the
> long longs 20 years ago :-).
> 
> long long was a hack to work around intmax_t not existing and long being
> unexpandable in practice because it was used in ABIs.  It should have gone
> away when intmax_t was standardized.  Unfortunately, long long was
> standardised too.
It does not make a sense even more.  long long is native compiler type,
while anything_t is a typename to provide MI fixed type.  long long was
obviosvly choosen to extend types without requiring new keyword.

> 
> It is "never needed" since anything that can be done with it can be done
> better using intmax_t or intN_t or int_fastN_T or int_leastN_t.  Except,
> there is no suffix for explicit intmax_t constants, so you would have to
> write such constants using INTMAX_C() or better a cast to intmax_t if
> the constant is not needed in a cpp expression.
If you replace long long with int there, the same logical structure of
sentences will hold.  Does it mean that 'int' is abomination since we
have int32_t which allows everything to be done better ?

> 
> >> I don't like using explicit long constants either.  Here the number of bits
> >> in the register is fixed by the hardware at 64.  The number of bits in a
> >> long on amd64 and a long on i386 is only fixed by ABI because the ABI is
> >> broken for historical reasons.
> > I really cannot make any sense of this statement.
> 
> To know that the ULL suffix is correct for 64-bit types, you have to now
> that long longs are 64 bits on all arches supported by the code.  Then
> to use this suffix, you have to hard-code this knowledge.  Then to read
> the code, the reader has to translate back to 64 bits.  The translations
> were easier 1 arch at a time.
And why it is bad ?  Same is true for int and long, which are often used
in MD code to provide specific word size.  In fact, there is not much for
a programmer to know: we and any other UNIX supports either ILP32 or LP64
for the given architecture.

> Casting to uint64_t is clearer, but doesn't
> work in cpp expressions.  In cpp expressions, use UINT64_C().  Almost no
> one knows about it uses this.  There are 5 examples of using it in /sys
> (3 in arm64 pte.h, 1 in powerpc pte.h, and 1 in mips xlr_machdep.c,
> where the use is unnecessary but interesting: it is ~UINT64_C(0).  We
> used to have squillions of magic ~0's for the rman max limit.  This was
> spelled ~0U, ~0UL and perhaps even plain ~0.  Plain ~0 worked best except
> on unsupported 1's complement machines, since it normally gets sign extended
> to as many bits as necessary.  Now this is spelled RM_MAX_END, which is
> implemented non-magically using a cast: (~(rman_res_t)0).  Grepping for
> ~0[uU] in dev/* shows only 1 obvious unconverted place.
This clearly demonstrates why ULL/UL notation is superior to UINT64_C() or
any other obfuscation.

> 
> >>  Only very MD code can safely assume the
> >> size of long and long long.  This code was MD enough before it was merged,
> >> but now it shouldn't use long since that varies between amd64 and i386,
> >> and it shouldn't use long long since that is a style bug.
> >
> > Well, I do not see anything wrong with long long, at least until
> > explained.
> >
> > Anyway, below is the patch to use uint64_t cast in important place,
> > and removal of LL suffix in unimportant expression.
> 
> This is correct.
> 
> > diff --git a/sys/x86/x86/x86_mem.c b/sys/x86/x86/x86_mem.c
> > index d639224f840..8bc4d3917a0 100644
> > --- a/sys/x86/x86/x86_mem.c
> > +++ b/sys/x86/x86/x86_mem.c
> > @@ -260,7 +260,7 @@ x86_mrfetch(struct mem_range_softc *sc)
> >
> > 		/* Compute the range from the mask. Ick. */
> > 		mrd->mr_len = (~(msrv & mtrr_physmask) &
> > -		    (mtrr_physmask | 0xfffLL)) + 1;
> > +		    (mtrr_physmask | 0xfff)) + 1;
> > 		if (!mrvalid(mrd->mr_base, mrd->mr_len))
> > 			mrd->mr_flags |= MDF_BOGUS;
> >
> > @@ -638,7 +638,8 @@ x86_mrinit(struct mem_range_softc *sc)
> > 	 * Determine the size of the PhysMask and PhysBase fields in
> > 	 * the variable range MTRRs.
> > 	 */
> > -	mtrr_physmask = (((uint64_t)1 << cpu_maxphyaddr) - 1) & ~0xfffULL;
> > +	mtrr_physmask = (((uint64_t)1 << cpu_maxphyaddr) - 1) &
> > +	    ~(uint64_t)0xfff;
> >
> > 	/* If fixed MTRRs supported and enabled. */
> > 	if ((mtrrcap & MTRR_CAP_FIXED) && (mtrrdef & MTRR_DEF_FIXED_ENABLE)) {
> 
> Now I wonder what these magic 0xfff's are.  Are they PAGE_MASK, where the
> register is encoded like a page table to put metadata in the low bits?
Many Intel registers have a structure where bits N:12 denote a physical
address aligned at page boundary, and bits 11:0 are used for attributes
not directly related to addresses. We do not use PAGE_MASK there
traditionally, PAGE_MASK is only used to mask the page offset in actual
virtual address.

> 
> There is already a macro MTRR_PHYSBASE_PHYSMASK which looks like it should
> be used here, except it is zero in the top 12 bits too.
> 
> There is no macro for 0xfff, but you get that by ORing the bits for other
> macros.  0xfff is just as readable.
> 
> The MTRR_* macros are in x86/specialreg.h, and are spelled without ULL
> suffixes.  I prefer the latter, but seem to rememeber bugs elsewhere
> caused by using expressions like ~FOO where FOO happens to be small.
> Actually the problems are mostly when FOO happens to be between
> INT_MAX+1U and UINT_MAX.  When FOO is small and has no suffix, e.g.,
> if it is 0, then its type is int and ~FOO has type int and sign-extends
> to 64 bits if necessary.  But if FOO is say 0x80000000, it has type u_int
> so ~FOO doesn't sign-extend.  (Decimal constants without a suffix never
> have an unsigned type and the hex constant here lets me write this number
> and automatically give it an unsigned type.  Normally this type is best.)
> 
> Explicit type suffixes mainly hide these problems.  If FOO is 0x80000000ULL,
> then it has the correct type for ~FOO to work in expressions where everything
> has type unsigned long long, but in other expressions a cast might still
> be needed.
Yes, yet another (and most useful) reason to use ULL and ignore a FUD about it.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170225101543.GC2092>