summaryrefslogtreecommitdiff
path: root/compiler_and_linker/unsorted/InstrSelection.c
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
committerAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
commit094b96ca1df4a035b5f93c351f773306c0241f3f (patch)
tree95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/unsorted/InstrSelection.c
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-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.c5348
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);
-}