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.

This commit is contained in:
Dale Weiler 2013-09-29 22:01:46 -04:00
parent 3c931ecbf1
commit b10de1b240
4 changed files with 33 additions and 25 deletions

9
ast.c
View file

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

View file

@ -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 */

20
ir.c
View file

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

View file

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