Better support for function attributes, autoconf cleanups

Use autoconf to detect function attributes; some compilers like Sun CC
do support some gcc-style attributes, but don't define __GNUC__.  Also
-U__STRICT_ANSI__ already in configure.ac so our tests match what we
might eventually encounter.

Add const_func and pure_func attributes.

Decorate functions in nasmlib.h with const_func and pure_func.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
H. Peter Anvin 2016-11-15 14:01:37 -08:00
parent 70d0458050
commit 8b19083483
4 changed files with 97 additions and 86 deletions

26
aclocal.m4 vendored
View file

@ -47,3 +47,29 @@ if test x"$LIBEXT" = x; then
fi
AC_MSG_RESULT([$LIBEXT])
AC_SUBST([LIBEXT])])
dnl --------------------------------------------------------------------------
dnl PA_FUNC_ATTRIBUTE
dnl
dnl See if this compiler supports the equivalent of a specific gcc
dnl attribute on a function, using the __attribute__(()) syntax.
dnl All arguments except the attribute name are optional.
dnl PA_FUNC_ATTRIBUTE(attribute, attribute_opts, return_type,
dnl prototype_args, call_args)
dnl --------------------------------------------------------------------------
AC_DEFUN(PA_FUNC_ATTRIBUTE,
[AC_MSG_CHECKING([if $CC supports the $1 function attribute])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <stdarg.h>
extern ifelse([$3],[],[void *],[$3]) __attribute__(($1$2))
bar(ifelse([$4],[],[int],[$4]));
void *foo(void)
{
return bar(ifelse([$5],[],[1],[$5]));
}
])],
[AC_MSG_RESULT([yes])
AC_DEFINE(m4_toupper([HAVE_FUNC_ATTRIBUTE_$1]), 1,
[Define to 1 if your compiler supports __attribute__(($1)) on functions])],
[AC_MSG_RESULT([no])])
])

View file

@ -4,46 +4,6 @@ AC_PREREQ(2.63)
AC_INIT(config/config.h.in)
AC_CONFIG_HEADERS(config/config.h)
dnl Check for broken VPATH handling on older NetBSD makes.
AC_DEFUN(AC_PROG_MAKE_VPATHOK,
[AC_MSG_CHECKING(whether ${MAKE-make} has sane VPATH handling)
set dummy ${MAKE-make}; ac_make=`echo "[$]2" | sed 'y%./+-%__p_%'`
AC_CACHE_VAL(ac_cv_prog_make_vpathok,
[mkdir conftestdir
cat > conftestdir/conftestmake <<\EOF
VPATH = ..
conftestfoo: conftestbar
@echo ac_make2temp=ok
conftestbar: conftestbaz
@echo ac_maketemp=broken
@touch conftestbar
EOF
echo > conftestbaz # these two lines need to be...
echo > conftestbar # ... in this order not the other
changequote(, )dnl
unset ac_maketemp
unset ac_make2temp
# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
eval `cd conftestdir; ${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
changequote([, ])dnl
if test -n "$ac_maketemp"; then
ac_cv_prog_make_vpathok=no
else
if test -n "$ac_make2temp"; then
ac_cv_prog_make_vpathok=yes
else
ac_cv_prog_make_vpathok=no
fi
fi
rm -rf conftestdir
rm -f conftestbar conftestbaz])dnl
if test $ac_cv_prog_make_vpathok = yes; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
])
AC_PREFIX_PROGRAM(nasm)
dnl Checks for programs.
@ -54,12 +14,6 @@ AC_PROG_CC
AC_PROG_CC_STDC
AC_PROG_LN_S
AC_PROG_MAKE_SET
if test -f nasm.c; then
# we're building in the source dir, so we don't need this check at all
ac_cv_prog_make_vpathok=yes
else
AC_PROG_MAKE_VPATHOK
fi
AC_PROG_INSTALL
dnl Check for library extension
@ -78,10 +32,16 @@ AH_TEMPLATE(WORDS_LITTLEENDIAN,
[Define to 1 if your processor stores words with the least significant
byte first (like Intel and VAX, unlike Motorola and SPARC).])
PA_ADD_CFLAGS([-std=c99])
dnl Force gcc and gcc-compatible compilers treat signed integers
dnl as 2's complement
PA_ADD_CFLAGS([-fwrapv])
dnl Some environments abuse __STRICT_ANSI__ to disable some
dnl function declarations
PA_ADD_CFLAGS([-U__STRICT_ANSI__])
dnl Don't put things in common if we can avoid it. We don't want to
dnl assume all compilers support common, and this will help find those
dnl problems. This also works around an OSX linker problem.
@ -152,6 +112,7 @@ AC_CHECK_FUNCS([access _access faccessat])
PA_HAVE_FUNC(__builtin_ctz, (0U))
PA_HAVE_FUNC(__builtin_ctzl, (0UL))
PA_HAVE_FUNC(__builtin_ctzll, (0ULL))
PA_HAVE_FUNC(__builtin_expect, (1,1))
dnl Functions for which we have replacements available in lib/
AC_CHECK_FUNCS([vsnprintf _vsnprintf])
@ -172,12 +133,18 @@ AC_CHECK_DECLS(strnlen)
dnl Check for missing types
AC_TYPE_UINTPTR_T
if test $ac_cv_prog_make_vpathok = no; then
echo Copying generated srcs into build directory to compensate for VPATH breakage
for file in macros.c insnsa.c insnsd.c insnsn.c insnsi.h version.h version.mac; do
if test ! -f $file; then cp -p ${srcdir}/${file} .; fi
done
fi
dnl
dnl Check for supported gcc attributes; some compilers (e.g. Sun CC)
dnl support these, but don't define __GNUC__ as they don't support
dnl some other features of gcc.
dnl
PA_FUNC_ATTRIBUTE(noreturn)
PA_FUNC_ATTRIBUTE(returns_nonnull)
PA_FUNC_ATTRIBUTE(malloc)
PA_FUNC_ATTRIBUTE(alloc_size, (1))
PA_FUNC_ATTRIBUTE(format, [(printf,1,2)], int, [const char *, ...], ["%d",1])
PA_FUNC_ATTRIBUTE(const)
PA_FUNC_ATTRIBUTE(pure)
dnl
dnl support cchace
@ -190,7 +157,6 @@ AC_ARG_ENABLE([ccache],
dnl If we have gcc, add appropriate code cleanliness options
PA_ADD_CFLAGS([-W])
PA_ADD_CFLAGS([-Wall])
PA_ADD_CFLAGS([-std=c99])
PA_ADD_CFLAGS([-pedantic])
dnl LLVM doesn't error out on invalid -W options unless this option is
dnl specified first. Enable this so this script can actually discover

View file

@ -172,7 +172,7 @@ char *strsep(char **, const char *);
* Hints to the compiler that a particular branch of code is more or
* less likely to be taken.
*/
#if defined(__GNUC__) && __GNUC__ >= 3
#if HAVE_BUILTIN_EXPECT
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#else
@ -183,25 +183,23 @@ char *strsep(char **, const char *);
/*
* Hints about malloc-like functions that never return NULL
*/
#if defined(__GNUC__) && __GNUC__ >= 4 /* ? */
#ifdef HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL
# define never_null __attribute__((returns_nonnull))
#else
# define never_null
#endif
#ifdef HAVE_FUNC_ATTRIBUTE_MALLOC
# define safe_alloc never_null __attribute__((malloc))
# ifdef __has_attribute
# if __has_attribute(alloc_size)
#else
# define safe_alloc
#endif
#ifdef HAVE_FUNC_ATTRIBUTE_ALLOC_SIZE
# define safe_malloc(s) safe_alloc __attribute__((alloc_size(s)))
# define safe_malloc2(s1,s2) safe_alloc __attribute__((alloc_size(s1,s2)))
# define safe_realloc(s) never_null __attribute__((alloc_size(s)))
# endif
# endif
#endif
#ifndef never_null
# define never_null
#endif
#ifndef safe_alloc
# define safe_alloc
#endif
#ifndef safe_malloc
#else
# define safe_malloc(s) safe_alloc
# define safe_malloc2(s1,s2) safe_alloc
# define safe_realloc(s) never_null
@ -210,7 +208,7 @@ char *strsep(char **, const char *);
/*
* How to tell the compiler that a function doesn't return
*/
#ifdef __GNUC__
#ifdef HAVE_FUNC_ATTRIBUTE_NORETURN
# define no_return void __attribute__((noreturn))
#else
# define no_return void
@ -219,10 +217,31 @@ char *strsep(char **, const char *);
/*
* How to tell the compiler that a function takes a printf-like string
*/
#ifdef __GNUC__
#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
# define printf_func(fmt, list) __attribute__((format(printf, fmt, list)))
#else
# define printf_func(fmt, list)
#endif
/*
* How to tell the compiler that a function is pure arithmetic
*/
#ifdef HAVE_FUNC_ATTRIBUTE_CONST
# define const_func __attribute__((const))
#else
# define const_func
#endif
/*
* This function has no side effects, but depends on its arguments,
* memory pointed to by its arguments, or global variables.
* NOTE: functions that return a value by modifying memory pointed to
* by a pointer argument are *NOT* considered pure.
*/
#ifdef HAVE_FUNC_ATTRIBUTE_PURE
# define pure_func __attribute__((pure))
#else
# define pure_func
#endif
#endif /* NASM_COMPILER_H */

View file

@ -186,7 +186,7 @@ no_return nasm_assert_failed(const char *, int, const char *);
#elif defined(HAVE_STRICMP)
#define nasm_stricmp stricmp
#else
int nasm_stricmp(const char *, const char *);
int pure_func nasm_stricmp(const char *, const char *);
#endif
#if defined(HAVE_STRNCASECMP)
@ -194,10 +194,10 @@ int nasm_stricmp(const char *, const char *);
#elif defined(HAVE_STRNICMP)
#define nasm_strnicmp strnicmp
#else
int nasm_strnicmp(const char *, const char *, size_t);
int pure_func nasm_strnicmp(const char *, const char *, size_t);
#endif
int nasm_memicmp(const char *, const char *, size_t);
int pure_func nasm_memicmp(const char *, const char *, size_t);
#if defined(HAVE_STRSEP)
#define nasm_strsep strsep
@ -206,7 +206,7 @@ char *nasm_strsep(char **stringp, const char *delim);
#endif
#ifndef HAVE_DECL_STRNLEN
size_t strnlen(const char *, size_t);
size_t pure_func strnlen(const char *, size_t);
#endif
/* This returns the numeric value of a given 'digit'. */
@ -230,8 +230,8 @@ int64_t readstrnum(char *str, int length, bool *warn);
* seg_init: Initialise the segment-number allocator.
* seg_alloc: allocate a hitherto unused segment number.
*/
void seg_init(void);
int32_t seg_alloc(void);
void pure_func seg_init(void);
int32_t pure_func seg_alloc(void);
/*
* many output formats will be able to make use of this: a standard
@ -436,7 +436,7 @@ char *nasm_opt_val(char *p, char **opt, char **val);
*/
char *nasm_realpath(const char *rel_path);
const char *prefix_name(int);
const char * pure_func prefix_name(int);
/*
* Wrappers around fopen()... for future change to a dedicated structure
@ -482,7 +482,7 @@ off_t nasm_file_size(FILE *f);
off_t nasm_file_size_by_path(const char *pathname);
void fwritezero(off_t bytes, FILE *fp);
static inline bool overflow_general(int64_t value, int bytes)
static inline bool const_func overflow_general(int64_t value, int bytes)
{
int sbit;
int64_t vmax, vmin;
@ -497,7 +497,7 @@ static inline bool overflow_general(int64_t value, int bytes)
return value < vmin || value > vmax;
}
static inline bool overflow_signed(int64_t value, int bytes)
static inline bool const_func overflow_signed(int64_t value, int bytes)
{
int sbit;
int64_t vmax, vmin;
@ -512,7 +512,7 @@ static inline bool overflow_signed(int64_t value, int bytes)
return value < vmin || value > vmax;
}
static inline bool overflow_unsigned(int64_t value, int bytes)
static inline bool const_func overflow_unsigned(int64_t value, int bytes)
{
int sbit;
int64_t vmax, vmin;
@ -527,7 +527,7 @@ static inline bool overflow_unsigned(int64_t value, int bytes)
return value < vmin || value > vmax;
}
static inline int64_t signed_bits(int64_t value, int bits)
static inline int64_t const_func signed_bits(int64_t value, int bits)
{
if (bits < 64) {
value &= ((int64_t)1 << bits) - 1;
@ -537,7 +537,7 @@ static inline int64_t signed_bits(int64_t value, int bits)
return value;
}
int idata_bytes(int opcode);
int const_func idata_bytes(int opcode);
/* check if value is power of 2 */
#define is_power2(v) ((v) && ((v) & ((v) - 1)) == 0)
@ -545,13 +545,13 @@ int idata_bytes(int opcode);
/*
* floor(log2(v))
*/
int ilog2_32(uint32_t v);
int ilog2_64(uint64_t v);
int const_func ilog2_32(uint32_t v);
int const_func ilog2_64(uint64_t v);
/*
* v == 0 ? 0 : is_power2(x) ? ilog2_X(v) : -1
*/
int alignlog2_32(uint32_t v);
int alignlog2_64(uint64_t v);
int const_func alignlog2_32(uint32_t v);
int const_func alignlog2_64(uint64_t v);
#endif