[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:
Bill Currie 2024-10-07 19:40:19 +09:00
parent dc878dbb4c
commit c3f11ba754
9 changed files with 73 additions and 33 deletions

View file

@ -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));

View file

@ -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) {

View file

@ -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))) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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))

View file

@ -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;
}

View file

@ -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");

View file

@ -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);
}