[gamecode] Add an extend instruction

The extend instruction is for loading narrower data types into wider
data types, eg, single element into 2, 3, or 4 element types, with a
small set of extension schemes: 0, 1, -1, copy (for 1->any and 2 -> 4).
Possibly most importantly, it works with unaligned data.

Progress towards #30
This commit is contained in:
Bill Currie 2022-08-18 14:48:53 +09:00
parent 59b73353dd
commit d9d0a80752
6 changed files with 339 additions and 5 deletions

View file

@ -21,7 +21,12 @@ libs_gamecode_libQFgamecode_la_SOURCES= \
libs/gamecode/pr_v6p_opcode.c \
libs/gamecode/pr_zone.c
noinst_PYTHON += $(opcodes_py) $(convert_py) $(hops_py) $(swizzle_py)
noinst_PYTHON += \
$(opcodes_py) \
$(convert_py) \
${extend_py} \
$(hops_py) \
$(swizzle_py)
opcodes_py = $(srcdir)/libs/gamecode/opcodes.py
pr_opcode_cinc = $(top_builddir)/libs/gamecode/pr_opcode.cinc
@ -34,6 +39,9 @@ libs/gamecode/pr_opcode.lo: libs/gamecode/pr_opcode.c ${pr_opcode_src}
convert_py = $(srcdir)/libs/gamecode/convert.py
pr_convert_cinc = $(top_builddir)/libs/gamecode/pr_convert.cinc
extend_py = $(srcdir)/libs/gamecode/extend.py
pr_extend_cinc = $(top_builddir)/libs/gamecode/pr_extend.cinc
hops_py = $(srcdir)/libs/gamecode/hops.py
pr_hops_cinc = $(top_builddir)/libs/gamecode/pr_hops.cinc
@ -45,6 +53,7 @@ BUILT_SOURCES += \
$(pr_opcode_cinc) \
$(pr_opcode_hinc) \
$(pr_convert_cinc) \
$(pr_extend_cinc) \
$(pr_hops_cinc) \
$(pr_swizzle32_cinc) \
$(pr_swizzle64_cinc)
@ -53,6 +62,7 @@ CLEANFILES += \
$(pr_opcode_cinc) \
$(pr_opcode_hinc) \
$(pr_convert_cinc) \
$(pr_extend_cinc) \
$(pr_hops_cinc) \
$(pr_swizzle32_cinc) \
$(pr_swizzle64_cinc)
@ -70,6 +80,10 @@ $(pr_convert_cinc): $(convert_py)
$(V_PY)$(PYTHON) $(convert_py) table > $(pr_convert_cinc).t && \
$(am__mv) $(pr_convert_cinc).t $(pr_convert_cinc)
$(pr_extend_cinc): $(extend_py)
$(V_PY)$(PYTHON) $(extend_py) table > $(pr_extend_cinc).t && \
$(am__mv) $(pr_extend_cinc).t $(pr_extend_cinc)
$(pr_hops_cinc): $(hops_py)
$(V_PY)$(PYTHON) $(hops_py) table > $(pr_hops_cinc).t && \
$(am__mv) $(pr_hops_cinc).t $(pr_hops_cinc)

77
libs/gamecode/extend.py Normal file
View file

@ -0,0 +1,77 @@
print("""// encoding is teemmm
// t = 0: 32-bit, t = 1: 64-bit
// e = 00: 0
// e = 01: 1.0
// e = 10: copy (1-n, 2-4, otherwise 0)
// e = 11: -1.0
// mmm = 000: 1 -> 2
// mmm = 001: 1 -> 3
// mmm = 010: 1 -> 4
// mmm = 011: 2 -> 3
// mmm = 100: 2 -> 4
// mmm = 101: 3 -> 4
// mmm = 110: reserved
// mmm = 111: reserved
""")
types = [
["ivec2", "ivec3", "ivec4", "ivec3", "ivec4", "ivec4"],
["lvec2", "lvec3", "lvec4", "lvec3", "lvec4", "lvec4"],
]
src_types = [
["int", "int", "int", "ivec2", "ivec2", "ivec3"],
["long", "long", "long", "lvec2", "lvec2", "lvec3"],
]
extend = [
["0", "INT32_C(0x3f800000)", "0", "INT32_C(0xbf800000)"],
["0", "INT64_C(0x3ff0000000000000)", "0", "INT64_C(0xbff0000000000000)"],
]
def case_str(type, ext, mode):
case = (type << 5) | (ext << 3) | (mode)
return f"case {case:03o}:"
def dst_str(type, ext, mode):
return f"OPC({types[type][mode]})"
def cast_str(type, ext, mode):
return f"(pr_{types[type][mode]}_t)"
def init_str(type, ext, mode):
ext_str = extend[type][ext]
src = f"OPA({src_types[type][mode]})"
if mode == 0:
if ext == 2:
ext_str = src
return f"{src}, {ext_str}"
elif mode == 1:
if ext == 2:
ext_str = src
return f"{src}, {ext_str}, {ext_str}"
elif mode == 2:
if ext == 2:
ext_str = src
return f"{src}, {ext_str}, {ext_str}, {ext_str}"
elif mode == 3:
return f"{src}[0], {src}[1], {ext_str}"
elif mode == 4:
if ext == 2:
return f"{src}[0], {src}[1], {src}[0], {src}[1]"
else:
return f"{src}[0], {src}[1], {ext_str}, {ext_str}"
elif mode == 5:
return f"{src}[0], {src}[1], {src}[2], {ext_str}"
for type in range(2):
for ext in range(4):
for mode in range(6): # 6, 7 are reserved
case = case_str(type, ext, mode)
dst = dst_str(type, ext, mode)
cast = cast_str(type, ext, mode)
init = init_str(type, ext, mode)
if mode in [1, 3]:
print(f"{case} VectorSet({init}, {dst}); break;");
else:
print(f"{case} {dst} = {cast} {{ {init} }}; break;");

View file

@ -34,7 +34,7 @@ bitmap_txt = """
1 1111 10oo fbitops
1 1111 1100 convert (conversion mode in st->b)
1 1111 1101 with (mode in st->a, value in st->b, reg in st->c)
1 1111 1110
1 1111 1110 extend
1 1111 1111 hops
"""
@ -204,6 +204,14 @@ fbitops_formats = {
],
},
}
extend_formats = {
"opcode": "OP_EXTEND",
"mnemonic": "extend",
"opname": "extend",
"format": "%Ga %Hb %gc",
"widths": "-1, 0, -1",
"types": "ev_void, ev_short, ev_void",
}
hops_formats = {
"opcode": "OP_HOPS",
"mnemonic": "hops",
@ -566,6 +574,7 @@ group_map = {
"compare2": compare2_formats,
"constant": constant_formats,
"convert": convert_formats,
"extend": extend_formats,
"fbitops": fbitops_formats,
"hops": hops_formats,
"jump": jump_formats,

View file

@ -2835,7 +2835,13 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
case OP_WITH:
pr_with (pr, st);
break;
// 1110 spare
case OP_EXTEND:
switch (st->b) {
#include "libs/gamecode/pr_extend.cinc"
default:
PR_RunError (pr, "invalid extend code: %04o", st->b);
}
break;
#define OP_hop2(vec, op) ((vec)[0] op (vec)[1])
#define OP_hop3(vec, op) ((vec)[0] op (vec)[1] op (vec)[2])
#define OP_hop4(vec, op) ((vec)[0] op (vec)[1] op (vec)[2] op (vec)[3])
@ -2843,8 +2849,7 @@ pr_exec_ruamoko (progs_t *pr, int exitdepth)
switch (st->b) {
#include "libs/gamecode/pr_hops.cinc"
default:
PR_RunError (pr, "invalid hops code: %04o",
st->b);
PR_RunError (pr, "invalid hops code: %04o", st->b);
}
break;
default:

View file

@ -11,6 +11,7 @@ libs_gamecode_tests = \
libs/gamecode/test/test-conv6 \
libs/gamecode/test/test-conv7 \
libs/gamecode/test/test-double \
libs/gamecode/test/test-extend \
libs/gamecode/test/test-float \
libs/gamecode/test/test-hops \
libs/gamecode/test/test-int \
@ -101,6 +102,11 @@ libs_gamecode_test_test_double_SOURCES= \
libs_gamecode_test_test_double_LDADD= $(test_gamecode_libs)
libs_gamecode_test_test_double_DEPENDENCIES=$(test_gamecode_libs)
libs_gamecode_test_test_extend_SOURCES= \
libs/gamecode/test/test-extend.c
libs_gamecode_test_test_extend_LDADD= $(test_gamecode_libs)
libs_gamecode_test_test_extend_DEPENDENCIES= $(test_gamecode_libs)
libs_gamecode_test_test_float_SOURCES= \
libs/gamecode/test/test-float.c
libs_gamecode_test_test_float_LDADD= $(test_gamecode_libs)

View file

@ -0,0 +1,223 @@
#include "head.c"
#include "QF/mathlib.h"
#define _ -6.259853398707798e+18 // 0xdeadbeef
static pr_vec4_t float_extend_init[] = {
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ 2, 3, 4, 5 },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
};
static pr_vec4_t float_extend_expect[] = {
{ 5, 0, _, _ },
{ 4, 0, 0, _ },
{ 3, 0, 0, 0 },
{ 4, 5, 0, _ },
{ 2, 3, 0, 0 },
{ 3, 4, 5, 0 },
{ 2, 3, 4, 5 },
{ _, _, 4, 1 },
{ _, 3, 1, 1 },
{ 2, 1, 1, 1 },
{ _, 4, 5, 1 },
{ 2, 3, 1, 1 },
{ 2, 3, 4, 1 },
{ _, _, _, _ },
{ 5, 5, _, _ },
{ 4, 4, 4, _ },
{ 3, 3, 3, 3 },
{ 4, 5, 0, _ },
{ 2, 3, 2, 3 },
{ 3, 4, 5, 0 },
{ _, _, _, _ },
{ _, _, 4, -1 },
{ _, 3, -1, -1 },
{ 2, -1, -1, -1 },
{ _, 4, 5, -1 },
{ 2, 3, -1, -1 },
{ 2, 3, 4, -1 },
{ _, _, _, _ },
};
static dstatement_t float_extend_statements[] = {
{ OP(0, 0, 0, OP_WITH), 0, 0, 0 },
{ OP(0, 0, 0, OP_WITH), 0, 28, 1 },
{ OP(0, 0, 0, OP_WITH), 0, 56, 2 },
{ OP(0, 0, 0, OP_WITH), 0, 84, 3 },
{ OP(0, 0, 0, OP_EXTEND), 27, 000, 0 },
{ OP(0, 0, 0, OP_EXTEND), 26, 001, 4 },
{ OP(0, 0, 0, OP_EXTEND), 25, 002, 8 },
{ OP(0, 0, 0, OP_EXTEND), 26, 003, 12 },
{ OP(0, 0, 0, OP_EXTEND), 24, 004, 16 },
{ OP(0, 0, 0, OP_EXTEND), 25, 005, 20 },
{ OP(0, 0, 1, OP_EXTEND), 26, 010, 2 },
{ OP(0, 0, 1, OP_EXTEND), 25, 011, 5 },
{ OP(0, 0, 1, OP_EXTEND), 24, 012, 8 },
{ OP(0, 0, 1, OP_EXTEND), 26, 013, 13 },
{ OP(0, 0, 1, OP_EXTEND), 24, 014, 16 },
{ OP(0, 0, 1, OP_EXTEND), 24, 015, 20 },
{ OP(0, 0, 2, OP_EXTEND), 27, 020, 0 },
{ OP(0, 0, 2, OP_EXTEND), 26, 021, 4 },
{ OP(0, 0, 2, OP_EXTEND), 25, 022, 8 },
{ OP(0, 0, 2, OP_EXTEND), 26, 023, 12 },
{ OP(0, 0, 2, OP_EXTEND), 24, 024, 16 },
{ OP(0, 0, 2, OP_EXTEND), 25, 025, 20 },
{ OP(0, 0, 3, OP_EXTEND), 26, 030, 2 },
{ OP(0, 0, 3, OP_EXTEND), 25, 031, 5 },
{ OP(0, 0, 3, OP_EXTEND), 24, 032, 8 },
{ OP(0, 0, 3, OP_EXTEND), 26, 033, 13 },
{ OP(0, 0, 3, OP_EXTEND), 24, 034, 16 },
{ OP(0, 0, 3, OP_EXTEND), 24, 035, 20 },
};
#undef _
#define _ -1.1885959257070704e+148 // 0xdeadbeefdeadbeef
static pr_dvec4_t double_extend_init[] = {
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ 2, 3, 4, 5 },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
{ _, _, _, _ },
};
static pr_dvec4_t double_extend_expect[] = {
{ 5, 0, _, _ },
{ 4, 0, 0, _ },
{ 3, 0, 0, 0 },
{ 4, 5, 0, _ },
{ 2, 3, 0, 0 },
{ 3, 4, 5, 0 },
{ 2, 3, 4, 5 },
{ _, _, 4, 1 },
{ _, 3, 1, 1 },
{ 2, 1, 1, 1 },
{ _, 4, 5, 1 },
{ 2, 3, 1, 1 },
{ 2, 3, 4, 1 },
{ _, _, _, _ },
{ 5, 5, _, _ },
{ 4, 4, 4, _ },
{ 3, 3, 3, 3 },
{ 4, 5, 0, _ },
{ 2, 3, 2, 3 },
{ 3, 4, 5, 0 },
{ _, _, _, _ },
{ _, _, 4, -1 },
{ _, 3, -1, -1 },
{ 2, -1, -1, -1 },
{ _, 4, 5, -1 },
{ 2, 3, -1, -1 },
{ 2, 3, 4, -1 },
{ _, _, _, _ },
};
static dstatement_t double_extend_statements[] = {
{ OP(0, 0, 0, OP_WITH), 0, 0, 0 },
{ OP(0, 0, 0, OP_WITH), 0, 56, 1 },
{ OP(0, 0, 0, OP_WITH), 0, 112, 2 },
{ OP(0, 0, 0, OP_WITH), 0, 168, 3 },
{ OP(0, 0, 0, OP_EXTEND), 54, 040, 0 },
{ OP(0, 0, 0, OP_EXTEND), 52, 041, 8 },
{ OP(0, 0, 0, OP_EXTEND), 50, 042, 16 },
{ OP(0, 0, 0, OP_EXTEND), 52, 043, 24 },
{ OP(0, 0, 0, OP_EXTEND), 48, 044, 32 },
{ OP(0, 0, 0, OP_EXTEND), 50, 045, 40 },
{ OP(0, 0, 1, OP_EXTEND), 52, 050, 4 },
{ OP(0, 0, 1, OP_EXTEND), 50, 051, 10 },
{ OP(0, 0, 1, OP_EXTEND), 48, 052, 16 },
{ OP(0, 0, 1, OP_EXTEND), 52, 053, 26 },
{ OP(0, 0, 1, OP_EXTEND), 48, 054, 32 },
{ OP(0, 0, 1, OP_EXTEND), 48, 055, 40 },
{ OP(0, 0, 2, OP_EXTEND), 54, 060, 0 },
{ OP(0, 0, 2, OP_EXTEND), 52, 061, 8 },
{ OP(0, 0, 2, OP_EXTEND), 50, 062, 16 },
{ OP(0, 0, 2, OP_EXTEND), 52, 063, 24 },
{ OP(0, 0, 2, OP_EXTEND), 48, 064, 32 },
{ OP(0, 0, 2, OP_EXTEND), 50, 065, 40 },
{ OP(0, 0, 3, OP_EXTEND), 52, 070, 4 },
{ OP(0, 0, 3, OP_EXTEND), 50, 071, 10 },
{ OP(0, 0, 3, OP_EXTEND), 48, 072, 16 },
{ OP(0, 0, 3, OP_EXTEND), 52, 073, 26 },
{ OP(0, 0, 3, OP_EXTEND), 48, 074, 32 },
{ OP(0, 0, 3, OP_EXTEND), 48, 075, 40 },
};
test_t tests[] = {
{
.desc = "float extend",
.num_globals = num_globals(float_extend_init,float_extend_expect),
.num_statements = num_statements (float_extend_statements),
.statements = float_extend_statements,
.init_globals = (pr_int_t *) float_extend_init,
.expect_globals = (pr_int_t *) float_extend_expect,
},
{
.desc = "double extend",
.num_globals = num_globals(double_extend_init,double_extend_expect),
.num_statements = num_statements (double_extend_statements),
.statements = double_extend_statements,
.init_globals = (pr_int_t *) double_extend_init,
.expect_globals = (pr_int_t *) double_extend_expect,
},
};
#include "main.c"