Commit c774b28f authored by Herbert Valerio Riedel's avatar Herbert Valerio Riedel 🕺

Implement new integer-gmp2 from scratch (re #9281)

This is done as a separate `integer-gmp2` backend library because it
turned out to become a complete rewrite from scratch.

Due to the different (over)allocation scheme and potentially different
accounting (via the new `{shrink,resize}MutableByteArray#` primitives),
some of the nofib benchmarks actually results in increased allocation
numbers (but not necessarily an increase in runtime!).  I believe the
allocation numbers could improve if `{resize,shrink}MutableByteArray#`
could be optimised to reallocate in-place more efficiently.

Here are the more apparent changes in the latest nofib comparision
between `integer-gmp` and `integer-gmp2`:

  ------------------------------------------------------------------
          Program     Size    Allocs   Runtime   Elapsed  TotalMem
  ------------------------------------------------------------------
              ...
       bernouilli    +1.6%    +15.3%     0.132     0.132      0.0%
              ...
     cryptarithm1    -2.2%      0.0%     -9.7%     -9.7%      0.0%
              ...
            fasta    -0.7%     -0.0%    +10.9%    +10.9%      0.0%
              ...
            kahan    +0.6%    +38.9%     0.169     0.169      0.0%
              ...
             lcss    -0.7%     -0.0%     -6.4%     -6.4%      0.0%
              ...
           mandel    +1.6%    +33.6%     0.049     0.049      0.0%
              ...
         pidigits    +0.8%     +8.5%     +3.9%     +3.9%      0.0%
            power    +1.4%    -23.8%    -18.6%    -18.6%    -16.7%
              ...
        primetest    +1.3%    +50.1%     0.085     0.085      0.0%
              ...
              rsa    +1.6%    +53.4%     0.026     0.026      0.0%
              ...
              scs    +1.2%     +6.6%     +6.5%     +6.6%    +14.3%
              ...
           symalg    +1.0%     +9.5%     0.010     0.010      0.0%
              ...
        transform    -0.6%     -0.0%     -5.9%     -5.9%      0.0%
              ...
  ------------------------------------------------------------------
              Min    -2.3%    -23.8%    -18.6%    -18.6%    -16.7%
              Max    +1.6%    +53.4%    +10.9%    +10.9%    +14.3%
   Geometric Mean    -0.3%     +1.9%     -0.8%     -0.8%     +0.0%

(see P35 / https://phabricator.haskell.org/P35 for full report)

By default, `INTEGER_LIBRARY=integer-gmp2` is active now, which results
in the package `integer-gmp-1.0.0.0` being registered in the package db.
The previous `integer-gmp-0.5.1.0` can be restored by setting
`INTEGER_LIBRARY=integer-gmp` (but will probably be removed altogether
for GHC 7.12). In-tree GMP support has been stolen from the old
`integer-gmp` (while unpatching the custom memory-allocators, as well as
forcing `-fPIC`)

A minor hack to `ghc-cabal` was necessary in order to support two different
`integer-gmp` packages (in different folders) with the same package key.

There will be a couple of follow-up commits re-implementing some features
that were dropped to keep D82 minimal, as well as further
clean-ups/improvements.

More information can be found via #9281 and
https://ghc.haskell.org/trac/ghc/wiki/Design/IntegerGmp2

Reviewed By: austin, rwbarton, simonmar

Differential Revision: https://phabricator.haskell.org/D82
parent fcfc87dc
......@@ -380,7 +380,12 @@ integerPackageKey, primPackageKey,
thPackageKey, dphSeqPackageKey, dphParPackageKey,
mainPackageKey, thisGhcPackageKey, interactivePackageKey :: PackageKey
primPackageKey = fsToPackageKey (fsLit "ghc-prim")
integerPackageKey = fsToPackageKey (fsLit cIntegerLibrary)
integerPackageKey = fsToPackageKey (fsLit n)
where
n = case cIntegerLibraryType of
IntegerGMP -> "integer-gmp"
IntegerGMP2 -> "integer-gmp"
IntegerSimple -> "integer-simple"
basePackageKey = fsToPackageKey (fsLit "base")
rtsPackageKey = fsToPackageKey (fsLit "rts")
thPackageKey = fsToPackageKey (fsLit "template-haskell")
......
......@@ -1123,7 +1123,8 @@ lookupIntegerSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)
lookupIntegerSDataConName dflags hsc_env = case cIntegerLibraryType of
IntegerGMP -> guardIntegerUse dflags $ liftM Just $
initTcForLookup hsc_env (tcLookupDataCon integerSDataConName)
IntegerGMP2-> guardIntegerUse dflags $ liftM Just $
initTcForLookup hsc_env (tcLookupDataCon integerSDataConName)
IntegerSimple -> return Nothing
-- | Helper for 'lookupMkIntegerName' and 'lookupIntegerSDataConName'
......
......@@ -53,8 +53,10 @@ compiler/stage%/build/Config.hs : mk/config.mk mk/project.mk | $$(dir $$@)/.
@echo >> $@
@echo '#include "ghc_boot_platform.h"' >> $@
@echo >> $@
@echo 'data IntegerLibrary = IntegerGMP | IntegerSimple' >> $@
@echo ' deriving Eq' >> $@
@echo 'data IntegerLibrary = IntegerGMP' >> $@
@echo ' | IntegerGMP2' >> $@
@echo ' | IntegerSimple' >> $@
@echo ' deriving Eq' >> $@
@echo >> $@
@echo 'cBuildPlatformString :: String' >> $@
@echo 'cBuildPlatformString = BuildPlatform_NAME' >> $@
......@@ -84,6 +86,8 @@ compiler/stage%/build/Config.hs : mk/config.mk mk/project.mk | $$(dir $$@)/.
@echo 'cIntegerLibraryType :: IntegerLibrary' >> $@
ifeq "$(INTEGER_LIBRARY)" "integer-gmp"
@echo 'cIntegerLibraryType = IntegerGMP' >> $@
else ifeq "$(INTEGER_LIBRARY)" "integer-gmp2"
@echo 'cIntegerLibraryType = IntegerGMP2' >> $@
else ifeq "$(INTEGER_LIBRARY)" "integer-simple"
@echo 'cIntegerLibraryType = IntegerSimple' >> $@
else ifneq "$(CLEANING)" "YES"
......
......@@ -356,6 +356,7 @@ basicKnownKeyNames
, ghciIoClassName, ghciStepIoMName
] ++ case cIntegerLibraryType of
IntegerGMP -> [integerSDataConName]
IntegerGMP2 -> [integerSDataConName]
IntegerSimple -> []
genericTyConNames :: [Name]
......@@ -936,6 +937,7 @@ integerTyConName = tcQual gHC_INTEGER_TYPE (fsLit "Integer") int
integerSDataConName = conName gHC_INTEGER_TYPE (fsLit n) integerSDataConKey
where n = case cIntegerLibraryType of
IntegerGMP -> "S#"
IntegerGMP2 -> "S#"
IntegerSimple -> panic "integerSDataConName evaluated for integer-simple"
mkIntegerName = varQual gHC_INTEGER_TYPE (fsLit "mkInteger") mkIntegerIdKey
integerToWord64Name = varQual gHC_INTEGER_TYPE (fsLit "integerToWord64") integerToWord64IdKey
......
......@@ -590,7 +590,9 @@ libraries/ghc-prim_dist-install_EXTRA_HADDOCK_SRCS = libraries/ghc-prim/dist-ins
ifneq "$(CLEANING)" "YES"
ifeq "$(INTEGER_LIBRARY)" "integer-gmp"
libraries/base_dist-install_CONFIGURE_OPTS += --flags=-integer-simple
libraries/base_dist-install_CONFIGURE_OPTS += --flags=integer-gmp
else ifeq "$(INTEGER_LIBRARY)" "integer-gmp2"
libraries/base_dist-install_CONFIGURE_OPTS += --flags=integer-gmp2
else ifeq "$(INTEGER_LIBRARY)" "integer-simple"
libraries/base_dist-install_CONFIGURE_OPTS += --flags=integer-simple
else
......@@ -657,6 +659,12 @@ BUILD_DIRS += libraries/integer-gmp/gmp
BUILD_DIRS += libraries/integer-gmp/mkGmpDerivedConstants
endif
ifeq "$(INTEGER_LIBRARY)" "integer-gmp2"
BUILD_DIRS += libraries/integer-gmp2/gmp
else ifneq "$(findstring clean,$(MAKECMDGOALS))" ""
BUILD_DIRS += libraries/integer-gmp2/gmp
endif
BUILD_DIRS += utils/haddock
BUILD_DIRS += utils/haddock/doc
BUILD_DIRS += compiler
......@@ -1212,6 +1220,7 @@ sdist_%:
CLEAN_FILES += libraries/bootstrapping.conf
CLEAN_FILES += libraries/integer-gmp/cbits/GmpDerivedConstants.h
CLEAN_FILES += libraries/integer-gmp/include/HsIntegerGmp.h
CLEAN_FILES += libraries/integer-gmp2/include/HsIntegerGmp.h
CLEAN_FILES += libraries/base/include/EventConfig.h
CLEAN_FILES += mk/config.mk.old
CLEAN_FILES += mk/project.mk.old
......
......@@ -27,7 +27,11 @@ import GHC.Show
import {-# SOURCE #-} GHC.Exception( divZeroException, overflowException, ratioZeroDenomException )
#ifdef OPTIMISE_INTEGER_GCD_LCM
# if defined(MIN_VERSION_integer_gmp) || defined(MIN_VERSION_integer_gmp2)
import GHC.Integer.GMP.Internals
# else
# error unsupported OPTIMISE_INTEGER_GCD_LCM configuration
# endif
#endif
infixr 8 ^, ^^
......
......@@ -44,6 +44,18 @@ source-repository head
Flag integer-simple
Description: Use integer-simple
Manual: True
Default: False
Flag integer-gmp
Description: Use integer-gmp
Manual: True
Default: False
Flag integer-gmp2
Description: Use integer-gmp2
Manual: True
Default: False
Library
default-language: Haskell2010
......@@ -90,10 +102,15 @@ Library
build-depends: rts == 1.0.*, ghc-prim >= 0.3.1 && < 0.4
if flag(integer-simple)
build-depends: integer-simple >= 0.1.1 && < 0.2
else
if flag(integer-gmp)
build-depends: integer-gmp >= 0.5.1 && < 0.6
cpp-options: -DOPTIMISE_INTEGER_GCD_LCM
if flag(integer-gmp2)
build-depends: integer-gmp >= 1.0 && < 1.1
cpp-options: -DOPTIMISE_INTEGER_GCD_LCM
exposed-modules:
Control.Applicative
Control.Arrow
......
/GNUmakefile
/autom4te.cache/
/config.log
/config.status
/configure
/dist-install/
/ghc.mk
/gmp/config.mk
/include/HsIntegerGmp.h
/integer-gmp.buildinfo
/gmp/gmp.h
/gmp/gmpbuild
Copyright (c) 2014, Herbert Valerio Riedel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Herbert Valerio Riedel nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
module Main (main) where
import Distribution.Simple
main :: IO ()
main = defaultMainWithHooks autoconfUserHooks
dnl--------------------------------------------------------------------
dnl * Check whether this machine has gmp/gmp3 installed
dnl--------------------------------------------------------------------
AC_DEFUN([LOOK_FOR_GMP_LIB],[
if test "$HaveFrameworkGMP" = "NO"
then
AC_CHECK_LIB([gmp], [__gmpz_powm],
[HaveLibGmp=YES; GMP_LIBS=gmp])
if test "$HaveLibGmp" = "NO"
then
AC_CHECK_LIB([gmp3], [__gmpz_powm],
[HaveLibGmp=YES; GMP_LIBS=gmp3])
fi
if test "$HaveLibGmp" = "YES"
then
AC_CHECK_LIB([$GMP_LIBS], [__gmpz_powm_sec],
[HaveSecurePowm=1])
fi
fi
])
dnl--------------------------------------------------------------------
dnl * Mac OS X only: check for GMP.framework
dnl--------------------------------------------------------------------
AC_DEFUN([LOOK_FOR_GMP_FRAMEWORK],[
if test "$HaveLibGmp" = "NO"
then
case $target_os in
darwin*)
AC_MSG_CHECKING([for GMP.framework])
save_libs="$LIBS"
LIBS="-framework GMP"
AC_TRY_LINK_FUNC(__gmpz_powm_sec,
[HaveFrameworkGMP=YES; GMP_FRAMEWORK=GMP])
LIBS="$save_libs"
AC_MSG_RESULT([$HaveFrameworkGMP])
;;
esac
fi
])
#define _ISOC99_SOURCE
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <stdio.h>
#include <gmp.h>
#include "HsFFI.h"
#include "MachDeps.h"
#if (GMP_NUMB_BITS) != (GMP_LIMB_BITS)
# error GMP_NUMB_BITS != GMP_LIMB_BITS not supported
#endif
#if (WORD_SIZE_IN_BITS) != (GMP_LIMB_BITS)
# error WORD_SIZE_IN_BITS != GMP_LIMB_BITS not supported
#endif
// sanity check
#if (SIZEOF_HSWORD*8) != WORD_SIZE_IN_BITS
# error (SIZEOF_HSWORD*8) != WORD_SIZE_IN_BITS
#endif
/* Perform arithmetic right shift on MPNs (multi-precision naturals)
*
* pre-conditions:
* - 0 < count < sn*GMP_NUMB_BITS
* - rn = sn - floor(count / GMP_NUMB_BITS)
* - sn > 0
*
* write {sp,sn} right-shifted by count bits into {rp,rn}
*
* return value: most-significant limb stored in {rp,rn} result
*/
mp_limb_t
integer_gmp_mpn_rshift (mp_limb_t rp[], const mp_limb_t sp[], mp_size_t sn,
mp_bitcnt_t count)
{
const mp_size_t limb_shift = count / GMP_NUMB_BITS;
const unsigned int bit_shift = count % GMP_NUMB_BITS;
const mp_size_t rn = sn - limb_shift;
if (bit_shift)
mpn_rshift(rp, &sp[limb_shift], rn, bit_shift);
else
memcpy(rp, &sp[limb_shift], rn*sizeof(mp_limb_t));
return rp[rn-1];
}
/* Twos-complement version of 'integer_gmp_mpn_rshift' for performing
* arithmetic right shifts on "negative" MPNs.
*
* Same pre-conditions as 'integer_gmp_mpn_rshift'
*
* This variant is needed to operate on MPNs interpreted as negative
* numbers, which require "rounding" towards minus infinity iff a
* non-zero bit is shifted out.
*/
mp_limb_t
integer_gmp_mpn_rshift_2c (mp_limb_t rp[], const mp_limb_t sp[],
const mp_size_t sn, const mp_bitcnt_t count)
{
const mp_size_t limb_shift = count / GMP_NUMB_BITS;
const unsigned int bit_shift = count % GMP_NUMB_BITS;
const mp_size_t rn = sn - limb_shift;
// whether non-zero bits were shifted out
bool nz_shift_out = false;
if (bit_shift) {
if (mpn_rshift(rp, &sp[limb_shift], rn, bit_shift))
nz_shift_out = true;
} else
memcpy(rp, &sp[limb_shift], rn*sizeof(mp_limb_t));
if (!nz_shift_out)
for (unsigned i = 0; i < limb_shift; i++)
if (sp[i]) {
nz_shift_out = true;
break;
}
// round if non-zero bits were shifted out
if (nz_shift_out)
if (mpn_add_1(rp, rp, rn, 1))
abort(); /* should never happen */
return rp[rn-1];
}
/* Perform left-shift operation on MPN
*
* pre-conditions:
* - 0 < count
* - rn = sn + ceil(count / GMP_NUMB_BITS)
* - sn > 0
*
* return value: most-significant limb stored in {rp,rn} result
*/
mp_limb_t
integer_gmp_mpn_lshift (mp_limb_t rp[], const mp_limb_t sp[],
const mp_size_t sn, const mp_bitcnt_t count)
{
const mp_size_t limb_shift = count / GMP_NUMB_BITS;
const unsigned int bit_shift = count % GMP_NUMB_BITS;
const mp_size_t rn0 = sn + limb_shift;
memset(rp, 0, limb_shift*sizeof(mp_limb_t));
if (bit_shift) {
const mp_limb_t msl = mpn_lshift(&rp[limb_shift], sp, sn, bit_shift);
rp[rn0] = msl;
return msl;
} else {
memcpy(&rp[limb_shift], sp, sn*sizeof(mp_limb_t));
return rp[rn0-1];
}
}
/*
*
* sign of mp_size_t argument controls sign of converted double
*/
HsDouble
integer_gmp_mpn_get_d (const mp_limb_t sp[], const mp_size_t sn,
const HsInt exponent)
{
if (sn == 0)
return 0.0; // should not happen
if (sn == 1 && sp[0] == 0)
return 0.0;
__mpz_struct const mpz = {
._mp_alloc = abs(sn),
._mp_size = sn,
._mp_d = (mp_limb_t*)sp
};
if (!exponent)
return mpz_get_d(&mpz);
long e = 0;
double d = mpz_get_d_2exp (&e, &mpz);
// TODO: over/underflow handling?
return ldexp(d, e+exponent);
}
mp_limb_t
integer_gmp_gcd_word(const mp_limb_t x, const mp_limb_t y)
{
if (!x) return y;
if (!y) return x;
return mpn_gcd_1(&x, 1, y);
}
mp_limb_t
integer_gmp_mpn_gcd_1(const mp_limb_t x[], const mp_size_t xn,
const mp_limb_t y)
{
assert (xn > 0);
assert (xn == 1 || y != 0);
if (xn == 1)
return integer_gmp_gcd_word(x[0], y);
return mpn_gcd_1(x, xn, y);
}
mp_size_t
integer_gmp_mpn_gcd(mp_limb_t r[],
const mp_limb_t x0[], const mp_size_t xn,
const mp_limb_t y0[], const mp_size_t yn)
{
assert (xn >= yn);
assert (yn > 0);
assert (xn == yn || yn > 1 || y0[0] != 0);
/* post-condition: rn <= xn */
if (yn == 1) {
if (y0[0]) {
r[0] = integer_gmp_mpn_gcd_1(x0, xn, y0[0]);
return 1;
} else { /* {y0,yn} == 0 */
assert (xn==yn); /* NB: redundant assertion */
memcpy(r, x0, xn*sizeof(mp_limb_t));
return xn;
}
} else {
// mpn_gcd() seems to require non-trivial normalization of its
// input arguments (which does not seem to be documented anywhere,
// see source of mpz_gcd() for more details), so we resort to just
// use mpz_gcd() which does the tiresome normalization for us at
// the cost of a few additional temporary buffer allocations in
// C-land.
const mpz_t op1 = {{
._mp_alloc = xn,
._mp_size = xn,
._mp_d = (mp_limb_t*)x0
}};
const mpz_t op2 = {{
._mp_alloc = yn,
._mp_size = yn,
._mp_d = (mp_limb_t*)y0
}};
mpz_t rop;
mpz_init (rop);
mpz_gcd(rop, op1, op2);
const mp_size_t rn = rop[0]._mp_size;
assert(rn > 0);
assert(rn <= xn);
/* the allocation/memcpy of the result can be neglectable since
mpz_gcd() already has to allocate other temporary buffers
anyway */
memcpy(r, rop[0]._mp_d, rn*sizeof(mp_limb_t));
mpz_clear(rop);
return rn;
}
}
/* Truncating (i.e. rounded towards zero) integer division-quotient of MPN */
void
integer_gmp_mpn_tdiv_q (mp_limb_t q[],
const mp_limb_t n[], const mp_size_t nn,
const mp_limb_t d[], const mp_size_t dn)
{
/* qn = 1+nn-dn; rn = dn */
assert(nn>=dn);
if (dn > 128) {
// Use temporary heap allocated throw-away buffer for MPNs larger
// than 1KiB for 64bit-sized limbs (larger than 512bytes for
// 32bit-sized limbs)
mp_limb_t *const r = malloc(dn*sizeof(mp_limb_t));
mpn_tdiv_qr(q, r, 0, n, nn, d, dn);
free (r);
} else { // allocate smaller arrays on the stack
mp_limb_t r[dn];
mpn_tdiv_qr(q, r, 0, n, nn, d, dn);
}
}
/* Truncating (i.e. rounded towards zero) integer division-remainder of MPNs */
void
integer_gmp_mpn_tdiv_r (mp_limb_t r[],
const mp_limb_t n[], const mp_size_t nn,
const mp_limb_t d[], const mp_size_t dn)
{
/* qn = 1+nn-dn; rn = dn */
assert(nn>=dn);
const mp_size_t qn = 1+nn-dn;
if (qn > 128) {
// Use temporary heap allocated throw-away buffer for MPNs larger
// than 1KiB for 64bit-sized limbs (larger than 512bytes for
// 32bit-sized limbs)
mp_limb_t *const q = malloc(qn*sizeof(mp_limb_t));
mpn_tdiv_qr(q, r, 0, n, nn, d, dn);
free (q);
} else { // allocate smaller arrays on the stack
mp_limb_t q[qn];
mpn_tdiv_qr(q, r, 0, n, nn, d, dn);
}
}
# Changelog for [`integer-gmp` package](http://hackage.haskell.org/package/integer-gmp)
## 1.0.0.0 **TBA**
* Bundled with GHC 7.10.1
* Complete rewrite of `integer-gmp`. For more details, see
https://ghc.haskell.org/trac/ghc/wiki/Design/IntegerGmp2
## 0.5.1.0 *Feb 2014*
* Bundled with GHC 7.8.1
* Improved Haddock documentation
* New [PrimBool](https://ghc.haskell.org/trac/ghc/wiki/PrimBool)
versions of comparison predicates in `GHC.Integer`:
eqInteger# :: Integer -> Integer -> Int#
geInteger# :: Integer -> Integer -> Int#
gtInteger# :: Integer -> Integer -> Int#
leInteger# :: Integer -> Integer -> Int#
ltInteger# :: Integer -> Integer -> Int#
neqInteger# :: Integer -> Integer -> Int#
* New `GHC.Integer.testBitInteger` primitive for use with `Data.Bits`
* Reduce short-lived heap allocation and try to demote `J#` back
to `S#` more aggressively. See also
[#8647](https://ghc.haskell.org/trac/ghc/ticket/8647)
for more details.
* New GMP-specific binary (de)serialization primitives added to
`GHC.Integer.GMP.Internals`:
importIntegerFromByteArray
importIntegerFromAddr
exportIntegerToAddr
exportIntegerToMutableByteArray
sizeInBaseInteger
* New GMP-implemented number-theoretic operations added to
`GHC.Integer.GMP.Internals`:
gcdExtInteger
nextPrimeInteger
testPrimeInteger
powInteger
powModInteger
powModSecInteger
recipModInteger
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2014 Free Software Foundation, Inc.
timestamp='2014-03-23'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
Output the configuration name of the system \`$me' is run on.
Operation modes:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
<