mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[qfcc] Add support for unsigned, long, etc
long is ignored for double, and v6p progs are stuck with 32 bits for longs (don't feel like extending v6p any further), but the basics are there for Ruamoko. short is ignored for ints because the minimum size is 32, and signed is just noise for ints anyway (and no chars, so...). unsigned, however, is finally implemented properly (or at least seems to be working correctly: tests pass after getting things compiling again, and lt.u is used where it should be :)
This commit is contained in:
parent
e11fa77a34
commit
df890432b7
7 changed files with 225 additions and 64 deletions
|
@ -7,5 +7,4 @@ typedef int int16_t;
|
|||
typedef int int32_t;
|
||||
typedef int int64_t;
|
||||
typedef int size_t;
|
||||
typedef int long;
|
||||
typedef int char;
|
||||
|
|
|
@ -104,6 +104,8 @@ extern type_t type_floatfield;
|
|||
|
||||
extern type_t *type_nil; // for passing nil into ...
|
||||
extern type_t *type_default; // default type (float or int)
|
||||
extern type_t *type_long_int; // supported type for long
|
||||
extern type_t *type_ulong_uint;// supported type for ulong
|
||||
|
||||
extern type_t type_va_list;
|
||||
extern type_t type_param;
|
||||
|
|
|
@ -290,23 +290,23 @@ static expr_type_t int_int[] = {
|
|||
};
|
||||
|
||||
static expr_type_t int_uint[] = {
|
||||
{'+', &type_int},
|
||||
{'-', &type_int},
|
||||
{'*', &type_int},
|
||||
{'/', &type_int},
|
||||
{'&', &type_int},
|
||||
{'|', &type_int},
|
||||
{'^', &type_int},
|
||||
{'%', &type_int},
|
||||
{MOD, &type_int},
|
||||
{SHL, &type_int},
|
||||
{SHR, &type_int},
|
||||
{EQ, &type_int},
|
||||
{NE, &type_int},
|
||||
{LE, &type_int},
|
||||
{GE, &type_int},
|
||||
{LT, &type_int},
|
||||
{GT, &type_int},
|
||||
{'+', &type_int, 0, &type_int},
|
||||
{'-', &type_int, 0, &type_int},
|
||||
{'*', &type_int, 0, &type_int},
|
||||
{'/', &type_int, 0, &type_int},
|
||||
{'&', &type_int, 0, &type_int},
|
||||
{'|', &type_int, 0, &type_int},
|
||||
{'^', &type_int, 0, &type_int},
|
||||
{'%', &type_int, 0, &type_int},
|
||||
{MOD, &type_int, 0, &type_int},
|
||||
{SHL, &type_int, 0, &type_int},
|
||||
{SHR, &type_int, 0, &type_int},
|
||||
{EQ, &type_int, 0, &type_int},
|
||||
{NE, &type_int, 0, &type_int},
|
||||
{LE, &type_int, 0, &type_int},
|
||||
{GE, &type_int, 0, &type_int},
|
||||
{LT, &type_int, 0, &type_int},
|
||||
{GT, &type_int, 0, &type_int},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
@ -353,23 +353,23 @@ static expr_type_t int_double[] = {
|
|||
#define uint_quat int_quat
|
||||
|
||||
static expr_type_t uint_int[] = {
|
||||
{'+', &type_int},
|
||||
{'-', &type_int},
|
||||
{'*', &type_int},
|
||||
{'/', &type_int},
|
||||
{'&', &type_int},
|
||||
{'|', &type_int},
|
||||
{'^', &type_int},
|
||||
{'%', &type_int},
|
||||
{MOD, &type_int},
|
||||
{SHL, &type_uint},
|
||||
{SHR, &type_uint},
|
||||
{EQ, &type_int},
|
||||
{NE, &type_int},
|
||||
{LE, &type_int},
|
||||
{GE, &type_int},
|
||||
{LT, &type_int},
|
||||
{GT, &type_int},
|
||||
{'+', &type_int, &type_int, &type_int },
|
||||
{'-', &type_int, &type_int, &type_int },
|
||||
{'*', &type_int, &type_int, &type_int },
|
||||
{'/', &type_int, &type_int, &type_int },
|
||||
{'&', &type_int, &type_int, &type_int },
|
||||
{'|', &type_int, &type_int, &type_int },
|
||||
{'^', &type_int, &type_int, &type_int },
|
||||
{'%', &type_int, &type_int, &type_int },
|
||||
{MOD, &type_int, &type_int, &type_int },
|
||||
{SHL, &type_uint, &type_int, &type_int },
|
||||
{SHR, &type_uint, 0, &type_int },
|
||||
{EQ, &type_int, &type_int, &type_int },
|
||||
{NE, &type_int, &type_int, &type_int },
|
||||
{LE, &type_int, &type_int, &type_int },
|
||||
{GE, &type_int, &type_int, &type_int },
|
||||
{LT, &type_int, &type_int, &type_int },
|
||||
{GT, &type_int, &type_int, &type_int },
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
@ -385,8 +385,8 @@ static expr_type_t uint_uint[] = {
|
|||
{MOD, &type_uint},
|
||||
{SHL, &type_uint},
|
||||
{SHR, &type_uint},
|
||||
{EQ, &type_int},
|
||||
{NE, &type_int},
|
||||
{EQ, &type_int, &type_int, &type_int},
|
||||
{NE, &type_int, &type_int, &type_int},
|
||||
{LE, &type_int},
|
||||
{GE, &type_int},
|
||||
{LT, &type_int},
|
||||
|
|
|
@ -47,8 +47,38 @@
|
|||
#include "tools/qfcc/include/statements.h"
|
||||
#include "tools/qfcc/include/type.h"
|
||||
|
||||
typedef struct v6p_uint_opcode_s {
|
||||
pr_opcode_v6p_e op;
|
||||
v6p_opcode_t opcode;
|
||||
} v6p_uint_opcode_t;
|
||||
|
||||
static v6p_uint_opcode_t v6p_uint_opcodes[] = {
|
||||
{OP_LOAD_I_v6p, {".", "load.i", ev_entity, ev_field, ev_uint }},
|
||||
{OP_LOADBI_I_v6p, {".", "loadbi.i", ev_ptr, ev_short, ev_uint }},
|
||||
{OP_ADDRESS_I_v6p, {"&", "address.i", ev_uint, ev_invalid, ev_ptr }},
|
||||
{OP_STORE_I_v6p, {"=", "store.i", ev_uint, ev_uint, ev_invalid }},
|
||||
{OP_STOREP_I_v6p, {".=", "storep.i", ev_uint, ev_ptr, ev_invalid }},
|
||||
{OP_STOREB_I_v6p, {".=", "storeb.i", ev_uint, ev_ptr, ev_int }},
|
||||
{OP_STOREBI_I_v6p, {".=", "storebi.i", ev_uint, ev_ptr, ev_short }},
|
||||
{OP_IF_v6p, {"<IF>", "if", ev_uint, ev_short, ev_invalid }},
|
||||
{OP_IFNOT_v6p, {"<IFNOT>", "ifnot", ev_uint, ev_short, ev_invalid }},
|
||||
{OP_ADD_I_v6p, {"+", "add.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_SUB_I_v6p, {"-", "sub.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_MUL_I_v6p, {"*", "mul.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_DIV_I_v6p, {"/", "div.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_BITAND_I_v6p, {"&", "bitand.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_BITOR_I_v6p, {"|", "bitor.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_BITXOR_I_v6p, {"^", "bitxor.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_REM_I_v6p, {"%", "rem.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_MOD_I_v6p, {"%%", "mod.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_SHL_I_v6p, {"<<", "shl.i", ev_uint, ev_uint, ev_uint }},
|
||||
{OP_BITNOT_I_v6p, {"<<", "bitnot.i", ev_uint, ev_invalid, ev_int }},
|
||||
{}
|
||||
};
|
||||
|
||||
static hashtab_t *v6p_opcode_type_table;
|
||||
static hashtab_t *v6p_opcode_void_table;
|
||||
static hashtab_t *v6p_opcode_uint_table;
|
||||
static v6p_opcode_t *v6p_opcode_map;
|
||||
|
||||
static hashtab_t *rua_opcode_type_table;
|
||||
|
@ -86,6 +116,21 @@ v6p_get_key (const void *op, void *unused)
|
|||
return ((v6p_opcode_t *) op)->name;
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
v6p_uint_get_hash (const void *_op, void *_tab)
|
||||
{
|
||||
__auto_type uint_op = (v6p_uint_opcode_t *) _op;
|
||||
return v6p_get_hash (&uint_op->opcode, _tab);
|
||||
}
|
||||
|
||||
static int
|
||||
v6p_uint_compare (const void *_opa, const void *_opb, void *data)
|
||||
{
|
||||
__auto_type uint_opa = (v6p_uint_opcode_t *) _opa;
|
||||
__auto_type uint_opb = (v6p_uint_opcode_t *) _opb;
|
||||
return v6p_compare (&uint_opa->opcode, &uint_opb->opcode, data);
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
rua_get_hash (const void *_op, void *_tab)
|
||||
{
|
||||
|
@ -139,17 +184,25 @@ static v6p_opcode_t *
|
|||
v6p_opcode_find (const char *name, operand_t *op_a, operand_t *op_b,
|
||||
operand_t *op_c)
|
||||
{
|
||||
v6p_opcode_t search_op = {};
|
||||
v6p_uint_opcode_t search_op = {
|
||||
.opcode = {
|
||||
.name = name,
|
||||
.type_a = op_a ? low_level_type (op_a->type) : ev_invalid,
|
||||
.type_b = op_b ? low_level_type (op_b->type) : ev_invalid,
|
||||
.type_c = op_c ? low_level_type (op_c->type) : ev_invalid,
|
||||
},
|
||||
};
|
||||
v6p_uint_opcode_t *uint_op;
|
||||
v6p_opcode_t *op;
|
||||
v6p_opcode_t *sop;
|
||||
void **op_list;
|
||||
int i;
|
||||
|
||||
search_op.name = name;
|
||||
search_op.type_a = op_a ? low_level_type (op_a->type) : ev_invalid;
|
||||
search_op.type_b = op_b ? low_level_type (op_b->type) : ev_invalid;
|
||||
search_op.type_c = op_c ? low_level_type (op_c->type) : ev_invalid;
|
||||
op = Hash_FindElement (v6p_opcode_type_table, &search_op);
|
||||
uint_op = Hash_FindElement (v6p_opcode_uint_table, &search_op);
|
||||
if (uint_op) {
|
||||
return v6p_opcode_map + uint_op->op;
|
||||
}
|
||||
op = Hash_FindElement (v6p_opcode_type_table, &search_op.opcode);
|
||||
if (op)
|
||||
return op;
|
||||
op_list = Hash_FindList (v6p_opcode_void_table, name);
|
||||
|
@ -157,9 +210,9 @@ v6p_opcode_find (const char *name, operand_t *op_a, operand_t *op_b,
|
|||
return op;
|
||||
for (i = 0; !op && op_list[i]; i++) {
|
||||
sop = op_list[i];
|
||||
if (check_operand_type (sop->type_a, search_op.type_a)
|
||||
&& check_operand_type (sop->type_b, search_op.type_b)
|
||||
&& check_operand_type (sop->type_c, search_op.type_c))
|
||||
if (check_operand_type (sop->type_a, search_op.opcode.type_a)
|
||||
&& check_operand_type (sop->type_b, search_op.opcode.type_b)
|
||||
&& check_operand_type (sop->type_c, search_op.opcode.type_c))
|
||||
op = sop;
|
||||
}
|
||||
free (op_list);
|
||||
|
@ -217,10 +270,14 @@ v6p_opcode_init (void)
|
|||
if (v6p_opcode_type_table) {
|
||||
Hash_FlushTable (v6p_opcode_void_table);
|
||||
Hash_FlushTable (v6p_opcode_type_table);
|
||||
Hash_FlushTable (v6p_opcode_uint_table);
|
||||
} else {
|
||||
v6p_opcode_type_table = Hash_NewTable (1021, 0, 0, 0, 0);
|
||||
Hash_SetHashCompare (v6p_opcode_type_table, v6p_get_hash, v6p_compare);
|
||||
v6p_opcode_void_table = Hash_NewTable (1021, v6p_get_key, 0, 0, 0);
|
||||
v6p_opcode_uint_table = Hash_NewTable (1021, 0, 0, 0, 0);
|
||||
Hash_SetHashCompare (v6p_opcode_uint_table,
|
||||
v6p_uint_get_hash, v6p_uint_compare);
|
||||
}
|
||||
|
||||
int num_opcodes = 0;
|
||||
|
@ -253,6 +310,11 @@ v6p_opcode_init (void)
|
|||
|| mop->type_c == ev_void)
|
||||
Hash_Add (v6p_opcode_void_table, mop);
|
||||
}
|
||||
if (options.code.progsversion != PROG_ID_VERSION) {
|
||||
for (__auto_type uiop = &v6p_uint_opcodes[0]; uiop->op; uiop++) {
|
||||
Hash_AddElement (v6p_opcode_uint_table, uiop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -377,7 +377,10 @@ static keyword_t qf_keywords[] = {
|
|||
{"quaternion", TYPE, &type_quaternion},
|
||||
{"double", TYPE, &type_double},
|
||||
{"int", TYPE, &type_int },
|
||||
{"unsigned", TYPE, &type_int },//FIXME
|
||||
{"unsigned", UNSIGNED, 0 },
|
||||
{"signed", SIGNED, 0 },
|
||||
{"long", LONG, 0 },
|
||||
{"short", SHORT, 0 },
|
||||
|
||||
{"@function", TYPE, &type_func },
|
||||
{"@args", ARGS, 0 },
|
||||
|
|
|
@ -148,6 +148,7 @@ int yylex (void);
|
|||
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS
|
||||
%token NIL GOTO SWITCH CASE DEFAULT ENUM
|
||||
%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT
|
||||
%token UNSIGNED SIGNED LONG SHORT
|
||||
%token <op> STRUCT
|
||||
%token <type> TYPE
|
||||
%token <symbol> OBJECT TYPE_NAME
|
||||
|
@ -253,6 +254,23 @@ spec_merge (specifier_t spec, specifier_t new)
|
|||
spec.storage = new.storage;
|
||||
spec.is_typedef = new.is_typedef;
|
||||
}
|
||||
if ((new.is_unsigned && spec.is_signed)
|
||||
|| (new.is_signed && spec.is_unsigned)) {
|
||||
if (!spec.multi_type) {
|
||||
error (0, "both signed and unsigned in declaration specifiers");
|
||||
spec.multi_type = 1;
|
||||
}
|
||||
}
|
||||
if ((new.is_long && spec.is_short) || (new.is_short && spec.is_long)) {
|
||||
if (!spec.multi_store) {
|
||||
error (0, "both long and short in declaration specifiers");
|
||||
spec.multi_store = 1;
|
||||
}
|
||||
}
|
||||
spec.is_signed |= new.is_signed;
|
||||
spec.is_unsigned |= new.is_unsigned;
|
||||
spec.is_short |= new.is_short;
|
||||
spec.is_long |= new.is_long;
|
||||
spec.is_overload |= new.is_overload;
|
||||
spec.nosave |= new.nosave;
|
||||
return spec;
|
||||
|
@ -261,6 +279,59 @@ spec_merge (specifier_t spec, specifier_t new)
|
|||
static specifier_t
|
||||
default_type (specifier_t spec, symbol_t *sym)
|
||||
{
|
||||
if (spec.type) {
|
||||
if (is_float (spec.type) && !spec.multi_type) {
|
||||
// no modifieres allowed
|
||||
if (spec.is_unsigned) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both unsigned and float in declaration specifiers");
|
||||
} else if (spec.is_signed) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both signed and float in declaration specifiers");
|
||||
} else if (spec.is_short) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both short and float in declaration specifiers");
|
||||
} else if (spec.is_long) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both long and float in declaration specifiers");
|
||||
}
|
||||
}
|
||||
if (is_double (spec.type)) {
|
||||
// long is allowed but ignored
|
||||
if (spec.is_unsigned) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both unsigned and double in declaration specifiers");
|
||||
} else if (spec.is_signed) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both signed and double in declaration specifiers");
|
||||
} else if (spec.is_short) {
|
||||
spec.multi_type = 1;
|
||||
error (0, "both short and double in declaration specifiers");
|
||||
}
|
||||
}
|
||||
if (is_int (spec.type)) {
|
||||
// signed and short are ignored
|
||||
if (spec.is_unsigned && spec.is_long) {
|
||||
spec.type = &type_ulong;
|
||||
} else if (spec.is_long) {
|
||||
spec.type = &type_long;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (spec.is_long) {
|
||||
if (spec.is_unsigned) {
|
||||
spec.type = type_ulong_uint;
|
||||
} else {
|
||||
spec.type = type_long_int;
|
||||
}
|
||||
} else {
|
||||
if (spec.is_unsigned) {
|
||||
spec.type = &type_uint;
|
||||
} else if (spec.is_signed) {
|
||||
spec.type = &type_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!spec.type) {
|
||||
spec.type = type_default;
|
||||
warning (0, "type defaults to '%s' in declaration of '%s'",
|
||||
|
@ -414,11 +485,10 @@ function_body
|
|||
: optional_state_expr
|
||||
{
|
||||
symbol_t *sym = $<symbol>0;
|
||||
specifier_t spec = default_type ($<spec>-1, sym);
|
||||
|
||||
if (!$<spec>-1.type)
|
||||
$<spec>-1.type = type_default;
|
||||
sym->type = find_type (append_type (sym->type, $<spec>-1.type));
|
||||
$<symbol>$ = function_symbol (sym, $<spec>-1.is_overload, 1);
|
||||
sym->type = find_type (append_type (sym->type, spec.type));
|
||||
$<symbol>$ = function_symbol (sym, spec.is_overload, 1);
|
||||
}
|
||||
save_storage
|
||||
{
|
||||
|
@ -438,12 +508,11 @@ function_body
|
|||
| '=' '#' expr ';'
|
||||
{
|
||||
symbol_t *sym = $<symbol>0;
|
||||
specifier_t spec = default_type ($<spec>-1, sym);
|
||||
|
||||
if (!$<spec>-1.type)
|
||||
$<spec>-1.type = type_default;
|
||||
sym->type = find_type (append_type (sym->type, $<spec>-1.type));
|
||||
sym = function_symbol (sym, $<spec>-1.is_overload, 1);
|
||||
build_builtin_function (sym, $3, 0, $<spec>-1.storage);
|
||||
sym->type = find_type (append_type (sym->type, spec.type));
|
||||
sym = function_symbol (sym, spec.is_overload, 1);
|
||||
build_builtin_function (sym, $3, 0, spec.storage);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -556,6 +625,26 @@ type_specifier
|
|||
{
|
||||
$$ = make_spec ($1, 0, 0, 0);
|
||||
}
|
||||
| UNSIGNED
|
||||
{
|
||||
$$ = make_spec (0, current_storage, 0, 0);
|
||||
$$.is_unsigned = 1;
|
||||
}
|
||||
| SIGNED
|
||||
{
|
||||
$$ = make_spec (0, current_storage, 0, 0);
|
||||
$$.is_signed = 1;
|
||||
}
|
||||
| LONG
|
||||
{
|
||||
$$ = make_spec (0, current_storage, 0, 0);
|
||||
$$.is_long = 1;
|
||||
}
|
||||
| SHORT
|
||||
{
|
||||
$$ = make_spec (0, current_storage, 0, 0);
|
||||
$$.is_short = 1;
|
||||
}
|
||||
| enum_specifier
|
||||
| struct_specifier
|
||||
| TYPE_NAME
|
||||
|
@ -768,8 +857,7 @@ struct_decl_list
|
|||
struct_decl
|
||||
: function_decl
|
||||
{
|
||||
if (!$<spec>0.type)
|
||||
$<spec>0.type = type_default;
|
||||
$<spec>0 = default_type ($<spec>-0, $1);
|
||||
$1->type = find_type (append_type ($1->type, $<spec>0.type));
|
||||
$1->sy_type = sy_var;
|
||||
$1->visibility = current_visibility;
|
||||
|
@ -780,8 +868,7 @@ struct_decl
|
|||
}
|
||||
| var_decl
|
||||
{
|
||||
if (!$<spec>0.type)
|
||||
$<spec>0.type = type_default;
|
||||
$<spec>0 = default_type ($<spec>-0, $1);
|
||||
$1->type = find_type (append_type ($1->type, $<spec>0.type));
|
||||
$1->sy_type = sy_var;
|
||||
$1->visibility = current_visibility;
|
||||
|
@ -900,8 +987,7 @@ qc_var_list
|
|||
param_declaration
|
||||
: type var_decl
|
||||
{
|
||||
if (!$1.type)
|
||||
$1.type = type_default;
|
||||
$1 = default_type ($1, $2);
|
||||
$2->type = find_type (append_type ($2->type, $1.type));
|
||||
$$ = new_param (0, $2->type, $2->name);
|
||||
}
|
||||
|
@ -913,8 +999,7 @@ abstract_decl
|
|||
: type abs_decl
|
||||
{
|
||||
$$ = $2;
|
||||
if (!$1.type)
|
||||
$1.type = type_default;
|
||||
$1 = default_type ($1, $2);
|
||||
$$->type = find_type (append_type ($$->type, $1.type));
|
||||
}
|
||||
| error { $$ = new_symbol (""); }
|
||||
|
|
|
@ -76,6 +76,8 @@ type_t type_invalid = { ev_invalid, "invalid" };
|
|||
|
||||
type_t *type_nil;
|
||||
type_t *type_default;
|
||||
type_t *type_long_int;
|
||||
type_t *type_ulong_uint;
|
||||
|
||||
// these will be built up further
|
||||
type_t type_va_list = { ev_invalid, 0, 0, ty_struct };
|
||||
|
@ -1118,6 +1120,14 @@ init_types (void)
|
|||
|
||||
type_nil = &type_quaternion;
|
||||
type_default = &type_int;
|
||||
type_long_int = &type_long;
|
||||
type_ulong_uint = &type_ulong;
|
||||
if (options.code.progsversion < PROG_VERSION) {
|
||||
// even v6p doesn't support long, and I don't feel like adding it
|
||||
// use ruamoko :P
|
||||
type_long_int = &type_int;
|
||||
type_ulong_uint = &type_uint;
|
||||
}
|
||||
if (options.code.progsversion == PROG_ID_VERSION) {
|
||||
// vector can't be part of .zero for v6 progs because for v6 progs,
|
||||
// .zero is only one word wide.
|
||||
|
|
Loading…
Reference in a new issue