From 544048ecef8fd8480d850fe80ba04ab9d7f8bdef Mon Sep 17 00:00:00 2001
From: David Schultz <das@FreeBSD.org>
Date: Sat, 31 Jan 2009 18:27:02 +0000
Subject: [PATCH] Add a function attribute called `__malloc_like', which
 informs gcc that the annotated function returns a pointer that doesn't alias
 any extant pointer. This results in a 50%+ speedup in microbenchmarks such as
 the following:

    char *cp = malloc(1), *buf = malloc(BUF);
    for (i = 0; i < BUF; i++) buf[i] = *cp;

In real programs, your mileage will vary. Note that gcc already
performs this optimization automatically for any function called
`malloc', `calloc', `strdup', or `strndup' unless -fno-builtins is
used.
---
 include/stdlib.h | 4 ++--
 include/string.h | 4 ++--
 include/wchar.h  | 2 +-
 sys/sys/cdefs.h  | 2 ++
 sys/sys/malloc.h | 4 ++--
 5 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index 0a8327066bd7..91be536668b7 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -88,14 +88,14 @@ int	 atoi(const char *);
 long	 atol(const char *);
 void	*bsearch(const void *, const void *, size_t,
 	    size_t, int (*)(const void *, const void *));
-void	*calloc(size_t, size_t);
+void	*calloc(size_t, size_t) __malloc_like;
 div_t	 div(int, int) __pure2;
 void	 exit(int) __dead2;
 void	 free(void *);
 char	*getenv(const char *);
 long	 labs(long) __pure2;
 ldiv_t	 ldiv(long, long) __pure2;
-void	*malloc(size_t);
+void	*malloc(size_t) __malloc_like;
 int	 mblen(const char *, size_t);
 size_t	 mbstowcs(wchar_t * __restrict , const char * __restrict, size_t);
 int	 mbtowc(wchar_t * __restrict, const char * __restrict, size_t);
diff --git a/include/string.h b/include/string.h
index 32a9ad3e5608..4770d101a139 100644
--- a/include/string.h
+++ b/include/string.h
@@ -78,7 +78,7 @@ int	 strcoll(const char *, const char *);
 char	*strcpy(char * __restrict, const char * __restrict);
 size_t	 strcspn(const char *, const char *) __pure;
 #if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE
-char	*strdup(const char *);
+char	*strdup(const char *) __malloc_like;
 #endif
 char	*strerror(int);
 #if __POSIX_VISIBLE >= 200112
@@ -96,7 +96,7 @@ char	*strncat(char * __restrict, const char * __restrict, size_t);
 int	 strncmp(const char *, const char *, size_t) __pure;
 char	*strncpy(char * __restrict, const char * __restrict, size_t);
 #if __BSD_VISIBLE
-char	*strndup(const char *, size_t);
+char	*strndup(const char *, size_t) __malloc_like;
 char	*strnstr(const char *, const char *, size_t) __pure;
 #endif
 char	*strpbrk(const char *, const char *) __pure;
diff --git a/include/wchar.h b/include/wchar.h
index 2326b1debb50..4fc6c8cb03b2 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -214,7 +214,7 @@ int	wcwidth(wchar_t);
 wchar_t	*fgetwln(struct __sFILE * __restrict, size_t * __restrict);
 size_t	mbsnrtowcs(wchar_t * __restrict, const char ** __restrict, size_t,
 	    size_t, mbstate_t * __restrict);
-wchar_t	*wcsdup(const wchar_t *);
+wchar_t	*wcsdup(const wchar_t *) __malloc_like;
 size_t	wcsnrtombs(char * __restrict, const wchar_t ** __restrict, size_t,
 	    size_t, mbstate_t * __restrict);
 size_t	wcslcat(wchar_t *, const wchar_t *, size_t);
diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h
index e796908d9e3d..a85095075ab9 100644
--- a/sys/sys/cdefs.h
+++ b/sys/sys/cdefs.h
@@ -221,8 +221,10 @@
 #endif
 
 #if __GNUC_PREREQ__(2, 96)
+#define	__malloc_like	__attribute__((__malloc__))
 #define	__pure		__attribute__((__pure__))
 #else
+#define	__malloc_like
 #define	__pure
 #endif
 
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index 33b287f83d92..24a044c2c6c4 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -190,9 +190,9 @@ typedef void malloc_type_list_func_t(struct malloc_type *, void *);
 void	contigfree(void *addr, unsigned long size, struct malloc_type *type);
 void	*contigmalloc(unsigned long size, struct malloc_type *type, int flags,
 	    vm_paddr_t low, vm_paddr_t high, unsigned long alignment,
-	    unsigned long boundary);
+	    unsigned long boundary) __malloc_like;
 void	free(void *addr, struct malloc_type *type);
-void	*malloc(unsigned long size, struct malloc_type *type, int flags);
+void	*malloc(unsigned long size, struct malloc_type *type, int flags) __malloc_like;
 void	malloc_init(void *);
 int	malloc_last_fail(void);
 void	malloc_type_allocated(struct malloc_type *type, unsigned long size);