diff mbox

RFC: 40 bit integer support

Message ID 4E0E10C5.3000804@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt July 1, 2011, 6:24 p.m. UTC
Here's my current patch for 40 bit integer support. This requires the
11-patch GET_MODE_PRECISION series I just posted.

C6X supports 40-bit integers in hardware; well enough that the old COFF
ABI apparently defined "long" as a 40-bit type. Add and subtract have
widening variants that can be used to synthesize 40-bit operations.
Shifts and comparisons with small constants are supported directly.

Other DSP-type CPUs are also likely to have a use for such operations.
Blackfin has multiply-accumulate instructions with 40 bit accumulators.
ARM Xscale supports this as well.

I'm not really asking for approval for the patch just yet as it's
untested in a 4.7 tree (4.5 c6x-elf testing shows that it basically
works), and I'd like to have some more testcases first. However, it's
IMO close to where it should be, and it would be good to know now if
this will eventually be acceptable or not.

Points that may be interesting.
 * Should we add an __int40_t keyword, or just do a pushdecl for it?
   The patch currently does the latter to match __int128_t, but
   decimal float and fixed-point support uses keywords. This may make
   a difference for (existing) code using "unsigned __int40_t".
 * What should be the name of the new mode? I'm using PImode, hoping
   to evoke the number five, but XImode by analogy with 80-bit floats
   might also work.
 * The __INT40_C macros use a cast, since using a new suffix is likely
   to conflict with something defined by a future standard. This means
   they are not usable in CPP tests. The TI compiler defines them in
   the same way, however, and mentions DR209.  The link they give is
   defunct:
     http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_209.htm


Bernd
* doc/cpp.texi (__INT40_TYPE, __UINT40_TYPE__, __INT_LEAST40_TYPE__,
	__UINT_LEAST40_TYPE__, __INT_FAST40_TYPE__, __UINT_FAST40_TYPE__,
	__INT40_MAX__, __UINT40_MAX__, __INT_LEAST40_MAX__,
	__UINT_LEAST40_MAX__, __INT_FAST40_MAX__, __UINT_FAST40_MAX__,
	__INT40_C, __UINT40_C): Document.
	* doc/tm.texi.in (INT40_TYPE, UINT40_TYPE, INT_LEAST40_TYPE,
	UINT_LEAST40_TYPE, INT_FAST40_TYPE, UINT_FAST40_TYPE): Document.
	* doc/tm.texi: Regenerate.
	* defaults.h (INT40_TYPE, UINT40_TYPE, INT_LEAST40_TYPE,
	UINT_LEAST40_TYPE, INT_FAST40_TYPE, UINT_FAST40_TYPE): Default
	to NULL.
	* tree.h (enum tree_index): Add TI_INTPI_TYPE and TI_UINTPI_TYPE.
	(intPI_type-node, unsigned_intPI_type_node): New macros.
	* tree.c (build_common_tree_nodes): Build these nodes.
	* ginclude/stdint-gcc.h (int40_t, uint40_t, int_least40_t,
	uint_least40_t, int_fast40_t, uint_fast40_t): Define if the
	corresponding macro is set.
	(INT40_MAX, INT40_MIN, UINT40_MAX, INT_LEAST40_MAX, INT_LEAST40_MIN,
	UINT_LEAST40_MAX, INT_FAST40_MAX, INT_FAST40_MIN, UINT_FAST40_MAX,
	INT40_C, UINT40_C): Define if appropriate.
	* c-family/c-cppbuiltin.c (builtin_define_stdint_macros): Add
	40 bit integer macros.
	(type_suffix): Return NULL for PImode types.
	(builtin_define_constants): Handle NULL suffix.
	(builtin_define_type_minmax): Add 40 bit constants.  Handle
	NULL suffix.
	* machmode.def (PI): New mode.
	* varasm.c (assemble_integer): Handle modes that are wider
	than a word but not a multiple of the word size.
	* c-family/c-common.c (c_common_type_for_size): Return PImode types
	if appropriate.
	(c_common_type_for_mode): Handle PImode.
	(c_common_signed_or_unsigned_type): Handle PImode types.
	(c_common_nodes_and_builtins): Define __int40_t and __uint40_t
	if supported.  Build 40 bit type nodes if requested.
	(c_stddef_cpp_builtins): Define 40 bit type macros if the types
	are available.
	* c-family/c-common.h (enum c_tree_index): Add CTI_INT40_TYPE,
	CTI_UINT40_TYPE, CTI_INT_LEAST40_TYPE, CTI_UINT_LEAST40_TYPE,
	CTI_INT_FAST40_TYPE and CTI_UINT_FAST40_TYPE.
	(int40_type_node, uint40_type_node, int_least40_type_node,
	uint_least40_type_node, int_fast40_type_node,
	uint_fast40_type_node): Define.
	* config/softp-fp/floatpisf.c: New file.
	* config/softp-fp/floatunpisf.c: New file.
	* config/softp-fp/floatpidf.c: New file.
	* config/softp-fp/floatunpidf.c: New file.
	* config/softp-fp/floatpitf.c: New file.
	* config/softp-fp/floatunpitf.c: New file.
	* config/softp-fp/fixunssfpi.c: New file.
	* config/softp-fp/fixsfpi.c: New file.
	* config/softp-fp/fixunsdfpi.c: New file.
	* config/softp-fp/fixdfpi.c: New file.
	* config/softp-fp/fixunstfpi.c: New file.
	* config/softp-fp/fixtfpi.c: New file.
	* config/soft-fp/soft-fp.h (PItype, UPItype): Declare if we have
	them.
	(PI_BITS): New macro.
	* libgcc2.h (PItype, UPItype0: Declare if supported.
	(__mulpi3, __divpi3, __modpi3, __udivpi3, __umodpi3): Define and
	declare.
	* libgcc2.c (__mulpi3, __divpi3, __modpi3, __udivpi3, __umodpi3):
	New functions.

	gcc/testsuite/
	* gcc.dg/c99-stdint-1.c (test_exact, test_least, test_fsat,
	test_max, test_constants): Add tests and comments for 40 bit
	integers.
	* gcc.dg/c99-stdint-3.c (check_corresponding): Add tests for
	40 bit integers.
	* gcc.dg/c99-stdint-7.c: Add comments about 40 bit integers.
	* gcc.dg/shift-pi.c: New test.
	* gcc.dg/arith-rand-40.c: New test.
	* gcc.dg/arith40.c: New test.
	* lib/target-supports.exp (check_effective_target_int40): New
	function.

	libgcc/
	* Makefile.in (lib2funcs): Add LIB2_PI_FUNCS.
	* config/t-pimode: New file.

Comments

Joseph Myers July 1, 2011, 7:49 p.m. UTC | #1
On Fri, 1 Jul 2011, Bernd Schmidt wrote:

>  * Should we add an __int40_t keyword, or just do a pushdecl for it?
>    The patch currently does the latter to match __int128_t, but
>    decimal float and fixed-point support uses keywords. This may make
>    a difference for (existing) code using "unsigned __int40_t".

My advice is neither, initially; leave it to the user to define typedefs 
using the mode (possibly providing a header that the user can include with 
-include).  __int128_t is legacy and undocumented, with the __int128 
keyword (from the x86_64 ABI) being preferred.  I also don't recommend 
adding any types to stdint.h (so eliminating a lot more of the 
complexity); there is no requirement to have those types there, and in 
any case libc's stdint.h is used in most cases instead of GCC's.

>  * The __INT40_C macros use a cast, since using a new suffix is likely
>    to conflict with something defined by a future standard. This means
>    they are not usable in CPP tests. The TI compiler defines them in
>    the same way, however, and mentions DR209.  The link they give is
>    defunct:
>      http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_209.htm

Don't try to understand anything about stdint.h with reference to C99 
versions before TC3; there were several defects fixed in the TCs.  DR#209 
was fixed by correcting the definitions of the types produced from certain 
macros.

Yes, you need a way of producing something usable in #if to define such a 
macro.  This is evidence that the type does not belong in stdint.h....
Joseph Myers July 1, 2011, 8:04 p.m. UTC | #2
I should add: make the type, the new mode, the testcases etc. entirely 
target-specific; target-independent GCC should not need to know or care 
about the specifics of this type.  It's bad enough target-independent GCC 
knowing about HImode, SImode, DImode and TImode outside default target 
hook implementations for targets that use those modes.  And is there 
anything wrong with the existing PDImode name?

(It's not wrong to provide a PDImode-support file for libgcc in 
libgcc/config/, say, to be used by any targets that want to use such a 
type, but I think it's best kept separate from the main libgcc2.c and 
libgcc2.h.  And you won't get the PDImode changes into upstream glibc's 
soft-fp.h, which dictates defining things in sfp-machine.h just as is done 
for TImode types - the TImode soft-fp files are local to GCC.)
Bernd Schmidt July 1, 2011, 8:14 p.m. UTC | #3
On 07/01/11 22:04, Joseph S. Myers wrote:
> I should add: make the type, the new mode, the testcases etc. entirely 
> target-specific; target-independent GCC should not need to know or care 
> about the specifics of this type.  It's bad enough target-independent GCC 
> knowing about HImode, SImode, DImode and TImode outside default target 
> hook implementations for targets that use those modes.

The idea here is that there is more than one target that supports 40 bit
operations, so why shouldn't we have support for it in
target-independent code and libgcc? It differs from QI/HI/SImode etc. in
that the precision is known and not target-specific.

> And is there anything wrong with the existing PDImode name?

PDImode is so far always defined as MODE_PARTIAL_INT which is handled
quite differently (i.e. by not handling it very much at all). IMO it
would be a bad idea to overload the name.


Bernd
Paul Koning July 1, 2011, 8:18 p.m. UTC | #4
On Jul 1, 2011, at 4:14 PM, Bernd Schmidt wrote:

> On 07/01/11 22:04, Joseph S. Myers wrote:
>> I should add: make the type, the new mode, the testcases etc. entirely 
>> target-specific; target-independent GCC should not need to know or care 
>> about the specifics of this type.  It's bad enough target-independent GCC 
>> knowing about HImode, SImode, DImode and TImode outside default target 
>> hook implementations for targets that use those modes.
> 
> The idea here is that there is more than one target that supports 40 bit
> operations, so why shouldn't we have support for it in
> target-independent code and libgcc? It differs from QI/HI/SImode etc. in
> that the precision is known and not target-specific.
> 
>> And is there anything wrong with the existing PDImode name?
> 
> PDImode is so far always defined as MODE_PARTIAL_INT which is handled
> quite differently (i.e. by not handling it very much at all). IMO it
> would be a bad idea to overload the name.

Would it make sense to fix the "not much at all" problem?

	paul
Bernd Schmidt July 1, 2011, 8:18 p.m. UTC | #5
On 07/01/11 21:49, Joseph S. Myers wrote:
> On Fri, 1 Jul 2011, Bernd Schmidt wrote:
> 
>>  * Should we add an __int40_t keyword, or just do a pushdecl for it?
>>    The patch currently does the latter to match __int128_t, but
>>    decimal float and fixed-point support uses keywords. This may make
>>    a difference for (existing) code using "unsigned __int40_t".
> 
> My advice is neither, initially; leave it to the user to define typedefs 
> using the mode (possibly providing a header that the user can include with 
> -include).  __int128_t is legacy and undocumented, with the __int128 
> keyword (from the x86_64 ABI) being preferred.  I also don't recommend 
> adding any types to stdint.h (so eliminating a lot more of the 
> complexity); there is no requirement to have those types there, 

Well, this was done for compatibility with an existing toolchain (which
unfortunately also allows "unsigned __int40_t"). I guess I could be
persuaded that we don't care enough and people must include
"c6x_intrinsics.h" when using gcc.

> and in any case libc's stdint.h is used in most cases instead of GCC's

That just means we'd have to modify newlib and uClibc as well if we
wanted to support this.

> Don't try to understand anything about stdint.h with reference to C99 
> versions before TC3; there were several defects fixed in the TCs.

Is this available anywhere (even if only inside CS?)


Bernd
Bernd Schmidt July 1, 2011, 8:22 p.m. UTC | #6
On 07/01/11 22:18, Paul Koning wrote:
>> PDImode is so far always defined as MODE_PARTIAL_INT which is handled
>> quite differently (i.e. by not handling it very much at all). IMO it
>> would be a bad idea to overload the name.
> 
> Would it make sense to fix the "not much at all" problem?

Ideally once I'm done with all this, people could change their PDImode
definitions to FRACTIONAL_INT_MODE with whatever precision they need.

It certainly would be nice if a suitable target maintainer applied my 11
patches and tried to test such a change :)


Bernd
Joseph Myers July 1, 2011, 8:36 p.m. UTC | #7
On Fri, 1 Jul 2011, Bernd Schmidt wrote:

> On 07/01/11 22:04, Joseph S. Myers wrote:
> > I should add: make the type, the new mode, the testcases etc. entirely 
> > target-specific; target-independent GCC should not need to know or care 
> > about the specifics of this type.  It's bad enough target-independent GCC 
> > knowing about HImode, SImode, DImode and TImode outside default target 
> > hook implementations for targets that use those modes.
> 
> The idea here is that there is more than one target that supports 40 bit
> operations, so why shouldn't we have support for it in
> target-independent code and libgcc? It differs from QI/HI/SImode etc. in
> that the precision is known and not target-specific.

Well, the idea of an integer mode with non-target-specific precision is 
pretty unusual in GCC; normally they are defined as a multiple of QImode 
(BITS_PER_UNIT).  And the existence of this mode is apparently 
target-specific even if its properties aren't.

Apart from the stdint.h code (inappropriate given the lack of a suffix, 
and where the proliferation of target macros etc. could be avoided once 
those macros are converted to hooks in some suitable way):

* The global tree nodes for various modes are suspicious.  Why are they 
needed at all?

* The c_common_type_for_size code using those nodes is suspicious.  Front 
ends shouldn't care about modes like that.  Check standard types, 
otherwise defer to something generic that loops over available types or 
modes or builds a type as needed.

Targets should be able to define integer types and modes as needed - but 
changing target-independent code for a particular type indicates something 
is wrong; I wouldn't expect any more target-independent changes than have 
been associated with floating-point types such as __fp16, __float80 or 
__float128.  There's the odd target hook, and it's necessary to tell 
libgcc what modes to build for (but in general you have a libgcc function 
implementation that can be used for more than one mode, depending on the 
properties of the types, rather than separate implementations per mode).  
Just as __float80 and __float128 are target-specific types defined by 
small amounts of target hook code on a couple of targets, I think 40-bit 
integers should also be like that.

> > And is there anything wrong with the existing PDImode name?
> 
> PDImode is so far always defined as MODE_PARTIAL_INT which is handled
> quite differently (i.e. by not handling it very much at all). IMO it
> would be a bad idea to overload the name.

What is the function of having both PARTIAL_INT_MODE and 
FRACTIONAL_INT_MODE?
Joseph Myers July 1, 2011, 8:48 p.m. UTC | #8
On Fri, 1 Jul 2011, Bernd Schmidt wrote:

> On 07/01/11 21:49, Joseph S. Myers wrote:
> > On Fri, 1 Jul 2011, Bernd Schmidt wrote:
> > 
> >>  * Should we add an __int40_t keyword, or just do a pushdecl for it?
> >>    The patch currently does the latter to match __int128_t, but
> >>    decimal float and fixed-point support uses keywords. This may make
> >>    a difference for (existing) code using "unsigned __int40_t".
> > 
> > My advice is neither, initially; leave it to the user to define typedefs 
> > using the mode (possibly providing a header that the user can include with 
> > -include).  __int128_t is legacy and undocumented, with the __int128 
> > keyword (from the x86_64 ABI) being preferred.  I also don't recommend 
> > adding any types to stdint.h (so eliminating a lot more of the 
> > complexity); there is no requirement to have those types there, 
> 
> Well, this was done for compatibility with an existing toolchain (which
> unfortunately also allows "unsigned __int40_t"). I guess I could be
> persuaded that we don't care enough and people must include
> "c6x_intrinsics.h" when using gcc.

Maybe there's a case for an __int40 keyword (and a built-in macro for 
__int40_t), but the point at which a second such keyword is added is the 
point to figure out a generic approach that also covers __int128, 
__float80 and __float128 - and doesn't need a load of code in the 
target-independent compiler for each type.  And I think that should really 
be kept separate from simply making the types work in the same way that 
TImode types worked for years (i.e. using mode attributes to access them, 
but having the required libgcc functions).

This patch does too much.  Once the series to make 40-bit types work is 
in, the next natural step would be adding such a type as target-specific.  
(FWIW, I wonder if all the new libgcc functions are really useful, or if 
the core compiler should just handle calling 64-bit functions and 
truncating as needed for most of the functions.)  When there are multiple 
targets, then share things between only the targets that need them.

> > Don't try to understand anything about stdint.h with reference to C99 
> > versions before TC3; there were several defects fixed in the TCs.
> 
> Is this available anywhere (even if only inside CS?)

C99+TC1+TC2+TC3 is WG14 document N1256, more readily available than the 
original C99.
Joseph Myers July 1, 2011, 9:07 p.m. UTC | #9
One more general point:

There are further issues around what we might call "extended types that 
behave much like integer and floating-point types", especially for C++; 
see my comment in PR 43622, and the references therein.  How to fix these 
(again, while avoiding hardcoding references to such types in 
target-independent code) should also be considered separately.
Bernd Schmidt July 1, 2011, 9:18 p.m. UTC | #10
On 07/01/11 22:36, Joseph S. Myers wrote:
> On Fri, 1 Jul 2011, Bernd Schmidt wrote:
>> The idea here is that there is more than one target that supports 40 bit
>> operations, so why shouldn't we have support for it in
>> target-independent code and libgcc? It differs from QI/HI/SImode etc. in
>> that the precision is known and not target-specific.
> 
> Well, the idea of an integer mode with non-target-specific precision is 
> pretty unusual in GCC; normally they are defined as a multiple of QImode 
> (BITS_PER_UNIT).

It's unusual only in terms of integer modes. It's analogous to decimal
float (where we also check targetm.scalar_mode_supported_p in the
frontend to determine whether to support it) or fixed-point support
(checked with targetm.fixed_point_supported_p, and the fixed-point modes
are all defined with specified precisions).

And even for integer modes, there's precedent with TI/__int128_t.

> And the existence of this mode is apparently target-specific even if
> its properties aren't.

Yes. That's probably a good way to think about it. Again, the analogy
would be decimal float or fixed-point.

> * The global tree nodes for various modes are suspicious.  Why are they 
> needed at all?

Do you mean only the PImode ones or also intQI_type_node etc.? These are
used to pick a suitable type in c_common_type_for_size.

> * The c_common_type_for_size code using those nodes is suspicious.  Front 
> ends shouldn't care about modes like that.

It doesn't care about the modes, it just picks a suitable one for a
given precision. Note that my patch does not introduce this mechanism,
it just extends it.

> Check standard types, 
> otherwise defer to something generic that loops over available types or 
> modes or builds a type as needed.

Please look at the code; this is exactly what is being done. The
function checks the standard types, and if it does not find one with an
exact match for the precision, it examines the available modes (exposed
through intQI_type_node etc.).

> Targets should be able to define integer types and modes as needed - but 
> changing target-independent code for a particular type indicates something 
> is wrong; I wouldn't expect any more target-independent changes than have 
> been associated with floating-point types such as __fp16, __float80 or 
> __float128.

That's because these all fall into the standard C type system of float,
double, long double.

> There's the odd target hook, and it's necessary to tell 
> libgcc what modes to build for (but in general you have a libgcc function 
> implementation that can be used for more than one mode, depending on the 
> properties of the types, rather than separate implementations per mode).  
> Just as __float80 and __float128 are target-specific types defined by 
> small amounts of target hook code on a couple of targets, I think 40-bit 
> integers should also be like that.

Floating point types tend not to be defined as bitfields, so naturally
there's no support in c_common_type_for_size. This is something that's
only useful for integer modes, and I don't think you can avoid this.

We could define such a type in each target that supports it, but since I
know about at least three machines where this particular feature exists,
I think it makes more sense to expose it in target-independent code. I
think doing this would also require uglier changes in
c_common_type_for_size.

If you subtract out all the INT_LEAST40_TYPE etc. support, there really
aren't very many changes in the C frontend, and I think the remaining
ones are just the same ones we have for TImode - pretty much unavoidable
for properly supporting a new integer type that is exposed to
programmers. I'll resubmit such a patch in the hope that it'll look more
palatable.

The fact that the libgcc implementations of typical functions can be
used with more than one mode depends on the fact that while we don't
know the exact size, we have a nice ladder of types where one is twice
as big as the next. int40_t falls outside of that.

> What is the function of having both PARTIAL_INT_MODE and 
> FRACTIONAL_INT_MODE?

Not having to change all the targets using PARTIAL_INT_MODE immediately
to use the better mechanism.


Bernd
Bernd Schmidt July 1, 2011, 9:35 p.m. UTC | #11
On 07/01/11 23:18, Bernd Schmidt wrote:
>> What is the function of having both PARTIAL_INT_MODE and 
>> FRACTIONAL_INT_MODE?
> 
> Not having to change all the targets using PARTIAL_INT_MODE immediately
> to use the better mechanism.

Also, come to think of it, preventing the rest of the compiler from
trying to use such a mode in case the target only supports some very
specific operations on it. A port could choose to use PImode, defined in
machmode.def (and get __int40_t support), or it could add its own
private PDImode to use in specific situations only.


Bernd
Joseph Myers July 1, 2011, 10:11 p.m. UTC | #12
On Fri, 1 Jul 2011, Bernd Schmidt wrote:

> > * The global tree nodes for various modes are suspicious.  Why are they 
> > needed at all?
> 
> Do you mean only the PImode ones or also intQI_type_node etc.? These are
> used to pick a suitable type in c_common_type_for_size.

All of them.

> > * The c_common_type_for_size code using those nodes is suspicious.  Front 
> > ends shouldn't care about modes like that.
> 
> It doesn't care about the modes, it just picks a suitable one for a
> given precision. Note that my patch does not introduce this mechanism,
> it just extends it.

I don't think anything would be worse without it being extended - these 
are generally places that would be improved by removing code for existing 
modes (maybe replaced by calls to build_nonstandard_integer_type if not 
already there) rather than adding it for more.  Removing this code would 
require some thought, but I don't think it needs adding to.

If logic for nonstandard precisions is needed and needs to do something 
other than call build_nonstandard_integer_type, a better approach might be 
a target-specific table (initialized by a target hook) of types to 
consider.  Most targets never need to consider intQI_type_node etc. since 
those types all correspond to some standard type, so rather than having 
the global nodes the hook would be responsible for entering those types in 
the table.  But since there are several such functions doing similar 
things, some thought should be given to avoiding duplication.

* For nonstandard types c_common_type_for_size only requires a number of 
bits <= to the precision of the mode.  I don't think it should matter that 
this would return a 64-bit type instead of a 40-bit one in some cases.

* For c_common_type_for_mode, after checking standard types it should just 
use some table of types for different modes that get built on demand then 
cached.  (Actually, put standard types there in appropriate order and then 
the function doesn't need to check them.)  However, the code checking 
registered_builtin_types will probably suffice for now if you make the 
target register the types in some way.

> > Check standard types, 
> > otherwise defer to something generic that loops over available types or 
> > modes or builds a type as needed.
> 
> Please look at the code; this is exactly what is being done. The
> function checks the standard types, and if it does not find one with an
> exact match for the precision, it examines the available modes (exposed
> through intQI_type_node etc.).

There are better ways of iterating through modes than hardcoding a list.

> > Targets should be able to define integer types and modes as needed - but 
> > changing target-independent code for a particular type indicates something 
> > is wrong; I wouldn't expect any more target-independent changes than have 
> > been associated with floating-point types such as __fp16, __float80 or 
> > __float128.
> 
> That's because these all fall into the standard C type system of float,
> double, long double.

No, in general they are different from those types.

> If you subtract out all the INT_LEAST40_TYPE etc. support, there really
> aren't very many changes in the C frontend, and I think the remaining
> ones are just the same ones we have for TImode - pretty much unavoidable
> for properly supporting a new integer type that is exposed to
> programmers. I'll resubmit such a patch in the hope that it'll look more

I think more is needed for a type wider than the standard types than for 
one within the range of precisions of standard types.
Joseph Myers July 1, 2011, 10:12 p.m. UTC | #13
On Fri, 1 Jul 2011, Bernd Schmidt wrote:

> On 07/01/11 23:18, Bernd Schmidt wrote:
> >> What is the function of having both PARTIAL_INT_MODE and 
> >> FRACTIONAL_INT_MODE?
> > 
> > Not having to change all the targets using PARTIAL_INT_MODE immediately
> > to use the better mechanism.
> 
> Also, come to think of it, preventing the rest of the compiler from
> trying to use such a mode in case the target only supports some very
> specific operations on it. A port could choose to use PImode, defined in

We have well-established ways of indicating supported operations with 
hooks (used for example to limit operations on __fpreg and __fp16 in the 
front ends) and optabs.
Bernd Schmidt July 1, 2011, 10:59 p.m. UTC | #14
On 07/02/11 00:11, Joseph S. Myers wrote:
> On Fri, 1 Jul 2011, Bernd Schmidt wrote:
> 
>>> * The global tree nodes for various modes are suspicious.  Why are they 
>>> needed at all?
>>
>> Do you mean only the PImode ones or also intQI_type_node etc.? These are
>> used to pick a suitable type in c_common_type_for_size.
> 
> All of them.
> 
>>> * The c_common_type_for_size code using those nodes is suspicious.  Front 
>>> ends shouldn't care about modes like that.
>>
>> It doesn't care about the modes, it just picks a suitable one for a
>> given precision. Note that my patch does not introduce this mechanism,
>> it just extends it.
> 
> I don't think anything would be worse without it being extended - these 
> are generally places that would be improved by removing code for existing 
> modes (maybe replaced by calls to build_nonstandard_integer_type if not 
> already there) rather than adding it for more.  Removing this code would 
> require some thought, but I don't think it needs adding to.

As far as I can tell, type_for_size is used in quite a few places for
optimizations. I've certainly seen intPI_type being used for 40-bit
bitfields, and also for bitsize-types used in variable-length array
calculations. There's a surprising amount of coverage in the testsuite
already using these two features. I suspect we'd lose that capability if
we don't extend this function.

> If logic for nonstandard precisions is needed and needs to do something 
> other than call build_nonstandard_integer_type, a better approach might be 
> a target-specific table (initialized by a target hook) of types to 
> consider.  Most targets never need to consider intQI_type_node etc. since 
> those types all correspond to some standard type, so rather than having 
> the global nodes the hook would be responsible for entering those types in 
> the table.  But since there are several such functions doing similar 
> things, some thought should be given to avoiding duplication.
> 
> * For nonstandard types c_common_type_for_size only requires a number of 
> bits <= to the precision of the mode.  I don't think it should matter that 
> this would return a 64-bit type instead of a 40-bit one in some cases.

See above. I think this loses optimization opportunities.

> * For c_common_type_for_mode, after checking standard types it should just 
> use some table of types for different modes that get built on demand then 
> cached.  (Actually, put standard types there in appropriate order and then 
> the function doesn't need to check them.)  However, the code checking 
> registered_builtin_types will probably suffice for now if you make the 
> target register the types in some way.

I'll think about this next week.


Bernd
Richard Biener July 2, 2011, 12:29 p.m. UTC | #15
On Sat, Jul 2, 2011 at 12:11 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Fri, 1 Jul 2011, Bernd Schmidt wrote:
>
>> > * The global tree nodes for various modes are suspicious.  Why are they
>> > needed at all?
>>
>> Do you mean only the PImode ones or also intQI_type_node etc.? These are
>> used to pick a suitable type in c_common_type_for_size.
>
> All of them.

Btw, I agree.  The type_for_size langhook shouldn't be used from the middle-end,
so the langhook should be restricted to handle those types the frontends use
the langhook for (which means, the language specific types available).

The middle-end uses of type-for-size should be all changed to
build_nonstandard_integer_type.

I think that in the end all global (middle-end visible) tree types
should be those
of the targets respective C ABI, thus those types necessary for example to
create the various builtins for the C library functions.

Thus, I don't understand why we have all those mode-specific global tree
type nodes.  In fact, most of them are not used at all.

Richard.
Richard Biener July 2, 2011, 12:32 p.m. UTC | #16
On Sat, Jul 2, 2011 at 12:59 AM, Bernd Schmidt <bernds@codesourcery.com> wrote:
> On 07/02/11 00:11, Joseph S. Myers wrote:
>> On Fri, 1 Jul 2011, Bernd Schmidt wrote:
>>
>>>> * The global tree nodes for various modes are suspicious.  Why are they
>>>> needed at all?
>>>
>>> Do you mean only the PImode ones or also intQI_type_node etc.? These are
>>> used to pick a suitable type in c_common_type_for_size.
>>
>> All of them.
>>
>>>> * The c_common_type_for_size code using those nodes is suspicious.  Front
>>>> ends shouldn't care about modes like that.
>>>
>>> It doesn't care about the modes, it just picks a suitable one for a
>>> given precision. Note that my patch does not introduce this mechanism,
>>> it just extends it.
>>
>> I don't think anything would be worse without it being extended - these
>> are generally places that would be improved by removing code for existing
>> modes (maybe replaced by calls to build_nonstandard_integer_type if not
>> already there) rather than adding it for more.  Removing this code would
>> require some thought, but I don't think it needs adding to.
>
> As far as I can tell, type_for_size is used in quite a few places for
> optimizations. I've certainly seen intPI_type being used for 40-bit
> bitfields, and also for bitsize-types used in variable-length array
> calculations. There's a surprising amount of coverage in the testsuite
> already using these two features. I suspect we'd lose that capability if
> we don't extend this function.

Using type_for_size is bogus, the middle-end should use
build_nonstandard_integer_type
instead.  It should already choose PDImode for 40-bit if available by the
code in layout_type().

Richard.
diff mbox

Patch

Index: gcc/doc/cpp.texi
===================================================================
--- gcc/doc/cpp.texi	(revision 325327)
+++ gcc/doc/cpp.texi	(working copy)
@@ -2122,46 +2122,55 @@  OSF/rose @option{-mno-underscores} optio
 @itemx __INT8_TYPE__
 @itemx __INT16_TYPE__
 @itemx __INT32_TYPE__
+@itemx __INT40_TYPE__
 @itemx __INT64_TYPE__
 @itemx __UINT8_TYPE__
 @itemx __UINT16_TYPE__
 @itemx __UINT32_TYPE__
+@itemx __UINT40_TYPE__
 @itemx __UINT64_TYPE__
 @itemx __INT_LEAST8_TYPE__
 @itemx __INT_LEAST16_TYPE__
 @itemx __INT_LEAST32_TYPE__
+@itemx __INT_LEAST40_TYPE__
 @itemx __INT_LEAST64_TYPE__
 @itemx __UINT_LEAST8_TYPE__
 @itemx __UINT_LEAST16_TYPE__
 @itemx __UINT_LEAST32_TYPE__
+@itemx __UINT_LEAST40_TYPE__
 @itemx __UINT_LEAST64_TYPE__
 @itemx __INT_FAST8_TYPE__
 @itemx __INT_FAST16_TYPE__
 @itemx __INT_FAST32_TYPE__
+@itemx __INT_FAST40_TYPE__
 @itemx __INT_FAST64_TYPE__
 @itemx __UINT_FAST8_TYPE__
 @itemx __UINT_FAST16_TYPE__
 @itemx __UINT_FAST32_TYPE__
+@itemx __UINT_FAST40_TYPE__
 @itemx __UINT_FAST64_TYPE__
 @itemx __INTPTR_TYPE__
 @itemx __UINTPTR_TYPE__
+
 These macros are defined to the correct underlying types for the
 @code{size_t}, @code{ptrdiff_t}, @code{wchar_t}, @code{wint_t},
 @code{intmax_t}, @code{uintmax_t}, @code{sig_atomic_t}, @code{int8_t},
-@code{int16_t}, @code{int32_t}, @code{int64_t}, @code{uint8_t},
-@code{uint16_t}, @code{uint32_t}, @code{uint64_t},
-@code{int_least8_t}, @code{int_least16_t}, @code{int_least32_t},
-@code{int_least64_t}, @code{uint_least8_t}, @code{uint_least16_t},
+@code{int16_t}, @code{int32_t}, @code{int32_t}, @code{int64_t},
+@code{uint8_t}, @code{uint16_t}, @code{uint32_t}, @code{uint32_t},
+@code{uint64_t}, @code{int_least8_t}, @code{int_least16_t},
+@code{int_least32_t}, @code{int_least32_t}, @code{int_least64_t},
+@code{uint_least8_t}, @code{uint_least16_t}, @code{uint_least32_t},
 @code{uint_least32_t}, @code{uint_least64_t}, @code{int_fast8_t},
-@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast64_t},
-@code{uint_fast8_t}, @code{uint_fast16_t}, @code{uint_fast32_t},
-@code{uint_fast64_t}, @code{intptr_t}, and @code{uintptr_t} typedefs,
-respectively.  They exist to make the standard header files
-@file{stddef.h}, @file{stdint.h}, and @file{wchar.h} work correctly.
-You should not use these macros directly; instead, include the
-appropriate headers and use the typedefs.  Some of these macros may
-not be defined on particular systems if GCC does not provide a
-@file{stdint.h} header on those systems.
+@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast32_t},
+@code{int_fast64_t}, @code{uint_fast8_t}, @code{uint_fast16_t},
+@code{uint_fast32_t}, @code{uint_fast32_t}, @code{uint_fast64_t},
+@code{intptr_t}, and @code{uintptr_t} typedefs, respectively.  They
+exist to make the standard header files @file{stddef.h},
+@file{stdint.h}, and @file{wchar.h} work correctly.  You should not use
+these macros directly; instead, include the appropriate headers and use
+the typedefs.  Some of these macros may not be defined on particular
+systems if GCC does not provide a @file{stdint.h} header on those
+systems.
 
 @item __CHAR_BIT__
 Defined to the number of bits used in the representation of the
@@ -2184,26 +2193,32 @@  this macro directly; instead, include th
 @itemx __INT8_MAX__
 @itemx __INT16_MAX__
 @itemx __INT32_MAX__
+@itemx __INT40_MAX__
 @itemx __INT64_MAX__
 @itemx __UINT8_MAX__
 @itemx __UINT16_MAX__
 @itemx __UINT32_MAX__
+@itemx __UINT40_MAX__
 @itemx __UINT64_MAX__
 @itemx __INT_LEAST8_MAX__
 @itemx __INT_LEAST16_MAX__
 @itemx __INT_LEAST32_MAX__
+@itemx __INT_LEAST40_MAX__
 @itemx __INT_LEAST64_MAX__
 @itemx __UINT_LEAST8_MAX__
 @itemx __UINT_LEAST16_MAX__
 @itemx __UINT_LEAST32_MAX__
+@itemx __UINT_LEAST40_MAX__
 @itemx __UINT_LEAST64_MAX__
 @itemx __INT_FAST8_MAX__
 @itemx __INT_FAST16_MAX__
 @itemx __INT_FAST32_MAX__
+@itemx __INT_FAST40_MAX__
 @itemx __INT_FAST64_MAX__
 @itemx __UINT_FAST8_MAX__
 @itemx __UINT_FAST16_MAX__
 @itemx __UINT_FAST32_MAX__
+@itemx __UINT_FAST40_MAX__
 @itemx __UINT_FAST64_MAX__
 @itemx __INTPTR_MAX__
 @itemx __UINTPTR_MAX__
@@ -2215,13 +2230,13 @@  Defined to the maximum value of the @cod
 @code{signed int}, @code{signed long}, @code{signed long long},
 @code{wint_t}, @code{size_t}, @code{ptrdiff_t},
 @code{intmax_t}, @code{uintmax_t}, @code{sig_atomic_t}, @code{int8_t},
-@code{int16_t}, @code{int32_t}, @code{int64_t}, @code{uint8_t},
-@code{uint16_t}, @code{uint32_t}, @code{uint64_t},
-@code{int_least8_t}, @code{int_least16_t}, @code{int_least32_t},
-@code{int_least64_t}, @code{uint_least8_t}, @code{uint_least16_t},
-@code{uint_least32_t}, @code{uint_least64_t}, @code{int_fast8_t},
-@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast64_t},
-@code{uint_fast8_t}, @code{uint_fast16_t}, @code{uint_fast32_t},
+@code{int16_t}, @code{int32_t},  @code{int40_t}, @code{int64_t}, @code{uint8_t},
+@code{uint16_t}, @code{uint32_t}, @code{uint40_t}, @code{uint64_t},
+@code{int_least8_t}, @code{int_least16_t}, @code{int_least32_t}, @code{int_least40_t},
+@code{int_least64_t}, @code{uint_least8_t}, @code{uint_least16_t}, @code{uint_least32_t},
+@code{uint_least40_t}, @code{uint_least64_t}, @code{int_fast8_t},
+@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast40_t}, @code{int_fast64_t},
+@code{uint_fast8_t}, @code{uint_fast16_t}, @code{uint_fast32_t}, @code{uint_fast40_t},
 @code{uint_fast64_t}, @code{intptr_t}, and @code{uintptr_t} types and
 to the minimum value of the @code{wchar_t}, @code{wint_t}, and
 @code{sig_atomic_t} types respectively.  They exist to make the
@@ -2233,9 +2248,11 @@  does not provide a @file{stdint.h} heade
 @item __INT8_C
 @itemx __INT16_C
 @itemx __INT32_C
+@itemx __INT40_C
 @itemx __INT64_C
 @itemx __UINT8_C
 @itemx __UINT16_C
+@itemx __UINT40_C
 @itemx __UINT32_C
 @itemx __UINT64_C
 @itemx __INTMAX_C
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 327382)
+++ gcc/doc/tm.texi	(working copy)
@@ -1820,39 +1820,47 @@  int}.
 @defmacx INT8_TYPE
 @defmacx INT16_TYPE
 @defmacx INT32_TYPE
+@defmacx INT40_TYPE
 @defmacx INT64_TYPE
 @defmacx UINT8_TYPE
 @defmacx UINT16_TYPE
 @defmacx UINT32_TYPE
+@defmacx UINT40_TYPE
 @defmacx UINT64_TYPE
 @defmacx INT_LEAST8_TYPE
 @defmacx INT_LEAST16_TYPE
 @defmacx INT_LEAST32_TYPE
+@defmacx INT_LEAST40_TYPE
 @defmacx INT_LEAST64_TYPE
 @defmacx UINT_LEAST8_TYPE
 @defmacx UINT_LEAST16_TYPE
 @defmacx UINT_LEAST32_TYPE
+@defmacx UINT_LEAST40_TYPE
 @defmacx UINT_LEAST64_TYPE
 @defmacx INT_FAST8_TYPE
 @defmacx INT_FAST16_TYPE
 @defmacx INT_FAST32_TYPE
+@defmacx INT_FAST40_TYPE
 @defmacx INT_FAST64_TYPE
 @defmacx UINT_FAST8_TYPE
 @defmacx UINT_FAST16_TYPE
 @defmacx UINT_FAST32_TYPE
+@defmacx UINT_FAST40_TYPE
 @defmacx UINT_FAST64_TYPE
 @defmacx INTPTR_TYPE
 @defmacx UINTPTR_TYPE
-C expressions for the standard types @code{sig_atomic_t},
-@code{int8_t}, @code{int16_t}, @code{int32_t}, @code{int64_t},
-@code{uint8_t}, @code{uint16_t}, @code{uint32_t}, @code{uint64_t},
-@code{int_least8_t}, @code{int_least16_t}, @code{int_least32_t},
-@code{int_least64_t}, @code{uint_least8_t}, @code{uint_least16_t},
-@code{uint_least32_t}, @code{uint_least64_t}, @code{int_fast8_t},
-@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast64_t},
-@code{uint_fast8_t}, @code{uint_fast16_t}, @code{uint_fast32_t},
-@code{uint_fast64_t}, @code{intptr_t}, and @code{uintptr_t}.  See
-@code{SIZE_TYPE} above for more information.
+C expressions for the standard types @code{sig_atomic_t}, @code{int8_t},
+@code{int16_t}, @code{int32_t}, @code{int40_t}, @code{int64_t},
+@code{uint8_t}, @code{uint16_t}, @code{uint32_t}, @code{uint40_t},
+@code{uint64_t}, @code{int_least8_t}, @code{int_least16_t},
+@code{int_least32_t}, @code{int_least40_t}, @code{int_least64_t},
+@code{uint_least8_t}, @code{uint_least16_t}, @code{uint_least32_t},
+@code{uint_least40_t}, @code{uint_least64_t}, @code{int_fast8_t},
+@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast40_t},
+@code{int_fast64_t}, @code{uint_fast8_t}, @code{uint_fast16_t},
+@code{uint_fast32_t}, @code{uint_fast40_t}, @code{uint_fast64_t},
+@code{intptr_t}, and @code{uintptr_t}.  See @code{SIZE_TYPE} above for
+more information.
 
 If any of these macros evaluates to a null pointer, the corresponding
 type is not supported; if GCC is configured to provide
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 327382)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -1820,39 +1820,47 @@  int}.
 @defmacx INT8_TYPE
 @defmacx INT16_TYPE
 @defmacx INT32_TYPE
+@defmacx INT40_TYPE
 @defmacx INT64_TYPE
 @defmacx UINT8_TYPE
 @defmacx UINT16_TYPE
 @defmacx UINT32_TYPE
+@defmacx UINT40_TYPE
 @defmacx UINT64_TYPE
 @defmacx INT_LEAST8_TYPE
 @defmacx INT_LEAST16_TYPE
 @defmacx INT_LEAST32_TYPE
+@defmacx INT_LEAST40_TYPE
 @defmacx INT_LEAST64_TYPE
 @defmacx UINT_LEAST8_TYPE
 @defmacx UINT_LEAST16_TYPE
 @defmacx UINT_LEAST32_TYPE
+@defmacx UINT_LEAST40_TYPE
 @defmacx UINT_LEAST64_TYPE
 @defmacx INT_FAST8_TYPE
 @defmacx INT_FAST16_TYPE
 @defmacx INT_FAST32_TYPE
+@defmacx INT_FAST40_TYPE
 @defmacx INT_FAST64_TYPE
 @defmacx UINT_FAST8_TYPE
 @defmacx UINT_FAST16_TYPE
 @defmacx UINT_FAST32_TYPE
+@defmacx UINT_FAST40_TYPE
 @defmacx UINT_FAST64_TYPE
 @defmacx INTPTR_TYPE
 @defmacx UINTPTR_TYPE
-C expressions for the standard types @code{sig_atomic_t},
-@code{int8_t}, @code{int16_t}, @code{int32_t}, @code{int64_t},
-@code{uint8_t}, @code{uint16_t}, @code{uint32_t}, @code{uint64_t},
-@code{int_least8_t}, @code{int_least16_t}, @code{int_least32_t},
-@code{int_least64_t}, @code{uint_least8_t}, @code{uint_least16_t},
-@code{uint_least32_t}, @code{uint_least64_t}, @code{int_fast8_t},
-@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast64_t},
-@code{uint_fast8_t}, @code{uint_fast16_t}, @code{uint_fast32_t},
-@code{uint_fast64_t}, @code{intptr_t}, and @code{uintptr_t}.  See
-@code{SIZE_TYPE} above for more information.
+C expressions for the standard types @code{sig_atomic_t}, @code{int8_t},
+@code{int16_t}, @code{int32_t}, @code{int40_t}, @code{int64_t},
+@code{uint8_t}, @code{uint16_t}, @code{uint32_t}, @code{uint40_t},
+@code{uint64_t}, @code{int_least8_t}, @code{int_least16_t},
+@code{int_least32_t}, @code{int_least40_t}, @code{int_least64_t},
+@code{uint_least8_t}, @code{uint_least16_t}, @code{uint_least32_t},
+@code{uint_least40_t}, @code{uint_least64_t}, @code{int_fast8_t},
+@code{int_fast16_t}, @code{int_fast32_t}, @code{int_fast40_t},
+@code{int_fast64_t}, @code{uint_fast8_t}, @code{uint_fast16_t},
+@code{uint_fast32_t}, @code{uint_fast40_t}, @code{uint_fast64_t},
+@code{intptr_t}, and @code{uintptr_t}.  See @code{SIZE_TYPE} above for
+more information.
 
 If any of these macros evaluates to a null pointer, the corresponding
 type is not supported; if GCC is configured to provide
Index: gcc/defaults.h
===================================================================
--- gcc/defaults.h	(revision 325327)
+++ gcc/defaults.h	(working copy)
@@ -589,6 +589,10 @@  see the files COPYING3 and COPYING.RUNTI
 #define INT32_TYPE ((const char *) NULL)
 #endif
 
+#ifndef INT40_TYPE
+#define INT40_TYPE ((const char *) NULL)
+#endif
+
 #ifndef INT64_TYPE
 #define INT64_TYPE ((const char *) NULL)
 #endif
@@ -605,6 +609,10 @@  see the files COPYING3 and COPYING.RUNTI
 #define UINT32_TYPE ((const char *) NULL)
 #endif
 
+#ifndef UINT40_TYPE
+#define UINT40_TYPE ((const char *) NULL)
+#endif
+
 #ifndef UINT64_TYPE
 #define UINT64_TYPE ((const char *) NULL)
 #endif
@@ -621,6 +629,10 @@  see the files COPYING3 and COPYING.RUNTI
 #define INT_LEAST32_TYPE ((const char *) NULL)
 #endif
 
+#ifndef INT_LEAST40_TYPE
+#define INT_LEAST40_TYPE ((const char *) NULL)
+#endif
+
 #ifndef INT_LEAST64_TYPE
 #define INT_LEAST64_TYPE ((const char *) NULL)
 #endif
@@ -637,6 +649,10 @@  see the files COPYING3 and COPYING.RUNTI
 #define UINT_LEAST32_TYPE ((const char *) NULL)
 #endif
 
+#ifndef UINT_LEAST40_TYPE
+#define UINT_LEAST40_TYPE ((const char *) NULL)
+#endif
+
 #ifndef UINT_LEAST64_TYPE
 #define UINT_LEAST64_TYPE ((const char *) NULL)
 #endif
@@ -653,6 +669,10 @@  see the files COPYING3 and COPYING.RUNTI
 #define INT_FAST32_TYPE ((const char *) NULL)
 #endif
 
+#ifndef INT_FAST40_TYPE
+#define INT_FAST40_TYPE ((const char *) NULL)
+#endif
+
 #ifndef INT_FAST64_TYPE
 #define INT_FAST64_TYPE ((const char *) NULL)
 #endif
@@ -669,6 +689,10 @@  see the files COPYING3 and COPYING.RUNTI
 #define UINT_FAST32_TYPE ((const char *) NULL)
 #endif
 
+#ifndef UINT_FAST40_TYPE
+#define UINT_FAST40_TYPE ((const char *) NULL)
+#endif
+
 #ifndef UINT_FAST64_TYPE
 #define UINT_FAST64_TYPE ((const char *) NULL)
 #endif
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 327382)
+++ gcc/tree.c	(working copy)
@@ -8822,12 +8822,14 @@  build_common_tree_nodes (bool signed_cha
   intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 0);
   intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 0);
   intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 0);
+  intPI_type_node = build_nonstandard_integer_type (40, false);
 
   unsigned_intQI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (QImode), 1);
   unsigned_intHI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (HImode), 1);
   unsigned_intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 1);
   unsigned_intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 1);
   unsigned_intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 1);
+  unsigned_intPI_type_node = build_nonstandard_integer_type (40, true);
 
   access_public_node = get_identifier ("public");
   access_protected_node = get_identifier ("protected");
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 325327)
+++ gcc/tree.h	(working copy)
@@ -3415,12 +3415,14 @@  enum tree_index
   TI_INTSI_TYPE,
   TI_INTDI_TYPE,
   TI_INTTI_TYPE,
+  TI_INTPI_TYPE,
 
   TI_UINTQI_TYPE,
   TI_UINTHI_TYPE,
   TI_UINTSI_TYPE,
   TI_UINTDI_TYPE,
   TI_UINTTI_TYPE,
+  TI_UINTPI_TYPE,
 
   TI_UINT32_TYPE,
   TI_UINT64_TYPE,
@@ -3569,12 +3571,14 @@  extern GTY(()) tree global_trees[TI_MAX]
 #define intSI_type_node			global_trees[TI_INTSI_TYPE]
 #define intDI_type_node			global_trees[TI_INTDI_TYPE]
 #define intTI_type_node			global_trees[TI_INTTI_TYPE]
+#define intPI_type_node			global_trees[TI_INTPI_TYPE]
 
 #define unsigned_intQI_type_node	global_trees[TI_UINTQI_TYPE]
 #define unsigned_intHI_type_node	global_trees[TI_UINTHI_TYPE]
 #define unsigned_intSI_type_node	global_trees[TI_UINTSI_TYPE]
 #define unsigned_intDI_type_node	global_trees[TI_UINTDI_TYPE]
 #define unsigned_intTI_type_node	global_trees[TI_UINTTI_TYPE]
+#define unsigned_intPI_type_node	global_trees[TI_UINTPI_TYPE]
 
 #define uint32_type_node		global_trees[TI_UINT32_TYPE]
 #define uint64_type_node		global_trees[TI_UINT64_TYPE]
Index: gcc/ginclude/stdint-gcc.h
===================================================================
--- gcc/ginclude/stdint-gcc.h	(revision 325327)
+++ gcc/ginclude/stdint-gcc.h	(working copy)
@@ -39,6 +39,9 @@  typedef __INT16_TYPE__ int16_t;
 #ifdef __INT32_TYPE__
 typedef __INT32_TYPE__ int32_t;
 #endif
+#ifdef __INT40_TYPE__
+typedef __INT40_TYPE__ int40_t;
+#endif
 #ifdef __INT64_TYPE__
 typedef __INT64_TYPE__ int64_t;
 #endif
@@ -51,6 +54,9 @@  typedef __UINT16_TYPE__ uint16_t;
 #ifdef __UINT32_TYPE__
 typedef __UINT32_TYPE__ uint32_t;
 #endif
+#ifdef __UINT40_TYPE__
+typedef __UINT40_TYPE__ uint40_t;
+#endif
 #ifdef __UINT64_TYPE__
 typedef __UINT64_TYPE__ uint64_t;
 #endif
@@ -66,6 +72,14 @@  typedef __UINT_LEAST16_TYPE__ uint_least
 typedef __UINT_LEAST32_TYPE__ uint_least32_t;
 typedef __UINT_LEAST64_TYPE__ uint_least64_t;
 
+
+#ifdef __INT_LEAST40_TYPE__
+typedef __INT_LEAST40_TYPE__ int_least40_t;
+#endif
+#ifdef __UINT_LEAST40_TYPE__
+typedef __UINT_LEAST40_TYPE__ uint_least40_t;
+#endif
+
 /* 7.8.1.3 Fastest minimum-width integer types */
 
 typedef __INT_FAST8_TYPE__ int_fast8_t;
@@ -77,6 +91,13 @@  typedef __UINT_FAST16_TYPE__ uint_fast16
 typedef __UINT_FAST32_TYPE__ uint_fast32_t;
 typedef __UINT_FAST64_TYPE__ uint_fast64_t;
 
+#ifdef __INT_FAST40_TYPE__
+typedef __INT_FAST40_TYPE__ int_fast40_t;
+#endif
+#ifdef __UINT_FAST40_TYPE__
+typedef __UINT_FAST40_TYPE__ uint_fast40_t;
+#endif
+
 /* 7.8.1.4 Integer types capable of holding object pointers */
 
 #ifdef __INTPTR_TYPE__
@@ -125,6 +146,16 @@  typedef __UINTMAX_TYPE__ uintmax_t;
 # undef UINT32_MAX
 # define UINT32_MAX __UINT32_MAX__
 #endif
+#ifdef __INT40_MAX__
+# undef INT40_MAX
+# define INT40_MAX __INT40_MAX__
+# undef INT40_MIN
+# define INT40_MIN (-INT40_MAX - 1)
+#endif
+#ifdef __UINT40_MAX__
+# undef UINT40_MAX
+# define UINT40_MAX __UINT40_MAX__
+#endif
 #ifdef __INT64_MAX__
 # undef INT64_MAX
 # define INT64_MAX __INT64_MAX__
@@ -154,6 +185,16 @@  typedef __UINTMAX_TYPE__ uintmax_t;
 #define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
 #undef UINT_LEAST32_MAX
 #define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
+#ifdef __INT40_TYPE__
+#undef INT_LEAST40_MAX
+#define INT_LEAST40_MAX __INT40_MAX__
+#undef INT_LEAST40_MIN
+#define INT_LEAST40_MIN (-INT40_MAX - 1)
+#endif
+#ifdef __UINT40_TYPE__
+#undef UINT_LEAST40_MAX
+#define UINT_LEAST40_MAX __UINT40_MAX__
+#endif
 #undef INT_LEAST64_MAX
 #define INT_LEAST64_MAX __INT_LEAST64_MAX__
 #undef INT_LEAST64_MIN
@@ -179,6 +220,16 @@  typedef __UINTMAX_TYPE__ uintmax_t;
 #define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
 #undef UINT_FAST32_MAX
 #define UINT_FAST32_MAX __UINT_FAST32_MAX__
+#ifdef __INT40_TYPE__
+#undef INT_FAST40_MAX
+#define INT_FAST40_MAX __INT40_MAX__
+#undef INT_FAST40_MIN
+#define INT_FAST40_MIN (-INT40_MAX - 1)
+#endif
+#ifdef __UINT40_TYPE__
+#undef UINT_FAST40_MAX
+#define UINT_FAST40_MAX __UINT40_MAX__
+#endif
 #undef INT_FAST64_MAX
 #define INT_FAST64_MAX __INT_FAST64_MAX__
 #undef INT_FAST64_MIN
@@ -239,6 +290,10 @@  typedef __UINTMAX_TYPE__ uintmax_t;
 #define INT16_C(c) __INT16_C(c)
 #undef INT32_C
 #define INT32_C(c) __INT32_C(c)
+#undef INT40_C
+#ifdef __INT40_TYPE__
+#define INT40_C(c) __INT40_C(c)
+#endif
 #undef INT64_C
 #define INT64_C(c) __INT64_C(c)
 #undef UINT8_C
@@ -247,6 +302,10 @@  typedef __UINTMAX_TYPE__ uintmax_t;
 #define UINT16_C(c) __UINT16_C(c)
 #undef UINT32_C
 #define UINT32_C(c) __UINT32_C(c)
+#undef UINT40_C
+#ifdef __UINT40_TYPE__
+#define UINT40_C(c) __UINT40_C(c)
+#endif
 #undef UINT64_C
 #define UINT64_C(c) __UINT64_C(c)
 #undef INTMAX_C
Index: gcc/c-family/c-cppbuiltin.c
===================================================================
--- gcc/c-family/c-cppbuiltin.c	(revision 325327)
+++ gcc/c-family/c-cppbuiltin.c	(working copy)
@@ -413,6 +413,8 @@  builtin_define_stdint_macros (void)
     builtin_define_type_max ("__INT16_MAX__", int16_type_node);
   if (int32_type_node)
     builtin_define_type_max ("__INT32_MAX__", int32_type_node);
+  if (int40_type_node)
+    builtin_define_type_max ("__INT40_MAX__", int40_type_node);
   if (int64_type_node)
     builtin_define_type_max ("__INT64_MAX__", int64_type_node);
   if (uint8_type_node)
@@ -421,6 +423,8 @@  builtin_define_stdint_macros (void)
     builtin_define_type_max ("__UINT16_MAX__", uint16_type_node);
   if (c_uint32_type_node)
     builtin_define_type_max ("__UINT32_MAX__", c_uint32_type_node);
+  if (uint40_type_node)
+    builtin_define_type_max ("__UINT40_MAX__", uint40_type_node);
   if (c_uint64_type_node)
     builtin_define_type_max ("__UINT64_MAX__", c_uint64_type_node);
   if (int_least8_type_node)
@@ -438,6 +442,11 @@  builtin_define_stdint_macros (void)
       builtin_define_type_max ("__INT_LEAST32_MAX__", int_least32_type_node);
       builtin_define_constants ("__INT32_C", int_least32_type_node);
     }
+  if (int_least40_type_node)
+    {
+      builtin_define_type_max ("__INT_LEAST40_MAX__", int_least40_type_node);
+      builtin_define_constants ("__INT40_C", int_least40_type_node);
+    }
   if (int_least64_type_node)
     {
       builtin_define_type_max ("__INT_LEAST64_MAX__", int_least64_type_node);
@@ -458,6 +467,11 @@  builtin_define_stdint_macros (void)
       builtin_define_type_max ("__UINT_LEAST32_MAX__", uint_least32_type_node);
       builtin_define_constants ("__UINT32_C", uint_least32_type_node);
     }
+  if (uint_least40_type_node)
+    {
+      builtin_define_type_max ("__UINT_LEAST40_MAX__", uint_least40_type_node);
+      builtin_define_constants ("__UINT40_C", uint_least40_type_node);
+    }
   if (uint_least64_type_node)
     {
       builtin_define_type_max ("__UINT_LEAST64_MAX__", uint_least64_type_node);
@@ -469,6 +483,8 @@  builtin_define_stdint_macros (void)
     builtin_define_type_max ("__INT_FAST16_MAX__", int_fast16_type_node);
   if (int_fast32_type_node)
     builtin_define_type_max ("__INT_FAST32_MAX__", int_fast32_type_node);
+  if (int_fast40_type_node)
+    builtin_define_type_max ("__INT_FAST40_MAX__", int_fast40_type_node);
   if (int_fast64_type_node)
     builtin_define_type_max ("__INT_FAST64_MAX__", int_fast64_type_node);
   if (uint_fast8_type_node)
@@ -477,6 +493,8 @@  builtin_define_stdint_macros (void)
     builtin_define_type_max ("__UINT_FAST16_MAX__", uint_fast16_type_node);
   if (uint_fast32_type_node)
     builtin_define_type_max ("__UINT_FAST32_MAX__", uint_fast32_type_node);
+  if (uint_fast40_type_node)
+    builtin_define_type_max ("__UINT_FAST40_MAX__", uint_fast40_type_node);
   if (uint_fast64_type_node)
     builtin_define_type_max ("__UINT_FAST64_MAX__", uint_fast64_type_node);
   if (intptr_type_node)
@@ -976,6 +994,10 @@  type_suffix (tree type)
   int unsigned_suffix;
   int is_long;
 
+  if (type == intPI_type_node
+      || type == unsigned_intPI_type_node)
+    return NULL;
+
   if (type == long_long_integer_type_node
       || type == long_long_unsigned_type_node)
     is_long = 2;
@@ -1011,7 +1033,14 @@  builtin_define_constants (const char *ma
 
   suffix = type_suffix (type);
 
-  if (suffix[0] == 0)
+  if (suffix == NULL)
+    {
+      const char *name = type == intTI_type_node ? "__int40_t" : "__uint40_t";
+      buf = (char *) alloca (strlen (macro) + 2 + strlen (name)
+			     + 9 + 1);
+      sprintf (buf, "%s(c)=(%s)(c)", macro, name);
+    }
+  else if (suffix[0] == 0)
     {
       buf = (char *) alloca (strlen (macro) + 6);
       sprintf (buf, "%s(c)=c", macro);
@@ -1044,6 +1073,7 @@  builtin_define_type_minmax (const char *
     = { "127", "255",
 	"32767", "65535",
 	"2147483647", "4294967295",
+	"549755813887", "1099511627775",
 	"9223372036854775807", "18446744073709551615",
 	"170141183460469231731687303715884105727",
 	"340282366920938463463374607431768211455" };
@@ -1060,17 +1090,27 @@  builtin_define_type_minmax (const char *
     case 8:	idx = 0; break;
     case 16:	idx = 2; break;
     case 32:	idx = 4; break;
-    case 64:	idx = 6; break;
-    case 128:	idx = 8; break;
+    case 40:	idx = 6; break;
+    case 64:	idx = 8; break;
+    case 128:	idx = 10; break;
     default:    gcc_unreachable ();
     }
 
   value = values[idx + TYPE_UNSIGNED (type)];
   suffix = type_suffix (type);
 
-  buf = (char *) alloca (strlen (max_macro) + 1 + strlen (value)
-                         + strlen (suffix) + 1);
-  sprintf (buf, "%s=%s%s", max_macro, value, suffix);
+  if (suffix != NULL)
+    {
+      buf = (char *) alloca (strlen (max_macro) + 1 + strlen (value)
+			     + strlen (suffix) + 1);
+      sprintf (buf, "%s=%s%s", max_macro, value, suffix);
+    }
+  else
+    {
+      buf = (char *) alloca (strlen (max_macro) + 10 + 3 + strlen (value) + 1);
+      sprintf (buf, "%s=__INT%d_C(%s)", max_macro, TYPE_PRECISION (type),
+	       value);
+    }
 
   cpp_define (parse_in, buf);
 
@@ -1078,8 +1118,18 @@  builtin_define_type_minmax (const char *
     {
       if (TYPE_UNSIGNED (type))
 	{
-	  buf = (char *) alloca (strlen (min_macro) + 2 + strlen (suffix) + 1);
-	  sprintf (buf, "%s=0%s", min_macro, suffix);
+	  if (suffix != NULL)
+	    {
+	      buf = (char *) alloca (strlen (min_macro) + 2 + strlen (suffix)
+				     + 1);
+	      sprintf (buf, "%s=0%s", min_macro, suffix);
+	    }
+	  else
+	    {
+	      buf = (char *) alloca (strlen (min_macro) + 12 + 3 + 1);
+	      sprintf (buf, "%s=__UINT%d_C(0)", min_macro,
+		       TYPE_PRECISION (type));
+	    }
 	}
       else
 	{
Index: gcc/testsuite/gcc.dg/c99-stdint-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-stdint-3.c	(revision 325327)
+++ gcc/testsuite/gcc.dg/c99-stdint-3.c	(working copy)
@@ -21,16 +21,25 @@  check_corresponding (void)
 #if defined(INT32_MAX) && defined(UINT32_MAX)
   CHECK_CORRESPONDING(int32_t, uint32_t);
 #endif
+#if defined(INT40_MAX) && defined(UINT40_MAX)
+  CHECK_CORRESPONDING(int40_t, uint40_t);
+#endif
 #if defined(INT64_MAX) && defined(UINT64_MAX)
   CHECK_CORRESPONDING(int64_t, uint64_t);
 #endif
   CHECK_CORRESPONDING(int_least8_t, uint_least8_t);
   CHECK_CORRESPONDING(int_least16_t, uint_least16_t);
   CHECK_CORRESPONDING(int_least32_t, uint_least32_t);
+#if defined(INT40_MAX) && defined(UINT40_MAX)
+  CHECK_CORRESPONDING(int_least40_t, uint_least40_t);
+#endif
   CHECK_CORRESPONDING(int_least64_t, uint_least64_t);
   CHECK_CORRESPONDING(int_fast8_t, uint_fast8_t);
   CHECK_CORRESPONDING(int_fast16_t, uint_fast16_t);
   CHECK_CORRESPONDING(int_fast32_t, uint_fast32_t);
+#if defined(INT40_MAX) && defined(UINT40_MAX)
+  CHECK_CORRESPONDING(int_fast40_t, uint_fast40_t);
+#endif
   CHECK_CORRESPONDING(int_fast64_t, uint_fast64_t);
 #if defined(INTPTR_MAX) && defined(UINTPTR_MAX)
   CHECK_CORRESPONDING(intptr_t, uintptr_t);
Index: gcc/testsuite/gcc.dg/c99-stdint-7.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-stdint-7.c	(revision 325327)
+++ gcc/testsuite/gcc.dg/c99-stdint-7.c	(working copy)
@@ -34,6 +34,7 @@ 
 #if defined(UINT32_MAX) != defined(__UINT32_TYPE__)
 #error "Unexpected UINT32_MAX definedness"
 #endif
+/* 40 bit macros are known not to be usable in this way.  */
 #if defined(INT64_MIN) != defined(__INT64_TYPE__)
 #error "Unexpected INT64_MIN definedness"
 #endif
@@ -80,6 +81,7 @@ 
 #if defined(UINT32_MAX) && UINT32_MAX != __UINT32_MAX__
 #error "UINT32_MAX not usable in #if or wrong value"
 #endif
+/* 40 bit macros are known not to be usable in this way.  */
 #if defined(INT64_MIN) && INT64_MIN != -__INT64_MAX__-1
 #error "INT64_MIN not usable in #if or wrong value"
 #endif
@@ -117,6 +119,7 @@ 
 #if UINT_LEAST32_MAX != __UINT_LEAST32_MAX__
 #error "UINT_LEAST32_MAX not usable in #if or wrong value"
 #endif
+/* 40 bit macros are known not to be usable in this way.  */
 #if INT_LEAST64_MIN != -__INT_LEAST64_MAX__-1
 #error "INT_LEAST64_MIN not usable in #if or wrong value"
 #endif
@@ -154,6 +157,7 @@ 
 #if UINT_FAST32_MAX != __UINT_FAST32_MAX__
 #error "UINT_FAST32_MAX not usable in #if or wrong value"
 #endif
+/* 40 bit macros are known not to be usable in this way.  */
 #if INT_FAST64_MIN != -__INT_FAST64_MAX__-1
 #error "INT_FAST64_MIN not usable in #if or wrong value"
 #endif
Index: gcc/testsuite/gcc.dg/shift-pi.c
===================================================================
--- gcc/testsuite/gcc.dg/shift-pi.c	(revision 0)
+++ gcc/testsuite/gcc.dg/shift-pi.c	(revision 0)
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target int40 } */
+/* { dg-options "-std=gnu89" } */
+
+__int40_t a;
+__uint40_t b;
+
+void foo ()
+{
+  a <<= 39; /* { dg-bogus "shift count" } */
+  a <<= 40; /* { dg-warning "shift count" } */
+  a >>= 39; /* { dg-bogus "shift count" } */
+  a >>= 40; /* { dg-warning "shift count" } */
+  b <<= 39; /* { dg-bogus "shift count" } */
+  b <<= 40; /* { dg-warning "shift count" } */
+  b >>= 39; /* { dg-bogus "shift count" } */
+  b >>= 40; /* { dg-warning "shift count" } */
+}
Index: gcc/testsuite/gcc.dg/c99-stdint-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-stdint-1.c	(revision 325327)
+++ gcc/testsuite/gcc.dg/c99-stdint-1.c	(working copy)
@@ -99,6 +99,10 @@  test_exact (void)
 #else
   CHECK_WIDTH_AT_LEAST(int_least32_t, 33);
 #endif
+#ifdef INT40_MIN
+  CHECK_WIDTH_EQUALS(int40_t, 40);
+  CHECK_SIGNED_LIMITS(int40_t, INT40_MIN, INT40_MAX);
+#endif
 #ifdef INT64_MIN
   CHECK_WIDTH_EQUALS(int64_t, 64);
   CHECK_SIGNED_LIMITS(int64_t, INT64_MIN, INT64_MAX);
@@ -123,6 +127,10 @@  test_exact (void)
 #else
   CHECK_WIDTH_AT_LEAST(uint_least32_t, 33);
 #endif
+#ifdef UINT40_MAX
+  CHECK_WIDTH_EQUALS(uint40_t, 40);
+  CHECK_UNSIGNED_LIMITS(uint40_t, UINT40_MAX);
+#endif
 #ifdef UINT64_MAX
   CHECK_WIDTH_EQUALS(uint64_t, 64);
   CHECK_UNSIGNED_LIMITS(uint64_t, UINT64_MAX);
@@ -143,6 +151,11 @@  test_least (void)
   CHECK_WIDTH_AT_LEAST(int_least32_t, 32);
   CHECK_WIDTH_ORDER(int_least32_t, int_fast32_t);
   CHECK_SIGNED_LIMITS(int_least32_t, INT_LEAST32_MIN, INT_LEAST32_MAX);
+#ifdef INT40_MIN
+  CHECK_WIDTH_AT_LEAST(int_least40_t, 40);
+  CHECK_WIDTH_ORDER(int_least40_t, int_fast40_t);
+  CHECK_SIGNED_LIMITS(int_least40_t, INT_LEAST40_MIN, INT_LEAST40_MAX);
+#endif
   CHECK_WIDTH_AT_LEAST(int_least64_t, 64);
   CHECK_WIDTH_ORDER(int_least64_t, int_fast64_t);
   CHECK_SIGNED_LIMITS(int_least64_t, INT_LEAST64_MIN, INT_LEAST64_MAX);
@@ -155,6 +168,11 @@  test_least (void)
   CHECK_WIDTH_AT_LEAST(uint_least32_t, 32);
   CHECK_WIDTH_ORDER(uint_least32_t, uint_fast32_t);
   CHECK_UNSIGNED_LIMITS(uint_least32_t, UINT_LEAST32_MAX);
+#ifdef INT40_MIN
+  CHECK_WIDTH_AT_LEAST(uint_least40_t, 40);
+  CHECK_WIDTH_ORDER(uint_least40_t, uint_fast40_t);
+  CHECK_UNSIGNED_LIMITS(uint_least40_t, UINT_LEAST40_MAX);
+#endif
   CHECK_WIDTH_AT_LEAST(uint_least64_t, 64);
   CHECK_WIDTH_ORDER(uint_least64_t, uint_fast64_t);
   CHECK_UNSIGNED_LIMITS(uint_least64_t, UINT_LEAST64_MAX);
@@ -169,6 +187,10 @@  test_fast (void)
   CHECK_SIGNED_LIMITS(int_fast16_t, INT_FAST16_MIN, INT_FAST16_MAX);
   CHECK_WIDTH_AT_LEAST(int_fast32_t, 32);
   CHECK_SIGNED_LIMITS(int_fast32_t, INT_FAST32_MIN, INT_FAST32_MAX);
+#ifdef INT40_MIN
+  CHECK_WIDTH_AT_LEAST(int_fast40_t, 40);
+  CHECK_SIGNED_LIMITS(int_fast40_t, INT_FAST40_MIN, INT_FAST40_MAX);
+#endif
   CHECK_WIDTH_AT_LEAST(int_fast64_t, 64);
   CHECK_SIGNED_LIMITS(int_fast64_t, INT_FAST64_MIN, INT_FAST64_MAX);
   CHECK_WIDTH_AT_LEAST(uint_fast8_t, 8);
@@ -177,6 +199,10 @@  test_fast (void)
   CHECK_UNSIGNED_LIMITS(uint_fast16_t, UINT_FAST16_MAX);
   CHECK_WIDTH_AT_LEAST(uint_fast32_t, 32);
   CHECK_UNSIGNED_LIMITS(uint_fast32_t, UINT_FAST32_MAX);
+#ifdef UINT40_MIN
+  CHECK_WIDTH_AT_LEAST(uint_fast40_t, 40);
+  CHECK_UNSIGNED_LIMITS(uint_fast40_t, UINT_FAST40_MAX);
+#endif
   CHECK_WIDTH_AT_LEAST(uint_fast64_t, 64);
   CHECK_UNSIGNED_LIMITS(uint_fast64_t, UINT_FAST64_MAX);
 }
@@ -200,6 +226,9 @@  test_max (void)
   CHECK_WIDTH_ORDER(int_fast8_t, intmax_t);
   CHECK_WIDTH_ORDER(int_fast16_t, intmax_t);
   CHECK_WIDTH_ORDER(int_fast32_t, intmax_t);
+#ifdef INT40_MIN
+  CHECK_WIDTH_ORDER(int_fast40_t, intmax_t);
+#endif
   CHECK_WIDTH_ORDER(int_fast64_t, intmax_t);
   CHECK_SIGNED_LIMITS(intmax_t, INTMAX_MIN, INTMAX_MAX);
   CHECK_WIDTH_AT_LEAST(uintmax_t, 64);
@@ -207,6 +236,9 @@  test_max (void)
   CHECK_WIDTH_ORDER(uint_fast8_t, uintmax_t);
   CHECK_WIDTH_ORDER(uint_fast16_t, uintmax_t);
   CHECK_WIDTH_ORDER(uint_fast32_t, uintmax_t);
+#ifdef UINT40_MIN
+  CHECK_WIDTH_ORDER(uint_fast40_t, intmax_t);
+#endif
   CHECK_WIDTH_ORDER(uint_fast64_t, uintmax_t);
   CHECK_UNSIGNED_LIMITS(uintmax_t, UINTMAX_MAX);
 }
@@ -230,11 +262,17 @@  test_constants (void)
   CHECK_CONSTS(int_least8_t, INT8_C);
   CHECK_CONSTS(int_least16_t, INT16_C);
   CHECK_CONSTS(int_least32_t, INT32_C);
+#ifdef INT40_MIN
+  CHECK_CONSTS(int_least40_t, INT40_C);
+#endif
   CHECK_CONSTS(int_least64_t, INT64_C);
   CHECK_CONSTS(intmax_t, INTMAX_C);
   CHECK_CONSTS(uint_least8_t, UINT8_C);
   CHECK_CONSTS(uint_least16_t, UINT16_C);
   CHECK_CONSTS(uint_least32_t, UINT32_C);
+#ifdef UINT40_MIN
+  CHECK_CONSTS(uint_least40_t, UINT40_C);
+#endif
   CHECK_CONSTS(uint_least64_t, UINT64_C);
   CHECK_CONSTS(uintmax_t, UINTMAX_C);
 #if INT8_C(12) != 12
@@ -246,6 +284,7 @@  test_constants (void)
 #if INT32_C(12) != 12
 #error "INT32_C not usable in #if"
 #endif
+  /* INT40_C is known not to be usable in #if.  */
 #if INT64_C(12) != 12
 #error "INT64_C not usable in #if"
 #endif
@@ -261,6 +300,7 @@  test_constants (void)
 #if UINT32_C(12) != 12
 #error "UINT32_C not usable in #if"
 #endif
+  /* UINT40_C is known not to be usable in #if.  */
 #if UINT64_C(12) != 12
 #error "UINT64_C not usable in #if"
 #endif
Index: gcc/testsuite/gcc.dg/torture/arith-rand-40.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/arith-rand-40.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/arith-rand-40.c	(revision 0)
@@ -0,0 +1,74 @@ 
+/* { dg-do run } */
+/* { dg-require-effective-target int40 } */
+
+#include <stdlib.h>
+
+long
+simple_rand ()
+{
+  static __uint40_t seed = 47114711;
+  __uint40_t this = seed * 1103515245 + 12345;
+  seed = this;
+  return this >> 8;
+}
+
+__uint40_t
+random_bitstring ()
+{
+  __uint40_t x;
+  int n_bits;
+  long ran;
+  int tot_bits = 0;
+
+  x = 0;
+  for (;;)
+    {
+      ran = simple_rand ();
+      n_bits = (ran >> 1) % 16;
+      tot_bits += n_bits;
+
+      if (n_bits == 0)
+	return x;
+      else
+	{
+	  x <<= n_bits;
+	  if (ran & 1)
+	    x |= (1 << n_bits) - 1;
+
+	  if (tot_bits > 8 * sizeof (long) + 6)
+	    return x;
+	}
+    }
+}
+
+#define ABS(x) ((x) >= 0 ? (x) : -(x))
+
+main ()
+{
+  long int i;
+
+  for (i = 0; i < 1000; i++)
+    {
+      __uint40_t x, y;
+      x = random_bitstring ();
+      y = random_bitstring ();
+
+      { __uint40_t xx = x, yy = y, r1, r2;
+	if (yy == 0) continue;
+	r1 = xx / yy;
+	r2 = xx % yy;
+	if (r2 >= yy || r1 * yy + r2 != xx)
+	  abort ();
+      }
+      { __int40_t xx = x, yy = y, r1, r2;
+	if ((__uint40_t) xx << 1 == 0 && yy == -1)
+	  continue;
+	r1 = xx / yy;
+	r2 = xx % yy;
+	if (ABS (r2) >= (__uint40_t) ABS (yy) || (__int40_t) (r1 * yy + r2) != xx)
+	  abort ();
+      }
+    }
+
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/arith40.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/arith40.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/arith40.c	(revision 0)
@@ -0,0 +1,207 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target int40 } */
+__int40_t add (__int40_t a, __int40_t b)
+{
+  return a + b;
+}
+__int40_t sub (__int40_t a, __int40_t b)
+{
+  return a - b;
+}
+__int40_t mul (__int40_t a, __int40_t b)
+{
+  return a * b;
+}
+__int40_t div (__int40_t a, __int40_t b)
+{
+  return a / b;
+}
+__int40_t mod (__int40_t a, __int40_t b)
+{
+  return a % b;
+}
+
+int lt (__int40_t a, __int40_t b)
+{
+  return a < b;
+}
+int le (__int40_t a, __int40_t b)
+{
+  return a <= b;
+}
+int gt (__int40_t a, __int40_t b)
+{
+  return a > b;
+}
+int ge (__int40_t a, __int40_t b)
+{
+  return a >= b;
+}
+int eq (__int40_t a, __int40_t b)
+{
+  return a == b;
+}
+int ne (__int40_t a, __int40_t b)
+{
+  return a != b;
+}
+
+__int40_t ext_int (int a)
+{
+  return (__int40_t)a;
+}
+long long ext_ll (__int40_t a)
+{
+  return (long long)a;
+}
+float conv_float (__int40_t a)
+{
+  return (float)a;
+}
+double conv_double (__int40_t a)
+{
+  return (double)a;
+}
+__int40_t fix_float (float a)
+{
+  return (__int40_t)a;
+}
+__int40_t fix_double (double a)
+{
+  return (__int40_t)a;
+}
+
+__int40_t abs40 (__int40_t a)
+{
+  return a < 0 ? -a : a;
+}
+__int40_t neg (__int40_t a)
+{
+  return -a;
+}
+__int40_t not (__int40_t a)
+{
+  return ~a;
+}
+
+__int40_t shl (__int40_t a, int b)
+{
+  return a << b;
+}
+__int40_t shr (__int40_t a, int b)
+{
+  return a >> b;
+}
+
+__int40_t rotr8 (__int40_t a)
+{
+  return ((a >> 8) & 0xffffffff) | (a << 32);
+}
+__int40_t rotl8 (__int40_t a)
+{
+  return (a << 8) | ((a >> 32) & 0xff);
+}
+
+
+__uint40_t uadd (__uint40_t a, __uint40_t b)
+{
+  return a + b;
+}
+__uint40_t usub (__uint40_t a, __uint40_t b)
+{
+  return a - b;
+}
+__uint40_t umul (__uint40_t a, __uint40_t b)
+{
+  return a * b;
+}
+__uint40_t udiv (__uint40_t a, __uint40_t b)
+{
+  return a / b;
+}
+__uint40_t umod (__uint40_t a, __uint40_t b)
+{
+  return a % b;
+}
+
+int ult (__uint40_t a, __uint40_t b)
+{
+  return a < b;
+}
+int ule (__uint40_t a, __uint40_t b)
+{
+  return a <= b;
+}
+int ugt (__uint40_t a, __uint40_t b)
+{
+  return a > b;
+}
+int uge (__uint40_t a, __uint40_t b)
+{
+  return a >= b;
+}
+int ueq (__uint40_t a, __uint40_t b)
+{
+  return a == b;
+}
+int une (__uint40_t a, __uint40_t b)
+{
+  return a != b;
+}
+
+__uint40_t uext_int (int a)
+{
+  return (__uint40_t)a;
+}
+long long uext_ll (__uint40_t a)
+{
+  return (long long)a;
+}
+float uconv_float (__uint40_t a)
+{
+  return (float)a;
+}
+double uconv_double (__uint40_t a)
+{
+  return (double)a;
+}
+__uint40_t ufix_float (float a)
+{
+  return (__uint40_t)a;
+}
+__uint40_t ufix_double (double a)
+{
+  return (__uint40_t)a;
+}
+
+__uint40_t uabs (__uint40_t a)
+{
+  return a < 0 ? -a : a;
+}
+__uint40_t uneg (__uint40_t a)
+{
+  return -a;
+}
+__uint40_t unot (__uint40_t a)
+{
+  return ~a;
+}
+
+__uint40_t ushl (__uint40_t a, int b)
+{
+  return a << b;
+}
+__uint40_t ushr (__uint40_t a, int b)
+{
+  return a >> b;
+}
+
+__uint40_t urotr8 (__uint40_t a)
+{
+  return (a >> 8) | (a << 32);
+}
+__uint40_t urotl8 (__uint40_t a)
+{
+  return (a << 8) | (a >> 32);
+}
+
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 325327)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -1449,6 +1449,15 @@  proc check_effective_target_dfprt { } {
     }]
 }
 
+# Return 1 if the target supports 40-bit integers as __int40_t,
+# 0 otherwise.
+
+proc check_effective_target_int40 { } {
+    return [check_no_compiler_messages in40 object {
+        __int40_t x; __uint40_t y;
+    }]
+}
+
 # Return 1 if the target supports compiling and assembling UCN, 0 otherwise.
 
 proc check_effective_target_ucn_nocache { } {
Index: gcc/machmode.def
===================================================================
--- gcc/machmode.def	(revision 325327)
+++ gcc/machmode.def	(working copy)
@@ -184,6 +184,10 @@  INT_MODE (SI, 4);
 INT_MODE (DI, 8);
 INT_MODE (TI, 16);
 
+/* A mode used for int40_t on machines that support operations on such a
+   type.  */
+FRACTIONAL_INT_MODE (PI, 40, 8);
+
 /* No partial integer modes are defined by default.  */
 
 /* Basic floating point modes.  SF and DF are the only modes provided
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 325327)
+++ gcc/varasm.c	(working copy)
@@ -2753,12 +2753,12 @@  assemble_integer (rtx x, unsigned int si
      it into words it if is multi-word, otherwise split it into bytes.  */
   if (size > 1)
     {
-      enum machine_mode omode, imode;
+      enum machine_mode omode, imode, hmode;
       unsigned int subalign;
       unsigned int subsize, i;
       enum mode_class mclass;
 
-      subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
+      subsize = size > UNITS_PER_WORD ? UNITS_PER_WORD : 1;
       subalign = MIN (align, subsize * BITS_PER_UNIT);
       if (GET_CODE (x) == CONST_FIXED)
 	mclass = GET_MODE_CLASS (GET_MODE (x));
@@ -2767,19 +2767,29 @@  assemble_integer (rtx x, unsigned int si
 
       omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0);
       imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0);
+      hmode = omode;
+      if (size > UNITS_PER_WORD && size % subsize != 0)
+	hmode = mode_for_size ((size % subsize) * BITS_PER_UNIT, mclass, 0);
 
       for (i = 0; i < size; i += subsize)
 	{
-	  rtx partial = simplify_subreg (omode, x, imode, i);
-	  if (!partial || !assemble_integer (partial, subsize, subalign, 0))
-	    break;
-	}
-      if (i == size)
-	return true;
+	  enum machine_mode this_mode;
+	  rtx partial;
 
-      /* If we've printed some of it, but not all of it, there's no going
-	 back now.  */
-      gcc_assert (!i);
+	  this_mode = omode;
+	  if (size > UNITS_PER_WORD
+	      && ((i == 0 && WORDS_BIG_ENDIAN)
+		  || (i + subsize >= size && !WORDS_BIG_ENDIAN)))
+	    {
+	      this_mode = hmode;
+	    }
+	  partial = simplify_subreg (this_mode, x, imode, i);
+	  gcc_assert (partial);
+	  if (!assemble_integer (partial, GET_MODE_SIZE (this_mode),
+				 subalign, 0))
+	    gcc_unreachable ();
+	}
+      return true;
     }
 
   gcc_assert (!force);
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 325327)
+++ gcc/c-family/c-common.c	(working copy)
@@ -2832,6 +2832,8 @@  check_case_bounds (tree type, tree orig_
 tree
 c_common_type_for_size (unsigned int bits, int unsignedp)
 {
+  tree retval;
+
   if (bits == TYPE_PRECISION (integer_type_node))
     return unsignedp ? unsigned_type_node : integer_type_node;
 
@@ -2853,18 +2855,23 @@  c_common_type_for_size (unsigned int bit
 	    : widest_integer_literal_type_node);
 
   if (bits <= TYPE_PRECISION (intQI_type_node))
-    return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+    retval = unsignedp ? unsigned_intQI_type_node : intQI_type_node;
 
-  if (bits <= TYPE_PRECISION (intHI_type_node))
-    return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+  else if (bits <= TYPE_PRECISION (intHI_type_node))
+    retval = unsignedp ? unsigned_intHI_type_node : intHI_type_node;
 
-  if (bits <= TYPE_PRECISION (intSI_type_node))
-    return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+  else if (bits <= TYPE_PRECISION (intSI_type_node))
+    retval = unsignedp ? unsigned_intSI_type_node : intSI_type_node;
 
-  if (bits <= TYPE_PRECISION (intDI_type_node))
-    return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+  else if (bits <= TYPE_PRECISION (intDI_type_node))
+    retval = unsignedp ? unsigned_intDI_type_node : intDI_type_node;
 
-  return 0;
+  if (targetm.scalar_mode_supported_p (PImode)
+      && bits <= TYPE_PRECISION (intPI_type_node)
+      && TYPE_PRECISION (intPI_type_node) <= TYPE_PRECISION (retval))
+    return unsignedp ? unsigned_intPI_type_node : intPI_type_node;
+
+  return retval;
 }
 
 /* Return a fixed-point type that has at least IBIT ibits and FBIT fbits
@@ -2942,6 +2949,9 @@  c_common_type_for_mode (enum machine_mod
   if (mode == DImode)
     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
 
+  if (mode == PImode)
+    return unsignedp ? unsigned_intPI_type_node : intPI_type_node;
+  
 #if HOST_BITS_PER_WIDE_INT >= 64
   if (mode == TYPE_MODE (intTI_type_node))
     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
@@ -3145,6 +3155,8 @@  c_common_signed_or_unsigned_type (int un
   if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node)
     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
 #endif
+  if (type1 == intPI_type_node || type1 == unsigned_intPI_type_node)
+    return unsignedp ? unsigned_intPI_type_node : intPI_type_node;
   if (type1 == intDI_type_node || type1 == unsigned_intDI_type_node)
     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
   if (type1 == intSI_type_node || type1 == unsigned_intSI_type_node)
@@ -4700,6 +4712,11 @@  c_common_nodes_and_builtins (void)
   lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
 					 TYPE_DECL, NULL_TREE,
 					 intDI_type_node));
+  if (targetm.scalar_mode_supported_p (PImode))
+    lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+					   TYPE_DECL,
+					   get_identifier ("__int40_t"),
+					   intPI_type_node));
 #if HOST_BITS_PER_WIDE_INT >= 64
   if (targetm.scalar_mode_supported_p (TImode))
     lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
@@ -4719,6 +4736,11 @@  c_common_nodes_and_builtins (void)
   lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
 					 TYPE_DECL, NULL_TREE,
 					 unsigned_intDI_type_node));
+  if (targetm.scalar_mode_supported_p (PImode))
+    lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
+					   TYPE_DECL,
+					   get_identifier ("__uint40_t"),
+					   unsigned_intPI_type_node));
 #if HOST_BITS_PER_WIDE_INT >= 64
   if (targetm.scalar_mode_supported_p (TImode))
     lang_hooks.decls.pushdecl (build_decl (UNKNOWN_LOCATION,
@@ -4985,6 +5007,9 @@  c_common_nodes_and_builtins (void)
   if (INT_LEAST32_TYPE)
     int_least32_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST32_TYPE)));
+  if (INT_LEAST40_TYPE)
+    int_least40_type_node =
+      TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST40_TYPE)));
   if (INT_LEAST64_TYPE)
     int_least64_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (INT_LEAST64_TYPE)));
@@ -4997,6 +5022,9 @@  c_common_nodes_and_builtins (void)
   if (UINT_LEAST32_TYPE)
     uint_least32_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST32_TYPE)));
+  if (UINT_LEAST40_TYPE)
+    uint_least40_type_node =
+      TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST40_TYPE)));
   if (UINT_LEAST64_TYPE)
     uint_least64_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (UINT_LEAST64_TYPE)));
@@ -5009,6 +5037,9 @@  c_common_nodes_and_builtins (void)
   if (INT_FAST32_TYPE)
     int_fast32_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST32_TYPE)));
+  if (INT_FAST40_TYPE)
+    int_fast40_type_node =
+      TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST40_TYPE)));
   if (INT_FAST64_TYPE)
     int_fast64_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (INT_FAST64_TYPE)));
@@ -5021,6 +5052,9 @@  c_common_nodes_and_builtins (void)
   if (UINT_FAST32_TYPE)
     uint_fast32_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST32_TYPE)));
+  if (UINT_FAST40_TYPE)
+    uint_fast40_type_node =
+      TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST40_TYPE)));
   if (UINT_FAST64_TYPE)
     uint_fast64_type_node =
       TREE_TYPE (identifier_global_value (c_get_ident (UINT_FAST64_TYPE)));
@@ -5717,6 +5751,8 @@  c_stddef_cpp_builtins(void)
     builtin_define_with_value ("__INT16_TYPE__", INT16_TYPE, 0);
   if (INT32_TYPE)
     builtin_define_with_value ("__INT32_TYPE__", INT32_TYPE, 0);
+  if (INT40_TYPE)
+    builtin_define_with_value ("__INT40_TYPE__", INT40_TYPE, 0);
   if (INT64_TYPE)
     builtin_define_with_value ("__INT64_TYPE__", INT64_TYPE, 0);
   if (UINT8_TYPE)
@@ -5725,6 +5761,8 @@  c_stddef_cpp_builtins(void)
     builtin_define_with_value ("__UINT16_TYPE__", UINT16_TYPE, 0);
   if (UINT32_TYPE)
     builtin_define_with_value ("__UINT32_TYPE__", UINT32_TYPE, 0);
+  if (UINT40_TYPE)
+    builtin_define_with_value ("__UINT40_TYPE__", UINT40_TYPE, 0);
   if (UINT64_TYPE)
     builtin_define_with_value ("__UINT64_TYPE__", UINT64_TYPE, 0);
   if (INT_LEAST8_TYPE)
@@ -5733,6 +5771,8 @@  c_stddef_cpp_builtins(void)
     builtin_define_with_value ("__INT_LEAST16_TYPE__", INT_LEAST16_TYPE, 0);
   if (INT_LEAST32_TYPE)
     builtin_define_with_value ("__INT_LEAST32_TYPE__", INT_LEAST32_TYPE, 0);
+  if (INT_LEAST40_TYPE)
+    builtin_define_with_value ("__INT_LEAST40_TYPE__", INT_LEAST40_TYPE, 0);
   if (INT_LEAST64_TYPE)
     builtin_define_with_value ("__INT_LEAST64_TYPE__", INT_LEAST64_TYPE, 0);
   if (UINT_LEAST8_TYPE)
@@ -5741,6 +5781,8 @@  c_stddef_cpp_builtins(void)
     builtin_define_with_value ("__UINT_LEAST16_TYPE__", UINT_LEAST16_TYPE, 0);
   if (UINT_LEAST32_TYPE)
     builtin_define_with_value ("__UINT_LEAST32_TYPE__", UINT_LEAST32_TYPE, 0);
+  if (UINT_LEAST40_TYPE)
+    builtin_define_with_value ("__UINT_LEAST40_TYPE__", UINT_LEAST40_TYPE, 0);
   if (UINT_LEAST64_TYPE)
     builtin_define_with_value ("__UINT_LEAST64_TYPE__", UINT_LEAST64_TYPE, 0);
   if (INT_FAST8_TYPE)
@@ -5749,6 +5791,8 @@  c_stddef_cpp_builtins(void)
     builtin_define_with_value ("__INT_FAST16_TYPE__", INT_FAST16_TYPE, 0);
   if (INT_FAST32_TYPE)
     builtin_define_with_value ("__INT_FAST32_TYPE__", INT_FAST32_TYPE, 0);
+  if (INT_FAST40_TYPE)
+    builtin_define_with_value ("__INT_FAST40_TYPE__", INT_FAST40_TYPE, 0);
   if (INT_FAST64_TYPE)
     builtin_define_with_value ("__INT_FAST64_TYPE__", INT_FAST64_TYPE, 0);
   if (UINT_FAST8_TYPE)
@@ -5757,6 +5801,8 @@  c_stddef_cpp_builtins(void)
     builtin_define_with_value ("__UINT_FAST16_TYPE__", UINT_FAST16_TYPE, 0);
   if (UINT_FAST32_TYPE)
     builtin_define_with_value ("__UINT_FAST32_TYPE__", UINT_FAST32_TYPE, 0);
+  if (UINT_FAST40_TYPE)
+    builtin_define_with_value ("__UINT_FAST40_TYPE__", UINT_FAST40_TYPE, 0);
   if (UINT_FAST64_TYPE)
     builtin_define_with_value ("__UINT_FAST64_TYPE__", UINT_FAST64_TYPE, 0);
   if (INTPTR_TYPE)
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 325327)
+++ gcc/c-family/c-common.h	(working copy)
@@ -197,26 +197,32 @@  enum c_tree_index
     CTI_INT8_TYPE,
     CTI_INT16_TYPE,
     CTI_INT32_TYPE,
+    CTI_INT40_TYPE,
     CTI_INT64_TYPE,
     CTI_UINT8_TYPE,
     CTI_UINT16_TYPE,
     CTI_UINT32_TYPE,
+    CTI_UINT40_TYPE,
     CTI_UINT64_TYPE,
     CTI_INT_LEAST8_TYPE,
     CTI_INT_LEAST16_TYPE,
     CTI_INT_LEAST32_TYPE,
+    CTI_INT_LEAST40_TYPE,
     CTI_INT_LEAST64_TYPE,
     CTI_UINT_LEAST8_TYPE,
     CTI_UINT_LEAST16_TYPE,
     CTI_UINT_LEAST32_TYPE,
+    CTI_UINT_LEAST40_TYPE,
     CTI_UINT_LEAST64_TYPE,
     CTI_INT_FAST8_TYPE,
     CTI_INT_FAST16_TYPE,
     CTI_INT_FAST32_TYPE,
+    CTI_INT_FAST40_TYPE,
     CTI_INT_FAST64_TYPE,
     CTI_UINT_FAST8_TYPE,
     CTI_UINT_FAST16_TYPE,
     CTI_UINT_FAST32_TYPE,
+    CTI_UINT_FAST40_TYPE,
     CTI_UINT_FAST64_TYPE,
     CTI_INTPTR_TYPE,
     CTI_UINTPTR_TYPE,
@@ -313,26 +319,32 @@  extern const unsigned int num_c_common_r
 #define int8_type_node			c_global_trees[CTI_INT8_TYPE]
 #define int16_type_node			c_global_trees[CTI_INT16_TYPE]
 #define int32_type_node			c_global_trees[CTI_INT32_TYPE]
+#define int40_type_node			c_global_trees[CTI_INT40_TYPE]
 #define int64_type_node			c_global_trees[CTI_INT64_TYPE]
 #define uint8_type_node			c_global_trees[CTI_UINT8_TYPE]
 #define uint16_type_node		c_global_trees[CTI_UINT16_TYPE]
 #define c_uint32_type_node		c_global_trees[CTI_UINT32_TYPE]
+#define uint40_type_node		c_global_trees[CTI_UINT40_TYPE]
 #define c_uint64_type_node		c_global_trees[CTI_UINT64_TYPE]
 #define int_least8_type_node		c_global_trees[CTI_INT_LEAST8_TYPE]
 #define int_least16_type_node		c_global_trees[CTI_INT_LEAST16_TYPE]
 #define int_least32_type_node		c_global_trees[CTI_INT_LEAST32_TYPE]
+#define int_least40_type_node		c_global_trees[CTI_INT_LEAST40_TYPE]
 #define int_least64_type_node		c_global_trees[CTI_INT_LEAST64_TYPE]
 #define uint_least8_type_node		c_global_trees[CTI_UINT_LEAST8_TYPE]
 #define uint_least16_type_node		c_global_trees[CTI_UINT_LEAST16_TYPE]
 #define uint_least32_type_node		c_global_trees[CTI_UINT_LEAST32_TYPE]
+#define uint_least40_type_node		c_global_trees[CTI_UINT_LEAST40_TYPE]
 #define uint_least64_type_node		c_global_trees[CTI_UINT_LEAST64_TYPE]
 #define int_fast8_type_node		c_global_trees[CTI_INT_FAST8_TYPE]
 #define int_fast16_type_node		c_global_trees[CTI_INT_FAST16_TYPE]
 #define int_fast32_type_node		c_global_trees[CTI_INT_FAST32_TYPE]
+#define int_fast40_type_node		c_global_trees[CTI_INT_FAST40_TYPE]
 #define int_fast64_type_node		c_global_trees[CTI_INT_FAST64_TYPE]
 #define uint_fast8_type_node		c_global_trees[CTI_UINT_FAST8_TYPE]
 #define uint_fast16_type_node		c_global_trees[CTI_UINT_FAST16_TYPE]
 #define uint_fast32_type_node		c_global_trees[CTI_UINT_FAST32_TYPE]
+#define uint_fast40_type_node		c_global_trees[CTI_UINT_FAST40_TYPE]
 #define uint_fast64_type_node		c_global_trees[CTI_UINT_FAST64_TYPE]
 #define intptr_type_node		c_global_trees[CTI_INTPTR_TYPE]
 #define uintptr_type_node		c_global_trees[CTI_UINTPTR_TYPE]
Index: gcc/config/soft-fp/floatpisf.c
===================================================================
--- gcc/config/soft-fp/floatpisf.c	(revision 325327)
+++ gcc/config/soft-fp/floatpisf.c	(working copy)
@@ -31,13 +31,13 @@ 
 #include "soft-fp.h"
 #include "single.h"
 
-SFtype __floattisf(TItype i)
+SFtype __floatpisf(PItype i)
 {
   FP_DECL_EX;
   FP_DECL_S(A);
   SFtype a;
 
-  FP_FROM_INT_S(A, i, TI_BITS, UTItype);
+  FP_FROM_INT_S(A, i, PI_BITS, UPItype);
   FP_PACK_RAW_S(a, A);
   FP_HANDLE_EXCEPTIONS;
 
Index: gcc/config/soft-fp/floatunpidf.c
===================================================================
--- gcc/config/soft-fp/floatunpidf.c	(revision 325327)
+++ gcc/config/soft-fp/floatunpidf.c	(working copy)
@@ -31,13 +31,13 @@ 
 #include "soft-fp.h"
 #include "double.h"
 
-DFtype __floatuntidf(UTItype i)
+DFtype __floatunpidf(UPItype i)
 {
   FP_DECL_EX;
   FP_DECL_D(A);
   DFtype a;
 
-  FP_FROM_INT_D(A, i, TI_BITS, UTItype);
+  FP_FROM_INT_D(A, i, PI_BITS, UPItype);
   FP_PACK_RAW_D(a, A);
   FP_HANDLE_EXCEPTIONS;
 
Index: gcc/config/soft-fp/floatunpitf.c
===================================================================
--- gcc/config/soft-fp/floatunpitf.c	(revision 325327)
+++ gcc/config/soft-fp/floatunpitf.c	(working copy)
@@ -31,13 +31,13 @@ 
 #include "soft-fp.h"
 #include "quad.h"
 
-TFtype __floatuntitf(UTItype i)
+TFtype __floatunpitf(UPItype i)
 {
   FP_DECL_EX;
   FP_DECL_Q(A);
   TFtype a;
 
-  FP_FROM_INT_Q(A, i, TI_BITS, UTItype);
+  FP_FROM_INT_Q(A, i, PI_BITS, UPItype);
   FP_PACK_RAW_Q(a, A);
   FP_HANDLE_EXCEPTIONS;
 
Index: gcc/config/soft-fp/fixunssfpi.c
===================================================================
--- gcc/config/soft-fp/fixunssfpi.c	(revision 325327)
+++ gcc/config/soft-fp/fixunssfpi.c	(working copy)
@@ -31,14 +31,14 @@ 
 #include "soft-fp.h"
 #include "single.h"
 
-UTItype __fixunssfti(SFtype a)
+UPItype __fixunssfpi(SFtype a)
 {
   FP_DECL_EX;
   FP_DECL_S(A);
-  UTItype r;
+  UPItype r;
 
   FP_UNPACK_RAW_S(A, a);
-  FP_TO_INT_S(r, A, TI_BITS, 0);
+  FP_TO_INT_S(r, A, PI_BITS, 0);
   FP_HANDLE_EXCEPTIONS;
 
   return r;
Index: gcc/config/soft-fp/fixsfpi.c
===================================================================
--- gcc/config/soft-fp/fixsfpi.c	(revision 325327)
+++ gcc/config/soft-fp/fixsfpi.c	(working copy)
@@ -31,14 +31,14 @@ 
 #include "soft-fp.h"
 #include "single.h"
 
-TItype __fixsfti(SFtype a)
+PItype __fixsfpi(SFtype a)
 {
   FP_DECL_EX;
   FP_DECL_S(A);
-  UTItype r;
+  UPItype r;
 
   FP_UNPACK_RAW_S(A, a);
-  FP_TO_INT_S(r, A, TI_BITS, 1);
+  FP_TO_INT_S(r, A, PI_BITS, 1);
   FP_HANDLE_EXCEPTIONS;
 
   return r;
Index: gcc/config/soft-fp/fixunsdfpi.c
===================================================================
--- gcc/config/soft-fp/fixunsdfpi.c	(revision 325327)
+++ gcc/config/soft-fp/fixunsdfpi.c	(working copy)
@@ -31,14 +31,14 @@ 
 #include "soft-fp.h"
 #include "double.h"
 
-UTItype __fixunsdfti(DFtype a)
+UPItype __fixunsdfpi(DFtype a)
 {
   FP_DECL_EX;
   FP_DECL_D(A);
-  UTItype r;
+  UPItype r;
 
   FP_UNPACK_RAW_D(A, a);
-  FP_TO_INT_D(r, A, TI_BITS, 0);
+  FP_TO_INT_D(r, A, PI_BITS, 0);
   FP_HANDLE_EXCEPTIONS;
 
   return r;
Index: gcc/config/soft-fp/fixdfpi.c
===================================================================
--- gcc/config/soft-fp/fixdfpi.c	(revision 325327)
+++ gcc/config/soft-fp/fixdfpi.c	(working copy)
@@ -31,14 +31,14 @@ 
 #include "soft-fp.h"
 #include "double.h"
 
-TItype __fixdfti(DFtype a)
+PItype __fixdfpi(DFtype a)
 {
   FP_DECL_EX;
   FP_DECL_D(A);
-  UTItype r;
+  UPItype r;
 
   FP_UNPACK_RAW_D(A, a);
-  FP_TO_INT_D(r, A, TI_BITS, 1);
+  FP_TO_INT_D(r, A, PI_BITS, 1);
   FP_HANDLE_EXCEPTIONS;
 
   return r;
Index: gcc/config/soft-fp/floatunpisf.c
===================================================================
--- gcc/config/soft-fp/floatunpisf.c	(revision 325327)
+++ gcc/config/soft-fp/floatunpisf.c	(working copy)
@@ -31,13 +31,13 @@ 
 #include "soft-fp.h"
 #include "single.h"
 
-SFtype __floatuntisf(UTItype i)
+SFtype __floatunpisf(UPItype i)
 {
   FP_DECL_EX;
   FP_DECL_S(A);
   SFtype a;
 
-  FP_FROM_INT_S(A, i, TI_BITS, UTItype);
+  FP_FROM_INT_S(A, i, PI_BITS, UPItype);
   FP_PACK_RAW_S(a, A);
   FP_HANDLE_EXCEPTIONS;
 
Index: gcc/config/soft-fp/fixunstfpi.c
===================================================================
--- gcc/config/soft-fp/fixunstfpi.c	(revision 325327)
+++ gcc/config/soft-fp/fixunstfpi.c	(working copy)
@@ -31,14 +31,14 @@ 
 #include "soft-fp.h"
 #include "quad.h"
 
-UTItype __fixunstfti(TFtype a)
+UPItype __fixunstfpi(TFtype a)
 {
   FP_DECL_EX;
   FP_DECL_Q(A);
-  UTItype r;
+  UPItype r;
 
   FP_UNPACK_RAW_Q(A, a);
-  FP_TO_INT_Q(r, A, TI_BITS, 0);
+  FP_TO_INT_Q(r, A, PI_BITS, 0);
   FP_HANDLE_EXCEPTIONS;
 
   return r;
Index: gcc/config/soft-fp/floatpidf.c
===================================================================
--- gcc/config/soft-fp/floatpidf.c	(revision 325327)
+++ gcc/config/soft-fp/floatpidf.c	(working copy)
@@ -31,13 +31,13 @@ 
 #include "soft-fp.h"
 #include "double.h"
 
-DFtype __floattidf(TItype i)
+DFtype __floatpidf(PItype i)
 {
   FP_DECL_EX;
   FP_DECL_D(A);
   DFtype a;
 
-  FP_FROM_INT_D(A, i, TI_BITS, UTItype);
+  FP_FROM_INT_D(A, i, PI_BITS, UPItype);
   FP_PACK_RAW_D(a, A);
   FP_HANDLE_EXCEPTIONS;
 
Index: gcc/config/soft-fp/fixtfpi.c
===================================================================
--- gcc/config/soft-fp/fixtfpi.c	(revision 325327)
+++ gcc/config/soft-fp/fixtfpi.c	(working copy)
@@ -31,14 +31,14 @@ 
 #include "soft-fp.h"
 #include "quad.h"
 
-TItype __fixtfti(TFtype a)
+PItype __fixtfpi(TFtype a)
 {
   FP_DECL_EX;
   FP_DECL_Q(A);
-  UTItype r;
+  UPItype r;
 
   FP_UNPACK_RAW_Q(A, a);
-  FP_TO_INT_Q(r, A, TI_BITS, 1);
+  FP_TO_INT_Q(r, A, PI_BITS, 1);
   FP_HANDLE_EXCEPTIONS;
 
   return r;
Index: gcc/config/soft-fp/soft-fp.h
===================================================================
--- gcc/config/soft-fp/soft-fp.h	(revision 325327)
+++ gcc/config/soft-fp/soft-fp.h	(working copy)
@@ -180,6 +180,9 @@  do {						\
 typedef int QItype __attribute__((mode(QI)));
 typedef int SItype __attribute__((mode(SI)));
 typedef int DItype __attribute__((mode(DI)));
+#ifdef __INT40_TYPE__
+typedef __int40_t PItype;
+#endif
 typedef unsigned int UQItype __attribute__((mode(QI)));
 typedef unsigned int USItype __attribute__((mode(SI)));
 typedef unsigned int UDItype __attribute__((mode(DI)));
@@ -188,6 +191,9 @@  typedef unsigned int UHWtype __attribute
 #elif _FP_W_TYPE_SIZE == 64
 typedef USItype UHWtype;
 #endif
+#ifdef __INT40_TYPE__
+typedef __uint40_t UPItype;
+#endif
 
 #ifndef CMPtype
 #define CMPtype		int
@@ -195,6 +201,7 @@  typedef USItype UHWtype;
 
 #define SI_BITS		(__CHAR_BIT__ * (int)sizeof(SItype))
 #define DI_BITS		(__CHAR_BIT__ * (int)sizeof(DItype))
+#define PI_BITS		40
 
 #ifndef umul_ppmm
 #ifdef _LIBC
Index: gcc/config/soft-fp/floatpitf.c
===================================================================
--- gcc/config/soft-fp/floatpitf.c	(revision 325327)
+++ gcc/config/soft-fp/floatpitf.c	(working copy)
@@ -31,13 +31,13 @@ 
 #include "soft-fp.h"
 #include "quad.h"
 
-TFtype __floattitf(TItype i)
+TFtype __floatpitf(PItype i)
 {
   FP_DECL_EX;
   FP_DECL_Q(A);
   TFtype a;
 
-  FP_FROM_INT_Q(A, i, TI_BITS, UTItype);
+  FP_FROM_INT_Q(A, i, PI_BITS, UPItype);
   FP_PACK_RAW_Q(a, A);
   FP_HANDLE_EXCEPTIONS;
 
Index: libgcc/Makefile.in
===================================================================
--- libgcc/Makefile.in  (revision 329707)
+++ libgcc/Makefile.in  (working copy)
@@ -315,6 +315,8 @@  lib2funcs = _muldi3 _negdi2 _lshrdi3 _as
            _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3 _divxc3        \
            _divtc3 _bswapsi2 _bswapdi2 _clrsbsi2 _clrsbdi2
 
+lib2funcs += $(LIB2_PI_FUNCS)
+
 # The floating-point conversion routines that involve a single-word integer.
 # XX stands for the integer mode.
 swfloatfuncs = $(patsubst %,_fixuns%XX,sf df xf)
Index: libgcc/config/t-pimode
===================================================================
--- libgcc/config/t-pimode      (revision 0)
+++ libgcc/config/t-pimode      (revision 0)
@@ -0,0 +1,2 @@ 
+LIB2_PI_FUNCS = _mulpi3 _divpi3 _udivpi3 _modpi3 _umodpi3
+
Index: gcc/libgcc2.c
===================================================================
--- gcc/libgcc2.c	(revision 329707)
+++ gcc/libgcc2.c	(working copy)
@@ -561,6 +561,21 @@  __muldi3 (DWtype u, DWtype v)
   return w.ll;
 }
 #endif
+
+#ifdef L_mulpi3
+PItype
+__mulpi3 (PItype u, PItype v)
+{
+  const DWunion uu = {.ll = u};
+  const DWunion vv = {.ll = v};
+  DWunion w = {.ll = __umulsidi3 (uu.s.low, vv.s.low)};
+
+  w.s.high += ((UHWtype) uu.s.low * (UHWtype) vv.s.high
+	       + (UHWtype) uu.s.high * (UHWtype) vv.s.low);
+
+  return w.ll;
+}
+#endif
 

 #if (defined (L_udivdi3) || defined (L_divdi3) || \
      defined (L_umoddi3) || defined (L_moddi3))
@@ -1182,6 +1197,73 @@  __udivdi3 (UDWtype n, UDWtype d)
 {
   return __udivmoddi4 (n, d, (UDWtype *) 0);
 }
+#endif
+
+#ifdef L_divpi3
+PItype
+__divpi3 (PItype u, PItype v)
+{
+  Wtype c = 0;
+  DWunion uu = {.ll = u};
+  DWunion vv = {.ll = v};
+  PItype w;
+
+  if (uu.s.high < 0)
+    c = ~c,
+    uu.ll = -uu.ll;
+  if (vv.s.high < 0)
+    c = ~c,
+    vv.ll = -vv.ll;
+
+  w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
+  if (c)
+    w = -w;
+
+  return w;
+}
+#endif
+
+#ifdef L_modpi3
+PItype
+__modpi3 (PItype u, PItype v)
+{
+  Wtype c = 0;
+  DWunion uu = {.ll = u};
+  DWunion vv = {.ll = v};
+  DWtype w;
+
+  if (uu.s.high < 0)
+    c = ~c,
+    uu.ll = -uu.ll;
+  if (vv.s.high < 0)
+    vv.ll = -vv.ll;
+
+  (void) __udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w);
+  if (c)
+    w = -w;
+
+  return w;
+}
+#endif
+
+#ifdef L_umodpi3
+UPItype
+__umodpi3 (UPItype u, UPItype v)
+{
+  UDWtype w;
+
+  (void) __udivmoddi4 (u, v, &w);
+
+  return w;
+}
+#endif
+
+#ifdef L_udivpi3
+UPItype
+__udivpi3 (UPItype n, UPItype d)
+{
+  return __udivmoddi4 (n, d, (UDWtype *) 0);
+}
 #endif
 

 #ifdef L_cmpdi2
Index: gcc/libgcc2.h
===================================================================
--- gcc/libgcc2.h	(revision 329707)
+++ gcc/libgcc2.h	(working copy)
@@ -152,6 +152,11 @@  typedef unsigned int UTItype	__attribute
 #endif
 #endif
 
+#ifdef __INT40_TYPE__
+typedef		 int PItype	__attribute__ ((mode (PI)));
+typedef unsigned int UPItype	__attribute__ ((mode (PI)));
+#endif
+
 #if LIBGCC2_HAS_SF_MODE
 typedef 	float SFtype	__attribute__ ((mode (SF)));
 typedef _Complex float SCtype	__attribute__ ((mode (SC)));
@@ -336,6 +341,11 @@  typedef int shift_count_type __attribute
 #define __popcountDI2	__NDW(popcount,2)
 #define __parityDI2	__NDW(parity,2)
 
+#define __mulpi3		__N(mulpi3)
+#define __divpi3		__N(divpi3)
+#define __modpi3		__N(modpi3)
+#define __udivpi3		__N(udivpi3)
+#define __umodpi3		__N(umodpi3)
 #define __clz_tab		__N(clz_tab)
 #define __bswapsi2		__N(bswapsi2)
 #define __bswapdi2		__N(bswapdi2)
@@ -392,6 +402,14 @@  extern DWtype __moddi3 (DWtype, DWtype);
 extern UDWtype __udivmoddi4 (UDWtype, UDWtype, UDWtype *);
 #endif
 
+#ifdef L_mulpi3
+extern PItype __mulpi3 (PItype, PItype);
+extern PItype __divpi3 (PItype, PItype);
+extern UPItype __udivpi3 (UPItype, UPItype);
+extern UPItype __umodpi3 (UPItype, UPItype);
+extern PItype __modpi3 (PItype, PItype);
+#endif
+
 /* __negdi2 is static inline when building other libgcc2 portions.  */
 #if !defined(L_divdi3) && !defined(L_moddi3)
 extern DWtype __negdi2 (DWtype);