mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-11-18 10:10:35 +03:00
Initial commit of Hyperscan
This commit is contained in:
131
src/nfa/accel.c
Normal file
131
src/nfa/accel.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "accel.h"
|
||||
#include "shufti.h"
|
||||
#include "truffle.h"
|
||||
#include "vermicelli.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
const u8 *run_accel(const union AccelAux *accel, const u8 *c, const u8 *c_end) {
|
||||
assert(ISALIGNED_N(accel, alignof(union AccelAux)));
|
||||
const u8 *rv;
|
||||
|
||||
switch (accel->accel_type) {
|
||||
case ACCEL_NONE:
|
||||
DEBUG_PRINTF("accel none %p %p\n", c, c_end);
|
||||
return c;
|
||||
|
||||
case ACCEL_VERM:
|
||||
DEBUG_PRINTF("accel verm %p %p\n", c, c_end);
|
||||
if (c + 15 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
rv = vermicelliExec(accel->verm.c, 0, c, c_end);
|
||||
break;
|
||||
|
||||
case ACCEL_VERM_NOCASE:
|
||||
DEBUG_PRINTF("accel verm nc %p %p\n", c, c_end);
|
||||
if (c + 15 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
rv = vermicelliExec(accel->verm.c, 1, c, c_end);
|
||||
break;
|
||||
|
||||
case ACCEL_DVERM:
|
||||
DEBUG_PRINTF("accel dverm %p %p\n", c, c_end);
|
||||
if (c + 16 + 1 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/* need to stop one early to get an accurate end state */
|
||||
rv = vermicelliDoubleExec(accel->dverm.c1, accel->dverm.c2, 0, c,
|
||||
c_end - 1);
|
||||
break;
|
||||
|
||||
case ACCEL_DVERM_NOCASE:
|
||||
DEBUG_PRINTF("accel dverm nc %p %p\n", c, c_end);
|
||||
if (c + 16 + 1 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/* need to stop one early to get an accurate end state */
|
||||
rv = vermicelliDoubleExec(accel->dverm.c1, accel->dverm.c2, 1, c,
|
||||
c_end - 1);
|
||||
break;
|
||||
|
||||
case ACCEL_SHUFTI:
|
||||
DEBUG_PRINTF("accel shufti %p %p\n", c, c_end);
|
||||
if (c + 15 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
rv = shuftiExec(accel->shufti.lo, accel->shufti.hi, c, c_end);
|
||||
break;
|
||||
|
||||
case ACCEL_TRUFFLE:
|
||||
DEBUG_PRINTF("accel Truffle %p %p\n", c, c_end);
|
||||
if (c + 15 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
rv = truffleExec(accel->truffle.mask1, accel->truffle.mask2, c, c_end);
|
||||
break;
|
||||
|
||||
case ACCEL_DSHUFTI:
|
||||
DEBUG_PRINTF("accel dshufti %p %p\n", c, c_end);
|
||||
if (c + 15 + 1 >= c_end) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/* need to stop one early to get an accurate end state */
|
||||
rv = shuftiDoubleExec(accel->dshufti.lo1,
|
||||
accel->dshufti.hi1,
|
||||
accel->dshufti.lo2,
|
||||
accel->dshufti.hi2, c, c_end - 1);
|
||||
break;
|
||||
|
||||
case ACCEL_RED_TAPE:
|
||||
DEBUG_PRINTF("accel red tape %p %p\n", c, c_end);
|
||||
rv = c_end;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"not here");
|
||||
return c;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("adjusting for offset %u\n", accel->generic.offset);
|
||||
/* adjust offset to take into account the offset */
|
||||
rv = MAX(c + accel->generic.offset, rv);
|
||||
rv -= accel->generic.offset;
|
||||
|
||||
return rv;
|
||||
}
|
||||
112
src/nfa/accel.h
Normal file
112
src/nfa/accel.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Acceleration: data structures and common definitions.
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_H
|
||||
#define ACCEL_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
/* run time defs */
|
||||
#define BAD_ACCEL_DIST 4
|
||||
#define SMALL_ACCEL_PENALTY 8
|
||||
#define BIG_ACCEL_PENALTY 32
|
||||
|
||||
/// Minimum length of the scan buffer for us to attempt acceleration.
|
||||
#define ACCEL_MIN_LEN 16
|
||||
|
||||
enum AccelType {
|
||||
ACCEL_NONE,
|
||||
ACCEL_VERM,
|
||||
ACCEL_VERM_NOCASE,
|
||||
ACCEL_DVERM,
|
||||
ACCEL_DVERM_NOCASE,
|
||||
ACCEL_RVERM,
|
||||
ACCEL_RVERM_NOCASE,
|
||||
ACCEL_RDVERM,
|
||||
ACCEL_RDVERM_NOCASE,
|
||||
ACCEL_REOD,
|
||||
ACCEL_REOD_NOCASE,
|
||||
ACCEL_RDEOD,
|
||||
ACCEL_RDEOD_NOCASE,
|
||||
ACCEL_SHUFTI,
|
||||
ACCEL_DSHUFTI,
|
||||
ACCEL_TRUFFLE,
|
||||
ACCEL_RED_TAPE
|
||||
};
|
||||
|
||||
/** \brief Structure for accel framework. */
|
||||
union AccelAux {
|
||||
u8 accel_type;
|
||||
struct {
|
||||
u8 accel_type;
|
||||
u8 offset;
|
||||
} generic;
|
||||
struct {
|
||||
u8 accel_type;
|
||||
u8 offset;
|
||||
u8 c; // uppercase if nocase
|
||||
} verm;
|
||||
struct {
|
||||
u8 accel_type;
|
||||
u8 offset;
|
||||
u8 c1; // uppercase if nocase
|
||||
u8 c2; // uppercase if nocase
|
||||
} dverm;
|
||||
struct {
|
||||
u8 accel_type;
|
||||
u8 offset;
|
||||
m128 lo;
|
||||
m128 hi;
|
||||
} shufti;
|
||||
struct {
|
||||
u8 accel_type;
|
||||
u8 offset;
|
||||
m128 lo1;
|
||||
m128 hi1;
|
||||
m128 lo2;
|
||||
m128 hi2;
|
||||
} dshufti;
|
||||
struct {
|
||||
u8 accel_type;
|
||||
u8 offset;
|
||||
m128 mask1;
|
||||
m128 mask2;
|
||||
} truffle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs the specified acceleration scheme between c and c_end, returns a point
|
||||
* such that the acceleration scheme does not match before.
|
||||
*/
|
||||
const u8 *run_accel(const union AccelAux *accel, const u8 *c, const u8 *c_end);
|
||||
|
||||
#endif
|
||||
152
src/nfa/accel_dump.cpp
Normal file
152
src/nfa/accel_dump.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Acceleration: dump code.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "accel.h"
|
||||
#include "accel_dump.h"
|
||||
#include "shufticompile.h"
|
||||
#include "trufflecompile.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/dump_charclass.h"
|
||||
#include "util/dump_mask.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
static
|
||||
const char *accelName(u8 accel_type) {
|
||||
switch (accel_type) {
|
||||
case ACCEL_NONE:
|
||||
return "none";
|
||||
case ACCEL_VERM:
|
||||
return "vermicelli";
|
||||
case ACCEL_VERM_NOCASE:
|
||||
return "vermicelli nocase";
|
||||
case ACCEL_DVERM:
|
||||
return "double-vermicelli";
|
||||
case ACCEL_DVERM_NOCASE:
|
||||
return "double-vermicelli nocase";
|
||||
case ACCEL_RVERM:
|
||||
return "reverse vermicelli";
|
||||
case ACCEL_RVERM_NOCASE:
|
||||
return "reverse vermicelli nocase";
|
||||
case ACCEL_RDVERM:
|
||||
return "reverse double-vermicelli";
|
||||
case ACCEL_RDVERM_NOCASE:
|
||||
return "reverse double-vermicelli nocase";
|
||||
case ACCEL_REOD:
|
||||
return "reverse eod";
|
||||
case ACCEL_REOD_NOCASE:
|
||||
return "reverse eod nocase";
|
||||
case ACCEL_RDEOD:
|
||||
return "reverse double-eod";
|
||||
case ACCEL_RDEOD_NOCASE:
|
||||
return "reverse double-eod nocase";
|
||||
case ACCEL_SHUFTI:
|
||||
return "shufti";
|
||||
case ACCEL_DSHUFTI:
|
||||
return "double-shufti";
|
||||
case ACCEL_TRUFFLE:
|
||||
return "truffle";
|
||||
case ACCEL_RED_TAPE:
|
||||
return "red tape";
|
||||
default:
|
||||
return "unknown!";
|
||||
}
|
||||
}
|
||||
|
||||
void dumpAccelInfo(FILE *f, const AccelAux &accel) {
|
||||
fprintf(f, " %s", accelName(accel.accel_type));
|
||||
if (accel.generic.offset) {
|
||||
fprintf(f, "+%hhu", accel.generic.offset);
|
||||
}
|
||||
|
||||
switch (accel.accel_type) {
|
||||
case ACCEL_VERM:
|
||||
case ACCEL_VERM_NOCASE:
|
||||
case ACCEL_RVERM:
|
||||
case ACCEL_RVERM_NOCASE:
|
||||
fprintf(f, " [\\x%02hhx]\n", accel.verm.c);
|
||||
break;
|
||||
case ACCEL_DVERM:
|
||||
case ACCEL_DVERM_NOCASE:
|
||||
case ACCEL_RDVERM:
|
||||
case ACCEL_RDVERM_NOCASE:
|
||||
fprintf(f, " [\\x%02hhx\\x%02hhx]\n", accel.dverm.c1, accel.dverm.c2);
|
||||
break;
|
||||
case ACCEL_SHUFTI: {
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "lo %s\n",
|
||||
dumpMask((const u8 *)&accel.shufti.lo, 128).c_str());
|
||||
fprintf(f, "hi %s\n",
|
||||
dumpMask((const u8 *)&accel.shufti.hi, 128).c_str());
|
||||
CharReach cr = shufti2cr(accel.shufti.lo, accel.shufti.hi);
|
||||
fprintf(f, "count %zu class %s\n", cr.count(),
|
||||
describeClass(cr).c_str());
|
||||
break;
|
||||
}
|
||||
case ACCEL_DSHUFTI:
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "lo1 %s\n",
|
||||
dumpMask((const u8 *)&accel.dshufti.lo1, 128).c_str());
|
||||
fprintf(f, "hi1 %s\n",
|
||||
dumpMask((const u8 *)&accel.dshufti.hi1, 128).c_str());
|
||||
fprintf(f, "lo2 %s\n",
|
||||
dumpMask((const u8 *)&accel.dshufti.lo2, 128).c_str());
|
||||
fprintf(f, "hi2 %s\n",
|
||||
dumpMask((const u8 *)&accel.dshufti.hi2, 128).c_str());
|
||||
break;
|
||||
case ACCEL_TRUFFLE: {
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "lo %s\n",
|
||||
dumpMask((const u8 *)&accel.truffle.mask1, 128).c_str());
|
||||
fprintf(f, "hi %s\n",
|
||||
dumpMask((const u8 *)&accel.truffle.mask2, 128).c_str());
|
||||
CharReach cr = truffle2cr(accel.truffle.mask1, accel.truffle.mask2);
|
||||
fprintf(f, "count %zu class %s\n", cr.count(),
|
||||
describeClass(cr).c_str());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
49
src/nfa/accel_dump.h
Normal file
49
src/nfa/accel_dump.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Acceleration: dump code.
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_DUMP_H
|
||||
#define ACCEL_DUMP_H
|
||||
|
||||
#if defined(DUMP_SUPPORT)
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
union AccelAux;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void dumpAccelInfo(FILE *f, const AccelAux &accel);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
#endif // ACCEL_DUMP_H
|
||||
191
src/nfa/accelcompile.cpp
Normal file
191
src/nfa/accelcompile.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "accel.h"
|
||||
#include "accelcompile.h"
|
||||
#include "shufticompile.h"
|
||||
#include "trufflecompile.h"
|
||||
#include "nfagraph/ng_limex_accel.h" /* for constants */
|
||||
#include "util/bitutils.h"
|
||||
#include "util/verify_types.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
static
|
||||
void buildAccelSingle(const AccelInfo &info, AccelAux *aux) {
|
||||
assert(aux->accel_type == ACCEL_NONE);
|
||||
if (info.single_stops.all()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t outs = info.single_stops.count();
|
||||
DEBUG_PRINTF("%zu outs\n", outs);
|
||||
assert(outs && outs < 256);
|
||||
u32 offset = info.single_offset;
|
||||
|
||||
if (outs == 1) {
|
||||
aux->accel_type = ACCEL_VERM;
|
||||
aux->verm.offset = offset;
|
||||
aux->verm.c = info.single_stops.find_first();
|
||||
DEBUG_PRINTF("building vermicelli caseful for 0x%02hhx\n", aux->verm.c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (outs == 2 && info.single_stops.isCaselessChar()) {
|
||||
aux->accel_type = ACCEL_VERM_NOCASE;
|
||||
aux->verm.offset = offset;
|
||||
aux->verm.c = info.single_stops.find_first() & CASE_CLEAR;
|
||||
DEBUG_PRINTF("building vermicelli caseless for 0x%02hhx\n",
|
||||
aux->verm.c);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("attempting shufti for %zu chars\n", outs);
|
||||
if (-1 != shuftiBuildMasks(info.single_stops, &aux->shufti.lo,
|
||||
&aux->shufti.hi)) {
|
||||
aux->accel_type = ACCEL_SHUFTI;
|
||||
aux->shufti.offset = offset;
|
||||
DEBUG_PRINTF("shufti built OK\n");
|
||||
return;
|
||||
} else {
|
||||
DEBUG_PRINTF("shufti build failed, falling through\n");
|
||||
}
|
||||
|
||||
if (outs <= ACCEL_MAX_STOP_CHAR) {
|
||||
DEBUG_PRINTF("building Truffle for %zu chars\n", outs);
|
||||
aux->accel_type = ACCEL_TRUFFLE;
|
||||
aux->truffle.offset = offset;
|
||||
truffleBuildMasks(info.single_stops, &aux->truffle.mask1,
|
||||
&aux->truffle.mask2);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("unable to accelerate case with %zu outs\n", outs);
|
||||
}
|
||||
|
||||
static
|
||||
bool isCaselessDouble(const flat_set<pair<u8, u8>> &stop) {
|
||||
// test for vector containing <A,Z> <A,z> <a,Z> <a,z>
|
||||
if (stop.size() != 4) {
|
||||
return false;
|
||||
}
|
||||
const u8 a = stop.begin()->first & CASE_CLEAR;
|
||||
const u8 b = stop.begin()->second & CASE_CLEAR;
|
||||
|
||||
flat_set<pair<u8, u8>>::const_iterator it, ite;
|
||||
for (it = stop.begin(), ite = stop.end(); it != ite; ++it) {
|
||||
if ((it->first & CASE_CLEAR) != a || (it->second & CASE_CLEAR) != b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
void buildAccelDouble(const AccelInfo &info, AccelAux *aux) {
|
||||
size_t outs1 = info.double_stop1.count();
|
||||
size_t outs2 = info.double_stop2.size();
|
||||
|
||||
u8 offset = verify_u8(info.double_offset);
|
||||
DEBUG_PRINTF("outs1=%zu, outs2=%zu\n", outs1, outs2);
|
||||
|
||||
assert(aux->accel_type == ACCEL_NONE);
|
||||
|
||||
if (!outs2) {
|
||||
/* no double byte accel available */
|
||||
return;
|
||||
}
|
||||
|
||||
// double-byte accel
|
||||
if (outs1 == 0 && outs2 == 1) {
|
||||
aux->accel_type = ACCEL_DVERM;
|
||||
aux->dverm.offset = offset;
|
||||
aux->dverm.c1 = info.double_stop2.begin()->first;
|
||||
aux->dverm.c2 = info.double_stop2.begin()->second;
|
||||
DEBUG_PRINTF("building double-vermicelli caseful for 0x%02hhx%02hhx\n",
|
||||
aux->dverm.c1, aux->dverm.c2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (outs1 == 0 && isCaselessDouble(info.double_stop2)) {
|
||||
aux->accel_type = ACCEL_DVERM_NOCASE;
|
||||
aux->dverm.offset = offset;
|
||||
aux->dverm.c1 = info.double_stop2.begin()->first & CASE_CLEAR;
|
||||
aux->dverm.c2 = info.double_stop2.begin()->second & CASE_CLEAR;
|
||||
DEBUG_PRINTF("building double-vermicelli caseless for 0x%02hhx%02hhx\n",
|
||||
aux->dverm.c1, aux->dverm.c2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (outs1 + outs2 <= 8) {
|
||||
if (outs1 < outs2 && outs1 <= 2) { // Heuristic from UE-438.
|
||||
DEBUG_PRINTF("building double-shufti for %zu one-byte and %zu"
|
||||
" two-byte literals\n", outs1, outs2);
|
||||
aux->accel_type = ACCEL_DSHUFTI;
|
||||
aux->dshufti.offset = offset;
|
||||
shuftiBuildDoubleMasks(info.double_stop1, info.double_stop2,
|
||||
&aux->dshufti.lo1,
|
||||
&aux->dshufti.hi1,
|
||||
&aux->dshufti.lo2,
|
||||
&aux->dshufti.hi2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// drop back to attempt single-byte accel
|
||||
DEBUG_PRINTF("dropping back to single-byte acceleration\n");
|
||||
aux->accel_type = ACCEL_NONE;
|
||||
}
|
||||
|
||||
bool buildAccelAux(const AccelInfo &info, AccelAux *aux) {
|
||||
assert(aux->accel_type == ACCEL_NONE);
|
||||
if (info.single_stops.none()) {
|
||||
DEBUG_PRINTF("picked red tape\n");
|
||||
aux->accel_type = ACCEL_RED_TAPE;
|
||||
aux->generic.offset = info.single_offset;
|
||||
} else {
|
||||
buildAccelDouble(info, aux);
|
||||
}
|
||||
if (aux->accel_type == ACCEL_NONE) {
|
||||
buildAccelSingle(info, aux);
|
||||
}
|
||||
|
||||
assert(aux->accel_type == ACCEL_NONE
|
||||
|| aux->generic.offset == info.single_offset
|
||||
|| aux->generic.offset == info.double_offset);
|
||||
return aux->accel_type != ACCEL_NONE;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
56
src/nfa/accelcompile.h
Normal file
56
src/nfa/accelcompile.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_COMPILE_H
|
||||
#define ACCEL_COMPILE_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
union AccelAux;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct AccelInfo {
|
||||
AccelInfo() : single_offset(0U), double_offset(0U),
|
||||
single_stops(CharReach::dot()) {}
|
||||
u32 single_offset; /**< offset correction to apply to single schemes */
|
||||
u32 double_offset; /**< offset correction to apply to double schemes */
|
||||
CharReach double_stop1; /**< single-byte accel stop literals for double
|
||||
* schemes */
|
||||
flat_set<std::pair<u8, u8>> double_stop2; /**< double-byte accel stop
|
||||
* literals */
|
||||
CharReach single_stops; /**< escapes for single byte acceleration */
|
||||
};
|
||||
|
||||
bool buildAccelAux(const AccelInfo &info, AccelAux *aux);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
76
src/nfa/callback.h
Normal file
76
src/nfa/callback.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 NFA Callback definitions, used at runtime.
|
||||
*/
|
||||
|
||||
#ifndef NFA_CALLBACK_H
|
||||
#define NFA_CALLBACK_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
/** \brief The type for an NFA callback.
|
||||
*
|
||||
* This is a function that takes as arguments the current offset where the
|
||||
* match occurs, the id of the match and the context pointer that was passed
|
||||
* into the NFA API function that executed the NFA.
|
||||
*
|
||||
* The offset where the match occurs will be the offset after the character
|
||||
* that caused the match. Thus, if we have a buffer containing 'abc', then a
|
||||
* pattern that matches an empty string will have an offset of 0, a pattern
|
||||
* that matches 'a' will have an offset of 1, and a pattern that matches 'abc'
|
||||
* will have an offset of 3, which will be a value that is 'beyond' the size of
|
||||
* the buffer. That is, if we have n characters in the buffer, there are n+1
|
||||
* different potential offsets for matches.
|
||||
*
|
||||
* This function should return an int - currently the possible return values
|
||||
* are 0, which means 'stop running the engine' or non-zero, which means
|
||||
* 'continue matching'.
|
||||
*/
|
||||
typedef int (*NfaCallback)(u64a offset, ReportID id, void *context);
|
||||
|
||||
/** \brief The type for an NFA callback which also tracks start of match.
|
||||
*
|
||||
* see \ref NfaCallback
|
||||
*/
|
||||
typedef int (*SomNfaCallback)(u64a from_offset, u64a to_offset, ReportID id,
|
||||
void *context);
|
||||
|
||||
/**
|
||||
* standard \ref NfaCallback return value indicating that engine execution
|
||||
* should continue. (any non-zero value will serve this purpose)
|
||||
*/
|
||||
#define MO_CONTINUE_MATCHING 1
|
||||
|
||||
/**
|
||||
* \ref NfaCallback return value indicating that engine execution should halt.
|
||||
*/
|
||||
#define MO_HALT_MATCHING 0
|
||||
|
||||
#endif // NFA_CALLBACK_H
|
||||
1016
src/nfa/castle.c
Normal file
1016
src/nfa/castle.c
Normal file
File diff suppressed because it is too large
Load Diff
64
src/nfa/castle.h
Normal file
64
src/nfa/castle.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef NFA_CASTLE_H
|
||||
#define NFA_CASTLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
struct mq;
|
||||
struct NFA;
|
||||
|
||||
char nfaExecCastle0_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecCastle0_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecCastle0_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecCastle0_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecCastle0_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecCastle0_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecCastle0_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecCastle0_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecCastle0_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecCastle0_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecCastle0_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecCastle0_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif
|
||||
116
src/nfa/castle_dump.cpp
Normal file
116
src/nfa/castle_dump.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Castle: multi-tenant repeat engine, dump code.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "castle_dump.h"
|
||||
|
||||
#include "castle_internal.h"
|
||||
#include "nfa_dump_internal.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "shufticompile.h"
|
||||
#include "trufflecompile.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/dump_charclass.h"
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecCastle0_dumpDot(const struct NFA *, FILE *) {
|
||||
// No GraphViz output for Castles.
|
||||
}
|
||||
|
||||
static
|
||||
void dumpTextSubCastle(const SubCastle &sub, FILE *f) {
|
||||
const RepeatInfo *info =
|
||||
(const RepeatInfo *)((const char *)&sub + sub.repeatInfoOffset);
|
||||
fprintf(f, " repeat model: %s\n", repeatTypeName(info->type));
|
||||
fprintf(f, " repeat bounds: {%u, %u}\n", info->repeatMin,
|
||||
info->repeatMax);
|
||||
fprintf(f, " min period: %u\n", info->minPeriod);
|
||||
|
||||
fprintf(f, " report: %u\n", sub.report);
|
||||
fprintf(f, " full state offset: %u\n", sub.fullStateOffset);
|
||||
fprintf(f, " stream state offset: %u\n", sub.streamStateOffset);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
void nfaExecCastle0_dumpText(const struct NFA *nfa, FILE *f) {
|
||||
const Castle *c = (const Castle *)getImplNfa(nfa);
|
||||
|
||||
fprintf(f, "Castle multi-tenant repeat engine\n");
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "Number of repeat tenants: %u\n", c->numRepeats);
|
||||
fprintf(f, "Scan type: ");
|
||||
switch (c->type) {
|
||||
case CASTLE_DOT:
|
||||
fprintf(f, "dot\n");
|
||||
break;
|
||||
case CASTLE_VERM:
|
||||
fprintf(f, "verm, scanning for 0x%02x\n", c->u.verm.c);
|
||||
break;
|
||||
case CASTLE_NVERM:
|
||||
fprintf(f, "negated verm, scanning for 0x%02x\n", c->u.verm.c);
|
||||
break;
|
||||
case CASTLE_SHUFTI: {
|
||||
const CharReach cr = shufti2cr(c->u.shuf.mask_lo, c->u.shuf.mask_hi);
|
||||
fprintf(f, "shufti, scanning for %s (%zu chars)\n",
|
||||
describeClass(cr).c_str(), cr.count());
|
||||
break;
|
||||
}
|
||||
case CASTLE_TRUFFLE: {
|
||||
const CharReach cr = truffle2cr(c->u.truffle.mask1, c->u.truffle.mask2);
|
||||
fprintf(f, "truffle, scanning for %s (%zu chars)\n",
|
||||
describeClass(cr).c_str(), cr.count());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(f, "unknown type %u\n", c->type);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
fprintf(f, "\n");
|
||||
|
||||
const SubCastle *sub =
|
||||
(const SubCastle *)((const char *)c + sizeof(Castle));
|
||||
for (u32 i = 0; i < c->numRepeats; i++) {
|
||||
fprintf(f, "Sub %u:\n", i);
|
||||
dumpTextSubCastle(sub[i], f);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
47
src/nfa/castle_dump.h
Normal file
47
src/nfa/castle_dump.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef CASTLE_DUMP_H
|
||||
#define CASTLE_DUMP_H
|
||||
|
||||
#if defined(DUMP_SUPPORT)
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecCastle0_dumpDot(const NFA *nfa, FILE *file);
|
||||
void nfaExecCastle0_dumpText(const NFA *nfa, FILE *file);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
|
||||
#endif
|
||||
101
src/nfa/castle_internal.h
Normal file
101
src/nfa/castle_internal.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Castle: multi-tenant repeat engine, data structures.
|
||||
*/
|
||||
|
||||
#ifndef NFA_CASTLE_INTERNAL_H
|
||||
#define NFA_CASTLE_INTERNAL_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "repeat_internal.h"
|
||||
|
||||
struct SubCastle {
|
||||
ReportID report; //!< report to raise on match
|
||||
u32 fullStateOffset; //!< offset within full state (scratch)
|
||||
u32 streamStateOffset; //!< offset within stream state
|
||||
u32 repeatInfoOffset; //!< offset of RepeatInfo structure
|
||||
// relative to the start of SubCastle
|
||||
char exclusive; //!< exclusive info of this SubCastle
|
||||
};
|
||||
|
||||
#define CASTLE_DOT 0
|
||||
#define CASTLE_VERM 1
|
||||
#define CASTLE_NVERM 2
|
||||
#define CASTLE_SHUFTI 3
|
||||
#define CASTLE_TRUFFLE 4
|
||||
|
||||
/**
|
||||
* \brief Castle engine structure.
|
||||
*
|
||||
* A Castle is a collection of repeats that all share the same character
|
||||
* reachability.
|
||||
*
|
||||
* The whole engine is laid out in memory as:
|
||||
*
|
||||
* - struct NFA
|
||||
* - struct Castle
|
||||
* - struct SubCastle[numRepeats]
|
||||
* - tables for sparse model repeats
|
||||
*
|
||||
* Castle stores an "active repeats" multibit in stream state, followed by the
|
||||
* packed repeat state for each SubCastle. If all SubCastles are mutual
|
||||
* exclusive, we store current active SubCastle id instead of "active repeats"
|
||||
* multibit in stream state. If there are both exclusive and non-exclusive
|
||||
* SubCastle groups, we use an active id for the exclusive group and a multibit
|
||||
* for the non-exclusive group.
|
||||
*
|
||||
* In full state (stored in scratch space) it stores a temporary multibit over
|
||||
* the repeats (used by \ref castleMatchLoop), followed by the repeat control
|
||||
* blocks for each SubCastle. If all SubCastles are mutual exclusive, we only
|
||||
* need to store the repeat control blocks for each SubCastle.
|
||||
*/
|
||||
struct ALIGN_AVX_DIRECTIVE Castle {
|
||||
u32 numRepeats;
|
||||
u8 type; //!< tells us which scanning mechanism (below) to use
|
||||
char exclusive; //!< tells us if there are mutual exclusive SubCastles
|
||||
char pureExclusive; //!< tells us if all SubCastles are mutual exclusive
|
||||
u8 activeIdxSize; //!< number of bytes in stream state to store
|
||||
// active SubCastle id for exclusive mode
|
||||
union {
|
||||
struct {
|
||||
char c;
|
||||
} verm;
|
||||
struct {
|
||||
m128 mask_lo;
|
||||
m128 mask_hi;
|
||||
} shuf;
|
||||
struct {
|
||||
m128 mask1;
|
||||
m128 mask2;
|
||||
} truffle;
|
||||
} u;
|
||||
};
|
||||
|
||||
#endif // NFA_CASTLE_INTERNAL_H
|
||||
1029
src/nfa/castlecompile.cpp
Normal file
1029
src/nfa/castlecompile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
src/nfa/castlecompile.h
Normal file
146
src/nfa/castlecompile.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Castle: multi-tenant repeat engine, compiler code.
|
||||
*/
|
||||
|
||||
#ifndef NFA_CASTLECOMPILE_H
|
||||
#define NFA_CASTLECOMPILE_H
|
||||
|
||||
#include "nfa_kind.h"
|
||||
#include "ue2common.h"
|
||||
#include "nfagraph/ng_repeat.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/depth.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
class CharReach;
|
||||
class NGHolder;
|
||||
struct CompileContext;
|
||||
|
||||
/**
|
||||
* \brief Prototype for a Castle engine: contains at least one CastleRepeat.
|
||||
*
|
||||
* Currently, all repeats in a Castle must have the same character
|
||||
* reachability.
|
||||
*
|
||||
* A CastleProto is converted into a single NFA, with each top triggering a
|
||||
* unique repeat. A CastleProto can contain at most CastleProto::max_occupancy
|
||||
* elements.
|
||||
*/
|
||||
struct CastleProto {
|
||||
static constexpr size_t max_occupancy = 65536; // arbitrary limit
|
||||
explicit CastleProto(const PureRepeat &pr);
|
||||
const CharReach &reach() const;
|
||||
|
||||
u32 add(const PureRepeat &pr);
|
||||
|
||||
/**
|
||||
* \brief Merge in the given repeat, returning the top used.
|
||||
*
|
||||
* If the repeat already exists in this castle, we will re-use (and return)
|
||||
* the old top. If it doesn't, it will be added and assigned a new top.
|
||||
* Returns \ref max_occupancy if capacity would be exceeded.
|
||||
*/
|
||||
u32 merge(const PureRepeat &pr);
|
||||
|
||||
/** \brief Mapping from unique top id to repeat. */
|
||||
std::map<u32, PureRepeat> repeats;
|
||||
};
|
||||
|
||||
std::set<ReportID> all_reports(const CastleProto &proto);
|
||||
depth findMinWidth(const CastleProto &proto);
|
||||
depth findMaxWidth(const CastleProto &proto);
|
||||
|
||||
/**
|
||||
* \brief Remap tops to be contiguous.
|
||||
*
|
||||
* Remap the tops in the given CastleProto so that they're contiguous in the
|
||||
* range [0 .. N-1].
|
||||
*/
|
||||
void remapCastleTops(CastleProto &proto, std::map<u32, u32> &top_map);
|
||||
|
||||
/**
|
||||
* \brief Construct an NFA from a CastleProto.
|
||||
*
|
||||
* NOTE: Tops must be contiguous, i.e. \ref remapCastleTops must have been run
|
||||
* first.
|
||||
*/
|
||||
ue2::aligned_unique_ptr<NFA>
|
||||
buildCastle(const CastleProto &proto,
|
||||
const std::map<u32, std::vector<std::vector<CharReach>>> &triggers,
|
||||
const CompileContext &cc);
|
||||
|
||||
/**
|
||||
* \brief Merge two CastleProto prototypes together, if possible.
|
||||
*
|
||||
* Returns true if merge of all repeats in c2 into c1 succeeds, and fills
|
||||
* mapping with the repeat indices.
|
||||
*/
|
||||
bool mergeCastle(CastleProto &c1, const CastleProto &c2,
|
||||
std::map<u32, u32> &top_map);
|
||||
|
||||
/**
|
||||
* \brief True if the two castles are identical with respect to the reports
|
||||
* given; i.e. the same tops lead to the same repeats, just with report1 in c1
|
||||
* and report2 in c2.
|
||||
*
|
||||
* Repeats leading to other reports are ignored.
|
||||
*/
|
||||
bool is_equal(const CastleProto &c1, ReportID report1, const CastleProto &c2,
|
||||
ReportID report2);
|
||||
|
||||
/**
|
||||
* \brief True if the two castles given are identical.
|
||||
*/
|
||||
bool is_equal(const CastleProto &c1, const CastleProto &c2);
|
||||
|
||||
/**
|
||||
* \brief True if the given castle contains more than a single instance of any
|
||||
* of the reports in the given set.
|
||||
*/
|
||||
bool requiresDedupe(const CastleProto &proto, const std::set<ReportID> &reports);
|
||||
|
||||
/**
|
||||
* \brief Build an NGHolder from a CastleProto.
|
||||
*/
|
||||
std::unique_ptr<NGHolder> makeHolder(const CastleProto &castle, nfa_kind kind,
|
||||
const CompileContext &cc);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // NFA_CASTLECOMPILE_H
|
||||
351
src/nfa/dfa_min.cpp
Normal file
351
src/nfa/dfa_min.cpp
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Build code for DFA minimization
|
||||
*/
|
||||
|
||||
/**
|
||||
* /Summary of the Hopcrofts algorithm/
|
||||
* partition := {F, Q \ F};
|
||||
* work_queue := {F};
|
||||
* while (work_queue is not empty) do
|
||||
* choose and remove a set A from work_queue
|
||||
* for each c in . do
|
||||
* let X be the set of states for which a transition on c
|
||||
* leads to a state in A
|
||||
* for each set Y in partition for which X . Y is nonempty and
|
||||
* Y \ X is nonempty do
|
||||
* replace Y in partition by the two sets X . Y and Y \ X
|
||||
* if Y is in work_queue
|
||||
* replace Y in work_queue by the same two sets
|
||||
* else
|
||||
* if |X . Y| <= |Y \ X|
|
||||
* add X . Y to work_queue
|
||||
* else
|
||||
* add Y \ X to work_queue
|
||||
* end;
|
||||
* end;
|
||||
* end;
|
||||
*/
|
||||
|
||||
#include "dfa_min.h"
|
||||
|
||||
#include "grey.h"
|
||||
#include "nfa/rdfa.h"
|
||||
#include "nfagraph/ng_mcclellan.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/partitioned_set.h"
|
||||
#include "util/container.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
namespace {
|
||||
|
||||
struct hopcroft_state_info {
|
||||
vector<vector<dstate_id_t> > prev;
|
||||
};
|
||||
|
||||
struct DFA_components : boost::noncopyable {
|
||||
dstate_id_t nstates;
|
||||
size_t inp_size;
|
||||
set<size_t> work_queue;
|
||||
/*Partition contains reduced states*/
|
||||
partitioned_set<dstate_id_t> partition;
|
||||
vector<hopcroft_state_info> states;
|
||||
|
||||
explicit DFA_components(const raw_dfa &rdfa);
|
||||
};
|
||||
|
||||
} //namespace
|
||||
|
||||
/**
|
||||
* create_map:
|
||||
* Creates an initial partitioning and work_queue.
|
||||
* Initial partition contains {accepting states..., Non-accepting states}
|
||||
* Initial work_queue contains accepting state subsets
|
||||
*
|
||||
* The initial partitioning needs to distinguish between the different
|
||||
* reporting behaviours (unlike standard hopcroft) --> more than one subset
|
||||
* possible for the accepting states.
|
||||
*
|
||||
* Look for accepting states in both reports and reports_eod.
|
||||
* Creates a map with a key(reports, reports_eod) and an id.
|
||||
* Reports of each state are searched against the map and
|
||||
* added to the corresponding id -> partition[id] and work_queue[id].
|
||||
* Non Accept states are added to partition[id+1].
|
||||
*/
|
||||
static
|
||||
vector<size_t> create_map(const raw_dfa &rdfa, set<size_t> &work_queue) {
|
||||
using ReportKey = pair<flat_set<ReportID>, flat_set<ReportID>>;
|
||||
map<ReportKey, size_t> subset_map;
|
||||
vector<size_t> state_to_subset(rdfa.states.size(), INVALID_SUBSET);
|
||||
|
||||
for (size_t i = 0; i < rdfa.states.size(); i++) {
|
||||
if (!rdfa.states[i].reports.empty() ||
|
||||
!rdfa.states[i].reports_eod.empty()) {
|
||||
ReportKey key(rdfa.states[i].reports, rdfa.states[i].reports_eod);
|
||||
if (contains(subset_map, key)) {
|
||||
state_to_subset[i] = subset_map[key];
|
||||
} else {
|
||||
size_t sub = subset_map.size();
|
||||
subset_map[key] = sub;
|
||||
state_to_subset[i] = sub;
|
||||
work_queue.insert(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* handle non accepts */
|
||||
size_t non_accept_sub = subset_map.size();
|
||||
for (size_t i = 0; i < state_to_subset.size(); i++) {
|
||||
if (state_to_subset[i] == INVALID_SUBSET) {
|
||||
state_to_subset[i] = non_accept_sub;
|
||||
}
|
||||
}
|
||||
|
||||
return state_to_subset;
|
||||
}
|
||||
|
||||
DFA_components::DFA_components(const raw_dfa &rdfa)
|
||||
: nstates(rdfa.states.size()),
|
||||
inp_size(rdfa.states[nstates - 1].next.size()),
|
||||
partition(create_map(rdfa, work_queue)) {
|
||||
/* initializing states */
|
||||
for (size_t i = 0; i < nstates; i++) {
|
||||
states.push_back(hopcroft_state_info());
|
||||
states.back().prev.resize(inp_size);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nstates; i++) { // i is the previous state
|
||||
for (size_t j = 0; j < inp_size; j++) {
|
||||
/* Creating X_table */
|
||||
dstate_id_t present_state = rdfa.states[i].next[j];
|
||||
states[present_state].prev[j].push_back(i);
|
||||
|
||||
DEBUG_PRINTF("rdfa.states[%zu].next[%zu] %hu \n", i, j,
|
||||
rdfa.states[i].next[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* choose and remove a set A from work_queue.
|
||||
*/
|
||||
static
|
||||
void get_work_item(DFA_components &mdfa, ue2::flat_set<dstate_id_t> &A) {
|
||||
A.clear();
|
||||
assert(!mdfa.work_queue.empty());
|
||||
set<size_t>::iterator pt = mdfa.work_queue.begin();
|
||||
insert(&A, mdfa.partition[*pt]);
|
||||
mdfa.work_queue.erase(pt);
|
||||
}
|
||||
|
||||
/**
|
||||
* X is the set of states for which a transition on the input leads to a state
|
||||
* in A.
|
||||
*/
|
||||
static
|
||||
void create_X(const DFA_components &mdfa, const ue2::flat_set<dstate_id_t> &A,
|
||||
size_t inp, ue2::flat_set<dstate_id_t> &X) {
|
||||
X.clear();
|
||||
|
||||
for (dstate_id_t id : A) {
|
||||
insert(&X, mdfa.states[id].prev[inp]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For a split set X, each subset S (given by part_index) in the partition, two
|
||||
* sets are created: v_inter (X intersection S) and v_sub (S - X).
|
||||
*
|
||||
* For each subset S in the partition that could be split (v_inter is nonempty
|
||||
* and v_sub is nonempty):
|
||||
* - replace S in partition by the two sets v_inter and v_sub.
|
||||
* - if S is in work_queue:
|
||||
* - replace S in work_queue by the two subsets.
|
||||
* - else:
|
||||
* - replace S in work_queue by the smaller of the two sets.
|
||||
*/
|
||||
static
|
||||
void split_and_replace_set(const size_t part_index, DFA_components &mdfa,
|
||||
const ue2::flat_set<dstate_id_t> &splitter) {
|
||||
/* singleton sets cannot be split */
|
||||
if (mdfa.partition[part_index].size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t small_index = mdfa.partition.split(part_index, splitter);
|
||||
|
||||
if (small_index == INVALID_SUBSET) {
|
||||
/* the set could not be split */
|
||||
return;
|
||||
}
|
||||
|
||||
/* larger subset remains at the input subset index, if the input subset was
|
||||
* already in the work queue then the larger subset will remain there. */
|
||||
|
||||
mdfa.work_queue.insert(small_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* The complete Hopcrofts algorithm is implemented in this function.
|
||||
* Choose and remove a set tray from work_queue
|
||||
* For each input- X is created.
|
||||
* For each subset in the partition, split_and_replace_sets are called with the
|
||||
* split set.
|
||||
*/
|
||||
static
|
||||
void dfa_min(DFA_components &mdfa) {
|
||||
ue2::flat_set<dstate_id_t> A, X;
|
||||
vector<size_t> cand_subsets;
|
||||
|
||||
while (!mdfa.work_queue.empty()) {
|
||||
get_work_item(mdfa, A);
|
||||
|
||||
for (size_t inp = 0; inp < mdfa.inp_size; inp++) {
|
||||
create_X(mdfa, A, inp, X);
|
||||
if (X.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we only need to consider subsets with at least one member in X for
|
||||
* splitting */
|
||||
cand_subsets.clear();
|
||||
mdfa.partition.find_overlapping(X, &cand_subsets);
|
||||
|
||||
for (size_t sub : cand_subsets) {
|
||||
split_and_replace_set(sub, mdfa, X);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creating new dfa table
|
||||
* Map ordering contains key being an equivalence classes first state
|
||||
* and the value being the equivalence class index.
|
||||
* Eq_state[i] tells us new state id the equivalence class located at
|
||||
* partition[i].
|
||||
*/
|
||||
static
|
||||
void mapping_new_states(const DFA_components &mdfa,
|
||||
vector<dstate_id_t> &old_to_new,
|
||||
raw_dfa &rdfa) {
|
||||
const size_t num_partitions = mdfa.partition.size();
|
||||
|
||||
// Mapping from equiv class's first state to equiv class index.
|
||||
map<dstate_id_t, size_t> ordering;
|
||||
|
||||
// New state id for each equiv class.
|
||||
vector<dstate_id_t> eq_state(num_partitions);
|
||||
|
||||
for (size_t i = 0; i < num_partitions; i++) {
|
||||
ordering[*mdfa.partition[i].begin()] = i;
|
||||
}
|
||||
|
||||
dstate_id_t new_id = 0;
|
||||
for (const auto &m : ordering) {
|
||||
eq_state[m.second] = new_id++;
|
||||
}
|
||||
|
||||
for (size_t t = 0; t < mdfa.partition.size(); t++) {
|
||||
for (dstate_id_t id : mdfa.partition[t]) {
|
||||
old_to_new[id] = eq_state[t];
|
||||
}
|
||||
}
|
||||
|
||||
vector<dstate> new_states;
|
||||
new_states.reserve(num_partitions);
|
||||
for (size_t i = 0; i < mdfa.nstates; i++) {
|
||||
if (contains(ordering, i)) {
|
||||
new_states.push_back(rdfa.states[i]);
|
||||
}
|
||||
}
|
||||
rdfa.states.swap(new_states);
|
||||
}
|
||||
|
||||
static
|
||||
void renumber_new_states(const DFA_components &mdfa,
|
||||
const vector<dstate_id_t> &old_to_new,
|
||||
raw_dfa &rdfa) {
|
||||
for (size_t i = 0; i < mdfa.partition.size(); i++) {
|
||||
for (size_t j = 0; j < mdfa.inp_size; j++) {
|
||||
dstate_id_t output = rdfa.states[i].next[j];
|
||||
rdfa.states[i].next[j] = old_to_new[output];
|
||||
}
|
||||
dstate_id_t dad = rdfa.states[i].daddy;
|
||||
rdfa.states[i].daddy = old_to_new[dad];
|
||||
}
|
||||
|
||||
rdfa.start_floating = old_to_new[rdfa.start_floating];
|
||||
rdfa.start_anchored = old_to_new[rdfa.start_anchored];
|
||||
}
|
||||
|
||||
static
|
||||
void new_dfa(raw_dfa &rdfa, const DFA_components &mdfa) {
|
||||
if (mdfa.partition.size() != mdfa.nstates) {
|
||||
vector<dstate_id_t> old_to_new(mdfa.nstates);
|
||||
mapping_new_states(mdfa, old_to_new, rdfa);
|
||||
renumber_new_states(mdfa, old_to_new, rdfa);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MAIN FUNCTION
|
||||
*/
|
||||
void minimize_hopcroft(raw_dfa &rdfa, const Grey &grey) {
|
||||
if (!grey.minimizeDFA) {
|
||||
return;
|
||||
}
|
||||
|
||||
UNUSED const size_t states_before = rdfa.states.size();
|
||||
|
||||
DFA_components mdfa(rdfa);
|
||||
|
||||
dfa_min(mdfa);
|
||||
new_dfa(rdfa, mdfa);
|
||||
|
||||
DEBUG_PRINTF("reduced from %zu to %zu states\n", states_before,
|
||||
rdfa.states.size());
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
45
src/nfa/dfa_min.h
Normal file
45
src/nfa/dfa_min.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Build code for McClellan DFA.
|
||||
*/
|
||||
|
||||
#ifndef DFA_MIN_H
|
||||
#define DFA_MIN_H
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct raw_dfa;
|
||||
struct Grey;
|
||||
|
||||
void minimize_hopcroft(raw_dfa &rdfa, const Grey &grey);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
1153
src/nfa/gough.c
Normal file
1153
src/nfa/gough.c
Normal file
File diff suppressed because it is too large
Load Diff
82
src/nfa/gough.h
Normal file
82
src/nfa/gough.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef GOUGH_H
|
||||
#define GOUGH_H
|
||||
|
||||
#include "callback.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
struct NFA;
|
||||
struct mq;
|
||||
|
||||
// 8-bit Gough
|
||||
|
||||
char nfaExecGough8_testEOD(const struct NFA *nfa, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback, SomNfaCallback som_cb,
|
||||
void *context);
|
||||
char nfaExecGough8_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecGough8_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecGough8_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecGough8_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecGough8_inAccept(const struct NFA *n, ReportID report, struct mq *q);
|
||||
char nfaExecGough8_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecGough8_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecGough8_queueCompressState(const struct NFA *nfa, const struct mq *q,
|
||||
s64a loc);
|
||||
char nfaExecGough8_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecGough8_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecGough8_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
// 16-bit Gough
|
||||
|
||||
char nfaExecGough16_testEOD(const struct NFA *nfa, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback, SomNfaCallback som_cb,
|
||||
void *context);
|
||||
char nfaExecGough16_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecGough16_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecGough16_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecGough16_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecGough16_inAccept(const struct NFA *n, ReportID report, struct mq *q);
|
||||
char nfaExecGough16_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecGough16_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecGough16_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecGough16_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecGough16_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecGough16_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
#endif
|
||||
134
src/nfa/gough_internal.h
Normal file
134
src/nfa/gough_internal.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef GOUGH_INTERNAL_H
|
||||
#define GOUGH_INTERNAL_H
|
||||
|
||||
#include "accel.h"
|
||||
#include "mcclellan_internal.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
#define INVALID_SLOT (~0U)
|
||||
|
||||
#define GOUGH_INS_END 0
|
||||
#define GOUGH_INS_MOV 1
|
||||
#define GOUGH_INS_NEW 2
|
||||
#define GOUGH_INS_MIN 3
|
||||
/* todo: add instructions targeting acc reg? */
|
||||
|
||||
struct gough_ins {
|
||||
u32 op; /* u32 to avoid padding */
|
||||
u32 dest;
|
||||
u32 src; /* for GOUGH_INS_NEW, this specifies the adjustment to apply to the
|
||||
* current offset */
|
||||
};
|
||||
|
||||
/*
|
||||
* HAPPY FUN ASCII ART TIME
|
||||
*
|
||||
* ----
|
||||
* | | struct NFA
|
||||
* ----
|
||||
* ~~~~ normal(ish) mcclellan engine
|
||||
* ~~~~
|
||||
* ~~~~
|
||||
* ~~~~
|
||||
* ~~~~
|
||||
* ~~~~
|
||||
* ~~~~
|
||||
* ~~~~
|
||||
* ---- = m->haig_offset
|
||||
* | | } struct gough_info
|
||||
* ----
|
||||
* | | }
|
||||
* | | } edge prog table -> provides the offset of the start of the program
|
||||
* | | } to run when the edge is taken. 0 indicates no
|
||||
* | | } work to do
|
||||
* ---- = h->top_prog_offset
|
||||
* | | }
|
||||
* | | } top prog table -> provides the offset of the start of the program
|
||||
* | | } to run when a top is taken from this state. 0
|
||||
* | | } indicates nothing to do
|
||||
* ---- = h->prog_base_offset
|
||||
* | | }
|
||||
* | | } programs to run
|
||||
* | | }
|
||||
* | | }
|
||||
* ----
|
||||
*/
|
||||
|
||||
struct gough_info {
|
||||
u32 top_prog_offset; /**< offset to the base of the top prog table */
|
||||
u32 prog_base_offset; /**< not used at runtime */
|
||||
u32 stream_som_loc_count; /**< number of som locs in the stream state */
|
||||
u8 stream_som_loc_width; /**< number of bytes per som loc */
|
||||
};
|
||||
|
||||
static really_inline
|
||||
const struct gough_info *get_gough(const struct mcclellan *m) {
|
||||
assert(m->haig_offset);
|
||||
const char *n = (const char *)m - sizeof(struct NFA);
|
||||
return (const struct gough_info *)(n + m->haig_offset);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u32 *get_gough_top_offsets(const struct mcclellan *m) {
|
||||
const struct gough_info *g = get_gough(m);
|
||||
if (!g->top_prog_offset) {
|
||||
return NULL;
|
||||
}
|
||||
const char *n = (const char *)m - sizeof(struct NFA);
|
||||
return (const u32 *)(n + g->top_prog_offset);
|
||||
}
|
||||
|
||||
/* Gough state representation in scratch.
|
||||
*
|
||||
* During execution, gough tracks a number of variables containing potential
|
||||
* starts of match. These are all stored in a large array of u64a slots.
|
||||
*/
|
||||
struct gough_som_info {
|
||||
u64a slots[1]; /* 'flexible' member array */
|
||||
};
|
||||
|
||||
struct gough_report {
|
||||
ReportID r;
|
||||
u32 som; /* som slot to report */
|
||||
};
|
||||
|
||||
struct gough_report_list {
|
||||
u32 count;
|
||||
struct gough_report report[];
|
||||
};
|
||||
|
||||
struct gough_accel {
|
||||
union AccelAux accel;
|
||||
u8 margin_dist;
|
||||
u32 prog_offset;
|
||||
};
|
||||
|
||||
#endif
|
||||
1320
src/nfa/goughcompile.cpp
Normal file
1320
src/nfa/goughcompile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
93
src/nfa/goughcompile.h
Normal file
93
src/nfa/goughcompile.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef GOUGHCOMPILE_H
|
||||
#define GOUGHCOMPILE_H
|
||||
|
||||
#include "mcclellancompile.h"
|
||||
#include "nfa_kind.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/ue2_containers.h"
|
||||
#include "util/order_check.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#define CREATE_NEW_SOM (~0U)
|
||||
|
||||
/* dest nfa state -> som info for dest state is min of provided loc idx som
|
||||
* info */
|
||||
typedef flat_map<u32, std::vector<u32>> som_tran_info;
|
||||
|
||||
struct som_report {
|
||||
som_report(ReportID r, u32 s) : report(r), slot(s) {}
|
||||
|
||||
ReportID report;
|
||||
u32 slot;
|
||||
|
||||
bool operator<(const som_report &b) const {
|
||||
const som_report &a = *this;
|
||||
ORDER_CHECK(report);
|
||||
ORDER_CHECK(slot);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct dstate_som {
|
||||
std::set<som_report> reports;
|
||||
std::set<som_report> reports_eod;
|
||||
som_tran_info preds; /* live nfa states mapped back to pred states */
|
||||
};
|
||||
|
||||
struct raw_som_dfa : public raw_dfa {
|
||||
raw_som_dfa(nfa_kind k, bool unordered_som_triggers_in)
|
||||
: raw_dfa(k), unordered_som_triggers(unordered_som_triggers_in) {
|
||||
assert(!unordered_som_triggers || is_triggered(kind));
|
||||
}
|
||||
|
||||
std::vector<dstate_som> state_som;
|
||||
u32 stream_som_loc_width;
|
||||
bool unordered_som_triggers;
|
||||
void stripExtraEodReports(void) override;
|
||||
|
||||
std::map<u32, u32> new_som_nfa_states; /* map nfa vertex id -> offset */
|
||||
u32 trigger_nfa_state; /* for triggered cases, slot_id that contains a new
|
||||
* som */
|
||||
};
|
||||
|
||||
aligned_unique_ptr<NFA> goughCompile(raw_som_dfa &raw, u8 somPrecision,
|
||||
const CompileContext &cc);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
281
src/nfa/goughcompile_accel.cpp
Normal file
281
src/nfa/goughcompile_accel.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "goughcompile_internal.h"
|
||||
#include "gough_internal.h"
|
||||
#include "grey.h"
|
||||
#include "mcclellancompile.h"
|
||||
#include "util/container.h"
|
||||
#include "util/graph.h"
|
||||
#include "util/graph_range.h"
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
template<typename Graph>
|
||||
void add_edge_if_not_selfloop(const typename Graph::vertex_descriptor &u,
|
||||
const typename Graph::vertex_descriptor &v,
|
||||
Graph &g) {
|
||||
if (u != v) {
|
||||
add_edge(u, v, g);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
bool can_accel_over_selfloop(const GoughVertexProps &vp, const GoughEdge &e,
|
||||
const GoughEdgeProps &ep, u32 *margin) {
|
||||
if (vp.vars.empty() && ep.vars.empty()) {
|
||||
/* if we update no som information, then it is trivial to accelerate */
|
||||
*margin = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if the effect of running a self loop stabilises after a small number of
|
||||
* iterations, it is possible to accelerate over the state and only then run
|
||||
* the block N times. To model this we create a graph which shows how the
|
||||
* value for a variable at the end of a self loop block is related to values
|
||||
* at the start */
|
||||
|
||||
typedef boost::adjacency_list<boost::vecS, boost::vecS,
|
||||
boost::bidirectionalS> basic_graph;
|
||||
typedef basic_graph::vertex_descriptor basic_vertex;
|
||||
basic_graph bg;
|
||||
|
||||
map<const GoughSSAVar *, basic_vertex> verts;
|
||||
|
||||
/* create verts */
|
||||
for (const auto &var : ep.vars) {
|
||||
verts[var.get()] = add_vertex(bg);
|
||||
}
|
||||
|
||||
for (const auto &var : vp.vars) {
|
||||
verts[var.get()] = add_vertex(bg);
|
||||
}
|
||||
|
||||
/* wire edges */
|
||||
set<basic_vertex> done;
|
||||
for (const auto &var : ep.vars) {
|
||||
assert(contains(verts, var.get()));
|
||||
basic_vertex v = verts[var.get()];
|
||||
for (GoughSSAVar *pred : var->get_inputs()) {
|
||||
if (!contains(verts, pred)) {
|
||||
continue;
|
||||
}
|
||||
basic_vertex u = verts[pred];
|
||||
if (contains(done, u)) { /* u has already taken on new values this
|
||||
* iteration */
|
||||
for (auto p : inv_adjacent_vertices_range(u, bg)) {
|
||||
add_edge_if_not_selfloop(p, v, bg);
|
||||
}
|
||||
} else {
|
||||
add_edge_if_not_selfloop(u, v, bg);
|
||||
}
|
||||
}
|
||||
done.insert(v);
|
||||
}
|
||||
|
||||
for (const auto &var : vp.vars) {
|
||||
GoughSSAVar *pred = var->get_input(e);
|
||||
assert(contains(verts, var.get()));
|
||||
basic_vertex v = verts[var.get()];
|
||||
if (!contains(verts, pred)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
basic_vertex u = verts[pred];
|
||||
if (contains(done, u)) { /* u has already taken on new values this
|
||||
* iteration */
|
||||
for (auto p : inv_adjacent_vertices_range(u, bg)) {
|
||||
add_edge_if_not_selfloop(p, v, bg);
|
||||
}
|
||||
} else {
|
||||
add_edge_if_not_selfloop(u, v, bg);
|
||||
}
|
||||
/* do not add v to done as all joins happen in parallel */
|
||||
}
|
||||
|
||||
/* check for loops - non self loops may prevent settling */
|
||||
|
||||
if (!is_dag(bg)) {
|
||||
DEBUG_PRINTF("can not %u accel as large loops\n", vp.state_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
*margin = num_vertices(bg); /* TODO: be less conservative */
|
||||
|
||||
if (*margin > 50) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool verify_neighbour(const GoughGraph &g, GoughVertex u,
|
||||
const map<gough_edge_id, vector<gough_ins> > &blocks,
|
||||
const set<GoughVertex> &succs,
|
||||
const vector<gough_ins> &block_sl) {
|
||||
for (const auto &e : out_edges_range(u, g)) {
|
||||
if (!g[e].reach.any()) { /* ignore top edges */
|
||||
continue;
|
||||
}
|
||||
|
||||
GoughVertex t = target(e, g);
|
||||
if (!contains(succs, t)) { /* must be an escape string */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!contains(blocks, gough_edge_id(g, e))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blocks.at(gough_edge_id(g, e)) != block_sl) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool verify_neighbour_no_block(const GoughGraph &g, GoughVertex u,
|
||||
const map<gough_edge_id, vector<gough_ins> > &blocks,
|
||||
const set<GoughVertex> &succs) {
|
||||
for (const auto &e : out_edges_range(u, g)) {
|
||||
if (!g[e].reach.any()) { /* ignore top edges */
|
||||
continue;
|
||||
}
|
||||
|
||||
GoughVertex t = target(e, g);
|
||||
if (!contains(succs, t)) { /* must be an escape string */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (contains(blocks, gough_edge_id(g, e))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Checks the som aspects of allowing two byte accel - it is expected that the
|
||||
* mcclellan logic will identify escape strings.
|
||||
*
|
||||
* For 2 byte acceleration to be correct we require that any non-escape sequence
|
||||
* characters xy from the accel state has the same effect as just the character
|
||||
* of y.
|
||||
*
|
||||
* The current way of ensuring this is to require:
|
||||
* (a) all edges out of the cyclic state behave identically to the cyclic self
|
||||
* loop edge
|
||||
* (b) edges out of the neighbouring state which do not correspond to escape
|
||||
* string behave identical to the cyclic state edges.
|
||||
*
|
||||
* TODO: these restrictions could be relaxed by looking at the effect on
|
||||
* relevant (live?) vars only, allowing additions to the escape string set, and
|
||||
* considering one byte escapes.
|
||||
*/
|
||||
static
|
||||
bool allow_two_byte_accel(const GoughGraph &g,
|
||||
const map<gough_edge_id, vector<gough_ins> > &blocks,
|
||||
GoughVertex v, const GoughEdge &self_loop) {
|
||||
if (contains(blocks, gough_edge_id(g, self_loop))) {
|
||||
DEBUG_PRINTF("edge plan on self loop\n");
|
||||
const auto &block_sl = blocks.at(gough_edge_id(g, self_loop));
|
||||
|
||||
set<GoughVertex> succs;
|
||||
for (const auto &e : out_edges_range(v, g)) {
|
||||
if (g[e].reach.none()) { /* ignore top edges */
|
||||
continue;
|
||||
}
|
||||
|
||||
gough_edge_id ged(g, e);
|
||||
if (!contains(blocks, ged) || blocks.at(ged) != block_sl) {
|
||||
DEBUG_PRINTF("different out-edge behaviour\n");
|
||||
return false;
|
||||
}
|
||||
succs.insert(target(e, g));
|
||||
}
|
||||
|
||||
for (auto w : adjacent_vertices_range(v, g)) {
|
||||
if (w != v && !verify_neighbour(g, w, blocks, succs, block_sl)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_PRINTF("no edge plan on self loop\n");
|
||||
set<GoughVertex> succs;
|
||||
for (const auto &e : out_edges_range(v, g)) {
|
||||
if (g[e].reach.none()) { /* ignore top edges */
|
||||
continue;
|
||||
}
|
||||
|
||||
gough_edge_id ged(g, e);
|
||||
if (contains(blocks, ged)) {
|
||||
DEBUG_PRINTF("different out-edge behaviour\n");
|
||||
return false;
|
||||
}
|
||||
succs.insert(target(e, g));
|
||||
|
||||
for (auto w : adjacent_vertices_range(v, g)) {
|
||||
if (w != v && !verify_neighbour_no_block(g, w, blocks, succs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("allowing two byte accel for %u\n", g[v].state_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void find_allowed_accel_states(const GoughGraph &g,
|
||||
const map<gough_edge_id, vector<gough_ins> > &blocks,
|
||||
map<dstate_id_t, gough_accel_state_info> *out) {
|
||||
for (auto v : vertices_range(g)) {
|
||||
GoughEdge e;
|
||||
if (!find_normal_self_loop(v, g, &e)) {
|
||||
continue; /* not accelerable */
|
||||
}
|
||||
u32 margin = 0;
|
||||
if (!can_accel_over_selfloop(g[v], e, g[e], &margin)) {
|
||||
continue; /* not accelerable */
|
||||
}
|
||||
bool tba = allow_two_byte_accel(g, blocks, v, e);
|
||||
out->emplace(g[v].state_id, gough_accel_state_info(margin, tba));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
334
src/nfa/goughcompile_dump.cpp
Normal file
334
src/nfa/goughcompile_dump.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "goughcompile_dump.h"
|
||||
#include "goughcompile_internal.h"
|
||||
#include "grey.h"
|
||||
#include "util/container.h"
|
||||
#include "util/graph_range.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
string dump_name(const GoughVertexProps &vp) {
|
||||
stringstream ss;
|
||||
ss << "vertex_" << vp.state_id;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static
|
||||
string dump_name(const GoughGraph &g, const GoughEdge &e) {
|
||||
stringstream ss;
|
||||
ss << "edge_" << g[source(e, g)].state_id << "_"
|
||||
<< g[target(e, g)].state_id;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
string dump_name(const gough_edge_id &e) {
|
||||
stringstream ss;
|
||||
ss << "edge_" << e.src << "_" << e.dest;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static
|
||||
void dump_graph(const GoughGraph &g, const string &base, const Grey &grey) {
|
||||
stringstream ss;
|
||||
ss << grey.dumpPath << "gough_" << base << ".dot";
|
||||
|
||||
FILE *f = fopen(ss.str().c_str(), "w");
|
||||
|
||||
fprintf(f, "digraph NFA {\n");
|
||||
fprintf(f, "rankdir=LR;\n");
|
||||
fprintf(f, "size=\"11.5,8\"\n");
|
||||
fprintf(f, "node [ shape = circle ];\n");
|
||||
fprintf(f, "START [style=invis];\n");
|
||||
|
||||
for (auto v : vertices_range(g)) {
|
||||
fprintf(f, "%s [ width = 1, fixedsize = true, fontsize = 12, ",
|
||||
dump_name(g[v]).c_str());
|
||||
if (!g[v].reports.empty() || !g[v].reports_eod.empty()) {
|
||||
fprintf(f, "shape = doublecircle ");
|
||||
}
|
||||
|
||||
fprintf(f, "label = \"%u\"];\n", g[v].state_id);
|
||||
}
|
||||
for (const auto &e : edges_range(g)) {
|
||||
GoughVertex s = source(e, g);
|
||||
GoughVertex t = target(e, g);
|
||||
|
||||
fprintf(f, "%s -> %s\n",
|
||||
dump_name(g[s]).c_str(), dump_name(g[t]).c_str());
|
||||
}
|
||||
fprintf(f, "}\n");
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static
|
||||
set<const GoughSSAVar *> uses(const GoughVertexProps &vp) {
|
||||
set<const GoughSSAVar *> rv;
|
||||
for (const auto &r : vp.reports) {
|
||||
if (r.second) {
|
||||
rv.insert(r.second);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &r : vp.reports_eod) {
|
||||
if (r.second) {
|
||||
rv.insert(r.second);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &var : vp.vars) {
|
||||
insert(&rv, var->get_inputs());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
set<const GoughSSAVar *> uses(const GoughEdgeProps &ep) {
|
||||
set<const GoughSSAVar *> rv;
|
||||
for (const auto &var : ep.vars) {
|
||||
insert(&rv, var->get_inputs());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
void dump_var_mapping(const GoughGraph &g, const string &base,
|
||||
const Grey &grey) {
|
||||
stringstream ss;
|
||||
ss << grey.dumpPath << "gough_" << base << "_vars.txt";
|
||||
FILE *f = fopen(ss.str().c_str(), "w");
|
||||
for (auto v : vertices_range(g)) {
|
||||
set<const GoughSSAVar *> used = uses(g[v]);
|
||||
if (g[v].vars.empty() && used.empty()) {
|
||||
continue;
|
||||
}
|
||||
fprintf(f, "%s\n", dump_name(g[v]).c_str());
|
||||
for (u32 i = 0; i < g[v].vars.size(); i++) {
|
||||
const GoughSSAVar *vp = g[v].vars[i].get();
|
||||
fprintf(f, "\t%u: slot %u\n", i, vp->slot);
|
||||
}
|
||||
if (!used.empty()) {
|
||||
fprintf(f, "\tuses:");
|
||||
vector<u32> used_id;
|
||||
for (const GoughSSAVar *var : used) {
|
||||
used_id.push_back(var->slot);
|
||||
}
|
||||
for (const u32 &id : used_id) {
|
||||
fprintf(f, " %u", id);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
for (const auto &e : edges_range(g)) {
|
||||
set<const GoughSSAVar *> used = uses(g[e]);
|
||||
if (g[e].vars.empty() && used.empty()) {
|
||||
continue;
|
||||
}
|
||||
fprintf(f, "%s\n", dump_name(g, e).c_str());
|
||||
for (u32 i = 0; i < g[e].vars.size(); i++) {
|
||||
const GoughSSAVar *vp = g[e].vars[i].get();
|
||||
fprintf(f, "\t%u: slot %u\n", i, vp->slot);
|
||||
}
|
||||
if (!used.empty()) {
|
||||
fprintf(f, "\tuses:");
|
||||
vector<u32> used_id;
|
||||
for (const GoughSSAVar *var : used) {
|
||||
used_id.push_back(var->slot);
|
||||
}
|
||||
for (const u32 &id : used_id) {
|
||||
fprintf(f, " %u", id);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static
|
||||
void gather_vars(const GoughGraph &g, vector<const GoughSSAVar *> *vars,
|
||||
map<const GoughSSAVar *, string> *names,
|
||||
map<const GoughSSAVar *, string> *src_label,
|
||||
set<const GoughSSAVar *> *reporters) {
|
||||
for (auto v : vertices_range(g)) {
|
||||
for (const auto &r : g[v].reports) {
|
||||
reporters->insert(r.second);
|
||||
}
|
||||
for (const auto &r : g[v].reports_eod) {
|
||||
reporters->insert(r.second);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < g[v].vars.size(); i++) {
|
||||
const GoughSSAVar *vp = g[v].vars[i].get();
|
||||
stringstream ss;
|
||||
ss << dump_name(g[v]) << "_" << i;
|
||||
vars->push_back(vp);
|
||||
names->insert(make_pair(vp, ss.str()));
|
||||
src_label->insert(make_pair(vp, dump_name(g[v])));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &e : edges_range(g)) {
|
||||
for (u32 i = 0; i < g[e].vars.size(); i++) {
|
||||
const GoughSSAVar *vp = g[e].vars[i].get();
|
||||
stringstream ss;
|
||||
ss << dump_name(g, e) << "_" << i;
|
||||
vars->push_back(vp);
|
||||
names->insert(make_pair(vp, ss.str()));
|
||||
src_label->insert(make_pair(vp, dump_name(g, e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dump_vars(const GoughGraph &g, const string &base, const Grey &grey) {
|
||||
FILE *f;
|
||||
{
|
||||
stringstream ss;
|
||||
ss << grey.dumpPath << "gough_" << base << "_vars.dot";
|
||||
f = fopen(ss.str().c_str(), "w");
|
||||
}
|
||||
fprintf(f, "digraph NFA {\n");
|
||||
fprintf(f, "rankdir=LR;\n");
|
||||
fprintf(f, "size=\"11.5,8\"\n");
|
||||
fprintf(f, "node [ shape = circle ];\n");
|
||||
fprintf(f, "START [style=invis];\n");
|
||||
|
||||
vector<const GoughSSAVar *> vars;
|
||||
map<const GoughSSAVar *, string> names;
|
||||
map<const GoughSSAVar *, string> src_label;
|
||||
set<const GoughSSAVar *> reporters;
|
||||
gather_vars(g, &vars, &names, &src_label, &reporters);
|
||||
|
||||
for (const GoughSSAVar *vp : vars) {
|
||||
fprintf(f, "%s [ width = 1, fixedsize = true, fontsize = 12, ",
|
||||
names[vp].c_str());
|
||||
fprintf(f, "label = \"%s\\n", src_label[vp].c_str());
|
||||
|
||||
if (dynamic_cast<const GoughSSAVarMin *>(vp)) {
|
||||
fprintf(f, "MIN");
|
||||
} else if (dynamic_cast<const GoughSSAVarJoin *>(vp)) {
|
||||
fprintf(f, "JOIN");
|
||||
} else if (dynamic_cast<const GoughSSAVarNew *>(vp)) {
|
||||
fprintf(f, "NEW");
|
||||
} else {
|
||||
fprintf(f, "???");
|
||||
}
|
||||
fprintf(f, "\"];\n");
|
||||
}
|
||||
|
||||
for (const GoughSSAVar *vp : reporters) {
|
||||
if (vp) {
|
||||
fprintf(f, "%s [ shape = doublecircle]\n", names[vp].c_str());
|
||||
} else {
|
||||
fprintf(f, "eps [ label = \"eps\" shape = doublecircle]\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (const GoughSSAVar *vp : vars) {
|
||||
const flat_set<GoughSSAVar *> &inputs = vp->get_inputs();
|
||||
for (const GoughSSAVar *v_in : inputs) {
|
||||
fprintf(f, "%s -> %s\n", names[v_in].c_str(), names[vp].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void dump(const GoughGraph &g, const string &base, const Grey &grey) {
|
||||
if (!grey.dumpFlags) {
|
||||
return;
|
||||
}
|
||||
|
||||
dump_graph(g, base, grey);
|
||||
dump_var_mapping(g, base, grey);
|
||||
dump_vars(g, base, grey);
|
||||
}
|
||||
|
||||
static
|
||||
void dump_block(FILE *f, const gough_edge_id &e,
|
||||
const vector<gough_ins> &block) {
|
||||
fprintf(f, "%s:\n", dump_name(e).c_str());
|
||||
for (const gough_ins &ins : block) {
|
||||
fprintf(f, "\t");
|
||||
switch (ins.op) {
|
||||
case GOUGH_INS_END:
|
||||
fprintf(f, "END");
|
||||
break;
|
||||
case GOUGH_INS_MOV:
|
||||
fprintf(f, "MOV %u %u", ins.dest, ins.src);
|
||||
break;
|
||||
case GOUGH_INS_NEW:
|
||||
fprintf(f, "NEW %u (+%u)", ins.dest, ins.src);
|
||||
break;
|
||||
case GOUGH_INS_MIN:
|
||||
fprintf(f, "MIN %u %u", ins.dest, ins.src);
|
||||
break;
|
||||
default:
|
||||
fprintf(f, "<UNKNOWN>");
|
||||
break;
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dump_blocks(const map<gough_edge_id, vector<gough_ins> > &blocks,
|
||||
const string &base, const Grey &grey) {
|
||||
if (!grey.dumpFlags) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
{
|
||||
stringstream ss;
|
||||
ss << grey.dumpPath << "gough_" << base << "_programs.txt";
|
||||
f = fopen(ss.str().c_str(), "w");
|
||||
}
|
||||
|
||||
for (const auto &m : blocks) {
|
||||
dump_block(f, m.first, m.second);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
63
src/nfa/goughcompile_dump.h
Normal file
63
src/nfa/goughcompile_dump.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef GOUGHCOMPILE_DUMP_H
|
||||
#define GOUGHCOMPILE_DUMP_H
|
||||
|
||||
#include "goughcompile_internal.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct Grey;
|
||||
#ifdef DUMP_SUPPORT
|
||||
|
||||
std::string dump_name(const GoughVertexProps &vp);
|
||||
std::string dump_name(const gough_edge_id &e);
|
||||
void dump(const GoughGraph &g, const std::string &base, const Grey &grey);
|
||||
void dump_blocks(const std::map<gough_edge_id, std::vector<gough_ins> > &blocks,
|
||||
const std::string &base, const Grey &grey);
|
||||
#else
|
||||
|
||||
static UNUSED
|
||||
void dump(UNUSED const GoughGraph &g, UNUSED const std::string &base,
|
||||
UNUSED const Grey &grey) {
|
||||
}
|
||||
static UNUSED
|
||||
void dump_blocks(
|
||||
UNUSED const std::map<gough_edge_id, std::vector<gough_ins> > &blocks,
|
||||
UNUSED const std::string &base, UNUSED const Grey &grey) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
227
src/nfa/goughcompile_internal.h
Normal file
227
src/nfa/goughcompile_internal.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef GOUGHCOMPILE_INTERNAL_H
|
||||
#define GOUGHCOMPILE_INTERNAL_H
|
||||
|
||||
#include "gough_internal.h"
|
||||
#include "mcclellancompile.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/order_check.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct Grey;
|
||||
struct GoughSSAVar;
|
||||
struct GoughSSAVarJoin;
|
||||
|
||||
struct GoughVertexProps {
|
||||
GoughVertexProps() {}
|
||||
explicit GoughVertexProps(u32 state_in) : state_id(state_in) {}
|
||||
u32 state_id = ~0U;
|
||||
|
||||
std::vector<std::shared_ptr<GoughSSAVarJoin> > vars; /* owns variables */
|
||||
|
||||
std::vector<std::pair<ReportID, GoughSSAVar *> > reports; /**< report som,
|
||||
som variable */
|
||||
std::vector<std::pair<ReportID, GoughSSAVar *> > reports_eod;
|
||||
};
|
||||
|
||||
struct GoughEdgeProps {
|
||||
GoughEdgeProps(void) : top(false) {}
|
||||
bool top;
|
||||
CharReach reach;
|
||||
|
||||
std::vector<std::shared_ptr<GoughSSAVar> > vars; /* owns variables */
|
||||
};
|
||||
|
||||
struct GoughGraphProps {
|
||||
boost::adjacency_list_traits<boost::vecS, boost::vecS>::vertex_descriptor
|
||||
initial_vertex; /* for triggered nfas, dead state;
|
||||
* for others start anchored or start floating
|
||||
*/
|
||||
};
|
||||
|
||||
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
|
||||
GoughVertexProps, GoughEdgeProps, GoughGraphProps> GoughGraph;
|
||||
|
||||
typedef GoughGraph::vertex_descriptor GoughVertex;
|
||||
typedef GoughGraph::edge_descriptor GoughEdge;
|
||||
|
||||
struct gough_edge_id {
|
||||
gough_edge_id(const GoughGraph &g, const GoughEdge &e)
|
||||
: src(g[source(e, g)].state_id), dest(g[target(e, g)].state_id),
|
||||
first_char(g[e].reach.find_first()) {}
|
||||
bool operator<(const gough_edge_id &b) const {
|
||||
const gough_edge_id &a = *this;
|
||||
ORDER_CHECK(src);
|
||||
ORDER_CHECK(dest);
|
||||
ORDER_CHECK(first_char);
|
||||
return false;
|
||||
}
|
||||
const u32 src;
|
||||
const u32 dest;
|
||||
const u32 first_char; /* ~0U if only top */
|
||||
};
|
||||
|
||||
struct GoughSSAVarWithInputs;
|
||||
struct GoughSSAVarMin;
|
||||
struct GoughSSAVarJoin;
|
||||
|
||||
struct GoughSSAVar : boost::noncopyable {
|
||||
GoughSSAVar(void) : seen(false), slot(INVALID_SLOT) {}
|
||||
virtual ~GoughSSAVar();
|
||||
const ue2::flat_set<GoughSSAVar *> &get_inputs() const {
|
||||
return inputs;
|
||||
}
|
||||
const ue2::flat_set<GoughSSAVarWithInputs *> &get_outputs() const {
|
||||
return outputs;
|
||||
}
|
||||
virtual void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) = 0;
|
||||
|
||||
virtual void generate(std::vector<gough_ins> *out) const = 0;
|
||||
|
||||
bool seen; /* for temp use by remove_dead alg */
|
||||
u32 slot;
|
||||
|
||||
void clear_outputs();
|
||||
|
||||
/** remove all inputs and outputs of the vertex, call before
|
||||
* removing vertex */
|
||||
virtual void clear_all() {
|
||||
clear_outputs();
|
||||
}
|
||||
protected:
|
||||
ue2::flat_set<GoughSSAVar *> inputs;
|
||||
ue2::flat_set<GoughSSAVarWithInputs *> outputs;
|
||||
friend struct GoughSSAVarWithInputs;
|
||||
friend struct GoughSSAVarMin;
|
||||
friend struct GoughSSAVarJoin;
|
||||
};
|
||||
|
||||
struct GoughSSAVarNew : public GoughSSAVar {
|
||||
explicit GoughSSAVarNew(u32 adjust_in) : adjust(adjust_in) {}
|
||||
|
||||
void replace_input(GoughSSAVar *, GoughSSAVar *) override {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void generate(std::vector<gough_ins> *out) const override;
|
||||
|
||||
const u32 adjust;
|
||||
};
|
||||
|
||||
struct GoughSSAVarWithInputs : public GoughSSAVar {
|
||||
GoughSSAVarWithInputs(void) {}
|
||||
void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) override = 0;
|
||||
virtual void clear_inputs() = 0;
|
||||
void clear_all() override;
|
||||
protected:
|
||||
virtual void remove_input_raw(GoughSSAVar *v) = 0;
|
||||
friend struct GoughSSAVar;
|
||||
};
|
||||
|
||||
struct GoughSSAVarMin : public GoughSSAVarWithInputs {
|
||||
GoughSSAVarMin(void) {}
|
||||
void generate(std::vector<gough_ins> *out) const override;
|
||||
|
||||
void clear_inputs() override;
|
||||
void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) override;
|
||||
|
||||
virtual void add_input(GoughSSAVar *v) {
|
||||
inputs.insert(v);
|
||||
v->outputs.insert(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
void remove_input_raw(GoughSSAVar *v) override;
|
||||
};
|
||||
|
||||
struct GoughSSAVarJoin : public GoughSSAVarWithInputs {
|
||||
GoughSSAVarJoin(void) {}
|
||||
|
||||
/* dummy; all joins at a point must be generated simultaneously */
|
||||
void generate(std::vector<gough_ins> *out) const override;
|
||||
GoughSSAVar *get_input(const GoughEdge &prev) const;
|
||||
|
||||
void clear_inputs() override;
|
||||
void replace_input(GoughSSAVar *old_v, GoughSSAVar *new_v) override;
|
||||
|
||||
void add_input(GoughSSAVar *v, GoughEdge prev);
|
||||
|
||||
const ue2::flat_set<GoughEdge> &get_edges_for_input(GoughSSAVar *input)
|
||||
const;
|
||||
const std::map<GoughSSAVar *, ue2::flat_set<GoughEdge> > &get_input_map()
|
||||
const;
|
||||
|
||||
protected:
|
||||
void remove_input_raw(GoughSSAVar *v) override;
|
||||
|
||||
private:
|
||||
std::map<GoughSSAVar *, ue2::flat_set<GoughEdge>> input_map;
|
||||
};
|
||||
|
||||
struct gough_accel_state_info {
|
||||
u32 margin;
|
||||
bool two_byte;
|
||||
|
||||
gough_accel_state_info(u32 margin_in, bool two_byte_in)
|
||||
: margin(margin_in), two_byte(two_byte_in) {
|
||||
}
|
||||
};
|
||||
|
||||
u32 assign_slots(GoughGraph &g, const Grey &grey);
|
||||
void find_allowed_accel_states(const GoughGraph &g,
|
||||
const std::map<gough_edge_id, std::vector<gough_ins> > &blocks,
|
||||
std::map<dstate_id_t, gough_accel_state_info> *out);
|
||||
bool find_normal_self_loop(GoughVertex v, const GoughGraph &g, GoughEdge *out);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
// Note: C structure, can't be in namespace ue2
|
||||
static inline
|
||||
bool operator==(const gough_ins &a, const gough_ins &b) {
|
||||
return a.op == b.op && a.dest == b.dest && a.src == b.src;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool operator<(const gough_ins &a, const gough_ins &b) {
|
||||
return std::tie(a.op, a.src, a.dest) < std::tie(b.op, b.src, b.dest);
|
||||
}
|
||||
|
||||
#endif
|
||||
502
src/nfa/goughcompile_reg.cpp
Normal file
502
src/nfa/goughcompile_reg.cpp
Normal file
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "goughcompile.h"
|
||||
#include "goughcompile_dump.h"
|
||||
#include "goughcompile_internal.h"
|
||||
#include "gough_internal.h"
|
||||
#include "grey.h"
|
||||
#include "util/container.h"
|
||||
#include "util/graph.h"
|
||||
#include "util/graph_range.h"
|
||||
#include "util/order_check.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/graph/depth_first_search.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
using namespace std;
|
||||
using boost::adaptors::map_values;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
template<typename VarP, typename VarQ>
|
||||
void push_back_all_raw(vector<VarP> *out, const vector<VarQ> &in) {
|
||||
for (const auto &var : in) {
|
||||
out->push_back(var.get());
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void all_vars(const GoughGraph &g, vector<GoughSSAVar *> *out) {
|
||||
for (auto v : vertices_range(g)) {
|
||||
push_back_all_raw(out, g[v].vars);
|
||||
}
|
||||
for (const auto &e : edges_range(g)) {
|
||||
push_back_all_raw(out, g[e].vars);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct GoughGraphAux {
|
||||
map<const GoughSSAVar *, GoughVertex> containing_v;
|
||||
map<const GoughSSAVar *, GoughEdge> containing_e;
|
||||
map<const GoughSSAVar *, set<GoughVertex> > reporters;
|
||||
};
|
||||
}
|
||||
|
||||
static never_inline
|
||||
void fill_aux(const GoughGraph &g, GoughGraphAux *aux) {
|
||||
for (auto v : vertices_range(g)) {
|
||||
for (const auto &var : g[v].vars) {
|
||||
aux->containing_v[var.get()] = v;
|
||||
DEBUG_PRINTF("%u is on vertex %u\n", var->slot, g[v].state_id);
|
||||
}
|
||||
|
||||
for (GoughSSAVar *var : g[v].reports | map_values) {
|
||||
aux->reporters[var].insert(v);
|
||||
}
|
||||
|
||||
for (GoughSSAVar *var : g[v].reports_eod | map_values) {
|
||||
aux->reporters[var].insert(v);
|
||||
}
|
||||
}
|
||||
for (const auto &e : edges_range(g)) {
|
||||
for (const auto &var : g[e].vars) {
|
||||
aux->containing_e[var.get()] = e;
|
||||
DEBUG_PRINTF("%u is on edge %u->%u\n", var->slot,
|
||||
g[source(e, g)].state_id, g[target(e, g)].state_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
bool is_block_local(const GoughGraph &cfg, GoughSSAVar *var,
|
||||
const GoughGraphAux &aux) {
|
||||
/* if var used as a report, it cannot be considered block local */
|
||||
if (contains(aux.reporters, var)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (useful) vertex/join vars never local - they are terminal in blocks
|
||||
* and so should be read by another block. */
|
||||
if (!contains(aux.containing_e, var)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* for other cases, require that all uses of var are later in the same edge
|
||||
* or on the target AND if on target it is sole on flow coming from the
|
||||
* edge in question. */
|
||||
const GoughEdge &e = aux.containing_e.at(var);
|
||||
GoughVertex t = target(e, cfg);
|
||||
|
||||
size_t seen_outputs = 0;
|
||||
const flat_set<GoughSSAVarWithInputs *> &out = var->get_outputs();
|
||||
bool seen_var = false;
|
||||
for (const auto &e_var : cfg[e].vars) {
|
||||
if (seen_var) {
|
||||
GoughSSAVarWithInputs *w
|
||||
= dynamic_cast<GoughSSAVarWithInputs *>(e_var.get());
|
||||
if (contains(out, w)) {
|
||||
seen_outputs++;
|
||||
}
|
||||
} else {
|
||||
seen_var = var == e_var.get();
|
||||
}
|
||||
}
|
||||
assert(seen_var);
|
||||
|
||||
for (const auto &t_var : cfg[t].vars) {
|
||||
if (contains(out, t_var.get())) {
|
||||
seen_outputs++;
|
||||
const flat_set<GoughEdge> &flow = t_var->get_edges_for_input(var);
|
||||
if (flow.size() != 1 || *flow.begin() != e) {
|
||||
/* this var is used by the target join var BUT on a different
|
||||
* flow, so this is not a block local variable */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(seen_outputs <= out.size());
|
||||
return seen_outputs == out.size();
|
||||
}
|
||||
|
||||
static
|
||||
void handle_pending_edge(const GoughGraph &g, const GoughEdge &e,
|
||||
GoughSSAVar *start, set<GoughVertex> &pending_vertex,
|
||||
set<const GoughSSAVar *> &rv) {
|
||||
const vector<shared_ptr<GoughSSAVar> > &vars = g[e].vars;
|
||||
bool marking = !start;
|
||||
DEBUG_PRINTF(" ---checking edge %u->%u %s %zu\n", g[source(e, g)].state_id,
|
||||
g[target(e, g)].state_id, marking ? "full" : "partial",
|
||||
vars.size());
|
||||
for (auto it = vars.rbegin(); it != vars.rend(); ++it) {
|
||||
GoughSSAVar *var = it->get();
|
||||
if (contains(rv, var)) {
|
||||
DEBUG_PRINTF("somebody has already processed this vertex [%u]\n",
|
||||
var->slot);
|
||||
return;
|
||||
}
|
||||
if (var == start) {
|
||||
assert(!marking);
|
||||
marking = true;
|
||||
continue;
|
||||
}
|
||||
if (marking) {
|
||||
rv.insert(var);
|
||||
}
|
||||
}
|
||||
assert(marking);
|
||||
GoughVertex s = source(e, g);
|
||||
for (const auto &var : g[s].vars) {
|
||||
DEBUG_PRINTF("interferes %u\n", var->slot);
|
||||
rv.insert(var.get());
|
||||
}
|
||||
pending_vertex.insert(s);
|
||||
}
|
||||
|
||||
static
|
||||
void handle_pending_vars(GoughSSAVar *def, const GoughGraph &g,
|
||||
const GoughGraphAux &aux,
|
||||
const flat_set<GoughSSAVarWithInputs *> &pending_var,
|
||||
set<GoughVertex> &pending_vertex,
|
||||
set<const GoughSSAVar *> &rv) {
|
||||
for (GoughSSAVarWithInputs *var : pending_var) {
|
||||
if (contains(aux.containing_v, var)) {
|
||||
/* def is used by join vertex, value only needs to be live on some
|
||||
* incoming edges */
|
||||
GoughSSAVarJoin *vj = (GoughSSAVarJoin *)var;
|
||||
const flat_set<GoughEdge> &live_edges
|
||||
= vj->get_edges_for_input(def);
|
||||
for (const auto &e : live_edges) {
|
||||
handle_pending_edge(g, e, nullptr, pending_vertex, rv);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const GoughEdge &e = aux.containing_e.at(var);
|
||||
handle_pending_edge(g, e, var, pending_vertex, rv);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void handle_pending_vertex(GoughVertex def_v, const GoughGraph &g,
|
||||
GoughVertex current,
|
||||
set<GoughVertex> &pending_vertex,
|
||||
set<const GoughSSAVar *> &rv) {
|
||||
DEBUG_PRINTF("---checking vertex %u\n", g[current].state_id);
|
||||
if (def_v == current) {
|
||||
DEBUG_PRINTF("contains target vertex\n");
|
||||
return; /* we have reached def */
|
||||
}
|
||||
for (const auto &e : in_edges_range(current, g)) {
|
||||
handle_pending_edge(g, e, nullptr, pending_vertex, rv);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void handle_pending_vertices(GoughSSAVar *def, const GoughGraph &g,
|
||||
const GoughGraphAux &aux,
|
||||
set<GoughVertex> &pending_vertex,
|
||||
set<const GoughSSAVar *> &rv) {
|
||||
if (pending_vertex.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GoughVertex def_v = GoughGraph::null_vertex();
|
||||
if (contains(aux.containing_v, def)) {
|
||||
def_v = aux.containing_v.at(def);
|
||||
}
|
||||
ue2::unordered_set<GoughVertex> done;
|
||||
while (!pending_vertex.empty()) {
|
||||
GoughVertex current = *pending_vertex.begin();
|
||||
pending_vertex.erase(current);
|
||||
if (contains(done, current)) {
|
||||
continue;
|
||||
}
|
||||
done.insert(current);
|
||||
handle_pending_vertex(def_v, g, current, pending_vertex, rv);
|
||||
}
|
||||
}
|
||||
|
||||
/* returns set of labels that the given def is live at */
|
||||
static never_inline
|
||||
set<const GoughSSAVar *> live_during(GoughSSAVar *def, const GoughGraph &g,
|
||||
const GoughGraphAux &aux) {
|
||||
DEBUG_PRINTF("checking who is defined during %u lifetime\n", def->slot);
|
||||
set<GoughVertex> pending_vertex;
|
||||
|
||||
set<const GoughSSAVar *> rv;
|
||||
rv.insert(def);
|
||||
|
||||
if (contains(aux.reporters, def)) {
|
||||
DEBUG_PRINTF("--> gets reported\n");
|
||||
const set<GoughVertex> &reporters = aux.reporters.at(def);
|
||||
for (auto v : reporters) {
|
||||
pending_vertex.insert(v);
|
||||
for (const auto &var : g[v].vars) {
|
||||
DEBUG_PRINTF("interferes %u\n", var->slot);
|
||||
rv.insert(var.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle_pending_vars(def, g, aux, def->get_outputs(), pending_vertex, rv);
|
||||
handle_pending_vertices(def, g, aux, pending_vertex, rv);
|
||||
|
||||
rv.erase(def);
|
||||
return rv;
|
||||
}
|
||||
|
||||
template<typename VarP>
|
||||
void set_initial_slots(const vector<VarP> &vars, u32 *next_slot) {
|
||||
for (auto &var : vars) {
|
||||
assert(var->slot == INVALID_SLOT);
|
||||
var->slot = (*next_slot)++;
|
||||
}
|
||||
}
|
||||
|
||||
/* crude, deterministic assignment of symbolic register slots.
|
||||
* returns number of slots given out
|
||||
*/
|
||||
static
|
||||
u32 initial_slots(const GoughGraph &g) {
|
||||
u32 next_slot = 0;
|
||||
for (auto v : vertices_range(g)) {
|
||||
set_initial_slots(g[v].vars, &next_slot);
|
||||
}
|
||||
for (const auto &e : edges_range(g)) {
|
||||
set_initial_slots(g[e].vars, &next_slot);
|
||||
}
|
||||
|
||||
return next_slot;
|
||||
}
|
||||
|
||||
#define NO_COLOUR (~0U)
|
||||
|
||||
static
|
||||
u32 available_colour(const flat_set<u32> &bad_colours) {
|
||||
u32 rv = 0;
|
||||
for (const u32 &colour : bad_colours) {
|
||||
if (colour != rv) {
|
||||
assert(colour > rv);
|
||||
break;
|
||||
}
|
||||
rv = colour + 1;
|
||||
}
|
||||
|
||||
assert(rv != NO_COLOUR);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
void poison_colours(const set<const GoughSSAVar *> &live, u32 c,
|
||||
const vector<u32> &colour_map,
|
||||
vector<flat_set<u32> > *bad_colour) {
|
||||
for (const GoughSSAVar *var : live) {
|
||||
u32 var_index = var->slot;
|
||||
if (colour_map[var_index] != NO_COLOUR) {
|
||||
assert(c != colour_map[var_index]);
|
||||
} else {
|
||||
(*bad_colour)[var_index].insert(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void find_bad_due_to_live(const set<const GoughSSAVar *> &live,
|
||||
const vector<u32> &colour_map, flat_set<u32> *out) {
|
||||
for (const GoughSSAVar *var : live) {
|
||||
u32 var_index = var->slot;
|
||||
if (colour_map[var_index] != NO_COLOUR) {
|
||||
out->insert(colour_map[var_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void sequential_vertex_colouring(const GoughGraph &g, const GoughGraphAux &aux,
|
||||
const vector<GoughSSAVar *> &order,
|
||||
vector<u32> &colour_map) {
|
||||
assert(order.size() < NO_COLOUR);
|
||||
colour_map.clear();
|
||||
colour_map.resize(order.size(), NO_COLOUR);
|
||||
vector<u32> temp(order.size(), ~0U);
|
||||
vector<flat_set<u32> > bad_colour(order.size());
|
||||
|
||||
for (GoughSSAVar *var : order) {
|
||||
u32 var_index = var->slot;
|
||||
if (is_block_local(g, var, aux)) {
|
||||
DEBUG_PRINTF("%u is block local\n", var_index);
|
||||
/* ignore variable whose lifetime is limited to their local block
|
||||
* there is no need to assign stream state to these variables */
|
||||
continue;
|
||||
}
|
||||
assert(colour_map[var_index] == NO_COLOUR);
|
||||
set<const GoughSSAVar *> live = live_during(var, g, aux);
|
||||
flat_set<u32> &local_bad = bad_colour[var_index];
|
||||
find_bad_due_to_live(live, colour_map, &local_bad);
|
||||
DEBUG_PRINTF("colouring %u\n", var_index);
|
||||
u32 c = available_colour(local_bad);
|
||||
colour_map[var_index] = c;
|
||||
assert(!contains(bad_colour[var_index], c));
|
||||
poison_colours(live, c, colour_map, &bad_colour);
|
||||
|
||||
flat_set<u32> temp_set;
|
||||
local_bad.swap(temp_set);
|
||||
DEBUG_PRINTF(" %u coloured %u\n", var_index, c);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename VarP>
|
||||
void add_to_dom_ordering(const vector<VarP> &vars,
|
||||
vector<GoughSSAVar *> *out) {
|
||||
for (const auto &var : vars) {
|
||||
out->push_back(var.get());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class FinishVisitor : public boost::default_dfs_visitor {
|
||||
public:
|
||||
explicit FinishVisitor(vector<GoughVertex> *o) : out(o) {}
|
||||
void finish_vertex(const GoughVertex v, const GoughGraph &) {
|
||||
out->push_back(v);
|
||||
}
|
||||
vector<GoughVertex> *out;
|
||||
};
|
||||
}
|
||||
|
||||
static
|
||||
void find_dom_ordering(const GoughGraph &cfg, vector<GoughSSAVar *> *out) {
|
||||
vector<GoughVertex> g_order;
|
||||
|
||||
/* due to construction quirks, default vertex order provides entry points */
|
||||
depth_first_search(cfg, visitor(FinishVisitor(&g_order))
|
||||
.root_vertex(cfg[boost::graph_bundle].initial_vertex));
|
||||
|
||||
for (auto it = g_order.rbegin(); it != g_order.rend(); ++it) {
|
||||
add_to_dom_ordering(cfg[*it].vars, out);
|
||||
for (const auto &e : out_edges_range(*it, cfg)) {
|
||||
add_to_dom_ordering(cfg[e].vars, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void create_slot_mapping(const GoughGraph &cfg, UNUSED u32 old_slot_count,
|
||||
vector<u32> *old_new) {
|
||||
/* Interference graphs from SSA form are chordal -> optimally colourable in
|
||||
* poly time.
|
||||
*
|
||||
* Chordal graphs can be coloured by walking in perfect elimination order.
|
||||
* If the SSA CFG is iterated over in a way that respects dominance
|
||||
* relationship, the interference graph will be iterated in a perfect
|
||||
* elimination order.
|
||||
*
|
||||
* We can avoid creating the full interference graph and use liveness
|
||||
* information as we iterate over the definitions to perform the colouring.
|
||||
*
|
||||
* See S Hack various 2006-
|
||||
*/
|
||||
vector<GoughSSAVar *> dom_order;
|
||||
|
||||
GoughGraphAux aux;
|
||||
fill_aux(cfg, &aux);
|
||||
|
||||
find_dom_ordering(cfg, &dom_order);
|
||||
assert(dom_order.size() == old_slot_count);
|
||||
sequential_vertex_colouring(cfg, aux, dom_order, *old_new);
|
||||
}
|
||||
|
||||
static
|
||||
void update_local_slots(GoughGraph &g, set<GoughSSAVar *> &locals,
|
||||
u32 local_base) {
|
||||
DEBUG_PRINTF("%zu local variables\n", locals.size());
|
||||
/* local variables only occur on edges (joins are never local) */
|
||||
|
||||
u32 allocated_count = 0;
|
||||
for (const auto &e : edges_range(g)) {
|
||||
u32 next_slot = local_base;
|
||||
for (auto &var : g[e].vars) {
|
||||
if (contains(locals, var.get())) {
|
||||
DEBUG_PRINTF("updating slot %u using local %u\n", var->slot,
|
||||
next_slot);
|
||||
var->slot = next_slot++;
|
||||
allocated_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(allocated_count == locals.size());
|
||||
}
|
||||
|
||||
static never_inline
|
||||
u32 update_slots(GoughGraph &g, const vector<u32> &old_new,
|
||||
UNUSED u32 old_slot_count) {
|
||||
vector<GoughSSAVar *> vars;
|
||||
set<GoughSSAVar *> locals;
|
||||
all_vars(g, &vars);
|
||||
u32 slot_count = 0;
|
||||
for (GoughSSAVar *v : vars) {
|
||||
assert(v->slot < old_new.size());
|
||||
DEBUG_PRINTF("updating slot %u to %u\n", v->slot, old_new[v->slot]);
|
||||
if (old_new[v->slot] != NO_COLOUR) { /* not local, assign final slot */
|
||||
v->slot = old_new[v->slot];
|
||||
ENSURE_AT_LEAST(&slot_count, v->slot + 1);
|
||||
} else {
|
||||
locals.insert(v);
|
||||
}
|
||||
}
|
||||
assert(slot_count <= old_slot_count);
|
||||
DEBUG_PRINTF("reduce stream slots from %u to %u\n", old_slot_count,
|
||||
slot_count);
|
||||
update_local_slots(g, locals, slot_count);
|
||||
|
||||
return slot_count;
|
||||
}
|
||||
|
||||
u32 assign_slots(GoughGraph &cfg, const Grey &grey) {
|
||||
u32 slot_count = initial_slots(cfg);
|
||||
|
||||
if (!grey.goughRegisterAllocate) {
|
||||
return slot_count;
|
||||
}
|
||||
dump(cfg, "slots_pre", grey);
|
||||
|
||||
vector<u32> old_new;
|
||||
create_slot_mapping(cfg, slot_count, &old_new);
|
||||
slot_count = update_slots(cfg, old_new, slot_count);
|
||||
|
||||
return slot_count;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
349
src/nfa/goughdump.cpp
Normal file
349
src/nfa/goughdump.cpp
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "goughdump.h"
|
||||
|
||||
#include "gough_internal.h"
|
||||
#include "mcclellandump.h"
|
||||
#include "nfa_dump_internal.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/dump_charclass.h"
|
||||
#include "util/unaligned.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
static
|
||||
void goughGetTransitions(const NFA *n, u16 s, u16 *t) {
|
||||
assert(isGoughType(n->type));
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(n);
|
||||
const mstate_aux *aux = getAux(n, s);
|
||||
const u32 as = m->alphaShift;
|
||||
const char *sher_base
|
||||
= (const char *)m - sizeof(struct NFA) + m->sherman_offset;
|
||||
|
||||
if (n->type == GOUGH_NFA_8) {
|
||||
const u8 *succ_table = (const u8 *)((const char *)m + sizeof(mcclellan));
|
||||
for (u16 c = 0; c < N_CHARS; c++) {
|
||||
t[c] = succ_table[((u32)s << as) + m->remap[c]];
|
||||
}
|
||||
} else {
|
||||
u16 base_s = s;
|
||||
|
||||
if (s >= m->sherman_limit) {
|
||||
const char *state_base
|
||||
= findShermanState(m, sher_base, m->sherman_limit, s);
|
||||
base_s = *(const u16 *)(state_base + SHERMAN_DADDY_OFFSET);
|
||||
}
|
||||
|
||||
const u16 *succ_table = (const u16 *)((const char *)m
|
||||
+ sizeof(mcclellan));
|
||||
for (u16 c = 0; c < N_CHARS; c++) {
|
||||
const u8 *addr
|
||||
= (const u8*)(succ_table + (((u32)base_s << as) + m->remap[c]));
|
||||
t[c] = unaligned_load_u16(addr);
|
||||
t[c] &= STATE_MASK;
|
||||
}
|
||||
|
||||
if (s >= m->sherman_limit) {
|
||||
const char *state_base
|
||||
= findShermanState(m, sher_base, m->sherman_limit, s);
|
||||
u8 len = *(const u8 *)(SHERMAN_LEN_OFFSET + state_base);
|
||||
const u8 *chars = (const u8 *)state_base + SHERMAN_CHARS_OFFSET;
|
||||
const u16 *states
|
||||
= (const u16 *)(state_base + SHERMAN_STATES_OFFSET(len));
|
||||
|
||||
for (u8 i = 0; i < len; i++) {
|
||||
for (u16 c = 0; c < N_CHARS; c++) {
|
||||
if (m->remap[c] != chars[i]) {
|
||||
t[c] = unaligned_load_u16((const u8*)&states[i])
|
||||
& STATE_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t[TOP] = aux->top & STATE_MASK;
|
||||
}
|
||||
|
||||
static
|
||||
void describeNode(const NFA *n, const mcclellan *m, u16 i, FILE *f) {
|
||||
const mstate_aux *aux = getAux(n, i);
|
||||
|
||||
bool isSherman = m->sherman_limit && i >= m->sherman_limit;
|
||||
const char *sher_base
|
||||
= (const char *)m - sizeof(NFA) + m->sherman_offset;
|
||||
|
||||
fprintf(f, "%u [ width = 1, fixedsize = true, fontsize = 12, "
|
||||
"label = \"%u%s\" ]; \n", i, i, isSherman ? "w":"");
|
||||
|
||||
if (aux->accel_offset) {
|
||||
dumpAccelDot(f, i,
|
||||
&((const gough_accel *)((const char *)m + aux->accel_offset))->accel);
|
||||
}
|
||||
|
||||
if (aux->accept_eod) {
|
||||
fprintf(f, "%u [ color = darkorchid ];\n", i);
|
||||
}
|
||||
|
||||
if (aux->accept) {
|
||||
fprintf(f, "%u [ shape = doublecircle ];\n", i);
|
||||
}
|
||||
|
||||
if (aux->top && aux->top != i) {
|
||||
fprintf(f, "%u -> %u [color = darkgoldenrod weight=0.1 ]\n", i,
|
||||
aux->top);
|
||||
}
|
||||
|
||||
if (i == m->start_anchored) {
|
||||
fprintf(f, "STARTA -> %u [color = blue ]\n", i);
|
||||
}
|
||||
|
||||
if (i == m->start_floating) {
|
||||
fprintf(f, "STARTF -> %u [color = red ]\n", i);
|
||||
}
|
||||
|
||||
if (isSherman) {
|
||||
const char *sherman_state
|
||||
= findShermanState(m, sher_base, m->sherman_limit, i);
|
||||
fprintf(f, "%u [ fillcolor = lightblue style=filled ];\n", i);
|
||||
u16 daddy = *(const u16 *)(sherman_state + SHERMAN_DADDY_OFFSET);
|
||||
if (daddy) {
|
||||
fprintf(f, "%u -> %u [ color=royalblue style=dashed weight=0.1]\n",
|
||||
i, daddy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dump_program(FILE *f, const pair<u32, u32> &e, const gough_ins *prog) {
|
||||
fprintf(f, "edge_%u_%u:\n", e.first, e.second);
|
||||
for (const gough_ins *it = prog;; ++it) {
|
||||
fprintf(f, "\t");
|
||||
u32 s = it->src;
|
||||
u32 d = it->dest;
|
||||
switch (it->op) {
|
||||
case GOUGH_INS_END:
|
||||
fprintf(f, "END");
|
||||
fprintf(f, "\n");
|
||||
return;
|
||||
case GOUGH_INS_MOV:
|
||||
fprintf(f, "MOV %u %u", d, s);
|
||||
break;
|
||||
case GOUGH_INS_NEW:
|
||||
fprintf(f, "NEW-%u %u", s, d);
|
||||
break;
|
||||
case GOUGH_INS_MIN:
|
||||
fprintf(f, "MIN %u %u", d, s);
|
||||
break;
|
||||
default:
|
||||
fprintf(f, "<UNKNOWN>");
|
||||
fprintf(f, "\n");
|
||||
return;
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dump_programs(FILE *f, const NFA *nfa,
|
||||
const set<pair<pair<u32, u32>, u32 > > &prog_dump) {
|
||||
fprintf(f, "Edge Programs\n");
|
||||
fprintf(f, "-------------\n");
|
||||
for (set<pair<pair<u32, u32>, u32 > >::const_iterator it
|
||||
= prog_dump.begin(); it != prog_dump.end(); ++it) {
|
||||
assert(it->second);
|
||||
const gough_ins *p = (const gough_ins *)((const u8 *)nfa + it->second);
|
||||
dump_program(f, it->first, p);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dumpTransitions(const NFA *nfa, FILE *f,
|
||||
set<pair<pair<u32, u32>, u32 > > *prog_dump) {
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
const gough_info *g = get_gough(m);
|
||||
u32 alphaSize = 1U << m->alphaShift;
|
||||
const u32 *prog_offset_table = (const u32 *)(g + 1);
|
||||
|
||||
for (u16 i = 0; i < m->state_count; i++) {
|
||||
fprintf(f, "%05hu", i);
|
||||
const mstate_aux *aux = getAux(nfa, i);
|
||||
|
||||
if (aux->accel_offset) {
|
||||
dumpAccelText(f, (const union AccelAux *)((const char *)m +
|
||||
aux->accel_offset));
|
||||
}
|
||||
|
||||
u16 trans[ALPHABET_SIZE];
|
||||
goughGetTransitions(nfa, i, trans);
|
||||
|
||||
int rstart = 0;
|
||||
u16 prev = 0xffff;
|
||||
for (int j = 0; j < N_CHARS; j++) {
|
||||
u16 curr = trans[j];
|
||||
if (curr == prev) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev != 0xffff) {
|
||||
if (j == rstart + 1) {
|
||||
fprintf(f, " %02x->%hu", rstart, prev);
|
||||
} else {
|
||||
fprintf(f, " [%02x - %02x]->%hu", rstart, j - 1, prev);
|
||||
}
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
rstart = j;
|
||||
|
||||
u32 edge_index = i * alphaSize + m->remap[j];
|
||||
u32 prog_offset = prog_offset_table[edge_index];
|
||||
if (prog_offset) {
|
||||
prog_dump->insert(make_pair(make_pair((u32)i, (u32)trans[j]),
|
||||
prog_offset));
|
||||
}
|
||||
}
|
||||
if (N_CHARS == rstart + 1) {
|
||||
fprintf(f, " %02x->%hu", rstart, prev);
|
||||
} else {
|
||||
fprintf(f, " [%02x - %02x]->%hu", rstart, N_CHARS - 1, prev);
|
||||
}
|
||||
fprintf(f, " TOP->%hu\n", trans[TOP]);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
void nfaExecGough8_dumpDot(const struct NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == GOUGH_NFA_8);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
|
||||
dumpDotPreambleDfa(f);
|
||||
|
||||
for (u16 i = 1; i < m->state_count; i++) {
|
||||
describeNode(nfa, m, i, f);
|
||||
|
||||
u16 t[ALPHABET_SIZE];
|
||||
|
||||
goughGetTransitions(nfa, i, t);
|
||||
|
||||
describeEdge(f, t, i);
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
}
|
||||
|
||||
void nfaExecGough8_dumpText(const struct NFA *nfa, FILE *f) {
|
||||
|
||||
assert(nfa->type == GOUGH_NFA_8);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
|
||||
fprintf(f, "gough 8\n");
|
||||
fprintf(f, "report: %u, states %u, length %u\n", m->arb_report,
|
||||
m->state_count, m->length);
|
||||
fprintf(f, "astart: %hu, fstart %hu\n", m->start_anchored,
|
||||
m->start_floating);
|
||||
fprintf(f, "accel_limit: %hu, accept_limit %hu\n", m->accel_limit_8,
|
||||
m->accept_limit_8);
|
||||
fprintf(f, "\n");
|
||||
|
||||
describeAlphabet(f, m);
|
||||
|
||||
set<pair<pair<u32, u32>, u32 > > prog_dump;
|
||||
|
||||
dumpTransitions(nfa, f, &prog_dump);
|
||||
dump_programs(f, nfa, prog_dump);
|
||||
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
void nfaExecGough16_dumpDot(const struct NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == GOUGH_NFA_16);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
|
||||
dumpDotPreambleDfa(f);
|
||||
|
||||
for (u16 i = 1; i < m->state_count; i++) {
|
||||
describeNode(nfa, m, i, f);
|
||||
|
||||
u16 t[ALPHABET_SIZE];
|
||||
|
||||
goughGetTransitions(nfa, i, t);
|
||||
|
||||
describeEdge(f, t, i);
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
}
|
||||
|
||||
void nfaExecGough16_dumpText(const struct NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == GOUGH_NFA_16);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
// const gough_info *h = get_gough(m);
|
||||
|
||||
fprintf(f, "gough 16\n");
|
||||
fprintf(f, "report: %u, states: %u, length: %u\n", m->arb_report,
|
||||
m->state_count, m->length);
|
||||
fprintf(f, "astart: %hu, fstart: %hu\n", m->start_anchored,
|
||||
m->start_floating);
|
||||
fprintf(f, "single accept: %d\n", !!(int)m->flags & MCCLELLAN_FLAG_SINGLE);
|
||||
fprintf(f, "sherman_limit: %u, sherman_end: %u\n", m->sherman_limit,
|
||||
m->sherman_end);
|
||||
|
||||
describeAlphabet(f, m);
|
||||
|
||||
set<pair<pair<u32, u32>, u32 > > prog_dump;
|
||||
|
||||
dumpTransitions(nfa, f, &prog_dump);
|
||||
dump_programs(f, nfa, prog_dump);
|
||||
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
49
src/nfa/goughdump.h
Normal file
49
src/nfa/goughdump.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef GOUGH_DUMP_H
|
||||
#define GOUGH_DUMP_H
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecGough8_dumpDot(const NFA *nfa, FILE *file);
|
||||
void nfaExecGough16_dumpDot(const NFA *nfa, FILE *file);
|
||||
void nfaExecGough8_dumpText(const NFA *nfa, FILE *file);
|
||||
void nfaExecGough16_dumpText(const NFA *nfa, FILE *file);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
527
src/nfa/lbr.c
Normal file
527
src/nfa/lbr.c
Normal file
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Large Bounded Repeat (LBR) engine: runtime code.
|
||||
*/
|
||||
#include "lbr.h"
|
||||
|
||||
#include "lbr_internal.h"
|
||||
#include "nfa_api.h"
|
||||
#include "nfa_api_queue.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "repeat.h"
|
||||
#include "repeat_internal.h"
|
||||
#include "shufti.h"
|
||||
#include "truffle.h"
|
||||
#include "vermicelli.h"
|
||||
#include "util/partial_store.h"
|
||||
#include "util/unaligned.h"
|
||||
|
||||
/** \brief Sentinel value used to indicate that a repeat is dead/empty/unused.
|
||||
* * */
|
||||
#define REPEAT_DEAD 0xffffffffffffffffull
|
||||
|
||||
enum MatchMode {
|
||||
CALLBACK_OUTPUT,
|
||||
STOP_AT_MATCH,
|
||||
};
|
||||
|
||||
static really_inline
|
||||
const struct RepeatInfo *getRepeatInfo(const struct lbr_common *l) {
|
||||
const struct RepeatInfo *repeatInfo =
|
||||
(const struct RepeatInfo *)((const char *)l + l->repeatInfoOffset);
|
||||
return repeatInfo;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void lbrCompressState(const struct lbr_common *l, u64a offset,
|
||||
const struct lbr_state *lstate, char *stream_state) {
|
||||
assert(l && lstate && stream_state);
|
||||
assert(ISALIGNED(lstate));
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
repeatPack(stream_state, info, &lstate->ctrl, offset);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void lbrExpandState(const struct lbr_common *l, u64a offset,
|
||||
const char *stream_state, struct lbr_state *lstate) {
|
||||
assert(l && stream_state && lstate);
|
||||
assert(ISALIGNED(lstate));
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
repeatUnpack(stream_state, info, offset, &lstate->ctrl);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void clearRepeat(const struct RepeatInfo *info, struct lbr_state *lstate) {
|
||||
assert(info && lstate);
|
||||
|
||||
DEBUG_PRINTF("clear repeat at %p\n", lstate);
|
||||
|
||||
switch ((enum RepeatType)info->type) {
|
||||
case REPEAT_RING:
|
||||
lstate->ctrl.ring.offset = REPEAT_DEAD;
|
||||
break;
|
||||
case REPEAT_RANGE:
|
||||
lstate->ctrl.range.offset = REPEAT_DEAD;
|
||||
break;
|
||||
case REPEAT_FIRST:
|
||||
case REPEAT_LAST:
|
||||
lstate->ctrl.offset.offset = REPEAT_DEAD;
|
||||
break;
|
||||
case REPEAT_BITMAP:
|
||||
lstate->ctrl.bitmap.offset = REPEAT_DEAD;
|
||||
break;
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
lstate->ctrl.ring.offset = REPEAT_DEAD;
|
||||
break;
|
||||
case REPEAT_TRAILER:
|
||||
lstate->ctrl.trailer.offset = REPEAT_DEAD;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char repeatIsDead(const struct RepeatInfo *info,
|
||||
const struct lbr_state *lstate) {
|
||||
assert(info && lstate);
|
||||
|
||||
switch ((enum RepeatType)info->type) {
|
||||
case REPEAT_RING:
|
||||
return lstate->ctrl.ring.offset == REPEAT_DEAD;
|
||||
case REPEAT_RANGE:
|
||||
return lstate->ctrl.range.offset == REPEAT_DEAD;
|
||||
case REPEAT_FIRST:
|
||||
case REPEAT_LAST:
|
||||
return lstate->ctrl.offset.offset == REPEAT_DEAD;
|
||||
case REPEAT_BITMAP:
|
||||
return lstate->ctrl.bitmap.offset == REPEAT_DEAD;
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
return lstate->ctrl.ring.offset == REPEAT_DEAD;
|
||||
case REPEAT_TRAILER:
|
||||
return lstate->ctrl.trailer.offset == REPEAT_DEAD;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Returns true if the LBR can produce matches at offsets greater than the
|
||||
* given one. TODO: can this be combined with lbrIsActive? */
|
||||
static really_inline
|
||||
char lbrIsAlive(const struct lbr_common *l, const struct lbr_state *lstate,
|
||||
const char *state, u64a offset) {
|
||||
assert(l && lstate && state);
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
DEBUG_PRINTF("repeat is dead\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->repeatMax == REPEAT_INF) {
|
||||
DEBUG_PRINTF("active repeat with inf max bound, alive\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(info->repeatMax < REPEAT_INF);
|
||||
const char *repeatState = state + info->packedCtrlSize;
|
||||
u64a lastTop = repeatLastTop(info, &lstate->ctrl, repeatState);
|
||||
if (offset < lastTop + info->repeatMax) {
|
||||
DEBUG_PRINTF("alive, as we can still produce matches after %llu\n",
|
||||
offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("dead\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns true if the LBR is matching at the given offset or it could produce
|
||||
* a match in the future. */
|
||||
static really_inline
|
||||
char lbrIsActive(const struct lbr_common *l, const struct lbr_state *lstate,
|
||||
const char *state, u64a offset) {
|
||||
assert(l && lstate && state);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
assert(!repeatIsDead(info, lstate)); // Guaranteed by caller.
|
||||
|
||||
const char *repeatState = state + info->packedCtrlSize;
|
||||
if (repeatHasMatch(info, &lstate->ctrl, repeatState, offset) ==
|
||||
REPEAT_MATCH) {
|
||||
DEBUG_PRINTF("currently matching\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
u64a i = repeatNextMatch(info, &lstate->ctrl, repeatState, offset);
|
||||
if (i != 0) {
|
||||
DEBUG_PRINTF("active, next match is at %llu\n", i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("no more matches\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void lbrTop(const struct lbr_common *l, struct lbr_state *lstate, char *state,
|
||||
u64a offset) {
|
||||
assert(l && lstate && state);
|
||||
DEBUG_PRINTF("top at %llu\n", offset);
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
char *repeatState = state + info->packedCtrlSize;
|
||||
|
||||
char is_alive = !repeatIsDead(info, lstate);
|
||||
if (is_alive) {
|
||||
// Ignore duplicate TOPs.
|
||||
u64a last = repeatLastTop(info, &lstate->ctrl, repeatState);
|
||||
assert(last <= offset);
|
||||
if (last == offset) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
repeatStore(info, &lstate->ctrl, repeatState, offset, is_alive);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrInAccept(const struct lbr_common *l, const struct lbr_state *lstate,
|
||||
const char *state, u64a offset, ReportID report) {
|
||||
assert(l && lstate && state);
|
||||
DEBUG_PRINTF("offset=%llu, report=%u\n", offset, report);
|
||||
|
||||
if (report != l->report) {
|
||||
DEBUG_PRINTF("report=%u is not LBR report %u\n", report, l->report);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
assert(!repeatIsDead(info, lstate)); // Guaranteed by caller.
|
||||
|
||||
const char *repeatState = state + info->packedCtrlSize;
|
||||
return repeatHasMatch(info, &lstate->ctrl, repeatState, offset) ==
|
||||
REPEAT_MATCH;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrFindMatch(const struct lbr_common *l, const u64a begin, const u64a end,
|
||||
const struct lbr_state *lstate, const char *state,
|
||||
size_t *mloc) {
|
||||
DEBUG_PRINTF("begin=%llu, end=%llu\n", begin, end);
|
||||
assert(begin <= end);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
const char *repeatState = state + info->packedCtrlSize;
|
||||
u64a i = repeatNextMatch(info, &lstate->ctrl, repeatState, begin);
|
||||
if (i == 0) {
|
||||
DEBUG_PRINTF("no more matches\n");
|
||||
return 0;
|
||||
}
|
||||
if (i > end) {
|
||||
DEBUG_PRINTF("next match at %llu is beyond the horizon\n", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("stop at match at %llu\n", i);
|
||||
assert(mloc);
|
||||
*mloc = i - begin;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrMatchLoop(const struct lbr_common *l, const u64a begin, const u64a end,
|
||||
const struct lbr_state *lstate, const char *state,
|
||||
NfaCallback cb, void *ctx) {
|
||||
DEBUG_PRINTF("begin=%llu, end=%llu\n", begin, end);
|
||||
assert(begin <= end);
|
||||
|
||||
if (begin == end) {
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
const char *repeatState = state + info->packedCtrlSize;
|
||||
|
||||
u64a i = begin;
|
||||
for (;;) {
|
||||
i = repeatNextMatch(info, &lstate->ctrl, repeatState, i);
|
||||
if (i == 0) {
|
||||
DEBUG_PRINTF("no more matches\n");
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
if (i > end) {
|
||||
DEBUG_PRINTF("next match at %llu is beyond the horizon\n", i);
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("firing match at %llu\n", i);
|
||||
if (cb(i, l->report, ctx) == MO_HALT_MATCHING) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrRevScanDot(UNUSED const struct NFA *nfa, UNUSED const u8 *buf,
|
||||
UNUSED size_t begin, UNUSED size_t end,
|
||||
UNUSED size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Dot);
|
||||
// Nothing can kill a dot!
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrRevScanVerm(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end, size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Verm);
|
||||
const struct lbr_verm *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = rvermicelliExec(l->c, 0, buf + begin, buf + end);
|
||||
if (ptr == buf + begin - 1) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
assert((char)*ptr == l->c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrRevScanNVerm(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end, size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_NVerm);
|
||||
const struct lbr_verm *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = rnvermicelliExec(l->c, 0, buf + begin, buf + end);
|
||||
if (ptr == buf + begin - 1) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
assert((char)*ptr != l->c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrRevScanShuf(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end,
|
||||
size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Shuf);
|
||||
const struct lbr_shuf *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = rshuftiExec(l->mask_lo, l->mask_hi, buf + begin, buf + end);
|
||||
if (ptr == buf + begin - 1) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrRevScanTruf(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end,
|
||||
size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Truf);
|
||||
const struct lbr_truf *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = rtruffleExec(l->mask1, l->mask2, buf + begin, buf + end);
|
||||
if (ptr == buf + begin - 1) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrFwdScanDot(UNUSED const struct NFA *nfa, UNUSED const u8 *buf,
|
||||
UNUSED size_t begin, UNUSED size_t end,
|
||||
UNUSED size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Dot);
|
||||
// Nothing can kill a dot!
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrFwdScanVerm(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end, size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Verm);
|
||||
const struct lbr_verm *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = vermicelliExec(l->c, 0, buf + begin, buf + end);
|
||||
if (ptr == buf + end) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
assert((char)*ptr == l->c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrFwdScanNVerm(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end, size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_NVerm);
|
||||
const struct lbr_verm *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = nvermicelliExec(l->c, 0, buf + begin, buf + end);
|
||||
if (ptr == buf + end) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
assert((char)*ptr != l->c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrFwdScanShuf(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end,
|
||||
size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Shuf);
|
||||
const struct lbr_shuf *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = shuftiExec(l->mask_lo, l->mask_hi, buf + begin, buf + end);
|
||||
if (ptr == buf + end) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char lbrFwdScanTruf(const struct NFA *nfa, const u8 *buf,
|
||||
size_t begin, size_t end,
|
||||
size_t *loc) {
|
||||
assert(begin <= end);
|
||||
assert(nfa->type == LBR_NFA_Truf);
|
||||
const struct lbr_truf *l = getImplNfa(nfa);
|
||||
|
||||
if (begin == end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 *ptr = truffleExec(l->mask1, l->mask2, buf + begin, buf + end);
|
||||
if (ptr == buf + end) {
|
||||
DEBUG_PRINTF("no escape found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(loc);
|
||||
*loc = (size_t)(ptr - buf);
|
||||
DEBUG_PRINTF("escape found at offset %zu\n", *loc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define ENGINE_ROOT_NAME Dot
|
||||
#include "lbr_common_impl.h"
|
||||
|
||||
#define ENGINE_ROOT_NAME Verm
|
||||
#include "lbr_common_impl.h"
|
||||
|
||||
#define ENGINE_ROOT_NAME NVerm
|
||||
#include "lbr_common_impl.h"
|
||||
|
||||
#define ENGINE_ROOT_NAME Shuf
|
||||
#include "lbr_common_impl.h"
|
||||
|
||||
#define ENGINE_ROOT_NAME Truf
|
||||
#include "lbr_common_impl.h"
|
||||
145
src/nfa/lbr.h
Normal file
145
src/nfa/lbr.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef LBR_H
|
||||
#define LBR_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
struct mq;
|
||||
struct NFA;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// LBR Dot
|
||||
|
||||
char nfaExecLbrDot_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrDot_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrDot_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecLbrDot_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrDot_inAccept(const struct NFA *n, ReportID report, struct mq *q);
|
||||
char nfaExecLbrDot_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrDot_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecLbrDot_queueCompressState(const struct NFA *nfa, const struct mq *q,
|
||||
s64a loc);
|
||||
char nfaExecLbrDot_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecLbrDot_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecLbrDot_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecLbrDot_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
// LBR Verm
|
||||
|
||||
char nfaExecLbrVerm_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrVerm_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrVerm_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecLbrVerm_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrVerm_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecLbrVerm_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrVerm_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecLbrVerm_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecLbrVerm_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecLbrVerm_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecLbrVerm_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecLbrVerm_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
// LBR Negated Verm
|
||||
|
||||
char nfaExecLbrNVerm_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrNVerm_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrNVerm_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecLbrNVerm_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrNVerm_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecLbrNVerm_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrNVerm_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecLbrNVerm_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecLbrNVerm_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecLbrNVerm_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecLbrNVerm_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecLbrNVerm_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
// LBR Shuf
|
||||
|
||||
char nfaExecLbrShuf_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrShuf_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrShuf_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecLbrShuf_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrShuf_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecLbrShuf_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrShuf_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecLbrShuf_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecLbrShuf_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecLbrShuf_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecLbrShuf_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecLbrShuf_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
// LBR Truffle
|
||||
|
||||
char nfaExecLbrTruf_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrTruf_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecLbrTruf_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecLbrTruf_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrTruf_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecLbrTruf_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecLbrTruf_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecLbrTruf_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecLbrTruf_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecLbrTruf_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecLbrTruf_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecLbrTruf_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
453
src/nfa/lbr_common_impl.h
Normal file
453
src/nfa/lbr_common_impl.h
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Large Bounded Repeat (LBR) engine: runtime impl X-macros.
|
||||
*/
|
||||
|
||||
#include "util/join.h"
|
||||
|
||||
#define ENGINE_EXEC_NAME JOIN(nfaExecLbr, ENGINE_ROOT_NAME)
|
||||
#define EXEC_FN JOIN(lbrExec, ENGINE_ROOT_NAME)
|
||||
#define FWDSCAN_FN JOIN(lbrFwdScan, ENGINE_ROOT_NAME)
|
||||
#define REVSCAN_FN JOIN(lbrRevScan, ENGINE_ROOT_NAME)
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _queueCompressState)(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc) {
|
||||
assert(nfa && q);
|
||||
assert(isLbrType(nfa->type));
|
||||
DEBUG_PRINTF("entry, q->offset=%llu, loc=%lld\n", q->offset, loc);
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct lbr_state *lstate = (const struct lbr_state *)q->state;
|
||||
|
||||
u64a offset = q->offset + loc;
|
||||
lbrCompressState(l, offset, lstate, q->streamState);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _expandState)(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset,
|
||||
UNUSED u8 key) {
|
||||
assert(nfa);
|
||||
assert(isLbrType(nfa->type));
|
||||
DEBUG_PRINTF("entry, offset=%llu\n", offset);
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
struct lbr_state *lstate = (struct lbr_state *)dest;
|
||||
lbrExpandState(l, offset, src, lstate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _reportCurrent)(const struct NFA *nfa,
|
||||
struct mq *q) {
|
||||
assert(nfa && q);
|
||||
assert(isLbrType(nfa->type));
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
u64a offset = q_cur_offset(q);
|
||||
DEBUG_PRINTF("firing match %u at %llu\n", l->report, offset);
|
||||
q->cb(offset, l->report, q->context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _inAccept)(const struct NFA *nfa,
|
||||
ReportID report, struct mq *q) {
|
||||
assert(nfa && q);
|
||||
assert(isLbrType(nfa->type));
|
||||
DEBUG_PRINTF("entry\n");
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
const struct lbr_state *lstate = (const struct lbr_state *)q->state;
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
DEBUG_PRINTF("repeat is dead\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64a offset = q->offset + q_last_loc(q);
|
||||
return lbrInAccept(l, lstate, q->streamState, offset, report);
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _queueInitState)(const struct NFA *nfa,
|
||||
struct mq *q) {
|
||||
assert(nfa && q);
|
||||
assert(isLbrType(nfa->type));
|
||||
DEBUG_PRINTF("entry\n");
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
|
||||
assert(q->state);
|
||||
struct lbr_state *lstate = (struct lbr_state *)q->state;
|
||||
assert(ISALIGNED(lstate));
|
||||
|
||||
lstate->lastEscape = 0;
|
||||
clearRepeat(info, lstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _initCompressedState)(const struct NFA *nfa,
|
||||
u64a offset,
|
||||
void *state, UNUSED u8 key) {
|
||||
assert(nfa && state);
|
||||
assert(isLbrType(nfa->type));
|
||||
DEBUG_PRINTF("entry\n");
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
struct lbr_state lstate; // temp control block on stack.
|
||||
clearRepeat(info, &lstate);
|
||||
lbrTop(l, &lstate, state, offset);
|
||||
lbrCompressState(l, offset, &lstate, state);
|
||||
|
||||
return 1; // LBR is alive
|
||||
}
|
||||
|
||||
// FIXME: this function could be much simpler for a Dot LBR, as all it needs to
|
||||
// do is find the next top.
|
||||
static really_inline
|
||||
char JOIN(ENGINE_EXEC_NAME, _TopScan)(const struct NFA *nfa, struct mq *q,
|
||||
s64a end) {
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
|
||||
const u64a offset = q->offset;
|
||||
struct lbr_state *lstate = (struct lbr_state *)q->state;
|
||||
assert(ISALIGNED(lstate));
|
||||
|
||||
assert(repeatIsDead(info, lstate));
|
||||
assert(q->cur < q->end);
|
||||
|
||||
DEBUG_PRINTF("entry, end=%lld, offset=%llu, lastEscape=%llu\n", end,
|
||||
offset, lstate->lastEscape);
|
||||
|
||||
while (1) {
|
||||
// Find the next top with location >= the last escape we saw.
|
||||
for (; q->cur < q->end && q_cur_loc(q) <= end; q->cur++) {
|
||||
enum mqe_event t = q_cur_type(q);
|
||||
if ((t == MQE_TOP || t == MQE_TOP_FIRST) &&
|
||||
q_cur_offset(q) >= lstate->lastEscape) {
|
||||
goto found_top;
|
||||
}
|
||||
DEBUG_PRINTF("skip event type=%d offset=%lld\n", t, q_cur_offset(q));
|
||||
}
|
||||
|
||||
// No more tops, we're done.
|
||||
break;
|
||||
|
||||
found_top:;
|
||||
assert(q->cur < q->end);
|
||||
|
||||
u64a sp = q_cur_offset(q);
|
||||
u64a first_match = sp + info->repeatMin;
|
||||
DEBUG_PRINTF("first possible match is at %llu\n", first_match);
|
||||
|
||||
u64a ep = MIN(MIN(end, (s64a)q->length) + offset, first_match);
|
||||
if (ep > sp && sp >= offset) {
|
||||
size_t eloc;
|
||||
DEBUG_PRINTF("rev b%llu e%llu/%zu\n", sp - offset, ep - offset,
|
||||
q->length);
|
||||
assert(ep - offset <= q->length);
|
||||
if (REVSCAN_FN(nfa, q->buffer, sp - offset, ep - offset, &eloc)) {
|
||||
DEBUG_PRINTF("escape found at %llu\n", offset + eloc);
|
||||
lstate->lastEscape = eloc;
|
||||
q->cur++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lbrTop(l, lstate, q->streamState, sp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("exhausted queue\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char JOIN(ENGINE_EXEC_NAME, _Q_i)(const struct NFA *nfa, struct mq *q,
|
||||
s64a end, enum MatchMode mode) {
|
||||
assert(nfa && q);
|
||||
assert(isLbrType(nfa->type));
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
|
||||
struct lbr_state *lstate = (struct lbr_state *)q->state;
|
||||
assert(ISALIGNED(lstate));
|
||||
|
||||
|
||||
if (q->report_current) {
|
||||
DEBUG_PRINTF("report_current: fire match at %llu\n", q_cur_offset(q));
|
||||
int rv = q->cb(q_cur_offset(q), l->report, q->context);
|
||||
q->report_current = 0;
|
||||
if (rv == MO_HALT_MATCHING) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
if (q->cur == q->end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(q->cur + 1 < q->end); /* require at least two items */
|
||||
assert(q_cur_type(q) == MQE_START);
|
||||
u64a sp = q_cur_offset(q);
|
||||
q->cur++;
|
||||
DEBUG_PRINTF("sp=%llu, abs_end=%llu\n", sp, end + q->offset);
|
||||
|
||||
while (q->cur < q->end) {
|
||||
DEBUG_PRINTF("q item type=%d offset=%llu\n", q_cur_type(q),
|
||||
q_cur_offset(q));
|
||||
|
||||
assert(sp >= q->offset); // not in history
|
||||
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
DEBUG_PRINTF("repeat is currently dead, skipping scan\n");
|
||||
goto scan_done;
|
||||
}
|
||||
|
||||
u64a ep = q_cur_offset(q);
|
||||
ep = MIN(ep, q->offset + end);
|
||||
if (sp < ep) {
|
||||
size_t eloc = 0;
|
||||
char escape_found = 0;
|
||||
DEBUG_PRINTF("scanning from sp=%llu to ep=%llu\n", sp, ep);
|
||||
assert(sp >= q->offset && ep >= q->offset);
|
||||
if (FWDSCAN_FN(nfa, q->buffer, sp - q->offset, ep - q->offset, &eloc)) {
|
||||
escape_found = 1;
|
||||
ep = q->offset + eloc;
|
||||
DEBUG_PRINTF("escape found at %llu\n", ep);
|
||||
assert(ep >= sp);
|
||||
}
|
||||
|
||||
assert(sp <= ep);
|
||||
|
||||
if (mode == STOP_AT_MATCH) {
|
||||
size_t mloc;
|
||||
if (lbrFindMatch(l, sp, ep, lstate, q->streamState, &mloc)) {
|
||||
DEBUG_PRINTF("storing match at %llu\n", sp + mloc);
|
||||
q->cur--;
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
q->items[q->cur].type = MQE_START;
|
||||
q->items[q->cur].location = (s64a)(sp - q->offset) + mloc;
|
||||
return MO_MATCHES_PENDING;
|
||||
}
|
||||
} else {
|
||||
assert(mode == CALLBACK_OUTPUT);
|
||||
char rv = lbrMatchLoop(l, sp, ep, lstate, q->streamState, q->cb,
|
||||
q->context);
|
||||
if (rv == MO_HALT_MATCHING) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
assert(rv == MO_CONTINUE_MATCHING);
|
||||
}
|
||||
|
||||
if (escape_found) {
|
||||
DEBUG_PRINTF("clearing repeat due to escape\n");
|
||||
clearRepeat(info, lstate);
|
||||
}
|
||||
}
|
||||
|
||||
scan_done:
|
||||
if (q_cur_loc(q) > end) {
|
||||
q->cur--;
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
q->items[q->cur].type = MQE_START;
|
||||
q->items[q->cur].location = end;
|
||||
return MO_ALIVE;
|
||||
}
|
||||
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
if (!JOIN(ENGINE_EXEC_NAME, _TopScan)(nfa, q, end)) {
|
||||
assert(repeatIsDead(info, lstate));
|
||||
if (q->cur < q->end && q_cur_loc(q) > end) {
|
||||
q->cur--;
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
q->items[q->cur].type = MQE_START;
|
||||
q->items[q->cur].location = end;
|
||||
return MO_ALIVE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
DEBUG_PRINTF("cur offset = %llu\n", q_cur_offset(q));
|
||||
} else {
|
||||
switch (q_cur_type(q)) {
|
||||
case MQE_TOP:
|
||||
case MQE_TOP_FIRST:
|
||||
lbrTop(l, lstate, q->streamState, q_cur_offset(q));
|
||||
break;
|
||||
case MQE_START:
|
||||
case MQE_END:
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF("unhandled event %d!\n", q_cur_type(q));
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sp = q_cur_offset(q);
|
||||
q->cur++;
|
||||
}
|
||||
|
||||
return lbrIsAlive(l, lstate, q->streamState, sp);
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _Q)(const struct NFA *nfa, struct mq *q, s64a end) {
|
||||
DEBUG_PRINTF("entry, offset=%llu, end=%lld\n", q->offset, end);
|
||||
return JOIN(ENGINE_EXEC_NAME, _Q_i)(nfa, q, end, CALLBACK_OUTPUT);
|
||||
}
|
||||
|
||||
char JOIN(ENGINE_EXEC_NAME, _Q2)(const struct NFA *nfa, struct mq *q, s64a end) {
|
||||
DEBUG_PRINTF("entry, offset=%llu, end=%lld\n", q->offset, end);
|
||||
return JOIN(ENGINE_EXEC_NAME, _Q_i)(nfa, q, end, STOP_AT_MATCH);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void JOIN(ENGINE_EXEC_NAME, _StreamSilent)(const struct NFA *nfa, struct mq *q,
|
||||
const u8 *buf, size_t length) {
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
struct lbr_state *lstate = (struct lbr_state *)q->state;
|
||||
assert(ISALIGNED(lstate));
|
||||
|
||||
assert(!repeatIsDead(info, lstate));
|
||||
|
||||
// This call doesn't produce matches, so we elide the lbrMatchLoop call
|
||||
// entirely and just do escape scans to maintain the repeat.
|
||||
|
||||
size_t eloc = 0;
|
||||
char escaped = FWDSCAN_FN(nfa, buf, 0, length, &eloc);
|
||||
if (escaped) {
|
||||
assert(eloc < length);
|
||||
DEBUG_PRINTF("escape found at %zu, clearing repeat\n", eloc);
|
||||
clearRepeat(info, lstate);
|
||||
}
|
||||
}
|
||||
|
||||
// Rose infix path.
|
||||
char JOIN(ENGINE_EXEC_NAME, _QR)(const struct NFA *nfa, struct mq *q,
|
||||
ReportID report) {
|
||||
assert(nfa && q);
|
||||
assert(isLbrType(nfa->type));
|
||||
|
||||
if (q->cur == q->end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(q->cur + 1 < q->end); /* require at least two items */
|
||||
assert(q_cur_type(q) == MQE_START);
|
||||
u64a sp = q_cur_offset(q);
|
||||
q->cur++;
|
||||
DEBUG_PRINTF("sp=%llu\n", sp);
|
||||
|
||||
const struct lbr_common *l = getImplNfa(nfa);
|
||||
const struct RepeatInfo *info = getRepeatInfo(l);
|
||||
struct lbr_state *lstate = (struct lbr_state *)q->state;
|
||||
assert(ISALIGNED(lstate));
|
||||
const s64a lastLoc = q_last_loc(q);
|
||||
|
||||
while (q->cur < q->end) {
|
||||
DEBUG_PRINTF("q item type=%d offset=%llu\n", q_cur_type(q),
|
||||
q_cur_offset(q));
|
||||
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
DEBUG_PRINTF("repeat is dead\n");
|
||||
goto scan_done;
|
||||
}
|
||||
|
||||
u64a ep = q_cur_offset(q);
|
||||
|
||||
if (sp < q->offset) {
|
||||
DEBUG_PRINTF("HISTORY BUFFER SCAN\n");
|
||||
assert(q->offset - sp <= q->hlength);
|
||||
u64a local_ep = MIN(q->offset, ep);
|
||||
const u8 *ptr = q->history + q->hlength + sp - q->offset;
|
||||
JOIN(ENGINE_EXEC_NAME, _StreamSilent)(nfa, q, ptr, local_ep - sp);
|
||||
sp = local_ep;
|
||||
}
|
||||
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
DEBUG_PRINTF("repeat is dead\n");
|
||||
goto scan_done;
|
||||
}
|
||||
|
||||
if (sp < ep) {
|
||||
DEBUG_PRINTF("MAIN BUFFER SCAN\n");
|
||||
assert(ep - q->offset <= q->length);
|
||||
const u8 *ptr = q->buffer + sp - q->offset;
|
||||
JOIN(ENGINE_EXEC_NAME, _StreamSilent)(nfa, q, ptr, ep - sp);
|
||||
}
|
||||
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
scan_done:
|
||||
if (!JOIN(ENGINE_EXEC_NAME, _TopScan)(nfa, q, lastLoc)) {
|
||||
assert(repeatIsDead(info, lstate));
|
||||
assert(q->cur == q->end);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
switch (q_cur_type(q)) {
|
||||
case MQE_TOP:
|
||||
case MQE_TOP_FIRST:
|
||||
lbrTop(l, lstate, q->streamState, q_cur_offset(q));
|
||||
break;
|
||||
case MQE_START:
|
||||
case MQE_END:
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF("unhandled event %d!\n", q_cur_type(q));
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sp = q_cur_offset(q);
|
||||
q->cur++;
|
||||
}
|
||||
|
||||
if (repeatIsDead(info, lstate)) {
|
||||
DEBUG_PRINTF("repeat is dead\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lbrInAccept(l, lstate, q->streamState, sp, report)) {
|
||||
return MO_MATCHES_PENDING;
|
||||
}
|
||||
|
||||
return lbrIsActive(l, lstate, q->streamState, sp);
|
||||
}
|
||||
|
||||
#undef ENGINE_EXEC_NAME
|
||||
#undef EXEC_FN
|
||||
#undef FWDSCAN_FN
|
||||
#undef REVSCAN_FN
|
||||
#undef ENGINE_ROOT_NAME
|
||||
142
src/nfa/lbr_dump.cpp
Normal file
142
src/nfa/lbr_dump.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Large Bounded Repeat (LBR): dump code.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "lbr_dump.h"
|
||||
|
||||
#include "lbr_internal.h"
|
||||
#include "nfa_dump_internal.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "repeat_internal.h"
|
||||
#include "shufticompile.h"
|
||||
#include "trufflecompile.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/dump_charclass.h"
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecLbrDot_dumpDot(UNUSED const NFA *nfa, UNUSED FILE *f) {
|
||||
// No impl
|
||||
}
|
||||
|
||||
void nfaExecLbrVerm_dumpDot(UNUSED const NFA *nfa, UNUSED FILE *f) {
|
||||
// No impl
|
||||
}
|
||||
|
||||
void nfaExecLbrNVerm_dumpDot(UNUSED const NFA *nfa, UNUSED FILE *f) {
|
||||
// No impl
|
||||
}
|
||||
|
||||
void nfaExecLbrShuf_dumpDot(UNUSED const NFA *nfa, UNUSED FILE *f) {
|
||||
// No impl
|
||||
}
|
||||
|
||||
void nfaExecLbrTruf_dumpDot(UNUSED const NFA *nfa, UNUSED FILE *f) {
|
||||
// No impl
|
||||
}
|
||||
|
||||
static
|
||||
void lbrDumpCommon(const lbr_common *lc, FILE *f) {
|
||||
const RepeatInfo *info
|
||||
= (const RepeatInfo *)((const char *)lc + lc->repeatInfoOffset);
|
||||
fprintf(f, "Limited Bounded Repeat\n");
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "repeat model: %s\n", repeatTypeName(info->type));
|
||||
fprintf(f, "repeat bounds: {%u, %u}\n", info->repeatMin,
|
||||
info->repeatMax);
|
||||
fprintf(f, "report id: %u\n", lc->report);
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "min period: %u\n", info->minPeriod);
|
||||
}
|
||||
|
||||
void nfaExecLbrDot_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa);
|
||||
assert(nfa->type == LBR_NFA_Dot);
|
||||
const lbr_dot *ld = (const lbr_dot *)getImplNfa(nfa);
|
||||
lbrDumpCommon(&ld->common, f);
|
||||
fprintf(f, "DOT model\n");
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
void nfaExecLbrVerm_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa);
|
||||
assert(nfa->type == LBR_NFA_Verm);
|
||||
const lbr_verm *lv = (const lbr_verm *)getImplNfa(nfa);
|
||||
lbrDumpCommon(&lv->common, f);
|
||||
fprintf(f, "VERM model, scanning for 0x%02x\n", lv->c);
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
void nfaExecLbrNVerm_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa);
|
||||
assert(nfa->type == LBR_NFA_NVerm);
|
||||
const lbr_verm *lv = (const lbr_verm *)getImplNfa(nfa);
|
||||
lbrDumpCommon(&lv->common, f);
|
||||
fprintf(f, "NEGATED VERM model, scanning for 0x%02x\n", lv->c);
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
void nfaExecLbrShuf_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa);
|
||||
assert(nfa->type == LBR_NFA_Shuf);
|
||||
const lbr_shuf *ls = (const lbr_shuf *)getImplNfa(nfa);
|
||||
lbrDumpCommon(&ls->common, f);
|
||||
|
||||
CharReach cr = shufti2cr(ls->mask_lo, ls->mask_hi);
|
||||
fprintf(f, "SHUF model, scanning for: %s (%zu chars)\n",
|
||||
describeClass(cr, 20, CC_OUT_TEXT).c_str(), cr.count());
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
void nfaExecLbrTruf_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa);
|
||||
assert(nfa->type == LBR_NFA_Truf);
|
||||
const lbr_truf *lt = (const lbr_truf *)getImplNfa(nfa);
|
||||
lbrDumpCommon(<->common, f);
|
||||
|
||||
CharReach cr = truffle2cr(lt->mask1, lt->mask2);
|
||||
fprintf(f, "TRUFFLE model, scanning for: %s (%zu chars)\n",
|
||||
describeClass(cr, 20, CC_OUT_TEXT).c_str(), cr.count());
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
55
src/nfa/lbr_dump.h
Normal file
55
src/nfa/lbr_dump.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef LBR_DUMP_H
|
||||
#define LBR_DUMP_H
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecLbrDot_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrVerm_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrNVerm_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrShuf_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrTruf_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrDot_dumpText(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrVerm_dumpText(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrNVerm_dumpText(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrTruf_dumpText(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecLbrShuf_dumpText(const struct NFA *nfa, FILE *file);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
src/nfa/lbr_internal.h
Normal file
82
src/nfa/lbr_internal.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Large Bounded Repeat (LBR): data structures.
|
||||
*/
|
||||
|
||||
#ifndef LBR_INTERNAL_H
|
||||
#define LBR_INTERNAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "repeat_internal.h"
|
||||
|
||||
/** \brief Common LBR header. */
|
||||
struct lbr_common {
|
||||
u32 repeatInfoOffset; //!< offset of RepeatInfo structure relative
|
||||
// to the start of lbr_common
|
||||
ReportID report; //!< report to raise on match
|
||||
};
|
||||
|
||||
struct lbr_dot {
|
||||
struct lbr_common common;
|
||||
};
|
||||
|
||||
struct lbr_verm {
|
||||
struct lbr_common common;
|
||||
char c; //!< escape char
|
||||
};
|
||||
|
||||
struct lbr_shuf {
|
||||
struct lbr_common common;
|
||||
m128 mask_lo; //!< shufti lo mask for escape chars
|
||||
m128 mask_hi; //!< shufti hi mask for escape chars
|
||||
};
|
||||
|
||||
struct lbr_truf {
|
||||
struct lbr_common common;
|
||||
m128 mask1;
|
||||
m128 mask2;
|
||||
};
|
||||
|
||||
/** \brief Uncompressed ("full") state structure used by the LBR. This is
|
||||
* stored in scratch, not in stream state. */
|
||||
struct lbr_state {
|
||||
u64a lastEscape; //!< \brief offset of last escape seen.
|
||||
union RepeatControl ctrl; //!< \brief repeat control block. */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // LBR_INTERNAL_H
|
||||
121
src/nfa/limex.h
Normal file
121
src/nfa/limex.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_H
|
||||
#define LIMEX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "nfa_api.h"
|
||||
|
||||
#if defined(DUMP_SUPPORT) && defined(__cplusplus)
|
||||
#define GENERATE_NFA_DUMP_DECL(gf_name) \
|
||||
} /* extern "C" */ \
|
||||
namespace ue2 { \
|
||||
void gf_name##_dumpDot(const struct NFA *nfa, FILE *file); \
|
||||
void gf_name##_dumpText(const struct NFA *nfa, FILE *file); \
|
||||
} /* namespace ue2 */ \
|
||||
extern "C" {
|
||||
|
||||
#else
|
||||
#define GENERATE_NFA_DUMP_DECL(gf_name)
|
||||
#endif
|
||||
|
||||
#define GENERATE_NFA_DECL(gf_name) \
|
||||
char gf_name##_testEOD(const struct NFA *nfa, const char *state, \
|
||||
const char *streamState, u64a offset, \
|
||||
NfaCallback callback, SomNfaCallback som_cb, \
|
||||
void *context); \
|
||||
char gf_name##_Q(const struct NFA *n, struct mq *q, s64a end); \
|
||||
char gf_name##_Q2(const struct NFA *n, struct mq *q, s64a end); \
|
||||
char gf_name##_QR(const struct NFA *n, struct mq *q, ReportID report); \
|
||||
char gf_name##_reportCurrent(const struct NFA *n, struct mq *q); \
|
||||
char gf_name##_inAccept(const struct NFA *n, ReportID report, \
|
||||
struct mq *q); \
|
||||
char gf_name##_queueInitState(const struct NFA *n, struct mq *q); \
|
||||
char gf_name##_initCompressedState(const struct NFA *n, u64a offset, \
|
||||
void *state, u8 key); \
|
||||
char gf_name##_B_Reverse(const struct NFA *n, u64a offset, const u8 *buf, \
|
||||
size_t buflen, const u8 *hbuf, size_t hlen, \
|
||||
struct hs_scratch *scratch, NfaCallback cb, \
|
||||
void *context); \
|
||||
char gf_name##_queueCompressState(const struct NFA *nfa, \
|
||||
const struct mq *q, s64a loc); \
|
||||
char gf_name##_expandState(const struct NFA *nfa, void *dest, \
|
||||
const void *src, u64a offset, u8 key); \
|
||||
enum nfa_zombie_status gf_name##_zombie_status(const struct NFA *nfa, \
|
||||
struct mq *q, s64a loc); \
|
||||
GENERATE_NFA_DUMP_DECL(gf_name)
|
||||
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_1)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_2)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_3)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_4)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_5)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_6)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx32_7)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_1)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_2)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_3)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_4)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_5)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_6)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx128_7)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_1)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_2)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_3)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_4)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_5)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_6)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx256_7)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_1)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_2)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_3)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_4)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_5)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_6)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx384_7)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_1)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_2)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_3)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_4)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_5)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_6)
|
||||
GENERATE_NFA_DECL(nfaExecLimEx512_7)
|
||||
|
||||
#undef GENERATE_NFA_DECL
|
||||
#undef GENERATE_NFA_DUMP_DECL
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
229
src/nfa/limex_accel.c
Normal file
229
src/nfa/limex_accel.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: acceleration runtime.
|
||||
*/
|
||||
|
||||
#include "limex_accel.h"
|
||||
|
||||
#include "accel.h"
|
||||
#include "limex_internal.h"
|
||||
#include "limex_limits.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "shufti.h"
|
||||
#include "truffle.h"
|
||||
#include "ue2common.h"
|
||||
#include "vermicelli.h"
|
||||
#include "util/bitutils.h"
|
||||
#include "util/shuffle.h"
|
||||
#include "util/simd_utils.h"
|
||||
#include "util/simd_utils_ssse3.h"
|
||||
#include "util/shuffle_ssse3.h"
|
||||
|
||||
static
|
||||
const u8 *accelScan(const union AccelAux *aux, const u8 *ptr, const u8 *end) {
|
||||
assert(ISALIGNED(aux)); // must be SIMD aligned for shufti
|
||||
assert(end > ptr);
|
||||
assert(end - ptr >= 16); // must be at least 16 bytes to scan
|
||||
|
||||
const u8 *start = ptr;
|
||||
u8 offset;
|
||||
switch (aux->accel_type) {
|
||||
case ACCEL_VERM:
|
||||
DEBUG_PRINTF("single vermicelli for 0x%02hhx\n", aux->verm.c);
|
||||
offset = aux->verm.offset;
|
||||
ptr = vermicelliExec(aux->verm.c, 0, ptr, end);
|
||||
break;
|
||||
case ACCEL_VERM_NOCASE:
|
||||
DEBUG_PRINTF("single vermicelli-nocase for 0x%02hhx\n", aux->verm.c);
|
||||
offset = aux->verm.offset;
|
||||
ptr = vermicelliExec(aux->verm.c, 1, ptr, end);
|
||||
break;
|
||||
case ACCEL_DVERM:
|
||||
DEBUG_PRINTF("double vermicelli for 0x%02hhx%02hhx\n",
|
||||
aux->dverm.c1, aux->dverm.c2);
|
||||
offset = aux->dverm.offset;
|
||||
ptr = vermicelliDoubleExec(aux->dverm.c1, aux->dverm.c2, 0, ptr, end);
|
||||
break;
|
||||
case ACCEL_DVERM_NOCASE:
|
||||
DEBUG_PRINTF("double vermicelli-nocase for 0x%02hhx%02hhx\n",
|
||||
aux->dverm.c1, aux->dverm.c2);
|
||||
offset = aux->dverm.offset;
|
||||
ptr = vermicelliDoubleExec(aux->dverm.c1, aux->dverm.c2,
|
||||
1, ptr, end);
|
||||
break;
|
||||
case ACCEL_SHUFTI:
|
||||
DEBUG_PRINTF("single shufti\n");
|
||||
offset = aux->shufti.offset;
|
||||
ptr = shuftiExec(aux->shufti.lo, aux->shufti.hi, ptr, end);
|
||||
break;
|
||||
case ACCEL_DSHUFTI:
|
||||
DEBUG_PRINTF("double shufti\n");
|
||||
offset = aux->dshufti.offset;
|
||||
ptr = shuftiDoubleExec(aux->dshufti.lo1, aux->dshufti.hi1,
|
||||
aux->dshufti.lo2, aux->dshufti.hi2, ptr, end);
|
||||
break;
|
||||
case ACCEL_TRUFFLE:
|
||||
DEBUG_PRINTF("truffle shuffle\n");
|
||||
offset = aux->truffle.offset;
|
||||
ptr = truffleExec(aux->truffle.mask1, aux->truffle.mask2, ptr, end);
|
||||
break;
|
||||
case ACCEL_RED_TAPE:
|
||||
ptr = end; /* there is no escape */
|
||||
offset = aux->generic.offset;
|
||||
break;
|
||||
default:
|
||||
/* no acceleration, fall through and return current ptr */
|
||||
offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
ptr -= offset;
|
||||
if (ptr < start) {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
size_t accelScanWrapper(const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, u32 idx, size_t i, size_t end) {
|
||||
assert(accelTable);
|
||||
assert(aux);
|
||||
|
||||
DEBUG_PRINTF("shuffle returned %u -> aux %u\n", idx, accelTable[idx]);
|
||||
assert(idx < (1 << NFA_MAX_ACCEL_STATES));
|
||||
if (!idx) {
|
||||
return end;
|
||||
}
|
||||
|
||||
u8 aux_idx = accelTable[idx];
|
||||
if (!aux_idx) {
|
||||
assert(aux[0].accel_type == ACCEL_NONE);
|
||||
DEBUG_PRINTF("no accel, bailing\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
aux = aux + aux_idx;
|
||||
const u8 *ptr = accelScan(aux, &input[i], &input[end]);
|
||||
assert(ptr >= &input[i]);
|
||||
size_t j = (size_t)(ptr - input);
|
||||
DEBUG_PRINTF("accel skipped %zu of %zu chars\n", (j - i), (end - i));
|
||||
DEBUG_PRINTF("returning j=%zu (i=%zu, end=%zu)\n", j, i, end);
|
||||
return j;
|
||||
}
|
||||
|
||||
size_t doAccel32(u32 s, u32 accel, const u8 *accelTable,
|
||||
const union AccelAux *aux, const u8 *input, size_t i,
|
||||
size_t end) {
|
||||
u32 idx = shuffleDynamic32(s, accel);
|
||||
return accelScanWrapper(accelTable, aux, input, idx, i, end);
|
||||
}
|
||||
|
||||
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) {
|
||||
u32 idx;
|
||||
m128 s = *state;
|
||||
DEBUG_PRINTF("using PSHUFB for 128-bit shuffle\n");
|
||||
m128 accelPerm = limex->accelPermute;
|
||||
m128 accelComp = limex->accelCompare;
|
||||
idx = shufflePshufb128(s, accelPerm, accelComp);
|
||||
return accelScanWrapper(accelTable, aux, input, idx, i, end);
|
||||
}
|
||||
|
||||
size_t doAccel256(const m256 *state, const struct LimExNFA256 *limex,
|
||||
const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, size_t i, size_t end) {
|
||||
u32 idx;
|
||||
m256 s = *state;
|
||||
DEBUG_PRINTF("using PSHUFB for 256-bit shuffle\n");
|
||||
m256 accelPerm = limex->accelPermute;
|
||||
m256 accelComp = limex->accelCompare;
|
||||
#if !defined(__AVX2__)
|
||||
u32 idx1 = shufflePshufb128(s.lo, accelPerm.lo, accelComp.lo);
|
||||
u32 idx2 = shufflePshufb128(s.hi, accelPerm.hi, accelComp.hi);
|
||||
#else
|
||||
// TODO: learn you some avx2 shuffles for great good
|
||||
u32 idx1 = shufflePshufb128(movdq_lo(s), movdq_lo(accelPerm),
|
||||
movdq_lo(accelComp));
|
||||
u32 idx2 = shufflePshufb128(movdq_hi(s), movdq_hi(accelPerm),
|
||||
movdq_hi(accelComp));
|
||||
#endif
|
||||
assert((idx1 & idx2) == 0); // should be no shared bits
|
||||
idx = idx1 | idx2;
|
||||
return accelScanWrapper(accelTable, aux, input, idx, i, end);
|
||||
}
|
||||
|
||||
size_t doAccel384(const m384 *state, const struct LimExNFA384 *limex,
|
||||
const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, size_t i, size_t end) {
|
||||
u32 idx;
|
||||
m384 s = *state;
|
||||
DEBUG_PRINTF("using PSHUFB for 384-bit shuffle\n");
|
||||
m384 accelPerm = limex->accelPermute;
|
||||
m384 accelComp = limex->accelCompare;
|
||||
u32 idx1 = shufflePshufb128(s.lo, accelPerm.lo, accelComp.lo);
|
||||
u32 idx2 = shufflePshufb128(s.mid, accelPerm.mid, accelComp.mid);
|
||||
u32 idx3 = shufflePshufb128(s.hi, accelPerm.hi, accelComp.hi);
|
||||
assert((idx1 & idx2 & idx3) == 0); // should be no shared bits
|
||||
idx = idx1 | idx2 | idx3;
|
||||
return accelScanWrapper(accelTable, aux, input, idx, i, end);
|
||||
}
|
||||
|
||||
size_t doAccel512(const m512 *state, const struct LimExNFA512 *limex,
|
||||
const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, size_t i, size_t end) {
|
||||
u32 idx;
|
||||
m512 s = *state;
|
||||
DEBUG_PRINTF("using PSHUFB for 512-bit shuffle\n");
|
||||
m512 accelPerm = limex->accelPermute;
|
||||
m512 accelComp = limex->accelCompare;
|
||||
#if !defined(__AVX2__)
|
||||
u32 idx1 = shufflePshufb128(s.lo.lo, accelPerm.lo.lo, accelComp.lo.lo);
|
||||
u32 idx2 = shufflePshufb128(s.lo.hi, accelPerm.lo.hi, accelComp.lo.hi);
|
||||
u32 idx3 = shufflePshufb128(s.hi.lo, accelPerm.hi.lo, accelComp.hi.lo);
|
||||
u32 idx4 = shufflePshufb128(s.hi.hi, accelPerm.hi.hi, accelComp.hi.hi);
|
||||
#else
|
||||
u32 idx1 = shufflePshufb128(movdq_lo(s.lo), movdq_lo(accelPerm.lo),
|
||||
movdq_lo(accelComp.lo));
|
||||
u32 idx2 = shufflePshufb128(movdq_hi(s.lo), movdq_hi(accelPerm.lo),
|
||||
movdq_hi(accelComp.lo));
|
||||
u32 idx3 = shufflePshufb128(movdq_lo(s.hi), movdq_lo(accelPerm.hi),
|
||||
movdq_lo(accelComp.hi));
|
||||
u32 idx4 = shufflePshufb128(movdq_hi(s.hi), movdq_hi(accelPerm.hi),
|
||||
movdq_hi(accelComp.hi));
|
||||
#endif
|
||||
assert((idx1 & idx2 & idx3 & idx4) == 0); // should be no shared bits
|
||||
idx = idx1 | idx2 | idx3 | idx4;
|
||||
return accelScanWrapper(accelTable, aux, input, idx, i, end);
|
||||
}
|
||||
68
src/nfa/limex_accel.h
Normal file
68
src/nfa/limex_accel.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: acceleration runtime.
|
||||
*
|
||||
* For the SIMD types (128 bits and above), we pass a pointer to the
|
||||
* implementation NFA structure instead of three masks: otherwise we spend all
|
||||
* our time building stack frames.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_ACCEL_H
|
||||
#define LIMEX_ACCEL_H
|
||||
|
||||
#include "util/simd_utils.h" // for m128 etc
|
||||
|
||||
union AccelAux;
|
||||
struct LimExNFA128;
|
||||
struct LimExNFA256;
|
||||
struct LimExNFA384;
|
||||
struct LimExNFA512;
|
||||
|
||||
size_t doAccel32(u32 s, u32 accel, const u8 *accelTable,
|
||||
const union AccelAux *aux, const u8 *input, size_t i,
|
||||
size_t end);
|
||||
|
||||
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);
|
||||
|
||||
size_t doAccel256(const m256 *s, const struct LimExNFA256 *limex,
|
||||
const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, size_t i, size_t end);
|
||||
|
||||
size_t doAccel384(const m384 *s, const struct LimExNFA384 *limex,
|
||||
const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, size_t i, size_t end);
|
||||
|
||||
size_t doAccel512(const m512 *s, const struct LimExNFA512 *limex,
|
||||
const u8 *accelTable, const union AccelAux *aux,
|
||||
const u8 *input, size_t i, size_t end);
|
||||
|
||||
#endif
|
||||
404
src/nfa/limex_common_impl.h
Normal file
404
src/nfa/limex_common_impl.h
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "repeat.h"
|
||||
#include "util/join.h"
|
||||
|
||||
/* 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.
|
||||
#endif
|
||||
|
||||
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
|
||||
|
||||
#define TESTEOD_FN JOIN(moNfaTestEod, SIZE)
|
||||
#define TESTEOD_REV_FN JOIN(moNfaRevTestEod, SIZE)
|
||||
#define LIMEX_INACCEPT_FN JOIN(limexInAccept, SIZE)
|
||||
#define EXPIRE_ESTATE_FN JOIN(limexExpireExtendedState, SIZE)
|
||||
#define REPORTCURRENT_FN JOIN(moNfaReportCurrent, SIZE)
|
||||
#define INITIAL_FN JOIN(moNfaInitial, SIZE)
|
||||
#define TOP_FN JOIN(moNfaTop, SIZE)
|
||||
#define TOPN_FN JOIN(moNfaTopN, SIZE)
|
||||
#define PROCESS_ACCEPTS_FN JOIN(moProcessAccepts, 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)
|
||||
#define CLEARBIT_STATE JOIN(clearbit_, STATE_T)
|
||||
#define TESTBIT_STATE JOIN(testbit_, STATE_T)
|
||||
#define ISNONZERO_STATE JOIN(isNonZero_, STATE_T)
|
||||
#define ISZERO_STATE JOIN(isZero_, STATE_T)
|
||||
#define SQUASH_UNTUG_BR_FN JOIN(lazyTug, SIZE)
|
||||
#define GET_NFA_REPEAT_INFO_FN JOIN(getNfaRepeatInfo, SIZE)
|
||||
|
||||
static really_inline
|
||||
void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex,
|
||||
const union RepeatControl *repeat_ctrl,
|
||||
const char *repeat_state, u64a offset,
|
||||
STATE_T *accstate) {
|
||||
// switch off cyclic tug-accepts which aren't tuggable right now.
|
||||
|
||||
/* TODO: might be nice to work which br to examine based on accstate rather
|
||||
* than iterating overall br */
|
||||
|
||||
if (!limex->repeatCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(repeat_ctrl);
|
||||
assert(repeat_state);
|
||||
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
|
||||
|
||||
u32 cyclicState = info->cyclicState;
|
||||
if (!TESTBIT_STATE(accstate, cyclicState)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("repeat %u (cyclic state %u) is active\n", i, cyclicState);
|
||||
DEBUG_PRINTF("checking if offset %llu would match\n", offset);
|
||||
|
||||
const union RepeatControl *ctrl = repeat_ctrl + i;
|
||||
const char *state = repeat_state + info->stateOffset;
|
||||
const struct RepeatInfo *repeat = getRepeatInfo(info);
|
||||
if (repeatHasMatch(repeat, ctrl, state, offset) != REPEAT_MATCH) {
|
||||
DEBUG_PRINTF("not ready to accept yet\n");
|
||||
CLEARBIT_STATE(accstate, cyclicState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static never_inline
|
||||
char PROCESS_ACCEPTS_FN(const IMPL_NFA_T *limex, STATE_T *s,
|
||||
const struct NFAAccept *acceptTable, u32 acceptCount,
|
||||
u64a offset, NfaCallback callback, void *context) {
|
||||
assert(s);
|
||||
assert(limex);
|
||||
assert(callback);
|
||||
assert(acceptCount);
|
||||
|
||||
// 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 char *)limex + limex->squashOffset);
|
||||
|
||||
for (u32 i = 0; i < acceptCount; i++) {
|
||||
const struct NFAAccept *a = &acceptTable[i];
|
||||
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(offset, a->externalId, context);
|
||||
if (unlikely(rv == MO_HALT_MATCHING)) {
|
||||
return 1;
|
||||
}
|
||||
if (a->squash != MO_INVALID_IDX) {
|
||||
assert(a->squash < limex->squashCount);
|
||||
const STATE_T *sq = &squashMasks[a->squash];
|
||||
DEBUG_PRINTF("squash mask %u @ %p\n", a->squash, sq);
|
||||
squash = AND_STATE(squash, LOAD_STATE(sq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STORE_STATE(s, AND_STATE(LOAD_STATE(s), squash));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static never_inline
|
||||
char PROCESS_ACCEPTS_NOSQUASH_FN(const STATE_T *s,
|
||||
const struct NFAAccept *acceptTable,
|
||||
u32 acceptCount, u64a offset,
|
||||
NfaCallback callback, void *context) {
|
||||
assert(s);
|
||||
assert(callback);
|
||||
assert(acceptCount);
|
||||
|
||||
for (u32 i = 0; i < acceptCount; i++) {
|
||||
const struct NFAAccept *a = &acceptTable[i];
|
||||
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(offset, a->externalId, context);
|
||||
if (unlikely(rv == MO_HALT_MATCHING)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Run EOD accepts.
|
||||
static really_inline
|
||||
char TESTEOD_FN(const IMPL_NFA_T *limex, const STATE_T *s,
|
||||
const union RepeatControl *repeat_ctrl,
|
||||
const char *repeat_state, u64a offset, char do_br,
|
||||
NfaCallback callback, void *context) {
|
||||
assert(limex && s);
|
||||
|
||||
// There may not be any EOD accepts in this NFA.
|
||||
if (!limex->acceptEodCount) {
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
const STATE_T acceptEodMask = LOAD_STATE(&limex->acceptAtEOD);
|
||||
STATE_T foundAccepts = AND_STATE(LOAD_STATE(s), acceptEodMask);
|
||||
|
||||
if (do_br) {
|
||||
SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state,
|
||||
offset + 1 /* EOD 'symbol' */, &foundAccepts);
|
||||
} else {
|
||||
assert(!limex->repeatCount);
|
||||
}
|
||||
|
||||
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
|
||||
const struct NFAAccept *acceptEodTable = getAcceptEodTable(limex);
|
||||
if (PROCESS_ACCEPTS_NOSQUASH_FN(&foundAccepts, acceptEodTable,
|
||||
limex->acceptEodCount, offset, callback,
|
||||
context)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char TESTEOD_REV_FN(const IMPL_NFA_T *limex, const STATE_T *s, u64a offset,
|
||||
NfaCallback callback, void *context) {
|
||||
assert(limex && s);
|
||||
|
||||
// There may not be any EOD accepts in this NFA.
|
||||
if (!limex->acceptEodCount) {
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
STATE_T acceptEodMask = LOAD_STATE(&limex->acceptAtEOD);
|
||||
STATE_T foundAccepts = AND_STATE(LOAD_STATE(s), acceptEodMask);
|
||||
|
||||
assert(!limex->repeatCount);
|
||||
|
||||
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
|
||||
const struct NFAAccept *acceptEodTable = getAcceptEodTable(limex);
|
||||
if (PROCESS_ACCEPTS_NOSQUASH_FN(&foundAccepts, acceptEodTable,
|
||||
limex->acceptEodCount, offset, callback,
|
||||
context)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
// Run accepts corresponding to current state.
|
||||
static really_inline
|
||||
char REPORTCURRENT_FN(const IMPL_NFA_T *limex, const struct mq *q) {
|
||||
assert(limex && q);
|
||||
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 foundAccepts = AND_STATE(s, acceptMask);
|
||||
|
||||
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
|
||||
DEBUG_PRINTF("found accepts\n");
|
||||
DEBUG_PRINTF("for nfa %p\n", limex);
|
||||
const struct NFAAccept *acceptTable = getAcceptTable(limex);
|
||||
u64a offset = q_cur_offset(q);
|
||||
|
||||
if (PROCESS_ACCEPTS_NOSQUASH_FN(&foundAccepts, acceptTable,
|
||||
limex->acceptCount, offset, q->cb,
|
||||
q->context)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
STATE_T INITIAL_FN(const IMPL_NFA_T *impl, char onlyDs) {
|
||||
return LOAD_STATE(onlyDs ? &impl->initDS : &impl->init);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
STATE_T TOP_FN(const IMPL_NFA_T *impl, char onlyDs, STATE_T state) {
|
||||
return OR_STATE(INITIAL_FN(impl, onlyDs), state);
|
||||
}
|
||||
|
||||
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]);
|
||||
return OR_STATE(top, state);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void EXPIRE_ESTATE_FN(const IMPL_NFA_T *limex, struct CONTEXT_T *ctx,
|
||||
u64a offset) {
|
||||
assert(limex);
|
||||
assert(ctx);
|
||||
|
||||
if (!limex->repeatCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("expire estate at offset %llu\n", offset);
|
||||
|
||||
const STATE_T cyclics =
|
||||
AND_STATE(LOAD_STATE(&ctx->s), LOAD_STATE(&limex->repeatCyclicMask));
|
||||
if (ISZERO_STATE(cyclics)) {
|
||||
DEBUG_PRINTF("no cyclic states are on\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
|
||||
|
||||
u32 cyclicState = info->cyclicState;
|
||||
if (!TESTBIT_STATE(&cyclics, cyclicState)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("repeat %u (cyclic state %u) is active\n", i,
|
||||
cyclicState);
|
||||
|
||||
const struct RepeatInfo *repeat = getRepeatInfo(info);
|
||||
if (repeat->repeatMax == REPEAT_INF) {
|
||||
continue; // can't expire
|
||||
}
|
||||
|
||||
const union RepeatControl *repeat_ctrl = ctx->repeat_ctrl + i;
|
||||
const char *repeat_state = ctx->repeat_state + info->stateOffset;
|
||||
u64a last_top = repeatLastTop(repeat, repeat_ctrl, repeat_state);
|
||||
assert(repeat->repeatMax < REPEAT_INF);
|
||||
DEBUG_PRINTF("offset %llu, last_top %llu repeatMax %u\n", offset,
|
||||
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)) {
|
||||
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)))) {
|
||||
DEBUG_PRINTF("tug possible - may still be inspected\n");
|
||||
adj = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset >= last_top + repeat->repeatMax + adj) {
|
||||
DEBUG_PRINTF("repeat state is stale, squashing state %u\n",
|
||||
cyclicState);
|
||||
CLEARBIT_STATE(&ctx->s, cyclicState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specialised inAccept call: LimEx NFAs with the "lazy tug" optimisation (see
|
||||
// UE-1636) need to guard cyclic tug-accepts as well.
|
||||
static really_inline
|
||||
char LIMEX_INACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
|
||||
union RepeatControl *repeat_ctrl, char *repeat_state,
|
||||
u64a offset, ReportID report) {
|
||||
assert(limex);
|
||||
|
||||
const STATE_T acceptMask = LOAD_STATE(&limex->accept);
|
||||
STATE_T accstate = AND_STATE(state, acceptMask);
|
||||
|
||||
// Are we in an accept state?
|
||||
if (ISZERO_STATE(accstate)) {
|
||||
DEBUG_PRINTF("no accept states are on\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accstate);
|
||||
|
||||
DEBUG_PRINTF("looking for report %u\n", report);
|
||||
|
||||
#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);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
// Does one of our states match the given report ID?
|
||||
const struct NFAAccept *acceptTable = getAcceptTable(limex);
|
||||
for (u32 i = 0; i < limex->acceptCount; i++) {
|
||||
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)) {
|
||||
DEBUG_PRINTF("report is on!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef TESTEOD_FN
|
||||
#undef TESTEOD_REV_FN
|
||||
#undef REPORTCURRENT_FN
|
||||
#undef EXPIRE_ESTATE_FN
|
||||
#undef LIMEX_INACCEPT_FN
|
||||
#undef INITIAL_FN
|
||||
#undef TOP_FN
|
||||
#undef TOPN_FN
|
||||
#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 CLEARBIT_STATE
|
||||
#undef TESTBIT_STATE
|
||||
#undef ISNONZERO_STATE
|
||||
#undef ISZERO_STATE
|
||||
#undef PROCESS_ACCEPTS_FN
|
||||
#undef PROCESS_ACCEPTS_NOSQUASH_FN
|
||||
#undef SQUASH_UNTUG_BR_FN
|
||||
#undef GET_NFA_REPEAT_INFO_FN
|
||||
|
||||
#undef SIZE
|
||||
#undef STATE_T
|
||||
#undef INLINE_ATTR
|
||||
2179
src/nfa/limex_compile.cpp
Normal file
2179
src/nfa/limex_compile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
99
src/nfa/limex_compile.h
Normal file
99
src/nfa/limex_compile.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Main NFA build code.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_COMPILE_H
|
||||
#define LIMEX_COMPILE_H
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "nfagraph/ng_holder.h"
|
||||
#include "nfagraph/ng_squash.h" // for NFAStateSet
|
||||
#include "util/alloc.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct BoundedRepeatData;
|
||||
struct CompileContext;
|
||||
|
||||
/** \brief Construct a LimEx NFA from an NGHolder.
|
||||
*
|
||||
* \param g Input NFA graph. Must have state IDs assigned.
|
||||
* \param repeats Bounded repeat information, if any.
|
||||
* \param reportSquashMap Single-match mode squash map.
|
||||
* \param squashMap More general squash map.
|
||||
* \param tops Tops and their start vertices,
|
||||
* \param zombies The set of zombifying states.
|
||||
* \param do_accel Calculate acceleration schemes.
|
||||
* \param stateCompression Allow (and calculate masks for) state compression.
|
||||
* \param hint If not INVALID_NFA, this allows a particular LimEx NFA model
|
||||
to be requested.
|
||||
* \param cc Compile context.
|
||||
* \return a built NFA, or nullptr if no NFA could be constructed for this
|
||||
* graph.
|
||||
*/
|
||||
aligned_unique_ptr<NFA> generate(NGHolder &g,
|
||||
const ue2::unordered_map<NFAVertex, u32> &states,
|
||||
const std::vector<BoundedRepeatData> &repeats,
|
||||
const std::map<NFAVertex, NFAStateSet> &reportSquashMap,
|
||||
const std::map<NFAVertex, NFAStateSet> &squashMap,
|
||||
const std::map<u32, NFAVertex> &tops,
|
||||
const std::set<NFAVertex> &zombies,
|
||||
bool do_accel,
|
||||
bool stateCompression,
|
||||
u32 hint,
|
||||
const CompileContext &cc);
|
||||
|
||||
/**
|
||||
* \brief For a given graph, count the number of accel states it will have in
|
||||
* an implementation.
|
||||
*
|
||||
* \return the number of accel states, or NFA_MAX_ACCEL_STATES + 1 if an
|
||||
* implementation would not be constructible.
|
||||
*/
|
||||
u32 countAccelStates(NGHolder &h,
|
||||
const ue2::unordered_map<NFAVertex, u32> &states,
|
||||
const std::vector<BoundedRepeatData> &repeats,
|
||||
const std::map<NFAVertex, NFAStateSet> &reportSquashMap,
|
||||
const std::map<NFAVertex, NFAStateSet> &squashMap,
|
||||
const std::map<u32, NFAVertex> &tops,
|
||||
const std::set<NFAVertex> &zombies,
|
||||
const CompileContext &cc);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
76
src/nfa/limex_context.h
Normal file
76
src/nfa/limex_context.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Runtime context structures (NFAContext128 and friends) for the NFA.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_CONTEXT_H
|
||||
#define LIMEX_CONTEXT_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "callback.h"
|
||||
#include "util/simd_utils.h" // for m128 etc
|
||||
|
||||
// Runtime context structures.
|
||||
|
||||
/* cached_estate/esucc etc...
|
||||
*
|
||||
* If the exception state matches the cached_estate we will apply
|
||||
* the or in the cached_esucc to the successor states rather than processing
|
||||
* the exceptions.
|
||||
*
|
||||
* If the current exception state is a superset of the cached_estate, the
|
||||
* cache is NOT used at all.
|
||||
*
|
||||
* The cache is updated when we see a different cacheable estate.
|
||||
*/
|
||||
|
||||
#define GEN_CONTEXT_STRUCT(nsize, ntype) \
|
||||
struct ALIGN_CL_DIRECTIVE NFAContext##nsize { \
|
||||
ntype s; /**< state bitvector (on entry/exit) */ \
|
||||
ntype local_succ; /**< used by exception handling for large models */ \
|
||||
ntype cached_estate; /* inited to 0 */ \
|
||||
ntype cached_esucc; \
|
||||
char cached_br; /**< cached_estate contains a br state */ \
|
||||
const ReportID *cached_reports; \
|
||||
union RepeatControl *repeat_ctrl; \
|
||||
char *repeat_state; \
|
||||
NfaCallback callback; \
|
||||
void *context; \
|
||||
};
|
||||
|
||||
GEN_CONTEXT_STRUCT(32, u32)
|
||||
GEN_CONTEXT_STRUCT(128, m128)
|
||||
GEN_CONTEXT_STRUCT(256, m256)
|
||||
GEN_CONTEXT_STRUCT(384, m384)
|
||||
GEN_CONTEXT_STRUCT(512, m512)
|
||||
|
||||
#undef GEN_CONTEXT_STRUCT
|
||||
|
||||
#endif
|
||||
497
src/nfa/limex_dump.cpp
Normal file
497
src/nfa/limex_dump.cpp
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "limex.h"
|
||||
|
||||
#include "accel.h"
|
||||
#include "accel_dump.h"
|
||||
#include "limex_internal.h"
|
||||
#include "nfa_dump_internal.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/dump_charclass.h"
|
||||
#include "util/dump_mask.h"
|
||||
#include "util/charreach.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
template<typename T> struct limex_traits {};
|
||||
template<> struct limex_traits<LimExNFA512> {
|
||||
static const u32 size = 512;
|
||||
typedef NFAException512 exception_type;
|
||||
};
|
||||
template<> struct limex_traits<LimExNFA384> {
|
||||
static const u32 size = 384;
|
||||
typedef NFAException384 exception_type;
|
||||
};
|
||||
template<> struct limex_traits<LimExNFA256> {
|
||||
static const u32 size = 256;
|
||||
typedef NFAException256 exception_type;
|
||||
};
|
||||
template<> struct limex_traits<LimExNFA128> {
|
||||
static const u32 size = 128;
|
||||
typedef NFAException128 exception_type;
|
||||
};
|
||||
template<> struct limex_traits<LimExNFA32> {
|
||||
static const u32 size = 32;
|
||||
typedef NFAException32 exception_type;
|
||||
};
|
||||
|
||||
static
|
||||
void dumpMask(FILE *f, const char *name, const u8 *mask, u32 mask_bits) {
|
||||
fprintf(f, "MSK %-20s %s\n", name, dumpMask(mask, mask_bits).c_str());
|
||||
}
|
||||
|
||||
template <typename limex_type>
|
||||
static
|
||||
void dumpRepeats(const limex_type *limex, u32 model_size, FILE *f) {
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "%u bounded repeats.\n", limex->repeatCount);
|
||||
|
||||
const char *base = (const char *)limex;
|
||||
const u32 *repeatOffset = (const u32 *)(base + limex->repeatOffset);
|
||||
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
const NFARepeatInfo *info =
|
||||
(const NFARepeatInfo *)(base + repeatOffset[i]);
|
||||
const RepeatInfo *repeat =
|
||||
(const RepeatInfo *)((const char *)info + sizeof(*info));
|
||||
fprintf(f, " repeat %u: %s {%u,%u} packedCtrlSize=%u, "
|
||||
"stateSize=%u\n",
|
||||
i, repeatTypeName(repeat->type), repeat->repeatMin,
|
||||
repeat->repeatMax, repeat->packedCtrlSize, repeat->stateSize);
|
||||
fprintf(f, " nfa state: stream offset %u\n", info->stateOffset);
|
||||
fprintf(f, " ");
|
||||
|
||||
const u8 *tug_mask = (const u8 *)info + info->tugMaskOffset;
|
||||
dumpMask(f, "tugs", tug_mask, model_size);
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static
|
||||
void dumpLimexReachMasks(u32 model_size, const u8 *reach, u32 reachCount,
|
||||
FILE *f) {
|
||||
for (u32 i = 0; i < reachCount; i++) {
|
||||
char tmp_common[100];
|
||||
const u8 *row = reach + (i * (model_size/8));
|
||||
sprintf(tmp_common, "reach mask %u ", i);
|
||||
dumpMask(f, tmp_common, row, model_size);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dumpLimexReachMap(const u8 *reachMap, FILE *f) {
|
||||
for (u32 i = 0; i < N_CHARS; i++) {
|
||||
fprintf(f, "reach 0x%02x ", i);
|
||||
if (!isprint(i)) {
|
||||
fprintf(f, " ");
|
||||
} else {
|
||||
fprintf(f, "'%c'", (char)i);
|
||||
}
|
||||
fprintf(f, " -> mask %hhu\n", reachMap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
const NFA *limex_to_nfa(const limex_type *limex) {
|
||||
return (const NFA *)((const char *)limex - sizeof(NFA));
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpAccel(const limex_type *limex, FILE *f) {
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "%u acceleration schemes.\n", limex->accelCount);
|
||||
|
||||
if (!limex->accelCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tableOffset = limex->accelTableOffset;
|
||||
u32 auxOffset = limex->accelAuxOffset;
|
||||
const u8 *accelTable = (const u8 *)((const char *)limex + tableOffset);
|
||||
const AccelAux *aux = (const AccelAux *)((const char *)limex + auxOffset);
|
||||
|
||||
for (u32 i = 0; i < limex->accelCount; i++) {
|
||||
fprintf(f, " accel %u (aux entry %u): ", i, accelTable[i]);
|
||||
dumpAccelInfo(f, aux[accelTable[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpAccepts(const limex_type *limex, FILE *f) {
|
||||
u32 acceptCount = limex->acceptCount;
|
||||
u32 acceptEodCount = limex->acceptEodCount;
|
||||
|
||||
fprintf(f, "\n%u accepts.\n", acceptCount);
|
||||
const struct NFAAccept *accepts
|
||||
= (const struct NFAAccept *)((const char *)limex + limex->acceptOffset);
|
||||
for (u32 i = 0; i < acceptCount; i++) {
|
||||
fprintf(f, " state %u fires report %u\n", accepts[i].state,
|
||||
accepts[i].externalId);
|
||||
}
|
||||
fprintf(f, "\n%u accepts at EOD.\n", acceptEodCount);
|
||||
accepts = (const struct NFAAccept *)((const char *)limex
|
||||
+ limex->acceptEodOffset);
|
||||
for (u32 i = 0; i < acceptEodCount; i++) {
|
||||
fprintf(f, " state %u fires report %u\n", accepts[i].state,
|
||||
accepts[i].externalId);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpSquash(const limex_type *limex, FILE *f) {
|
||||
u32 size = limex_traits<limex_type>::size;
|
||||
|
||||
// Dump squash masks, if there are any.
|
||||
const u8 *squashMask = (const u8 *)limex + limex->squashOffset;
|
||||
for (u32 i = 0; i < limex->squashCount; i++) {
|
||||
std::ostringstream name;
|
||||
name << "squash_" << i;
|
||||
dumpMask(f, name.str().c_str(), squashMask, size);
|
||||
squashMask += size / 8;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
const typename limex_traits<limex_type>::exception_type *
|
||||
getExceptionTable(const limex_type *limex) {
|
||||
return (const typename limex_traits<limex_type>::exception_type *)
|
||||
((const char *)limex + limex->exceptionOffset);
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
const ReportID *getReportList(const limex_type *limex) {
|
||||
return (const ReportID *)((const char *)limex + limex->exReportOffset);
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpLimexExceptions(const limex_type *limex, FILE *f) {
|
||||
const typename limex_traits<limex_type>::exception_type *e =
|
||||
getExceptionTable(limex);
|
||||
const ReportID *reports = getReportList(limex);
|
||||
const u32 size = limex_traits<limex_type>::size;
|
||||
|
||||
fprintf(f, "\n");
|
||||
for (u32 i = 0; i < limex->exceptionCount; i++) {
|
||||
fprintf(f, "exception %u: hasSquash=%u, reports offset=%u\n",
|
||||
i, e[i].hasSquash, e[i].reports);
|
||||
switch (e[i].trigger) {
|
||||
case LIMEX_TRIGGER_TUG: fprintf(f, " trigger: TUG\n"); break;
|
||||
case LIMEX_TRIGGER_POS: fprintf(f, " trigger: POS\n"); break;
|
||||
default: break;
|
||||
}
|
||||
dumpMask(f, "succ", (const u8 *)&e[i].successors, size);
|
||||
dumpMask(f, "squash", (const u8 *)&e[i].squash, size);
|
||||
fprintf(f, "reports: ");
|
||||
if (e[i].reports == MO_INVALID_IDX) {
|
||||
fprintf(f, " <none>\n");
|
||||
} else {
|
||||
const ReportID *r = reports + e[i].reports;
|
||||
while (*r != MO_INVALID_IDX) {
|
||||
fprintf(f, " %u", *r++);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpLimexText(const limex_type *limex, FILE *f) {
|
||||
u32 size = limex_traits<limex_type>::size;
|
||||
|
||||
dumpMask(f, "init", (const u8 *)&limex->init, size);
|
||||
dumpMask(f, "init_dot_star", (const u8 *)&limex->initDS, size);
|
||||
dumpMask(f, "accept", (const u8 *)&limex->accept, size);
|
||||
dumpMask(f, "accept_at_eod", (const u8 *)&limex->acceptAtEOD, size);
|
||||
dumpMask(f, "accel", (const u8 *)&limex->accel, size);
|
||||
dumpMask(f, "accel_and_friends", (const u8 *)&limex->accel_and_friends,
|
||||
size);
|
||||
dumpMask(f, "compress_mask", (const u8 *)&limex->compressMask, size);
|
||||
dumpMask(f, "emask", (const u8 *)&limex->exceptionMask, size);
|
||||
dumpMask(f, "zombie", (const u8 *)&limex->zombieMask, size);
|
||||
|
||||
// Dump top masks, if there are any.
|
||||
u32 topCount = limex->topCount;
|
||||
const u8 *topMask = (const u8 *)limex + limex->topOffset;
|
||||
for (u32 i = 0; i < topCount; i++) {
|
||||
std::ostringstream name;
|
||||
name << "top_" << i;
|
||||
dumpMask(f, name.str().c_str(), topMask, size);
|
||||
topMask += size / 8;
|
||||
}
|
||||
|
||||
dumpSquash(limex, f);
|
||||
|
||||
dumpLimexReachMap(limex->reachMap, f);
|
||||
dumpLimexReachMasks(size, (const u8 *)limex + sizeof(*limex) /* reach*/,
|
||||
limex->reachSize, f);
|
||||
|
||||
dumpAccepts(limex, f);
|
||||
|
||||
dumpLimexExceptions<limex_type>(limex, f);
|
||||
|
||||
dumpAccel<limex_type>(limex, f);
|
||||
|
||||
dumpRepeats(limex, size, f);
|
||||
dumpTextReverse(limex_to_nfa(limex), f);
|
||||
}
|
||||
|
||||
static
|
||||
bool testbit(const u8 *mask, UNUSED u32 mask_bits, u32 bit) {
|
||||
u32 byte = bit / 8;
|
||||
return mask[byte] & (1 << (bit % 8));
|
||||
}
|
||||
|
||||
static
|
||||
void setupReach(const u8 *reachMap, const u8 *reachBase, u32 size,
|
||||
u32 state_count, vector<CharReach> *perStateReach) {
|
||||
for (u32 i = 0; i < state_count; i++) {
|
||||
perStateReach->push_back(CharReach());
|
||||
for (u32 j = 0; j < N_CHARS; j++) {
|
||||
u8 k = reachMap[j];
|
||||
const u8 *r = reachBase + k * (size/8);
|
||||
if (testbit(r, size, i)) {
|
||||
perStateReach->back().set(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct nfa_labeller {
|
||||
virtual ~nfa_labeller() {}
|
||||
virtual void label_state(FILE *f, u32 state) const = 0;
|
||||
};
|
||||
|
||||
template<typename limex_type>
|
||||
struct limex_labeller : public nfa_labeller {
|
||||
explicit limex_labeller(const limex_type *limex_in) : limex(limex_in) {}
|
||||
|
||||
void label_state(FILE *f, u32 state) const {
|
||||
const typename limex_traits<limex_type>::exception_type *exceptions
|
||||
= getExceptionTable(limex);
|
||||
if (!testbit((const u8 *)&limex->exceptionMask,
|
||||
limex_traits<limex_type>::size, state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 ex_index = limex->exceptionMap[state];
|
||||
const typename limex_traits<limex_type>::exception_type *e
|
||||
= &exceptions[ex_index];
|
||||
|
||||
switch (e->trigger) {
|
||||
case LIMEX_TRIGGER_TUG: fprintf(f, "\\nTUG"); break;
|
||||
case LIMEX_TRIGGER_POS: fprintf(f, "\\nPOS"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
const limex_type *limex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpVertexDotInfo(const limex_type *limex, u32 state_count, FILE *f,
|
||||
const nfa_labeller &labeller) {
|
||||
u32 size = sizeof(limex->init) * 8;
|
||||
const u8 *reach = (const u8 *)limex + sizeof(*limex);
|
||||
vector<CharReach> perStateReach;
|
||||
setupReach(limex->reachMap, reach, size, state_count, &perStateReach);
|
||||
|
||||
const u8 *topMask = (const u8 *)limex + limex->topOffset;
|
||||
|
||||
for (u32 state = 0; state < state_count; state++) {
|
||||
fprintf(f, "%u [ width = 1, fixedsize = true, fontsize = 12, "
|
||||
"label = \"%u\\n", state, state);
|
||||
assert(perStateReach[state].any());
|
||||
describeClass(f, perStateReach[state], 5, CC_OUT_DOT);
|
||||
labeller.label_state(f, state);
|
||||
// bung in another couple lines to push char class (the widest thing) up a bit
|
||||
fprintf(f, "\\n\\n\" ];\n");
|
||||
|
||||
if (testbit((const u8 *)&limex->acceptAtEOD, size, state)) {
|
||||
fprintf(f, "%u [ shape = box ];\n", state);
|
||||
} else if (testbit((const u8 *)&limex->accept, size, state)) {
|
||||
fprintf(f, "%u [ shape = doublecircle ];\n", state);
|
||||
}
|
||||
if (testbit((const u8 *)&limex->accel, size, state)) {
|
||||
fprintf(f, "%u [ color = red style = diagonals];\n", state);
|
||||
}
|
||||
if (testbit((const u8 *)&limex->init, size, state)) {
|
||||
fprintf(f, "START -> %u [ color = grey ];\n", state);
|
||||
}
|
||||
|
||||
// vertex could be in a top mask.
|
||||
for (u32 i = 0; i < limex->topCount; i++) {
|
||||
const u8 *msk = topMask + i * (size / 8);
|
||||
if (testbit(msk, size, state)) {
|
||||
fprintf(f, "START -> %u [ color = grey, "
|
||||
"label = \"TOP %u\" ];\n",
|
||||
state, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpExDotInfo(const limex_type *limex, u32 state, FILE *f) {
|
||||
u32 size = limex_traits<limex_type>::size;
|
||||
if (!testbit((const u8 *)&limex->exceptionMask, size, state)) {
|
||||
return; /* not exceptional */
|
||||
}
|
||||
|
||||
const typename limex_traits<limex_type>::exception_type *exceptions
|
||||
= getExceptionTable(limex);
|
||||
|
||||
u32 ex_index = limex->exceptionMap[state];
|
||||
const typename limex_traits<limex_type>::exception_type *e
|
||||
= &exceptions[ex_index];
|
||||
|
||||
u32 state_count = limex_to_nfa(limex)->nPositions;
|
||||
|
||||
for (u32 j = 0; j < state_count; j++) {
|
||||
if (testbit((const u8 *)&e->successors, size, j)) {
|
||||
fprintf(f, "%u -> %u [color = blue];\n", state, j);
|
||||
}
|
||||
if (!testbit((const u8 *)&e->squash, size, j)) {
|
||||
fprintf(f, "%u -> %u [color = grey style = dashed];\n", state, j);
|
||||
}
|
||||
}
|
||||
if (e->trigger != LIMEX_TRIGGER_NONE) {
|
||||
fprintf(f, "%u [color = forestgreen];\n", state);
|
||||
} else {
|
||||
fprintf(f, "%u [color = blue];\n", state);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename limex_type>
|
||||
static
|
||||
void dumpLimDotInfo(const limex_type *limex, u32 state, FILE *f) {
|
||||
for (u32 j = 0; j < MAX_MAX_SHIFT; j++) {
|
||||
if (testbit((const u8 *)&limex->shift[j],
|
||||
limex_traits<limex_type>::size, state)) {
|
||||
fprintf(f, "%u -> %u;\n", state, state + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DUMP_TEXT_FN(ddf_u, ddf_n, ddf_s) \
|
||||
void nfaExecLimEx##ddf_n##_##ddf_s##_dumpText(const NFA *nfa, FILE *f) { \
|
||||
dumpLimexText((const LimExNFA##ddf_n *)getImplNfa(nfa), f); \
|
||||
}
|
||||
|
||||
#define DUMP_DOT_FN(ddf_u, ddf_n, ddf_s) \
|
||||
void nfaExecLimEx##ddf_n##_##ddf_s##_dumpDot(const NFA *nfa, FILE *f) { \
|
||||
const LimExNFA##ddf_n *limex = \
|
||||
(const LimExNFA##ddf_n *)getImplNfa(nfa); \
|
||||
\
|
||||
dumpDotPreamble(f); \
|
||||
u32 state_count = nfa->nPositions; \
|
||||
dumpVertexDotInfo(limex, state_count, f, \
|
||||
limex_labeller<LimExNFA##ddf_n>(limex)); \
|
||||
for (u32 i = 0; i < state_count; i++) { \
|
||||
dumpLimDotInfo(limex, i, f); \
|
||||
dumpExDotInfo(limex, i, f); \
|
||||
} \
|
||||
\
|
||||
dumpDotTrailer(f); \
|
||||
}
|
||||
|
||||
#define LIMEX_DUMP_FNS(ntype, size, shifts) \
|
||||
DUMP_TEXT_FN(ntype, size, shifts) \
|
||||
DUMP_DOT_FN(ntype, size, shifts)
|
||||
|
||||
LIMEX_DUMP_FNS(u32, 32, 1)
|
||||
LIMEX_DUMP_FNS(u32, 32, 2)
|
||||
LIMEX_DUMP_FNS(u32, 32, 3)
|
||||
LIMEX_DUMP_FNS(u32, 32, 4)
|
||||
LIMEX_DUMP_FNS(u32, 32, 5)
|
||||
LIMEX_DUMP_FNS(u32, 32, 6)
|
||||
LIMEX_DUMP_FNS(u32, 32, 7)
|
||||
|
||||
LIMEX_DUMP_FNS(m128, 128, 1)
|
||||
LIMEX_DUMP_FNS(m128, 128, 2)
|
||||
LIMEX_DUMP_FNS(m128, 128, 3)
|
||||
LIMEX_DUMP_FNS(m128, 128, 4)
|
||||
LIMEX_DUMP_FNS(m128, 128, 5)
|
||||
LIMEX_DUMP_FNS(m128, 128, 6)
|
||||
LIMEX_DUMP_FNS(m128, 128, 7)
|
||||
|
||||
LIMEX_DUMP_FNS(m256, 256, 1)
|
||||
LIMEX_DUMP_FNS(m256, 256, 2)
|
||||
LIMEX_DUMP_FNS(m256, 256, 3)
|
||||
LIMEX_DUMP_FNS(m256, 256, 4)
|
||||
LIMEX_DUMP_FNS(m256, 256, 5)
|
||||
LIMEX_DUMP_FNS(m256, 256, 6)
|
||||
LIMEX_DUMP_FNS(m256, 256, 7)
|
||||
|
||||
LIMEX_DUMP_FNS(m384, 384, 1)
|
||||
LIMEX_DUMP_FNS(m384, 384, 2)
|
||||
LIMEX_DUMP_FNS(m384, 384, 3)
|
||||
LIMEX_DUMP_FNS(m384, 384, 4)
|
||||
LIMEX_DUMP_FNS(m384, 384, 5)
|
||||
LIMEX_DUMP_FNS(m384, 384, 6)
|
||||
LIMEX_DUMP_FNS(m384, 384, 7)
|
||||
|
||||
LIMEX_DUMP_FNS(m512, 512, 1)
|
||||
LIMEX_DUMP_FNS(m512, 512, 2)
|
||||
LIMEX_DUMP_FNS(m512, 512, 3)
|
||||
LIMEX_DUMP_FNS(m512, 512, 4)
|
||||
LIMEX_DUMP_FNS(m512, 512, 5)
|
||||
LIMEX_DUMP_FNS(m512, 512, 6)
|
||||
LIMEX_DUMP_FNS(m512, 512, 7)
|
||||
|
||||
} // namespace ue2
|
||||
330
src/nfa/limex_exceptional.h
Normal file
330
src/nfa/limex_exceptional.h
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: runtime exception processing code.
|
||||
*
|
||||
* 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.
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "limex_ring.h"
|
||||
#include "util/join.h"
|
||||
#include "util/uniform_ops.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 TESTBIT_STATE JOIN(testbit_, STATE_T)
|
||||
#define EXCEPTION_T JOIN(struct NFAException, SIZE)
|
||||
#define CONTEXT_T JOIN(NFAContext, SIZE)
|
||||
#define IMPL_NFA_T JOIN(LimExNFA, SIZE)
|
||||
#define GET_NFA_REPEAT_INFO_FN JOIN(getNfaRepeatInfo, SIZE)
|
||||
|
||||
#ifdef ESTATE_ON_STACK
|
||||
#define ESTATE_ARG STATE_T estate
|
||||
#else
|
||||
#define ESTATE_ARG const STATE_T *estatep
|
||||
#define estate LOAD_STATE(estatep)
|
||||
#endif
|
||||
|
||||
#ifdef STATE_ON_STACK
|
||||
#define STATE_ARG_NAME s
|
||||
#define STATE_ARG STATE_T STATE_ARG_NAME
|
||||
#define STATE_ARG_P &s
|
||||
#else
|
||||
#define STATE_ARG_NAME sp
|
||||
#define STATE_ARG const STATE_T *STATE_ARG_NAME
|
||||
#define STATE_ARG_P sp
|
||||
#endif
|
||||
|
||||
#ifndef STATE_ON_STACK
|
||||
#define BIG_MODEL
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_64_BIT
|
||||
#define CHUNK_T u64a
|
||||
#define FIND_AND_CLEAR_FN findAndClearLSB_64
|
||||
#else
|
||||
#define CHUNK_T u32
|
||||
#define FIND_AND_CLEAR_FN findAndClearLSB_32
|
||||
#endif
|
||||
|
||||
/** \brief Process a single exception. Returns 1 if exception handling should
|
||||
* continue, 0 if an accept callback has instructed us to halt. */
|
||||
static really_inline
|
||||
int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
|
||||
STATE_T *succ,
|
||||
#ifndef BIG_MODEL
|
||||
STATE_T *local_succ,
|
||||
#endif
|
||||
const struct IMPL_NFA_T *limex,
|
||||
const ReportID *exReports,
|
||||
u64a offset,
|
||||
struct CONTEXT_T *ctx,
|
||||
struct proto_cache *new_cache,
|
||||
enum CacheResult *cacheable,
|
||||
char in_rev,
|
||||
const char flags) {
|
||||
assert(e);
|
||||
|
||||
#ifdef DEBUG_EXCEPTIONS
|
||||
printf("EXCEPTION e=%p reports=%u trigger=", e, e->reports);
|
||||
if (e->trigger == LIMEX_TRIGGER_NONE) {
|
||||
printf("none");
|
||||
} else if (e->trigger == LIMEX_TRIGGER_POS) {
|
||||
printf("pos");
|
||||
} else if (e->trigger == LIMEX_TRIGGER_TUG) {
|
||||
printf("tug");
|
||||
} else {
|
||||
printf("unknown!");
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
// Trigger exceptions, used in bounded repeats.
|
||||
assert(!in_rev || e->trigger == LIMEX_TRIGGER_NONE);
|
||||
if (!in_rev && e->trigger != LIMEX_TRIGGER_NONE) {
|
||||
assert(e->repeatOffset != MO_INVALID_IDX);
|
||||
const struct NFARepeatInfo *info =
|
||||
(const struct NFARepeatInfo *)((const char *)limex +
|
||||
e->repeatOffset);
|
||||
const struct RepeatInfo *repeat = getRepeatInfo(info);
|
||||
assert(ctx->repeat_ctrl && ctx->repeat_state);
|
||||
union RepeatControl *repeat_ctrl = ctx->repeat_ctrl + info->ctrlIndex;
|
||||
char *repeat_state = ctx->repeat_state + info->stateOffset;
|
||||
|
||||
if (e->trigger == LIMEX_TRIGGER_POS) {
|
||||
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;
|
||||
} else {
|
||||
assert(e->trigger == LIMEX_TRIGGER_TUG);
|
||||
enum TriggerResult rv =
|
||||
processTugTrigger(repeat, repeat_ctrl, repeat_state, offset);
|
||||
if (rv == TRIGGER_FAIL) {
|
||||
*cacheable = DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES;
|
||||
DEBUG_PRINTF("tug found no valid matches in repeat state\n");
|
||||
return 1; // continue
|
||||
} else if (rv == TRIGGER_STALE) {
|
||||
*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)));
|
||||
return 1; // continue
|
||||
} else if (rv == TRIGGER_SUCCESS_CACHE) {
|
||||
new_cache->br = 1;
|
||||
} else {
|
||||
assert(rv == TRIGGER_SUCCESS);
|
||||
*cacheable = DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some exceptions fire accepts.
|
||||
if (e->reports != MO_INVALID_IDX) {
|
||||
if (flags & CALLBACK_OUTPUT) {
|
||||
const ReportID *reports = exReports + e->reports;
|
||||
if (unlikely(limexRunReports(reports, ctx->callback,
|
||||
ctx->context, offset)
|
||||
== MO_HALT_MATCHING)) {
|
||||
DEBUG_PRINTF("callback instructed us to stop\n");
|
||||
return 0; // halt
|
||||
}
|
||||
if (*cacheable == CACHE_RESULT) {
|
||||
if (!new_cache->reports || new_cache->reports == reports) {
|
||||
new_cache->reports = reports;
|
||||
} else {
|
||||
*cacheable = DO_NOT_CACHE_RESULT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((flags & FIRST_BYTE) && *cacheable == CACHE_RESULT) {
|
||||
*cacheable = DO_NOT_CACHE_RESULT;
|
||||
} /* otherwise we can cache as we never care about accepts */
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
#else
|
||||
STORE_STATE(&ctx->local_succ, OR_STATE(LOAD_STATE(&ctx->local_succ),
|
||||
LOAD_STATE(&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 (*cacheable == CACHE_RESULT) {
|
||||
*cacheable = DO_NOT_CACHE_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; // continue
|
||||
}
|
||||
|
||||
#ifndef RUN_EXCEPTION_FN_ONLY
|
||||
|
||||
/** \brief Process all of the exceptions associated with the states in the \a estate. */
|
||||
static really_inline
|
||||
int PE_FN(STATE_ARG, ESTATE_ARG, u32 diffmask, STATE_T *succ,
|
||||
const struct IMPL_NFA_T *limex,
|
||||
const u32 *exceptionMap, const EXCEPTION_T *exceptions,
|
||||
const ReportID *exReports,
|
||||
u64a offset, struct CONTEXT_T *ctx, char in_rev, char flags) {
|
||||
assert(diffmask > 0); // guaranteed by caller macro
|
||||
|
||||
if (EQ_STATE(estate, LOAD_STATE(&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)));
|
||||
if (ctx->cached_reports) {
|
||||
if (unlikely(limexRunReports(ctx->cached_reports, ctx->callback,
|
||||
ctx->context, offset)
|
||||
== MO_HALT_MATCHING)) {
|
||||
return PE_RV_HALT; // halt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef BIG_MODEL
|
||||
STATE_T local_succ = ZERO_STATE;
|
||||
#else
|
||||
STORE_STATE(&ctx->local_succ, ZERO_STATE);
|
||||
#endif
|
||||
|
||||
// A copy of the estate as an array of GPR-sized chunks.
|
||||
CHUNK_T chunks[sizeof(STATE_T) / sizeof(CHUNK_T)];
|
||||
#ifdef ESTATE_ON_STACK
|
||||
memcpy(chunks, &estate, sizeof(STATE_T));
|
||||
#else
|
||||
memcpy(chunks, estatep, sizeof(STATE_T));
|
||||
#endif
|
||||
|
||||
struct proto_cache new_cache = {0, NULL};
|
||||
enum CacheResult cacheable = CACHE_RESULT;
|
||||
|
||||
do {
|
||||
u32 t = findAndClearLSB_32(&diffmask);
|
||||
#ifdef ARCH_64_BIT
|
||||
t >>= 1; // Due to diffmask64, which leaves holes in the bitmask.
|
||||
#endif
|
||||
assert(t < ARRAY_LENGTH(chunks));
|
||||
CHUNK_T word = chunks[t];
|
||||
assert(word != 0);
|
||||
u32 base = t * sizeof(CHUNK_T) * 8;
|
||||
do {
|
||||
u32 bit = FIND_AND_CLEAR_FN(&word) + base;
|
||||
u32 idx = exceptionMap[bit];
|
||||
const EXCEPTION_T *e = &exceptions[idx];
|
||||
|
||||
if (!RUN_EXCEPTION_FN(e, STATE_ARG_NAME, succ,
|
||||
#ifndef BIG_MODEL
|
||||
&local_succ,
|
||||
#endif
|
||||
limex, exReports, offset, ctx, &new_cache,
|
||||
&cacheable, in_rev, flags)) {
|
||||
return PE_RV_HALT;
|
||||
}
|
||||
} while (word);
|
||||
} while (diffmask);
|
||||
|
||||
#ifndef BIG_MODEL
|
||||
STORE_STATE(succ, OR_STATE(LOAD_STATE(succ), local_succ));
|
||||
#else
|
||||
STORE_STATE(succ, OR_STATE(LOAD_STATE(succ), ctx->local_succ));
|
||||
#endif
|
||||
|
||||
if (cacheable == CACHE_RESULT) {
|
||||
STORE_STATE(&ctx->cached_estate, estate);
|
||||
#ifndef BIG_MODEL
|
||||
ctx->cached_esucc = local_succ;
|
||||
#else
|
||||
STORE_STATE(&ctx->cached_esucc, LOAD_STATE(&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);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef ZERO_STATE
|
||||
#undef AND_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 EXCEPTION_T
|
||||
|
||||
#ifdef estate
|
||||
#undef estate
|
||||
#endif
|
||||
|
||||
#ifdef BIG_MODEL
|
||||
#undef BIG_MODEL
|
||||
#endif
|
||||
|
||||
#undef STATE_ARG
|
||||
#undef STATE_ARG_NAME
|
||||
#undef STATE_ARG_P
|
||||
|
||||
#undef CHUNK_T
|
||||
#undef FIND_AND_CLEAR_FN
|
||||
#undef IMPL_NFA_T
|
||||
#undef GET_NFA_REPEAT_INFO_FN
|
||||
|
||||
// Parameters.
|
||||
#undef SIZE
|
||||
#undef STATE_T
|
||||
204
src/nfa/limex_internal.h
Normal file
204
src/nfa/limex_internal.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
This file provides the internal structures and definitions required for the
|
||||
real NFAs (aka limex NFAs );
|
||||
|
||||
Limex NFAs now have variable length in memory. They look like this:
|
||||
|
||||
LimExNFA structure
|
||||
Fixed length, e.g. LimExNFA256.
|
||||
Reachability table
|
||||
Variable length array of state bitvectors, mapped into by
|
||||
NFACommonXXX.reachMap.
|
||||
Tops
|
||||
Variable length array of state bitvectors, used for TOP_N events.
|
||||
Acceleration structures
|
||||
Variable length array of AccelAux structs.
|
||||
Accepts
|
||||
Variable length array of NFAAccept structs.
|
||||
EOD Accepts
|
||||
Variable length array of NFAAccept structs.
|
||||
Exceptions
|
||||
Variable length array of NFAExceptionXXX structs.
|
||||
Repeat Structure Offsets
|
||||
Array of u32 offsets that point at each "Repeat Structure" (below)
|
||||
Repeat Structures
|
||||
Variable length repeat structures, addressed via
|
||||
NFAException32::repeatOffset etc.
|
||||
|
||||
The state associated with the NFA is split into:
|
||||
|
||||
-# The "traditional" NFA state as a bitvector. This is stored in the
|
||||
first N bytes of the state space (length given in
|
||||
NFACommonXXX.stateSize), and may be stored shrunk to CEIL(stateSize/8)
|
||||
or compressed. If it is stored compressed, than the
|
||||
LIMEX_FLAG_COMPRESS_STATE flag is set in NFACommonXXX.flags.
|
||||
-# Extended NFA state, only used in some LimEx NFAs. This consists of a
|
||||
variable length array of LimExNFAExtendedState structures, each with
|
||||
pointers to a packed list of mmbit structures that follows them. Only
|
||||
present when used.
|
||||
|
||||
The value of NFA.stateSize gives the total state size in bytes (the sum of
|
||||
all the above).
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_INTERNAL_H
|
||||
#define LIMEX_INTERNAL_H
|
||||
|
||||
#include "nfa_internal.h"
|
||||
#include "repeat_internal.h"
|
||||
|
||||
// Constants
|
||||
#define MAX_MAX_SHIFT 8 /**< largest maxshift used by a LimEx NFA */
|
||||
|
||||
#define LIMEX_FLAG_COMPRESS_STATE 1 /**< pack state into stream state */
|
||||
#define LIMEX_FLAG_COMPRESS_MASKED 2 /**< use reach mask-based compression */
|
||||
|
||||
enum LimExTrigger {
|
||||
LIMEX_TRIGGER_NONE = 0,
|
||||
LIMEX_TRIGGER_POS = 1,
|
||||
LIMEX_TRIGGER_TUG = 2
|
||||
};
|
||||
|
||||
enum LimExSquash {
|
||||
LIMEX_SQUASH_NONE = 0, //!< no squash for you!
|
||||
LIMEX_SQUASH_CYCLIC = 1, //!< squash due to cyclic state
|
||||
LIMEX_SQUASH_TUG = 2, //!< squash due to tug trigger with stale estate
|
||||
LIMEX_SQUASH_REPORT = 3 //!< squash when report is raised
|
||||
};
|
||||
|
||||
struct LimExNFABase {
|
||||
u8 reachMap[N_CHARS];
|
||||
u32 reachSize;
|
||||
u32 accelCount;
|
||||
u32 accelTableOffset;
|
||||
u32 accelAuxCount;
|
||||
u32 accelAuxOffset;
|
||||
u32 acceptCount;
|
||||
u32 acceptOffset;
|
||||
u32 acceptEodCount;
|
||||
u32 acceptEodOffset;
|
||||
u32 exceptionCount;
|
||||
u32 exceptionOffset;
|
||||
u32 exReportOffset;
|
||||
u32 repeatCount;
|
||||
u32 repeatOffset;
|
||||
};
|
||||
|
||||
/* uniform looking types for the macros */
|
||||
typedef u8 u_8;
|
||||
typedef u16 u_16;
|
||||
typedef u32 u_32;
|
||||
typedef u64a u_64;
|
||||
typedef m128 u_128;
|
||||
typedef m256 u_256;
|
||||
typedef m384 u_384;
|
||||
typedef m512 u_512;
|
||||
|
||||
#define CREATE_NFA_LIMEX(size) \
|
||||
struct NFAException##size { \
|
||||
u_##size squash; /**< mask of states to leave on */ \
|
||||
u_##size successors; /**< mask of states to switch on */ \
|
||||
u32 reports; /**< offset to start of reports list, or MO_INVALID_IDX */ \
|
||||
u32 repeatOffset; /**< offset to NFARepeatInfo, or MO_INVALID_IDX */ \
|
||||
u8 hasSquash; /**< from enum LimExSquash */ \
|
||||
u8 trigger; /**< from enum LimExTrigger */ \
|
||||
}; \
|
||||
\
|
||||
struct LimExNFA##size { /* MUST align with LimExNFABase */ \
|
||||
u8 reachMap[N_CHARS]; /**< map of char -> entry in reach[] */ \
|
||||
u32 reachSize; /**< number of reach masks */ \
|
||||
u32 accelCount; /**< number of entries in accel table */ \
|
||||
u32 accelTableOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 accelAuxCount; /**< number of entries in aux table */ \
|
||||
u32 accelAuxOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 acceptCount; \
|
||||
u32 acceptOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 acceptEodCount; \
|
||||
u32 acceptEodOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 exceptionCount; \
|
||||
u32 exceptionOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 exReportOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 repeatCount; \
|
||||
u32 repeatOffset; \
|
||||
u32 exceptionMap[size]; \
|
||||
u32 squashOffset; /* rel. to start of LimExNFA; for accept squashing */ \
|
||||
u32 squashCount; \
|
||||
u32 topCount; \
|
||||
u32 topOffset; /* rel. to start of LimExNFA */ \
|
||||
u32 stateSize; /**< not including extended history */ \
|
||||
u32 flags; \
|
||||
u_##size init; \
|
||||
u_##size initDS; \
|
||||
u_##size accept; /**< mask of accept states */ \
|
||||
u_##size acceptAtEOD; /**< mask of states that accept at EOD */ \
|
||||
u_##size accel; /**< mask of accelerable states */ \
|
||||
u_##size accelPermute; /**< pshufb permute mask (not GPR) */ \
|
||||
u_##size accelCompare; /**< pshufb compare mask (not GPR) */ \
|
||||
u_##size accel_and_friends; /**< mask of accelerable states + likely
|
||||
* followers */ \
|
||||
u_##size compressMask; /**< switch off before compress */ \
|
||||
u_##size exceptionMask; \
|
||||
u_##size repeatCyclicMask; \
|
||||
u_##size shift[MAX_MAX_SHIFT]; \
|
||||
u_##size zombieMask; /**< zombie if in any of the set states */ \
|
||||
};
|
||||
|
||||
CREATE_NFA_LIMEX(32)
|
||||
CREATE_NFA_LIMEX(128)
|
||||
CREATE_NFA_LIMEX(256)
|
||||
CREATE_NFA_LIMEX(384)
|
||||
CREATE_NFA_LIMEX(512)
|
||||
|
||||
/** \brief Structure describing a bounded repeat within the LimEx NFA.
|
||||
*
|
||||
* This struct is followed in memory by:
|
||||
*
|
||||
* -# a RepeatInfo structure
|
||||
* -# a variable-sized lookup table for REPEAT_SPARSE_OPTIMAL_P repeats
|
||||
* -# a TUG mask
|
||||
*/
|
||||
struct NFARepeatInfo {
|
||||
u32 cyclicState; //!< index of this repeat's cyclic state
|
||||
u32 ctrlIndex; //!< index of this repeat's control block
|
||||
u32 packedCtrlOffset; //!< offset to packed control block in stream state
|
||||
u32 stateOffset; //!< offset to repeat state in stream state
|
||||
u32 stateSize; //!< total size of packed stream state for this repeat
|
||||
u32 tugMaskOffset; //!< offset to tug mask (rel. to NFARepeatInfo)
|
||||
};
|
||||
|
||||
struct NFAAccept {
|
||||
u32 state; //!< state ID of triggering state
|
||||
ReportID externalId; //!< report ID to raise
|
||||
u32 squash; //!< offset into masks, or MO_INVALID_IDX
|
||||
};
|
||||
|
||||
#endif
|
||||
36
src/nfa/limex_limits.h
Normal file
36
src/nfa/limex_limits.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_LIMITS_H
|
||||
#define LIMEX_LIMITS_H
|
||||
|
||||
#define NFA_MAX_STATES 512 /**< max states in an NFA */
|
||||
#define NFA_MAX_ACCEL_STATES 8 /**< max accel states in a NFA */
|
||||
#define NFA_MAX_TOP_MASKS 32 /**< max number of MQE_TOP_N event types */
|
||||
|
||||
#endif
|
||||
163
src/nfa/limex_native.c
Normal file
163
src/nfa/limex_native.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: native GPR runtime implementations.
|
||||
*/
|
||||
|
||||
//#define DEBUG
|
||||
//#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"
|
||||
|
||||
// Common code
|
||||
#define STATE_ON_STACK
|
||||
#define ESTATE_ON_STACK
|
||||
|
||||
#include "limex_runtime.h"
|
||||
|
||||
// Other implementation code from X-Macro impl.
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#include "limex_state_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define INLINE_ATTR really_inline
|
||||
#include "limex_common_impl.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// LimEx NFA implementation code - general purpose registers
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Process exceptional states
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define STATE_ON_STACK
|
||||
#define ESTATE_ON_STACK
|
||||
#define RUN_EXCEPTION_FN_ONLY
|
||||
#include "limex_exceptional.h"
|
||||
|
||||
static really_inline
|
||||
int processExceptional32(u32 s, u32 estate, UNUSED u32 diffmask, u32 *succ,
|
||||
const struct LimExNFA32 *limex,
|
||||
const u32 *exceptionMap,
|
||||
const struct NFAException32 *exceptions,
|
||||
const ReportID *exReports, u64a offset,
|
||||
struct NFAContext32 *ctx, char in_rev, char flags) {
|
||||
assert(estate != 0); // guaranteed by calling macro
|
||||
|
||||
if (estate == ctx->cached_estate) {
|
||||
DEBUG_PRINTF("using cached succ from previous state\n");
|
||||
*succ |= ctx->cached_esucc;
|
||||
if (ctx->cached_reports) {
|
||||
if (unlikely(limexRunReports(ctx->cached_reports, ctx->callback,
|
||||
ctx->context, offset)
|
||||
== MO_HALT_MATCHING)) {
|
||||
return PE_RV_HALT; // halt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 orig_estate = estate; // for caching
|
||||
u32 local_succ = 0;
|
||||
struct proto_cache new_cache = {0, NULL};
|
||||
enum CacheResult cacheable = CACHE_RESULT;
|
||||
|
||||
/* Note that only exception-states that consist of exceptions that _only_
|
||||
* set successors (not fire accepts or squash states) are cacheable. */
|
||||
|
||||
do {
|
||||
u32 bit = findAndClearLSB_32(&estate);
|
||||
u32 idx = exceptionMap[bit];
|
||||
const struct NFAException32 *e = &exceptions[idx];
|
||||
if (!runException32(e, s, succ, &local_succ, limex, exReports, offset,
|
||||
ctx, &new_cache, &cacheable, in_rev, flags)) {
|
||||
return PE_RV_HALT;
|
||||
}
|
||||
} while (estate != 0);
|
||||
|
||||
*succ |= local_succ;
|
||||
|
||||
if (cacheable == CACHE_RESULT) {
|
||||
ctx->cached_estate = orig_estate;
|
||||
ctx->cached_esucc = local_succ;
|
||||
ctx->cached_reports = new_cache.reports;
|
||||
ctx->cached_br = new_cache.br;
|
||||
} else if (cacheable == DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES) {
|
||||
ctx->cached_estate = 0U;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 32-bit models.
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 1
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 2
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 3
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 4
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 5
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 6
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 32
|
||||
#define STATE_T u32
|
||||
#define SHIFT 7
|
||||
#include "limex_runtime_impl.h"
|
||||
106
src/nfa/limex_ring.h
Normal file
106
src/nfa/limex_ring.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Bounded Repeat implementation for the LimEx NFA.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_RING_H
|
||||
#define LIMEX_RING_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "repeat.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** \brief Return values from \ref processTugTrigger, used to provide feedback
|
||||
* about a bounded repeat to the caller.
|
||||
*
|
||||
* TRIGGER_FAIL does not get cached as we prefer to use TRIGGER_STALE which
|
||||
* allows the exception to squash the cyclic state as well. */
|
||||
enum TriggerResult {
|
||||
TRIGGER_FAIL, /**< no valid matches, but history still valid */
|
||||
TRIGGER_SUCCESS, /**< valid match found */
|
||||
TRIGGER_STALE, /**< no valid matches and history is invalid (stale) */
|
||||
TRIGGER_SUCCESS_CACHE /**< valid match found; can cache as the repeat has no
|
||||
upper bound. */
|
||||
};
|
||||
|
||||
/** \brief Handle a TUG trigger: given an \p offset, returns whether a repeat
|
||||
* matches or not. */
|
||||
static really_inline
|
||||
enum TriggerResult processTugTrigger(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const char *state, u64a offset) {
|
||||
DEBUG_PRINTF("tug trigger, %s history, repeat={%u,%u}, offset=%llu, "
|
||||
"ctrl=%p, state=%p\n",
|
||||
repeatTypeName(info->type), info->repeatMin, info->repeatMax,
|
||||
offset, ctrl, state);
|
||||
|
||||
assert(ISALIGNED(ctrl));
|
||||
|
||||
enum RepeatMatch rv = repeatHasMatch(info, ctrl, state, offset);
|
||||
switch (rv) {
|
||||
case REPEAT_NOMATCH:
|
||||
return TRIGGER_FAIL;
|
||||
case REPEAT_STALE:
|
||||
return TRIGGER_STALE;
|
||||
case REPEAT_MATCH:
|
||||
if (info->repeatMax == REPEAT_INF) {
|
||||
// {N,} repeats can be cached.
|
||||
return TRIGGER_SUCCESS_CACHE;
|
||||
} else {
|
||||
return TRIGGER_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0); // unreachable
|
||||
return TRIGGER_FAIL;
|
||||
}
|
||||
|
||||
/** \brief Handle a POS trigger: stores a top in the repeat. */
|
||||
static really_inline
|
||||
void processPosTrigger(const struct RepeatInfo *info, union RepeatControl *ctrl,
|
||||
char *state, u64a offset, char is_alive) {
|
||||
DEBUG_PRINTF("pos trigger, %s history, repeat={%u,%u}, offset=%llu, "
|
||||
"is_alive=%d\n", repeatTypeName(info->type),
|
||||
info->repeatMin, info->repeatMax, offset, is_alive);
|
||||
|
||||
assert(ISALIGNED(ctrl));
|
||||
|
||||
repeatStore(info, ctrl, state, offset, is_alive);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
207
src/nfa/limex_runtime.h
Normal file
207
src/nfa/limex_runtime.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 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.
|
||||
*/
|
||||
|
||||
#ifndef LIMEX_RUNTIME_H
|
||||
#define LIMEX_RUNTIME_H
|
||||
|
||||
#include "limex_accel.h"
|
||||
#include "limex_context.h"
|
||||
#include "limex_internal.h"
|
||||
#include "nfa_api_util.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "scratch.h"
|
||||
#include "util/uniform_ops.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// LimEx NFA implementation code - common macros
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef DEBUG_INPUT
|
||||
#include <ctype.h>
|
||||
#define DUMP_INPUT(index) DEBUG_PRINTF("input %p i=%zu: %02hhx (%c)\n", \
|
||||
&input[index], index, input[index], \
|
||||
isprint(input[index]) ? input[index] : ' ')
|
||||
#else
|
||||
#define DUMP_INPUT(index) do { } while(0)
|
||||
#endif
|
||||
|
||||
#define NO_OUTPUT 0
|
||||
#define CALLBACK_OUTPUT 1
|
||||
#define FIRST_BYTE 16
|
||||
|
||||
enum CacheResult {
|
||||
DO_NOT_CACHE_RESULT,
|
||||
CACHE_RESULT,
|
||||
DO_NOT_CACHE_RESULT_AND_FLUSH_BR_ENTRIES
|
||||
};
|
||||
|
||||
struct proto_cache {
|
||||
char br;
|
||||
const ReportID *reports;
|
||||
};
|
||||
|
||||
// Shift macros for Limited NFAs. Defined in terms of uniform ops.
|
||||
#define NFA_EXEC_LIM_SHIFT(nels_type, nels_i) \
|
||||
(JOIN(shift_, nels_type)( \
|
||||
JOIN(and_, nels_type)(s, \
|
||||
JOIN(load_, nels_type)(&limex->shift[nels_i])), \
|
||||
nels_i))
|
||||
|
||||
// Calculate the (limited model) successors for a given max shift. Assumes
|
||||
// LimExNFAxxx ptr in 'l', current state in 's' and successors in 'succ'.
|
||||
|
||||
#define NFA_EXEC_GET_LIM_SUCC(gls_type, gls_shift) \
|
||||
do { \
|
||||
succ = \
|
||||
JOIN(and_, gls_type)(s, JOIN(load_, gls_type)(&limex->shift[0])); \
|
||||
switch (gls_shift) { \
|
||||
case 7: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 7)); \
|
||||
case 6: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 6)); \
|
||||
case 5: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 5)); \
|
||||
case 4: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 4)); \
|
||||
case 3: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 3)); \
|
||||
case 2: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 2)); \
|
||||
case 1: \
|
||||
succ = JOIN(or_, gls_type)(succ, NFA_EXEC_LIM_SHIFT(gls_type, 1)); \
|
||||
case 0: \
|
||||
; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PE_RV_HALT 1
|
||||
|
||||
#ifdef STATE_ON_STACK
|
||||
#define pass_state s
|
||||
#else
|
||||
#define pass_state &s
|
||||
#endif
|
||||
|
||||
#ifdef ESTATE_ON_STACK
|
||||
#define pass_estate estate
|
||||
#else
|
||||
#define pass_estate &estate
|
||||
#endif
|
||||
|
||||
static really_inline
|
||||
int limexRunReports(const ReportID *reports, NfaCallback callback,
|
||||
void *context, u64a offset) {
|
||||
assert(reports);
|
||||
assert(callback);
|
||||
|
||||
for (; *reports != MO_INVALID_IDX; ++reports) {
|
||||
DEBUG_PRINTF("firing report for id %u at offset %llu\n",
|
||||
*reports, offset);
|
||||
int rv = callback(offset, *reports, context);
|
||||
if (rv == MO_HALT_MATCHING) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
return MO_CONTINUE_MATCHING; // continue
|
||||
}
|
||||
|
||||
/** \brief Return a (correctly typed) pointer to the exception table. */
|
||||
#define getExceptionTable(exc_type, lim) \
|
||||
((const exc_type *)((const char *)(lim) + (lim)->exceptionOffset))
|
||||
|
||||
/** \brief Return a pointer to the exceptional reports list. */
|
||||
#define getExReports(lim) \
|
||||
((const ReportID *)((const char *)(lim) + (lim)->exReportOffset))
|
||||
|
||||
/** \brief Return a pointer to the ordinary accepts table. */
|
||||
#define getAcceptTable(lim) \
|
||||
((const struct NFAAccept *)((const char *)(lim) + (lim)->acceptOffset))
|
||||
|
||||
/** \brief Return a pointer to the EOD accepts table. */
|
||||
#define getAcceptEodTable(lim) \
|
||||
((const struct NFAAccept *)((const char *)(lim) + (lim)->acceptEodOffset))
|
||||
|
||||
#define MAKE_GET_NFA_REPEAT_INFO(size) \
|
||||
static really_inline const struct NFARepeatInfo *getNfaRepeatInfo##size( \
|
||||
const struct LimExNFA##size *limex, unsigned num) { \
|
||||
assert(num < limex->repeatCount); \
|
||||
\
|
||||
const char *base = (const char *)limex; \
|
||||
const u32 *repeatOffset = (const u32 *)(base + limex->repeatOffset); \
|
||||
assert(ISALIGNED(repeatOffset)); \
|
||||
\
|
||||
const struct NFARepeatInfo *info = \
|
||||
(const struct NFARepeatInfo *)(base + repeatOffset[num]); \
|
||||
assert(ISALIGNED(info)); \
|
||||
return info; \
|
||||
}
|
||||
|
||||
MAKE_GET_NFA_REPEAT_INFO(32)
|
||||
MAKE_GET_NFA_REPEAT_INFO(128)
|
||||
MAKE_GET_NFA_REPEAT_INFO(256)
|
||||
MAKE_GET_NFA_REPEAT_INFO(384)
|
||||
MAKE_GET_NFA_REPEAT_INFO(512)
|
||||
|
||||
static really_inline
|
||||
const struct RepeatInfo *getRepeatInfo(const struct NFARepeatInfo *info) {
|
||||
const struct RepeatInfo *repeat =
|
||||
(const struct RepeatInfo *)((const char *)info + sizeof(*info));
|
||||
assert(ISALIGNED(repeat));
|
||||
return repeat;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
union RepeatControl *getRepeatControlBase(char *state, size_t nfa_state_size) {
|
||||
union RepeatControl *ctrl_base =
|
||||
(union RepeatControl *)(state +
|
||||
ROUNDUP_N(nfa_state_size,
|
||||
alignof(union RepeatControl)));
|
||||
assert(ISALIGNED(ctrl_base));
|
||||
return ctrl_base;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const union RepeatControl *getRepeatControlBaseConst(const char *state,
|
||||
size_t nfa_state_size) {
|
||||
const union RepeatControl *ctrl_base =
|
||||
(const union RepeatControl *)(state +
|
||||
ROUNDUP_N(nfa_state_size,
|
||||
alignof(union RepeatControl)));
|
||||
assert(ISALIGNED(ctrl_base));
|
||||
return ctrl_base;
|
||||
}
|
||||
|
||||
#endif
|
||||
948
src/nfa/limex_runtime_impl.h
Normal file
948
src/nfa/limex_runtime_impl.h
Normal file
@@ -0,0 +1,948 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#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) || !defined(SHIFT)
|
||||
# error Must define SIZE and STATE_T and SHIFT in includer.
|
||||
#endif
|
||||
|
||||
#define LIMEX_API_ROOT JOIN(JOIN(JOIN(nfaExecLimEx, SIZE), _), SHIFT)
|
||||
|
||||
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
|
||||
|
||||
#define TESTEOD_FN JOIN(moNfaTestEod, SIZE)
|
||||
#define TESTEOD_REV_FN JOIN(moNfaRevTestEod, SIZE)
|
||||
#define INITIAL_FN JOIN(moNfaInitial, SIZE)
|
||||
#define TOP_FN JOIN(moNfaTop, SIZE)
|
||||
#define TOPN_FN JOIN(moNfaTopN, SIZE)
|
||||
#define REPORTCURRENT_FN JOIN(moNfaReportCurrent, SIZE)
|
||||
#define COMPRESS_FN JOIN(moNfaCompressState, SIZE)
|
||||
#define EXPAND_FN JOIN(moNfaExpandState, SIZE)
|
||||
#define COMPRESS_REPEATS_FN JOIN(LIMEX_API_ROOT, _Compress_Repeats)
|
||||
#define EXPAND_REPEATS_FN JOIN(LIMEX_API_ROOT, _Expand_Repeats)
|
||||
#define PROCESS_ACCEPTS_FN JOIN(moProcessAccepts, SIZE)
|
||||
#define PROCESS_ACCEPTS_NOSQUASH_FN JOIN(moProcessAcceptsNoSquash, SIZE)
|
||||
#define GET_NFA_REPEAT_INFO_FN JOIN(getNfaRepeatInfo, SIZE)
|
||||
#define RUN_ACCEL_FN JOIN(LIMEX_API_ROOT, _Run_Accel)
|
||||
#define RUN_EXCEPTIONS_FN JOIN(LIMEX_API_ROOT, _Run_Exceptions)
|
||||
#define REV_STREAM_FN JOIN(LIMEX_API_ROOT, _Rev_Stream)
|
||||
#define STREAM_FN JOIN(LIMEX_API_ROOT, _Stream)
|
||||
#define STREAMCB_FN JOIN(LIMEX_API_ROOT, _Stream_CB)
|
||||
#define STREAMFIRST_FN JOIN(LIMEX_API_ROOT, _Stream_First)
|
||||
#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 TESTBIT_STATE JOIN(testbit_, STATE_T)
|
||||
#define ZERO_STATE JOIN(zero_, STATE_T)
|
||||
#define ISNONZERO_STATE JOIN(isNonZero_, STATE_T)
|
||||
#define ISZERO_STATE JOIN(isZero_, STATE_T)
|
||||
#define NOTEQ_STATE JOIN(noteq_, STATE_T)
|
||||
|
||||
// Pick an appropriate diffrich function for this platform.
|
||||
#ifdef ARCH_64_BIT
|
||||
#define DIFFRICH_STATE JOIN(diffrich64_, STATE_T)
|
||||
#else
|
||||
#define DIFFRICH_STATE JOIN(diffrich_, STATE_T)
|
||||
#endif
|
||||
|
||||
#define EXPIRE_ESTATE_FN JOIN(limexExpireExtendedState, SIZE)
|
||||
#define SQUASH_UNTUG_BR_FN JOIN(lazyTug, SIZE)
|
||||
|
||||
// Acceleration and exception masks: we load them on the fly for really big
|
||||
// models.
|
||||
#if SIZE < 256
|
||||
#define ACCEL_MASK accelMask
|
||||
#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)
|
||||
#endif
|
||||
|
||||
// Run exception processing, if necessary. Returns 0 if scanning should
|
||||
// continue, 1 if an accept was fired and the user instructed us to halt.
|
||||
static really_inline
|
||||
char RUN_EXCEPTIONS_FN(const IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
|
||||
const ReportID *exReports, const u32 *exceptionMap,
|
||||
STATE_T s, const STATE_T emask, size_t i, u64a offset,
|
||||
STATE_T *succ, u64a *final_loc, struct CONTEXT_T *ctx,
|
||||
const char flags, const char in_rev,
|
||||
const char first_match) {
|
||||
STATE_T estate = AND_STATE(s, emask);
|
||||
u32 diffmask = DIFFRICH_STATE(ZERO_STATE, estate);
|
||||
if (likely(!diffmask)) {
|
||||
return 0; // No exceptions to process.
|
||||
}
|
||||
|
||||
if (first_match && i) {
|
||||
STATE_T acceptMask = LOAD_STATE(&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);
|
||||
*final_loc = i;
|
||||
return 1; // Halt matching.
|
||||
}
|
||||
}
|
||||
|
||||
u64a callback_offset = i + offset;
|
||||
char localflags = (!i && !in_rev) ? NO_OUTPUT | FIRST_BYTE : flags;
|
||||
|
||||
int rv = JOIN(processExceptional, SIZE)(
|
||||
pass_state, pass_estate, diffmask, succ, limex, exceptionMap,
|
||||
exceptions, exReports, callback_offset, ctx, in_rev, localflags);
|
||||
if (rv == PE_RV_HALT) {
|
||||
return 1; // Halt matching.
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
size_t RUN_ACCEL_FN(const STATE_T s, UNUSED const STATE_T accelMask,
|
||||
UNUSED const IMPL_NFA_T *limex, const u8 *accelTable,
|
||||
const union AccelAux *accelAux, const u8 *input, size_t i,
|
||||
size_t length) {
|
||||
size_t j;
|
||||
#if SIZE < 128
|
||||
// For small cases, we pass the state by value.
|
||||
j = JOIN(doAccel, SIZE)(s, accelMask, accelTable, accelAux, input, i,
|
||||
length);
|
||||
#else
|
||||
j = JOIN(doAccel, SIZE)(&s, limex, accelTable, accelAux, input, i, length);
|
||||
#endif
|
||||
|
||||
assert(j >= i);
|
||||
assert(i <= length);
|
||||
return j;
|
||||
}
|
||||
|
||||
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));
|
||||
#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);
|
||||
#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);
|
||||
const u32 *exceptionMap = limex->exceptionMap;
|
||||
assert(ISALIGNED_CL(ctx));
|
||||
assert(ISALIGNED_CL(&ctx->s));
|
||||
STATE_T s = LOAD_STATE(&ctx->s);
|
||||
STORE_STATE(&ctx->cached_estate, ZERO_STATE); /* TODO: understand why this is required */
|
||||
|
||||
/* assert(ISALIGNED_16(exceptions)); */
|
||||
/* assert(ISALIGNED_16(reach)); */
|
||||
|
||||
size_t i = 0;
|
||||
size_t min_accel_offset = 0;
|
||||
if (!limex->accelCount || length < ACCEL_MIN_LEN) {
|
||||
min_accel_offset = length;
|
||||
goto without_accel;
|
||||
} else {
|
||||
goto with_accel;
|
||||
}
|
||||
|
||||
without_accel:
|
||||
for (; i != min_accel_offset; i++) {
|
||||
DUMP_INPUT(i);
|
||||
if (ISZERO_STATE(s)) {
|
||||
DEBUG_PRINTF("no states are switched on, early exit\n");
|
||||
STORE_STATE(&ctx->s, s);
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
u8 c = input[i];
|
||||
STATE_T succ;
|
||||
NFA_EXEC_GET_LIM_SUCC(STATE_T, SHIFT);
|
||||
|
||||
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, exceptionMap, s,
|
||||
EXCEPTION_MASK, i, offset, &succ, final_loc, ctx,
|
||||
flags, 0, first_match)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
|
||||
s = AND_STATE(succ, LOAD_STATE(&reach[limex->reachMap[c]]));
|
||||
}
|
||||
|
||||
with_accel:
|
||||
for (; i != length; i++) {
|
||||
DUMP_INPUT(i);
|
||||
if (i + 16 <= length &&
|
||||
ISZERO_STATE(ANDNOT_STATE(ACCEL_AND_FRIENDS_MASK, s))) {
|
||||
DEBUG_PRINTF("current states are all accelerable\n");
|
||||
assert(i + 16 <= length);
|
||||
size_t post_idx =
|
||||
RUN_ACCEL_FN(s, ACCEL_MASK, limex, accelTable, accelAux, input,
|
||||
i, length);
|
||||
if (post_idx != i) {
|
||||
/* squashing any friends as they may no longer be valid;
|
||||
* offset back off should ensure they weren't doing anything
|
||||
* important */
|
||||
s = AND_STATE(ACCEL_MASK, s);
|
||||
}
|
||||
|
||||
if (i && post_idx < min_accel_offset + BAD_ACCEL_DIST) {
|
||||
min_accel_offset = post_idx + BIG_ACCEL_PENALTY;
|
||||
} else {
|
||||
min_accel_offset = post_idx + SMALL_ACCEL_PENALTY;
|
||||
}
|
||||
|
||||
if (min_accel_offset >= length - ACCEL_MIN_LEN) {
|
||||
min_accel_offset = length;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("advanced %zd, next accel chance in %zd/%zd\n",
|
||||
post_idx - i, min_accel_offset - post_idx,
|
||||
length - post_idx);
|
||||
|
||||
i = post_idx;
|
||||
if (i == length) {
|
||||
break; /* all chars eaten, break out of loop */
|
||||
}
|
||||
goto without_accel;
|
||||
}
|
||||
|
||||
u8 c = input[i];
|
||||
STATE_T succ;
|
||||
NFA_EXEC_GET_LIM_SUCC(STATE_T, SHIFT);
|
||||
|
||||
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, exceptionMap, s,
|
||||
EXCEPTION_MASK, i, offset, &succ, final_loc, ctx,
|
||||
flags, 0, first_match)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
|
||||
s = AND_STATE(succ, LOAD_STATE(&reach[limex->reachMap[c]]));
|
||||
}
|
||||
|
||||
STORE_STATE(&ctx->s, s);
|
||||
|
||||
if ((first_match || (flags & CALLBACK_OUTPUT)) && limex->acceptCount) {
|
||||
STATE_T acceptMask = LOAD_STATE(&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);
|
||||
assert(final_loc);
|
||||
*final_loc = length;
|
||||
return MO_HALT_MATCHING;
|
||||
} else if (PROCESS_ACCEPTS_FN(limex, &ctx->s, acceptTable,
|
||||
acceptCount, offset + length,
|
||||
ctx->callback, ctx->context)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (first_match) {
|
||||
assert(final_loc);
|
||||
*final_loc = length;
|
||||
}
|
||||
return MO_CONTINUE_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));
|
||||
#if SIZE < 256
|
||||
const STATE_T exceptionMask = LOAD_STATE(&limex->exceptionMask);
|
||||
#endif
|
||||
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
|
||||
const ReportID *exReports = getExReports(limex);
|
||||
const u32 *exceptionMap = limex->exceptionMap;
|
||||
STATE_T s = LOAD_STATE(&ctx->s);
|
||||
STORE_STATE(&ctx->cached_estate, ZERO_STATE); /* TODO: understand why this is required */
|
||||
|
||||
/* assert(ISALIGNED_16(exceptions)); */
|
||||
/* assert(ISALIGNED_16(reach)); */
|
||||
const char flags = CALLBACK_OUTPUT;
|
||||
u64a *final_loc = NULL;
|
||||
|
||||
for (size_t i = length; i != 0; i--) {
|
||||
DUMP_INPUT(i-1);
|
||||
if (ISZERO_STATE(s)) {
|
||||
DEBUG_PRINTF("no states are switched on, early exit\n");
|
||||
STORE_STATE(&ctx->s, s);
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
u8 c = input[i-1];
|
||||
STATE_T succ;
|
||||
NFA_EXEC_GET_LIM_SUCC(STATE_T, SHIFT);
|
||||
|
||||
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, exceptionMap, s,
|
||||
EXCEPTION_MASK, i, offset, &succ, final_loc, ctx,
|
||||
flags, 1, 0)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
|
||||
s = AND_STATE(succ, reach[limex->reachMap[c]]);
|
||||
}
|
||||
|
||||
STORE_STATE(&ctx->s, s);
|
||||
|
||||
STATE_T acceptMask = LOAD_STATE(&limex->accept);
|
||||
const struct NFAAccept *acceptTable = getAcceptTable(limex);
|
||||
const u32 acceptCount = limex->acceptCount;
|
||||
assert(flags & CALLBACK_OUTPUT);
|
||||
if (acceptCount) {
|
||||
STATE_T foundAccepts = AND_STATE(s, acceptMask);
|
||||
if (unlikely(ISNONZERO_STATE(foundAccepts))) {
|
||||
if (PROCESS_ACCEPTS_NOSQUASH_FN(&ctx->s, acceptTable, acceptCount,
|
||||
offset, ctx->callback,
|
||||
ctx->context)) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
}
|
||||
return MO_CONTINUE_MATCHING;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void COMPRESS_REPEATS_FN(const IMPL_NFA_T *limex, void *dest, const void *src,
|
||||
u64a offset) {
|
||||
if (!limex->repeatCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: we compress all repeats, as they may have *just* had their
|
||||
// cyclic states switched off a moment ago. TODO: is this required
|
||||
|
||||
const union RepeatControl *ctrl =
|
||||
getRepeatControlBaseConst((const char *)src, sizeof(STATE_T));
|
||||
char *state_base = (char *)dest + limex->stateSize;
|
||||
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
|
||||
const struct RepeatInfo *repeat = getRepeatInfo(info);
|
||||
repeatPack(state_base + info->packedCtrlOffset, repeat, &ctrl[i],
|
||||
offset);
|
||||
}
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _queueCompressState)(const struct NFA *n,
|
||||
const struct mq *q,
|
||||
s64a loc) {
|
||||
void *dest = q->streamState;
|
||||
const void *src = q->state;
|
||||
u8 key = queue_prev_byte(q, loc);
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
COMPRESS_FN(limex, dest, src, key);
|
||||
COMPRESS_REPEATS_FN(limex, dest, src, q->offset + loc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void EXPAND_REPEATS_FN(const IMPL_NFA_T *limex, void *dest, const void *src,
|
||||
u64a offset) {
|
||||
if (!limex->repeatCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: we expand all repeats, as they may have *just* had their
|
||||
// cyclic states switched off a moment ago. TODO: is this required?
|
||||
|
||||
union RepeatControl *ctrl =
|
||||
getRepeatControlBase((char *)dest, sizeof(STATE_T));
|
||||
const char *state_base = (const char *)src + limex->stateSize;
|
||||
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
|
||||
const struct RepeatInfo *repeat = getRepeatInfo(info);
|
||||
repeatUnpack(state_base + info->packedCtrlOffset, repeat, offset,
|
||||
&ctrl[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _expandState)(const struct NFA *n, void *dest,
|
||||
const void *src, u64a offset,
|
||||
u8 key) {
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
EXPAND_FN(limex, dest, src, key);
|
||||
EXPAND_REPEATS_FN(limex, dest, src, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _queueInitState)(const struct NFA *n,
|
||||
struct mq *q) {
|
||||
STORE_STATE(q->state, ZERO_STATE);
|
||||
|
||||
// Zero every bounded repeat control block in state.
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
union RepeatControl *ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
memset(&ctrl[i], 0, sizeof(*ctrl));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _initCompressedState)(const struct NFA *n,
|
||||
u64a offset, void *state,
|
||||
u8 key) {
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
|
||||
STATE_T s = INITIAL_FN(limex, !!offset);
|
||||
if (ISZERO_STATE(s)) {
|
||||
DEBUG_PRINTF("state went to zero\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NFA is still active, compress its state and ship it out.
|
||||
COMPRESS_FN(limex, state, &s, key);
|
||||
|
||||
// Zero every packed bounded repeat control block in stream state.
|
||||
char *repeat_region = (char *)state + limex->stateSize;
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
const struct NFARepeatInfo *info = GET_NFA_REPEAT_INFO_FN(limex, i);
|
||||
const struct RepeatInfo *repeat = getRepeatInfo(info);
|
||||
|
||||
memset(repeat_region + info->packedCtrlOffset, 0,
|
||||
repeat->packedCtrlSize);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Helper for history buffer scans, which catch up the NFA state but don't emit
|
||||
// matches.
|
||||
static never_inline
|
||||
void STREAMSILENT_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
|
||||
struct CONTEXT_T *ctx, u64a offset) {
|
||||
const char first_match = 0;
|
||||
|
||||
UNUSED char rv = STREAM_FN(limex, input, length, ctx, offset, NO_OUTPUT,
|
||||
NULL, first_match);
|
||||
assert(rv != MO_HALT_MATCHING);
|
||||
}
|
||||
|
||||
static never_inline
|
||||
char STREAMCB_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
|
||||
struct CONTEXT_T *ctx, u64a offset) {
|
||||
const char first_match = 0;
|
||||
assert(ISALIGNED_CL(ctx));
|
||||
return STREAM_FN(limex, input, length, ctx, offset, CALLBACK_OUTPUT, NULL,
|
||||
first_match);
|
||||
}
|
||||
|
||||
static never_inline
|
||||
char STREAMFIRST_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
|
||||
struct CONTEXT_T *ctx, u64a offset, u64a *final_loc) {
|
||||
const char first_match = 1; // Run to first match and stop, no callbacks.
|
||||
return STREAM_FN(limex, input, length, ctx, offset, NO_OUTPUT, final_loc,
|
||||
first_match);
|
||||
}
|
||||
|
||||
// Common code for handling the current event on the queue.
|
||||
static really_inline
|
||||
void JOIN(LIMEX_API_ROOT, _HandleEvent)(const IMPL_NFA_T *limex,
|
||||
struct mq *q, struct CONTEXT_T *ctx,
|
||||
u64a sp) {
|
||||
#define DEFINE_CASE(ee) \
|
||||
case ee: \
|
||||
DEBUG_PRINTF(#ee "\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)));
|
||||
break;
|
||||
DEFINE_CASE(MQE_START)
|
||||
break;
|
||||
DEFINE_CASE(MQE_END)
|
||||
break;
|
||||
default:
|
||||
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));
|
||||
}
|
||||
#undef DEFINE_CASE
|
||||
}
|
||||
|
||||
// "Classic" queue call, used by outfixes
|
||||
char JOIN(LIMEX_API_ROOT, _Q)(const struct NFA *n, struct mq *q, s64a end) {
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
|
||||
if (q->report_current) {
|
||||
char rv = REPORTCURRENT_FN(limex, q);
|
||||
|
||||
q->report_current = 0;
|
||||
|
||||
if (rv == MO_HALT_MATCHING) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
if (q->cur == q->end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(q->cur + 1 < q->end); /* require at least two items */
|
||||
|
||||
struct CONTEXT_T *ctx = q->scratch->nfaContext;
|
||||
assert(ISALIGNED_CL(ctx));
|
||||
ctx->repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
|
||||
ctx->repeat_state = q->streamState + limex->stateSize;
|
||||
ctx->callback = q->cb;
|
||||
ctx->context = q->context;
|
||||
STORE_STATE(&ctx->cached_estate, ZERO_STATE);
|
||||
STORE_STATE(&ctx->cached_esucc, ZERO_STATE);
|
||||
|
||||
assert(q->items[q->cur].location >= 0);
|
||||
DEBUG_PRINTF("LOAD STATE\n");
|
||||
STORE_STATE(&ctx->s, LOAD_STATE(q->state));
|
||||
assert(q->items[q->cur].type == MQE_START);
|
||||
|
||||
u64a offset = q->offset;
|
||||
u64a sp = offset + q->items[q->cur].location;
|
||||
u64a end_abs = offset + end;
|
||||
q->cur++;
|
||||
|
||||
while (q->cur < q->end && sp <= end_abs) {
|
||||
u64a ep = offset + q->items[q->cur].location;
|
||||
ep = MIN(ep, end_abs);
|
||||
assert(ep >= sp);
|
||||
|
||||
assert(sp >= offset); // We no longer do history buffer scans here.
|
||||
|
||||
if (sp >= ep) {
|
||||
goto scan_done;
|
||||
}
|
||||
|
||||
/* do main buffer region */
|
||||
DEBUG_PRINTF("MAIN BUFFER SCAN\n");
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("SCAN DONE\n");
|
||||
scan_done:
|
||||
sp = ep;
|
||||
|
||||
if (sp != offset + q->items[q->cur].location) {
|
||||
assert(q->cur);
|
||||
DEBUG_PRINTF("bail: sp = %llu end_abs == %llu offset == %llu\n",
|
||||
sp, end_abs, offset);
|
||||
assert(sp == end_abs);
|
||||
q->cur--;
|
||||
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));
|
||||
return MO_ALIVE;
|
||||
}
|
||||
|
||||
JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, ctx, sp);
|
||||
|
||||
q->cur++;
|
||||
}
|
||||
|
||||
EXPIRE_ESTATE_FN(limex, ctx, sp);
|
||||
|
||||
DEBUG_PRINTF("END\n");
|
||||
STORE_STATE(q->state, LOAD_STATE(&ctx->s));
|
||||
|
||||
if (q->cur != q->end) {
|
||||
q->cur--;
|
||||
q->items[q->cur].type = MQE_START;
|
||||
q->items[q->cur].location = sp - offset;
|
||||
return MO_ALIVE;
|
||||
}
|
||||
|
||||
return ISNONZERO_STATE(LOAD_STATE(&ctx->s));
|
||||
}
|
||||
|
||||
/* used by suffix execution in Rose */
|
||||
char JOIN(LIMEX_API_ROOT, _Q2)(const struct NFA *n, struct mq *q, s64a end) {
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
|
||||
if (q->report_current) {
|
||||
char rv = REPORTCURRENT_FN(limex, q);
|
||||
|
||||
q->report_current = 0;
|
||||
|
||||
if (rv == MO_HALT_MATCHING) {
|
||||
return MO_HALT_MATCHING;
|
||||
}
|
||||
}
|
||||
|
||||
if (q->cur == q->end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(q->cur + 1 < q->end); /* require at least two items */
|
||||
|
||||
struct CONTEXT_T *ctx = q->scratch->nfaContext;
|
||||
assert(ISALIGNED_CL(ctx));
|
||||
ctx->repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
|
||||
ctx->repeat_state = q->streamState + limex->stateSize;
|
||||
ctx->callback = q->cb;
|
||||
ctx->context = q->context;
|
||||
STORE_STATE(&ctx->cached_estate, ZERO_STATE);
|
||||
STORE_STATE(&ctx->cached_esucc, ZERO_STATE);
|
||||
|
||||
DEBUG_PRINTF("LOAD STATE\n");
|
||||
STORE_STATE(&ctx->s, LOAD_STATE(q->state));
|
||||
assert(q->items[q->cur].type == MQE_START);
|
||||
|
||||
u64a offset = q->offset;
|
||||
u64a sp = offset + q->items[q->cur].location;
|
||||
u64a end_abs = offset + end;
|
||||
q->cur++;
|
||||
|
||||
while (q->cur < q->end && sp <= end_abs) {
|
||||
u64a ep = offset + q->items[q->cur].location;
|
||||
DEBUG_PRINTF("sp = %llu, ep = %llu, end_abs = %llu\n",
|
||||
sp, ep, end_abs);
|
||||
ep = MIN(ep, end_abs);
|
||||
assert(ep >= sp);
|
||||
|
||||
assert(sp >= offset); // We no longer do history buffer scans here.
|
||||
|
||||
if (sp >= ep) {
|
||||
goto scan_done;
|
||||
}
|
||||
|
||||
/* do main buffer region */
|
||||
u64a final_look = 0;
|
||||
assert(ep - offset <= q->length);
|
||||
if (STREAMFIRST_FN(limex, q->buffer + sp - offset, ep - sp, ctx, sp,
|
||||
&final_look) == MO_HALT_MATCHING) {
|
||||
DEBUG_PRINTF("final_look:%llu sp:%llu end_abs:%llu offset:%llu\n",
|
||||
final_look, sp, end_abs, offset);
|
||||
assert(q->cur);
|
||||
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));
|
||||
return MO_MATCHES_PENDING;
|
||||
}
|
||||
|
||||
scan_done:
|
||||
sp = ep;
|
||||
|
||||
if (sp != offset + q->items[q->cur].location) {
|
||||
assert(q->cur);
|
||||
DEBUG_PRINTF("bail: sp = %llu end_abs == %llu offset == %llu\n",
|
||||
sp, end_abs, offset);
|
||||
assert(sp == end_abs);
|
||||
q->cur--;
|
||||
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));
|
||||
return MO_ALIVE;
|
||||
}
|
||||
|
||||
JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, ctx, sp);
|
||||
|
||||
q->cur++;
|
||||
}
|
||||
|
||||
EXPIRE_ESTATE_FN(limex, ctx, sp);
|
||||
|
||||
DEBUG_PRINTF("END\n");
|
||||
STORE_STATE(q->state, LOAD_STATE(&ctx->s));
|
||||
|
||||
if (q->cur != q->end) {
|
||||
q->cur--;
|
||||
q->items[q->cur].type = MQE_START;
|
||||
q->items[q->cur].location = sp - offset;
|
||||
return MO_ALIVE;
|
||||
}
|
||||
|
||||
return ISNONZERO_STATE(LOAD_STATE(&ctx->s));
|
||||
}
|
||||
|
||||
// Used for execution Rose prefix/infixes.
|
||||
char JOIN(LIMEX_API_ROOT, _QR)(const struct NFA *n, struct mq *q,
|
||||
ReportID report) {
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
|
||||
if (q->cur == q->end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(q->cur + 1 < q->end); /* require at least two items */
|
||||
|
||||
struct CONTEXT_T *ctx = q->scratch->nfaContext;
|
||||
ctx->repeat_ctrl = getRepeatControlBase(q->state, sizeof(STATE_T));
|
||||
ctx->repeat_state = q->streamState + limex->stateSize;
|
||||
ctx->callback = NULL;
|
||||
ctx->context = NULL;
|
||||
STORE_STATE(&ctx->cached_estate, ZERO_STATE);
|
||||
STORE_STATE(&ctx->cached_esucc, ZERO_STATE);
|
||||
|
||||
DEBUG_PRINTF("LOAD STATE\n");
|
||||
STORE_STATE(&ctx->s, LOAD_STATE(q->state));
|
||||
assert(q->items[q->cur].type == MQE_START);
|
||||
|
||||
u64a offset = q->offset;
|
||||
u64a sp = offset + q->items[q->cur].location;
|
||||
q->cur++;
|
||||
|
||||
while (q->cur < q->end) {
|
||||
u64a ep = offset + q->items[q->cur].location;
|
||||
if (n->maxWidth) {
|
||||
if (ep - sp > n->maxWidth) {
|
||||
sp = ep - n->maxWidth;
|
||||
STORE_STATE(&ctx->s, INITIAL_FN(limex, !!sp));
|
||||
}
|
||||
}
|
||||
assert(ep >= sp);
|
||||
|
||||
if (sp < offset) {
|
||||
DEBUG_PRINTF("HISTORY BUFFER SCAN\n");
|
||||
assert(offset - sp <= q->hlength);
|
||||
u64a local_ep = MIN(offset, ep);
|
||||
/* we are starting inside the history buffer */
|
||||
STREAMSILENT_FN(limex, q->history + q->hlength + sp - offset,
|
||||
local_ep - sp, ctx, sp);
|
||||
|
||||
sp = local_ep;
|
||||
}
|
||||
|
||||
if (sp >= ep) {
|
||||
goto scan_done;
|
||||
}
|
||||
|
||||
/* do main buffer region */
|
||||
DEBUG_PRINTF("MAIN BUFFER SCAN\n");
|
||||
assert(ep - offset <= q->length);
|
||||
STREAMSILENT_FN(limex, q->buffer + sp - offset, ep - sp, ctx, sp);
|
||||
|
||||
DEBUG_PRINTF("SCAN DONE\n");
|
||||
scan_done:
|
||||
sp = ep;
|
||||
|
||||
JOIN(LIMEX_API_ROOT, _HandleEvent)(limex, q, ctx, sp);
|
||||
|
||||
q->cur++;
|
||||
}
|
||||
|
||||
EXPIRE_ESTATE_FN(limex, ctx, sp);
|
||||
|
||||
DEBUG_PRINTF("END, nfa is %s\n",
|
||||
ISNONZERO_STATE(ctx->s) ? "still alive" : "dead");
|
||||
|
||||
STORE_STATE(q->state, LOAD_STATE(&ctx->s));
|
||||
|
||||
if (JOIN(limexInAccept, SIZE)(limex, LOAD_STATE(&ctx->s), ctx->repeat_ctrl,
|
||||
ctx->repeat_state, sp + 1, report)) {
|
||||
return MO_MATCHES_PENDING;
|
||||
}
|
||||
|
||||
return ISNONZERO_STATE(LOAD_STATE(&ctx->s));
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _testEOD)(const struct NFA *n, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback,
|
||||
UNUSED SomNfaCallback som_callback,
|
||||
void *context) {
|
||||
assert(n && state);
|
||||
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
const STATE_T *sptr = (const STATE_T *)state;
|
||||
const union RepeatControl *repeat_ctrl =
|
||||
getRepeatControlBaseConst(state, sizeof(STATE_T));
|
||||
const char *repeat_state = streamState + limex->stateSize;
|
||||
return TESTEOD_FN(limex, sptr, repeat_ctrl, repeat_state, offset, 1,
|
||||
callback, context);
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _reportCurrent)(const struct NFA *n, struct mq *q) {
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
REPORTCURRENT_FN(limex, q);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Block mode reverse scan.
|
||||
char JOIN(LIMEX_API_ROOT, _B_Reverse)(const struct NFA *n, u64a offset,
|
||||
const u8 *buf, size_t buflen,
|
||||
const u8 *hbuf, size_t hlen,
|
||||
struct hs_scratch *scratch,
|
||||
NfaCallback cb, void *context) {
|
||||
assert(buf || hbuf);
|
||||
assert(buflen || hlen);
|
||||
|
||||
/* This may be called INSIDE another NFA, so we need a separate
|
||||
* context --> Hence the nfaContextSom */
|
||||
struct CONTEXT_T *ctx = scratch->nfaContextSom;
|
||||
ctx->repeat_ctrl = NULL;
|
||||
ctx->repeat_state = NULL;
|
||||
ctx->callback = cb;
|
||||
ctx->context = context;
|
||||
STORE_STATE(&ctx->cached_estate, ZERO_STATE);
|
||||
STORE_STATE(&ctx->cached_esucc, ZERO_STATE);
|
||||
|
||||
const IMPL_NFA_T *limex = getImplNfa(n);
|
||||
STORE_STATE(&ctx->s, INITIAL_FN(limex, 0)); // always anchored
|
||||
|
||||
// 'buf' may be null, for example when we're scanning at EOD time.
|
||||
if (buflen) {
|
||||
assert(buf);
|
||||
DEBUG_PRINTF("MAIN BUFFER SCAN, %zu bytes\n", buflen);
|
||||
offset -= buflen;
|
||||
REV_STREAM_FN(limex, buf, buflen, ctx, offset);
|
||||
}
|
||||
|
||||
if (hlen) {
|
||||
assert(hbuf);
|
||||
DEBUG_PRINTF("HISTORY BUFFER SCAN, %zu bytes\n", hlen);
|
||||
offset -= hlen;
|
||||
REV_STREAM_FN(limex, hbuf, hlen, ctx, offset);
|
||||
}
|
||||
|
||||
if (offset == 0 && ISNONZERO_STATE(LOAD_STATE(&ctx->s))) {
|
||||
TESTEOD_REV_FN(limex, &ctx->s, offset, cb, context);
|
||||
}
|
||||
|
||||
// NOTE: return value is unused.
|
||||
return 0;
|
||||
}
|
||||
|
||||
char JOIN(LIMEX_API_ROOT, _inAccept)(const struct NFA *nfa,
|
||||
ReportID report, struct mq *q) {
|
||||
assert(nfa && q);
|
||||
assert(q->state && q->streamState);
|
||||
|
||||
const IMPL_NFA_T *limex = getImplNfa(nfa);
|
||||
union RepeatControl *repeat_ctrl =
|
||||
getRepeatControlBase(q->state, sizeof(STATE_T));
|
||||
char *repeat_state = q->streamState + limex->stateSize;
|
||||
STATE_T state = LOAD_STATE(q->state);
|
||||
u64a offset = q->offset + q_last_loc(q) + 1;
|
||||
|
||||
return JOIN(limexInAccept, SIZE)(limex, state, repeat_ctrl, repeat_state,
|
||||
offset, report);
|
||||
}
|
||||
|
||||
enum nfa_zombie_status JOIN(LIMEX_API_ROOT, _zombie_status)(
|
||||
const struct NFA *nfa,
|
||||
struct mq *q,
|
||||
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);
|
||||
|
||||
if (limex->repeatCount) {
|
||||
u64a offset = q->offset + loc + 1;
|
||||
union RepeatControl *repeat_ctrl =
|
||||
getRepeatControlBase(q->state, sizeof(STATE_T));
|
||||
char *repeat_state = q->streamState + limex->stateSize;
|
||||
SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &state);
|
||||
}
|
||||
|
||||
if (ISNONZERO_STATE(AND_STATE(state, zmask))) {
|
||||
return NFA_ZOMBIE_ALWAYS_YES;
|
||||
}
|
||||
|
||||
return NFA_ZOMBIE_NO;
|
||||
}
|
||||
|
||||
#undef TESTEOD_FN
|
||||
#undef TESTEOD_REV_FN
|
||||
#undef INITIAL_FN
|
||||
#undef TOP_FN
|
||||
#undef TOPN_FN
|
||||
#undef REPORTCURRENT_FN
|
||||
#undef COMPRESS_FN
|
||||
#undef EXPAND_FN
|
||||
#undef COMPRESS_REPEATS_FN
|
||||
#undef EXPAND_REPEATS_FN
|
||||
#undef PROCESS_ACCEPTS_FN
|
||||
#undef PROCESS_ACCEPTS_NOSQUASH_FN
|
||||
#undef GET_NFA_REPEAT_INFO_FN
|
||||
#undef RUN_ACCEL_FN
|
||||
#undef RUN_EXCEPTIONS_FN
|
||||
#undef REV_STREAM_FN
|
||||
#undef STREAM_FN
|
||||
#undef STREAMCB_FN
|
||||
#undef STREAMFIRST_FN
|
||||
#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 TESTBIT_STATE
|
||||
#undef ZERO_STATE
|
||||
#undef ISNONZERO_STATE
|
||||
#undef ISZERO_STATE
|
||||
#undef NOTEQ_STATE
|
||||
#undef DIFFRICH_STATE
|
||||
#undef INLINE_ATTR_INT
|
||||
#undef IMPL_NFA_T
|
||||
#undef SQUASH_UNTUG_BR_FN
|
||||
#undef ACCEL_MASK
|
||||
#undef ACCEL_AND_FRIENDS_MASK
|
||||
#undef EXCEPTION_MASK
|
||||
|
||||
// Parameters.
|
||||
#undef SIZE
|
||||
#undef STATE_T
|
||||
#undef SHIFT
|
||||
#undef LIMEX_API_ROOT
|
||||
97
src/nfa/limex_simd128.c
Normal file
97
src/nfa/limex_simd128.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
//#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 128
|
||||
#define STATE_T 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
|
||||
#define SHIFT 1
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 128
|
||||
#define STATE_T m128
|
||||
#define SHIFT 2
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 128
|
||||
#define STATE_T m128
|
||||
#define SHIFT 3
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 128
|
||||
#define STATE_T m128
|
||||
#define SHIFT 4
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 128
|
||||
#define STATE_T m128
|
||||
#define SHIFT 5
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 128
|
||||
#define STATE_T m128
|
||||
#define SHIFT 6
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 128
|
||||
#define STATE_T m128
|
||||
#define SHIFT 7
|
||||
#include "limex_runtime_impl.h"
|
||||
94
src/nfa/limex_simd256.c
Normal file
94
src/nfa/limex_simd256.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: 256-bit SIMD runtime implementations.
|
||||
*/
|
||||
|
||||
//#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
|
||||
#include "limex_runtime.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T 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
|
||||
#define SHIFT 1
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T m256
|
||||
#define SHIFT 2
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T m256
|
||||
#define SHIFT 3
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T m256
|
||||
#define SHIFT 4
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T m256
|
||||
#define SHIFT 5
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T m256
|
||||
#define SHIFT 6
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 256
|
||||
#define STATE_T m256
|
||||
#define SHIFT 7
|
||||
#include "limex_runtime_impl.h"
|
||||
94
src/nfa/limex_simd384.c
Normal file
94
src/nfa/limex_simd384.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: 384-bit SIMD runtime implementations.
|
||||
*/
|
||||
|
||||
//#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
|
||||
#include "limex_runtime.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T 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
|
||||
#define SHIFT 1
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T m384
|
||||
#define SHIFT 2
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T m384
|
||||
#define SHIFT 3
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T m384
|
||||
#define SHIFT 4
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T m384
|
||||
#define SHIFT 5
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T m384
|
||||
#define SHIFT 6
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 384
|
||||
#define STATE_T m384
|
||||
#define SHIFT 7
|
||||
#include "limex_runtime_impl.h"
|
||||
74
src/nfa/limex_simd512a.c
Normal file
74
src/nfa/limex_simd512a.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: 512-bit SIMD runtime implementations.
|
||||
*/
|
||||
|
||||
//#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
|
||||
#include "limex_runtime.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T 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
|
||||
#define SHIFT 2
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T m512
|
||||
#define SHIFT 1
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T m512
|
||||
#define SHIFT 3
|
||||
#include "limex_runtime_impl.h"
|
||||
69
src/nfa/limex_simd512b.c
Normal file
69
src/nfa/limex_simd512b.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: 512-bit SIMD runtime implementations.
|
||||
*/
|
||||
|
||||
//#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
|
||||
#include "limex_runtime.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T 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
|
||||
#define SHIFT 4
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T m512
|
||||
#define SHIFT 5
|
||||
#include "limex_runtime_impl.h"
|
||||
69
src/nfa/limex_simd512c.c
Normal file
69
src/nfa/limex_simd512c.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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: 512-bit SIMD runtime implementations.
|
||||
*/
|
||||
|
||||
//#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
|
||||
#include "limex_runtime.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T 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
|
||||
#define SHIFT 6
|
||||
#include "limex_runtime_impl.h"
|
||||
|
||||
#define SIZE 512
|
||||
#define STATE_T m512
|
||||
#define SHIFT 7
|
||||
#include "limex_runtime_impl.h"
|
||||
144
src/nfa/limex_state_impl.h
Normal file
144
src/nfa/limex_state_impl.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 NFA stream state handling.
|
||||
*/
|
||||
|
||||
#include "util/join.h"
|
||||
#include "util/partial_store.h"
|
||||
#include "util/state_compress.h"
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(SIZE) || !defined(STATE_T)
|
||||
# error Must define SIZE and STATE_T in includer.
|
||||
#endif
|
||||
|
||||
#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
|
||||
#define COMMON_T JOIN(NFACommon, 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 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]];
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
DEBUG_PRINTF("compress state: %p -> %p\n", src, dest);
|
||||
|
||||
if (!(limex->flags & LIMEX_FLAG_COMPRESS_STATE)) {
|
||||
// No key-based compression, just a partial store.
|
||||
DEBUG_PRINTF("store state into %u bytes\n", limex->stateSize);
|
||||
PARTIAL_STORE_FN(dest, a_src, limex->stateSize);
|
||||
} else {
|
||||
DEBUG_PRINTF("compress state, key=%hhx\n", key);
|
||||
|
||||
const 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);
|
||||
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));
|
||||
COMPRESSED_STORE_FN(dest, &s, &mask, limex->stateSize);
|
||||
} else {
|
||||
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) {
|
||||
assert(ISALIGNED_N(dest, alignof(STATE_T)));
|
||||
DEBUG_PRINTF("expand state: %p -> %p\n", src, dest);
|
||||
|
||||
if (!(limex->flags & LIMEX_FLAG_COMPRESS_STATE)) {
|
||||
// No key-based compression, just a partial load.
|
||||
DEBUG_PRINTF("load state from %u bytes\n", limex->stateSize);
|
||||
*dest = PARTIAL_LOAD_FN(src, limex->stateSize);
|
||||
} else {
|
||||
DEBUG_PRINTF("expand state, key=%hhx\n", key);
|
||||
const 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));
|
||||
COMPRESSED_LOAD_FN(dest, src, &mask, limex->stateSize);
|
||||
STORE_STATE(dest, OR_STATE(LOAD_STATE(&limex->initDS),
|
||||
LOAD_STATE(dest)));
|
||||
} else {
|
||||
COMPRESSED_LOAD_FN(dest, src, reachmask, limex->stateSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef IMPL_NFA_T
|
||||
#undef COMMON_T
|
||||
#undef REACHMASK_FN
|
||||
#undef COMPRESS_FN
|
||||
#undef EXPAND_FN
|
||||
#undef COMPRESSED_STORE_FN
|
||||
#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
|
||||
1121
src/nfa/mcclellan.c
Normal file
1121
src/nfa/mcclellan.c
Normal file
File diff suppressed because it is too large
Load Diff
109
src/nfa/mcclellan.h
Normal file
109
src/nfa/mcclellan.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MCCLELLAN_H
|
||||
#define MCCLELLAN_H
|
||||
|
||||
#include "callback.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
struct mq;
|
||||
struct NFA;
|
||||
|
||||
// 8-bit McClellan
|
||||
|
||||
char nfaExecMcClellan8_testEOD(const struct NFA *nfa, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback, SomNfaCallback som_cb,
|
||||
void *context);
|
||||
char nfaExecMcClellan8_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecMcClellan8_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecMcClellan8_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecMcClellan8_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecMcClellan8_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecMcClellan8_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecMcClellan8_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecMcClellan8_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecMcClellan8_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecMcClellan8_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecMcClellan8_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
// 16-bit McClellan
|
||||
|
||||
char nfaExecMcClellan16_testEOD(const struct NFA *nfa, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback, SomNfaCallback som_cb,
|
||||
void *context);
|
||||
char nfaExecMcClellan16_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecMcClellan16_Q2(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecMcClellan16_QR(const struct NFA *n, struct mq *q, ReportID report);
|
||||
char nfaExecMcClellan16_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecMcClellan16_inAccept(const struct NFA *n, ReportID report,
|
||||
struct mq *q);
|
||||
char nfaExecMcClellan16_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecMcClellan16_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecMcClellan16_queueCompressState(const struct NFA *nfa,
|
||||
const struct mq *q, s64a loc);
|
||||
char nfaExecMcClellan16_expandState(const struct NFA *nfa, void *dest,
|
||||
const void *src, u64a offset, u8 key);
|
||||
|
||||
#define nfaExecMcClellan16_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecMcClellan16_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
/**
|
||||
* Simple streaming mode calls:
|
||||
* - always uses the anchored start state regardless if top is set regardless of
|
||||
* start_off
|
||||
* - never checks eod
|
||||
*/
|
||||
void nfaExecMcClellan8_SimpStream(const struct NFA *nfa, char *state,
|
||||
const u8 *buf, char top, size_t start_off,
|
||||
size_t len, NfaCallback cb, void *ctxt);
|
||||
|
||||
void nfaExecMcClellan16_SimpStream(const struct NFA *nfa, char *state,
|
||||
const u8 *buf, char top, size_t start_off,
|
||||
size_t len, NfaCallback cb, void *ctxt);
|
||||
|
||||
/**
|
||||
* Simple block mode calls:
|
||||
* - always uses the anchored start state regardless of initial start
|
||||
*/
|
||||
|
||||
char nfaExecMcClellan8_B(const struct NFA *n, u64a offset, const u8 *buffer,
|
||||
size_t length, NfaCallback cb, void *context);
|
||||
|
||||
char nfaExecMcClellan16_B(const struct NFA *n, u64a offset, const u8 *buffer,
|
||||
size_t length, NfaCallback cb, void *context);
|
||||
|
||||
#endif
|
||||
92
src/nfa/mcclellan_common_impl.h
Normal file
92
src/nfa/mcclellan_common_impl.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#if defined(__INTEL_COMPILER) || defined(__clang__) || defined(_WIN32) || defined(__GNUC__) && (__GNUC__ < 4)
|
||||
#define really_flatten
|
||||
#else
|
||||
#define really_flatten __attribute__ ((flatten))
|
||||
#endif
|
||||
|
||||
#define CASE_MASK 0xdf
|
||||
|
||||
enum MatchMode {
|
||||
CALLBACK_OUTPUT,
|
||||
STOP_AT_MATCH,
|
||||
NO_MATCHES
|
||||
};
|
||||
|
||||
static really_inline
|
||||
const struct mstate_aux *get_aux(const struct mcclellan *m, u16 s) {
|
||||
const char *nfa = (const char *)m - sizeof(struct NFA);
|
||||
const struct mstate_aux *aux
|
||||
= s + (const struct mstate_aux *)(nfa + m->aux_offset);
|
||||
|
||||
assert(ISALIGNED(aux));
|
||||
return aux;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
u16 mcclellanEnableStarts(const struct mcclellan *m, u16 s) {
|
||||
const struct mstate_aux *aux = get_aux(m, s);
|
||||
|
||||
DEBUG_PRINTF("enabling starts %hu->%hu\n", s, aux->top);
|
||||
return aux->top;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
u16 doSherman16(const char *sherman_state, u8 cprime, const u16 *succ_table,
|
||||
u32 as) {
|
||||
assert(ISALIGNED_N(sherman_state, 16));
|
||||
|
||||
u8 len = *(const u8 *)(sherman_state + SHERMAN_LEN_OFFSET);
|
||||
|
||||
if (len) {
|
||||
m128 ss_char = load128(sherman_state);
|
||||
m128 cur_char = set16x8(cprime);
|
||||
|
||||
u32 z = movemask128(eq128(ss_char, cur_char));
|
||||
|
||||
/* remove header cruft: type 1, len 1, daddy 2*/
|
||||
z &= ~0xf;
|
||||
z &= (1U << (len + 4)) - 1;
|
||||
|
||||
if (z) {
|
||||
u32 i = ctz32(z & ~0xf) - 4;
|
||||
|
||||
u16 s_out = unaligned_load_u16((const u8 *)sherman_state
|
||||
+ SHERMAN_STATES_OFFSET(len)
|
||||
+ sizeof(u16) * i);
|
||||
DEBUG_PRINTF("found sherman match at %u/%u for c'=%hhu "
|
||||
"s=%hu\n", i, len, cprime, s_out);
|
||||
return s_out;
|
||||
}
|
||||
}
|
||||
|
||||
u16 daddy = *(const u16 *)(sherman_state + SHERMAN_DADDY_OFFSET);
|
||||
return succ_table[((u32)daddy << as) + cprime];
|
||||
}
|
||||
113
src/nfa/mcclellan_internal.h
Normal file
113
src/nfa/mcclellan_internal.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MCCLELLAN_INTERNAL_H
|
||||
#define MCCLELLAN_INTERNAL_H
|
||||
|
||||
#include "nfa_internal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define ACCEPT_FLAG 0x8000
|
||||
#define ACCEL_FLAG 0x4000
|
||||
#define STATE_MASK 0x3fff
|
||||
|
||||
#define SHERMAN_STATE 1
|
||||
|
||||
#define SHERMAN_TYPE_OFFSET 0
|
||||
#define SHERMAN_FIXED_SIZE 32
|
||||
|
||||
#define SHERMAN_LEN_OFFSET 1
|
||||
#define SHERMAN_DADDY_OFFSET 2
|
||||
#define SHERMAN_CHARS_OFFSET 4
|
||||
#define SHERMAN_STATES_OFFSET(sso_len) (4 + (sso_len))
|
||||
|
||||
struct report_list {
|
||||
u32 count;
|
||||
ReportID report[];
|
||||
};
|
||||
|
||||
struct mstate_aux {
|
||||
u32 accept;
|
||||
u32 accept_eod;
|
||||
u16 top;
|
||||
u32 accel_offset; /* relative to start of struct mcclellan; 0 if no accel */
|
||||
};
|
||||
|
||||
#define MCCLELLAN_FLAG_SINGLE 1 /**< we raise only single accept id */
|
||||
|
||||
struct mcclellan {
|
||||
u16 state_count; /**< total number of states */
|
||||
u32 length; /**< length of dfa in bytes */
|
||||
u16 start_anchored; /**< anchored start state */
|
||||
u16 start_floating; /**< floating start state */
|
||||
u32 aux_offset; /**< offset of the aux structures relative to the start of
|
||||
* the nfa structure */
|
||||
u32 sherman_offset; /**< offset of to array of sherman state offsets
|
||||
* the state_info structures relative to the start of the
|
||||
* nfa structure */
|
||||
u32 sherman_end; /**< offset of the end of the state_info structures relative
|
||||
* to the start of the nfa structure */
|
||||
u16 accel_limit_8; /**< 8 bit, lowest accelerable state */
|
||||
u16 accept_limit_8; /**< 8 bit, lowest accept state */
|
||||
u16 sherman_limit; /**< lowest sherman state */
|
||||
u8 alphaShift;
|
||||
u8 flags;
|
||||
u8 has_accel; /**< 1 iff there are any accel planes */
|
||||
u8 remap[256]; /**< remaps characters to a smaller alphabet */
|
||||
ReportID arb_report; /**< one of the accepts that this dfa may raise */
|
||||
u32 accel_offset; /**< offset of the accel structures from start of NFA */
|
||||
u32 haig_offset; /**< reserved for use by Haig, relative to start of NFA */
|
||||
};
|
||||
|
||||
static really_inline
|
||||
const char *findShermanState(UNUSED const struct mcclellan *m,
|
||||
const char *sherman_base_offset, u16 sherman_base,
|
||||
u16 s) {
|
||||
const char *rv
|
||||
= sherman_base_offset + SHERMAN_FIXED_SIZE * (s - sherman_base);
|
||||
assert(rv < (const char *)m + m->length - sizeof(struct NFA));
|
||||
UNUSED u8 type = *(const u8 *)(rv + SHERMAN_TYPE_OFFSET);
|
||||
assert(type == SHERMAN_STATE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char *findMutableShermanState(char *sherman_base_offset, u16 sherman_base,
|
||||
u16 s) {
|
||||
return sherman_base_offset + SHERMAN_FIXED_SIZE * (s - sherman_base);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1252
src/nfa/mcclellancompile.cpp
Normal file
1252
src/nfa/mcclellancompile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
120
src/nfa/mcclellancompile.h
Normal file
120
src/nfa/mcclellancompile.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MCCLELLANCOMPILE_H
|
||||
#define MCCLELLANCOMPILE_H
|
||||
|
||||
#include "rdfa.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct CompileContext;
|
||||
|
||||
struct raw_report_info {
|
||||
raw_report_info();
|
||||
virtual ~raw_report_info();
|
||||
virtual u32 getReportListSize() const = 0; /* in bytes */
|
||||
virtual size_t size() const = 0; /* number of lists */
|
||||
virtual void fillReportLists(NFA *n, size_t base_offset,
|
||||
std::vector<u32> &ro /* out */) const = 0;
|
||||
};
|
||||
|
||||
struct escape_info {
|
||||
CharReach outs;
|
||||
CharReach outs2_single;
|
||||
flat_set<std::pair<u8, u8>> outs2;
|
||||
bool outs2_broken = false;
|
||||
};
|
||||
|
||||
class dfa_build_strat {
|
||||
public:
|
||||
virtual ~dfa_build_strat();
|
||||
virtual raw_dfa &get_raw() const = 0;
|
||||
virtual std::unique_ptr<raw_report_info> gatherReports(
|
||||
std::vector<u32> &reports /* out */,
|
||||
std::vector<u32> &reports_eod /* out */,
|
||||
u8 *isSingleReport /* out */,
|
||||
ReportID *arbReport /* out */) const = 0;
|
||||
virtual void find_escape_strings(dstate_id_t this_idx,
|
||||
escape_info *out) const = 0;
|
||||
virtual size_t accelSize(void) const = 0;
|
||||
virtual void buildAccel(dstate_id_t this_idx, void *accel_out) = 0;
|
||||
};
|
||||
|
||||
class mcclellan_build_strat : public dfa_build_strat {
|
||||
public:
|
||||
explicit mcclellan_build_strat(raw_dfa &r) : rdfa(r) {}
|
||||
raw_dfa &get_raw() const override { return rdfa; }
|
||||
std::unique_ptr<raw_report_info> gatherReports(
|
||||
std::vector<u32> &reports /* out */,
|
||||
std::vector<u32> &reports_eod /* out */,
|
||||
u8 *isSingleReport /* out */,
|
||||
ReportID *arbReport /* out */) const override;
|
||||
void find_escape_strings(dstate_id_t this_idx,
|
||||
escape_info *out) const override;
|
||||
size_t accelSize(void) const override;
|
||||
void buildAccel(dstate_id_t this_idx, void *accel_out) override;
|
||||
|
||||
private:
|
||||
raw_dfa &rdfa;
|
||||
};
|
||||
|
||||
/* accel_states: (optional) on success, is filled with the set of accelerable
|
||||
* states */
|
||||
ue2::aligned_unique_ptr<NFA>
|
||||
mcclellanCompile(raw_dfa &raw, const CompileContext &cc,
|
||||
std::set<dstate_id_t> *accel_states = nullptr);
|
||||
|
||||
/* used internally by mcclellan/haig/gough compile process */
|
||||
ue2::aligned_unique_ptr<NFA>
|
||||
mcclellanCompile_i(raw_dfa &raw, dfa_build_strat &strat,
|
||||
const CompileContext &cc,
|
||||
std::set<dstate_id_t> *accel_states = nullptr);
|
||||
|
||||
/**
|
||||
* \brief Returns the width of the character reach at start.
|
||||
*/
|
||||
u32 mcclellanStartReachSize(const raw_dfa *raw);
|
||||
|
||||
std::set<ReportID> all_reports(const raw_dfa &rdfa);
|
||||
|
||||
bool has_accel_dfa(const NFA *nfa);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
337
src/nfa/mcclellancompile_util.cpp
Normal file
337
src/nfa/mcclellancompile_util.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "mcclellancompile_util.h"
|
||||
|
||||
#include "rdfa.h"
|
||||
#include "util/container.h"
|
||||
#include "util/ue2_containers.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#define INIT_STATE 1
|
||||
|
||||
static
|
||||
u32 count_dots(const raw_dfa &raw) {
|
||||
assert(raw.start_anchored == INIT_STATE);
|
||||
|
||||
u32 i = INIT_STATE;
|
||||
for (; i < raw.states.size() && i != raw.start_floating; i++) {
|
||||
DEBUG_PRINTF("checking %u\n", i);
|
||||
assert(raw.states[i].reports.empty());
|
||||
assert(raw.states[i].reports_eod.empty());
|
||||
|
||||
for (symbol_t s = 0; s < raw.getImplAlphaSize(); s++) {
|
||||
DEBUG_PRINTF("%hu -> %hu\n", s, raw.states[i].next[s]);
|
||||
if (raw.states[i].next[s] != i + 1) {
|
||||
goto validate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!raw.states[raw.states[i].next[0]].reports.empty()
|
||||
|| !raw.states[raw.states[i].next[0]].reports_eod.empty()) {
|
||||
goto validate;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("got dot\n");
|
||||
}
|
||||
|
||||
validate:
|
||||
u32 dot_count = i - INIT_STATE;
|
||||
|
||||
/* we need to check that no later state has a transition into these leading
|
||||
* dots */
|
||||
for (; i < raw.states.size(); i++) {
|
||||
for (symbol_t s = 0; s < raw.getImplAlphaSize(); s++) {
|
||||
DEBUG_PRINTF("%hu -> %hu\n", s, raw.states[i].next[s]);
|
||||
dstate_id_t n = raw.states[i].next[s];
|
||||
if (n != DEAD_STATE && n <= dot_count) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dot_count;
|
||||
}
|
||||
|
||||
static
|
||||
void prune_leading_states(raw_dfa &raw, u32 count) {
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = INIT_STATE + count; i < raw.states.size(); i++) {
|
||||
dstate &curr = raw.states[i - count];
|
||||
curr = raw.states[i];
|
||||
if (curr.daddy > count) {
|
||||
curr.daddy -= count;
|
||||
} else {
|
||||
curr.daddy = DEAD_STATE;
|
||||
}
|
||||
|
||||
for (u32 j = 0; j < raw.alpha_size; j++) {
|
||||
assert(curr.next[j] == DEAD_STATE || curr.next[j] > count);
|
||||
if (curr.next[j]) {
|
||||
curr.next[j] -= count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raw.states.erase(raw.states.end() - count, raw.states.end());
|
||||
}
|
||||
|
||||
u32 remove_leading_dots(raw_dfa &raw) {
|
||||
u32 count = count_dots(raw);
|
||||
prune_leading_states(raw, count);
|
||||
DEBUG_PRINTF("removed %u leading dots\n", count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static never_inline
|
||||
u32 calc_min_dist_from_bob(raw_dfa &raw, vector<u32> *dist_in) {
|
||||
vector<u32> &dist = *dist_in;
|
||||
dist.clear();
|
||||
dist.resize(raw.states.size(), ~0U);
|
||||
|
||||
assert(raw.start_anchored != DEAD_STATE);
|
||||
|
||||
deque<dstate_id_t> to_visit;
|
||||
to_visit.push_back(raw.start_anchored);
|
||||
dist[raw.start_anchored] = 0;
|
||||
|
||||
u32 last_d = 0;
|
||||
|
||||
while (!to_visit.empty()) {
|
||||
dstate_id_t s = to_visit.front();
|
||||
DEBUG_PRINTF("inspecting %u\n", s);
|
||||
to_visit.pop_front();
|
||||
assert(s != DEAD_STATE);
|
||||
|
||||
u32 d = dist[s];
|
||||
assert(d >= last_d);
|
||||
assert(d != ~0U);
|
||||
|
||||
for (u32 j = 0; j < raw.alpha_size; j++) {
|
||||
dstate_id_t t = raw.states[s].next[j];
|
||||
if (t == DEAD_STATE) {
|
||||
continue;
|
||||
}
|
||||
if (dist[t] == ~0U) {
|
||||
to_visit.push_back(t);
|
||||
dist[t] = d + 1;
|
||||
} else {
|
||||
assert(dist[t] <= d + 1);
|
||||
}
|
||||
}
|
||||
|
||||
last_d = d;
|
||||
}
|
||||
|
||||
return last_d;
|
||||
}
|
||||
|
||||
static
|
||||
void find_in_edges(const raw_dfa &raw, vector<vector<dstate_id_t> > *in_edges) {
|
||||
in_edges->clear();
|
||||
in_edges->resize(raw.states.size());
|
||||
ue2::unordered_set<dstate_id_t> seen;
|
||||
|
||||
for (u32 s = 1; s < raw.states.size(); s++) {
|
||||
seen.clear();
|
||||
for (u32 j = 0; j < raw.alpha_size; j++) {
|
||||
dstate_id_t t = raw.states[s].next[j];
|
||||
if (contains(seen, t)) {
|
||||
continue;
|
||||
}
|
||||
seen.insert(t);
|
||||
(*in_edges)[t].push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void calc_min_dist_to_accept(const raw_dfa &raw,
|
||||
const vector<vector<dstate_id_t> > &in_edges,
|
||||
vector<u32> *accept_dist) {
|
||||
vector<u32> &dist = *accept_dist;
|
||||
dist.clear();
|
||||
dist.resize(raw.states.size(), ~0U);
|
||||
|
||||
/* for reporting states to start from */
|
||||
deque<dstate_id_t> to_visit;
|
||||
for (u32 s = 0; s < raw.states.size(); s++) {
|
||||
if (!raw.states[s].reports.empty()
|
||||
|| !raw.states[s].reports_eod.empty()) {
|
||||
to_visit.push_back(s);
|
||||
dist[s] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* bfs */
|
||||
UNUSED u32 last_d = 0;
|
||||
while (!to_visit.empty()) {
|
||||
dstate_id_t s = to_visit.front();
|
||||
to_visit.pop_front();
|
||||
assert(s != DEAD_STATE);
|
||||
|
||||
u32 d = dist[s];
|
||||
assert(d >= last_d);
|
||||
assert(d != ~0U);
|
||||
|
||||
for (vector<dstate_id_t>::const_iterator it = in_edges[s].begin();
|
||||
it != in_edges[s].end(); ++it) {
|
||||
dstate_id_t t = *it;
|
||||
if (t == DEAD_STATE) {
|
||||
continue;
|
||||
}
|
||||
if (dist[t] == ~0U) {
|
||||
to_visit.push_back(t);
|
||||
dist[t] = d + 1;
|
||||
} else {
|
||||
assert(dist[t] <= d + 1);
|
||||
}
|
||||
}
|
||||
|
||||
last_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
void prune_overlong(raw_dfa &raw, u32 max_offset) {
|
||||
DEBUG_PRINTF("pruning to at most %u\n", max_offset);
|
||||
vector<u32> bob_dist;
|
||||
u32 max_min_dist_bob = calc_min_dist_from_bob(raw, &bob_dist);
|
||||
|
||||
if (max_min_dist_bob <= max_offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<vector<dstate_id_t> > in_edges;
|
||||
find_in_edges(raw, &in_edges);
|
||||
|
||||
vector<u32> accept_dist;
|
||||
calc_min_dist_to_accept(raw, in_edges, &accept_dist);
|
||||
|
||||
in_edges.clear();
|
||||
|
||||
/* look over the states and filter out any which cannot reach a report
|
||||
* states before max_offset */
|
||||
vector<dstate_id_t> new_ids(raw.states.size());
|
||||
vector<dstate> new_states;
|
||||
u32 count = 1;
|
||||
new_states.push_back(raw.states[DEAD_STATE]);
|
||||
|
||||
for (u32 s = DEAD_STATE + 1; s < raw.states.size(); s++) {
|
||||
if (bob_dist[s] + accept_dist[s] > max_offset) {
|
||||
DEBUG_PRINTF("pruned %u: bob %u, report %u\n", s, bob_dist[s],
|
||||
accept_dist[s]);
|
||||
new_ids[s] = DEAD_STATE;
|
||||
} else {
|
||||
new_ids[s] = count++;
|
||||
new_states.push_back(raw.states[s]);
|
||||
assert(new_states.size() == count);
|
||||
assert(new_ids[s] <= s);
|
||||
}
|
||||
}
|
||||
|
||||
/* swap states */
|
||||
DEBUG_PRINTF("pruned %zu -> %u\n", raw.states.size(), count);
|
||||
raw.states.swap(new_states);
|
||||
new_states.clear();
|
||||
|
||||
/* update edges and daddys to refer to the new ids */
|
||||
for (u32 s = DEAD_STATE + 1; s < raw.states.size(); s++) {
|
||||
for (u32 j = 0; j < raw.alpha_size; j++) {
|
||||
dstate_id_t old_t = raw.states[s].next[j];
|
||||
raw.states[s].next[j] = new_ids[old_t];
|
||||
}
|
||||
raw.states[s].daddy = new_ids[raw.states[s].daddy];
|
||||
}
|
||||
|
||||
/* update specials */
|
||||
raw.start_floating = new_ids[raw.start_floating];
|
||||
raw.start_anchored = new_ids[raw.start_anchored];
|
||||
}
|
||||
|
||||
set<ReportID> all_reports(const raw_dfa &rdfa) {
|
||||
set<ReportID> all;
|
||||
for (const auto &ds : rdfa.states) {
|
||||
insert(&all, ds.reports);
|
||||
insert(&all, ds.reports_eod);
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
bool has_eod_accepts(const raw_dfa &rdfa) {
|
||||
for (const auto &ds : rdfa.states) {
|
||||
if (!ds.reports_eod.empty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_non_eod_accepts(const raw_dfa &rdfa) {
|
||||
for (const auto &ds : rdfa.states) {
|
||||
if (!ds.reports.empty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash_dfa_no_reports(const raw_dfa &rdfa) {
|
||||
using boost::hash_combine;
|
||||
using boost::hash_range;
|
||||
|
||||
size_t v = 0;
|
||||
hash_combine(v, rdfa.alpha_size);
|
||||
hash_combine(v, hash_range(begin(rdfa.alpha_remap), end(rdfa.alpha_remap)));
|
||||
|
||||
for (const auto &ds : rdfa.states) {
|
||||
hash_combine(v, hash_range(begin(ds.next), end(ds.next)));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t hash_dfa(const raw_dfa &rdfa) {
|
||||
using boost::hash_combine;
|
||||
size_t v = 0;
|
||||
hash_combine(v, hash_dfa_no_reports(rdfa));
|
||||
hash_combine(v, all_reports(rdfa));
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
55
src/nfa/mcclellancompile_util.h
Normal file
55
src/nfa/mcclellancompile_util.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MCCLELLAN_COMPILE_UTIL_H
|
||||
#define MCCLELLAN_COMPILE_UTIL_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct raw_dfa;
|
||||
|
||||
u32 remove_leading_dots(raw_dfa &raw);
|
||||
void prune_overlong(raw_dfa &raw, u32 max_offset);
|
||||
std::set<ReportID> all_reports(const raw_dfa &rdfa);
|
||||
bool has_eod_accepts(const raw_dfa &rdfa);
|
||||
bool has_non_eod_accepts(const raw_dfa &rdfa);
|
||||
|
||||
/** \brief Compute a simple hash of this raw_dfa. Does not include report
|
||||
* information. */
|
||||
size_t hash_dfa_no_reports(const raw_dfa &rdfa);
|
||||
|
||||
/** \brief Compute a simple hash of this raw_dfa, including its reports. */
|
||||
size_t hash_dfa(const raw_dfa &rdfa);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
438
src/nfa/mcclellandump.cpp
Normal file
438
src/nfa/mcclellandump.cpp
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mcclellandump.h"
|
||||
|
||||
#include "accel.h"
|
||||
#include "accel_dump.h"
|
||||
#include "nfa_dump_internal.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "mcclellan_internal.h"
|
||||
#include "rdfa.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/dump_charclass.h"
|
||||
#include "util/unaligned.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
const mstate_aux *getAux(const NFA *n, dstate_id_t i) {
|
||||
assert(n && isDfaType(n->type));
|
||||
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(n);
|
||||
const mstate_aux *aux_base
|
||||
= (const mstate_aux *)((const char *)n + m->aux_offset);
|
||||
|
||||
const mstate_aux *aux = aux_base + i;
|
||||
|
||||
assert((const char *)aux < (const char *)n + m->length);
|
||||
return aux;
|
||||
}
|
||||
|
||||
static
|
||||
void mcclellanGetTransitions(const NFA *n, u16 s, u16 *t) {
|
||||
assert(isMcClellanType(n->type));
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(n);
|
||||
const mstate_aux *aux = getAux(n, s);
|
||||
const u32 as = m->alphaShift;
|
||||
|
||||
if (n->type == MCCLELLAN_NFA_8) {
|
||||
const u8 *succ_table = (const u8 *)((const char *)m
|
||||
+ sizeof(mcclellan));
|
||||
for (u16 c = 0; c < N_CHARS; c++) {
|
||||
t[c] = succ_table[((u32)s << as) + m->remap[c]];
|
||||
}
|
||||
} else {
|
||||
u16 base_s = s;
|
||||
const char *winfo_base = (const char *)n + m->sherman_offset;
|
||||
const char *state_base
|
||||
= winfo_base + SHERMAN_FIXED_SIZE * (s - m->sherman_limit);
|
||||
|
||||
if (s >= m->sherman_limit) {
|
||||
base_s = unaligned_load_u16(state_base + SHERMAN_DADDY_OFFSET);
|
||||
}
|
||||
|
||||
const u16 *succ_table = (const u16 *)((const char *)m
|
||||
+ sizeof(mcclellan));
|
||||
for (u16 c = 0; c < N_CHARS; c++) {
|
||||
const u8 *addr = (const u8*)(succ_table + (((u32)base_s << as)
|
||||
+ m->remap[c]));
|
||||
t[c] = unaligned_load_u16(addr);
|
||||
t[c] &= STATE_MASK;
|
||||
}
|
||||
|
||||
if (s >= m->sherman_limit) {
|
||||
UNUSED char type = *(state_base + SHERMAN_TYPE_OFFSET);
|
||||
assert(type == SHERMAN_STATE);
|
||||
u8 len = *(const u8 *)(SHERMAN_LEN_OFFSET + state_base);
|
||||
const char *chars = state_base + SHERMAN_CHARS_OFFSET;
|
||||
const u16 *states = (const u16 *)(state_base
|
||||
+ SHERMAN_STATES_OFFSET(len));
|
||||
|
||||
for (u8 i = 0; i < len; i++) {
|
||||
for (u16 c = 0; c < N_CHARS; c++) {
|
||||
if (m->remap[c] == chars[i]) {
|
||||
t[c] = unaligned_load_u16((const u8*)&states[i]) & STATE_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t[TOP] = aux->top & STATE_MASK;
|
||||
}
|
||||
|
||||
void describeEdge(FILE *f, const u16 *t, u16 i) {
|
||||
for (u16 s = 0; s < N_CHARS; s++) {
|
||||
if (!t[s]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
u16 ss;
|
||||
for (ss = 0; ss < s; ss++) {
|
||||
if (t[s] == t[ss]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ss != s) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CharReach reach;
|
||||
for (ss = s; ss < 256; ss++) {
|
||||
if (t[s] == t[ss]) {
|
||||
reach.set(ss);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "%u -> %u [ label = \"", i, t[s]);
|
||||
|
||||
describeClass(f, reach, 5, CC_OUT_DOT);
|
||||
|
||||
fprintf(f, "\" ];\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dumpAccelText(FILE *f, const union AccelAux *accel) {
|
||||
switch(accel->accel_type) {
|
||||
case ACCEL_NONE:
|
||||
break;
|
||||
case ACCEL_VERM:
|
||||
fprintf(f, ":V");
|
||||
break;
|
||||
case ACCEL_DVERM:
|
||||
fprintf(f, ":VV");
|
||||
break;
|
||||
case ACCEL_VERM_NOCASE:
|
||||
fprintf(f, ":VN");
|
||||
break;
|
||||
case ACCEL_DVERM_NOCASE:
|
||||
fprintf(f, ":VVN");
|
||||
break;
|
||||
case ACCEL_SHUFTI:
|
||||
fprintf(f, ":S");
|
||||
break;
|
||||
case ACCEL_DSHUFTI:
|
||||
fprintf(f, ":SS");
|
||||
break;
|
||||
case ACCEL_TRUFFLE:
|
||||
fprintf(f, ":M");
|
||||
break;
|
||||
default:
|
||||
fprintf(f, ":??");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpAccelDot(FILE *f, u16 i, const union AccelAux *accel) {
|
||||
switch(accel->accel_type) {
|
||||
case ACCEL_NONE:
|
||||
break;
|
||||
case ACCEL_VERM:
|
||||
case ACCEL_VERM_NOCASE:
|
||||
case ACCEL_DVERM:
|
||||
case ACCEL_DVERM_NOCASE:
|
||||
fprintf(f, "%u [ color = forestgreen style=diagonals];\n", i);
|
||||
break;
|
||||
case ACCEL_SHUFTI:
|
||||
case ACCEL_DSHUFTI:
|
||||
case ACCEL_TRUFFLE:
|
||||
fprintf(f, "%u [ color = darkgreen style=diagonals ];\n", i);
|
||||
break;
|
||||
default:
|
||||
fprintf(f, "%u [ color = yellow style=diagonals ];\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void describeNode(const NFA *n, const mcclellan *m, u16 i, FILE *f) {
|
||||
const mstate_aux *aux = getAux(n, i);
|
||||
|
||||
bool isSherman = m->sherman_limit && i >= m->sherman_limit;
|
||||
|
||||
fprintf(f, "%u [ width = 1, fixedsize = true, fontsize = 12, "
|
||||
"label = \"%u%s\" ]; \n", i, i, isSherman ? "w":"");
|
||||
|
||||
if (aux->accel_offset) {
|
||||
dumpAccelDot(f, i, (const union AccelAux *)
|
||||
((const char *)m + aux->accel_offset));
|
||||
}
|
||||
|
||||
if (aux->accept_eod) {
|
||||
fprintf(f, "%u [ color = darkorchid ];\n", i);
|
||||
}
|
||||
|
||||
if (aux->accept) {
|
||||
fprintf(f, "%u [ shape = doublecircle ];\n", i);
|
||||
}
|
||||
|
||||
if (aux->top && aux->top != i) {
|
||||
fprintf(f, "%u -> %u [color = darkgoldenrod weight=0.1 ]\n", i,
|
||||
aux->top);
|
||||
}
|
||||
|
||||
if (i == m->start_anchored) {
|
||||
fprintf(f, "STARTA -> %u [color = blue ]\n", i);
|
||||
}
|
||||
|
||||
if (i == m->start_floating) {
|
||||
fprintf(f, "STARTF -> %u [color = red ]\n", i);
|
||||
}
|
||||
|
||||
if (isSherman) {
|
||||
const char *winfo_base = (const char *)n + m->sherman_offset;
|
||||
const char *state_base
|
||||
= winfo_base + SHERMAN_FIXED_SIZE * (i - m->sherman_limit);
|
||||
assert(state_base < (const char *)m + m->length - sizeof(NFA));
|
||||
UNUSED u8 type = *(const u8 *)(state_base + SHERMAN_TYPE_OFFSET);
|
||||
assert(type == SHERMAN_STATE);
|
||||
fprintf(f, "%u [ fillcolor = lightblue style=filled ];\n", i);
|
||||
u16 daddy = *(const u16 *)(state_base + SHERMAN_DADDY_OFFSET);
|
||||
if (daddy) {
|
||||
fprintf(f, "%u -> %u [ color=royalblue style=dashed weight=0.1]\n",
|
||||
i, daddy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dumpDotPreambleDfa(FILE *f) {
|
||||
dumpDotPreamble(f);
|
||||
|
||||
// DFA specific additions.
|
||||
fprintf(f, "STARTF [style=invis];\n");
|
||||
fprintf(f, "STARTA [style=invis];\n");
|
||||
fprintf(f, "0 [style=invis];\n");
|
||||
}
|
||||
|
||||
void nfaExecMcClellan16_dumpDot(const NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == MCCLELLAN_NFA_16);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
|
||||
dumpDotPreambleDfa(f);
|
||||
|
||||
for (u16 i = 1; i < m->state_count; i++) {
|
||||
describeNode(nfa, m, i, f);
|
||||
|
||||
u16 t[ALPHABET_SIZE];
|
||||
|
||||
mcclellanGetTransitions(nfa, i, t);
|
||||
|
||||
describeEdge(f, t, i);
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
}
|
||||
|
||||
void nfaExecMcClellan8_dumpDot(const NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == MCCLELLAN_NFA_8);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
|
||||
dumpDotPreambleDfa(f);
|
||||
|
||||
for (u16 i = 1; i < m->state_count; i++) {
|
||||
describeNode(nfa, m, i, f);
|
||||
|
||||
u16 t[ALPHABET_SIZE];
|
||||
|
||||
mcclellanGetTransitions(nfa, i, t);
|
||||
|
||||
describeEdge(f, t, i);
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
}
|
||||
|
||||
static
|
||||
void dumpAccelMasks(FILE *f, const mcclellan *m, const mstate_aux *aux) {
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "Acceleration\n");
|
||||
fprintf(f, "------------\n");
|
||||
|
||||
for (u16 i = 0; i < m->state_count; i++) {
|
||||
if (!aux[i].accel_offset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const AccelAux *accel = (const AccelAux *)((const char *)m
|
||||
+ aux[i].accel_offset);
|
||||
fprintf(f, "%05hu ", i);
|
||||
dumpAccelInfo(f, *accel);
|
||||
}
|
||||
}
|
||||
|
||||
void describeAlphabet(FILE *f, const mcclellan *m) {
|
||||
map<u8, CharReach> rev;
|
||||
|
||||
for (u16 i = 0; i < N_CHARS; i++) {
|
||||
rev[m->remap[i]].clear();
|
||||
}
|
||||
|
||||
for (u16 i = 0; i < N_CHARS; i++) {
|
||||
rev[m->remap[i]].set(i);
|
||||
}
|
||||
|
||||
map<u8, CharReach>::const_iterator it;
|
||||
fprintf(f, "\nAlphabet\n");
|
||||
for (it = rev.begin(); it != rev.end(); ++it) {
|
||||
fprintf(f, "%3hhu: ", it->first);
|
||||
describeClass(f, it->second, 10240, CC_OUT_TEXT);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static
|
||||
void dumpCommonHeader(FILE *f, const mcclellan *m) {
|
||||
fprintf(f, "report: %u, states: %u, length: %u\n", m->arb_report,
|
||||
m->state_count, m->length);
|
||||
fprintf(f, "astart: %hu, fstart: %hu\n", m->start_anchored,
|
||||
m->start_floating);
|
||||
fprintf(f, "single accept: %d, has_accel: %d\n",
|
||||
!!(int)m->flags & MCCLELLAN_FLAG_SINGLE, m->has_accel);
|
||||
}
|
||||
|
||||
static
|
||||
void dumpTransitions(FILE *f, const NFA *nfa, const mcclellan *m,
|
||||
const mstate_aux *aux) {
|
||||
for (u16 i = 0; i < m->state_count; i++) {
|
||||
fprintf(f, "%05hu", i);
|
||||
if (aux[i].accel_offset) {
|
||||
dumpAccelText(f, (const union AccelAux *)((const char *)m +
|
||||
aux[i].accel_offset));
|
||||
}
|
||||
|
||||
u16 trans[ALPHABET_SIZE];
|
||||
mcclellanGetTransitions(nfa, i, trans);
|
||||
|
||||
int rstart = 0;
|
||||
u16 prev = 0xffff;
|
||||
for (int j = 0; j < N_CHARS; j++) {
|
||||
u16 curr = trans[j];
|
||||
if (curr == prev) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev != 0xffff) {
|
||||
if (j == rstart + 1) {
|
||||
fprintf(f, " %02x->%hu", rstart, prev);
|
||||
} else {
|
||||
fprintf(f, " [%02x - %02x]->%hu", rstart, j - 1, prev);
|
||||
}
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
rstart = j;
|
||||
}
|
||||
if (N_CHARS == rstart + 1) {
|
||||
fprintf(f, " %02x->%hu", rstart, prev);
|
||||
} else {
|
||||
fprintf(f, " [%02x - %02x]->%hu", rstart, N_CHARS - 1, prev);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void nfaExecMcClellan16_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == MCCLELLAN_NFA_16);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
const mstate_aux *aux =
|
||||
(const mstate_aux *)((const char *)nfa + m->aux_offset);
|
||||
|
||||
fprintf(f, "mcclellan 16\n");
|
||||
dumpCommonHeader(f, m);
|
||||
fprintf(f, "sherman_limit: %d, sherman_end: %d\n", (int)m->sherman_limit,
|
||||
(int)m->sherman_end);
|
||||
fprintf(f, "\n");
|
||||
|
||||
describeAlphabet(f, m);
|
||||
dumpTransitions(f, nfa, m, aux);
|
||||
dumpAccelMasks(f, m, aux);
|
||||
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
void nfaExecMcClellan8_dumpText(const NFA *nfa, FILE *f) {
|
||||
assert(nfa->type == MCCLELLAN_NFA_8);
|
||||
const mcclellan *m = (const mcclellan *)getImplNfa(nfa);
|
||||
const mstate_aux *aux =
|
||||
(const mstate_aux *)((const char *)nfa + m->aux_offset);
|
||||
|
||||
fprintf(f, "mcclellan 8\n");
|
||||
dumpCommonHeader(f, m);
|
||||
fprintf(f, "accel_limit: %hu, accept_limit %hu\n", m->accel_limit_8,
|
||||
m->accept_limit_8);
|
||||
fprintf(f, "\n");
|
||||
|
||||
describeAlphabet(f, m);
|
||||
dumpTransitions(f, nfa, m, aux);
|
||||
dumpAccelMasks(f, m, aux);
|
||||
|
||||
fprintf(f, "\n");
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
63
src/nfa/mcclellandump.h
Normal file
63
src/nfa/mcclellandump.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MCCLELLAN_DUMP_H
|
||||
#define MCCLELLAN_DUMP_H
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
|
||||
#include "rdfa.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
struct mcclellan;
|
||||
struct mstate_aux;
|
||||
struct NFA;
|
||||
union AccelAux;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecMcClellan8_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecMcClellan16_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecMcClellan8_dumpText(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecMcClellan16_dumpText(const struct NFA *nfa, FILE *file);
|
||||
|
||||
/* These functions are shared with the Haig dump code. */
|
||||
|
||||
const mstate_aux *getAux(const NFA *n, dstate_id_t i);
|
||||
void describeEdge(FILE *f, const u16 *t, u16 i);
|
||||
void dumpAccelText(FILE *f, const union AccelAux *accel);
|
||||
void dumpAccelDot(FILE *f, u16 i, const union AccelAux *accel);
|
||||
void describeAlphabet(FILE *f, const mcclellan *m);
|
||||
void dumpDotPreambleDfa(FILE *f);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
|
||||
#endif // MCCLELLAN_DUMP_H
|
||||
1093
src/nfa/mpv.c
Normal file
1093
src/nfa/mpv.c
Normal file
File diff suppressed because it is too large
Load Diff
60
src/nfa/mpv.h
Normal file
60
src/nfa/mpv.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MPV_H
|
||||
#define MPV_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
struct mq;
|
||||
struct NFA;
|
||||
|
||||
char nfaExecMpv0_Q(const struct NFA *n, struct mq *q, s64a end);
|
||||
char nfaExecMpv0_reportCurrent(const struct NFA *n, struct mq *q);
|
||||
char nfaExecMpv0_inAccept(const struct NFA *n, ReportID report, struct mq *q);
|
||||
char nfaExecMpv0_queueInitState(const struct NFA *n, struct mq *q);
|
||||
char nfaExecMpv0_initCompressedState(const struct NFA *n, u64a offset,
|
||||
void *state, u8 key);
|
||||
char nfaExecMpv0_queueCompressState(const struct NFA *nfa, const struct mq *q,
|
||||
s64a loc);
|
||||
char nfaExecMpv0_expandState(const struct NFA *nfa, void *dest, const void *src,
|
||||
u64a offset, u8 key);
|
||||
|
||||
#define nfaExecMpv0_testEOD NFA_API_NO_IMPL
|
||||
#define nfaExecMpv0_inAccept NFA_API_NO_IMPL
|
||||
#define nfaExecMpv0_QR NFA_API_NO_IMPL
|
||||
#define nfaExecMpv0_Q2 NFA_API_NO_IMPL /* for non-chained suffixes. */
|
||||
#define nfaExecMpv0_B_Reverse NFA_API_NO_IMPL
|
||||
#define nfaExecMpv0_zombie_status NFA_API_NO_IMPL
|
||||
|
||||
/**
|
||||
* return 0 if the mpv dies, otherwise returns the location of the next possible
|
||||
* match (given the currently known events). */
|
||||
s64a nfaExecMpv0_QueueExecRaw(const struct NFA *nfa, struct mq *q, s64a end);
|
||||
|
||||
#endif
|
||||
152
src/nfa/mpv_dump.cpp
Normal file
152
src/nfa/mpv_dump.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mpv_dump.h"
|
||||
|
||||
#include "mpv_internal.h"
|
||||
#include "nfa_dump_internal.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/compare.h"
|
||||
#include "util/dump_mask.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecMpv0_dumpDot(UNUSED const NFA *nfa, UNUSED FILE *file) {
|
||||
}
|
||||
|
||||
static really_inline
|
||||
u32 largest_puff_repeat(const mpv *m, const mpv_kilopuff *kp) {
|
||||
return get_puff_array(m, kp)[kp->count - 1].repeats;
|
||||
}
|
||||
|
||||
static
|
||||
void dumpKilo(FILE *f, const mpv *m, const mpv_kilopuff *k) {
|
||||
if (k->auto_restart) {
|
||||
fprintf(f, " AUTO RESTART\n");
|
||||
}
|
||||
|
||||
fprintf(f, " ");
|
||||
|
||||
switch (k->type) {
|
||||
case MPV_DOT:
|
||||
fprintf(f, "dot\n");
|
||||
break;
|
||||
case MPV_VERM:
|
||||
if (!ourisprint(k->u.verm.c)) {
|
||||
fprintf(f, "verm 0x%hhu\n", k->u.verm.c);
|
||||
} else {
|
||||
fprintf(f, "verm 0x%hhu '%c'\n", k->u.verm.c, k->u.verm.c);
|
||||
}
|
||||
break;
|
||||
case MPV_SHUFTI:
|
||||
fprintf(f, "shufti\n");
|
||||
fprintf(f, "lo %s\n",
|
||||
dumpMask((const u8 *)&k->u.shuf.mask_lo, 128).c_str());
|
||||
fprintf(f, "hi %s\n",
|
||||
dumpMask((const u8 *)&k->u.shuf.mask_hi, 128).c_str());
|
||||
break;
|
||||
case MPV_TRUFFLE:
|
||||
fprintf(f, "truffle\n");
|
||||
break;
|
||||
case MPV_NVERM:
|
||||
if (!ourisprint(k->u.verm.c)) {
|
||||
fprintf(f, "nverm 0x%hhu\n", k->u.verm.c);
|
||||
} else {
|
||||
fprintf(f, "nverm 0x%hhu '%c'\n", k->u.verm.c, k->u.verm.c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(f, "unknown type: %hhu\n", k->type);
|
||||
}
|
||||
|
||||
fprintf(f, " %u puffettes\n", k->count);
|
||||
fprintf(f, " largest repeat %u\n", largest_puff_repeat(m, k));
|
||||
fprintf(f, " dead point %llu\n", k->dead_point);
|
||||
fprintf(f, " counter offset %u\n", k->counter_offset);
|
||||
fprintf(f, " puffette offset %u\n", k->puffette_offset);
|
||||
|
||||
const mpv_puffette *p = get_puff_array(m, k);
|
||||
for (u32 i = 0; i < k->count; i++) {
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, " Puffette %u\n", i);
|
||||
fprintf(f, " repeats: %u%s\n", p[i].repeats,
|
||||
p[i].unbounded ? "," : "");
|
||||
fprintf(f, " report id: %u\n", p[i].report);
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static
|
||||
void dumpCounter(FILE *f, const mpv_counter_info *c) {
|
||||
fprintf(f, " max value %llu\n", c->max_counter);
|
||||
fprintf(f, " state offset %u\n", c->counter_offset);
|
||||
fprintf(f, " used by kilopuffs %u - %u\n", c->kilo_begin,
|
||||
c->kilo_end - 1);
|
||||
fprintf(f, " bytes %u\n", c->counter_size);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
void nfaExecMpv0_dumpText(const NFA *nfa, FILE *f) {
|
||||
const mpv *m = (const mpv *)getImplNfa(nfa);
|
||||
|
||||
fprintf(f, "Puff the Magic Engines\n");
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "%u puffettes in %u kilopuffs\n", m->puffette_count,
|
||||
m->kilo_count);
|
||||
fprintf(f, "initial kilopuffs %u - %u\n", m->top_kilo_begin,
|
||||
m->top_kilo_end - 1);
|
||||
|
||||
const mpv_kilopuff *k = (const mpv_kilopuff *)(m + 1);
|
||||
for (u32 i = 0; i < m->kilo_count; i++) {
|
||||
fprintf(f, "\nKILOPUFF %u\n", i);
|
||||
dumpKilo(f, m, k++);
|
||||
}
|
||||
|
||||
const mpv_counter_info *c = get_counter_info(m);
|
||||
for (u32 i = 0; i < m->counter_count; i++) {
|
||||
fprintf(f, "\nCOUNTER %u\n", i);
|
||||
dumpCounter(f, c++);
|
||||
}
|
||||
|
||||
dumpTextReverse(nfa, f);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
47
src/nfa/mpv_dump.h
Normal file
47
src/nfa/mpv_dump.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MPVDUMP_H
|
||||
#define MPVDUMP_H
|
||||
|
||||
#if defined(DUMP_SUPPORT)
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void nfaExecMpv0_dumpDot(const struct NFA *nfa, FILE *file);
|
||||
void nfaExecMpv0_dumpText(const struct NFA *nfa, FILE *file);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
|
||||
#endif // MPVDUMP_H
|
||||
188
src/nfa/mpv_internal.h
Normal file
188
src/nfa/mpv_internal.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MPV_INTERNAL_H
|
||||
#define MPV_INTERNAL_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
#define MPV_DOT 0
|
||||
#define MPV_VERM 1
|
||||
#define MPV_SHUFTI 2
|
||||
#define MPV_TRUFFLE 3
|
||||
#define MPV_NVERM 4
|
||||
|
||||
struct mpv_puffette {
|
||||
u32 repeats;
|
||||
char unbounded;
|
||||
ReportID report;
|
||||
};
|
||||
|
||||
struct mpv_kilopuff {
|
||||
u32 counter_offset; /**< offset (in full stream state) to the counter that
|
||||
* this kilopuff refers to */
|
||||
u32 count; /**< number of real (non sentinel mpv puffettes) */
|
||||
u32 puffette_offset; /**< relative to base of mpv, points past the 1st
|
||||
* sent */
|
||||
u64a dead_point;
|
||||
u8 auto_restart;
|
||||
u8 type; /* MPV_DOT, MPV_VERM, etc */
|
||||
union {
|
||||
struct {
|
||||
char c;
|
||||
} verm;
|
||||
struct {
|
||||
m128 mask_lo;
|
||||
m128 mask_hi;
|
||||
} shuf;
|
||||
struct {
|
||||
m128 mask1;
|
||||
m128 mask2;
|
||||
} truffle;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct mpv_counter_info {
|
||||
u64a max_counter; /**< maximum value this counter needs to track */
|
||||
u32 counter_size; /**< number of bytes to represent the counter in stream
|
||||
* state */
|
||||
u32 counter_offset; /**< offset that this counter is stored at in the
|
||||
* full stream state */
|
||||
u32 kilo_begin; /**< first kilo to turn on when the counter is started */
|
||||
u32 kilo_end; /**< 1 + last kilo to turn on when the counter is started */
|
||||
};
|
||||
|
||||
struct ALIGN_AVX_DIRECTIVE mpv {
|
||||
u32 kilo_count; /**< number of kilopuffs following */
|
||||
u32 counter_count; /**< number of counters managed by the mpv */
|
||||
u32 puffette_count; /**< total number of puffettes under all the kilos */
|
||||
u32 pq_offset; /**< offset to the priority queue in the decompressed
|
||||
* state */
|
||||
u32 reporter_offset; /**< offset to the reporter mmbit in the decompressed
|
||||
* state */
|
||||
u32 report_list_offset; /**< offset to the report list scratch space in the
|
||||
* decompressed state */
|
||||
u32 active_offset; /**< offset to the active kp mmbit in the compressed
|
||||
* state */
|
||||
u32 top_kilo_begin; /**< first kilo to switch on when top arrives */
|
||||
u32 top_kilo_end; /**< one past the last kilo to switch on when top
|
||||
* arrives */
|
||||
};
|
||||
|
||||
struct mpv_decomp_kilo {
|
||||
u64a limit;
|
||||
const struct mpv_puffette *curr;
|
||||
};
|
||||
|
||||
/* note: size varies on different platforms */
|
||||
struct mpv_decomp_state {
|
||||
u32 pq_size;
|
||||
char filled;
|
||||
u64a counter_adj; /**< progress not yet written to the real counters */
|
||||
struct mpv_decomp_kilo active[];
|
||||
};
|
||||
|
||||
/* ---
|
||||
* | | mpv
|
||||
* ---
|
||||
* | |
|
||||
* | | kilo_count * mpv_kilopuffs
|
||||
* | |
|
||||
* ...
|
||||
* | |
|
||||
* ---
|
||||
* | |
|
||||
* | | counter_count * mpv_counter_infos
|
||||
* | |
|
||||
* ...
|
||||
* | |
|
||||
* ---
|
||||
* | | sentinel mpv_puffette
|
||||
* ---
|
||||
* | | mpv_puffettes for 1st kilopuff
|
||||
* | | (mpv_puffettes are ordered by minimum number of repeats)
|
||||
* | |
|
||||
* ---
|
||||
* | | sentinel mpv_puffette
|
||||
* ---
|
||||
* | | mpv_puffettes for 2nd kilopuff
|
||||
* ...
|
||||
* | |
|
||||
* ---
|
||||
* | | sentinel mpv_puffette
|
||||
* ---
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stream State
|
||||
* [Compressed Counter 0]
|
||||
* [Compressed Counter 1]
|
||||
* ...
|
||||
* [Compressed Counter N]
|
||||
* [mmbit of active kilopuffs]
|
||||
*
|
||||
* Decompressed State
|
||||
* [header (limit pq_size)]
|
||||
* [
|
||||
* [kilo 1 current reports]
|
||||
* ...
|
||||
* [kilo N current reports]
|
||||
* ]
|
||||
* [
|
||||
* [Full Counter 0]
|
||||
* [Full Counter 1]
|
||||
* ...
|
||||
* [Full Counter N]
|
||||
* ]
|
||||
* [pq of kilo changes]
|
||||
* [scratch space for current report lists (total number of puffettes)]
|
||||
* [mmbit of kilopuffs with active reports]
|
||||
*/
|
||||
|
||||
struct mpv_pq_item {
|
||||
u64a trigger_loc;
|
||||
u32 kilo;
|
||||
};
|
||||
|
||||
/* returns pointer to first non sentinel mpv_puff */
|
||||
static really_inline
|
||||
const struct mpv_puffette *get_puff_array(const struct mpv *m,
|
||||
const struct mpv_kilopuff *kp) {
|
||||
return (const struct mpv_puffette *)((const char *)m + kp->puffette_offset);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const struct mpv_counter_info *get_counter_info(const struct mpv *m) {
|
||||
return (const struct mpv_counter_info *)((const char *)(m + 1)
|
||||
+ m->kilo_count * sizeof(struct mpv_kilopuff));
|
||||
}
|
||||
|
||||
#define MPV_DEAD_VALUE (~0ULL)
|
||||
#define INVALID_REPORT (~0U)
|
||||
|
||||
#endif
|
||||
389
src/nfa/mpvcompile.cpp
Normal file
389
src/nfa/mpvcompile.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "mpvcompile.h"
|
||||
|
||||
#include "mpv_internal.h"
|
||||
#include "nfa_api_queue.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "shufticompile.h"
|
||||
#include "trufflecompile.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/multibit_internal.h"
|
||||
#include "util/order_check.h"
|
||||
#include "util/verify_types.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
using namespace std;
|
||||
using boost::adaptors::map_values;
|
||||
using boost::adaptors::map_keys;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
namespace {
|
||||
struct pcomp {
|
||||
bool operator()(const raw_puff &a, const raw_puff &b) const {
|
||||
ORDER_CHECK(repeats);
|
||||
ORDER_CHECK(unbounded);
|
||||
ORDER_CHECK(report);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClusterKey {
|
||||
explicit ClusterKey(const raw_puff &src)
|
||||
: trigger_event(MQE_INVALID), reach(src.reach),
|
||||
auto_restart(src.auto_restart) {}
|
||||
ClusterKey(u32 event, const raw_puff &src)
|
||||
: trigger_event(event), reach(src.reach),
|
||||
auto_restart(src.auto_restart) {}
|
||||
|
||||
u32 trigger_event;
|
||||
CharReach reach;
|
||||
bool auto_restart;
|
||||
|
||||
bool operator<(const ClusterKey &b) const {
|
||||
const ClusterKey &a = *this;
|
||||
ORDER_CHECK(trigger_event); /* want triggered puffs first */
|
||||
ORDER_CHECK(auto_restart);
|
||||
ORDER_CHECK(reach);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static
|
||||
void writePuffette(mpv_puffette *out, const raw_puff &rp) {
|
||||
DEBUG_PRINTF("outputting %u %d %u to %p\n", rp.repeats, (int)rp.unbounded,
|
||||
rp.report, out);
|
||||
out->repeats = rp.repeats;
|
||||
out->unbounded = rp.unbounded;
|
||||
out->report = rp.report;
|
||||
}
|
||||
|
||||
static
|
||||
void writeDeadPoint(mpv_kilopuff *out, const vector<raw_puff> &puffs) {
|
||||
for (const auto &puff : puffs) {
|
||||
if (puff.unbounded) { /* mpv can never die */
|
||||
out->dead_point = MPV_DEAD_VALUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out->dead_point = puffs.back().repeats + 1;
|
||||
}
|
||||
|
||||
static
|
||||
size_t calcSize(const map<ClusterKey, vector<raw_puff>> &raw,
|
||||
const vector<mpv_counter_info> &counters) {
|
||||
size_t len = sizeof(NFA) + sizeof(mpv);
|
||||
|
||||
len += sizeof(mpv_kilopuff) * raw.size(); /* need a kilopuff for each
|
||||
distinct reach */
|
||||
|
||||
len += sizeof(mpv_counter_info) * counters.size();
|
||||
|
||||
len += sizeof(mpv_puffette); /* initial sent */
|
||||
|
||||
for (const vector<raw_puff> &puffs : raw | map_values) {
|
||||
len += sizeof(mpv_puffette) * puffs.size();
|
||||
len += sizeof(mpv_puffette); /* terminal sent */
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static
|
||||
void populateClusters(const vector<raw_puff> &puffs_in,
|
||||
const vector<raw_puff> &triggered_puffs,
|
||||
map<ClusterKey, vector<raw_puff>> *raw) {
|
||||
map<ClusterKey, vector<raw_puff>> &puff_clusters = *raw;
|
||||
|
||||
u32 e = MQE_TOP_FIRST;
|
||||
for (const auto &puff : triggered_puffs) {
|
||||
puff_clusters[ClusterKey(e, puff)].push_back(puff);
|
||||
e++;
|
||||
}
|
||||
|
||||
for (const auto &puff : puffs_in) {
|
||||
puff_clusters[ClusterKey(puff)].push_back(puff);
|
||||
}
|
||||
|
||||
|
||||
for (vector<raw_puff> &puffs : puff_clusters | map_values) {
|
||||
sort(puffs.begin(), puffs.end(), pcomp());
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void writeKiloPuff(const map<ClusterKey, vector<raw_puff>>::const_iterator &it,
|
||||
u32 counter_offset, mpv *m, mpv_kilopuff *kp,
|
||||
mpv_puffette **pa) {
|
||||
const CharReach &reach = it->first.reach;
|
||||
const vector<raw_puff> &puffs = it->second;
|
||||
|
||||
kp->auto_restart = it->first.auto_restart;
|
||||
|
||||
if (reach.all()) {
|
||||
kp->type = MPV_DOT;
|
||||
} else if (reach.count() == 255) {
|
||||
kp->type = MPV_VERM;
|
||||
size_t unset = (~reach).find_first();
|
||||
assert(unset != CharReach::npos);
|
||||
kp->u.verm.c = (char)unset;
|
||||
} else if (reach.count() == 1) {
|
||||
kp->type = MPV_NVERM;
|
||||
size_t set = reach.find_first();
|
||||
assert(set != CharReach::npos);
|
||||
kp->u.verm.c = (char)set;
|
||||
} else if (shuftiBuildMasks(~reach, &kp->u.shuf.mask_lo,
|
||||
&kp->u.shuf.mask_hi) != -1) {
|
||||
kp->type = MPV_SHUFTI;
|
||||
} else {
|
||||
kp->type = MPV_TRUFFLE;
|
||||
truffleBuildMasks(~reach, &kp->u.truffle.mask1, &kp->u.truffle.mask2);
|
||||
}
|
||||
|
||||
kp->count = verify_u32(puffs.size());
|
||||
kp->counter_offset = counter_offset;
|
||||
|
||||
/* start of real puffette array */
|
||||
kp->puffette_offset = verify_u32((char *)*pa - (char *)m);
|
||||
for (size_t i = 0; i < puffs.size(); i++) {
|
||||
assert(!it->first.auto_restart || puffs[i].unbounded);
|
||||
writePuffette(*pa + i, puffs[i]);
|
||||
}
|
||||
|
||||
*pa += puffs.size();
|
||||
writePuffette(*pa, raw_puff(0U, false, INVALID_REPORT, CharReach()));
|
||||
++*pa;
|
||||
|
||||
writeDeadPoint(kp, puffs);
|
||||
}
|
||||
|
||||
static
|
||||
void writeCoreNfa(NFA *nfa, u32 len, u32 min_width, u32 max_counter,
|
||||
u32 streamStateSize, u32 scratchStateSize) {
|
||||
assert(nfa);
|
||||
|
||||
nfa->length = len;
|
||||
nfa->nPositions = max_counter - 1;
|
||||
nfa->type = MPV_NFA_0;
|
||||
nfa->streamStateSize = streamStateSize;
|
||||
assert(16 >= sizeof(mpv_decomp_kilo));
|
||||
nfa->scratchStateSize = scratchStateSize;
|
||||
nfa->minWidth = min_width;
|
||||
}
|
||||
|
||||
static
|
||||
void findCounterSize(map<ClusterKey, vector<raw_puff>>::const_iterator kp_it,
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator kp_ite,
|
||||
u64a *max_counter_out, u32 *counter_size) {
|
||||
u32 max_counter = 0; /* max counter that we may need to know about is one
|
||||
more than largest repeat */
|
||||
for (; kp_it != kp_ite; ++kp_it) {
|
||||
max_counter = MAX(max_counter, kp_it->second.back().repeats + 1);
|
||||
}
|
||||
|
||||
if (max_counter < (1U << 8)) {
|
||||
*counter_size = 1;
|
||||
} else if (max_counter < (1U << 16)) {
|
||||
*counter_size = 2;
|
||||
} else if (max_counter < (1U << 24)) {
|
||||
*counter_size = 3;
|
||||
} else {
|
||||
*counter_size = 4;
|
||||
}
|
||||
|
||||
*max_counter_out = max_counter;
|
||||
}
|
||||
|
||||
static
|
||||
void fillCounterInfo(mpv_counter_info *out, u32 *curr_decomp_offset,
|
||||
u32 *curr_comp_offset,
|
||||
const map<ClusterKey, vector<raw_puff>> &kilopuffs,
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator kp_it,
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator kp_ite) {
|
||||
|
||||
out->kilo_begin = distance(kilopuffs.begin(), kp_it);
|
||||
out->kilo_end = distance(kilopuffs.begin(), kp_ite);
|
||||
findCounterSize(kp_it, kp_ite, &out->max_counter, &out->counter_size);
|
||||
out->counter_offset = *curr_decomp_offset;
|
||||
*curr_decomp_offset += sizeof(u64a);
|
||||
*curr_comp_offset += out->counter_size;
|
||||
}
|
||||
|
||||
static
|
||||
void fillCounterInfos(vector<mpv_counter_info> *out, u32 *curr_decomp_offset,
|
||||
u32 *curr_comp_offset,
|
||||
const map<ClusterKey, vector<raw_puff>> &kilopuffs) {
|
||||
/* first the triggered puffs */
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator it = kilopuffs.begin();
|
||||
while (it != kilopuffs.end() && it->first.trigger_event != ~0U) {
|
||||
assert(!it->first.auto_restart);
|
||||
assert(it->first.trigger_event
|
||||
== MQE_TOP_FIRST + distance(kilopuffs.begin(), it));
|
||||
|
||||
out->push_back(mpv_counter_info());
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator it_o = it;
|
||||
++it;
|
||||
fillCounterInfo(&out->back(), curr_decomp_offset, curr_comp_offset,
|
||||
kilopuffs, it_o, it);
|
||||
}
|
||||
|
||||
/* we may have 2 sets of non triggered puffs:
|
||||
* 1) always started with no auto_restart
|
||||
* 2) always started with auto_restart
|
||||
*/
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator trig_ite = it;
|
||||
while (it != kilopuffs.end() && !it->first.auto_restart) {
|
||||
assert(it->first.trigger_event == ~0U);
|
||||
|
||||
++it;
|
||||
}
|
||||
if (it != trig_ite) {
|
||||
out->push_back(mpv_counter_info());
|
||||
fillCounterInfo(&out->back(), curr_decomp_offset, curr_comp_offset,
|
||||
kilopuffs, kilopuffs.begin(), it);
|
||||
}
|
||||
while (it != kilopuffs.end() && it->first.auto_restart) {
|
||||
assert(it->first.trigger_event == ~0U);
|
||||
|
||||
out->push_back(mpv_counter_info());
|
||||
map<ClusterKey, vector<raw_puff>>::const_iterator it_o = it;
|
||||
++it;
|
||||
fillCounterInfo(&out->back(), curr_decomp_offset, curr_comp_offset,
|
||||
kilopuffs, it_o, it);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
const mpv_counter_info &findCounter(const vector<mpv_counter_info> &counters,
|
||||
u32 i) {
|
||||
for (const auto &counter : counters) {
|
||||
if (i >= counter.kilo_begin && i < counter.kilo_end) {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return counters.front();
|
||||
}
|
||||
|
||||
aligned_unique_ptr<NFA> mpvCompile(const vector<raw_puff> &puffs_in,
|
||||
const vector<raw_puff> &triggered_puffs) {
|
||||
assert(!puffs_in.empty() || !triggered_puffs.empty());
|
||||
u32 puffette_count = puffs_in.size() + triggered_puffs.size();
|
||||
|
||||
map<ClusterKey, vector<raw_puff>> puff_clusters;
|
||||
populateClusters(puffs_in, triggered_puffs, &puff_clusters);
|
||||
|
||||
u32 curr_comp_offset = 0;
|
||||
|
||||
u32 curr_decomp_offset = sizeof(mpv_decomp_state);
|
||||
curr_decomp_offset += 16 * puff_clusters.size();
|
||||
|
||||
vector<mpv_counter_info> counters;
|
||||
fillCounterInfos(&counters, &curr_decomp_offset, &curr_comp_offset,
|
||||
puff_clusters);
|
||||
|
||||
u32 pq_offset = curr_decomp_offset;
|
||||
curr_decomp_offset += sizeof(mpv_pq_item) * puff_clusters.size();
|
||||
|
||||
u32 rl_offset = curr_decomp_offset;
|
||||
curr_decomp_offset += sizeof(ReportID) * puffette_count;
|
||||
|
||||
u32 reporter_offset = curr_decomp_offset;
|
||||
curr_decomp_offset += mmbit_size(puff_clusters.size());
|
||||
|
||||
u32 active_offset = curr_comp_offset;
|
||||
curr_comp_offset += mmbit_size(puff_clusters.size());
|
||||
|
||||
u32 len = calcSize(puff_clusters, counters);
|
||||
|
||||
DEBUG_PRINTF("%u puffs, len = %u\n", puffette_count, len);
|
||||
|
||||
aligned_unique_ptr<NFA> nfa = aligned_zmalloc_unique<NFA>(len);
|
||||
|
||||
mpv_puffette *pa_base = (mpv_puffette *)
|
||||
((char *)nfa.get() + sizeof(NFA) + sizeof(mpv)
|
||||
+ sizeof(mpv_kilopuff) * puff_clusters.size()
|
||||
+ sizeof(mpv_counter_info) * counters.size());
|
||||
mpv_puffette *pa = pa_base;
|
||||
|
||||
writePuffette(pa, raw_puff(0U, false, INVALID_REPORT, CharReach()));
|
||||
|
||||
++pa; /* skip init sentinel */
|
||||
|
||||
u32 min_repeat = ~0U;
|
||||
u32 max_counter = 0; /* max counter that we may need to know about is one
|
||||
more than largest repeat */
|
||||
for (const vector<raw_puff> &puffs : puff_clusters | map_values) {
|
||||
max_counter = max(max_counter, puffs.back().repeats + 1);
|
||||
min_repeat = min(min_repeat, puffs.front().repeats);
|
||||
}
|
||||
|
||||
mpv *m = (mpv *)getMutableImplNfa(nfa.get());
|
||||
m->kilo_count = verify_u32(puff_clusters.size());
|
||||
m->counter_count = verify_u32(counters.size());
|
||||
m->puffette_count = puffette_count;
|
||||
m->pq_offset = pq_offset;
|
||||
m->reporter_offset = reporter_offset;
|
||||
m->report_list_offset = rl_offset;
|
||||
m->active_offset = active_offset;
|
||||
m->top_kilo_begin = verify_u32(triggered_puffs.size());
|
||||
m->top_kilo_end = verify_u32(puff_clusters.size());
|
||||
|
||||
mpv_kilopuff *kp_begin = (mpv_kilopuff *)(m + 1);
|
||||
mpv_kilopuff *kp = kp_begin;
|
||||
for (auto it = puff_clusters.begin(); it != puff_clusters.end(); ++it) {
|
||||
writeKiloPuff(it, findCounter(counters, kp - kp_begin).counter_offset,
|
||||
m, kp, &pa);
|
||||
++kp;
|
||||
}
|
||||
assert((char *)pa == (char *)nfa.get() + len);
|
||||
|
||||
mpv_counter_info *out_ci = (mpv_counter_info *)kp;
|
||||
for (const auto &counter : counters) {
|
||||
*out_ci = counter;
|
||||
++out_ci;
|
||||
}
|
||||
assert((char *)out_ci == (char *)pa_base);
|
||||
|
||||
writeCoreNfa(nfa.get(), len, min_repeat, max_counter, curr_comp_offset,
|
||||
curr_decomp_offset);
|
||||
|
||||
return nfa;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
65
src/nfa/mpvcompile.h
Normal file
65
src/nfa/mpvcompile.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef MPV_COMPILE_H
|
||||
#define MPV_COMPILE_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/charreach.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
struct raw_puff {
|
||||
raw_puff(u32 repeats_in, bool unbounded_in, ReportID report_in,
|
||||
const CharReach &reach_in, bool auto_restart_in = false)
|
||||
: repeats(repeats_in), unbounded(unbounded_in),
|
||||
auto_restart(auto_restart_in), report(report_in), reach(reach_in) {}
|
||||
u32 repeats; /**< report match after this many matching bytes */
|
||||
bool unbounded; /**< keep producing matches after repeats are reached */
|
||||
bool auto_restart; /**< for /[^X]{n}/ type patterns */
|
||||
ReportID report;
|
||||
CharReach reach; /**< = ~escapes */
|
||||
};
|
||||
|
||||
/*
|
||||
* puffs in the triggered_puffs vector are enabled when an TOP_N event is
|
||||
* delivered corresponding to their index in the vector
|
||||
*/
|
||||
aligned_unique_ptr<NFA>
|
||||
mpvCompile(const std::vector<raw_puff> &puffs,
|
||||
const std::vector<raw_puff> &triggered_puffs);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
257
src/nfa/nfa_api.h
Normal file
257
src/nfa/nfa_api.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Declarations for the main NFA Engine API.
|
||||
*
|
||||
* This file provides the internal API for all runtime engines ("NFAs", even if
|
||||
* they're not strictly NFA implementations).
|
||||
*/
|
||||
|
||||
#ifndef NFA_API_H
|
||||
#define NFA_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "callback.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
struct hs_scratch;
|
||||
struct mq;
|
||||
struct NFA;
|
||||
|
||||
/**
|
||||
* Indicates if an nfa is a zombie. Note: that there were plans for a more
|
||||
* nuanced view of zombiehood but this never eventuated.
|
||||
*/
|
||||
enum nfa_zombie_status {
|
||||
NFA_ZOMBIE_NO, /**< nfa is not a zombie and will respond to top events */
|
||||
NFA_ZOMBIE_ALWAYS_YES /**< nfa is a zombie and will always be a zombie */
|
||||
};
|
||||
|
||||
/**
|
||||
* Compresses an engine's state.
|
||||
* The expanded state (@ref mq::state, @ref mq::streamState) is reduced purely
|
||||
* to a corresponding compressed stream state (@ref mq::streamState).
|
||||
*
|
||||
* @param nfa engine the state belongs to
|
||||
* @param q queue for the engine. The final compressed stream stream is placed
|
||||
* in the location indicated by @ref mq::streamState
|
||||
* @param loc the location corresponding to the engine's current state
|
||||
*/
|
||||
char nfaQueueCompressState(const struct NFA *nfa, const struct mq *q, s64a loc);
|
||||
|
||||
/**
|
||||
* Expands an engine's compressed stream state, into its scratch space
|
||||
* representation. This is required before an engine starts operating over its
|
||||
* queue.
|
||||
*
|
||||
* @param nfa engine the state belongs to
|
||||
* @param dest location in scratch for decompressed state
|
||||
* @param src compressed stream state
|
||||
* @param offset the current stream offset.
|
||||
* @param key byte corresponding to the location where the compressed state was
|
||||
* created.
|
||||
*/
|
||||
char nfaExpandState(const struct NFA *nfa, void *dest, const void *src,
|
||||
u64a offset, u8 key);
|
||||
|
||||
/**
|
||||
* Gives us a properly initialised dead state suitable for later @ref
|
||||
* nfaQueueExec calls.
|
||||
*/
|
||||
char nfaQueueInitState(const struct NFA *nfa, struct mq *q);
|
||||
|
||||
/**
|
||||
* Initialise the state, applying a TOP appropriate for the offset. If the
|
||||
* NFA becomes inactive, return zero. Otherwise, write out its compressed
|
||||
* representation to `state' and return non-zero.
|
||||
*
|
||||
* @param nfa engine the state belongs to
|
||||
* @param offset offset in the stream (relative to start of stream)
|
||||
* @param state pointer indicating where the state is to be written
|
||||
* @param key byte corresponding to the location where the compressed state is
|
||||
* to be created.
|
||||
*/
|
||||
char nfaInitCompressedState(const struct NFA *nfa, u64a offset, void *state,
|
||||
u8 key);
|
||||
|
||||
/**
|
||||
* Process the queued commands on the given NFA.
|
||||
*
|
||||
* @param nfa the NFA to execute
|
||||
* @param q the queued commands. It must start with some variant of start and
|
||||
* end with some variant of end. The location field of the events must
|
||||
* be monotonically increasing.
|
||||
* @param end stop processing command queue when we reach this point
|
||||
*
|
||||
* @return non-zero if the nfa is still active, if the nfa is not active the
|
||||
* state data is undefined
|
||||
*
|
||||
* Note: this function can not process events from the past: the location field
|
||||
* of each event must be >= current offset.
|
||||
*/
|
||||
char nfaQueueExec(const struct NFA *nfa, struct mq *q, s64a end);
|
||||
|
||||
/** Return value indicating that the engine is alive. */
|
||||
#define MO_ALIVE 1
|
||||
|
||||
/** Return value from @ref nfaQueueExecToMatch indicating that engine progress
|
||||
* stopped as a match state was reached. */
|
||||
#define MO_MATCHES_PENDING 2
|
||||
|
||||
/**
|
||||
* Process the queued commands on the given nfa up to end or the first match.
|
||||
* This function will only fire the callback in response to an report_current
|
||||
* being set and accepts at the starting offset, in all other situations accepts
|
||||
* will result in the queue pausing with a return value of
|
||||
* @ref MO_MATCHES_PENDING.
|
||||
*
|
||||
* @param nfa the NFA to execute
|
||||
* @param q the queued commands. It must start with some variant of start and
|
||||
* end with some variant of end. The location field of the events must
|
||||
* be monotonically increasing. If not all the data was processed during
|
||||
* the call, the queue is updated to reflect the remaining work.
|
||||
* @param end stop processing command queue when we reach this point
|
||||
*
|
||||
* @return @ref MO_ALIVE if the nfa is still active with no matches pending,
|
||||
* and @ref MO_MATCHES_PENDING if there are matches pending, 0 if not
|
||||
* alive
|
||||
*
|
||||
* Note: if it can be determined that the stream can never match, the nfa
|
||||
* may be reported as dead even if not all the data was scanned
|
||||
*
|
||||
* Note: if the nfa is not alive the state data is undefined
|
||||
*
|
||||
* Note: this function can not process events from the past: the location field
|
||||
* of each event must be >= current offset.
|
||||
*/
|
||||
char nfaQueueExecToMatch(const struct NFA *nfa, struct mq *q, s64a end);
|
||||
|
||||
/**
|
||||
* Report matches at the current queue location.
|
||||
*
|
||||
* @param nfa the NFA to execute
|
||||
* @param q the queued commands. It must start with some variant of start and
|
||||
* end with some variant of end. The location field of the events must
|
||||
* be monotonically increasing.
|
||||
*
|
||||
* Note: the queue MUST be located at position where @ref nfaQueueExecToMatch
|
||||
* returned @ref MO_MATCHES_PENDING.
|
||||
*
|
||||
* Note: the return value of this call is undefined, and should be ignored.
|
||||
*/
|
||||
char nfaReportCurrentMatches(const struct NFA *nfa, struct mq *q);
|
||||
|
||||
/**
|
||||
* Returns non-zero if the NFA is in an accept state with the given report ID.
|
||||
*/
|
||||
char nfaInAcceptState(const struct NFA *nfa, ReportID report, struct mq *q);
|
||||
|
||||
/**
|
||||
* Process the queued commands on the given NFA up to end or the first match.
|
||||
*
|
||||
* Note: This version is meant for rose prefix NFAs:
|
||||
* - never uses a callback
|
||||
* - loading of state at a point in history is not special cased
|
||||
*
|
||||
* @param nfa the NFA to execute
|
||||
* @param q the queued commands. It must start with some variant of start and
|
||||
* end with some variant of end. The location field of the events must
|
||||
* be monotonically increasing. If not all the data was processed during
|
||||
* the call, the queue is updated to reflect the remaining work.
|
||||
* @param report we are interested in, if set at the end of the scan returns
|
||||
* @ref MO_MATCHES_PENDING
|
||||
* @return @ref MO_ALIVE if the nfa is still active with no matches pending,
|
||||
* and @ref MO_MATCHES_PENDING if there are matches pending, 0 if not
|
||||
* alive
|
||||
*
|
||||
* Note: if it can be determined that the stream can never match, the nfa
|
||||
* may be reported as dead even if not all the data was scanned
|
||||
*
|
||||
* Note: if the NFA is not active the state data is undefined.
|
||||
*/
|
||||
char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID report);
|
||||
|
||||
/**
|
||||
* Runs an NFA in reverse from (buf + buflen) to buf and then from (hbuf + hlen)
|
||||
* to hbuf (main buffer and history buffer).
|
||||
*
|
||||
* @param nfa engine to run
|
||||
* @param offset base offset of buf
|
||||
* @param buf main buffer
|
||||
* @param buflen length of buf
|
||||
* @param hbuf history buf
|
||||
* @param hlen length of hbuf
|
||||
* @param scratch scratch
|
||||
* @param callback the callback to call for each match raised
|
||||
* @param context context pointer passed to each callback
|
||||
*
|
||||
* Note: is NOT reentrant
|
||||
*/
|
||||
char nfaBlockExecReverse(const struct NFA *nfa, u64a offset, const u8 *buf,
|
||||
size_t buflen, const u8 *hbuf, size_t hlen,
|
||||
struct hs_scratch *scratch, NfaCallback callback,
|
||||
void *context);
|
||||
|
||||
/**
|
||||
* Check whether the given NFA's state indicates that it is in one or more
|
||||
* final (accept at end of data) state. If so, call the callback for each
|
||||
* match.
|
||||
*
|
||||
* @param nfa the NFA to execute
|
||||
* @param state current state associated with this NFA
|
||||
* @param streamState stream version of the state associated with this NFA
|
||||
* (including br region)
|
||||
* @param offset the offset to return (via the callback) with each match
|
||||
* @param callback the callback to call for each match raised
|
||||
* @param som_cb the callback to call for each match raised (Haig)
|
||||
* @param context context pointer passed to each callback
|
||||
*/
|
||||
char nfaCheckFinalState(const struct NFA *nfa, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback, SomNfaCallback som_cb,
|
||||
void *context);
|
||||
|
||||
/**
|
||||
* Indicates if an engine is a zombie.
|
||||
*
|
||||
* @param nfa engine to consider
|
||||
* @param q queue corresponding to the engine
|
||||
* @param loc current location in the buffer for an engine
|
||||
*/
|
||||
enum nfa_zombie_status nfaGetZombieStatus(const struct NFA *nfa, struct mq *q,
|
||||
s64a loc);
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
376
src/nfa/nfa_api_dispatch.c
Normal file
376
src/nfa/nfa_api_dispatch.c
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Dispatches NFA engine API calls to the appropriate engines
|
||||
*/
|
||||
#include "nfa_api.h"
|
||||
|
||||
#include "nfa_api_queue.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
// Engine implementations.
|
||||
#include "castle.h"
|
||||
#include "gough.h"
|
||||
#include "lbr.h"
|
||||
#include "limex.h"
|
||||
#include "mcclellan.h"
|
||||
#include "mpv.h"
|
||||
|
||||
#define DISPATCH_CASE(dc_ltype, dc_ftype, dc_subtype, dc_func_call) \
|
||||
case dc_ltype##_NFA_##dc_subtype: \
|
||||
return nfaExec##dc_ftype##dc_subtype##dc_func_call; \
|
||||
break
|
||||
|
||||
// general framework calls
|
||||
|
||||
#define DISPATCH_BY_NFA_TYPE(dbnt_func) \
|
||||
switch (nfa->type) { \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_7, dbnt_func); \
|
||||
DISPATCH_CASE(MCCLELLAN, McClellan, 8, dbnt_func); \
|
||||
DISPATCH_CASE(MCCLELLAN, McClellan, 16, dbnt_func); \
|
||||
DISPATCH_CASE(GOUGH, Gough, 8, dbnt_func); \
|
||||
DISPATCH_CASE(GOUGH, Gough, 16, dbnt_func); \
|
||||
DISPATCH_CASE(MPV, Mpv, 0, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Dot, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Verm, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, NVerm, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Shuf, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Truf, dbnt_func); \
|
||||
DISPATCH_CASE(CASTLE, Castle, 0, dbnt_func); \
|
||||
default: \
|
||||
assert(0); \
|
||||
}
|
||||
|
||||
char nfaCheckFinalState(const struct NFA *nfa, const char *state,
|
||||
const char *streamState, u64a offset,
|
||||
NfaCallback callback, SomNfaCallback som_cb,
|
||||
void *context) {
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
|
||||
// Caller should avoid calling us if we can never produce matches.
|
||||
assert(nfaAcceptsEod(nfa));
|
||||
|
||||
DISPATCH_BY_NFA_TYPE(_testEOD(nfa, state, streamState, offset, callback,
|
||||
som_cb, context));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char nfaQueueInitState(const struct NFA *nfa, struct mq *q) {
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
|
||||
DISPATCH_BY_NFA_TYPE(_queueInitState(nfa, q));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char nfaQueueExec_i(const struct NFA *nfa, struct mq *q, s64a end) {
|
||||
DISPATCH_BY_NFA_TYPE(_Q(nfa, q, end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char nfaQueueExec2_i(const struct NFA *nfa, struct mq *q, s64a end) {
|
||||
DISPATCH_BY_NFA_TYPE(_Q2(nfa, q, end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
char nfaQueueExecRose_i(const struct NFA *nfa, struct mq *q, ReportID report) {
|
||||
DISPATCH_BY_NFA_TYPE(_QR(nfa, q, report));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns 0 if this NFA cannot possibly match (due to width constraints etc)
|
||||
* and the caller should return 0. May also edit the queue. */
|
||||
static really_inline
|
||||
char nfaQueueCanMatch(const struct NFA *nfa, struct mq *q, s64a end,
|
||||
char *q_trimmed) {
|
||||
assert(q_trimmed);
|
||||
assert(q->end - q->cur >= 2);
|
||||
assert(end >= 0);
|
||||
|
||||
DEBUG_PRINTF("q->offset=%llu, end=%lld\n", q->offset, end);
|
||||
DEBUG_PRINTF("maxBiAnchoredWidth=%u, maxOffset=%u\n",
|
||||
nfa->maxBiAnchoredWidth, nfa->maxOffset);
|
||||
|
||||
if (nfa->maxBiAnchoredWidth &&
|
||||
(end + q->offset > nfa->maxBiAnchoredWidth)) {
|
||||
DEBUG_PRINTF("stream too long: o %llu l %zu max: %hhu\n", q->offset,
|
||||
q->length, nfa->maxBiAnchoredWidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nfa->maxOffset) {
|
||||
if (q->offset >= nfa->maxOffset) {
|
||||
DEBUG_PRINTF("stream is past maxOffset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (q->offset + end > nfa->maxOffset) {
|
||||
s64a maxEnd = nfa->maxOffset - q->offset;
|
||||
DEBUG_PRINTF("me %lld off %llu len = %lld\n", maxEnd,
|
||||
q->offset, end);
|
||||
while (q->end > q->cur
|
||||
&& q->items[q->end - 1].location > maxEnd) {
|
||||
*q_trimmed = 1;
|
||||
DEBUG_PRINTF("killing item %u %lld %u\n", q->end,
|
||||
q->items[q->end - 1].location,
|
||||
q->items[q->end - 1].type);
|
||||
q->items[q->end - 1].location = maxEnd;
|
||||
q->items[q->end - 1].type = MQE_END;
|
||||
if (q->end - q->cur < 2
|
||||
||q->items[q->end - 2].location <= maxEnd) {
|
||||
break;
|
||||
}
|
||||
q->end--;
|
||||
}
|
||||
|
||||
if (q->end - q->cur < 2) { /* nothing left on q */
|
||||
DEBUG_PRINTF("queue empty\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (*q_trimmed) {
|
||||
debugQueue(q);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char nfaQueueExec(const struct NFA *nfa, struct mq *q, s64a end) {
|
||||
DEBUG_PRINTF("nfa=%p end=%lld\n", nfa, end);
|
||||
#ifdef DEBUG
|
||||
debugQueue(q);
|
||||
#endif
|
||||
|
||||
assert(q && q->context && q->state);
|
||||
assert(end >= 0);
|
||||
assert(q->cur < q->end);
|
||||
assert(q->end <= MAX_MQE_LEN);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
assert(end < q->items[q->end - 1].location
|
||||
|| q->items[q->end - 1].type == MQE_END);
|
||||
|
||||
if (q->items[q->cur].location > end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char q_trimmed = 0;
|
||||
|
||||
assert(end <= (s64a)q->length || !q->hlength);
|
||||
/* due to reverse accel in block mode some queues may work on a truncated
|
||||
* buffer */
|
||||
if (end > (s64a)q->length) {
|
||||
end = q->length;
|
||||
q_trimmed = 1;
|
||||
}
|
||||
|
||||
if (!nfaQueueCanMatch(nfa, q, end, &q_trimmed)) {
|
||||
if (q->report_current) {
|
||||
nfaReportCurrentMatches(nfa, q);
|
||||
q->report_current = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char rv = nfaQueueExec_i(nfa, q, end);
|
||||
|
||||
#ifdef DEBUG
|
||||
debugQueue(q);
|
||||
#endif
|
||||
|
||||
assert(!q->report_current);
|
||||
DEBUG_PRINTF("returned rv=%d, q_trimmed=%d\n", rv, q_trimmed);
|
||||
return rv && !q_trimmed;
|
||||
}
|
||||
|
||||
char nfaQueueExecToMatch(const struct NFA *nfa, struct mq *q, s64a end) {
|
||||
DEBUG_PRINTF("nfa=%p end=%lld\n", nfa, end);
|
||||
#ifdef DEBUG
|
||||
debugQueue(q);
|
||||
#endif
|
||||
|
||||
assert(q);
|
||||
assert(end >= 0);
|
||||
assert(q->context);
|
||||
assert(q->state);
|
||||
assert(q->cur < q->end);
|
||||
assert(q->end <= MAX_MQE_LEN);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
assert(end < q->items[q->end - 1].location
|
||||
|| q->items[q->end - 1].type == MQE_END);
|
||||
|
||||
char q_trimmed_ra = 0;
|
||||
assert(end <= (s64a)q->length || !q->hlength);
|
||||
/* due to reverse accel in block mode some queues may work on a truncated
|
||||
* buffer */
|
||||
if (q->items[q->cur].location > end) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (end > (s64a)q->length) {
|
||||
end = q->length;
|
||||
q_trimmed_ra = 1;
|
||||
}
|
||||
|
||||
char q_trimmed = 0;
|
||||
if (!nfaQueueCanMatch(nfa, q, end, &q_trimmed)) {
|
||||
if (q->report_current) {
|
||||
nfaReportCurrentMatches(nfa, q);
|
||||
q->report_current = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char rv = nfaQueueExec2_i(nfa, q, end);
|
||||
assert(!q->report_current);
|
||||
DEBUG_PRINTF("returned rv=%d, q_trimmed=%d\n", rv, q_trimmed);
|
||||
if (rv == MO_MATCHES_PENDING) {
|
||||
if (q_trimmed) {
|
||||
// We need to "fix" the queue so that subsequent operations must
|
||||
// trim it as well.
|
||||
assert(q->end > 0);
|
||||
assert(nfa->maxOffset);
|
||||
q->items[q->end - 1].location = nfa->maxOffset + 1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
return rv && !q_trimmed && !q_trimmed_ra;
|
||||
}
|
||||
|
||||
char nfaReportCurrentMatches(const struct NFA *nfa, struct mq *q) {
|
||||
DISPATCH_BY_NFA_TYPE(_reportCurrent(nfa, q));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char nfaInAcceptState(const struct NFA *nfa, ReportID report, struct mq *q) {
|
||||
DISPATCH_BY_NFA_TYPE(_inAccept(nfa, report, q));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char nfaQueueExecRose(const struct NFA *nfa, struct mq *q, ReportID r) {
|
||||
DEBUG_PRINTF("nfa=%p\n", nfa);
|
||||
#ifdef DEBUG
|
||||
debugQueue(q);
|
||||
#endif
|
||||
|
||||
assert(q && !q->context && q->state);
|
||||
assert(q->cur <= q->end);
|
||||
assert(q->end <= MAX_MQE_LEN);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
assert(!q->report_current);
|
||||
|
||||
return nfaQueueExecRose_i(nfa, q, r);
|
||||
}
|
||||
|
||||
char nfaBlockExecReverse(const struct NFA *nfa, u64a offset, const u8 *buf,
|
||||
size_t buflen, const u8 *hbuf, size_t hlen,
|
||||
struct hs_scratch *scratch, NfaCallback callback,
|
||||
void *context) {
|
||||
assert(nfa);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
|
||||
DISPATCH_BY_NFA_TYPE(_B_Reverse(nfa, offset, buf, buflen, hbuf, hlen,
|
||||
scratch, callback, context));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char nfaQueueCompressState(const struct NFA *nfa, const struct mq *q,
|
||||
s64a loc) {
|
||||
assert(nfa && q);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
|
||||
DISPATCH_BY_NFA_TYPE(_queueCompressState(nfa, q, loc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char nfaExpandState(const struct NFA *nfa, void *dest, const void *src,
|
||||
u64a offset, u8 key) {
|
||||
assert(nfa && dest && src);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
|
||||
DISPATCH_BY_NFA_TYPE(_expandState(nfa, dest, src, offset, key));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char nfaInitCompressedState(const struct NFA *nfa, u64a offset, void *state,
|
||||
u8 key) {
|
||||
assert(nfa && state);
|
||||
assert(ISALIGNED_CL(nfa) && ISALIGNED_CL(getImplNfa(nfa)));
|
||||
|
||||
DISPATCH_BY_NFA_TYPE(_initCompressedState(nfa, offset, state, key));
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum nfa_zombie_status nfaGetZombieStatus(const struct NFA *nfa, struct mq *q,
|
||||
s64a loc) {
|
||||
DISPATCH_BY_NFA_TYPE(_zombie_status(nfa, q, loc));
|
||||
return NFA_ZOMBIE_NO;
|
||||
}
|
||||
278
src/nfa/nfa_api_queue.h
Normal file
278
src/nfa/nfa_api_queue.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef NFA_API_QUEUE_H
|
||||
#define NFA_API_QUEUE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "callback.h"
|
||||
|
||||
/** Size of mq::items, max elements on a queue. */
|
||||
#define MAX_MQE_LEN 10
|
||||
|
||||
/** Queue events */
|
||||
enum mqe_event {
|
||||
MQE_START = 0, /**< and begin! Note: stateless engines will start from
|
||||
* this location */
|
||||
MQE_END = 1, /**< stop scanning */
|
||||
MQE_TOP = 2, /**< enable start + start dot star */
|
||||
MQE_TOP_FIRST = 4, /**< first event corresponding to a TOP _N_ */
|
||||
|
||||
/*
|
||||
* Additional tops (in multi-top engines) use the event values from
|
||||
* MQE_TOP_FIRST to something.
|
||||
*/
|
||||
|
||||
MQE_INVALID = ~0U
|
||||
};
|
||||
|
||||
/** Queue item */
|
||||
struct mq_item {
|
||||
u32 type; /**< event; from mqe_event */
|
||||
s64a location; /**< relative to the start of the current buffer */
|
||||
u64a som; /**< pattern start-of-match corresponding to a top, only used
|
||||
* by som engines. */
|
||||
};
|
||||
|
||||
// Forward decl.
|
||||
struct NFA;
|
||||
|
||||
/**
|
||||
* Queue of events to control engine execution. mq::cur is index of first
|
||||
* valid event, mq::end is one past the index of last valid event.
|
||||
*/
|
||||
struct mq {
|
||||
const struct NFA *nfa; /**< nfa corresponding to the queue */
|
||||
u32 cur; /**< index of the first valid item in the queue */
|
||||
u32 end; /**< index one past the last valid item in the queue */
|
||||
char *state; /**< uncompressed stream state; lives in scratch */
|
||||
char *streamState; /**<
|
||||
* real stream state; used to access structures which
|
||||
* not duplicated the scratch state (bounded repeats,
|
||||
* etc) */
|
||||
u64a offset; /**< base offset of the buffer */
|
||||
const u8 *buffer; /**< buffer to scan */
|
||||
size_t length; /**< length of buffer */
|
||||
const u8 *history; /**<
|
||||
* history buffer; (logically) immediately before the
|
||||
* main buffer */
|
||||
size_t hlength; /**< length of the history buffer */
|
||||
struct hs_scratch *scratch; /**< global scratch space */
|
||||
char report_current; /**<
|
||||
* report_current matches at starting offset through
|
||||
* callback. If true, the queue must be located at a
|
||||
* point where MO_MATCHES_PENDING was returned */
|
||||
NfaCallback cb; /**< callback to trigger on matches */
|
||||
SomNfaCallback som_cb; /**< callback with som info; used by haig */
|
||||
void *context; /**< context to pass along with a callback */
|
||||
struct mq_item items[MAX_MQE_LEN]; /**< queue items */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pushes an (event, location, som) item onto a queue. If it is identical to the
|
||||
* previous item on the queue, it is not added to the queue.
|
||||
* @param q queue
|
||||
* @param e event
|
||||
* @param som som marker
|
||||
* @param loc event location
|
||||
*/
|
||||
static really_inline
|
||||
void pushQueueSom(struct mq * restrict q, u32 e, s64a loc, u64a som) {
|
||||
DEBUG_PRINTF("pushing %u@%lld -> %u [som = %llu]\n", e, loc, q->end, som);
|
||||
assert(q->end < MAX_MQE_LEN);
|
||||
assert(e < MQE_INVALID);
|
||||
/* stop gcc getting too smart for its own good */
|
||||
/* assert(!q->end || q->items[q->end - 1].location <= loc); */
|
||||
assert(q->end || e == MQE_START);
|
||||
|
||||
// Avoid duplicate items on the queue.
|
||||
if (q->end) {
|
||||
struct mq_item *item = &q->items[q->end - 1];
|
||||
if (item->type == e && item->location == loc) {
|
||||
DEBUG_PRINTF("dropping duplicate item\n");
|
||||
LIMIT_TO_AT_MOST(&item->som, som); /* take lower som */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
u32 end = q->end;
|
||||
struct mq_item *item = &q->items[end];
|
||||
item->type = e;
|
||||
item->location = loc;
|
||||
item->som = som;
|
||||
q->end = end + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes an (event, location) item onto a queue. If it is identical to the
|
||||
* previous item on the queue, it is not added to the queue.
|
||||
* @param q queue
|
||||
* @param e event
|
||||
* @param loc event location
|
||||
*/
|
||||
static really_inline
|
||||
void pushQueue(struct mq * restrict q, u32 e, s64a loc) {
|
||||
pushQueueSom(q, e, loc, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes an (event, location) item onto a queue.
|
||||
* This version of @ref pushQueue does not check to ensure that the item being
|
||||
* added is not already on the queue. Used for events other than tops.
|
||||
*/
|
||||
static really_inline
|
||||
void pushQueueNoMerge(struct mq * restrict q, u32 e, s64a loc) {
|
||||
DEBUG_PRINTF("pushing %u@%lld -> %u\n", e, loc, q->end);
|
||||
assert(q->end < MAX_MQE_LEN);
|
||||
assert(e < MQE_INVALID);
|
||||
/* stop gcc getting too smart for its own good */
|
||||
/* assert(!q->end || q->items[q->end - 1].location <= loc); */
|
||||
assert(q->end || e == MQE_START);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// We assert that the event is different from its predecessor. If it's a
|
||||
// dupe, you should have used the ordinary pushQueue call.
|
||||
if (q->end) {
|
||||
UNUSED struct mq_item *prev = &q->items[q->end - 1];
|
||||
assert(prev->type != e || prev->location != loc);
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 end = q->end;
|
||||
struct mq_item *item = &q->items[end];
|
||||
item->type = e;
|
||||
item->location = loc;
|
||||
item->som = 0;
|
||||
q->end = end + 1;
|
||||
}
|
||||
|
||||
/** \brief Returns the type of the current queue event. */
|
||||
static really_inline u32 q_cur_type(const struct mq *q) {
|
||||
assert(q->cur < q->end);
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
return q->items[q->cur].type;
|
||||
}
|
||||
|
||||
/** \brief Returns the location (relative to the beginning of the current data
|
||||
* buffer) of the current queue event. */
|
||||
static really_inline s64a q_cur_loc(const struct mq *q) {
|
||||
assert(q->cur < q->end);
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
return q->items[q->cur].location;
|
||||
}
|
||||
|
||||
/** \brief Returns the location (relative to the beginning of the current data
|
||||
* buffer) of the last event in the queue. */
|
||||
static really_inline s64a q_last_loc(const struct mq *q) {
|
||||
assert(q->cur < q->end);
|
||||
assert(q->end > 0);
|
||||
assert(q->end <= MAX_MQE_LEN);
|
||||
return q->items[q->end - 1].location;
|
||||
}
|
||||
|
||||
/** \brief Returns the absolute stream offset of the current queue event. */
|
||||
static really_inline u64a q_cur_offset(const struct mq *q) {
|
||||
assert(q->cur < q->end);
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
return q->offset + (u64a)q->items[q->cur].location;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Removes all events in the queue before the given location.
|
||||
*/
|
||||
static really_inline
|
||||
void q_skip_forward_to(struct mq *q, s64a min_loc) {
|
||||
assert(q->cur < q->end);
|
||||
assert(q->cur < MAX_MQE_LEN);
|
||||
assert(q->items[q->cur].type == MQE_START);
|
||||
|
||||
if (q_cur_loc(q) >= min_loc) {
|
||||
DEBUG_PRINTF("all events >= loc %lld\n", min_loc);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 start_loc = q->cur;
|
||||
|
||||
do {
|
||||
DEBUG_PRINTF("remove item with loc=%lld\n", q_cur_loc(q));
|
||||
q->cur++;
|
||||
} while (q->cur < q->end && q_cur_loc(q) < min_loc);
|
||||
|
||||
if (q->cur > start_loc) {
|
||||
// Move original MQE_START item forward.
|
||||
q->cur--;
|
||||
q->items[q->cur] = q->items[start_loc];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Dump the contents of the given queue.
|
||||
static never_inline UNUSED
|
||||
void debugQueue(const struct mq *q) {
|
||||
DEBUG_PRINTF("q=%p, nfa=%p\n", q, q->nfa);
|
||||
DEBUG_PRINTF("q offset=%llu, buf={%p, len=%zu}, history={%p, len=%zu}\n",
|
||||
q->offset, q->buffer, q->length, q->history, q->hlength);
|
||||
DEBUG_PRINTF("q cur=%u, end=%u\n", q->cur, q->end);
|
||||
for (u32 cur = q->cur; cur < q->end; cur++) {
|
||||
const char *type = "UNKNOWN";
|
||||
u32 e = q->items[cur].type;
|
||||
switch (e) {
|
||||
case MQE_START:
|
||||
type = "MQE_START";
|
||||
break;
|
||||
case MQE_END:
|
||||
type = "MQE_END";
|
||||
break;
|
||||
case MQE_TOP:
|
||||
type = "MQE_TOP";
|
||||
break;
|
||||
case MQE_INVALID:
|
||||
type = "MQE_INVALID";
|
||||
break;
|
||||
default:
|
||||
assert(e >= MQE_TOP_FIRST && e < MQE_INVALID);
|
||||
type = "MQE_TOP_N";
|
||||
break;
|
||||
}
|
||||
DEBUG_PRINTF("\tq[%u] %lld %d:%s\n", cur, q->items[cur].location,
|
||||
q->items[cur].type, type);
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
src/nfa/nfa_api_util.h
Normal file
82
src/nfa/nfa_api_util.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef NFA_API_UTIL_H
|
||||
#define NFA_API_UTIL_H
|
||||
|
||||
#include "nfa_api_queue.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
/* returns the byte prior to the given location, NUL if not available */
|
||||
static really_inline
|
||||
u8 queue_prev_byte(const struct mq *q, s64a loc) {
|
||||
if (loc <= 0) {
|
||||
if (1LL - loc > (s64a)q->hlength) {
|
||||
return 0; /* assume NUL for start of stream write */
|
||||
}
|
||||
// In the history buffer.
|
||||
assert(q->history);
|
||||
assert(q->hlength >= (u64a)(loc * -1));
|
||||
return q->history[q->hlength - 1 + loc];
|
||||
} else {
|
||||
// In the stream write buffer.
|
||||
assert(q->buffer);
|
||||
assert(q->length >= (u64a)loc);
|
||||
return q->buffer[loc - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* this is a modified version of pushQueue where we statically know the state of
|
||||
* the queue. Does not attempt to merge and inserts at the given queue
|
||||
* position. */
|
||||
static really_inline
|
||||
void pushQueueAt(struct mq * restrict q, u32 pos, u32 e, s64a loc) {
|
||||
assert(pos == q->end);
|
||||
DEBUG_PRINTF("pushing %u@%lld -> %u\n", e, loc, q->end);
|
||||
assert(q->end < MAX_MQE_LEN);
|
||||
assert(e < MQE_INVALID);
|
||||
/* stop gcc getting too smart for its own good */
|
||||
/* assert(!q->end || q->items[q->end - 1].location <= loc); */
|
||||
assert(q->end || e == MQE_START);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// We assert that the event is different from its predecessor. If it's a
|
||||
// dupe, you should have used the ordinary pushQueue call.
|
||||
if (q->end) {
|
||||
UNUSED struct mq_item *prev = &q->items[q->end - 1];
|
||||
assert(prev->type != e || prev->location != loc);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct mq_item *item = &q->items[pos];
|
||||
item->type = e;
|
||||
item->location = loc;
|
||||
item->som = 0;
|
||||
q->end = pos + 1;
|
||||
}
|
||||
#endif
|
||||
434
src/nfa/nfa_build_util.cpp
Normal file
434
src/nfa/nfa_build_util.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "nfa_build_util.h"
|
||||
|
||||
#include "limex_internal.h"
|
||||
#include "mcclellancompile.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "repeat_internal.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
namespace {
|
||||
|
||||
template<NFAEngineType t> struct NFATraits { };
|
||||
|
||||
template<template<NFAEngineType t> class sfunc, typename rv_t, typename arg_t,
|
||||
NFAEngineType lb>
|
||||
struct DISPATCH_BY_NFA_TYPE_INT {
|
||||
static rv_t doOp(NFAEngineType i, const arg_t &arg) {
|
||||
if (i == lb) {
|
||||
return sfunc<lb>::call(arg);
|
||||
} else {
|
||||
return DISPATCH_BY_NFA_TYPE_INT<sfunc, rv_t, arg_t,
|
||||
(NFAEngineType)(lb + 1)>
|
||||
::doOp(i, arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<template<NFAEngineType t> class sfunc, typename rv_t, typename arg_t>
|
||||
struct DISPATCH_BY_NFA_TYPE_INT<sfunc, rv_t, arg_t, INVALID_NFA> {
|
||||
// dummy
|
||||
static rv_t doOp(NFAEngineType, const arg_t &) {
|
||||
assert(0);
|
||||
throw std::logic_error("Unreachable");
|
||||
}
|
||||
};
|
||||
|
||||
#define DISPATCH_BY_NFA_TYPE(i, op, arg) \
|
||||
DISPATCH_BY_NFA_TYPE_INT<op, decltype(op<(NFAEngineType)0>::call(arg)), \
|
||||
decltype(arg), (NFAEngineType)0>::doOp(i, arg)
|
||||
}
|
||||
|
||||
typedef bool (*has_accel_fn)(const NFA *nfa);
|
||||
|
||||
template<typename T>
|
||||
static
|
||||
bool has_accel_limex(const NFA *nfa) {
|
||||
const T *limex = (const T *)getImplNfa(nfa);
|
||||
return limex->accelCount;
|
||||
}
|
||||
|
||||
static
|
||||
bool has_accel_generic(const NFA *) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
namespace {
|
||||
template<NFAEngineType t>
|
||||
struct getName {
|
||||
static const char *call(void *) {
|
||||
return NFATraits<t>::name;
|
||||
}
|
||||
};
|
||||
|
||||
// descr helper for LimEx NFAs
|
||||
template<NFAEngineType t>
|
||||
static
|
||||
string getDescriptionLimEx(const NFA *nfa) {
|
||||
const typename NFATraits<t>::implNFA_t *limex =
|
||||
(const typename NFATraits<t>::implNFA_t *)getImplNfa(nfa);
|
||||
ostringstream oss;
|
||||
oss << NFATraits<t>::name << "/" << limex->exceptionCount;
|
||||
if (limex->repeatCount) {
|
||||
oss << " +" << limex->repeatCount << "r";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
// generic description: just return the name
|
||||
namespace {
|
||||
template<NFAEngineType t>
|
||||
struct getDescription {
|
||||
static string call(const void *) {
|
||||
return string(NFATraits<t>::name);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* build-utility Traits */
|
||||
|
||||
namespace {
|
||||
enum NFACategory {NFA_LIMEX, NFA_OTHER};
|
||||
|
||||
// Some of our traits we want around in DUMP_SUPPORT mode only.
|
||||
#if defined(DUMP_SUPPORT)
|
||||
#define DO_IF_DUMP_SUPPORT(a) a
|
||||
#else
|
||||
#define DO_IF_DUMP_SUPPORT(a)
|
||||
#endif
|
||||
|
||||
#define MAKE_LIMEX_TRAITS(mlt_size, mlt_shift) \
|
||||
template<> struct NFATraits<LIMEX_NFA_##mlt_size##_##mlt_shift> { \
|
||||
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 has_accel_fn has_accel; \
|
||||
static const u32 stateAlign = \
|
||||
MAX(alignof(tableRow_t), alignof(RepeatControl)); \
|
||||
static const bool fast = mlt_size <= 64; \
|
||||
}; \
|
||||
const has_accel_fn NFATraits<LIMEX_NFA_##mlt_size##_##mlt_shift>::has_accel \
|
||||
= has_accel_limex<LimExNFA##mlt_size>; \
|
||||
DO_IF_DUMP_SUPPORT( \
|
||||
const char *NFATraits<LIMEX_NFA_##mlt_size##_##mlt_shift>::name \
|
||||
= "LimEx (0-"#mlt_shift") "#mlt_size; \
|
||||
template<> struct getDescription<LIMEX_NFA_##mlt_size##_##mlt_shift> { \
|
||||
static string call(const void *ptr) { \
|
||||
return getDescriptionLimEx<LIMEX_NFA_##mlt_size##_##mlt_shift>((const NFA *)ptr); \
|
||||
} \
|
||||
};)
|
||||
|
||||
MAKE_LIMEX_TRAITS(32, 1)
|
||||
MAKE_LIMEX_TRAITS(32, 2)
|
||||
MAKE_LIMEX_TRAITS(32, 3)
|
||||
MAKE_LIMEX_TRAITS(32, 4)
|
||||
MAKE_LIMEX_TRAITS(32, 5)
|
||||
MAKE_LIMEX_TRAITS(32, 6)
|
||||
MAKE_LIMEX_TRAITS(32, 7)
|
||||
MAKE_LIMEX_TRAITS(128, 1)
|
||||
MAKE_LIMEX_TRAITS(128, 2)
|
||||
MAKE_LIMEX_TRAITS(128, 3)
|
||||
MAKE_LIMEX_TRAITS(128, 4)
|
||||
MAKE_LIMEX_TRAITS(128, 5)
|
||||
MAKE_LIMEX_TRAITS(128, 6)
|
||||
MAKE_LIMEX_TRAITS(128, 7)
|
||||
MAKE_LIMEX_TRAITS(256, 1)
|
||||
MAKE_LIMEX_TRAITS(256, 2)
|
||||
MAKE_LIMEX_TRAITS(256, 3)
|
||||
MAKE_LIMEX_TRAITS(256, 4)
|
||||
MAKE_LIMEX_TRAITS(256, 5)
|
||||
MAKE_LIMEX_TRAITS(256, 6)
|
||||
MAKE_LIMEX_TRAITS(256, 7)
|
||||
MAKE_LIMEX_TRAITS(384, 1)
|
||||
MAKE_LIMEX_TRAITS(384, 2)
|
||||
MAKE_LIMEX_TRAITS(384, 3)
|
||||
MAKE_LIMEX_TRAITS(384, 4)
|
||||
MAKE_LIMEX_TRAITS(384, 5)
|
||||
MAKE_LIMEX_TRAITS(384, 6)
|
||||
MAKE_LIMEX_TRAITS(384, 7)
|
||||
MAKE_LIMEX_TRAITS(512, 1)
|
||||
MAKE_LIMEX_TRAITS(512, 2)
|
||||
MAKE_LIMEX_TRAITS(512, 3)
|
||||
MAKE_LIMEX_TRAITS(512, 4)
|
||||
MAKE_LIMEX_TRAITS(512, 5)
|
||||
MAKE_LIMEX_TRAITS(512, 6)
|
||||
MAKE_LIMEX_TRAITS(512, 7)
|
||||
|
||||
template<> struct NFATraits<MCCLELLAN_NFA_8> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 1;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<MCCLELLAN_NFA_8>::has_accel = has_accel_dfa;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<MCCLELLAN_NFA_8>::name = "McClellan 8";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<MCCLELLAN_NFA_16> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 2;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<MCCLELLAN_NFA_16>::has_accel = has_accel_dfa;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<MCCLELLAN_NFA_16>::name = "McClellan 16";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<GOUGH_NFA_8> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<GOUGH_NFA_8>::has_accel = has_accel_dfa;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<GOUGH_NFA_8>::name = "Goughfish 8";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<GOUGH_NFA_16> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<GOUGH_NFA_16>::has_accel = has_accel_dfa;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<GOUGH_NFA_16>::name = "Goughfish 16";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<MPV_NFA_0> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<MPV_NFA_0>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<MPV_NFA_0>::name = "Mega-Puff-Vac";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<CASTLE_NFA_0> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<CASTLE_NFA_0>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<CASTLE_NFA_0>::name = "Castle";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<LBR_NFA_Dot> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<LBR_NFA_Dot>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<LBR_NFA_Dot>::name = "Lim Bounded Repeat (D)";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<LBR_NFA_Verm> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<LBR_NFA_Verm>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<LBR_NFA_Verm>::name = "Lim Bounded Repeat (V)";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<LBR_NFA_NVerm> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<LBR_NFA_NVerm>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<LBR_NFA_NVerm>::name = "Lim Bounded Repeat (NV)";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<LBR_NFA_Shuf> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<LBR_NFA_Shuf>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<LBR_NFA_Shuf>::name = "Lim Bounded Repeat (S)";
|
||||
#endif
|
||||
|
||||
template<> struct NFATraits<LBR_NFA_Truf> {
|
||||
UNUSED static const char *name;
|
||||
static const NFACategory category = NFA_OTHER;
|
||||
static const u32 stateAlign = 8;
|
||||
static const bool fast = true;
|
||||
static const has_accel_fn has_accel;
|
||||
};
|
||||
const has_accel_fn NFATraits<LBR_NFA_Truf>::has_accel = has_accel_generic;
|
||||
#if defined(DUMP_SUPPORT)
|
||||
const char *NFATraits<LBR_NFA_Truf>::name = "Lim Bounded Repeat (M)";
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(DUMP_SUPPORT)
|
||||
|
||||
const char *nfa_type_name(NFAEngineType type) {
|
||||
return DISPATCH_BY_NFA_TYPE(type, getName, nullptr);
|
||||
}
|
||||
|
||||
string describe(const NFA &nfa) {
|
||||
return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, getDescription, &nfa);
|
||||
}
|
||||
|
||||
#endif /* DUMP_SUPPORT */
|
||||
|
||||
namespace {
|
||||
template<NFAEngineType t>
|
||||
struct getStateAlign {
|
||||
static u32 call(void *) {
|
||||
return NFATraits<t>::stateAlign;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
u32 state_alignment(const NFA &nfa) {
|
||||
return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, getStateAlign, nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<NFAEngineType t>
|
||||
struct getFastness {
|
||||
static u32 call(void *) {
|
||||
return NFATraits<t>::fast;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool is_fast(const NFA &nfa) {
|
||||
NFAEngineType t = (NFAEngineType)nfa.type;
|
||||
return DISPATCH_BY_NFA_TYPE(t, getFastness, nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<NFAEngineType t>
|
||||
struct is_limex {
|
||||
static bool call(const void *) {
|
||||
return NFATraits<t>::category == NFA_LIMEX;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool has_bounded_repeats_other_than_firsts(const NFA &nfa) {
|
||||
if (!DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, is_limex, &nfa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const LimExNFABase *limex = (const LimExNFABase *)getImplNfa(&nfa);
|
||||
const char *ptr = (const char *)limex;
|
||||
|
||||
const u32 *repeatOffset = (const u32 *)(ptr + limex->repeatOffset);
|
||||
|
||||
for (u32 i = 0; i < limex->repeatCount; i++) {
|
||||
u32 offset = repeatOffset[i];
|
||||
const NFARepeatInfo *info = (const NFARepeatInfo *)(ptr + offset);
|
||||
const RepeatInfo *repeat =
|
||||
(const RepeatInfo *)((const char *)info + sizeof(*info));
|
||||
if (repeat->type != REPEAT_FIRST) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_bounded_repeats(const NFA &nfa) {
|
||||
if (!DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, is_limex, &nfa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const LimExNFABase *limex = (const LimExNFABase *)getImplNfa(&nfa);
|
||||
return limex->repeatCount;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<NFAEngineType t>
|
||||
struct has_accel_dispatch {
|
||||
static has_accel_fn call(const void *) {
|
||||
return NFATraits<t>::has_accel;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool has_accel(const NFA &nfa) {
|
||||
return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, has_accel_dispatch,
|
||||
&nfa)
|
||||
(&nfa);
|
||||
}
|
||||
|
||||
bool requires_decompress_key(const NFA &nfa) {
|
||||
return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, is_limex, &nfa);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
64
src/nfa/nfa_build_util.h
Normal file
64
src/nfa/nfa_build_util.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef NFA_BUILD_UTIL_H
|
||||
#define NFA_BUILD_UTIL_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "nfa_internal.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
/* provided for debugging functions */
|
||||
const char *nfa_type_name(NFAEngineType type);
|
||||
std::string describe(const NFA &nfa);
|
||||
#endif
|
||||
|
||||
// For a given NFA, retrieve the alignment required by its uncompressed state.
|
||||
u32 state_alignment(const NFA &nfa);
|
||||
|
||||
/* returns true if the nfa is considered 'fast'. TODO: work out what we mean by
|
||||
* fast. */
|
||||
bool is_fast(const NFA &n);
|
||||
|
||||
bool has_bounded_repeats_other_than_firsts(const NFA &n);
|
||||
|
||||
bool has_bounded_repeats(const NFA &n);
|
||||
|
||||
bool has_accel(const NFA &n);
|
||||
|
||||
bool requires_decompress_key(const NFA &n);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
56
src/nfa/nfa_dump_api.h
Normal file
56
src/nfa/nfa_dump_api.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Declarations for the NFA Engine dump API.
|
||||
*/
|
||||
|
||||
#ifndef NFA_DUMP_API_H
|
||||
#define NFA_DUMP_API_H
|
||||
|
||||
#if defined(DUMP_SUPPORT)
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
/**
|
||||
* \brief Dump (in Graphviz 'dot' format) a representation of the NFA into the
|
||||
* file pointed to by dotFile.
|
||||
*/
|
||||
void nfaDumpDot(const struct NFA *nfa, FILE *dotFile);
|
||||
|
||||
/** \brief Dump a textual representation of the NFA. */
|
||||
void nfaDumpText(const struct NFA *fact, FILE *textFile);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
#endif // NFA_DUMP_API_H
|
||||
119
src/nfa/nfa_dump_dispatch.cpp
Normal file
119
src/nfa/nfa_dump_dispatch.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "nfa_dump_api.h"
|
||||
|
||||
#include "nfa_internal.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
// Engine implementations.
|
||||
#include "goughdump.h"
|
||||
#include "castle_dump.h"
|
||||
#include "lbr_dump.h"
|
||||
#include "limex.h"
|
||||
#include "mcclellandump.h"
|
||||
#include "mpv_dump.h"
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error "no dump support"
|
||||
#endif
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#define DISPATCH_CASE(dc_ltype, dc_ftype, dc_subtype, dc_func_call) \
|
||||
case dc_ltype##_NFA_##dc_subtype: \
|
||||
nfaExec##dc_ftype##dc_subtype##dc_func_call; \
|
||||
break
|
||||
|
||||
// general framework calls
|
||||
|
||||
#define DISPATCH_BY_NFA_TYPE(dbnt_func) \
|
||||
DEBUG_PRINTF("dispatch for NFA type %u\n", nfa->type); \
|
||||
switch (nfa->type) { \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 32_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 128_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 256_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 384_7, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_1, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_2, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_3, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_4, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_5, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_6, dbnt_func); \
|
||||
DISPATCH_CASE(LIMEX, LimEx, 512_7, dbnt_func); \
|
||||
DISPATCH_CASE(MCCLELLAN, McClellan, 8, dbnt_func); \
|
||||
DISPATCH_CASE(MCCLELLAN, McClellan, 16, dbnt_func); \
|
||||
DISPATCH_CASE(GOUGH, Gough, 8, dbnt_func); \
|
||||
DISPATCH_CASE(GOUGH, Gough, 16, dbnt_func); \
|
||||
DISPATCH_CASE(MPV, Mpv, 0, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Dot, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Verm, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, NVerm, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Shuf, dbnt_func); \
|
||||
DISPATCH_CASE(LBR, Lbr, Truf, dbnt_func); \
|
||||
DISPATCH_CASE(CASTLE, Castle, 0, dbnt_func); \
|
||||
default: \
|
||||
assert(0); \
|
||||
}
|
||||
|
||||
void nfaDumpDot(const struct NFA *nfa, FILE *dotFile) {
|
||||
DISPATCH_BY_NFA_TYPE(_dumpDot(nfa, dotFile));
|
||||
}
|
||||
|
||||
void nfaDumpText(const struct NFA *nfa, FILE *txtFile) {
|
||||
DISPATCH_BY_NFA_TYPE(_dumpText(nfa, txtFile));
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
149
src/nfa/nfa_dump_internal.cpp
Normal file
149
src/nfa/nfa_dump_internal.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "nfa_dump_internal.h"
|
||||
|
||||
#include "accel.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
#include <cctype> // for isprint
|
||||
#include <sstream>
|
||||
|
||||
#ifndef DUMP_SUPPORT
|
||||
#error No dump support!
|
||||
#endif
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
void dumpDotPreamble(FILE *dotFile) {
|
||||
fprintf(dotFile, "digraph NFA {\n");
|
||||
fprintf(dotFile, "rankdir=LR;\n");
|
||||
fprintf(dotFile, "size=\"11.5,8\"\n");
|
||||
fprintf(dotFile, "node [ shape = circle ];\n");
|
||||
fprintf(dotFile, "START [style=invis];\n");
|
||||
}
|
||||
|
||||
void dumpDotTrailer(FILE *dotFile) {
|
||||
fprintf(dotFile, "}\n");
|
||||
}
|
||||
|
||||
static
|
||||
void dumpFlags(const struct NFA *nfa, FILE *f) {
|
||||
fprintf(f, "Flags : ");
|
||||
if (nfa->flags & NFA_ACCEPTS_EOD) {
|
||||
fprintf(f, "ACCEPTS_EOD ");
|
||||
}
|
||||
if (nfa->flags & NFA_ZOMBIE) {
|
||||
fprintf(f, "ZOMBIE ");
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
// Render an unsigned integer as a string, returning "inf/unknown" if it's
|
||||
// zero.
|
||||
static
|
||||
std::string value_or_inf(const u64a v) {
|
||||
std::ostringstream oss;
|
||||
if (v) {
|
||||
oss << v;
|
||||
} else {
|
||||
oss << "inf/unknown";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void dumpTextReverse(const struct NFA *nfa, FILE *f) {
|
||||
bool twofer = false;
|
||||
|
||||
fprintf(f, "Queue : %u\n", nfa->queueIndex);
|
||||
fprintf(f, "Length : %u bytes\n", nfa->length);
|
||||
fprintf(f, "Num Positions : %u\n", nfa->nPositions);
|
||||
fprintf(f, "Scratch State : %u bytes\n", nfa->scratchStateSize);
|
||||
fprintf(f, "Stream State : %u bytes\n", nfa->streamStateSize);
|
||||
dumpFlags(nfa, f);
|
||||
fprintf(f, "Max Width : %s\n", value_or_inf(nfa->maxWidth).c_str());
|
||||
fprintf(f, "Min Width : %u\n", nfa->minWidth);
|
||||
fprintf(f, "BiAnchored Width : %s\n",
|
||||
value_or_inf(nfa->maxBiAnchoredWidth).c_str());
|
||||
fprintf(f, "Max Offset : %s\n", value_or_inf(nfa->maxOffset).c_str());
|
||||
fprintf(f, "Reverse Acceleration : ");
|
||||
|
||||
switch (nfa->rAccelType) {
|
||||
case ACCEL_NONE:
|
||||
fprintf(f, "NONE\n");
|
||||
return;
|
||||
case ACCEL_RVERM:
|
||||
fprintf(f, "R VERM");
|
||||
break;
|
||||
case ACCEL_RVERM_NOCASE:
|
||||
fprintf(f, "R VERM NOCASE");
|
||||
break;
|
||||
case ACCEL_RDVERM:
|
||||
fprintf(f, "R VERM x2");
|
||||
twofer = true;
|
||||
break;
|
||||
case ACCEL_RDVERM_NOCASE:
|
||||
fprintf(f, "R VERM NOCASE x2");
|
||||
twofer = true;
|
||||
break;
|
||||
case ACCEL_REOD:
|
||||
fprintf(f, "R EOD");
|
||||
break;
|
||||
case ACCEL_REOD_NOCASE:
|
||||
fprintf(f, "R EOD NOCASE");
|
||||
break;
|
||||
case ACCEL_RDEOD:
|
||||
fprintf(f, "R EOD x2");
|
||||
twofer = true;
|
||||
break;
|
||||
case ACCEL_RDEOD_NOCASE:
|
||||
fprintf(f, "R EOD x2 NOCASE");
|
||||
twofer = true;
|
||||
break;
|
||||
default:
|
||||
fprintf(f, "UNKNOWN\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char c1 = nfa->rAccelData.array[0];
|
||||
char c2 = nfa->rAccelData.array[1];
|
||||
|
||||
if (!twofer) {
|
||||
fprintf(f, " \\x%02hhx (%c) ", c1, isprint(c1) ? c1 : '?');
|
||||
} else {
|
||||
fprintf(f, " \\x%02hhx\\x%02hhx (%c%c) ", c1, c2,
|
||||
isprint(c1) ? c1 : '?', isprint(c2) ? c2 : '?');
|
||||
}
|
||||
|
||||
fprintf(f, "offset %hhd\n", nfa->rAccelOffset);
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
56
src/nfa/nfa_dump_internal.h
Normal file
56
src/nfa/nfa_dump_internal.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Common dump code for nfa engines.
|
||||
*/
|
||||
|
||||
#ifndef NFA_DUMP_INTERNAL_H
|
||||
#define NFA_DUMP_INTERNAL_H
|
||||
|
||||
#if defined(DUMP_SUPPORT)
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
struct NFA;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
/** \brief Writes a Graphviz DOT graph preamble. */
|
||||
void dumpDotPreamble(FILE *f);
|
||||
|
||||
/** \brief Finishes a Graphviz DOT graph. */
|
||||
void dumpDotTrailer(FILE *f);
|
||||
|
||||
/** \brief Dumps text information about \a nfa. */
|
||||
void dumpTextReverse(const struct NFA *nfa, FILE *f);
|
||||
|
||||
}
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
#endif
|
||||
256
src/nfa/nfa_internal.h
Normal file
256
src/nfa/nfa_internal.h
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Declarations for the main NFA engine types and structures.
|
||||
*/
|
||||
#ifndef NFA_INTERNAL_H
|
||||
#define NFA_INTERNAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
// Constants
|
||||
|
||||
#define MO_INVALID_IDX 0xffffffff /**< index meaning value is invalid */
|
||||
|
||||
// Flags (used in NFA::flags)
|
||||
|
||||
#define NFA_ACCEPTS_EOD 1U /**< can produce matches on EOD. */
|
||||
#define NFA_ZOMBIE 2U /**< supports zombies */
|
||||
|
||||
// Common data structures for NFAs
|
||||
|
||||
enum NFAEngineType {
|
||||
LIMEX_NFA_32_1,
|
||||
LIMEX_NFA_32_2,
|
||||
LIMEX_NFA_32_3,
|
||||
LIMEX_NFA_32_4,
|
||||
LIMEX_NFA_32_5,
|
||||
LIMEX_NFA_32_6,
|
||||
LIMEX_NFA_32_7,
|
||||
LIMEX_NFA_128_1,
|
||||
LIMEX_NFA_128_2,
|
||||
LIMEX_NFA_128_3,
|
||||
LIMEX_NFA_128_4,
|
||||
LIMEX_NFA_128_5,
|
||||
LIMEX_NFA_128_6,
|
||||
LIMEX_NFA_128_7,
|
||||
LIMEX_NFA_256_1,
|
||||
LIMEX_NFA_256_2,
|
||||
LIMEX_NFA_256_3,
|
||||
LIMEX_NFA_256_4,
|
||||
LIMEX_NFA_256_5,
|
||||
LIMEX_NFA_256_6,
|
||||
LIMEX_NFA_256_7,
|
||||
LIMEX_NFA_384_1,
|
||||
LIMEX_NFA_384_2,
|
||||
LIMEX_NFA_384_3,
|
||||
LIMEX_NFA_384_4,
|
||||
LIMEX_NFA_384_5,
|
||||
LIMEX_NFA_384_6,
|
||||
LIMEX_NFA_384_7,
|
||||
LIMEX_NFA_512_1,
|
||||
LIMEX_NFA_512_2,
|
||||
LIMEX_NFA_512_3,
|
||||
LIMEX_NFA_512_4,
|
||||
LIMEX_NFA_512_5,
|
||||
LIMEX_NFA_512_6,
|
||||
LIMEX_NFA_512_7,
|
||||
MCCLELLAN_NFA_8, /**< magic pseudo nfa */
|
||||
MCCLELLAN_NFA_16, /**< magic pseudo nfa */
|
||||
GOUGH_NFA_8, /**< magic pseudo nfa */
|
||||
GOUGH_NFA_16, /**< magic pseudo nfa */
|
||||
MPV_NFA_0, /**< magic pseudo nfa */
|
||||
LBR_NFA_Dot, /**< magic pseudo nfa */
|
||||
LBR_NFA_Verm, /**< magic pseudo nfa */
|
||||
LBR_NFA_NVerm, /**< magic pseudo nfa */
|
||||
LBR_NFA_Shuf, /**< magic pseudo nfa */
|
||||
LBR_NFA_Truf, /**< magic pseudo nfa */
|
||||
CASTLE_NFA_0, /**< magic pseudo nfa */
|
||||
/** \brief bogus NFA - not used */
|
||||
INVALID_NFA
|
||||
};
|
||||
|
||||
/** \brief header for the NFA implementation. */
|
||||
struct ALIGN_CL_DIRECTIVE NFA {
|
||||
u32 flags;
|
||||
|
||||
/** \brief The size in bytes of the NFA engine. The engine is
|
||||
* serialized to the extent that copying length bytes back into a
|
||||
* 16-byte aligned memory location yields a structure that has the same
|
||||
* behaviour as the original engine. */
|
||||
u32 length;
|
||||
|
||||
/** \brief Active implementation used by this NFAEngineType */
|
||||
u8 type;
|
||||
|
||||
u8 rAccelType;
|
||||
u8 rAccelOffset;
|
||||
u8 maxBiAnchoredWidth; /**< if non zero, max width of the block */
|
||||
|
||||
union {
|
||||
u8 c;
|
||||
u16 dc;
|
||||
u8 array[2];
|
||||
} rAccelData;
|
||||
|
||||
u32 queueIndex; /**< index of the associated queue in scratch */
|
||||
|
||||
/** \brief The number of valid positions/states for this NFA. Debug only */
|
||||
u32 nPositions;
|
||||
|
||||
/** \brief Size of the state required in scratch space.
|
||||
*
|
||||
* This state has less strict size requirements (as it doesn't go in stream
|
||||
* state) and does not persist between stream writes.
|
||||
*/
|
||||
u32 scratchStateSize;
|
||||
|
||||
/** \brief Size of the state required in stream state.
|
||||
*
|
||||
* This encompasses all state stored by the engine that must persist between
|
||||
* stream writes. */
|
||||
u32 streamStateSize;
|
||||
|
||||
u32 maxWidth; /**< longest possible match in this NFA, 0 if unbounded */
|
||||
u32 minWidth; /**< minimum bytes required to match this NFA */
|
||||
u32 maxOffset; /**< non zero: maximum offset this pattern can match at */
|
||||
|
||||
/* Note: implementation (e.g. a LimEx) directly follows struct in memory */
|
||||
} ;
|
||||
|
||||
// Accessor macro for the implementation NFA: we do things this way to avoid
|
||||
// type-punning warnings.
|
||||
#define getImplNfa(nfa) \
|
||||
((const void *)((const char *)(nfa) + sizeof(struct NFA)))
|
||||
|
||||
// Non-const version of the above, used at compile time.
|
||||
#define getMutableImplNfa(nfa) ((char *)(nfa) + sizeof(struct NFA))
|
||||
|
||||
static really_inline u32 nfaAcceptsEod(const struct NFA *nfa) {
|
||||
return nfa->flags & NFA_ACCEPTS_EOD;
|
||||
}
|
||||
|
||||
static really_inline u32 nfaSupportsZombie(const struct NFA *nfa) {
|
||||
return nfa->flags & NFA_ZOMBIE;
|
||||
}
|
||||
|
||||
/** \brief True if the given type (from NFA::type) is a McClellan DFA. */
|
||||
static really_inline int isMcClellanType(u8 t) {
|
||||
return t == MCCLELLAN_NFA_8 || t == MCCLELLAN_NFA_16;
|
||||
}
|
||||
|
||||
/** \brief True if the given type (from NFA::type) is a Gough DFA. */
|
||||
static really_inline int isGoughType(u8 t) {
|
||||
return t == GOUGH_NFA_8 || t == GOUGH_NFA_16;
|
||||
}
|
||||
|
||||
/** \brief True if the given type (from NFA::type) is a McClellan or Gough DFA.
|
||||
* */
|
||||
static really_inline int isDfaType(u8 t) {
|
||||
return isMcClellanType(t) || isGoughType(t);
|
||||
}
|
||||
|
||||
/** \brief True if the given type (from NFA::type) is an NFA. */
|
||||
static really_inline int isNfaType(u8 t) {
|
||||
switch (t) {
|
||||
case LIMEX_NFA_32_1:
|
||||
case LIMEX_NFA_32_2:
|
||||
case LIMEX_NFA_32_3:
|
||||
case LIMEX_NFA_32_4:
|
||||
case LIMEX_NFA_32_5:
|
||||
case LIMEX_NFA_32_6:
|
||||
case LIMEX_NFA_32_7:
|
||||
case LIMEX_NFA_128_1:
|
||||
case LIMEX_NFA_128_2:
|
||||
case LIMEX_NFA_128_3:
|
||||
case LIMEX_NFA_128_4:
|
||||
case LIMEX_NFA_128_5:
|
||||
case LIMEX_NFA_128_6:
|
||||
case LIMEX_NFA_128_7:
|
||||
case LIMEX_NFA_256_1:
|
||||
case LIMEX_NFA_256_2:
|
||||
case LIMEX_NFA_256_3:
|
||||
case LIMEX_NFA_256_4:
|
||||
case LIMEX_NFA_256_5:
|
||||
case LIMEX_NFA_256_6:
|
||||
case LIMEX_NFA_256_7:
|
||||
case LIMEX_NFA_384_1:
|
||||
case LIMEX_NFA_384_2:
|
||||
case LIMEX_NFA_384_3:
|
||||
case LIMEX_NFA_384_4:
|
||||
case LIMEX_NFA_384_5:
|
||||
case LIMEX_NFA_384_6:
|
||||
case LIMEX_NFA_384_7:
|
||||
case LIMEX_NFA_512_1:
|
||||
case LIMEX_NFA_512_2:
|
||||
case LIMEX_NFA_512_3:
|
||||
case LIMEX_NFA_512_4:
|
||||
case LIMEX_NFA_512_5:
|
||||
case LIMEX_NFA_512_6:
|
||||
case LIMEX_NFA_512_7:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \brief True if the given type (from NFA::type) is an LBR. */
|
||||
static really_inline
|
||||
int isLbrType(u8 t) {
|
||||
return t == LBR_NFA_Dot || t == LBR_NFA_Verm || t == LBR_NFA_NVerm ||
|
||||
t == LBR_NFA_Shuf || t == LBR_NFA_Truf;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
int isMultiTopType(u8 t) {
|
||||
return !isDfaType(t) && !isLbrType(t);
|
||||
}
|
||||
/** Macro used in place of unimplemented NFA API functions for a given
|
||||
* engine. */
|
||||
#if !defined(_WIN32)
|
||||
#define NFA_API_NO_IMPL(...) \
|
||||
({ \
|
||||
assert("not implemented for this engine!"); \
|
||||
0; /* return value, for places that need it */ \
|
||||
})
|
||||
#else
|
||||
#define NFA_API_NO_IMPL(...) 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
57
src/nfa/nfa_kind.h
Normal file
57
src/nfa/nfa_kind.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef NFA_KIND_H
|
||||
#define NFA_KIND_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
/** \brief Specify the use-case for an nfa engine. */
|
||||
enum nfa_kind {
|
||||
NFA_PREFIX, //!< rose prefix
|
||||
NFA_INFIX, //!< rose infix
|
||||
NFA_SUFFIX, //!< rose suffix
|
||||
NFA_OUTFIX, //!< "outfix" nfa not triggered by external events
|
||||
NFA_REV_PREFIX, //! reverse running prefixes (for som)
|
||||
};
|
||||
|
||||
static UNUSED
|
||||
bool is_triggered(enum nfa_kind k) {
|
||||
return k == NFA_INFIX || k == NFA_SUFFIX || k == NFA_REV_PREFIX;
|
||||
}
|
||||
|
||||
static UNUSED
|
||||
bool generates_callbacks(enum nfa_kind k) {
|
||||
return k == NFA_SUFFIX || k == NFA_OUTFIX || k == NFA_REV_PREFIX;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif
|
||||
157
src/nfa/nfa_rev_api.h
Normal file
157
src/nfa/nfa_rev_api.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Reverse-acceleration optimizations for the NFA API block mode scans.
|
||||
*/
|
||||
|
||||
#ifndef NFA_REV_API_H
|
||||
#define NFA_REV_API_H
|
||||
|
||||
#include "accel.h"
|
||||
#include "nfa_internal.h"
|
||||
#include "vermicelli.h"
|
||||
#include "util/unaligned.h"
|
||||
|
||||
static really_inline
|
||||
size_t nfaRevAccel_i(const struct NFA *nfa, const u8 *buffer, size_t length) {
|
||||
DEBUG_PRINTF("checking rev accel mw %u\n", nfa->minWidth);
|
||||
assert(nfa->rAccelOffset >= 1);
|
||||
assert(nfa->rAccelOffset <= nfa->minWidth);
|
||||
|
||||
const u8 *rv; // result for accel engine
|
||||
|
||||
switch (nfa->rAccelType) {
|
||||
case ACCEL_RVERM:
|
||||
DEBUG_PRINTF("ACCEL_RVERM\n");
|
||||
if (length + 1 - nfa->rAccelOffset < 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = rvermicelliExec(nfa->rAccelData.c, 0, buffer,
|
||||
buffer + length + 1 - nfa->rAccelOffset);
|
||||
length = (size_t)(rv - buffer + nfa->rAccelOffset);
|
||||
break;
|
||||
case ACCEL_RVERM_NOCASE:
|
||||
DEBUG_PRINTF("ACCEL_RVERM_NOCASE\n");
|
||||
if (length + 1 - nfa->rAccelOffset < 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = rvermicelliExec(nfa->rAccelData.c, 1, buffer,
|
||||
buffer + length + 1 - nfa->rAccelOffset);
|
||||
length = (size_t)(rv - buffer + nfa->rAccelOffset);
|
||||
break;
|
||||
case ACCEL_RDVERM:
|
||||
DEBUG_PRINTF("ACCEL_RDVERM\n");
|
||||
if (length + 1 - nfa->rAccelOffset < 17) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = rvermicelliDoubleExec(nfa->rAccelData.array[0],
|
||||
nfa->rAccelData.array[1], 0, buffer,
|
||||
buffer + length + 1 - nfa->rAccelOffset);
|
||||
length = (size_t)(rv - buffer + nfa->rAccelOffset);
|
||||
break;
|
||||
case ACCEL_RDVERM_NOCASE:
|
||||
DEBUG_PRINTF("ACCEL_RVERM_NOCASE\n");
|
||||
if (length + 1 - nfa->rAccelOffset < 17) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = rvermicelliDoubleExec(nfa->rAccelData.array[0],
|
||||
nfa->rAccelData.array[1], 1, buffer,
|
||||
buffer + length + 1 - nfa->rAccelOffset);
|
||||
length = (size_t)(rv - buffer + nfa->rAccelOffset);
|
||||
break;
|
||||
case ACCEL_REOD:
|
||||
DEBUG_PRINTF("ACCEL_REOD\n");
|
||||
if (buffer[length - nfa->rAccelOffset] != nfa->rAccelData.c) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ACCEL_REOD_NOCASE:
|
||||
DEBUG_PRINTF("ACCEL_REOD_NOCASE\n");
|
||||
if ((buffer[length - nfa->rAccelOffset] & CASE_CLEAR) !=
|
||||
nfa->rAccelData.c) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ACCEL_RDEOD:
|
||||
DEBUG_PRINTF("ACCEL_RDEOD\n");
|
||||
if (unaligned_load_u16(buffer + length - nfa->rAccelOffset) !=
|
||||
nfa->rAccelData.dc) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ACCEL_RDEOD_NOCASE:
|
||||
DEBUG_PRINTF("ACCEL_RDEOD_NOCASE\n");
|
||||
if ((unaligned_load_u16(buffer + length - nfa->rAccelOffset) &
|
||||
DOUBLE_CASE_CLEAR) != nfa->rAccelData.dc) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(!"not here");
|
||||
}
|
||||
|
||||
if (nfa->minWidth > length) {
|
||||
DEBUG_PRINTF("post-accel, scan skipped: %zu < min %u bytes\n", length,
|
||||
nfa->minWidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/** \brief Reverse acceleration check. Returns a new length for the block,
|
||||
* guaranteeing that a match cannot occur beyond that point. */
|
||||
static really_inline
|
||||
size_t nfaRevAccelCheck(const struct NFA *nfa, const u8 *buffer,
|
||||
size_t length) {
|
||||
assert(nfa);
|
||||
|
||||
// If this block is not long enough to satisfy the minimum width
|
||||
// constraint on this NFA, we can avoid the scan altogether.
|
||||
if (nfa->minWidth > length) {
|
||||
DEBUG_PRINTF("scan skipped: %zu < min %u bytes\n", length,
|
||||
nfa->minWidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nfa->rAccelType == ACCEL_NONE) {
|
||||
DEBUG_PRINTF("no rev accel available\n");
|
||||
return length;
|
||||
}
|
||||
|
||||
size_t rv_length = nfaRevAccel_i(nfa, buffer, length);
|
||||
assert(rv_length <= length);
|
||||
return rv_length;
|
||||
}
|
||||
|
||||
#endif
|
||||
91
src/nfa/rdfa.h
Normal file
91
src/nfa/rdfa.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef RDFA_H
|
||||
#define RDFA_H
|
||||
|
||||
#include "nfa_kind.h"
|
||||
#include "ue2common.h"
|
||||
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
typedef u16 dstate_id_t;
|
||||
typedef u16 symbol_t;
|
||||
|
||||
static constexpr symbol_t TOP = 256;
|
||||
static constexpr symbol_t ALPHABET_SIZE = 257;
|
||||
static constexpr symbol_t N_SPECIAL_SYMBOL = 1;
|
||||
static constexpr dstate_id_t DEAD_STATE = 0;
|
||||
|
||||
/** Structure representing a dfa state during construction. */
|
||||
struct dstate {
|
||||
/** Next state; indexed by remapped sym */
|
||||
std::vector<dstate_id_t> next;
|
||||
|
||||
/** Set by ng_mcclellan, refined by mcclellancompile */
|
||||
dstate_id_t daddy = 0;
|
||||
|
||||
/** Set by mcclellancompile, implementation state id, excludes edge
|
||||
* decorations */
|
||||
dstate_id_t impl_id = 0;
|
||||
|
||||
/** Reports to fire (at any location). */
|
||||
flat_set<ReportID> reports;
|
||||
|
||||
/** Reports to fire (at EOD). */
|
||||
flat_set<ReportID> reports_eod;
|
||||
|
||||
explicit dstate(size_t alphabet_size) : next(alphabet_size, 0) {}
|
||||
};
|
||||
|
||||
struct raw_dfa {
|
||||
nfa_kind kind;
|
||||
std::vector<dstate> states;
|
||||
dstate_id_t start_anchored = DEAD_STATE;
|
||||
dstate_id_t start_floating = DEAD_STATE;
|
||||
u16 alpha_size = 0; /* including special symbols */
|
||||
|
||||
/* mapping from input symbol --> equiv class id */
|
||||
std::array<u16, ALPHABET_SIZE> alpha_remap;
|
||||
|
||||
explicit raw_dfa(nfa_kind k) : kind(k) {}
|
||||
virtual ~raw_dfa();
|
||||
|
||||
u16 getImplAlphaSize() const;
|
||||
virtual void stripExtraEodReports(void);
|
||||
bool hasEodReports(void) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
393
src/nfa/rdfa_merge.cpp
Normal file
393
src/nfa/rdfa_merge.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#include "rdfa_merge.h"
|
||||
|
||||
#include "grey.h"
|
||||
#include "dfa_min.h"
|
||||
#include "mcclellancompile_util.h"
|
||||
#include "rdfa.h"
|
||||
#include "ue2common.h"
|
||||
#include "nfagraph/ng_mcclellan_internal.h"
|
||||
#include "util/container.h"
|
||||
#include "util/determinise.h"
|
||||
#include "util/make_unique.h"
|
||||
#include "util/report_manager.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#define MAX_DFA_STATES 16383
|
||||
|
||||
namespace {
|
||||
|
||||
class Automaton_Merge {
|
||||
public:
|
||||
typedef vector<u16> StateSet;
|
||||
typedef ue2::unordered_map<StateSet, dstate_id_t> StateMap;
|
||||
|
||||
Automaton_Merge(const raw_dfa *rdfa1, const raw_dfa *rdfa2,
|
||||
const ReportManager *rm_in, const Grey &grey_in)
|
||||
: rm(rm_in), grey(grey_in), nfas{rdfa1, rdfa2}, dead(2) {
|
||||
calculateAlphabet();
|
||||
populateAsFs();
|
||||
prunable = isPrunable();
|
||||
}
|
||||
|
||||
Automaton_Merge(const vector<const raw_dfa *> &dfas,
|
||||
const ReportManager *rm_in, const Grey &grey_in)
|
||||
: rm(rm_in), grey(grey_in), nfas(dfas), dead(nfas.size()) {
|
||||
calculateAlphabet();
|
||||
populateAsFs();
|
||||
prunable = isPrunable();
|
||||
}
|
||||
|
||||
void populateAsFs(void) {
|
||||
bool fs_same = true;
|
||||
bool fs_dead = true;
|
||||
|
||||
as.resize(nfas.size());
|
||||
fs.resize(nfas.size());
|
||||
for (size_t i = 0, end = nfas.size(); i < end; i++) {
|
||||
as[i] = nfas[i]->start_anchored;
|
||||
fs[i] = nfas[i]->start_floating;
|
||||
|
||||
if (fs[i]) {
|
||||
fs_dead = false;
|
||||
}
|
||||
|
||||
if (as[i] != fs[i]) {
|
||||
fs_same = false;
|
||||
}
|
||||
}
|
||||
|
||||
start_anchored = DEAD_STATE + 1;
|
||||
if (fs_same) {
|
||||
start_floating = start_anchored;
|
||||
} else if (fs_dead) {
|
||||
start_floating = DEAD_STATE;
|
||||
} else {
|
||||
start_floating = start_anchored + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void calculateAlphabet(void) {
|
||||
DEBUG_PRINTF("calculating alphabet\n");
|
||||
vector<CharReach> esets = {CharReach::dot()};
|
||||
|
||||
for (const auto &rdfa : nfas) {
|
||||
DEBUG_PRINTF("...next dfa alphabet\n");
|
||||
assert(rdfa);
|
||||
const auto &alpha_remap = rdfa->alpha_remap;
|
||||
|
||||
for (size_t i = 0; i < esets.size(); i++) {
|
||||
assert(esets[i].count());
|
||||
if (esets[i].count() == 1) {
|
||||
DEBUG_PRINTF("skipping singleton eq set\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
CharReach t;
|
||||
u8 leader_s = alpha_remap[esets[i].find_first()];
|
||||
|
||||
DEBUG_PRINTF("checking eq set, leader %02hhx \n", leader_s);
|
||||
|
||||
for (size_t s = esets[i].find_first(); s != CharReach::npos;
|
||||
s = esets[i].find_next(s)) {
|
||||
if (alpha_remap[s] != leader_s) {
|
||||
t.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (t.any() && t != esets[i]) {
|
||||
esets[i] &= ~t;
|
||||
esets.push_back(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alphasize = buildAlphabetFromEquivSets(esets, alpha, unalpha);
|
||||
}
|
||||
|
||||
bool isPrunable() const {
|
||||
if (!grey.highlanderPruneDFA || !rm) {
|
||||
DEBUG_PRINTF("disabled, or not managed reports\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(!nfas.empty());
|
||||
if (!generates_callbacks(nfas.front()->kind)) {
|
||||
DEBUG_PRINTF("doesn't generate callbacks\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collect all reports from all merge candidates.
|
||||
flat_set<ReportID> merge_reports;
|
||||
for (const auto &rdfa : nfas) {
|
||||
insert(&merge_reports, all_reports(*rdfa));
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("all reports: %s\n", as_string_list(merge_reports).c_str());
|
||||
|
||||
// Return true if they're all exhaustible with the same exhaustion key.
|
||||
u32 ekey = INVALID_EKEY;
|
||||
for (const auto &report_id : merge_reports) {
|
||||
const Report &r = rm->getReport(report_id);
|
||||
if (!isSimpleExhaustible(r)) {
|
||||
DEBUG_PRINTF("report %u not simple exhaustible\n", report_id);
|
||||
return false;
|
||||
}
|
||||
assert(r.ekey != INVALID_EKEY);
|
||||
if (ekey == INVALID_EKEY) {
|
||||
ekey = r.ekey;
|
||||
} else if (ekey != r.ekey) {
|
||||
DEBUG_PRINTF("two different ekeys, %u and %u\n", ekey, r.ekey);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("is prunable\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void transition(const StateSet &in, StateSet *next) {
|
||||
u16 t[ALPHABET_SIZE];
|
||||
|
||||
for (u32 i = 0; i < alphasize; i++) {
|
||||
next[i].resize(nfas.size());
|
||||
}
|
||||
|
||||
for (size_t j = 0, j_end = nfas.size(); j < j_end; j++) {
|
||||
getFullTransitionFromState(*nfas[j], in[j], t);
|
||||
for (u32 i = 0; i < alphasize; i++) {
|
||||
next[i][j] = t[unalpha[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const vector<StateSet> initial() {
|
||||
vector<StateSet> rv = {as};
|
||||
if (start_floating != DEAD_STATE && start_floating != start_anchored) {
|
||||
rv.push_back(fs);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
void reports_i(const StateSet &in, flat_set<ReportID> dstate::*r_set,
|
||||
flat_set<ReportID> &r) const {
|
||||
for (size_t i = 0, end = nfas.size(); i < end; i++) {
|
||||
const auto &rs = nfas[i]->states[in[i]].*r_set;
|
||||
insert(&r, rs);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void reports(const StateSet &in, flat_set<ReportID> &rv) const {
|
||||
reports_i(in, &dstate::reports, rv);
|
||||
}
|
||||
void reportsEod(const StateSet &in, flat_set<ReportID> &rv) const {
|
||||
reports_i(in, &dstate::reports_eod, rv);
|
||||
}
|
||||
|
||||
bool canPrune(const flat_set<ReportID> &test_reports) const {
|
||||
if (!grey.highlanderPruneDFA || !prunable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must all be external reports.
|
||||
assert(rm);
|
||||
for (const auto &report_id : test_reports) {
|
||||
if (!isExternalReport(rm->getReport(report_id))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** True if the minimization algorithm should be run after merging. */
|
||||
bool shouldMinimize() const {
|
||||
// We only need to run minimization if our merged DFAs shared a report.
|
||||
flat_set<ReportID> seen_reports;
|
||||
for (const auto &rdfa : nfas) {
|
||||
for (const auto &report_id : all_reports(*rdfa)) {
|
||||
if (!seen_reports.insert(report_id).second) {
|
||||
DEBUG_PRINTF("report %u in several dfas\n", report_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const ReportManager *rm;
|
||||
const Grey &grey;
|
||||
|
||||
vector<const raw_dfa *> nfas;
|
||||
vector<dstate_id_t> as;
|
||||
vector<dstate_id_t> fs;
|
||||
|
||||
bool prunable = false;
|
||||
|
||||
public:
|
||||
std::array<u16, ALPHABET_SIZE> alpha;
|
||||
std::array<u16, ALPHABET_SIZE> unalpha;
|
||||
u16 alphasize;
|
||||
StateSet dead;
|
||||
|
||||
u16 start_anchored;
|
||||
u16 start_floating;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
unique_ptr<raw_dfa> mergeTwoDfas(const raw_dfa *d1, const raw_dfa *d2,
|
||||
size_t max_states, const ReportManager *rm,
|
||||
const Grey &grey) {
|
||||
assert(d1 && d2);
|
||||
assert(d1->kind == d2->kind);
|
||||
assert(max_states <= MAX_DFA_STATES);
|
||||
|
||||
auto rdfa = ue2::make_unique<raw_dfa>(d1->kind);
|
||||
|
||||
Automaton_Merge autom(d1, d2, rm, grey);
|
||||
if (!determinise(autom, rdfa->states, max_states)) {
|
||||
rdfa->start_anchored = autom.start_anchored;
|
||||
rdfa->start_floating = autom.start_floating;
|
||||
rdfa->alpha_size = autom.alphasize;
|
||||
rdfa->alpha_remap = autom.alpha;
|
||||
DEBUG_PRINTF("merge succeeded, %zu states\n", rdfa->states.size());
|
||||
|
||||
if (autom.shouldMinimize()) {
|
||||
minimize_hopcroft(*rdfa, grey);
|
||||
DEBUG_PRINTF("minimized, %zu states\n", rdfa->states.size());
|
||||
}
|
||||
|
||||
return rdfa;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void mergeDfas(vector<unique_ptr<raw_dfa>> &dfas, size_t max_states,
|
||||
const ReportManager *rm, const Grey &grey) {
|
||||
assert(max_states <= MAX_DFA_STATES);
|
||||
|
||||
if (dfas.size() <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("before merging, we have %zu dfas\n", dfas.size());
|
||||
|
||||
queue<unique_ptr<raw_dfa>> q;
|
||||
for (auto &dfa : dfas) {
|
||||
q.push(move(dfa));
|
||||
}
|
||||
|
||||
// All DFAs are now on the queue, so we'll clear the vector and use it for
|
||||
// output from here.
|
||||
dfas.clear();
|
||||
|
||||
while (q.size() > 1) {
|
||||
// Attempt to merge the two front elements of the queue.
|
||||
unique_ptr<raw_dfa> d1 = move(q.front());
|
||||
q.pop();
|
||||
unique_ptr<raw_dfa> d2 = move(q.front());
|
||||
q.pop();
|
||||
|
||||
auto rdfa = mergeTwoDfas(d1.get(), d2.get(), max_states, rm, grey);
|
||||
if (rdfa) {
|
||||
q.push(move(rdfa));
|
||||
} else {
|
||||
DEBUG_PRINTF("failed to merge\n");
|
||||
// Put the larger of the two DFAs on the output list, retain the
|
||||
// smaller one on the queue for further merge attempts.
|
||||
if (d2->states.size() > d1->states.size()) {
|
||||
dfas.push_back(move(d2));
|
||||
q.push(move(d1));
|
||||
} else {
|
||||
dfas.push_back(move(d1));
|
||||
q.push(move(d2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!q.empty()) {
|
||||
dfas.push_back(move(q.front()));
|
||||
q.pop();
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("after merging, we have %zu dfas\n", dfas.size());
|
||||
}
|
||||
|
||||
unique_ptr<raw_dfa> mergeAllDfas(const vector<const raw_dfa *> &dfas,
|
||||
size_t max_states, const ReportManager *rm,
|
||||
const Grey &grey) {
|
||||
assert(max_states <= MAX_DFA_STATES);
|
||||
assert(!dfas.empty());
|
||||
|
||||
// All the DFAs should be of the same kind.
|
||||
const auto kind = dfas.front()->kind;
|
||||
assert(all_of(begin(dfas), end(dfas),
|
||||
[&kind](const raw_dfa *rdfa) { return rdfa->kind == kind; }));
|
||||
|
||||
auto rdfa = ue2::make_unique<raw_dfa>(kind);
|
||||
Automaton_Merge n(dfas, rm, grey);
|
||||
|
||||
DEBUG_PRINTF("merging dfa\n");
|
||||
|
||||
if (determinise(n, rdfa->states, max_states)) {
|
||||
DEBUG_PRINTF("state limit (%zu) exceeded\n", max_states);
|
||||
return nullptr; /* over state limit */
|
||||
}
|
||||
|
||||
rdfa->start_anchored = n.start_anchored;
|
||||
rdfa->start_floating = n.start_floating;
|
||||
rdfa->alpha_size = n.alphasize;
|
||||
rdfa->alpha_remap = n.alpha;
|
||||
|
||||
DEBUG_PRINTF("merged, building impl dfa (a,f) = (%hu,%hu)\n",
|
||||
rdfa->start_anchored, rdfa->start_floating);
|
||||
|
||||
if (n.shouldMinimize()) {
|
||||
minimize_hopcroft(*rdfa, grey);
|
||||
DEBUG_PRINTF("minimized, %zu states\n", rdfa->states.size());
|
||||
}
|
||||
|
||||
return rdfa;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
62
src/nfa/rdfa_merge.h
Normal file
62
src/nfa/rdfa_merge.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Merge code for McClellan DFA.
|
||||
*/
|
||||
|
||||
#ifndef RDFA_MERGE_H
|
||||
#define RDFA_MERGE_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
class ReportManager;
|
||||
struct raw_dfa;
|
||||
struct Grey;
|
||||
|
||||
/** \brief Attempts to merge two raw_dfas into one. */
|
||||
std::unique_ptr<raw_dfa> mergeTwoDfas(const raw_dfa *d1, const raw_dfa *d2,
|
||||
size_t max_states, const ReportManager *rm,
|
||||
const Grey &grey);
|
||||
|
||||
/** \brief Attempts to merge all the given raw_dfas into one. */
|
||||
std::unique_ptr<raw_dfa> mergeAllDfas(const std::vector<const raw_dfa *> &dfas,
|
||||
size_t max_states,
|
||||
const ReportManager *rm,
|
||||
const Grey &grey);
|
||||
|
||||
/** \brief Merges the given list of raw_dfas as much as possible in-place. */
|
||||
void mergeDfas(std::vector<std::unique_ptr<raw_dfa>> &dfas, size_t max_states,
|
||||
const ReportManager *rm, const Grey &grey);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // RDFA_MERGE_H
|
||||
1553
src/nfa/repeat.c
Normal file
1553
src/nfa/repeat.c
Normal file
File diff suppressed because it is too large
Load Diff
361
src/nfa/repeat.h
Normal file
361
src/nfa/repeat.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 API for handling bounded repeats.
|
||||
*
|
||||
* This file provides an internal API for handling bounded repeats of character
|
||||
* classes. It is used by the Large Bounded Repeat (LBR) engine and by the
|
||||
* bounded repeat handling in the LimEx NFA engine as well.
|
||||
*
|
||||
* The state required by these functions is split into two regions:
|
||||
*
|
||||
* 1. Control block. This is a small structure (size varies with repeat mode)
|
||||
* that may be copied around or compressed into stream state.
|
||||
* 2. Repeat state. This is a larger structure that can be quite big for large
|
||||
* repeats, often containing a multibit ring or large vector of indices.
|
||||
* This generally lives in stream state and is not copied.
|
||||
*/
|
||||
|
||||
#ifndef REPEAT_H
|
||||
#define REPEAT_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "repeat_internal.h"
|
||||
#include "util/bitutils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** Returns the offset of the most recent 'top' offset set in the repeat. */
|
||||
static really_inline
|
||||
u64a repeatLastTop(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, const void *state);
|
||||
|
||||
/** Returns the offset of the next match after 'offset', or zero if no further
|
||||
* matches are possible. */
|
||||
static really_inline
|
||||
u64a repeatNextMatch(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, const void *state,
|
||||
u64a offset);
|
||||
|
||||
/** Stores a new top in the repeat. If is_alive is false, the repeat will be
|
||||
* initialised first and this top will become the first (and only) one. */
|
||||
static really_inline
|
||||
void repeatStore(const struct RepeatInfo *info, union RepeatControl *ctrl,
|
||||
void *state, u64a offset, char is_alive);
|
||||
|
||||
/** Return type for repeatHasMatch. */
|
||||
enum RepeatMatch {
|
||||
REPEAT_NOMATCH, /**< This offset is not a valid match. */
|
||||
REPEAT_MATCH, /**< This offset is a valid match. */
|
||||
REPEAT_STALE /**< This offset is not a valid match and no greater
|
||||
offset will be (unless another top is stored). */
|
||||
};
|
||||
|
||||
/** Query whether the repeat has a match at the given offset. Returns
|
||||
* ::REPEAT_STALE if it does not have a match at that offset _and_
|
||||
* no further matches are possible. */
|
||||
static really_inline
|
||||
enum RepeatMatch repeatHasMatch(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
/** \brief Serialize a packed version of the repeat control block into stream
|
||||
* state. */
|
||||
void repeatPack(char *dest, const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, u64a offset);
|
||||
|
||||
/** \brief Deserialize a packed version of the repeat control block. */
|
||||
void repeatUnpack(const char *src, const struct RepeatInfo *info, u64a offset,
|
||||
union RepeatControl *ctrl);
|
||||
|
||||
////
|
||||
//// IMPLEMENTATION.
|
||||
////
|
||||
|
||||
u64a repeatLastTopRing(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl);
|
||||
|
||||
u64a repeatLastTopRange(const union RepeatControl *ctrl,
|
||||
const void *state);
|
||||
|
||||
u64a repeatLastTopBitmap(const union RepeatControl *ctrl);
|
||||
|
||||
u64a repeatLastTopTrailer(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl);
|
||||
|
||||
u64a repeatLastTopSparseOptimalP(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state);
|
||||
|
||||
static really_inline
|
||||
u64a repeatLastTop(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, const void *state) {
|
||||
assert(info && ctrl && state);
|
||||
|
||||
switch ((enum RepeatType)info->type) {
|
||||
case REPEAT_RING:
|
||||
return repeatLastTopRing(info, ctrl);
|
||||
case REPEAT_FIRST:
|
||||
case REPEAT_LAST:
|
||||
return ctrl->offset.offset;
|
||||
case REPEAT_RANGE:
|
||||
return repeatLastTopRange(ctrl, state);
|
||||
case REPEAT_BITMAP:
|
||||
return repeatLastTopBitmap(ctrl);
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
return repeatLastTopSparseOptimalP(info, ctrl, state);
|
||||
case REPEAT_TRAILER:
|
||||
return repeatLastTopTrailer(info, ctrl);
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("bad repeat type %u\n", info->type);
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Used for both FIRST and LAST models.
|
||||
static really_inline
|
||||
u64a repeatNextMatchOffset(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, u64a offset) {
|
||||
u64a first = ctrl->offset.offset + info->repeatMin;
|
||||
if (offset < first) {
|
||||
return first;
|
||||
}
|
||||
|
||||
if (info->repeatMax == REPEAT_INF ||
|
||||
offset < ctrl->offset.offset + info->repeatMax) {
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
return 0; // No more matches.
|
||||
}
|
||||
|
||||
u64a repeatNextMatchRing(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
u64a repeatNextMatchRange(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
u64a repeatNextMatchBitmap(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, u64a offset);
|
||||
|
||||
u64a repeatNextMatchSparseOptimalP(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
u64a repeatNextMatchTrailer(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, u64a offset);
|
||||
|
||||
static really_inline
|
||||
u64a repeatNextMatch(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl, const void *state,
|
||||
u64a offset) {
|
||||
assert(info && ctrl && state);
|
||||
assert(ISALIGNED(info));
|
||||
assert(ISALIGNED(ctrl));
|
||||
|
||||
switch ((enum RepeatType)info->type) {
|
||||
case REPEAT_RING:
|
||||
return repeatNextMatchRing(info, ctrl, state, offset);
|
||||
case REPEAT_FIRST:
|
||||
// fall through
|
||||
case REPEAT_LAST:
|
||||
return repeatNextMatchOffset(info, ctrl, offset);
|
||||
case REPEAT_RANGE:
|
||||
return repeatNextMatchRange(info, ctrl, state, offset);
|
||||
case REPEAT_BITMAP:
|
||||
return repeatNextMatchBitmap(info, ctrl, offset);
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
return repeatNextMatchSparseOptimalP(info, ctrl, state, offset);
|
||||
case REPEAT_TRAILER:
|
||||
return repeatNextMatchTrailer(info, ctrl, offset);
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("bad repeat type %u\n", info->type);
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void repeatStoreFirst(union RepeatControl *ctrl, u64a offset,
|
||||
char is_alive) {
|
||||
if (is_alive) {
|
||||
return;
|
||||
}
|
||||
ctrl->offset.offset = offset;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
void repeatStoreLast(union RepeatControl *ctrl, u64a offset,
|
||||
UNUSED char is_alive) {
|
||||
assert(!is_alive || offset >= ctrl->offset.offset);
|
||||
ctrl->offset.offset = offset;
|
||||
}
|
||||
|
||||
void repeatStoreRing(const struct RepeatInfo *info,
|
||||
union RepeatControl *ctrl, void *state, u64a offset,
|
||||
char is_alive);
|
||||
|
||||
void repeatStoreRange(const struct RepeatInfo *info,
|
||||
union RepeatControl *ctrl, void *state, u64a offset,
|
||||
char is_alive);
|
||||
|
||||
void repeatStoreBitmap(const struct RepeatInfo *info,
|
||||
union RepeatControl *ctrl, u64a offset,
|
||||
char is_alive);
|
||||
|
||||
void repeatStoreSparseOptimalP(const struct RepeatInfo *info,
|
||||
union RepeatControl *ctrl, void *state,
|
||||
u64a offset, char is_alive);
|
||||
|
||||
void repeatStoreTrailer(const struct RepeatInfo *info,
|
||||
union RepeatControl *ctrl, u64a offset,
|
||||
char is_alive);
|
||||
|
||||
static really_inline
|
||||
void repeatStore(const struct RepeatInfo *info, union RepeatControl *ctrl,
|
||||
void *state, u64a offset, char is_alive) {
|
||||
assert(info && ctrl && state);
|
||||
assert(ISALIGNED(info));
|
||||
assert(ISALIGNED(ctrl));
|
||||
|
||||
assert(info->repeatMin <= info->repeatMax);
|
||||
assert(info->repeatMax <= REPEAT_INF);
|
||||
|
||||
switch ((enum RepeatType)info->type) {
|
||||
case REPEAT_RING:
|
||||
repeatStoreRing(info, ctrl, state, offset, is_alive);
|
||||
break;
|
||||
case REPEAT_FIRST:
|
||||
repeatStoreFirst(ctrl, offset, is_alive);
|
||||
break;
|
||||
case REPEAT_LAST:
|
||||
repeatStoreLast(ctrl, offset, is_alive);
|
||||
break;
|
||||
case REPEAT_RANGE:
|
||||
repeatStoreRange(info, ctrl, state, offset, is_alive);
|
||||
break;
|
||||
case REPEAT_BITMAP:
|
||||
repeatStoreBitmap(info, ctrl, offset, is_alive);
|
||||
break;
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
repeatStoreSparseOptimalP(info, ctrl, state, offset, is_alive);
|
||||
break;
|
||||
case REPEAT_TRAILER:
|
||||
repeatStoreTrailer(info, ctrl, offset, is_alive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static really_inline
|
||||
enum RepeatMatch repeatHasMatchFirst(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
u64a offset) {
|
||||
if (offset < ctrl->offset.offset + info->repeatMin) {
|
||||
return REPEAT_NOMATCH;
|
||||
}
|
||||
|
||||
// FIRST models are {N,} repeats, i.e. they always have inf max depth.
|
||||
assert(info->repeatMax == REPEAT_INF);
|
||||
return REPEAT_MATCH;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
enum RepeatMatch repeatHasMatchLast(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
u64a offset) {
|
||||
if (offset < ctrl->offset.offset + info->repeatMin) {
|
||||
return REPEAT_NOMATCH;
|
||||
}
|
||||
assert(info->repeatMax < REPEAT_INF);
|
||||
if (offset <= ctrl->offset.offset + info->repeatMax) {
|
||||
return REPEAT_MATCH;
|
||||
}
|
||||
return REPEAT_STALE;
|
||||
}
|
||||
|
||||
enum RepeatMatch repeatHasMatchRing(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
enum RepeatMatch repeatHasMatchRange(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
enum RepeatMatch repeatHasMatchSparseOptimalP(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset);
|
||||
|
||||
enum RepeatMatch repeatHasMatchBitmap(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
u64a offset);
|
||||
|
||||
enum RepeatMatch repeatHasMatchTrailer(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
u64a offset);
|
||||
|
||||
static really_inline
|
||||
enum RepeatMatch repeatHasMatch(const struct RepeatInfo *info,
|
||||
const union RepeatControl *ctrl,
|
||||
const void *state, u64a offset) {
|
||||
assert(info && ctrl && state);
|
||||
assert(ISALIGNED(info));
|
||||
assert(ISALIGNED(ctrl));
|
||||
|
||||
switch ((enum RepeatType)info->type) {
|
||||
case REPEAT_RING:
|
||||
return repeatHasMatchRing(info, ctrl, state, offset);
|
||||
case REPEAT_FIRST:
|
||||
return repeatHasMatchFirst(info, ctrl, offset);
|
||||
case REPEAT_LAST:
|
||||
return repeatHasMatchLast(info, ctrl, offset);
|
||||
case REPEAT_RANGE:
|
||||
return repeatHasMatchRange(info, ctrl, state, offset);
|
||||
case REPEAT_BITMAP:
|
||||
return repeatHasMatchBitmap(info, ctrl, offset);
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
return repeatHasMatchSparseOptimalP(info, ctrl, state, offset);
|
||||
case REPEAT_TRAILER:
|
||||
return repeatHasMatchTrailer(info, ctrl, offset);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return REPEAT_NOMATCH;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // REPEAT_H
|
||||
212
src/nfa/repeat_internal.h
Normal file
212
src/nfa/repeat_internal.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef REPEAT_INTERNAL_H
|
||||
#define REPEAT_INTERNAL_H
|
||||
|
||||
#include "ue2common.h"
|
||||
|
||||
/** \file
|
||||
* \brief Bounded Repeat models.
|
||||
*
|
||||
* Used by the NFA, to represent bounded repeats managed via special POS and
|
||||
* TUG exceptions, and by the LBR (limited bounded repeat) and Castle
|
||||
* specialist engines.
|
||||
*
|
||||
* We currently have a number of different kinds of bounded repeat model, for
|
||||
* different kinds of {N,M} repeats, described by ::RepeatType.
|
||||
*/
|
||||
|
||||
/** Different types of bounded repeats. */
|
||||
enum RepeatType {
|
||||
/** General mechanism for tracking {N,M} repeats. Stores the first top as
|
||||
* an absolute offset, then subsequent tops in the {N,M} range as a ring of
|
||||
* relative top indices stored in a multibit. */
|
||||
REPEAT_RING = 0,
|
||||
|
||||
/** Used to track {N,} repeats. Uses the \ref RepeatOffsetControl structure,
|
||||
* since only the first top encountered needs to be stored. */
|
||||
REPEAT_FIRST = 1,
|
||||
|
||||
/** Used to track {0,N} repeats. Much like ::REPEAT_FIRST, except that we
|
||||
* store the most recent top encountered. */
|
||||
REPEAT_LAST = 2,
|
||||
|
||||
/** Like ::REPEAT_RING, this is also used for {N,M} repeats, but for cases
|
||||
* where there is a large difference between N and M, and developed to
|
||||
* reduce the state requirements of this case (relative to the RING model).
|
||||
* Uses a small ordered array of top indices relative to \ref
|
||||
* RepeatRangeControl::offset. */
|
||||
REPEAT_RANGE = 3,
|
||||
|
||||
/** Used for {N,M} repeats where 0 < M <= 64. Uses the \ref
|
||||
* RepeatBitmapControl structure at runtime. */
|
||||
REPEAT_BITMAP = 4,
|
||||
|
||||
/** Optimal mechanism for tracking {N,M} repeats when there is a bound on
|
||||
* how frequently they can be retriggered.
|
||||
* Assume f(repeat, min) representing the number of possible bit patterns
|
||||
* we can have for repeat size = repeat, minimum period = min
|
||||
* We will have the following recurrence relation:
|
||||
* f(repeat, min) = f(repeat - 1, min) + f(repeat - min, min);
|
||||
* We use this recurrence to encode bit patterns with 64-bit values by
|
||||
* referencing a table that stores values from f(0, min) to f(repeat, min)
|
||||
* eg: repeat = 5, min = 2. 10001 => f(4,2) + f(0,2) = 9.
|
||||
* We search the optimal patch size between min and repeat in advance and
|
||||
* use the scheme above to do encoding and decoding to reduce stream state size
|
||||
* */
|
||||
REPEAT_SPARSE_OPTIMAL_P = 5,
|
||||
|
||||
/** Used for {N,M} repeats where 0 < N < 64. Uses the \ref RepeatTrailerControl
|
||||
* structure at runtime. */
|
||||
REPEAT_TRAILER = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Value used to represent an unbounded max repeat.
|
||||
*
|
||||
* Note that we do not support \ref RepeatInfo::repeatMax values larger than
|
||||
* this.
|
||||
*/
|
||||
#define REPEAT_INF 65535
|
||||
|
||||
/** Max slots used by ::REPEAT_RANGE repeat model. */
|
||||
#define REPEAT_RANGE_MAX_SLOTS 16
|
||||
|
||||
/** Structure describing a bounded repeat in the bytecode */
|
||||
struct RepeatInfo {
|
||||
u8 type; //!< from enum RepeatType.
|
||||
u32 repeatMin; //!< minimum number of repeats.
|
||||
u32 repeatMax; //!< maximum number of repeats, or REPEAT_INF if unbounded.
|
||||
|
||||
/** Maximum value that is required to be stored in the control block
|
||||
* counters. Any value greater than this will be capped at the horizon.
|
||||
*/
|
||||
u32 horizon;
|
||||
|
||||
/** Size of the compressed control block in bytes. This is what is written
|
||||
* out to stream state at stream boundaries. */
|
||||
u32 packedCtrlSize;
|
||||
|
||||
/** Size of the repeat state block in bytes. This is where the REPEAT_RANGE
|
||||
* vector and REPEAT_RING multibit are stored, in stream state, and they
|
||||
* are manipulated directly (i.e. not copied at stream boundaries). */
|
||||
u32 stateSize;
|
||||
|
||||
/** How soon after one trigger we can see the next trigger.
|
||||
* Used by REPEAT_SPARSE_OPTIMAL_P. */
|
||||
u32 minPeriod;
|
||||
|
||||
/** Packed control block field sizes (in bits), used by REPEAT_TRAILER. */
|
||||
u32 packedFieldSizes[2];
|
||||
|
||||
/* Number of patches, used by REPEAT_SPARSE_OPTIMAL_P. */
|
||||
u32 patchCount;
|
||||
|
||||
/* Optimal patch length, used by REPEAT_SPARSE_OPTIMAL_P. */
|
||||
u32 patchSize;
|
||||
|
||||
/* Encoding patch length in bytes, used by REPEAT_SPARSE_OPTIMAL_P. */
|
||||
u32 encodingSize;
|
||||
|
||||
/* RepeatInfo struct length including table size. */
|
||||
u32 length;
|
||||
|
||||
/** Offset of patches relative to the start of repeat stream state,
|
||||
* used by REPEAT_SPARSE_OPTIMAL_P. */
|
||||
u32 patchesOffset;
|
||||
};
|
||||
|
||||
/** Runtime control block structure for ::REPEAT_RING and
|
||||
* ::REPEAT_SPARSE_OPTIMAL_P bounded repeats. Note that this struct is packed
|
||||
* (may not be aligned). */
|
||||
struct RepeatRingControl {
|
||||
u64a offset; //!< index of first top.
|
||||
u16 first; //!< start index in ring.
|
||||
u16 last; //!< end index in ring.
|
||||
};
|
||||
|
||||
/** Runtime control block structure for ::REPEAT_RANGE bounded repeats. Note
|
||||
* that this struct is packed (may not be aligned). */
|
||||
struct RepeatRangeControl {
|
||||
u64a offset; //!< index of first top.
|
||||
u8 num; //!< number of elements in array.
|
||||
};
|
||||
|
||||
/** Runtime control block structure for cases where only a single offset is
|
||||
* needed to track the repeat, both ::REPEAT_FIRST and ::REPEAT_LAST. Note that
|
||||
* this struct is packed (may not be aligned). */
|
||||
struct RepeatOffsetControl {
|
||||
u64a offset; //!< index of a top.
|
||||
};
|
||||
|
||||
/** Runtime control block structure for ::REPEAT_BITMAP bounded repeats. */
|
||||
struct RepeatBitmapControl {
|
||||
u64a offset; //!< index of first top.
|
||||
u64a bitmap; //!< forward bitmap of tops relative to base offset.
|
||||
};
|
||||
|
||||
/** Runtime control block structure for ::REPEAT_TRAILER bounded repeats. */
|
||||
struct RepeatTrailerControl {
|
||||
u64a offset; //!< min extent of most recent match window.
|
||||
u64a bitmap; //!< trailing bitmap of earlier matches, relative to offset.
|
||||
};
|
||||
|
||||
/** \brief Union of control block types, used at runtime. */
|
||||
union RepeatControl {
|
||||
struct RepeatRingControl ring;
|
||||
struct RepeatRangeControl range;
|
||||
struct RepeatOffsetControl offset;
|
||||
struct RepeatBitmapControl bitmap;
|
||||
struct RepeatTrailerControl trailer;
|
||||
};
|
||||
|
||||
/** For debugging, returns the name of a repeat model. */
|
||||
static really_inline UNUSED
|
||||
const char *repeatTypeName(u8 type) {
|
||||
switch ((enum RepeatType)type) {
|
||||
case REPEAT_RING:
|
||||
return "RING";
|
||||
case REPEAT_FIRST:
|
||||
return "FIRST";
|
||||
case REPEAT_LAST:
|
||||
return "LAST";
|
||||
case REPEAT_RANGE:
|
||||
return "RANGE";
|
||||
case REPEAT_BITMAP:
|
||||
return "BITMAP";
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
return "SPARSE_OPTIMAL_P";
|
||||
case REPEAT_TRAILER:
|
||||
return "TRAILER";
|
||||
}
|
||||
assert(0);
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
#endif // REPEAT_INTERNAL_H
|
||||
374
src/nfa/repeatcompile.cpp
Normal file
374
src/nfa/repeatcompile.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Bounded repeat compile-time code.
|
||||
*/
|
||||
#include "repeatcompile.h"
|
||||
#include "util/bitutils.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/depth.h"
|
||||
#include "util/dump_charclass.h"
|
||||
#include "util/multibit_internal.h"
|
||||
#include "util/verify_types.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring> // memset
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
/** \brief Calculate the number of slots required to store the given repeat in
|
||||
* a RANGE model. */
|
||||
static
|
||||
u32 numRangeSlots(u32 repeatMin, u32 repeatMax) {
|
||||
assert(repeatMax > repeatMin);
|
||||
|
||||
u32 d = repeatMax - repeatMin;
|
||||
u32 slots = 2 * ((repeatMax / d) + 1);
|
||||
return slots;
|
||||
}
|
||||
|
||||
static
|
||||
u32 calcPackedBits(u64a val) {
|
||||
assert(val);
|
||||
if (val <= 1) {
|
||||
return 1;
|
||||
}
|
||||
u32 bits = lg2_64(val - 1) + 1U; /* lg2 rounds down */
|
||||
DEBUG_PRINTF("packing %llu into %u bits\n", val, bits);
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* returns the min number of bytes required to represent val options */
|
||||
u32 calcPackedBytes(u64a val) {
|
||||
u32 rv = (calcPackedBits(val) + 7U) / 8U;
|
||||
DEBUG_PRINTF("packing %llu into %u bytes\n", val, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
u64a repeatRecurTable(struct RepeatStateInfo *info, const depth &repeatMax,
|
||||
const u32 minPeriod) {
|
||||
u32 repeatTmp = info->patchCount > 2 ? 64 : (u32)repeatMax;
|
||||
u32 repeat_index = repeatTmp < minPeriod ? repeatTmp : minPeriod;
|
||||
for (u32 i = 0; i <= repeat_index; i++) {
|
||||
info->table.push_back(i + 1);
|
||||
}
|
||||
for (u32 i = minPeriod + 1; i <= repeatTmp; i++) {
|
||||
info->table.push_back(info->table[i - 1] + info->table[i - minPeriod]);
|
||||
if (info->table[i] < info->table[i - 1]) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
u32 findOptimalPatchSize(struct RepeatStateInfo *info, const depth &repeatMax,
|
||||
const u32 minPeriod, u64a rv) {
|
||||
u32 cnt = 0;
|
||||
u32 patch_bits = 0;
|
||||
u32 total_size = 0;
|
||||
u32 min = ~0U;
|
||||
u32 patch_len = 0;
|
||||
|
||||
if (!rv) {
|
||||
rv = repeatMax;
|
||||
}
|
||||
|
||||
for (u32 i = minPeriod; i <= rv; i++) {
|
||||
cnt = ((u32)repeatMax + (i - 1)) / i + 1;
|
||||
|
||||
// no bit packing version
|
||||
patch_bits = calcPackedBits(info->table[i]);
|
||||
total_size = (patch_bits + 7U) / 8U * cnt;
|
||||
|
||||
if (total_size < min) {
|
||||
patch_len = i;
|
||||
min = total_size;
|
||||
info->patchCount = cnt;
|
||||
}
|
||||
}
|
||||
return patch_len;
|
||||
}
|
||||
|
||||
RepeatStateInfo::RepeatStateInfo(enum RepeatType type, const depth &repeatMin,
|
||||
const depth &repeatMax, u32 minPeriod)
|
||||
: stateSize(0), packedCtrlSize(0), horizon(0), patchCount(0),
|
||||
patchSize(0), encodingSize(0), patchesOffset(0) {
|
||||
assert(repeatMin <= repeatMax);
|
||||
assert(repeatMax.is_reachable());
|
||||
assert(minPeriod || type != REPEAT_SPARSE_OPTIMAL_P);
|
||||
|
||||
switch (type) {
|
||||
case REPEAT_FIRST:
|
||||
assert(repeatMin.is_finite());
|
||||
stateSize = 0; // everything is in the control block.
|
||||
horizon = repeatMin;
|
||||
packedCtrlSize = calcPackedBytes(horizon + 1);
|
||||
break;
|
||||
case REPEAT_LAST:
|
||||
assert(repeatMax.is_finite());
|
||||
stateSize = 0; // everything is in the control block.
|
||||
horizon = repeatMax + 1;
|
||||
packedCtrlSize = calcPackedBytes(horizon + 1);
|
||||
break;
|
||||
case REPEAT_RING:
|
||||
assert(repeatMax.is_finite());
|
||||
stateSize = mmbit_size(repeatMax + 1);
|
||||
horizon = repeatMax * 2 + 1; /* TODO: investigate tightening */
|
||||
// Packed offset member, plus two bytes for each ring index, reduced to
|
||||
// one byte each if they'll fit in eight bits.
|
||||
{
|
||||
u32 offset_len = calcPackedBytes(horizon + 1);
|
||||
u32 ring_indices_len = repeatMax < depth(254) ? 2 : 4;
|
||||
packedCtrlSize = offset_len + ring_indices_len;
|
||||
}
|
||||
break;
|
||||
case REPEAT_RANGE:
|
||||
assert(repeatMax.is_finite());
|
||||
assert(repeatMin < repeatMax);
|
||||
stateSize = numRangeSlots(repeatMin, repeatMax) * sizeof(u16);
|
||||
horizon = repeatMax * 2 + 1;
|
||||
// Packed offset member, plus one byte for the number of range
|
||||
// elements.
|
||||
packedCtrlSize = calcPackedBytes(horizon + 1) + 1;
|
||||
break;
|
||||
case REPEAT_BITMAP:
|
||||
stateSize = 0; // everything is in the control block.
|
||||
horizon = 0; // unused
|
||||
packedCtrlSize = ROUNDUP_N(repeatMax + 1, 8) / 8;
|
||||
break;
|
||||
case REPEAT_SPARSE_OPTIMAL_P:
|
||||
assert(minPeriod);
|
||||
assert(repeatMax.is_finite());
|
||||
{
|
||||
u64a rv = repeatRecurTable(this, repeatMax, minPeriod);
|
||||
u32 repeatTmp = 0;
|
||||
if ((u32)repeatMax < minPeriod) {
|
||||
repeatTmp = repeatMax;
|
||||
patchCount = 1;
|
||||
} else {
|
||||
// find optimal patch size
|
||||
repeatTmp =
|
||||
findOptimalPatchSize(this, repeatMax, minPeriod, rv);
|
||||
assert(patchCount < 65536);
|
||||
}
|
||||
DEBUG_PRINTF("repeat[%u %u], period=%u\n", (u32)repeatMin,
|
||||
(u32)repeatMax, minPeriod);
|
||||
u64a maxVal = table[repeatTmp];
|
||||
encodingSize = calcPackedBytes(maxVal);
|
||||
patchSize = repeatTmp;
|
||||
assert(encodingSize <= 64);
|
||||
|
||||
patchesOffset = mmbit_size(patchCount);
|
||||
stateSize = patchesOffset + encodingSize * patchCount;
|
||||
horizon = (repeatTmp * patchCount) * 2 + 1;
|
||||
u32 ring_indices_len = patchCount < depth(254) ? 2 : 4;
|
||||
packedCtrlSize = calcPackedBytes(horizon + 1) + ring_indices_len;
|
||||
}
|
||||
break;
|
||||
case REPEAT_TRAILER:
|
||||
assert(repeatMax.is_finite());
|
||||
assert(repeatMin <= depth(64));
|
||||
stateSize = 0; // everything is in the control block.
|
||||
horizon = repeatMax + 1;
|
||||
packedFieldSizes.resize(2);
|
||||
packedFieldSizes[0] = calcPackedBits(horizon + 1);
|
||||
packedFieldSizes[1] = repeatMin;
|
||||
packedCtrlSize = (packedFieldSizes[0] + packedFieldSizes[1] + 7U) / 8U;
|
||||
break;
|
||||
}
|
||||
DEBUG_PRINTF("stateSize=%u, packedCtrlSize=%u, horizon=%u\n", stateSize,
|
||||
packedCtrlSize, horizon);
|
||||
|
||||
assert(packedCtrlSize <= sizeof(RepeatControl));
|
||||
}
|
||||
|
||||
/** \brief Returns the packed control block size in bytes for a given bounded
|
||||
* repeat. */
|
||||
static
|
||||
u32 packedSize(enum RepeatType type, const depth &repeatMin,
|
||||
const depth &repeatMax, u32 minPeriod) {
|
||||
RepeatStateInfo rsi(type, repeatMin, repeatMax, minPeriod);
|
||||
return rsi.packedCtrlSize;
|
||||
}
|
||||
|
||||
/** \brief Returns the stream state size in bytes for a given bounded
|
||||
* repeat. */
|
||||
static
|
||||
u32 streamStateSize(enum RepeatType type, const depth &repeatMin,
|
||||
const depth &repeatMax, u32 minPeriod) {
|
||||
RepeatStateInfo rsi(type, repeatMin, repeatMax, minPeriod);
|
||||
return rsi.stateSize;
|
||||
}
|
||||
|
||||
enum RepeatType chooseRepeatType(const depth &repeatMin, const depth &repeatMax,
|
||||
u32 minPeriod, bool is_reset) {
|
||||
if (repeatMax.is_infinite()) {
|
||||
return REPEAT_FIRST;
|
||||
}
|
||||
|
||||
if (repeatMin == depth(0) || is_reset) {
|
||||
return REPEAT_LAST;
|
||||
}
|
||||
|
||||
// Cases with max < 64 can be handled with either bitmap or trailer. We use
|
||||
// whichever has smaller packed state.
|
||||
|
||||
if (repeatMax < depth(64)) {
|
||||
u32 bitmap_len =
|
||||
packedSize(REPEAT_BITMAP, repeatMin, repeatMax, minPeriod);
|
||||
u32 trailer_len =
|
||||
packedSize(REPEAT_TRAILER, repeatMin, repeatMax, minPeriod);
|
||||
return bitmap_len <= trailer_len ? REPEAT_BITMAP : REPEAT_TRAILER;
|
||||
}
|
||||
|
||||
if (repeatMin <= depth(64)) {
|
||||
return REPEAT_TRAILER;
|
||||
}
|
||||
|
||||
u32 range_len = ~0U;
|
||||
if (repeatMax > repeatMin &&
|
||||
numRangeSlots(repeatMin, repeatMax) <= REPEAT_RANGE_MAX_SLOTS) {
|
||||
assert(numRangeSlots(repeatMin, repeatMax) < 256); // stored in u8
|
||||
range_len =
|
||||
streamStateSize(REPEAT_RANGE, repeatMin, repeatMax, minPeriod);
|
||||
}
|
||||
|
||||
assert(repeatMax.is_finite());
|
||||
|
||||
u32 sparse_len = ~0U;
|
||||
if (minPeriod > 6) {
|
||||
sparse_len =
|
||||
streamStateSize(REPEAT_SPARSE_OPTIMAL_P, repeatMin, repeatMax, minPeriod);
|
||||
}
|
||||
|
||||
if (range_len != ~0U || sparse_len != ~0U) {
|
||||
return range_len < sparse_len ? REPEAT_RANGE : REPEAT_SPARSE_OPTIMAL_P;
|
||||
}
|
||||
|
||||
return REPEAT_RING;
|
||||
}
|
||||
|
||||
bool matches(vector<CharReach>::const_iterator a_it,
|
||||
vector<CharReach>::const_iterator a_ite,
|
||||
vector<CharReach>::const_iterator b_it,
|
||||
UNUSED vector<CharReach>::const_iterator b_ite) {
|
||||
for (; a_it != a_ite; ++a_it, ++b_it) {
|
||||
assert(b_it != b_ite);
|
||||
if ((*a_it & *b_it).none()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(b_it == b_ite);
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
u32 minDistAfterA(const vector<CharReach> &a, const vector<CharReach> &b) {
|
||||
/* we do not count the case where b can end at the same position as a */
|
||||
|
||||
for (u32 i = 1; i < b.size(); i++) {
|
||||
u32 overlap_len = b.size() - i;
|
||||
if (overlap_len <= a.size()) {
|
||||
if (matches(a.end() - overlap_len, a.end(),
|
||||
b.begin(), b.end() - i)) {
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
assert(overlap_len > a.size());
|
||||
if (matches(a.begin(), a.end(),
|
||||
b.end() - i - a.size(), b.end() - i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return b.size();
|
||||
}
|
||||
|
||||
vector<size_t> minResetDistToEnd(const vector<vector<CharReach>> &triggers,
|
||||
const CharReach &cr) {
|
||||
/* if a trigger does not reset the repeat, it gets a distance of trigger
|
||||
length */
|
||||
vector<size_t> out;
|
||||
for (const auto &trig : triggers) {
|
||||
size_t size = trig.size();
|
||||
size_t i = 0;
|
||||
for (; i < size; i++) {
|
||||
if ((trig[size - i - 1] & cr).none()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.push_back(i);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(DUMP_SUPPORT)
|
||||
|
||||
static UNUSED
|
||||
string dumpTrigger(const vector<CharReach> &trigger) {
|
||||
string s;
|
||||
for (const auto &cr : trigger) {
|
||||
s += describeClass(cr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
u32 minPeriod(const vector<vector<CharReach>> &triggers, const CharReach &cr,
|
||||
bool *can_reset) {
|
||||
assert(!triggers.empty());
|
||||
|
||||
u32 rv = ~0U;
|
||||
*can_reset = true;
|
||||
vector<size_t> min_reset_dist = minResetDistToEnd(triggers, cr);
|
||||
|
||||
for (const auto &trigger : triggers) {
|
||||
DEBUG_PRINTF("trigger: %s\n", dumpTrigger(trigger).c_str());
|
||||
for (size_t j = 0; j < triggers.size(); j++) {
|
||||
u32 min_ext = minDistAfterA(trigger, triggers[j]);
|
||||
rv = min(rv, min_ext);
|
||||
if (min_ext <= min_reset_dist[j]) {
|
||||
*can_reset = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("min period %u\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
89
src/nfa/repeatcompile.h
Normal file
89
src/nfa/repeatcompile.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Bounded repeat compile-time code.
|
||||
*/
|
||||
|
||||
#ifndef REPEATCOMPILE_H
|
||||
#define REPEATCOMPILE_H
|
||||
|
||||
#include "repeat_internal.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
class CharReach;
|
||||
class depth;
|
||||
|
||||
/**
|
||||
* \brief Structure representing the various state requirements for a given
|
||||
* bounded repeat.
|
||||
*/
|
||||
struct RepeatStateInfo {
|
||||
RepeatStateInfo(enum RepeatType type, const depth &repeatMin,
|
||||
const depth &repeatMax, u32 minPeriod);
|
||||
|
||||
u32 stateSize;
|
||||
u32 packedCtrlSize;
|
||||
u32 horizon;
|
||||
u32 patchCount;
|
||||
u32 patchSize;
|
||||
u32 encodingSize;
|
||||
u32 patchesOffset;
|
||||
std::vector<u32> packedFieldSizes;
|
||||
std::vector<uint64_t> table; // not u64a, for boost/gcc-4.9
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Given the parameters of a repeat, choose a repeat implementation
|
||||
* type.
|
||||
*/
|
||||
enum RepeatType chooseRepeatType(const depth &repeatMin, const depth &repeatMax,
|
||||
u32 minPeriod, bool is_reset);
|
||||
|
||||
u32 calcPackedBytes(u64a val);
|
||||
|
||||
bool matches(std::vector<CharReach>::const_iterator a_it,
|
||||
std::vector<CharReach>::const_iterator a_ite,
|
||||
std::vector<CharReach>::const_iterator b_it,
|
||||
std::vector<CharReach>::const_iterator b_ite);
|
||||
|
||||
std::vector<size_t>
|
||||
minResetDistToEnd(const std::vector<std::vector<CharReach>> &triggers,
|
||||
const CharReach &cr);
|
||||
|
||||
u32 minPeriod(const std::vector<std::vector<CharReach>> &triggers,
|
||||
const CharReach &cr, bool *can_reset);
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // REPEATCOMPILE_H
|
||||
623
src/nfa/shufti.c
Normal file
623
src/nfa/shufti.c
Normal file
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Shufti: character class acceleration.
|
||||
*
|
||||
* Utilises the SSSE3 pshufb shuffle instruction
|
||||
*/
|
||||
|
||||
#include "shufti.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/bitutils.h"
|
||||
#include "util/simd_utils.h"
|
||||
#include "util/unaligned.h"
|
||||
|
||||
/** \brief Naive byte-by-byte implementation. */
|
||||
static really_inline
|
||||
const u8 *shuftiFwdSlow(const u8 *lo, const u8 *hi, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
assert(buf < buf_end);
|
||||
|
||||
for (; buf < buf_end; ++buf) {
|
||||
u8 c = *buf;
|
||||
if (lo[c & 0xf] & hi[c >> 4]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** \brief Naive byte-by-byte implementation. */
|
||||
static really_inline
|
||||
const u8 *shuftiRevSlow(const u8 *lo, const u8 *hi, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
assert(buf < buf_end);
|
||||
|
||||
for (buf_end--; buf_end >= buf; buf_end--) {
|
||||
u8 c = *buf_end;
|
||||
if (lo[c & 0xf] & hi[c >> 4]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buf_end;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <ctype.h>
|
||||
|
||||
#define DUMP_MSK(_t) \
|
||||
static UNUSED \
|
||||
void dumpMsk##_t(m##_t msk) { \
|
||||
u8 * mskAsU8 = (u8 *)&msk; \
|
||||
for (unsigned i = 0; i < sizeof(msk); i++) { \
|
||||
u8 c = mskAsU8[i]; \
|
||||
for (int j = 0; j < 8; j++) { \
|
||||
if ((c >> (7-j)) & 0x1) \
|
||||
printf("1"); \
|
||||
else \
|
||||
printf("0"); \
|
||||
} \
|
||||
printf(" "); \
|
||||
} \
|
||||
} \
|
||||
static UNUSED \
|
||||
void dumpMsk##_t##AsChars(m##_t msk) { \
|
||||
u8 * mskAsU8 = (u8 *)&msk; \
|
||||
for (unsigned i = 0; i < sizeof(msk); i++) { \
|
||||
u8 c = mskAsU8[i]; \
|
||||
if (isprint(c)) \
|
||||
printf("%c",c); \
|
||||
else \
|
||||
printf("."); \
|
||||
} \
|
||||
}
|
||||
|
||||
DUMP_MSK(128)
|
||||
#endif
|
||||
|
||||
#include "util/simd_utils_ssse3.h"
|
||||
|
||||
#if !defined(__AVX2__)
|
||||
/* Normal SSSE3 shufti */
|
||||
|
||||
#define GET_LO_4(chars) and128(chars, low4bits)
|
||||
#define GET_HI_4(chars) rshift2x64(andnot128(low4bits, chars), 4)
|
||||
|
||||
static really_inline
|
||||
const u8 *firstMatch(const u8 *buf, m128 t, m128 compare) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF("confirming match in:"); dumpMsk128(t); printf("\n");
|
||||
#endif
|
||||
|
||||
u32 z = movemask128(eq128(t, compare));
|
||||
if (unlikely(z != 0xffff)) {
|
||||
u32 pos = ctz32(~z & 0xffff);
|
||||
assert(pos < 16);
|
||||
return buf + pos;
|
||||
} else {
|
||||
return NULL; // no match
|
||||
}
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *fwdBlock(m128 mask_lo, m128 mask_hi, m128 chars, const u8 *buf,
|
||||
const m128 low4bits, const m128 zeroes) {
|
||||
m128 c_lo = pshufb(mask_lo, GET_LO_4(chars));
|
||||
m128 c_hi = pshufb(mask_hi, GET_HI_4(chars));
|
||||
m128 t = and128(c_lo, c_hi);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" chars: "); dumpMsk128AsChars(chars); printf("\n");
|
||||
DEBUG_PRINTF(" char: "); dumpMsk128(chars); printf("\n");
|
||||
DEBUG_PRINTF(" c_lo: "); dumpMsk128(c_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c_hi: "); dumpMsk128(c_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t: "); dumpMsk128(t); printf("\n");
|
||||
#endif
|
||||
|
||||
return firstMatch(buf, t, zeroes);
|
||||
}
|
||||
|
||||
const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
assert(buf && buf_end);
|
||||
assert(buf < buf_end);
|
||||
|
||||
// Slow path for small cases.
|
||||
if (buf_end - buf < 16) {
|
||||
return shuftiFwdSlow((const u8 *)&mask_lo, (const u8 *)&mask_hi,
|
||||
buf, buf_end);
|
||||
}
|
||||
|
||||
const m128 zeroes = zeroes128();
|
||||
const m128 low4bits = _mm_set1_epi8(0xf);
|
||||
const u8 *rv;
|
||||
|
||||
size_t min = (size_t)buf % 16;
|
||||
assert(buf_end - buf >= 16);
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m128 chars = loadu128(buf);
|
||||
rv = fwdBlock(mask_lo, mask_hi, chars, buf, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += (16 - min);
|
||||
|
||||
// Unrolling was here, but it wasn't doing anything but taking up space.
|
||||
// Reroll FTW.
|
||||
|
||||
const u8 *last_block = buf_end - 16;
|
||||
while (buf < last_block) {
|
||||
m128 lchars = load128(buf);
|
||||
rv = fwdBlock(mask_lo, mask_hi, lchars, buf, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += 16;
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 16 bytes and get an accurate
|
||||
// picture to buf_end.
|
||||
assert(buf <= buf_end && buf >= buf_end - 16);
|
||||
chars = loadu128(buf_end - 16);
|
||||
rv = fwdBlock(mask_lo, mask_hi, chars, buf_end - 16, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf_end;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *lastMatch(const u8 *buf, m128 t, m128 compare) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF("confirming match in:"); dumpMsk128(t); printf("\n");
|
||||
#endif
|
||||
|
||||
u32 z = movemask128(eq128(t, compare));
|
||||
if (unlikely(z != 0xffff)) {
|
||||
u32 pos = clz32(~z & 0xffff);
|
||||
DEBUG_PRINTF("buf=%p, pos=%u\n", buf, pos);
|
||||
assert(pos >= 16 && pos < 32);
|
||||
return buf + (31 - pos);
|
||||
} else {
|
||||
return NULL; // no match
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static really_inline
|
||||
const u8 *revBlock(m128 mask_lo, m128 mask_hi, m128 chars, const u8 *buf,
|
||||
const m128 low4bits, const m128 zeroes) {
|
||||
m128 c_lo = pshufb(mask_lo, GET_LO_4(chars));
|
||||
m128 c_hi = pshufb(mask_hi, GET_HI_4(chars));
|
||||
m128 t = and128(c_lo, c_hi);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" chars: "); dumpMsk128AsChars(chars); printf("\n");
|
||||
DEBUG_PRINTF(" char: "); dumpMsk128(chars); printf("\n");
|
||||
DEBUG_PRINTF(" c_lo: "); dumpMsk128(c_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c_hi: "); dumpMsk128(c_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t: "); dumpMsk128(t); printf("\n");
|
||||
#endif
|
||||
|
||||
return lastMatch(buf, t, zeroes);
|
||||
}
|
||||
|
||||
const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
assert(buf && buf_end);
|
||||
assert(buf < buf_end);
|
||||
|
||||
// Slow path for small cases.
|
||||
if (buf_end - buf < 16) {
|
||||
return shuftiRevSlow((const u8 *)&mask_lo, (const u8 *)&mask_hi,
|
||||
buf, buf_end);
|
||||
}
|
||||
|
||||
const m128 zeroes = zeroes128();
|
||||
const m128 low4bits = _mm_set1_epi8(0xf);
|
||||
const u8 *rv;
|
||||
|
||||
assert(buf_end - buf >= 16);
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m128 chars = loadu128(buf_end - 16);
|
||||
rv = revBlock(mask_lo, mask_hi, chars, buf_end - 16, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf_end = (const u8 *)((size_t)buf_end & ~((size_t)0xf));
|
||||
|
||||
// Unrolling was here, but it wasn't doing anything but taking up space.
|
||||
// Reroll FTW.
|
||||
|
||||
const u8 *last_block = buf + 16;
|
||||
while (buf_end > last_block) {
|
||||
buf_end -= 16;
|
||||
m128 lchars = load128(buf_end);
|
||||
rv = revBlock(mask_lo, mask_hi, lchars, buf_end, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 16 bytes and get an accurate
|
||||
// picture to buf.
|
||||
chars = loadu128(buf);
|
||||
rv = revBlock(mask_lo, mask_hi, chars, buf, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *fwdBlock2(m128 mask1_lo, m128 mask1_hi, m128 mask2_lo, m128 mask2_hi,
|
||||
m128 chars, const u8 *buf, const m128 low4bits,
|
||||
const m128 ones) {
|
||||
m128 chars_lo = GET_LO_4(chars);
|
||||
m128 chars_hi = GET_HI_4(chars);
|
||||
m128 c_lo = pshufb(mask1_lo, chars_lo);
|
||||
m128 c_hi = pshufb(mask1_hi, chars_hi);
|
||||
m128 t = or128(c_lo, c_hi);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" chars: "); dumpMsk128AsChars(chars); printf("\n");
|
||||
DEBUG_PRINTF(" char: "); dumpMsk128(chars); printf("\n");
|
||||
DEBUG_PRINTF(" c_lo: "); dumpMsk128(c_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c_hi: "); dumpMsk128(c_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t: "); dumpMsk128(t); printf("\n");
|
||||
#endif
|
||||
|
||||
m128 c2_lo = pshufb(mask2_lo, chars_lo);
|
||||
m128 c2_hi = pshufb(mask2_hi, chars_hi);
|
||||
m128 t2 = or128(t, shiftRight8Bits(or128(c2_lo, c2_hi)));
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" c2_lo: "); dumpMsk128(c2_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c2_hi: "); dumpMsk128(c2_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t2: "); dumpMsk128(t2); printf("\n");
|
||||
#endif
|
||||
|
||||
return firstMatch(buf, t2, ones);
|
||||
}
|
||||
|
||||
const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
|
||||
m128 mask2_lo, m128 mask2_hi,
|
||||
const u8 *buf, const u8 *buf_end) {
|
||||
const m128 ones = ones128();
|
||||
const m128 low4bits = _mm_set1_epi8(0xf);
|
||||
const u8 *rv;
|
||||
|
||||
size_t min = (size_t)buf % 16;
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m128 chars = loadu128(buf);
|
||||
rv = fwdBlock2(mask1_lo, mask1_hi, mask2_lo, mask2_hi,
|
||||
chars, buf, low4bits, ones);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += (16 - min);
|
||||
|
||||
// Unrolling was here, but it wasn't doing anything but taking up space.
|
||||
// Reroll FTW.
|
||||
|
||||
const u8 *last_block = buf_end - 16;
|
||||
while (buf < last_block) {
|
||||
m128 lchars = load128(buf);
|
||||
rv = fwdBlock2(mask1_lo, mask1_hi, mask2_lo, mask2_hi,
|
||||
lchars, buf, low4bits, ones);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += 16;
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 16 bytes and get an accurate
|
||||
// picture to buf_end.
|
||||
chars = loadu128(buf_end - 16);
|
||||
rv = fwdBlock2(mask1_lo, mask1_hi, mask2_lo, mask2_hi,
|
||||
chars, buf_end - 16, low4bits, ones);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf_end;
|
||||
}
|
||||
|
||||
#else // AVX2 - 256 wide shuftis
|
||||
|
||||
#ifdef DEBUG
|
||||
DUMP_MSK(256)
|
||||
#endif
|
||||
|
||||
#define GET_LO_4(chars) and256(chars, low4bits)
|
||||
#define GET_HI_4(chars) rshift4x64(andnot256(low4bits, chars), 4)
|
||||
|
||||
static really_inline
|
||||
const u8 *firstMatch(const u8 *buf, m256 t, m256 compare) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF("confirming match in:"); dumpMsk256(t); printf("\n");
|
||||
#endif
|
||||
|
||||
u32 z = movemask256(eq256(t, compare));
|
||||
if (unlikely(z != 0xffffffff)) {
|
||||
u32 pos = ctz32(~z);
|
||||
assert(pos < 32);
|
||||
return buf + pos;
|
||||
} else {
|
||||
return NULL; // no match
|
||||
}
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *fwdBlock(m256 mask_lo, m256 mask_hi, m256 chars, const u8 *buf,
|
||||
const m256 low4bits, const m256 zeroes) {
|
||||
m256 c_lo = vpshufb(mask_lo, GET_LO_4(chars));
|
||||
m256 c_hi = vpshufb(mask_hi, GET_HI_4(chars));
|
||||
m256 t = and256(c_lo, c_hi);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" chars: "); dumpMsk256AsChars(chars); printf("\n");
|
||||
DEBUG_PRINTF(" char: "); dumpMsk256(chars); printf("\n");
|
||||
DEBUG_PRINTF(" c_lo: "); dumpMsk256(c_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c_hi: "); dumpMsk256(c_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
|
||||
#endif
|
||||
|
||||
return firstMatch(buf, t, zeroes);
|
||||
}
|
||||
|
||||
/* takes 128 bit masks, but operates on 256 bits of data */
|
||||
const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
assert(buf && buf_end);
|
||||
assert(buf < buf_end);
|
||||
|
||||
// Slow path for small cases.
|
||||
if (buf_end - buf < 32) {
|
||||
return shuftiFwdSlow((const u8 *)&mask_lo, (const u8 *)&mask_hi,
|
||||
buf, buf_end);
|
||||
}
|
||||
|
||||
const m256 zeroes = zeroes256();
|
||||
const m256 low4bits = set32x8(0xf);
|
||||
const m256 wide_mask_lo = set2x128(mask_lo);
|
||||
const m256 wide_mask_hi = set2x128(mask_hi);
|
||||
const u8 *rv;
|
||||
|
||||
size_t min = (size_t)buf % 32;
|
||||
assert(buf_end - buf >= 32);
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m256 chars = loadu256(buf);
|
||||
rv = fwdBlock(wide_mask_lo, wide_mask_hi, chars, buf, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += (32 - min);
|
||||
|
||||
// Unrolling was here, but it wasn't doing anything but taking up space.
|
||||
// Reroll FTW.
|
||||
|
||||
const u8 *last_block = buf_end - 32;
|
||||
while (buf < last_block) {
|
||||
m256 lchars = load256(buf);
|
||||
rv = fwdBlock(wide_mask_lo, wide_mask_hi, lchars, buf, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += 32;
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 32 bytes and get an accurate
|
||||
// picture to buf_end.
|
||||
assert(buf <= buf_end && buf >= buf_end - 32);
|
||||
chars = loadu256(buf_end - 32);
|
||||
rv = fwdBlock(wide_mask_lo, wide_mask_hi, chars, buf_end - 32, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf_end;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *lastMatch(const u8 *buf, m256 t, m256 compare) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF("confirming match in:"); dumpMsk256(t); printf("\n");
|
||||
#endif
|
||||
|
||||
u32 z = movemask256(eq256(t, compare));
|
||||
if (unlikely(z != 0xffffffff)) {
|
||||
u32 pos = clz32(~z);
|
||||
DEBUG_PRINTF("buf=%p, pos=%u\n", buf, pos);
|
||||
return buf + (31 - pos);
|
||||
} else {
|
||||
return NULL; // no match
|
||||
}
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *revBlock(m256 mask_lo, m256 mask_hi, m256 chars, const u8 *buf,
|
||||
const m256 low4bits, const m256 zeroes) {
|
||||
m256 c_lo = vpshufb(mask_lo, GET_LO_4(chars));
|
||||
m256 c_hi = vpshufb(mask_hi, GET_HI_4(chars));
|
||||
m256 t = and256(c_lo, c_hi);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" chars: "); dumpMsk256AsChars(chars); printf("\n");
|
||||
DEBUG_PRINTF(" char: "); dumpMsk256(chars); printf("\n");
|
||||
DEBUG_PRINTF(" c_lo: "); dumpMsk256(c_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c_hi: "); dumpMsk256(c_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
|
||||
#endif
|
||||
|
||||
return lastMatch(buf, t, zeroes);
|
||||
}
|
||||
|
||||
/* takes 128 bit masks, but operates on 256 bits of data */
|
||||
const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
assert(buf && buf_end);
|
||||
assert(buf < buf_end);
|
||||
|
||||
// Slow path for small cases.
|
||||
if (buf_end - buf < 64) {
|
||||
return shuftiRevSlow((const u8 *)&mask_lo, (const u8 *)&mask_hi,
|
||||
buf, buf_end);
|
||||
}
|
||||
|
||||
const m256 zeroes = zeroes256();
|
||||
const m256 low4bits = set32x8(0xf);
|
||||
const m256 wide_mask_lo = set2x128(mask_lo);
|
||||
const m256 wide_mask_hi = set2x128(mask_hi);
|
||||
const u8 *rv;
|
||||
|
||||
assert(buf_end - buf >= 32);
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m256 chars = loadu256(buf_end - 32);
|
||||
rv = revBlock(wide_mask_lo, wide_mask_hi, chars, buf_end - 32, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf_end = (const u8 *)((size_t)buf_end & ~((size_t)0x1f));
|
||||
|
||||
// Unrolling was here, but it wasn't doing anything but taking up space.
|
||||
// Reroll FTW.
|
||||
const u8 *last_block = buf + 32;
|
||||
while (buf_end > last_block) {
|
||||
buf_end -= 32;
|
||||
m256 lchars = load256(buf_end);
|
||||
rv = revBlock(wide_mask_lo, wide_mask_hi, lchars, buf_end, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 32 bytes and get an accurate
|
||||
// picture to buf.
|
||||
chars = loadu256(buf);
|
||||
rv = revBlock(wide_mask_lo, wide_mask_hi, chars, buf, low4bits, zeroes);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *fwdBlock2(m256 mask1_lo, m256 mask1_hi, m256 mask2_lo, m256 mask2_hi,
|
||||
m256 chars, const u8 *buf, const m256 low4bits,
|
||||
const m256 ones) {
|
||||
DEBUG_PRINTF("buf %p\n", buf);
|
||||
m256 chars_lo = GET_LO_4(chars);
|
||||
m256 chars_hi = GET_HI_4(chars);
|
||||
m256 c_lo = vpshufb(mask1_lo, chars_lo);
|
||||
m256 c_hi = vpshufb(mask1_hi, chars_hi);
|
||||
m256 t = or256(c_lo, c_hi);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" chars: "); dumpMsk256AsChars(chars); printf("\n");
|
||||
DEBUG_PRINTF(" char: "); dumpMsk256(chars); printf("\n");
|
||||
DEBUG_PRINTF(" c_lo: "); dumpMsk256(c_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c_hi: "); dumpMsk256(c_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t: "); dumpMsk256(t); printf("\n");
|
||||
#endif
|
||||
|
||||
m256 c2_lo = vpshufb(mask2_lo, chars_lo);
|
||||
m256 c2_hi = vpshufb(mask2_hi, chars_hi);
|
||||
m256 t2 = or256(t, shift256Right8Bits(or256(c2_lo, c2_hi)));
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTF(" c2_lo: "); dumpMsk256(c2_lo); printf("\n");
|
||||
DEBUG_PRINTF(" c2_hi: "); dumpMsk256(c2_hi); printf("\n");
|
||||
DEBUG_PRINTF(" t2: "); dumpMsk256(t2); printf("\n");
|
||||
#endif
|
||||
|
||||
return firstMatch(buf, t2, ones);
|
||||
}
|
||||
|
||||
/* takes 128 bit masks, but operates on 256 bits of data */
|
||||
const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
|
||||
m128 mask2_lo, m128 mask2_hi,
|
||||
const u8 *buf, const u8 *buf_end) {
|
||||
if (buf_end - buf < 32) {
|
||||
// not worth it
|
||||
return buf;
|
||||
}
|
||||
const m256 ones = ones256();
|
||||
const m256 low4bits = set32x8(0xf);
|
||||
const m256 wide_mask1_lo = set2x128(mask1_lo);
|
||||
const m256 wide_mask1_hi = set2x128(mask1_hi);
|
||||
const m256 wide_mask2_lo = set2x128(mask2_lo);
|
||||
const m256 wide_mask2_hi = set2x128(mask2_hi);
|
||||
const u8 *rv;
|
||||
|
||||
size_t min = (size_t)buf % 32;
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m256 chars = loadu256(buf);
|
||||
rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo, wide_mask2_hi,
|
||||
chars, buf, low4bits, ones);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += (32 - min);
|
||||
|
||||
// Unrolling was here, but it wasn't doing anything but taking up space.
|
||||
// Reroll FTW.
|
||||
const u8 *last_block = buf_end - 32;
|
||||
while (buf < last_block) {
|
||||
m256 lchars = load256(buf);
|
||||
rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo, wide_mask2_hi,
|
||||
lchars, buf, low4bits, ones);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += 32;
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 32 bytes and get an accurate
|
||||
// picture to buf_end.
|
||||
chars = loadu256(buf_end - 32);
|
||||
rv = fwdBlock2(wide_mask1_lo, wide_mask1_hi, wide_mask2_lo, wide_mask2_hi,
|
||||
chars, buf_end - 32, low4bits, ones);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf_end;
|
||||
}
|
||||
|
||||
#endif //AVX2
|
||||
61
src/nfa/shufti.h
Normal file
61
src/nfa/shufti.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Shufti: character class acceleration.
|
||||
*
|
||||
* Utilises the SSSE3 pshufb shuffle instruction
|
||||
*/
|
||||
|
||||
#ifndef SHUFTI_H
|
||||
#define SHUFTI_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "util/simd_utils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
const u8 *shuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
|
||||
const u8 *buf_end);
|
||||
|
||||
// Returns (buf - 1) if not found.
|
||||
const u8 *rshuftiExec(m128 mask_lo, m128 mask_hi, const u8 *buf,
|
||||
const u8 *buf_end);
|
||||
|
||||
const u8 *shuftiDoubleExec(m128 mask1_lo, m128 mask1_hi,
|
||||
m128 mask2_lo, m128 mask2_hi,
|
||||
const u8 *buf, const u8 *buf_end);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
191
src/nfa/shufticompile.cpp
Normal file
191
src/nfa/shufticompile.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Shufti acceleration: compile code.
|
||||
*/
|
||||
#include "shufticompile.h"
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
/** \brief Single-byte variant.
|
||||
*
|
||||
* Returns -1 if unable to construct masks, otherwise returns number of bits
|
||||
* used in the mask.
|
||||
*
|
||||
* Note: always able to construct masks for 8 or fewer characters.
|
||||
*/
|
||||
int shuftiBuildMasks(const CharReach &c, m128 *lo, m128 *hi) {
|
||||
/* Things could be packed much more optimally, but this should be able to
|
||||
* handle any set of characters entirely in the lower half. */
|
||||
|
||||
assert(c.count() < 256);
|
||||
assert(!c.none());
|
||||
|
||||
map<u8, CharReach> by_hi; /* hi nibble -> set of matching lo nibbles */
|
||||
/* group matching characters by high nibble */
|
||||
for (size_t i = c.find_first(); i != CharReach::npos; i = c.find_next(i)) {
|
||||
u8 it_hi = i >> 4;
|
||||
u8 it_lo = i & 0xf;
|
||||
by_hi[it_hi].set(it_lo);
|
||||
}
|
||||
|
||||
map<CharReach, CharReach> by_lo_set;
|
||||
/* group all hi nibbles with a common set of lo nibbles together */
|
||||
for (map<u8, CharReach>::const_iterator it = by_hi.begin();
|
||||
it != by_hi.end(); ++it) {
|
||||
by_lo_set[it->second].set(it->first);
|
||||
}
|
||||
|
||||
if (by_lo_set.size() > 8) {
|
||||
/* too many char classes on the dance floor */
|
||||
assert(c.size() > 8);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 bit_index = 0;
|
||||
array<u8, 16> lo_a; lo_a.fill(0);
|
||||
array<u8, 16> hi_a; hi_a.fill(0);
|
||||
for (map<CharReach, CharReach>::const_iterator it = by_lo_set.begin();
|
||||
it != by_lo_set.end(); ++it) {
|
||||
const CharReach &lo_nibbles = it->first;
|
||||
const CharReach &hi_nibbles = it->second;
|
||||
|
||||
/* set bits in low mask */
|
||||
for (size_t j = lo_nibbles.find_first(); j != CharReach::npos;
|
||||
j = lo_nibbles.find_next(j)) {
|
||||
lo_a[j] |= (1 << bit_index);
|
||||
}
|
||||
|
||||
/* set bits in high mask */
|
||||
for (size_t j = hi_nibbles.find_first(); j != CharReach::npos;
|
||||
j = hi_nibbles.find_next(j)) {
|
||||
hi_a[j] |= (1 << bit_index);
|
||||
}
|
||||
|
||||
bit_index++;
|
||||
}
|
||||
|
||||
memcpy(lo, lo_a.data(), sizeof(m128));
|
||||
memcpy(hi, hi_a.data(), sizeof(m128));
|
||||
|
||||
return bit_index;
|
||||
}
|
||||
|
||||
void shuftiBuildDoubleMasks(const CharReach &onechar,
|
||||
const flat_set<pair<u8, u8>> &twochar,
|
||||
m128 *lo1, m128 *hi1, m128 *lo2, m128 *hi2) {
|
||||
DEBUG_PRINTF("unibytes %zu dibytes %zu\n", onechar.size(),
|
||||
twochar.size());
|
||||
assert(onechar.count() + twochar.size() <= 8);
|
||||
|
||||
array<u8, 16> lo1_a;
|
||||
array<u8, 16> lo2_a;
|
||||
array<u8, 16> hi1_a;
|
||||
array<u8, 16> hi2_a;
|
||||
|
||||
lo1_a.fill(0xff);
|
||||
lo2_a.fill(0xff);
|
||||
hi1_a.fill(0xff);
|
||||
hi2_a.fill(0xff);
|
||||
|
||||
u32 i = 0;
|
||||
|
||||
// two-byte literals
|
||||
for (flat_set<pair<u8, u8>>::const_iterator it = twochar.begin();
|
||||
it != twochar.end(); ++it, i++) {
|
||||
DEBUG_PRINTF("%u: %02hhx %02hhx\n", i, it->first, it->second);
|
||||
u8 b1 = it->first & 0xf;
|
||||
u8 t1 = it->first >> 4;
|
||||
u8 b2 = it->second & 0xf;
|
||||
u8 t2 = it->second >> 4;
|
||||
|
||||
lo1_a[b1] &= ~(1 << i);
|
||||
hi1_a[t1] &= ~(1 << i);
|
||||
lo2_a[b2] &= ~(1 << i);
|
||||
hi2_a[t2] &= ~(1 << i);
|
||||
}
|
||||
|
||||
// one-byte literals (second byte is a wildcard)
|
||||
for (size_t it = onechar.find_first(); it != CharReach::npos;
|
||||
it = onechar.find_next(it), i++) {
|
||||
DEBUG_PRINTF("%u: %02hhx\n", i, (u8)it);
|
||||
u8 b1 = it & 0xf;
|
||||
u8 t1 = it >> 4;
|
||||
|
||||
lo1_a[b1] &= ~(1 << i);
|
||||
hi1_a[t1] &= ~(1 << i);
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
lo2_a[j] &= ~(1 << i);
|
||||
hi2_a[j] &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(lo1, lo1_a.data(), sizeof(m128));
|
||||
memcpy(lo2, lo2_a.data(), sizeof(m128));
|
||||
memcpy(hi1, hi1_a.data(), sizeof(m128));
|
||||
memcpy(hi2, hi2_a.data(), sizeof(m128));
|
||||
}
|
||||
|
||||
void mergeShuftiMask(m128 *lo, const m128 lo_in, u32 lo_bits) {
|
||||
assert(lo_bits <= 8);
|
||||
const u8 *lo_in_p = (const u8 *)&lo_in;
|
||||
u8 *lo_p = (u8 *)lo;
|
||||
for (u32 i = 0; i < 16; i++) {
|
||||
lo_p[i] |= lo_in_p[i] << lo_bits;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
|
||||
CharReach shufti2cr(const m128 lo_in, const m128 hi_in) {
|
||||
const u8 *lo = (const u8 *)&lo_in;
|
||||
const u8 *hi = (const u8 *)&hi_in;
|
||||
CharReach cr;
|
||||
for (u32 i = 0; i < 256; i++) {
|
||||
if (lo[(u8)i & 0xf] & hi[(u8)i >> 4]) {
|
||||
cr.set(i);
|
||||
}
|
||||
}
|
||||
return cr;
|
||||
}
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
|
||||
} // namespace ue2
|
||||
71
src/nfa/shufticompile.h
Normal file
71
src/nfa/shufticompile.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 Shufti acceleration: compile code.
|
||||
*/
|
||||
|
||||
#ifndef SHUFTI_COMPILE_H
|
||||
#define SHUFTI_COMPILE_H
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "util/charreach.h"
|
||||
#include "util/ue2_containers.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
/** \brief Single-byte variant.
|
||||
*
|
||||
* Returns -1 if unable to construct masks, otherwise returns number of bits
|
||||
* used in the mask.
|
||||
*
|
||||
* Note: always able to construct masks for 8 or fewer characters.
|
||||
*/
|
||||
int shuftiBuildMasks(const CharReach &chars, m128 *lo, m128 *hi);
|
||||
|
||||
void shuftiBuildDoubleMasks(const CharReach &onechar,
|
||||
const flat_set<std::pair<u8, u8>> &twochar,
|
||||
m128 *lo1, m128 *hi1, m128 *lo2, m128 *hi2);
|
||||
|
||||
void mergeShuftiMask(m128 *lo, const m128 lo_in, u32 lo_bits);
|
||||
|
||||
#ifdef DUMP_SUPPORT
|
||||
|
||||
/**
|
||||
* \brief Dump code: returns a CharReach with the reach that would match this
|
||||
* shufti.
|
||||
*/
|
||||
CharReach shufti2cr(const m128 lo, const m128 hi);
|
||||
|
||||
#endif // DUMP_SUPPORT
|
||||
|
||||
} // namespace ue2
|
||||
|
||||
#endif // SHUFTI_COMPILE_H
|
||||
236
src/nfa/truffle.c
Normal file
236
src/nfa/truffle.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Matches a byte in a charclass using three shuffles
|
||||
*/
|
||||
|
||||
|
||||
#include "ue2common.h"
|
||||
#include "truffle.h"
|
||||
#include "util/bitutils.h"
|
||||
#include "util/simd_utils.h"
|
||||
#include "util/simd_utils_ssse3.h"
|
||||
|
||||
#define shift128r(a, b) _mm_srli_epi64((a), (b))
|
||||
|
||||
static really_inline
|
||||
const u8 *firstMatch(const u8 *buf, u32 z) {
|
||||
if (unlikely(z != 0xffff)) {
|
||||
u32 pos = ctz32(~z & 0xffff);
|
||||
assert(pos < 16);
|
||||
return buf + pos;
|
||||
}
|
||||
|
||||
return NULL; // no match
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *lastMatch(const u8 *buf, u32 z) {
|
||||
if (unlikely(z != 0xffff)) {
|
||||
u32 pos = clz32(~z & 0xffff);
|
||||
assert(pos >= 16 && pos < 32);
|
||||
return buf + (31 - pos);
|
||||
}
|
||||
|
||||
return NULL; // no match
|
||||
}
|
||||
|
||||
static really_inline
|
||||
u32 block(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset, m128 v) {
|
||||
|
||||
m128 highconst = _mm_set1_epi8(0x80);
|
||||
m128 shuf_mask_hi = _mm_set1_epi64x(0x8040201008040201);
|
||||
|
||||
// and now do the real work
|
||||
m128 shuf1 = pshufb(shuf_mask_lo_highclear, v);
|
||||
m128 t1 = xor128(v, highconst);
|
||||
m128 shuf2 = pshufb(shuf_mask_lo_highset, t1);
|
||||
m128 t2 = andnot128(highconst, shift128r(v, 4));
|
||||
m128 shuf3 = pshufb(shuf_mask_hi, t2);
|
||||
m128 tmp = and128(or128(shuf1, shuf2), shuf3);
|
||||
m128 tmp2 = eq128(tmp, zeroes128());
|
||||
u32 z = movemask128(tmp2);
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *fwdBlock(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
|
||||
m128 v, const u8 *buf) {
|
||||
u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
|
||||
return firstMatch(buf, z);
|
||||
}
|
||||
|
||||
static really_inline
|
||||
const u8 *revBlock(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
|
||||
m128 v, const u8 *buf) {
|
||||
u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, v);
|
||||
return lastMatch(buf, z);
|
||||
}
|
||||
|
||||
static
|
||||
const u8 *truffleMini(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
|
||||
const u8 *buf, const u8 *buf_end) {
|
||||
uintptr_t len = buf_end - buf;
|
||||
assert(len < 16);
|
||||
|
||||
m128 chars = zeroes128();
|
||||
memcpy(&chars, buf, len);
|
||||
|
||||
u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
|
||||
// can't be these bytes in z
|
||||
u32 mask = (0xFFFF >> (16 - len)) ^ 0xFFFF;
|
||||
const u8 *rv = firstMatch(buf, z| mask);
|
||||
|
||||
if (rv) {
|
||||
return rv;
|
||||
} else {
|
||||
return buf_end;
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *truffleExec(m128 shuf_mask_lo_highclear,
|
||||
m128 shuf_mask_lo_highset,
|
||||
const u8 *buf, const u8 *buf_end) {
|
||||
DEBUG_PRINTF("len %zu\n", buf_end - buf);
|
||||
|
||||
assert(buf && buf_end);
|
||||
assert(buf < buf_end);
|
||||
const u8 *rv;
|
||||
|
||||
if (buf_end - buf < 16) {
|
||||
return truffleMini(shuf_mask_lo_highclear, shuf_mask_lo_highset, buf,
|
||||
buf_end);
|
||||
}
|
||||
|
||||
size_t min = (size_t)buf % 16;
|
||||
assert(buf_end - buf >= 16);
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m128 chars = loadu128(buf);
|
||||
rv = fwdBlock(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars, buf);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += (16 - min);
|
||||
|
||||
const u8 *last_block = buf_end - 16;
|
||||
while (buf < last_block) {
|
||||
m128 lchars = load128(buf);
|
||||
rv = fwdBlock(shuf_mask_lo_highclear, shuf_mask_lo_highset, lchars,
|
||||
buf);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf += 16;
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 16 bytes and get an accurate
|
||||
// picture to buf_end.
|
||||
assert(buf <= buf_end && buf >= buf_end - 16);
|
||||
chars = loadu128(buf_end - 16);
|
||||
rv = fwdBlock(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars,
|
||||
buf_end - 16);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf_end;
|
||||
}
|
||||
|
||||
static
|
||||
const u8 *truffleRevMini(m128 shuf_mask_lo_highclear,
|
||||
m128 shuf_mask_lo_highset, const u8 *buf,
|
||||
const u8 *buf_end) {
|
||||
uintptr_t len = buf_end - buf;
|
||||
assert(len < 16);
|
||||
|
||||
m128 chars = zeroes128();
|
||||
memcpy(&chars, buf, len);
|
||||
|
||||
u32 mask = (0xFFFF >> (16 - len)) ^ 0xFFFF;
|
||||
u32 z = block(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars);
|
||||
const u8 *rv = lastMatch(buf, z | mask);
|
||||
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
|
||||
const u8 *rtruffleExec(m128 shuf_mask_lo_highclear,
|
||||
m128 shuf_mask_lo_highset,
|
||||
const u8 *buf, const u8 *buf_end) {
|
||||
|
||||
assert(buf && buf_end);
|
||||
assert(buf < buf_end);
|
||||
const u8 *rv;
|
||||
|
||||
DEBUG_PRINTF("len %zu\n", buf_end - buf);
|
||||
|
||||
if (buf_end - buf < 16) {
|
||||
return truffleRevMini(shuf_mask_lo_highclear, shuf_mask_lo_highset, buf,
|
||||
buf_end);
|
||||
}
|
||||
|
||||
assert(buf_end - buf >= 16);
|
||||
|
||||
// Preconditioning: most of the time our buffer won't be aligned.
|
||||
m128 chars = loadu128(buf_end - 16);
|
||||
rv = revBlock(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars,
|
||||
buf_end - 16);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
buf_end = (const u8 *)((size_t)buf_end & ~((size_t)0xf));
|
||||
|
||||
const u8 *last_block = buf + 16;
|
||||
while (buf_end > last_block) {
|
||||
buf_end -= 16;
|
||||
m128 lchars = load128(buf_end);
|
||||
rv = revBlock(shuf_mask_lo_highclear, shuf_mask_lo_highset, lchars,
|
||||
buf_end);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Use an unaligned load to mop up the last 16 bytes and get an accurate
|
||||
// picture to buf_end.
|
||||
chars = loadu128(buf);
|
||||
rv = revBlock(shuf_mask_lo_highclear, shuf_mask_lo_highset, chars, buf);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
|
||||
49
src/nfa/truffle.h
Normal file
49
src/nfa/truffle.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef TRUFFLE_H
|
||||
#define TRUFFLE_H
|
||||
#include "util/simd_types.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
const u8 *truffleExec(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
|
||||
const u8 *buf, const u8 *buf_end);
|
||||
|
||||
const u8 *rtruffleExec(m128 shuf_mask_lo_highclear, m128 shuf_mask_lo_highset,
|
||||
const u8 *buf, const u8 *buf_end);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* TRUFFLE_H */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user