#ifndef COMPILER_H
#define COMPILER_H

#ifndef __ASSEMBLY__

#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>

/* Use builtin memcpy and memset optimizations */
#define memset(s,c,n)	__builtin_memset(s,c,n)
#define memcpy(d,s,n)	__builtin_memcpy(d,s,n)
#define memmove(d,s,n)	__builtin_memmove(d,s,n)
extern void *__memcpy_aligned(void * __restrict,
			      const void * __restrict, size_t);
extern void *__memcpy_bytewise(volatile void * __restrict,
			       const volatile void * __restrict, size_t);

#define likely(x)	__builtin_expect(!!(x), 1)
#define unlikely(x)	__builtin_expect(!!(x), 0)

/* Handy composite pointer types */
typedef union xptr {
    uint32_t *l;
    uint16_t *w;
    uint8_t  *b;
    void     *v;
    size_t    a;
} xptr_t;
typedef union xcptr {
    const uint32_t *l;
    const uint16_t *w;
    const uint8_t  *b;
    const void     *v;
    size_t          a;
} xcptr_t;

/* The container_of construct: if p is a pointer to member m of
   container class c, then return a pointer to the container of which
   *p is a member. */
#ifndef container_of
# define container_of(p, c, m) ((c *)((char *)(p) - offsetof(c,m)))
#endif

#define offset_diff(c, m1, m2) ((ptrdiff_t)offsetof(c,m2) - \
				(ptrdiff_t)offsetof(c,m1))

#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))

#define ARRAY_SIZE (sizeof(a)/sizeof(a[0]))

#define alignof(a) __alignof__(a)

#define no_return void __attribute__((noreturn))

#define ___section(s,a,...) __attribute__((__section__(s)))

#define __hot		__attribute__((__hot__))
#define __cold		__attribute__((__cold__))
#define __aligned(x)	__attribute__((__aligned__(x)))
#define __unused	__attribute__((__unused__))
#define __must_inline	__attribute__((__always_inline__))
#define __noinline	__attribute__ ((__noinline__))
#define __constfunc	__attribute__((__const__))
#define __purefunc	__attribute__((__pure__))

#define __fmt_printf(fstr,farg)	__attribute__((__format__(__printf__,fstr,farg)))

#define __is_constant(expr)	__builtin_constant_p(expr)

#else /* __ASSEMBLY__ */

#define ___section(s,a,...)	.pushsection s, a, ## __VA_ARGS__

#endif /* __ASSEMBLY__ */

#define __text_hot	___section(".text.hot","ax")
#define __rodata_hot	___section(".rodata.hot","a")
#define __data_hot	___section(".data.hot","aw")
#define __rwtext	___section(".rwtext","awx")
#define __sdata		___section(".sdata","aw")
#define __string_hot	___section(".rodata.hot.str","aMS")
#define __sbss		___section(".sbss.hot","aw",@nobits)
#define __bss_hot	___section(".bss.hot","aw",@nobits)
#define __dram_text	___section(".dram.text","ax")
#define __dram_rodata	___section(".dram.rodata","a")
#define __dram_string	___section(".dram.rodata.str","aMS")
#define __dram_data	___section(".dram.data","aw")
#define __dram_bss	___section(".dram.bss","aw",@nobits)
#define __dram_noinit	___section(".dram.noinit","aw",@nobits)

#ifndef __ASSEMBLY__

#define hotstr(x) ({ static __string_hot const char _str[] = (x); _str; })

#endif /* __ASSEMBLY__ */

#endif /* COMPILER_H */
