[gamecode] Add a new Ruamoko instruction set

When it's finalized (most of the conversion operations will go, probably
the float bit ops, maybe (very undecided) the 3-component vector ops,
and likely the CALLN ops), this will be the actual instruction set for
Ruamoko.

Main features:
 - Significant reduction in redundant instructions: no more multiple
   opcodes to move the one operand size.
 - load, store, push, and pop share unified addressing mode encoding
   (with the exception of mode 0 for load as that is redundant with mode
   0 for store, thus load mode 0 gives quick access to entity.field).
 - Full support for both 32 and 64 bit signed integer, unsigned integer,
   and floating point values.
 - SIMD for 1, 2, (currently) 3, and 4 components. Transfers support up
   to 128-bit wide operations (need two operations to transfer a full
   4-component double/long vector), but all math operations support both
   128-bit (32-bit components) and 256-bit (64-bit components) vectors.
 - "Interpreted" operations for the various vector sizes: complex dot
   and multiplication, 3d vector dot and cross product, quaternion dot
   and multiplication, along with qv and vq shortcuts.
 - 4-component swizzles for both sizes (not yet implemented, but the
   instructions are allocated), with the option to zero or negate (thus
   conjugates for complex and quaternion values) individual components.
 - "Based offsets": all relevant instructions include base register
   indices for all three operands allowing for direct access to any of
   four areas (eg, current entity, current stack frame, Objective-QC
   self, ...) instructions to set a register and push/pop the four
   registers to/from the stack.

Remaining work:
 - Implement swizzle operations and a few other stragglers.
 = Make a decision about conversion operations (if any instructions
   remain, they'll be just single-component (at 14 meaningful pairs,
   that's a lot of instructions to waste on SIMD versions).
 - Decide whether to keep CALL1-CALL8: probably little point in
   supporting two different calling conventions, and it would free up
   another eight instructions.
 - Unit tests for the instructions.
 - Teach qfcc to generate code for the new instruction set (hah, biggest
   job, I'm sure, though hopefully not as crazy as the rewrite eleven
   years ago).
This commit is contained in:
Bill Currie 2022-01-02 23:15:15 +09:00
parent 0c17c6dc24
commit 925797b1d4
4 changed files with 1116 additions and 9 deletions

View file

@ -424,6 +424,188 @@ typedef enum {
} pr_opcode_v6p_e;
#define OP_BREAK 0x8000
typedef enum {
// 0 0000 load from [a,b] -> c
OP_LOAD_E_1, OP_LOAD_E_2, OP_LOAD_E_3, OP_LOAD_E_4,
OP_LOAD_B_1, OP_LOAD_B_2, OP_LOAD_B_3, OP_LOAD_B_4,
OP_LOAD_C_1, OP_LOAD_C_2, OP_LOAD_C_3, OP_LOAD_C_4,
OP_LOAD_D_1, OP_LOAD_D_2, OP_LOAD_D_3, OP_LOAD_D_4,
// 0 0001 store from c -> [a, b]
OP_STORE_A_1, OP_STORE_A_2, OP_STORE_A_3, OP_STORE_A_4, // redundant?
OP_STORE_B_1, OP_STORE_B_2, OP_STORE_B_3, OP_STORE_B_4,
OP_STORE_C_1, OP_STORE_C_2, OP_STORE_C_3, OP_STORE_C_4,
OP_STORE_D_1, OP_STORE_D_2, OP_STORE_D_3, OP_STORE_D_4,
// 0 0010 push from [a,b] to the stack
OP_PUSH_A_1, OP_PUSH_A_2, OP_PUSH_A_3, OP_PUSH_A_4,
OP_PUSH_B_1, OP_PUSH_B_2, OP_PUSH_B_3, OP_PUSH_B_4,
OP_PUSH_C_1, OP_PUSH_C_2, OP_PUSH_C_3, OP_PUSH_C_4,
OP_PUSH_D_1, OP_PUSH_D_2, OP_PUSH_D_3, OP_PUSH_D_4,
// 0 0011 pop from the stack to [a,b]
OP_POP_A_1, OP_POP_A_2, OP_POP_A_3, OP_POP_A_4,
OP_POP_B_1, OP_POP_B_2, OP_POP_B_3, OP_POP_B_4,
OP_POP_C_1, OP_POP_C_2, OP_POP_C_3, OP_POP_C_4,
OP_POP_D_1, OP_POP_D_2, OP_POP_D_3, OP_POP_D_4,
// 0 0100 flow control
OP_IFNOT_A, OP_IFNOT_B, OP_IFNOT_C, OP_IFNOT_D,
OP_IF_A, OP_IF_B, OP_IF_C, OP_IF_D,
OP_JUMP_A, OP_JUMP_B, OP_JUMP_C, OP_JUMP_D,
OP_CALL_A, OP_CALL_B, OP_CALL_C, OP_CALL_D,
// 0 0101 calls
OP_CALL_1, OP_CALL_2, OP_CALL_3, OP_CALL_4,
OP_CALL_5, OP_CALL_6, OP_CALL_7, OP_CALL_8,
OP_RETURN_1, OP_RETURN_2, OP_RETURN_3, OP_RETURN_4,
OP_RETURN_0, OP_WITH, OP_STATE_ft, OP_STATE_ftt,
// 0 0110 flow control 2
OP_IFA_A, OP_IFA_B, OP_IFA_C, OP_IFA_D,
OP_IFBE_A, OP_IFBE_B, OP_IFBE_C, OP_IFBE_D,
OP_IFB_A, OP_IFB_B, OP_IFB_C, OP_IFB_D,
OP_IFAE_A, OP_IFAE_B, OP_IFAE_C, OP_IFAE_D,
// 0 0111 interpreted vector multiplication
// C complex
// V vector (3d)
// Q quaternion
OP_DOT_CC_F, OP_DOT_VV_F, OP_DOT_QQ_F, OP_CROSS_VV_F,
OP_MUL_CC_F, OP_MUL_QV_F, OP_MUL_VQ_F, OP_MUL_QQ_F,
OP_DOT_CC_D, OP_DOT_VV_D, OP_DOT_QQ_D, OP_CROSS_VV_D,
OP_MUL_CC_D, OP_MUL_QV_D, OP_MUL_VQ_D, OP_MUL_QQ_D,
// comparison
// 0 1000 ==
OP_EQ_I_1, OP_EQ_I_2, OP_EQ_I_3, OP_EQ_I_4,
OP_EQ_F_1, OP_EQ_F_2, OP_EQ_F_3, OP_EQ_F_4,
OP_EQ_L_1, OP_EQ_L_2, OP_EQ_L_3, OP_EQ_L_4,
OP_EQ_D_1, OP_EQ_D_2, OP_EQ_D_3, OP_EQ_D_4,
// 0 1001 <
OP_LT_I_1, OP_LT_I_2, OP_LT_I_3, OP_LT_I_4,
OP_LT_F_1, OP_LT_F_2, OP_LT_F_3, OP_LT_F_4,
OP_LT_L_1, OP_LT_L_2, OP_LT_L_3, OP_LT_L_4,
OP_LT_D_1, OP_LT_D_2, OP_LT_D_3, OP_LT_D_4,
// 0 1010 >
OP_GT_I_1, OP_GT_I_2, OP_GT_I_3, OP_GT_I_4,
OP_GT_F_1, OP_GT_F_2, OP_GT_F_3, OP_GT_F_4,
OP_GT_L_1, OP_GT_L_2, OP_GT_L_3, OP_GT_L_4,
OP_GT_D_1, OP_GT_D_2, OP_GT_D_3, OP_GT_D_4,
// 0 1011 convert between signed integral and double(XXX how useful as vec?)
OP_CONV_ID_1, OP_CONV_ID_2, OP_CONV_ID_3, OP_CONV_ID_4,
OP_CONV_DI_1, OP_CONV_DI_2, OP_CONV_DI_3, OP_CONV_DI_4,
OP_CONV_LD_1, OP_CONV_LD_2, OP_CONV_LD_3, OP_CONV_LD_4,
OP_CONV_DL_1, OP_CONV_DL_2, OP_CONV_DL_3, OP_CONV_DL_4,
// comparison
// 0 1100 !=
OP_NE_I_1, OP_NE_I_2, OP_NE_I_3, OP_NE_I_4,
OP_NE_F_1, OP_NE_F_2, OP_NE_F_3, OP_NE_F_4,
OP_NE_L_1, OP_NE_L_2, OP_NE_L_3, OP_NE_L_4,
OP_NE_D_1, OP_NE_D_2, OP_NE_D_3, OP_NE_D_4,
// 0 1101 >=
OP_GE_I_1, OP_GE_I_2, OP_GE_I_3, OP_GE_I_4,
OP_GE_F_1, OP_GE_F_2, OP_GE_F_3, OP_GE_F_4,
OP_GE_L_1, OP_GE_L_2, OP_GE_L_3, OP_GE_L_4,
OP_GE_D_1, OP_GE_D_2, OP_GE_D_3, OP_GE_D_4,
// 0 1110 <=
OP_LE_I_1, OP_LE_I_2, OP_LE_I_3, OP_LE_I_4,
OP_LE_F_1, OP_LE_F_2, OP_LE_F_3, OP_LE_F_4,
OP_LE_L_1, OP_LE_L_2, OP_LE_L_3, OP_LE_L_4,
OP_LE_D_1, OP_LE_D_2, OP_LE_D_3, OP_LE_D_4,
// 0 1111 convert between signed integral sizes (XXX how useful as vec?)
OP_CONV_IL_1, OP_CONV_IL_2, OP_CONV_IL_3, OP_CONV_IL_4,
OP_CONV_LI_1, OP_CONV_LI_2, OP_CONV_LI_3, OP_CONV_LI_4,
OP_CONV_uU_1, OP_CONV_uU_2, OP_CONV_uU_3, OP_CONV_uU_4,
OP_CONV_Uu_1, OP_CONV_Uu_2, OP_CONV_Uu_3, OP_CONV_Uu_4,
// 1 0000 c = a * b
OP_MUL_I_1, OP_MUL_I_2, OP_MUL_I_3, OP_MUL_I_4,
OP_MUL_F_1, OP_MUL_F_2, OP_MUL_F_3, OP_MUL_F_4,
OP_MUL_L_1, OP_MUL_L_2, OP_MUL_L_3, OP_MUL_L_4,
OP_MUL_D_1, OP_MUL_D_2, OP_MUL_D_3, OP_MUL_D_4,
// 1 0001 c = a / b
OP_DIV_I_1, OP_DIV_I_2, OP_DIV_I_3, OP_DIV_I_4,
OP_DIV_F_1, OP_DIV_F_2, OP_DIV_F_3, OP_DIV_F_4,
OP_DIV_L_1, OP_DIV_L_2, OP_DIV_L_3, OP_DIV_L_4,
OP_DIV_D_1, OP_DIV_D_2, OP_DIV_D_3, OP_DIV_D_4,
// 1 0010 c = a % b (remainder, C %)
OP_REM_I_1, OP_REM_I_2, OP_REM_I_3, OP_REM_I_4,
OP_REM_F_1, OP_REM_F_2, OP_REM_F_3, OP_REM_F_4,
OP_REM_L_1, OP_REM_L_2, OP_REM_L_3, OP_REM_L_4,
OP_REM_D_1, OP_REM_D_2, OP_REM_D_3, OP_REM_D_4,
// 1 0011 c = a %% b (true modulo, python %)
OP_MOD_I_1, OP_MOD_I_2, OP_MOD_I_3, OP_MOD_I_4,
OP_MOD_F_1, OP_MOD_F_2, OP_MOD_F_3, OP_MOD_F_4,
OP_MOD_L_1, OP_MOD_L_2, OP_MOD_L_3, OP_MOD_L_4,
OP_MOD_D_1, OP_MOD_D_2, OP_MOD_D_3, OP_MOD_D_4,
// 1 0100 c = a + b
OP_ADD_I_1, OP_ADD_I_2, OP_ADD_I_3, OP_ADD_I_4,
OP_ADD_F_1, OP_ADD_F_2, OP_ADD_F_3, OP_ADD_F_4,
OP_ADD_L_1, OP_ADD_L_2, OP_ADD_L_3, OP_ADD_L_4,
OP_ADD_D_1, OP_ADD_D_2, OP_ADD_D_3, OP_ADD_D_4,
// 1 0101 c = a - b
OP_SUB_I_1, OP_SUB_I_2, OP_SUB_I_3, OP_SUB_I_4,
OP_SUB_F_1, OP_SUB_F_2, OP_SUB_F_3, OP_SUB_F_4,
OP_SUB_L_1, OP_SUB_L_2, OP_SUB_L_3, OP_SUB_L_4,
OP_SUB_D_1, OP_SUB_D_2, OP_SUB_D_3, OP_SUB_D_4,
// 1 0110 c = a << b (string ops mixed in)
OP_SHL_I_1, OP_SHL_I_2, OP_SHL_I_3, OP_SHL_I_4,
OP_EQ_S, OP_LT_S, OP_GT_S, OP_ADD_S,
OP_SHL_L_1, OP_SHL_L_2, OP_SHL_L_3, OP_SHL_L_4,
OP_CMP_S, OP_GE_S, OP_LE_S, OP_NOT_S, //OP_CMP_S doubles as NE
// 1 0111 c = a >> b
OP_SHR_I_1, OP_SHR_I_2, OP_SHR_I_3, OP_SHR_I_4,
OP_SHR_u_1, OP_SHR_u_2, OP_SHR_u_3, OP_SHR_u_4,
OP_SHR_L_1, OP_SHR_L_2, OP_SHR_L_3, OP_SHR_L_4,
OP_SHR_U_1, OP_SHR_U_2, OP_SHR_U_3, OP_SHR_U_4,
// 1 1000 c = a (& | ^) b or ~a (bitwise ops)
OP_BITAND_I_1, OP_BITAND_I_2, OP_BITAND_I_3, OP_BITAND_I_4,
OP_BITOR_I_1, OP_BITOR_I_2, OP_BITOR_I_3, OP_BITOR_I_4,
OP_BITXOR_I_1, OP_BITXOR_I_2, OP_BITXOR_I_3, OP_BITXOR_I_4,
OP_BITNOT_I_1, OP_BITNOT_I_2, OP_BITNOT_I_3, OP_BITNOT_I_4,
// 1 1001 < unsigned (float logic and bit ops mixed in)
OP_LT_u_1, OP_LT_u_2, OP_LT_u_3, OP_LT_u_4,
OP_BITAND_F, OP_BITOR_F, OP_BITXOR_F, OP_BITNOT_F,
OP_LT_U_1, OP_LT_U_2, OP_LT_U_3, OP_LT_U_4,
OP_AND_F, OP_OR_F, OP_XOR_F, OP_NOT_F,
// 1 1010 > unsigned
OP_GT_u_1, OP_GT_u_2, OP_GT_u_3, OP_GT_u_4,
OP_spare, OP_NOT_D, OP_NOT_V, OP_NOT_Q,
OP_GT_U_1, OP_GT_U_2, OP_GT_U_3, OP_GT_U_4,
OP_EQ_V, OP_EQ_Q, OP_NE_V, OP_NE_Q,
// 1 1011 lea, with, etc
OP_LEA_A, OP_LEA_B, OP_LEA_C, OP_LEA_D,
OP_LEA_E, OP_ANY_2, OP_ANY_3, OP_ANY_4,
OP_PUSHREG, OP_ALL_2, OP_ALL_3, OP_ALL_4,
OP_POPREG, OP_NONE_2, OP_NONE_3, OP_NONE_4,
// 1 1100 c = a (&& || ^^) b or !a (logical ops (no short circuit))
OP_AND_I_1, OP_AND_I_2, OP_AND_I_3, OP_AND_I_4,
OP_OR_I_1, OP_OR_I_2, OP_OR_I_3, OP_OR_I_4,
OP_XOR_I_1, OP_XOR_I_2, OP_XOR_I_3, OP_XOR_I_4,
OP_NOT_I_1, OP_NOT_I_2, OP_NOT_I_3, OP_NOT_I_4,
// 1 1101 >= unsigned with float shifts and moves mixed in
OP_GE_u_1, OP_GE_u_2, OP_GE_u_3, OP_GE_u_4,
OP_SHL_F, OP_MOVE_I, OP_MOVE_P, OP_MOVE_PI,
OP_GE_U_1, OP_GE_U_2, OP_GE_U_3, OP_GE_U_4,
OP_SHR_F, OP_MEMSET_I, OP_MEMSET_P, OP_MEMSET_PI,
// 1 1110 <= unsigned with scale and swizzle mixed in
OP_LE_u_1, OP_LE_u_2, OP_LE_u_3, OP_LE_u_4,
OP_SWIZZLE_F, OP_SCALE_F_2, OP_SCALE_F_3, OP_SCALE_F_4,
OP_LE_U_1, OP_LE_U_2, OP_LE_U_3, OP_LE_U_4,
OP_SWIZZLE_D, OP_SCALE_D_2, OP_SCALE_D_3, OP_SCALE_D_4,
// 1 1111 convert between integral and float (XXX how useful as vec?)
OP_CONV_IF_1, OP_CONV_IF_2, OP_CONV_IF_3, OP_CONV_IF_4,
OP_CONV_FI_1, OP_CONV_FI_2, OP_CONV_FI_3, OP_CONV_FI_4,
OP_CONV_FD_1, OP_CONV_FD_2, OP_CONV_FD_3, OP_CONV_FD_4,
OP_CONV_DF_1, OP_CONV_DF_2, OP_CONV_DF_3, OP_CONV_DF_4,
} pr_opcode_e;
#define OP_A_SHIFT (9)
#define OP_B_SHIFT (11)
#define OP_C_SHIFT (13)
#define OP_A_BASE (3 << OP_A_SHIFT)
#define OP_B_BASE (3 << OP_B_SHIFT)
#define OP_C_BASE (3 << OP_C_SHIFT)
typedef enum {
OP_with_zero,
OP_with_base,
OP_with_stack,
OP_with_entity,
} pr_with_e;
typedef struct v6p_opcode_s {
const char *name;
const char *opname;
@ -437,7 +619,7 @@ const v6p_opcode_t *PR_v6p_Opcode (pr_ushort_t opcode) __attribute__((const));
void PR_Opcode_Init (void); // idempotent
typedef struct dstatement_s {
pr_opcode_v6p_e op:16;
pr_opcode_e op:16; // will be pr_opcode_v6p_e for older progs
pr_ushort_t a,b,c;
} GCC_STRUCT dstatement_t;

View file

@ -1793,6 +1793,8 @@ extern const char *pr_gametype;
#define MAX_STACK_DEPTH 64
#define LOCALSTACK_SIZE 4096
#define PR_RS_SLOTS 16
#define PR_BASE_IND(o, b) (((o) & OP_##b##_BASE) >> OP_##b##_SHIFT)
#define PR_BASE(p, s, b) (p->pr_bases[PR_BASE_IND(s->op, b)])
typedef struct strref_s strref_t;
@ -1876,6 +1878,7 @@ struct progs_s {
dstatement_t *pr_statements;
pr_type_t *pr_globals;
unsigned globals_size;
pr_uivec4_t pr_bases; ///< base registers (index in opcode)
///@}
/// \name parameter block

View file

@ -44,6 +44,12 @@
#include "QF/sys.h"
#include "QF/zone.h"
#include "QF/simd/vec2d.h"
#include "QF/simd/vec2f.h"
#include "QF/simd/vec2i.h"
#include "QF/simd/vec4d.h"
#include "QF/simd/vec4f.h"
#include "QF/simd/vec4i.h"
#include "compat.h"
@ -1713,6 +1719,917 @@ op_call:
exit_program:
}
#define MM(type) (*((pr_##type##_t *) (mm)))
#define STK(type) (*((pr_##type##_t *) (stk)))
static pr_type_t *
pr_entity_mode (progs_t *pr, const dstatement_t *st, int shift)
{
pr_type_t *op_a = pr->pr_globals + st->a + PR_BASE (pr, st, A);
pr_type_t *op_b = pr->pr_globals + st->b + PR_BASE (pr, st, A);
int mm_ind = (st->op >> shift) & 3;
pointer_t edict_area = pr->pr_edict_area - pr->pr_globals;
pointer_t mm_offs = 0;
switch (mm_ind) {
case 0:
// entity.field (equivalent to OP_LOAD_t_v6p)
mm_offs = edict_area + OPA(uint) + OPB(uint);
break;
case 1:
// simple pointer dereference: *a
mm_offs = OPA(uint);
break;
case 2:
// constant indexed pointer: *a + b
mm_offs = OPA(uint) + st->b;
break;
case 3:
// verible indexed pointer: *a + *b (supports -ve offset)
mm_offs = OPA(uint) + OPB(int);
break;
}
return pr->pr_globals + mm_offs;
}
static pr_type_t *
pr_address_mode (progs_t *pr, const dstatement_t *st, int shift)
{
pr_type_t *op_a = pr->pr_globals + st->a + PR_BASE (pr, st, A);
pr_type_t *op_b = pr->pr_globals + st->b + PR_BASE (pr, st, A);
int mm_ind = (st->op >> shift) & 3;
pointer_t mm_offs = 0;
switch (mm_ind) {
case 0:
// regular global access
mm_offs = op_a - pr->pr_globals;
break;
case 1:
// simple pointer dereference: *a
mm_offs = OPA(uint);
break;
case 2:
// constant indexed pointer: *a + b
mm_offs = OPA(uint) + st->b;
break;
case 3:
// verible indexed pointer: *a + *b (supports -ve offset)
mm_offs = OPA(uint) + OPB(int);
break;
}
return pr->pr_globals + mm_offs;
}
static pr_pointer_t
pr_jump_mode (progs_t *pr, const dstatement_t *st)
{
pr_type_t *op_a = pr->pr_globals + st->a + PR_BASE (pr, st, A);
pr_type_t *op_b = pr->pr_globals + st->b + PR_BASE (pr, st, A);
int jump_ind = st->op & 3;
pointer_t jump_offs = pr->pr_xstatement;
switch (jump_ind) {
case 0:
// instruction relative offset
jump_offs = jump_offs + st->a;
break;
case 1:
// simple pointer dereference: *a
jump_offs = OPA(uint);
break;
case 2:
// constant indexed pointer: *a + b
jump_offs = OPA(uint) + st->b;
break;
case 3:
// verible indexed pointer: *a + *b (supports -ve offset)
jump_offs = OPA(uint) + OPB(int);
break;
}
return jump_offs - 1; // for st++
}
static pr_pointer_t __attribute__((pure))
pr_with (progs_t *pr, const dstatement_t *st)
{
pr_type_t *op_b = pr->pr_globals + st->b + PR_BASE (pr, st, A);
pointer_t edict_area = pr->pr_edict_area - pr->pr_globals;
switch (st->a) {
case 0:
// hard-0 base
return st->b;
case 1:
// relative to current base
return op_b - pr->pr_globals;
case 2:
// relative to stack (-ve offset)
return *pr->globals.stack + (pr_short_t) st->b;
case 3:
// relative to edict_area (+ve only)
return edict_area + st->b;
}
PR_RunError (pr, "Invalid with index: %u", st->a);
}
static pr_type_t *
pr_stack_push (progs_t *pr)
{
// keep the stack 16-byte aligned
pointer_t stack = *pr->globals.stack - 4;
pr_type_t *stk = pr->pr_globals + stack;
if (pr_boundscheck->int_val) {
check_stack_pointer (pr, stack, 4);
}
*pr->globals.stack = stack;
return stk;
}
static pr_type_t *
pr_stack_pop (progs_t *pr)
{
pointer_t stack = *pr->globals.stack;
pr_type_t *stk = pr->pr_globals + stack;
if (pr_boundscheck->int_val) {
check_stack_pointer (pr, stack, 4);
}
// keep the stack 16-byte aligned
*pr->globals.stack = stack + 4;
return stk;
}
static void
pr_exec_ruamoko (progs_t *pr, int exitdepth)
{
int profile, startprofile;
dstatement_t *st;
pr_type_t old_val = {0};
// make a stack frame
startprofile = profile = 0;
st = pr->pr_statements + pr->pr_xstatement;
if (pr->watch) {
old_val = *pr->watch;
}
while (1) {
st++;
++pr->pr_xstatement;
if (pr->pr_xstatement != st - pr->pr_statements)
PR_RunError (pr, "internal error");
if (++profile > 1000000 && !pr->no_exec_limit) {
PR_RunError (pr, "runaway loop error");
}
if (pr->pr_trace) {
if (pr->debug_handler) {
pr->debug_handler (prd_trace, 0, pr->debug_data);
} else {
PR_PrintStatement (pr, st, 1);
}
}
if (st->op & OP_BREAK) {
if (pr->debug_handler) {
pr->debug_handler (prd_breakpoint, 0, pr->debug_data);
} else {
PR_RunError (pr, "breakpoint hit");
}
}
pointer_t st_a = st->a + PR_BASE (pr, st, A);
pointer_t st_b = st->b + PR_BASE (pr, st, A);
pointer_t st_c = st->c + PR_BASE (pr, st, A);
pr_type_t *op_a = pr->pr_globals + st_a;
pr_type_t *op_b = pr->pr_globals + st_b;
pr_type_t *op_c = pr->pr_globals + st_c;
pr_type_t *stk;
pr_type_t *mm;
func_t function;
pr_opcode_e st_op = st->op & ~(OP_BREAK|OP_A_BASE|OP_B_BASE|OP_C_BASE);
switch (st_op) {
// 0 0000
case OP_LOAD_E_1:
case OP_LOAD_B_1:
case OP_LOAD_C_1:
case OP_LOAD_D_1:
mm = pr_entity_mode (pr, st, 2);
OPC(int) = MM(int);
break;
case OP_LOAD_E_2:
case OP_LOAD_B_2:
case OP_LOAD_C_2:
case OP_LOAD_D_2:
mm = pr_entity_mode (pr, st, 2);
OPC(ivec2) = MM(ivec2);
break;
case OP_LOAD_E_3:
case OP_LOAD_B_3:
case OP_LOAD_C_3:
case OP_LOAD_D_3:
mm = pr_entity_mode (pr, st, 2);
VectorCopy (&MM(int), &OPC(int));
break;
case OP_LOAD_E_4:
case OP_LOAD_B_4:
case OP_LOAD_C_4:
case OP_LOAD_D_4:
mm = pr_entity_mode (pr, st, 2);
OPC(ivec4) = MM(ivec4);
break;
// 0 0001
case OP_STORE_A_1:
case OP_STORE_B_1:
case OP_STORE_C_1:
case OP_STORE_D_1:
mm = pr_address_mode (pr, st, 2);
MM(int) = OPC(int);
break;
case OP_STORE_A_2:
case OP_STORE_B_2:
case OP_STORE_C_2:
case OP_STORE_D_2:
mm = pr_address_mode (pr, st, 2);
MM(ivec2) = OPC(ivec2);
break;
case OP_STORE_A_3:
case OP_STORE_B_3:
case OP_STORE_C_3:
case OP_STORE_D_3:
mm = pr_address_mode (pr, st, 2);
VectorCopy (&OPC(int), &MM(int));
break;
case OP_STORE_A_4:
case OP_STORE_B_4:
case OP_STORE_C_4:
case OP_STORE_D_4:
mm = pr_address_mode (pr, st, 2);
MM(ivec4) = OPC(ivec4);
break;
// 0 0010
case OP_PUSH_A_1:
case OP_PUSH_B_1:
case OP_PUSH_C_1:
case OP_PUSH_D_1:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_push (pr);
STK(int) = MM(int);
break;
case OP_PUSH_A_2:
case OP_PUSH_B_2:
case OP_PUSH_C_2:
case OP_PUSH_D_2:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_push (pr);
STK(ivec2) = MM(ivec2);
break;
case OP_PUSH_A_3:
case OP_PUSH_B_3:
case OP_PUSH_C_3:
case OP_PUSH_D_3:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_push (pr);
VectorCopy (&MM(int), &STK(int));
break;
case OP_PUSH_A_4:
case OP_PUSH_B_4:
case OP_PUSH_C_4:
case OP_PUSH_D_4:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_push (pr);
STK(ivec4) = MM(ivec4);
break;
// 0 0011
case OP_POP_A_1:
case OP_POP_B_1:
case OP_POP_C_1:
case OP_POP_D_1:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_pop (pr);
MM(int) = STK(int);
break;
case OP_POP_A_2:
case OP_POP_B_2:
case OP_POP_C_2:
case OP_POP_D_2:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_pop (pr);
MM(ivec2) = STK(ivec2);
break;
case OP_POP_A_3:
case OP_POP_B_3:
case OP_POP_C_3:
case OP_POP_D_3:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_pop (pr);
VectorCopy (&STK(int), &MM(int));
break;
case OP_POP_A_4:
case OP_POP_B_4:
case OP_POP_C_4:
case OP_POP_D_4:
mm = pr_address_mode (pr, st, 2);
stk = pr_stack_pop (pr);
MM(ivec4) = STK(ivec4);
break;
// 0 0100
case OP_IFNOT_A:
case OP_IFNOT_B:
case OP_IFNOT_C:
case OP_IFNOT_D:
if (!OPC(int)) {
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
}
break;
case OP_IF_A:
case OP_IF_B:
case OP_IF_C:
case OP_IF_D:
if (OPC(int)) {
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
}
break;
case OP_JUMP_A:
case OP_JUMP_B:
case OP_JUMP_C:
case OP_JUMP_D:
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
break;
case OP_CALL_A:
case OP_CALL_B:
case OP_CALL_C:
case OP_CALL_D:
mm = pr_address_mode (pr, st, 0);
function = mm->func_var;
pr->pr_argc = 0;
op_call:
pr->pr_xfunction->profile += profile - startprofile;
startprofile = profile;
PR_CallFunction (pr, function);
st = pr->pr_statements + pr->pr_xstatement;
break;
// 0 0101
case OP_CALL_2: case OP_CALL_3: case OP_CALL_4:
case OP_CALL_5: case OP_CALL_6: case OP_CALL_7: case OP_CALL_8:
pr->pr_params[1] = op_c;
goto op_call_n;
case OP_CALL_1:
pr->pr_params[1] = pr->pr_real_params[1];
op_call_n:
pr->pr_params[0] = op_b;
function = op_a->func_var;
pr->pr_argc = st->op - OP_CALL_1 + 1;
goto op_call;
case OP_RETURN_4:
memcpy (&R_INT (pr), op_a, 4 * sizeof (*op_a));
goto op_return;
case OP_RETURN_3:
memcpy (&R_INT (pr), op_a, 3 * sizeof (*op_a));
goto op_return;
case OP_RETURN_2:
memcpy (&R_INT (pr), op_a, 2 * sizeof (*op_a));
goto op_return;
case OP_RETURN_1:
memcpy (&R_INT (pr), op_a, 1 * sizeof (*op_a));
goto op_return;
case OP_RETURN_0:
op_return:
pr->pr_xfunction->profile += profile - startprofile;
startprofile = profile;
PR_LeaveFunction (pr, pr->pr_depth == exitdepth);
st = pr->pr_statements + pr->pr_xstatement;
if (pr->pr_depth== exitdepth) {
if (pr->pr_trace && pr->pr_depth <= pr->pr_trace_depth) {
pr->pr_trace = false;
}
goto exit_program;
}
break;
case OP_WITH:
pr->pr_bases[st->c] = pr_with (pr, st);
break;
case OP_STATE_ft:
{
int self = *pr->globals.self;
int nextthink = pr->fields.nextthink + self;
int frame = pr->fields.frame + self;
int think = pr->fields.think + self;
float time = *pr->globals.time + 0.1;
pr->pr_edict_area[nextthink].float_var = time;
pr->pr_edict_area[frame].float_var = OPA(float);
pr->pr_edict_area[think].func_var = op_b->func_var;
}
break;
case OP_STATE_ftt:
{
int self = *pr->globals.self;
int nextthink = pr->fields.nextthink + self;
int frame = pr->fields.frame + self;
int think = pr->fields.think + self;
float time = *pr->globals.time + OPC(float);
pr->pr_edict_area[nextthink].float_var = time;
pr->pr_edict_area[frame].float_var = OPA(float);
pr->pr_edict_area[think].func_var = op_b->func_var;
}
break;
// 0 0110
case OP_IFA_A:
case OP_IFA_B:
case OP_IFA_C:
case OP_IFA_D:
if (OPC(int) > 0) {
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
}
break;
case OP_IFBE_A:
case OP_IFBE_B:
case OP_IFBE_C:
case OP_IFBE_D:
if (OPC(int) <= 0) {
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
}
break;
case OP_IFB_A:
case OP_IFB_B:
case OP_IFB_C:
case OP_IFB_D:
if (OPC(int) < 0) {
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
}
break;
case OP_IFAE_A:
case OP_IFAE_B:
case OP_IFAE_C:
case OP_IFAE_D:
if (OPC(int) >= 0) {
pr->pr_xstatement = pr_jump_mode (pr, st);
st = pr->pr_statements + pr->pr_xstatement;
}
break;
// 0 0111
case OP_DOT_CC_F:
OPC(vec2) = dot2f (OPA(vec2), OPB(vec2));
break;
case OP_DOT_VV_F:
{
vec_t d = DotProduct (&OPA(float),
&OPB(float));
VectorSet (d, d, d, &OPC(float));
}
break;
case OP_DOT_QQ_F:
OPC(vec4) = dotf (OPA(vec4), OPB(vec4));
break;
case OP_CROSS_VV_F:
{
pr_vec4_t a = loadvec3f (&OPA(float));
pr_vec4_t b = loadvec3f (&OPB(float));
pr_vec4_t c = crossf (a, b);
storevec3f (&OPC(float), c);
}
break;
case OP_MUL_CC_F:
OPC(vec2) = cmulf (OPA(vec2), OPB(vec2));
break;
case OP_MUL_QV_F:
{
pr_vec4_t v = loadvec3f (&OPB(float));
v = qvmulf (OPA(vec4), v);
storevec3f (&OPC(float), v);
}
break;
case OP_MUL_VQ_F:
{
pr_vec4_t v = loadvec3f (&OPA(float));
v = vqmulf (v, OPB(vec4));
storevec3f (&OPC(float), v);
}
break;
case OP_MUL_QQ_F:
OPC(vec4) = qmulf (OPA(vec4), OPB(vec4));
break;
case OP_DOT_CC_D:
OPC(dvec2) = dot2d (OPA(dvec2), OPB(dvec2));
break;
case OP_DOT_VV_D:
{
double d = DotProduct (&OPA(double),
&OPB(double));
VectorSet (d, d, d, &OPC(double));
}
break;
case OP_DOT_QQ_D:
OPC(dvec4) = dotd (OPA(dvec4), OPB(dvec4));
break;
case OP_CROSS_VV_D:
{
pr_dvec4_t a = loadvec3d (&OPA(double));
pr_dvec4_t b = loadvec3d (&OPB(double));
pr_dvec4_t c = crossd (a, b);
storevec3d (&OPC(double), c);
}
break;
case OP_MUL_CC_D:
OPC(dvec2) = cmuld (OPA(dvec2), OPB(dvec2));
break;
case OP_MUL_QV_D:
{
pr_dvec4_t v = loadvec3d (&OPB(double));
v = qvmuld (OPA(dvec4), v);
storevec3d (&OPC(double), v);
}
break;
case OP_MUL_VQ_D:
{
pr_dvec4_t v = loadvec3d (&OPA(double));
v = vqmuld (v, OPB(dvec4));
storevec3d (&OPC(double), v);
}
break;
case OP_MUL_QQ_D:
OPC(dvec4) = qmuld (OPA(dvec4), OPB(dvec4));
break;
#define OP_cmp_1(OP, T, rt, cmp, ct) \
case OP_##OP##_##T##_1: \
OPC(rt) = -(OPA(ct) cmp OPB(ct)); \
break
#define OP_cmp_2(OP, T, rt, cmp, ct) \
case OP_##OP##_##T##_2: \
OPC(rt) = (OPA(ct) cmp OPB(ct)); \
break
#define OP_cmp_3(OP, T, rt, cmp, ct) \
case OP_##OP##_##T##_3: \
VectorCompCompare (&OPC(rt), -, &OPA(ct), cmp, &OPB(ct)); \
break;
#define OP_cmp_4(OP, T, rt, cmp, ct) \
case OP_##OP##_##T##_4: \
OPC(rt) = (OPA(ct) cmp OPB(ct)); \
break
#define OP_cmp_T(OP, T, rt1, rt2, rt4, cmp, ct1, ct2, ct4) \
OP_cmp_1 (OP, T, rt1, cmp, ct1); \
OP_cmp_2 (OP, T, rt2, cmp, ct2); \
OP_cmp_3 (OP, T, rt1, cmp, ct1); \
OP_cmp_4 (OP, T, rt4, cmp, ct4)
#define OP_cmp(OP, cmp) \
OP_cmp_T (OP, I, int, ivec2, ivec4, cmp, int, ivec2, ivec4); \
OP_cmp_T (OP, F, int, ivec2, ivec4, cmp, float, vec2, vec4); \
OP_cmp_T (OP, L, long, lvec2, lvec4, cmp, long, lvec2, lvec4); \
OP_cmp_T (OP, D, long, lvec2, lvec4, cmp, double, dvec2, dvec4)
// 0 1000
OP_cmp(EQ, ==);
// 0 1001
OP_cmp(LT, <);
// 0 1010
OP_cmp(GT, >);
// 0 1011
//FIXME conversion 1
// 0 1100
OP_cmp(NE, !=);
// 0 1101
OP_cmp(GE, >=);
// 0 1110
OP_cmp(LE, <=);
// 0 1011
//FIXME conversion 2
#define OP_op_1(OP, T, t, op) \
case OP_##OP##_##T##_1: \
OPC(t) = (OPA(t) op OPB(t)); \
break
#define OP_op_2(OP, T, t, op) \
case OP_##OP##_##T##_2: \
OPC(t) = (OPA(t) op OPB(t)); \
break
#define OP_op_3(OP, T, t, op) \
case OP_##OP##_##T##_3: \
VectorCompOp (&OPC(t), &OPA(t), op, &OPB(t)); \
break;
#define OP_op_4(OP, T, t, op) \
case OP_##OP##_##T##_4: \
OPC(t) = (OPA(t) op OPB(t)); \
break
#define OP_op_T(OP, T, t1, t2, t4, op) \
OP_op_1 (OP, T, t1, op); \
OP_op_2 (OP, T, t2, op); \
OP_op_3 (OP, T, t1, op); \
OP_op_4 (OP, T, t4, op)
#define OP_op(OP, op) \
OP_op_T (OP, I, int, ivec2, ivec4, op); \
OP_op_T (OP, F, float, vec2, vec4, op); \
OP_op_T (OP, L, long, lvec2, lvec4, op); \
OP_op_T (OP, D, double, dvec2, dvec4, op)
#define OP_uop_1(OP, T, t, op) \
case OP_##OP##_##T##_1: \
OPC(t) = op (OPA(t)); \
break
#define OP_uop_2(OP, T, t, op) \
case OP_##OP##_##T##_2: \
OPC(t) = op (OPA(t)); \
break
#define OP_uop_3(OP, T, t, op) \
case OP_##OP##_##T##_3: \
VectorCompUop (&OPC(t), op, &OPA(t)); \
break;
#define OP_uop_4(OP, T, t, op) \
case OP_##OP##_##T##_4: \
OPC(t) = op (OPA(t)); \
break
#define OP_uop_T(OP, T, t1, t2, t4, op) \
OP_uop_1 (OP, T, t1, op); \
OP_uop_2 (OP, T, t2, op); \
OP_uop_3 (OP, T, t1, op); \
OP_uop_4 (OP, T, t4, op)
// 1 0000
OP_op(MUL, *);
// 1 0001
OP_op(DIV, /);
#define OP_store(d, s) *(d) = s
#define OP_remmod_T(OP, T, n, t, l, f, s) \
case OP_##OP##_##T##_##n: \
{ \
__auto_type a = l (&OPA(t)); \
__auto_type b = l (&OPB(t)); \
s (&OPC(t), a - b * f(a / b)); \
} \
break
#define OP_rem_T(T, n, t, l, f, s) \
OP_remmod_T(REM, T, n, t, l, f, s)
// 1 0010
OP_op_T (REM, I, int, ivec2, ivec4, %);
OP_rem_T (F, 1, float, *, truncf, OP_store);
OP_rem_T (F, 2, vec2, *, vtrunc2f, OP_store);
OP_rem_T (F, 3, float, loadvec3f, vtrunc4f, storevec3f);
OP_rem_T (F, 4, vec4, *, vtrunc4f, OP_store);
OP_op_T (REM, L, long, lvec2, lvec4, %);
OP_rem_T (D, 1, double, *, trunc, OP_store);
OP_rem_T (D, 2, dvec2, *, vtrunc2d, OP_store);
OP_rem_T (D, 3, double, loadvec3d, vtrunc4d, storevec3d);
OP_rem_T (D, 4, dvec4, *, vtrunc4d, OP_store);
// implement true modulo for integers:
// 5 mod 3 = 2
// -5 mod 3 = 1
// 5 mod -3 = -1
// -5 mod -3 = -2
#define OP_mod_Ti(T, n, t, l, m, s) \
case OP_MOD_##T##_##n: \
{ \
__auto_type a = l(&OPA(t)); \
__auto_type b = l(&OPB(t)); \
__auto_type c = a % b; \
/* % is really remainder and so has the same sign rules */\
/* as division: -5 % 3 = -2, so need to add b (3 here) */\
/* if c's sign is incorrect, but only if c is non-zero */\
__auto_type mask = m((a ^ b) < 0); \
mask &= m(c != 0); \
s(&OPC(t), c + (mask & b)); \
} \
break
// floating point modulo is so much easier :P (just use floor instead of trunc)
#define OP_mod_Tf(T, n, t, l, f, s) \
OP_remmod_T(MOD, T, n, t, l, f, s)
// 1 0011
OP_mod_Ti (I, 1, int, *, -, OP_store);
OP_mod_Ti (I, 2, ivec2, *, +, OP_store);
OP_mod_Ti (I, 3, int, loadvec3i, +, storevec3i);
OP_mod_Ti (I, 4, ivec4, *, +, OP_store);
OP_mod_Tf (F, 1, float, *, floorf, OP_store);
OP_mod_Tf (F, 2, vec2, *, vfloor2f, OP_store);
OP_mod_Tf (F, 3, float, loadvec3f, vfloor4f, storevec3f);
OP_mod_Tf (F, 4, vec4, *, vfloor4f, OP_store);
OP_mod_Ti (L, 1, long, *, -, OP_store);
OP_mod_Ti (L, 2, ivec2, *, +, OP_store);
OP_mod_Ti (L, 3, long, loadvec3l, +, storevec3l);
OP_mod_Ti (L, 4, ivec4, *, +, OP_store);
OP_mod_Tf (D, 1, double, *, floor, OP_store);
OP_mod_Tf (D, 2, dvec2, *, vfloor2d, OP_store);
OP_mod_Tf (D, 3, double, loadvec3d, vfloor4d, storevec3d);
OP_mod_Tf (D, 4, dvec4, *, vfloor4d, OP_store);
// 1 0100
OP_op(ADD, +);
// 1 0101
OP_op(SUB, -);
// 1 0110
OP_op_T (SHL, I, int, ivec2, ivec4, <<);
OP_op_T (SHL, L, long, lvec2, lvec4, <<);
case OP_EQ_S:
case OP_LT_S:
case OP_GT_S:
case OP_CMP_S:
case OP_GE_S:
case OP_LE_S:
{
int cmp = strcmp (PR_GetString (pr, OPA(string)),
PR_GetString (pr, OPB(string)));
switch (st_op) {
case OP_EQ_S: cmp = (cmp == 0); break;
case OP_LT_S: cmp = (cmp < 0); break;
case OP_GT_S: cmp = (cmp > 0); break;
case OP_GE_S: cmp = (cmp >= 0); break;
case OP_LE_S: cmp = (cmp <= 0); break;
case OP_NOT_S: break;
default: break;
}
OPC(int) = cmp;
}
break;
case OP_ADD_S:
OPC(string) = PR_CatStrings(pr, PR_GetString (pr, OPA(string)),
PR_GetString (pr, OPB(string)));
break;
case OP_NOT_S:
OPC(int) = !OPA(string) || !*PR_GetString (pr, OPA(string));
break;
// 1 0111
OP_op_T (SHR, I, int, ivec2, ivec4, >>);
OP_op_T (SHR, u, uint, uivec2, uivec4, >>);
OP_op_T (SHR, L, long, lvec2, lvec4, >>);
OP_op_T (SHR, U, ulong, ulvec2, ulvec4, >>);
// 1 1000
OP_op_T (BITAND, I, int, ivec2, ivec4, &);
OP_op_T (BITOR, I, int, ivec2, ivec4, |);
OP_op_T (BITXOR, I, int, ivec2, ivec4, ^);
OP_uop_T (BITNOT, I, int, ivec2, ivec4, ~);
// 1 1001
OP_op_T (LT, u, uint, uivec2, uivec4, <);
//FIXME float ops
OP_op_T (LT, U, ulong, ulvec2, ulvec4, <);
//FIXME float ops
// 1 1010
OP_op_T (GT, u, uint, uivec2, uivec4, >);
//FIXME misc ops
OP_op_T (GT, U, ulong, ulvec2, ulvec4, >);
//FIXME misc ops
// 1 1011
case OP_LEA_A:
case OP_LEA_B:
case OP_LEA_C:
case OP_LEA_D:
mm = pr_address_mode (pr, st, 0);
op_c->pointer_var = mm - pr->pr_globals;
break;
case OP_LEA_E:
// ensures OP_LEA_E is compatible with OP_LOAD_E_n and thus
// with pr_entity_mode
mm = __builtin_choose_expr (
(OP_LEA_E & 3) == 0,
pr_entity_mode (pr, st, 0),
(void) 0);
op_c->pointer_var = mm - pr->pr_globals;
break;
case OP_ANY_2:
OPC(int) = any2i (OPA(ivec2));
break;
case OP_ANY_3:
{
__auto_type v = loadvec3i (&OPA(int));
OPC(int) = any4i (v);
}
break;
case OP_ANY_4:
OPC(int) = any4i (OPA(ivec4));
break;
case OP_PUSHREG:
stk = pr_stack_push (pr);
STK(uivec4) = pr->pr_bases;
break;
case OP_ALL_2:
OPC(int) = all2i (OPA(ivec2));
break;
case OP_ALL_3:
{
__auto_type v = loadvec3i (&OPA(int));
v[3] = -1;
OPC(int) = all4i (v);
}
break;
case OP_ALL_4:
OPC(int) = all4i (OPA(ivec4));
break;
case OP_POPREG:
stk = pr_stack_pop (pr);
pr->pr_bases = STK(uivec4);
break;
case OP_NONE_2:
OPC(int) = none2i (OPA(ivec2));
break;
case OP_NONE_3:
{
__auto_type v = loadvec3i (&OPA(int));
OPC(int) = none4i (v);
}
break;
case OP_NONE_4:
OPC(int) = none4i (OPA(ivec4));
break;
#define OP_bool_n(OP, t, n, op, m) \
case OP_##OP##_I_##n: \
OPC(t) = m((OPA(t) != 0) op (OPB(t) != 0)); \
break
#define OP_bool_3(OP, t, n, op, m) \
case OP_##OP##_I_##n: \
{ \
__auto_type a = loadvec3i (&OPA(int)); \
__auto_type b = loadvec3i (&OPB(int)); \
storevec3i (&OPC(int), (a != 0) op (b != 0)); \
} \
break
#define OP_bool(OP, op) \
OP_bool_n (OP, int, 1, op, -); \
OP_bool_n (OP, ivec2, 2, op, +); \
OP_bool_3 (OP, int, 3, op, +); \
OP_bool_n (OP, ivec4, 4, op, +)
#define OP_not_n(OP, t, n, m) \
case OP_##OP##_I_##n: \
OPC(t) = m((OPA(t) == 0)); \
break
#define OP_not_3(OP, t, n, m) \
case OP_##OP##_I_##n: \
{ \
__auto_type a = loadvec3i (&OPA(int)); \
storevec3i (&OPC(int), (a == 0)); \
} \
break
// 1 1100
OP_bool (AND, &);
OP_bool (OR, |);
OP_bool (XOR, ^);
OP_not_n (NOT, int, 1, -);
OP_not_n (NOT, ivec2, 2, +);
OP_not_3 (NOT, int, 3, +);
OP_not_n (NOT, ivec4, 4, +);
// 1 1101
OP_op_T (GE, u, uint, uivec2, uivec4, >=);
//FIXME float shift
case OP_MOVE_I:
memmove (op_c, op_a, st->b * sizeof (pr_type_t));
break;
case OP_MOVE_P:
memmove (pr->pr_globals + OPC(int), pr->pr_globals + OPA(int),
OPB(uint) * sizeof (pr_type_t));
break;
case OP_MOVE_PI:
memmove (pr->pr_globals + OPC(int), pr->pr_globals + OPA(int),
st->b * sizeof (pr_type_t));
break;
OP_op_T (GE, U, ulong, ulvec2, ulvec4, >=);
//FIXME float shift
case OP_MEMSET_I:
memset (op_c, OPA(int), st->b * sizeof (pr_type_t));
break;
case OP_MEMSET_P:
memset (pr->pr_globals + OPC(int), OPA(int),
OPB(uint) * sizeof (pr_type_t));
break;
case OP_MEMSET_PI:
memset (pr->pr_globals + OPC(int), OPA(int),
st->b * sizeof (pr_type_t));
break;
// 1 1110
OP_op_T (LE, u, uint, uivec2, uivec4, <=);
//FIXME misc ops
OP_op_T (LE, U, ulong, ulvec2, ulvec4, <=);
//FIXME misc ops
// 1 1111
//FIXME conversion 3
default:
PR_RunError (pr, "Bad opcode %i", st->op);
}
if (pr->watch && pr->watch->integer_var != old_val.integer_var) {
if (!pr->wp_conditional
|| pr->watch->integer_var == pr->wp_val.integer_var) {
if (pr->debug_handler) {
pr->debug_handler (prd_watchpoint, 0, pr->debug_data);
} else {
PR_RunError (pr, "watchpoint hit: %d -> %d",
old_val.integer_var, pr->watch->integer_var);
}
}
old_val.integer_var = pr->watch->integer_var;
}
}
exit_program:
}
/*
PR_ExecuteProgram
@ -1735,6 +2652,8 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
}
if (1) {
pr_exec_quakec (pr, exitdepth);
} else {
pr_exec_ruamoko (pr, exitdepth);
}
exit_program:
if (pr->debug_handler) {

View file

@ -1544,7 +1544,7 @@ is_vector_parameter_store (progs_t *pr, dstatement_t *st,
{
int i;
if (st->op != OP_STORE_V_v6p)
if ((pr_opcode_v6p_e) st->op != OP_STORE_V_v6p)
return 0;
if (operand != st->a)
return 0;
@ -1653,13 +1653,15 @@ PR_Check_Opcodes (progs_t *pr)
if (0 && !pr_boundscheck->int_val) {
for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements;
st++, i++) {
op = PR_v6p_Opcode (st->op);
pr_opcode_v6p_e st_op = st->op;
op = PR_v6p_Opcode (st_op);
if (!op) {
PR_Error (pr, "PR_Check_Opcodes: unknown opcode %d at "
"statement %ld", st->op,
"statement %ld", st_op,
(long)(st - pr->pr_statements));
}
if ((st->op == OP_STATE_v6p || st->op == OP_STATE_F_v6p) && !state_ok) {
if ((st_op == OP_STATE_v6p || st_op == OP_STATE_F_v6p)
&& !state_ok) {
PR_Error (pr, "PR_Check_Opcodes: %s used with missing fields "
"or globals", op->opname);
}
@ -1672,13 +1674,14 @@ PR_Check_Opcodes (progs_t *pr)
} else {
for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements;
st++, i++) {
op = PR_v6p_Opcode (st->op);
pr_opcode_v6p_e st_op = st->op;
op = PR_v6p_Opcode (st_op);
if (!op) {
PR_Error (pr, "PR_Check_Opcodes: unknown opcode %d at "
"statement %ld", st->op,
"statement %ld", st_op,
(long)(st - pr->pr_statements));
}
switch (st->op) {
switch (st_op) {
case OP_IF_v6p:
case OP_IFNOT_v6p:
check_global (pr, st, op, op->type_a, st->a, 1);
@ -1702,7 +1705,7 @@ PR_Check_Opcodes (progs_t *pr)
case OP_RCALL6_v6p:
case OP_RCALL7_v6p:
case OP_RCALL8_v6p:
if (st->op > OP_RCALL1_v6p)
if (st_op > OP_RCALL1_v6p)
check_global (pr, st, op, ev_integer, st->c, 1);
check_global (pr, st, op, ev_integer, st->b, 1);
check_global (pr, st, op, ev_func, st->a, 1);