X-Git-Url: http://git.silc.fi/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilctypes.h;h=5d768d819ab70828b844996265ef97ce2befddc3;hb=0591a422cd4b71e5af6581bcd3d00d184d84a017;hp=59e92484944208bbdbdf3b92d3abeb62dbe90e30;hpb=8ba5d4a123b0b4614203e1fa210f757f33f2b560;p=runtime.git diff --git a/lib/silcutil/silctypes.h b/lib/silcutil/silctypes.h index 59e92484..5d768d81 100644 --- a/lib/silcutil/silctypes.h +++ b/lib/silcutil/silctypes.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002 - 2007 Pekka Riikonen + Copyright (C) 2002 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,19 +17,34 @@ */ -/****h* silcutil/SILC Types +/****h* silcutil/Types and Definitions * * DESCRIPTION * - * This header file includes basic types and definitions used in SILC Toolkits. - * It contains all types, and many utility macros and functions. + * This header file includes basic types and definitions, and various system + * specific macros and functions used in SILC Toolkits. Application programmer + * may use them when needed. * ***/ #ifndef SILCTYPES_H #define SILCTYPES_H -/****d* silcutil/SILCTypes/SilcBool +/* The bool macro is deprecated. Use SilcBool instead. */ +#ifdef SILC_MACOSX +#define bool _Bool +#endif +#ifndef __cplusplus +#ifndef bool +#define bool unsigned char +#endif +#endif + +#if SILC_SIZEOF_SHORT > 2 +#error "size of the short must be 2 bytes" +#endif + +/****d* silcutil/SilcBool * * NAME * @@ -42,17 +57,7 @@ ***/ typedef unsigned char SilcBool; -/* The bool macro is deprecated. Use SilcBool instead. */ -#ifdef SILC_MACOSX -#define bool _Bool -#endif -#ifndef __cplusplus -#ifndef bool -#define bool unsigned char -#endif -#endif - -/****d* silcutil/SILCTypes/TRUE +/****d* silcutil/TRUE * * NAME * @@ -69,7 +74,7 @@ typedef unsigned char SilcBool; #endif /***/ -/****d* silcutil/SILCTypes/FALSE +/****d* silcutil/FALSE * * NAME * @@ -86,24 +91,7 @@ typedef unsigned char SilcBool; #endif /***/ -/* Our offsetof macro */ -#define silc_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/* silc_likely and silc_unlikely GCC branch prediction macros. Use only if - you have profiled the code first. */ -#if __GNUC__ >= 3 -#define silc_likely(expr) __builtin_expect(!!(expr), 1) -#define silc_unlikely(expr) __builtin_expect(!!(expr), 0) -#else -#define silc_likely(expr) (expr) -#define silc_unlikely(expr) (expr) -#endif /* __GNUC__ >= 3 */ - -#if SILC_SIZEOF_SHORT > 2 -#error "size of the short must be 2 bytes" -#endif - -/****d* silcutil/SILCTypes/SilcUInt8 +/****d* silcutil/SilcUInt8 * * NAME * @@ -118,7 +106,7 @@ typedef unsigned char SilcBool; typedef unsigned char SilcUInt8; /***/ -/****d* silcutil/SILCTypes/SilcInt8 +/****d* silcutil/SilcInt8 * * NAME * @@ -133,7 +121,7 @@ typedef unsigned char SilcUInt8; typedef signed char SilcInt8; /***/ -/****d* silcutil/SILCTypes/SilcUInt16 +/****d* silcutil/SilcUInt16 * * NAME * @@ -148,7 +136,7 @@ typedef signed char SilcInt8; typedef unsigned short SilcUInt16; /***/ -/****d* silcutil/SILCTypes/SilcInt16 +/****d* silcutil/SilcInt16 * * NAME * @@ -163,7 +151,7 @@ typedef unsigned short SilcUInt16; typedef signed short SilcInt16; /***/ -/****d* silcutil/SILCTypes/SilcUInt32 +/****d* silcutil/SilcUInt32 * * NAME * @@ -193,7 +181,7 @@ typedef signed long long SilcInt32; #endif /***/ -/****d* silcutil/SILCTypes/SilcInt32 +/****d* silcutil/SilcInt32 * * NAME * @@ -205,7 +193,7 @@ typedef signed long long SilcInt32; * ***/ -/****d* silcutil/SILCTypes/SilcUInt64 +/****d* silcutil/SilcUInt64 * * NAME * @@ -237,7 +225,7 @@ typedef SilcInt32 SilcInt64; #endif /***/ -/****d* silcutil/SILCTypes/SilcInt64 +/****d* silcutil/SilcInt64 * * NAME * @@ -250,11 +238,37 @@ typedef SilcInt32 SilcInt64; * ***/ +/****d* silcutil/SilcFloat32 + * + * NAME + * + * typedef float SilcFloat32; + * + * DESCRIPTION + * + * 32-bit floating point number. + * + ***/ +typedef float SilcFloat32; + +/****d* silcutil/SilcFloat64 + * + * NAME + * + * typedef double SilcFloat64; + * + * DESCRIPTION + * + * 64-bit floating point number. + * + ***/ +typedef double SilcFloat64; + #if SILC_SIZEOF_VOID_P < 4 typedef SilcUInt32 * void *; #endif -/****d* silcutil/SILCTypes/SilcSocket +/****d* silcutil/SilcSocket * * NAME * @@ -265,7 +279,7 @@ typedef SilcUInt32 * void *; * Platform specific socket. On POSIX compliant systems this is simply * an integer, representing the socket. On other systems it is platform * specific socket context. Access it only through routines that can - * handle SilcSocket types, unless you know what you are doing. + * handle SilcSocket types. * * SOURCE */ @@ -278,6 +292,93 @@ typedef void * SilcSocket; #endif /***/ +/****d* silcutil/SilcParam + * + * NAME + * + * typedef SilcUInt32 SilcParam; + * + * DESCRIPTION + * + * A generic parameters that describe the type of an parameter or argument. + * They can be used to describe function arguments, buffer encoding format, + * etc. + * + * SOURCE + */ +typedef SilcUInt32 SilcParam; + +#define SILC_PARAM_SINT8 1 /* SilcInt8 */ +#define SILC_PARAM_UINT8 2 /* SilcUInt8 */ +#define SILC_PARAM_SINT16 3 /* SilcInt16 */ +#define SILC_PARAM_UINT16 4 /* SilcUInt16 */ +#define SILC_PARAM_SINT32 5 /* SilcInt32 */ +#define SILC_PARAM_UINT32 6 /* SilcUInt32 */ +#define SILC_PARAM_SINT64 7 /* SilcInt64 */ +#define SILC_PARAM_UINT64 8 /* SilcUInt64 */ +#define SILC_PARAM_SICHAR 9 /* signed char * */ +#define SILC_PARAM_UICHAR 10 /* unsigned char * */ +#define SILC_PARAM_BUFFER 11 /* SilcBuffer */ +#define SILC_PARAM_PTR 12 /* void * */ +#define SILC_PARAM_END 0xfeeefff1 /* End of parameters */ +/***/ + +/* Internal parameter types, not publicly documented, used mainly by the + SILC Buffer Format API (silcbuffmt.h). */ +#define SILC_PARAM_UI8_STRING 100 /* String (max len 8-bits) */ +#define SILC_PARAM_UI16_STRING 101 /* String (max len 16-bits) */ +#define SILC_PARAM_UI32_STRING 102 /* String (max len 32-bits) */ +#define SILC_PARAM_UI8_NSTRING 103 /* String (max len 8-bits) */ +#define SILC_PARAM_UI16_NSTRING 104 /* String (max len 16-bits) */ +#define SILC_PARAM_UI32_NSTRING 105 /* String (max len 32-bits) */ +#define SILC_PARAM_OFFSET 106 +#define SILC_PARAM_ADVANCE 107 +#define SILC_PARAM_FUNC 108 +#define SILC_PARAM_REGEX 109 +#define SILC_PARAM_OFFSET_START 110 +#define SILC_PARAM_OFFSET_END 111 +#define SILC_PARAM_DELETE 112 +#define SILC_PARAM_ALLOC 0x00010000 /* Allocate, bitmask */ +#define SILC_PARAM_REPLACE 0x00020000 /* Replace, bitmask */ + +/****d* silcutil/SilcCompareValue + * + * NAME + * + * typedef enum { ... } SilcCompareValue + * + * DESCRIPTION + * + * Values that can be returned by the SilcCompare function. Note that + * not all routines may respect all of the return values. + * + * SOURCE + */ +typedef enum { + SILC_COMPARE_LESS_THAN_EQUAL_TO = -2, /* Value 1 <= value 2 */ + SILC_COMPARE_LESS_THAN = -1, /* Value 1 < value 2 */ + SILC_COMPARE_EQUAL_TO = 0, /* Value 1 == value 2 */ + SILC_COMPARE_GREATER_THAN = 1, /* Value 1 > value 2 */ + SILC_COMPARE_GREATER_THAN_EQUAL_TO = 2, /* Value 1 >= value 2 */ + SILC_COMPARE_STOP = 3, /* Stop comparison */ +} SilcCompareValue; +/***/ + +/****f* silcutil/SilcCompare + * + * SYNOPSIS + * + * typedef SilcCompareValue (*SilcCompare)(void *value1, void *value2, + * void *context); + * + * DESCRIPTION + * + * A comparison function used by many routines in SILC Runtime Toolkit. + * + ***/ +typedef SilcCompareValue (*SilcCompare)(void *value1, void *value2, + void *context); + /* Macros */ #if (defined(SILC_I486) || defined(SILC_X86_64)) && defined(__GNUC__) @@ -295,7 +396,33 @@ typedef void * SilcSocket; | ((SilcUInt32)(SilcUInt8)(cp)[3]) #endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ -/****d* silcutil/SILCTypes/SILC_GET16_MSB +/****d* silcutil/SILC_MAX + * + * NAME + * + * #define SILC_MAX(a, b) + * + * DESCRIPTION + * + * Return `a' if it is bigger than `b', otherwise return `b'. + * + ***/ +#define SILC_MAX(a, b) ((a) > (b) ? (a) : (b)) + +/****d* silcutil/SILC_MIN + * + * NAME + * + * #define SILC_MIN(a, b) + * + * DESCRIPTION + * + * Return `a' if it is smaller than `b', otherwise return `b'. + * + ***/ +#define SILC_MIN(a, b) ((a) < (b) ? (a) : (b)) + +/****d* silcutil/SILC_GET16_MSB * * NAME * @@ -320,7 +447,7 @@ do { \ #endif /* (SILC_I386 || SILC_X86_64) && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_GET32_MSB +/****d* silcutil/SILC_GET32_MSB * * NAME * @@ -365,7 +492,7 @@ do { \ | ((SilcUInt32)(SilcUInt8)(cp)[3]); #endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ -/****d* silcutil/SILCTypes/SILC_GET64_MSB +/****d* silcutil/SILC_GET64_MSB * * NAME * @@ -390,7 +517,7 @@ do { \ #endif /* SILC_X86_64 && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_GET16_LSB +/****d* silcutil/SILC_GET16_LSB * * NAME * @@ -413,7 +540,7 @@ do { \ #endif /* SILC_I386 || SILC_X86_64 */ /***/ -/****d* silcutil/SILCTypes/SILC_GET32_LSB +/****d* silcutil/SILC_GET32_LSB * * NAME * @@ -449,7 +576,7 @@ do { \ | ((SilcUInt32)(SilcUInt8)(cp)[3] << 24) #endif /* SILC_I386 || SILC_X86_64 */ -/****d* silcutil/SILCTypes/SILC_PUT16_MSB +/****d* silcutil/SILC_PUT16_MSB * * NAME * @@ -474,7 +601,7 @@ do { \ #endif /* (SILC_I386 || SILC_X86_64) && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_PUT32_MSB +/****d* silcutil/SILC_PUT32_MSB * * NAME * @@ -501,7 +628,7 @@ do { \ #endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_PUT64_MSB +/****d* silcutil/SILC_PUT64_MSB * * NAME * @@ -526,7 +653,7 @@ do { \ #endif /* SILC_X86_64 && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_PUT16_LSB +/****d* silcutil/SILC_PUT16_LSB * * NAME * @@ -549,7 +676,7 @@ do { \ #endif /* SILC_I386 || SILC_X86_64 */ /***/ -/****d* silcutil/SILCTypes/SILC_PUT32_LSB +/****d* silcutil/SILC_PUT32_LSB * * NAME * @@ -574,7 +701,7 @@ do { \ #endif /* SILC_I386 || SILC_X86_64 */ /***/ -/****d* silcutil/SILCTypes/SILC_SWAB_16 +/****d* silcutil/SILC_SWAB_16 * * NAME * @@ -591,7 +718,7 @@ do { \ ({ \ SilcUInt16 _result_; \ asm volatile ("movw %w1, %w0; rolw $8, %w0" \ - : "=q" (_result_): "q" (l)); \ + : "=q" (_result_) : "q" (l)); \ _result_; \ }) #else @@ -601,7 +728,7 @@ do { \ #endif /* (SILC_I386 || SILC_X86_64) && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_SWAB_32 +/****d* silcutil/SILC_SWAB_32 * * NAME * @@ -618,7 +745,7 @@ do { \ ({ \ SilcUInt32 _result_; \ asm volatile ("movl %1, %0; bswapl %0" \ - : "=q" (_result_): "q" (l)); \ + : "=q" (_result_) : "q" (l)); \ _result_; \ }) #else @@ -630,7 +757,7 @@ do { \ #endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ /***/ -/****d* silcutil/SILCTypes/SILC_PTR_TO_32 +/****d* silcutil/SILC_PTR_TO_32 * * NAME * @@ -652,7 +779,7 @@ do { \ #endif /***/ -/****d* silcutil/SILCTypes/SILC_PTR_TO_64 +/****d* silcutil/SILC_PTR_TO_64 * * NAME * @@ -673,7 +800,7 @@ do { \ #endif /***/ -/****d* silcutil/SILCTypes/SILC_32_TO_PTR +/****d* silcutil/SILC_32_TO_PTR * * NAME * @@ -694,7 +821,7 @@ do { \ #endif /***/ -/****d* silcutil/SILCTypes/SILC_64_TO_PTR +/****d* silcutil/SILC_64_TO_PTR * * NAME * @@ -716,7 +843,58 @@ do { \ #endif /***/ -/****d* silcutil/SILCTypes/silc_rol +/****d* silcutil/SILC_ASSERT + * + * NAME + * + * #define SILC_ASSERT(experssion) + * + * DESCRIPTION + * + * Assert macro that prints error message to stderr and calls abort() + * if the `expression' is false (ie. compares equal to zero). If + * SILC_DEBUG is not defined this macro has no effect. + * + * SOURCE + */ +#if defined(SILC_DEBUG) +#define SILC_ASSERT(expr) assert((expr)); +#else +#define SILC_ASSERT(expr) do { } while(0) +#endif /* SILC_DEBUG */ +/***/ + +/****d* silcutil/SILC_VERIFY + * + * NAME + * + * #define SILC_VERIFY(experssion) + * + * DESCRIPTION + * + * Verification macro that prints error message to stderr and calls + * abort() if the `expression' is false (ie. compares equal to zero) + * on debug builds (SILC_DEBUG defined), and prints error message to + * stderr on release builds (SILC_DEBUG undefined) but does not abort(). + * This macro is always compiled even if debugging (SILC_DEBUG) is not + * defined. + * + * SOURCE + */ +#if defined(SILC_DEBUG) +#define SILC_VERIFY(expr) assert((expr)); +#else +#define SILC_VERIFY(expr) \ + if (silc_unlikely(!(expr))) { \ + SILC_LOG_ERROR(("SILC_VERIFY %s:%s:%d", \ + __FILE__, __FUNCTION__, __LINE__)); \ + silc_set_errno_reason_nofail(SILC_ERR_ASSERT, "SILC_VERIFY %s:%s:%d", \ + __FILE__, __FUNCTION__, __LINE__); \ + } +#endif /* SILC_DEBUG */ +/***/ + +/****d* silcutil/silc_rol * * NAME * @@ -733,14 +911,38 @@ static inline SilcUInt32 silc_rol(SilcUInt32 val, int num) { #if (defined(SILC_I386) || defined(SILC_X86_64)) && defined(__GNUC__) asm volatile ("roll %%cl, %0" - : "=q" (val) : "0" (val), "c" (num)); + : "=r" (val) : "0" (val), "c" (num)); + return val; +#else + return ((val << (SilcUInt32)num) | (val >> (32 - (SilcUInt32)num))); +#endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ +} + +/****d* silcutil/silc_rolc + * + * NAME + * + * static inline SilcUInt32 silc_rolc(SilcUInt32 val, const int num); + * + * DESCRIPTION + * + * Rotate 32-bit integer's bits to left `num' times. Bits pushed to the + * left will appear from the right side of the integer, thus rotating. + * Returns the rotated value. + * + ***/ +static inline SilcUInt32 silc_rolc(SilcUInt32 val, const int num) +{ +#if (defined(SILC_I386) || defined(SILC_X86_64)) && defined(__GNUC__) + asm volatile ("roll %2, %0" + : "=r" (val) : "0" (val), "I" (num)); return val; #else return ((val << (SilcUInt32)num) | (val >> (32 - (SilcUInt32)num))); #endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ } -/****d* silcutil/SILCTypes/silc_ror +/****d* silcutil/silc_ror * * NAME * @@ -757,14 +959,38 @@ static inline SilcUInt32 silc_ror(SilcUInt32 val, int num) { #if (defined(SILC_I386) || defined(SILC_X86_64)) && defined(__GNUC__) asm volatile ("rorl %%cl, %0" - : "=q" (val) : "0" (val), "c" (num)); + : "=r" (val) : "0" (val), "c" (num)); return val; #else return ((val >> (SilcUInt32)num) | (val << (32 - (SilcUInt32)num))); #endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ } -/****d* silcutil/SILCTypes/silc_rol64 +/****d* silcutil/silc_rorc + * + * NAME + * + * static inline SilcUInt32 silc_ror(SilcUInt32 val, const int num); + * + * DESCRIPTION + * + * Rotate 32-bit integer's bits to right `num' times. Bits pushed to the + * right will appear from the left side of the integer, thus rotating. + * Returns the rotated value. + * + ***/ +static inline SilcUInt32 silc_rorc(SilcUInt32 val, const int num) +{ +#if (defined(SILC_I386) || defined(SILC_X86_64)) && defined(__GNUC__) + asm volatile ("rorl %2, %0" + : "=r" (val) : "0" (val), "I" (num)); + return val; +#else + return ((val >> (SilcUInt32)num) | (val << (32 - (SilcUInt32)num))); +#endif /* (SILC_I486 || SILC_X86_64) && __GNUC__ */ +} + +/****d* silcutil/silc_rol64 * * NAME * @@ -781,14 +1007,38 @@ static inline SilcUInt64 silc_rol64(SilcUInt64 val, int num) { #if defined(SILC_X86_64) && defined(__GNUC__) asm volatile ("rolq %%cl, %0" - : "=q" (val) : "0" (val), "c" (num)); + : "=r" (val) : "0" (val), "c" (num)); + return val; +#else + return ((val << (SilcUInt64)num) | (val >> (64 - (SilcUInt64)num))); +#endif /* SILC_X86_64 && __GNUC__ */ +} + +/****d* silcutil/silc_rolc64 + * + * NAME + * + * static inline SilcUInt64 silc_rolc64(SilcUInt64 val, const int num); + * + * DESCRIPTION + * + * Rotate 64-bit integer's bits to left `num' times. Bits pushed to the + * left will appear from the right side of the integer, thus rotating. + * Returns the rotated value. + * + ***/ +static inline SilcUInt64 silc_rolc64(SilcUInt64 val, const int num) +{ +#if defined(SILC_X86_64) && defined(__GNUC__) + asm volatile ("rolq %2, %0" + : "=r" (val) : "0" (val), "J" (num)); return val; #else return ((val << (SilcUInt64)num) | (val >> (64 - (SilcUInt64)num))); #endif /* SILC_X86_64 && __GNUC__ */ } -/****d* silcutil/SILCTypes/silc_ror64 +/****d* silcutil/silc_ror64 * * NAME * @@ -805,11 +1055,274 @@ static inline SilcUInt64 silc_ror64(SilcUInt64 val, int num) { #if defined(SILC_X86_64) && defined(__GNUC__) asm volatile ("rorq %%cl, %0" - : "=q" (val) : "0" (val), "c" (num)); + : "=r" (val) : "0" (val), "c" (num)); return val; #else return ((val >> (SilcUInt64)num) | (val << (64 - (SilcUInt64)num))); #endif /* SILC_X86_64 && __GNUC__ */ } +/****d* silcutil/silc_rorc64 + * + * NAME + * + * static inline SilcUInt64 silc_rorc64(SilcUInt64 val, const int num); + * + * DESCRIPTION + * + * Rotate 64-bit integer's bits to right `num' times. Bits pushed to the + * right will appear from the left side of the integer, thus rotating. + * Returns the rotated value. + * + ***/ +static inline SilcUInt64 silc_rorc64(SilcUInt64 val, const int num) +{ +#if defined(SILC_X86_64) && defined(__GNUC__) + asm volatile ("rorq %2, %0" + : "=r" (val) : "0" (val), "J" (num)); + return val; +#else + return ((val >> (SilcUInt64)num) | (val << (64 - (SilcUInt64)num))); +#endif /* SILC_X86_64 && __GNUC__ */ +} + +/****d* silcutil/silc_offsetof + * + * NAME + * + * #define silc_offsetof(TYPE, MEMBER) + * + * DESCRIPTION + * + * offsetof() macro replacement. Use this instead of offsetof(). + * + ***/ +#define silc_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/****d* silcutil/silc_attribute + * + * NAME + * + * #define silc_attribute(attrlist) + * + * DESCRIPTION + * + * Compiler attributes. If compiler doesn't support attributes this macro + * doesn't do anything. Currently this works only with GCC compiler. + * See GCC documentation for specified attributes. + * + * EXAMPLE + * + * int printf(const char *fmt, ...) silc_attribute((format(printf, 1, 2))); + * + ***/ +#if defined(__GNUC__) +#define silc_attribute(attrlist) __attribute__ (attrlist) +#else +#define silc_attribute(attrlist) +#endif /* __GNUC__ */ + +/****d* silcutil/silc_likely + * + * NAME + * + * #define silc_likely(expression) + * + * DESCRIPTION + * + * Branch prediction macro. It specifies that it is likely that the branch + * where silc_likely is applied is taken. Compiler will optimize the + * code based on this prediction. Never use this before you have profiled + * the code first. + * + ***/ + +/****d* silcutil/silc_unlikely + * + * NAME + * + * #define silc_unlikely(expression) + * + * DESCRIPTION + * + * Branch prediction macro. It specifies that it is unlikely that the + * branch where silc_unlikely is applied is taken. Compiler will optimize + * the code based on this prediction. Never use this before you have + * profiled the code first. + * + ***/ +#if __GNUC__ >= 3 +#define silc_likely(expr) __builtin_expect(!!(expr), 1) +#define silc_unlikely(expr) __builtin_expect(!!(expr), 0) +#else +#define silc_likely(expr) (expr) +#define silc_unlikely(expr) (expr) +#endif /* __GNUC__ >= 3 */ + +/* Prefetch operations. Use these to prefetch data to CPU cache before + reading or writing if you think that the data will be needed soon after + prefetching. */ + +/****d* silcutil/silc_prefetch + * + * NAME + * + * static inline void silc_prefetch(void *addr, int rw, int locality); + * + * DESCRIPTION + * + * Simple prefetch. Loads memory from specified address to CPU cache. + * The amount of data loaded is CPU dependant (cache line length). The + * `rw' argument defines the reason for prefetch: 0=read, 1=write. The + * `locality' argument defines the locality of the prefetch, 0=non-temporal + * (non-temporal cache, cache closest to CPU, data will not stay long in + * the cache), 1=temporal (L2+ cache), 2=temporal (L2, L3+ cache), + * 3=temporal (fetch to all caches, data stays longer time in cache). + * + * NOTES + * + * This produces only a hint for CPU. CPU doesn't have to actually + * prefetch the data. Use silc_prefetch_block to ensure CPU always + * prefetches. + * + ***/ + +static inline silc_attribute((always_inline)) +void silc_prefetch(void *addr, int rw, int locality) +{ +#if __GNUC__ > 3 + __builtin_prefetch(addr, rw, locality); +#endif /* __GNUC__ */ +} + +/****d* silcutil/silc_prefetch_block + * + * NAME + * + * static inline void silc_prefetch_block(void *addr, + * int prefetch_length, + * const int cache_line_length) + * + * DESCRIPTION + * + * Enforced block prefetch. This function loads the specified amount + * `prefetch_length' of memory from the specified address `addr' to CPU + * cache with each loaded cache line being the size of `cache_line_length'. + * If you don't know the cache line size use 64 bytes. Note that, the + * `cache_line_length' is a const int. In this context this mean its + * value must not come from a variable but must be a constant (the code + * won't compile if it comes from a variable). + * + * The `prefetch_length' must be multiple of twice of the + * `cache_line_length' or 128 if you don't know the cache line size, hence + * the minimum length for `prefetch_length' is 128 bytes when the + * `cache_line_length' is 64 bytes. Shorter cache line length (32 bytes) + * can be used too. + * + * You should use the correct `cache_line_length' value for your CPU or + * the value of the CPU for which you want to optimize your code. Intel + * CPUs usually have cache size of 32 or 64 bytes. The most optimal + * prefetch is achieved if the `cache_line_length' is the actual CPU cache + * line size. Always do performance testing with and without prefetching + * to make sure the prefetch actually helps. If used improperly, it may + * slow down your program. + * + * The difference to silc_prefetch is that this function always performs + * the prefetch and has the ability to prefetch more than one cache line + * worth of memory, whereas silc_prefetch can prefetch only one cache line + * and may not do the prefetch at all. + * + ***/ + +static inline silc_attribute((always_inline)) +void silc_prefetch_block(void *addr, + int prefetch_length, + const int cache_line_length) +{ +#if 0 + SILC_ASSERT(cache_line_length >= 32); + SILC_ASSERT(cache_line_length % 32 == 0); + SILC_ASSERT(prefetch_length >= cache_line_length); + SILC_ASSERT(prefetch_length % (cache_line_length * 2) == 0); +#endif + +#if SILC_SIZEOF_VOID_P < 8 +#define SILC_PREFETCH_UINT SilcUInt32 +#else +#define SILC_PREFETCH_UINT SilcUInt64 +#endif /* SILC_SIZEOF_VOID_P < 8 */ + +#if defined(__GNUC__) && (defined(SILC_I386) || defined(SILC_X86_64)) + + /* Assembler implementation. + + The idea here is to simply enforce the CPU to load the requested amount + of bytes to cache. We simply mov data from the memory to a register. + Each mov will load a full cache line worth of data from the memory. + + We expect the `cache_line_length' to be the actual cache line size. + It doesn't matter if it is. If it is smaller the prefetch is a bit + slower as there is redundancy. If it is larger we skip some of the + data and don't prefetch everything. + + The loop is unrolled to handle two mov's at once, this why we expect + the `prefetch_length' to be multiple of twice the length of + `cache_line_length`. We also mov the data from end to beginning instead + of from the beginning to assure CPU doesn't prefetch the data before + we actually want to do it. + + This technique is described by AMD in: + http://cdrom.amd.com/devconn/events/AMD_block_prefetch_paper.pdf */ + + { + SILC_PREFETCH_UINT temp; + +#define SILC_PREFETCH_ASM(ip, rp) \ + asm volatile ("1: \n\t" \ + "mov" ip " -%c4(%2, %" rp "3), %0 \n\t" \ + "mov" ip " -%c5(%2, %" rp "3), %0 \n\t" \ + "sub" ip " %5, %" rp "3 \n\t" \ + "jnz 1b " \ + : "=&r" (temp), "=r" (prefetch_length) \ + : "r" (addr), "1" (prefetch_length), \ + "Z" (cache_line_length), \ + "Z" (cache_line_length * 2) \ + : "memory", "cc"); + +#if defined(SILC_I386) + /* 32-bit prefetch */ + SILC_PREFETCH_ASM("l", ""); +#else + /* 64-bit prefetch */ + SILC_PREFETCH_ASM("q", "q"); +#endif /* SILC_I386 */ + } + +#else + /* C implementation. Yes, you can do it in C too. In fact, we'll try to + make the compiler generate nearly identical code to the above assembler + code. Note that, the memory access must be volatile, otherwise the + compiler will optimize them away because the temp variable isn't actually + used for anything. This should be as fast as the assembler code above, + unless the compiler decides to start meddling with it (don't use + -funroll-loops with this code). */ + + { + register unsigned char *a = addr; + register int len = prefetch_length; + register SILC_PREFETCH_UINT temp; + + do { + temp = *(SILC_PREFETCH_UINT volatile *) + (a + (len - cache_line_length)); + temp = *(SILC_PREFETCH_UINT volatile *) + (a + (len - (cache_line_length * 2))); + len -= (cache_line_length * 2); + } while (len != 0); + } +#endif /* __GNUC__ */ +#undef SILC_PREFETCH_UINT +#undef SILC_PREFETCH_ASM +} + #endif /* SILCTYPES_H */