summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2011-04-10 08:55:41 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2011-04-10 09:55:27 +0200
commit57555c75a8faf71bc7d664d73a2b9914ddb809d0 (patch)
tree69ef7906240427ee77d9a3f0d0cec7fc04098982
parent6ceb3b0e0836f08ede425fd58ff93f322b881636 (diff)
downloadgnutls-57555c75a8faf71bc7d664d73a2b9914ddb809d0.tar.gz
Added support for x86 intel AES instruction acceleration if detected.
-rw-r--r--configure.ac180
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/accelerated/Makefile.am40
-rw-r--r--lib/accelerated/accelerated.c14
-rw-r--r--lib/accelerated/accelerated.h1
-rw-r--r--lib/accelerated/aes-x86.c221
-rw-r--r--lib/accelerated/aes-x86.h1
-rw-r--r--lib/accelerated/x86.h3
-rw-r--r--lib/gnutls_global.c3
-rw-r--r--m4/gcc.m428
10 files changed, 416 insertions, 78 deletions
diff --git a/configure.ac b/configure.ac
index f451464d72..941fa9f686 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,85 +91,27 @@ AC_CHECK_TYPES(uint,,, [
# include <sys/types.h>
])
-# For Guile bindings.
-opt_guile_bindings=yes
-AC_MSG_CHECKING([whether building Guile bindings])
-AC_ARG_ENABLE(guile,
- AS_HELP_STRING([--enable-guile], [build GNU Guile bindings]),
-opt_guile_bindings=$enableval)
-AC_MSG_RESULT($opt_guile_bindings)
-
-AC_ARG_WITH([--with-guile-site-dir],
- [AS_HELP_STRING([--with-guile-site-dir],
- [use the given directory as the Guile site (use with care)])])
-
-if test "$opt_guile_bindings" = "yes"; then
- AC_MSG_RESULT([***
-*** Detecting GNU Guile...
-])
-
- AC_PATH_PROG([guile_snarf], [guile-snarf])
- if test "x$guile_snarf" = "x"; then
- AC_MSG_WARN([`guile-snarf' from Guile 1.8 not found. Guile bindings not built.])
- opt_guile_bindings=no
- else
- GUILE_PROGS
- GUILE_FLAGS
-
- save_CFLAGS="$CFLAGS"
- save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $GUILE_CFLAGS"
- LIBS="$LIBS $GUILE_LDFLAGS"
- AC_MSG_CHECKING([whether GNU Guile is recent enough])
- AC_LINK_IFELSE(AC_LANG_CALL([], [scm_from_locale_string]),
- [], [opt_guile_bindings=no])
- CFLAGS="$save_CFLAGS"
- LIBS="$save_LIBS"
-
- if test "$opt_guile_bindings" = "yes"; then
- AC_MSG_RESULT([yes])
- case "x$with_guile_site_dir" in
- xno)
- # Use the default $(GUILE_SITE).
- GUILE_SITE_DIR
- ;;
- x|xyes)
- # Automatically derive $(GUILE_SITE) from $(pkgdatadir). This
- # hack is used to allow `distcheck' to work (see
- # `DISTCHECK_CONFIGURE_FLAGS' in the top-level `Makefile.am').
- GUILE_SITE="\$(datadir)/guile/site"
- AC_SUBST(GUILE_SITE)
- ;;
- *)
- # Use the user-specified directory as $(GUILE_SITE).
- GUILE_SITE="$with_guile_site_dir"
- AC_SUBST(GUILE_SITE)
- ;;
- esac
- AC_MSG_CHECKING([whether gcc supports -fgnu89-inline])
- _gcc_cflags_save="$CFLAGS"
- CFLAGS="${CFLAGS} -fgnu89-inline"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
- gnu89_inline=yes, gnu89_inline=no)
- AC_MSG_RESULT($gnu89_inline)
- CFLAGS="$_gcc_cflags_save"
+AC_ARG_ENABLE(hardware-acceleration,
+ AS_HELP_STRING([--disable-hardware-acceleration], [unconditionally disable hardware acceleration]),
+ use_accel=$enableval, use_accel=yes)
+hw_accel=none
+
+if test "$use_accel" != "no"; then
+case $host_cpu in
+ i?86 | x86_64 | amd64)
+ GCC_FLAG_ADD([-maes -mpclmul],[X86])
+
+ if test "x$X86" = "xyes";then
+ hw_accel="x86"
+ fi
+ ;;
+ *)
+ ;;
+esac
- # Optional Guile functions.
- save_CFLAGS="$CFLAGS"
- save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $GUILE_CFLAGS"
- LIBS="$LIBS $GUILE_LDFLAGS"
- AC_CHECK_FUNCS([scm_gc_malloc_pointerless])
- CFLAGS="$save_CFLAGS"
- LIBS="$save_LIBS"
- else
- AC_MSG_RESULT([no])
- AC_MSG_WARN([A sufficiently recent GNU Guile not found. Guile bindings not built.])
- opt_guile_bindings=no
- fi
- fi
fi
-AM_CONDITIONAL(HAVE_GUILE, test "$opt_guile_bindings" = "yes")
+
+AM_CONDITIONAL(TRY_X86_OPTIMIZATIONS, test "$X86" = "yes")
AM_CONDITIONAL(HAVE_GCC_GNU89_INLINE_OPTION, test "$gnu89_inline" = "yes"])
AM_CONDITIONAL(HAVE_GCC, test "$GCC" = "yes")
@@ -310,6 +252,87 @@ AC_SUBST([WSTACK_CFLAGS])
AC_SUBST([WARN_CFLAGS])
AM_CONDITIONAL(ENABLE_CXX, test "$use_cxx" != "no")
+# For Guile bindings.
+opt_guile_bindings=yes
+AC_MSG_CHECKING([whether building Guile bindings])
+AC_ARG_ENABLE(guile,
+ AS_HELP_STRING([--enable-guile], [build GNU Guile bindings]),
+opt_guile_bindings=$enableval)
+AC_MSG_RESULT($opt_guile_bindings)
+
+AC_ARG_WITH([--with-guile-site-dir],
+ [AS_HELP_STRING([--with-guile-site-dir],
+ [use the given directory as the Guile site (use with care)])])
+
+if test "$opt_guile_bindings" = "yes"; then
+ AC_MSG_RESULT([***
+*** Detecting GNU Guile...
+])
+
+ AC_PATH_PROG([guile_snarf], [guile-snarf])
+ if test "x$guile_snarf" = "x"; then
+ AC_MSG_WARN([`guile-snarf' from Guile 1.8 not found. Guile bindings not built.])
+ opt_guile_bindings=no
+ else
+ GUILE_PROGS
+ GUILE_FLAGS
+
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GUILE_CFLAGS"
+ LIBS="$LIBS $GUILE_LDFLAGS"
+ AC_MSG_CHECKING([whether GNU Guile is recent enough])
+ AC_LINK_IFELSE(AC_LANG_CALL([], [scm_from_locale_string]),
+ [], [opt_guile_bindings=no])
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+
+ if test "$opt_guile_bindings" = "yes"; then
+ AC_MSG_RESULT([yes])
+ case "x$with_guile_site_dir" in
+ xno)
+ # Use the default $(GUILE_SITE).
+ GUILE_SITE_DIR
+ ;;
+ x|xyes)
+ # Automatically derive $(GUILE_SITE) from $(pkgdatadir). This
+ # hack is used to allow `distcheck' to work (see
+ # `DISTCHECK_CONFIGURE_FLAGS' in the top-level `Makefile.am').
+ GUILE_SITE="\$(datadir)/guile/site"
+ AC_SUBST(GUILE_SITE)
+ ;;
+ *)
+ # Use the user-specified directory as $(GUILE_SITE).
+ GUILE_SITE="$with_guile_site_dir"
+ AC_SUBST(GUILE_SITE)
+ ;;
+ esac
+ AC_MSG_CHECKING([whether gcc supports -fgnu89-inline])
+ _gcc_cflags_save="$CFLAGS"
+ CFLAGS="${CFLAGS} -fgnu89-inline"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+ gnu89_inline=yes, gnu89_inline=no)
+ AC_MSG_RESULT($gnu89_inline)
+ CFLAGS="$_gcc_cflags_save"
+
+ # Optional Guile functions.
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GUILE_CFLAGS"
+ LIBS="$LIBS $GUILE_LDFLAGS"
+ AC_CHECK_FUNCS([scm_gc_malloc_pointerless])
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_WARN([A sufficiently recent GNU Guile not found. Guile bindings not built.])
+ opt_guile_bindings=no
+ fi
+ fi
+fi
+AM_CONDITIONAL(HAVE_GUILE, test "$opt_guile_bindings" = "yes")
+
+
LIBGNUTLS_EXTRA_LIBS="-L${libdir} -lgnutls-extra $LZO_LIBS $LIBGNUTLS_LIBS"
LIBGNUTLS_EXTRA_CFLAGS="-I${includedir}"
AC_SUBST(LIBGNUTLS_EXTRA_LIBS)
@@ -376,6 +399,7 @@ AC_CONFIG_FILES([
lib/gcrypt/Makefile
lib/nettle/Makefile
tests/suite/Makefile
+ lib/accelerated/Makefile
])
AC_OUTPUT
@@ -386,6 +410,7 @@ AC_MSG_NOTICE([summary of build options:
Host type: ${host}
Install prefix: ${prefix}
Compiler: ${CC}
+ CFlags: ${CFLAGS}
Warning flags: errors: ${WERROR_CFLAGS} warnings: ${WARN_CFLAGS}
Library types: Shared=${enable_shared}, Static=${enable_static}
Valgrind: $opt_valgrind_tests ${VALGRIND}
@@ -393,5 +418,6 @@ AC_MSG_NOTICE([summary of build options:
C++ library: $use_cxx
OpenSSL library: $enable_openssl
/dev/crypto: $enable_cryptodev
+ Hardware accel: $hw_accel
Crypto library: $cryptolib
])
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f8dac6716a..982ae6ea48 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -23,7 +23,7 @@
ACLOCAL_AMFLAGS = -I ../m4 -I ../gl/m4
-SUBDIRS = includes x509
+SUBDIRS = includes x509 accelerated
if ENABLE_MINITASN1
SUBDIRS += minitasn1
endif
@@ -121,6 +121,7 @@ libgnutls_la_LDFLAGS = -no-undefined \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libgnutls_la_LIBADD = ../gl/libgnu.la x509/libgnutls_x509.la \
+ accelerated/libaccelerated.la \
$(LTLIBZ) $(LTLIBINTL) $(LIBSOCKET)
if ENABLE_OPENPGP
diff --git a/lib/accelerated/Makefile.am b/lib/accelerated/Makefile.am
new file mode 100644
index 0000000000..bfe9a168c1
--- /dev/null
+++ b/lib/accelerated/Makefile.am
@@ -0,0 +1,40 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2011 Free Software
+# Foundation, Inc.
+#
+# Author: Nikos Mavrogiannopoulos
+#
+# This file is part of GNUTLS.
+#
+# The GNUTLS library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# The GNUTLS library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNUTLS library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA
+
+AM_CFLAGS = $(WERROR_CFLAGS) $(WSTACK_CFLAGS) $(WARN_CFLAGS)
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../gl \
+ -I$(srcdir)/../includes \
+ -I$(builddir)/../includes \
+ -I$(srcdir)/..
+
+noinst_LTLIBRARIES = libaccelerated.la
+
+EXTRA_DIST = x86.h aes-x86.h accelerated.h
+libaccelerated_la_SOURCES = accelerated.c
+
+if TRY_X86_OPTIMIZATIONS
+AM_CFLAGS += -DTRY_X86_OPTIMIZATIONS
+libaccelerated_la_SOURCES += aes-x86.c
+endif
+
diff --git a/lib/accelerated/accelerated.c b/lib/accelerated/accelerated.c
new file mode 100644
index 0000000000..91e7040fb0
--- /dev/null
+++ b/lib/accelerated/accelerated.c
@@ -0,0 +1,14 @@
+#include <accelerated.h>
+#ifdef TRY_X86_OPTIMIZATIONS
+# include <aes-x86.h>
+#endif
+
+void _gnutls_register_accel_crypto(void)
+{
+
+#ifdef TRY_X86_OPTIMIZATIONS
+ register_x86_crypto ();
+#endif
+
+ return;
+}
diff --git a/lib/accelerated/accelerated.h b/lib/accelerated/accelerated.h
new file mode 100644
index 0000000000..1fccccbb3c
--- /dev/null
+++ b/lib/accelerated/accelerated.h
@@ -0,0 +1 @@
+void _gnutls_register_accel_crypto(void);
diff --git a/lib/accelerated/aes-x86.c b/lib/accelerated/aes-x86.c
new file mode 100644
index 0000000000..1b705edf5d
--- /dev/null
+++ b/lib/accelerated/aes-x86.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2011, Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ * The following code is an implementation of the AES-128-CBC cipher
+ * using intel's AES instruction set. It is based on Intel reference
+ * code.
+ */
+
+#include <gnutls_errors.h>
+#include <gnutls_int.h>
+#include <gnutls/crypto.h>
+#include <gnutls_errors.h>
+#include <wmmintrin.h>
+#include <aes-x86.h>
+#include <x86.h>
+
+struct aes_ctx {
+ uint8_t iv[16];
+ uint8_t key[16*10];
+ size_t keysize;
+};
+
+static int
+aes_cipher_init (gnutls_cipher_algorithm_t algorithm, void **_ctx)
+{
+ struct aes_ctx *ctx;
+
+ if (algorithm != GNUTLS_CIPHER_AES_128_CBC)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ *_ctx = gnutls_calloc (1, sizeof (struct aes_ctx));
+ if (*_ctx == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ctx = *_ctx;
+
+ return 0;
+}
+
+inline static __m128i aes128_assist (__m128i temp1, __m128i temp2)
+{
+__m128i temp3;
+ temp2 = _mm_shuffle_epi32 (temp2 ,0xff);
+ temp3 = _mm_slli_si128 (temp1, 0x4);
+ temp1 = _mm_xor_si128 (temp1, temp3);
+ temp3 = _mm_slli_si128 (temp3, 0x4);
+ temp1 = _mm_xor_si128 (temp1, temp3);
+ temp3 = _mm_slli_si128 (temp3, 0x4);
+ temp1 = _mm_xor_si128 (temp1, temp3);
+ temp1 = _mm_xor_si128 (temp1, temp2);
+
+ return temp1;
+}
+
+static int
+aes_cipher_setkey (void *_ctx, const void *userkey, size_t keysize)
+{
+struct aes_ctx *ctx = _ctx;
+__m128i temp1, temp2;
+__m128i *Key_Schedule = (__m128i*)ctx->key;
+
+ temp1 = _mm_loadu_si128((__m128i*)userkey);
+ Key_Schedule[0] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1 ,0x1);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[1] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x2);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[2] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x4);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[3] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x8);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[4] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x10);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[5] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x20);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[6] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x40);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[7] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x80);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[8] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x1b);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[9] = temp1;
+ temp2 = _mm_aeskeygenassist_si128 (temp1,0x36);
+ temp1 = aes128_assist(temp1, temp2);
+ Key_Schedule[10] = temp1;
+
+ ctx->keysize = keysize;
+
+ return 0;
+}
+
+static int
+aes_setiv (void *_ctx, const void *iv, size_t iv_size)
+{
+ struct aes_ctx *ctx = _ctx;
+
+ memcpy (ctx->iv, iv, 16);
+
+ return 0;
+}
+
+#define AES_128_ROUNDS 10
+
+static int
+aes_encrypt (void *_ctx, const void *plain, size_t plainsize,
+ void *encr, size_t length)
+{
+struct aes_ctx *ctx = _ctx;
+__m128i feedback,data;
+int i,j;
+
+ feedback=_mm_loadu_si128 ((__m128i*)ctx->iv);
+ for(i=0; i < length; i++) {
+ data = _mm_loadu_si128 (&((__m128i*)plain)[i]);
+ feedback = _mm_xor_si128 (data,feedback);
+ feedback = _mm_xor_si128 (feedback,((__m128i*)ctx->key)[0]);
+
+ for(j=1; j <AES_128_ROUNDS; j++)
+ feedback = _mm_aesenc_si128 (feedback,((__m128i*)ctx->key)[j]);
+
+ feedback = _mm_aesenclast_si128 (feedback,((__m128i*)ctx->key)[j]);
+ _mm_storeu_si128 (&((__m128i*)encr)[i],feedback);
+ }
+
+ return 0;
+}
+
+static int
+aes_decrypt (void *_ctx, const void *encr, size_t encrsize,
+ void *plain, size_t length)
+{
+struct aes_ctx *ctx = _ctx;
+__m128i data,feedback,last_in;
+int i,j;
+
+ feedback=_mm_loadu_si128 ((__m128i*)ctx->iv);
+
+ for(i=0; i < length; i++) {
+ last_in=_mm_loadu_si128 (&((__m128i*)encr)[i]);
+ data = _mm_xor_si128 (last_in,((__m128i*)ctx->key)[0]);
+
+ for(j=1; j <AES_128_ROUNDS; j++)
+ data = _mm_aesdec_si128 (data,((__m128i*)ctx->key)[j]);
+
+ data = _mm_aesdeclast_si128 (data,((__m128i*)ctx->key)[j]);
+ data = _mm_xor_si128 (data,feedback);
+ _mm_storeu_si128 (&((__m128i*)plain)[i],data);
+ feedback=last_in;
+ }
+
+ return 0;
+}
+
+static void
+aes_deinit (void *_ctx)
+{
+ gnutls_free (_ctx);
+}
+
+static const gnutls_crypto_cipher_st cipher_struct = {
+ .init = aes_cipher_init,
+ .setkey = aes_cipher_setkey,
+ .setiv = aes_setiv,
+ .encrypt = aes_encrypt,
+ .decrypt = aes_decrypt,
+ .deinit = aes_deinit,
+};
+
+static unsigned check_optimized_aes(void)
+{
+unsigned int a,b,c,d;
+ cpuid(1, a,b,c,d);
+
+ return (c & 0x2000000);
+}
+
+void
+register_x86_crypto (void)
+{
+int ret;
+ if (check_optimized_aes()) {
+ fprintf(stderr, "Intel AES accelerator was detected\n");
+ ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_CBC, 90, &cipher_struct);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ }
+ }
+
+ return;
+}
diff --git a/lib/accelerated/aes-x86.h b/lib/accelerated/aes-x86.h
new file mode 100644
index 0000000000..40d6a0c2b2
--- /dev/null
+++ b/lib/accelerated/aes-x86.h
@@ -0,0 +1 @@
+void register_x86_crypto (void);
diff --git a/lib/accelerated/x86.h b/lib/accelerated/x86.h
new file mode 100644
index 0000000000..c344283e36
--- /dev/null
+++ b/lib/accelerated/x86.h
@@ -0,0 +1,3 @@
+#define cpuid(func,ax,bx,cx,dx)\
+ __asm__ __volatile__ ("cpuid":\
+ "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c
index 1a59bdfc19..3c7f263968 100644
--- a/lib/gnutls_global.c
+++ b/lib/gnutls_global.c
@@ -33,6 +33,7 @@
#include <gnutls_extensions.h> /* for _gnutls_ext_init */
#include <gnutls_cryptodev.h>
#include <locks.h>
+#include <accelerated/accelerated.h>
#include "sockets.h"
#include "gettext.h"
@@ -187,6 +188,8 @@ gnutls_global_init (void)
return GNUTLS_E_CRYPTO_INIT_FAILED;
}
+ _gnutls_register_accel_crypto();
+
/* initialize ASN.1 parser
* This should not deal with files in the final
* version.
diff --git a/m4/gcc.m4 b/m4/gcc.m4
new file mode 100644
index 0000000000..ad40adac7e
--- /dev/null
+++ b/m4/gcc.m4
@@ -0,0 +1,28 @@
+# gcc.m4 serial 2
+dnl Copyright (C) 2008-2011 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Based on code by Simon Josefsson
+
+# GCC_FLAG_ADD(PARAMETER, [ACTION])
+# ------------------------------------------------
+# Adds parameter to CFLAGS if the compiler supports it. For example,
+# GCC_FLAG_ADD([-maes], [VAR]).
+AC_DEFUN([GCC_FLAG_ADD],
+[AS_VAR_PUSHDEF([GCC_FLAG], [gl_cv_GCC_FLAG_$1])dnl
+AC_CACHE_CHECK([whether compiler handles $1], [GCC_FLAG], [
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="${CFLAGS} $1"
+ AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
+ [AS_VAR_SET([GCC_FLAG], [yes])],
+ [AS_VAR_SET([GCC_FLAG], [no])])
+ CFLAGS="$save_CFLAGS"
+])
+AS_VAR_IF([GCC_FLAG], [yes], [
+m4_ifval([$2], [AC_SUBST([$2],[yes])])
+CFLAGS="${CFLAGS} $1"
+])dnl
+AS_VAR_POPDEF([GCC_FLAG])
+])