simd multimap operations - first version, seem compatible with non-multi for now

This commit is contained in:
Richard Thier 2024-10-23 00:27:46 +02:00
parent cd30b70457
commit d219203939

View File

@ -71,12 +71,22 @@ static inline SM_ALWAYS_INLINE char simd_map_free(simd_map *map) {
/**
* Returns if this key is stored in the given map LANE or not - returns NULL if not found.
*
* Rem.: The lane_begin and lane_next_begin parameters are used for reentrant multisearch.
*
* @param map_lane The lane to find in.
* @param key The key to search for.
* @param lane_modulo When non-zero, the lane only searched by this many elements. Zero means all elements. (mod lane length)
* @param lane_modulo When non-zero, the lane only searched until this index. Zero means all remaining elements. (mod lane length)
* @param lane_begin The lane is searched from this location(find_all). If full lane / lane prefix is needed, this should be 0.
* @param lane_next_begin This pointer will be filled on non-NULL retvals with the incremented in-lane index (with % modulus).
* @returns NULL when not found, otherwise pointer to the stored value for the key.
*/
static inline SM_ALWAYS_INLINE uint32_t *simd_map_lane_find(simd_map_lane *map_lane, uint32_t key, int lane_modulo) {
static inline SM_ALWAYS_INLINE uint32_t *simd_map_lane_find(
simd_map_lane *map_lane,
uint32_t key,
int lane_modulo,
int lane_begin,
int *lane_next_begin) {
uint32_t *keys = map_lane->keys;
uint32_t *values = map_lane->values;
@ -90,18 +100,22 @@ static inline SM_ALWAYS_INLINE uint32_t *simd_map_lane_find(simd_map_lane *map_l
/* Regular integer code - should have good ILP and cache locality patterns anyways */
if(lane_modulo == 0) {
/** Pretty hopeful this can get more easily unrolled / autovectorized */
for(int i = 0; i < SM_LANE_SPAN; ++i) {
for(int i = lane_begin; i < SM_LANE_SPAN; ++i) {
if(SM_UNLIKELY(keys[i] == key)) {
return &values[i];
uint32_t *ptr = &values[i];
*lane_next_begin = (i + 1) % SM_LANE_SPAN;
return ptr;
}
}
return NULL;
} else {
non_simd_modulo:
for(int i = 0; i < lane_modulo; ++i) {
for(int i = lane_begin; i < lane_modulo; ++i) {
if(SM_UNLIKELY(keys[i] == key)) {
return &values[i];
uint32_t *ptr = &values[i];
*lane_next_begin = (i + 1) % SM_LANE_SPAN;
return ptr;
}
}
@ -109,31 +123,99 @@ non_simd_modulo:
}
}
// TODO: Implement find_all(..) and delegate to it in find(..)
/** The result of the find_all(..) operation */
struct simd_map_find_res {
/** The found location - or NULL when the key was not found */
uint32_t *value_location;
/** Meta-data for continuation of the search */
uint32_t lane_next;
/** Meta-data for continuation of the search */
int lane_next_begin;
};
typedef struct simd_map_find_res simd_map_find_res;
/** Returns if this key is stored in the map or not - returns NULL if does not exists. */
static inline uint32_t *simd_map_find(simd_map *map, uint32_t key) {
/* Do not process last element because of last incomplete lane */
if(map->usage_end > 0) for(uint32_t i = 0; i < map->usage_end - 1; ++i) {
uint32_t *found = simd_map_lane_find(&(map->lanes[i]), key, 0);
if(found) return found;
/** Create the value for starting a find_all call */
static inline simd_map_find_res simd_map_find_all_begin() {
simd_map_find_res ret;
ret.value_location = NULL;
ret.lane_next = 0;
ret.lane_next_begin = 0;
return ret;
}
/**
* Useful for multimap-like operations to find multiple mappings for the same key.
*
* @param map The map
* @param key The key to search
* @param prev The previous result - or simd_map_find_all_begin() to find the first / start lookup!
* @returns The found pointer / location (if any) and if location was non-NULL meta-data so we can search further same-keys!
*/
static inline SM_ALWAYS_INLINE simd_map_find_res simd_map_find_all(simd_map *map, uint32_t key, simd_map_find_res prev) {
simd_map_find_res ret;
/* Process most lanes */
/* Do not process last element (-1) because of last incomplete lane */
if(map->usage_end > 0) for(uint32_t i = prev.lane_next; i < map->usage_end - 1; ++i) {
uint32_t *found = simd_map_lane_find(
&(map->lanes[i]),
key,
0,
prev.lane_next_begin,
&(ret.lane_next_begin)); /* XXX: Fills part of retval! */
/* Needed so only the currently found are ignored in find_all(..) */
prev.lane_next_begin = 0;
if(found) {
ret.value_location = found;
ret.lane_next = i + (ret.lane_next_begin != 0);
return ret;
}
}
/* Process last lane - with a modulo lane */
if(map->usage_end > 0) {
if((map->usage_end > 0) && (prev.lane_next < map->usage_end)) {
uint32_t *found = simd_map_lane_find(
&(map->lanes[map->usage_end - 1]),
key,
map->lane_modulo);
if(found) return found;
&(map->lanes[map->usage_end - 1]),
key,
map->lane_modulo,
prev.lane_next_begin,
&(ret.lane_next_begin)); /* XXX: Fills part of retval! */
/* Needed so only the currently found are ignored in find_all(..) */
prev.lane_next_begin = 0;
if(found) {
ret.value_location = found;
ret.lane_next = (map->usage_end - 1) + (ret.lane_next_begin != 0);
return ret;
}
}
/* Not found */
return NULL;
ret = simd_map_find_all_begin();
return ret;
}
/** Useful if you know the key have never been before added (faster)! Returns 0 on errors, otherwise 1. */
static inline SM_ALWAYS_INLINE char simd_map_force_insert(simd_map *map, uint32_t key, uint32_t value) {
/** Returns if this key is stored in the map or not - returns NULL if does not exists. */
static inline uint32_t *simd_map_find(simd_map *map, uint32_t key) {
simd_map_find_res begin = simd_map_find_all_begin();
simd_map_find_res fires = simd_map_find_all(map, key, begin);
return fires.value_location;
}
/**
* Insert without checking that the value have been already added or not.
*
* Useful for multimap operation or if you know the key have never been before added (faster)!
*
* @param map The map
* @param key The key to insert
* @param value The value for this key to insert
* @returns 0 on errors, otherwise 1.
*/
static inline SM_ALWAYS_INLINE char simd_map_multi_insert(simd_map *map, uint32_t key, uint32_t value) {
/* Handle storage growth needs. */
uint32_t storage_needed = (map->lane_modulo == 0) ? 1 : 0;
if(SM_UNLIKELY(map->end - map->usage_end < storage_needed)) {
@ -171,7 +253,7 @@ static inline SM_ALWAYS_INLINE char simd_map_force_insert(simd_map *map, uint32_
static inline char simd_map_set(simd_map *map, uint32_t key, uint32_t value) {
uint32_t *found = simd_map_find(map, key);
if(!found) {
return simd_map_force_insert(map, key, value);
return simd_map_multi_insert(map, key, value);
} else {
/* Overwrite already existing mapping */
*found = value;