On 64-bit platforms, the Limex 64 model is implemented in normal GPRs.
On 32-bit platforms, however, 128-bit SSE registers are used for the
runtime implementation.
src/nfa/limex_exceptional.h
src/nfa/limex_native.c
src/nfa/limex_ring.h
+ src/nfa/limex_64.c
src/nfa/limex_simd128.c
src/nfa/limex_simd256.c
src/nfa/limex_simd384.c
GENERATE_NFA_DUMP_DECL(gf_name)
GENERATE_NFA_DECL(nfaExecLimEx32)
+GENERATE_NFA_DECL(nfaExecLimEx64)
GENERATE_NFA_DECL(nfaExecLimEx128)
GENERATE_NFA_DECL(nfaExecLimEx256)
GENERATE_NFA_DECL(nfaExecLimEx384)
--- /dev/null
+/*
+ * Copyright (c) 2015-2016, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ * \brief LimEx NFA: 128-bit SIMD runtime implementations.
+ */
+
+/* Limex64 is unusual on as on 32 bit platforms, at runtime it uses an m128 for
+ * state calculations.
+ */
+
+//#define DEBUG_INPUT
+//#define DEBUG_EXCEPTIONS
+
+#include "limex.h"
+
+#include "accel.h"
+#include "limex_internal.h"
+#include "nfa_internal.h"
+#include "ue2common.h"
+#include "util/bitutils.h"
+#include "util/simd_utils.h"
+
+// Common code
+#define STATE_ON_STACK
+#define ESTATE_ON_STACK
+
+#include "limex_runtime.h"
+
+#define SIZE 64
+#define ENG_STATE_T u64a
+
+#ifdef ARCH_64_BIT
+#define STATE_T u64a
+#define LOAD_FROM_ENG load_u64a
+#else
+#define STATE_T m128
+#define LOAD_FROM_ENG load_m128_from_u64a
+#endif
+
+#include "limex_exceptional.h"
+
+#include "limex_state_impl.h"
+
+#define INLINE_ATTR really_inline
+#include "limex_common_impl.h"
+
+#include "limex_runtime_impl.h"
return accelScanWrapper(accelTable, aux, input, idx, i, end);
}
+#ifdef ARCH_64_BIT
+size_t doAccel64(u64a s, u64a accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end) {
+ u32 idx = packedExtract64(s, accel);
+ return accelScanWrapper(accelTable, aux, input, idx, i, end);
+}
+#else
+size_t doAccel64(m128 s, m128 accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end) {
+ u32 idx = packedExtract64(movq(s), movq(accel));
+ return accelScanWrapper(accelTable, aux, input, idx, i, end);
+}
+#endif
+
size_t doAccel128(const m128 *state, const struct LimExNFA128 *limex,
const u8 *accelTable, const union AccelAux *aux,
const u8 *input, size_t i, size_t end) {
/*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
#include "util/simd_utils.h" // for m128 etc
union AccelAux;
+struct LimExNFA64;
struct LimExNFA128;
struct LimExNFA256;
struct LimExNFA384;
const union AccelAux *aux, const u8 *input, size_t i,
size_t end);
+#ifdef ARCH_64_BIT
+size_t doAccel64(u64a s, u64a accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end);
+#else
+size_t doAccel64(m128 s, m128 accel, const u8 *accelTable,
+ const union AccelAux *aux, const u8 *input, size_t i,
+ size_t end);
+#endif
+
size_t doAccel128(const m128 *s, const struct LimExNFA128 *limex,
const u8 *accelTable, const union AccelAux *aux,
const u8 *input, size_t i, size_t end);
/* impl of limex functions which depend only on state size */
-#if !defined(SIZE) || !defined(STATE_T) || !defined(INLINE_ATTR)
-# error Must define SIZE and STATE_T and INLINE_ATTR in includer.
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG) \
+ || !defined(INLINE_ATTR)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG and INLINE_ATTR in includer.
#endif
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
#define PROCESS_ACCEPTS_NOSQUASH_FN JOIN(moProcessAcceptsNoSquash, SIZE)
#define CONTEXT_T JOIN(NFAContext, SIZE)
#define ONES_STATE JOIN(ones_, STATE_T)
-#define LOAD_STATE JOIN(load_, STATE_T)
-#define STORE_STATE JOIN(store_, STATE_T)
#define AND_STATE JOIN(and_, STATE_T)
#define OR_STATE JOIN(or_, STATE_T)
#define ANDNOT_STATE JOIN(andnot_, STATE_T)
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
u32 cyclicState = info->cyclicState;
- if (!TESTBIT_STATE(accstate, cyclicState)) {
+ if (!TESTBIT_STATE(*accstate, cyclicState)) {
continue;
}
// We have squash masks we might have to apply after firing reports.
STATE_T squash = ONES_STATE;
- const STATE_T *squashMasks = (const STATE_T *)
+ const ENG_STATE_T *squashMasks = (const ENG_STATE_T *)
((const char *)limex + limex->squashOffset);
for (u32 i = 0; i < acceptCount; i++) {
const struct NFAAccept *a = &acceptTable[i];
- if (TESTBIT_STATE(s, a->state)) {
+ if (TESTBIT_STATE(*s, a->state)) {
DEBUG_PRINTF("state %u is on, firing report id=%u, offset=%llu\n",
a->state, a->externalId, offset);
int rv = callback(0, offset, a->externalId, context);
}
if (a->squash != MO_INVALID_IDX) {
assert(a->squash < limex->squashCount);
- const STATE_T *sq = &squashMasks[a->squash];
+ const ENG_STATE_T *sq = &squashMasks[a->squash];
DEBUG_PRINTF("squash mask %u @ %p\n", a->squash, sq);
- squash = AND_STATE(squash, LOAD_STATE(sq));
+ squash = AND_STATE(squash, LOAD_FROM_ENG(sq));
}
}
}
- STORE_STATE(s, AND_STATE(LOAD_STATE(s), squash));
+ *s = AND_STATE(*s, squash);
return 0;
}
for (u32 i = 0; i < acceptCount; i++) {
const struct NFAAccept *a = &acceptTable[i];
- if (TESTBIT_STATE(s, a->state)) {
+ if (TESTBIT_STATE(*s, a->state)) {
DEBUG_PRINTF("state %u is on, firing report id=%u, offset=%llu\n",
a->state, a->externalId, offset);
int rv = callback(0, offset, a->externalId, context);
return MO_CONTINUE_MATCHING;
}
- const STATE_T acceptEodMask = LOAD_STATE(&limex->acceptAtEOD);
- STATE_T foundAccepts = AND_STATE(LOAD_STATE(s), acceptEodMask);
+ const STATE_T acceptEodMask = LOAD_FROM_ENG(&limex->acceptAtEOD);
+ STATE_T foundAccepts = AND_STATE(*s, acceptEodMask);
if (do_br) {
SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state,
return MO_CONTINUE_MATCHING;
}
- STATE_T acceptEodMask = LOAD_STATE(&limex->acceptAtEOD);
- STATE_T foundAccepts = AND_STATE(LOAD_STATE(s), acceptEodMask);
+ STATE_T acceptEodMask = LOAD_FROM_ENG(&limex->acceptAtEOD);
+ STATE_T foundAccepts = AND_STATE(*s, acceptEodMask);
assert(!limex->repeatCount);
assert(q->state);
assert(q_cur_type(q) == MQE_START);
- STATE_T s = LOAD_STATE(q->state);
- STATE_T acceptMask = LOAD_STATE(&limex->accept);
+ STATE_T s = *(STATE_T *)q->state;
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
static really_inline
STATE_T INITIAL_FN(const IMPL_NFA_T *impl, char onlyDs) {
- return LOAD_STATE(onlyDs ? &impl->initDS : &impl->init);
+ return LOAD_FROM_ENG(onlyDs ? &impl->initDS : &impl->init);
}
static really_inline
static really_inline
STATE_T TOPN_FN(const IMPL_NFA_T *limex, STATE_T state, u32 n) {
assert(n < limex->topCount);
- const STATE_T *topsptr =
- (const STATE_T *)((const char *)limex + limex->topOffset);
- STATE_T top = LOAD_STATE(&topsptr[n]);
+ const ENG_STATE_T *topsptr =
+ (const ENG_STATE_T *)((const char *)limex + limex->topOffset);
+ STATE_T top = LOAD_FROM_ENG(&topsptr[n]);
return OR_STATE(top, state);
}
DEBUG_PRINTF("expire estate at offset %llu\n", offset);
- const STATE_T cyclics =
- AND_STATE(LOAD_STATE(&ctx->s), LOAD_STATE(&limex->repeatCyclicMask));
+ const STATE_T cyclics
+ = AND_STATE(ctx->s, LOAD_FROM_ENG(&limex->repeatCyclicMask));
if (ISZERO_STATE(cyclics)) {
DEBUG_PRINTF("no cyclic states are on\n");
return;
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
u32 cyclicState = info->cyclicState;
- if (!TESTBIT_STATE(&cyclics, cyclicState)) {
+ if (!TESTBIT_STATE(cyclics, cyclicState)) {
continue;
}
last_top, repeat->repeatMax);
u64a adj = 0;
/* if the cycle's tugs are active at repeat max, it is still alive */
- if (TESTBIT_STATE((const STATE_T *)&limex->accept, cyclicState) ||
- TESTBIT_STATE((const STATE_T *)&limex->acceptAtEOD, cyclicState)) {
+ if (TESTBIT_STATE(LOAD_FROM_ENG(&limex->accept), cyclicState) ||
+ TESTBIT_STATE(LOAD_FROM_ENG(&limex->acceptAtEOD), cyclicState)) {
DEBUG_PRINTF("lazy tug possible - may still be inspected\n");
adj = 1;
} else {
- const STATE_T *tug_mask =
- (const STATE_T *)((const char *)info + info->tugMaskOffset);
- if (ISNONZERO_STATE(AND_STATE(ctx->s, LOAD_STATE(tug_mask)))) {
+ const ENG_STATE_T *tug_mask =
+ (const ENG_STATE_T *)((const char *)info + info->tugMaskOffset);
+ if (ISNONZERO_STATE(AND_STATE(ctx->s, LOAD_FROM_ENG(tug_mask)))) {
DEBUG_PRINTF("tug possible - may still be inspected\n");
adj = 1;
}
u64a offset, ReportID report) {
assert(limex);
- const STATE_T acceptMask = LOAD_STATE(&limex->accept);
+ const STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
STATE_T accstate = AND_STATE(state, acceptMask);
// Are we in an accept state?
#ifdef DEBUG
DEBUG_PRINTF("accept states that are on: ");
for (u32 i = 0; i < sizeof(STATE_T) * 8; i++) {
- if (TESTBIT_STATE(&accstate, i)) printf("%u ", i);
+ if (TESTBIT_STATE(accstate, i)) printf("%u ", i);
}
printf("\n");
#endif
const struct NFAAccept *a = &acceptTable[i];
DEBUG_PRINTF("checking idx=%u, externalId=%u\n", a->state,
a->externalId);
- if (a->externalId == report && TESTBIT_STATE(&accstate, a->state)) {
+ if (a->externalId == report && TESTBIT_STATE(accstate, a->state)) {
DEBUG_PRINTF("report is on!\n");
return 1;
}
u64a offset) {
assert(limex);
- const STATE_T acceptMask = LOAD_STATE(&limex->accept);
+ const STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
STATE_T accstate = AND_STATE(state, acceptMask);
// Are we in an accept state?
#undef CONTEXT_T
#undef IMPL_NFA_T
#undef ONES_STATE
-#undef LOAD_STATE
-#undef STORE_STATE
#undef AND_STATE
#undef OR_STATE
#undef ANDNOT_STATE
#undef PROCESS_ACCEPTS_NOSQUASH_FN
#undef SQUASH_UNTUG_BR_FN
#undef GET_NFA_REPEAT_INFO_FN
-
-#undef SIZE
-#undef STATE_T
-#undef INLINE_ATTR
sizeof(limex->init), stateSize, repeatscratchStateSize,
repeatStreamState);
- size_t scratchStateSize = sizeof(limex->init);
+ size_t scratchStateSize = NFATraits<dtype>::scratch_state_size;
+
if (repeatscratchStateSize) {
scratchStateSize
= ROUNDUP_N(scratchStateSize, alignof(RepeatControl));
sz = 32;
}
- // Special case: with SIMD available, we definitely prefer using
- // 128-bit NFAs over 64-bit ones given the paucity of registers
- // available.
- if (sz == 64) {
- sz = 128;
- }
-
if (args.cc.grey.nfaForceSize) {
sz = args.cc.grey.nfaForceSize;
}
typedef u_##mlt_size tableRow_t; \
typedef NFAException##mlt_size exception_t; \
static const size_t maxStates = mlt_size; \
+ static const size_t scratch_state_size = mlt_size == 64 ? sizeof(m128) \
+ : sizeof(tableRow_t); \
};
MAKE_LIMEX_TRAITS(32)
+MAKE_LIMEX_TRAITS(64)
MAKE_LIMEX_TRAITS(128)
MAKE_LIMEX_TRAITS(256)
MAKE_LIMEX_TRAITS(384)
/*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
// Runtime context structures.
+/* Note: The size of the context structures may vary from platform to platform
+ * (notably, for the Limex64 structure). As a result, information based on the
+ * size and other detail of these structures should not be written into the
+ * bytecode -- really, the details of the structure should not be accessed by
+ * the ue2 compile side at all.
+ */
+#ifdef __cplusplus
+#error ue2 runtime only file
+#endif
+
/* cached_estate/esucc etc...
*
* If the exception state matches the cached_estate we will apply
};
GEN_CONTEXT_STRUCT(32, u32)
+#ifdef ARCH_64_BIT
+GEN_CONTEXT_STRUCT(64, u64a)
+#else
+GEN_CONTEXT_STRUCT(64, m128)
+#endif
GEN_CONTEXT_STRUCT(128, m128)
GEN_CONTEXT_STRUCT(256, m256)
GEN_CONTEXT_STRUCT(384, m384)
static const u32 size = 128;
typedef NFAException128 exception_type;
};
+template<> struct limex_traits<LimExNFA64> {
+ static const u32 size = 64;
+ typedef NFAException64 exception_type;
+};
template<> struct limex_traits<LimExNFA32> {
static const u32 size = 32;
typedef NFAException32 exception_type;
DUMP_DOT_FN(size)
LIMEX_DUMP_FNS(32)
+LIMEX_DUMP_FNS(64)
LIMEX_DUMP_FNS(128)
LIMEX_DUMP_FNS(256)
LIMEX_DUMP_FNS(384)
* X-macro generic impl, included into the various LimEx model implementations.
*/
-#if !defined(SIZE) || !defined(STATE_T)
-# error Must define SIZE and STATE_T in includer.
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
#endif
#include "config.h"
#define PE_FN JOIN(processExceptional, SIZE)
#define RUN_EXCEPTION_FN JOIN(runException, SIZE)
#define ZERO_STATE JOIN(zero_, STATE_T)
-#define LOAD_STATE JOIN(load_, STATE_T)
-#define STORE_STATE JOIN(store_, STATE_T)
#define AND_STATE JOIN(and_, STATE_T)
#define EQ_STATE(a, b) (!JOIN(noteq_, STATE_T)((a), (b)))
#define OR_STATE JOIN(or_, STATE_T)
#define ESTATE_ARG STATE_T estate
#else
#define ESTATE_ARG const STATE_T *estatep
-#define estate LOAD_STATE(estatep)
+#define estate (*estatep)
#endif
#ifdef STATE_ON_STACK
char *repeat_state = ctx->repeat_state + info->stateOffset;
if (e->trigger == LIMEX_TRIGGER_POS) {
- char cyclic_on = TESTBIT_STATE(STATE_ARG_P, info->cyclicState);
+ char cyclic_on = TESTBIT_STATE(*STATE_ARG_P, info->cyclicState);
processPosTrigger(repeat, repeat_ctrl, repeat_state, offset,
cyclic_on);
*cacheable = DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES;
*cacheable = DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES;
DEBUG_PRINTF("stale history, squashing cyclic state\n");
assert(e->hasSquash == LIMEX_SQUASH_TUG);
- STORE_STATE(succ, AND_STATE(LOAD_STATE(succ),
- LOAD_STATE(&e->squash)));
+ *succ = AND_STATE(*succ, LOAD_FROM_ENG(&e->squash));
return 1; // continue
} else if (rv == TRIGGER_SUCCESS_CACHE) {
new_cache->br = 1;
// Most exceptions have a set of successors to switch on. `local_succ' is
// ORed into `succ' at the end of the caller's loop.
#ifndef BIG_MODEL
- *local_succ = OR_STATE(*local_succ, LOAD_STATE(&e->successors));
+ *local_succ = OR_STATE(*local_succ, LOAD_FROM_ENG(&e->successors));
#else
- STORE_STATE(&ctx->local_succ, OR_STATE(LOAD_STATE(&ctx->local_succ),
- LOAD_STATE(&e->successors)));
+ ctx->local_succ = OR_STATE(ctx->local_succ, LOAD_FROM_ENG(&e->successors));
#endif
// Some exceptions squash states behind them. Note that we squash states in
// 'succ', not local_succ.
- if (e->hasSquash == LIMEX_SQUASH_CYCLIC ||
- e->hasSquash == LIMEX_SQUASH_REPORT) {
- STORE_STATE(succ, AND_STATE(LOAD_STATE(succ),
- LOAD_STATE(&e->squash)));
+ if (e->hasSquash == LIMEX_SQUASH_CYCLIC
+ || e->hasSquash == LIMEX_SQUASH_REPORT) {
+ *succ = AND_STATE(*succ, LOAD_FROM_ENG(&e->squash));
if (*cacheable == CACHE_RESULT) {
*cacheable = DO_NOT_CACHE_RESULT;
}
char in_rev, char flags) {
assert(diffmask > 0); // guaranteed by caller macro
- if (EQ_STATE(estate, LOAD_STATE(&ctx->cached_estate))) {
+ if (EQ_STATE(estate, ctx->cached_estate)) {
DEBUG_PRINTF("using cached succ from previous state\n");
- STORE_STATE(succ, OR_STATE(LOAD_STATE(succ), LOAD_STATE(&ctx->cached_esucc)));
+ *succ = OR_STATE(*succ, ctx->cached_esucc);
if (ctx->cached_reports && (flags & CALLBACK_OUTPUT)) {
DEBUG_PRINTF("firing cached reports from previous state\n");
if (unlikely(limexRunReports(ctx->cached_reports, ctx->callback,
#ifndef BIG_MODEL
STATE_T local_succ = ZERO_STATE;
#else
- STORE_STATE(&ctx->local_succ, ZERO_STATE);
+ ctx->local_succ = ZERO_STATE;
#endif
// A copy of the estate as an array of GPR-sized chunks.
u32 base_index[sizeof(STATE_T) / sizeof(CHUNK_T)];
base_index[0] = 0;
- for (u32 i = 0; i < ARRAY_LENGTH(base_index) - 1; i++) {
+ for (s32 i = 0; i < (s32)ARRAY_LENGTH(base_index) - 1; i++) {
base_index[i + 1] = base_index[i] + POPCOUNT_FN(emask_chunks[i]);
}
} while (diffmask);
#ifndef BIG_MODEL
- STORE_STATE(succ, OR_STATE(LOAD_STATE(succ), local_succ));
+ *succ = OR_STATE(*succ, local_succ);
#else
- STORE_STATE(succ, OR_STATE(LOAD_STATE(succ), ctx->local_succ));
+ *succ = OR_STATE(*succ, ctx->local_succ);
#endif
if (cacheable == CACHE_RESULT) {
- STORE_STATE(&ctx->cached_estate, estate);
+ ctx->cached_estate = estate;
#ifndef BIG_MODEL
ctx->cached_esucc = local_succ;
#else
- STORE_STATE(&ctx->cached_esucc, LOAD_STATE(&ctx->local_succ));
+ ctx->cached_esucc = ctx->local_succ;
#endif
ctx->cached_reports = new_cache.reports;
ctx->cached_br = new_cache.br;
} else if (cacheable == DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES) {
if (ctx->cached_br) {
- STORE_STATE(&ctx->cached_estate, ZERO_STATE);
+ ctx->cached_estate = ZERO_STATE;
}
}
#undef EQ_STATE
#undef OR_STATE
#undef TESTBIT_STATE
-#undef LOAD_STATE
-#undef STORE_STATE
#undef PE_FN
#undef RUN_EXCEPTION_FN
#undef CONTEXT_T
#undef FIND_AND_CLEAR_FN
#undef IMPL_NFA_T
#undef GET_NFA_REPEAT_INFO_FN
-
-// Parameters.
-#undef SIZE
-#undef STATE_T
};
CREATE_NFA_LIMEX(32)
+CREATE_NFA_LIMEX(64)
CREATE_NFA_LIMEX(128)
CREATE_NFA_LIMEX(256)
CREATE_NFA_LIMEX(384)
#include "limex_runtime.h"
// Other implementation code from X-Macro impl.
-#define SIZE 32
-#define STATE_T u32
+#define SIZE 32
+#define STATE_T u32
+#define ENG_STATE_T u32
+#define LOAD_FROM_ENG load_u32
+
#include "limex_state_impl.h"
-#define SIZE 32
-#define STATE_T u32
#define INLINE_ATTR really_inline
#include "limex_common_impl.h"
// Process exceptional states
-#define SIZE 32
-#define STATE_T u32
#define STATE_ON_STACK
#define ESTATE_ON_STACK
#define RUN_EXCEPTION_FN_ONLY
}
// 32-bit models.
-
-#define SIZE 32
-#define STATE_T u32
#include "limex_runtime_impl.h"
\brief Limex Execution Engine Or:
How I Learned To Stop Worrying And Love The Preprocessor
- This file includes utility functions which do not depend on the state size or
- shift masks directly.
+ This file includes utility functions which do not depend on the size of the
+ state or shift masks directly.
*/
#ifndef LIMEX_RUNTIME_H
const ReportID *reports;
};
-// Shift macros for Limited NFAs. Defined in terms of uniform ops.
-// LimExNFAxxx ptr in 'limex' and the current state in 's'
-#define NFA_EXEC_LIM_SHIFT(nels_type, nels_i) \
- (JOIN(lshift_, nels_type)( \
- JOIN(and_, nels_type)(s, \
- JOIN(load_, nels_type)(&limex->shift[nels_i])), \
- limex->shiftAmount[nels_i]))
-
-// Calculate the (limited model) successors for a number of variable shifts.
-// Assumes current state in 's' and successors in 'succ'.
-
-#define NFA_EXEC_GET_LIM_SUCC(gls_type) \
- do { \
- succ = NFA_EXEC_LIM_SHIFT(gls_type, 0); \
- switch (limex->shiftCount) { \
- case 8: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 7)); \
- case 7: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 6)); \
- case 6: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 5)); \
- case 5: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 4)); \
- case 4: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 3)); \
- case 3: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 2)); \
- case 2: \
- succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 1)); \
- case 1: \
- case 0: \
- ; \
- } \
- } while (0)
-
#define PE_RV_HALT 1
#ifdef STATE_ON_STACK
}
MAKE_GET_NFA_REPEAT_INFO(32)
+MAKE_GET_NFA_REPEAT_INFO(64)
MAKE_GET_NFA_REPEAT_INFO(128)
MAKE_GET_NFA_REPEAT_INFO(256)
MAKE_GET_NFA_REPEAT_INFO(384)
#include "util/join.h"
#include <string.h>
-
/** \file
* \brief Limex Execution Engine Or:
* How I Learned To Stop Worrying And Love The Preprocessor
* Version 2.0: now with X-Macros, so you get line numbers in your debugger.
*/
-#if !defined(SIZE) || !defined(STATE_T)
-# error Must define SIZE and STATE_T in includer.
+
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
#endif
#define LIMEX_API_ROOT JOIN(nfaExecLimEx, SIZE)
#define STREAMSILENT_FN JOIN(LIMEX_API_ROOT, _Stream_Silent)
#define CONTEXT_T JOIN(NFAContext, SIZE)
#define EXCEPTION_T JOIN(struct NFAException, SIZE)
-#define LOAD_STATE JOIN(load_, STATE_T)
-#define STORE_STATE JOIN(store_, STATE_T)
#define AND_STATE JOIN(and_, STATE_T)
#define ANDNOT_STATE JOIN(andnot_, STATE_T)
#define OR_STATE JOIN(or_, STATE_T)
+#define LSHIFT_STATE JOIN(lshift_, STATE_T)
#define TESTBIT_STATE JOIN(testbit_, STATE_T)
#define CLEARBIT_STATE JOIN(clearbit_, STATE_T)
#define ZERO_STATE JOIN(zero_, STATE_T)
#define ACCEL_AND_FRIENDS_MASK accel_and_friendsMask
#define EXCEPTION_MASK exceptionMask
#else
-#define ACCEL_MASK LOAD_STATE(&limex->accel)
-#define ACCEL_AND_FRIENDS_MASK LOAD_STATE(&limex->accel_and_friends)
-#define EXCEPTION_MASK LOAD_STATE(&limex->exceptionMask)
+#define ACCEL_MASK LOAD_FROM_ENG(&limex->accel)
+#define ACCEL_AND_FRIENDS_MASK LOAD_FROM_ENG(&limex->accel_and_friends)
+#define EXCEPTION_MASK LOAD_FROM_ENG(&limex->exceptionMask)
#endif
// Run exception processing, if necessary. Returns 0 if scanning should
}
if (first_match && i) {
- STATE_T acceptMask = LOAD_STATE(&limex->accept);
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
DEBUG_PRINTF("first match at %zu\n", i);
DEBUG_PRINTF("for nfa %p\n", limex);
assert(final_loc);
- STORE_STATE(&ctx->s, s);
+ ctx->s = s;
*final_loc = i;
return 1; // Halt matching.
}
return j;
}
+// Shift macros for Limited NFAs. Defined in terms of uniform ops.
+// LimExNFAxxx ptr in 'limex' and the current state in 's'
+#define NFA_EXEC_LIM_SHIFT(limex_m, curr_m, shift_idx) \
+ LSHIFT_STATE(AND_STATE(curr_m, LOAD_FROM_ENG(&limex_m->shift[shift_idx])), \
+ limex_m->shiftAmount[shift_idx])
+
+// Calculate the (limited model) successors for a number of variable shifts.
+// Assumes current state in 'curr_m' and places the successors in 'succ_m'.
+#define NFA_EXEC_GET_LIM_SUCC(limex_m, curr_m, succ_m) \
+ do { \
+ succ_m = NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 0); \
+ switch (limex_m->shiftCount) { \
+ case 8: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 7)); \
+ case 7: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 6)); \
+ case 6: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 5)); \
+ case 5: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 4)); \
+ case 4: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 3)); \
+ case 3: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 2)); \
+ case 2: \
+ succ_m = OR_STATE(succ_m, NFA_EXEC_LIM_SHIFT(limex_m, curr_m, 1)); \
+ case 1: \
+ case 0: \
+ ; \
+ } \
+ } while (0)
+
+
static really_inline
char STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
struct CONTEXT_T *ctx, u64a offset, const char flags,
u64a *final_loc, const char first_match) {
- const STATE_T *reach = (const STATE_T *)((const char *)limex + sizeof(*limex));
+ const ENG_STATE_T *reach = get_reach_table(limex);
#if SIZE < 256
- const STATE_T accelMask = LOAD_STATE(&limex->accel);
- const STATE_T accel_and_friendsMask = LOAD_STATE(&limex->accel_and_friends);
- const STATE_T exceptionMask = LOAD_STATE(&limex->exceptionMask);
+ const STATE_T accelMask = LOAD_FROM_ENG(&limex->accel);
+ const STATE_T accel_and_friendsMask
+ = LOAD_FROM_ENG(&limex->accel_and_friends);
+ const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
#endif
const u8 *accelTable = (const u8 *)((const char *)limex + limex->accelTableOffset);
const union AccelAux *accelAux =
(const union AccelAux *)((const char *)limex + limex->accelAuxOffset);
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
const ReportID *exReports = getExReports(limex);
- STATE_T s = LOAD_STATE(&ctx->s);
+ STATE_T s = ctx->s;
/* assert(ISALIGNED_16(exceptions)); */
/* assert(ISALIGNED_16(reach)); */
DUMP_INPUT(i);
if (ISZERO_STATE(s)) {
DEBUG_PRINTF("no states are switched on, early exit\n");
- STORE_STATE(&ctx->s, s);
+ ctx->s = s;
return MO_CONTINUE_MATCHING;
}
u8 c = input[i];
STATE_T succ;
- NFA_EXEC_GET_LIM_SUCC(STATE_T);
+ NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, s, EXCEPTION_MASK,
i, offset, &succ, final_loc, ctx, flags, 0,
return MO_HALT_MATCHING;
}
- s = AND_STATE(succ, LOAD_STATE(&reach[limex->reachMap[c]]));
+ s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
}
with_accel:
u8 c = input[i];
STATE_T succ;
- NFA_EXEC_GET_LIM_SUCC(STATE_T);
+ NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, s, EXCEPTION_MASK,
i, offset, &succ, final_loc, ctx, flags, 0,
return MO_HALT_MATCHING;
}
- s = AND_STATE(succ, LOAD_STATE(&reach[limex->reachMap[c]]));
+ s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
}
- STORE_STATE(&ctx->s, s);
+ ctx->s = s;
if ((first_match || (flags & CALLBACK_OUTPUT)) && limex->acceptCount) {
- STATE_T acceptMask = LOAD_STATE(&limex->accept);
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
const struct NFAAccept *acceptTable = getAcceptTable(limex);
const u32 acceptCount = limex->acceptCount;
STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
if (first_match) {
- STORE_STATE(&ctx->s, s);
+ ctx->s = s;
assert(final_loc);
*final_loc = length;
return MO_HALT_MATCHING;
static never_inline
char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
struct CONTEXT_T *ctx, u64a offset) {
- const STATE_T *reach = (const STATE_T *)((const char *)limex + sizeof(*limex));
+ const ENG_STATE_T *reach = get_reach_table(limex);
#if SIZE < 256
- const STATE_T exceptionMask = LOAD_STATE(&limex->exceptionMask);
+ const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
#endif
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
const ReportID *exReports = getExReports(limex);
- STATE_T s = LOAD_STATE(&ctx->s);
+ STATE_T s = ctx->s;
/* assert(ISALIGNED_16(exceptions)); */
/* assert(ISALIGNED_16(reach)); */
DUMP_INPUT(i-1);
if (ISZERO_STATE(s)) {
DEBUG_PRINTF("no states are switched on, early exit\n");
- STORE_STATE(&ctx->s, s);
+ ctx->s = s;
return MO_CONTINUE_MATCHING;
}
u8 c = input[i-1];
STATE_T succ;
- NFA_EXEC_GET_LIM_SUCC(STATE_T);
+ NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, s,
EXCEPTION_MASK, i, offset, &succ, final_loc, ctx,
return MO_HALT_MATCHING;
}
- s = AND_STATE(succ, reach[limex->reachMap[c]]);
+ s = AND_STATE(succ, LOAD_FROM_ENG(&reach[limex->reachMap[c]]));
}
- STORE_STATE(&ctx->s, s);
+ ctx->s = s;
- STATE_T acceptMask = LOAD_STATE(&limex->accept);
+ STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
const struct NFAAccept *acceptTable = getAcceptTable(limex);
const u32 acceptCount = limex->acceptCount;
assert(flags & CALLBACK_OUTPUT);
return;
}
- STATE_T s = LOAD_STATE(src);
+ STATE_T s = *(STATE_T *)src;
- if (ISZERO_STATE(AND_STATE(s, LOAD_STATE(&limex->repeatCyclicMask)))) {
+ if (ISZERO_STATE(AND_STATE(LOAD_FROM_ENG(&limex->repeatCyclicMask), s))) {
DEBUG_PRINTF("no cyclics are on\n");
return;
}
DEBUG_PRINTF("repeat %u\n", i);
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
- if (!TESTBIT_STATE(&s, info->cyclicState)) {
+ if (!TESTBIT_STATE(s, info->cyclicState)) {
DEBUG_PRINTF("is dead\n");
continue;
}
offset);
}
- STORE_STATE(src, s);
+ *(STATE_T *)src = s;
}
char JOIN(LIMEX_API_ROOT, _queueCompressState)(const struct NFA *n,
// Note: state has already been expanded into 'dest'.
const STATE_T cyclics =
- AND_STATE(LOAD_STATE(dest), LOAD_STATE(&limex->repeatCyclicMask));
+ AND_STATE(*(STATE_T *)dest, LOAD_FROM_ENG(&limex->repeatCyclicMask));
if (ISZERO_STATE(cyclics)) {
DEBUG_PRINTF("no cyclics are on\n");
return;
DEBUG_PRINTF("repeat %u\n", i);
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
- if (!TESTBIT_STATE(&cyclics, info->cyclicState)) {
+ if (!TESTBIT_STATE(cyclics, info->cyclicState)) {
DEBUG_PRINTF("is dead\n");
continue;
}
return 0;
}
-char JOIN(LIMEX_API_ROOT, _queueInitState)(const struct NFA *n,
- struct mq *q) {
- STORE_STATE(q->state, ZERO_STATE);
+char JOIN(LIMEX_API_ROOT, _queueInitState)(const struct NFA *n, struct mq *q) {
+ *(STATE_T *)q->state = ZERO_STATE;
// Zero every bounded repeat control block in state.
const IMPL_NFA_T *limex = getImplNfa(n);
u32 e = q->items[q->cur].type;
switch (e) {
DEFINE_CASE(MQE_TOP)
- STORE_STATE(&ctx->s, TOP_FN(limex, !!sp, LOAD_STATE(&ctx->s)));
+ ctx->s = TOP_FN(limex, !!sp, ctx->s);
break;
DEFINE_CASE(MQE_START)
break;
assert(e >= MQE_TOP_FIRST);
assert(e < MQE_INVALID);
DEBUG_PRINTF("MQE_TOP + %d\n", ((int)e - MQE_TOP_FIRST));
- STORE_STATE(&ctx->s,
- TOPN_FN(limex, LOAD_STATE(&ctx->s), e - MQE_TOP_FIRST));
+ ctx->s = TOPN_FN(limex, ctx->s, e - MQE_TOP_FIRST);
}
#undef DEFINE_CASE
}
ctx.repeat_state = q->streamState + limex->stateSize;
ctx.callback = q->cb;
ctx.context = q->context;
- STORE_STATE(&ctx.cached_estate, ZERO_STATE);
+ ctx.cached_estate = ZERO_STATE;
ctx.cached_br = 0;
assert(q->items[q->cur].location >= 0);
DEBUG_PRINTF("LOAD STATE\n");
- STORE_STATE(&ctx.s, LOAD_STATE(q->state));
+ ctx.s = *(STATE_T *)q->state;
assert(q->items[q->cur].type == MQE_START);
u64a offset = q->offset;
assert(ep - offset <= q->length);
if (STREAMCB_FN(limex, q->buffer + sp - offset, ep - sp, &ctx, sp)
== MO_HALT_MATCHING) {
- STORE_STATE(q->state, ZERO_STATE);
+ *(STATE_T *)q->state = ZERO_STATE;
return 0;
}
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp - offset;
DEBUG_PRINTF("bailing q->cur %u q->end %u\n", q->cur, q->end);
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
return MO_ALIVE;
}
EXPIRE_ESTATE_FN(limex, &ctx, sp);
DEBUG_PRINTF("END\n");
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
if (q->cur != q->end) {
q->cur--;
return MO_ALIVE;
}
- return ISNONZERO_STATE(LOAD_STATE(&ctx.s));
+ return ISNONZERO_STATE(ctx.s);
}
/* used by suffix execution in Rose */
ctx.repeat_state = q->streamState + limex->stateSize;
ctx.callback = q->cb;
ctx.context = q->context;
- STORE_STATE(&ctx.cached_estate, ZERO_STATE);
+ ctx.cached_estate = ZERO_STATE;
ctx.cached_br = 0;
DEBUG_PRINTF("LOAD STATE\n");
- STORE_STATE(&ctx.s, LOAD_STATE(q->state));
+ ctx.s = *(STATE_T *)q->state;
assert(q->items[q->cur].type == MQE_START);
u64a offset = q->offset;
q->cur--;
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp + final_look - offset;
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
return MO_MATCHES_PENDING;
}
q->cur--;
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp + final_look - offset;
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
return MO_MATCHES_PENDING;
}
q->items[q->cur].type = MQE_START;
q->items[q->cur].location = sp - offset;
DEBUG_PRINTF("bailing q->cur %u q->end %u\n", q->cur, q->end);
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
return MO_ALIVE;
}
EXPIRE_ESTATE_FN(limex, &ctx, sp);
DEBUG_PRINTF("END\n");
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
if (q->cur != q->end) {
q->cur--;
return MO_ALIVE;
}
- return ISNONZERO_STATE(LOAD_STATE(&ctx.s));
+ return ISNONZERO_STATE(ctx.s);
}
// Used for execution Rose prefix/infixes.
ctx.repeat_state = q->streamState + limex->stateSize;
ctx.callback = NULL;
ctx.context = NULL;
- STORE_STATE(&ctx.cached_estate, ZERO_STATE);
+ ctx.cached_estate = ZERO_STATE;
ctx.cached_br = 0;
DEBUG_PRINTF("LOAD STATE\n");
- STORE_STATE(&ctx.s, LOAD_STATE(q->state));
+ ctx.s = *(STATE_T *)q->state;
assert(q->items[q->cur].type == MQE_START);
u64a offset = q->offset;
if (n->maxWidth) {
if (ep - sp > n->maxWidth) {
sp = ep - n->maxWidth;
- STORE_STATE(&ctx.s, INITIAL_FN(limex, !!sp));
+ ctx.s = INITIAL_FN(limex, !!sp);
}
}
assert(ep >= sp);
DEBUG_PRINTF("END, nfa is %s\n",
ISNONZERO_STATE(ctx.s) ? "still alive" : "dead");
- STORE_STATE(q->state, LOAD_STATE(&ctx.s));
+ *(STATE_T *)q->state = ctx.s;
- if (JOIN(limexInAccept, SIZE)(limex, LOAD_STATE(&ctx.s), ctx.repeat_ctrl,
+ if (JOIN(limexInAccept, SIZE)(limex, ctx.s, ctx.repeat_ctrl,
ctx.repeat_state, sp + 1, report)) {
return MO_MATCHES_PENDING;
}
- return ISNONZERO_STATE(LOAD_STATE(&ctx.s));
+ return ISNONZERO_STATE(ctx.s);
}
char JOIN(LIMEX_API_ROOT, _testEOD)(const struct NFA *n, const char *state,
ctx.repeat_state = NULL;
ctx.callback = cb;
ctx.context = context;
- STORE_STATE(&ctx.cached_estate, ZERO_STATE);
+ ctx.cached_estate = ZERO_STATE;
ctx.cached_br = 0;
const IMPL_NFA_T *limex = getImplNfa(n);
- STORE_STATE(&ctx.s, INITIAL_FN(limex, 0)); // always anchored
+ ctx.s = INITIAL_FN(limex, 0); // always anchored
// 'buf' may be null, for example when we're scanning at EOD time.
if (buflen) {
REV_STREAM_FN(limex, hbuf, hlen, &ctx, offset);
}
- if (offset == 0 && ISNONZERO_STATE(LOAD_STATE(&ctx.s))) {
+ if (offset == 0 && ISNONZERO_STATE(ctx.s)) {
TESTEOD_REV_FN(limex, &ctx.s, offset, cb, context);
}
union RepeatControl *repeat_ctrl =
getRepeatControlBase(q->state, sizeof(STATE_T));
char *repeat_state = q->streamState + limex->stateSize;
- STATE_T state = LOAD_STATE(q->state);
+ STATE_T state = *(STATE_T *)q->state;
u64a offset = q->offset + q_last_loc(q) + 1;
return JOIN(limexInAccept, SIZE)(limex, state, repeat_ctrl, repeat_state,
union RepeatControl *repeat_ctrl =
getRepeatControlBase(q->state, sizeof(STATE_T));
char *repeat_state = q->streamState + limex->stateSize;
- STATE_T state = LOAD_STATE(q->state);
+ STATE_T state = *(STATE_T *)q->state;
u64a offset = q->offset + q_last_loc(q) + 1;
return JOIN(limexInAnyAccept, SIZE)(limex, state, repeat_ctrl, repeat_state,
s64a loc) {
assert(nfa->flags & NFA_ZOMBIE);
const IMPL_NFA_T *limex = getImplNfa(nfa);
- STATE_T state = LOAD_STATE(q->state);
- STATE_T zmask = LOAD_STATE(&limex->zombieMask);
+ STATE_T state = *(STATE_T *)q->state;
+ STATE_T zmask = LOAD_FROM_ENG(&limex->zombieMask);
if (limex->repeatCount) {
u64a offset = q->offset + loc + 1;
#undef STREAMSILENT_FN
#undef CONTEXT_T
#undef EXCEPTION_T
-#undef LOAD_STATE
-#undef STORE_STATE
#undef AND_STATE
#undef ANDNOT_STATE
#undef OR_STATE
+#undef LSHIFT_STATE
#undef TESTBIT_STATE
#undef CLEARBIT_STATE
#undef ZERO_STATE
#undef ACCEL_MASK
#undef ACCEL_AND_FRIENDS_MASK
#undef EXCEPTION_MASK
-
-// Parameters.
-#undef SIZE
-#undef STATE_T
#undef LIMEX_API_ROOT
#include "limex_runtime.h"
-#define SIZE 128
-#define STATE_T m128
+#define SIZE 128
+#define STATE_T m128
+#define ENG_STATE_T m128
+#define LOAD_FROM_ENG load_m128
+
#include "limex_exceptional.h"
-#define SIZE 128
-#define STATE_T m128
#include "limex_state_impl.h"
-#define SIZE 128
-#define STATE_T m128
#define INLINE_ATTR really_inline
#include "limex_common_impl.h"
-#define SIZE 128
-#define STATE_T m128
#include "limex_runtime_impl.h"
// Common code
#include "limex_runtime.h"
-#define SIZE 256
-#define STATE_T m256
+#define SIZE 256
+#define STATE_T m256
+#define ENG_STATE_T m256
+#define LOAD_FROM_ENG load_m256
+
#include "limex_exceptional.h"
-#define SIZE 256
-#define STATE_T m256
#include "limex_state_impl.h"
-#define SIZE 256
-#define STATE_T m256
#define INLINE_ATTR really_inline
#include "limex_common_impl.h"
-#define SIZE 256
-#define STATE_T m256
#include "limex_runtime_impl.h"
// Common code
#include "limex_runtime.h"
-#define SIZE 384
-#define STATE_T m384
+#define SIZE 384
+#define STATE_T m384
+#define ENG_STATE_T m384
+#define LOAD_FROM_ENG load_m384
+
#include "limex_exceptional.h"
-#define SIZE 384
-#define STATE_T m384
#include "limex_state_impl.h"
-#define SIZE 384
-#define STATE_T m384
#define INLINE_ATTR really_inline
#include "limex_common_impl.h"
-#define SIZE 384
-#define STATE_T m384
#include "limex_runtime_impl.h"
// Common code
#include "limex_runtime.h"
-#define SIZE 512
-#define STATE_T m512
+#define SIZE 512
+#define STATE_T m512
+#define ENG_STATE_T m512
+#define LOAD_FROM_ENG load_m512
+
#include "limex_exceptional.h"
-#define SIZE 512
-#define STATE_T m512
#include "limex_state_impl.h"
-#define SIZE 512
-#define STATE_T m512
#define INLINE_ATTR really_inline
#include "limex_common_impl.h"
-#define SIZE 512
-#define STATE_T m512
#include "limex_runtime_impl.h"
/*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
#include "util/state_compress.h"
#include <string.h>
-#if !defined(SIZE) || !defined(STATE_T)
-# error Must define SIZE and STATE_T in includer.
+#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
+# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
#endif
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
#define REACHMASK_FN JOIN(moNfaReachMask, SIZE)
#define COMPRESS_FN JOIN(moNfaCompressState, SIZE)
#define EXPAND_FN JOIN(moNfaExpandState, SIZE)
-#define COMPRESSED_STORE_FN JOIN(storecompressed, SIZE)
-#define COMPRESSED_LOAD_FN JOIN(loadcompressed, SIZE)
+#define COMPRESSED_STORE_FN JOIN(store_compressed_, STATE_T)
+#define COMPRESSED_LOAD_FN JOIN(load_compressed_, STATE_T)
#define PARTIAL_STORE_FN JOIN(partial_store_, STATE_T)
#define PARTIAL_LOAD_FN JOIN(partial_load_, STATE_T)
-#define LOAD_STATE JOIN(load_, STATE_T)
-#define STORE_STATE JOIN(store_, STATE_T)
#define OR_STATE JOIN(or_, STATE_T)
#define AND_STATE JOIN(and_, STATE_T)
#define ISZERO_STATE JOIN(isZero_, STATE_T)
static really_inline
-const STATE_T *REACHMASK_FN(const IMPL_NFA_T *limex, const u8 key) {
- const STATE_T *reach
- = (const STATE_T *)((const char *)limex + sizeof(*limex));
- assert(ISALIGNED_N(reach, alignof(STATE_T)));
- return &reach[limex->reachMap[key]];
+const ENG_STATE_T *get_reach_table(const IMPL_NFA_T *limex) {
+ const ENG_STATE_T *reach
+ = (const ENG_STATE_T *)((const char *)limex + sizeof(*limex));
+ assert(ISALIGNED_N(reach, alignof(ENG_STATE_T)));
+ return reach;
+}
+
+static really_inline
+STATE_T REACHMASK_FN(const IMPL_NFA_T *limex, const u8 key) {
+ const ENG_STATE_T *reach = get_reach_table(limex);
+ return LOAD_FROM_ENG(&reach[limex->reachMap[key]]);
}
static really_inline
void COMPRESS_FN(const IMPL_NFA_T *limex, u8 *dest, const STATE_T *src,
u8 key) {
assert(ISALIGNED_N(src, alignof(STATE_T)));
- STATE_T a_src = LOAD_STATE(src);
+ STATE_T a_src = *src;
DEBUG_PRINTF("compress state: %p -> %p\n", src, dest);
} else {
DEBUG_PRINTF("compress state, key=%hhx\n", key);
- const STATE_T *reachmask = REACHMASK_FN(limex, key);
+ STATE_T reachmask = REACHMASK_FN(limex, key);
// Masked compression means that we mask off the initDs states and
// provide a shortcut for the all-zeroes case. Note that these must be
// switched on in the EXPAND call below.
if (limex->flags & LIMEX_FLAG_COMPRESS_MASKED) {
- STATE_T s = AND_STATE(LOAD_STATE(&limex->compressMask), a_src);
+ STATE_T s = AND_STATE(LOAD_FROM_ENG(&limex->compressMask), a_src);
if (ISZERO_STATE(s)) {
DEBUG_PRINTF("after compression mask, all states are zero\n");
memset(dest, 0, limex->stateSize);
return;
}
- STATE_T mask = AND_STATE(LOAD_STATE(&limex->compressMask),
- LOAD_STATE(reachmask));
+ STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
+ reachmask);
COMPRESSED_STORE_FN(dest, &s, &mask, limex->stateSize);
} else {
- COMPRESSED_STORE_FN(dest, src, reachmask, limex->stateSize);
+ COMPRESSED_STORE_FN(dest, src, &reachmask, limex->stateSize);
}
}
}
static really_inline
-void EXPAND_FN(const IMPL_NFA_T *limex, STATE_T *dest, const u8 *src,
- u8 key) {
+void EXPAND_FN(const IMPL_NFA_T *limex, STATE_T *dest, const u8 *src, u8 key) {
assert(ISALIGNED_N(dest, alignof(STATE_T)));
DEBUG_PRINTF("expand state: %p -> %p\n", src, dest);
*dest = PARTIAL_LOAD_FN(src, limex->stateSize);
} else {
DEBUG_PRINTF("expand state, key=%hhx\n", key);
- const STATE_T *reachmask = REACHMASK_FN(limex, key);
+ STATE_T reachmask = REACHMASK_FN(limex, key);
if (limex->flags & LIMEX_FLAG_COMPRESS_MASKED) {
- STATE_T mask = AND_STATE(LOAD_STATE(&limex->compressMask),
- LOAD_STATE(reachmask));
+ STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
+ reachmask);
COMPRESSED_LOAD_FN(dest, src, &mask, limex->stateSize);
- STORE_STATE(dest, OR_STATE(LOAD_STATE(&limex->initDS),
- LOAD_STATE(dest)));
+ *dest = OR_STATE(LOAD_FROM_ENG(&limex->initDS), *dest);
} else {
- COMPRESSED_LOAD_FN(dest, src, reachmask, limex->stateSize);
+ COMPRESSED_LOAD_FN(dest, src, &reachmask, limex->stateSize);
}
}
}
#undef COMPRESSED_LOAD_FN
#undef PARTIAL_STORE_FN
#undef PARTIAL_LOAD_FN
-#undef LOAD_STATE
-#undef STORE_STATE
#undef OR_STATE
#undef AND_STATE
#undef ISZERO_STATE
-
-#undef SIZE
-#undef STATE_T
#define DISPATCH_BY_NFA_TYPE(dbnt_func) \
switch (nfa->type) { \
DISPATCH_CASE(LIMEX, LimEx, 32, dbnt_func); \
+ DISPATCH_CASE(LIMEX, LimEx, 64, dbnt_func); \
DISPATCH_CASE(LIMEX, LimEx, 128, dbnt_func); \
DISPATCH_CASE(LIMEX, LimEx, 256, dbnt_func); \
DISPATCH_CASE(LIMEX, LimEx, 384, dbnt_func); \
#define DO_IF_DUMP_SUPPORT(a)
#endif
-#define MAKE_LIMEX_TRAITS(mlt_size) \
+#define MAKE_LIMEX_TRAITS(mlt_size, mlt_align) \
template<> struct NFATraits<LIMEX_NFA_##mlt_size> { \
static UNUSED const char *name; \
static const NFACategory category = NFA_LIMEX; \
typedef LimExNFA##mlt_size implNFA_t; \
- typedef u_##mlt_size tableRow_t; \
static const nfa_dispatch_fn has_accel; \
static const nfa_dispatch_fn has_repeats; \
static const nfa_dispatch_fn has_repeats_other_than_firsts; \
static const u32 stateAlign = \
- MAX(alignof(tableRow_t), alignof(RepeatControl)); \
+ MAX(mlt_align, alignof(RepeatControl)); \
static const bool fast = mlt_size <= 64; \
}; \
const nfa_dispatch_fn NFATraits<LIMEX_NFA_##mlt_size>::has_accel \
const char *NFATraits<LIMEX_NFA_##mlt_size>::name \
= "LimEx "#mlt_size; \
template<> struct getDescription<LIMEX_NFA_##mlt_size> { \
- static string call(const void *ptr) { \
- return getDescriptionLimEx<LIMEX_NFA_##mlt_size>((const NFA *)ptr); \
- } \
+ static string call(const void *p) { \
+ return getDescriptionLimEx<LIMEX_NFA_##mlt_size>((const NFA *)p); \
+ } \
};)
-MAKE_LIMEX_TRAITS(32)
-MAKE_LIMEX_TRAITS(128)
-MAKE_LIMEX_TRAITS(256)
-MAKE_LIMEX_TRAITS(384)
-MAKE_LIMEX_TRAITS(512)
+MAKE_LIMEX_TRAITS(32, alignof(u32))
+MAKE_LIMEX_TRAITS(64, alignof(m128)) /* special, 32bit arch uses m128 */
+MAKE_LIMEX_TRAITS(128, alignof(m128))
+MAKE_LIMEX_TRAITS(256, alignof(m256))
+MAKE_LIMEX_TRAITS(384, alignof(m384))
+MAKE_LIMEX_TRAITS(512, alignof(m512))
template<> struct NFATraits<MCCLELLAN_NFA_8> {
UNUSED static const char *name;
DEBUG_PRINTF("dispatch for NFA type %u\n", nfa->type); \
switch (nfa->type) { \
DISPATCH_CASE(LIMEX, LimEx, 32, dbnt_func); \
+ DISPATCH_CASE(LIMEX, LimEx, 64, dbnt_func); \
DISPATCH_CASE(LIMEX, LimEx, 128, dbnt_func); \
DISPATCH_CASE(LIMEX, LimEx, 256, dbnt_func); \
DISPATCH_CASE(LIMEX, LimEx, 384, dbnt_func); \
enum NFAEngineType {
LIMEX_NFA_32,
+ LIMEX_NFA_64,
LIMEX_NFA_128,
LIMEX_NFA_256,
LIMEX_NFA_384,
static really_inline int isNfaType(u8 t) {
switch (t) {
case LIMEX_NFA_32:
+ case LIMEX_NFA_64:
case LIMEX_NFA_128:
case LIMEX_NFA_256:
case LIMEX_NFA_384:
#endif
}
+/* another form of movq */
+static really_inline
+m128 load_m128_from_u64a(const u64a *p) {
+ return _mm_loadl_epi64((const m128 *)p);
+}
+
#define rshiftbyte_m128(a, count_immed) _mm_srli_si128(a, count_immed)
#define lshiftbyte_m128(a, count_immed) _mm_slli_si128(a, count_immed)
// tests bit N in the given vector.
static really_inline
-char testbit128(const m128 *ptr, unsigned int n) {
+char testbit128(m128 val, unsigned int n) {
const m128 mask = mask1bit128(n);
#if defined(__SSE4_1__)
- return !_mm_testz_si128(mask, *ptr);
+ return !_mm_testz_si128(mask, val);
#else
- return isnonzero128(and128(mask, *ptr));
+ return isnonzero128(and128(mask, val));
#endif
}
// tests bit N in the given vector.
static really_inline
-char testbit256(const m256 *ptr, unsigned int n) {
- assert(n < sizeof(*ptr) * 8);
- const m128 *sub;
+char testbit256(m256 val, unsigned int n) {
+ assert(n < sizeof(val) * 8);
+ m128 sub;
if (n < 128) {
- sub = &ptr->lo;
+ sub = val.lo;
} else {
- sub = &ptr->hi;
+ sub = val.hi;
n -= 128;
}
return testbit128(sub, n);
// tests bit N in the given vector.
static really_inline
-char testbit256(const m256 *ptr, unsigned int n) {
+char testbit256(m256 val, unsigned int n) {
const m256 mask = mask1bit256(n);
- return !_mm256_testz_si256(mask, *ptr);
+ return !_mm256_testz_si256(mask, val);
}
static really_really_inline
// tests bit N in the given vector.
static really_inline
-char testbit384(const m384 *ptr, unsigned int n) {
- assert(n < sizeof(*ptr) * 8);
- const m128 *sub;
+char testbit384(m384 val, unsigned int n) {
+ assert(n < sizeof(val) * 8);
+ m128 sub;
if (n < 128) {
- sub = &ptr->lo;
+ sub = val.lo;
} else if (n < 256) {
- sub = &ptr->mid;
+ sub = val.mid;
} else {
- sub = &ptr->hi;
+ sub = val.hi;
}
return testbit128(sub, n % 128);
}
// tests bit N in the given vector.
static really_inline
-char testbit512(const m512 *ptr, unsigned int n) {
- assert(n < sizeof(*ptr) * 8);
+char testbit512(m512 val, unsigned int n) {
+ assert(n < sizeof(val) * 8);
#if !defined(__AVX2__)
- const m128 *sub;
+ m128 sub;
if (n < 128) {
- sub = &ptr->lo.lo;
+ sub = val.lo.lo;
} else if (n < 256) {
- sub = &ptr->lo.hi;
+ sub = val.lo.hi;
} else if (n < 384) {
- sub = &ptr->hi.lo;
+ sub = val.hi.lo;
} else {
- sub = &ptr->hi.hi;
+ sub = val.hi.hi;
}
return testbit128(sub, n % 128);
#else
- const m256 *sub;
+ m256 sub;
if (n < 256) {
- sub = &ptr->lo;
+ sub = val.lo;
} else {
- sub = &ptr->hi;
+ sub = val.hi;
n -= 256;
}
return testbit256(sub, n);
#define partial_load_m384(ptr, sz) loadbytes384(ptr, sz)
#define partial_load_m512(ptr, sz) loadbytes512(ptr, sz)
-#define store_compressed_u32(ptr, x, m) storecompressed32(ptr, x, m)
-#define store_compressed_u64a(ptr, x, m) storecompressed64(ptr, x, m)
-#define store_compressed_m128(ptr, x, m) storecompressed128(ptr, x, m)
-#define store_compressed_m256(ptr, x, m) storecompressed256(ptr, x, m)
-#define store_compressed_m384(ptr, x, m) storecompressed384(ptr, x, m)
-#define store_compressed_m512(ptr, x, m) storecompressed512(ptr, x, m)
-
-#define load_compressed_u32(x, ptr, m) loadcompressed32(x, ptr, m)
-#define load_compressed_u64a(x, ptr, m) loadcompressed64(x, ptr, m)
-#define load_compressed_m128(x, ptr, m) loadcompressed128(x, ptr, m)
-#define load_compressed_m256(x, ptr, m) loadcompressed256(x, ptr, m)
-#define load_compressed_m384(x, ptr, m) loadcompressed384(x, ptr, m)
-#define load_compressed_m512(x, ptr, m) loadcompressed512(x, ptr, m)
-
-static really_inline void clearbit_u32(u32 *p, u32 n) {
+#define store_compressed_u32(ptr, x, m, len) storecompressed32(ptr, x, m, len)
+#define store_compressed_u64a(ptr, x, m, len) storecompressed64(ptr, x, m, len)
+#define store_compressed_m128(ptr, x, m, len) storecompressed128(ptr, x, m, len)
+#define store_compressed_m256(ptr, x, m, len) storecompressed256(ptr, x, m, len)
+#define store_compressed_m384(ptr, x, m, len) storecompressed384(ptr, x, m, len)
+#define store_compressed_m512(ptr, x, m, len) storecompressed512(ptr, x, m, len)
+
+#define load_compressed_u32(x, ptr, m, len) loadcompressed32(x, ptr, m, len)
+#define load_compressed_u64a(x, ptr, m, len) loadcompressed64(x, ptr, m, len)
+#define load_compressed_m128(x, ptr, m, len) loadcompressed128(x, ptr, m, len)
+#define load_compressed_m256(x, ptr, m, len) loadcompressed256(x, ptr, m, len)
+#define load_compressed_m384(x, ptr, m, len) loadcompressed384(x, ptr, m, len)
+#define load_compressed_m512(x, ptr, m, len) loadcompressed512(x, ptr, m, len)
+
+static really_inline
+void clearbit_u32(u32 *p, u32 n) {
assert(n < sizeof(*p) * 8);
*p &= ~(1U << n);
}
-static really_inline void clearbit_u64a(u64a *p, u32 n) {
+
+static really_inline
+void clearbit_u64a(u64a *p, u32 n) {
assert(n < sizeof(*p) * 8);
*p &= ~(1ULL << n);
}
+
#define clearbit_m128(ptr, n) (clearbit128(ptr, n))
#define clearbit_m256(ptr, n) (clearbit256(ptr, n))
#define clearbit_m384(ptr, n) (clearbit384(ptr, n))
#define clearbit_m512(ptr, n) (clearbit512(ptr, n))
-static really_inline char testbit_u32(const u32 *p, u32 n) {
- assert(n < sizeof(*p) * 8);
- return !!(*p & (1U << n));
+static really_inline
+char testbit_u32(u32 val, u32 n) {
+ assert(n < sizeof(val) * 8);
+ return !!(val & (1U << n));
}
-static really_inline char testbit_u64a(const u64a *p, u32 n) {
- assert(n < sizeof(*p) * 8);
- return !!(*p & (1ULL << n));
+
+static really_inline
+char testbit_u64a(u64a val, u32 n) {
+ assert(n < sizeof(val) * 8);
+ return !!(val & (1ULL << n));
}
-#define testbit_m128(ptr, n) (testbit128(ptr, n))
-#define testbit_m256(ptr, n) (testbit256(ptr, n))
-#define testbit_m384(ptr, n) (testbit384(ptr, n))
-#define testbit_m512(ptr, n) (testbit512(ptr, n))
+
+#define testbit_m128(val, n) (testbit128(val, n))
+#define testbit_m256(val, n) (testbit256(val, n))
+#define testbit_m384(val, n) (testbit384(val, n))
+#define testbit_m512(val, n) (testbit512(val, n))
#endif
#include "grey.h"
#include "compiler/compiler.h"
-#include "nfa/limex_context.h"
#include "nfa/limex_internal.h"
#include "nfa/nfa_api.h"
#include "nfa/nfa_api_util.h"
TEST_P(LimExModelTest, CompressExpand) {
ASSERT_TRUE(nfa != nullptr);
- // 64-bit NFAs assume during compression that they have >= 5 bytes of
- // compressed NFA state, which isn't true for our 8-state test pattern. We
- // skip this test for just these models.
- if (nfa->scratchStateSize == 8) {
- return;
+ u32 real_state_size = nfa->scratchStateSize;
+ /* Only look at 8 bytes for limex 64 (rather than the padding) */
+ if (nfa->type == LIMEX_NFA_64) {
+ real_state_size = sizeof(u64a);
}
initQueue();
memset(dest, 0xff, nfa->scratchStateSize);
nfaExpandState(nfa.get(), dest, q.streamState, q.offset,
queue_prev_byte(&q, end));
- ASSERT_TRUE(std::equal(dest, dest + nfa->scratchStateSize,
- full_state.get()));
+ ASSERT_TRUE(std::equal(dest, dest + real_state_size, full_state.get()));
}
TEST_P(LimExModelTest, InitCompressedState0) {
void simd_setbit(m256 *a, unsigned int i) { return setbit256(a, i); }
void simd_setbit(m384 *a, unsigned int i) { return setbit384(a, i); }
void simd_setbit(m512 *a, unsigned int i) { return setbit512(a, i); }
-bool simd_testbit(const m128 *a, unsigned int i) { return testbit128(a, i); }
-bool simd_testbit(const m256 *a, unsigned int i) { return testbit256(a, i); }
-bool simd_testbit(const m384 *a, unsigned int i) { return testbit384(a, i); }
-bool simd_testbit(const m512 *a, unsigned int i) { return testbit512(a, i); }
+bool simd_testbit(const m128 &a, unsigned int i) { return testbit128(a, i); }
+bool simd_testbit(const m256 &a, unsigned int i) { return testbit256(a, i); }
+bool simd_testbit(const m384 &a, unsigned int i) { return testbit384(a, i); }
+bool simd_testbit(const m512 &a, unsigned int i) { return testbit512(a, i); }
u32 simd_diffrich(const m128 &a, const m128 &b) { return diffrich128(a, b); }
u32 simd_diffrich(const m256 &a, const m256 &b) { return diffrich256(a, b); }
u32 simd_diffrich(const m384 &a, const m384 &b) { return diffrich384(a, b); }
// First, all bits are on in 'ones'.
for (unsigned int i = 0; i < total_bits; i++) {
- ASSERT_EQ(1, simd_testbit(&ones, i)) << "bit " << i << " is on";
+ ASSERT_EQ(1, simd_testbit(ones, i)) << "bit " << i << " is on";
}
// Try individual bits; only 'i' should be on.
for (unsigned int i = 0; i < total_bits; i++) {
TypeParam a = setbit<TypeParam>(i);
for (unsigned int j = 0; j < total_bits; j++) {
- ASSERT_EQ(i == j ? 1 : 0, simd_testbit(&a, j)) << "bit " << i
- << " is wrong";
+ ASSERT_EQ(i == j ? 1 : 0, simd_testbit(a, j)) << "bit " << i
+ << " is wrong";
}
}
}
// and nothing is on in zeroes
for (unsigned int i = 0; i < total_bits; i++) {
- ASSERT_EQ(0, simd_testbit(&zeroes, i)) << "bit " << i << " is off";
+ ASSERT_EQ(0, simd_testbit(zeroes, i)) << "bit " << i << " is off";
}
// All-zeroes and all-ones differ in all words
/*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
TEST(Uniform, testbit_u32) {
for (u32 i = 0; i < 32; i++) {
u32 v = 0;
- EXPECT_EQ((char)0, testbit_u32(&v, i));
+ EXPECT_EQ((char)0, testbit_u32(v, i));
v |= 1ULL << i;
- EXPECT_EQ((char)1, testbit_u32(&v, i));
+ EXPECT_EQ((char)1, testbit_u32(v, i));
v = ~v;
- EXPECT_EQ((char)0, testbit_u32(&v, i));
+ EXPECT_EQ((char)0, testbit_u32(v, i));
v |= 1ULL << i;
- EXPECT_EQ((char)1, testbit_u32(&v, i));
+ EXPECT_EQ((char)1, testbit_u32(v, i));
}
}
TEST(Uniform, testbit_u64a) {
for (u32 i = 0; i < 64; i++) {
u64a v = 0;
- EXPECT_EQ((char)0, testbit_u64a(&v, i));
+ EXPECT_EQ((char)0, testbit_u64a(v, i));
v |= 1ULL << i;
- EXPECT_EQ((char)1, testbit_u64a(&v, i));
+ EXPECT_EQ((char)1, testbit_u64a(v, i));
v = ~v;
- EXPECT_EQ((char)0, testbit_u64a(&v, i));
+ EXPECT_EQ((char)0, testbit_u64a(v, i));
v |= 1ULL << i;
- EXPECT_EQ((char)1, testbit_u64a(&v, i));
+ EXPECT_EQ((char)1, testbit_u64a(v, i));
}
}
for (u32 i = 0; i < 32; i++) {
u32 v = ~0U;
clearbit_u32(&v, i);
- EXPECT_EQ((char)0, testbit_u32(&v, i));
+ EXPECT_EQ((char)0, testbit_u32(v, i));
v = ~v;
clearbit_u32(&v, i);
EXPECT_EQ(0U, v);
for (u32 i = 0; i < 64; i++) {
u64a v = ~0ULL;
clearbit_u64a(&v, i);
- EXPECT_EQ((char)0, testbit_u64a(&v, i));
+ EXPECT_EQ((char)0, testbit_u64a(v, i));
v = ~v;
clearbit_u64a(&v, i);
EXPECT_EQ(0ULL, v);