diff --git a/aclocal.m4 b/aclocal.m4 index de80e143..cee63dfb 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -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 +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])]) +]) diff --git a/configure.ac b/configure.ac index 10fed65c..21624950 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/include/compiler.h b/include/compiler.h index 8d609376..71f135d8 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -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 */ diff --git a/include/nasmlib.h b/include/nasmlib.h index b1c490ca..c772d1da 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -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