From: Dale Weiler Date: Mon, 30 Sep 2013 02:01:46 +0000 (-0400) Subject: Make unary - operator act as an ast_unary node. This allows for consistency (no sense... X-Git-Tag: 0.3.5~61 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=b10de1b240911487e2f3731342725c842d711496 Make unary - operator act as an ast_unary node. This allows for consistency (no sense in making unary use binstore nodes, it doesn't make much sense). It also allows for the peephole optimization on unary chains that cancel each other to take place; i.e code like "-(-a)" simplifies to "a", thus eliminating instructions. --- diff --git a/ast.c b/ast.c index 3f5f02b..ad85e4f 100644 --- a/ast.c +++ b/ast.c @@ -515,7 +515,7 @@ ast_unary* ast_unary_new(lex_ctx_t ctx, int op, ast_instantiate(ast_unary, ctx, ast_unary_delete); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_unary_codegen); - self->op = op; + self->op = op; self->operand = expr; if (ast_istype(expr, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) { @@ -530,10 +530,13 @@ ast_unary* ast_unary_new(lex_ctx_t ctx, int op, ast_propagate_effects(self, expr); - if (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) { + if (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) { self->expression.vtype = TYPE_FLOAT; - } else + } else if (op >= VINSTR_NEG_F && op <= VINSTR_NEG_V) { + self->expression.vtype = TYPE_FLOAT; + } else { compile_error(ctx, "cannot determine type of unary operation %s", util_instr_str[op]); + } return self; } diff --git a/gmqcc.h b/gmqcc.h index d8ad374..9848f20 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -712,6 +712,7 @@ enum { VINSTR_PHI, VINSTR_JUMP, VINSTR_COND, + /* A never returning CALL. * Creating this causes IR blocks to be marked as 'final'. * No-Return-Call @@ -726,7 +727,9 @@ enum { VINSTR_BITXOR, VINSTR_BITXOR_V, VINSTR_BITXOR_VF, - VINSTR_CROSS + VINSTR_CROSS, + VINSTR_NEG_F, + VINSTR_NEG_V }; /* TODO: elide */ diff --git a/ir.c b/ir.c index f92d552..49d4b2f 100644 --- a/ir.c +++ b/ir.c @@ -1878,16 +1878,22 @@ ir_value* ir_block_create_unary(ir_block *self, lex_ctx_t ctx, case INSTR_NOT_V: case INSTR_NOT_S: case INSTR_NOT_ENT: - case INSTR_NOT_FNC: -#if 0 - case INSTR_NOT_I: -#endif + case INSTR_NOT_FNC: /* + case INSTR_NOT_I: */ ot = TYPE_FLOAT; break; - /* QC doesn't have other unary operations. We expect extensions to fill - * the above list, otherwise we assume out-type = in-type, eg for an - * unary minus + + /* + * Negation for virtual instructions is emulated with 0-value. Thankfully + * the operand for 0 already exists so we just source it from here. */ + case VINSTR_NEG_F: + return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_F, NULL, operand, ot); + break; + case VINSTR_NEG_V: + return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_V, NULL, operand, ot); + break; + default: ot = operand->vtype; break; diff --git a/parser.c b/parser.c index bfc8be4..7d4698e 100644 --- a/parser.c +++ b/parser.c @@ -466,22 +466,18 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('-','P'): if (!(out = fold_op(parser->fold, op, exprs))) { - switch (exprs[0]->vtype) { - case TYPE_FLOAT: - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, - (ast_expression*)parser->fold->imm_float[0], - exprs[0]); - break; - case TYPE_VECTOR: - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, - (ast_expression*)parser->fold->imm_vector[0], - exprs[0]); - break; - default: - compile_error(ctx, "invalid types used in expression: cannot negate type %s", - type_name[exprs[0]->vtype]); + if (exprs[0]->vtype != TYPE_FLOAT && + exprs[0]->vtype != TYPE_VECTOR) { + compile_error(ctx, "invalid types used in unary expression: cannot negate type %s", + type_name[exprs[0]->vtype]); return false; } + /* + * TYPE_VECTOR = TYPE_FLOAT+1, + * VINSTR_NEG_V = VINSTR_NEG_F+1, + * thus (VINSTR_NEG_F-TYPE_FLOAT) + TYPE_* = VINSTR_NEG_*. + */ + out = (ast_expression*)ast_unary_new(ctx, (VINSTR_NEG_F-TYPE_FLOAT) + exprs[0]->vtype, exprs[0]); } break;