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;