#include "compiler/Operands.h" #include "compiler/CError.h" #include "compiler/PCode.h" #include "compiler/PCodeInfo.h" #include "compiler/PCodeUtilities.h" #include "compiler/enode.h" #include "compiler/objects.h" #include "compiler.h" unsigned long long uns_to_float_cc = 0x4330000000000000; unsigned long long int_to_float_cc = 0x4330000080000000; Float one_point_zero = {1.0}; void load_immediate(short reg, SInt32 value) { short tmpreg = reg; short tmpreg2; if (!FITS_IN_SHORT(value)) { if (copts.optimizationlevel > 1 && value) tmpreg = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_LIS, tmpreg2 = tmpreg, 0, (short) HIGH_PART(value)); if (value) emitpcode(PC_ADDI, reg, tmpreg2, 0, LOW_PART(value)); } else { emitpcode(PC_LI, reg, value); } } static void set_op_flags(Operand *op, ENode *expr) { #line 118 CError_ASSERT(op); if (expr) { if (expr->type == EINTCONST) { op->flags = 0; if (expr->flags & ENODE_FLAG_VOLATILE) op->flags |= OpndFlags_Volatile; if (expr->flags & ENODE_FLAG_CONST) op->flags |= OpndFlags_Const; } else { op->flags = CParserIsVolatileExpr(expr) ? OpndFlags_Volatile : 0; op->flags |= CParserIsConstExpr(expr) ? OpndFlags_Const : 0; } } else { op->flags = 0; } } void symbol_operand(Operand *op, Object *obj) { memclrw(op, sizeof(Operand)); op->optype = OpndType_Symbol; op->object = obj; } void indirect(Operand *op, ENode *expr) { switch (op->optype) { case OpndType_GPRPair: #line 163 CError_FATAL(); case OpndType_CRField: case OpndType_IndirectGPR_ImmOffset: case OpndType_IndirectGPR_Indexed: case OpndType_IndirectSymbol: if (op->optype) Coerce_to_register(op, (Type *) &void_ptr, 0); case OpndType_GPR: op->immOffset = 0; op->object = NULL; case OpndType_GPR_ImmOffset: op->optype = OpndType_IndirectGPR_ImmOffset; set_op_flags(op, expr); break; case OpndType_GPR_Indexed: op->optype = OpndType_IndirectGPR_Indexed; set_op_flags(op, expr); break; case OpndType_Absolute: if (FITS_IN_SHORT(op->immediate)) { op->reg = 0; op->immOffset = op->immediate; } else { emitpcode(PC_LIS, op->reg = used_virtual_registers[RegClass_GPR]++, 0, (short) HIGH_PART(op->immediate)); op->immOffset = LOW_PART(op->immediate); } op->object = NULL; op->optype = OpndType_IndirectGPR_ImmOffset; set_op_flags(op, expr); break; case OpndType_Symbol: op->optype = OpndType_IndirectSymbol; set_op_flags(op, expr); break; default: #line 215 CError_FATAL(); } } #define COMBO_OP(a, b) (b + (a * 11)) void combine(Operand *opA, Operand *opB, short output_reg, Operand *opOut) { Operand *tmp_op; int tmp; if (opA->optype == OpndType_Symbol || opA->optype == OpndType_IndirectSymbol) coerce_to_addressable(opA); if (opB->optype == OpndType_Symbol || opB->optype == OpndType_IndirectSymbol) coerce_to_addressable(opB); switch (COMBO_OP(opA->optype, opB->optype)) { case COMBO_OP(OpndType_GPR, OpndType_GPR): opOut->optype = OpndType_GPR_Indexed; opOut->reg = opA->reg; opOut->regOffset = opB->reg; break; case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_GPR_ImmOffset): if (FITS_IN_SHORT(opA->immOffset + opB->immOffset) && (!opA->object || !opB->object)) { opB->immOffset += opA->immOffset; if (!opB->object) opB->object = opA->object; } else { tmp = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; add_immediate(tmp, opA->reg, opA->object, opA->immOffset); opA->reg = tmp; } case COMBO_OP(OpndType_GPR, OpndType_GPR_ImmOffset): tmp_op = opA; opA = opB; opB = tmp_op; case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_GPR): if (opA->reg == _FP_ || opA->reg == _CALLER_SP_) { opOut->optype = OpndType_GPR_Indexed; opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; opOut->regOffset = opB->reg; add_immediate(opOut->reg, opA->reg, opA->object, LOW_PART(opA->immOffset)); } else if (opB->reg == _FP_ || opB->reg == _CALLER_SP_) { opOut->optype = OpndType_GPR_Indexed; opOut->reg = (output_reg && (output_reg != opA->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; opOut->regOffset = opA->reg; add_immediate(opOut->reg, opB->reg, opA->object, LOW_PART(opA->immOffset)); } else if (opA->object) { opOut->optype = OpndType_GPR_Indexed; opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; opOut->regOffset = opB->reg; add_immediate(opOut->reg, opA->reg, opA->object, LOW_PART(opA->immOffset)); } else { opOut->optype = OpndType_GPR_ImmOffset; opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; opOut->immOffset = opA->immOffset; opOut->object = opA->object; emitpcode(PC_ADD, opOut->reg, opA->reg, opB->reg); } break; case COMBO_OP(OpndType_GPR, OpndType_GPR_Indexed): tmp_op = opA; opA = opB; opB = tmp_op; case COMBO_OP(OpndType_GPR_Indexed, OpndType_GPR): opOut->optype = OpndType_GPR_Indexed; opOut->reg = opA->reg; opOut->regOffset = (output_reg && (output_reg != opA->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, opOut->regOffset, opA->regOffset, opB->reg); break; case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_GPR_Indexed): tmp_op = opA; opA = opB; opB = tmp_op; case COMBO_OP(OpndType_GPR_Indexed, OpndType_GPR_ImmOffset): if (opB->object) { opOut->optype = OpndType_GPR_Indexed; opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; opOut->regOffset = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, opOut->reg, opA->reg, opA->regOffset); add_immediate(opOut->regOffset, opB->reg, opB->object, opB->immOffset); } else { opOut->optype = OpndType_GPR_ImmOffset; opOut->immOffset = opB->immOffset; opOut->object = opB->object; opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, opOut->reg, opA->reg, opA->regOffset); emitpcode(PC_ADD, opOut->reg, opOut->reg, opB->reg); } break; case COMBO_OP(OpndType_GPR_Indexed, OpndType_GPR_Indexed): opOut->optype = OpndType_GPR_Indexed; opOut->reg = opA->reg; opOut->regOffset = (output_reg && (output_reg != opA->regOffset)) ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, opOut->regOffset, opB->reg, opB->regOffset); emitpcode(PC_ADD, opOut->regOffset, opOut->regOffset, opA->regOffset); break; case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_Absolute): tmp_op = opA; opA = opB; opB = tmp_op; case COMBO_OP(OpndType_Absolute, OpndType_GPR_ImmOffset): if (!opB->object) { opOut->optype = OpndType_GPR_ImmOffset; opOut->reg = opB->reg; opOut->immOffset = opB->immOffset; opOut->object = opB->object; if (FITS_IN_SHORT(opOut->immOffset + opA->immediate)) { opOut->immOffset += opA->immediate; } else { opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; if (!HIGH_PART(opA->immediate)) { emitpcode(PC_ADDI, opOut->reg, opB->reg, 0, LOW_PART(opA->immediate)); } else { emitpcode(PC_ADDIS, opOut->reg, opB->reg, 0, (short) HIGH_PART(opA->immediate)); if (FITS_IN_SHORT(opOut->immOffset + LOW_PART(opA->immediate))) { opOut->immOffset += LOW_PART(opA->immediate); } else { emitpcode(PC_ADDI, opOut->reg, opOut->reg, 0, LOW_PART(opA->immediate)); } } } break; } else if (opB->object->datatype == DLOCAL && can_add_displ_to_local(opB->object, opB->immOffset + opA->immediate)) { opOut->optype = OpndType_GPR_ImmOffset; opOut->object = opB->object; opOut->reg = opB->reg; opOut->immOffset = LOW_PART(opB->immOffset + opA->immediate); break; } else { opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; add_immediate(opOut->reg, opB->reg, opB->object, opB->immOffset); opB->optype = OpndType_GPR; opB->reg = opOut->reg; tmp_op = opA; opA = opB; opB = tmp_op; } case COMBO_OP(OpndType_GPR, OpndType_Absolute): tmp_op = opA; opA = opB; opB = tmp_op; case COMBO_OP(OpndType_Absolute, OpndType_GPR): opOut->optype = (opA->immediate != 0) ? OpndType_GPR_ImmOffset : OpndType_GPR; opOut->immOffset = LOW_PART(opA->immediate); opOut->object = NULL; if (FITS_IN_SHORT(opA->immediate)) { opOut->reg = opB->reg; } else { opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADDIS, opOut->reg, opB->reg, 0, (short) HIGH_PART(opA->immediate)); } break; case COMBO_OP(OpndType_GPR_Indexed, OpndType_Absolute): tmp_op = opA; opA = opB; opB = tmp_op; case COMBO_OP(OpndType_Absolute, OpndType_GPR_Indexed): opOut->optype = OpndType_GPR_Indexed; opOut->reg = opB->reg; opOut->regOffset = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; if (!HIGH_PART(opA->immediate)) { emitpcode(PC_ADDI, opOut->regOffset, opB->regOffset, 0, LOW_PART(opA->immediate)); } else { emitpcode(PC_ADDIS, opOut->regOffset, opB->regOffset, 0, (short) HIGH_PART(opA->immediate)); if (opA->immediate != 0) emitpcode(PC_ADDI, opOut->regOffset, opOut->regOffset, 0, LOW_PART(opA->immediate)); } break; case COMBO_OP(OpndType_Absolute, OpndType_Absolute): opOut->optype = OpndType_Absolute; opOut->immediate = opA->immediate + opB->immediate; break; default: #line 415 CError_FATAL(); } } void coerce_to_addressable(Operand *op) { UInt32 offset; short reg; short flag; short tmp; Object *obj; flag = 0; obj = op->object; tmp = 0; switch (op->optype) { case OpndType_GPR: case OpndType_GPR_ImmOffset: case OpndType_GPR_Indexed: case OpndType_GPRPair: case OpndType_Absolute: case OpndType_VR: case OpndType_CRField: case OpndType_IndirectGPR_ImmOffset: case OpndType_IndirectGPR_Indexed: break; case OpndType_IndirectSymbol: flag = 1; case OpndType_Symbol: if (obj->datatype == DLOCAL) { if (!local_is_16bit_offset(obj)) { reg = used_virtual_registers[RegClass_GPR]++; op_absolute_ha(reg, local_base_register(obj), obj, 0, 1); op->optype = OpndType_GPR_ImmOffset; op->reg = reg; op->object = obj; } else { op->optype = OpndType_GPR_ImmOffset; op->reg = local_base_register(obj); op->object = obj; } } else if (obj->datatype == DABSOLUTE) { offset = obj->u.address; if (FITS_IN_SHORT(offset)) { op->reg = 0; op->immOffset = obj->u.address; } else { emitpcode(PC_LIS, op->reg = used_virtual_registers[RegClass_GPR]++, 0, (short) HIGH_PART(offset)); op->immOffset = LOW_PART(obj->u.address); } op->object = obj; op->optype = OpndType_GPR_ImmOffset; } else { if (copts.codegen_pic) tmp = pic_base_reg; reg = used_virtual_registers[RegClass_GPR]++; op_absolute_ha(reg, tmp, obj, 0, 1); op->optype = OpndType_GPR_ImmOffset; op->reg = reg; } if (flag) { if (op->optype == OpndType_GPR_ImmOffset) { op->optype = OpndType_IndirectGPR_ImmOffset; } else { #line 563 CError_FATAL(); } } break; default: #line 581 CError_FATAL(); } } SInt32 offset; short opcode; short reg; short tmp; short cond_neg; short cond; short bit_offset; short bit_size; if (TYPE_IS_8BYTES(type)) { coerce_to_register_pair(op, type, output_reg, 0); return; } coerce_to_addressable(op); switch (op->optype) { case OpndType_GPRPair: return; case OpndType_GPR: return; case OpndType_GPR_ImmOffset: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; add_immediate(reg, op->reg, op->object, op->immOffset); break; case OpndType_GPR_Indexed: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, reg, op->reg, op->regOffset); break; case OpndType_Absolute: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; offset = op->immediate; if (FITS_IN_SHORT(offset)) { emitpcode(PC_LI, reg, offset); } else { tmp = reg; if (copts.optimizationlevel > 1 && offset) tmp = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_LIS, tmp, 0, (short) HIGH_PART(offset)); if (offset) emitpcode(PC_ADDI, reg, tmp, 0, LOW_PART(offset)); } break; case OpndType_IndirectGPR_ImmOffset: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; opcode = PC_LWZ; if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) { switch (type->size) { case 1: opcode = PC_LBZ; break; case 2: if (is_unsigned(type)) opcode = PC_LHZ; else opcode = PC_LHA; break; } } else { #line 680 CError_ASSERT(IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)); } load_store_register(opcode, reg, op->reg, op->object, op->immOffset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; opcode = PC_LWZX; if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) { switch (type->size) { case 1: opcode = PC_LBZX; break; case 2: if (is_unsigned(type)) opcode = PC_LHZX; else opcode = PC_LHAX; break; } } else { #line 724 CError_ASSERT(IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)); } emitpcode(opcode, reg, op->reg, op->regOffset); setpcodeflags(op->flags); break; case OpndType_CRField: cond_neg = 0; cond = 0; reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_MFCR, tmp = reg); switch (op->regOffset) { case ENOTEQU: cond_neg = 1; case EEQU: cond = 2; break; case EGREATEREQU: cond_neg = 1; case ELESS: cond = 0; break; case ELESSEQU: cond_neg = 1; case EGREATER: cond = 1; break; default: #line 758 CError_FATAL(); } bit_offset = cond + (op->reg << 2); bit_size = 1; emitpcode(PC_RLWINM, tmp, tmp, (bit_size + bit_offset) & 31, 32 - bit_size, 31); if (cond_neg) emitpcode(PC_XORI, tmp, tmp, 1); break; default: #line 769 CError_FATAL(); } op->optype = OpndType_GPR; op->reg = reg; } void coerce_to_register_pair(Operand *op, Type *type, short output_reg, short output_regHi) { SInt32 offset; short reg; short regHi; short tmp1; short tmp2; regHi = -1; #line 794 CError_ASSERT(TYPE_IS_8BYTES(type) || (IS_TYPE_STRUCT(type) && type->size == 8)); coerce_to_addressable(op); switch (op->optype) { case OpndType_GPRPair: if (output_reg && !output_regHi) output_regHi = used_virtual_registers[RegClass_GPR]++; if (output_regHi && !output_reg) output_reg = used_virtual_registers[RegClass_GPR]++; if (op->reg != output_reg || op->regHi != output_regHi) { tmp1 = output_reg ? output_reg : op->reg; tmp2 = output_regHi ? output_regHi : op->regHi; if (tmp1 != op->reg) { if (tmp1 == op->regHi) { #line 818 CError_ASSERT(tmp1 != tmp2); emitpcode(PC_MR, tmp2, op->regHi); emitpcode(PC_MR, tmp1, op->reg); } else { emitpcode(PC_MR, tmp1, op->reg); if (op->regHi != tmp2) emitpcode(PC_MR, tmp2, op->regHi); } } else if (tmp2 != op->regHi) { if (tmp2 == op->reg) { #line 832 CError_ASSERT(tmp1 != tmp2); emitpcode(PC_MR, tmp1, op->reg); emitpcode(PC_MR, tmp2, op->regHi); } else { emitpcode(PC_MR, tmp2, op->regHi); if (op->reg != tmp1) emitpcode(PC_MR, tmp1, op->reg); } } } reg = op->reg; regHi = op->regHi; break; case OpndType_GPR: #line 849 CError_FATAL(); break; case OpndType_GPR_ImmOffset: #line 852 CError_FATAL(); break; case OpndType_GPR_Indexed: #line 855 CError_FATAL(); break; case OpndType_Absolute: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; offset = op->immediate; if (FITS_IN_SHORT(offset)) { emitpcode(PC_LI, reg, offset); } else { tmp1 = reg; if (copts.optimizationlevel > 1 && offset) tmp1 = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_LIS, tmp1, 0, (short) HIGH_PART(offset)); if (offset) emitpcode(PC_ADDI, reg, tmp1, 0, LOW_PART(offset)); } regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++; if (is_unsigned(type) || offset >= 0) load_immediate(regHi, 0); else load_immediate(regHi, -1); break; case OpndType_IndirectGPR_ImmOffset: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++; if (op->reg == regHi) { if (op->reg == reg) { #line 887 CError_FATAL(); } else { load_store_register(PC_LWZ, reg, op->reg, op->object, op->immOffset + low_offset); setpcodeflags(op->flags); load_store_register(PC_LWZ, regHi, op->reg, op->object, op->immOffset + high_offset); setpcodeflags(op->flags); } } else { load_store_register(PC_LWZ, regHi, op->reg, op->object, op->immOffset + high_offset); setpcodeflags(op->flags); load_store_register(PC_LWZ, reg, op->reg, op->object, op->immOffset + low_offset); setpcodeflags(op->flags); } break; case OpndType_IndirectGPR_Indexed: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, reg, op->reg, op->regOffset); load_store_register(PC_LWZ, regHi, reg, NULL, high_offset); setpcodeflags(op->flags); load_store_register(PC_LWZ, reg, reg, NULL, low_offset); setpcodeflags(op->flags); break; default: #line 912 CError_FATAL(); } if (regHi == -1) { #line 916 CError_FATAL(); } else { op->optype = OpndType_GPRPair; op->reg = reg; op->regHi = regHi; } } void Coerce_to_fp_register(Operand *op, TypeIntegral *tint, short output_reg) { short reg; coerce_to_addressable(op); switch (op->optype) { case OpndType_FPR: reg = op->reg; break; case OpndType_IndirectGPR_ImmOffset: reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++; load_store_register((tint->size == 4) ? PC_LFS : PC_LFD, reg, op->reg, op->object, op->immOffset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++; emitpcode((tint->size == 4) ? PC_LFSX : PC_LFDX, reg, op->reg, op->regOffset, 0, 0x390); setpcodeflags(op->flags); break; default: #line 986 CError_FATAL(); } op->optype = OpndType_FPR; op->reg = reg; } void Coerce_to_v_register(Operand *op, TypeStruct *tstruct, short output_reg) { short reg; coerce_to_addressable(op); switch (op->optype) { case OpndType_VR: reg = op->reg; break; case OpndType_IndirectGPR_ImmOffset: reg = output_reg ? output_reg : used_virtual_registers[RegClass_VR]++; load_store_register(PC_LVX, reg, op->reg, op->object, op->immOffset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: reg = output_reg ? output_reg : used_virtual_registers[RegClass_VR]++; emitpcode(PC_LVX, reg, op->reg, op->regOffset); setpcodeflags(op->flags); break; case OpndType_Absolute: reg = output_reg ? output_reg : used_virtual_registers[RegClass_VR]++; switch (tstruct->stype) { case STRUCT_TYPE_4: case STRUCT_TYPE_5: case STRUCT_TYPE_6: emitpcode(PC_VSPLTISB, reg, op->immediate); break; case STRUCT_TYPE_7: case STRUCT_TYPE_8: case STRUCT_TYPE_9: case STRUCT_TYPE_E: emitpcode(PC_VSPLTISH, reg, op->immediate); break; case STRUCT_TYPE_A: case STRUCT_TYPE_B: case STRUCT_TYPE_C: case STRUCT_TYPE_D: emitpcode(PC_VSPLTISW, reg, op->immediate); break; default: #line 1049 CError_FATAL(); } op->optype = OpndType_VR; op->reg = reg; setpcodeflags(op->flags); break; default: #line 1059 CError_FATAL(); } op->optype = OpndType_VR; op->reg = reg; } void store(short reg, Operand *op, Type *type) { short opcode; coerce_to_addressable(op); switch (op->optype) { case OpndType_IndirectGPR_ImmOffset: opcode = PC_STW; if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) { switch (type->size) { case 1: opcode = PC_STB; break; case 2: opcode = PC_STH; break; } } else { #line 1171 CError_ASSERT(IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)); } load_store_register(opcode, reg, op->reg, op->object, op->immOffset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: opcode = PC_STWX; if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) { switch (type->size) { case 1: opcode = PC_STBX; break; case 2: opcode = PC_STHX; break; } } else { #line 1188 CError_ASSERT(IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)); } emitpcode(opcode, reg, op->reg, op->regOffset); setpcodeflags(op->flags); break; default: #line 1193 CError_FATAL(); } } void store_pair(short reg, short regHi, Operand *op, Type *type) { short tmp; #line 1208 CError_ASSERT(TYPE_IS_8BYTES(type)); coerce_to_addressable(op); switch (op->optype) { case OpndType_IndirectGPR_ImmOffset: load_store_register(PC_STW, reg, op->reg, op->object, op->immOffset + low_offset); setpcodeflags(op->flags); load_store_register(PC_STW, regHi, op->reg, op->object, op->immOffset + high_offset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: tmp = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_ADD, tmp, op->reg, op->regOffset); load_store_register(PC_STW, reg, tmp, NULL, low_offset); setpcodeflags(op->flags); load_store_register(PC_STW, regHi, tmp, NULL, high_offset); setpcodeflags(op->flags); break; default: #line 1228 CError_FATAL(); } } void store_fp(short reg, Operand *op, Type *tint) { coerce_to_addressable(op); switch (op->optype) { case OpndType_IndirectGPR_ImmOffset: load_store_register((tint->size == 4) ? PC_STFS : PC_STFD, reg, op->reg, op->object, op->immOffset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: emitpcode((tint->size == 4) ? PC_STFSX : PC_STFDX, reg, op->reg, op->regOffset); setpcodeflags(op->flags); break; default: #line 1259 CError_FATAL(); } } void store_v(short reg, Operand *op, Type *tstruct) { coerce_to_addressable(op); switch (op->optype) { case OpndType_IndirectGPR_ImmOffset: load_store_register(PC_STVX, reg, op->reg, op->object, op->immOffset); setpcodeflags(op->flags); break; case OpndType_IndirectGPR_Indexed: emitpcode(PC_STVX, reg, op->reg, op->regOffset); setpcodeflags(op->flags); break; default: #line 1283 CError_FATAL(); } } static Boolean last_matches_rlwinm_or_exts(Operand *op, short opcode, short b, short c) { PCode *pc; if (pclastblock->pcodeCount <= 0) return 0; pc = pclastblock->lastPCode; if (pc->args[0].kind != PCOp_REGISTER || pc->args[0].arg != RegClass_GPR || pc->args[0].data.reg.reg != op->reg) return 0; if (pc->op != opcode && (opcode != PC_EXTSH || pc->op != PC_EXTSB)) return 0; if (opcode == PC_RLWINM) { if (pc->args[2].data.imm.value != 0 || pc->args[3].data.imm.value != b || pc->args[4].data.imm.value != c) return 0; } return 1; } void extend32(Operand *op, Type *type, short output_reg) { int r28; int reg; r28 = op->optype >= OpndType_IndirectGPR_ImmOffset; if (op->optype != OpndType_GPR) Coerce_to_register(op, type, output_reg); switch (type->size) { case 1: if (is_unsigned(type)) { if (r28) return; if (last_matches_rlwinm_or_exts(op, PC_RLWINM, 24, 31)) return; reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_RLWINM, reg, op->reg, 0, 24, 31); } else { reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; if (last_matches_rlwinm_or_exts(op, PC_EXTSB, 0, 0)) return; emitpcode(PC_EXTSB, reg, op->reg); } break; case 2: if (r28) return; if (is_unsigned(type)) { if (last_matches_rlwinm_or_exts(op, PC_RLWINM, 16, 31)) return; reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_RLWINM, reg, op->reg, 0, 16, 31); } else { if (last_matches_rlwinm_or_exts(op, PC_EXTSH, 0, 0)) return; reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_EXTSH, reg, op->reg); } break; default: #line 1389 CError_FATAL(); } op->optype = OpndType_GPR; op->reg = reg; } void extend64(Operand *op, Type *type, short output_reg, short output_regHi) { short tmp; short regHi; if (op->optype != OpndType_GPR) Coerce_to_register(op, type, output_reg); regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++; if (regHi == op->reg) { tmp = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; emitpcode(PC_MR, tmp, op->reg); op->reg = tmp; } if (is_unsigned(type)) load_immediate(regHi, 0); else emitpcode(PC_SRAWI, regHi, op->reg, 31); op->optype = OpndType_GPRPair; op->regHi = regHi; } void load_floating_constant(short reg, Type *type, double *data) { // do me AFTER } void convert_integer_to_floating(Operand *op, Boolean is_single, short output_reg) { // issue with matching the PC_FSUB/PC_FSUBS ternary Operand temp_op; double d; int const_reg; int tmp_reg; int work_reg; int result_reg; short opcode; symbol_operand(&temp_op, maketemporary((Type *) &stdouble)); coerce_to_addressable(&temp_op); d = *((double *) &int_to_float_cc); const_reg = used_virtual_registers[RegClass_FPR]++; load_floating_constant(const_reg, &stdouble, &d); tmp_reg = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_XORIS, tmp_reg, op->reg, 0x8000); load_store_register(PC_STW, tmp_reg, temp_op.reg, temp_op.object, low_offset); emitpcode(PC_LIS, tmp_reg = used_virtual_registers[RegClass_GPR]++, 0, 0x4330); load_store_register(PC_STW, tmp_reg, temp_op.reg, temp_op.object, high_offset); load_store_register(PC_LFD, work_reg = used_virtual_registers[RegClass_FPR]++, temp_op.reg, temp_op.object, 0); result_reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++; //opcode = PC_FSUB; //if (is_single) // opcode = PC_FSUBS; //opcode = (is_single != 0) ? PC_FSUBS : PC_FSUB; if (is_single != 0) opcode = PC_FSUBS; else opcode = PC_FSUB; emitpcode(opcode, result_reg, work_reg, const_reg); op->optype = OpndType_FPR; op->reg = result_reg; } void convert_unsigned_to_floating(Operand *op, Boolean is_single, short output_reg) { // issue with matching the PC_FSUB/PC_FSUBS ternary Operand temp_op; double d; int const_reg; int tmp_reg; int work_reg; int result_reg; short opcode; symbol_operand(&temp_op, maketemporary((Type *) &stdouble)); coerce_to_addressable(&temp_op); d = *((double *) &uns_to_float_cc); const_reg = used_virtual_registers[RegClass_FPR]++; load_floating_constant(const_reg, &stdouble, &d); load_store_register(PC_STW, op->reg, temp_op.reg, temp_op.object, low_offset); emitpcode(PC_LIS, tmp_reg = used_virtual_registers[RegClass_GPR]++, 0, 0x4330); load_store_register(PC_STW, tmp_reg, temp_op.reg, temp_op.object, high_offset); load_store_register(PC_LFD, work_reg = used_virtual_registers[RegClass_FPR]++, temp_op.reg, temp_op.object, 0); result_reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++; //opcode = PC_FSUB; //if (is_single) // opcode = PC_FSUBS; //opcode = (is_single != 0) ? PC_FSUBS : PC_FSUB; if (is_single != 0) opcode = PC_FSUBS; else opcode = PC_FSUB; emitpcode(opcode, result_reg, work_reg, const_reg); op->optype = OpndType_FPR; op->reg = result_reg; } void convert_floating_to_integer(Operand *op, short output_reg) { Operand temp_op; int tmp_reg; int result_reg; symbol_operand(&temp_op, maketemporary((Type *) &stdouble)); coerce_to_addressable(&temp_op); tmp_reg = used_virtual_registers[RegClass_FPR]++; emitpcode(PC_FCTIWZ, tmp_reg, op->reg); load_store_register(PC_STFD, tmp_reg, temp_op.reg, temp_op.object, 0); result_reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; load_store_register(PC_LWZ, result_reg, temp_op.reg, temp_op.object, low_offset); op->optype = OpndType_GPR; op->reg = result_reg; } void convert_floating_to_unsigned(Operand *op, short output_reg) { static UInt32 used_regs[RegClassMax] = {0, 0, 0, 2, 0}; if (op->reg != 1) emitpcode(PC_FMR, 1, op->reg); branch_subroutine(rt_cvt_fp2unsigned, 0, used_regs); op->optype = OpndType_GPR; op->reg = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_MR, op->reg, 3); } void extract_bitfield(Operand *input_op, TypeBitfield *tbitfield, short output_reg, Operand *output_op) { int r27; int offset; int tmp_reg; int output; offset = tbitfield->unkB; output = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; r27 = tbitfield->unkA + (32 - (tbitfield->bitfieldtype->size * 8)); if (is_unsigned(tbitfield->bitfieldtype)) { emitpcode(PC_RLWINM, output, input_op->reg, (r27 + offset) & 31, 32 - offset, 31); } else if (r27 == 0) { emitpcode(PC_SRAWI, output, input_op->reg, 32 - offset); } else { tmp_reg = used_virtual_registers[RegClass_GPR]++; emitpcode(PC_RLWINM, tmp_reg, input_op->reg, r27 & 31, 0, offset); emitpcode(PC_SRAWI, output, tmp_reg, 32 - offset); } output_op->optype = OpndType_GPR; output_op->reg = output; } void insert_bitfield(short reg, Operand *op, TypeBitfield *tbitfield) { int offset = tbitfield->unkB; int r7 = tbitfield->unkA + (32 - (tbitfield->bitfieldtype->size * 8)); emitpcode(PC_RLWIMI, op->reg, reg, 32 - (r7 + offset), r7, r7 + offset - 1); } void load_address(short dest_reg, Operand *op) { coerce_to_addressable(op); if (op->optype == OpndType_IndirectGPR_ImmOffset) { if (!op->immOffset && !op->object) { if (op->reg != dest_reg) { emitpcode(PC_MR, dest_reg, op->reg); } } else { add_immediate(dest_reg, op->reg, op->object, op->immOffset); } } else if (op->optype == OpndType_IndirectGPR_Indexed) { emitpcode(PC_ADD, dest_reg, op->reg, op->regOffset); } else { #line 1849 CError_FATAL(); } }