mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Add basic (type) support for references
I realized that spir-v pointers are essentially references (the way they're used) since OpVariable requires a pointer type rather than the base type. Thus, under the hood, references are just pointers with automatic dereferencing. However, nothing uses references yet, and I expect to run into issues with is_pointer vs is_reference vs is_ptr (high-level pointer, reference, low-level pointer, respectively).
This commit is contained in:
parent
dc878dbb4c
commit
c3f11ba754
9 changed files with 73 additions and 33 deletions
|
@ -53,6 +53,7 @@ typedef struct ty_func_s {
|
|||
|
||||
typedef struct ty_fldptr_s {
|
||||
const struct type_s *type;
|
||||
bool deref; ///< automatic dereference for pointers (C++ &)
|
||||
} ty_fldptr_t;
|
||||
|
||||
typedef struct ty_array_s {
|
||||
|
@ -154,6 +155,7 @@ const type_t *find_type (const type_t *new);
|
|||
void new_typedef (const char *name, type_t *type);
|
||||
const type_t *field_type (const type_t *aux);
|
||||
const type_t *pointer_type (const type_t *aux);
|
||||
const type_t *reference_type (const type_t *aux);
|
||||
const type_t *vector_type (const type_t *ele_type, int width) __attribute__((pure));
|
||||
const type_t *matrix_type (const type_t *ele_type, int cols, int rows) __attribute__((pure));
|
||||
const type_t *base_type (const type_t *vec_type) __attribute__((pure));
|
||||
|
@ -220,6 +222,8 @@ const char *type_get_encoding (const type_t *type);
|
|||
#define EV_TYPE(t) int is_##t (const type_t *type) __attribute__((pure));
|
||||
#include "QF/progs/pr_type_names.h"
|
||||
|
||||
int is_pointer (const type_t *type) __attribute__((pure));
|
||||
int is_reference (const type_t *type) __attribute__((pure));
|
||||
int is_enum (const type_t *type) __attribute__((pure));
|
||||
int is_bool (const type_t *type) __attribute__((pure));
|
||||
int is_integral (const type_t *type) __attribute__((pure));
|
||||
|
|
|
@ -337,7 +337,7 @@ emit_instance_defs (def_t *def, void *data, int index)
|
|||
{
|
||||
obj_static_instances_data_t *da = (obj_static_instances_data_t *)data;
|
||||
|
||||
if (!is_array (def->type) || !is_ptr (dereference_type (def->type)))
|
||||
if (!is_array (def->type) || !is_pointer (dereference_type (def->type)))
|
||||
internal_error (0, "%s: expected array of pointers def", __FUNCTION__);
|
||||
if (index < 0 || index >= da->num_instances + 1)
|
||||
internal_error (0, "%s: out of bounds index: %d %d",
|
||||
|
@ -499,7 +499,7 @@ is_method_description (const type_t *type)
|
|||
static protocollist_t *
|
||||
obj_get_class_protos (const type_t *type)
|
||||
{
|
||||
if (is_ptr (type))
|
||||
if (is_pointer (type))
|
||||
type = type->fldptr.type;
|
||||
if (is_class (type))
|
||||
return type->class->protocols;
|
||||
|
@ -509,7 +509,7 @@ obj_get_class_protos (const type_t *type)
|
|||
static protocollist_t *
|
||||
obj_get_protos (const type_t *type)
|
||||
{
|
||||
if (is_ptr (type))
|
||||
if (is_pointer (type))
|
||||
type = type->fldptr.type;
|
||||
return type->protos;
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ obj_get_protos (const type_t *type)
|
|||
static category_t *
|
||||
obj_get_categories (const type_t *type)
|
||||
{
|
||||
if (is_ptr (type))
|
||||
if (is_pointer (type))
|
||||
type = type->fldptr.type;
|
||||
if (is_class (type))
|
||||
return type->class->categories;
|
||||
|
@ -538,7 +538,7 @@ obj_classname (const type_t *type)
|
|||
} else if (is_Class (type)) {
|
||||
dstring_copystr (str, "Class");
|
||||
} else {
|
||||
if (is_ptr (type))
|
||||
if (is_pointer (type))
|
||||
type = type->fldptr.type;
|
||||
if (is_class (type))
|
||||
dstring_copystr (str, type->class->name);
|
||||
|
@ -1562,7 +1562,7 @@ emit_symtab_defs (def_t *def, void *data, int index)
|
|||
{
|
||||
obj_symtab_data_t *da = (obj_symtab_data_t *)data;
|
||||
|
||||
if (!is_array (def->type) || !is_ptr (dereference_type (def->type)))
|
||||
if (!is_array (def->type) || !is_pointer (dereference_type (def->type)))
|
||||
internal_error (0, "%s: expected array of pointers def", __FUNCTION__);
|
||||
if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt + 1)
|
||||
internal_error (0, "%s: out of bounds index: %d %d",
|
||||
|
@ -1838,7 +1838,7 @@ emit_protocol (protocol_t *protocol)
|
|||
static void
|
||||
emit_protocol_next (def_t *def, void *data, int index)
|
||||
{
|
||||
if (!is_ptr(def->type)) {
|
||||
if (!is_pointer(def->type)) {
|
||||
internal_error (0, "%s: expected pointer def", __FUNCTION__);
|
||||
}
|
||||
D_INT (def) = 0;
|
||||
|
@ -1861,7 +1861,7 @@ emit_protocol_list_item (def_t *def, void *data, int index)
|
|||
protocollist_t *protocols = (protocollist_t *) data;
|
||||
protocol_t *protocol = protocols->list[index];
|
||||
|
||||
if (!is_array (def->type) || !is_ptr(dereference_type (def->type))) {
|
||||
if (!is_array (def->type) || !is_pointer(dereference_type (def->type))) {
|
||||
internal_error (0, "%s: expected array of pointer def", __FUNCTION__);
|
||||
}
|
||||
if (index < 0 || index >= protocols->count) {
|
||||
|
|
|
@ -1442,7 +1442,7 @@ is_math_val (const expr_t *e)
|
|||
const expr_t *
|
||||
new_alias_expr (const type_t *type, const expr_t *expr)
|
||||
{
|
||||
if (is_ptr (type) && expr->type == ex_address) {
|
||||
if (is_pointer (type) && expr->type == ex_address) {
|
||||
auto new = new_address_expr (type, expr->address.lvalue,
|
||||
expr->address.offset);
|
||||
new->address.type = type;
|
||||
|
@ -1715,7 +1715,7 @@ field_expr (const expr_t *e1, const expr_t *e2)
|
|||
return e;
|
||||
}
|
||||
}
|
||||
} else if (is_ptr (t1)) {
|
||||
} else if (is_pointer (t1)) {
|
||||
if (is_struct (t1->fldptr.type) || is_union (t1->fldptr.type)) {
|
||||
symbol_t *field;
|
||||
|
||||
|
@ -2610,7 +2610,7 @@ array_expr (const expr_t *array, const expr_t *index)
|
|||
if (index->type == ex_error)
|
||||
return index;
|
||||
|
||||
if (!is_ptr (array_type) && !is_array (array_type)
|
||||
if (!is_pointer (array_type) && !is_array (array_type)
|
||||
&& !is_nonscalar (array_type))
|
||||
return error (array, "not an array");
|
||||
if (!is_integral (index_type))
|
||||
|
@ -2639,7 +2639,7 @@ array_expr (const expr_t *array, const expr_t *index)
|
|||
if (is_array (array_type)) {
|
||||
ele_type = dereference_type (array_type);
|
||||
base = new_int_expr (array_type->array.base, false);
|
||||
} else if (is_ptr (array_type)) {
|
||||
} else if (is_pointer (array_type)) {
|
||||
ele_type = array_type->fldptr.type;
|
||||
base = new_int_expr (0, false);
|
||||
} else {
|
||||
|
@ -2698,7 +2698,7 @@ const expr_t *
|
|||
offset_pointer_expr (const expr_t *pointer, const expr_t *offset)
|
||||
{
|
||||
auto ptr_type = get_type (pointer);
|
||||
if (!is_ptr (ptr_type)) {
|
||||
if (!is_pointer (ptr_type)) {
|
||||
internal_error (pointer, "not a pointer");
|
||||
}
|
||||
if (!is_integral (get_type (offset))) {
|
||||
|
|
|
@ -352,7 +352,7 @@ assign_expr (const expr_t *dst, const expr_t *src)
|
|||
internal_error (src, "src_type broke in assign_expr");
|
||||
}
|
||||
|
||||
if (is_ptr (dst_type) && is_array (src_type)) {
|
||||
if (is_pointer (dst_type) && is_array (src_type)) {
|
||||
// assigning an array to a pointer is the same as taking the address of
|
||||
// the array but using the type of the array elements
|
||||
src = address_expr (src, src_type->fldptr.type);
|
||||
|
|
|
@ -921,10 +921,10 @@ pointer_arithmetic (int op, const expr_t *e1, const expr_t *e2)
|
|||
const expr_t *psize;
|
||||
const type_t *ptype = 0;
|
||||
|
||||
if (!is_ptr (t1) && !is_ptr (t2)) {
|
||||
if (!is_pointer (t1) && !is_pointer (t2)) {
|
||||
internal_error (e1, "pointer arithmetic on non-pointers");
|
||||
}
|
||||
if (is_ptr (t1) && is_ptr (t2)) {
|
||||
if (is_pointer (t1) && is_pointer (t2)) {
|
||||
if (op != '-') {
|
||||
return error (e2, "invalid pointer operation");
|
||||
}
|
||||
|
@ -936,11 +936,11 @@ pointer_arithmetic (int op, const expr_t *e1, const expr_t *e2)
|
|||
e2 = cast_expr (&type_int, e2);
|
||||
psize = new_int_expr (type_size (t1->fldptr.type), false);
|
||||
return binary_expr ('/', binary_expr ('-', e1, e2), psize);
|
||||
} else if (is_ptr (t1)) {
|
||||
} else if (is_pointer (t1)) {
|
||||
offset = cast_expr (&type_int, e2);
|
||||
ptr = e1;
|
||||
ptype = t1;
|
||||
} else if (is_ptr (t2)) {
|
||||
} else if (is_pointer (t2)) {
|
||||
offset = cast_expr (&type_int, e1);
|
||||
ptr = e2;
|
||||
ptype = t2;
|
||||
|
@ -1360,11 +1360,11 @@ binary_expr (int op, const expr_t *e1, const expr_t *e2)
|
|||
t2 = float_type (t1);
|
||||
e2 = cast_expr (t2, e2);
|
||||
}
|
||||
if (is_array (t1) && (is_ptr (t2) || is_integral (t2))) {
|
||||
if (is_array (t1) && (is_pointer (t2) || is_integral (t2))) {
|
||||
t1 = pointer_type (dereference_type (t1));
|
||||
e1 = cast_expr (t1, e1);
|
||||
}
|
||||
if (is_array (t2) && (is_ptr (t1) || is_integral (t1))) {
|
||||
if (is_array (t2) && (is_pointer (t1) || is_integral (t1))) {
|
||||
t1 = pointer_type (dereference_type (t2));
|
||||
e2 = cast_expr (t2, e2);
|
||||
}
|
||||
|
|
|
@ -106,8 +106,8 @@ cast_expr (const type_t *dstType, const expr_t *e)
|
|||
if ((dstType == type_default && is_enum (srcType))
|
||||
|| (is_enum (dstType) && srcType == type_default))
|
||||
return e;
|
||||
if ((is_ptr (dstType) && is_string (srcType))
|
||||
|| (is_string (dstType) && is_ptr (srcType))) {
|
||||
if ((is_pointer (dstType) && is_string (srcType))
|
||||
|| (is_string (dstType) && is_pointer (srcType))) {
|
||||
return new_alias_expr (dstType, e);
|
||||
}
|
||||
if (is_algebra (dstType) || is_algebra (srcType)) {
|
||||
|
@ -118,9 +118,10 @@ cast_expr (const type_t *dstType, const expr_t *e)
|
|||
return cast_error (e, srcType, dstType);
|
||||
}
|
||||
|
||||
if (!(is_ptr (dstType) && (is_ptr (srcType) || is_integral (srcType)
|
||||
|| is_array (srcType)))
|
||||
&& !(is_integral (dstType) && is_ptr (srcType))
|
||||
if (!(is_pointer (dstType)
|
||||
&& (is_pointer (srcType) || is_integral (srcType)
|
||||
|| is_array (srcType)))
|
||||
&& !(is_integral (dstType) && is_pointer (srcType))
|
||||
&& !(is_func (dstType) && is_func (srcType))
|
||||
&& !(is_math (dstType) && is_math (srcType)
|
||||
&& type_width (dstType) == type_width (srcType))
|
||||
|
|
|
@ -536,7 +536,7 @@ emit_selectors (void)
|
|||
static void
|
||||
emit_methods_next (def_t *def, void *data, int index)
|
||||
{
|
||||
if (!is_ptr(def->type))
|
||||
if (!is_pointer(def->type))
|
||||
internal_error (0, "%s: expected pointer def", __FUNCTION__);
|
||||
D_INT (def) = 0;
|
||||
}
|
||||
|
|
|
@ -431,7 +431,8 @@ function_spec (specifier_t spec, param_t *params)
|
|||
} else if (is_array (spec.sym->type)) {
|
||||
error (0, "declaration of '%s' as array of functions",
|
||||
spec.sym->name);
|
||||
} else if (!is_ptr (spec.sym->type) && !is_field (spec.sym->type)) {
|
||||
} else if (!is_pointer (spec.sym->type)
|
||||
&& !is_field (spec.sym->type)) {
|
||||
internal_error (0, "unexpected type");
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +452,7 @@ array_spec (specifier_t spec, unsigned size)
|
|||
if (is_func (spec.sym->type)) {
|
||||
error (0, "'%s' declared as function returning an array",
|
||||
spec.sym->name);
|
||||
} else if (!is_ptr (spec.sym->type)
|
||||
} else if (!is_pointer (spec.sym->type)
|
||||
&& !is_array (spec.sym->type)
|
||||
&& !is_field (spec.sym->type)) {
|
||||
internal_error (0, "unexpected type");
|
||||
|
@ -466,7 +467,7 @@ pointer_spec (specifier_t quals, specifier_t spec)
|
|||
{
|
||||
if (spec.sym->type) {
|
||||
if (!is_func (spec.sym->type)
|
||||
&& !is_ptr (spec.sym->type)
|
||||
&& !is_pointer (spec.sym->type)
|
||||
&& !is_array (spec.sym->type)
|
||||
&& !is_field (spec.sym->type)) {
|
||||
internal_error (0, "unexpected type");
|
||||
|
|
|
@ -665,6 +665,28 @@ pointer_type (const type_t *aux)
|
|||
new->alignment = 1;
|
||||
new->width = 1;
|
||||
new->columns = 1;
|
||||
new->fldptr.deref = false;
|
||||
if (aux) {
|
||||
return find_type (append_type (new, aux));
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
const type_t *
|
||||
reference_type (const type_t *aux)
|
||||
{
|
||||
type_t _new;
|
||||
type_t *new = &_new;
|
||||
|
||||
if (aux)
|
||||
memset (&_new, 0, sizeof (_new));
|
||||
else
|
||||
new = new_type ();
|
||||
new->type = ev_ptr;
|
||||
new->alignment = 1;
|
||||
new->width = 1;
|
||||
new->columns = 1;
|
||||
new->fldptr.deref = true;
|
||||
if (aux) {
|
||||
return find_type (append_type (new, aux));
|
||||
}
|
||||
|
@ -1207,8 +1229,8 @@ encode_type (dstring_t *encoding, const type_t *type)
|
|||
dasprintf (encoding, "#");
|
||||
return;
|
||||
}
|
||||
dasprintf (encoding, type->fldptr.deref ? "&" : "^");
|
||||
type = type->fldptr.type;
|
||||
dasprintf (encoding, "^");
|
||||
encode_type (encoding, type);
|
||||
return;
|
||||
case ev_quaternion:
|
||||
|
@ -1268,6 +1290,18 @@ int is_##t (const type_t *type) \
|
|||
}
|
||||
#include "QF/progs/pr_type_names.h"
|
||||
|
||||
int
|
||||
is_pointer (const type_t *type)
|
||||
{
|
||||
return is_ptr (type) && !type->fldptr.deref;
|
||||
}
|
||||
|
||||
int
|
||||
is_reference (const type_t *type)
|
||||
{
|
||||
return is_ptr (type) && type->fldptr.deref;
|
||||
}
|
||||
|
||||
int
|
||||
is_enum (const type_t *type)
|
||||
{
|
||||
|
@ -1416,7 +1450,7 @@ type_compatible (const type_t *dst, const type_t *src)
|
|||
if (is_func (dst) && is_func (src)) {
|
||||
return 1;
|
||||
}
|
||||
if (is_ptr (dst) && is_ptr (src)) {
|
||||
if (is_pointer (dst) && is_pointer (src)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1438,13 +1472,13 @@ type_assignable (const type_t *dst, const type_t *src)
|
|||
if (dst->type == ev_field && src->type == ev_field)
|
||||
return 1;
|
||||
// pointer = array
|
||||
if (is_ptr (dst) && is_array (src)) {
|
||||
if (is_pointer (dst) && is_array (src)) {
|
||||
if (is_void (dst->fldptr.type)
|
||||
|| dst->fldptr.type == src->array.type)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (!is_ptr (dst) || !is_ptr (src)) {
|
||||
if (!is_pointer (dst) || !is_pointer (src)) {
|
||||
if (is_algebra (dst) || is_algebra (src)) {
|
||||
return algebra_type_assignable (dst, src);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue