From 95b8424ddfd10bc353aa31bd3efa52746e766758 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 18 Aug 2022 17:46:14 +0900 Subject: [PATCH] [qfcc] Use new extend instruction instead of swizzle While swizzle does work, it requires the source to be properly aligned and thus is not really the best choice. The extend instruction has no alignment requirements (at all) and thus is much better suited to converting a scalar to a vector type. Fixes #30 --- tools/qfcc/include/expr.h | 9 +++++++++ tools/qfcc/include/expr_names.h | 1 + tools/qfcc/source/expr.c | 23 +++++++++++++++++++++ tools/qfcc/source/expr_assign.c | 1 + tools/qfcc/source/expr_binary.c | 9 +-------- tools/qfcc/source/statements.c | 36 +++++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 8 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index b9534086e..43dc6a255 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -269,6 +269,12 @@ typedef struct { struct type_s *type; ///< result type } ex_swizzle_t; +typedef struct { + struct expr_s *src; ///< source expression + int extend; ///< extend mode 0: 0, 1: 1, 2: copy/0 3:-1 + struct type_s *type; ///< result type; +} ex_extend_t; + #define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val) typedef struct expr_s { @@ -305,6 +311,7 @@ typedef struct expr_s { struct type_s *nil; ///< type for nil if known ex_horizontal_t hop; ///< horizontal vector operation ex_swizzle_t swizzle; ///< vector swizzle operation + ex_extend_t extend; ///< vector extend operation } e; } expr_t; @@ -494,6 +501,8 @@ expr_t *new_horizontal_expr (int op, expr_t *vec, struct type_s *type); expr_t *new_swizzle_expr (expr_t *src, const char *swizzle); +expr_t *new_extend_expr (expr_t *src, struct type_s *type, int ext); + /** Create a new def reference (non-temporary variable) expression node. \return The new def reference expression node (::def_t). diff --git a/tools/qfcc/include/expr_names.h b/tools/qfcc/include/expr_names.h index 8c6db70b6..978684073 100644 --- a/tools/qfcc/include/expr_names.h +++ b/tools/qfcc/include/expr_names.h @@ -64,5 +64,6 @@ EX_EXPR(with) ///< with expression (::ex_with_t) EX_EXPR(args) ///< @args marker in parameter list. no data EX_EXPR(horizontal) ///< horizontal vector operation (::ex_horzontal_t) EX_EXPR(swizzle) ///< vector swizzle operation (::ex_swizzle_t) +EX_EXPR(extend) ///< vector extend operation (::ex_extend_t) ///@} diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 595eb1e87..b112d7296 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -197,6 +197,8 @@ get_type (expr_t *e) return e->e.hop.type; case ex_swizzle: return e->e.swizzle.type; + case ex_extend: + return e->e.extend.type; case ex_count: internal_error (e, "invalid expression"); } @@ -432,6 +434,11 @@ copy_expr (expr_t *e) *n = *e; e->e.swizzle.src = copy_expr (e->e.swizzle.src); return n; + case ex_extend: + n = new_expr (); + *n = *e; + e->e.extend.src = copy_expr (e->e.extend.src); + return n; case ex_count: break; } @@ -686,6 +693,17 @@ new_swizzle_expr (expr_t *src, const char *swizzle) return expr; } +expr_t * +new_extend_expr (expr_t *src, type_t *type, int ext) +{ + expr_t *expr = new_expr (); + expr->type = ex_extend; + expr->e.extend.src = src; + expr->e.extend.extend = ext; + expr->e.extend.type = type; + return expr; +} + expr_t * new_def_expr (def_t *def) { @@ -1624,6 +1642,8 @@ has_function_call (expr_t *e) return has_function_call (e->e.hop.vec); case ex_swizzle: return has_function_call (e->e.swizzle.src); + case ex_extend: + return has_function_call (e->e.extend.src); case ex_error: case ex_state: case ex_label: @@ -1770,6 +1790,7 @@ unary_expr (int op, expr_t *e) case ex_assign: case ex_horizontal: case ex_swizzle: + case ex_extend: { expr_t *n = new_unary_expr (op, e); @@ -1864,6 +1885,7 @@ unary_expr (int op, expr_t *e) case ex_assign: case ex_horizontal: case ex_swizzle: + case ex_extend: if (options.code.progsversion == PROG_VERSION) { return binary_expr (EQ, e, new_nil_expr ()); } else { @@ -1954,6 +1976,7 @@ unary_expr (int op, expr_t *e) case ex_assign: case ex_horizontal: case ex_swizzle: + case ex_extend: bitnot_expr: if (options.code.progsversion == PROG_ID_VERSION) { expr_t *n1 = new_int_expr (-1); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index b04a98b36..b1a8c3e5a 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -143,6 +143,7 @@ is_lvalue (const expr_t *expr) case ex_args: case ex_horizontal: case ex_swizzle: + case ex_extend: break; case ex_count: internal_error (expr, "invalid expression"); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index d8888dc7f..f01e165b2 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -667,14 +667,7 @@ convert_scalar (expr_t *scalar, int op, expr_t *vec) return new_vector_list (scalar); } - char swizzle[] = "xxxx"; - type_t *vec_base = base_type (vec_type); - expr_t *tmp = new_temp_def_expr (vector_type (vec_base, 4)); - expr_t *block = new_block_expr (); - swizzle[type_width (vec_type)] = 0; - append_expr (block, assign_expr (tmp, new_swizzle_expr (scalar, swizzle))); - block->e.block.result = new_alias_expr (vec_type, tmp); - return block; + return new_extend_expr (scalar, vec_type, 2);//2 = copy } static expr_t * diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 190464202..ec011d1e4 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1810,6 +1810,41 @@ expr_swizzle (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_extend (sblock_t *sblock, expr_t *e, operand_t **op) +{ + type_t *src_type = get_type (e->e.extend.src); + type_t *res_type = e->e.extend.type; + int src_width = type_width (src_type); + int res_width = type_width (res_type); + type_t *src_base = base_type (src_type); + type_t *res_base = base_type (res_type); + static int mode[4][4] = { + {-1, 0, 1, 2}, + {-1,-1, 3, 4}, + {-1,-1,-1, 5}, + {-1,-1,-1,-1}, + }; + int ext = mode[src_width - 1][res_width - 1]; + ext |= (e->e.extend.extend & 3) << 3; + ext |= (pr_type_size[res_base->type] - 1) << 5; + if (ext < 0 || res_base != src_base) { + internal_error (e, "invalid type combination for extend %d %d %d", + ext, src_width, res_width); + } + + statement_t *s = new_statement (st_expr, "extend", e); + sblock = statement_subexpr (sblock, e->e.extend.src, &s->opa); + s->opb = short_operand (ext, e); + if (!*op) { + *op = temp_operand (res_type, e); + } + s->opc = *op; + sblock_add_statement (sblock, s); + + return sblock; +} + static sblock_t * expr_def (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -1954,6 +1989,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) [ex_address] = expr_address, [ex_assign] = expr_assign, [ex_branch] = expr_branch, + [ex_extend] = expr_extend, }; if (!e) { *op = 0;