diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-11 22:29:53 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-11 22:29:53 +0000 |
commit | 0bec4f557a96e1a40437cf5af20cc78a5eec8a63 (patch) | |
tree | c1e05ec804c43aa5a8f5f21b0ed02d0587d29563 /compiler_and_linker/unsorted/InstrSelection.c | |
parent | aec1b8dddc68ecb8288ec6132932e4c7b4bca09f (diff) | |
download | MWCC-0bec4f557a96e1a40437cf5af20cc78a5eec8a63.tar.gz MWCC-0bec4f557a96e1a40437cf5af20cc78a5eec8a63.zip |
getting closer
Diffstat (limited to 'compiler_and_linker/unsorted/InstrSelection.c')
-rw-r--r-- | compiler_and_linker/unsorted/InstrSelection.c | 991 |
1 files changed, 770 insertions, 221 deletions
diff --git a/compiler_and_linker/unsorted/InstrSelection.c b/compiler_and_linker/unsorted/InstrSelection.c index 1916711..0ea8bf9 100644 --- a/compiler_and_linker/unsorted/InstrSelection.c +++ b/compiler_and_linker/unsorted/InstrSelection.c @@ -139,7 +139,7 @@ void gen_POSTINCDEC(ENode *expr, short outputReg, short outputRegHi, Operand *ou output->reg = (outputReg && outputReg != objReg) ? outputReg : ALLOC_FPR(); emitpcode(PC_FMR, output->reg, objReg); fval = one_point_zero; - load_floating_constant(constReg = ALLOC_FPR(), type, &fval.value); + load_floating_constant(constReg = ALLOC_FPR(), type, &fval); if (ENODE_IS(expr, EPOSTINC)) { emitpcode((type->size == 4) ? PC_FADDS : PC_FADD, objReg, objReg, constReg); @@ -157,7 +157,7 @@ void gen_POSTINCDEC(ENode *expr, short outputReg, short outputRegHi, Operand *ou emitpcode(PC_FMR, output->reg, b.reg); fval = one_point_zero; - load_floating_constant(constReg = ALLOC_FPR(), type, &fval.value); + load_floating_constant(constReg = ALLOC_FPR(), type, &fval); finalReg = ALLOC_FPR(); if (ENODE_IS(expr, EPOSTINC)) @@ -2907,351 +2907,340 @@ void gen_condition(ENode *cond, Operand *output) { void gen_condition_gpr(ENode *cond, Operand *output, short outputReg) { ENode *left; ENode *right; - Operand op1; + Operand condOp; + int finalReg; int tmpReg; - int reg; + int tmpReg2; + int tmpReg3; + int tmpReg4; int a; int b; left = cond->data.diadic.left; right = cond->data.diadic.right; - memclrw(&op1, sizeof(Operand)); + memclrw(&condOp, sizeof(Operand)); if (!IS_TYPE_FLOAT(left->rtype)) { + Operand op1; Operand op2; - Operand op3; - Operand op4; + Operand opTmp; + memclrw(&op1, sizeof(Operand)); memclrw(&op2, sizeof(Operand)); - memclrw(&op3, sizeof(Operand)); - memclrw(&op4, sizeof(Operand)); + memclrw(&opTmp, sizeof(Operand)); if (right->hascall) { - GEN_NODE(right, &op3); + GEN_NODE(right, &op2); if (!IS_INT_CONST_ZERO(right)) { if (right->rtype->size < 4) - extend32(&op3, right->rtype, 0); - ENSURE_GPR(&op3, right->rtype, 0); + extend32(&op2, right->rtype, 0); + ENSURE_GPR(&op2, right->rtype, 0); } - GEN_NODE(left, &op2); + GEN_NODE(left, &op1); if (left->rtype->size < 4) - extend32(&op2, left->rtype, 0); - ENSURE_GPR(&op2, left->rtype, 0); + extend32(&op1, left->rtype, 0); + ENSURE_GPR(&op1, left->rtype, 0); } else { - GEN_NODE(left, &op2); - ENSURE_GPR(&op2, left->rtype, 0); + GEN_NODE(left, &op1); + ENSURE_GPR(&op1, left->rtype, 0); if (left->rtype->size < 4) - extend32(&op2, left->rtype, 0); + extend32(&op1, left->rtype, 0); - GEN_NODE(right, &op3); + GEN_NODE(right, &op2); if (!IS_INT_CONST_ZERO(right)) { if (right->rtype->size < 4) - extend32(&op3, right->rtype, 0); - ENSURE_GPR(&op3, right->rtype, 0); + extend32(&op2, right->rtype, 0); + ENSURE_GPR(&op2, right->rtype, 0); } } switch (cond->type) { case EEQU: if ( - copts.peephole && - IS_INT_CONST(right) && - pclastblock->pcodeCount > 0) { + copts.peephole && + IS_INT_CONST(right) && + pclastblock->pcodeCount > 0 && + pclastblock->lastPCode->op == PC_RLWINM && + pclastblock->lastPCode->args[0].data.reg.reg == op1.reg + ) + { PCode *pc = pclastblock->lastPCode; - if (pc->op == PC_RLWINM && pc->args[0].data.reg.reg == op2.reg) { - SInt32 r6 = pc->args[2].data.imm.value; - SInt32 r7 = pc->args[3].data.imm.value; - SInt32 r3 = right->data.intval.lo; - if (r7 == pc->args[4].data.imm.value) { - reg = outputReg ? outputReg : ALLOC_GPR(); - if (r3 != (r3 & 1)) { - emitpcode(PC_LI, reg, 0); - } else if (r3 == 0) { - int tmpreg = ALLOC_GPR(); - emitpcode( - PC_RLWINM, tmpreg, - pc->args[1].data.reg.reg, - (r6 + r7 + 1) & 31, 31, 31); - emitpcode(PC_XORI, reg, tmpreg, 1); - } else if (r3 == 1) { - emitpcode( - PC_RLWINM, reg, - pc->args[1].data.reg.reg, - (r6 + r7 + 1) & 31, 31, 31); - } else { - CError_FATAL(5434); - } - output->optype = OpndType_GPR; - output->reg = reg; - return; + SInt32 a = pc->args[2].data.imm.value; + SInt32 b = pc->args[3].data.imm.value; + SInt32 value = right->data.intval.lo; + if (b == pc->args[4].data.imm.value) { + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + if (value != (value & 1)) { + emitpcode(PC_LI, finalReg, 0); + } else if (value == 0) { + tmpReg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, tmpReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + emitpcode(PC_XORI, finalReg, tmpReg, 1); + } else if (value == 1) { + emitpcode( + PC_RLWINM, finalReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + } else { + CError_FATAL(5434); } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; } } if (IS_INT_CONST_ZERO(right)) { - //int tmpReg = ALLOC_GPR(); // affected - int tmpReg; - int t = used_virtual_registers[RegClass_GPR]; - used_virtual_registers[RegClass_GPR]++; - emitpcode(PC_CNTLZW, t, op2.reg, 0); - tmpReg = t; - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg, 27, 5, 31); + tmpReg = ALLOC_GPR(); + emitpcode(PC_CNTLZW, tmpReg, op1.reg, 0); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg, 27, 5, 31); output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } else { - int tmpReg, tmpReg2; - tmpReg = ALLOC_GPR(); // affected - emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg); tmpReg2 = ALLOC_GPR(); emitpcode(PC_CNTLZW, tmpReg2, tmpReg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg2, 27, 5, 31); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg2, 27, 5, 31); output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } case ENOTEQU: if ( - copts.peephole && - IS_INT_CONST(right) && - pclastblock->pcodeCount > 0) { + copts.peephole && + IS_INT_CONST(right) && + pclastblock->pcodeCount > 0 && + pclastblock->lastPCode->op == PC_RLWINM && + pclastblock->lastPCode->args[0].data.reg.reg == op1.reg + ) + { PCode *pc = pclastblock->lastPCode; - if (pc->op == PC_RLWINM && pc->args[0].data.reg.reg == op2.reg) { - SInt32 r6 = pc->args[2].data.imm.value; - SInt32 r7 = pc->args[3].data.imm.value; - SInt32 r3 = right->data.intval.lo; - if (r7 == pc->args[4].data.imm.value) { - reg = outputReg ? outputReg : ALLOC_GPR(); - if (r3 != (r3 & 1)) { - emitpcode(PC_LI, reg, 1); - } else if (r3 == 0) { - emitpcode( - PC_RLWINM, reg, - pc->args[1].data.reg.reg, - (r6 + r7 + 1) & 31, 31, 31); - } else if (r3 == 1) { - int tmpreg = ALLOC_GPR(); // affected - emitpcode( - PC_RLWINM, tmpreg, - pc->args[1].data.reg.reg, - (r6 + r7 + 1) & 31, 31, 31); - emitpcode(PC_XORI, reg, tmpreg, 1); - } else { - CError_FATAL(5503); - } - output->optype = OpndType_GPR; - output->reg = reg; - return; + SInt32 a = pc->args[2].data.imm.value; + SInt32 b = pc->args[3].data.imm.value; + SInt32 value = right->data.intval.lo; + if (b == pc->args[4].data.imm.value) { + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + if (value != (value & 1)) { + emitpcode(PC_LI, finalReg, 1); + } else if (value == 0) { + emitpcode( + PC_RLWINM, finalReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + } else if (value == 1) { + tmpReg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, tmpReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + emitpcode(PC_XORI, finalReg, tmpReg, 1); + } else { + CError_FATAL(5503); } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; } } if (IS_INT_CONST_ZERO(right)) { if (copts.optimize_for_size) { - int tmpReg; - tmpReg = ALLOC_GPR(); // affected - emitpcode(PC_ADDIC, tmpReg, op2.reg, -1); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_SUBFE, reg, tmpReg, op2.reg); - } else { - int tmpReg, tmpReg2; - // tmpReg, tmpReg2 swap - tmpReg = ALLOC_GPR(); - emitpcode(PC_NEG, tmpReg, op2.reg); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_OR, tmpReg2, tmpReg, op2.reg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg2, 1, 31, 31); - } - output->optype = OpndType_GPR; - output->reg = reg; - return; - } else { - if (copts.optimize_for_size) { - int tmpReg, tmpReg2; - // tmpReg, tmpReg2 swap tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_ADDIC, tmpReg2, tmpReg, -1); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_SUBFE, reg, tmpReg2, tmpReg); + emitpcode(PC_ADDIC, tmpReg, op1.reg, -1); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg, op1.reg); } else { - int tmpReg, tmpReg2, tmpReg3; - // tmpReg, tmpReg2 swap tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + emitpcode(PC_NEG, tmpReg, op1.reg); tmpReg2 = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg2, op3.reg, op2.reg); - tmpReg3 = ALLOC_GPR(); - emitpcode(PC_OR, tmpReg3, tmpReg, tmpReg2); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg3, 1, 31, 31); + emitpcode(PC_OR, tmpReg2, tmpReg, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg2, 1, 31, 31); } output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } + if (copts.optimize_for_size) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ADDIC, tmpReg2, tmpReg, -1); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg2, tmpReg); + } else { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg2, op2.reg, op1.reg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_OR, tmpReg3, tmpReg, tmpReg2); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg3, 1, 31, 31); + } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + case EGREATEREQU: if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) { - int tmpReg; tmpReg = ALLOC_GPR(); - emitpcode(PC_RLWINM, tmpReg, op2.reg, 1, 31, 31); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_XORI, reg, tmpReg, 1); + emitpcode(PC_RLWINM, tmpReg, op1.reg, 1, 31, 31); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_XORI, finalReg, tmpReg, 1); output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } - op4 = op3; - op3 = op2; - op2 = op4; + opTmp = op2; + op2 = op1; + op1 = opTmp; + case ELESSEQU: if (is_unsigned(left->rtype)) { if (copts.optimize_for_size) { - int tmpReg, tmpReg2; tmpReg = ALLOC_GPR(); emitpcode(PC_LI, tmpReg, -1); tmpReg2 = ALLOC_GPR(); - emitpcode(PC_SUBFC, tmpReg2, op2.reg, op3.reg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_SUBFZE, reg, tmpReg); + emitpcode(PC_SUBFC, tmpReg2, op1.reg, op2.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFZE, finalReg, tmpReg); } else { - int tmpReg, tmpReg2, tmpReg3, tmpReg4; tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg); tmpReg2 = ALLOC_GPR(); - emitpcode(PC_ORC, tmpReg2, op3.reg, op2.reg); + emitpcode(PC_ORC, tmpReg2, op2.reg, op1.reg); tmpReg3 = ALLOC_GPR(); emitpcode(PC_RLWINM, tmpReg3, tmpReg, 31, 1, 31); tmpReg4 = ALLOC_GPR(); emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg4, 1, 31, 31); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg4, 1, 31, 31); } output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } if (IS_INT_CONST_ZERO(right)) { - int tmpReg, tmpReg2; tmpReg = ALLOC_GPR(); emitpcode(PC_LI, tmpReg, 1); tmpReg2 = ALLOC_GPR(); - emitpcode(PC_CNTLZW, tmpReg2, op2.reg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWNM, reg, tmpReg, tmpReg2, 31, 31); - output->optype = OpndType_GPR; - output->reg = reg; - return; - } else { - int tmpReg, tmpReg2, tmpReg3; - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpReg2, op3.reg, 31); - tmpReg = ALLOC_GPR(); - emitpcode(PC_RLWINM, tmpReg, op2.reg, 1, 31, 31); - tmpReg3 = ALLOC_GPR(); - emitpcode(PC_SUBFC, tmpReg3, op2.reg, op3.reg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_ADDE, reg, tmpReg2, tmpReg); + emitpcode(PC_CNTLZW, tmpReg2, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWNM, finalReg, tmpReg, tmpReg2, 31, 31); output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpReg2, op2.reg, 31); + tmpReg = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg, op1.reg, 1, 31, 31); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg3, op1.reg, op2.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_ADDE, finalReg, tmpReg2, tmpReg); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + case EGREATER: if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) { - int tmpReg, tmpReg2; tmpReg = ALLOC_GPR(); - emitpcode(PC_NEG, tmpReg, op2.reg); + emitpcode(PC_NEG, tmpReg, op1.reg); tmpReg2 = ALLOC_GPR(); - emitpcode(PC_ANDC, tmpReg2, tmpReg, op2.reg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg2, 1, 31, 31); + emitpcode(PC_ANDC, tmpReg2, tmpReg, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg2, 1, 31, 31); output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } - op4 = op3; - op3 = op2; - op2 = op4; + opTmp = op2; + op2 = op1; + op1 = opTmp; + case ELESS: if (is_unsigned(left->rtype)) { if (left->rtype->size <= 2) { - int tmpReg; tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg, op3.reg, op2.reg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg, 1, 31, 31); + emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg, 1, 31, 31); output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; } else { if (copts.optimize_for_size) { - int tmpReg, tmpReg2; tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBFC, tmpReg, op3.reg, op2.reg); + emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg); tmpReg2 = ALLOC_GPR(); emitpcode(PC_SUBFE, tmpReg2, tmpReg, tmpReg); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_NEG, reg, tmpReg2); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_NEG, finalReg, tmpReg2); } else { - int tmpReg, tmpReg2, tmpReg3; tmpReg = ALLOC_GPR(); - emitpcode(PC_XOR, tmpReg, op3.reg, op2.reg); + emitpcode(PC_XOR, tmpReg, op2.reg, op1.reg); tmpReg2 = ALLOC_GPR(); emitpcode(PC_CNTLZW, tmpReg2, tmpReg); tmpReg3 = ALLOC_GPR(); - emitpcode(PC_SLW, tmpReg3, op3.reg, tmpReg2); - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg3, 1, 31, 31); + emitpcode(PC_SLW, tmpReg3, op2.reg, tmpReg2); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg3, 1, 31, 31); } output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; return; } return; - } else { - if (IS_INT_CONST_ZERO(right)) { - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, op2.reg, 1, 31, 31); - output->optype = OpndType_GPR; - output->reg = reg; - return; - } else { - int tmpReg, tmpReg2, tmpReg3, tmpReg4; - tmpReg = ALLOC_GPR(); - emitpcode(PC_XOR, tmpReg, op3.reg, op2.reg); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpReg2, tmpReg, 1); - tmpReg3 = ALLOC_GPR(); - emitpcode(PC_AND, tmpReg3, tmpReg, op3.reg); - tmpReg4 = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2); + } - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, tmpReg4, 1, 31, 31); - output->optype = OpndType_GPR; - output->reg = reg; - return; - } + if (IS_INT_CONST_ZERO(right)) { + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, op1.reg, 1, 31, 31); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; } + tmpReg = ALLOC_GPR(); + emitpcode(PC_XOR, tmpReg, op2.reg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpReg2, tmpReg, 1); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_AND, tmpReg3, tmpReg, op2.reg); + tmpReg4 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2); + + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, finalReg, tmpReg4, 1, 31, 31); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + default: CError_FATAL(5777); } } - gen_condition(cond, &op1); + gen_condition(cond, &condOp); emitpcode(PC_MFCR, tmpReg = used_virtual_registers[RegClass_GPR]++); a = 0; - b = op1.reg * 4; - switch (op1.regOffset) { + b = condOp.reg * 4; + switch (condOp.regOffset) { case ENOTEQU: a = 1; case EEQU: @@ -3267,18 +3256,349 @@ void gen_condition_gpr(ENode *cond, Operand *output, short outputReg) { break; } - reg = outputReg ? outputReg : ALLOC_GPR(); + finalReg = outputReg ? outputReg : ALLOC_GPR(); if (a) { emitpcode(PC_RLWINM, tmpReg, tmpReg, b + 1, 31, 31); - emitpcode(PC_XORI, reg, tmpReg, 1); + emitpcode(PC_XORI, finalReg, tmpReg, 1); } else { - emitpcode(PC_RLWINM, reg, tmpReg, b + 1, 31, 31); + emitpcode(PC_RLWINM, finalReg, tmpReg, b + 1, 31, 31); } output->optype = OpndType_GPR; - output->reg = reg; + output->reg = finalReg; } void gen_negated_condition_gpr(ENode *cond, Operand *output, short outputReg) { + ENode *left; + ENode *right; + Operand op1; + Operand op2; + Operand opTmp; + int finalReg; + int tmpReg; + int tmpReg2; + int tmpReg3; + + left = cond->data.diadic.left; + right = cond->data.diadic.right; + CError_ASSERT(5843, TYPE_FITS_IN_REGISTER(left->rtype) && TYPE_FITS_IN_REGISTER(right->rtype)); + + memclrw(&op1, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + memclrw(&opTmp, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &op2); + if (!IS_INT_CONST_ZERO(right)) { + if (right->rtype->size < 4) + extend32(&op2, right->rtype, 0); + ENSURE_GPR(&op2, right->rtype, 0); + } + + GEN_NODE(left, &op1); + if (left->rtype->size < 4) + extend32(&op1, left->rtype, 0); + ENSURE_GPR(&op1, left->rtype, 0); + } else { + GEN_NODE(left, &op1); + ENSURE_GPR(&op1, left->rtype, 0); + if (left->rtype->size < 4) + extend32(&op1, left->rtype, 0); + + GEN_NODE(right, &op2); + if (!IS_INT_CONST_ZERO(right)) { + if (right->rtype->size < 4) + extend32(&op2, right->rtype, 0); + ENSURE_GPR(&op2, right->rtype, 0); + } + } + + switch (cond->type) { + case EEQU: + if ( + copts.peephole && + IS_INT_CONST(right) && + pclastblock->pcodeCount > 0 && + pclastblock->lastPCode->op == PC_RLWINM && + pclastblock->lastPCode->args[0].data.reg.reg == op1.reg + ) + { + PCode *pc = pclastblock->lastPCode; + SInt32 a = pc->args[2].data.imm.value; + SInt32 b = pc->args[3].data.imm.value; + SInt32 value = right->data.intval.lo; + if (b == pc->args[4].data.imm.value) { + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + if (value != (value & 1)) { + emitpcode(PC_LI, finalReg, 0); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (value == 0) { + tmpReg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, tmpReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + emitpcode(PC_ADDI, finalReg, tmpReg, 0, -1); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (value == 1) { + tmpReg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, + tmpReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, + 31, + 31); + emitpcode(PC_NEG, finalReg, tmpReg); + output->optype = OpndType_GPR; + output->reg = tmpReg; // bug??? + return; + } + + CError_FATAL(5923); + } + } + + if (IS_INT_CONST_ZERO(right)) { + if (copts.optimize_for_size) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_ADDIC, tmpReg, op1.reg, -1); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg, tmpReg); + } else { + tmpReg = ALLOC_GPR(); + emitpcode(PC_CNTLZW, tmpReg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg2, tmpReg, 27, 31, 31); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_NEG, finalReg, tmpReg2); + } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (copts.optimize_for_size) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ADDIC, tmpReg2, tmpReg, -1); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg2, tmpReg2); + } else { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg2, op1.reg, op2.reg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_NOR, tmpReg3, tmpReg, tmpReg2); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, finalReg, tmpReg3, 31); + } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + + case ENOTEQU: + if ( + copts.peephole && + IS_INT_CONST(right) && + pclastblock->pcodeCount > 0 && + pclastblock->lastPCode->op == PC_RLWINM && + pclastblock->lastPCode->args[0].data.reg.reg == op1.reg + ) + { + PCode *pc = pclastblock->lastPCode; + SInt32 a = pc->args[2].data.imm.value; + SInt32 b = pc->args[3].data.imm.value; + SInt32 value = right->data.intval.lo; + if (b == pc->args[4].data.imm.value) { + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + if (value != (value & 1)) { + emitpcode(PC_LI, finalReg, -1); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (value == 0) { + tmpReg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, tmpReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + emitpcode(PC_NEG, finalReg, tmpReg); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (value == 1) { + tmpReg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, tmpReg, + pc->args[1].data.reg.reg, + (a + b + 1) & 31, 31, 31); + emitpcode(PC_ADDI, finalReg, tmpReg, 0, -1); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + CError_FATAL(6031); + } + } + + if (IS_INT_CONST_ZERO(right)) { + if (copts.optimize_for_size) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBFIC, tmpReg, op1.reg, 0); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg, tmpReg); + } else { + tmpReg = ALLOC_GPR(); + emitpcode(PC_NEG, tmpReg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_OR, tmpReg2, tmpReg, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, finalReg, tmpReg2, 31); + } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (copts.optimize_for_size) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBFIC, tmpReg2, tmpReg, 0); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg2, tmpReg2); + } else { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg2, op1.reg, op2.reg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_OR, tmpReg3, tmpReg, tmpReg2); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, finalReg, tmpReg3, 31); + } + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + + case EGREATEREQU: + if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg, op1.reg, 1, 31, 31); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_ADDI, finalReg, tmpReg, 0, -1); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + opTmp = op2; + op2 = op1; + op1 = opTmp; + + case ELESSEQU: + if (is_unsigned(left->rtype)) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg, op1.reg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ADDZE, tmpReg2, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBF, finalReg, tmpReg2, op1.reg); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (IS_INT_CONST_ZERO(right)) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_NEG, tmpReg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ORC, tmpReg2, op1.reg, tmpReg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, finalReg, tmpReg2, 31); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + tmpReg = ALLOC_GPR(); + emitpcode(PC_XORIS, tmpReg, op1.reg, 0x8000); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg2, op1.reg, op2.reg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_ADDC, tmpReg3, tmpReg2, tmpReg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg3, tmpReg3); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + + case EGREATER: + if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_NEG, tmpReg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ANDC, tmpReg2, tmpReg, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, finalReg, tmpReg2, 31); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + opTmp = op2; + op2 = op1; + op1 = opTmp; + + case ELESS: + if (is_unsigned(left->rtype)) { + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg, tmpReg); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + if (IS_INT_CONST_ZERO(right)) { + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, finalReg, op1.reg, 31); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + } + + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg2, op2.reg, 1, 31, 31); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg3, op1.reg, 1, 31, 31); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, finalReg, tmpReg3, tmpReg2); + output->optype = OpndType_GPR; + output->reg = finalReg; + return; + + default: + CError_FATAL(6240); + } } void compare_floating(short nt, ENode *left, ENode *right, Operand *output) { @@ -3347,9 +3667,127 @@ void compare_integer(short nt, ENode *left, ENode *right, Operand *output) { } void compare_immediate(short nt, ENode *left, SInt32 value, Operand *output) { + int postIncFlag; + short postIncReg; + Operand op; + SInt32 postIncValue; + + memclrw(&op, sizeof(Operand)); + + postIncFlag = ispostincrementopportunity(left, &op, &postIncValue); + if (!postIncFlag) { + GEN_NODE(left, &op); + if (op.optype != OpndType_CRField) { + if (left->rtype->size < 4) + extend32(&op, left->rtype, 0); + else + ENSURE_GPR(&op, left->rtype, 0); + } + } else { + postIncReg = op.reg; + if (left->rtype->size < 4) + extend32(&op, left->rtype, 0); + ENSURE_GPR(&op, left->rtype, 0); + } + + if (op.optype == OpndType_CRField) { + if ( + (nt == EEQU && value == 1) || + (nt == ENOTEQU && value == 0) || + (nt == EGREATER && value == 0) || + (nt == EGREATEREQU && value == 1) + ) + { + *output = op; + return; + } + + if ( + (nt == EEQU && value == 0) || + (nt == ENOTEQU && value == 1) || + (nt == ELESS && value == 1) || + (nt == ELESSEQU && value == 0) + ) + { + *output = op; + switch (op.regOffset) { + case EEQU: + output->regOffset = ENOTEQU; + return; + case ENOTEQU: + output->regOffset = EEQU; + return; + case ELESS: + output->regOffset = EGREATEREQU; + return; + case EGREATER: + output->regOffset = ELESSEQU; + return; + case ELESSEQU: + output->regOffset = EGREATER; + return; + case EGREATEREQU: + output->regOffset = ELESS; + return; + } + } + + ENSURE_GPR(&op, left->rtype, 0); + } + + if ( + copts.peephole && + value == 0 && + pclastblock->pcodeCount > 0 && + pclastblock->lastPCode->op != PC_RLWINM && + (PCODE_FLAG_SET_F(pclastblock->lastPCode) & (fIsMove | fSideEffects | fCanSetRecordBit | fOpTypeGPR)) == (fCanSetRecordBit | fOpTypeGPR) && + pclastblock->lastPCode->args[0].data.reg.reg == op.reg && + (!is_unsigned(left->rtype) || nt == EEQU || nt == ENOTEQU) + ) + { + pcsetrecordbit(pclastblock->lastPCode); + } else { + emitpcode(is_unsigned(left->rtype) ? PC_CMPLI : PC_CMPI, 0, op.reg, value); + } + + if (postIncFlag) + add_register_immediate(postIncReg, postIncReg, postIncValue); + + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = nt; } void compare_immediate_long(short nt, ENode *left, SInt32 value, Operand *output) { + int postIncFlag; + short postIncReg; + int outputReg; + Operand op; + SInt32 postIncValue; + + memclrw(&op, sizeof(Operand)); + + postIncFlag = ispostincrementopportunity(left, &op, &postIncValue); + if (!postIncFlag) { + GEN_NODE(left, &op); + } else { + postIncReg = op.reg; + } + + if (left->rtype->size < 4) + extend32(&op, left->rtype, 0); + ENSURE_GPR(&op, left->rtype, 0); + + outputReg = ALLOC_GPR(); + emitpcode(PC_ADDIS, outputReg, op.reg, 0, (SInt16) (~(value >> 16) + 1)); + emitpcode(PC_CMPLI, 0, outputReg, value & 0xFFFF); + + if (postIncFlag) + add_register_immediate(postIncReg, postIncReg, postIncValue); + + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = nt; } static int ismask(SInt32 value, short *first, short *last) { @@ -3729,12 +4167,123 @@ void I8_gen_SUB(ENode *expr, short outputReg, short outputRegHi, Operand *output } void I8_gen_XOR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + short reg; + short regHi; + Operand opleft; + Operand opright; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + } else { + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + } + + CError_ASSERT(7254, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); + + reg = outputReg ? outputReg : ALLOC_GPR(); + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + + emitpcode(PC_XOR, reg, opleft.reg, opright.reg); + emitpcode(PC_XOR, regHi, opleft.regHi, opright.regHi); + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; } void I8_gen_OR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + short reg; + short regHi; + Operand opleft; + Operand opright; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + } else { + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + } + + CError_ASSERT(7304, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); + + reg = outputReg ? outputReg : ALLOC_GPR(); + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + + emitpcode(PC_OR, reg, opleft.reg, opright.reg); + emitpcode(PC_OR, regHi, opleft.regHi, opright.regHi); + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; } void I8_gen_AND(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + short reg; + short regHi; + Operand opleft; + Operand opright; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + } else { + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + } + + CError_ASSERT(7354, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); + + reg = outputReg ? outputReg : ALLOC_GPR(); + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + + emitpcode(PC_AND, reg, opleft.reg, opright.reg); + emitpcode(PC_AND, regHi, opleft.regHi, opright.regHi); + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; } int I8_getbit(UInt64 val) { @@ -4173,7 +4722,7 @@ void I8_gen_ASS(ENode *expr, short outputReg, short outputRegHi, Operand *output if (ENODE_IS(left, EINDIRECT)) left = left->data.monadic; else - CError_FATAL(8238); + CError_FATAL(8328); right = expr->data.cond.expr2; } else { left = expr->data.diadic.left; |