diff --git a/gmqcc.h b/gmqcc.h index d8ad374..6f42d44 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -726,7 +726,13 @@ enum { VINSTR_BITXOR, VINSTR_BITXOR_V, VINSTR_BITXOR_VF, - VINSTR_CROSS + VINSTR_CROSS, + + /* + * An instruction that is never emitted, useful for marking ir_instr + * to not be generated (just set the ->opcode member to it). + */ + VINSTR_NOP }; /* TODO: elide */ diff --git a/ir.c b/ir.c index 0411c92..e911b02 100644 --- a/ir.c +++ b/ir.c @@ -2799,6 +2799,10 @@ static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *bloc { instr = block->instr[i]; + /* Ignore NOP instruction */ + if (instr->opcode == VINSTR_NOP) + continue; + if (instr->opcode == VINSTR_PHI) { irerror(block->context, "cannot generate virtual instruction (phi)"); return false; @@ -3174,6 +3178,32 @@ static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *bloc if (instr->_ops[2]) stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]); + if (stmt.opcode == INSTR_NOT_F) { + /* + * We can optimize for superfluous cases of not. Consider + */ + if (i + 4 <= vec_size(block->instr)) { + for (j = 0; j < 2; j++) { + if (ir_value_code_addr(block->instr[i+j]->_ops[0]) != ir_value_code_addr(block->instr[i+j]->_ops[1])) + break; + } + if (--j && block->instr[i+2]->_ops[0] && block->instr[i+2]->_ops[1] + && block->instr[i+3]->_ops[0] && block->instr[i+2]->_ops[1] + && ir_value_code_addr(block->instr[i+2]->_ops[1]) == ir_value_code_addr(block->instr[i+3]->_ops[0]) + && ir_value_code_addr(block->instr[i+2]->_ops[0]) == ir_value_code_addr(block->instr[i+3]->_ops[1])) + { + code_push_statement(code, &stmt, instr->context); + code_push_statement(code, &stmt, instr->context); + for (j = 1; j < 4; j++) + block->instr[i+j]->opcode = VINSTR_NOP; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; + continue; + } + } + code_push_statement(code, &stmt, instr->context); + continue; + } + if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE) { stmt.o1.u1 = stmt.o3.u1;