mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-06-09 23:08:18 +02:00
util: Add runtime parser for boolean lookup tables
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41872>
This commit is contained in:
parent
0dcca5ad8c
commit
b74eff31d9
3 changed files with 188 additions and 1 deletions
125
src/util/lut.c
125
src/util/lut.c
|
|
@ -3,6 +3,10 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "lut.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* This table was generated by an offline tool in the following manner:
|
||||
* for each function value, we generated a tree of all expressions that evaluate
|
||||
|
|
@ -269,3 +273,124 @@ const char *util_lut3_to_str[256] = {
|
|||
[0xFE] = "a | b | c",
|
||||
[0xFF] = "ones",
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
struct lut3_parser {
|
||||
const char *s;
|
||||
bool error;
|
||||
};
|
||||
|
||||
static void
|
||||
lut3_skip_space(struct lut3_parser *p)
|
||||
{
|
||||
while (p->s[0] == ' ')
|
||||
p->s++;
|
||||
}
|
||||
|
||||
static bool
|
||||
lut3_match(struct lut3_parser *p, char c)
|
||||
{
|
||||
lut3_skip_space(p);
|
||||
|
||||
if (p->s[0] == c) {
|
||||
p->s++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
lut3_match_str(struct lut3_parser *p, const char *pat)
|
||||
{
|
||||
lut3_skip_space(p);
|
||||
|
||||
size_t len = strlen(pat);
|
||||
if (!strncmp(p->s, pat, len)) {
|
||||
p->s += len;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static util_lut3 lut3_parse_or(struct lut3_parser *p);
|
||||
|
||||
static util_lut3
|
||||
lut3_parse_value(struct lut3_parser *p)
|
||||
{
|
||||
if (lut3_match(p, 'a')) return UTIL_LUT3(a);
|
||||
if (lut3_match(p, 'b')) return UTIL_LUT3(b);
|
||||
if (lut3_match(p, 'c')) return UTIL_LUT3(c);
|
||||
|
||||
if (lut3_match_str(p, "zeros")) return UTIL_LUT3(0);
|
||||
if (lut3_match_str(p, "ones")) return UTIL_LUT3(~0);
|
||||
|
||||
if (lut3_match(p, '(')) {
|
||||
util_lut3 val = lut3_parse_or(p);
|
||||
if (lut3_match(p, ')'))
|
||||
return val;
|
||||
}
|
||||
|
||||
p->error = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static util_lut3
|
||||
lut3_parse_not(struct lut3_parser *p)
|
||||
{
|
||||
bool has_not = false;
|
||||
while (lut3_match(p, '~'))
|
||||
has_not = !has_not;
|
||||
util_lut3 val = lut3_parse_value(p);
|
||||
return has_not ? ~val : val;
|
||||
}
|
||||
|
||||
static util_lut3
|
||||
lut3_parse_and(struct lut3_parser *p)
|
||||
{
|
||||
util_lut3 val = lut3_parse_not(p);
|
||||
while (lut3_match(p, '&'))
|
||||
val &= lut3_parse_not(p);
|
||||
return val;
|
||||
}
|
||||
|
||||
static util_lut3
|
||||
lut3_parse_xor(struct lut3_parser *p)
|
||||
{
|
||||
util_lut3 val = lut3_parse_and(p);
|
||||
while (lut3_match(p, '^'))
|
||||
val ^= lut3_parse_and(p);
|
||||
return val;
|
||||
}
|
||||
|
||||
static util_lut3
|
||||
lut3_parse_or(struct lut3_parser *p)
|
||||
{
|
||||
util_lut3 val = lut3_parse_xor(p);
|
||||
while (lut3_match(p, '|'))
|
||||
val |= lut3_parse_xor(p);
|
||||
return val;
|
||||
}
|
||||
|
||||
util_lut3
|
||||
util_lut3_parse(const char *s, bool *ok)
|
||||
{
|
||||
struct lut3_parser p = { .s = s };
|
||||
|
||||
util_lut3 val = 0;
|
||||
|
||||
if (s && s[0]) {
|
||||
val = lut3_parse_or(&p);
|
||||
lut3_skip_space(&p);
|
||||
if (p.s[0])
|
||||
p.error = true;
|
||||
} else {
|
||||
p.error = true;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
*ok = !p.error;
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,9 +6,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "util/macros.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Represents a boolean lookup table in sum-of-minterms form. These are
|
||||
* natural encodings, matching the Intel BFN and Apple BITOP instructions.
|
||||
|
|
@ -61,6 +66,8 @@ util_lut2_invert_source(util_lut2 l, unsigned s)
|
|||
{
|
||||
return (util_lut2)(util_lut3_invert_source((util_lut3)l, s) & 0xf);
|
||||
}
|
||||
|
||||
util_lut3 util_lut3_parse(const char *s, bool *ok);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -102,6 +109,10 @@ util_lut3_swap_sources(util_lut3 l, unsigned a, unsigned b)
|
|||
UNREACHABLE("invalid source selection");
|
||||
}
|
||||
|
||||
|
||||
/* Finding minimal string forms of LUTs is tricky, so we precompute. */
|
||||
extern const char *util_lut3_to_str[256];
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -72,4 +72,55 @@ TEST(lut, swap_sources3)
|
|||
EXPECT_LUT3(util_lut3_swap_sources(UTIL_LUT3(a | ~b | c), 0, 2), "a | ~b | c");
|
||||
EXPECT_LUT3(util_lut3_swap_sources(UTIL_LUT3(a | ~b | c), 1, 2), "a | b | ~c");
|
||||
}
|
||||
|
||||
TEST(lut, parse)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(util_lut3_to_str); i++) {
|
||||
const char *str = util_lut3_to_str[i];
|
||||
bool ok = false;
|
||||
const unsigned got = util_lut3_parse(str, &ok);
|
||||
EXPECT_TRUE(ok) << "CASE: " << str;
|
||||
EXPECT_EQ(got, i) << "CASE: " << str;
|
||||
}
|
||||
|
||||
const char *invalids[] = {
|
||||
NULL,
|
||||
"",
|
||||
" ",
|
||||
"a)",
|
||||
"onesx",
|
||||
"a &",
|
||||
"((a)",
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(invalids); i++) {
|
||||
bool ok = true;
|
||||
util_lut3_parse(invalids[i], &ok);
|
||||
EXPECT_FALSE(ok) << "CASE #" << i;
|
||||
}
|
||||
|
||||
struct {
|
||||
const char *a;
|
||||
const char *b;
|
||||
} equivalents[] = {
|
||||
{ "~~a", "a" },
|
||||
{ "a | b & c", "a | (b & c)" },
|
||||
{ "a | b ^ c", "a | (b ^ c)" },
|
||||
{ "a & (b | c)", "a & b | a & c" },
|
||||
{ "a & ones", "a" },
|
||||
{ "~(a & b)", "~a | ~b" },
|
||||
{ "((a | b) & (b | c))", "(a | b) & (b | c)" },
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(equivalents); i++) {
|
||||
bool ok_a = false;
|
||||
bool ok_b = false;
|
||||
util_lut3 a = util_lut3_parse(equivalents[i].a, &ok_a);
|
||||
util_lut3 b = util_lut3_parse(equivalents[i].b, &ok_b);
|
||||
EXPECT_TRUE(ok_a) << equivalents[i].a;
|
||||
EXPECT_TRUE(ok_b) << equivalents[i].b;
|
||||
EXPECT_EQ(a, b) << equivalents[i].a << " and " << equivalents[i].b;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue