diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/unsorted/InstrSelection.c | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.tar.gz MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/unsorted/InstrSelection.c')
-rw-r--r-- | compiler_and_linker/unsorted/InstrSelection.c | 5348 |
1 files changed, 0 insertions, 5348 deletions
diff --git a/compiler_and_linker/unsorted/InstrSelection.c b/compiler_and_linker/unsorted/InstrSelection.c deleted file mode 100644 index 359c980..0000000 --- a/compiler_and_linker/unsorted/InstrSelection.c +++ /dev/null @@ -1,5348 +0,0 @@ -#include "compiler/InstrSelection.h" -#include "compiler/CError.h" -#include "compiler/CInt64.h" -#include "compiler/CMachine.h" -#include "compiler/CParser.h" -#include "compiler/CodeGen.h" -#include "compiler/CompilerTools.h" -#include "compiler/FunctionCalls.h" -#include "compiler/Intrinsics.h" -#include "compiler/Operands.h" -#include "compiler/PCode.h" -#include "compiler/PCodeInfo.h" -#include "compiler/PCodeUtilities.h" -#include "compiler/RegisterInfo.h" -#include "compiler/StructMoves.h" -#include "compiler/TOC.h" -#include "compiler/enode.h" -#include "compiler/objects.h" -#include "compiler/types.h" - -PrecomputedOperand *precomputedoperands; -void (*cgdispatch[MAXEXPR + 1])(ENode *, short, short, Operand *); - -// forward decls -static int ispowerof2(SInt32 val); -static void binary_immediate(Opcode opcode, ENode *left, SInt32 value, short outputReg, Operand *output); -static void shift_left_immediate(ENode *expr, short shift, short negate, short outputReg, Operand *output); -static void shift_right_immediate(ENode *expr, Type *type, short shift, short outputReg, Operand *output); -static void or_xor_immediate(Opcode opcode, ENode *expr, SInt32 value, short outputReg, Operand *output); -static void signed_divide_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output); -static void signed_mod_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output); -static void fp_binary_operator(Opcode opcode, ENode *left, ENode *right, short outputReg, Operand *output); -static void logical_expression_nobranch(ENode *cond, Boolean invert, Operand *output); -static void shift_and_mask(ENode *expr, short a, short b, short c, short outputReg, Operand *output); -static ENodeType invert_relop(ENodeType nt); - -#define IS_INT_CONST(node) ( ENODE_IS((node), EINTCONST) && IS_TYPE_INT((node)->rtype) && (node)->rtype->size <= 4 ) -#define IS_INT_CONST_ZERO(node) ( IS_INT_CONST(node) && (node)->data.intval.lo == 0 ) - -void init_cgdispatch(void) { - ENodeType t; - - for (t = 0; t <= MAXEXPR; t++) - cgdispatch[t] = gen_UNEXPECTED; - - cgdispatch[EPOSTINC] = gen_POSTINCDEC; - cgdispatch[EPOSTDEC] = gen_POSTINCDEC; - cgdispatch[EINDIRECT] = gen_INDIRECT; - cgdispatch[EMONMIN] = gen_MONMIN; - cgdispatch[EBINNOT] = gen_BINNOT; - cgdispatch[ELOGNOT] = gen_LOGICAL; - cgdispatch[EFORCELOAD] = gen_FORCELOAD; - cgdispatch[EMUL] = gen_MUL; - cgdispatch[EDIV] = gen_DIV; - cgdispatch[EMODULO] = gen_MODULO; - cgdispatch[EADD] = gen_ADD; - cgdispatch[ESUB] = gen_SUB; - cgdispatch[ESHL] = gen_SHL; - cgdispatch[ESHR] = gen_SHR; - cgdispatch[ELESS] = gen_COMPARE; - cgdispatch[EGREATER] = gen_COMPARE; - cgdispatch[ELESSEQU] = gen_COMPARE; - cgdispatch[EGREATEREQU] = gen_COMPARE; - cgdispatch[EEQU] = gen_COMPARE; - cgdispatch[ENOTEQU] = gen_COMPARE; - cgdispatch[EAND] = gen_AND; - cgdispatch[EXOR] = gen_XOR; - cgdispatch[EOR] = gen_OR; - cgdispatch[ELAND] = gen_LOGICAL; - cgdispatch[ELOR] = gen_LOGICAL; - cgdispatch[EASS] = gen_ASS; - cgdispatch[ECOMMA] = gen_COMMA; - cgdispatch[ETYPCON] = gen_TYPCON; - cgdispatch[EBITFIELD] = gen_BITFIELD; - cgdispatch[EINTCONST] = gen_INTCONST; - cgdispatch[EFLOATCONST] = gen_FLOATCONST; - cgdispatch[ESTRINGCONST] = gen_STRINGCONST; - cgdispatch[ECOND] = gen_COND; - cgdispatch[EFUNCCALL] = gen_FUNCCALL; - cgdispatch[EFUNCCALLP] = gen_FUNCCALL; - cgdispatch[EOBJREF] = gen_OBJREF; - cgdispatch[ENULLCHECK] = gen_NULLCHECK; - cgdispatch[EPRECOMP] = gen_PRECOMP; - cgdispatch[EDEFINE] = gen_DEFINE; - cgdispatch[EREUSE] = gen_REUSE; - cgdispatch[EVECTOR128CONST] = gen_VECTOR128CONST; - cgdispatch[ECONDASS] = gen_CONDASS; -} - -void gen_DEFINE(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Operand *op; - - if (!expr->data.diadic.right) { - op = lalloc(sizeof(Operand)); - memclrw(op, sizeof(Operand)); - expr->data.diadic.right = (ENode *) op; - GEN_NODE(expr->data.diadic.left, op); - } - - op = (Operand *) expr->data.diadic.right; - *output = *op; -} - -void gen_REUSE(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner = expr->data.monadic; - CError_ASSERT(250, ENODE_IS(inner, EDEFINE)); - gen_DEFINE(inner, outputReg, outputRegHi, output); -} - -void gen_POSTINCDEC(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - TypeBitfield *tbitfield; - ENode *inner; - Type *type; - Operand a; - Operand b; - Operand c; - Float fval; - int objReg; - int constReg; - int finalReg; - SInt32 incval; - - inner = expr->data.monadic->data.monadic; - type = expr->rtype; - tbitfield = NULL; - - memclrw(&a, sizeof(Operand)); - memclrw(&b, sizeof(Operand)); - memclrw(&c, sizeof(Operand)); - - if (TYPE_IS_8BYTES(type)) { - I8_gen_POSTINCDEC(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_FLOAT(type)) { - if (ENODE_IS(inner, EOBJREF) && (objReg = OBJECT_REG(inner->data.objref))) { - output->optype = OpndType_FPR; - 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); - - if (ENODE_IS(expr, EPOSTINC)) { - emitpcode((type->size == 4) ? PC_FADDS : PC_FADD, objReg, objReg, constReg); - } else { - emitpcode((type->size == 4) ? PC_FSUBS : PC_FSUB, objReg, objReg, constReg); - } - } else { - GEN_NODE(inner, &a); - indirect(&a, inner); - b = a; - ENSURE_FPR(&b, type, 0); - - output->optype = OpndType_FPR; - output->reg = ALLOC_FPR(); - emitpcode(PC_FMR, output->reg, b.reg); - - fval = one_point_zero; - load_floating_constant(constReg = ALLOC_FPR(), type, &fval); - - finalReg = ALLOC_FPR(); - if (ENODE_IS(expr, EPOSTINC)) - emitpcode((type->size == 4) ? PC_FADDS : PC_FADD, finalReg, b.reg, constReg); - else - emitpcode((type->size == 4) ? PC_FSUBS : PC_FSUB, finalReg, b.reg, constReg); - - store_fp(finalReg, &a, type); - } - } else { - if (IS_TYPE_POINTER(type)) { - if (ENODE_IS(expr, EPOSTINC)) - incval = TPTR_TARGET(type)->size; - else - incval = -TPTR_TARGET(type)->size; - } else { - if (ENODE_IS(expr, EPOSTINC)) - incval = 1; - else - incval = -1; - } - - if (ENODE_IS(inner, EOBJREF) && (objReg = OBJECT_REG(inner->data.objref))) { - output->optype = OpndType_GPR; - output->reg = (outputReg && outputReg != objReg) ? outputReg : ALLOC_GPR(); - emitpcode(PC_MR, output->reg, objReg); - add_register_immediate(objReg, objReg, incval); - } else { - if (ENODE_IS(inner, EBITFIELD)) { - tbitfield = TYPE_BITFIELD(TPTR_TARGET(inner)); - inner = inner->data.monadic; - } - GEN_NODE(inner, &a); - indirect(&a, inner); - b = a; - ENSURE_GPR(&b, type, 0); - - if (tbitfield) { - c = b; - extract_bitfield(&c, tbitfield, 0, &b); - } - output->optype = OpndType_GPR; - - output->reg = ALLOC_GPR(); - emitpcode(PC_MR, output->reg, b.reg); - - finalReg = ALLOC_GPR(); - add_register_immediate(finalReg, b.reg, incval); - - if (tbitfield) { - insert_bitfield(finalReg, &c, tbitfield); - finalReg = c.reg; - } - - store(finalReg, &a, type); - } - } -} - -void gen_INDIRECT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *inner; - VarInfo *vi; - SInt32 postincvalue; - Operand op; - - type = expr->rtype; - inner = expr->data.monadic; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_INDIRECT(expr, outputReg, outputRegHi, output); - return; - } - - memclrw(&op, sizeof(Operand)); - if (ENODE_IS(inner, EOBJREF) && OBJECT_REG(inner->data.objref)) { - vi = Registers_GetVarInfo(inner->data.objref); - switch (vi->rclass) { - case RegClass_GPR: - output->optype = OpndType_GPR; - break; - case RegClass_FPR: - output->optype = OpndType_FPR; - break; - case RegClass_VR: - output->optype = OpndType_VR; - break; - case RegClass_CRFIELD: - output->optype = OpndType_CRField; - break; - default: - CError_FATAL(456); - } - output->reg = vi->reg; - output->object = NULL; - return; - } - - if (ENODE_IS(inner, EBITFIELD)) { - GEN_NODE(inner->data.monadic, &op); - indirect(&op, expr); - ENSURE_GPR(&op, type, 0); - extract_bitfield(&op, TYPE_BITFIELD(inner->rtype), outputReg, output); - return; - } - - if (ispostincrementopportunity(inner, &op, &postincvalue) && (TYPE_FITS_IN_REGISTER(type) || IS_TYPE_FLOAT(type) || IS_TYPE_VECTOR(type))) { - indirect(&op, expr); - *output = op; - if (TYPE_FITS_IN_REGISTER(type)) { - ENSURE_GPR(output, type, outputReg); - } else if (IS_TYPE_FLOAT(type)) { - ENSURE_FPR(output, type, outputReg); - } else { - ENSURE_VR(output, type, outputReg); - } - - add_register_immediate(op.reg, op.reg, postincvalue); - return; - } - - GEN_NODE(inner, output); - indirect(output, expr); -} - -void gen_MONMIN(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - Type *type; - ENode *scan; - - inner = expr->data.monadic; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_MONMIN(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_FLOAT(type)) { - if (ENODE_IS(inner, EADD) && ENODE_IS(inner->data.diadic.left, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FNMADDS : PC_FNMADD, - inner->data.diadic.left->data.diadic.left, - inner->data.diadic.left->data.diadic.right, - inner->data.diadic.right, - outputReg, - output); - } else if (ENODE_IS(inner, EADD) && ENODE_IS(inner->data.diadic.right, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FNMADDS : PC_FNMADD, - inner->data.diadic.right->data.diadic.left, - inner->data.diadic.right->data.diadic.right, - inner->data.diadic.left, - outputReg, - output); - } else if (ENODE_IS(inner, ESUB) && ENODE_IS(inner->data.diadic.left, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FNMSUBS : PC_FNMSUB, - inner->data.diadic.left->data.diadic.left, - inner->data.diadic.left->data.diadic.right, - inner->data.diadic.right, - outputReg, - output); - } else { - fp_unary_operator(PC_FNEG, inner, outputReg, output); - } - return; - } - - scan = inner; - while (ENODE_IS(scan, ETYPCON) && IS_TYPE_INT_OR_ENUM(type) && !is_unsigned(type)) - scan = scan->data.monadic; - - switch (scan->type) { - case ELESS: - case EGREATER: - case ELESSEQU: - case EGREATEREQU: - case EEQU: - case ENOTEQU: - if (TYPE_FITS_IN_REGISTER(scan->data.diadic.left->rtype) && TYPE_FITS_IN_REGISTER(scan->data.diadic.right->rtype)) { - gen_negated_condition_gpr(scan, output, outputReg); - return; - } - } - unary_operator(PC_NEG, inner, outputReg, output); -} - -void gen_BINNOT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - Type *type; - - inner = expr->data.monadic; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_BINNOT(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(inner, EAND)) - binary_operator(PC_NAND, inner->data.diadic.left, inner->data.diadic.right, outputReg, output); - else if (ENODE_IS(inner, EOR)) - binary_operator(PC_NOR, inner->data.diadic.left, inner->data.diadic.right, outputReg, output); - else if (ENODE_IS(inner, EXOR)) - binary_operator(PC_EQV, inner->data.diadic.left, inner->data.diadic.right, outputReg, output); - else - unary_operator(PC_NOT, inner, outputReg, output); -} - -void gen_FORCELOAD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - - inner = expr->data.monadic; - GEN_NODE(inner, output); - - if (IS_TYPE_FLOAT(inner->rtype)) { - ENSURE_FPR(output, inner->rtype, outputReg); - } else if (IS_TYPE_VECTOR(inner->rtype)) { - ENSURE_VR(output, inner->rtype, outputReg); - } else if (TYPE_FITS_IN_REGISTER(inner->rtype)) { - if (TYPE_IS_8BYTES(inner->rtype)) - coerce_to_register_pair(output, inner->rtype, outputReg, outputRegHi); - else - ENSURE_GPR(output, inner->rtype, outputReg); - } else if (!IS_TYPE_VOID(inner->rtype)) { - CError_FATAL(681); - } -} - -void gen_MUL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - Type *type; - int tmp; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_MUL(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_FLOAT(type)) { - fp_binary_operator((type->size == 4) ? PC_FMULS : PC_FMUL, left, right, outputReg, output); - return; - } - - if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { - shift_left_immediate(left, tmp, 0, outputReg, output); - } else if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(-right->data.intval.lo))) { - shift_left_immediate(left, tmp, 1, outputReg, output); - } else if (ENODE_IS(left, EINTCONST) && (tmp = ispowerof2(left->data.intval.lo))) { - shift_left_immediate(right, tmp, 0, outputReg, output); - } else if (ENODE_IS(left, EINTCONST) && (tmp = ispowerof2(-left->data.intval.lo))) { - shift_left_immediate(right, tmp, 1, outputReg, output); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT(right->data.intval.lo)) { - binary_immediate(PC_MULLI, left, right->data.intval.lo, outputReg, output); - } else if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT(left->data.intval.lo)) { - binary_immediate(PC_MULLI, right, left->data.intval.lo, outputReg, output); - } else { - binary_operator(PC_MULLW, left, right, outputReg, output); - } -} - -struct ms { - SInt32 m; - int s; -}; -static void create_signed_magic(SInt32 val, struct ms *output) { - // PowerPC CWG page 57-58 - int p; - UInt32 ad, anc, delta, q1, r1, q2, r2, t; - - ad = abs(val); - t = 0x80000000U + ((UInt32) val >> 31); - anc = t - 1 - t % ad; - p = 31; - q1 = 0x80000000U / anc; - r1 = 0x80000000U - q1 * anc; - q2 = 0x80000000U / ad; - r2 = 0x80000000U - q2 * ad; - - do { - p = p + 1; - q1 = 2 * q1; - r1 = 2 * r1; - if (r1 >= anc) { - q1 = q1 + 1; - r1 = r1 - anc; - } - q2 = 2 * q2; - r2 = 2 * r2; - if (r2 >= ad) { - q2 = q2 + 1; - r2 = r2 - ad; - } - delta = ad - r2; - } while (q1 < delta || (q1 == delta && r1 == 0)); - - // after loop - output->m = q2 + 1; - if (val < 0) - output->m = -output->m; - output->s = p - 32; -} - -struct mu { - UInt32 m; - int a; - int s; -}; -static void create_unsigned_magic(UInt32 val, struct mu *output) { - // PowerPC CWG page 58-59 - int p; - UInt32 nc, delta, q1, r1, q2, r2; - - output->a = 0; - nc = - 1 - (-val) % val; - p = 31; - q1 = 0x80000000U / nc; - r1 = 0x80000000U - q1 * nc; - q2 = 0x7FFFFFFFU / val; - r2 = 0x7FFFFFFFU - q2 * val; - do { - p = p + 1; - if (r1 >= nc - r1) { - q1 = 2 * q1 + 1; - r1 = 2 * r1 - nc; - } else { - q1 = 2 * q1; - r1 = 2 * r1; - } - if (r2 + 1 >= val - r2) { - if (q2 >= 0x7FFFFFFFU) - output->a = 1; - q2 = 2 * q2 + 1; - r2 = 2 * r2 + 1 - val; - } else { - if (q2 >= 0x80000000U) - output->a = 1; - q2 = 2 * q2; - r2 = 2 * r2 + 1; - } - delta = val - 1 - r2; - } while (p < 64 && (q1 < delta || (q1 == delta && r1 == 0))); - - output->m = q2 + 1; - output->s = p - 32; -} - -void gen_DIV(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - Type *type; - int tmp; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_DIV_MOD(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_FLOAT(type)) { - fp_binary_operator((type->size == 4) ? PC_FDIVS : PC_FDIV, left, right, outputReg, output); - return; - } - - if (is_unsigned(type)) { - if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { - shift_right_immediate(left, type, tmp, outputReg, output); - } else if (!copts.optimizesize && ENODE_IS(right, EINTCONST) && right->data.intval.lo != 1) { - SInt32 value; - int tmpreg1; - int tmpreg2; - int tmpreg3; - int tmpreg4; - int tmpreg5; - int tmpreg6; - int finalReg; - struct mu u_magicoutput; - Operand op1; - value = right->data.intval.lo; - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - - memclrw(&op1, sizeof(Operand)); - GEN_NODE(left, &op1); - ENSURE_GPR(&op1, left->rtype, 0); - - tmpreg3 = op1.reg; - create_unsigned_magic(value, &u_magicoutput); - load_immediate(tmpreg2, u_magicoutput.m); - emitpcode(PC_MULHWU, tmpreg1, tmpreg2, tmpreg3); - if (u_magicoutput.a == 0) { - if (u_magicoutput.s) - emitpcode(PC_RLWINM, finalReg, tmpreg1, (32 - u_magicoutput.s) & 31, u_magicoutput.s, 31); - else - emitpcode(PC_MR, finalReg, tmpreg1); - } else if (u_magicoutput.a == 1) { - tmpreg4 = ALLOC_GPR(); - if (copts.optimizationlevel > 1) { - tmpreg5 = ALLOC_GPR(); - tmpreg6 = ALLOC_GPR(); - } else { - tmpreg5 = tmpreg4; - tmpreg6 = tmpreg4; - } - - emitpcode(PC_SUBF, tmpreg4, tmpreg1, tmpreg3); - emitpcode(PC_RLWINM, tmpreg5, tmpreg4, 31, 1, 31); - emitpcode(PC_ADD, tmpreg6, tmpreg5, tmpreg1); - emitpcode(PC_RLWINM, finalReg, tmpreg6, (32 - (u_magicoutput.s - 1)) & 31, u_magicoutput.s - 1, 31); - } - - output->optype = OpndType_GPR; - output->reg = finalReg; - } else { - binary_operator(PC_DIVWU, left, right, outputReg, output); - } - } else { - SInt32 value; - if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { - signed_divide_by_power_of_2(left, tmp, 0, outputReg, output); - } else if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(-right->data.intval.lo))) { - signed_divide_by_power_of_2(left, tmp, 1, outputReg, output); - } else if (!copts.optimizesize && ENODE_IS(right, EINTCONST) && (value = right->data.intval.lo) != 1u && value != -1) { - int tmpreg2; - int tmpreg3; - int tmpreg1; - int tmpreg4; - int finalReg; - struct ms s_magicoutput; - Operand op2; - value = right->data.intval.lo; - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - - memclrw(&op2, sizeof(Operand)); - GEN_NODE(left, &op2); - ENSURE_GPR(&op2, left->rtype, 0); - - tmpreg4 = op2.reg; - create_signed_magic(value, &s_magicoutput); - load_immediate(tmpreg2, s_magicoutput.m); - emitpcode(PC_MULHW, tmpreg1, tmpreg2, tmpreg4); - if (value > 0 && s_magicoutput.m < 0) { - int t = ALLOC_GPR(); - emitpcode(PC_ADD, t, tmpreg1, tmpreg4); - tmpreg1 = t; - } else if (value < 0 && s_magicoutput.m > 0) { - int t = ALLOC_GPR(); - emitpcode(PC_SUBF, t, tmpreg4, tmpreg1); - tmpreg1 = t; - } - - if (s_magicoutput.s) { - int t = ALLOC_GPR(); - emitpcode(PC_SRAWI, t, tmpreg1, s_magicoutput.s); - tmpreg1 = t; - } - - emitpcode(PC_RLWINM, tmpreg3, tmpreg1, 1, 31, 31); - emitpcode(PC_ADD, finalReg, tmpreg1, tmpreg3); - - output->optype = OpndType_GPR; - output->reg = finalReg; - } else { - binary_operator(PC_DIVW, left, right, outputReg, output); - } - } -} - -void gen_MODULO(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - int tmp; - struct mu u_magicoutput; - struct ms s_magicoutput; - Operand op1; - Operand op2; - SInt32 value; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - memclrw(&op1, sizeof(Operand)); - memclrw(&op2, sizeof(Operand)); - - if (TYPE_IS_8BYTES(expr->rtype)) { - I8_gen_DIV_MOD(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { - if (is_unsigned(expr->rtype)) - shift_and_mask(left, 0, 32 - tmp, 31, outputReg, output); - else - signed_mod_by_power_of_2(left, tmp, 0, outputReg, output); - } else if (!copts.optimizesize && ENODE_IS(right, EINTCONST) && (value = right->data.intval.lo) != 1u && value != -1) { - GEN_NODE(left, &op1); - ENSURE_GPR(&op1, left->rtype, 0); - - if (is_unsigned(expr->rtype)) { - int tmpreg1; - int tmpreg2; - int tmpreg3; - int tmpreg4; - int tmpreg5; - int tmpreg6; - int tmpreg7; - int tmpreg8; - int finalReg; - - tmpreg1 = op1.reg; - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - tmpreg4 = ALLOC_GPR(); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - - create_unsigned_magic(right->data.intval.lo, &u_magicoutput); - load_immediate(tmpreg3, u_magicoutput.m); - emitpcode(PC_MULHWU, tmpreg2, tmpreg3, tmpreg1); - - if (u_magicoutput.a == 0 && u_magicoutput.s != 0) - emitpcode(PC_RLWINM, tmpreg2, tmpreg2, (32 - u_magicoutput.s) & 31, u_magicoutput.s, 31); - - if (u_magicoutput.a == 1) { - tmpreg5 = ALLOC_GPR(); - if (copts.optimizationlevel > 1) { - tmpreg6 = ALLOC_GPR(); - tmpreg7 = ALLOC_GPR(); - tmpreg8 = ALLOC_GPR(); - } else { - tmpreg6 = tmpreg5; - tmpreg7 = tmpreg5; - tmpreg8 = tmpreg5; - } - emitpcode(PC_SUBF, tmpreg5, tmpreg2, tmpreg1); - emitpcode(PC_RLWINM, tmpreg6, tmpreg5, 31, 1, 31); - emitpcode(PC_ADD, tmpreg7, tmpreg6, tmpreg2); - emitpcode(PC_RLWINM, tmpreg8, tmpreg7, (32 - (u_magicoutput.s - 1)) & 31, u_magicoutput.s - 1, 31); - tmpreg2 = tmpreg8; - } - - if (value > 0 && value < 0x7FFF) { - emitpcode(PC_MULLI, tmpreg4, tmpreg2, value); - } else { - GEN_NODE(right, &op2); - ENSURE_GPR(&op2, right->rtype, 0); - emitpcode(PC_MULLW, tmpreg4, tmpreg2, op2.reg); - } - - emitpcode(PC_SUBF, finalReg, tmpreg4, tmpreg1); - output->optype = OpndType_GPR; - output->reg = finalReg; - } else { - int tmpreg1; - int tmpreg2; - int tmpreg3; - int tmpreg4; - int tmpreg5; - int tmpreg6; - int finalReg; - - tmpreg1 = op1.reg; - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - tmpreg4 = ALLOC_GPR(); - tmpreg5 = ALLOC_GPR(); - tmpreg6 = ALLOC_GPR(); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - - create_signed_magic(right->data.intval.lo, &s_magicoutput); - load_immediate(tmpreg3, s_magicoutput.m); - emitpcode(PC_MULHW, tmpreg2, tmpreg3, tmpreg1); - - if (value > 0 && s_magicoutput.m < 0) { - int tmp = ALLOC_GPR(); - emitpcode(PC_ADD, tmp, tmpreg2, tmpreg1); - tmpreg2 = tmp; - } else if (value < 0 && s_magicoutput.m > 0) { - int tmp = ALLOC_GPR(); - emitpcode(PC_SUBF, tmp, tmpreg1, tmpreg2); - tmpreg2 = tmp; - } - - if (s_magicoutput.s != 0) { - int tmp = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmp, tmpreg2, s_magicoutput.s); - tmpreg2 = tmp; - } - - emitpcode(PC_RLWINM, tmpreg4, tmpreg2, 1, 31, 31); - emitpcode(PC_ADD, tmpreg5, tmpreg2, tmpreg4); - - if (value < 0x7FFF && value > -0x4000) { - emitpcode(PC_MULLI, tmpreg6, tmpreg5, value); - } else { - GEN_NODE(right, &op2); - ENSURE_GPR(&op2, right->rtype, 0); - - emitpcode(PC_MULLW, tmpreg6, tmpreg5, op2.reg); - } - - emitpcode(PC_SUBF, finalReg, tmpreg6, tmpreg1); - output->optype = OpndType_GPR; - output->reg = finalReg; - } - } else { - int tmpreg1; - int tmpreg2; - int finalReg; - - if (right->hascall) { - GEN_NODE(right, &op2); - ENSURE_GPR(&op2, right->rtype, 0); - GEN_NODE(left, &op1); - ENSURE_GPR(&op1, left->rtype, 0); - } else { - GEN_NODE(left, &op1); - ENSURE_GPR(&op1, left->rtype, 0); - GEN_NODE(right, &op2); - ENSURE_GPR(&op2, right->rtype, 0); - } - - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - - emitpcode(is_unsigned(expr->rtype) ? PC_DIVWU : PC_DIVW, tmpreg1, op1.reg, op2.reg); - emitpcode(PC_MULLW, tmpreg2, tmpreg1, op2.reg); - emitpcode(PC_SUBF, finalReg, tmpreg2, op1.reg); - - output->optype = OpndType_GPR; - output->reg = finalReg; - } -} - -void gen_ADD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - Type *type; - Operand opleft; - Operand opright; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - if (TYPE_IS_8BYTES(type)) { - I8_gen_ADD(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_FLOAT(type)) { - if (ENODE_IS(left, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FMADDS : PC_FMADD, - left->data.diadic.left, - left->data.diadic.right, - right, - outputReg, output); - } else if (ENODE_IS(right, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FMADDS : PC_FMADD, - right->data.diadic.left, - right->data.diadic.right, - left, - outputReg, output); - } else { - fp_binary_operator( - (type->size == 4) ? PC_FADDS : PC_FADD, - left, right, - outputReg, output); - } - return; - } - - if (right->hascall) { - GEN_NODE(right, &opright); - if (opright.optype >= OpndType_IndirectGPR_ImmOffset) - ENSURE_GPR(&opright, right->rtype, 0); - - GEN_NODE(left, &opleft); - if (opleft.optype >= OpndType_IndirectGPR_ImmOffset) - ENSURE_GPR(&opleft, left->rtype, 0); - } else { - GEN_NODE(left, &opleft); - if (opleft.optype >= OpndType_IndirectGPR_ImmOffset) - ENSURE_GPR(&opleft, left->rtype, 0); - - GEN_NODE(right, &opright); - if (opright.optype >= OpndType_IndirectGPR_ImmOffset) - ENSURE_GPR(&opright, right->rtype, 0); - } - - if (IS_TYPE_POINTER(expr->rtype)) { - if (TYPE_IS_8BYTES(expr->data.diadic.left->rtype)) { - opleft.optype = OpndType_GPR; - opleft.regHi = 0; - } - if (TYPE_IS_8BYTES(expr->data.diadic.right->rtype)) { - opright.optype = OpndType_GPR; - opright.regHi = 0; - } - } - - combine(&opleft, &opright, outputReg, output); -} - -void gen_SUB(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - Type *type; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_SUB(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_FLOAT(type)) { - if (ENODE_IS(left, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FMSUBS : PC_FMSUB, - left->data.diadic.left, - left->data.diadic.right, - right, - outputReg, output); - } else if (ENODE_IS(right, EMUL) && copts.fp_contract) { - fp_multiply_add( - (type->size == 4) ? PC_FNMSUBS : PC_FNMSUB, - right->data.diadic.left, - right->data.diadic.right, - left, - outputReg, output); - } else { - fp_binary_operator( - (type->size == 4) ? PC_FSUBS : PC_FSUB, - left, right, - outputReg, output); - } - return; - } - - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT(left->data.intval.lo)) - binary_immediate(PC_SUBFIC, right, left->data.intval.lo, outputReg, output); - else - binary_operator(PC_SUBF, right, left, outputReg, output); -} - -void gen_SHL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_SHL_SHR(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(right, EINTCONST)) - shift_left_immediate(left, right->data.intval.lo, 0, outputReg, output); - else - binary_operator(PC_SLW, left, right, outputReg, output); -} - -void gen_SHR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_SHL_SHR(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(right, EINTCONST)) - shift_right_immediate(left, type, right->data.intval.lo, outputReg, output); - else - binary_operator(is_unsigned(type) ? PC_SRW : PC_SRAW, left, right, outputReg, output); -} - -void gen_AND(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - short first; - short last; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_AND(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(right, EINTCONST) && ismaskconstant(right->data.intval.lo, &first, &last)) { - if (ENODE_IS(left, ESHL) && ENODE_IS(left->data.diadic.right, EINTCONST) && (int)(left->data.diadic.right->data.intval.lo + last) < 32) { - shift_and_mask( - left->data.diadic.left, - left->data.diadic.right->data.intval.lo, - first, last, - outputReg, output); - } else if (ENODE_IS(left, ESHR) && ENODE_IS(left->data.diadic.right, EINTCONST) && (int)left->data.diadic.right->data.intval.lo <= first && last >= first) { - if (left->data.diadic.right->data.intval.lo == 0) - shift_and_mask(left->data.diadic.left, 0, first, last, outputReg, output); - else - shift_and_mask(left->data.diadic.left, 32 - left->data.diadic.right->data.intval.lo, first, last, outputReg, output); - } else { - shift_and_mask(left, 0, first, last, outputReg, output); - } - return; - } - - if (ENODE_IS(right, EINTCONST) && FITS_IN_USHORT(right->data.intval.lo)) { - binary_immediate(PC_ANDI, left, right->data.intval.lo, outputReg, output); - return; - } - if (ENODE_IS(right, EINTCONST) && FITS_IN_HI_SHORT(right->data.intval.lo)) { - binary_immediate(PC_ANDIS, left, right->data.intval.lo >> 16, outputReg, output); - return; - } - - if (ENODE_IS(left, EINTCONST) && ismaskconstant(left->data.intval.lo, &first, &last)) { - if (ENODE_IS(right, ESHL) && ENODE_IS(right->data.diadic.right, EINTCONST) && (int)(right->data.diadic.right->data.intval.lo + last) < 32) { - shift_and_mask( - right->data.diadic.left, - right->data.diadic.right->data.intval.lo, - first, last, - outputReg, output); - } else if (ENODE_IS(right, ESHR) && ENODE_IS(right->data.diadic.right, EINTCONST) && (int)right->data.diadic.right->data.intval.lo <= first) { - if (right->data.diadic.right->data.intval.lo == 0) - shift_and_mask(right->data.diadic.left, 0, first, last, outputReg, output); - else - shift_and_mask(right->data.diadic.left, 32 - right->data.diadic.right->data.intval.lo, first, last, outputReg, output); - } else { - shift_and_mask(right, 0, first, last, outputReg, output); - } - return; - } - - if (ENODE_IS(left, EINTCONST) && FITS_IN_USHORT(left->data.intval.lo)) { - binary_immediate(PC_ANDI, right, left->data.intval.lo, outputReg, output); - return; - } - if (ENODE_IS(left, EINTCONST) && FITS_IN_HI_SHORT(left->data.intval.lo)) { - binary_immediate(PC_ANDIS, right, left->data.intval.lo >> 16, outputReg, output); - return; - } - - if (ENODE_IS(right, EBINNOT)) - binary_operator(PC_ANDC, left, right->data.monadic, outputReg, output); - else if (ENODE_IS(left, EBINNOT)) - binary_operator(PC_ANDC, right, left->data.monadic, outputReg, output); - else - binary_operator(PC_AND, left, right, outputReg, output); -} - -void gen_XOR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_XOR(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(left, EINTCONST)) - or_xor_immediate(PC_XORI, right, left->data.intval.lo, outputReg, output); - else if (ENODE_IS(right, EINTCONST)) - or_xor_immediate(PC_XORI, left, right->data.intval.lo, outputReg, output); - else if (ENODE_IS(right, EBINNOT)) - binary_operator(PC_EQV, left, right->data.monadic, outputReg, output); - else if (ENODE_IS(left, EBINNOT)) - binary_operator(PC_EQV, left->data.monadic, right, outputReg, output); - else - binary_operator(PC_XOR, left, right, outputReg, output); -} - -void gen_OR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - type = expr->rtype; - - if (TYPE_IS_8BYTES(type)) { - I8_gen_OR(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(left, EINTCONST)) - or_xor_immediate(PC_ORI, right, left->data.intval.lo, outputReg, output); - else if (ENODE_IS(right, EINTCONST)) - or_xor_immediate(PC_ORI, left, right->data.intval.lo, outputReg, output); - else if (ENODE_IS(right, EBINNOT)) - binary_operator(PC_ORC, left, right->data.monadic, outputReg, output); - else if (ENODE_IS(left, EBINNOT)) - binary_operator(PC_ORC, right, left->data.monadic, outputReg, output); - else - binary_operator(PC_OR, left, right, outputReg, output); -} - -void gen_ASS(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - Operand opleft; - Operand opright; - Operand op2; - VarInfo *vi; - SInt32 incval; - short align; - short align2; - - type = expr->rtype; - if (ENODE_IS(expr, ECONDASS)) { - left = expr->data.cond.expr1; - if (ENODE_IS(left, EINDIRECT)) { - left = left->data.monadic; - } else { - CError_FATAL(1759); - } - right = expr->data.cond.expr2; - } else { - left = expr->data.diadic.left; - right = expr->data.diadic.right; - } - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - memclrw(&op2, sizeof(Operand)); - - if (TYPE_IS_8BYTES(type)) { - I8_gen_ASS(expr, outputReg, outputRegHi, output); - return; - } - - if (ENODE_IS(left, EOBJREF) && OBJECT_REG(left->data.objref)) { - vi = Registers_GetVarInfo(left->data.objref); - GEN_NODE_TO_REG(right, vi->reg, 0, &opright); - switch (vi->rclass) { - case RegClass_GPR: - ENSURE_GPR(&opright, type, vi->reg); - output->optype = OpndType_GPR; - break; - case RegClass_FPR: - ENSURE_FPR(&opright, type, vi->reg); - output->optype = OpndType_FPR; - break; - case RegClass_VR: - ENSURE_VR(&opright, type, vi->reg); - output->optype = OpndType_VR; - break; - default: - CError_FATAL(1810); - } - if (opright.reg != vi->reg) { - PCodeArg a, b; - a.kind = PCOp_REGISTER; - a.arg = vi->rclass; - a.data.reg.reg = vi->reg; - a.data.reg.effect = EffectWrite; - b.kind = PCOp_REGISTER; - b.arg = vi->rclass; - b.data.reg.reg = opright.reg; - b.data.reg.effect = EffectRead; - appendpcode(pclastblock, makecopyinstruction(&b, &a)); - } - output->reg = vi->reg; - return; - } - - if (IS_TYPE_FLOAT(type)) { - GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); - if (ispostincrementopportunity(left, &opleft, &incval)) { - indirect(&opleft, expr); - store_fp(opright.reg, &opleft, type); - add_register_immediate(opleft.reg, opleft.reg, incval); - } else { - GEN_NODE(left, &opleft); - indirect(&opleft, expr); - store_fp(opright.reg, &opleft, type); - } - output->optype = OpndType_FPR; - output->reg = opright.reg; - return; - } - - if (IS_TYPE_VECTOR(type)) { - GEN_NODE(right, &opright); - if (opright.optype == OpndType_Absolute) - ENSURE_VR(&opright, type, 0); - else - ENSURE_VR(&opright, right->rtype, 0); - - if (ispostincrementopportunity(left, &opleft, &incval)) { - indirect(&opleft, expr); - store_v(opright.reg, &opleft, type); - add_register_immediate(opleft.reg, opleft.reg, incval); - } else { - GEN_NODE(left, &opleft); - indirect(&opleft, expr); - store_v(opright.reg, &opleft, type); - } - output->optype = OpndType_VR; - output->reg = opright.reg; - return; - } - - if (TYPE_FITS_IN_REGISTER(type)) { - GEN_NODE_TO_GPR(right, &opright, right->rtype, 0); - - if (ENODE_IS(left, EBITFIELD)) { - GEN_NODE(left->data.monadic, &opleft); - indirect(&opleft, expr); - - op2 = opleft; - ENSURE_GPR(&op2, type, 0); - insert_bitfield(opright.reg, &op2, TYPE_BITFIELD(left->rtype)); - store(op2.reg, &opleft, type); - - if (!expr->ignored) - extract_bitfield(&op2, TYPE_BITFIELD(left->rtype), opright.reg, &opleft); - } else if (ispostincrementopportunity(left, &opleft, &incval)) { - indirect(&opleft, expr); - store(opright.reg, &opleft, type); - add_register_immediate(opleft.reg, opleft.reg, incval); - } else { - GEN_NODE(left, &opleft); - indirect(&opleft, expr); - store(opright.reg, &opleft, type); - } - - output->optype = OpndType_GPR; - output->reg = opright.reg; - return; - } - - GEN_NODE(right, &opright); - GEN_NODE(left, output); - - indirect(output, expr); - if (output->object) { - if (output->object->datatype == DLOCAL && (output->object->u.var.info->flags & VarInfoFlag1)) - align = CMach_ArgumentAlignment(type); - else - align = CMach_AllocationAlignment(type, output->object->qual); - } else { - align = CMach_AllocationAlignment(type, 0); - } - if (opright.object) { - if (opright.object->datatype == DLOCAL && (opright.object->u.var.info->flags & VarInfoFlag1)) - align2 = CMach_ArgumentAlignment(type); - else - align2 = CMach_AllocationAlignment(type, opright.object->qual); - } else { - align2 = CMach_AllocationAlignment(type, 0); - } - - if (align2 < align) - align = align2; - - move_block(output, &opright, type->size, align); -} - -ENode *evaluate_and_skip_comma(ENode *expr) { - Operand op; - ENode *inner; - - memclrw(&op, sizeof(Operand)); - while (ENODE_IS(expr, ECOMMA)) { - inner = expr->data.diadic.left; - GEN_NODE(inner, &op); - if (ENODE_IS(inner, EINDIRECT) && (op.flags & OpndFlags_Volatile)) { - if (TYPE_FITS_IN_REGISTER_2(inner->rtype)) { - ENSURE_GPR(&op, inner->rtype, 0); - } else if (IS_TYPE_FLOAT(inner->rtype)) { - ENSURE_FPR(&op, inner->rtype, 0); - } - } - expr = expr->data.diadic.right; - } - return expr; -} - -void gen_COMMA(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - GEN_NODE(left, output); - - if (ENODE_IS(left, EINDIRECT) && (output->flags & OpndFlags_Volatile)) { - if (TYPE_FITS_IN_REGISTER_2(left->rtype)) { - ENSURE_GPR(output, left->rtype, 0); - } else if (IS_TYPE_FLOAT(left->rtype)) { - ENSURE_FPR(output, left->rtype, 0); - } - } - - GEN_NODE_TO_REG(right, outputReg, 0, output); -} - -void gen_TYPCON(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - Type *srctype; - Type *dsttype; - - inner = expr->data.monadic; - srctype = inner->rtype; - dsttype = expr->rtype; - - if (TYPE_IS_8BYTES(srctype) || TYPE_IS_8BYTES(dsttype)) { - I8_gen_TYPCON(expr, outputReg, outputRegHi, output); - return; - } - - if (IS_TYPE_VOID(dsttype)) { - GEN_NODE(inner, output); - if (ENODE_IS(inner, EINDIRECT) && (output->flags & OpndFlags_Volatile)) { - if (TYPE_FITS_IN_REGISTER_2(srctype)) { - ENSURE_GPR(output, srctype, 0); - } else if (IS_TYPE_FLOAT(srctype)) { - ENSURE_FPR(output, srctype, 0); - } - } - } else if (IS_TYPE_INT_OR_ENUM(srctype)) { - if (IS_TYPE_FLOAT(dsttype)) { - GEN_NODE(inner, output); - if (srctype->size < 4) - extend32(output, srctype, 0); - ENSURE_GPR(output, srctype, 0); - - if (is_unsigned(srctype)) - convert_unsigned_to_floating(output, dsttype->size == 4, outputReg); - else - convert_integer_to_floating(output, dsttype->size == 4, outputReg); - } else if (IS_TYPE_VECTOR(dsttype)) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - ENSURE_VR(output, dsttype, outputReg); - } else if ( - srctype->size < dsttype->size && - !ENODE_IS_INDIRECT_TO(inner, EBITFIELD) && - !ENODE_IS_ASSIGN_TO(inner, EBITFIELD) && - !(ENODE_IS_RANGE(inner, EPOSTINC, EPREDEC) && ENODE_IS(inner->data.monadic->data.monadic, EBITFIELD)) - ) { - GEN_NODE(inner, output); - extend32(output, srctype, outputReg); - } else if (dsttype->size < srctype->size || dsttype->size < 4) { - GEN_NODE(inner, output); - ENSURE_GPR(output, srctype, 0); - extend32(output, dsttype, outputReg); - } else { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - } - } else if (IS_TYPE_POINTER(srctype)) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - if (dsttype->size < srctype->size) - ENSURE_GPR(output, srctype, outputReg); - } else if (IS_TYPE_FLOAT(srctype)) { - if (IS_TYPE_FLOAT(dsttype)) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - ENSURE_FPR(output, srctype, outputReg); - - if (dsttype->size == 4 && srctype->size != 4) { - int tmp = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(PC_FRSP, tmp, output->reg); - output->optype = OpndType_FPR; - output->reg = tmp; - } - } else if (is_unsigned(dsttype) && dsttype->size == 4) { - GEN_NODE_TO_REG(inner, 1, 0, output); - ENSURE_FPR(output, srctype, 1); - convert_floating_to_unsigned(output, outputReg); - } else { - GEN_NODE_TO_REG(inner, 0, 0, output); - ENSURE_FPR(output, srctype, 0); - convert_floating_to_integer(output, outputReg); - } - } else if (IS_TYPE_VECTOR(srctype) && IS_TYPE_VECTOR(dsttype)) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - ENSURE_VR(output, srctype, outputReg); - } else if (srctype->size == dsttype->size) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - } else { - CError_FATAL(2224); - } -} - -void gen_BITFIELD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - CError_FATAL(2238); -} - -void gen_INTCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - if (TYPE_IS_8BYTES(expr->rtype)) { - I8_gen_INTCONST(expr, outputReg, outputRegHi, output); - return; - } - - output->optype = OpndType_Absolute; - output->immediate = CInt64_GetULong(&expr->data.intval); -} - -void gen_FLOATCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - CError_FATAL(2294); -} - -void gen_STRINGCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - CError_FATAL(2308); -} - -static Boolean COND_is_ABS_MatchNodes(ENode *cond, ENode *expr1, ENode *expr2) { - if (cond->type != expr1->type || cond->type != expr2->type) - return 0; - - if (!(TYPE_FITS_IN_REGISTER(cond->rtype) && TYPE_FITS_IN_REGISTER(expr1->rtype) && TYPE_FITS_IN_REGISTER(expr2->rtype))) - return 0; - - if (cond->rtype->size != expr1->rtype->size || cond->rtype->size != expr2->rtype->size) - return 0; - - switch (cond->type) { - case EOBJREF: - if (cond->data.objref != expr1->data.objref || cond->data.objref != expr2->data.objref) - return 0; - return 1; - case EINDIRECT: - case ETYPCON: - return COND_is_ABS_MatchNodes(cond->data.monadic, expr1->data.monadic, expr2->data.monadic); - default: - return 0; - } -} - -static ENode *COND_is_ABS(ENode *cond, ENode *expr1, ENode *expr2) { - ENode *tmp; - - int parity = 0; - while (ENODE_IS(cond, ELOGNOT)) { - parity = (parity + 1) & 1; - cond = cond->data.monadic; - } - - if (parity) { - tmp = expr1; - expr1 = expr2; - expr2 = tmp; - } - - switch (cond->type) { - case ELESS: - case ELESSEQU: - tmp = expr1; - expr1 = expr2; - expr2 = tmp; - break; - case EGREATER: - case EGREATEREQU: - break; - default: - return NULL; - } - - if (IS_INT_CONST_ZERO(cond->data.diadic.right)) { - cond = cond->data.diadic.left; - } else if (IS_INT_CONST_ZERO(cond->data.diadic.left)) { - cond = cond->data.diadic.left; - tmp = expr1; - expr1 = expr2; - expr2 = tmp; - } else { - return NULL; - } - - if (ENODE_IS(expr1, EADD) && ENODE_IS(expr2, ESUB)) { - if (COND_is_ABS_MatchNodes(cond, expr1->data.diadic.right, expr2->data.diadic.right)) - return expr1; - else - return NULL; - } - - if (!ENODE_IS(expr2, EMONMIN)) - return NULL; - - expr2 = expr2->data.monadic; - if (COND_is_ABS_MatchNodes(cond, expr1, expr2)) - return expr1; - - return NULL; -} - -static int COND_has_const(ENode *expr1, ENode *expr2) { - SInt32 diff; - int result = 0; - - if (IS_INT_CONST(expr1)) - result += 1; - if (IS_INT_CONST(expr2)) - result += 2; - - if (result & 1) { - if (IS_INT_CONST_ZERO(expr1)) - return 5; - } - if (result & 2) { - if (IS_INT_CONST_ZERO(expr2)) - return 6; - } - - if (result == 3) { - diff = expr1->data.intval.lo - expr2->data.intval.lo; - if (diff == 1 || diff == -1) - return 4; - } - - return result; -} - -static Boolean COND_is_COMPARE(ENode *cond, ENode *expr1, ENode *expr2, short outputReg, Operand *output) { - SInt32 left; - SInt32 right; - int parity; - int negate; - ENodeType nt; - - while (ENODE_IS(expr1, ETYPCON) && TYPE_FITS_IN_REGISTER(expr1->rtype)) - expr1 = expr1->data.monadic; - while (ENODE_IS(expr2, ETYPCON) && TYPE_FITS_IN_REGISTER(expr2->rtype)) - expr2 = expr2->data.monadic; - - if (!(ENODE_IS(expr1, EINTCONST) && TYPE_FITS_IN_REGISTER(expr1->rtype) && CInt64_IsInRange(expr1->data.intval, 4))) - return 0; - if (!(ENODE_IS(expr2, EINTCONST) && TYPE_FITS_IN_REGISTER(expr2->rtype) && CInt64_IsInRange(expr2->data.intval, 4))) - return 0; - - left = CInt64_GetULong(&expr1->data.intval); - right = CInt64_GetULong(&expr2->data.intval); - parity = 0; - negate = 0; - switch (left) { - case 1: - if (right != 0) - return 0; - break; - case 0: - parity = 1; - if (right == -1) - negate = 1; - else if (right != 1) - return 0; - break; - case -1: - if (right != 0) - return 0; - negate = 1; - break; - default: - return 0; - } - - while (ENODE_IS(cond, ELOGNOT)) { - parity = (parity + 1) & 1; - cond = cond->data.monadic; - } - - if (parity) { - nt = invert_relop(cond->type); - if (nt == cond->type) - return 0; - cond->type = nt; - } - - if (negate) - gen_negated_condition_gpr(cond, output, outputReg); - else - gen_condition_gpr(cond, output, outputReg); - - return 1; -} - -void gen_COND(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *cond; - ENode *expr1; - ENode *expr2; - Type *type; - PCodeLabel *label1; - PCodeLabel *label2; - PCodeLabel *label3; - Operand op1; - Operand op2; - int has_const; - int reg1; - int reg2; - int reg3; - short align; - short max_align; - - expr1 = expr->data.cond.expr1; - expr2 = expr->data.cond.expr2; - type = expr->rtype; - - label1 = makepclabel(); - label2 = makepclabel(); - label3 = makepclabel(); - - memclrw(&op1, sizeof(Operand)); - memclrw(&op2, sizeof(Operand)); - - cond = evaluate_and_skip_comma(expr->data.cond.cond); - - if (TOC_use_fsel(expr)) { - ENode *left; - ENode *right; - ENode *tmp; - ENodeType nt; - Boolean flag; - Operand op; - int fneg_reg; - int fneg_reg2; - int fneg_reg3; - int fsel_reg; - int final_reg; - - left = cond->data.diadic.left; - right = cond->data.diadic.right; - nt = cond->type; - flag = 0; - memclrw(&op, sizeof(Operand)); - - switch (nt) { - case EGREATEREQU: - case EEQU: - break; - case EGREATER: - tmp = left; - left = right; - right = tmp; - case ELESS: - case ENOTEQU: - tmp = expr1; - expr1 = expr2; - expr2 = tmp; - break; - case ELESSEQU: - tmp = left; - left = right; - right = tmp; - break; - default: - CError_FATAL(2780); - } - - if (ENODE_IS(left, EFLOATCONST) && CMach_FloatIsZero(left->data.floatval)) { - GEN_NODE(right, &op); - ENSURE_FPR(&op, right->rtype, 0); - flag = 1; - } else if (ENODE_IS(right, EFLOATCONST) && CMach_FloatIsZero(right->data.floatval)) { - GEN_NODE(left, &op); - ENSURE_FPR(&op, left->rtype, 0); - } else { - fp_binary_operator((type->size == 4) ? PC_FSUBS : PC_FSUB, left, right, 0, &op); - } - - switch (cond->type) { - case EEQU: - case ENOTEQU: - if (flag) { - GEN_NODE_TO_FPR(expr1, &op1, expr1->rtype, 0); - GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); - - fneg_reg = ALLOC_FPR(); - emitpcode(PC_FNEG, fneg_reg, op.reg); - fsel_reg = ALLOC_FPR(); - emitpcode(PC_FSEL, fsel_reg, op.reg, op1.reg, op2.reg); - final_reg = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(PC_FSEL, final_reg, fneg_reg, fsel_reg, op2.reg); - } else { - GEN_NODE_TO_FPR(expr1, &op1, expr1->rtype, 0); - GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); - - fneg_reg2 = ALLOC_FPR(); - emitpcode(PC_FNEG, fneg_reg2, op.reg); - fsel_reg = ALLOC_FPR(); - emitpcode(PC_FSEL, fsel_reg, op.reg, op1.reg, op2.reg); - final_reg = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(PC_FSEL, final_reg, fneg_reg2, fsel_reg, op2.reg); - } - break; - case ELESS: - case EGREATER: - case ELESSEQU: - case EGREATEREQU: - GEN_NODE_TO_FPR(expr1, &op1, expr1->rtype, 0); - GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); - - fneg_reg3 = op.reg; - if (flag) { - fneg_reg3 = ALLOC_FPR(); - emitpcode(PC_FNEG, fneg_reg3, op.reg); - } - - final_reg = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(PC_FSEL, final_reg, fneg_reg3, op1.reg, op2.reg); - break; - default: - CError_FATAL(2862); - } - - output->optype = OpndType_FPR; - output->reg = final_reg; - return; - } - - if (TOC_use_isel(expr, 1)) { - Operand isel_op1; - Operand isel_op2; - ENode *x; - ENode *y; - ENode *abs_expr; - - memclrw(&isel_op1, sizeof(Operand)); - memclrw(&isel_op2, sizeof(Operand)); - - if (COND_is_COMPARE(cond, expr1, expr2, outputReg, output)) - return; - - if ((abs_expr = COND_is_ABS(cond, expr1, expr2))) { - if (ENODE_IS(expr1, EADD) && ENODE_IS(expr2, ESUB)) { - x = expr1->data.diadic.left; - y = expr2->data.diadic.right; - if (y->hascall) { - GEN_NODE(y, &op2); - ENSURE_GPR(&op2, y->rtype, 0); - - GEN_NODE(x, &op1); - if (op1.optype >= OpndType_IndirectGPR_ImmOffset) - ENSURE_GPR(&op1, x->rtype, 0); - } else { - GEN_NODE(x, &op1); - if (op1.optype >= OpndType_IndirectGPR_ImmOffset) - ENSURE_GPR(&op1, x->rtype, 0); - - GEN_NODE(y, &op2); - ENSURE_GPR(&op2, y->rtype, 0); - } - - reg1 = ALLOC_GPR(); - emitpcode(PC_SRAWI, reg1, op2.reg, 31); - reg2 = ALLOC_GPR(); - emitpcode(PC_XOR, reg2, reg1, op2.reg); - reg3 = ALLOC_GPR(); - emitpcode(PC_SUBF, reg3, reg1, reg2); - op2.optype = OpndType_GPR; - op2.reg = reg3; - combine(&op1, &op2, outputReg, output); - } else { - GEN_NODE(abs_expr, output); - ENSURE_GPR(output, abs_expr->rtype, 0); - - reg1 = ALLOC_GPR(); - emitpcode(PC_SRAWI, reg1, output->reg, 31); - reg2 = ALLOC_GPR(); - emitpcode(PC_XOR, reg2, reg1, output->reg); - reg3 = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_SUBF, reg3, reg1, reg2); - output->optype = OpndType_GPR; - output->reg = reg3; - } - return; - } - - if ((has_const = COND_has_const(expr1, expr2))) { - switch (COND_has_const(expr1, expr2)) { - case 0: - case 2: - break; - case 3: - case 4: - if (has_const == 4) { - if (expr1->data.intval.lo < expr2->data.intval.lo) - gen_negated_condition_gpr(cond, &isel_op1, 0); - else - gen_condition_gpr(cond, &isel_op1, 0); - - GEN_NODE(expr1, &op1); - GEN_NODE(expr2, &op2); - reg1 = ALLOC_GPR(); - ENSURE_GPR(&op2, expr2->rtype, reg1); - emitpcode(PC_ADD, reg1, isel_op1.reg, op2.reg); - if (outputReg) { - emitpcode(PC_MR, reg2 = outputReg, reg1); - reg1 = reg2; - } - output->optype = OpndType_GPR; - output->reg = reg1; - return; - } - break; - case 5: - case 6: - gen_negated_condition_gpr(cond, &isel_op1, 0); - ENSURE_GPR(&isel_op1, TYPE(&stunsignedint), 0); - GEN_NODE(expr1, &op1); - GEN_NODE(expr2, &op2); - - reg1 = outputReg ? outputReg : ALLOC_GPR(); - if (op1.optype == OpndType_Absolute && op1.immediate == 0) { - ENSURE_GPR(&op2, expr2->rtype, 0); - emitpcode(PC_ANDC, reg1, op2.reg, isel_op1.reg); - } else if (op2.optype == OpndType_Absolute && op2.immediate == 0) { - ENSURE_GPR(&op1, expr1->rtype, 0); - emitpcode(PC_AND, reg1, op1.reg, isel_op1.reg); - } else { - CError_FATAL(3119); - } - - output->optype = OpndType_GPR; - output->reg = reg1; - return; - case 1: - reg2 = ALLOC_GPR(); - reg1 = reg2; - logical_expression_nobranch(cond, 0, &isel_op2); - - GEN_NODE_TO_REG(expr1, reg1, 0, &op1); - ENSURE_GPR(&op1, expr1->rtype, reg1); - if (op1.reg != reg1) - emitpcode(PC_MR, reg1, op1.reg); - - branch_conditional(isel_op2.reg, isel_op2.regOffset, 1, label2); - branch_label(label1); - - GEN_NODE_TO_REG(expr2, reg1, 0, &op2); - ENSURE_GPR(&op2, expr2->rtype, reg1); - if (op2.reg != reg1) - emitpcode(PC_MR, reg1, op2.reg); - - branch_label(label2); - - if (outputReg) { - emitpcode(PC_MR, reg2 = outputReg, reg1); - reg1 = reg2; - } - - output->optype = OpndType_GPR; - output->reg = reg1; - return; - - default: - CError_FATAL(3168); - } - } - - reg1 = ALLOC_GPR(); - logical_expression_nobranch(cond, 0, &isel_op2); - - GEN_NODE_TO_REG(expr2, reg1, 0, &op2); - ENSURE_GPR(&op2, expr2->rtype, reg1); - if (op2.reg != reg1) - emitpcode(PC_MR, reg1, op2.reg); - - branch_conditional(isel_op2.reg, isel_op2.regOffset, 0, label2); - branch_label(label1); - - GEN_NODE_TO_REG(expr1, reg1, 0, &op1); - ENSURE_GPR(&op1, expr1->rtype, reg1); - if (op1.reg != reg1) - emitpcode(PC_MR, reg1, op1.reg); - - branch_label(label2); - - if (outputReg) { - emitpcode(PC_MR, reg2 = outputReg, reg1); - reg1 = reg2; - } - - output->optype = OpndType_GPR; - output->reg = reg1; - return; - } - - logical_expression(cond, label1, label2, label1); - branch_label(label1); - - if (IS_TYPE_VOID(type) || expr->ignored) { - GEN_NODE(expr1, &op1); - branch_always(label3); - branch_label(label2); - GEN_NODE(expr2, &op2); - } else if (IS_TYPE_FLOAT(type)) { - if (expr1->hascall || expr2->hascall) - reg1 = ALLOC_FPR(); - else - reg1 = outputReg ? outputReg : ALLOC_FPR(); - - GEN_NODE_TO_REG(expr1, reg1, 0, &op1); - ENSURE_FPR(&op1, expr1->rtype, reg1); - if (op1.reg != reg1) - emitpcode(PC_FMR, reg1, op1.reg); - - branch_always(label3); - branch_label(label2); - - GEN_NODE_TO_REG(expr2, reg1, 0, &op2); - ENSURE_FPR(&op2, expr2->rtype, reg1); - if (op2.reg != reg1) - emitpcode(PC_FMR, reg1, op2.reg); - - output->optype = OpndType_FPR; - output->reg = reg1; - } else if (TYPE_IS_8BYTES(type)) { - if (expr1->hascall || expr2->hascall) { - reg1 = ALLOC_GPR(); - reg3 = ALLOC_GPR(); - reg2 = reg3; - } else { - reg1 = outputReg ? outputReg : ALLOC_GPR(); - reg3 = outputRegHi ? outputRegHi : ALLOC_GPR(); - reg2 = reg3; - } - - GEN_NODE_TO_REG(expr1, reg1, reg2, &op1); - coerce_to_register_pair(&op1, expr1->rtype, reg1, reg2); - - branch_always(label3); - branch_label(label2); - - GEN_NODE_TO_REG(expr2, reg1, reg2, &op2); - coerce_to_register_pair(&op2, expr2->rtype, reg1, reg2); - - output->optype = OpndType_GPRPair; - output->reg = reg1; - output->regHi = reg2; - } else if (TYPE_FITS_IN_REGISTER(type)) { - if (expr1->hascall || expr2->hascall) - reg1 = ALLOC_GPR(); - else - reg1 = outputReg ? outputReg : ALLOC_GPR(); - - GEN_NODE_TO_REG(expr1, reg1, 0, &op1); - ENSURE_GPR(&op1, expr1->rtype, reg1); - if (op1.reg != reg1) - emitpcode(PC_MR, reg1, op1.reg); - - branch_always(label3); - branch_label(label2); - - GEN_NODE_TO_REG(expr2, reg1, 0, &op2); - ENSURE_GPR(&op2, expr2->rtype, reg1); - if (op2.reg != reg1) - emitpcode(PC_MR, reg1, op2.reg); - - output->optype = OpndType_GPR; - output->reg = reg1; - } else if (IS_TYPE_VECTOR(type)) { - if (expr1->hascall || expr2->hascall) - reg1 = ALLOC_VR(); - else - reg1 = outputReg ? outputReg : ALLOC_VR(); - - GEN_NODE_TO_REG(expr1, reg1, 0, &op1); - ENSURE_VR(&op1, expr1->rtype, reg1); - if (op1.reg != reg1) - emitpcode(PC_VMR, reg1, op1.reg); - - branch_always(label3); - branch_label(label2); - - GEN_NODE_TO_REG(expr2, reg1, 0, &op2); - ENSURE_VR(&op2, expr2->rtype, reg1); - if (op2.reg != reg1) - emitpcode(PC_VMR, reg1, op2.reg); - - output->optype = OpndType_VR; - output->reg = reg1; - } else { - symbol_operand(output, maketemporary(type)); - indirect(output, NULL); - coerce_to_addressable(output); - - GEN_NODE(expr1, &op1); - - if (op1.object) { - if (op1.object->datatype == DLOCAL && (op1.object->u.var.info->flags & VarInfoFlag1)) - align = CMach_ArgumentAlignment(type); - else - align = CMach_AllocationAlignment(type, op1.object->qual); - } else { - align = CMach_AllocationAlignment(type, 0); - } - - max_align = CMach_AllocationAlignment(type, 0); - if (align > max_align) - align = max_align; - - move_block(output, &op1, type->size, align); - - branch_always(label3); - branch_label(label2); - - GEN_NODE(expr2, &op2); - - if (op2.object) { - if (op2.object->datatype == DLOCAL && (op2.object->u.var.info->flags & VarInfoFlag1)) - align = CMach_ArgumentAlignment(type); - else - align = CMach_AllocationAlignment(type, op2.object->qual); - } else { - align = CMach_AllocationAlignment(type, 0); - } - - if (align > max_align) - align = max_align; - - move_block(output, &op2, type->size, align); - } - - branch_label(label3); -} - -static Boolean CONDASS_is_ABS(ENode *cond, ENode *expr1, ENode *expr2) { - ENode *inner; - - int parity = 0; - while (ENODE_IS(cond, ELOGNOT)) { - parity = (parity + 1) & 1; - cond = cond->data.monadic; - } - - if (IS_INT_CONST_ZERO(cond->data.diadic.right)) { - inner = cond->data.diadic.left; - } else if (IS_INT_CONST_ZERO(cond->data.diadic.left)) { - inner = cond->data.diadic.left; - parity = (parity + 1) & 1; - } else { - return 0; - } - - switch (cond->type) { - case EGREATER: - case EGREATEREQU: - if (!parity) - return 0; - break; - case ELESS: - case ELESSEQU: - if (parity) - return 0; - break; - default: - return 0; - } - - if (!ENODE_IS(expr2, EMONMIN)) - return 0; - - expr2 = expr2->data.monadic; - if (ENODE_IS(inner, EASS)) { - inner = inner->data.diadic.left; - if (!ENODE_IS(expr2, EINDIRECT)) - return 0; - expr2 = expr2->data.monadic; - if (!ENODE_IS(expr1, EINDIRECT)) - return 0; - expr1 = expr1->data.monadic; - } - - return COND_is_ABS_MatchNodes(inner, expr1, expr2); -} - -static int CONDASS_is_OPASS_One(ENode *a, ENode *b, SInt32 *value, ENodeType *nodetype) { - Type *type; - - type = a->rtype; - if (!ENODE_IS(a, EINDIRECT)) - return 0; - a = a->data.monadic; - if (!ENODE_IS(a, EOBJREF)) - return 0; - - if (ENODE_IS(b, ETYPCON) && b->rtype == type) - b = b->data.monadic; - - if (b->type != EOR && b->type != EADD && b->type != ESUB) - return 0; - - *nodetype = b->type; - if (!IS_INT_CONST(b->data.diadic.right)) - return 0; - *value = b->data.diadic.right->data.intval.lo; - - if (*value != 1 && *value != -1) - return 0; - - b = b->data.diadic.left; - if (ENODE_IS(b, ETYPCON) && TYPE_FITS_IN_REGISTER(b->rtype)) - b = b->data.monadic; - - if (!ENODE_IS(b, EINDIRECT)) - return 0; - b = b->data.monadic; - if (!ENODE_IS(b, EOBJREF)) - return 0; - - if (a->data.objref == b->data.objref) - return 1; - return 0; -} - -void gen_CONDASS(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *cond; - ENode *expr1; - ENode *expr2; - Type *type; - PCodeLabel *label1; - PCodeLabel *label2; - Operand op1; - Operand op2; - Operand op3; - int reg1; - int reg2; - - expr1 = expr->data.cond.expr1; - expr2 = expr->data.cond.expr2; - type = expr->rtype; - - label1 = makepclabel(); - label2 = makepclabel(); - - memclrw(&op1, sizeof(Operand)); - memclrw(&op2, sizeof(Operand)); - memclrw(&op3, sizeof(Operand)); - - cond = evaluate_and_skip_comma(expr->data.cond.cond); - - if (TOC_use_fsel(expr)) { - ENode *left; - ENode *right; - ENode *tmp; - ENodeType nt; - Boolean flag; - Boolean flag2; - Operand op; - int tmpreg; - int fneg_reg; - int fsel_reg; - int final_reg; - - left = cond->data.diadic.left; - right = cond->data.diadic.right; - nt = cond->type; - flag = 0; - memclrw(&op, sizeof(Operand)); - - CError_ASSERT(3704, ENODE_IS(expr1, EINDIRECT)); - CError_ASSERT(3705, ENODE_IS(expr1->data.monadic, EOBJREF)); - - tmpreg = OBJECT_REG(expr1->data.monadic->data.objref); - final_reg = outputReg ? tmpreg : ALLOC_FPR(); - - switch (nt) { - case EGREATER: - tmp = left; - left = right; - right = tmp; - case ELESS: - case ENOTEQU: - tmp = expr1; - expr1 = expr2; - expr2 = tmp; - flag2 = 1; - break; - case ELESSEQU: - tmp = left; - left = right; - right = tmp; - flag2 = 0; - break; - case EGREATEREQU: - case EEQU: - flag2 = 0; - break; - default: - CError_FATAL(3744); - } - - if (ENODE_IS(left, EFLOATCONST) && CMach_FloatIsZero(left->data.floatval)) { - GEN_NODE(right, &op); - ENSURE_FPR(&op, right->rtype, 0); - flag = 1; - } else if (ENODE_IS(right, EFLOATCONST) && CMach_FloatIsZero(right->data.floatval)) { - GEN_NODE(left, &op); - ENSURE_FPR(&op, left->rtype, 0); - } else { - fp_binary_operator((type->size == 4) ? PC_FSUBS : PC_FSUB, left, right, 0, &op); - } - - switch (cond->type) { - case EEQU: - case ENOTEQU: - if (flag) { - GEN_NODE(expr1, &op1); - op3 = op1; - ENSURE_FPR(&op1, expr1->rtype, 0); - - GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); - - fneg_reg = ALLOC_FPR(); - emitpcode(PC_FNEG, fneg_reg, op.reg); - fsel_reg = ALLOC_FPR(); - emitpcode(PC_FSEL, fsel_reg, op.reg, op2.reg, op1.reg); - emitpcode(PC_FSEL, final_reg, fneg_reg, op2.reg, fsel_reg); - } else { - GEN_NODE(expr1, &op1); - op3 = op1; - ENSURE_FPR(&op1, expr1->rtype, 0); - - GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); - - fneg_reg = ALLOC_FPR(); - emitpcode(PC_FNEG, fneg_reg, op.reg); - fsel_reg = ALLOC_FPR(); - emitpcode(PC_FSEL, fsel_reg, op.reg, op2.reg, op1.reg); - emitpcode(PC_FSEL, final_reg, fneg_reg, op2.reg, fsel_reg); - } - break; - case ELESS: - case EGREATER: - case ELESSEQU: - case EGREATEREQU: - GEN_NODE(expr1, &op1); - GEN_NODE(expr2, &op2); - op3 = flag2 ? op2 : op1; - - ENSURE_FPR(&op1, expr1->rtype, 0); - ENSURE_FPR(&op2, expr2->rtype, 0); - - fneg_reg = op.reg; - if (flag) { - fneg_reg = ALLOC_FPR(); - emitpcode(PC_FNEG, fneg_reg, op.reg); - } - - emitpcode(PC_FSEL, final_reg, fneg_reg, op2.reg, op1.reg); - break; - default: - CError_FATAL(2862); - } - - if (op3.optype != OpndType_FPR) - store_fp(final_reg, &op3, type); - - output->optype = OpndType_FPR; - output->reg = final_reg; - return; - } - - if (TOC_use_isel(expr, 1)) { - Operand isel_op; - ENode *x; - ENode *y; - ENode *abs_expr; - - memclrw(&isel_op, sizeof(Operand)); - CError_ASSERT(3966, ENODE_IS(expr1, EINDIRECT)); - CError_ASSERT(3968, ENODE_IS(expr1->data.monadic, EOBJREF)); - - if (CONDASS_is_ABS(cond, expr1, expr2)) { - if (ENODE_IS(cond->data.diadic.left, EASS)) - GEN_NODE(cond->data.diadic.left, &isel_op); - else if (ENODE_IS(cond->data.diadic.right, EASS)) - GEN_NODE(cond->data.diadic.right, &isel_op); - - outputReg = OBJECT_REG(expr1->data.monadic->data.objref); - CError_ASSERT(3979, outputReg); - - GEN_NODE(expr1, &op1); - op3 = op1; - - CError_ASSERT(3986, op3.optype == OpndType_GPR && op3.reg == outputReg); - - ENSURE_GPR(&op1, expr1->rtype, 0); - if (expr1->rtype->size < 4) - extend32(output, expr1->rtype, op3.reg); - - reg1 = ALLOC_GPR(); - reg2 = ALLOC_GPR(); - emitpcode(PC_SRAWI, reg1, op1.reg, 31); - emitpcode(PC_XOR, reg2, reg1, op1.reg); - emitpcode(PC_SUBF, outputReg, reg1, reg2); - output->optype = OpndType_GPR; - output->reg = op3.reg; - - if (expr1->rtype->size < 4) - extend32(output, expr1->rtype, op3.reg); - - return; - } - } - - logical_expression(cond, label1, label2, label1); - branch_label(label1); - gen_ASS(expr, outputReg, outputRegHi, output); - branch_label(label2); -} - -void gen_FUNCCALL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - if (is_intrinsic_function_call(expr)) - call_intrinsic_function(expr, outputReg, output); - else - call_function(expr, output); -} - -void gen_OBJREF(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - symbol_operand(output, expr->data.objref); -} - -void gen_UNEXPECTED(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - CError_FATAL(4160); -} - -static int small(ENode *expr) { - Type *type; - - type = expr->rtype; - if (!ENODE_IS(expr, ETYPCON)) - return 0; - - do { - expr = expr->data.monadic; - } while (ENODE_IS(expr, ETYPCON) && (type = expr->rtype)->size == 4); - - return IS_TYPE_INT_OR_ENUM(type) && ((type->size < 2) || (type->size == 2 && !is_unsigned(type))); -} - -void binary_operator(Opcode opcode, ENode *left, ENode *right, short outputReg, Operand *output) { - Operand opleft; - Operand opright; - int reg; - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - if (right->hascall) { - GEN_NODE_TO_GPR(right, &opright, right->rtype, 0); - GEN_NODE_TO_GPR(left, &opleft, left->rtype, 0); - } else { - GEN_NODE_TO_GPR(left, &opleft, left->rtype, 0); - GEN_NODE_TO_GPR(right, &opright, right->rtype, 0); - } - - reg = outputReg ? outputReg : ALLOC_GPR(); - - if (opcode == PC_MULLW && small(left)) - emitpcode(opcode, reg, opright.reg, opleft.reg); - else - emitpcode(opcode, reg, opleft.reg, opright.reg); - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void binary_immediate(Opcode opcode, ENode *left, SInt32 value, short outputReg, Operand *output) { - Operand opleft; - int reg; - - memclrw(&opleft, sizeof(Operand)); - GEN_NODE_TO_GPR(left, &opleft, left->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - - if (opcode == PC_MULLI && value == 0) - emitpcode(PC_LI, reg, 0); - else if (opcode == PC_MULLI && value == 1) - emitpcode(PC_MR, reg, opleft.reg); - else - emitpcode(opcode, reg, opleft.reg, value); - - output->optype = OpndType_GPR; - output->reg = reg; -} - -void unary_operator(Opcode opcode, ENode *expr, short outputReg, Operand *output) { - Operand op; - int reg; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(opcode, reg, op.reg); - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void or_xor_immediate(Opcode opcode, ENode *expr, SInt32 value, short outputReg, Operand *output) { - Operand op; - int reg; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - - if (expr->rtype->size > 2 && value != (value & 0xFFFF)) { - if (value & 0xFFFF) { - emitpcode((opcode == PC_ORI) ? PC_ORIS : PC_XORIS, reg, op.reg, value >> 16); - emitpcode(opcode, reg, reg, value & 0xFFFF); - } else { - emitpcode((opcode == PC_ORI) ? PC_ORIS : PC_XORIS, reg, op.reg, value >> 16); - } - } else { - emitpcode(opcode, reg, op.reg, value & 0xFFFF); - } - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void shift_left_immediate(ENode *expr, short shift, short negate, short outputReg, Operand *output) { - Operand op; - int reg; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); - - if (negate) - reg = ALLOC_GPR(); - else - reg = outputReg ? outputReg : ALLOC_GPR(); - - emitpcode(PC_RLWINM, reg, op.reg, shift & 31, 0, 31 - (shift & 31)); - - if (negate) { - int tmp = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_NEG, tmp, reg); - reg = tmp; - } - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void shift_right_immediate(ENode *expr, Type *type, short shift, short outputReg, Operand *output) { - Operand op; - int reg; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - - if (is_unsigned(type)) - emitpcode(PC_RLWINM, reg, op.reg, (32 - (shift & 31)) & 31, (shift & 31) + (32 - (type->size * 8)), 31); - else - emitpcode(PC_SRAWI, reg, op.reg, shift & 31); - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void signed_divide_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output) { - Operand op; - int reg; - int tmpreg1; - int tmpreg2; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); - - if (!copts.optimizesize && shift == 1) { - tmpreg1 = ALLOC_GPR(); - emitpcode(PC_RLWINM, tmpreg1, op.reg, 1, 31, 31); - tmpreg2 = ALLOC_GPR(); - emitpcode(PC_ADD, tmpreg2, tmpreg1, op.reg); - reg = (outputReg && !negate) ? outputReg : ALLOC_GPR(); - emitpcode(PC_SRAWI, reg, tmpreg2, 1); - } else { - tmpreg1 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpreg1, op.reg, shift); - reg = (outputReg && !negate) ? outputReg : ALLOC_GPR(); - emitpcode(PC_ADDZE, reg, tmpreg1); - } - - if (negate) { - int prevreg = reg; - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_NEG, reg, prevreg); - } - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void signed_mod_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output) { - Operand op; - int reg; - int tmpreg1; - int tmpreg2; - int tmpreg3; - int tmpreg4; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - - if (shift == 1) { - emitpcode(PC_RLWINM, tmpreg1, op.reg, 1, 31, 31); - emitpcode(PC_RLWINM, tmpreg2, op.reg, 0, 31, 31); - emitpcode(PC_XOR, tmpreg3, tmpreg2, tmpreg1); - emitpcode(PC_SUBF, reg, tmpreg1, tmpreg3); - } else { - tmpreg4 = ALLOC_GPR(); - emitpcode(PC_RLWINM, tmpreg1, op.reg, 32 - shift, 0, 31 - (32 - shift)); - emitpcode(PC_RLWINM, tmpreg2, op.reg, 1, 31, 31); - emitpcode(PC_SUBF, tmpreg3, tmpreg2, tmpreg1); - emitpcode(PC_RLWINM, tmpreg4, tmpreg3, shift, 0, 31); - emitpcode(PC_ADD, reg, tmpreg4, tmpreg2); - } - - output->optype = OpndType_GPR; - output->reg = reg; -} - -static void fp_binary_operator(Opcode opcode, ENode *left, ENode *right, short outputReg, Operand *output) { - Operand opleft; - Operand opright; - int reg; - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - if (right->hascall) { - GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); - GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); - } else { - GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); - GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); - } - - reg = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(opcode, reg, opleft.reg, opright.reg); - - output->optype = OpndType_FPR; - output->reg = reg; -} - -void fp_unary_operator(Opcode opcode, ENode *expr, short outputReg, Operand *output) { - Operand op; - int reg; - - memclrw(&op, sizeof(Operand)); - GEN_NODE_TO_FPR(expr, &op, expr->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(opcode, reg, op.reg); - - output->optype = OpndType_FPR; - output->reg = reg; -} - -void fp_multiply_add(Opcode opcode, ENode *a, ENode *b, ENode *c, short outputReg, Operand *output) { - Operand opA; - Operand opB; - Operand opC; - int reg; - - memclrw(&opA, sizeof(Operand)); - memclrw(&opB, sizeof(Operand)); - memclrw(&opC, sizeof(Operand)); - - if (c->hascall) { - GEN_NODE_TO_FPR(c, &opC, c->rtype, 0); - if (b->hascall) { - GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); - GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); - } else { - GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); - GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); - } - } else { - if (b->hascall) { - GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); - GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); - GEN_NODE_TO_FPR(c, &opC, c->rtype, 0); - } else { - GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); - GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); - GEN_NODE_TO_FPR(c, &opC, c->rtype, 0); - } - } - - reg = outputReg ? outputReg : ALLOC_FPR(); - emitpcode(opcode, reg, opA.reg, opB.reg, opC.reg); - - output->optype = OpndType_FPR; - output->reg = reg; -} - -void gen_COMPARE(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - expr = evaluate_and_skip_comma(expr); - if (TYPE_IS_8BYTES(expr->data.diadic.right->rtype) || TYPE_IS_8BYTES(expr->data.diadic.left->rtype)) - I8_gen_condition(expr, output, 1); - else - gen_condition_gpr(expr, output, outputReg); -} - -void gen_LOGICAL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - ENodeType op; - - expr = evaluate_and_skip_comma(expr); - inner = evaluate_and_skip_comma(expr->data.monadic); - expr->data.monadic = inner; - - if (ENODE_IS(expr, ELOGNOT) && !ENODE_IS2(inner, ELAND, ELOR)) { - op = inner->type; - if (ENODE_IS(inner, ELOGNOT)) { - switch (inner->data.monadic->type) { - case ELOGNOT: - case ELESS: - case EGREATER: - case ELESSEQU: - case EGREATEREQU: - case EEQU: - case ENOTEQU: - case ELAND: - case ELOR: - GEN_NODE(inner->data.monadic, output); - if (expr->data.monadic->rtype->size < 4) - extend32(output, expr->data.monadic->rtype, 0); - ENSURE_GPR(output, expr->data.monadic->rtype, 0); - return; - } - } - - if (ENODE_IS(inner, ENOTEQU) && !TYPE_IS_8BYTES(inner->data.diadic.left->rtype) && ENODE_IS(inner->data.diadic.right, EINTCONST) && inner->data.diadic.right->data.intval.lo == 0) { - int tmpreg1; - int tmpreg2; - GEN_NODE(inner->data.diadic.left, output); - if (inner->data.diadic.left->rtype->size < 4) - extend32(output, inner->data.diadic.left->rtype, 0); - ENSURE_GPR(output, inner->data.diadic.left->rtype, 0); - - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - CError_ASSERT(4853, output->optype == OpndType_GPR); - - emitpcode(PC_CNTLZW, tmpreg2, output->reg); - emitpcode(PC_RLWINM, tmpreg1, tmpreg2, 27, 5, 31); - output->optype = OpndType_GPR; - output->reg = tmpreg1; - } else { - int tmpreg1; - int tmpreg2; - ENodeType inverted; - - inverted = invert_relop(op); - if (op != inverted && !IS_TYPE_FLOAT(inner->data.diadic.left->rtype)) { - inner->type = inverted; - gen_COMPARE(inner, 0, 0, output); - inner->type = inverted; - return; - } - - GEN_NODE(inner, output); - if (inner->rtype->size < 4) - extend32(output, inner->rtype, 0); - ENSURE_GPR(output, inner->rtype, 0); - - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - CError_ASSERT(4883, output->optype == OpndType_GPR); - - emitpcode(PC_CNTLZW, tmpreg2, output->reg); - emitpcode(PC_RLWINM, tmpreg1, tmpreg2, 27, 5, 31); - output->optype = OpndType_GPR; - output->reg = tmpreg1; - } - } else { - PCodeLabel *label1; - PCodeLabel *label2; - int tmpreg; - - label1 = makepclabel(); - label2 = makepclabel(); - - tmpreg = ALLOC_GPR(); - emitpcode(PC_LI, tmpreg, 0); - logical_expression(expr, label1, label2, label1); - branch_label(label1); - emitpcode(PC_LI, tmpreg, 1); - branch_label(label2); - output->optype = OpndType_GPR; - output->reg = tmpreg; - } -} - -void gen_NULLCHECK(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *left; - ENode *right; - Operand opleft; - Operand opright; - PrecomputedOperand *precomp; - int flag; - int reg; - PCodeLabel *label; - - left = expr->data.nullcheck.nullcheckexpr; - right = expr->data.nullcheck.condexpr; - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - flag = !IS_TYPE_VOID(expr->rtype) && !expr->ignored; - - GEN_NODE(left, &opleft); - if (left->rtype->size < 4) - extend32(&opleft, left->rtype, 0); - ENSURE_GPR(&opleft, left->rtype, 0); - - precomp = lalloc(sizeof(PrecomputedOperand)); - precomp->precompid = expr->data.nullcheck.precompid; - precomp->operand = opleft; - precomp->next = precomputedoperands; - precomputedoperands = precomp; - - emitpcode(PC_CMPI, 0, opleft.reg, 0); - if (flag) { - emitpcode(PC_MR, reg = ALLOC_GPR(), opleft.reg); - } - - label = makepclabel(); - branch_conditional(0, EEQU, 1, label); - GEN_NODE(right, &opright); - precomputedoperands = precomputedoperands->next; - - if (flag) { - ENSURE_GPR(&opright, right->rtype, reg); - if (opright.reg != reg) - emitpcode(PC_MR, reg, opright.reg); - output->optype = OpndType_GPR; - output->reg = reg; - } - - branch_label(label); -} - -void gen_PRECOMP(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - PrecomputedOperand *precomp; - - for (precomp = precomputedoperands; precomp; precomp = precomp->next) { - if (precomp->precompid == expr->data.precompid) - break; - } - - *output = precomp->operand; -} - -void logical_expression(ENode *cond, PCodeLabel *if_true, PCodeLabel *if_false, PCodeLabel *end) { - PCodeLabel *label; - Operand op; - memclrw(&op, sizeof(Operand)); - - cond = evaluate_and_skip_comma(cond); - switch (cond->type) { - case ELAND: - label = makepclabel(); - logical_expression(cond->data.diadic.left, label, if_false, label); - branch_label(label); - logical_expression(cond->data.diadic.right, if_true, if_false, end); - break; - case ELOR: - label = makepclabel(); - logical_expression(cond->data.diadic.left, if_true, label, label); - branch_label(label); - logical_expression(cond->data.diadic.right, if_true, if_false, end); - break; - case ELOGNOT: - logical_expression(cond->data.monadic, if_false, if_true, end); - break; - case ELESS: - case EGREATER: - case ELESSEQU: - case EGREATEREQU: - case EEQU: - case ENOTEQU: - if (TYPE_IS_8BYTES(cond->data.diadic.right->rtype) || TYPE_IS_8BYTES(cond->data.diadic.left->rtype)) - I8_gen_condition(cond, &op, 0); - else - gen_condition(cond, &op); - - if (end == if_true) - branch_conditional(op.reg, op.regOffset, 0, if_false); - else - branch_conditional(op.reg, op.regOffset, 1, if_true); - break; - default: - CError_FATAL(5160); - } -} - -static void logical_expression_nobranch(ENode *cond, Boolean invert, Operand *output) { - cond = evaluate_and_skip_comma(cond); - switch (cond->type) { - case ELOGNOT: - logical_expression_nobranch(cond->data.monadic, 1, output); - break; - case ELESS: - case EGREATER: - case ELESSEQU: - case EGREATEREQU: - case EEQU: - case ENOTEQU: - if (invert) { - ENodeType nt = invert_relop(cond->type); - CError_ASSERT(5190, nt != cond->type); - cond->type = nt; - } - - if (TYPE_IS_8BYTES(cond->data.diadic.right->rtype) || TYPE_IS_8BYTES(cond->data.diadic.left->rtype)) - I8_gen_condition(cond, output, 0); - else - gen_condition(cond, output); - - break; - default: - CError_FATAL(5206); - } -} - -static ENodeType invert_relop(ENodeType nt) { - switch (nt) { - case ELESS: return EGREATEREQU; - case EGREATER: return ELESSEQU; - case ELESSEQU: return EGREATER; - case EGREATEREQU: return ELESS; - case EEQU: return ENOTEQU; - case ENOTEQU: return EEQU; - default: return nt; - } -} - -static int reverse_relop(int nt) { - switch (nt) { - case ELESS: return EGREATER; - case EGREATER: return ELESS; - case ELESSEQU: return EGREATEREQU; - case EGREATEREQU: return ELESSEQU; - default: return nt; - } -} - -void gen_condition(ENode *cond, Operand *output) { - ENode *left; - ENode *right; - - left = cond->data.diadic.left; - right = cond->data.diadic.right; - if (IS_TYPE_FLOAT(left->rtype)) { - compare_floating(cond->type, left, right, output); - return; - } - - if (ENODE_IS(right, EINTCONST)) { - if (is_unsigned(left->rtype)) { - UInt32 val = right->data.intval.lo; - if (FITS_IN_USHORT(val)) { - compare_immediate(cond->type, left, val, output); - return; - } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { - compare_immediate_long(cond->type, left, val, output); - return; - } - } else { - UInt32 val = right->data.intval.lo; - if (FITS_IN_SHORT(val)) { - compare_immediate(cond->type, left, val, output); - return; - } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { - compare_immediate_long(cond->type, left, val, output); - return; - } - } - } else if (ENODE_IS(left, EINTCONST)) { - if (is_unsigned(right->rtype)) { - UInt32 val = left->data.intval.lo; - if (FITS_IN_USHORT(val)) { - compare_immediate(reverse_relop(cond->type), right, val, output); - return; - } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { - compare_immediate_long(reverse_relop(cond->type), right, val, output); - return; - } - } else { - UInt32 val = left->data.intval.lo; - if (FITS_IN_SHORT(val)) { - compare_immediate(reverse_relop(cond->type), right, val, output); - return; - } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { - compare_immediate_long(reverse_relop(cond->type), right, val, output); - return; - } - } - } - - compare_integer(cond->type, left, right, output); -} - -void gen_condition_gpr(ENode *cond, Operand *output, short outputReg) { - ENode *left; - ENode *right; - Operand condOp; - int finalReg; - int tmpReg; - int tmpReg2; - int tmpReg3; - int tmpReg4; - int a; - int b; - - left = cond->data.diadic.left; - right = cond->data.diadic.right; - memclrw(&condOp, sizeof(Operand)); - - if (!IS_TYPE_FLOAT(left->rtype)) { - Operand op1; - Operand op2; - Operand opTmp; - 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); - } 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)) { - 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 = finalReg; - return; - } else { - tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_CNTLZW, tmpReg2, tmpReg); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, finalReg, tmpReg2, 27, 5, 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); - } 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.optimizesize) { - tmpReg = ALLOC_GPR(); - emitpcode(PC_ADDIC, tmpReg, op1.reg, -1); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_SUBFE, finalReg, tmpReg, op1.reg); - } 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_RLWINM, finalReg, tmpReg2, 1, 31, 31); - } - output->optype = OpndType_GPR; - output->reg = finalReg; - return; - } - - if (copts.optimizesize) { - 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)) { - tmpReg = ALLOC_GPR(); - 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 = finalReg; - return; - } - opTmp = op2; - op2 = op1; - op1 = opTmp; - - case ELESSEQU: - if (is_unsigned(left->rtype)) { - if (copts.optimizesize) { - tmpReg = ALLOC_GPR(); - emitpcode(PC_LI, tmpReg, -1); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_SUBFC, tmpReg2, op1.reg, op2.reg); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_SUBFZE, finalReg, tmpReg); - } else { - tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg); - tmpReg2 = ALLOC_GPR(); - 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); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, finalReg, tmpReg4, 1, 31, 31); - } - output->optype = OpndType_GPR; - output->reg = finalReg; - return; - } - - if (IS_INT_CONST_ZERO(right)) { - tmpReg = ALLOC_GPR(); - emitpcode(PC_LI, tmpReg, 1); - tmpReg2 = ALLOC_GPR(); - 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 = 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)) { - 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_RLWINM, finalReg, tmpReg2, 1, 31, 31); - output->optype = OpndType_GPR; - output->reg = finalReg; - return; - } - - opTmp = op2; - op2 = op1; - op1 = opTmp; - - case ELESS: - if (is_unsigned(left->rtype)) { - if (left->rtype->size <= 2) { - tmpReg = ALLOC_GPR(); - 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 = finalReg; - } else { - if (copts.optimizesize) { - tmpReg = ALLOC_GPR(); - emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_SUBFE, tmpReg2, tmpReg, tmpReg); - finalReg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_NEG, finalReg, tmpReg2); - } else { - tmpReg = ALLOC_GPR(); - emitpcode(PC_XOR, tmpReg, op2.reg, op1.reg); - tmpReg2 = ALLOC_GPR(); - emitpcode(PC_CNTLZW, tmpReg2, tmpReg); - tmpReg3 = ALLOC_GPR(); - 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 = finalReg; - return; - } - 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, &condOp); - emitpcode(PC_MFCR, tmpReg = used_virtual_registers[RegClass_GPR]++); - a = 0; - b = condOp.reg * 4; - switch (condOp.regOffset) { - case ENOTEQU: - a = 1; - case EEQU: - b += 2; - break; - case EGREATEREQU: - a = 1; - break; - case ELESSEQU: - a = 1; - case EGREATER: - b += 1; - break; - } - - finalReg = outputReg ? outputReg : ALLOC_GPR(); - if (a) { - emitpcode(PC_RLWINM, tmpReg, tmpReg, b + 1, 31, 31); - emitpcode(PC_XORI, finalReg, tmpReg, 1); - } else { - emitpcode(PC_RLWINM, finalReg, tmpReg, b + 1, 31, 31); - } - output->optype = OpndType_GPR; - 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.optimizesize) { - 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.optimizesize) { - 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.optimizesize) { - 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.optimizesize) { - 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) { - Operand opleft; - Operand opright; - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - if (right->hascall) { - GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); - GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); - } else { - GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); - GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); - } - - emitpcode((nt == EEQU || nt == ENOTEQU) ? PC_FCMPU : PC_FCMPO, 0, opleft.reg, opright.reg); - if (nt == ELESSEQU) { - emitpcode(PC_CROR, 0, 2, 0, 0, 0, 2); - nt = EEQU; - } else if (nt == EGREATEREQU) { - emitpcode(PC_CROR, 0, 2, 0, 1, 0, 2); - nt = EEQU; - } - - output->optype = OpndType_CRField; - output->reg = 0; - output->regOffset = nt; -} - -void compare_integer(short nt, ENode *left, ENode *right, Operand *output) { - Operand opleft; - Operand opright; - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - if (right->hascall) { - GEN_NODE(right, &opright); - if (right->rtype->size < 4) - extend32(&opright, right->rtype, 0); - ENSURE_GPR(&opright, right->rtype, 0); - - GEN_NODE(left, &opleft); - if (left->rtype->size < 4) - extend32(&opleft, left->rtype, 0); - ENSURE_GPR(&opleft, left->rtype, 0); - } else { - GEN_NODE(left, &opleft); - ENSURE_GPR(&opleft, left->rtype, 0); - if (left->rtype->size < 4) - extend32(&opleft, left->rtype, 0); - - GEN_NODE(right, &opright); - if (right->rtype->size < 4) - extend32(&opright, right->rtype, 0); - ENSURE_GPR(&opright, right->rtype, 0); - } - - emitpcode(is_unsigned(left->rtype) ? PC_CMPL : PC_CMP, 0, opleft.reg, opright.reg); - - output->optype = OpndType_CRField; - output->reg = 0; - output->regOffset = nt; -} - -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) { - int start, end, bit; - start = end = -1; - for (bit = 31; bit >= 0; bit--) { - if (value & 1) { - if (start != -1) - return 0; - if (end == -1) - end = bit; - } else { - if (end != -1 && start == -1) - start = bit + 1; - } - value >>= 1; - } - - if (end == -1) - return 0; - if (start == -1) - start = 0; - *first = start; - *last = end; - return 1; -} - -int ismaskconstant(SInt32 value, short *first, short *last) { - short my_first; - short my_last; - if (ismask(value, first, last)) - return 1; - - if (value && ismask(~value, &my_first, &my_last)) { - *first = my_last + 1; - *last = my_first - 1; - return 1; - } else { - return 0; - } -} - -static void shift_and_mask(ENode *expr, short a, short b, short c, short outputReg, Operand *output) { - Operand op; - int reg; - - memclrw(&op, sizeof(Operand)); - GEN_NODE(expr, &op); - ENSURE_GPR(&op, expr->rtype, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_RLWINM, reg, op.reg, a, b, c); - - output->optype = OpndType_GPR; - output->reg = reg; -} - -int ispostincrementopportunity(ENode *expr, Operand *op, SInt32 *value) { - Type *type; - int reg; - - type = expr->rtype; - if (!ENODE_IS2(expr, EPOSTINC, EPOSTDEC)) - return 0; - if (!ENODE_IS(expr->data.monadic, EINDIRECT)) - return 0; - if (!ENODE_IS(expr->data.monadic->data.monadic, EOBJREF)) - return 0; - - reg = OBJECT_REG(expr->data.monadic->data.monadic->data.objref); - if (!reg) - return 0; - - if (IS_TYPE_POINTER(type)) { - if (ENODE_IS(expr, EPOSTINC)) - *value = TPTR_TARGET(type)->size; - else - *value = -TPTR_TARGET(type)->size; - } else { - if (ENODE_IS(expr, EPOSTINC)) - *value = 1; - else - *value = -1; - } - - op->optype = OpndType_GPR; - op->reg = reg; - return 1; -} - -void add_register_immediate(short regA, short regB, SInt32 value) { - if (!FITS_IN_SHORT(value)) { - emitpcode(PC_ADDIS, regA, regB, 0, HIGH_PART(value)); - if (LOW_PART(value)) - emitpcode(PC_ADDI, regA, regA, 0, LOW_PART(value)); - } else { - emitpcode(PC_ADDI, regA, regB, 0, value); - } -} - -static int ispowerof2(SInt32 val) { - int bit = getbit(val); - return (bit > 0 && bit < 31) ? bit : 0; -} - -void I8_gen_ADD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - int is_uns; - ENode *left; - ENode *right; - short reg; - short regHi; - short tmpreg1; - short tmpreg2; - SInt32 skipleft; - SInt32 skipright; - 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); - if (TYPE_IS_8BYTES(right->rtype)) - coerce_to_register_pair(&opright, right->rtype, 0, 0); - else - ENSURE_GPR(&opright, right->rtype, 0); - - GEN_NODE(left, &opleft); - if (TYPE_IS_8BYTES(left->rtype)) - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - else - ENSURE_GPR(&opleft, left->rtype, 0); - } else { - GEN_NODE(left, &opleft); - if (TYPE_IS_8BYTES(left->rtype)) - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - else - ENSURE_GPR(&opleft, left->rtype, 0); - - GEN_NODE(right, &opright); - if (TYPE_IS_8BYTES(right->rtype)) - coerce_to_register_pair(&opright, right->rtype, 0, 0); - else - ENSURE_GPR(&opright, right->rtype, 0); - } - - reg = ALLOC_GPR(); - regHi = ALLOC_GPR(); - is_uns = is_unsigned(expr->rtype) != 0; - skipleft = GetSizeSkip(left); - skipright = GetSizeSkip(right); - - if (skipleft < skipright) { - Operand tmpop; - SInt32 tmp; - - expr->data.diadic.left = right; - expr->data.diadic.right = left; - left = expr->data.diadic.left; - right = expr->data.diadic.right; - - tmpop = opright; - opright = opleft; - opleft = tmpop; - - tmp = skipleft; - skipleft = skipright; - skipright = tmp; - } - - switch (skipleft + skipright) { - case 1 + 1: - case 1 + 2: - case 2 + 2: - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { - emitpcode(PC_ADDIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { - emitpcode(PC_ADDIC, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - } else { - emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); - } - if (is_uns) - emitpcode(PC_LI, regHi, 0); - else - emitpcode(PC_SRAWI, regHi, reg, 31); - break; - case 1 + 4: - case 2 + 4: - case 4 + 4: - if (!is_uns) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpreg2, opleft.reg, 31); - emitpcode(PC_SRAWI, tmpreg1, opright.reg, 31); - } - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { - emitpcode(PC_ADDIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { - emitpcode(PC_ADDIC, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - } else { - emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); - } - if (is_uns) { - tmpreg1 = ALLOC_GPR(); - emitpcode(PC_LI, tmpreg1, 0); - emitpcode(PC_ADDZE, regHi, tmpreg1); - } else { - emitpcode(PC_ADDE, regHi, tmpreg1, tmpreg2); - } - break; - case 1 + 8: - case 2 + 8: - case 4 + 8: - CError_ASSERT(6933, skipleft == 8); - if (!is_uns) { - tmpreg2 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpreg2, opright.reg, 31); - } - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { - emitpcode(PC_ADDIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo) && right->data.intval.hi == 0) { - emitpcode(PC_ADDIC, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - } else { - emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); - } - if (is_uns) - emitpcode(PC_ADDZE, regHi, opleft.regHi); - else - emitpcode(PC_ADDE, regHi, opleft.regHi, tmpreg2); - break; - case 8 + 8: - emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); - emitpcode(PC_ADDE, regHi, opleft.regHi, opright.regHi); - break; - default: - CError_FATAL(6979); - } - - output->optype = OpndType_GPRPair; - output->reg = reg; - output->regHi = regHi; -} - -void I8_gen_INTCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - short reg; - short regHi; - - reg = outputReg ? outputReg : ALLOC_GPR(); - regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); - - load_immediate(reg, expr->data.intval.lo); - load_immediate(regHi, expr->data.intval.hi); - - output->optype = OpndType_GPRPair; - output->reg = reg; - output->regHi = regHi; -} - -void I8_gen_SUB(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - int is_uns; - ENode *left; - ENode *right; - short reg; - short regHi; - short tmpreg1; - short tmpreg2; - short tmpreg3; - SInt32 skipleft; - SInt32 skipright; - 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); - if (TYPE_IS_8BYTES(right->rtype)) - coerce_to_register_pair(&opright, right->rtype, 0, 0); - else - ENSURE_GPR(&opright, right->rtype, 0); - - GEN_NODE(left, &opleft); - if (TYPE_IS_8BYTES(left->rtype)) - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - else - ENSURE_GPR(&opleft, left->rtype, 0); - } else { - GEN_NODE(left, &opleft); - if (TYPE_IS_8BYTES(left->rtype)) - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - else - ENSURE_GPR(&opleft, left->rtype, 0); - - GEN_NODE(right, &opright); - if (TYPE_IS_8BYTES(right->rtype)) - coerce_to_register_pair(&opright, right->rtype, 0, 0); - else - ENSURE_GPR(&opright, right->rtype, 0); - } - - reg = ALLOC_GPR(); - regHi = ALLOC_GPR(); - is_uns = is_unsigned(expr->rtype) != 0; - skipleft = GetSizeSkip(left); - skipright = GetSizeSkip(right); - - switch (skipleft + skipright) { - case 1 + 1: - case 1 + 2: - case 2 + 2: - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { - emitpcode(PC_SUBFIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else { - emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); - } - if (is_uns) - emitpcode(PC_LI, regHi, 0); - else - emitpcode(PC_SRAWI, regHi, reg, 31); - break; - case 1 + 4: - case 2 + 4: - case 4 + 4: - if (!is_uns) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpreg2, opleft.reg, 31); - emitpcode(PC_SRAWI, tmpreg1, opright.reg, 31); - } - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { - emitpcode(PC_SUBFIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else { - emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); - } - if (is_uns) { - tmpreg1 = ALLOC_GPR(); - emitpcode(PC_LI, tmpreg1, 0); - emitpcode(PC_SUBFZE, regHi, tmpreg1); - } else { - emitpcode(PC_SUBFE, regHi, tmpreg1, tmpreg2); - } - break; - case 1 + 8: - case 2 + 8: - case 4 + 8: - if (skipleft < skipright) { - emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); - emitpcode(PC_SUBFE, regHi, opright.regHi, opleft.regHi); - } else { - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { - emitpcode(PC_SUBFIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else { - emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); - } - tmpreg1 = ALLOC_GPR(); - emitpcode(PC_LI, tmpreg1, 0); - emitpcode(PC_SUBFE, regHi, tmpreg1, opleft.regHi); - } - break; - case 8 + 8: - emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); - emitpcode(PC_SUBFE, regHi, opright.regHi, opleft.regHi); - break; - default: - CError_FATAL(7211); - } - - output->optype = OpndType_GPRPair; - output->reg = reg; - output->regHi = regHi; -} - -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) { - switch (val) { - case 0: return -1; - case 1ULL << 0: return 0; - case 1ULL << 1: return 1; - case 1ULL << 2: return 2; - case 1ULL << 3: return 3; - case 1ULL << 4: return 4; - case 1ULL << 5: return 5; - case 1ULL << 6: return 6; - case 1ULL << 7: return 7; - case 1ULL << 8: return 8; - case 1ULL << 9: return 9; - case 1ULL << 10: return 10; - case 1ULL << 11: return 11; - case 1ULL << 12: return 12; - case 1ULL << 13: return 13; - case 1ULL << 14: return 14; - case 1ULL << 15: return 15; - case 1ULL << 16: return 16; - case 1ULL << 17: return 17; - case 1ULL << 18: return 18; - case 1ULL << 19: return 19; - case 1ULL << 20: return 20; - case 1ULL << 21: return 21; - case 1ULL << 22: return 22; - case 1ULL << 23: return 23; - case 1ULL << 24: return 24; - case 1ULL << 25: return 25; - case 1ULL << 26: return 26; - case 1ULL << 27: return 27; - case 1ULL << 28: return 28; - case 1ULL << 29: return 29; - case 1ULL << 30: return 30; - case 1ULL << 31: return 31; - case 1ULL << 32: return 32; - case 1ULL << 33: return 33; - case 1ULL << 34: return 34; - case 1ULL << 35: return 35; - case 1ULL << 36: return 36; - case 1ULL << 37: return 37; - case 1ULL << 38: return 38; - case 1ULL << 39: return 39; - case 1ULL << 40: return 40; - case 1ULL << 41: return 41; - case 1ULL << 42: return 42; - case 1ULL << 43: return 43; - case 1ULL << 44: return 44; - case 1ULL << 45: return 45; - case 1ULL << 46: return 46; - case 1ULL << 47: return 47; - case 1ULL << 48: return 48; - case 1ULL << 49: return 49; - case 1ULL << 50: return 50; - case 1ULL << 51: return 51; - case 1ULL << 52: return 52; - case 1ULL << 53: return 53; - case 1ULL << 54: return 54; - case 1ULL << 55: return 55; - case 1ULL << 56: return 56; - case 1ULL << 57: return 57; - case 1ULL << 58: return 58; - case 1ULL << 59: return 59; - case 1ULL << 60: return 60; - case 1ULL << 61: return 61; - case 1ULL << 62: return 62; - case 1ULL << 63: return 63; - default: return -2; - } -} - -int I8_log2n(UInt64 val) { - int bit = I8_getbit(val); - return (bit > 0 && bit < 63) ? bit : 0; -} - -void I8_ShiftLeftImmediate(Operand opnd, SInt32 value, int is_unsigned, SInt32 size, short reg, short regHi) { - if (opnd.reg == reg || opnd.regHi == regHi || opnd.reg == regHi || opnd.regHi == reg) - CError_FATAL(7703); - - if (value < 32) { - emitpcode(PC_RLWINM, reg, opnd.reg, value, 0, 31 - value); - if (size > 4) { - emitpcode(PC_RLWINM, regHi, opnd.regHi, value, 0, 31 - value); - emitpcode(PC_RLWIMI, regHi, opnd.reg, value, 32 - value, 31); - } else { - emitpcode(PC_RLWINM, regHi, opnd.reg, value, 32 - value, 31); - } - } else if (value <= 63) { - if (value == 32) - emitpcode(PC_MR, regHi, opnd.reg); - else - emitpcode(PC_RLWINM, regHi, opnd.reg, value - 32, 0, 63 - value); - emitpcode(PC_LI, reg, 0); - } else { - CError_FATAL(7732); - } -} - -void I8_ShiftRightImmediate(Operand opnd, SInt32 value, int is_unsigned, short reg, short regHi, int unk) { - short tmpreg1; - short tmpreg2; - short tmpreg3; - short tmpreg4; - - if (opnd.reg == reg || opnd.regHi == regHi || opnd.reg == regHi || opnd.regHi == reg) - CError_FATAL(7756); - - if (value < 32) { - emitpcode(PC_RLWINM, reg, opnd.reg, 32 - value, 0, 31); - emitpcode(PC_RLWIMI, reg, opnd.regHi, 32 - value, 0, value - 1); - if (is_unsigned) { - emitpcode(PC_RLWINM, regHi, opnd.regHi, 32 - value, value, 31); - } else if (unk) { - tmpreg1 = ALLOC_GPR(); - emitpcode(PC_MR, tmpreg1, opnd.regHi); - emitpcode(PC_RLWIMI, tmpreg1, opnd.reg, 0, 31 - (value - 1), 31); - emitpcode(PC_SRAWI, regHi, tmpreg1, value); - } else { - emitpcode(PC_SRAWI, regHi, opnd.regHi, value); - } - } else if (value == 32) { - if (is_unsigned) { - emitpcode(PC_MR, reg, opnd.regHi); - emitpcode(PC_LI, regHi, 0); - } else if (unk) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - emitpcode(PC_NEG, tmpreg1, opnd.reg); - emitpcode(PC_OR, tmpreg2, tmpreg1, opnd.reg); - emitpcode(PC_RLWINM, tmpreg3, tmpreg2, 1, 31, 31); - emitpcode(PC_RLWIMI, tmpreg3, opnd.regHi, 0, 0, 0); - emitpcode(PC_MR, reg, opnd.regHi); - emitpcode(PC_SRAWI, regHi, value, 31); - } else { - emitpcode(PC_MR, reg, opnd.regHi); - emitpcode(PC_SRAWI, regHi, opnd.regHi, 31); - } - } else if (value <= 63) { - if (is_unsigned) { - emitpcode(PC_RLWINM, reg, opnd.regHi, 64 - value, value - 32, 31); - emitpcode(PC_LI, regHi, 0); - } else if (unk) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - tmpreg4 = ALLOC_GPR(); - emitpcode(PC_NEG, tmpreg1, opnd.reg); - emitpcode(PC_OR, tmpreg2, tmpreg1, opnd.reg); - emitpcode(PC_RLWINM, tmpreg3, tmpreg2, 1, 31, 31); - emitpcode(PC_OR, tmpreg4, opnd.regHi, tmpreg3); - emitpcode(PC_SRAWI, regHi, opnd.regHi, 31); - emitpcode(PC_SRAWI, reg, tmpreg4, value - 32); - } else { - emitpcode(PC_SRAWI, reg, opnd.regHi, value - 32); - emitpcode(PC_SRAWI, regHi, opnd.regHi, 31); - } - } else { - CError_FATAL(7866); - } -} - -void I8_gen_MUL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - int is_uns; - ENode *left; - ENode *right; - short reg; - short regHi; - short tmpreg1; - short tmpreg2; - short tmpreg3; - short tmpreg4; - SInt32 skipleft; - SInt32 skipright; - Operand opleft; - Operand opright; - SInt64 leftval; - SInt64 rightval; - int shift; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - skipleft = GetSizeSkip(left); - skipright = GetSizeSkip(right); - - if (ENODE_IS(right, EINTCONST) && ENODE_IS(left, EINTCONST)) - CError_FATAL(7900); - - if (ENODE_IS(left, EINTCONST)) - leftval = left->data.intval.lo + (((SInt64) ((skipleft < 8) ? 0 : left->data.intval.hi)) << 32); - if (ENODE_IS(right, EINTCONST)) - rightval = right->data.intval.lo + (((SInt64) ((skipright < 8) ? 0 : right->data.intval.hi)) << 32); - - if (right->hascall) { - GEN_NODE(right, &opright); - if (TYPE_IS_8BYTES(right->rtype)) - coerce_to_register_pair(&opright, right->rtype, 0, 0); - else - ENSURE_GPR(&opright, right->rtype, 0); - - if (!(ENODE_IS(left, EINTCONST) && I8_log2n(leftval) > 0)) { - GEN_NODE(left, &opleft); - if (TYPE_IS_8BYTES(left->rtype)) - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - else - ENSURE_GPR(&opleft, left->rtype, 0); - } - } else { - if (!(ENODE_IS(left, EINTCONST) && I8_log2n(leftval) > 0)) { - GEN_NODE(left, &opleft); - if (TYPE_IS_8BYTES(left->rtype)) - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - else - ENSURE_GPR(&opleft, left->rtype, 0); - } - - if (!(ENODE_IS(right, EINTCONST) && I8_log2n(rightval) > 0)) { - GEN_NODE(right, &opright); - if (TYPE_IS_8BYTES(right->rtype)) - coerce_to_register_pair(&opright, right->rtype, 0, 0); - else - ENSURE_GPR(&opright, right->rtype, 0); - } - } - - is_uns = is_unsigned(expr->rtype) != 0; - - if (skipleft < skipright) { - Operand tmpop; - SInt64 tmp64; - SInt32 tmp; - - expr->data.diadic.left = right; - expr->data.diadic.right = left; - left = expr->data.diadic.left; - right = expr->data.diadic.right; - - tmpop = opright; - opright = opleft; - opleft = tmpop; - - tmp64 = leftval; - leftval = rightval; - rightval = tmp64; - - tmp = skipleft; - skipleft = skipright; - skipright = tmp; - } - - reg = ALLOC_GPR(); - regHi = ALLOC_GPR(); - - if (ENODE_IS(left, EINTCONST) && (shift = I8_log2n(leftval)) > 0) { - I8_ShiftLeftImmediate(opright, shift, is_uns, skipright, reg, regHi); - } else if (ENODE_IS(right, EINTCONST) && (shift = I8_log2n(rightval)) > 0) { - I8_ShiftLeftImmediate(opleft, shift, is_uns, skipleft, reg, regHi); - } else { - switch (skipleft + skipright) { - case 1 + 1: - case 1 + 2: - case 2 + 2: - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { - emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { - emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - } else { - emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); - } - if (is_uns) - emitpcode(PC_LI, regHi, 0); - else - emitpcode(PC_SRAWI, regHi, reg, 31); - break; - case 1 + 4: - case 2 + 4: - case 4 + 4: - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { - emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { - emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - } else { - emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); - } - if (is_uns) - emitpcode(PC_MULHWU, regHi, opleft.reg, opright.reg); - else - emitpcode(PC_MULHW, regHi, opleft.reg, opright.reg); - break; - case 1 + 8: - case 2 + 8: - case 4 + 8: - CError_ASSERT(8097, skipleft == 8); - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { - emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); - if (is_uns) - emitpcode(PC_MULHWU, regHi, opright.reg, opleft.reg); - else - emitpcode(PC_MULHW, regHi, opright.reg, opleft.reg); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo) && right->data.intval.hi == 0) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - if (is_uns) { - emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); - emitpcode(PC_MULLI, tmpreg1, opleft.regHi, LOW_PART(right->data.intval.lo)); - emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); - } else { - tmpreg3 = ALLOC_GPR(); - tmpreg4 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpreg4, opright.reg, 31); - emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); - emitpcode(PC_MULLI, tmpreg1, opleft.regHi, LOW_PART(right->data.intval.lo)); - emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - emitpcode(PC_MULLW, tmpreg3, opleft.reg, tmpreg4); - emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); - emitpcode(PC_ADD, regHi, regHi, tmpreg3); - } - } else { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - if (is_uns) { - emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); - emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); - emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); - emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); - } else { - tmpreg3 = ALLOC_GPR(); - tmpreg4 = ALLOC_GPR(); - emitpcode(PC_SRAWI, tmpreg4, opright.reg, 31); - emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); - emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); - emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); - emitpcode(PC_MULLW, tmpreg3, opleft.reg, tmpreg4); - emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); - emitpcode(PC_ADD, regHi, regHi, tmpreg3); - } - } - break; - case 8 + 8: - if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - emitpcode(PC_MULHWU, tmpreg1, opright.reg, opleft.reg); - emitpcode(PC_MULLW, tmpreg2, opright.reg, opleft.regHi); - emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); - emitpcode(PC_ADD, regHi, tmpreg1, tmpreg2); - } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo) && right->data.intval.hi == 0) { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); - emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); - emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); - emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); - } else { - tmpreg1 = ALLOC_GPR(); - tmpreg2 = ALLOC_GPR(); - tmpreg3 = ALLOC_GPR(); - tmpreg4 = ALLOC_GPR(); - emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); - emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); - emitpcode(PC_ADD, tmpreg3, tmpreg2, tmpreg1); - emitpcode(PC_MULLW, tmpreg4, opleft.reg, opright.regHi); - emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); - emitpcode(PC_ADD, regHi, tmpreg3, tmpreg4); - } - break; - default: - CError_FATAL(8218); - } - } - - output->optype = OpndType_GPRPair; - output->reg = reg; - output->regHi = regHi; -} - -void I8_gen_BINNOT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - Operand op; - int reg; - int regHi; - - inner = expr->data.monadic; - memclrw(&op, sizeof(Operand)); - GEN_NODE(inner, &op); - coerce_to_register_pair(&op, inner->rtype, 0, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); - emitpcode(PC_NOR, reg, op.reg, op.reg); - emitpcode(PC_NOR, regHi, op.regHi, op.regHi); - - output->optype = OpndType_GPRPair; - output->reg = reg; - output->regHi = regHi; -} - -void I8_gen_MONMIN(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - Operand op; - int reg; - int regHi; - - inner = expr->data.monadic; - memclrw(&op, sizeof(Operand)); - GEN_NODE(inner, &op); - coerce_to_register_pair(&op, inner->rtype, 0, 0); - - reg = outputReg ? outputReg : ALLOC_GPR(); - regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); - emitpcode(PC_SUBFIC, reg, op.reg, 0); - emitpcode(PC_SUBFZE, regHi, op.regHi); - - output->optype = OpndType_GPRPair; - output->reg = reg; - output->regHi = regHi; -} - -void I8_gen_ASS(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *type; - ENode *left; - ENode *right; - Operand opleft; - Operand opright; - VarInfo *vi; - - type = expr->rtype; - if (ENODE_IS(expr, ECONDASS)) { - left = expr->data.cond.expr1; - if (ENODE_IS(left, EINDIRECT)) - left = left->data.monadic; - else - CError_FATAL(8328); - right = expr->data.cond.expr2; - } else { - left = expr->data.diadic.left; - right = expr->data.diadic.right; - } - - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - if (ENODE_IS(left, EOBJREF) && OBJECT_REG(left->data.objref)) { - vi = Registers_GetVarInfo(left->data.objref); - GEN_NODE_TO_REG(right, vi->reg, vi->regHi, &opright); - if (vi->rclass != RegClass_GPR) { - CError_FATAL(8348); - } else { - coerce_to_register_pair(&opright, type, vi->reg, vi->regHi); - *output = opright; - } - return; - } - - if (TYPE_FITS_IN_REGISTER(type)) { - GEN_NODE(right, &opright); - coerce_to_register_pair(&opright, right->rtype, 0, 0); - - if (ENODE_IS(left, EBITFIELD)) { - CError_FATAL(8376); - } else { - GEN_NODE(left, &opleft); - indirect(&opleft, left); - store_pair(opright.reg, opright.regHi, &opleft, type); - } - - output->optype = OpndType_GPRPair; - output->reg = opright.reg; - output->regHi = opright.regHi; - } -} - -void I8_gen_POSTINCDEC(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - Type *type; - int flag; - int reg; - int regHi; - Operand op1; - Operand op2; - Operand op3; - - inner = expr->data.monadic->data.monadic; - type = expr->rtype; - flag = 0; - memclrw(&op1, sizeof(Operand)); - memclrw(&op2, sizeof(Operand)); - - if (ENODE_IS(inner, EOBJREF) && (reg = OBJECT_REG(inner->data.objref))) { - regHi = Registers_GetVarInfo(inner->data.objref)->regHi; - output->optype = OpndType_GPRPair; - output->reg = (outputReg && outputReg != reg && outputReg != regHi) ? outputReg : ALLOC_GPR(); - output->regHi = (outputRegHi && outputRegHi != regHi && outputRegHi != reg) ? outputRegHi : ALLOC_GPR(); - emitpcode(PC_MR, output->reg, reg); - emitpcode(PC_MR, output->regHi, regHi); - if (ENODE_IS(expr, EPOSTINC)) { - emitpcode(PC_ADDIC, reg, reg, 1); - emitpcode(PC_ADDME, regHi, regHi); - } else { - emitpcode(PC_ADDIC, reg, reg, -1); - emitpcode(PC_ADDZE, regHi, regHi); - } - return; - } - - CError_ASSERT(8446, !ENODE_IS(inner, EBITFIELD)); - - GEN_NODE(inner, &op1); - indirect(&op1, inner); - op2 = op1; - coerce_to_register_pair(&op2, type, 0, 0); - - output->optype = OpndType_GPRPair; - output->reg = ALLOC_GPR(); - output->regHi = ALLOC_GPR(); - - emitpcode(PC_MR, output->reg, op2.reg); - emitpcode(PC_MR, output->regHi, op2.regHi); - - reg = ALLOC_GPR(); - regHi = ALLOC_GPR(); - - if (ENODE_IS(expr, EPOSTINC)) { - emitpcode(PC_ADDIC, reg, op2.reg, 1); - emitpcode(PC_ADDZE, regHi, op2.regHi); - } else { - emitpcode(PC_ADDIC, reg, op2.reg, -1); - emitpcode(PC_ADDME, regHi, op2.regHi); - } - store_pair(reg, regHi, &op1, type); -} - -void I8_gen_INDIRECT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - ENode *inner; - VarInfo *vi; - - inner = expr->data.monadic; - if (ENODE_IS(inner, EOBJREF) && OBJECT_REG(inner->data.objref)) { - vi = Registers_GetVarInfo(inner->data.objref); - switch (vi->rclass) { - case RegClass_GPR: - output->optype = OpndType_GPRPair; - break; - case RegClass_FPR: - output->optype = OpndType_FPR; - break; - default: - CError_FATAL(8511); - } - - output->reg = vi->reg; - output->regHi = vi->regHi; - output->object = NULL; - return; - } - - if (ENODE_IS(inner, EBITFIELD)) { - CError_FATAL(8529); - return; - } - - GEN_NODE(inner, output); - indirect(output, inner); -} - -void I8_gen_condition(ENode *cond, Operand *output, int write_to_gpr) { - ENode *left; - ENode *right; - Operand opleft; - Operand opright; - Operand tmpop; - int reg1; - int reg2; - int reg3; - int reg4; - int reg5; - - left = cond->data.diadic.left; - right = cond->data.diadic.right; - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - memclrw(&tmpop, sizeof(Operand)); - - if (right->hascall) { - GEN_NODE(right, &opright); - if (right->rtype->size < 4) - extend32(&opright, right->rtype, 0); - ENSURE_GPR(&opright, right->rtype, 0); - - if (right->rtype->size < 8) { - short tmp = ALLOC_GPR(); - if (is_unsigned(right->rtype)) - load_immediate(tmp, 0); - else - emitpcode(PC_SRAWI, tmp, opright.reg, 31); - opright.optype = OpndType_GPRPair; - opright.regHi = tmp; - } - - GEN_NODE(left, &opleft); - if (left->rtype->size < 4) - extend32(&opleft, left->rtype, 0); - ENSURE_GPR(&opleft, left->rtype, 0); - - if (left->rtype->size < 8) { - short tmp = ALLOC_GPR(); - // this looks like a bug??? surely this should check left->rtype - if (is_unsigned(right->rtype)) - load_immediate(tmp, 0); - else - emitpcode(PC_SRAWI, tmp, opleft.reg, 31); - opleft.optype = OpndType_GPRPair; - opleft.regHi = tmp; - } - } else { - GEN_NODE(left, &opleft); - ENSURE_GPR(&opleft, left->rtype, 0); - if (left->rtype->size < 4) - extend32(&opleft, left->rtype, 0); - - if (left->rtype->size < 8) { - short tmp = ALLOC_GPR(); - if (is_unsigned(right->rtype)) - load_immediate(tmp, 0); - else - emitpcode(PC_SRAWI, tmp, opleft.reg, 31); - opleft.optype = OpndType_GPRPair; - opleft.regHi = tmp; - } - - GEN_NODE(right, &opright); - if (right->rtype->size < 4) - extend32(&opright, right->rtype, 0); - ENSURE_GPR(&opright, right->rtype, 0); - - if (right->rtype->size < 8) { - short tmp = ALLOC_GPR(); - if (is_unsigned(right->rtype)) - load_immediate(tmp, 0); - else - emitpcode(PC_SRAWI, tmp, opright.reg, 31); - opright.optype = OpndType_GPRPair; - opright.regHi = tmp; - } - } - - CError_ASSERT(8704, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); - - switch (cond->type) { - case EEQU: - case ENOTEQU: - reg1 = ALLOC_GPR(); - reg2 = ALLOC_GPR(); - emitpcode(PC_XOR, reg1, opleft.reg, opright.reg); - emitpcode(PC_XOR, reg2, opleft.regHi, opright.regHi); - emitpcode(PC_OR, reg2, reg1, reg2); - if (write_to_gpr) { - if (ENODE_IS(cond, EEQU)) { - emitpcode(PC_CNTLZW, reg2, reg2); - emitpcode(PC_RLWINM, reg2, reg2, 27, 5, 31); - } else { - emitpcode(PC_ADDIC, reg1, reg2, -1); - emitpcode(PC_SUBFE, reg2, reg1, reg2); - } - output->optype = OpndType_GPR; - output->reg = reg2; - output->regHi = 0; - } else { - emitpcode(PC_CMPI, 0, reg2, 0); - output->optype = OpndType_CRField; - output->reg = 0; - output->regOffset = cond->type; - } - break; - case EGREATER: - tmpop = opleft; - opleft = opright; - opright = tmpop; - case ELESS: - reg1 = ALLOC_GPR(); - reg2 = ALLOC_GPR(); - reg3 = ALLOC_GPR(); - if (left->rtype != TYPE(&stunsignedlonglong) && right->rtype != TYPE(&stunsignedlonglong)) { - emitpcode(PC_XORIS, reg1, opleft.regHi, 0x8000); - emitpcode(PC_XORIS, reg2, opright.regHi, 0x8000); - reg4 = reg1; - reg5 = reg2; - } else { - reg4 = opleft.regHi; - reg5 = opright.regHi; - } - emitpcode(PC_SUBFC, reg3, opright.reg, opleft.reg); - emitpcode(PC_SUBFE, reg2, reg5, reg4); - emitpcode(PC_SUBFE, reg2, reg1, reg1); - emitpcode(PC_NEG, reg2, reg2); - if (write_to_gpr) { - output->optype = OpndType_GPR; - output->reg = reg2; - output->regHi = 0; - } else { - emitpcode(PC_CMPI, 0, reg2, 0); - output->optype = OpndType_CRField; - output->reg = 0; - output->regOffset = ENOTEQU; - } - break; - case ELESSEQU: - tmpop = opleft; - opleft = opright; - opright = tmpop; - case EGREATEREQU: - reg1 = ALLOC_GPR(); - reg2 = ALLOC_GPR(); - reg3 = ALLOC_GPR(); - if (left->rtype != TYPE(&stunsignedlonglong) && right->rtype != TYPE(&stunsignedlonglong)) { - emitpcode(PC_XORIS, reg1, opleft.regHi, 0x8000); - emitpcode(PC_XORIS, reg2, opright.regHi, 0x8000); - reg4 = reg1; - reg5 = reg2; - } else { - reg4 = opleft.regHi; - reg5 = opright.regHi; - } - emitpcode(PC_SUBFC, reg3, opright.reg, opleft.reg); - emitpcode(PC_SUBFE, reg2, reg5, reg4); - emitpcode(PC_SUBFE, reg2, reg1, reg1); - emitpcode(PC_NEG, reg2, reg2); - if (write_to_gpr) { - emitpcode(PC_SUBFIC, reg2, reg2, 1); - output->optype = OpndType_GPR; - output->reg = reg2; - output->regHi = 0; - } else { - emitpcode(PC_CMPI, 0, reg2, 0); - output->optype = OpndType_CRField; - output->reg = 0; - output->regOffset = EEQU; - } - break; - default: - CError_FATAL(8814); - } -} - -void I8_gen_SHL_SHR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - static UInt32 used_regs[RegClassMax] = {0, 0, 0, 0, (1 << 3) | (1 << 4) | (1 << 5)}; - - ENode *left; - ENode *right; - Operand opleft; - Operand opright; - int is_uns; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - GEN_NODE(left, &opleft); - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - - output->optype = OpndType_GPRPair; - output->reg = ALLOC_GPR(); - output->regHi = ALLOC_GPR(); - - is_uns = is_unsigned(expr->rtype) != 0; - - if (ENODE_IS(right, EINTCONST)) { - if (ENODE_IS(expr, ESHL)) { - I8_ShiftLeftImmediate(opleft, right->data.intval.lo, is_uns, expr->rtype->size, output->reg, output->regHi); - } else { - I8_ShiftRightImmediate(opleft, right->data.intval.lo, is_uns, output->reg, output->regHi, 0); - } - return; - } - - GEN_NODE(right, &opright); - ENSURE_GPR(&opright, right->rtype, 0); - if (opright.optype == OpndType_GPRPair) { - opright.regHi = 0; - opright.optype = OpndType_GPR; - } - - CError_ASSERT(8890, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPR); - - if (opleft.regHi != high_reg) - emitpcode(PC_MR, high_reg, opleft.regHi); - if (opleft.reg != low_reg) - emitpcode(PC_MR, low_reg, opleft.reg); - if (opright.reg != 5) - emitpcode(PC_MR, 5, opright.reg); - - if (ENODE_IS(expr, ESHR)) { - if (is_unsigned(left->rtype)) - branch_subroutine(rt_shr2u, 0, used_regs); - else - branch_subroutine(rt_shr2i, 0, used_regs); - } else if (ENODE_IS(expr, ESHL)) { - branch_subroutine(rt_shl2i, 0, used_regs); - } else { - CError_FATAL(8909); - } - - emitpcode(PC_MR, output->reg, low_reg); - emitpcode(PC_MR, output->regHi, high_reg); -} - -void I8_gen_DIV_MOD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - static UInt32 used_regs[RegClassMax] = {0, 0, 0, 0, (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)}; - - int is_uns; - ENode *left; - ENode *right; - Operand opleft; - Operand opright; - SInt64 constval; - int shift; - - left = expr->data.diadic.left; - right = expr->data.diadic.right; - memclrw(&opleft, sizeof(Operand)); - memclrw(&opright, sizeof(Operand)); - - GEN_NODE(left, &opleft); - coerce_to_register_pair(&opleft, left->rtype, 0, 0); - - output->optype = OpndType_GPRPair; - output->reg = ALLOC_GPR(); - output->regHi = ALLOC_GPR(); - - is_uns = is_unsigned(expr->rtype) != 0; - - if (ENODE_IS(right, EINTCONST)) - constval = (((SInt64) right->data.intval.hi) << 32) + right->data.intval.lo; - if (ENODE_IS(right, EINTCONST) && ((shift = I8_log2n(constval)) > 0)) { - CError_ASSERT(8976, opleft.optype == OpndType_GPRPair); - if (ENODE_IS(expr, EDIV)) { - I8_ShiftRightImmediate(opleft, shift, is_uns, output->reg, output->regHi, 1); - if (!is_uns) { - emitpcode(PC_ADDZE, output->reg, output->reg); - emitpcode(PC_ADDZE, output->regHi, output->regHi); - } - } else { - if (is_uns) { - if (shift < 32) { - emitpcode(PC_LI, output->regHi, 0); - emitpcode(PC_RLWINM, output->reg, opleft.reg, 0, 32 - shift, 31); - } else if (shift == 32) { - emitpcode(PC_LI, output->regHi, 0); - emitpcode(PC_MR, output->reg, opleft.reg); - } else if (shift <= 63) { - emitpcode(PC_RLWINM, output->regHi, opleft.regHi, 0, 32 - (shift - 32), 31); - emitpcode(PC_MR, output->reg, opleft.reg); - } else { - CError_FATAL(9018); - } - } else { - short tmpreg1 = ALLOC_GPR(); - short tmpreg2 = ALLOC_GPR(); - I8_ShiftRightImmediate(opleft, shift, is_uns, output->reg, output->regHi, 1); - emitpcode(PC_ADDZE, output->reg, output->reg); - emitpcode(PC_ADDZE, output->regHi, output->regHi); - I8_ShiftLeftImmediate(*output, shift, is_uns, expr->rtype->size, tmpreg1, tmpreg2); - emitpcode(PC_SUBFC, output->reg, tmpreg1, opleft.reg); - emitpcode(PC_SUBFE, output->regHi, tmpreg2, opleft.regHi); - } - } - return; - } - - GEN_NODE(right, &opright); - coerce_to_register_pair(&opright, right->rtype, 0, 0); - - CError_ASSERT(9048, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); - - if (opleft.regHi != high_reg) - emitpcode(PC_MR, high_reg, opleft.regHi); - if (opleft.reg != low_reg) - emitpcode(PC_MR, low_reg, opleft.reg); - if (opright.regHi != high_reg2) - emitpcode(PC_MR, high_reg2, opright.regHi); - if (opright.reg != low_reg2) - emitpcode(PC_MR, low_reg2, opright.reg); - - if (ENODE_IS(expr, EDIV)) { - if (is_unsigned(left->rtype) || is_unsigned(right->rtype)) - branch_subroutine(rt_div2u, 0, used_regs); - else - branch_subroutine(rt_div2i, 0, used_regs); - } else if (ENODE_IS(expr, EMODULO)) { - if (is_unsigned(left->rtype) || is_unsigned(right->rtype)) - branch_subroutine(rt_mod2u, 0, used_regs); - else - branch_subroutine(rt_mod2i, 0, used_regs); - } else { - CError_FATAL(9074); - } - - emitpcode(PC_MR, output->reg, low_reg); - emitpcode(PC_MR, output->regHi, high_reg); -} - -void I8_gen_TYPCON(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - Type *dsttype; - ENode *inner; - Type *srctype; - short regHi; - short reg; - - static UInt32 used_regs[RegClassMax] = {0, 0, 0, 0, (1 << 3) | (1 << 4)}; - static UInt32 used_regs_f1[RegClassMax] = {0, 0, 0, (1 << 1), 0}; - - inner = expr->data.monadic; - srctype = inner->rtype; - dsttype = expr->rtype; - - if (IS_TYPE_VOID(dsttype)) { - GEN_NODE(inner, output); - if (ENODE_IS(inner, EINDIRECT) && (output->flags & OpndFlags_Volatile)) - coerce_to_register_pair(output, inner->rtype, 0, 0); - output->optype = OpndType_Absolute; - output->immediate = 0; - return; - } - - if (IS_TYPE_INT_OR_ENUM(srctype)) { - if (IS_TYPE_FLOAT(dsttype)) { - GEN_NODE(inner, output); - coerce_to_register_pair(output, srctype, 0, 0); - if (output->regHi != high_reg) - emitpcode(PC_MR, high_reg, output->regHi); - if (output->reg != low_reg) - emitpcode(PC_MR, low_reg, output->reg); - - if (is_unsigned(srctype)) { - branch_subroutine( - (dsttype->size == 4) ? rt_cvt_ull_flt : rt_cvt_ull_dbl, - 0, - used_regs); - } else { - branch_subroutine( - (dsttype->size == 4) ? rt_cvt_sll_flt : rt_cvt_sll_dbl, - 0, - used_regs); - } - - output->optype = OpndType_FPR; - output->reg = ALLOC_FPR(); - emitpcode(PC_FMR, output->reg, 1); - return; - } - - if (srctype->size < dsttype->size) { - CError_ASSERT(9171, TYPE_IS_8BYTES(dsttype)); - - GEN_NODE(inner, output); - if (srctype->size < 4 && - !ENODE_IS_INDIRECT_TO(inner, EBITFIELD) && - !((ENODE_IS_ASSIGN(inner) || ENODE_IS_RANGE(inner, EPOSTINC, EPREDEC)) && ENODE_IS(inner->data.monadic->data.monadic, EBITFIELD)) - ) { - extend32(output, srctype, outputReg); - } - extend64(output, srctype, outputReg, outputRegHi); - } else { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - if (dsttype->size < srctype->size) { - coerce_to_register_pair(output, srctype, outputReg, outputRegHi); - output->optype = OpndType_GPR; - output->regHi = 0; - } - } - return; - } - - if (IS_TYPE_POINTER(srctype)) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - CError_ASSERT(9200, TYPE_IS_8BYTES(expr->rtype)); - GEN_NODE_TO_REG(inner, outputReg, 0, output); - - regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); - if (regHi == output->reg) { - reg = outputReg ? outputReg : ALLOC_GPR(); - emitpcode(PC_MR, reg, output->reg); - output->reg = reg; - } - if (is_unsigned(inner->rtype)) - load_immediate(regHi, 0); - else - emitpcode(PC_SRAWI, regHi, output->reg, 31); - output->optype = OpndType_GPRPair; - output->regHi = regHi; - return; - } - - if (IS_TYPE_FLOAT(srctype)) { - if (IS_TYPE_FLOAT(dsttype)) { - CError_FATAL(9222); - return; - } - - GEN_NODE(inner, output); - ENSURE_FPR(output, srctype, 0); - if (output->reg != 1) - emitpcode(PC_FMR, 1, output->reg); - - branch_subroutine(rt_cvt_dbl_usll, 0, used_regs_f1); - - output->optype = OpndType_GPRPair; - output->reg = ALLOC_GPR(); - output->regHi = ALLOC_GPR(); - emitpcode(PC_MR, output->reg, low_reg); - emitpcode(PC_MR, output->regHi, high_reg); - return; - } - - if (IS_TYPE_STRUCT(srctype)) { - GEN_NODE_TO_REG(inner, outputReg, 0, output); - - if (TYPE_IS_8BYTES(expr->rtype) && dsttype->size == srctype->size) { - coerce_to_register_pair(output, srctype, outputReg, outputRegHi); - } else { - CError_FATAL(9256); - } - return; - } - - CError_FATAL(9261); -} - -void gen_VECTOR128CONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { - int gpr; - int vr; - COVCResult result; - - vr = outputReg ? outputReg : ALLOC_VR(); - if (!canoptimizevectorconst(&expr->data.vector128val, expr->rtype, &result)) - CError_FATAL(9282); - - if (result.op1 != -1) { - emitpcode(result.op1, vr, result.arg); - output->optype = OpndType_VR; - output->reg = vr; - return; - } - - if (result.op2 != -1) { - gpr = ALLOC_GPR(); - emitpcode(PC_LI, gpr, result.arg); - emitpcode(result.op2, vr, 0, gpr); - output->optype = OpndType_VR; - output->reg = vr; - return; - } - - CError_FATAL(9298); -} |