diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/BackEnd/PowerPC/CodeGenerator | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-main.tar.gz MWCC-main.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/CodeGenerator')
14 files changed, 25299 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c new file mode 100644 index 0000000..d3bac77 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c @@ -0,0 +1,2437 @@ +#include "compiler/CodeGen.h" +#include "compiler/CCompiler.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/COptimizer.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/Coloring.h" +#include "compiler/CompilerTools.h" +#include "compiler/DumpIR.h" +#include "compiler/Exceptions.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/Intrinsics.h" +#include "compiler/InstrSelection.h" +#include "compiler/GlobalOptimizer.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/Operands.h" +#include "compiler/PCode.h" +#include "compiler/PCodeAssembly.h" +#include "compiler/PCodeInfo.h" +#include "compiler/PCodeListing.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/Peephole.h" +#include "compiler/PPCError.h" +#include "compiler/RegisterInfo.h" +#include "compiler/Scheduler.h" +#include "compiler/StackFrame.h" +#include "compiler/Switch.h" +#include "compiler/TOC.h" +#include "compiler/ValueNumbering.h" +#include "compiler/enode.h" +#include "compiler/objc.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/tokens.h" +#include "compiler/types.h" + +static Macro powcM; +static Macro __powcM; +static Macro ppc_cpu; +static Macro profM; +static Macro hostM; +static Macro bendM; +static Macro _ppc_M; +static Macro longI; +static Macro IEEED; +Macro vecM; +Macro altivecM; +static Macro macM2; +static Macro appleM; +static Macro optM; +static Macro alignM; +static Macro _machM; +static Macro archM; +static Macro dynM; +static Macro ppcM; +Object *gFunction; +static ObjectList *temps; +CLabel *returnlabel; +CLabel *cleanreturnlabel; +Boolean needs_cleanup; +Statement *current_statement; +int has_catch_blocks; +int disable_optimizer; +SInt32 current_linenumber; +Boolean has_altivec_arrays; +short high_reg; +short low_reg; +short high_offset; +short low_offset; +short low_reg2; +short high_reg2; +PCodeLabel *pic_base_pcodelabel; +Object *dyld_stub_binding_helper; +Object *rt_cvt_fp2unsigned; +Object *rt_profile_entry; +Object *rt_profile_exit; +Object *rt_div2i; +Object *rt_div2u; +Object *rt_mod2i; +Object *rt_mod2u; +Object *rt_shr2i; +Object *rt_shr2u; +Object *rt_shl2i; +Object *rt_cvt_ull_dbl; +Object *rt_cvt_sll_dbl; +Object *rt_cvt_ull_flt; +Object *rt_cvt_sll_flt; +Object *rt_cvt_dbl_usll; +static heaperror_t saveheaperror; + +enum { + GPRLimit = 10, + FPRLimit = 13, + VRLimit = 13 +}; + +// forward decls +static void CodeGen_heaperror(void); + +VarInfo *CodeGen_GetNewVarInfo(void) { + VarInfo *vi; + + vi = lalloc(sizeof(VarInfo)); + memclrw(vi, sizeof(VarInfo)); + + vi->deftoken = *CPrep_CurStreamElement(); + vi->varnumber = localcount++; + + return vi; +} + +Object *maketemporary(Type *type) { + ObjectList *list; + Object *obj; + + for (list = temps; list; list = list->next) { + obj = list->object; + if (obj->u.var.uid == 0 && obj->type == type) { + obj->u.var.uid = 1; + return obj; + } + } + + obj = lalloc(sizeof(Object)); + memclrw(obj, sizeof(Object)); + obj->otype = OT_OBJECT; + obj->access = ACCESSPUBLIC; + obj->datatype = DLOCAL; + obj->type = type; + obj->name = CParser_GetUniqueName(); + obj->u.var.info = CodeGen_GetNewVarInfo(); + obj->u.var.uid = 1; + + list = lalloc(sizeof(ObjectList)); + memclrw(list, sizeof(ObjectList)); + list->next = temps; + list->object = obj; + temps = list; + + return obj; +} + +static void free_temporaries(void) { + ObjectList *list; + + for (list = temps; list; list = list->next) + list->object->u.var.uid = 0; +} + +static void allocate_temporaries(void) { + ObjectList *list; + + for (list = temps; list; list = list->next) + assign_local_memory(list->object); +} + +void process_arguments(ArgumentProcessor func, Boolean flag) { + short gpr = 3; + short fpr = 1; + short vr = 2; + Type *type; + ObjectList *list; + + for (list = arguments; list; list = list->next) { + type = list->object->type; + if (IS_TYPE_FLOAT(type)) { + func(list->object, (fpr <= FPRLimit) ? fpr : 0); + fpr++; + if (type->size == 4) + gpr++; + else + gpr += 2; + } else if (IS_TYPE_VECTOR(type)) { + func(list->object, (vr <= VRLimit) ? vr : 0); + vr++; + if (flag) { + if ((vr - 1) == 2) + gpr = 9; + else if ((vr - 1) > 2) + gpr = 11; + } + } else { + func(list->object, (gpr <= GPRLimit) ? gpr : 0); + if (TYPE_FITS_IN_REGISTER(type)) { + if (type->size <= 4) + gpr += 1; + else + gpr += 2; + } else { + gpr += (type->size >> 2); + if (type->size & 3) + gpr++; + } + } + } + + last_argument_register[RegClass_GPR] = gpr - 1; + last_argument_register[RegClass_FPR] = fpr - 1; + last_argument_register[RegClass_VR] = vr - 1; + if (flag) + move_varargs_to_memory(); +} + +static void retain_argument_register(Object *obj, short reg) { + VarInfo *vi = Registers_GetVarInfo(obj); + Type *type = obj->type; + + if (reg && !vi->noregister && vi->used) { + if (TYPE_FITS_IN_REGISTER(type)) { + if (type->size <= 4) { + retain_register(obj, RegClass_GPR, reg); + } else if (reg < GPRLimit) { + if (copts.littleendian) + retain_GPR_pair(obj, reg, reg + 1); + else + retain_GPR_pair(obj, reg + 1, reg); + } + } else if (IS_TYPE_FLOAT(type)) { + retain_register(obj, RegClass_FPR, reg); + } else if (IS_TYPE_VECTOR(type)) { + retain_register(obj, RegClass_VR, reg); + } + } +} + +static void allocate_local_vregs(void) { + ObjectList *list; + Object *obj; + VarInfo *vi; + + if (copts.codegen_pic && uses_globals && assignable_registers[RegClass_GPR]) { + if (assignable_registers[RegClass_GPR]) { + vi = pic_base.u.var.info; + vi->reg = 0; + assign_register_by_type(&pic_base); + pic_base_reg = vi->reg; + CError_ASSERT(497, pic_base_reg); + } else { + CError_FATAL(500); + } + } else { + pic_base_reg = 0; + } + + for (list = exceptionlist; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + + if (vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg) + assign_register_by_type(obj); + } + } + + set_last_exception_registers(); + + for (list = arguments; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + + if (vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg) + assign_register_by_type(obj); + } + } + + for (list = locals; list; list = list->next) { + obj = list->object; + if (!IsTempName(obj->name)) { + vi = Registers_GetVarInfo(obj); + + if (vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg) + assign_register_by_type(obj); + } + } + } + + open_fe_temp_registers(); + + for (list = locals; list; list = list->next) { + obj = list->object; + if (IsTempName(obj->name)) { + vi = Registers_GetVarInfo(obj); + + if (vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg) + assign_register_by_type(obj); + } + } + } + + for (list = toclist; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + + if (!vi->reg && vi->used && vi->usage > 1) + assign_register_by_type(obj); + } +} + +static void allocate_local_GPRs(void) { + ObjectList *list; + Object *obj; + Object *winning_obj; + SInt32 winning_usage; + VarInfo *vi; + Type *type; + + if (copts.codegen_pic && uses_globals && assignable_registers[RegClass_GPR]) { + vi = pic_base.u.var.info; + vi->reg = 0; + assign_register_by_type(&pic_base); + pic_base_reg = vi->reg; + CError_ASSERT(605, pic_base_reg); + } else { + pic_base_reg = 0; + } + + while (assignable_registers[RegClass_GPR]) { + winning_obj = NULL; + winning_usage = -1; + if (!(disable_optimizer & 2)) { + for (list = arguments; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + type = obj->type; + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) { + if (TYPE_FITS_IN_REGISTER(type) && (!TYPE_IS_8BYTES(type) || assignable_registers[RegClass_GPR] >= 2)) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + } + } + if (!(disable_optimizer & 2)) { + for (list = locals; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + type = obj->type; + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) { + if (TYPE_FITS_IN_REGISTER(type) && (!TYPE_IS_8BYTES(type) || assignable_registers[RegClass_GPR] >= 2)) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + } + } + for (list = toclist; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used) { + if (vi->usage >= winning_usage && vi->usage >= 3) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + + if (!winning_obj) + break; + + assign_register_by_type(winning_obj); + CError_ASSERT(698, Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2); + } +} + +static void allocate_local_FPRs(void) { + ObjectList *list; + Object *obj; + Object *winning_obj; + SInt32 winning_usage; + VarInfo *vi; + Type *type; + + while (assignable_registers[RegClass_FPR]) { + winning_obj = NULL; + winning_usage = -1; + if (!(disable_optimizer & 2)) { + for (list = arguments; list; list = list->next) { + obj = list->object; + type = obj->type; + vi = Registers_GetVarInfo(obj); + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) { + if (IS_TYPE_FLOAT(type)) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + } + } + if (!(disable_optimizer & 2)) { + for (list = locals; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) { + if (IS_TYPE_FLOAT(obj->type)) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + } + } + + if (!winning_obj) + break; + + assign_register_by_type(winning_obj); + CError_ASSERT(782, Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2); + } +} + +static void allocate_local_VRs(void) { + ObjectList *list; + Object *obj; + Object *winning_obj; + SInt32 winning_usage; + VarInfo *vi; + + while (assignable_registers[RegClass_VR]) { + winning_obj = NULL; + winning_usage = -1; + if (!(disable_optimizer & 2)) { + for (list = arguments; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) { + if (IS_TYPE_VECTOR(obj->type)) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + } + } + if (!(disable_optimizer & 2)) { + for (list = locals; list; list = list->next) { + obj = list->object; + vi = Registers_GetVarInfo(obj); + if (vi->flags & VarInfoFlag40) + vi->usage = 100000; + if (!vi->reg && vi->used && !vi->noregister) { + if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) { + if (IS_TYPE_VECTOR(obj->type)) { + winning_obj = obj; + winning_usage = vi->usage; + } + } + } + } + } + + if (!winning_obj) + break; + + assign_register_by_type(winning_obj); + CError_ASSERT(846, Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2); + } +} + +static void allocate_locals(void) { + has_altivec_arrays = 0; + + if (!requires_frame && !optimizing) + process_arguments(retain_argument_register, 0); + + if (optimizing) { + allocate_local_vregs(); + } else { + allocate_local_GPRs(); + allocate_local_FPRs(); + allocate_local_VRs(); + } + + assign_locals_to_memory(locals); +} + +void move_assigned_argument(Object *obj, short reg) { + VarInfo *vi; + Type *type; + SInt32 bytesLeft; + SInt32 offset; + + vi = Registers_GetVarInfo(obj); + type = obj->type; + CError_ASSERT(901, obj->datatype == DLOCAL); + + if (!vi->used) + return; + + if (reg) { + if (vi->reg) { + if (TYPE_IS_8BYTES(type)) { + if (copts.littleendian) { + if (vi->reg != reg) + emitpcode(PC_MR, vi->reg, reg); + if (reg < GPRLimit) { + CError_FAIL(916, (vi->regHi == reg) || (vi->reg == (reg + 1))); + if (vi->regHi != (reg + 1)) + emitpcode(PC_MR, vi->regHi, reg + 1); + } else { + load_store_register(PC_LWZ, vi->regHi, local_base_register(obj), obj, high_offset); + } + } else { + if (vi->regHi != reg) + emitpcode(PC_MR, vi->regHi, reg); + if (reg < GPRLimit) { + CError_FAIL(931, (vi->reg == reg) || (vi->regHi == (reg + 1))); + if (vi->reg != (reg + 1)) + emitpcode(PC_MR, vi->reg, reg + 1); + } else { + load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, low_offset); + } + } + } else if (vi->reg != reg) { + if (IS_TYPE_FLOAT(type)) { + emitpcode(PC_FMR, vi->reg, reg); + } else if (IS_TYPE_VECTOR(type)) { + emitpcode(PC_VMR, vi->reg, reg); + } else { + emitpcode(PC_MR, vi->reg, reg); + } + } + } else { + if (IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)) { + load_store_register(PC_STW, reg, local_base_register(obj), obj, 0); + } else if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) { + switch (type->size) { + case 1: + load_store_register(PC_STB, reg, local_base_register(obj), obj, 0); + break; + case 2: + load_store_register(PC_STH, reg, local_base_register(obj), obj, 0); + break; + case 4: + load_store_register(PC_STW, reg, local_base_register(obj), obj, 0); + break; + case 8: + load_store_register(PC_STW, reg, local_base_register(obj), obj, 0); + if (reg < GPRLimit) + load_store_register(PC_STW, reg + 1, local_base_register(obj), obj, 4); + break; + default: + CError_FATAL(993); + } + } else if (IS_TYPE_FLOAT(type)) { + load_store_register((type->size == 4) ? PC_STFS : PC_STFD, reg, local_base_register(obj), obj, 0); + } else if (IS_TYPE_VECTOR(type)) { + load_store_register(PC_STVX, reg, local_base_register(obj), obj, 0); + } else { + bytesLeft = (11 - reg) * 4; + if (bytesLeft > obj->type->size) + bytesLeft = obj->type->size; + offset = 0; + while (bytesLeft > 0) { + load_store_register(PC_STW, reg, local_base_register(obj), obj, offset); + reg++; + offset += 4; + bytesLeft -= 4; + } + } + } + } else { + if (vi->reg) { + if (IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)) { + load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, 0); + } else if (IS_TYPE_FLOAT(type)) { + load_store_register((type->size == 4) ? PC_LFS : PC_LFD, vi->reg, local_base_register(obj), obj, 0); + } else if (IS_TYPE_VECTOR(type)) { + load_store_register(PC_LVX, vi->reg, local_base_register(obj), obj, 0); + } else { + switch (type->size) { + case 1: + load_store_register(PC_LBZ, vi->reg, local_base_register(obj), obj, 0); + break; + case 2: + load_store_register(is_unsigned(type) ? PC_LHZ : PC_LHA, vi->reg, local_base_register(obj), obj, 0); + break; + case 4: + load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, 0); + break; + case 8: + load_store_register(PC_LWZ, vi->regHi, local_base_register(obj), obj, high_offset); + load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, low_offset); + break; + default: + CError_FATAL(1095); + } + } + } else if (!optimizing) { + local_base_register(obj); + } + } +} + +static void load_TOC_pointers(void) { + VarInfo *vi; + Object *obj; + ObjectList *list; + PCode *pc; + Operand opnd; + + if (uses_globals && pic_base_reg) { + pic_base_pcodelabel = makepclabel(); + pc = makepcode(PC_BC, 20, 7, 3, pic_base_pcodelabel); + pcsetlinkbit(pc); + pcsetsideeffects(pc); + appendpcode(pclastblock, pc); + pcbranch(pclastblock, pic_base_pcodelabel); + makepcblock(); + pclabel(pclastblock, pic_base_pcodelabel); + emitpcode(PC_MFLR, pic_base_reg); + } + + memclrw(&opnd, sizeof(Operand)); + for (list = toclist; list; list = list->next) { + obj = list->object; + if ((vi = Registers_GetVarInfo(obj)) && (vi->flags & VarInfoFlag2)) { + switch (obj->datatype) { + case DNONLAZYPTR: + symbol_operand(&opnd, obj); + opnd.optype = OpndType_IndirectSymbol; + if (opnd.optype) + Coerce_to_register(&opnd, TYPE(&void_ptr), vi->reg); + if (opnd.reg != vi->reg) + emitpcode(PC_MR, vi->reg, opnd.reg); + break; + default: + CError_FATAL(1206); + } + } + } +} + +static int has_vararglist(Object *funcobj) { + FuncArg *arg; + + arg = TYPE_FUNC(funcobj->type)->args; + while (arg && arg != &elipsis) + arg = arg->next; + + return (arg == &elipsis); +} + +void assign_labels(Statement *stmt) { + Statement *last; + + last = NULL; + while (stmt) { + if (stmt->type == ST_LABEL && !stmt->label->pclabel) { + if (last && last->type == ST_LABEL) + stmt->label->pclabel = last->label->pclabel; + else + stmt->label->pclabel = makepclabel(); + } + + last = stmt; + stmt = stmt->next; + } +} + +static Boolean islaststatement(Statement *stmt) { + for (stmt = stmt->next; stmt; stmt = stmt->next) { + if (stmt->type > ST_LABEL) + return 0; + } + return 1; +} + +static void newstatement(SInt32 sourceoffset, SInt32 value, int flag) { + PCodeBlock *block = pclastblock; + + pcloopweight = value; + if (!block->pcodeCount) + block->loopWeight = value; + + if (block->pcodeCount > 100) + branch_label(makepclabel()); + + if (flag) + block->flags |= fPCBlockFlag4000; +} + +static void expressionstatement(ENode *expr) { + Operand opnd; + + memclrw(&opnd, sizeof(Operand)); + cgdispatch[expr->type](expr, 0, 0, &opnd); + + if (ENODE_IS(expr, EINDIRECT) && (opnd.flags & OpndFlags_Volatile)) { + if (TYPE_FITS_IN_REGISTER_2(expr->rtype)) { + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, expr->rtype, 0); + } else if (IS_TYPE_FLOAT(expr->rtype)) { + if (opnd.optype != OpndType_FPR) + Coerce_to_fp_register(&opnd, expr->rtype, 0); + } else if (IS_TYPE_VECTOR(expr->rtype)) { + if (opnd.optype != OpndType_VR) + Coerce_to_v_register(&opnd, expr->rtype, 0); + } + } +} + +static void labelstatement(CLabel *label) { + if (!label->pclabel) + label->pclabel = makepclabel(); + if (!label->pclabel->resolved) + branch_label(label->pclabel); + free_temporaries(); +} + +static void gotostatement(CLabel *label) { + if (!label->pclabel) + label->pclabel = makepclabel(); + branch_always(label->pclabel); + free_temporaries(); +} + +static void gotoexpression(ENode *expr) { + Operand opnd; + CodeLabelList *list; + + memclrw(&opnd, sizeof(Operand)); + cgdispatch[expr->type](expr, 0, 0, &opnd); + + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, TYPE(&void_ptr), 0); + CError_ASSERT(1397, opnd.optype == OpndType_GPR); + + for (list = codelabellist; list; list = list->next) + pcbranch(pclastblock, list->label->pclabel); + + emitpcode(PC_MTCTR, opnd.reg); + branch_indirect(NULL); +} + +static void conditionalstatement(ENode *cond, CLabel *label, short truthy) { + Operand opnd; + memclrw(&opnd, sizeof(Operand)); + + cond = evaluate_and_skip_comma(cond); + if (!label->pclabel) + label->pclabel = makepclabel(); + + if (TYPE_IS_8BYTES(cond->data.diadic.right->rtype) || TYPE_IS_8BYTES(cond->data.diadic.left->rtype)) + I8_gen_condition(cond, &opnd, 0); + else + gen_condition(cond, &opnd); + + branch_conditional(opnd.reg, opnd.regOffset, truthy, label->pclabel); + free_temporaries(); +} + +static void returnstatement(ENode *expr, Boolean dont_branch) { + Operand opnd; + Type *type; + memclrw(&opnd, sizeof(Operand)); + + if (expr) { + type = expr->rtype; + if (TYPE_FITS_IN_REGISTER(type)) { + if (TYPE_IS_8BYTES(type)) { + cgdispatch[expr->type](expr, low_reg, high_reg, &opnd); + coerce_to_register_pair(&opnd, type, low_reg, high_reg); + } else { + cgdispatch[expr->type](expr, 3, 0, &opnd); + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, type, 3); + if (opnd.reg != 3) + emitpcode(PC_MR, 3, opnd.reg); + } + } else if (IS_TYPE_FLOAT(type)) { + cgdispatch[expr->type](expr, 1, 0, &opnd); + if (opnd.optype != OpndType_FPR) + Coerce_to_fp_register(&opnd, type, 1); + if (opnd.reg != 1) + emitpcode(PC_FMR, 1, opnd.reg); + } else if (IS_TYPE_VECTOR(type)) { + cgdispatch[expr->type](expr, 2, 0, &opnd); + if (opnd.optype != OpndType_VR) + Coerce_to_v_register(&opnd, type, 2); + if (opnd.reg != 2) + emitpcode(PC_VMR, 2, opnd.reg); + } else { + cgdispatch[expr->type](expr, 0, 0, &opnd); + } + } + + if (!dont_branch) { + if (!returnlabel->pclabel) + returnlabel->pclabel = makepclabel(); + branch_always(returnlabel->pclabel); + free_temporaries(); + } +} + +static void capturestackpointer(Object *obj) { + branch_label(makepclabel()); + CError_ASSERT(1568, obj->datatype == DLOCAL); + + load_store_register(PC_STW, 1, local_base_register(obj), obj, 20); + branch_label(makepclabel()); +} + +static void resetstackpointer(Object *obj) { + PCode *pc; + + CError_ASSERT(1595, obj->datatype == DLOCAL); + + branch_label(makepclabel()); + + load_store_register(PC_LWZ, 0, 1, NULL, 0); + + pc = makepcode(PC_LWZ, 1, local_base_register(obj), obj, 20); + pcsetsideeffects(pc); + appendpcode(pclastblock, pc); + + load_store_register(PC_STW, 0, 1, NULL, 0); + + branch_label(makepclabel()); +} + +static void callprofiler(char *name) { + UInt32 masks[RegClassMax] = {0, 0, 0, 0, 0}; + load_store_register(PC_LWZ, 3, 1, NULL, 0); + load_store_register(PC_LWZ, 3, 3, NULL, 8); + masks[RegClass_GPR] |= (1 << 3); + branch_subroutine(rt_profile_entry, 1, masks); +} + +static void exitprofiler(void) { +} + +void CodeGen_Generator(Statement *statements, Object *func, UInt8 mysteryFlag, Boolean callOnModuleBind) { + Statement *stmt; + Boolean has_varargs; + PCodeBlock *tmp; + SInt32 size; + + CodeGen_InitialSanityCheck(); + if (!saveheaperror) { + saveheaperror = getheaperror(); + setheaperror(CodeGen_heaperror); + } + + if (cparamblkptr->precompile == 1) + CError_Error(CErrorStr180); + + if (!func) { + func = createstaticinitobject(); + } else { +#ifdef CW_CLT + if (func && func->name) + PrintProgressFunction(func->name->name); +#endif + } + + gFunction = func; + has_varargs = has_vararglist(func); + init_endian(); + init_stack_globals(func); + assign_arguments_to_memory(func, mysteryFlag, has_varargs); + + needs_cleanup = 0; + disable_optimizer = 0; + has_catch_blocks = 0; + current_statement = NULL; + current_linenumber = 0; + precomputedoperands = NULL; + switchtables = NULL; + temps = NULL; + initializeexceptiontables(); + returnlabel = cleanreturnlabel = newlabel(); + + if (copts.debuglisting) + DumpIR(statements, func); + + statements = COpt_Optimizer(func, statements); + if (copts.debuglisting) + DumpIR(statements, func); + + resetTOCvarinfo(); + init_registers(); + expandTOCreferences(&statements->next); + if (copts.debuglisting) + DumpIR(statements, func); + + if (copts.profile) { + makes_call = 1; + requires_frame = 1; + } + + initpcode(); + + pclabel(prologue = makepcblock(), makepclabel()); + prologue->flags |= fIsProlog; + + pclabel(tmp = makepcblock(), makepclabel()); + pcbranch(prologue, tmp->labels); + + init_frame_sizes(has_varargs); + allocate_locals(); + process_arguments(move_assigned_argument, has_varargs); + + if (copts.schedule_factor || copts.altivec_model) + branch_label(makepclabel()); + + load_TOC_pointers(); + + if (copts.profile) + callprofiler(CMangler_GetLinkName(func)->name); + + assign_labels(statements->next); + open_temp_registers(); + + for (stmt = statements->next; stmt; stmt = stmt->next) { + current_statement = stmt; + current_linenumber = stmt->sourceoffset; + switch (stmt->type) { + case ST_NOP: + break; + case ST_EXPRESSION: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + expressionstatement(stmt->expr); + break; + case ST_LABEL: + labelstatement(stmt->label); + break; + case ST_IFGOTO: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + conditionalstatement(stmt->expr, stmt->label, 1); + break; + case ST_IFNGOTO: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + conditionalstatement(stmt->expr, stmt->label, 0); + break; + case ST_GOTOEXPR: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + gotoexpression(stmt->expr); + break; + case ST_GOTO: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + gotostatement(stmt->label); + break; + case ST_RETURN: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + returnstatement(stmt->expr, islaststatement(stmt)); + break; + case ST_SWITCH: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + switchstatement(stmt->expr, (SwitchInfo *) stmt->label); + break; + case ST_BEGINCATCH: + capturestackpointer(stmt->expr->data.objref); + break; + case ST_ENDCATCHDTOR: + CError_ASSERT(2056, stmt->expr->data.objref->datatype == DLOCAL); + add_immediate(3, local_base_register(stmt->expr->data.objref), stmt->expr->data.objref, 0); + { + UInt32 masks[RegClassMax] = {0, 0, 0, 0, 0}; + masks[RegClass_GPR] |= 1 << 3; + branch_subroutine(Xecth_func, 1, masks); + } + case ST_ENDCATCH: + resetstackpointer(stmt->expr->data.objref); + break; + case ST_ASM: + if (stmt->expr) { + if (((InlineAsm *) stmt->expr)->flags & IAFlag1) { + CError_FATAL(2076); + } else { + branch_label(makepclabel()); + InlineAsm_TranslateIRtoPCode(stmt); + } + } + break; + case ST_BEGINLOOP: + CError_FATAL(2086); + break; + case ST_ENDLOOP: + CError_FATAL(2090); + break; + default: + CError_FATAL(2094); + } + check_temp_registers(); + } + + close_temp_registers(); + labelstatement(returnlabel); + + current_statement = NULL; + + epilogue = pclastblock; + pclastblock->flags |= fIsEpilogue; + + pccomputepredecessors(); + deleteunreachableblocks(); + + if (copts.report_heap_info > 0) + CodeGen_reportheapinfo(0, CMangler_GetLinkName(func)->name, "before optimization"); + + if (copts.optimizationlevel > 0 && !disable_optimizer) + globallyoptimizepcode(func); + else + pclistblocks(CMangler_GetLinkName(func)->name, "INITIAL CODE"); + + if (copts.schedule_factor == 2) { + if (copts.peephole) + peepholemergeblocks(func, 0); + if (copts.debuglisting) + pclistblocks_start_scheduler(CMangler_GetLinkName(func)->name, "BEFORE SCHEDULING"); + scheduleinstructions(0); + if (copts.debuglisting) + pclistblocks_end_scheduler(); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER INSTRUCTION SCHEDULING"); + } + + if (copts.peephole) { + if (copts.schedule_factor == 0 && copts.optimizationlevel > 1) + peepholemergeblocks(func, 0); + peepholeoptimizeforward(func); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER PEEPHOLE FORWARD"); + } + + allocate_temporaries(); + colorinstructions(func); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER REGISTER COLORING"); + + if (copts.optimizationlevel > 1 && !disable_optimizer) { + removecommonsubexpressions(func, 1); + if (removedcommonsubexpressions && copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER VALUE NUMBERING (POST COLORING)"); + } + + compute_frame_sizes(); + generate_prologue(prologue, has_varargs); + if (copts.profile) + exitprofiler(); + generate_epilogue(epilogue, 1); + + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER GENERATING EPILOGUE, PROLOGUE"); + + if (copts.peephole) { + if (copts.schedule_factor) { + peepholemergeblocks(func, 1); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER MERGING EPILOGUE, PROLOGUE"); + } + peepholeoptimizepcode(func); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER PEEPHOLE OPTIMIZATION"); + } + + if (copts.schedule_factor) { + if (copts.debuglisting) + pclistblocks_start_scheduler(CMangler_GetLinkName(func)->name, "BEFORE SCHEDULING"); + scheduleinstructions(1); + if (copts.debuglisting) + pclistblocks_end_scheduler(); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "FINAL CODE AFTER INSTRUCTION SCHEDULING"); + } else { + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "FINAL CODE"); + } + + size = assemblefunction(func, NULL); + dumpswitchtables(func); + dumpcodelabels(func); + if (callOnModuleBind) + ObjGen_DeclareInitFunction(func); + + pic_base_pcodelabel = NULL; + pic_base_reg = 0; + if (copts.exceptions && requires_frame) + dumpexceptiontables(func, size); + + if (copts.report_heap_info > 0) + CodeGen_reportheapinfo(0, CMangler_GetLinkName(func)->name, "finished"); + + if (saveheaperror) + setheaperror(saveheaperror); +} + +enum { + reg3 = 3, + reg4 = 4 +}; + +void CodeGen_GenVDispatchThunk(Object *thunkobj, Object *obj, SInt32 a, SInt32 b, SInt32 c) { + Boolean save_debug; + Boolean save_peephole; + Boolean save_traceback; + char reg; + + save_debug = copts.filesyminfo; + save_peephole = copts.peephole; + save_traceback = copts.traceback; + + CodeGen_InitialSanityCheck(); + CError_ASSERT(2270, b == 0); + + initpcode(); + makepcblock(); + + if (a) { + reg = CMach_PassResultInHiddenArg(TYPE_FUNC(obj->type)->functype) ? reg4 : reg3; + + if (c >= 0) { + if (!FITS_IN_SHORT(c)) { + emitpcode(PC_ADDIS, 11, 0, 0, HIGH_PART(c)); + if (c) + emitpcode(PC_ADDI, 11, 11, 0, LOW_PART(c)); + } else { + emitpcode(PC_ADDI, 11, 0, 0, c); + } + emitpcode(PC_LWZX, 11, reg, 11); + emitpcode(PC_ADD, reg, reg, 11); + } + + if (!FITS_IN_SHORT(a)) { + emitpcode(PC_ADDIS, reg, reg, 0, HIGH_PART(a)); + if (a) + emitpcode(PC_ADDI, reg, reg, 0, LOW_PART(a)); + } else { + emitpcode(PC_ADDI, reg, reg, 0, a); + } + } + + emitpcode(PC_B, 0, obj); + + copts.filesyminfo = 0; + copts.peephole = 0; + copts.traceback = 0; + assemblefunction(thunkobj, NULL); + copts.filesyminfo = save_debug; + copts.peephole = save_peephole; + copts.traceback = save_traceback; +} + +void CodeGen_SetupRuntimeObjects(void) { + setupaddressing(); + dyld_stub_binding_helper = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_fp2unsigned = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_profile_entry = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_profile_exit = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_div2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_div2u = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_mod2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_mod2u = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_shr2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_shr2u = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_shl2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_ull_dbl = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_sll_dbl = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_ull_flt = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_sll_flt = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_dbl_usll = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + Intrinsics_SetupRuntimeObjects(); +} + +Boolean CodeGen_ReInitRuntimeObjects(Boolean is_precompiler) { + dyld_stub_binding_helper->name = GetHashNameNodeExport("dyld_stub_binding_helper"); + dyld_stub_binding_helper->u.func.linkname = dyld_stub_binding_helper->name; + + rt_cvt_fp2unsigned->name = GetHashNameNodeExport("__cvt_fp2unsigned"); + + rt_profile_entry->name = GetHashNameNodeExport("mcount"); + rt_profile_entry->u.func.linkname = rt_profile_entry->name; + + rt_profile_exit->name = GetHashNameNodeExport("profile_exit"); + + rt_div2i->name = GetHashNameNodeExport("__div2i"); + rt_div2u->name = GetHashNameNodeExport("__div2u"); + rt_mod2i->name = GetHashNameNodeExport("__mod2i"); + rt_mod2u->name = GetHashNameNodeExport("__mod2u"); + rt_shr2i->name = GetHashNameNodeExport("__shr2i"); + rt_shr2u->name = GetHashNameNodeExport("__shr2u"); + rt_shl2i->name = GetHashNameNodeExport("__shl2i"); + + rt_cvt_ull_dbl->name = GetHashNameNodeExport("__cvt_ull_dbl"); + rt_cvt_sll_dbl->name = GetHashNameNodeExport("__cvt_sll_dbl"); + rt_cvt_ull_flt->name = GetHashNameNodeExport("__cvt_ull_flt"); + rt_cvt_sll_flt->name = GetHashNameNodeExport("__cvt_sll_flt"); + rt_cvt_dbl_usll->name = GetHashNameNodeExport("__cvt_dbl_usll"); + + CMach_ReInitRuntimeObjects(); + return Intrinsics_ReInitRuntimeObjects(is_precompiler); +} + +Boolean CodeGen_IsPublicRuntimeObject(Object *obj) { + return Intrinsics_IsPublicRuntimeObject(obj); +} + +void CodeGen_SOMStub(Object *a, Object *b, Object *c, SInt32 offset) { + Boolean save_debug; + Boolean save_peephole; + Boolean save_traceback; + Object *tmp; + Operand opnd; + + save_debug = copts.filesyminfo; + save_peephole = copts.peephole; + save_traceback = copts.traceback; + + CodeGen_InitialSanityCheck(); + memclrw(&opnd, sizeof(Operand)); + CError_ASSERT(2528, offset <= 0x7FFF); + + initpcode(); + makepcblock(); + + tmp = createIndirect(c, 1, 1); + if (tmp) { + opnd.optype = OpndType_Symbol; + opnd.object = tmp; + indirect(&opnd, NULL); + } else { + opnd.optype = OpndType_Symbol; + opnd.object = c; + } + + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, TYPE(&void_ptr), 12); + + if (opnd.optype != OpndType_GPR) { + CError_FATAL(2562); + } else if (opnd.reg != 12) { + emitpcode(PC_MR, 12, opnd.reg); + } + + load_store_register(PC_LWZ, 12, 12, NULL, (short) offset); + emitpcode(PC_B, 0, b); + + copts.filesyminfo = 0; + copts.peephole = 0; + copts.traceback = 0; + assemblefunction(a, NULL); + copts.filesyminfo = save_debug; + copts.peephole = save_peephole; + copts.traceback = save_traceback; +} + +void CodeGen_ParseDeclSpec(HashNameNode *identifier, DeclInfo *declinfo) { + if (!strcmp(identifier->name, "private_extern")) { + declinfo->storageclass = TK_EXTERN; + declinfo->exportflags = EXPORT_FLAGS_INTERNAL; + } else { + CError_Error(CErrorStr176); + } +} + +static void CodeGen_EOLCheck(void) { + short t; + + if (plex() != TK_EOL) { + CPrep_Error(CErrorStr113); + do { + t = plex(); + } while (t != TK_EOL && t != 0); + } +} + +static void schedule_for(int what) { + CPrep_PushOption(OPT_OFFSET(scheduling), what); + if (copts.schedule_factor == 0) + CPrep_PushOption(OPT_OFFSET(schedule_factor), 2); +} + +static void pragma_scheduling(void) { + Boolean *flag; + int cpu; + + tk = plex(); + if (tk == TK_IDENTIFIER) { + flag = &copts.altivec_model; + if (!strcmp(tkidentifier->name, "vger")) { + schedule_for(10); + return; + } else if (!strcmp(tkidentifier->name, "altivec")) { + schedule_for(7); + return; + } else if (!strcmp(tkidentifier->name, "reset")) { + CPrep_PopOption(OPT_OFFSET(scheduling)); + CPrep_PopOption(OPT_OFFSET(schedule_factor)); + return; + } else if (!strcmp(tkidentifier->name, "off")) { + CPrep_PushOption(OPT_OFFSET(schedule_factor), 0); + return; + } else if (!strcmp(tkidentifier->name, "once")) { + CPrep_PushOption(OPT_OFFSET(schedule_factor), 1); + return; + } else if (!strcmp(tkidentifier->name, "twice")) { + CPrep_PushOption(OPT_OFFSET(schedule_factor), 2); + return; + } else if (!strcmp(tkidentifier->name, "on")) { + CPrep_PushOption(OPT_OFFSET(schedule_factor), 2); + return; + } else if (!*flag) { + if (!strcmp(tkidentifier->name, "603e")) { + schedule_for(5); + return; + } else if (!strcmp(tkidentifier->name, "604e")) { + schedule_for(6); + return; + } else if (!strcmp(tkidentifier->name, "PPC603e")) { + schedule_for(5); + return; + } else if (!strcmp(tkidentifier->name, "PPC604e")) { + schedule_for(6); + return; + } + } else { + PPCError_Error(PPCErrorStr115); + return; + } + CPrep_Error(CErrorStr186); + return; + } + + if (tk == TK_INTCONST) { + switch (CInt64_GetULong(&tkintconst)) { + case 601: + cpu = 1; + break; + case 603: + cpu = 2; + break; + case 604: + cpu = 3; + break; + case 750: + cpu = 4; + break; + case 7400: + cpu = 7; + break; + case 7450: + cpu = 10; + break; + case 8240: + case 8260: + cpu = 5; + break; + case 801: + case 821: + case 823: + case 850: + case 860: + cpu = 9; + break; + default: + CPrep_Error(CErrorStr186); + return; + } + schedule_for(cpu); + return; + } + + if (copts.warn_illpragma) + CPrep_Warning(CErrorStr186); +} + +static SInt32 CodeGen_ParseLongIntegerORonORoff(void) { + SInt32 result; + short t; + + result = 0; + t = plex(); + if (t == TK_INTCONST) { + if (!tkintconst.hi) + result = CInt64_GetULong(&tkintconst); + else + CPrep_Error(CErrorStr154); + CodeGen_EOLCheck(); + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "on")) { + CodeGen_EOLCheck(); + return 1; + } + if (!strcmp(tkidentifier->name, "off")) { + CodeGen_EOLCheck(); + return 0; + } + if (copts.warn_illpragma) + CPrep_Warning(CErrorStr186); + return 0; + } else { + if (copts.warn_illpragma) + CPrep_Warning(CErrorStr186); + } + + return result; +} + +void CodeGen_ParsePragma(HashNameNode *name) { + short t; + SInt32 value; + char *str; + NameSpace *nspace; + NameSpaceObjectList *list; + + if (!strcmp(name->name, "debuglisting")) { + copts.debuglisting = CodeGen_ParseLongIntegerORonORoff(); + return; + } + + if (!strcmp(name->name, "report_heap_info")) { + t = plex(); + if (t == TK_INTCONST) { + copts.report_heap_info = CInt64_GetULong(&tkintconst); + if (copts.report_heap_info < 0) { + copts.report_heap_info = 0; + CError_Error(CErrorStr186); + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.report_heap_info = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.report_heap_info = 1; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "scheduling")) { + pragma_scheduling(); + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "ppc_unroll_speculative")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.unroll_speculative = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.unroll_speculative = 1; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "ppc_unroll_instructions_limit")) { + t = plex(); + if (t == TK_INTCONST) { + copts.unroll_instr_limit = CInt64_GetULong(&tkintconst); + if (copts.unroll_instr_limit < 0) { + copts.unroll_instr_limit = 0; + CError_Error(CErrorStr186); + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.unroll_instr_limit = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.unroll_instr_limit = 70; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "gen_fsel")) { + t = plex(); + if (t == TK_INTCONST) { + value = CInt64_GetULong(&tkintconst); + if (value < 0) { + copts.gen_fsel = 0; + CError_Error(CErrorStr186); + } else if (value > 255) { + copts.gen_fsel = 255; + CError_Error(CErrorStr186); + } else { + copts.gen_fsel = value; + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.gen_fsel = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.gen_fsel = 10; + } else if (!strcmp(tkidentifier->name, "always")) { + copts.gen_fsel = 255; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "ppc_unroll_factor_limit")) { + t = plex(); + if (t == TK_INTCONST) { + copts.unroll_factor_limit = CInt64_GetULong(&tkintconst); + if (copts.unroll_factor_limit < 0) { + copts.unroll_factor_limit = 0; + CError_Error(CErrorStr186); + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.unroll_factor_limit = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.unroll_factor_limit = 10; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "altivec_model")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.altivec_model = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.altivec_model = 1; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "altivec_vrsave")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + CPrep_PushOption(OPT_OFFSET(altivec_vrsave), 0); + } else if (!strcmp(tkidentifier->name, "on")) { + CPrep_PushOption(OPT_OFFSET(altivec_vrsave), 1); + } else if (!strcmp(tkidentifier->name, "allon")) { + CPrep_PushOption(OPT_OFFSET(altivec_vrsave), 2); + } else if (!strcmp(tkidentifier->name, "reset")) { + CPrep_PopOption(OPT_OFFSET(altivec_vrsave)); + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "function_align")) { + t = plex(); + if (t == TK_INTCONST) { + value = CInt64_GetULong(&tkintconst); + switch (value) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + CPrep_PushOption(OPT_OFFSET(function_align), value); + break; + default: + PPCError_Warning(PPCErrorStr161); + CodeGen_EOLCheck(); + return; + } + } else if (t == TK_IDENTIFIER && !strcmp(tkidentifier->name, "reset")) { + CPrep_PopOption(OPT_OFFSET(function_align)); + } else { + PPCError_Warning(PPCErrorStr161); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "processor")) { + if (cscope_currentfunc) { + PPCError_Warning(PPCErrorStr156, "pragma processor"); + return; + } + t = plex(); + if (t == TK_INTCONST) { + switch (CInt64_GetULong(&tkintconst)) { + case 401: + copts.processor = 0; + break; + case 403: + copts.processor = 1; + break; + case 505: + copts.processor = 2; + break; + case 509: + copts.processor = 3; + break; + case 555: + copts.processor = 4; + break; + case 556: + copts.processor = 25; + break; + case 565: + copts.processor = 26; + break; + case 601: + copts.processor = 5; + break; + case 602: + copts.processor = 6; + break; + case 8240: + copts.processor = 18; + break; + case 8260: + copts.processor = 19; + break; + case 603: + copts.processor = 7; + break; + case 604: + copts.processor = 9; + break; + case 740: + copts.processor = 11; + break; + case 750: + copts.processor = 12; + break; + case 801: + copts.processor = 13; + break; + case 821: + copts.processor = 14; + break; + case 823: + copts.processor = 15; + break; + case 850: + copts.processor = 16; + break; + case 860: + copts.processor = 17; + break; + case 7400: + copts.processor = 21; + break; + default: + PPCError_Warning(PPCErrorStr208); + CodeGen_EOLCheck(); + return; + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "generic")) + copts.processor = 20; + else if (!strcmp(tkidentifier->name, "603e")) + copts.processor = 8; + else if (!strcmp(tkidentifier->name, "604e")) + copts.processor = 10; + else if (!strcmp(tkidentifier->name, "PPC603e")) + copts.processor = 8; + else if (!strcmp(tkidentifier->name, "PPC604e")) + copts.processor = 10; + else + PPCError_Warning(PPCErrorStr208); + } else { + PPCError_Warning(PPCErrorStr208); + } + + if ((str = CMach_GetCPU())) + CPrep_InsertSpecialMacro(&ppc_cpu, str); + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "min_struct_alignment")) { + t = plex(); + if (t == TK_INTCONST) { + value = CInt64_GetULong(&tkintconst); + switch (value) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + CPrep_PushOption(OPT_OFFSET(min_struct_alignment), value); + break; + default: + PPCError_Warning(PPCErrorStr191); + CodeGen_EOLCheck(); + return; + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "reset")) + CPrep_PopOption(OPT_OFFSET(min_struct_alignment)); + else if (!strcmp(tkidentifier->name, "on")) + CPrep_PushOption(OPT_OFFSET(min_struct_alignment), 4); + else if (!strcmp(tkidentifier->name, "off")) + CPrep_PushOption(OPT_OFFSET(min_struct_alignment), 1); + } else { + PPCError_Warning(PPCErrorStr161); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "tvectors")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + no_descriptors = 1; + } else if (!strcmp(tkidentifier->name, "on")) { + no_descriptors = 0; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "dynamic")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.codegen_dynamic = 0; + copts.codegen_pic = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.codegen_dynamic = 1; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "pic")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.codegen_pic = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.codegen_pic = 1; + if (!copts.codegen_dynamic) { + PPCError_Error(PPCErrorStr189); + copts.codegen_pic = 0; + } + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "implicit_templates")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.no_implicit_templates = 1; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.no_implicit_templates = 0; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "common")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.no_common = 1; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.no_common = 0; + } else { + CError_Error(CErrorStr186); + return; + } + } else { + CError_Error(CErrorStr186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "CALL_ON_MODULE_BIND")) { + if (plex() == TK_IDENTIFIER) { + for (nspace = cscope_current; nspace; nspace = nspace->parent) { + list = CScope_GetLocalObject(nspace, tkidentifier); + if (list && list->object->otype == OT_OBJECT && OBJECT(list->object)->datatype == DFUNC) { + ObjGen_DeclareInitFunction(OBJECT(list->object)); + break; + } + } + } else { + CError_Error(CErrorStr186); + } + + CodeGen_EOLCheck(); + return; + } + + if (copts.warn_illpragma) + CPrep_Warning(CErrorStr186); + + if (plex() != TK_EOL) { + do { + t = plex(); + } while (t != TK_EOL && t != 0); + } +} + +void CodeGen_UpdateObject(Object *object) { + if (object->datatype == DDATA && object->section == SECT_DEFAULT && object == rt_ptmf_null) + object->sclass = TK_EXTERN; +} + +void CodeGen_UpdateBackEndOptions(void) { + copts.globaloptimizer = 1; +} + +SInt32 CodeGen_objc_method_self_offset(ObjCMethod *meth) { + SInt32 size; + + if (!meth->return_type) { + size = 4; + } else if ( + IS_TYPE_ARRAY(meth->return_type) || + IS_TYPE_NONVECTOR_STRUCT(meth->return_type) || + IS_TYPE_CLASS(meth->return_type) || + IS_TYPE_12BYTES_MEMBERPOINTER(meth->return_type) + ) + { + size = 8; + } else { + size = meth->return_type->size; + } + + if (size == 0) + size = 1; + + return (size + 3) & ~3; +} + +SInt32 CodeGen_objc_method_sel_offset(ObjCMethod *meth) { + return (CodeGen_objc_method_self_offset(meth) + 7) & ~3; +} + +SInt32 CodeGen_objc_method_arg_offset(ObjCMethod *meth, ObjCMethodArg *arg) { + SInt32 pos; + ObjCMethodArg *scan; + + pos = CodeGen_objc_method_sel_offset(meth) + 4; + for (scan = meth->selector_args; scan; scan = scan->next) { + if (scan == arg) + return pos; + + if (scan->type == NULL) + pos += 4; + else + pos += scan->type->size; + + pos = (pos + 3) & ~3; + } + + return 0; +} + +SInt32 CodeGen_objc_method_args_size(ObjCMethod *meth) { + SInt32 size; + ObjCMethodArg *scan; + + size = CodeGen_objc_method_self_offset(meth); + for (scan = meth->selector_args; scan; scan = scan->next) { + if (scan->next == NULL && scan->type == NULL) + return size; + + size = (size + 3) & ~3; + if (scan->type == NULL) + size += 4; + else + size += scan->type->size; + } + + return size; +} + +ENode *CodeGen_HandleIntrinsicCall(Object *func, ENodeList *arg_exprs) { + return Intrinsics_HandleIntrinsicCall(func, arg_exprs); +} + +ENode *CodeGen_HandleTypeCast(ENode *expr, Type *type, UInt32 qual) { + short flags; + + if (copts.altivec_model) { + flags = qual & ENODE_FLAG_QUALS; + if (IS_TYPE_STRUCT(type) && IS_TYPE_STRUCT(expr->rtype) && expr->flags == flags) { + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + case STRUCT_VECTOR_FLOAT: + case STRUCT_VECTOR_PIXEL: + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = flags; + return expr; + } + } + } + + return NULL; +} + +short CodeGen_AssignCheck(const ENode *expr, const Type *type, Boolean flag1, Boolean flag2) { + short result; + const Type *exprtype = expr->rtype; + + if ( + copts.altivec_model && + IS_TYPE_VECTOR(type) && + IS_TYPE_VECTOR(exprtype) && + TYPE_STRUCT(type)->stype == TYPE_STRUCT(exprtype)->stype + ) + result = CheckResult3; + else + result = CheckResult0; + return result; +} + +Boolean CodeGen_CollapseVectorExpression(ENode *expr, MWVector128 *vec, Type *type) { + // this function is a mess and needs lots of fixing + Boolean result; + //int count; + int i; + ENode *escan; + + result = 0; + for (i = 0; i < 4; i++) + vec->ul[i] = 0; + + if (ENODE_IS(expr, ECOMMA)) { + i = 0; + escan = expr; + while (ENODE_IS(escan, ECOMMA)) { + i++; + escan = escan->data.diadic.left; + } + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + if (i < 15) { + PPCError_Error(PPCErrorStr110, type, 0); + } else if (i > 15) { + PPCError_Error(PPCErrorStr111, type, 0); + } else { + escan = expr; + i = 15; + while (ENODE_IS(escan, ECOMMA)) { + CInt64 v; + expr = escan->data.diadic.right; + v = expr->data.intval; + if (!ENODE_IS(expr, EINTCONST)) { + PPCError_Error(PPCErrorStr112); + break; + } + + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UCHAR) { + if (!CInt64_IsInURange(v, 1)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 1)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + + vec->uc[i--] = (UInt8) v.lo; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EINTCONST)) { + CInt64 v = escan->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UCHAR) { + if (!CInt64_IsInURange(v, 1)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 1)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + vec->uc[0] = (UInt8) v.lo; + } else { + PPCError_Error(PPCErrorStr112); + break; + } + result = 1; + } + break; + + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_PIXEL: + if (i < 7) { + PPCError_Error(PPCErrorStr110, type, 0); + } else if (i > 7) { + PPCError_Error(PPCErrorStr111, type, 0); + } else { + escan = expr; + i = 7; + while (ENODE_IS(escan, ECOMMA)) { + ENode *e = escan->data.diadic.right; + CInt64 v = e->data.intval; + if (!ENODE_IS(e, EINTCONST)) { + PPCError_Error(PPCErrorStr112); + break; + } + + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_USHORT || TYPE_STRUCT(type)->stype == STRUCT_VECTOR_PIXEL) { + if (!CInt64_IsInURange(v, 2)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 2)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + + vec->us[i--] = (UInt16) e->data.intval.lo; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EINTCONST)) { + CInt64 v = escan->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_USHORT || TYPE_STRUCT(type)->stype == STRUCT_VECTOR_PIXEL) { + if (!CInt64_IsInURange(v, 2)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 2)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + vec->us[0] = (UInt16) v.lo; + } else { + PPCError_Error(PPCErrorStr112); + break; + } + result = 1; + } + break; + + case STRUCT_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + if (i < 3) { + PPCError_Error(PPCErrorStr110, type, 0); + } else if (i > 3) { + PPCError_Error(PPCErrorStr111, type, 0); + } else { + escan = expr; + i = 3; + while (ENODE_IS(escan, ECOMMA)) { + CInt64 v; + expr = escan->data.diadic.right; + v = expr->data.intval; + if (!ENODE_IS(expr, EINTCONST)) { + PPCError_Error(PPCErrorStr112); + break; + } + + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UINT) { + if (!CInt64_IsInURange(v, 4)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 4)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + + vec->ul[i--] = expr->data.intval.lo; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EINTCONST)) { + CInt64 v = escan->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UINT) { + if (!CInt64_IsInURange(v, 4)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 4)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + vec->ul[0] = v.lo; + } else { + PPCError_Error(PPCErrorStr112); + break; + } + result = 1; + } + break; + + case STRUCT_VECTOR_FLOAT: + if (i < 3) { + PPCError_Error(PPCErrorStr110, type, 0); + } else if (i > 3) { + PPCError_Error(PPCErrorStr111, type, 0); + } else { + Float fv; + escan = expr; + i = 3; + while (ENODE_IS(escan, ECOMMA)) { + expr = escan->data.diadic.right; + if (ENODE_IS(expr, EFLOATCONST)) { + fv = expr->data.floatval; + } else if (ENODE_IS(escan->data.diadic.right, EINTCONST)) { + fv = CMach_CalcFloatConvertFromInt(expr->rtype, + expr->data.intval); + } else { + PPCError_Error(PPCErrorStr112); + break; + } + + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[i]); + i--; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EFLOATCONST)) { + fv = escan->data.floatval; + } else if (ENODE_IS(escan, EINTCONST)) { + fv = CMach_CalcFloatConvertFromInt(escan->rtype, escan->data.intval); + } else { + PPCError_Error(PPCErrorStr112); + break; + } + + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[0]); + result = 1; + } + break; + } + } else if (ENODE_IS(expr, EINTCONST)) { + int i = 0; + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + { + CInt64 v = expr->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UCHAR) { + if (!CInt64_IsInURange(v, 1)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 1)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + while (i < 16) + vec->uc[i++] = (UInt8) v.lo; + result = 1; + break; + } + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_PIXEL: + { + CInt64 v = expr->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_USHORT || TYPE_STRUCT(type)->stype == STRUCT_VECTOR_PIXEL) { + if (!CInt64_IsInURange(v, 2)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 2)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + while (i < 8) + vec->us[i++] = (UInt16) v.lo; + result = 1; + break; + } + case STRUCT_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + { + CInt64 v = expr->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UINT) { + if (!CInt64_IsInURange(v, 4)) + PPCError_Warning(PPCErrorStr113, type, 0); + } else { + if (!CInt64_IsInRange(v, 4)) + PPCError_Warning(PPCErrorStr113, type, 0); + } + } + while (i < 4) + vec->ul[i++] = v.lo; + result = 1; + break; + } + case STRUCT_VECTOR_FLOAT: + { + Float fv; + if (!CInt64_IsInRange(expr->data.intval, 4)) { + PPCError_Error(PPCErrorStr112); + break; + } + fv = CMach_CalcFloatConvertFromInt(expr->rtype, expr->data.intval); + for (; i < 4; i++) + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[i]); + result = 1; + break; + } + default: + PPCError_Error(PPCErrorStr112); + } + } else if (ENODE_IS(expr, EFLOATCONST)) { + switch (TYPE_STRUCT(type)->stype) { + default: + PPCError_Error(PPCErrorStr112); + break; + case STRUCT_VECTOR_FLOAT: + { + Float fv; + i = 0; + fv = expr->data.floatval; + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[0]); + while (i < 4) + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[i++]); + result = 1; + break; + } + } + } else if (ENODE_IS2(expr, EINDIRECT, EFUNCCALL)) { + if (!IS_TYPE_STRUCT(expr->rtype)) + PPCError_Error(PPCErrorStr112); + } else if (!ENODE_IS(expr, EVECTOR128CONST)) { + PPCError_Error(PPCErrorStr112); + } + + return result; +} + +void CodeGen_InsertSpecialMacros(void) { + char *str; + + CPrep_InsertSpecialMacro(&vecM, "__VEC__"); + CPrep_InsertSpecialMacro(&altivecM, "__ALTIVEC__"); + CPrep_InsertSpecialMacro(&powcM, "powerc"); + CPrep_InsertSpecialMacro(&__powcM, "__powerc"); + CPrep_InsertSpecialMacro(&hostM, "__POWERPC__"); + CPrep_InsertSpecialMacro(&_ppc_M, "__ppc__"); + + CPrep_InsertSpecialMacro(&bendM, "__BIG_ENDIAN__"); + + if ((str = CMach_GetCPU())) + CPrep_InsertSpecialMacro(&ppc_cpu, str); + + CPrep_InsertSpecialMacro(&profM, "__profile__"); + CPrep_InsertSpecialMacro(&longI, "__fourbyteints__"); + CPrep_InsertSpecialMacro(&IEEED, "__IEEEdoubles__"); + CPrep_InsertSpecialMacro(&macM2, "__MACOS__"); + CPrep_InsertSpecialMacro(&appleM, "__APPLE__"); + CPrep_InsertSpecialMacro(&_machM, "__MACH__"); + CPrep_InsertSpecialMacro(&archM, "__ARCHITECTURE__"); + + if (copts.optimizationlevel > 0) + CPrep_InsertSpecialMacro(&optM, "__OPTIMIZE__"); + + if (copts.codegen_dynamic) + CPrep_InsertSpecialMacro(&dynM, "__DYNAMIC__"); + if (!copts.codegen_dynamic) + CPrep_InsertSpecialMacro(&dynM, "__STATIC__"); + + if (copts.oldalignment && copts.structalignment == AlignMode2_PPC) + CPrep_InsertSpecialMacro(&alignM, "__NATURAL_ALIGNMENT__"); + + if (!copts.ANSIstrict) + CPrep_InsertSpecialMacro(&ppcM, "ppc"); +} + +char *CodeGen_ExpandSpecialMacro(Macro *macro) { + if (macro == &vecM) return "10205"; + if (macro == &altivecM) return "100000000"; + if (macro == &powcM) return "1"; + if (macro == &__powcM) return "1"; + if (macro == &hostM) return "1"; + if (macro == &bendM) return "1"; + if (macro == &_ppc_M) return "1"; + if (CMach_GetCPU() && macro == &ppc_cpu) return "1"; + if (macro == &profM) return copts.profile ? "1" : "0"; + if (macro == &longI) return "1"; + if (macro == &IEEED) return "1"; + if (macro == &macM2) return "1"; + if (macro == &appleM) return "1"; + if (macro == &alignM) return "1"; + + if (macro == &optM) { + switch (copts.optimizationlevel) { + case 1: return "1"; + case 2: return "2"; + case 3: return "3"; + case 4: return "4"; + case 0: return "0"; + default: return "9"; + } + } + + if (macro == &_machM) return "1"; + if (macro == &archM) return "ppc"; + if (macro == &dynM) return "1"; + if (!copts.ANSIstrict && macro == &ppcM) return "1"; + if (macro == &_ppc_M) return "1"; + + CError_FATAL(4801); + return "0"; +} + +void CodeGen_reportheapinfo(Boolean release_flag, char *name, char *text) { + HeapInfo o; + HeapInfo all; + + CTool_GetHeapInfo(&o, 3); + CTool_GetHeapInfo(&all, 5); + + if (release_flag) + releaseoheap(); + + PPCError_Message( + "%n:%u HEAP STATUS\n" + " optimizer: %i blocks, used: %i, free: %i, total: %i, largest free: %i\n" + " all: %i blocks, used: %i, free: %i, total: %i, largest free: %i", + name, text, + o.blocks, o.total_size - o.total_free, o.total_free, o.total_size, o.largest_free_block, + all.blocks, all.total_size - all.total_free, all.total_free, all.total_size, all.largest_free_block + ); +} + +static void CodeGen_heaperror(void) { + CodeGen_reportheapinfo(1, "?", "out of memory"); + if (saveheaperror) { + setheaperror(saveheaperror); + saveheaperror(); + } +} + +void CodeGen_InitialSanityCheck(void) { +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c new file mode 100644 index 0000000..14627cf --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c @@ -0,0 +1,857 @@ +#include "compiler/Exceptions.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CInit.h" +#include "compiler/CFunc.h" +#include "compiler/CParser.h" +#include "compiler/CompilerTools.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/PCode.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/RegisterInfo.h" +#include "compiler/StackFrame.h" +#include "compiler/objects.h" + +static PCAction *pc_actions; +static PCAction *last_pc_action; +EANode *DAG[EAT_NACTIONS]; +static GList exceptmodule; +static OLinkList *except_refs; +static OLinkList *last_except_ref; + +static EANode *makeEAnode(ExceptionAction *ea) { + EANode *prev; + EANode *node; + + for (node = DAG[ea->type]; node; node = node->dagListNext) { + if (node->action == ea) + return node; + } + + if (ea->prev) + prev = makeEAnode(ea->prev); + else + prev = NULL; + + for (node = DAG[ea->type]; node; node = node->dagListNext) { + if (node->prev == prev && CExcept_ActionCompare(node->action, ea)) + return node; + } + + node = lalloc(sizeof(EANode)); + node->prev = prev; + node->action = ea; + node->count = 0; + node->xE = 0; + + node->dagListNext = DAG[ea->type]; + DAG[ea->type] = node; + + if (prev) + prev->count++; + return node; +} + +static void addrelocation(Object *obj, SInt32 offset) { + OLinkList *ref; + + ref = lalloc(sizeof(OLinkList)); + ref->next = NULL; + ref->obj = obj; + ref->offset = offset; + ref->somevalue = 0; + if (except_refs) + last_except_ref->next = ref; + else + except_refs = ref; + last_except_ref = ref; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct AABC { + UInt8 a; + UInt8 b; + UInt16 c; + UInt32 d; +} AABC; + +typedef struct AACC { + UInt8 a; + UInt8 b; + UInt32 c; + UInt32 d; +} AACC; + +typedef struct AABBC { + UInt8 a; + UInt8 b; + UInt16 c; + UInt16 d; + UInt32 e; +} AABBC; + +typedef struct AABCC { + UInt8 a; + UInt8 b; + UInt16 c; + UInt32 d; + UInt32 e; +} AABCC; + +typedef struct AACCC { + UInt8 a; + UInt8 b; + UInt32 c; + UInt32 d; + UInt32 e; +} AACCC; + +typedef struct AABBBC { + UInt8 a; + UInt8 b; + UInt16 c; + UInt16 d; + UInt16 e; + UInt32 f; +} AABBBC; + +typedef struct AABBCC { + UInt8 a; + UInt8 b; + UInt16 c; + UInt16 d; + UInt32 e; + UInt32 f; +} AABBCC; + +typedef struct AACCCC { + UInt8 a; + UInt8 b; + UInt32 c; + UInt32 d; + UInt32 e; + UInt32 f; +} AACCCC; + +typedef struct AABCCCC { + UInt8 a; + UInt8 b; + UInt16 c; + UInt32 d; + UInt32 e; + UInt32 f; + UInt32 g; +} AABCCCC; + +typedef struct AACCCCC { + UInt8 a; + UInt8 b; + UInt32 c; + UInt32 d; + UInt32 e; + UInt32 f; + UInt32 g; +} AACCCCC; + +typedef struct AAB { + UInt8 a; + UInt8 b; + UInt16 c; +} AAB; + +typedef struct AAC { + UInt8 a; + UInt8 b; + UInt32 c; +} AAC; + +typedef struct AA { + UInt8 a; + UInt8 b; +} AA; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static void allocateactioninfo(EANode *node) { + ExceptionAction *ea; + SInt32 offset; + UInt32 flag26; + int reg; + int reg2; + + while (node && (node->xE == 0 || node->prev == NULL)) { + offset = exceptmodule.size; + if (node->xE == 0) + node->xE = offset; + + flag26 = node->prev ? 0 : 0x80; + + ea = node->action; + + switch (ea->type) { + case EAT_NOP: + CError_FATAL(146); + break; + case EAT_DESTROYLOCAL: { + if (local_is_16bit_offset(ea->data.destroy_local.local)) { + AABC e; + e.a = flag26 | 2; + e.b = 0; + e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local.local)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local.dtor, offset + 4); + } else { + AACC e; + e.a = flag26 | 0x11; + e.b = 0; + e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local.local)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local.dtor, offset + 6); + } + break; + } + case EAT_DESTROYLOCALCOND: { + reg = OBJECT_REG(ea->data.destroy_local_cond.cond); + if ( + (reg || local_is_16bit_offset(ea->data.destroy_local_cond.cond)) && + local_is_16bit_offset(ea->data.destroy_local_cond.local) + ) + { + AABBC e; + e.a = flag26 | 3; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_local_cond.cond)); + e.d = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local_cond.local)); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_cond.dtor, offset + 6); + } else { + AACCC e; + e.a = flag26 | 0x12; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_local_cond.cond)); + e.d = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local_cond.local)); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_cond.dtor, offset + 10); + } + break; + } + case EAT_DESTROYLOCALOFFSET: { + if (local_is_16bit_offset(ea->data.destroy_local_offset.local)) { + AABC e; + e.a = flag26 | 2; + e.b = 0; + e.c = CTool_EndianConvertWord16(ea->data.destroy_local_offset.offset + local_offset_16(ea->data.destroy_local_offset.local)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_offset.dtor, offset + 4); + } else { + AACC e; + e.a = flag26 | 0x11; + e.b = 0; + e.c = CTool_EndianConvertWord32(ea->data.destroy_local_offset.offset + local_offset_32(ea->data.destroy_local_offset.local)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_offset.dtor, offset + 6); + } + break; + } + case EAT_DESTROYLOCALPOINTER: { + reg = OBJECT_REG(ea->data.destroy_local_pointer.pointer); + if (reg || local_is_16bit_offset(ea->data.destroy_local_pointer.pointer)) { + AABC e; + e.a = flag26 | 4; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_local_pointer.pointer)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_pointer.dtor, offset + 4); + } else { + AACC e; + e.a = flag26 | 0x13; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_local_pointer.pointer)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_pointer.dtor, offset + 6); + } + break; + } + case EAT_DESTROYLOCALARRAY: { + if (local_is_16bit_offset(ea->data.destroy_local_array.localarray)) { + AABBBC e; + e.a = flag26 | 5; + e.b = 0; + e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local_array.localarray)); + e.d = CTool_EndianConvertWord16(ea->data.destroy_local_array.elements); + e.e = CTool_EndianConvertWord16(ea->data.destroy_local_array.element_size); + e.f = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_array.dtor, offset + 8); + } else { + AACCCC e; + e.a = flag26 | 0x14; + e.b = 0; + e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local_array.localarray)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_local_array.elements); + e.e = CTool_EndianConvertWord32(ea->data.destroy_local_array.element_size); + e.f = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_local_array.dtor, offset + 14); + } + break; + } + case EAT_DESTROYMEMBER: { + reg = OBJECT_REG(ea->data.destroy_member.objectptr); + if (reg || local_is_16bit_offset(ea->data.destroy_member.objectptr)) { + AABCC e; + e.a = flag26 | 7; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member.objectptr)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member.dtor, offset + 8); + } else { + AACCC e; + e.a = flag26 | 0x16; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member.objectptr)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member.dtor, offset + 10); + } + break; + } + case EAT_DESTROYBASE: { + reg = OBJECT_REG(ea->data.destroy_member.objectptr); + if (reg || local_is_16bit_offset(ea->data.destroy_member.objectptr)) { + AABCC e; + e.a = flag26 | 6; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member.objectptr)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member.dtor, offset + 8); + } else { + AACCC e; + e.a = flag26 | 0x15; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member.objectptr)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member.dtor, offset + 10); + } + break; + } + case EAT_DESTROYMEMBERCOND: { + reg = OBJECT_REG(ea->data.destroy_member_cond.cond); + reg2 = OBJECT_REG(ea->data.destroy_member_cond.objectptr); + if ( + (reg || local_is_16bit_offset(ea->data.destroy_member_cond.cond)) && + (reg2 || local_is_16bit_offset(ea->data.destroy_member_cond.objectptr)) + ) + { + AABBCC e; + e.a = flag26 | 8; + e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6); + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member_cond.cond)); + e.d = CTool_EndianConvertWord16(reg2 ? reg2 : local_offset_16(ea->data.destroy_member_cond.objectptr)); + e.e = CTool_EndianConvertWord32(ea->data.destroy_member_cond.offset); + e.f = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member_cond.dtor, offset + 10); + } else { + AACCCC e; + e.a = flag26 | 0x17; + e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6); + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member_cond.cond)); + e.d = CTool_EndianConvertWord32(reg2 ? reg2 : local_offset_32(ea->data.destroy_member_cond.objectptr)); + e.e = CTool_EndianConvertWord32(ea->data.destroy_member_cond.offset); + e.f = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member_cond.dtor, offset + 14); + } + break; + } + case EAT_DESTROYMEMBERARRAY: { + reg = OBJECT_REG(ea->data.destroy_member_array.objectptr); + if (reg || local_is_16bit_offset(ea->data.destroy_member_array.objectptr)) { + AABCCCC e; + e.a = flag26 | 9; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member_array.objectptr)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_member_array.offset); + e.e = CTool_EndianConvertWord32(ea->data.destroy_member_array.elements); + e.f = CTool_EndianConvertWord32(ea->data.destroy_member_array.element_size); + e.g = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member_array.dtor, offset + 16); + } else { + AACCCCC e; + e.a = flag26 | 0x18; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member_array.objectptr)); + e.d = CTool_EndianConvertWord32(ea->data.destroy_member_array.offset); + e.e = CTool_EndianConvertWord32(ea->data.destroy_member_array.elements); + e.f = CTool_EndianConvertWord32(ea->data.destroy_member_array.element_size); + e.g = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.destroy_member_array.dtor, offset + 18); + } + break; + } + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: { + reg = OBJECT_REG(ea->data.delete_pointer.pointerobject); + if (reg || local_is_16bit_offset(ea->data.delete_pointer.pointerobject)) { + AABC e; + e.a = flag26 | 0xA; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.delete_pointer.pointerobject)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.delete_pointer.deletefunc, offset + 4); + } else { + AACC e; + e.a = flag26 | 0x19; + e.b = (reg != 0) << 7; + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.delete_pointer.pointerobject)); + e.d = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.delete_pointer.deletefunc, offset + 6); + } + break; + } + case EAT_DELETEPOINTERCOND: { + reg = OBJECT_REG(ea->data.delete_pointer_cond.cond); + reg2 = OBJECT_REG(ea->data.delete_pointer_cond.pointerobject); + if ( + (reg || local_is_16bit_offset(ea->data.delete_pointer_cond.cond)) && + (reg2 || local_is_16bit_offset(ea->data.delete_pointer_cond.pointerobject)) + ) + { + AABBC e; + e.a = flag26 | 0xB; + e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6); + e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.delete_pointer_cond.cond)); + e.d = CTool_EndianConvertWord16(reg2 ? reg2 : local_offset_16(ea->data.delete_pointer_cond.pointerobject)); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.delete_pointer_cond.deletefunc, offset + 6); + } else { + AACCC e; + e.a = flag26 | 0x1A; + e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6); + e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.delete_pointer_cond.cond)); + e.d = CTool_EndianConvertWord32(reg2 ? reg2 : local_offset_32(ea->data.delete_pointer_cond.pointerobject)); + e.e = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + addrelocation(ea->data.delete_pointer_cond.deletefunc, offset + 10); + } + break; + } + case EAT_CATCHBLOCK: { + AACCC e; + e.a = flag26 | 0x10; + e.b = 0; + e.c = 0; + if (ea->data.catch_block.catch_label->pclabel) + e.d = CTool_EndianConvertWord32(ea->data.catch_block.catch_label->pclabel->block->codeOffset); + else + e.d = 0; + e.e = CTool_EndianConvertWord32(local_offset_16(ea->data.catch_block.catch_info_object)); + AppendGListData(&exceptmodule, &e, sizeof(e)); + if (ea->data.catch_block.catch_typeid) + addrelocation(ea->data.catch_block.catch_typeid, offset + 2); + break; + } + case EAT_ACTIVECATCHBLOCK: { + if (local_is_16bit_offset(ea->data.active_catch_block.catch_info_object)) { + AAB e; + e.a = flag26 | 0xD; + e.b = 0; + e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.active_catch_block.catch_info_object)); + AppendGListData(&exceptmodule, &e, sizeof(e)); + } else { + AAC e; + e.a = flag26 | 0x1B; + e.b = 0; + e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.active_catch_block.catch_info_object)); + AppendGListData(&exceptmodule, &e, sizeof(e)); + } + break; + } + case EAT_SPECIFICATION: { + AABCC e; + int i; + + e.a = flag26 | 0xF; + e.b = 0; + e.c = CTool_EndianConvertWord16(ea->data.specification.unexp_ids); + if (ea->data.specification.unexp_label->pclabel) + e.d = CTool_EndianConvertWord32(ea->data.specification.unexp_label->pclabel->block->codeOffset); + e.e = CTool_EndianConvertWord32(local_offset_16(ea->data.specification.unexp_info_object)); + AppendGListData(&exceptmodule, &e, sizeof(e)); + + for (i = 0; i < ea->data.specification.unexp_ids; i++) { + addrelocation(ea->data.specification.unexp_id[i], 12 + i * 4 + offset); + AppendGListLong(&exceptmodule, 0); + } + break; + } + case EAT_TERMINATE: { + AA e; + e.a = flag26 | 0xE; + e.b = 0; + AppendGListData(&exceptmodule, &e, sizeof(e)); + break; + } + default: + CError_FATAL(671); + } + + node = node->prev; + } + + if (node) { + AAB e; + e.a = 1; + e.b = 0; + e.c = CTool_EndianConvertWord16(node->xE); + AppendGListData(&exceptmodule, &e, sizeof(e)); + } +} + +static UInt32 findPC(PCode *instr) { + UInt32 pc = instr->block->codeOffset; + instr = instr->prevPCode; + while (instr) { + instr = instr->prevPCode; + pc += 4; + } + CError_ASSERT(704, FITS_IN_USHORT(pc)); + return pc; +} + +static UInt32 findPC_long(PCode *instr) { + UInt32 pc = instr->block->codeOffset; + instr = instr->prevPCode; + while (instr) { + instr = instr->prevPCode; + pc += 4; + } + return pc; +} + +void initializeexceptiontables(void) { + int i; + + for (i = 0; i < EAT_NACTIONS; i++) + DAG[i] = NULL; + + pc_actions = last_pc_action = NULL; + except_refs = last_except_ref = NULL; +} + +int countexceptionactionregisters(ExceptionAction *actions) { + int count = 0; + + while (actions) { + switch (actions->type) { + case EAT_DESTROYLOCALCOND: + if (OBJECT_REG(actions->data.destroy_local_cond.cond)) + count++; + break; + case EAT_DESTROYLOCALPOINTER: + if (OBJECT_REG(actions->data.destroy_local_pointer.pointer)) + count++; + break; + case EAT_DESTROYMEMBER: + if (OBJECT_REG(actions->data.destroy_member.objectptr)) + count++; + break; + case EAT_DESTROYBASE: + if (OBJECT_REG(actions->data.destroy_base.objectptr)) + count++; + break; + case EAT_DESTROYMEMBERCOND: + if (OBJECT_REG(actions->data.destroy_member_cond.cond)) + count++; + if (OBJECT_REG(actions->data.destroy_member_cond.objectptr)) + count++; + break; + case EAT_DESTROYMEMBERARRAY: + if (OBJECT_REG(actions->data.destroy_member_array.objectptr)) + count++; + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + if (OBJECT_REG(actions->data.delete_pointer.pointerobject)) + count++; + break; + case EAT_DELETEPOINTERCOND: + if (OBJECT_REG(actions->data.delete_pointer_cond.cond)) + count++; + if (OBJECT_REG(actions->data.delete_pointer_cond.pointerobject)) + count++; + break; + } + actions = actions->prev; + } + + return count; +} + +void noteexceptionactionregisters(ExceptionAction *actions, PCodeArg *ops) { + Object *obj; + int reg; + + while (actions) { + switch (actions->type) { + case EAT_DESTROYLOCALCOND: + if ((reg = OBJECT_REG(obj = actions->data.destroy_local_cond.cond))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DESTROYLOCALPOINTER: + if ((reg = OBJECT_REG(obj = actions->data.destroy_local_pointer.pointer))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DESTROYMEMBER: + if ((reg = OBJECT_REG(obj = actions->data.destroy_member.objectptr))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DESTROYBASE: + if ((reg = OBJECT_REG(obj = actions->data.destroy_base.objectptr))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DESTROYMEMBERCOND: + if ((reg = OBJECT_REG(obj = actions->data.destroy_member_cond.cond))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + if ((reg = OBJECT_REG(obj = actions->data.destroy_member_cond.objectptr))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DESTROYMEMBERARRAY: + if ((reg = OBJECT_REG(obj = actions->data.destroy_member_array.objectptr))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + if ((reg = OBJECT_REG(obj = actions->data.delete_pointer.pointerobject))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + case EAT_DELETEPOINTERCOND: + if ((reg = OBJECT_REG(obj = actions->data.delete_pointer_cond.cond))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + if ((reg = OBJECT_REG(obj = actions->data.delete_pointer_cond.pointerobject))) { + ops->kind = PCOp_REGISTER; + ops->arg = obj->u.var.info->rclass; + ops->data.reg.reg = reg; + ops->data.reg.effect = EffectRead | Effect8; + ops++; + } + break; + } + actions = actions->prev; + } +} + +void recordexceptionactions(PCode *instr, ExceptionAction *actions) { + PCAction *pca; + + if (!actions && (!last_pc_action || !last_pc_action->actions)) + return; + + pca = lalloc(sizeof(PCAction)); + pca->next = NULL; + pca->firstInstr = pca->lastInstr = instr; + pca->actions = actions; + pca->prev = last_pc_action; + if (last_pc_action) + last_pc_action->next = pca; + else + pc_actions = pca; + last_pc_action = pca; + + branch_label(makepclabel()); + while (actions) { + if (actions->type == EAT_CATCHBLOCK && actions->data.catch_block.catch_label->pclabel) + pcbranch(instr->block, actions->data.catch_block.catch_label->pclabel); + else if (actions->type == EAT_SPECIFICATION && actions->data.specification.unexp_label->pclabel) + pcbranch(instr->block, actions->data.specification.unexp_label->pclabel); + actions = actions->prev; + } +} + +static void deleteexceptionaction(PCAction *pca) { + if (pca->prev) + pca->prev->next = pca->next; + else + pc_actions = pca->next; + + if (pca->next) + pca->next->prev = pca->prev; +} + +static int mergeexceptionactions(void) { + int count; + PCAction *pca; + PCAction *prev; + + if (!pc_actions) + return 0; + + for (pca = pc_actions; pca; pca = pca->next) { + if (pca->firstInstr->block->flags & fDeleted) + deleteexceptionaction(pca); + } + + if (!(pca = pc_actions)) + return 0; + + while (pca) { + pca->node = pca->actions ? makeEAnode(pca->actions) : NULL; + pca = pca->next; + } + + prev = pc_actions; + for (pca = pc_actions->next; pca; pca = pca->next) { + if (pca->node == prev->node) { + prev->lastInstr = pca->lastInstr; + deleteexceptionaction(pca); + } else { + prev = pca; + } + } + + count = 0; + for (pca = pc_actions; pca; pca = pca->next) { + if (!pca->actions) + deleteexceptionaction(pca); + else + count++; + } + + return count; +} + +typedef struct ExceptionThing { + UInt32 x0; + UInt16 x4; + UInt16 x6; +} ExceptionThing; + +void dumpexceptiontables(Object *function, SInt32 codesize) { + PCAction *pca; + UInt32 insn_start; + UInt32 insn_count; + UInt16 *sh; + ExceptionThing *thing; + int count; + + count = mergeexceptionactions(); + InitGList(&exceptmodule, 256); + AppendGListNoData(&exceptmodule, 8 * count + 4); + AppendGListLong(&exceptmodule, 0); + + for (pca = pc_actions; pca; pca = pca->next) { + if (pca->node->count == 0 && pca->node->xE == 0) + allocateactioninfo(pca->node); + } + + sh = (UInt16 *) *exceptmodule.data; + if (copts.altivec_model && used_nonvolatile_registers[RegClass_VR]) { + sh[0] = + CTool_EndianConvertWord16( + (used_nonvolatile_registers[RegClass_GPR] << 11) | + ((used_nonvolatile_registers[RegClass_FPR] & 0x1F) << 6) | + (((used_nonvolatile_registers[RegClass_CRFIELD] != 0) & 1) << 5) | + ((dynamic_stack & 1) << 4) | + 8); + sh[0] |= 4; + if (copts.altivec_vrsave) + sh[1] = CTool_EndianConvertWord16((used_nonvolatile_registers[RegClass_VR] << 11) | 0x400); + else + sh[1] = CTool_EndianConvertWord16((used_nonvolatile_registers[RegClass_VR] & 0x1F) << 11); + } else { + sh[0] = + CTool_EndianConvertWord16( + (used_nonvolatile_registers[RegClass_GPR] << 11) | + ((used_nonvolatile_registers[RegClass_FPR] & 0x1F) << 6) | + (((used_nonvolatile_registers[RegClass_CRFIELD] != 0) & 1) << 5) | + ((dynamic_stack & 1) << 4) | + 8); + sh[1] = 0; + } + + thing = (ExceptionThing *) (sh + 2); + pca = pc_actions; + while (pca) { + insn_start = findPC_long(pca->firstInstr); + insn_count = (findPC_long(pca->lastInstr) - insn_start) / 4; + CError_ASSERT(1203, (insn_count & 0xFFFF0000) == 0); + thing->x0 = CTool_EndianConvertWord32(insn_start + 4); + thing->x4 = CTool_EndianConvertWord16(insn_count); + thing->x6 = CTool_EndianConvertWord16(pca->node->xE); + pca = pca->next; + thing++; + } + + LockGList(&exceptmodule); + ObjGen_DeclareExceptionTables(function, codesize, *exceptmodule.data, exceptmodule.size, except_refs); + FreeGList(&exceptmodule); +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c new file mode 100644 index 0000000..67d7443 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c @@ -0,0 +1,642 @@ +#include "compiler/FunctionCalls.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/InstrSelection.h" +#include "compiler/Operands.h" +#include "compiler/PCode.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/Registers.h" +#include "compiler/StackFrame.h" +#include "compiler/StructMoves.h" +#include "compiler/types.h" + +enum { + AIF_PassInGPR = 1, + AIF_PassInFPR = 2, + AIF_PassOnStack = 4, + AIF_ExtendTo32Bits = 8, + AIF_ForceDoublePrecision = 0x10, + AIF_PassInVR = 0x20, + AIF_PassMask = AIF_PassInGPR | AIF_PassInFPR | AIF_PassOnStack | AIF_PassInVR +}; + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct ArgInfo { + struct ArgInfo *next; + ENode *expr; + Operand opnd; + SInt32 offset; + short gpr; + short gprHi; + short fpr; + short vr; + short evaluated; + short flags; +} ArgInfo; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +// forward decls +static void branch_subroutine_indirect_ctr(Operand *addrOpnd, UInt32 *used_regs); + +static ArgInfo *make_arginfo(ENode *expr) { + ArgInfo *info = lalloc(sizeof(ArgInfo)); + memclrw(info, sizeof(ArgInfo)); + + info->next = NULL; + info->expr = expr; + info->offset = -1; + info->gpr = -1; + info->gprHi = -1; + info->fpr = -1; + info->vr = -1; + info->evaluated = 0; + info->flags = 0; + + return info; +} + +static ArgInfo *analyze_arguments(ENode *funcref, ENodeList *arg_expr, FuncArg *arg, UInt32 *used_regs, Boolean *resultHasFloats, char has_varargs) { + ArgInfo *infos; + ArgInfo *info; + SInt32 displ; + SInt32 arg_size; + int gpr_counter; + int fpr_counter; + int vr_counter; + Type *type; + RegClass rclass; + Boolean spilledVectorFlag; + + infos = NULL; + displ = 0; + gpr_counter = 3; + fpr_counter = 1; + vr_counter = 2; + + for (rclass = 0; rclass < RegClassMax; rclass++) + used_regs[rclass] = 0; + *resultHasFloats = 0; + + while (arg_expr) { + if (arg_expr->node == funcref) { + arg_expr = arg_expr->next; + arg = arg->next; + continue; + } + + type = arg_expr->node->rtype; + if (infos) { + info->next = make_arginfo(arg_expr->node); + info = info->next; + } else { + infos = info = make_arginfo(arg_expr->node); + } + + arg_size = 0; + if (IS_TYPE_VECTOR(type)) { + if (arg == &elipsis) { + spilledVectorFlag = 1; + info->flags |= AIF_PassOnStack; + } else { + spilledVectorFlag = 0; + if (vr_counter <= 13) { + info->flags |= AIF_PassInVR; + info->vr = vr_counter; + used_regs[RegClass_VR] |= 1 << vr_counter; + } else { + spilledVectorFlag = 1; + info->flags |= AIF_PassOnStack; + } + } + + if (has_varargs) { + if (gpr_counter < 10) { + gpr_counter = ((gpr_counter - 2) & ~3) + 5; + if (arg == &elipsis && gpr_counter < 10) { + info->flags |= AIF_PassInGPR; + info->gpr = gpr_counter; + used_regs[RegClass_GPR] |= (15 << gpr_counter) & 0x7E0; + } + gpr_counter += 4; + } + spilledVectorFlag = 1; + } + + if (spilledVectorFlag) + arg_size = 16; + vr_counter++; + } else if (IS_TYPE_FLOAT(type)) { + *resultHasFloats = 1; + if (!arg || arg == &oldstyle) { + if (fpr_counter <= 13) { + info->flags |= AIF_PassInFPR; + info->fpr = fpr_counter; + used_regs[RegClass_FPR] |= 1 << fpr_counter; + } else { + info->flags |= AIF_PassOnStack | AIF_ForceDoublePrecision; + } + arg_size = 8; + fpr_counter++; + gpr_counter += 2; + } else if (arg == &elipsis) { + if (gpr_counter < 10) { + info->flags |= AIF_PassInGPR; + info->gpr = gpr_counter; + used_regs[RegClass_GPR] |= 3 << gpr_counter; + } else if (gpr_counter == 10) { + info->flags |= AIF_PassInGPR | AIF_PassOnStack | AIF_ForceDoublePrecision; + info->gpr = gpr_counter; + used_regs[RegClass_GPR] |= 3 << gpr_counter; + } else { + info->flags |= AIF_PassOnStack | AIF_ForceDoublePrecision; + } + arg_size = 8; + fpr_counter++; + gpr_counter += 2; + } else { + if (fpr_counter <= 13) { + info->flags |= AIF_PassInFPR; + info->fpr = fpr_counter; + used_regs[RegClass_FPR] |= 1 << fpr_counter; + } else { + info->flags |= AIF_PassOnStack; + } + + if (type->size == 4) { + arg_size = 4; + gpr_counter++; + } else { + arg_size = 8; + gpr_counter += 2; + } + + fpr_counter++; + } + } else if (TYPE_IS_8BYTES(type)) { + if (gpr_counter <= 10) { + info->flags |= AIF_PassInGPR; + if (copts.littleendian) { + info->gpr = gpr_counter; + info->gprHi = gpr_counter + 1; + } else { + info->gpr = gpr_counter + 1; + info->gprHi = gpr_counter; + } + used_regs[RegClass_GPR] |= 1 << gpr_counter; + if ((gpr_counter + 1) <= 10) + used_regs[RegClass_GPR] |= 1 << (gpr_counter + 1); + } else { + info->flags |= AIF_PassOnStack; + } + + arg_size = 8; + gpr_counter += 2; + } else if (TYPE_FITS_IN_REGISTER(type)) { + if ((!arg || arg == &elipsis || arg == &oldstyle) && type->size < 4) + info->flags |= AIF_ExtendTo32Bits; + + if (gpr_counter <= 10) { + info->flags |= AIF_PassInGPR; + info->gpr = gpr_counter; + used_regs[RegClass_GPR] |= 1 << gpr_counter; + } else { + info->flags |= AIF_PassOnStack; + } + + arg_size = 4; + gpr_counter++; + } else if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) || + IS_TYPE_12BYTES_MEMBERPOINTER(type)) { + SInt32 gprs_needed = (type->size >> 2) + ((type->size & 3) != 0); + if (gpr_counter <= 10) { + if ((gpr_counter + gprs_needed - 1) <= 10) { + info->flags |= AIF_PassInGPR; + info->gpr = gpr_counter; + used_regs[RegClass_GPR] |= ((1 << gprs_needed) - 1) << gpr_counter; + } else { + info->flags |= AIF_PassInGPR | AIF_PassOnStack; + info->gpr = gpr_counter; + used_regs[RegClass_GPR] |= ((1 << (11 - gpr_counter)) - 1) << gpr_counter; + } + } else { + info->flags |= AIF_PassOnStack; + } + + gpr_counter += gprs_needed; + arg_size = type->size; + } else { + CError_FATAL(421); + } + + displ = set_out_param_displ(displ, type, info->flags & AIF_PassOnStack, &info->offset, arg_size); + + arg_expr = arg_expr->next; + if (arg && arg != &elipsis && arg != &oldstyle) + arg = arg->next; + } + + update_out_param_size(displ); + + return infos; +} + +static void pass_in_memory(ArgInfo *info) { + Type *type; + Operand opnd; + + type = info->expr->rtype; + memclrw(&opnd, sizeof(Operand)); + + if (TYPE_FITS_IN_REGISTER(type)) { + if (TYPE_IS_8BYTES(type)) { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + coerce_to_register_pair(&info->opnd, type, 0, 0); + + load_store_register( + PC_STW, info->opnd.reg, 1, + NULL, low_offset + out_param_displ_to_offset(info->offset)); + load_store_register( + PC_STW, info->opnd.regHi, 1, + NULL, high_offset + out_param_displ_to_offset(info->offset)); + } else { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + if (info->flags & AIF_ExtendTo32Bits) + extend32(&info->opnd, type, 0); + ENSURE_GPR(&info->opnd, type, 0); + + load_store_register( + PC_STW, info->opnd.reg, 1, + NULL, out_param_displ_to_offset(info->offset)); + } + } else if (IS_TYPE_FLOAT(type)) { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + ENSURE_FPR(&info->opnd, type, 0); + + if (type->size == 4 && !(info->flags & AIF_ForceDoublePrecision)) { + load_store_register( + PC_STFS, info->opnd.reg, 1, + NULL, out_param_displ_to_offset(info->offset)); + } else { + load_store_register( + PC_STFD, info->opnd.reg, 1, + NULL, out_param_displ_to_offset(info->offset)); + } + } else if (IS_TYPE_VECTOR(type)) { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + ENSURE_VR(&info->opnd, type, 0); + + load_store_register( + PC_STVX, info->opnd.reg, 1, + NULL, out_param_displ_to_offset(info->offset)); + } else { + opnd.optype = OpndType_IndirectGPR_ImmOffset; + opnd.reg = 1; + opnd.object = NULL; + opnd.immOffset = out_param_displ_to_offset(info->offset); + + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + + move_block(&opnd, &info->opnd, type->size, CMach_ArgumentAlignment(type)); + } +} + +static void pass_in_register(ArgInfo *info) { + Type *type; + + type = info->expr->rtype; + + if ((info->flags & AIF_PassMask) == AIF_PassInFPR) { + if (!info->evaluated) + GEN_NODE_TO_REG(info->expr, info->fpr, 0, &info->opnd); + ENSURE_FPR(&info->opnd, type, info->fpr); + if (info->opnd.reg != info->fpr) + emitpcode(PC_FMR, info->fpr, info->opnd.reg); + } else if ((info->flags & AIF_PassMask) == AIF_PassInVR) { + if (!info->evaluated) + GEN_NODE_TO_REG(info->expr, info->vr, 0, &info->opnd); + ENSURE_VR(&info->opnd, type, info->vr); + if (info->opnd.reg != info->vr) + emitpcode(PC_VMR, info->vr, info->opnd.reg); + } else if (TYPE_FITS_IN_REGISTER(type)) { + if (TYPE_IS_8BYTES(type)) { + if (!info->evaluated) + GEN_NODE_TO_REG(info->expr, info->gpr, info->gprHi, &info->opnd); + coerce_to_register_pair(&info->opnd, type, info->gpr, info->gprHi); + if (copts.littleendian) { + if (info->gprHi > 10) { + load_store_register( + PC_STW, info->opnd.regHi, 1, + NULL, high_offset + out_param_displ_to_offset(info->offset)); + } + } else { + if (info->gpr > 10) { + load_store_register( + PC_STW, info->opnd.reg, 1, + NULL, low_offset + out_param_displ_to_offset(info->offset)); + } + } + } else { + if (!info->evaluated) + GEN_NODE_TO_REG(info->expr, info->gpr, 0, &info->opnd); + if (info->flags & AIF_ExtendTo32Bits) + extend32(&info->opnd, type, info->gpr); + ENSURE_GPR(&info->opnd, type, info->gpr); + if (info->opnd.reg != info->gpr) + emitpcode(PC_MR, info->gpr, info->opnd.reg); + } + } else if (IS_TYPE_FLOAT(type)) { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + + if (type->size != 4 && info->opnd.optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register( + PC_LWZ, info->gpr, info->opnd.reg, + info->opnd.object, info->opnd.immOffset); + load_store_register( + PC_LWZ, info->gpr + 1, info->opnd.reg, + info->opnd.object, info->opnd.immOffset + 4); + } else { + ENSURE_FPR(&info->opnd, type, 0); + load_store_register( + PC_STFD, info->opnd.reg, 1, + NULL, out_param_displ_to_offset(info->offset)); + load_store_register( + PC_LWZ, info->gpr, 1, + NULL, out_param_displ_to_offset(info->offset)); + load_store_register( + PC_LWZ, info->gpr + 1, 1, + NULL, out_param_displ_to_offset(info->offset) + 4); + } + } else if (IS_TYPE_VECTOR(type)) { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + + if (info->opnd.optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register( + PC_LWZ, info->gpr, info->opnd.reg, + info->opnd.object, info->opnd.immOffset); + load_store_register( + PC_LWZ, info->gpr + 1, info->opnd.reg, + info->opnd.object, info->opnd.immOffset + 4); + if ((info->gpr + 2) < 10) { + load_store_register( + PC_LWZ, info->gpr + 2, info->opnd.reg, + info->opnd.object, info->opnd.immOffset + 8); + load_store_register( + PC_LWZ, info->gpr + 3, info->opnd.reg, + info->opnd.object, info->opnd.immOffset + 12); + } + } else { + ENSURE_VR(&info->opnd, type, 0); + load_store_register( + PC_STVX, info->opnd.reg, 1, + NULL, out_param_displ_to_offset(info->offset)); + load_store_register( + PC_LWZ, info->gpr, 1, + NULL, out_param_displ_to_offset(info->offset)); + load_store_register( + PC_LWZ, info->gpr + 1, 1, + NULL, out_param_displ_to_offset(info->offset) + 4); + if ((info->gpr + 2) < 10) { + load_store_register( + PC_LWZ, info->gpr + 2, 1, + NULL, out_param_displ_to_offset(info->offset) + 8); + load_store_register( + PC_LWZ, info->gpr + 3, 1, + NULL, out_param_displ_to_offset(info->offset) + 12); + } + } + } else { + if (!info->evaluated) + GEN_NODE(info->expr, &info->opnd); + + if (type->size <= 4) { + if (info->opnd.optype == OpndType_IndirectSymbol) + coerce_to_addressable(&info->opnd); + + if (info->opnd.optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register( + PC_LWZ, info->gpr, info->opnd.reg, + info->opnd.object, info->opnd.immOffset); + } else if (info->opnd.optype == OpndType_IndirectGPR_Indexed) { + emitpcode( + PC_LWZX, info->gpr, info->opnd.reg, + info->opnd.regOffset); + } + } else { + SInt32 gprs_needed = (type->size >> 2) + ((type->size & 3) != 0); + SInt32 i; + + make_addressable(&info->opnd, gprs_needed * 4, 12); + for (i = 0; i < gprs_needed; i++) { + if (info->opnd.reg != (info->gpr + i)) { + load_store_register( + PC_LWZ, info->gpr + i, info->opnd.reg, + info->opnd.object, info->opnd.immOffset + i * 4); + } + } + + if (info->opnd.reg >= info->gpr && info->opnd.reg < (info->gpr + gprs_needed)) { + load_store_register( + PC_LWZ, info->opnd.reg, info->opnd.reg, + info->opnd.object, info->opnd.immOffset + (info->opnd.reg - info->gpr) * 4); + } + } + } +} + +static void pass_in_register_and_memory(ArgInfo *info) { + Type *type; + int gpr; + SInt32 offset; + + type = info->expr->rtype; + gpr = info->gpr; + offset = 0; + while (offset < type->size && gpr <= 10) { + load_store_register( + PC_LWZ, gpr, 1, + NULL, offset + out_param_displ_to_offset(info->offset)); + gpr++; + offset += 4; + } +} + +static Boolean needs_TOC_reload(Object *func) { + return 0; +} + +static void load_virtual_function(TypeClass *tclass, SInt32 offset, int reg, Operand *opnd) { + if (tclass->flags & CLASS_HANDLEOBJECT) { + load_store_register(PC_LWZ, 12, reg, NULL, 0); + load_store_register(PC_LWZ, 12, 12, NULL, tclass->vtable->offset); + } else { + load_store_register(PC_LWZ, 12, reg, NULL, tclass->vtable->offset); + } + load_store_register(PC_LWZ, 12, 12, NULL, offset); + opnd->optype = OpndType_GPR; + opnd->reg = 12; +} + +static void branch_subroutine_indirect(Object *func, Operand *addrOpnd, UInt32 *used_regs) { + if (addrOpnd->reg != 12) + emitpcode(PC_MR, 12, addrOpnd->reg); + + used_regs[RegClass_GPR] |= 1 << 12; + branch_subroutine(func, 1, used_regs); +} + +static void evaluate_nested_function_calls(ArgInfo *info) { + ArgInfo *scan; + + scan = info->next; + while (scan && !scan->expr->hascall) + scan = scan->next; + + if (scan) + evaluate_nested_function_calls(scan); + + if (info->expr->hascall) { + GEN_NODE(info->expr, &info->opnd); + info->evaluated = 1; + } +} + +void call_function(ENode *expr, Operand *output) { + ArgInfo *infos; // r31 + ENode *funcref = expr->data.funccall.funcref; // r27 + Type *resultType = expr->data.funccall.functype->functype; // r26 + ENode *node = NULL; // r25 + char has_varargs; // r24 + ArgInfo *info; // r22 + Operand opnd; + UInt32 used_regs[RegClassMax] = {0}; + Boolean has_floats; + FuncArg *arg; + + memclrw(&opnd, sizeof(Operand)); + + has_varargs = 0; + for (arg = expr->data.funccall.functype->args; arg; arg = arg->next) { + if (arg == &elipsis) { + has_varargs = 1; + break; + } + } + + if (expr->data.funccall.functype->flags & FUNC_FLAGS_80) { + if (CMach_PassResultInHiddenArg(resultType)) + node = expr->data.funccall.args->next->node; + else + node = expr->data.funccall.args->node; + } + + infos = analyze_arguments( + node, + expr->data.funccall.args, + expr->data.funccall.functype->args, + used_regs, + &has_floats, + has_varargs); + + if (infos) + evaluate_nested_function_calls(infos); + + if (funcref->hascall) { + GEN_NODE_TO_GPR(funcref, &opnd, TYPE(&void_ptr), 0); + } else if (node && node->hascall) { + GEN_NODE_TO_GPR(node, &opnd, TYPE(&void_ptr), 0); + } + + for (info = infos; info; info = info->next) { + if (info->flags & AIF_PassOnStack) + pass_in_memory(info); + } + for (info = infos; info; info = info->next) { + if ((info->flags & AIF_PassMask) == (AIF_PassInGPR | AIF_PassOnStack)) + pass_in_register_and_memory(info); + } + for (info = infos; info; info = info->next) { + int flag = info->flags & AIF_PassMask; + if ( + flag == AIF_PassInGPR || + flag == AIF_PassInFPR || + flag == AIF_PassInVR + ) + pass_in_register(info); + } + + if (funcref->type == EOBJREF) { + TypeClass *tclass; + SInt32 vfOffset; + if (CParser_IsVirtualFunction(funcref->data.objref, &tclass, &vfOffset)) { + load_virtual_function( + tclass, + vfOffset, + CMach_PassResultInHiddenArg(resultType) ? Register4 : Register3, + &opnd + ); + branch_subroutine_indirect_ctr(&opnd, used_regs); + } else if (node) { + if (!node->hascall) { + GEN_NODE_TO_REG(node, 12, 0, &opnd); + ENSURE_GPR(&opnd, TYPE(&void_ptr), 12); + } + branch_subroutine_indirect(funcref->data.objref, &opnd, used_regs); + } else { + branch_subroutine(funcref->data.objref, needs_TOC_reload(funcref->data.objref), used_regs); + } + } else { + if (!funcref->hascall) + GEN_NODE_TO_REG(funcref, 12, 0, &opnd); + ENSURE_GPR(&opnd, TYPE(&void_ptr), 12); + branch_subroutine_indirect_ctr(&opnd, used_regs); + } + + if (IS_TYPE_FLOAT(resultType)) { + output->optype = OpndType_FPR; + output->reg = used_virtual_registers[RegClass_FPR]++; + emitpcode(PC_FMR, output->reg, 1); + } else if (IS_TYPE_VECTOR(resultType)) { + output->optype = OpndType_VR; + output->reg = used_virtual_registers[RegClass_VR]++; + emitpcode(PC_VMR, output->reg, 2); + } else if (TYPE_FITS_IN_REGISTER(resultType)) { + if (resultType->size > 4) { + output->optype = OpndType_GPRPair; + output->reg = used_virtual_registers[RegClass_GPR]++; + output->regHi = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_MR, output->reg, low_reg); + emitpcode(PC_MR, output->regHi, high_reg); + } else { + output->optype = OpndType_GPR; + output->reg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_MR, output->reg, 3); + } + } else { + output->optype = OpndType_Absolute; + output->immediate = 0; + } +} + +static void branch_subroutine_indirect_ctr(Operand *addrOpnd, UInt32 *used_regs) { + if (addrOpnd->reg != 12) + emitpcode(PC_MR, 12, addrOpnd->reg); + + emitpcode(PC_MTCTR, 12); + used_regs[RegClass_GPR] |= 1 << 12; + branch_subroutine_ctr(used_regs); +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c new file mode 100644 index 0000000..359c980 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c @@ -0,0 +1,5348 @@ +#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); +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c new file mode 100644 index 0000000..49334b8 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c @@ -0,0 +1,4894 @@ +#include "compiler/Intrinsics.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CScope.h" +#include "compiler/CompilerTools.h" +#include "compiler/FunctionCalls.h" +#include "compiler/InstrSelection.h" +#include "compiler/PCode.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/PPCError.h" +#include "compiler/RegisterInfo.h" +#include "compiler/StackFrame.h" +#include "compiler/StructMoves.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +Object *__memcpy_object; +static Object *intrinsics[311]; +int VectorConditions; // unused? +static Object *cur_intrinsic_object; + +static TypePointer stvectorunsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stvectorunsignedchar), 0}; +static TypePointer stvectorsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stvectorsignedchar), 0}; +static TypePointer stvectorboolchar_ptr = {TYPEPOINTER, 4, TYPE(&stvectorboolchar), 0}; +static TypePointer stvectorunsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stvectorunsignedshort), 0}; +static TypePointer stvectorsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stvectorsignedshort), 0}; +static TypePointer stvectorboolshort_ptr = {TYPEPOINTER, 4, TYPE(&stvectorboolshort), 0}; +static TypePointer stvectorunsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stvectorunsignedlong), 0}; +static TypePointer stvectorsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stvectorsignedlong), 0}; +static TypePointer stvectorboollong_ptr = {TYPEPOINTER, 4, TYPE(&stvectorboollong), 0}; +static TypePointer stvectorfloat_ptr = {TYPEPOINTER, 4, TYPE(&stvectorfloat), 0}; +static TypePointer stvectorpixel_ptr = {TYPEPOINTER, 4, TYPE(&stvectorpixel), 0}; +static TypePointer stunsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedchar), 0}; +static TypePointer stsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stsignedchar), 0}; +static TypePointer stunsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedshort), 0}; +static TypePointer stsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stsignedshort), 0}; +static TypePointer stunsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedlong), 0}; +static TypePointer stsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stsignedlong), 0}; +static TypePointer stunsignedint_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedint), 0}; +static TypePointer stsignedint_ptr = {TYPEPOINTER, 4, TYPE(&stsignedint), 0}; +static TypePointer stfloat_ptr = {TYPEPOINTER, 4, TYPE(&stfloat), 0}; + +// Verify1VectorArg2Ops +typedef struct TypeTable22 { + Type *rtype; + Type *arg1; + int opcode1; + int opcode2; +} TypeTable22; + +// VerifyNoVectorArgs +typedef struct TypeTable11 { + Type *rtype; + int opcode; +} TypeTable11; + +// Verify1VectorArg +typedef struct TypeTable21 { + Type *rtype; + Type *arg1; + int opcode; +} TypeTable21; + +// Verify2VectorArgs +typedef struct TypeTable31 { + Type *rtype; + Type *arg1; + Type *arg2; + int opcode; +} TypeTable31; + +// Verify3VectorArgs +typedef struct TypeTable41 { + Type *rtype; + Type *arg1; + Type *arg2; + Type *arg3; + int opcode; +} TypeTable41; + +static TypeTable31 vector_add_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDUBM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDUHM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDUWM, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VADDFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_addc_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDCUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_adds_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDSBS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDSHS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDSWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_and_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VAND, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VAND, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VAND, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VAND, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VAND, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VAND, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VAND, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VAND, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VAND, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VAND, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VAND, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VAND, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VAND, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VAND, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VAND, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VAND, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VAND, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VAND, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VAND, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VAND, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VAND, + TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VAND, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VAND, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VAND, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_andc_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VANDC, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VANDC, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VANDC, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VANDC, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VANDC, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VANDC, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VANDC, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VANDC, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VANDC, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VANDC, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VANDC, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VANDC, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VANDC, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VANDC, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VANDC, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VANDC, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VANDC, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VANDC, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VANDC, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VANDC, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VANDC, + TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VANDC, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VANDC, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VANDC, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_avg_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VAVGUB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VAVGSB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VAVGUH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VAVGSH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VAVGUW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VAVGSW, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_ceil_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_cmpb_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPBFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_cmpeq_type_table[] = { + TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_cmpge_type_table[] = { + TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_cmpgt_type_table[] = { + TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_ctf_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VCFUX, + TYPE(&stvectorfloat), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VCFSX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_cts_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VCTSXS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_ctu_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VCTUXS, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_dss_type_table[] = { + TYPE(&stvoid), TYPE(&stsignedint), PC_DSS, PC_B, + NULL, NULL, 0 +}; +static TypeTable11 vector_dssall_type_table[] = { + TYPE(&stvoid), PC_DSSALL, + NULL, 0 +}; +static TypeTable41 vector_datastream_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorboolchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorunsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorboolshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorpixel_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorunsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorboollong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stvectorfloat_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stunsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stunsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stunsignedint_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stsignedint_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stunsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + TYPE(&stvoid), TYPE(&stfloat_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_expte_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VEXPTEFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_floor_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIM, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_load_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_LVX, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVX, + TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_LVX, + TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVX, + TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_LVX, + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_LVX, + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVX, + TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_LVX, + TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVX, + TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_LVX, + TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_LVX, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_LVX, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVX, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_LVX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVX, + TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_LVX, + TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_LVX, + TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_loade_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVEBX, + TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVEBX, + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVEHX, + TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVEHX, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVEWX, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVEWX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVEWX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVEWX, + TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVEWX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_loadl_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_LVXL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVXL, + TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_LVXL, + TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVXL, + TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_LVXL, + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_LVXL, + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVXL, + TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_LVXL, + TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVXL, + TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_LVXL, + TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_LVXL, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_LVXL, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVXL, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVXL, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_LVXL, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVXL, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVXL, + TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_LVXL, + TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_LVXL, + TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVXL, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_loge_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VLOGEFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_lvsl_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVSL, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVSL, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_lvsr_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVSR, + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVSR, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_madd_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMADDFP, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_madds_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMHADDSHS, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_max_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMAXUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMAXUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMAXUB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMAXSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMAXSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMAXSB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMAXUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMAXUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMAXUH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMAXSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMAXSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMAXSH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMAXUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMAXUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMAXUW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMAXSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMAXSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMAXSW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMAXFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_mergeh_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGHB, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGHB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGHH, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGHH, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGHH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGHW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGHW, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGHW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGHW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_mergel_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGLB, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGLB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGLH, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGLH, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGLH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGLW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGLW, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGLW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGLW, + NULL, NULL, NULL, 0 +}; +static TypeTable11 vector_mfvscr_type_table[] = { + TYPE(&stvectorunsignedshort), PC_MFVSCR, + NULL, 0 +}; +static TypeTable31 vector_min_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMINUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMINUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMINUB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMINSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMINSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMINSB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMINUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMINUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMINUH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMINSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMINSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMINSH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMINUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMINUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMINUW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMINSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMINSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMINSW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMINFP, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_mladd_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMLADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMLADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMLADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMLADDUHM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_mradds_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMHRADDSHS, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_msum_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VMSUMUBM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedlong), PC_VMSUMMBM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_msums_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHS, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable21 vector_mtvscr_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedchar), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorsignedchar), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorboolchar), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorunsignedshort), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorsignedshort), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorboolshort), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorpixel), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorsignedlong), PC_MTVSCR, + TYPE(&stvoid), TYPE(&stvectorboollong), PC_MTVSCR, + NULL, NULL, 0 +}; +static TypeTable31 vector_mule_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULEUB, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULESB, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULEUH, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULESH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_mulo_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULOUB, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULOSB, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULOUH, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULOSH, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_nmsub_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VNMSUBFP, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_nor_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VNOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VNOR, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VNOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VNOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VNOR, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VNOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VNOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VNOR, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VNOR, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VNOR, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_or_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VOR, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VOR, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VOR, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VOR, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VOR, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VOR, + TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VOR, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VOR, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VOR, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_pack_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKUHUM, + TYPE(&stvectorboolchar), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VPKUHUM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKUWUM, + TYPE(&stvectorboolshort), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VPKUWUM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_packpx_type_table[] = { + TYPE(&stvectorpixel), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKPX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_packs_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHSS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWSS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_packsu_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHUS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWUS, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_perm_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedchar), PC_VPERM, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedchar), PC_VPERM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_re_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VREFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_rl_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_round_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIN, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_rsqrte_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRSQRTEFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable41 vector_sel_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSEL, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSEL, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSEL, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSEL, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSEL, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VSEL, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSEL, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSEL, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSEL, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSEL, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSEL, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VSEL, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSEL, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSEL, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSEL, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSEL, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSEL, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VSEL, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedlong), PC_VSEL, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VSEL, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sl_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_sld_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSLDOI, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VSLDOI, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sll_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSL, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedchar), PC_VSL, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedshort), PC_VSL, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSL, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_slo_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), PC_VSLO, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedchar), PC_VSLO, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorsignedchar), PC_VSLO, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_splat_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSPLTB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTB, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stsignedint), PC_VSPLTB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSPLTW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTW, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stsignedint), PC_VSPLTW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VSPLTW, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_splat_s8_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTISB, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_splat_s16_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTISH, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_splat_s32_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTISW, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_splat_u8_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSPLTISB, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_splat_u16_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSPLTISH, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_splat_u32_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSPLTISW, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_sr_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sra_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_srl_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSR, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedchar), PC_VSR, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedshort), PC_VSR, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSR, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sro_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), PC_VSRO, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedchar), PC_VSRO, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorsignedchar), PC_VSRO, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_st_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVX, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_ste_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVEBX, + TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX, + TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVEBX, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_stl_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVXL, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVXL, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sub_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBUBM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBUHM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBUWM, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VSUBFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_subc_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBCUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_subs_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBSBS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBSHS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBSWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sum4s_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSUM4UBS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedlong), PC_VSUM4SBS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VSUM4SHS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sum2s_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUM2SWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_sums_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUMSWS, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_trunc_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIZ, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_unpack2sh_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB, + TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_unpack2sl_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB, + TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_unpack2uh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_unpack2ul_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH, + NULL, NULL, NULL, 0 +}; +static TypeTable21 vector_unpackh_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKHSB, + TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKHSB, + TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKHPX, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKHSH, + TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKHSH, + NULL, NULL, 0 +}; +static TypeTable21 vector_unpackl_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKLSB, + TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKLSB, + TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKLPX, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKLSH, + TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKLSH, + NULL, NULL, 0 +}; +static TypeTable31 vector_xor_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VXOR, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VXOR, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VXOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VXOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VXOR, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VXOR, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VXOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VXOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VXOR, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VXOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VXOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VXOR, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VXOR, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VXOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VXOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VXOR, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VXOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VXOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VXOR, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VXOR, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VXOR, + TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VXOR, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VXOR, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VXOR, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_eq_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_ge_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_gt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_in_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPBFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_le_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_lt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP +}; +static TypeTable22 vector_all_nan_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_all_ne_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_nge_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_ngt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_nle_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_all_nlt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_all_numeric_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_any_eq_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_ge_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_gt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_le_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_lt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_any_nan_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_any_ne_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW, + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_nge_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_ngt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_nle_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_any_nlt_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_any_numeric_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_any_out_type_table[] = { + TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPBFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vaddubm_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDUBM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vadduhm_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDUHM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vadduwm_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDUWM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vaddfp_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VADDFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vaddubs_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vaddsbs_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDSBS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vadduhs_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vaddshs_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDSHS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vadduws_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vaddsws_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDSWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vavgub_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VAVGUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vavgsb_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VAVGSB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vavguh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VAVGUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vavgsh_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VAVGSH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vavguw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VAVGUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vavgsw_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VAVGSW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpequb_type_table[] = { + TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB, + TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpequh_type_table[] = { + TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH, + TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpequw_type_table[] = { + TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW, + TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpeqfp_type_table[] = { + TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtub_type_table[] = { + TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtsb_type_table[] = { + TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtuh_type_table[] = { + TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtsh_type_table[] = { + TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtuw_type_table[] = { + TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtsw_type_table[] = { + TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcmpgtfp_type_table[] = { + TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcfux_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VCFUX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vcfsx_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VCFSX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_lvebx_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVEBX, + TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVEBX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_lvehx_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVEHX, + TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVEHX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_lvewx_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVEWX, + TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVEWX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVEWX, + TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVEWX, + TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVEWX, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxub_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMAXUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMAXUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMAXUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxsb_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMAXSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMAXSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMAXSB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxuh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMAXUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMAXUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMAXUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxsh_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMAXSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMAXSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMAXSH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxuw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMAXUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMAXUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMAXUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxsw_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMAXSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMAXSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMAXSW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmaxfp_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMAXFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmrghb_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGHB, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGHB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmrghh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGHH, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGHH, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGHH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmrghw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGHW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGHW, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGHW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGHW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmrglb_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGLB, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGLB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmrglh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGLH, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGLH, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGLH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmrglw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGLW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGLW, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGLW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGLW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminub_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMINUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMINUB, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMINUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminsb_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMINSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMINSB, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMINSB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminuh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMINUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMINUH, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMINUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminsh_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMINSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMINSH, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMINSH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminuw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMINUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMINUW, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMINUW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminsw_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMINSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMINSW, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMINSW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vminfp_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMINFP, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_vmsumubm_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VMSUMUBM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_vmsumuhm_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_vmsummbm_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedlong), PC_VMSUMMBM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_vmsumshm_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHM, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_vmsumuhs_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHS, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_vmsumshs_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHS, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmuleub_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULEUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmulesb_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULESB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmuleuh_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULEUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmulesh_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULESH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmuloub_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULOUB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmulosb_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULOSB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmulouh_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULOUH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vmulosh_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULOSH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkuhum_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKUHUM, + TYPE(&stvectorboolchar), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VPKUHUM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkuwum_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKUWUM, + TYPE(&stvectorboolshort), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VPKUWUM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkuhus_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkshss_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHSS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkuwus_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkswss_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWSS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkshus_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHUS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vpkswus_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWUS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vrlb_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vrlh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vrlw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vslb_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vslh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vslw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vspltb_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSPLTB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTB, + TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stsignedint), PC_VSPLTB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsplth_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stsignedint), PC_VSPLTH, + TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stsignedint), PC_VSPLTH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vspltw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSPLTW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTW, + TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stsignedint), PC_VSPLTW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VSPLTW, + NULL, NULL, NULL, 0 +}; +static TypeTable22 vector_vspltisb_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTISB, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_vspltish_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTISH, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_vspltisw_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTISW, PC_B, + NULL, NULL, 0 +}; +static TypeTable31 vector_vsrb_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsrh_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsrw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsrab_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsrah_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsraw_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW, + NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_stvebx_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVEBX, + TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX, + TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_stvehx_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX, + TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable41 vector_stvewx_type_table[] = { + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX, + TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX, + NULL, NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsububm_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBUBM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubuhm_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBUHM, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubuwm_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBUWM, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VSUBFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubfp_type_table[] = { + TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VSUBFP, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsububs_type_table[] = { + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBS, + TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubsbs_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBSBS, + TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBSBS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubuhs_type_table[] = { + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHS, + TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubshs_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBSHS, + TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBSHS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubuws_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWS, + TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsubsws_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBSWS, + TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBSWS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsum4ubs_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSUM4UBS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsum4sbs_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedlong), PC_VSUM4SBS, + NULL, NULL, NULL, 0 +}; +static TypeTable31 vector_vsum4shs_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VSUM4SHS, + NULL, NULL, NULL, 0 +}; +static TypeTable21 vector_vupkhsb_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKHSB, + TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKHSB, + NULL, NULL, 0 +}; +static TypeTable21 vector_vupklsb_type_table[] = { + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKLSB, + TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKLSB, + NULL, NULL, 0 +}; +static TypeTable22 vector_vupkhpx_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKHPX, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_vupklpx_type_table[] = { + TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKLPX, PC_B, + NULL, NULL, 0 +}; +static TypeTable21 vector_vupkhsh_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKHSH, + TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKHSH, + NULL, NULL, 0 +}; +static TypeTable21 vector_vupklsh_type_table[] = { + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKLSH, + TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKLSH, + NULL, NULL, 0 +}; +static TypeTable22 vector_abs_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBUBM, PC_VMAXSB, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBUHM, PC_VMAXSH, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBUWM, PC_VMAXSW, + TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VANDC, PC_B, + NULL, NULL, 0 +}; +static TypeTable22 vector_abss_type_table[] = { + TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBSBS, PC_VMAXSB, + TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBSHS, PC_VMAXSH, + TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBSWS, PC_VMAXSW, + NULL, NULL, 0 +}; +static void *typeTable[] = { + vector_add_type_table, + vector_addc_type_table, + vector_adds_type_table, + vector_and_type_table, + vector_andc_type_table, + vector_avg_type_table, + vector_ceil_type_table, + vector_cmpb_type_table, + vector_cmpeq_type_table, + vector_cmpge_type_table, + vector_cmpge_type_table, + vector_cmpgt_type_table, + vector_cmpgt_type_table, + vector_ctf_type_table, + vector_cts_type_table, + vector_ctu_type_table, + vector_dss_type_table, + vector_dssall_type_table, + vector_datastream_type_table, + vector_datastream_type_table, + vector_datastream_type_table, + vector_datastream_type_table, + vector_expte_type_table, + vector_floor_type_table, + vector_load_type_table, + vector_loade_type_table, + vector_loadl_type_table, + vector_loge_type_table, + vector_lvsl_type_table, + vector_lvsr_type_table, + vector_madd_type_table, + vector_madds_type_table, + vector_max_type_table, + vector_mergeh_type_table, + vector_mergel_type_table, + vector_mfvscr_type_table, + vector_min_type_table, + vector_mladd_type_table, + vector_mradds_type_table, + vector_msum_type_table, + vector_msums_type_table, + vector_mtvscr_type_table, + vector_mule_type_table, + vector_mulo_type_table, + vector_nmsub_type_table, + vector_nor_type_table, + vector_or_type_table, + vector_pack_type_table, + vector_packpx_type_table, + vector_packs_type_table, + vector_packsu_type_table, + vector_perm_type_table, + vector_re_type_table, + vector_rl_type_table, + vector_round_type_table, + vector_rsqrte_type_table, + vector_sel_type_table, + vector_sl_type_table, + vector_sld_type_table, + vector_sll_type_table, + vector_slo_type_table, + vector_splat_type_table, + vector_splat_s8_type_table, + vector_splat_s16_type_table, + vector_splat_s32_type_table, + vector_splat_u8_type_table, + vector_splat_u16_type_table, + vector_splat_u32_type_table, + vector_sr_type_table, + vector_sra_type_table, + vector_srl_type_table, + vector_sro_type_table, + vector_st_type_table, + vector_ste_type_table, + vector_stl_type_table, + vector_sub_type_table, + vector_subc_type_table, + vector_subs_type_table, + vector_sum4s_type_table, + vector_sum2s_type_table, + vector_sums_type_table, + vector_trunc_type_table, + vector_unpack2sh_type_table, + vector_unpack2sl_type_table, + vector_unpack2uh_type_table, + vector_unpack2ul_type_table, + vector_unpackh_type_table, + vector_unpackl_type_table, + vector_xor_type_table, + vector_all_eq_type_table, + vector_all_ge_type_table, + vector_all_gt_type_table, + vector_all_in_type_table, + vector_all_le_type_table, + vector_all_lt_type_table, + vector_all_nan_type_table, + vector_all_ne_type_table, + vector_all_nge_type_table, + vector_all_ngt_type_table, + vector_all_nle_type_table, + vector_all_nlt_type_table, + vector_all_numeric_type_table, + vector_any_eq_type_table, + vector_any_ge_type_table, + vector_any_gt_type_table, + vector_any_le_type_table, + vector_any_lt_type_table, + vector_any_nan_type_table, + vector_any_ne_type_table, + vector_any_nge_type_table, + vector_any_ngt_type_table, + vector_any_nle_type_table, + vector_any_nlt_type_table, + vector_any_numeric_type_table, + vector_any_out_type_table, + vector_vaddubm_type_table, + vector_vadduhm_type_table, + vector_vadduwm_type_table, + vector_vaddfp_type_table, + vector_addc_type_table, + vector_vaddubs_type_table, + vector_vaddsbs_type_table, + vector_vadduhs_type_table, + vector_vaddshs_type_table, + vector_vadduws_type_table, + vector_vaddsws_type_table, + vector_and_type_table, + vector_andc_type_table, + vector_vavgub_type_table, + vector_vavgsb_type_table, + vector_vavguh_type_table, + vector_vavgsh_type_table, + vector_vavguw_type_table, + vector_vavgsw_type_table, + vector_ceil_type_table, + vector_cmpb_type_table, + vector_vcmpequb_type_table, + vector_vcmpequh_type_table, + vector_vcmpequw_type_table, + vector_vcmpeqfp_type_table, + vector_cmpge_type_table, + vector_vcmpgtub_type_table, + vector_vcmpgtsb_type_table, + vector_vcmpgtuh_type_table, + vector_vcmpgtsh_type_table, + vector_vcmpgtuw_type_table, + vector_vcmpgtsw_type_table, + vector_vcmpgtfp_type_table, + vector_vcfux_type_table, + vector_vcfsx_type_table, + vector_cts_type_table, + vector_ctu_type_table, + vector_expte_type_table, + vector_floor_type_table, + vector_load_type_table, + vector_lvebx_type_table, + vector_lvehx_type_table, + vector_lvewx_type_table, + vector_loadl_type_table, + vector_loge_type_table, + vector_madd_type_table, + vector_madds_type_table, + vector_vmaxub_type_table, + vector_vmaxsb_type_table, + vector_vmaxuh_type_table, + vector_vmaxsh_type_table, + vector_vmaxuw_type_table, + vector_vmaxsw_type_table, + vector_vmaxfp_type_table, + vector_vmrghb_type_table, + vector_vmrghh_type_table, + vector_vmrghw_type_table, + vector_vmrglb_type_table, + vector_vmrglh_type_table, + vector_vmrglw_type_table, + vector_vminub_type_table, + vector_vminsb_type_table, + vector_vminuh_type_table, + vector_vminsh_type_table, + vector_vminuw_type_table, + vector_vminsw_type_table, + vector_vminfp_type_table, + vector_mladd_type_table, + vector_mradds_type_table, + vector_vmsumubm_type_table, + vector_vmsumuhm_type_table, + vector_vmsummbm_type_table, + vector_vmsumshm_type_table, + vector_vmsumuhs_type_table, + vector_vmsumshs_type_table, + vector_vmuleub_type_table, + vector_vmulesb_type_table, + vector_vmuleuh_type_table, + vector_vmulesh_type_table, + vector_vmuloub_type_table, + vector_vmulosb_type_table, + vector_vmulouh_type_table, + vector_vmulosh_type_table, + vector_nmsub_type_table, + vector_nor_type_table, + vector_or_type_table, + vector_vpkuhum_type_table, + vector_vpkuwum_type_table, + vector_packpx_type_table, + vector_vpkuhus_type_table, + vector_vpkshss_type_table, + vector_vpkuwus_type_table, + vector_vpkswss_type_table, + vector_vpkshus_type_table, + vector_vpkswus_type_table, + vector_perm_type_table, + vector_re_type_table, + vector_vrlb_type_table, + vector_vrlh_type_table, + vector_vrlw_type_table, + vector_round_type_table, + vector_rsqrte_type_table, + vector_sel_type_table, + vector_vslb_type_table, + vector_vslh_type_table, + vector_vslw_type_table, + vector_sld_type_table, + vector_sll_type_table, + vector_slo_type_table, + vector_vspltb_type_table, + vector_vsplth_type_table, + vector_vspltw_type_table, + vector_vspltisb_type_table, + vector_vspltish_type_table, + vector_vspltisw_type_table, + vector_vsrb_type_table, + vector_vsrh_type_table, + vector_vsrw_type_table, + vector_vsrab_type_table, + vector_vsrah_type_table, + vector_vsraw_type_table, + vector_srl_type_table, + vector_sro_type_table, + vector_st_type_table, + vector_stvebx_type_table, + vector_stvehx_type_table, + vector_stvewx_type_table, + vector_stl_type_table, + vector_vsububm_type_table, + vector_vsubuhm_type_table, + vector_vsubuwm_type_table, + vector_vsubfp_type_table, + vector_subc_type_table, + vector_vsububs_type_table, + vector_vsubsbs_type_table, + vector_vsubuhs_type_table, + vector_vsubshs_type_table, + vector_vsubuws_type_table, + vector_vsubsws_type_table, + vector_vsum4ubs_type_table, + vector_vsum4sbs_type_table, + vector_vsum4shs_type_table, + vector_sum2s_type_table, + vector_sums_type_table, + vector_trunc_type_table, + vector_vupkhsb_type_table, + vector_vupklsb_type_table, + vector_vupkhpx_type_table, + vector_vupklpx_type_table, + vector_vupkhsh_type_table, + vector_vupklsh_type_table, + vector_xor_type_table, + vector_abs_type_table, + vector_abss_type_table, + NULL +}; + +int is_intrinsic_function_call(ENode *funccall) { + ENode *funcref = funccall->data.funccall.funcref; + return + ENODE_IS(funcref, EOBJREF) && + funcref->data.objref->datatype == DFUNC && + (TYPE_FUNC(funcref->data.objref->type)->flags & FUNC_INTRINSIC); +} + +static void abs_intrinsic(ENode *expr, short outputReg, Operand *output) { + int reg1; + int reg2; + Operand op; + + memclrw(&op, sizeof(op)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + reg1 = ALLOC_GPR(); + emitpcode(PC_SRAWI, reg1, op.reg, 31); + + reg2 = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_XOR, reg2, reg1, op.reg); + emitpcode(PC_SUBF, reg2, reg1, reg2); + + output->optype = OpndType_GPR; + output->reg = reg2; +} + +static void setflm_intrinsic(ENode *expr, short outputReg, Operand *output, int flag) { + int reg; + Operand op; + + memclrw(&op, sizeof(op)); + GEN_NODE_TO_FPR(expr, &op, expr->rtype, 0); + + if (!flag) { + output->optype = OpndType_FPR; + reg = (outputReg && outputReg != op.reg) ? outputReg : ALLOC_FPR(); + emitpcode(PC_MFFS, output->reg = reg); + } + + emitpcode(PC_MTFSF, 255, op.reg); +} + +static void alloca_intrinsic(ENode *expr, short outputReg, Operand *output) { + int reg; + Operand op; + + memclrw(&op, sizeof(op)); + + if (ENODE_IS(expr, EINTCONST)) { + reg = outputReg ? outputReg : ALLOC_GPR(); + allocate_dynamic_stack_space( + 1, reg, ALLOC_GPR(), CInt64_GetULong(&expr->data.intval)); + } else { + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + reg = outputReg ? outputReg : ALLOC_GPR(); + + emitpcode(PC_NEG, reg, op.reg); + emitpcode(PC_RLWINM, reg, reg, 0, 0, get_alloca_alignment()); + allocate_dynamic_stack_space(0, reg, ALLOC_GPR(), 0); + } + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void load_bytereversed_intrinsic(Opcode opcode, ENode *expr1, ENode *expr2, short outputReg, Operand *output) { + int reg; + Operand op1; + Operand op2; + + reg = outputReg ? outputReg : ALLOC_GPR(); + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + + if (ENODE_IS(expr2, EINTCONST) && expr2->data.intval.lo == 0) { + GEN_NODE(expr1, &op1); + if (op1.optype == OpndType_GPR_Indexed) { + emitpcode(opcode, reg, op1.reg, op1.regOffset); + } else { + ENSURE_GPR(&op1, expr1->rtype, 0); + emitpcode(opcode, reg, 0, op1.reg); + } + } else { + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0); + emitpcode(opcode, reg, op1.reg, op2.reg); + } + + setpcodeflags(fSideEffects | ((expr1->flags | expr2->flags | output->flags) & (fIsConst | fIsVolatile))); + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void store_bytereversed_intrinsic(Opcode opcode, ENode *expr1, ENode *expr2, ENode *expr3) { + Operand op1; + Operand op2; + Operand op3; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + memclrw(&op3, sizeof(op3)); + + if (ENODE_IS(expr3, EINTCONST) && expr3->data.intval.lo == 0) { + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE(expr2, &op2); + if (op2.optype == OpndType_GPR_Indexed) { + emitpcode(opcode, op1.reg, op2.reg, op2.regOffset); + } else { + ENSURE_GPR(&op2, expr2->rtype, 0); + emitpcode(opcode, op1.reg, 0, op2.reg); + } + } else { + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0); + GEN_NODE_TO_GPR(expr3, &op3, expr3->rtype, 0); + emitpcode(opcode, op1.reg, op2.reg, op3.reg); + } + + setpcodeflags(fSideEffects | ((op1.flags | op2.flags | op3.flags) & (fIsConst | fIsVolatile))); +} + +static void data_cache_block_intrinsic(Opcode opcode, ENode *expr1, ENode *expr2) { + Operand op1; + Operand op2; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + + if (ENODE_IS(expr2, EINTCONST) && expr2->data.intval.lo == 0) { + GEN_NODE(expr1, &op1); + if (op1.optype == OpndType_GPR_Indexed) { + emitpcode(opcode, op1.reg, op1.regOffset); + } else { + ENSURE_GPR(&op1, expr1->rtype, 0); + emitpcode(opcode, 0, op1.reg); + } + } else { + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0); + emitpcode(opcode, op1.reg, op2.reg); + } +} + +static void memcpy_intrinsic(ENode *destexpr, ENode *srcexpr, SInt32 size, Boolean ignored, Operand *output) { + UInt32 qual; + Operand destOp; + Operand srcOp; + + qual = 0; + + memclrw(&destOp, sizeof(destOp)); + memclrw(&srcOp, sizeof(srcOp)); + + GEN_NODE(srcexpr, &srcOp); + indirect(&srcOp, srcexpr); + + GEN_NODE(destexpr, output); + destOp = *output; + indirect(&destOp, destexpr); + + if (destOp.object) + qual = destOp.object->qual; + + move_block(&destOp, &srcOp, size, destexpr->rtype ? CMach_AllocationAlignment(destexpr->rtype, qual) : 1); +} + +static SInt32 checkconstintarg(ENode *expr, char *name, SInt32 min, SInt32 max, int argnum) { + SInt32 value; + + if (!ENODE_IS(expr, EINTCONST)) + PPCError_ErrorTerm(PPCErrorStr210, name, 3, max, argnum); + + value = CInt64_GetULong(&expr->data.intval); + + if (value < min) { + PPCError_Warning(PPCErrorStr211, name, argnum, value, min, max, min); + return min; + } + + if (value > max) { + PPCError_Warning(PPCErrorStr211, name, argnum, value, min, max, value & max); + value = value & max; + } + + return value; +} + +static void rlwimi_intrinsic(ENode *expr1, ENode *expr2, ENode *expr3, ENode *expr4, ENode *expr5, short outputReg, Operand *output) { + SInt32 arg3; + SInt32 arg4; + SInt32 arg5; + Operand op1; + Operand op2; + int reg; + char *name = "__rlwimi"; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + + arg3 = checkconstintarg(expr3, name, 0, 31, 3); + arg4 = checkconstintarg(expr4, name, 0, 31, 4); + arg5 = checkconstintarg(expr5, name, 0, 31, 5); + + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + + GEN_NODE(expr2, &op2); + if (copts.optimizationlevel > 1) { + reg = ALLOC_GPR(); + emitpcode(PC_MR, reg, op1.reg); + op1.reg = reg; + } + ENSURE_GPR(&op2, expr2->rtype, 0); + + emitpcode(PC_RLWIMI, op1.reg, op2.reg, arg3, arg4, arg5); + + output->optype = OpndType_GPR; + output->reg = op1.reg; +} + +static void rlwinm_intrinsic(ENode *expr1, ENode *expr2, ENode *expr3, ENode *expr4, short outputReg, Operand *output) { + char *name = "__rlwinm"; + short reg; + short arg2; + short arg3; + short arg4; + Operand op1; + + memclrw(&op1, sizeof(op1)); + arg2 = checkconstintarg(expr2, name, 0, 31, 2); + arg3 = checkconstintarg(expr3, name, 0, 31, 3); + arg4 = checkconstintarg(expr4, name, 0, 31, 4); + + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, op1.reg, arg2, arg3, arg4); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void rlwnm_intrinsic(ENode *expr1, ENode *expr2, ENode *expr3, ENode *expr4, short outputReg, Operand *output) { + short reg; + short arg3; + short arg4; + char *name = "__rlwnm"; + Operand op1; + Operand op2; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + arg3 = checkconstintarg(expr3, name, 0, 31, 3); + arg4 = checkconstintarg(expr4, name, 0, 31, 4); + + GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWNM, reg, op1.reg, op2.reg, arg3, arg4); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static Boolean promotable_types_are_equal(Type *a, Type *b) { + if (a == b) + return 1; + + if (a == TYPE(&stsignedint)) { + if ( + b == TYPE(&stunsignedint) || + b == TYPE(&stsignedchar) || + b == TYPE(&stunsignedchar) || + b == TYPE(&stsignedshort) || + b == TYPE(&stunsignedshort) || + b == TYPE(&stsignedlong) || + b == TYPE(&stunsignedlong) || + b == TYPE(&stbool) + ) + return 1; + } + + return 0; +} + +static int Intrinsics_VerifyParameterCount(int wantedCount, ENodeList *args, HashNameNode *name) { + ENodeList *scan; + int count; + + for (scan = args, count = 0; scan; scan = scan->next) + count++; + + if (count != wantedCount) { + PPCError_Error(PPCErrorStr103, name->name, count, wantedCount); + return 0; + } + + return 1; +} + +static ENode *Intrinsics_CreateIntrinsicFunc(Object *func, ENodeList *args, Type *rtype) { + TypeFunc *tfunc; + ENodeList *scan; + ENode *expr; + + tfunc = TYPE_FUNC(func->type); + CError_ASSERT(3741, IS_TYPE_FUNC(tfunc)); + + for (scan = args; scan; scan = scan->next) { + if (IS_TYPE_ARRAY(scan->node->rtype)) + scan->node = CExpr_PointerGeneration(scan->node); + } + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = rtype; + expr->ignored = 0; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = create_objectrefnode(func); + expr->data.funccall.args = args; + expr->data.funccall.functype = tfunc; + return CExpr_AdjustFunctionCall(expr); +} + +static Type *Intrinsics_Verify1VectorArg2Ops(Intrinsics id, ENodeList *args, HashNameNode *name) { + ENode *arg1; + TypeTable22 *table; + Type *typeA; + Type *typeB; + Type *rtype; + + arg1 = args->node; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB = arg1->rtype; + typeA = table->arg1; + if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) { + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + } + if (promotable_types_are_equal(typeA, typeB)) + break; + } + + rtype = table->rtype; + if (!rtype) { + PPCError_Error(PPCErrorStr104, name->name, name->name, arg1->rtype, 0); + rtype = NULL; + } + return rtype; +} + +static Type *Intrinsics_VerifyNoVectorArgs(Intrinsics id, HashNameNode *name) { + TypeTable11 *table = typeTable[id - Intrinsic_042]; + return table->rtype; +} + +static Type *Intrinsics_Verify1VectorArg(Intrinsics id, ENodeList *args, HashNameNode *name) { + ENode *arg1; + TypeTable21 *table; + Type *typeA; + Type *typeB; + Type *rtype; + + arg1 = args->node; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB = arg1->rtype; + typeA = table->arg1; + if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) { + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + } + if (promotable_types_are_equal(typeA, typeB)) + break; + } + + switch (id) { + case Intrinsic_104: + case Intrinsic_105: + case Intrinsic_106: + case Intrinsic_107: + case Intrinsic_108: + case Intrinsic_109: + case Intrinsic_269: + case Intrinsic_270: + case Intrinsic_271: + if (ENODE_IS(arg1, EINTCONST)) { + SInt32 val = arg1->data.intval.lo; + if (val > 15 || val < -16) { + PPCError_Error(PPCErrorStr108, name->name, name->name, 5); + return NULL; + } + } else { + PPCError_Error(PPCErrorStr108, name->name, name->name, 5); + return NULL; + } + break; + case Intrinsic_058: + if (ENODE_IS(arg1, EINTCONST)) { + SInt32 val = arg1->data.intval.lo; + if (val > 3 || val < 0) { + PPCError_Error(PPCErrorStr108, name->name, name->name, 2); + return NULL; + } + } else { + PPCError_Error(PPCErrorStr108, name->name, name->name, 2); + return NULL; + } + break; + } + + rtype = table->rtype; + if (!rtype) { + PPCError_Error(PPCErrorStr104, name->name, name->name, arg1->rtype, 0); + rtype = NULL; + } + return rtype; +} + +static Type *Intrinsics_Verify2VectorArgs(Intrinsics id, ENodeList *args, HashNameNode *name) { + ENode *arg1; + ENode *arg2; + TypeTable31 *table; + Type *typeB1; + Type *typeB2; + Type *typeA1; + Type *typeA2; + + arg1 = args->node; + arg2 = args->next->node; + table = typeTable[id - Intrinsic_042]; + + switch (id) { + case Intrinsic_055: + case Intrinsic_056: + case Intrinsic_057: + case Intrinsic_103: + case Intrinsic_190: + case Intrinsic_191: + case Intrinsic_192: + case Intrinsic_193: + case Intrinsic_266: + case Intrinsic_267: + case Intrinsic_268: + if (ENODE_IS(arg2, EINTCONST)) { + if (arg2->data.intval.lo > 31 || arg2->data.intval.hi < 0) { + PPCError_Error(PPCErrorStr108, name->name, name->name, 5); + return NULL; + } + } else { + PPCError_Error(PPCErrorStr108, name->name, name->name, 5); + return NULL; + } + break; + } + + for (; table->rtype; table++) { + typeB1 = arg1->rtype; + typeB2 = arg2->rtype; + typeA1 = table->arg1; + typeA2 = table->arg2; + if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) { + typeA1 = TPTR_TARGET(typeA1); + typeB1 = TPTR_TARGET(typeB1); + } + if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) { + typeA2 = TPTR_TARGET(typeA2); + typeB2 = TPTR_TARGET(typeB2); + } + if (promotable_types_are_equal(typeA1, typeB1) && + promotable_types_are_equal(typeA2, typeB2)) + break; + } + + if (!table->rtype) { + PPCError_Error(PPCErrorStr105, name->name, name->name, arg1->rtype, 0, arg2->rtype, 0); + return NULL; + } + + switch (id) { + case Intrinsic_066: + case Intrinsic_067: + case Intrinsic_068: + if (arg2->flags & ENODE_FLAG_VOLATILE) + PPCError_Warning(PPCErrorStr178, name->name); + } + + return table->rtype; +} + +static Type *Intrinsics_Verify3VectorArgs(Intrinsics id, ENodeList *args, HashNameNode *name) { + ENode *arg1; + ENode *arg2; + ENode *arg3; + TypeTable41 *table; + Type *typeB1; + Type *typeB2; + Type *typeB3; + Type *typeA1; + Type *typeA2; + Type *typeA3; + + arg1 = args->node; + arg2 = args->next->node; + arg3 = args->next->next->node; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB1 = arg1->rtype; + typeB2 = arg2->rtype; + typeB3 = arg3->rtype; + typeA1 = table->arg1; + typeA2 = table->arg2; + typeA3 = table->arg3; + if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) { + typeA1 = TPTR_TARGET(typeA1); + typeB1 = TPTR_TARGET(typeB1); + } + if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) { + typeA2 = TPTR_TARGET(typeA2); + typeB2 = TPTR_TARGET(typeB2); + } + if (IS_TYPE_POINTER(typeA3) && IS_TYPE_POINTER(typeB3)) { + typeA3 = TPTR_TARGET(typeA3); + typeB3 = TPTR_TARGET(typeB3); + } + if (promotable_types_are_equal(typeA1, typeB1) && + promotable_types_are_equal(typeA2, typeB2) && + promotable_types_are_equal(typeA3, typeB3)) + break; + } + + switch (id) { + case Intrinsic_060: + case Intrinsic_061: + case Intrinsic_062: + case Intrinsic_063: + if (ENODE_IS(arg3, EINTCONST)) { + SInt32 val = arg3->data.intval.lo; + if (val > 3 || val < 0) { + PPCError_Error(PPCErrorStr108, name->name, name->name, 2); + return NULL; + } + } else { + PPCError_Error(PPCErrorStr108, name->name, name->name, 2); + return NULL; + } + break; + case Intrinsic_100: + case Intrinsic_263: + if (ENODE_IS(arg3, EINTCONST)) { + if (arg3->data.intval.lo > 15 || arg3->data.intval.hi < 0) { + PPCError_Error(PPCErrorStr108, name->name, name->name, 4); + return NULL; + } + } else { + PPCError_Error(PPCErrorStr108, name->name, name->name, 4); + return NULL; + } + break; + } + + if (!table->rtype) { + PPCError_Error(PPCErrorStr106, name->name, name->name, arg1->rtype, 0, arg2->rtype, 0, arg3->rtype, 0); + return NULL; + } + + switch (id) { + case Intrinsic_114: + case Intrinsic_115: + case Intrinsic_116: + if (arg3->flags & ENODE_FLAG_VOLATILE) + PPCError_Warning(PPCErrorStr178, name->name); + } + + return table->rtype; +} + +static Opcode Intrinsics_FindOpcodeNoArgs(Intrinsics id, ENode *funccall) { + TypeTable11 *table = typeTable[id - Intrinsic_042]; + return table->opcode; +} + +static Opcode Intrinsics_FindOpcode1Arg(Intrinsics id, ENode *funccall, ENode *arg1) { + TypeTable21 *table; + Type *typeA; + Type *typeB; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB = arg1->rtype; + typeA = table->arg1; + if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) { + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + } + if (promotable_types_are_equal(typeA, typeB)) + break; + } + + CError_ASSERT(4105, table->rtype); + return table->opcode; +} + +static Opcode Intrinsics_FindOpcode2Args(Intrinsics id, ENode *funccall, ENode *arg1, ENode *arg2) { + TypeTable31 *table; + Type *typeB1; + Type *typeB2; + Type *typeA1; + Type *typeA2; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB1 = arg1->rtype; + typeB2 = arg2->rtype; + typeA1 = table->arg1; + typeA2 = table->arg2; + if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) { + typeA1 = TPTR_TARGET(typeA1); + typeB1 = TPTR_TARGET(typeB1); + } + if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) { + typeA2 = TPTR_TARGET(typeA2); + typeB2 = TPTR_TARGET(typeB2); + } + if (promotable_types_are_equal(typeA1, typeB1) && + promotable_types_are_equal(typeA2, typeB2)) + break; + } + + CError_ASSERT(4144, table->rtype); + return table->opcode; +} + +static Opcode Intrinsics_FindOpcode3Args(Intrinsics id, ENode *funccall, ENode *arg1, ENode *arg2, ENode *arg3) { + TypeTable41 *table; + Type *typeB1; + Type *typeB2; + Type *typeB3; + Type *typeA1; + Type *typeA2; + Type *typeA3; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB1 = arg1->rtype; + typeB2 = arg2->rtype; + typeB3 = arg3->rtype; + typeA1 = table->arg1; + typeA2 = table->arg2; + typeA3 = table->arg3; + if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) { + typeA1 = TPTR_TARGET(typeA1); + typeB1 = TPTR_TARGET(typeB1); + } + if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) { + typeA2 = TPTR_TARGET(typeA2); + typeB2 = TPTR_TARGET(typeB2); + } + if (IS_TYPE_POINTER(typeA3) && IS_TYPE_POINTER(typeB3)) { + typeA3 = TPTR_TARGET(typeA3); + typeB3 = TPTR_TARGET(typeB3); + } + if (promotable_types_are_equal(typeA1, typeB1) && + promotable_types_are_equal(typeA2, typeB2) && + promotable_types_are_equal(typeA3, typeB3)) + break; + } + + CError_ASSERT(4191, table->rtype); + return table->opcode; +} + +static void vector_intrinsic_no_args(Opcode opcode) { + emitpcode(opcode); +} + +static void vector_intrinsic_mfvscr(short outputReg, Opcode opcode, Operand *output) { + short reg; + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_1arg(ENode *arg1, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + short reg; + + memclrw(&op1, sizeof(op1)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.reg); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_splats(ENode *arg1, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + short reg; + + memclrw(&op1, sizeof(op1)); + CError_ASSERT(4253, ENODE_IS(arg1, EINTCONST)); + GEN_NODE(arg1, &op1); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.immediate); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_splatu8(ENode *arg1, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + short reg; + + memclrw(&op1, sizeof(op1)); + CError_ASSERT(4277, ENODE_IS(arg1, EINTCONST)); + GEN_NODE(arg1, &op1); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.immediate); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_splatu16(ENode *arg1, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + short reg; + + memclrw(&op1, sizeof(op1)); + CError_ASSERT(4301, ENODE_IS(arg1, EINTCONST)); + GEN_NODE(arg1, &op1); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.immediate); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_splatu32(ENode *arg1, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + short reg; + + memclrw(&op1, sizeof(op1)); + CError_ASSERT(4325, ENODE_IS(arg1, EINTCONST)); + GEN_NODE(arg1, &op1); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.immediate); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_dss(ENode *arg1) { + Operand op1; + + memclrw(&op1, sizeof(op1)); + CError_ASSERT(4348, ENODE_IS(arg1, EINTCONST)); + GEN_NODE(arg1, &op1); + + emitpcode(PC_DSS, op1.immediate, 0); +} + +static void vector_intrinsic_2args(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + Operand op2; + short reg; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.reg, op2.reg); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_2args1const(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + Operand op2; + short reg; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + CError_ASSERT(4393, ENODE_IS(arg2, EINTCONST)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + GEN_NODE(arg2, &op2); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.reg, op2.immediate); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_3args(ENode *arg1, ENode *arg2, ENode *arg3, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + Operand op2; + Operand op3; + short reg; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + memclrw(&op3, sizeof(op3)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0); + GEN_NODE_TO_VR(arg3, &op3, arg3->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.reg, op2.reg, op3.reg); + + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_datastream(ENode *arg1, ENode *arg2, ENode *arg3, Opcode opcode) { + Operand op1; + Operand op2; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + CError_ASSERT(4445, ENODE_IS(arg3, EINTCONST)); + GEN_NODE_TO_GPR(arg1, &op1, arg1->rtype, 0); + GEN_NODE_TO_GPR(arg2, &op2, arg2->rtype, 0); + + switch (opcode) { + case PC_DST: + case PC_DSTST: + emitpcode(opcode, op1.reg, op2.reg, arg3->data.intval.lo, 0); + break; + case PC_DSTT: + case PC_DSTSTT: + emitpcode(opcode, op1.reg, op2.reg, arg3->data.intval.lo); + break; + default: + CError_FATAL(4463); + } +} + +static void vector_intrinsic_sld(ENode *arg1, ENode *arg2, ENode *arg3, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + Operand op2; + short reg; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + CError_ASSERT(4479, ENODE_IS(arg3, EINTCONST)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0); + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.reg, op2.reg, arg3->data.intval.lo); + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_load(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + Operand op2; + short reg; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + + GEN_NODE(arg1, &op1); + if (op1.optype == OpndType_Absolute && op1.immediate == 0) { + op1.optype = OpndType_GPR; + op1.reg = 0; + } else { + ENSURE_GPR(&op1, arg1->rtype, 0); + } + + GEN_NODE(arg2, &op2); + if (op2.optype == OpndType_Absolute && op2.immediate == 0 && op1.reg != 0) { + op2 = op1; + op1.optype = OpndType_GPR; + op1.reg = 0; + } else { + ENSURE_GPR(&op2, arg2->rtype, 0); + } + + reg = outputReg ? outputReg : ALLOC_VR(); + + emitpcode(opcode, reg, op1.reg, op2.reg); + output->optype = OpndType_VR; + output->reg = reg; +} + +static void vector_intrinsic_store(ENode *arg1, ENode *arg2, ENode *arg3, short outputReg, Operand *output, Opcode opcode) { + Operand op1; + Operand op2; + Operand op3; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + memclrw(&op3, sizeof(op3)); + + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + + GEN_NODE(arg2, &op2); + if (op2.optype == OpndType_Absolute && op2.immediate == 0) { + op2.optype = OpndType_GPR; + op2.reg = 0; + } else { + ENSURE_GPR(&op2, arg2->rtype, 0); + } + + GEN_NODE(arg3, &op3); + if (op3.optype == OpndType_Absolute && op3.immediate == 0 && op2.reg != 0) { + op3 = op2; + op2.optype = OpndType_GPR; + op2.reg = 0; + } else { + ENSURE_GPR(&op3, arg3->rtype, 0); + } + + emitpcode(opcode, op1.reg, op2.reg, op3.reg); + output->optype = OpndType_VR; + output->reg = op1.reg; +} + +static void vector_intrinsic_abs(Intrinsics id, ENode *funccall, ENode *arg1, short outputReg, Operand *output) { + TypeTable22 *table; + Type *typeA; + Type *typeB; + short reg1; + short reg2; + short reg3; + Operand op1; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB = arg1->rtype; + typeA = table->arg1; + if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) { + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + } + if (promotable_types_are_equal(typeA, typeB)) + break; + } + + CError_ASSERT(4617, table->rtype); + + reg1 = ALLOC_VR(); + reg2 = ALLOC_VR(); + reg3 = outputReg ? outputReg : ALLOC_VR(); + + memclrw(&op1, sizeof(op1)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + + if (arg1->rtype == TYPE(&stvectorfloat)) { + emitpcode(PC_VSPLTISW, reg1, -1); + emitpcode(PC_VSLW, reg2, reg1, reg1); + emitpcode(table->opcode1, reg3, op1.reg, reg2); + } else { + emitpcode(PC_VSPLTISB, reg1, 0); + emitpcode(table->opcode1, reg2, reg1, op1.reg); + emitpcode(table->opcode2, reg3, op1.reg, reg2); + } + + output->optype = OpndType_VR; + output->reg = reg3; +} + +static void vector_intrinsic_abss(Intrinsics id, ENode *funccall, ENode *arg1, short outputReg, Operand *output) { + TypeTable22 *table; + Type *typeA; + Type *typeB; + short reg1; + short reg2; + short reg3; + Operand op1; + + for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) { + typeB = arg1->rtype; + typeA = table->arg1; + if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) { + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + } + if (promotable_types_are_equal(typeA, typeB)) + break; + } + + CError_ASSERT(4683, table->rtype); + + reg1 = ALLOC_VR(); + reg2 = ALLOC_VR(); + reg3 = outputReg ? outputReg : ALLOC_VR(); + + memclrw(&op1, sizeof(op1)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + + emitpcode(PC_VSPLTISB, reg1, 0); + emitpcode(table->opcode1, reg2, reg1, op1.reg); + emitpcode(table->opcode2, reg3, op1.reg, reg2); + + output->optype = OpndType_VR; + output->reg = reg3; +} + +static void vector_intrinsic_mtvscr(ENode *arg1, Operand *output, Opcode opcode) { + Operand op1; + + memclrw(&op1, sizeof(op1)); + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + emitpcode(opcode, op1.reg); +} + +static void vector_predicate_2args(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode, Intrinsics id) { + Operand op1; + Operand op2; + short reg1; + short reg2; + short reg3; + Opcode cond; + + memclrw(&op1, sizeof(op1)); + memclrw(&op2, sizeof(op2)); + + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0); + + reg1 = ALLOC_VR(); + reg2 = op1.reg; + reg3 = op2.reg; + if ( + ((id == Intrinsic_132 || id == Intrinsic_145) && arg1->rtype != TYPE(&stvectorfloat)) || + ((id == Intrinsic_135 || id == Intrinsic_147) && arg1->rtype == TYPE(&stvectorfloat)) || + id == Intrinsic_136 || + id == Intrinsic_148 || + id == Intrinsic_153 || + id == Intrinsic_141 || + id == Intrinsic_142 || + id == Intrinsic_154 + ) + { + reg3 = op1.reg; + reg2 = op2.reg; + } + emitpcode(opcode, reg1, reg2, reg3); + pcsetrecordbit(pclastblock->lastPCode); + + if (arg1->rtype == TYPE(&stvectorfloat)) { + switch (id) { + case Intrinsic_131: + case Intrinsic_132: + case Intrinsic_133: + case Intrinsic_135: + case Intrinsic_136: + cond = ELESS; + break; + case Intrinsic_150: + case Intrinsic_151: + case Intrinsic_152: + case Intrinsic_153: + case Intrinsic_154: + cond = EGREATEREQU; + break; + case Intrinsic_134: + case Intrinsic_138: + case Intrinsic_139: + case Intrinsic_140: + case Intrinsic_141: + case Intrinsic_142: + cond = EEQU; + break; + case Intrinsic_144: + case Intrinsic_145: + case Intrinsic_146: + case Intrinsic_147: + case Intrinsic_148: + case Intrinsic_156: + cond = ENOTEQU; + break; + default: + CError_FATAL(4805); + } + } else { + switch (id) { + case Intrinsic_131: + case Intrinsic_133: + case Intrinsic_136: + cond = ELESS; + break; + case Intrinsic_144: + case Intrinsic_146: + case Intrinsic_148: + cond = ENOTEQU; + break; + case Intrinsic_132: + case Intrinsic_135: + case Intrinsic_138: + cond = EEQU; + break; + case Intrinsic_145: + case Intrinsic_147: + case Intrinsic_150: + cond = EGREATEREQU; + break; + default: + CError_FATAL(4834); + } + } + + output->optype = OpndType_CRField; + output->reg = 6; + output->regOffset = cond; +} + +static void vector_predicate_1arg(ENode *arg1, short outputReg, Operand *output, Opcode opcode, Intrinsics id) { + Operand op1; + short reg; + Opcode cond; + + memclrw(&op1, sizeof(op1)); + + GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0); + + reg = ALLOC_VR(); + emitpcode(opcode, reg, op1.reg, op1.reg); + pcsetrecordbit(pclastblock->lastPCode); + + switch (id) { + case Intrinsic_143: + cond = ELESS; + break; + case Intrinsic_149: + cond = EGREATEREQU; + break; + case Intrinsic_137: + cond = EEQU; + break; + case Intrinsic_155: + cond = ENOTEQU; + break; + default: + CError_FATAL(4878); + } + + output->optype = OpndType_CRField; + output->reg = 6; + output->regOffset = cond; +} + +ENode *Intrinsics_HandleIntrinsicCall(Object *func, ENodeList *args) { + ENode *callexpr; + Type *rtype; + Intrinsics id; + + callexpr = NULL; + + if (copts.altivec_model) { + id = func->u.func.u.intrinsicid; + switch (id) { + case Intrinsic_060: + case Intrinsic_061: + case Intrinsic_062: + case Intrinsic_063: + case Intrinsic_072: + case Intrinsic_073: + case Intrinsic_079: + case Intrinsic_080: + case Intrinsic_081: + case Intrinsic_082: + case Intrinsic_086: + case Intrinsic_093: + case Intrinsic_098: + case Intrinsic_100: + case Intrinsic_114: + case Intrinsic_115: + case Intrinsic_116: + case Intrinsic_202: + case Intrinsic_203: + case Intrinsic_224: + case Intrinsic_225: + case Intrinsic_226: + case Intrinsic_227: + case Intrinsic_228: + case Intrinsic_229: + case Intrinsic_230: + case Intrinsic_231: + case Intrinsic_240: + case Intrinsic_252: + case Intrinsic_259: + case Intrinsic_263: + case Intrinsic_280: + case Intrinsic_281: + case Intrinsic_282: + case Intrinsic_283: + case Intrinsic_284: + if (Intrinsics_VerifyParameterCount(3, args, func->name)) { + if ((rtype = Intrinsics_Verify3VectorArgs(id, args, func->name))) + callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype); + } + break; + case Intrinsic_042: + case Intrinsic_043: + case Intrinsic_044: + case Intrinsic_045: + case Intrinsic_046: + case Intrinsic_047: + case Intrinsic_049: + case Intrinsic_050: + case Intrinsic_051: + case Intrinsic_052: + case Intrinsic_053: + case Intrinsic_054: + case Intrinsic_055: + case Intrinsic_056: + case Intrinsic_057: + case Intrinsic_066: + case Intrinsic_067: + case Intrinsic_068: + case Intrinsic_070: + case Intrinsic_071: + case Intrinsic_074: + case Intrinsic_075: + case Intrinsic_076: + case Intrinsic_078: + case Intrinsic_084: + case Intrinsic_085: + case Intrinsic_087: + case Intrinsic_088: + case Intrinsic_089: + case Intrinsic_090: + case Intrinsic_091: + case Intrinsic_092: + case Intrinsic_095: + case Intrinsic_099: + case Intrinsic_101: + case Intrinsic_102: + case Intrinsic_103: + case Intrinsic_110: + case Intrinsic_111: + case Intrinsic_112: + case Intrinsic_113: + case Intrinsic_117: + case Intrinsic_118: + case Intrinsic_119: + case Intrinsic_120: + case Intrinsic_121: + case Intrinsic_122: + case Intrinsic_124: + case Intrinsic_125: + case Intrinsic_126: + case Intrinsic_127: + case Intrinsic_130: + case Intrinsic_131: + case Intrinsic_132: + case Intrinsic_133: + case Intrinsic_134: + case Intrinsic_135: + case Intrinsic_136: + case Intrinsic_138: + case Intrinsic_139: + case Intrinsic_140: + case Intrinsic_141: + case Intrinsic_142: + case Intrinsic_144: + case Intrinsic_145: + case Intrinsic_146: + case Intrinsic_147: + case Intrinsic_148: + case Intrinsic_150: + case Intrinsic_151: + case Intrinsic_152: + case Intrinsic_153: + case Intrinsic_154: + case Intrinsic_156: + case Intrinsic_157: + case Intrinsic_158: + case Intrinsic_159: + case Intrinsic_160: + case Intrinsic_161: + case Intrinsic_162: + case Intrinsic_163: + case Intrinsic_164: + case Intrinsic_165: + case Intrinsic_166: + case Intrinsic_167: + case Intrinsic_168: + case Intrinsic_169: + case Intrinsic_170: + case Intrinsic_171: + case Intrinsic_172: + case Intrinsic_173: + case Intrinsic_174: + case Intrinsic_175: + case Intrinsic_177: + case Intrinsic_178: + case Intrinsic_179: + case Intrinsic_180: + case Intrinsic_181: + case Intrinsic_182: + case Intrinsic_183: + case Intrinsic_184: + case Intrinsic_185: + case Intrinsic_186: + case Intrinsic_187: + case Intrinsic_188: + case Intrinsic_189: + case Intrinsic_190: + case Intrinsic_191: + case Intrinsic_192: + case Intrinsic_193: + case Intrinsic_196: + case Intrinsic_197: + case Intrinsic_198: + case Intrinsic_199: + case Intrinsic_200: + case Intrinsic_204: + case Intrinsic_205: + case Intrinsic_206: + case Intrinsic_207: + case Intrinsic_208: + case Intrinsic_209: + case Intrinsic_210: + case Intrinsic_211: + case Intrinsic_212: + case Intrinsic_213: + case Intrinsic_214: + case Intrinsic_215: + case Intrinsic_216: + case Intrinsic_217: + case Intrinsic_218: + case Intrinsic_219: + case Intrinsic_220: + case Intrinsic_221: + case Intrinsic_222: + case Intrinsic_223: + case Intrinsic_232: + case Intrinsic_233: + case Intrinsic_234: + case Intrinsic_235: + case Intrinsic_236: + case Intrinsic_237: + case Intrinsic_238: + case Intrinsic_239: + case Intrinsic_241: + case Intrinsic_242: + case Intrinsic_243: + case Intrinsic_244: + case Intrinsic_245: + case Intrinsic_246: + case Intrinsic_247: + case Intrinsic_248: + case Intrinsic_249: + case Intrinsic_250: + case Intrinsic_251: + case Intrinsic_254: + case Intrinsic_255: + case Intrinsic_256: + case Intrinsic_260: + case Intrinsic_261: + case Intrinsic_262: + case Intrinsic_264: + case Intrinsic_265: + case Intrinsic_266: + case Intrinsic_267: + case Intrinsic_268: + case Intrinsic_272: + case Intrinsic_273: + case Intrinsic_274: + case Intrinsic_275: + case Intrinsic_276: + case Intrinsic_277: + case Intrinsic_278: + case Intrinsic_279: + case Intrinsic_285: + case Intrinsic_286: + case Intrinsic_287: + case Intrinsic_288: + case Intrinsic_289: + case Intrinsic_290: + case Intrinsic_291: + case Intrinsic_292: + case Intrinsic_293: + case Intrinsic_294: + case Intrinsic_295: + case Intrinsic_296: + case Intrinsic_297: + case Intrinsic_298: + case Intrinsic_299: + case Intrinsic_300: + case Intrinsic_308: + if (Intrinsics_VerifyParameterCount(2, args, func->name)) { + if ((rtype = Intrinsics_Verify2VectorArgs(id, args, func->name))) + callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype); + } + break; + case Intrinsic_048: + case Intrinsic_058: + case Intrinsic_064: + case Intrinsic_065: + case Intrinsic_069: + case Intrinsic_083: + case Intrinsic_094: + case Intrinsic_096: + case Intrinsic_097: + case Intrinsic_104: + case Intrinsic_105: + case Intrinsic_106: + case Intrinsic_107: + case Intrinsic_108: + case Intrinsic_109: + case Intrinsic_123: + case Intrinsic_128: + case Intrinsic_129: + case Intrinsic_137: + case Intrinsic_143: + case Intrinsic_149: + case Intrinsic_155: + case Intrinsic_176: + case Intrinsic_194: + case Intrinsic_195: + case Intrinsic_201: + case Intrinsic_253: + case Intrinsic_257: + case Intrinsic_258: + case Intrinsic_269: + case Intrinsic_270: + case Intrinsic_271: + case Intrinsic_301: + case Intrinsic_302: + case Intrinsic_303: + case Intrinsic_304: + case Intrinsic_305: + case Intrinsic_306: + case Intrinsic_307: + if (Intrinsics_VerifyParameterCount(1, args, func->name)) { + if ((rtype = Intrinsics_Verify1VectorArg(id, args, func->name))) + callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype); + } + break; + case Intrinsic_059: + case Intrinsic_077: + if (Intrinsics_VerifyParameterCount(0, args, func->name)) { + if ((rtype = Intrinsics_VerifyNoVectorArgs(id, func->name))) + callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype); + } + break; + case Intrinsic_309: + case Intrinsic_310: + if (Intrinsics_VerifyParameterCount(1, args, func->name)) { + if ((rtype = Intrinsics_Verify1VectorArg2Ops(id, args, func->name))) + callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype); + } + break; + } + } + + return callexpr; +} + +void call_intrinsic_function(ENode *funccall, short outputReg, Operand *output) { + ENodeList *args; + Object *object; + Intrinsics id; + Opcode op; + short reg; + + static Opcode opcode[MaxIntrinsics] = { + /* Intrinsic_000 */ PC_EIEIO, + /* Intrinsic_001 */ PC_SYNC, + /* Intrinsic_002 */ PC_ISYNC, + 0, + 0, + /* Intrinsic_005 */ PC_FABS, + /* Intrinsic_006 */ PC_FNABS, + 0, + 0, + /* Intrinsic_009 */ PC_CNTLZW, + /* Intrinsic_010 */ PC_LHBRX, + /* Intrinsic_011 */ PC_LWBRX, + /* Intrinsic_012 */ PC_STHBRX, + /* Intrinsic_013 */ PC_STWBRX, + /* Intrinsic_014 */ PC_DCBF, + /* Intrinsic_015 */ PC_DCBT, + /* Intrinsic_016 */ PC_DCBST, + /* Intrinsic_017 */ PC_DCBTST, + /* Intrinsic_018 */ PC_DCBZ, + /* Intrinsic_019 */ PC_MULHW, + /* Intrinsic_020 */ PC_MULHWU, + /* Intrinsic_021 */ PC_DIVW, + /* Intrinsic_022 */ PC_DIVWU, + /* Intrinsic_023 */ PC_FMADD, + /* Intrinsic_024 */ PC_FMSUB, + /* Intrinsic_025 */ PC_FNMADD, + /* Intrinsic_026 */ PC_FNMSUB, + /* Intrinsic_027 */ PC_FMADDS, + /* Intrinsic_028 */ PC_FMSUBS, + /* Intrinsic_029 */ PC_FNMADDS, + /* Intrinsic_030 */ PC_FNMSUBS, + /* Intrinsic_031 */ PC_MFFS, + /* Intrinsic_032 */ PC_FRES, + /* Intrinsic_033 */ PC_FRSQRTE, + /* Intrinsic_004 */ PC_FSEL, + 0, + 0, + /* Intrinsic_037 */ PC_RLWIMI, + /* Intrinsic_038 */ PC_RLWINM, + /* Intrinsic_039 */ PC_RLWNM, + /* Intrinsic_040 */ PC_FABS, + /* Intrinsic_041 */ PC_FNABS + }; + + args = funccall->data.funccall.args; + object = funccall->data.funccall.funcref->data.objref; + id = object->u.func.u.intrinsicid; + cur_intrinsic_object = object; + + switch (id) { + case Intrinsic_000: + case Intrinsic_001: + case Intrinsic_002: + appendpcode(pclastblock, makepcode(opcode[id])); + output->optype = OpndType_Absolute; + break; + case Intrinsic_003: + case Intrinsic_004: + abs_intrinsic(args->node, outputReg, output); + break; + case Intrinsic_005: + case Intrinsic_006: + case Intrinsic_032: + case Intrinsic_033: + case Intrinsic_040: + case Intrinsic_041: + fp_unary_operator(opcode[id], args->node, outputReg, output); + break; + case Intrinsic_007: + setflm_intrinsic(args->node, outputReg, output, funccall->ignored); + break; + case Intrinsic_008: + alloca_intrinsic(args->node, outputReg, output); + break; + case Intrinsic_009: + unary_operator(PC_CNTLZW, args->node, outputReg, output); + break; + case Intrinsic_010: + case Intrinsic_011: + load_bytereversed_intrinsic(opcode[id], args->node, args->next->node, outputReg, output); + break; + case Intrinsic_012: + case Intrinsic_013: + store_bytereversed_intrinsic(opcode[id], args->node, args->next->node, args->next->next->node); + output->optype = OpndType_Absolute; + break; + case Intrinsic_014: + case Intrinsic_015: + case Intrinsic_016: + case Intrinsic_017: + case Intrinsic_018: + data_cache_block_intrinsic(opcode[id], args->node, args->next->node); + output->optype = OpndType_Absolute; + break; + case Intrinsic_019: + case Intrinsic_020: + case Intrinsic_021: + case Intrinsic_022: + binary_operator(opcode[id], args->node, args->next->node, outputReg, output); + break; + case Intrinsic_023: + case Intrinsic_024: + case Intrinsic_025: + case Intrinsic_026: + case Intrinsic_027: + case Intrinsic_028: + case Intrinsic_029: + case Intrinsic_030: + case Intrinsic_034: + fp_multiply_add(opcode[id], + args->node, args->next->node, args->next->next->node, + outputReg, output); + break; + case Intrinsic_031: + reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(PC_MFFS, output->reg = reg); + output->optype = OpndType_FPR; + break; + case Intrinsic_035: + call_function(funccall, output); + break; + case Intrinsic_036: + if (ENODE_IS(args->next->next->node, EINTCONST)) + memcpy_intrinsic( + args->node, args->next->node, args->next->next->node->data.intval.lo, + funccall->ignored, output); + else + call_function(funccall, output); + break; + case Intrinsic_037: + rlwimi_intrinsic( + args->node, + args->next->node, + args->next->next->node, + args->next->next->next->node, + args->next->next->next->next->node, + outputReg, output); + break; + case Intrinsic_038: + rlwinm_intrinsic( + args->node, + args->next->node, + args->next->next->node, + args->next->next->next->node, + outputReg, output); + break; + case Intrinsic_039: + rlwnm_intrinsic( + args->node, + args->next->node, + args->next->next->node, + args->next->next->next->node, + outputReg, output); + break; + case Intrinsic_072: + case Intrinsic_073: + case Intrinsic_079: + case Intrinsic_080: + case Intrinsic_081: + case Intrinsic_082: + case Intrinsic_086: + case Intrinsic_093: + case Intrinsic_098: + case Intrinsic_202: + case Intrinsic_203: + case Intrinsic_224: + case Intrinsic_225: + case Intrinsic_226: + case Intrinsic_227: + case Intrinsic_228: + case Intrinsic_229: + case Intrinsic_230: + case Intrinsic_231: + case Intrinsic_240: + case Intrinsic_252: + case Intrinsic_259: + op = Intrinsics_FindOpcode3Args(id, funccall, args->node, args->next->node, args->next->next->node); + vector_intrinsic_3args(args->node, args->next->node, args->next->next->node, outputReg, output, op); + break; + case Intrinsic_100: + case Intrinsic_263: + op = Intrinsics_FindOpcode3Args(id, funccall, args->node, args->next->node, args->next->next->node); + vector_intrinsic_sld(args->node, args->next->node, args->next->next->node, outputReg, output, op); + break; + case Intrinsic_042: + case Intrinsic_043: + case Intrinsic_044: + case Intrinsic_045: + case Intrinsic_046: + case Intrinsic_047: + case Intrinsic_049: + case Intrinsic_050: + case Intrinsic_051: + case Intrinsic_053: + case Intrinsic_074: + case Intrinsic_075: + case Intrinsic_076: + case Intrinsic_078: + case Intrinsic_084: + case Intrinsic_085: + case Intrinsic_087: + case Intrinsic_088: + case Intrinsic_089: + case Intrinsic_090: + case Intrinsic_091: + case Intrinsic_092: + case Intrinsic_095: + case Intrinsic_099: + case Intrinsic_101: + case Intrinsic_102: + case Intrinsic_110: + case Intrinsic_111: + case Intrinsic_112: + case Intrinsic_113: + case Intrinsic_117: + case Intrinsic_118: + case Intrinsic_119: + case Intrinsic_120: + case Intrinsic_121: + case Intrinsic_122: + case Intrinsic_124: + case Intrinsic_125: + case Intrinsic_126: + case Intrinsic_127: + case Intrinsic_130: + case Intrinsic_157: + case Intrinsic_158: + case Intrinsic_159: + case Intrinsic_160: + case Intrinsic_161: + case Intrinsic_162: + case Intrinsic_163: + case Intrinsic_164: + case Intrinsic_165: + case Intrinsic_166: + case Intrinsic_167: + case Intrinsic_168: + case Intrinsic_169: + case Intrinsic_170: + case Intrinsic_171: + case Intrinsic_172: + case Intrinsic_173: + case Intrinsic_174: + case Intrinsic_175: + case Intrinsic_177: + case Intrinsic_178: + case Intrinsic_179: + case Intrinsic_180: + case Intrinsic_181: + case Intrinsic_182: + case Intrinsic_183: + case Intrinsic_184: + case Intrinsic_185: + case Intrinsic_186: + case Intrinsic_187: + case Intrinsic_188: + case Intrinsic_189: + case Intrinsic_204: + case Intrinsic_205: + case Intrinsic_206: + case Intrinsic_207: + case Intrinsic_208: + case Intrinsic_209: + case Intrinsic_210: + case Intrinsic_211: + case Intrinsic_212: + case Intrinsic_213: + case Intrinsic_214: + case Intrinsic_215: + case Intrinsic_216: + case Intrinsic_217: + case Intrinsic_218: + case Intrinsic_219: + case Intrinsic_220: + case Intrinsic_221: + case Intrinsic_222: + case Intrinsic_223: + case Intrinsic_232: + case Intrinsic_233: + case Intrinsic_234: + case Intrinsic_235: + case Intrinsic_236: + case Intrinsic_237: + case Intrinsic_238: + case Intrinsic_239: + case Intrinsic_241: + case Intrinsic_242: + case Intrinsic_243: + case Intrinsic_244: + case Intrinsic_245: + case Intrinsic_246: + case Intrinsic_247: + case Intrinsic_248: + case Intrinsic_249: + case Intrinsic_250: + case Intrinsic_251: + case Intrinsic_254: + case Intrinsic_255: + case Intrinsic_256: + case Intrinsic_260: + case Intrinsic_261: + case Intrinsic_262: + case Intrinsic_264: + case Intrinsic_265: + case Intrinsic_272: + case Intrinsic_273: + case Intrinsic_274: + case Intrinsic_275: + case Intrinsic_276: + case Intrinsic_277: + case Intrinsic_278: + case Intrinsic_279: + case Intrinsic_285: + case Intrinsic_286: + case Intrinsic_287: + case Intrinsic_288: + case Intrinsic_289: + case Intrinsic_290: + case Intrinsic_291: + case Intrinsic_292: + case Intrinsic_293: + case Intrinsic_294: + case Intrinsic_295: + case Intrinsic_296: + case Intrinsic_297: + case Intrinsic_298: + case Intrinsic_299: + case Intrinsic_300: + case Intrinsic_308: + op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node); + vector_intrinsic_2args(args->node, args->next->node, outputReg, output, op); + break; + case Intrinsic_048: + case Intrinsic_064: + case Intrinsic_065: + case Intrinsic_069: + case Intrinsic_094: + case Intrinsic_096: + case Intrinsic_097: + case Intrinsic_123: + case Intrinsic_128: + case Intrinsic_129: + case Intrinsic_176: + case Intrinsic_194: + case Intrinsic_195: + case Intrinsic_201: + case Intrinsic_253: + case Intrinsic_257: + case Intrinsic_258: + case Intrinsic_301: + case Intrinsic_302: + case Intrinsic_303: + case Intrinsic_304: + case Intrinsic_305: + case Intrinsic_306: + case Intrinsic_307: + op = Intrinsics_FindOpcode1Arg(id, funccall, args->node); + vector_intrinsic_1arg(args->node, outputReg, output, op); + break; + case Intrinsic_055: + case Intrinsic_056: + case Intrinsic_057: + case Intrinsic_103: + case Intrinsic_190: + case Intrinsic_191: + case Intrinsic_192: + case Intrinsic_193: + case Intrinsic_266: + case Intrinsic_267: + case Intrinsic_268: + op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node); + vector_intrinsic_2args1const(args->node, args->next->node, outputReg, output, op); + break; + case Intrinsic_104: + case Intrinsic_105: + case Intrinsic_106: + case Intrinsic_269: + case Intrinsic_270: + case Intrinsic_271: + op = Intrinsics_FindOpcode1Arg(id, funccall, args->node); + vector_intrinsic_splats(args->node, outputReg, output, op); + break; + case Intrinsic_107: + op = Intrinsics_FindOpcode1Arg(id, funccall, args->node); + vector_intrinsic_splatu8(args->node, outputReg, output, op); + break; + case Intrinsic_108: + op = Intrinsics_FindOpcode1Arg(id, funccall, args->node); + vector_intrinsic_splatu16(args->node, outputReg, output, op); + break; + case Intrinsic_109: + op = Intrinsics_FindOpcode1Arg(id, funccall, args->node); + vector_intrinsic_splatu32(args->node, outputReg, output, op); + break; + case Intrinsic_083: + vector_intrinsic_mtvscr(args->node, output, PC_MTVSCR); + break; + case Intrinsic_077: + op = Intrinsics_FindOpcodeNoArgs(id, funccall); + vector_intrinsic_mfvscr(outputReg, op, output); + break; + case Intrinsic_058: + vector_intrinsic_dss(args->node); + break; + case Intrinsic_059: + op = Intrinsics_FindOpcodeNoArgs(id, funccall); + vector_intrinsic_no_args(op); + break; + case Intrinsic_060: + case Intrinsic_061: + case Intrinsic_062: + case Intrinsic_063: + switch (id) { + case Intrinsic_060: + op = PC_DST; + break; + case Intrinsic_061: + op = PC_DSTST; + break; + case Intrinsic_062: + op = PC_DSTSTT; + break; + case Intrinsic_063: + op = PC_DSTT; + break; + } + vector_intrinsic_datastream(args->node, args->next->node, args->next->next->node, op); + break; + case Intrinsic_066: + case Intrinsic_067: + case Intrinsic_068: + case Intrinsic_070: + case Intrinsic_071: + case Intrinsic_196: + case Intrinsic_197: + case Intrinsic_198: + case Intrinsic_199: + case Intrinsic_200: + op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node); + vector_intrinsic_load(args->node, args->next->node, outputReg, output, op); + break; + case Intrinsic_114: + case Intrinsic_115: + case Intrinsic_116: + case Intrinsic_280: + case Intrinsic_281: + case Intrinsic_282: + case Intrinsic_283: + case Intrinsic_284: + op = Intrinsics_FindOpcode3Args(id, funccall, args->node, args->next->node, args->next->next->node); + vector_intrinsic_store(args->node, args->next->node, args->next->next->node, outputReg, output, op); + break; + case Intrinsic_131: + case Intrinsic_132: + case Intrinsic_133: + case Intrinsic_134: + case Intrinsic_135: + case Intrinsic_136: + case Intrinsic_138: + case Intrinsic_139: + case Intrinsic_140: + case Intrinsic_141: + case Intrinsic_142: + case Intrinsic_144: + case Intrinsic_145: + case Intrinsic_146: + case Intrinsic_147: + case Intrinsic_148: + case Intrinsic_150: + case Intrinsic_151: + case Intrinsic_152: + case Intrinsic_153: + case Intrinsic_154: + case Intrinsic_156: + op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node); + vector_predicate_2args(args->node, args->next->node, outputReg, output, op, id); + break; + case Intrinsic_137: + case Intrinsic_143: + case Intrinsic_149: + case Intrinsic_155: + op = Intrinsics_FindOpcode1Arg(id, funccall, args->node); + vector_predicate_1arg(args->node, outputReg, output, op, id); + break; + case Intrinsic_309: + vector_intrinsic_abs(id, funccall, args->node, outputReg, output); + break; + case Intrinsic_310: + vector_intrinsic_abss(id, funccall, args->node, outputReg, output); + break; + case Intrinsic_052: + case Intrinsic_054: + op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node); + vector_intrinsic_2args(args->node, args->next->node, outputReg, output, op); + break; + default: + CError_FATAL(6152); + } +} + +void Intrinsics_SetupRuntimeObjects(void) { + static TypePointer char_ptr = {TYPEPOINTER, 4, TYPE(&stchar), 0}; + Boolean savecpp; + int i; + + savecpp = copts.cplusplus; + copts.cplusplus = 0; + + for (i = 0; i < MaxIntrinsics; i++) + intrinsics[i] = NULL; + + intrinsics[Intrinsic_000] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__eieio"), 0, 0); + intrinsics[Intrinsic_001] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__sync"), 0, 0); + intrinsics[Intrinsic_002] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__isync"), 0, 0); + intrinsics[Intrinsic_003] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__abs"), 0, 1, &stsignedint); + intrinsics[Intrinsic_004] = CParser_NewRTFunc(TYPE(&stsignedlong), GetHashNameNodeExport("__labs"), 0, 1, &stsignedlong); + intrinsics[Intrinsic_005] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fabs"), 0, 1, &stdouble); + intrinsics[Intrinsic_006] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fnabs"), 0, 1, &stdouble); + intrinsics[Intrinsic_007] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__setflm"), 0, 1, &stdouble); + intrinsics[Intrinsic_033] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__frsqrte"), 0, 1, &stdouble); + intrinsics[Intrinsic_008] = CParser_NewRTFunc(TYPE(&void_ptr), GetHashNameNodeExport("__alloca"), 0, 1, &stunsignedint); + intrinsics[Intrinsic_009] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__cntlzw"), 0, 1, &stunsignedint); + intrinsics[Intrinsic_010] = CParser_NewRTFunc(TYPE(&stunsignedint), GetHashNameNodeExport("__lhbrx"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_011] = CParser_NewRTFunc(TYPE(&stunsignedint), GetHashNameNodeExport("__lwbrx"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_012] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__sthbrx"), 0, 3, &stunsignedshort, &void_ptr, &stsignedint); + intrinsics[Intrinsic_013] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__stwbrx"), 0, 3, &stunsignedint, &void_ptr, &stsignedint); + intrinsics[Intrinsic_014] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbf"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_015] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbt"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_016] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbst"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_017] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbtst"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_018] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbz"), 0, 2, &void_ptr, &stsignedint); + intrinsics[Intrinsic_019] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__mulhw"), 0, 2, &stsignedint, &stsignedint); + intrinsics[Intrinsic_020] = CParser_NewRTFunc(TYPE(&stunsignedint), GetHashNameNodeExport("__mulhwu"), 0, 2, &stunsignedint, &stunsignedint); + intrinsics[Intrinsic_021] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__divw"), 0, 2, &stsignedint, &stsignedint); + intrinsics[Intrinsic_022] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__divwu"), 0, 2, &stsignedint, &stsignedint); + intrinsics[Intrinsic_023] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fmadd"), 0, 3, &stdouble, &stdouble, &stdouble); + intrinsics[Intrinsic_024] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fmsub"), 0, 3, &stdouble, &stdouble, &stdouble); + intrinsics[Intrinsic_025] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fnmadd"), 0, 3, &stdouble, &stdouble, &stdouble); + intrinsics[Intrinsic_026] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fnmsub"), 0, 3, &stdouble, &stdouble, &stdouble); + intrinsics[Intrinsic_034] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fsel"), 0, 3, &stdouble, &stdouble, &stdouble); + intrinsics[Intrinsic_027] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fmadds"), 0, 3, &stfloat, &stfloat, &stfloat); + intrinsics[Intrinsic_028] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fmsubs"), 0, 3, &stfloat, &stfloat, &stfloat); + intrinsics[Intrinsic_029] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fnmadds"), 0, 3, &stfloat, &stfloat, &stfloat); + intrinsics[Intrinsic_030] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fnmsubs"), 0, 3, &stfloat, &stfloat, &stfloat); + intrinsics[Intrinsic_031] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__mffs"), 0, 0); + intrinsics[Intrinsic_032] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fres"), 0, 1, &stfloat); + intrinsics[Intrinsic_040] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fabsf"), 0, 1, &stfloat); + intrinsics[Intrinsic_041] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fnabsf"), 0, 1, &stfloat); + intrinsics[Intrinsic_035] = CParser_NewRTFunc(TYPE(&char_ptr), GetHashNameNodeExport("__strcpy"), 0, 2, &char_ptr, &char_ptr); + TYPE_FUNC(intrinsics[Intrinsic_035]->type)->args->next->qual |= Q_CONST; + intrinsics[Intrinsic_036] = CParser_NewRTFunc(TYPE(&void_ptr), GetHashNameNodeExport("__memcpy"), 0, 3, &void_ptr, &void_ptr, &stunsignedlong); + __memcpy_object = intrinsics[Intrinsic_036]; + TYPE_FUNC(intrinsics[Intrinsic_036]->type)->args->next->qual |= Q_CONST; + intrinsics[Intrinsic_037] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__rlwimi"), 0, 5, &stsignedint, &stsignedint, &stsignedint, &stsignedint, &stsignedint); + intrinsics[Intrinsic_038] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__rlwinm"), 0, 4, &stsignedint, &stsignedint, &stsignedint, &stsignedint); + intrinsics[Intrinsic_039] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__rlwnm"), 0, 4, &stsignedint, &stsignedint, &stsignedint, &stsignedint); + intrinsics[Intrinsic_042] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_add"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_043] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_addc"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_044] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_adds"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_045] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_and"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_046] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_andc"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_047] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_avg"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_048] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ceil"), 0, 1, &stvector); + intrinsics[Intrinsic_049] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_050] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpeq"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_051] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpge"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_052] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmple"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_053] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpgt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_054] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmplt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_055] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ctf"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_056] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cts"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_057] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ctu"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_058] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dss"), 0, 1, &stsignedint); + intrinsics[Intrinsic_059] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dssall"), 0, 0); + intrinsics[Intrinsic_060] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dst"), 0, 3, &stvector, &stsignedint, &stsignedint); + intrinsics[Intrinsic_061] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dstst"), 0, 3, &stvector, &stsignedint, &stsignedint); + intrinsics[Intrinsic_062] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dststt"), 0, 3, &stvector, &stsignedint, &stsignedint); + intrinsics[Intrinsic_063] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dstt"), 0, 3, &stvector, &stsignedint, &stsignedint); + intrinsics[Intrinsic_064] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_expte"), 0, 1, &stvector); + intrinsics[Intrinsic_065] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_floor"), 0, 1, &stvector); + intrinsics[Intrinsic_066] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ld"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_067] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lde"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_068] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ldl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_069] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_loge"), 0, 1, &stvector); + intrinsics[Intrinsic_070] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvsl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_071] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvsr"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_072] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_madd"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_073] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_madds"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_074] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_max"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_075] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mergeh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_076] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mergel"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_077] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mfvscr"), 0, 0); + intrinsics[Intrinsic_078] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_min"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_079] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mladd"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_080] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mradds"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_081] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_msum"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_082] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_msums"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_083] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mtvscr"), 0, 1, &stvector); + intrinsics[Intrinsic_084] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mule"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_085] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mulo"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_086] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_nmsub"), 0, 2, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_087] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_nor"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_088] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_or"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_089] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_pack"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_090] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_packpx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_091] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_packs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_092] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_packsu"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_093] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_perm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_094] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_re"), 0, 1, &stvector); + intrinsics[Intrinsic_095] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_rl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_096] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_round"), 0, 1, &stvector); + intrinsics[Intrinsic_097] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_rsqrte"), 0, 1, &stvector); + intrinsics[Intrinsic_098] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sel"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_099] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_100] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sld"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_101] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sll"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_102] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_slo"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_103] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_104] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_s8"), 0, 1, &stvector); + intrinsics[Intrinsic_105] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_s16"), 0, 1, &stvector); + intrinsics[Intrinsic_106] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_s32"), 0, 1, &stvector); + intrinsics[Intrinsic_107] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_u8"), 0, 1, &stvector); + intrinsics[Intrinsic_108] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_u16"), 0, 1, &stvector); + intrinsics[Intrinsic_109] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_u32"), 0, 1, &stvector); + intrinsics[Intrinsic_110] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sr"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_111] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sra"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_112] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_srl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_113] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sro"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_114] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_st"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_115] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ste"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_116] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stl"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_117] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_118] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_subc"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_119] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_subs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_120] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sum4s"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_121] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sum2s"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_122] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sums"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_123] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_trunc"), 0, 1, &stvector); + intrinsics[Intrinsic_124] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2sh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_125] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2sl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_126] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2uh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_127] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2ul"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_128] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpackh"), 0, 1, &stvector); + intrinsics[Intrinsic_129] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpackl"), 0, 1, &stvector); + intrinsics[Intrinsic_130] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_xor"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_131] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_eq"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_132] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_ge"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_133] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_gt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_134] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_in"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_135] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_le"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_136] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_lt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_137] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nan"), 0, 1, &stvector); + intrinsics[Intrinsic_138] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_ne"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_139] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nge"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_140] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_ngt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_141] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nle"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_142] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nlt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_143] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_numeric"), 0, 1, &stvector); + intrinsics[Intrinsic_144] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_eq"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_145] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_ge"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_146] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_gt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_147] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_le"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_148] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_lt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_149] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nan"), 0, 1, &stvector); + intrinsics[Intrinsic_150] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_ne"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_151] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nge"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_152] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_ngt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_153] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nle"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_154] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nlt"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_155] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_numeric"), 0, 1, &stvector); + intrinsics[Intrinsic_156] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_out"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_157] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddubm"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_158] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduhm"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_159] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduwm"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_160] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_161] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddcuw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_162] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddubs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_163] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddsbs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_164] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduhs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_165] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddshs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_166] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduws"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_167] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddsws"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_168] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vand"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_169] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vandc"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_170] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_171] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgsb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_172] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavguh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_173] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgsh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_174] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavguw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_175] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgsw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_176] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfip"), 0, 1, &stvector); + intrinsics[Intrinsic_177] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpbfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_178] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpequb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_179] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpequh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_180] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpequw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_181] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpeqfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_182] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgefp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_183] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_184] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtsb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_185] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtuh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_186] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtsh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_187] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtuw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_188] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtsw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_189] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_190] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcfux"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_191] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcfsx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_192] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vctsxs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_193] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vctuxs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_194] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vexptefp"), 0, 1, &stvector); + intrinsics[Intrinsic_195] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfim"), 0, 1, &stvector); + intrinsics[Intrinsic_196] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_197] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvebx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_198] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvehx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_199] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvewx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_200] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvxl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_201] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vlogefp"), 0, 1, &stvector); + intrinsics[Intrinsic_202] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaddfp"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_203] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmhaddshs"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_204] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_205] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxsb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_206] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxuh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_207] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxsh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_208] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxuw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_209] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxsw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_210] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_211] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrghb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_212] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrghh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_213] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrghw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_214] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrglb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_215] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrglh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_216] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrglw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_217] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_218] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminsb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_219] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminuh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_220] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminsh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_221] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminuw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_222] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminsw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_223] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_224] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmladduhm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_225] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmhraddshs"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_226] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumubm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_227] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumuhm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_228] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsummbm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_229] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumshm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_230] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumuhs"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_231] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumshs"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_232] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmuleub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_233] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulesb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_234] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmuleuh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_235] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulesh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_236] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmuloub"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_237] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulosb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_238] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulouh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_239] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulosh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_240] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vnmsubfp"), 0, 2, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_241] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vnor"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_242] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vor"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_243] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuhum"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_244] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuwum"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_245] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkpx"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_246] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuhus"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_247] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkshss"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_248] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuwus"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_249] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkswss"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_250] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkshus"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_251] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkswus"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_252] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vperm"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_253] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrefp"), 0, 1, &stvector); + intrinsics[Intrinsic_254] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrlb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_255] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrlh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_256] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrlw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_257] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfin"), 0, 1, &stvector); + intrinsics[Intrinsic_258] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrsqrtefp"), 0, 1, &stvector); + intrinsics[Intrinsic_259] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsel"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_260] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_261] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_262] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_263] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsldoi"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_264] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsl"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_265] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslo"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_266] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_267] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsplth"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_268] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_269] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltisb"), 0, 1, &stvector); + intrinsics[Intrinsic_270] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltish"), 0, 1, &stvector); + intrinsics[Intrinsic_271] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltisw"), 0, 1, &stvector); + intrinsics[Intrinsic_272] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrb"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_273] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrh"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_274] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_275] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrab"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_276] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrah"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_277] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsraw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_278] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsr"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_279] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsro"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_280] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvx"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_281] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvebx"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_282] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvehx"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_283] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvewx"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_284] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvxl"), 0, 3, &stvector, &stvector, &stvector); + intrinsics[Intrinsic_285] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsububm"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_286] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuhm"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_287] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuwm"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_288] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubfp"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_289] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubcuw"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_290] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsububs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_291] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubsbs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_292] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuhs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_293] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubshs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_294] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuws"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_295] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubsws"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_296] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum4ubs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_297] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum4sbs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_298] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum4shs"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_299] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum2sws"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_300] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsumsws"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_301] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfiz"), 0, 1, &stvector); + intrinsics[Intrinsic_302] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupkhsb"), 0, 1, &stvector); + intrinsics[Intrinsic_303] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupklsb"), 0, 1, &stvector); + intrinsics[Intrinsic_304] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupkhpx"), 0, 1, &stvector); + intrinsics[Intrinsic_305] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupklpx"), 0, 1, &stvector); + intrinsics[Intrinsic_306] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupkhsh"), 0, 1, &stvector); + intrinsics[Intrinsic_307] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupklsh"), 0, 1, &stvector); + intrinsics[Intrinsic_308] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vxor"), 0, 2, &stvector, &stvector); + intrinsics[Intrinsic_309] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_abs"), 0, 1, &stvector); + intrinsics[Intrinsic_310] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_abss"), 0, 1, &stvector); + + for (i = 0; i < MaxIntrinsics; i++) { + CError_ASSERT(6600, intrinsics[i]); + intrinsics[i]->u.func.u.intrinsicid = i; + TYPE_FUNC(intrinsics[i]->type)->flags |= FUNC_INTRINSIC; + CScope_AddGlobalObject(intrinsics[i]); + } + + copts.cplusplus = savecpp; +} + +static Object *CheckRuntimeObject(char *name) { + NameSpaceName *nsname = CScope_FindNameSpaceName(cscope_root, GetHashNameNodeExport(name)); + + if (!nsname) + return NULL; + + if (nsname->first.object && nsname->first.next == NULL) + return OBJECT(nsname->first.object); + + return NULL; +} + +Boolean Intrinsics_ReInitRuntimeObjects(Boolean flag) { + if (flag) { + if (!(intrinsics[Intrinsic_000] = CheckRuntimeObject("__eieio"))) return 0; + if (!(intrinsics[Intrinsic_001] = CheckRuntimeObject("__sync"))) return 0; + if (!(intrinsics[Intrinsic_002] = CheckRuntimeObject("__isync"))) return 0; + if (!(intrinsics[Intrinsic_003] = CheckRuntimeObject("__abs"))) return 0; + if (!(intrinsics[Intrinsic_004] = CheckRuntimeObject("__labs"))) return 0; + if (!(intrinsics[Intrinsic_005] = CheckRuntimeObject("__fabs"))) return 0; + if (!(intrinsics[Intrinsic_006] = CheckRuntimeObject("__fnabs"))) return 0; + if (!(intrinsics[Intrinsic_007] = CheckRuntimeObject("__setflm"))) return 0; + if (!(intrinsics[Intrinsic_033] = CheckRuntimeObject("__frsqrte"))) return 0; + if (!(intrinsics[Intrinsic_008] = CheckRuntimeObject("__alloca"))) return 0; + if (!(intrinsics[Intrinsic_009] = CheckRuntimeObject("__cntlzw"))) return 0; + if (!(intrinsics[Intrinsic_010] = CheckRuntimeObject("__lhbrx"))) return 0; + if (!(intrinsics[Intrinsic_011] = CheckRuntimeObject("__lwbrx"))) return 0; + if (!(intrinsics[Intrinsic_012] = CheckRuntimeObject("__sthbrx"))) return 0; + if (!(intrinsics[Intrinsic_013] = CheckRuntimeObject("__stwbrx"))) return 0; + if (!(intrinsics[Intrinsic_014] = CheckRuntimeObject("__dcbf"))) return 0; + if (!(intrinsics[Intrinsic_015] = CheckRuntimeObject("__dcbt"))) return 0; + if (!(intrinsics[Intrinsic_016] = CheckRuntimeObject("__dcbst"))) return 0; + if (!(intrinsics[Intrinsic_017] = CheckRuntimeObject("__dcbtst"))) return 0; + if (!(intrinsics[Intrinsic_018] = CheckRuntimeObject("__dcbz"))) return 0; + if (!(intrinsics[Intrinsic_019] = CheckRuntimeObject("__mulhw"))) return 0; + if (!(intrinsics[Intrinsic_020] = CheckRuntimeObject("__mulhwu"))) return 0; + if (!(intrinsics[Intrinsic_021] = CheckRuntimeObject("__divw"))) return 0; + if (!(intrinsics[Intrinsic_022] = CheckRuntimeObject("__divwu"))) return 0; + if (!(intrinsics[Intrinsic_023] = CheckRuntimeObject("__fmadd"))) return 0; + if (!(intrinsics[Intrinsic_024] = CheckRuntimeObject("__fmsub"))) return 0; + if (!(intrinsics[Intrinsic_025] = CheckRuntimeObject("__fnmadd"))) return 0; + if (!(intrinsics[Intrinsic_026] = CheckRuntimeObject("__fnmsub"))) return 0; + if (!(intrinsics[Intrinsic_034] = CheckRuntimeObject("__fsel"))) return 0; + if (!(intrinsics[Intrinsic_027] = CheckRuntimeObject("__fmadds"))) return 0; + if (!(intrinsics[Intrinsic_028] = CheckRuntimeObject("__fmsubs"))) return 0; + if (!(intrinsics[Intrinsic_029] = CheckRuntimeObject("__fnmadds"))) return 0; + if (!(intrinsics[Intrinsic_030] = CheckRuntimeObject("__fnmsubs"))) return 0; + if (!(intrinsics[Intrinsic_031] = CheckRuntimeObject("__mffs"))) return 0; + if (!(intrinsics[Intrinsic_032] = CheckRuntimeObject("__fres"))) return 0; + if (!(intrinsics[Intrinsic_040] = CheckRuntimeObject("__fabsf"))) return 0; + if (!(intrinsics[Intrinsic_041] = CheckRuntimeObject("__fnabsf"))) return 0; + if (!(intrinsics[Intrinsic_035] = CheckRuntimeObject("__strcpy"))) return 0; + if (!(intrinsics[Intrinsic_037] = CheckRuntimeObject("__rlwimi"))) return 0; + if (!(intrinsics[Intrinsic_038] = CheckRuntimeObject("__rlwinm"))) return 0; + if (!(intrinsics[Intrinsic_039] = CheckRuntimeObject("__rlwnm"))) return 0; + if (!(intrinsics[Intrinsic_042] = CheckRuntimeObject("vec_add"))) return 0; + if (!(intrinsics[Intrinsic_043] = CheckRuntimeObject("vec_addc"))) return 0; + if (!(intrinsics[Intrinsic_044] = CheckRuntimeObject("vec_adds"))) return 0; + if (!(intrinsics[Intrinsic_045] = CheckRuntimeObject("vec_and"))) return 0; + if (!(intrinsics[Intrinsic_046] = CheckRuntimeObject("vec_andc"))) return 0; + if (!(intrinsics[Intrinsic_047] = CheckRuntimeObject("vec_avg"))) return 0; + if (!(intrinsics[Intrinsic_048] = CheckRuntimeObject("vec_ceil"))) return 0; + if (!(intrinsics[Intrinsic_049] = CheckRuntimeObject("vec_cmpb"))) return 0; + if (!(intrinsics[Intrinsic_050] = CheckRuntimeObject("vec_cmpeq"))) return 0; + if (!(intrinsics[Intrinsic_051] = CheckRuntimeObject("vec_cmpge"))) return 0; + if (!(intrinsics[Intrinsic_052] = CheckRuntimeObject("vec_cmple"))) return 0; + if (!(intrinsics[Intrinsic_053] = CheckRuntimeObject("vec_cmpgt"))) return 0; + if (!(intrinsics[Intrinsic_054] = CheckRuntimeObject("vec_cmplt"))) return 0; + if (!(intrinsics[Intrinsic_055] = CheckRuntimeObject("vec_ctf"))) return 0; + if (!(intrinsics[Intrinsic_056] = CheckRuntimeObject("vec_cts"))) return 0; + if (!(intrinsics[Intrinsic_057] = CheckRuntimeObject("vec_ctu"))) return 0; + if (!(intrinsics[Intrinsic_064] = CheckRuntimeObject("vec_expte"))) return 0; + if (!(intrinsics[Intrinsic_065] = CheckRuntimeObject("vec_floor"))) return 0; + if (!(intrinsics[Intrinsic_066] = CheckRuntimeObject("vec_ld"))) return 0; + if (!(intrinsics[Intrinsic_067] = CheckRuntimeObject("vec_lde"))) return 0; + if (!(intrinsics[Intrinsic_068] = CheckRuntimeObject("vec_ldl"))) return 0; + if (!(intrinsics[Intrinsic_069] = CheckRuntimeObject("vec_loge"))) return 0; + if (!(intrinsics[Intrinsic_070] = CheckRuntimeObject("vec_lvsl"))) return 0; + if (!(intrinsics[Intrinsic_071] = CheckRuntimeObject("vec_lvsr"))) return 0; + if (!(intrinsics[Intrinsic_072] = CheckRuntimeObject("vec_madd"))) return 0; + if (!(intrinsics[Intrinsic_073] = CheckRuntimeObject("vec_madds"))) return 0; + if (!(intrinsics[Intrinsic_074] = CheckRuntimeObject("vec_max"))) return 0; + if (!(intrinsics[Intrinsic_075] = CheckRuntimeObject("vec_mergeh"))) return 0; + if (!(intrinsics[Intrinsic_076] = CheckRuntimeObject("vec_mergel"))) return 0; + if (!(intrinsics[Intrinsic_077] = CheckRuntimeObject("vec_mfvscr"))) return 0; + if (!(intrinsics[Intrinsic_078] = CheckRuntimeObject("vec_min"))) return 0; + if (!(intrinsics[Intrinsic_079] = CheckRuntimeObject("vec_mladd"))) return 0; + if (!(intrinsics[Intrinsic_080] = CheckRuntimeObject("vec_mradds"))) return 0; + if (!(intrinsics[Intrinsic_081] = CheckRuntimeObject("vec_msum"))) return 0; + if (!(intrinsics[Intrinsic_082] = CheckRuntimeObject("vec_msums"))) return 0; + if (!(intrinsics[Intrinsic_083] = CheckRuntimeObject("vec_mtvscr"))) return 0; + if (!(intrinsics[Intrinsic_084] = CheckRuntimeObject("vec_mule"))) return 0; + if (!(intrinsics[Intrinsic_085] = CheckRuntimeObject("vec_mulo"))) return 0; + if (!(intrinsics[Intrinsic_086] = CheckRuntimeObject("vec_nmsub"))) return 0; + if (!(intrinsics[Intrinsic_087] = CheckRuntimeObject("vec_nor"))) return 0; + if (!(intrinsics[Intrinsic_088] = CheckRuntimeObject("vec_or"))) return 0; + if (!(intrinsics[Intrinsic_089] = CheckRuntimeObject("vec_pack"))) return 0; + if (!(intrinsics[Intrinsic_090] = CheckRuntimeObject("vec_packpx"))) return 0; + if (!(intrinsics[Intrinsic_091] = CheckRuntimeObject("vec_packs"))) return 0; + if (!(intrinsics[Intrinsic_092] = CheckRuntimeObject("vec_packsu"))) return 0; + if (!(intrinsics[Intrinsic_093] = CheckRuntimeObject("vec_perm"))) return 0; + if (!(intrinsics[Intrinsic_094] = CheckRuntimeObject("vec_re"))) return 0; + if (!(intrinsics[Intrinsic_095] = CheckRuntimeObject("vec_rl"))) return 0; + if (!(intrinsics[Intrinsic_096] = CheckRuntimeObject("vec_round"))) return 0; + if (!(intrinsics[Intrinsic_097] = CheckRuntimeObject("vec_rsqrte"))) return 0; + if (!(intrinsics[Intrinsic_098] = CheckRuntimeObject("vec_sel"))) return 0; + if (!(intrinsics[Intrinsic_099] = CheckRuntimeObject("vec_sl"))) return 0; + if (!(intrinsics[Intrinsic_100] = CheckRuntimeObject("vec_sld"))) return 0; + if (!(intrinsics[Intrinsic_101] = CheckRuntimeObject("vec_sll"))) return 0; + if (!(intrinsics[Intrinsic_102] = CheckRuntimeObject("vec_slo"))) return 0; + if (!(intrinsics[Intrinsic_103] = CheckRuntimeObject("vec_splat"))) return 0; + if (!(intrinsics[Intrinsic_104] = CheckRuntimeObject("vec_splat_s8"))) return 0; + if (!(intrinsics[Intrinsic_105] = CheckRuntimeObject("vec_splat_s16"))) return 0; + if (!(intrinsics[Intrinsic_106] = CheckRuntimeObject("vec_splat_s32"))) return 0; + if (!(intrinsics[Intrinsic_107] = CheckRuntimeObject("vec_splat_u8"))) return 0; + if (!(intrinsics[Intrinsic_108] = CheckRuntimeObject("vec_splat_u16"))) return 0; + if (!(intrinsics[Intrinsic_109] = CheckRuntimeObject("vec_splat_u32"))) return 0; + if (!(intrinsics[Intrinsic_110] = CheckRuntimeObject("vec_sr"))) return 0; + if (!(intrinsics[Intrinsic_111] = CheckRuntimeObject("vec_sra"))) return 0; + if (!(intrinsics[Intrinsic_112] = CheckRuntimeObject("vec_srl"))) return 0; + if (!(intrinsics[Intrinsic_113] = CheckRuntimeObject("vec_sro"))) return 0; + if (!(intrinsics[Intrinsic_114] = CheckRuntimeObject("vec_st"))) return 0; + if (!(intrinsics[Intrinsic_115] = CheckRuntimeObject("vec_ste"))) return 0; + if (!(intrinsics[Intrinsic_116] = CheckRuntimeObject("vec_stl"))) return 0; + if (!(intrinsics[Intrinsic_117] = CheckRuntimeObject("vec_sub"))) return 0; + if (!(intrinsics[Intrinsic_118] = CheckRuntimeObject("vec_subc"))) return 0; + if (!(intrinsics[Intrinsic_119] = CheckRuntimeObject("vec_subs"))) return 0; + if (!(intrinsics[Intrinsic_120] = CheckRuntimeObject("vec_sum4s"))) return 0; + if (!(intrinsics[Intrinsic_121] = CheckRuntimeObject("vec_sum2s"))) return 0; + if (!(intrinsics[Intrinsic_122] = CheckRuntimeObject("vec_sums"))) return 0; + if (!(intrinsics[Intrinsic_123] = CheckRuntimeObject("vec_trunc"))) return 0; + if (!(intrinsics[Intrinsic_124] = CheckRuntimeObject("vec_unpack2sh"))) return 0; + if (!(intrinsics[Intrinsic_125] = CheckRuntimeObject("vec_unpack2sl"))) return 0; + if (!(intrinsics[Intrinsic_126] = CheckRuntimeObject("vec_unpack2uh"))) return 0; + if (!(intrinsics[Intrinsic_127] = CheckRuntimeObject("vec_unpack2ul"))) return 0; + if (!(intrinsics[Intrinsic_128] = CheckRuntimeObject("vec_unpackh"))) return 0; + if (!(intrinsics[Intrinsic_129] = CheckRuntimeObject("vec_unpackl"))) return 0; + if (!(intrinsics[Intrinsic_130] = CheckRuntimeObject("vec_xor"))) return 0; + if (!(intrinsics[Intrinsic_131] = CheckRuntimeObject("vec_all_eq"))) return 0; + if (!(intrinsics[Intrinsic_132] = CheckRuntimeObject("vec_all_ge"))) return 0; + if (!(intrinsics[Intrinsic_133] = CheckRuntimeObject("vec_all_gt"))) return 0; + if (!(intrinsics[Intrinsic_134] = CheckRuntimeObject("vec_all_in"))) return 0; + if (!(intrinsics[Intrinsic_135] = CheckRuntimeObject("vec_all_le"))) return 0; + if (!(intrinsics[Intrinsic_136] = CheckRuntimeObject("vec_all_lt"))) return 0; + if (!(intrinsics[Intrinsic_137] = CheckRuntimeObject("vec_all_nan"))) return 0; + if (!(intrinsics[Intrinsic_138] = CheckRuntimeObject("vec_all_ne"))) return 0; + if (!(intrinsics[Intrinsic_139] = CheckRuntimeObject("vec_all_nge"))) return 0; + if (!(intrinsics[Intrinsic_140] = CheckRuntimeObject("vec_all_ngt"))) return 0; + if (!(intrinsics[Intrinsic_141] = CheckRuntimeObject("vec_all_nle"))) return 0; + if (!(intrinsics[Intrinsic_142] = CheckRuntimeObject("vec_all_nlt"))) return 0; + if (!(intrinsics[Intrinsic_143] = CheckRuntimeObject("vec_all_numeric"))) return 0; + if (!(intrinsics[Intrinsic_144] = CheckRuntimeObject("vec_any_eq"))) return 0; + if (!(intrinsics[Intrinsic_145] = CheckRuntimeObject("vec_any_ge"))) return 0; + if (!(intrinsics[Intrinsic_146] = CheckRuntimeObject("vec_any_gt"))) return 0; + if (!(intrinsics[Intrinsic_147] = CheckRuntimeObject("vec_any_le"))) return 0; + if (!(intrinsics[Intrinsic_148] = CheckRuntimeObject("vec_any_lt"))) return 0; + if (!(intrinsics[Intrinsic_149] = CheckRuntimeObject("vec_any_nan"))) return 0; + if (!(intrinsics[Intrinsic_150] = CheckRuntimeObject("vec_any_ne"))) return 0; + if (!(intrinsics[Intrinsic_151] = CheckRuntimeObject("vec_any_nge"))) return 0; + if (!(intrinsics[Intrinsic_152] = CheckRuntimeObject("vec_any_ngt"))) return 0; + if (!(intrinsics[Intrinsic_153] = CheckRuntimeObject("vec_any_nle"))) return 0; + if (!(intrinsics[Intrinsic_154] = CheckRuntimeObject("vec_any_nlt"))) return 0; + if (!(intrinsics[Intrinsic_155] = CheckRuntimeObject("vec_any_numeric"))) return 0; + if (!(intrinsics[Intrinsic_156] = CheckRuntimeObject("vec_any_out"))) return 0; + if (!(intrinsics[Intrinsic_157] = CheckRuntimeObject("vec_vaddubm"))) return 0; + if (!(intrinsics[Intrinsic_158] = CheckRuntimeObject("vec_vadduhm"))) return 0; + if (!(intrinsics[Intrinsic_159] = CheckRuntimeObject("vec_vadduwm"))) return 0; + if (!(intrinsics[Intrinsic_160] = CheckRuntimeObject("vec_vaddfp"))) return 0; + if (!(intrinsics[Intrinsic_161] = CheckRuntimeObject("vec_vaddcuw"))) return 0; + if (!(intrinsics[Intrinsic_162] = CheckRuntimeObject("vec_vaddubs"))) return 0; + if (!(intrinsics[Intrinsic_163] = CheckRuntimeObject("vec_vaddubs"))) return 0; + if (!(intrinsics[Intrinsic_164] = CheckRuntimeObject("vec_vadduhs"))) return 0; + if (!(intrinsics[Intrinsic_165] = CheckRuntimeObject("vec_vadduhs"))) return 0; + if (!(intrinsics[Intrinsic_166] = CheckRuntimeObject("vec_vadduws"))) return 0; + if (!(intrinsics[Intrinsic_167] = CheckRuntimeObject("vec_vadduws"))) return 0; + if (!(intrinsics[Intrinsic_168] = CheckRuntimeObject("vec_vand"))) return 0; + if (!(intrinsics[Intrinsic_169] = CheckRuntimeObject("vec_vandc"))) return 0; + if (!(intrinsics[Intrinsic_170] = CheckRuntimeObject("vec_vavgub"))) return 0; + if (!(intrinsics[Intrinsic_171] = CheckRuntimeObject("vec_vavgsb"))) return 0; + if (!(intrinsics[Intrinsic_172] = CheckRuntimeObject("vec_vavguh"))) return 0; + if (!(intrinsics[Intrinsic_173] = CheckRuntimeObject("vec_vavgsh"))) return 0; + if (!(intrinsics[Intrinsic_174] = CheckRuntimeObject("vec_vavguw"))) return 0; + if (!(intrinsics[Intrinsic_175] = CheckRuntimeObject("vec_vavgsw"))) return 0; + if (!(intrinsics[Intrinsic_176] = CheckRuntimeObject("vec_vrfip"))) return 0; + if (!(intrinsics[Intrinsic_177] = CheckRuntimeObject("vec_vcmpbfp"))) return 0; + if (!(intrinsics[Intrinsic_178] = CheckRuntimeObject("vec_vcmpequb"))) return 0; + if (!(intrinsics[Intrinsic_179] = CheckRuntimeObject("vec_vcmpequh"))) return 0; + if (!(intrinsics[Intrinsic_180] = CheckRuntimeObject("vec_vcmpequw"))) return 0; + if (!(intrinsics[Intrinsic_181] = CheckRuntimeObject("vec_vcmpeqfp"))) return 0; + if (!(intrinsics[Intrinsic_182] = CheckRuntimeObject("vec_vcmpgefp"))) return 0; + if (!(intrinsics[Intrinsic_183] = CheckRuntimeObject("vec_vcmpgtub"))) return 0; + if (!(intrinsics[Intrinsic_184] = CheckRuntimeObject("vec_vcmpgtsb"))) return 0; + if (!(intrinsics[Intrinsic_185] = CheckRuntimeObject("vec_vcmpgtuh"))) return 0; + if (!(intrinsics[Intrinsic_186] = CheckRuntimeObject("vec_vcmpgtsh"))) return 0; + if (!(intrinsics[Intrinsic_187] = CheckRuntimeObject("vec_vcmpgtuw"))) return 0; + if (!(intrinsics[Intrinsic_188] = CheckRuntimeObject("vec_vcmpgtsw"))) return 0; + if (!(intrinsics[Intrinsic_189] = CheckRuntimeObject("vec_vcmpgtfp"))) return 0; + if (!(intrinsics[Intrinsic_190] = CheckRuntimeObject("vec_vcfux"))) return 0; + if (!(intrinsics[Intrinsic_191] = CheckRuntimeObject("vec_vcfsx"))) return 0; + if (!(intrinsics[Intrinsic_192] = CheckRuntimeObject("vec_vctsxs"))) return 0; + if (!(intrinsics[Intrinsic_193] = CheckRuntimeObject("vec_vctuxs"))) return 0; + if (!(intrinsics[Intrinsic_194] = CheckRuntimeObject("vec_vexptefp"))) return 0; + if (!(intrinsics[Intrinsic_195] = CheckRuntimeObject("vec_vrfim"))) return 0; + if (!(intrinsics[Intrinsic_196] = CheckRuntimeObject("vec_lvx"))) return 0; + if (!(intrinsics[Intrinsic_197] = CheckRuntimeObject("vec_lvebx"))) return 0; + if (!(intrinsics[Intrinsic_198] = CheckRuntimeObject("vec_lvehx"))) return 0; + if (!(intrinsics[Intrinsic_199] = CheckRuntimeObject("vec_lvewx"))) return 0; + if (!(intrinsics[Intrinsic_200] = CheckRuntimeObject("vec_lvxl"))) return 0; + if (!(intrinsics[Intrinsic_201] = CheckRuntimeObject("vec_vlogefp"))) return 0; + if (!(intrinsics[Intrinsic_202] = CheckRuntimeObject("vec_vmaddfp"))) return 0; + if (!(intrinsics[Intrinsic_203] = CheckRuntimeObject("vec_vmhaddshs"))) return 0; + if (!(intrinsics[Intrinsic_204] = CheckRuntimeObject("vec_vmaxub"))) return 0; + if (!(intrinsics[Intrinsic_205] = CheckRuntimeObject("vec_vmaxsb"))) return 0; + if (!(intrinsics[Intrinsic_206] = CheckRuntimeObject("vec_vmaxuh"))) return 0; + if (!(intrinsics[Intrinsic_207] = CheckRuntimeObject("vec_vmaxsh"))) return 0; + if (!(intrinsics[Intrinsic_208] = CheckRuntimeObject("vec_vmaxuw"))) return 0; + if (!(intrinsics[Intrinsic_209] = CheckRuntimeObject("vec_vmaxsw"))) return 0; + if (!(intrinsics[Intrinsic_210] = CheckRuntimeObject("vec_vmaxfp"))) return 0; + if (!(intrinsics[Intrinsic_211] = CheckRuntimeObject("vec_vmrghb"))) return 0; + if (!(intrinsics[Intrinsic_212] = CheckRuntimeObject("vec_vmrghh"))) return 0; + if (!(intrinsics[Intrinsic_213] = CheckRuntimeObject("vec_vmrghw"))) return 0; + if (!(intrinsics[Intrinsic_214] = CheckRuntimeObject("vec_vmrglb"))) return 0; + if (!(intrinsics[Intrinsic_215] = CheckRuntimeObject("vec_vmrglh"))) return 0; + if (!(intrinsics[Intrinsic_216] = CheckRuntimeObject("vec_vmrglw"))) return 0; + if (!(intrinsics[Intrinsic_204] = CheckRuntimeObject("vec_vminub"))) return 0; + if (!(intrinsics[Intrinsic_205] = CheckRuntimeObject("vec_vminsb"))) return 0; + if (!(intrinsics[Intrinsic_206] = CheckRuntimeObject("vec_vminuh"))) return 0; + if (!(intrinsics[Intrinsic_207] = CheckRuntimeObject("vec_vminsh"))) return 0; + if (!(intrinsics[Intrinsic_208] = CheckRuntimeObject("vec_vminuw"))) return 0; + if (!(intrinsics[Intrinsic_209] = CheckRuntimeObject("vec_vminsw"))) return 0; + if (!(intrinsics[Intrinsic_210] = CheckRuntimeObject("vec_vminfp"))) return 0; + if (!(intrinsics[Intrinsic_224] = CheckRuntimeObject("vec_vmladduhm"))) return 0; + if (!(intrinsics[Intrinsic_225] = CheckRuntimeObject("vec_vmhraddshs"))) return 0; + if (!(intrinsics[Intrinsic_226] = CheckRuntimeObject("vec_vmsumubm"))) return 0; + if (!(intrinsics[Intrinsic_227] = CheckRuntimeObject("vec_vmsumuhm"))) return 0; + if (!(intrinsics[Intrinsic_228] = CheckRuntimeObject("vec_vmsummbm"))) return 0; + if (!(intrinsics[Intrinsic_229] = CheckRuntimeObject("vec_vmsumshm"))) return 0; + if (!(intrinsics[Intrinsic_230] = CheckRuntimeObject("vec_vmsumuhs"))) return 0; + if (!(intrinsics[Intrinsic_231] = CheckRuntimeObject("vec_vmsumshs"))) return 0; + if (!(intrinsics[Intrinsic_232] = CheckRuntimeObject("vec_vmuleub"))) return 0; + if (!(intrinsics[Intrinsic_233] = CheckRuntimeObject("vec_vmulesb"))) return 0; + if (!(intrinsics[Intrinsic_234] = CheckRuntimeObject("vec_vmuleuh"))) return 0; + if (!(intrinsics[Intrinsic_235] = CheckRuntimeObject("vec_vmulesh"))) return 0; + if (!(intrinsics[Intrinsic_236] = CheckRuntimeObject("vec_vmuloub"))) return 0; + if (!(intrinsics[Intrinsic_237] = CheckRuntimeObject("vec_vmulosb"))) return 0; + if (!(intrinsics[Intrinsic_238] = CheckRuntimeObject("vec_vmulouh"))) return 0; + if (!(intrinsics[Intrinsic_239] = CheckRuntimeObject("vec_vmulosh"))) return 0; + if (!(intrinsics[Intrinsic_240] = CheckRuntimeObject("vec_vnmsubfp"))) return 0; + if (!(intrinsics[Intrinsic_241] = CheckRuntimeObject("vec_vnor"))) return 0; + if (!(intrinsics[Intrinsic_242] = CheckRuntimeObject("vec_vor"))) return 0; + if (!(intrinsics[Intrinsic_243] = CheckRuntimeObject("vec_vpkuhum"))) return 0; + if (!(intrinsics[Intrinsic_244] = CheckRuntimeObject("vec_vpkuwum"))) return 0; + if (!(intrinsics[Intrinsic_245] = CheckRuntimeObject("vec_vpkpx"))) return 0; + if (!(intrinsics[Intrinsic_246] = CheckRuntimeObject("vec_vpkuhus"))) return 0; + if (!(intrinsics[Intrinsic_247] = CheckRuntimeObject("vec_vpkshss"))) return 0; + if (!(intrinsics[Intrinsic_248] = CheckRuntimeObject("vec_vpkuwus"))) return 0; + if (!(intrinsics[Intrinsic_249] = CheckRuntimeObject("vec_vpkswss"))) return 0; + if (!(intrinsics[Intrinsic_250] = CheckRuntimeObject("vec_vpkshus"))) return 0; + if (!(intrinsics[Intrinsic_251] = CheckRuntimeObject("vec_vpkswus"))) return 0; + if (!(intrinsics[Intrinsic_252] = CheckRuntimeObject("vec_vperm"))) return 0; + if (!(intrinsics[Intrinsic_253] = CheckRuntimeObject("vec_vrefp"))) return 0; + if (!(intrinsics[Intrinsic_254] = CheckRuntimeObject("vec_vrlb"))) return 0; + if (!(intrinsics[Intrinsic_255] = CheckRuntimeObject("vec_vrlh"))) return 0; + if (!(intrinsics[Intrinsic_256] = CheckRuntimeObject("vec_vrlw"))) return 0; + if (!(intrinsics[Intrinsic_257] = CheckRuntimeObject("vec_vrfin"))) return 0; + if (!(intrinsics[Intrinsic_258] = CheckRuntimeObject("vec_vrsqrtefp"))) return 0; + if (!(intrinsics[Intrinsic_259] = CheckRuntimeObject("vec_vsel"))) return 0; + if (!(intrinsics[Intrinsic_260] = CheckRuntimeObject("vec_vslb"))) return 0; + if (!(intrinsics[Intrinsic_261] = CheckRuntimeObject("vec_vslh"))) return 0; + if (!(intrinsics[Intrinsic_262] = CheckRuntimeObject("vec_vslw"))) return 0; + if (!(intrinsics[Intrinsic_263] = CheckRuntimeObject("vec_vsldoi"))) return 0; + if (!(intrinsics[Intrinsic_264] = CheckRuntimeObject("vec_vsl"))) return 0; + if (!(intrinsics[Intrinsic_265] = CheckRuntimeObject("vec_vslo"))) return 0; + if (!(intrinsics[Intrinsic_266] = CheckRuntimeObject("vec_vspltb"))) return 0; + if (!(intrinsics[Intrinsic_267] = CheckRuntimeObject("vec_vsplth"))) return 0; + if (!(intrinsics[Intrinsic_268] = CheckRuntimeObject("vec_vspltw"))) return 0; + if (!(intrinsics[Intrinsic_269] = CheckRuntimeObject("vec_vspltisb"))) return 0; + if (!(intrinsics[Intrinsic_270] = CheckRuntimeObject("vec_vspltish"))) return 0; + if (!(intrinsics[Intrinsic_271] = CheckRuntimeObject("vec_vspltisw"))) return 0; + if (!(intrinsics[Intrinsic_272] = CheckRuntimeObject("vec_vsrb"))) return 0; + if (!(intrinsics[Intrinsic_273] = CheckRuntimeObject("vec_vsrh"))) return 0; + if (!(intrinsics[Intrinsic_274] = CheckRuntimeObject("vec_vsrw"))) return 0; + if (!(intrinsics[Intrinsic_275] = CheckRuntimeObject("vec_vsrab"))) return 0; + if (!(intrinsics[Intrinsic_276] = CheckRuntimeObject("vec_vsrah"))) return 0; + if (!(intrinsics[Intrinsic_277] = CheckRuntimeObject("vec_vsraw"))) return 0; + if (!(intrinsics[Intrinsic_278] = CheckRuntimeObject("vec_vsr"))) return 0; + if (!(intrinsics[Intrinsic_279] = CheckRuntimeObject("vec_vsro"))) return 0; + if (!(intrinsics[Intrinsic_280] = CheckRuntimeObject("vec_stvx"))) return 0; + if (!(intrinsics[Intrinsic_281] = CheckRuntimeObject("vec_stvebx"))) return 0; + if (!(intrinsics[Intrinsic_282] = CheckRuntimeObject("vec_stvehx"))) return 0; + if (!(intrinsics[Intrinsic_283] = CheckRuntimeObject("vec_stvewx"))) return 0; + if (!(intrinsics[Intrinsic_284] = CheckRuntimeObject("vec_stvxl"))) return 0; + if (!(intrinsics[Intrinsic_285] = CheckRuntimeObject("vec_vsububm"))) return 0; + if (!(intrinsics[Intrinsic_286] = CheckRuntimeObject("vec_vsubuhm"))) return 0; + if (!(intrinsics[Intrinsic_287] = CheckRuntimeObject("vec_vsubuwm"))) return 0; + if (!(intrinsics[Intrinsic_288] = CheckRuntimeObject("vec_vsubfp"))) return 0; + if (!(intrinsics[Intrinsic_289] = CheckRuntimeObject("vec_vsubcuw"))) return 0; + if (!(intrinsics[Intrinsic_290] = CheckRuntimeObject("vec_vsububs"))) return 0; + if (!(intrinsics[Intrinsic_291] = CheckRuntimeObject("vec_vsubsbs"))) return 0; + if (!(intrinsics[Intrinsic_292] = CheckRuntimeObject("vec_vsubuhs"))) return 0; + if (!(intrinsics[Intrinsic_293] = CheckRuntimeObject("vec_vsubshs"))) return 0; + if (!(intrinsics[Intrinsic_294] = CheckRuntimeObject("vec_vsubuws"))) return 0; + if (!(intrinsics[Intrinsic_295] = CheckRuntimeObject("vec_vsubsws"))) return 0; + if (!(intrinsics[Intrinsic_296] = CheckRuntimeObject("vec_vsum4ubs"))) return 0; + if (!(intrinsics[Intrinsic_297] = CheckRuntimeObject("vec_vsum4sbs"))) return 0; + if (!(intrinsics[Intrinsic_298] = CheckRuntimeObject("vec_vsum4shs"))) return 0; + if (!(intrinsics[Intrinsic_299] = CheckRuntimeObject("vec_vsum2sws"))) return 0; + if (!(intrinsics[Intrinsic_300] = CheckRuntimeObject("vec_vsumsws"))) return 0; + if (!(intrinsics[Intrinsic_301] = CheckRuntimeObject("vec_vrfiz"))) return 0; + if (!(intrinsics[Intrinsic_302] = CheckRuntimeObject("vec_vupkhsb"))) return 0; + if (!(intrinsics[Intrinsic_303] = CheckRuntimeObject("vec_vupklsb"))) return 0; + if (!(intrinsics[Intrinsic_304] = CheckRuntimeObject("vec_vupkhpx"))) return 0; + if (!(intrinsics[Intrinsic_305] = CheckRuntimeObject("vec_vupklpx"))) return 0; + if (!(intrinsics[Intrinsic_306] = CheckRuntimeObject("vec_vupkhsh"))) return 0; + if (!(intrinsics[Intrinsic_307] = CheckRuntimeObject("vec_vupklsh"))) return 0; + if (!(intrinsics[Intrinsic_308] = CheckRuntimeObject("vec_vxor"))) return 0; + if (!(intrinsics[Intrinsic_309] = CheckRuntimeObject("vec_abs"))) return 0; + if (!(intrinsics[Intrinsic_310] = CheckRuntimeObject("vec_abss"))) return 0; + } + + return 1; +} + +Boolean Intrinsics_IsPublicRuntimeObject(Object *object) { + int i; + + for (i = 0; i < MaxIntrinsics; i++) { + if (object == intrinsics[i]) + return 1; + } + + return 0; +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c new file mode 100644 index 0000000..c5da285 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c @@ -0,0 +1,1040 @@ +#include "compiler/Operands.h" +#include "compiler/CError.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/RegisterInfo.h" +#include "compiler/Registers.h" +#include "compiler/StackFrame.h" +#include "compiler/TOC.h" +#include "compiler/enode.h" +#include "compiler/objects.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 && LOW_PART_BUGGY(value)) + tmpreg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LIS, tmpreg2 = tmpreg, 0, (short) HIGH_PART(value)); + if (LOW_PART_BUGGY(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) { + CError_ASSERT(118, 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: + CError_FATAL(163); + 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: + CError_FATAL(215); + } +} + +#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 (LOW_PART_BUGGY(opA->immediate)) + 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: + CError_FATAL(415); + } +} + +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 { + CError_FATAL(563); + } + } + break; + default: + CError_FATAL(581); + } +} + +void Coerce_to_register(Operand *op, Type *type, short output_reg) { + SInt32 offset; + Opcode 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 && LOW_PART_BUGGY(offset)) + tmp = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LIS, tmp, 0, (short) HIGH_PART(offset)); + if (LOW_PART_BUGGY(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 { + CError_ASSERT(680, 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 { + CError_ASSERT(724, 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: + CError_FATAL(758); + } + 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: + CError_FATAL(769); + } + + 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; + + CError_ASSERT(794, 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) { + CError_ASSERT(818, 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) { + CError_ASSERT(832, 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: + CError_FATAL(849); + break; + case OpndType_GPR_ImmOffset: + CError_FATAL(852); + break; + case OpndType_GPR_Indexed: + CError_FATAL(855); + 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 && LOW_PART_BUGGY(offset)) + tmp1 = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LIS, tmp1, 0, (short) HIGH_PART(offset)); + if (LOW_PART_BUGGY(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) { + CError_FATAL(887); + } 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: + CError_FATAL(912); + } + + if (regHi == -1) { + CError_FATAL(916); + } else { + op->optype = OpndType_GPRPair; + op->reg = reg; + op->regHi = regHi; + } +} + +void Coerce_to_fp_register(Operand *op, Type *type, 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((type->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((type->size == 4) ? PC_LFSX : PC_LFDX, reg, op->reg, op->regOffset, 0, 0x390); + setpcodeflags(op->flags); + break; + default: + CError_FATAL(986); + } + + op->optype = OpndType_FPR; + op->reg = reg; +} + +void Coerce_to_v_register(Operand *op, Type *type, 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 (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + emitpcode(PC_VSPLTISB, reg, op->immediate); + break; + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_PIXEL: + emitpcode(PC_VSPLTISH, reg, op->immediate); + break; + case STRUCT_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + case STRUCT_VECTOR_FLOAT: + emitpcode(PC_VSPLTISW, reg, op->immediate); + break; + default: + CError_FATAL(1049); + } + op->optype = OpndType_VR; + op->reg = reg; + setpcodeflags(op->flags); + break; + default: + CError_FATAL(1059); + } + + op->optype = OpndType_VR; + op->reg = reg; +} + +void store(short reg, Operand *op, Type *type) { + Opcode 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 { + CError_ASSERT(1171, 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 { + CError_ASSERT(1188, IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)); + } + emitpcode(opcode, reg, op->reg, op->regOffset); + setpcodeflags(op->flags); + break; + default: + CError_FATAL(1193); + } +} + +void store_pair(short reg, short regHi, Operand *op, Type *type) { + short tmp; + + CError_ASSERT(1208, 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: + CError_FATAL(1228); + } +} + +void store_fp(short reg, Operand *op, Type *type) { + coerce_to_addressable(op); + switch (op->optype) { + case OpndType_IndirectGPR_ImmOffset: + load_store_register((type->size == 4) ? PC_STFS : PC_STFD, reg, op->reg, op->object, op->immOffset); + setpcodeflags(op->flags); + break; + case OpndType_IndirectGPR_Indexed: + emitpcode((type->size == 4) ? PC_STFSX : PC_STFDX, reg, op->reg, op->regOffset); + setpcodeflags(op->flags); + break; + default: + CError_FATAL(1259); + } +} + +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: + CError_FATAL(1283); + } +} + +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: + CError_FATAL(1389); + } + + 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, Float *data) { + Object *object; + Object *indObject; + Operand op1; + Operand op2; + Operand op3; + SInt32 offset = 0; + + memclrw(&op1, sizeof(Operand)); + + object = CreateFloatConst(type, data, &offset); + indObject = createIndirect(object, 0, 1); + + if (indObject) { + symbol_operand(&op1, indObject); + indirect(&op1, NULL); + } else { + symbol_operand(&op1, object); + } + + if (offset) { + op2 = op1; + memclrw(&op3, sizeof(Operand)); + op3.optype = OpndType_Absolute; + op3.immediate = offset; + if (op2.optype != OpndType_GPR) + Coerce_to_register(&op2, TYPE(&void_ptr), 0); + combine(&op2, &op3, 0, &op1); + } + + indirect(&op1, NULL); + if (op1.optype != OpndType_FPR) + Coerce_to_fp_register(&op1, type, reg); +} + +void convert_integer_to_floating(Operand *op, Boolean is_single, short output_reg) { + Operand temp_op; + Float d; + int const_reg; + int tmp_reg; + int work_reg; + int result_reg; + Opcode opcode; + + symbol_operand(&temp_op, maketemporary(TYPE(&stdouble))); + coerce_to_addressable(&temp_op); + d.value = *((double *) &int_to_float_cc); + + const_reg = used_virtual_registers[RegClass_FPR]++; + load_floating_constant(const_reg, TYPE(&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]++; + 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) { + Operand temp_op; + Float d; + int const_reg; + int tmp_reg; + int work_reg; + int result_reg; + Opcode opcode; + + symbol_operand(&temp_op, maketemporary(TYPE(&stdouble))); + coerce_to_addressable(&temp_op); + d.value = *((double *) &uns_to_float_cc); + + const_reg = used_virtual_registers[RegClass_FPR]++; + load_floating_constant(const_reg, TYPE(&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]++; + 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->bitlength; + output = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; + r27 = tbitfield->offset + (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->bitlength; + int r7 = tbitfield->offset + (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, (SInt16) op->immOffset); + } + } else if (op->optype == OpndType_IndirectGPR_Indexed) { + emitpcode(PC_ADD, dest_reg, op->reg, op->regOffset); + } else { + CError_FATAL(1849); + } +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c new file mode 100644 index 0000000..368f8c5 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c @@ -0,0 +1,1613 @@ +#include "compiler/PCodeAssembly.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/PCodeListing.h" +#include "compiler/PPCError.h" +#include "compiler/RegisterInfo.h" +#include "compiler/StackFrame.h" +#include "compiler/TOC.h" +#include "compiler/objects.h" + +static UInt32 codebase; + +static SInt32 pcode_update_mem_labeldiff_imm(PCode *instr, const PCodeArg *op, WeirdOperand *wop) { + SInt32 offset; + Object *object; + UInt8 arg; + + if (op->kind == PCOp_MEMORY) { + object = op->data.mem.obj; + offset = op->data.mem.offset; + switch (object->datatype) { + case DLOCAL: + switch ((UInt8) op->arg) { + case RefType_1: + offset += local_offset_16(object); + break; + case RefType_D: + offset = local_offset_lo(object, offset); + break; + case RefType_C: + offset = local_offset_ha(object, offset); + break; + default: + CError_FATAL(83); + } + break; + case DDATA: + case DFUNC: + case DVFUNC: + case DNONLAZYPTR: + switch ((UInt8) op->arg) { + case RefType_6: + wop->type = MW_RELOC_5_LO16; + break; + case RefType_2: + wop->type = MW_RELOC_3; + break; + case RefType_3: + wop->type = MW_RELOC_4; + break; + case RefType_8: + wop->type = MW_RELOC_7_HA16; + break; + case RefType_7: + wop->type = MW_RELOC_6_HI16; + break; + default: + CError_FATAL(135); + } + + wop->x2 = object; + CError_ASSERT(144, offset == 0); + break; + default: + CError_FATAL(164); + } + } else if (op->kind == PCOp_LABELDIFF) { + arg = op->arg; + + offset = op->data.labeldiff.labelA->block->codeOffset - op->data.labeldiff.labelB->block->codeOffset; + offset += op->data.labeldiff.offset; + if (arg == 1) + offset = -offset; + + if (offset > 0x7FFF) + PPCError_Error(PPCErrorStr109); + else if (offset < -0x8000) + PPCError_Error(PPCErrorStr109); + } else if (op->kind == PCOp_IMMEDIATE) { + offset = op->data.imm.value; + } else { + CError_FATAL(193); + } + + return offset; +} + +UInt32 assemblepcode(PCode *instr, UInt32 offset, WeirdOperand *wop) { + UInt32 bits; + + bits = opcodeinfo[instr->op].insn; + wop->type = -1; + wop->x6 = 0; + + switch (instr->op) { + case PC_BL: { + int flag = PCODE_FLAG_SET_T(instr) & fAbsolute; + if (instr->args[0].kind == PCOp_MEMORY) { + bits |= instr->args[0].data.mem.offset & 0x3FFFFFC; + wop->type = MW_RELOC_2_BR24; + wop->x2 = instr->args[0].data.mem.obj; + if (flag == 0) + wop->type = MW_RELOC_2_BR24; + else + CError_FATAL(246); + } else if (instr->args[0].kind == PCOp_IMMEDIATE) { + bits |= instr->args[0].data.imm.value & 0x3FFFFFC; + if (flag) + bits |= 2; + } else { + bits |= (instr->args[0].data.label.label->block->codeOffset - offset) & 0x3FFFFFC; + if (flag) + CError_FATAL(261); + } + break; + } + + case PC_B: { + int flag = PCODE_FLAG_SET_T(instr) & fAbsolute; + if (instr->args[0].kind == PCOp_MEMORY) { + bits |= instr->args[0].data.mem.offset & 0x3FFFFFC; + wop->x2 = instr->args[0].data.mem.obj; + if (flag == 0) + wop->type = MW_RELOC_2_BR24; + else + CError_FATAL(288); + } else if (instr->args[0].kind == PCOp_IMMEDIATE) { + bits |= instr->args[0].data.imm.value & 0x3FFFFFC; + if (flag) + bits |= 2; + } else { + bits |= (instr->args[0].data.label.label->block->codeOffset - offset) & 0x3FFFFFC; + if (flag) + CError_FATAL(302); + } + if (PCODE_FLAG_SET_T(instr) & fLink) + bits |= 1; + break; + } + + case PC_BDNZ: + case PC_BDZ: { + int flag = PCODE_FLAG_SET_T(instr) & fAbsolute; + if (instr->args[0].kind == PCOp_MEMORY) { + bits |= instr->args[0].data.mem.offset & 0xFFFC; + wop->x2 = instr->args[0].data.mem.obj; + if (flag == 0) + wop->type = MW_RELOC_8; + else + CError_FATAL(333); + } else { + SInt32 value; + if (instr->args[0].kind == PCOp_IMMEDIATE) + value = instr->args[0].data.imm.value; + else + value = instr->args[0].data.label.label->block->codeOffset - offset; + + bits |= value & 0xFFFF; + if (value < 0) { + if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken) + bits |= 0x200000u; + } else { + if (PCODE_FLAG_SET_T(instr) & fBranchTaken) + bits |= 0x200000u; + } + } + if (PCODE_FLAG_SET_T(instr) & fLink) + bits |= 1; + break; + } + + case PC_BC: { + int flag = PCODE_FLAG_SET_T(instr) & fAbsolute; + bits |= (instr->args[0].data.imm.value & 31) << 21; + bits |= ((instr->args[1].data.reg.reg * 4 + instr->args[2].data.imm.value) & 31) << 16; + + if (instr->args[3].kind == PCOp_MEMORY) { + bits |= instr->args[3].data.mem.offset & 0xFFFC; + wop->x2 = instr->args[3].data.mem.obj; + if (flag == 0) + wop->type = MW_RELOC_8; + else + CError_FATAL(387); + } else { + SInt32 value; + if (instr->args[3].kind == PCOp_IMMEDIATE) + value = instr->args[3].data.imm.value; + else + value = instr->args[3].data.label.label->block->codeOffset - offset; + + bits |= value & 0xFFFF; + if (value < 0) { + if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken) + bits |= 0x200000u; + } else { + if (PCODE_FLAG_SET_T(instr) & fBranchTaken) + bits |= 0x200000u; + } + } + if (PCODE_FLAG_SET_T(instr) & fLink) + bits |= 1; + break; + } + + case PC_BT: + case PC_BF: + case PC_BDNZT: + case PC_BDNZF: + case PC_BDZT: + case PC_BDZF: { + int flag = PCODE_FLAG_SET_T(instr) & fAbsolute; + bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 16; + + if (instr->args[2].kind == PCOp_MEMORY) { + bits |= instr->args[2].data.mem.offset & 0xFFFC; + wop->x2 = instr->args[2].data.mem.obj; + if (flag == 0) + wop->type = MW_RELOC_8; + else + CError_FATAL(446); + } else { + SInt32 value; + if (instr->args[2].kind == PCOp_IMMEDIATE) { + value = instr->args[2].data.imm.value; + if (flag) + bits |= 2; + } else { + value = instr->args[2].data.label.label->block->codeOffset - offset; + CError_ASSERT(458, !flag); + } + + bits |= value & 0xFFFF; + + if (value < 0) { + if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken) + bits |= 0x200000u; + } else { + if (PCODE_FLAG_SET_T(instr) & fBranchTaken) + bits |= 0x200000u; + } + } + + if (PCODE_FLAG_SET_T(instr) & fLink) + bits |= 1; + break; + } + + case PC_BTLR: + case PC_BTCTR: + case PC_BFLR: + case PC_BFCTR: + bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 16; + if (PCODE_FLAG_SET_T(instr) & fLink) + bits |= 1; + if (PCODE_FLAG_SET_T(instr) & fBranchTaken) + bits |= 0x200000u; + break; + + case PC_BCLR: + case PC_BCCTR: + bits |= instr->args[0].data.imm.value << 21; + bits |= ((instr->args[1].data.reg.reg * 4 + instr->args[2].data.imm.value) & 31) << 16; + case PC_BLR: + case PC_BCTR: + case PC_BCTRL: + case PC_BLRL: + if (PCODE_FLAG_SET_T(instr) & fLink) + bits |= 1; + if (PCODE_FLAG_SET_T(instr) & fBranchTaken) + bits |= 0x200000u; + break; + + case PC_CRAND: + case PC_CRANDC: + case PC_CREQV: + case PC_CRNAND: + case PC_CRNOR: + case PC_CROR: + case PC_CRORC: + case PC_CRXOR: + bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 21; + bits |= ((instr->args[2].data.reg.reg * 4 + instr->args[3].data.imm.value) & 31) << 16; + bits |= ((instr->args[4].data.reg.reg * 4 + instr->args[5].data.imm.value) & 31) << 11; + break; + + case PC_MCRF: + bits |= instr->args[0].data.reg.reg << 23; + bits |= instr->args[1].data.reg.reg << 18; + break; + + case PC_LBZ: + case PC_LBZU: + case PC_LHZ: + case PC_LHZU: + case PC_LHA: + case PC_LHAU: + case PC_LWZ: + case PC_LWZU: + case PC_LMW: + case PC_STB: + case PC_STBU: + case PC_STH: + case PC_STHU: + case PC_STW: + case PC_STWU: + case PC_STMW: + case PC_LFS: + case PC_LFSU: + case PC_LFD: + case PC_LFDU: + case PC_STFS: + case PC_STFSU: + case PC_STFD: + case PC_STFDU: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF; + break; + + case PC_LBZX: + case PC_LBZUX: + case PC_LHZX: + case PC_LHZUX: + case PC_LHAX: + case PC_LHAUX: + case PC_LHBRX: + case PC_LWZX: + case PC_LWZUX: + case PC_LWBRX: + case PC_STBX: + case PC_STBUX: + case PC_STHX: + case PC_STHUX: + case PC_STHBRX: + case PC_STWX: + case PC_STWUX: + case PC_STWBRX: + case PC_LFSX: + case PC_LFSUX: + case PC_LFDX: + case PC_LFDUX: + case PC_STFSX: + case PC_STFSUX: + case PC_STFDX: + case PC_STFDUX: + case PC_LWARX: + case PC_LSWX: + case PC_STFIWX: + case PC_STSWX: + case PC_STWCX: + case PC_ECIWX: + case PC_ECOWX: + case PC_DCREAD: + case PC_TLBSX: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_DCBF: + case PC_DCBST: + case PC_DCBT: + case PC_DCBTST: + case PC_DCBZ: + case PC_DCBI: + case PC_ICBI: + case PC_DCCCI: + case PC_ICBT: + case PC_ICCCI: + case PC_ICREAD: + case PC_DCBA: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 11; + break; + + case PC_ADD: + case PC_ADDC: + case PC_ADDE: + case PC_DIVW: + case PC_DIVWU: + case PC_MULHW: + case PC_MULHWU: + case PC_MULLW: + case PC_SUBF: + case PC_SUBFC: + case PC_SUBFE: + bits |= instr->args[2].data.reg.reg << 11; + case PC_ADDME: + case PC_ADDZE: + case PC_NEG: + case PC_SUBFME: + case PC_SUBFZE: + case PC_MFROM: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + if (PCODE_FLAG_SET_F(instr) & fOverflow) + bits |= 0x400; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_ADDI: + case PC_ADDIC: + case PC_ADDICR: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF; + break; + + case PC_ADDIS: + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[0].data.reg.reg << 21; + bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF; + break; + + case PC_MULLI: + case PC_SUBFIC: + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[2].data.imm.value & 0xFFFF; + break; + + case PC_LI: + case PC_LIS: + bits |= instr->args[0].data.reg.reg << 21; + bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[1], wop) & 0xFFFF; + break; + + case PC_ANDI: + case PC_ANDIS: + case PC_ORI: + case PC_ORIS: + case PC_XORI: + case PC_XORIS: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF; + break; + + case PC_AND: + case PC_OR: + case PC_XOR: + case PC_NAND: + case PC_NOR: + case PC_EQV: + case PC_ANDC: + case PC_ORC: + case PC_SLW: + case PC_SRW: + case PC_SRAW: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_EXTSH: + case PC_EXTSB: + case PC_CNTLZW: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_MR: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_NOT: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_SRAWI: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= (instr->args[2].data.imm.value & 31) << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_RLWINM: + case PC_RLWIMI: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= (instr->args[2].data.imm.value & 31) << 11; + bits |= (instr->args[3].data.imm.value & 31) << 6; + bits |= (instr->args[4].data.imm.value & 31) << 1; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_RLWNM: + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[2].data.reg.reg << 11; + bits |= (instr->args[3].data.imm.value & 31) << 6; + bits |= (instr->args[4].data.imm.value & 31) << 1; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_CMP: + case PC_CMPL: + bits |= instr->args[0].data.reg.reg << 23; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + break; + + case PC_CMPI: + case PC_CMPLI: + bits |= instr->args[0].data.reg.reg << 23; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.imm.value & 0xFFFF; + break; + + case PC_MTXER: + case PC_MTCTR: + case PC_MTLR: + case PC_MTMSR: + case PC_MFMSR: + case PC_MFXER: + case PC_MFCTR: + case PC_MFLR: + case PC_MFCR: + bits |= instr->args[0].data.reg.reg << 21; + break; + + case PC_MFFS: + bits |= instr->args[0].data.reg.reg << 21; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_MTCRF: + bits |= instr->args[0].data.imm.value << 12; + bits |= instr->args[1].data.reg.reg << 21; + break; + + case PC_MTFSF: + bits |= (instr->args[0].data.imm.value & 0xFF) << 17; + bits |= instr->args[1].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_FMR: + case PC_FABS: + case PC_FNEG: + case PC_FNABS: + case PC_FRES: + case PC_FRSQRTE: + case PC_FRSP: + case PC_FCTIW: + case PC_FCTIWZ: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_FADD: + case PC_FADDS: + case PC_FSUB: + case PC_FSUBS: + case PC_FDIV: + case PC_FDIVS: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_FMADD: + case PC_FMADDS: + case PC_FMSUB: + case PC_FMSUBS: + case PC_FNMADD: + case PC_FNMADDS: + case PC_FNMSUB: + case PC_FNMSUBS: + case PC_FSEL: + bits |= instr->args[3].data.reg.reg << 11; + case PC_FMUL: + case PC_FMULS: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 6; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_FCMPU: + case PC_FCMPO: + bits |= instr->args[0].data.reg.reg << 23; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + break; + + case PC_MTSPR: + if (instr->args[0].kind == PCOp_REGISTER) { + CError_ASSERT(1027, instr->args[0].arg == RegClass_SPR); + CError_ASSERT(1028, instr->args[0].data.reg.reg < 4); + bits |= ((spr_to_sysreg[instr->args[0].data.reg.reg] & 0x1F) << 16) + + ((spr_to_sysreg[instr->args[0].data.reg.reg] & 0x3E0) << 6); + } else if (instr->args[0].kind == PCOp_SYSREG && instr->args[0].arg == 0) { + bits |= ((instr->args[0].data.reg.reg & 0x1F) << 16) + + ((instr->args[0].data.reg.reg & 0x3E0) << 6); + } else { + CError_FATAL(1033); + } + + bits |= instr->args[1].data.reg.reg << 21; + break; + + case PC_MTDCR: + if (instr->args[0].kind == PCOp_IMMEDIATE) { + bits |= ((instr->args[0].data.imm.value & 0x1F) << 16) + + ((instr->args[0].data.imm.value & 0x3E0) << 6); + } else { + CError_FATAL(1042); + } + + bits |= instr->args[1].data.reg.reg << 21; + break; + + case PC_MFSPR: + bits |= instr->args[0].data.reg.reg << 21; + + if (instr->args[1].kind == PCOp_REGISTER && instr->args[1].arg == RegClass_SPR) { + CError_ASSERT(1055, instr->args[1].data.reg.reg < 4); + bits |= ((spr_to_sysreg[instr->args[1].data.reg.reg] & 0x1F) << 16) + + ((spr_to_sysreg[instr->args[1].data.reg.reg] & 0x3E0) << 6); + } else if (instr->args[1].kind == PCOp_SYSREG && instr->args[1].arg == 0) { + bits |= ((instr->args[1].data.reg.reg & 0x1F) << 16) + + ((instr->args[1].data.reg.reg & 0x3E0) << 6); + } else { + CError_FATAL(1060); + } + break; + + case PC_MFDCR: + bits |= instr->args[0].data.reg.reg << 21; + + if (instr->args[1].kind == PCOp_IMMEDIATE) { + bits |= ((instr->args[1].data.imm.value & 0x1F) << 16) + + ((instr->args[1].data.imm.value & 0x3E0) << 6); + } else { + CError_FATAL(1069); + } + break; + + case PC_LSWI: + case PC_STSWI: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= (instr->args[2].data.imm.value & 31) << 11; + break; + + case PC_MCRFS: + bits |= (instr->args[1].data.imm.value & 7) << 18; + case PC_MCRXR: + bits |= instr->args[0].data.reg.reg << 23; + break; + + case PC_MFTB: + bits |= instr->args[0].data.reg.reg << 21; + if (instr->args[1].kind == PCOp_SYSREG && instr->args[1].arg == 0) { + if (instr->args[1].data.reg.reg == 284) + bits |= 0xC4000u; + else if (instr->args[1].data.reg.reg == 285) + bits |= 0xD4000u; + else + CError_FATAL(1100); + } else { + CError_FATAL(1103); + } + break; + + case PC_MTSR: + bits |= instr->args[1].data.reg.reg << 21; + bits |= (instr->args[0].data.imm.value & 15) << 16; + break; + + case PC_MFSR: + bits |= instr->args[0].data.reg.reg << 21; + bits |= (instr->args[1].data.imm.value & 15) << 16; + break; + + case PC_MFSRIN: + case PC_MTSRIN: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + break; + + case PC_MTFSB0: + case PC_MTFSB1: + bits |= (instr->args[0].data.imm.value & 31) << 21; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_MTFSFI: + bits |= instr->args[0].data.reg.reg << 23; + bits |= (instr->args[1].data.imm.value & 15) << 12; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_FSQRT: + case PC_FSQRTS: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_TLBIE: + case PC_TLBLD: + case PC_TLBLI: + bits |= instr->args[0].data.reg.reg << 11; + break; + + case PC_TW: + bits |= (instr->args[0].data.imm.value & 31) << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + break; + + case PC_TWI: + bits |= (instr->args[0].data.imm.value & 31) << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.imm.value & 0xFFFF; + break; + + case PC_OPWORD: + CError_ASSERT(1176, instr->args[0].kind != PCOp_MEMORY); + bits = pcode_update_mem_labeldiff_imm(instr, &instr->args[0], wop); + break; + + case PC_MASKG: + case PC_MASKIR: + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_LSCBX: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_DIV: + case PC_DIVS: + case PC_DOZ: + case PC_MUL: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fOverflow) + bits |= 0x400; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_NABS: + case PC_ABS: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + if (PCODE_FLAG_SET_F(instr) & fOverflow) + bits |= 0x400; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_CLCS: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_DOZI: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.imm.value & 0xFFFF; + break; + + case PC_RLMI: + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + bits |= (instr->args[3].data.imm.value & 31) << 6; + bits |= (instr->args[4].data.imm.value & 31) << 1; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_SLE: + case PC_SLEQ: + case PC_SLLQ: + case PC_SLQ: + case PC_SRAQ: + case PC_SRE: + case PC_SREA: + case PC_SREQ: + case PC_SRLQ: + case PC_SRQ: + case PC_RRIB: + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_SLIQ: + case PC_SLLIQ: + case PC_SRAIQ: + case PC_SRIQ: + case PC_SRLIQ: + bits |= instr->args[1].data.reg.reg << 21; + bits |= instr->args[0].data.reg.reg << 16; + bits |= (instr->args[2].data.imm.value & 31) << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 1; + break; + + case PC_TLBRE: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= (instr->args[2].data.imm.value & 1) << 11; + break; + + case PC_TLBWE: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= (instr->args[2].data.imm.value & 1) << 11; + break; + + case PC_WRTEE: + bits |= instr->args[0].data.reg.reg << 21; + break; + + case PC_WRTEEI: + bits |= instr->args[0].data.imm.value << 15; + break; + + case PC_DSTT: + case PC_DSTSTT: + bits |= 0x2000000u; + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 11; + bits |= (instr->args[2].data.imm.value & 3) << 21; + break; + + case PC_DST: + case PC_DSTST: + bits |= (instr->args[3].data.imm.value & 1) << 25; + bits |= instr->args[0].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 11; + bits |= (instr->args[2].data.imm.value & 3) << 21; + break; + + case PC_DSSALL: + bits |= 0x2000000u; + break; + + case PC_DSS: + bits |= (instr->args[1].data.imm.value & 1) << 25; + bits |= (instr->args[0].data.imm.value & 3) << 21; + break; + + case PC_LVEBX: + case PC_LVEHX: + case PC_LVEWX: + case PC_LVSL: + case PC_LVSR: + case PC_LVX: + case PC_LVXL: + case PC_STVEBX: + case PC_STVEHX: + case PC_STVEWX: + case PC_STVX: + case PC_STVXL: + case PC_VADDCUW: + case PC_VADDFP: + case PC_VADDSBS: + case PC_VADDSHS: + case PC_VADDSWS: + case PC_VADDUBM: + case PC_VADDUBS: + case PC_VADDUHM: + case PC_VADDUHS: + case PC_VADDUWM: + case PC_VADDUWS: + case PC_VAND: + case PC_VANDC: + case PC_VAVGSB: + case PC_VAVGSH: + case PC_VAVGSW: + case PC_VAVGUB: + case PC_VAVGUH: + case PC_VAVGUW: + case PC_VMAXFP: + case PC_VMAXSB: + case PC_VMAXSH: + case PC_VMAXSW: + case PC_VMAXUB: + case PC_VMAXUH: + case PC_VMAXUW: + case PC_VMINFP: + case PC_VMINSB: + case PC_VMINSH: + case PC_VMINSW: + case PC_VMINUB: + case PC_VMINUH: + case PC_VMINUW: + case PC_VMRGHB: + case PC_VMRGHH: + case PC_VMRGHW: + case PC_VMRGLB: + case PC_VMRGLH: + case PC_VMRGLW: + case PC_VMULESB: + case PC_VMULESH: + case PC_VMULEUB: + case PC_VMULEUH: + case PC_VMULOSB: + case PC_VMULOSH: + case PC_VMULOUB: + case PC_VMULOUH: + case PC_VNOR: + case PC_VOR: + case PC_VPKPX: + case PC_VPKSHSS: + case PC_VPKSHUS: + case PC_VPKSWSS: + case PC_VPKSWUS: + case PC_VPKUHUM: + case PC_VPKUHUS: + case PC_VPKUWUM: + case PC_VPKUWUS: + case PC_VRLB: + case PC_VRLH: + case PC_VRLW: + case PC_VSL: + case PC_VSLB: + case PC_VSLH: + case PC_VSLO: + case PC_VSLW: + case PC_VSR: + case PC_VSRAB: + case PC_VSRAH: + case PC_VSRAW: + case PC_VSRB: + case PC_VSRH: + case PC_VSRO: + case PC_VSRW: + case PC_VSUBCUW: + case PC_VSUBFP: + case PC_VSUBSBS: + case PC_VSUBSHS: + case PC_VSUBSWS: + case PC_VSUBUBM: + case PC_VSUBUBS: + case PC_VSUBUHM: + case PC_VSUBUHS: + case PC_VSUBUWM: + case PC_VSUBUWS: + case PC_VSUMSWS: + case PC_VSUM2SWS: + case PC_VSUM4SBS: + case PC_VSUM4SHS: + case PC_VSUM4UBS: + case PC_VXOR: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + break; + + case PC_VCFSX: + case PC_VCFUX: + case PC_VCTSXS: + case PC_VCTUXS: + case PC_VSPLTB: + case PC_VSPLTH: + case PC_VSPLTW: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + bits |= (instr->args[2].data.imm.value & 31) << 16; + break; + + case PC_VEXPTEFP: + case PC_VLOGEFP: + case PC_VREFP: + case PC_VRFIM: + case PC_VRFIN: + case PC_VRFIP: + case PC_VRFIZ: + case PC_VRSQRTEFP: + case PC_VUPKHPX: + case PC_VUPKHSB: + case PC_VUPKHSH: + case PC_VUPKLPX: + case PC_VUPKLSB: + case PC_VUPKLSH: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 11; + break; + + case PC_VCMPBFP: + case PC_VCMPEQFP: + case PC_VCMPEQUB: + case PC_VCMPEQUH: + case PC_VCMPEQUW: + case PC_VCMPGEFP: + case PC_VCMPGTFP: + case PC_VCMPGTSB: + case PC_VCMPGTSH: + case PC_VCMPGTSW: + case PC_VCMPGTUB: + case PC_VCMPGTUH: + case PC_VCMPGTUW: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + bits |= 0x400; + break; + + case PC_VSPLTISB: + case PC_VSPLTISH: + case PC_VSPLTISW: + bits |= instr->args[0].data.reg.reg << 21; + bits |= (instr->args[1].data.imm.value & 31) << 16; + break; + + case PC_VMHADDSHS: + case PC_VMHRADDSHS: + case PC_VMLADDUHM: + case PC_VMSUMMBM: + case PC_VMSUMSHM: + case PC_VMSUMSHS: + case PC_VMSUMUBM: + case PC_VMSUMUHM: + case PC_VMSUMUHS: + case PC_VPERM: + case PC_VSEL: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + bits |= instr->args[3].data.reg.reg << 6; + break; + + case PC_VMADDFP: + case PC_VNMSUBFP: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 6; + bits |= instr->args[3].data.reg.reg << 11; + break; + + case PC_VSLDOI: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[2].data.reg.reg << 11; + bits |= (instr->args[3].data.imm.value & 15) << 6; + break; + + case PC_VMR: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 11; + break; + + case PC_VMRP: + bits |= instr->args[0].data.reg.reg << 21; + bits |= instr->args[1].data.reg.reg << 16; + bits |= instr->args[1].data.reg.reg << 11; + break; + + case PC_MFVSCR: + bits |= instr->args[0].data.reg.reg << 21; + break; + + case PC_MTVSCR: + bits |= instr->args[0].data.reg.reg << 11; + break; + + case PC_EIEIO: + case PC_ISYNC: + case PC_SYNC: + case PC_RFI: + case PC_NOP: + case PC_SC: + case PC_TLBIA: + case PC_TLBSYNC: + case PC_TRAP: + case PC_DSA: + case PC_ESA: + case PC_RFCI: + break; + + default: + CError_FATAL(2203); + } + + return CTool_EndianConvertWord32(bits); +} + +static PCode *targetinstruction(PCodeLabel *label) { + PCodeBlock *block = label->block; + while (block->pcodeCount == 0) + block = block->nextBlock; + return block->firstPCode; +} + +static void invertybit(PCode *instr, SInt32 value) { + if (instr->op == PC_BC) { + if (instr->args[0].data.imm.value & 1) { + if (value < 0) + instr->flags |= fBranchNotTaken; + else + instr->flags |= fBranchTaken; + } + } else if (instr->op == PC_BCCTR || instr->op == PC_BCLR) { + if (instr->args[0].data.imm.value & 1) + instr->flags |= fBranchTaken; + } + + if (PCODE_FLAG_SET_T(instr) & fBranchTaken) + instr->flags = (instr->flags & ~fBranchTaken) | fBranchNotTaken; + else if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken) + instr->flags = (instr->flags & ~fBranchNotTaken) | fBranchTaken; + else if (value < 0) + instr->flags = (instr->flags & ~fBranchTaken) | fBranchNotTaken; + else + instr->flags = (instr->flags & ~fBranchNotTaken) | fBranchTaken; +} + +static void insertlongbranches(SInt32 mask) { + PCodeBlock *block; + PCodeLabel *label; + SInt32 i; + + i = 0; + for (block = pcbasicblocks; block; block = block->nextBlock) { + block->codeOffset = i; + if (block->pcodeCount) { + i += block->pcodeCount * 4; + if (block->pcodeCount && (block->lastPCode->flags & fIsBranch)) + i += 4; + } + } + + for (block = pcbasicblocks; block; block = block->nextBlock) { + if (block->pcodeCount && (block->lastPCode->flags & fIsBranch)) { + switch (block->lastPCode->op) { + case PC_BT: + case PC_BF: + i = block->codeOffset + ((block->pcodeCount - 1) * 4); + if (block->lastPCode->args[2].kind == PCOp_LABEL) { + label = block->lastPCode->args[2].data.label.label; + i = label->block->codeOffset - i; + if (i != ((SInt16) (i & mask))) { + block->lastPCode->op = (block->lastPCode->op == PC_BT) ? PC_BF : PC_BT; + block->lastPCode->args[2].data.label.label = block->nextBlock->labels; + invertybit(block->lastPCode, i); + appendpcode(block, makepcode(PC_B, label)); + } + } + break; + + case PC_BC: + i = block->codeOffset + ((block->pcodeCount - 1) * 4); + if (block->lastPCode->args[3].kind == PCOp_LABEL) { + label = block->lastPCode->args[3].data.label.label; + i = label->block->codeOffset - i; + invertybit(block->lastPCode, i); + if (i != ((SInt16) (i & mask))) { + switch (block->lastPCode->args[0].data.imm.value & 30) { + case 0: + case 2: + case 8: + case 10: + block->lastPCode->args[0].data.imm.value ^= 11; + block->lastPCode->args[3].data.label.label = block->nextBlock->labels; + break; + case 16: + case 18: + block->lastPCode->args[0].data.imm.value ^= 3; + block->lastPCode->args[3].data.label.label = block->nextBlock->labels; + break; + case 4: + case 12: + block->lastPCode->args[0].data.imm.value ^= 9; + block->lastPCode->args[3].data.label.label = block->nextBlock->labels; + break; + case 20: + deletepcode(block->lastPCode); + break; + default: + CError_FATAL(2368); + } + + appendpcode(block, makepcode(PC_B, label)); + } + } + break; + + case PC_BDNZ: + case PC_BDZ: + i = block->codeOffset + ((block->pcodeCount - 1) * 4); + if (block->lastPCode->args[0].kind == PCOp_LABEL) { + label = block->lastPCode->args[0].data.label.label; + i = label->block->codeOffset - i; + if (i != ((SInt16) (i & mask))) { + switch (block->lastPCode->op) { + case PC_BDZ: + block->lastPCode->op = PC_BDNZ; + break; + case PC_BDNZ: + block->lastPCode->op = PC_BDZ; + break; + default: + CError_FATAL(2389); + } + + block->lastPCode->args[0].data.label.label = block->nextBlock->labels; + invertybit(block->lastPCode, i); + appendpcode(block, makepcode(PC_B, label)); + } + } + break; + + case PC_BDNZT: + case PC_BDNZF: + case PC_BDZT: + case PC_BDZF: + i = block->codeOffset + ((block->pcodeCount - 1) * 4); + if (block->lastPCode->args[2].kind == PCOp_LABEL) { + label = block->lastPCode->args[2].data.label.label; + i = label->block->codeOffset - i; + if (i != ((SInt16) (i & mask))) { + switch (block->lastPCode->op) { + case PC_BDNZT: + block->lastPCode->op = PC_BDZF; + break; + case PC_BDNZF: + block->lastPCode->op = PC_BDZT; + break; + case PC_BDZT: + block->lastPCode->op = PC_BDNZF; + break; + case PC_BDZF: + block->lastPCode->op = PC_BDNZT; + break; + default: + CError_FATAL(2420); + } + + block->lastPCode->args[2].data.label.label = block->nextBlock->labels; + invertybit(block->lastPCode, i); + appendpcode(block, makepcode(PC_B, label)); + } + } + break; + + } + } + } +} + +SInt32 optimizefinalbranches(SInt32 codesize) { + PCodeBlock *block; + PCode *instr; + SInt32 offset; + int changed; + int deleted; + PCodeLabel *label; + PCode *target; + + do { + changed = deleted = 0; + + for (block = pcbasicblocks; block; block = block->nextBlock) { + if (block->pcodeCount == 0) + continue; + + instr = block->lastPCode; + if (!(instr->flags & fIsBranch)) + continue; + + offset = block->codeOffset + (block->pcodeCount - 1) * 4; + + if (instr->op == PC_B && instr->args[0].kind == PCOp_LABEL) { + label = instr->args[0].data.label.label; + target = targetinstruction(label); + + if (label->block->codeOffset == (offset + 4)) { + deletepcode(instr); + changed = deleted = 1; + } else if (target->op == PC_B) { + if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[0].data.label.label) { + instr->args[0].data.label.label = target->args[0].data.label.label; + changed = 1; + } + } else if (target->op == PC_BLR) { + instr->op = PC_BLR; + changed = 1; + } + continue; + } + + if ((instr->op == PC_BT || instr->op == PC_BF) && instr->args[2].kind == PCOp_LABEL) { + PCodeBlock *block2 = instr->block; + label = instr->args[2].data.label.label; + target = targetinstruction(label); + + if (label->block->codeOffset == (offset + 4)) { + deletepcode(instr); + changed = deleted = 1; + } else if (target->op == PC_B) { + if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[2].data.label.label) { + instr->args[2].data.label.label = target->args[0].data.label.label; + changed = 1; + } + } else if (copts.opt_bcc_lr_ctr) { + if (target->op == PC_BLR) { + if (instr->op == PC_BT) + instr->op = PC_BTLR; + else + instr->op = PC_BFLR; + instr->argCount = 2; + changed = 1; + } else if (target->op == PC_BCTR) { + if (instr->op == PC_BT) + instr->op = PC_BTCTR; + else + instr->op = PC_BFCTR; + instr->argCount = 2; + changed = 1; + } else if ( + block2->nextBlock && + block2->nextBlock->firstPCode && + block2->nextBlock->firstPCode->op == PC_BLR && + label->block->codeOffset == (offset + 8) + ) { + if ( + block2->nextBlock->predecessors && + block2->nextBlock->predecessors->block == block2 && + !block2->nextBlock->predecessors->nextLink + ) { + if (instr->op == PC_BT) + instr->op = PC_BFLR; + else + instr->op = PC_BTLR; + change_num_operands(instr, 2); + deletepcode(block2->nextBlock->firstPCode); + changed = deleted = 1; + } + } else if ( + block2->nextBlock && + block2->nextBlock->firstPCode && + block2->nextBlock->firstPCode->op == PC_BCTR && + label->block->codeOffset == (offset + 8) + ) { + if ( + block2->nextBlock->predecessors && + block2->nextBlock->predecessors->block == block2 && + !block2->nextBlock->predecessors->nextLink + ) { + if (instr->op == PC_BT) + instr->op = PC_BFCTR; + else + instr->op = PC_BTCTR; + change_num_operands(instr, 2); + deletepcode(block2->nextBlock->firstPCode); + changed = deleted = 1; + } + } + } + continue; + } + + if ( + instr->op == PC_BC && + instr->args[3].kind == PCOp_LABEL && + !(PCODE_FLAG_SET_T(instr) & (fSideEffects | fLink)) + ) + { + PCodeBlock *block2 = instr->block; + label = instr->args[3].data.label.label; + target = targetinstruction(label); + + if (label->block->codeOffset == (offset + 4)) { + deletepcode(instr); + changed = deleted = 1; + } else if (target->op == PC_B) { + if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[3].data.label.label) { + instr->args[3].data.label.label = target->args[0].data.label.label; + changed = 1; + } + } else if (copts.opt_bcc_lr_ctr) { + if (target->op == PC_BLR) { + instr->op = PC_BCLR; + instr->argCount = 3; + changed = 1; + } else if (target->op == PC_BCTR) { + instr->op = PC_BCCTR; + instr->argCount = 3; + changed = 1; + } else if ( + block2->nextBlock && + block2->nextBlock->firstPCode && + block2->nextBlock->firstPCode->op == PC_BLR && + label->block->codeOffset == (offset + 8) + ) { + SInt32 val = instr->args[0].data.imm.value & 30; + if ( + block2->nextBlock->predecessors && + block2->nextBlock->predecessors->block == block2 && + !block2->nextBlock->predecessors->nextLink + ) { + if ((val & 30) == 4) + instr->args[0].data.imm.value = val | 12; + else if ((val & 30) == 12) + instr->args[0].data.imm.value = val & 23; + instr->op = PC_BCLR; + instr->argCount = 3; + deletepcode(block2->nextBlock->firstPCode); + changed = deleted = 1; + } + } else if ( + block2->nextBlock && + block2->nextBlock->firstPCode && + block2->nextBlock->firstPCode->op == PC_BCTR && + label->block->codeOffset == (offset + 8) + ) { + SInt32 val = instr->args[0].data.imm.value & 30; + if ( + block2->nextBlock->predecessors && + block2->nextBlock->predecessors->block == block2 && + !block2->nextBlock->predecessors->nextLink + ) { + if ((val & 30) == 4) + instr->args[0].data.imm.value = val | 12; + else if ((val & 30) == 12) + instr->args[0].data.imm.value = val & 23; + instr->op = PC_BCCTR; + instr->argCount = 3; + deletepcode(block2->nextBlock->firstPCode); + changed = deleted = 1; + } + } + } + } + } + + if (deleted) + codesize = pccomputeoffsets(); + } while (changed); + + return codesize; +} + +static SInt32 insert_align_nops(Object *func, SInt32 codesize) { + PCodeBlock *block; + int changed; + PCodeBlock *prev; + + do { + changed = 0; + + for (block = pcbasicblocks; block; block = block->nextBlock) { + if ( + (block->flags & fPCBlockFlag6000) == fPCBlockFlag2000 && + (block->codeOffset & 7) && + block->pcodeCount < 8 && + (prev = block->prevBlock) && + !(prev->flags & fPCBlockFlag2000) + ) + { + if (prev->lastPCode && prev->lastPCode->op == PC_NOP && !(prev->lastPCode->flags & fSideEffects)) { + deletepcode(prev->lastPCode); + } else { + PCode *nop = makepcode(PC_NOP); + nop->flags &= ~fSideEffects; + appendpcode(prev, nop); + } + + codesize = pccomputeoffsets(); + changed = 1; + } + } + + if (changed) { + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER INSERT ALIGN NOPs"); + if (codesize > 32766) { + insertlongbranches(32766); + codesize = pccomputeoffsets(); + } + } + + } while (changed); + + return codesize; +} + +SInt32 assemblefunction(Object *func, EntryPoint *entrypoints) { + void *tbdata; + GList *gl; + PCodeBlock *block; + PCode *instr; + SInt32 offset2; + SInt32 codesize; + SInt32 tbsize; + SInt32 offset; + SectionHandle section; + EntryPoint *ep; + WeirdOperand wop; + + codesize = pccomputeoffsets(); + if (codesize <= 0) + PPCError_Error(PPCErrorStr190, func->name->name); + + if (copts.peephole || copts.optimizationlevel >= 3) + codesize = optimizefinalbranches(codesize); + + if (codesize > 32766) { + insertlongbranches(32766); + codesize = pccomputeoffsets(); + } + + if (copts.function_align > 4) + codesize = insert_align_nops(func, codesize); + + tbsize = 0; + if (copts.traceback) + tbdata = generate_traceback(codesize, CMangler_GetLinkName(func)->name, &tbsize, func); + + if (func->section == SECT_DEFAULT) + func->section = SECT_TEXT; + + offset = tbsize; + section = ObjGen_DeclareCode(func, codesize + tbsize); + gl = ObjGen_GetSectionGList(section); + + codebase = gl->size; + AppendGListNoData(gl, codesize + tbsize); + + if (copts.filesyminfo) { + ObjGen_SymFunc(func); + ObjGen_Line(functionbodyoffset, 0); + ObjGen_DeclareSymInfo(); + } + + if (uses_globals && pic_base_reg) + ObjGen_DeclarePICBase(func, pic_base_pcodelabel->block->codeOffset); + + if (entrypoints) { + for (ep = entrypoints; ep; ep = ep->next) { + ObjGen_DeclareEntry(ep->object, ep->block->codeOffset); + } + } + + for (block = pcbasicblocks; block; block = block->nextBlock) { + for (offset2 = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset2 += 4) { + if (copts.filesyminfo && instr->sourceoffset != -1) + ObjGen_Line(instr->sourceoffset, offset2); + + *((UInt32 *) (*gl->data + codebase + offset2)) = assemblepcode(instr, offset2, &wop); + + if (wop.type != -1) + ObjGen_RelocateObj(section, offset2, wop.x2, wop.type); + } + } + + if (copts.filesyminfo) + ObjGenMach_SymFuncEnd(func, codesize); + + if (copts.traceback) + memcpy(*gl->data + codebase + codesize, tbdata, offset); + + if (copts.traceback) + return codesize + tbsize; + else + return codesize; +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c new file mode 100644 index 0000000..7a9fa13 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c @@ -0,0 +1,536 @@ +#include "compiler/PCodeListing.h" +#include "compiler/CError.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/Alias.h" +#include "compiler/BitVectors.h" +#include "compiler/CompilerTools.h" +#include "compiler/InterferenceGraph.h" +#include "compiler/LiveInfo.h" +#include "compiler/PCode.h" +#include "compiler/PCodeAssembly.h" +#include "compiler/Registers.h" +#include "compiler/Scheduler.h" +#include "compiler/objects.h" + +static FILE *pcfile; +static int ptime; +static int sourcetext; +static int sourcetext_is_main; +static int sourcelength; +int pclist_bad_operand; + +static void formatdataflowset(char *name, UInt32 *vec, UInt32 size, char *format) { + UInt32 i; + UInt32 counter; + char *separator; + + separator = ""; + fprintf(pcfile, "%s = {", name); + + for (i = 0, counter = 0; i < size; i++) { + if (bitvectorgetbit(i, vec)) { + if (i) + fprintf(pcfile, separator); + if (counter++ == 10) { + fprintf(pcfile, "\n\t\t"); + counter = 0; + } + fprintf(pcfile, format, i); + separator = ","; + } + } + + fprintf(pcfile, "}\n"); +} + +static void pclistblock(PCodeBlock *block, char *format, UInt32 vecSize) { + PCLink *link; + PCodeLabel *label; + int cpu; + int chr; + PCode *instr; + int offset; + int latency; + UInt32 opcode; + MachineInfo *mi; + char buf[500]; + WeirdOperand dummyArg; + + fprintf(pcfile, ":{%4.4x}::::::::::::::::::::::::::::::::::::::::LOOPWEIGHT=%" PRId32 "\n", block->flags, block->loopWeight); + fprintf(pcfile, "B%" PRId32 ": ", block->blockIndex); + + fprintf(pcfile, "Successors = { "); + for (link = block->successors; link; link = link->nextLink) { + if (link->block) + fprintf(pcfile, "B%" PRId32 " ", link->block->blockIndex); + } + fprintf(pcfile, "} "); + + fprintf(pcfile, "Predecessors = { "); + for (link = block->predecessors; link; link = link->nextLink) { + if (link->block) + fprintf(pcfile, "B%" PRId32 " ", link->block->blockIndex); + } + + if (block->labels) { + fprintf(pcfile, "} Labels = { "); + for (label = block->labels; label; label = label->nextLabel) + fprintf(pcfile, "L%" PRId32 " ", label->index); + } + + fprintf(pcfile, "}\n\n"); + + cpu = copts.scheduling; + if (cpu == 10) { + mi = &machine7450; + } else if (copts.altivec_model != 0 || cpu == 7) { + mi = &machine7400; + } else if (cpu == 2) { + mi = &machine603; + } else if (cpu == 5) { + mi = &machine603e; + } else if (cpu == 3) { + mi = &machine604; + } else if (cpu == 6) { + mi = &machine604; + } else if (cpu == 4) { + mi = &machine750; + } else if (cpu == 1) { + mi = &machine601; + } else if (cpu == 9) { + mi = &machine821; + } else { + mi = &machine603; + } + + for (offset = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset += 4) { + latency = mi->latency(instr); + formatoperands(instr, buf, 1); + chr = (PCODE_FLAG_SET_F(instr) & fRecordBit) ? '.' : ' '; + if (coloring) + opcode = 0; + else + opcode = assemblepcode(instr, offset, &dummyArg); + + fprintf( + pcfile, + " %.8" PRIX32 " %.8" PRIX32 " %4" PRId32 " %-7s%c %s\n", + offset, CTool_EndianConvertWord32(opcode), latency, + opcodeinfo[instr->op].name, chr, buf + ); + + if (instr->alias) + dumpalias(instr->alias, 0, 1, 0); + } + + if (vecSize) { + fprintf(pcfile, "............................................................\n"); + formatdataflowset("use", liveinfo[block->blockIndex].use, vecSize, format); + formatdataflowset("def", liveinfo[block->blockIndex].def, vecSize, format); + formatdataflowset("in ", liveinfo[block->blockIndex].in, vecSize, format); + formatdataflowset("out", liveinfo[block->blockIndex].out, vecSize, format); + } + + fflush(pcfile); + + if (pclist_bad_operand) + CError_FATAL(252); +} + +static void pclistonoff(int flag) { + if (flag) + fprintf(pcfile, "On\n"); + else + fprintf(pcfile, "Off\n"); +} + +void pcinitlisting() { + // unknown args, etc +} + +void pccleanuplisting(void) { +#ifdef CW_ENABLE_PCODE_DEBUG + // this code is not based on the original as we don't have it + if (pcfile) { + fclose(pcfile); + pcfile = NULL; + } +#endif +} + +void pclistblocks(char *name1, char *name2) { +#ifdef CW_ENABLE_PCODE_DEBUG + // this code is not based on the original as we don't have it + PCodeBlock *block; + if (copts.debuglisting) { + if (!pcfile) + pcfile = fopen("pcdump.txt", "a"); + + fprintf(pcfile, "\n%s\n%s\n", name1, name2); + for (block = pcbasicblocks; block; block = block->nextBlock) + pclistblock(block, NULL, 0); + } +#endif +} + +void pclistdataflow() { + // unknown args +} + +void pclistinterferences(char *class_format, int regcount) { +} + +void pclistspill() { + // unknown args +} + +void pclistcopypropitem() { + // unknown args +} + +void pclistcoalesce() { + // unknown args +} + +void pclistusedefs() { + // unknown args +} + +void pclistpropinfo() { + // unknown args +} + +static void listloop() { + // unknown args +} + +static void listloops() { + // unknown args +} + +void pclistloops() { + // unknown args +} + +static void listswitchtables() { + // unknown args +} + +void pclistswitchtables() { + // unknown args +} + +void pclistdominators() { + // unknown args +} + +void pclistbackedge() { + // unknown args +} + +static char *GetInterferenceFlags(IGNode *node) { + char *buf; + Boolean first; + + first = 1; + buf = oalloc(512); + buf[0] = 0; + + if (node->flags & fSpilled) { + strcat(buf, "fSpilled"); + first = 0; + } + + if (node->flags & fPushed) { + if (!first) + strcat(buf, "|"); + strcat(buf, "fPushed"); + first = 0; + } + + if (node->flags & fCoalesced) { + if (!first) + strcat(buf, "|"); + strcat(buf, "fCoalesced"); + first = 0; + } + + if (node->flags & fCoalescedInto) { + if (!first) + strcat(buf, "|"); + strcat(buf, "fCoalescedInto"); + first = 0; + } + + if (node->flags & fPairHigh) { + if (!first) + strcat(buf, "|"); + strcat(buf, "fPairHigh"); + first = 0; + } + + if (node->flags & fPairLow) { + if (!first) + strcat(buf, "|"); + strcat(buf, "fPairLow"); + first = 0; + } + + if (!*buf) + strcat(buf, "no_flags"); + + return buf; +} + +void pclistinterferencegraphnode() { + // unknown args +} + +void pclistinterferencegraph() { + // unknown args +} + +void pclistblock_scheduler() { + // unknown args +} + +void pclistblocks_start_scheduler(char *str1, char *str2) { +} + +void pclistblocks_end_scheduler(void) { + if (pclist_bad_operand) + CError_FATAL(1318); +} + +static void printheapsize() { + // unknown args +} + +void pctotalheap() { + // unknown args +} + +void pctotalmemory() { + // unknown args +} + +void pcmessage(char *probably_a_string, ...) { +} + +int formatalias(Alias *alias, char *buf, int bufSize) { + char *name; + char *typestr; + int len; + int len2; + + if (bufSize < 16) + return sprintf(buf, "..."); + + switch (alias->type) { + case AliasType0: + case AliasType1: + name = CMangler_GetLinkName(alias->object)->name; + if (!strlen(name) || name[0] < 0) + CError_FATAL(1458); + + if (strlen(name) + 16 > bufSize) + return sprintf(buf, "..."); + + switch (alias->object->datatype) { + case DNONLAZYPTR: + typestr = "{NL}"; + break; + case DDATA: + typestr = "{RW}"; + break; + case DLOCAL: + typestr = "{SP}"; + break; + default: + typestr = ""; + } + + len = sprintf(buf, "%0.*s%s", bufSize - 20, name, typestr, alias->size); + buf += len; + if (alias->type == AliasType0) + return len; + + if (alias->offset == 0) + len2 = sprintf(buf, ":%d", alias->size); + else if (alias->offset > 0) + len2 = sprintf(buf, "+%d:%d", alias->offset, alias->size); + else + len2 = sprintf(buf, "-%d:%d", -alias->offset, alias->size); + + return len + len2; + + case AliasType2: + len = 0; + + len2 = sprintf(buf, "{"); + buf += len2; + len += len2; + + len2 = sprintf(buf, "*"); + buf += len2; + len += len2; + + len2 = sprintf(buf, "}"); + buf += len2; + len += len2; + return len; + + default: + CError_FATAL(1543); + return 0; + } +} + +int dumpalias(Alias *alias, int len, Boolean flag1, Boolean flag2) { + char *name; + char *typestr; + AliasMember *member; + Boolean notFirst; + + if (!flag2 && alias == worst_case) { + fprintf(pcfile, " ALIAS = {worst_case}"); + if (flag1) + fprintf(pcfile, "\n"); + return 0; + } + + if (flag1) { + if (alias == worst_case) + fprintf(pcfile, "ALIAS worst_case = "); + else + fprintf(pcfile, " ALIAS = "); + } + + switch (alias->type) { + case AliasType0: + case AliasType1: + name = CMangler_GetLinkName(alias->object)->name; + if (!strlen(name) || name[0] < 0) + CError_FATAL(1581); + + switch (alias->object->datatype) { + case DNONLAZYPTR: + typestr = "{NL}"; + break; + case DDATA: + typestr = "{RW}"; + break; + case DLOCAL: + typestr = "{SP}"; + break; + default: + typestr = ""; + } + + len += fprintf(pcfile, "%0.80s%s", name, typestr); + + if (alias->type == AliasType0) { + if (flag1) + fprintf(pcfile, "\n"); + return len; + } + + if (alias->offset == 0) + len += fprintf(pcfile, ":%d", alias->size); + else if (alias->offset > 0) + len += fprintf(pcfile, "+%d:%d", alias->offset, alias->size); + else + len += fprintf(pcfile, "-%d:%d", -alias->offset, alias->size); + + if (flag1) + fprintf(pcfile, "\n"); + + return len; + + case AliasType2: + len += fprintf(pcfile, "{"); + notFirst = 0; + for (member = alias->parents; member; member = member->nextParent) { + if (member->child->type == AliasType0) { + if (notFirst) + len += fprintf(pcfile, ","); + if (len > 60) { + fprintf(pcfile, "\n "); + len = 0; + } + len = dumpalias(member->child, len, 0, 0); + notFirst = 1; + } + } + for (member = alias->parents; member; member = member->nextParent) { + if (member->child->type != AliasType0) { + if (notFirst) + len += fprintf(pcfile, ","); + if (len > 60) { + fprintf(pcfile, "\n "); + len = 0; + } + len = dumpalias(member->child, len, 0, 0); + notFirst = 1; + } + } + + len += fprintf(pcfile, "}"); + if (flag1) + fprintf(pcfile, "\n"); + return len; + + default: + CError_FATAL(1661); + return 0; + } +} + +void pcformatset() { + // unknown args +} + +int GetLineEndOffset(char *str, int lineNum, int len) { + int offset; + char *work; + + offset = GetLineOffset(str, lineNum, len); + if (offset < 0) + return offset; + + work = str + offset; + while (*work) { + if (*work == '\n') + return work - str - 1; + work++; + } + return -1; +} + +int GetLineOffset(char *str, int lineNum, int len) { + char *work = str; + char *end; + + if (lineNum < 0) + return -1; + + end = str + len; + while (work < end) { + if (*work == '\n' && --lineNum <= 0) + return work - str; + work++; + } + + return 0; +} + +void DumpSourceCode() { + // unknown args +} + +int DumpIR_SrcBreak() { + // unknown args + return 0; +} + diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c new file mode 100644 index 0000000..b1f8ffb --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c @@ -0,0 +1,345 @@ +#include "compiler/PCodeUtilities.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/Exceptions.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/Registers.h" +#include "compiler/enode.h" +#include "compiler/objects.h" + +void pcsetrecordbit(PCode *pc) { + int reg; + PCodeArg *arg; + short argCount; + int argIdx; + + pc->flags &= ~(fIsMove | fCommutative | fIsCSE); + if ((pc->flags & fOpTypeMask) == fOpTypeFPR) { + reg = 1; + } else if ((pc->flags & fOpTypeMask) == fOpTypeVR) { + reg = 6; + } else { + reg = 0; + } + + if (pc->op == PC_ANDI || pc->op == PC_ANDIS) { + pc->flags |= fRecordBit; + } else if (pc->op == PC_ADDI || pc->op == PC_ADDIC) { + pc->flags |= fSetsCarry; + pc->flags |= fRecordBit; + change_num_operands(pc, 5); + pc->op = PC_ADDICR; + + CError_ASSERT(76, pc->args[3].kind == PCOp_PLACEHOLDEROPERAND); + pc->args[3].kind = PCOp_REGISTER; + pc->args[3].arg = RegClass_SPR; + pc->args[3].data.reg.reg = 0; + pc->args[3].data.reg.effect = EffectWrite; + CError_ASSERT(80, pc->args[4].kind == PCOp_PLACEHOLDEROPERAND); + pc->args[4].kind = PCOp_REGISTER; + pc->args[4].arg = RegClass_CRFIELD; + pc->args[4].data.reg.reg = reg; + pc->args[4].data.reg.effect = EffectWrite; + } else { + arg = pc->args; + argIdx = argCount = pc->argCount; + while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) { + if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_CRFIELD && arg->data.reg.reg == reg) { + arg->data.reg.effect |= EffectWrite; + pc->flags |= fRecordBit; + return; + } + arg++; + argIdx--; + } + + if (argIdx <= 0) { + arg = &pc->args[argCount]; + pc->argCount++; + } + + CError_ASSERT(105, arg->kind == PCOp_PLACEHOLDEROPERAND); + arg->kind = PCOp_REGISTER; + arg->arg = RegClass_CRFIELD; + arg->data.reg.reg = reg; + arg->data.reg.effect = EffectWrite; + if (pc->op != PC_ADDICR) + pc->flags |= fRecordBit; + } +} + +void pcsetsideeffects(PCode *pc) { + pc->flags &= ~(fIsMove | fCommutative | fIsCSE); + pc->flags |= fSideEffects; +} + +void pcsetlinkbit(PCode *pc) { + PCodeArg *arg; + int argIdx; + + switch (pc->op) { + case PC_B: + pc->op = PC_BL; + break; + case PC_BCTR: + pc->op = PC_BCTRL; + break; + case PC_BLR: + pc->op = PC_BLRL; + break; + } + + arg = pc->args; + argIdx = pc->argCount; + while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) { + if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_SPR && arg->data.reg.reg == 1) { + arg->data.reg.effect |= EffectWrite; + pc->flags |= fLink; + return; + } + arg++; + argIdx--; + } + + CError_ASSERT(169, arg->kind == PCOp_PLACEHOLDEROPERAND); + arg->kind = PCOp_REGISTER; + arg->arg = RegClass_SPR; + arg->data.reg.reg = 1; + arg->data.reg.effect = EffectWrite; + + if (opcodeinfo[pc->op].flags & fIsCall) { + pc->flags &= ~fIsBranch; + pc->flags |= fIsCall; + } + pc->flags |= fLink; +} + +void branch_label(PCodeLabel *label) { + if (pclastblock->pcodeCount) { + pcbranch(pclastblock, label); + makepcblock(); + } + pclabel(pclastblock, label); +} + +void branch_conditional(short a, short compareop, short c, PCodeLabel *label) { + PCodeBlock *tmpblock; + PCodeLabel *tmplabel; + int r28; + + tmpblock = pclastblock; + tmplabel = makepclabel(); + + switch (compareop) { + case ENOTEQU: + c = !c; + case EEQU: + r28 = 2; + break; + case EGREATEREQU: + c = !c; + case ELESS: + r28 = 0; + break; + case ELESSEQU: + c = !c; + case EGREATER: + r28 = 1; + break; + } + + emitpcode(c ? PC_BT : PC_BF, a, r28, label); + pcbranch(pclastblock, label); + pcbranch(pclastblock, tmplabel); + makepcblock(); + pclabel(pclastblock, tmplabel); +} + +void branch_always(PCodeLabel *label) { + emitpcode(PC_B, label); + pcbranch(pclastblock, label); + makepcblock(); +} + +void branch_decrement_always(Opcode opcode, PCodeLabel *label) { + PCodeLabel *tmplabel = makepclabel(); + emitpcode(opcode, label); + pcbranch(pclastblock, label); + pcbranch(pclastblock, tmplabel); + makepcblock(); + pclabel(pclastblock, tmplabel); +} + +void branch_indirect(Object *obj) { + emitpcode(PC_BCTR, obj, 0); + makepcblock(); +} + +int branch_count_volatiles(void) { + int count = 0; + int i; + RegClass rclass; + + for (rclass = 0; rclass < RegClassMax; rclass++) { + for (i = 0; i < n_scratch_registers[rclass]; i++) { + count++; + } + } + + return count; +} + +PCodeArg *branch_record_volatiles(PCodeArg *arglist, UInt32 *masks) { + int i; + RegClass rclass; + + for (rclass = RegClassMax - 1; rclass >= 0; rclass--) { + for (i = 0; i < n_scratch_registers[rclass]; i++) { + arglist->kind = PCOp_REGISTER; + arglist->arg = rclass; + arglist->data.reg.reg = scratch_registers[rclass][i]; + arglist->data.reg.effect = EffectWrite; + if (masks[rclass] & (1 << scratch_registers[rclass][i])) + arglist->data.reg.effect |= EffectRead; + arglist++; + } + } + + return arglist; +} + +void branch_subroutine(Object *obj, short add_nop, UInt32 *masks) { + int count; + PCode *pc; + PCodeArg *arg; + + count = branch_count_volatiles(); + if (copts.exceptions && current_statement) + count += countexceptionactionregisters(current_statement->dobjstack); + + pc = makepcode(PC_BL, count, obj, 0); + arg = branch_record_volatiles(pc->args + 1, masks); + if (copts.exceptions && current_statement) + noteexceptionactionregisters(current_statement->dobjstack, arg); + appendpcode(pclastblock, pc); + + if (add_nop) + emitpcode(PC_NOP); + + branch_label(makepclabel()); + if (copts.exceptions && current_statement) + recordexceptionactions(pc, current_statement->dobjstack); +} + +void branch_subroutine_ctr(UInt32 *masks) { + int count; + PCode *pc; + PCodeArg *arg; + + count = branch_count_volatiles(); + if (copts.exceptions && current_statement) + count += countexceptionactionregisters(current_statement->dobjstack); + + pc = makepcode(PC_BCTRL, count); + arg = branch_record_volatiles(pc->args + 1, masks); + if (copts.exceptions && current_statement) + noteexceptionactionregisters(current_statement->dobjstack, arg); + appendpcode(pclastblock, pc); + + branch_label(makepclabel()); + if (copts.exceptions && current_statement) + recordexceptionactions(pc, current_statement->dobjstack); +} + +void add_immediate(short dest_reg, short base_reg, Object *obj, SInt16 offset) { + short tmp_reg = base_reg; + + if (obj && offset && obj->datatype != DLOCAL) { + tmp_reg = used_virtual_registers[RegClass_GPR]++; + add_immediate_lo(tmp_reg, base_reg, obj, 0, 1); + obj = NULL; + } + + if (!obj && !offset) + emitpcode(PC_MR, dest_reg, tmp_reg); + else + emitpcode(PC_ADDI, dest_reg, tmp_reg, obj, offset); +} + +PCode *add_immediate_lo(short dest_reg, short base_reg, Object *obj, SInt16 offset, char add_to_block) { + PCode *pc; + + CError_ASSERT(577, obj); + + pc = makepcode(PC_ADDI, dest_reg, base_reg, obj, offset); + if (add_to_block) + appendpcode(pclastblock, pc); + return pc; +} + +PCode *op_absolute_ha(short dest_reg, short base_reg, Object *obj, short offset, char add_to_block) { + PCode *pc; + int tmp_reg; + + if (obj->datatype == DLOCAL) { + pc = makepcode(PC_ADDIS, dest_reg, base_reg, obj, offset); + } else if (copts.codegen_pic) { + tmp_reg = base_reg; + CError_ASSERT(601, tmp_reg); + pc = makepcode(PC_ADDIS, dest_reg, tmp_reg, obj, offset); + } else { + CError_ASSERT(606, base_reg == 0); + pc = makepcode(PC_LIS, dest_reg, obj, offset); + } + + if (add_to_block) + appendpcode(pclastblock, pc); + return pc; +} + +void load_store_register(Opcode opcode, short dest_reg, short base_reg, Object *obj, SInt32 offset) { + short addi_tmp; + short offset_reg1; + short offset_reg2; + + offset_reg1 = base_reg; + if (obj && offset && obj->datatype != DLOCAL) { + offset_reg1 = used_virtual_registers[RegClass_GPR]++; + add_immediate_lo(offset_reg1, base_reg, obj, 0, 1); + obj = NULL; + } + + if (offset != (short)offset) { + if (opcode == PC_LWZ && dest_reg == 12) + offset_reg2 = 12; + else if (opcode == PC_LWZ && dest_reg == 11) + offset_reg2 = 11; + else + offset_reg2 = used_virtual_registers[RegClass_GPR]++; + + emitpcode(PC_ADDIS, offset_reg2, offset_reg1, 0, (short) ((offset >> 16) + ((offset & 0x8000) >> 15))); + offset = (short) offset; + offset_reg1 = offset_reg2; + } + + if (opcode == PC_STVX || opcode == PC_LVX) { + offset_reg2 = 0; + if (obj) { + addi_tmp = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_ADDI, addi_tmp, offset_reg1, obj, offset); + offset_reg1 = addi_tmp; + } else if (offset) { + offset_reg2 = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LI, offset_reg2, offset); + } + if (!offset_reg2) + emitpcode(opcode, dest_reg, 0, offset_reg1); + else + emitpcode(opcode, dest_reg, offset_reg1, offset_reg2); + } else { + emitpcode(opcode, dest_reg, offset_reg1, obj, offset); + } +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c new file mode 100644 index 0000000..151e448 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c @@ -0,0 +1,2753 @@ +#include "compiler/Peephole.h" +#include "compiler/CompilerTools.h" +#include "compiler/InstrSelection.h" +#include "compiler/PCode.h" +#include "compiler/objects.h" +#include "compiler/types.h" +#include "compiler/Scheduler.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/Alias.h" +#include "compiler/CParser.h" + +typedef int (*PeepholeFunc)(PCode *instr, UInt32 *masks); + +typedef struct Pattern { + struct Pattern *next; + PeepholeFunc func; +} Pattern; + +typedef struct LiveRegs { + UInt32 x0; + UInt32 x4; + UInt32 x8; + UInt32 xC; +} LiveRegs; + +static LiveRegs *liveregs[RegClassMax]; +static Pattern *peepholepatterns[OPCODE_MAX]; +static PCode **defininginstruction; + +static void computeregisterusedefs(void) { + PCodeBlock *block; + PCode *instr; + PCodeArg *op; + int i; + RegClass rclass; + LiveRegs *lr; + UInt32 array1[RegClassMax]; + UInt32 array2[RegClassMax]; + + for (block = pcbasicblocks; block; block = block->nextBlock) { + for (rclass = 0; rclass < RegClassMax; rclass++) { + array1[rclass] = 0; + array2[rclass] = 0; + } + + for (instr = block->firstPCode; instr; instr = instr->nextPCode) { + for (op = instr->args, i = instr->argCount; i--; op++) { + if ( + op->kind == PCOp_REGISTER && + (op->data.reg.effect & EffectRead) && + !((1 << op->data.reg.reg) & array2[op->arg]) + ) + array1[op->arg] |= 1 << op->data.reg.reg; + } + + for (op = instr->args, i = instr->argCount; i--; op++) { + if ( + op->kind == PCOp_REGISTER && + (op->data.reg.effect & EffectWrite) && + !((1 << op->data.reg.reg) & array1[op->arg]) + ) + array2[op->arg] |= 1 << op->data.reg.reg; + } + } + + for (rclass = 0; rclass < RegClassMax; rclass++) { + lr = liveregs[rclass] + block->blockIndex; + lr->x0 = array1[rclass]; + lr->x4 = array2[rclass]; + if (rclass == RegClass_GPR) { + lr->x8 = 1 << 1; + lr->xC = 1 << 1; + } else { + lr->x8 = 0; + lr->xC = 0; + } + } + } +} + +static void computeliveness(LiveRegs *lrarray, UInt32 x) { + PCodeBlock *block; + LiveRegs *lr; + PCLink *link; + UInt32 newC; + UInt32 new8; + int i; + int flag; + + flag = 1; + while (flag) { + flag = 0; + i = pcblockcount; + while (i) { + if ((block = depthfirstordering[--i])) { + lr = lrarray + block->blockIndex; + newC = x; + for (link = block->successors; link; link = link->nextLink) + newC |= lrarray[link->block->blockIndex].x8; + lr->xC = newC; + + new8 = lr->x0 | (lr->xC & ~lr->x4); + if (new8 != lr->x8) { + lr->x8 = new8; + flag = 1; + } + } + } + } +} + +static void computeliveregisters(Object *func) { + Type *returntype; + RegClass rclass; + + returntype = TYPE_FUNC(func->type)->functype; + + for (rclass = 0; rclass < RegClassMax; rclass++) + liveregs[rclass] = lalloc(sizeof(LiveRegs) * pcblockcount); + + computedepthfirstordering(); + computeregisterusedefs(); + + if (TYPE_FITS_IN_REGISTER(returntype)) { + liveregs[RegClass_GPR][epilogue->blockIndex].x0 |= 1 << 3; + if (TYPE_IS_8BYTES(returntype)) + liveregs[RegClass_GPR][epilogue->blockIndex].x0 |= 1 << 4; + } else if (IS_TYPE_FLOAT(returntype)) { + liveregs[RegClass_FPR][epilogue->blockIndex].x0 |= 1 << 1; + } else if (IS_TYPE_VECTOR(returntype)) { + liveregs[RegClass_VR][epilogue->blockIndex].x0 |= 1 << 2; + } + + for (rclass = 0; rclass < RegClassMax; rclass++) { + if (rclass == RegClass_GPR) + computeliveness(liveregs[rclass], 2); + else + computeliveness(liveregs[rclass], 0); + } +} + +static void computeinstructionpredecessors(PCodeBlock *block) { + PCode *nop; + RegClass rclass; + SInt32 i; + SInt32 defID; + SInt32 totalOps; + PCode *instr; + PCodeArg *op; + PCode *array[RegClassMax][32]; + + nop = makepcode(PC_NOP); + for (rclass = 0; rclass < RegClassMax; rclass++) { + for (i = 0; i < 32; i++) { + array[rclass][i] = nop; + } + } + + totalOps = 0; + for (instr = block->firstPCode; instr; instr = instr->nextPCode) + totalOps += instr->argCount; + + if (totalOps) { + defininginstruction = oalloc(sizeof(PCode *) * totalOps); + for (i = 0; i < totalOps; i++) + defininginstruction[i] = nop; + + defID = 0; + for (instr = block->firstPCode; instr; instr = instr->nextPCode) { + instr->defID = defID; + + for (i = 0, op = instr->args; i < instr->argCount; i++, op++) { + if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectRead)) + defininginstruction[defID + i] = array[op->arg][op->data.reg.reg]; + } + + for (i = 0, op = instr->args; i < instr->argCount; i++, op++) { + if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite)) + array[op->arg][op->data.reg.reg] = instr; + } + + defID += instr->argCount; + } + } +} + +static int dead(PCode *instr, UInt32 *masks) { + int i; + PCodeArg *op; + + if (instr->block->flags & (fIsProlog | fIsEpilogue)) + return 0; + if (instr->flags & (fIsBranch | fIsWrite | fIsCall | fIsVolatile | fSideEffects)) + return 0; + if (!instr->block->predecessors) + return 1; + + for (op = instr->args, i = instr->argCount; i--; op++) { + if ( + op->kind == PCOp_REGISTER && + (op->data.reg.effect & EffectWrite) && + ((1 << op->data.reg.reg) & masks[op->arg]) + ) + return 0; + } + + return 1; +} + +static int definedbetween(PCode *start, PCode *end, PCodeArg *checkOp) { + PCode *instr; + PCodeArg *op; + int i; + + for (instr = start->prevPCode; instr != end; instr = instr->prevPCode) { + for (op = instr->args, i = instr->argCount; i--; op++) { + if (PC_OP_IS_WRITE_REGISTER(op, checkOp->arg, checkOp->data.reg.reg)) + return 1; + } + } + + return 0; +} + +static int usedbetween(PCode *start, PCode *end, PCodeArg *checkOp) { + PCode *instr; + PCodeArg *op; + int i; + + for (instr = start->prevPCode; instr != end; instr = instr->prevPCode) { + for (op = instr->args, i = instr->argCount; i--; op++) { + if (PC_OP_IS_READ_REGISTER(op, checkOp->arg, checkOp->data.reg.reg)) + return 1; + } + } + + return 0; +} + +static int isSPRlive(PCode *instr, int reg) { + PCode *scan; + PCodeArg *op; + int i; + + for (scan = instr->nextPCode; scan; scan = scan->nextPCode) { + for (op = scan->args, i = scan->argCount; i--; op++) { + if (PC_OP_IS_READ_REGISTER(op, RegClass_SPR, reg)) + return 1; + + if (PC_OP_IS_WRITE_REGISTER(op, RegClass_SPR, reg)) + return 0; + } + } + + return 0; +} + +static SInt32 extractedbits(PCode *instr) { + SInt32 a = instr->args[2].data.imm.value; + SInt32 b = instr->args[3].data.imm.value; + SInt32 c = instr->args[4].data.imm.value; + SInt32 val; + + if (b <= c) + val = ((b > 31) ? 0 : (0xFFFFFFFFu >> b)) & ~(((c + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c + 1))); + else + val = ((b > 31) ? 0 : (0xFFFFFFFFu >> b)) | ~(((c + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c + 1))); + + return ((UInt32) val >> a) | (val << (32 - a)); +} + +static int canmergemasks(SInt32 b1, SInt32 c1, SInt32 a, SInt32 b2, SInt32 c2, short *first, short *last) { + SInt32 val1; + SInt32 val2; + + if (b1 <= c1) + val1 = ((b1 > 31) ? 0 : (0xFFFFFFFFu >> b1)) & ~(((c1 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c1 + 1))); + else + val1 = ((b1 > 31) ? 0 : (0xFFFFFFFFu >> b1)) | ~(((c1 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c1 + 1))); + + if (b2 <= c2) + val2 = ((b2 > 31) ? 0 : (0xFFFFFFFFu >> b2)) & ~(((c2 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c2 + 1))); + else + val2 = ((b2 > 31) ? 0 : (0xFFFFFFFFu >> b2)) | ~(((c2 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c2 + 1))); + + return ismaskconstant(val2 & ((val1 << a) | ((UInt32) val1 >> (32 - a))), first, last); +} + +static int canuseupdatetest(PCodeBlock *block, PCode *instr, int count1, int count2, int count3, int count4, int count5) { + int i; + PCLink *link; + + while (instr) { + if (++count1 > 17) + return 1; + + switch (instr->op) { + case PC_DIVW: + case PC_DIVWU: + case PC_MULHW: + case PC_MULHWU: + case PC_MULLI: + case PC_MULLW: + return count3 == 0; + case PC_MTXER: + case PC_MTCTR: + case PC_MTLR: + case PC_MTCRF: + case PC_MTMSR: + case PC_MTSPR: + case PC_MFMSR: + case PC_MFSPR: + case PC_MFXER: + case PC_MFCTR: + case PC_MFLR: + case PC_MFCR: + case PC_ECIWX: + case PC_ECOWX: + case PC_DCBI: + case PC_ICBI: + case PC_MCRFS: + case PC_MCRXR: + case PC_MFTB: + case PC_MFSR: + case PC_MTSR: + case PC_MFSRIN: + case PC_MTSRIN: + case PC_MTFSB0: + case PC_MTFSB1: + case PC_MTFSFI: + case PC_SC: + case PC_TLBIA: + case PC_TLBIE: + case PC_TLBLD: + case PC_TLBLI: + case PC_TLBSYNC: + case PC_TW: + case PC_TRAP: + case PC_TWI: + case PC_MFROM: + case PC_DSA: + case PC_ESA: + return 1; + case PC_CRAND: + case PC_CRANDC: + case PC_CREQV: + case PC_CRNAND: + case PC_CRNOR: + case PC_CROR: + case PC_CRORC: + case PC_CRXOR: + case PC_MCRF: + if (++count5 > 1) + return 1; + } + + if (instr->flags & (fIsRead | fIsWrite)) { + if (++count4 > 1) + return 1; + } else if (instr->flags & fIsBranch) { + if (++count2 > 2) + return 1; + + for (i = 0; i < instr->argCount; i++) { + if (PC_OP_IS_ANY_REGISTER(&instr->args[i], RegClass_CRFIELD)) { + ++count3; + break; + } + } + } + + instr = instr->nextPCode; + } + + if (block && block->successors) { + for (link = block->successors; link; link = link->nextLink) { + if (link->block && !canuseupdatetest(link->block, link->block->firstPCode, count1, count2, count3, count4, count5)) + return 0; + } + } + + return 1; +} + +static int canuseupdate(PCode *instr) { + return canuseupdatetest(instr->block, instr->nextPCode, 0, 0, 0, 0, 0); +} + +static int MR_Rx_Rx(PCode *instr, UInt32 *masks) { + if ( + instr->args[0].data.reg.reg == instr->args[1].data.reg.reg && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) + ) + { + deletepcode(instr); + return 1; + } + + return 0; +} + +static int FMR_Fx_Fx(PCode *instr, UInt32 *masks) { + if ( + instr->args[0].data.reg.reg == instr->args[1].data.reg.reg && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) + ) + { + deletepcode(instr); + return 1; + } + + return 0; +} + +static int VMR_Vx_Vx(PCode *instr, UInt32 *masks) { + if ( + instr->args[0].data.reg.reg == instr->args[1].data.reg.reg && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) + ) + { + deletepcode(instr); + return 1; + } + + return 0; +} + +static int MR_MR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_MR && + instr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg && + !definedbetween(instr, defInstr, &instr->args[0]) && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) + ) + { + deletepcode(instr); + return 1; + } + + return 0; +} + +static int FMR_FMR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_FMR && + instr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + !definedbetween(instr, defInstr, &instr->args[0]) + ) + { + deletepcode(instr); + return 1; + } + + return 0; +} + +static int VMR_VMR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_VMR && + instr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + !definedbetween(instr, defInstr, &instr->args[0]) + ) + { + deletepcode(instr); + return 1; + } + + return 0; +} + +static int VMR_VMRP(PCode *instr, UInt32 *masks) { + PCode *prev = instr->prevPCode; + PCode *next = instr->nextPCode; + int prevFlag = 0; + int prevPermute = 0; + int nextFlag = 0; + int nextPermute = 0; + + if (prev) { + prevFlag = (prev->flags & fOpTypeMask) == fOpTypeVR; + prevPermute = uses_vpermute_unit(prev); + } + if (next) { + nextFlag = (next->flags & fOpTypeMask) == fOpTypeVR; + nextPermute = uses_vpermute_unit(next); + } + + if (prev) { + if (next) { + if (prevFlag && !prevPermute) { + if (nextFlag) { + if (!nextPermute) { + change_opcode(instr, PC_VMRP); + return 1; + } + } else { + change_opcode(instr, PC_VMRP); + return 1; + } + } + } else { + if (prevFlag && !prevPermute) { + change_opcode(instr, PC_VMRP); + return 1; + } + } + } else { + if (next && nextFlag && !nextPermute) { + change_opcode(instr, PC_VMRP); + return 1; + } + } + + return 0; +} + +static int MR_CMPI(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + PCodeArg op; + + if ( + instr->args[0].data.reg.reg == 0 && + instr->args[2].data.imm.value == 0 && + (PCODE_FLAG_SET_F(defInstr) & (fSideEffects | fCanSetRecordBit | fOpTypeGPR)) == (fCanSetRecordBit | fOpTypeGPR) && + !usedbetween(instr, defInstr, &instr->args[0]) && + !definedbetween(instr, defInstr, &instr->args[0]) + ) + { + if (defInstr->op == PC_ADDI) { + op.kind = PCOp_REGISTER; + op.arg = RegClass_SPR; + op.data.reg.reg = 0; + op.data.reg.effect = EffectRead | EffectWrite; + if (usedbetween(instr, defInstr, &op)) + return 0; + } + + pcsetrecordbit(defInstr); + deletepcode(instr); + return 1; + } + + return 0; +} + +static int EXTSB_RLWINM(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_EXTSB && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + (extractedbits(instr) & 0xFFFFFF00) == 0 + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int EXTSH_RLWINM(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_EXTSH && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + (extractedbits(instr) & 0xFFFF0000) == 0 + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int LBZ_RLWINM(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + (defInstr->op == PC_LBZ || defInstr->op == PC_LBZX) && + instr->args[2].data.imm.value == 0 && + instr->args[3].data.imm.value <= 24 && + instr->args[4].data.imm.value == 31 && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + !definedbetween(instr, defInstr, &instr->args[0]) && + !usedbetween(instr, defInstr, &instr->args[0]) + ) + { + defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg; + deletepcode(instr); + return 1; + } + + return 0; +} + +static int LHZ_RLWINM(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + (defInstr->op == PC_LHZ || defInstr->op == PC_LHZX) && + instr->args[2].data.imm.value == 0 && + instr->args[3].data.imm.value <= 16 && + instr->args[4].data.imm.value == 31 && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + !definedbetween(instr, defInstr, &instr->args[0]) && + !usedbetween(instr, defInstr, &instr->args[0]) + ) + { + defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg; + deletepcode(instr); + return 1; + } + + return 0; +} + +static int LHA_EXTSH(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_LHA && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + !definedbetween(instr, defInstr, &instr->args[0]) && + !usedbetween(instr, defInstr, &instr->args[0]) + ) + { + defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg; + deletepcode(instr); + return 1; + } + + if ( + defInstr->op == PC_EXTSB && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) + ) + { + if (defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg) { + if ( + !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + { + change_opcode(instr, PC_EXTSB); + deletepcode(defInstr); + return 1; + } + } else { + if (!definedbetween(instr, defInstr, &defInstr->args[1])) { + change_opcode(instr, PC_EXTSB); + instr->args[1] = defInstr->args[1]; + } else { + change_opcode(instr, PC_MR); + } + return 1; + } + } + + return 0; +} + +static int ADDI_L_S(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + SInt32 addleft; + SInt32 addright; + + if (defInstr->op == PC_ADDI && instr->args[2].kind == PCOp_IMMEDIATE) { + if (!PC_OP_IS_REGISTER(&instr->args[0], RegClass_GPR, instr->args[1].data.reg.reg)) { + if ( + instr->args[2].data.imm.value == 0 && + defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + (!(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) || canuseupdate(instr)) + ) + { + if (!(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) { + instr->args[2] = defInstr->args[2]; + } else { + instr->op++; + instr->args[1].data.reg.effect |= EffectWrite; + instr->args[2] = defInstr->args[2]; + } + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + addleft = 0x1FFFF; + addright = instr->args[2].data.imm.value; + if (defInstr->args[2].kind == PCOp_IMMEDIATE) { + addleft = defInstr->args[2].data.imm.value; + } else if (defInstr->args[2].kind == PCOp_MEMORY) { + if (defInstr->args[2].data.mem.obj->datatype == DLOCAL) + addleft = defInstr->args[2].data.mem.offset + defInstr->args[2].data.mem.obj->u.var.uid; + else if (addright == 0) + addleft = 0; + else + return 0; + } + + if (!FITS_IN_SHORT(addleft + addright)) + return 0; + + if ( + !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + !definedbetween(instr, defInstr, &defInstr->args[1]) + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + if (defInstr->args[2].kind == PCOp_MEMORY) { + instr->args[2] = defInstr->args[2]; + instr->args[2].data.mem.offset += addright; + if (instr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) { + instr->alias = make_alias( + instr->args[2].data.mem.obj, + instr->args[2].data.mem.offset, + nbytes_loaded_or_stored_by(instr) + ); + } + } else { + instr->args[2].data.imm.value = addleft + addright; + } + + deletepcode(defInstr); + return 1; + } + + if ( + instr->args[1].data.reg.reg != defInstr->args[1].data.reg.reg && + !definedbetween(instr, defInstr, &defInstr->args[1]) + ) + { + if (defInstr->args[2].kind == PCOp_MEMORY && defInstr->args[2].data.mem.obj->datatype != DLOCAL) + return 0; + + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + if (defInstr->args[2].kind == PCOp_MEMORY) { + instr->args[2] = defInstr->args[2]; + instr->args[2].data.mem.offset += addright; + if (instr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) { + instr->alias = make_alias( + instr->args[2].data.mem.obj, + instr->args[2].data.mem.offset, + nbytes_loaded_or_stored_by(instr) + ); + } + } else { + instr->args[2].data.imm.value = addleft + addright; + } + + return 1; + } + } + } else { + if ( + defInstr->op == PC_MR && + PC_OP_IS_ANY_REGISTER(&defInstr->args[1], RegClass_GPR) && + defInstr->args[1].data.reg.reg != 0 && + !definedbetween(instr, defInstr, &defInstr->args[1]) + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + } + } + + return 0; +} + +static int ADDI_LU_SU(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + instr->args[2].kind == PCOp_IMMEDIATE && + defInstr->args[2].kind == PCOp_IMMEDIATE && + defInstr->op == PC_ADDI && + defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg && + !(instr->args[0].arg == instr->args[1].arg && instr->args[0].data.reg.reg == instr->args[1].data.reg.reg) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + FITS_IN_SHORT(instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) + ) + { + if ((instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) == 0) { + instr->op--; + instr->args[1].data.reg.effect &= ~EffectWrite; + instr->args[2].data.imm.value = 0; + } else { + instr->args[2].data.imm.value += defInstr->args[2].data.imm.value; + } + + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int L_S_ADDI(PCode *instr, UInt32 *masks) { + PCode *scan; + PCodeArg *op; + int i; + short reg; + + if (instr->args[2].kind != PCOp_IMMEDIATE) + return 0; + + reg = instr->args[1].data.reg.reg; + if (!canuseupdate(instr)) + return 0; + + for (scan = instr->nextPCode; scan; scan = scan->nextPCode) { + for (op = scan->args, i = scan->argCount; i--; op++) { + if (PC_OP_IS_READ_REGISTER(op, RegClass_GPR, reg)) + return 0; + + if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg)) { + if (scan->op != PC_ADDI) + return 0; + if (scan->args[2].kind != PCOp_IMMEDIATE) + return 0; + + if ( + instr->args[2].data.imm.value == scan->args[2].data.imm.value && + scan->args[0].data.reg.reg == scan->args[1].data.reg.reg && + !(instr->args[0].arg == instr->args[1].arg && instr->args[0].data.reg.reg == instr->args[1].data.reg.reg) + ) + { + if (!(masks[RegClass_GPR] & (1 << scan->args[0].data.reg.reg))) { + instr->args[2] = scan->args[2]; + } else { + instr->op++; + instr->args[1].data.reg.effect |= EffectWrite; + instr->args[2] = scan->args[2]; + } + + change_opcode(scan, PC_NOP); + change_num_operands(scan, 0); + deletepcode(scan); + return 1; + } + + return 0; + } + } + } + + return 0; +} + +static int LI_CMP_BC(PCode *instr, UInt32 *masks) { + PCode *defInstr; + PCode *defInstr2; + PCLink *link; + PCLink **ptr; + + if (instr->args[1].data.imm.value == 2) { + defInstr = defininginstruction[instr->defID]; + if ((defInstr->op == PC_CMPLI || defInstr->op == PC_CMPI) && defInstr->args[0].data.reg.reg == 0) { + defInstr2 = defininginstruction[defInstr->defID + 1]; + if ( + defInstr2->op == PC_LI && + defInstr2->args[1].kind == PCOp_IMMEDIATE && + (instr->op == PC_BT) == (defInstr2->args[1].data.imm.value == defInstr->args[2].data.imm.value) + ) + { + change_opcode(instr, PC_B); + instr->args[0] = instr->args[2]; + change_num_operands(instr, 1); + + defininginstruction[instr->defID] = defininginstruction[instr->defID + 1]; + + for (ptr = &instr->block->successors; (link = *ptr); ptr = &link->nextLink) { + if (link->block == instr->block->nextBlock) { + *ptr = link->nextLink; + break; + } + } + + for (ptr = &instr->block->nextBlock->predecessors; (link = *ptr); ptr = &link->nextLink) { + if (link->block == instr->block) { + *ptr = link->nextLink; + break; + } + } + } + } + } + + return 0; +} + +static int RLWINM_CMPLI_BC(PCode *instr, UInt32 *masks) { + PCode *defInstr; + PCode *defInstr2; + + if (instr->args[1].data.imm.value == 2) { + defInstr = defininginstruction[instr->defID]; + if (defInstr->op == PC_CMPLI && defInstr->args[0].data.reg.reg == 0 && defInstr->args[2].data.imm.value == 0) { + defInstr2 = defininginstruction[defInstr->defID + 1]; + if ( + (PCODE_FLAG_SET_F(defInstr2) & (fSideEffects | fCanSetRecordBit | fOpTypeGPR)) == (fCanSetRecordBit | fOpTypeGPR) && + !usedbetween(defInstr, defInstr2, &defInstr->args[0]) && + !definedbetween(defInstr, defInstr2, &defInstr->args[0]) + ) + { + pcsetrecordbit(defInstr2); + defininginstruction[instr->defID] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + } + } + + return 0; +} + +static int LBZ_EXTSB_CMPI_BC(PCode *instr, UInt32 *masks) { + PCode *defInstr; + PCode *defInstr2; + + if (instr->args[1].data.imm.value == 2) { + defInstr = defininginstruction[instr->defID]; + if ( + ( + (defInstr->op == PC_CMPI || defInstr->op == PC_CMPLI) && + defInstr->args[2].data.imm.value >= 0 && + defInstr->args[2].data.imm.value <= 127 + ) + || + ( + (defInstr->op == PC_EXTSB || defInstr->op == PC_EXTSH) && + (PCODE_FLAG_SET_F(defInstr) & fRecordBit) + ) + ) + { + defInstr2 = defininginstruction[defInstr->defID + 1]; + if ( + defInstr2->op == PC_EXTSB && + defininginstruction[defInstr2->defID + 1]->op == PC_LBZ && + !(masks[RegClass_GPR] & (1 << defInstr2->args[0].data.reg.reg)) && + !usedbetween(instr, defInstr, &defInstr2->args[0]) && + !usedbetween(defInstr, defInstr2, &defInstr2->args[0]) && + !definedbetween(defInstr, defInstr2, &defInstr2->args[1]) + ) + { + defInstr->args[1].data.reg.reg = defInstr2->args[1].data.reg.reg; + defininginstruction[defInstr->defID + 1] = defininginstruction[defInstr2->defID + 1]; + deletepcode(defInstr2); + return 1; + } + } + } + + return 0; +} + +static int FRSP_STFS(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID]; + + if ( + defInstr->op == PC_FRSP && + !(masks[RegClass_FPR] & (1 << defInstr->args[0].data.reg.reg)) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + { + instr->args[0].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int NOT_AND(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 2]; + + if ( + defInstr->op == PC_NOT && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + { + instr->args[2].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 2] = defininginstruction[defInstr->defID + 1]; + change_opcode(instr, PC_ANDC); + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int LI_MR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_LI && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + { + change_opcode(instr, PC_LI); + instr->args[1] = defInstr->args[1]; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int VSPLTIS_VMR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + short opcode = defInstr->op; + + if ( + (opcode == PC_VSPLTISB || opcode == PC_VSPLTISH || opcode == PC_VSPLTISW) && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_VR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + { + change_opcode(instr, opcode); + instr->args[1] = defInstr->args[1]; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int L_MR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + (defInstr->flags & fIsRead) && + !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + !usedbetween(instr, defInstr, &instr->args[0]) && + !definedbetween(instr, defInstr, &instr->args[0]) + ) + { + defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg; + deletepcode(instr); + return 1; + } + + return 0; +} + +static int L_FMR(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + (defInstr->flags & fIsRead) && + !(masks[RegClass_FPR] & (1 << defInstr->args[0].data.reg.reg)) && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + !usedbetween(instr, defInstr, &instr->args[0]) && + !definedbetween(instr, defInstr, &instr->args[0]) + ) + { + defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg; + deletepcode(instr); + return 1; + } + + return 0; +} + +static int L_S(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID]; + SInt32 isIndexed; + SInt32 isFloat; + SInt32 isVector; + PCode *scan; + SInt32 loadSize; + SInt32 defInstrOffset; + SInt32 scanOffset; + SInt32 storeSize; + + if (PCODE_FLAG_SET_F(instr) & (fIsVolatile | fSideEffects | fUpdatesPtr)) + return 0; + if (PCODE_FLAG_SET_F(defInstr) & (fIsVolatile | fSideEffects | fUpdatesPtr)) + return 0; + + if ( + (defInstr->flags & fIsRead) && + PC_OP_IS_REGISTER(&defInstr->args[1], RegClass_GPR, instr->args[1].data.reg.reg) && + defInstr->args[2].kind == instr->args[2].kind && + !definedbetween(instr, defInstr, &instr->args[1]) + ) + { + if (instr->args[2].kind == PCOp_IMMEDIATE) { + if (instr->args[2].data.imm.value != defInstr->args[2].data.imm.value) + return 0; + } else if (instr->args[2].kind == PCOp_MEMORY) { + if (instr->args[2].data.mem.offset != defInstr->args[2].data.mem.offset || + instr->args[2].data.mem.obj != defInstr->args[2].data.mem.obj) + return 0; + } else if (instr->args[2].kind == PCOp_REGISTER && instr->args[2].arg == RegClass_GPR) { + if (instr->args[2].data.reg.reg != defInstr->args[2].data.reg.reg || + definedbetween(instr, defInstr, &instr->args[2])) + return 0; + } else { + return 0; + } + + isIndexed = 0; + isFloat = 0; + isVector = 0; + switch (defInstr->op) { + case PC_LBZX: + isIndexed = 1; + case PC_LBZ: + loadSize = 1; + break; + case PC_LHZX: + case PC_LHAX: + isIndexed = 1; + case PC_LHZ: + case PC_LHA: + loadSize = 2; + break; + case PC_LWZX: + isIndexed = 1; + case PC_LWZ: + loadSize = 4; + break; + case PC_LFSX: + isIndexed = 1; + case PC_LFS: + isFloat = 1; + loadSize = 4; + break; + case PC_LFDX: + isIndexed = 1; + case PC_LFD: + isFloat = 1; + loadSize = 8; + break; + case PC_LVX: + case PC_LVXL: + isIndexed = 1; + isVector = 1; + loadSize = 16; + break; + default: + return 0; + } + + switch (instr->op) { + case PC_STBX: + if (!isIndexed) return 0; + case PC_STB: + if (isFloat) return 0; + if (loadSize != 1) return 0; + break; + case PC_STHX: + if (!isIndexed) return 0; + case PC_STH: + if (isFloat) return 0; + if (loadSize != 2) return 0; + break; + case PC_STWX: + if (!isIndexed) return 0; + case PC_STW: + if (isFloat) return 0; + if (loadSize != 4) return 0; + break; + case PC_STFSX: + if (!isIndexed) return 0; + case PC_STFS: + if (!isFloat) return 0; + if (loadSize != 4) return 0; + break; + case PC_STFDX: + if (!isIndexed) return 0; + case PC_STFD: + if (!isFloat) return 0; + if (loadSize != 8) return 0; + break; + case PC_STVX: + case PC_STVXL: + if (!isIndexed) return 0; + if (!isVector) return 0; + if (loadSize != 16) return 0; + break; + default: + return 0; + } + + for (scan = instr->prevPCode; scan && scan != defInstr; scan = scan->prevPCode) { + if (scan->flags & fIsWrite) { + if (scan->args[1].data.reg.reg != instr->args[1].data.reg.reg) + return 0; + if (scan->args[2].kind != defInstr->args[2].kind) + return 0; + + if (scan->args[2].kind == PCOp_MEMORY) { + if (instr->args[2].data.mem.obj == scan->args[2].data.mem.obj) { + if (instr->args[2].data.mem.offset == defInstr->args[2].data.mem.offset) + return 0; + defInstrOffset = defInstr->args[2].data.mem.offset; + scanOffset = scan->args[2].data.mem.offset; + } + } else if (scan->args[2].kind == PCOp_IMMEDIATE) { + if (instr->args[1].data.reg.reg != scan->args[1].data.reg.reg) + return 0; + if (instr->args[2].data.imm.value == scan->args[2].data.imm.value) + return 0; + defInstrOffset = defInstr->args[2].data.imm.value; + scanOffset = scan->args[2].data.imm.value; + } else { + return 0; + } + + switch (scan->op) { + case PC_STB: + case PC_STBX: + storeSize = 1; + break; + case PC_STH: + case PC_STHX: + storeSize = 2; + break; + case PC_STW: + case PC_STWX: + case PC_STFS: + case PC_STFSX: + storeSize = 4; + break; + case PC_STFD: + case PC_STFDX: + storeSize = 8; + break; + case PC_STVX: + case PC_STVXL: + storeSize = 16; + break; + default: + return 0; + } + + if (defInstrOffset > scanOffset) { + if ((scanOffset + storeSize) > defInstrOffset) + return 0; + } else { + if ((defInstrOffset + loadSize) > scanOffset) + return 0; + } + } + } + + deletepcode(instr); + return 1; + } + + return 0; +} + +static int RLWINM_RLWINM(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + short start; + short end; + + if ( + defInstr->op == PC_RLWINM && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !( + defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg && + ( + (defInstr->args[0].data.reg.reg != instr->args[0].data.reg.reg && (masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) || + usedbetween(instr, defInstr, &defInstr->args[0]) + ) + ) && + canmergemasks( + defInstr->args[3].data.imm.value, + defInstr->args[4].data.imm.value, + instr->args[2].data.imm.value, + instr->args[3].data.imm.value, + instr->args[4].data.imm.value, + &start, &end) + ) + { + if (instr->op == PC_RLWIMI) { + if (instr->args[0].data.reg.reg == defInstr->args[0].data.reg.reg) + return 0; + if (start != instr->args[3].data.imm.value || end != instr->args[4].data.imm.value) + return 0; + } + + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + instr->args[2].data.imm.value = (instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) & 31; + instr->args[3].data.imm.value = start; + instr->args[4].data.imm.value = end; + + if ( + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + deletepcode(defInstr); + + return 1; + } + + if ( + defInstr->op == PC_MR && + instr->op == PC_RLWINM && + !definedbetween(instr, defInstr, &defInstr->args[1]) + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + if ( + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !usedbetween(instr, defInstr, &defInstr->args[0]) + ) + deletepcode(defInstr); + + return 1; + } + + return 0; +} + +static int MULLI_MULLI(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_MULLI && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + FITS_IN_SHORT(instr->args[2].data.imm.value * defInstr->args[2].data.imm.value) + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + instr->args[2].data.imm.value *= defInstr->args[2].data.imm.value; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int ADDI_ADDI(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_ADDI && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + instr->args[2].kind == PCOp_IMMEDIATE && + defInstr->args[2].kind == PCOp_IMMEDIATE && + FITS_IN_SHORT(instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + instr->args[2].data.imm.value += defInstr->args[2].data.imm.value; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int SRAWI_SRAWI(PCode *instr, UInt32 *masks) { + PCode *defInstr = defininginstruction[instr->defID + 1]; + + if ( + defInstr->op == PC_SRAWI && + (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) && + !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) && + !definedbetween(instr, defInstr, &defInstr->args[1]) && + !usedbetween(instr, defInstr, &defInstr->args[0]) && + instr->args[2].kind == PCOp_IMMEDIATE && + defInstr->args[2].kind == PCOp_IMMEDIATE && + (instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) < 32 && + (instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) > 0 + ) + { + instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1]; + + instr->args[2].data.imm.value += defInstr->args[2].data.imm.value; + deletepcode(defInstr); + return 1; + } + + return 0; +} + +static int MR_ADDI(PCode *instr, UInt32 *masks) { + PCode *prev = instr->prevPCode; + PCode *next = instr->nextPCode; + int prevFlag = 0; + int nextFlag = 0; + + if (copts.processor == CPU_PPC603e) { + if (prev) + prevFlag = (prev->flags & fOpTypeMask) == fOpTypeGPR; + if (next) + nextFlag = (next->flags & fOpTypeMask) == fOpTypeGPR; + + if ( + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + instr->argCount >= 2 && + instr->args[1].data.reg.reg != 0 && + (prevFlag || nextFlag) + ) + { + change_opcode(instr, PC_ADDI); + instr->args[2].kind = PCOp_IMMEDIATE; + instr->args[2].data.imm.value = 0; + instr->args[2].data.imm.obj = NULL; + change_num_operands(instr, 3); + } + } + + return 0; +} + +static int rotatedefinedusedtest(UInt32 *masks, PCode *instr, PCode *a, PCode *b, PCode *subfic) { + PCode *scan; + PCodeArg *op; + int i; + int reg1; + int reg2; + + if ( + (masks[RegClass_GPR] & (1 << subfic->args[0].data.reg.reg)) && + subfic->args[0].data.reg.reg != instr->args[0].data.reg.reg && + subfic->args[0].data.reg.reg != a->args[2].data.reg.reg + ) + return 1; + + for (scan = instr->block->firstPCode; scan != instr->block->lastPCode; scan = scan->nextPCode) { + if (scan == a) break; + if (scan == b) break; + if (scan == subfic) break; + } + + reg1 = a->args[1].data.reg.reg; + reg2 = subfic->args[1].data.reg.reg; + while (scan != instr) { + for (op = instr->args, i = instr->argCount; i--; op++) { + if ( + op->kind == PCOp_REGISTER && + op->arg == RegClass_GPR && + ( + ( + (op->data.reg.reg == reg1 || op->data.reg.reg == reg2) && + (op->data.reg.effect & EffectWrite) + ) + || + ( + op->data.reg.reg == subfic->args[0].data.reg.reg && (op->data.reg.effect & EffectRead) + ) + ) && + scan != a && + scan != b && + scan != subfic + ) + return 1; + } + + scan = scan->nextPCode; + } + + return 0; +} + +static int SRW_SUBFIC_RLW_OR(PCode *instr, UInt32 *masks) { + PCode *subfic; + PCode *defInstr1 = defininginstruction[instr->defID + 1]; + PCode *defInstr2 = defininginstruction[instr->defID + 2]; + + if (PCODE_FLAG_SET_F(instr) & fRecordBit) + return 0; + + if ( + (masks[RegClass_GPR] & (1 << instr->args[1].data.reg.reg)) && + instr->args[1].data.reg.reg != instr->args[0].data.reg.reg + ) + return 0; + + if ( + (masks[RegClass_GPR] & (1 << instr->args[2].data.reg.reg)) && + instr->args[1].data.reg.reg != instr->args[0].data.reg.reg + ) + return 0; + + if (defInstr1->op != PC_SRW && defInstr1->op != PC_SLW) + return 0; + if (defInstr2->op != PC_SRW && defInstr2->op != PC_SLW) + return 0; + + if (usedbetween(instr, defInstr1, &defInstr1->args[0])) + return 0; + if (usedbetween(instr, defInstr2, &defInstr2->args[0])) + return 0; + + if ( + defInstr1->op == PC_SRW && defInstr2->op == PC_SLW && + defInstr1->args[1].data.reg.reg == defInstr2->args[1].data.reg.reg + ) + { + subfic = defininginstruction[defInstr1->defID + 2]; + if ( + subfic->op == PC_SUBFIC && + subfic->args[1].data.reg.reg == defInstr2->args[2].data.reg.reg && + subfic->args[2].data.imm.value == 32 + ) + { + if (rotatedefinedusedtest(masks, instr, defInstr2, defInstr1, subfic)) + return 0; + + change_opcode(instr, PC_RLWNM); + + instr->args[1] = defInstr1->args[1]; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1]; + + instr->args[2] = defInstr2->args[2]; + defininginstruction[instr->defID + 2] = defininginstruction[defInstr2->defID + 2]; + + instr->args[3].kind = PCOp_IMMEDIATE; + instr->args[3].data.imm.value = 0; + instr->args[3].data.imm.obj = NULL; + + instr->args[4].kind = PCOp_IMMEDIATE; + instr->args[4].data.imm.value = 31; + instr->args[4].data.imm.obj = NULL; + + deletepcode(defInstr1); + deletepcode(defInstr2); + deletepcode(subfic); + return 1; + } + + subfic = defininginstruction[defInstr2->defID + 2]; + if ( + subfic->op == PC_SUBFIC && + subfic->args[1].data.reg.reg == defInstr1->args[2].data.reg.reg && + subfic->args[2].data.imm.value == 32 + ) + { + if (rotatedefinedusedtest(masks, instr, defInstr2, defInstr1, subfic)) + return 0; + + change_opcode(instr, PC_RLWNM); + + instr->args[1] = defInstr1->args[1]; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1]; + + instr->args[2] = defInstr2->args[2]; + defininginstruction[instr->defID + 2] = defininginstruction[defInstr2->defID + 2]; + + instr->args[3].kind = PCOp_IMMEDIATE; + instr->args[3].data.imm.value = 0; + instr->args[3].data.imm.obj = NULL; + + instr->args[4].kind = PCOp_IMMEDIATE; + instr->args[4].data.imm.value = 31; + instr->args[4].data.imm.obj = NULL; + + deletepcode(defInstr1); + deletepcode(defInstr2); + return 1; + } + } else if ( + defInstr1->op == PC_SLW && defInstr2->op == PC_SRW && + defInstr1->args[1].data.reg.reg == defInstr2->args[1].data.reg.reg + ) + { + subfic = defininginstruction[defInstr1->defID + 2]; + if ( + subfic->op == PC_SUBFIC && + subfic->args[1].data.reg.reg == defInstr2->args[2].data.reg.reg && + subfic->args[2].data.imm.value == 32 + ) + { + if (rotatedefinedusedtest(masks, instr, defInstr1, defInstr2, subfic)) + return 0; + + change_opcode(instr, PC_RLWNM); + + instr->args[1] = defInstr1->args[1]; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1]; + + instr->args[2] = defInstr1->args[2]; + defininginstruction[instr->defID + 2] = defininginstruction[defInstr1->defID + 2]; + + instr->args[3].kind = PCOp_IMMEDIATE; + instr->args[3].data.imm.value = 0; + instr->args[3].data.imm.obj = NULL; + + instr->args[4].kind = PCOp_IMMEDIATE; + instr->args[4].data.imm.value = 31; + instr->args[4].data.imm.obj = NULL; + + deletepcode(defInstr1); + deletepcode(defInstr2); + return 1; + } + + subfic = defininginstruction[defInstr2->defID + 2]; + if ( + subfic->op == PC_SUBFIC && + subfic->args[1].data.reg.reg == defInstr1->args[2].data.reg.reg && + subfic->args[2].data.imm.value == 32 + ) + { + if (rotatedefinedusedtest(masks, instr, defInstr1, defInstr2, subfic)) + return 0; + + change_opcode(instr, PC_RLWNM); + + instr->args[1] = defInstr1->args[1]; + defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1]; + + instr->args[2] = defInstr1->args[2]; + defininginstruction[instr->defID + 2] = defininginstruction[defInstr1->defID + 2]; + + instr->args[3].kind = PCOp_IMMEDIATE; + instr->args[3].data.imm.value = 0; + instr->args[3].data.imm.obj = NULL; + + instr->args[4].kind = PCOp_IMMEDIATE; + instr->args[4].data.imm.value = 31; + instr->args[4].data.imm.obj = NULL; + + deletepcode(defInstr1); + deletepcode(defInstr2); + deletepcode(subfic); + return 1; + } + } + + return 0; +} + +static int RLWINM_RLWIMI_STW(PCode *instr, UInt32 *masks) { + PCode *newInstr; + Boolean isZeroOffset; + int flags; + PCode *scan; + int i; + PCode *array[4]; + + flags = 0; + isZeroOffset = 0; + if (instr->op == PC_STW && instr->args[2].kind == PCOp_IMMEDIATE && instr->args[2].data.imm.value == 0) + isZeroOffset = 1; + + scan = instr; + for (i = 0; i < 4; i++) { + if (scan->op == PC_RLWINM) + array[i] = defininginstruction[scan->defID + 1]; + else + array[i] = defininginstruction[scan->defID]; + + scan = array[i]; + if (array[0]->args[1].data.reg.reg != scan->args[1].data.reg.reg) + return 0; + + if (i < 3) { + if (scan->op != PC_RLWIMI) + return 0; + } else { + if (scan->op != PC_RLWINM) + return 0; + } + + if (scan->args[2].data.imm.value == 8) { + if (scan->args[3].data.imm.value == 24 && scan->args[4].data.imm.value == 31) { + if (flags & 1) + return 0; + flags |= 1; + } else if (scan->args[3].data.imm.value == 8 && scan->args[4].data.imm.value == 15) { + if (flags & 4) + return 0; + flags |= 4; + } else { + return 0; + } + } else if (scan->args[2].data.imm.value == 24) { + if (scan->args[3].data.imm.value == 0 && scan->args[4].data.imm.value == 7) { + if (flags & 8) + return 0; + flags |= 8; + } else if (scan->args[3].data.imm.value == 16 && scan->args[4].data.imm.value == 23) { + if (flags & 2) + return 0; + flags |= 2; + } else { + return 0; + } + } else { + return 0; + } + } + + if (definedbetween(instr, array[3], &array[0]->args[1])) + return 0; + + if (instr->op == PC_STWX) { + change_opcode(instr, PC_STWBRX); + instr->args[0] = array[0]->args[1]; + defininginstruction[instr->defID] = defininginstruction[array[3]->defID + 1]; + return 1; + } + + if (instr->op == PC_STW) { + if (!isZeroOffset) { + if (masks[RegClass_GPR] & (1 << array[0]->args[0].data.reg.reg)) + return 0; + + if (usedbetween(array[2], array[3], &array[0]->args[0])) + return 0; + if (usedbetween(array[1], array[2], &array[0]->args[0])) + return 0; + if (usedbetween(array[0], array[1], &array[0]->args[0])) + return 0; + if (usedbetween(instr, array[0], &array[0]->args[0])) + return 0; + } + + defininginstruction[instr->defID] = defininginstruction[array[3]->defID + 1]; + + if (!isZeroOffset) { + newInstr = makepcode(PC_STWBRX, array[3]->args[1].data.reg.reg, 0, instr->args[0].data.reg.reg); + newInstr->alias = instr->alias; + change_opcode(instr, PC_ADDI); + insertpcodeafter(instr, newInstr); + + masks[RegClass_GPR] |= 1 << newInstr->args[0].data.reg.reg; + masks[RegClass_GPR] |= 1 << newInstr->args[2].data.reg.reg; + instr->args[0].data.reg.effect &= ~EffectRead; + instr->args[0].data.reg.effect |= EffectWrite; + defininginstruction[instr->defID] = instr; + + deletepcode(array[0]); + deletepcode(array[1]); + deletepcode(array[2]); + deletepcode(array[3]); + } else { + change_opcode(instr, PC_STWBRX); + instr->args[0] = array[0]->args[1]; + instr->args[2] = instr->args[1]; + defininginstruction[instr->defID + 2] = defininginstruction[instr->defID + 1]; + + instr->args[1].kind = PCOp_REGISTER; + instr->args[1].arg = RegClass_GPR; + instr->args[1].data.reg.reg = 0; + instr->args[1].data.reg.effect = 0; + } + + return 1; + } + + return 0; +} + +static int RLWINM_RLWIMI_STH(PCode *instr, UInt32 *masks) { + PCode *newInstr; + Boolean isZeroOffset; + int flags; + PCode *scan; + int i; + PCode *array[2]; + + flags = 0; + isZeroOffset = 0; + if (instr->op == PC_STH && instr->args[2].kind == PCOp_IMMEDIATE && instr->args[2].data.imm.value == 0) + isZeroOffset = 1; + + scan = instr; + for (i = 0; i < 2; i++) { + if (scan->op == PC_RLWINM) + array[i] = defininginstruction[scan->defID + 1]; + else + array[i] = defininginstruction[scan->defID]; + + scan = array[i]; + if (array[0]->args[1].data.reg.reg != scan->args[1].data.reg.reg) + return 0; + + if (i < 1) { + if (scan->op != PC_RLWIMI) + return 0; + } else { + if (scan->op != PC_RLWINM) + return 0; + } + + if (scan->args[2].data.imm.value == 8) { + if (scan->args[3].data.imm.value == 16 && scan->args[4].data.imm.value == 23) { + if (flags & 2) + return 0; + flags |= 2; + } else { + return 0; + } + } else if (scan->args[2].data.imm.value == 24) { + if (scan->args[3].data.imm.value == 24 && scan->args[4].data.imm.value == 31) { + if (flags & 1) + return 0; + flags |= 1; + } else { + return 0; + } + } else { + return 0; + } + } + + if (definedbetween(instr, array[1], &array[0]->args[1])) + return 0; + + if (instr->op == PC_STHX) { + change_opcode(instr, PC_STHBRX); + instr->args[0] = array[0]->args[1]; + defininginstruction[instr->defID] = defininginstruction[array[1]->defID + 1]; + return 1; + } + + if (instr->op == PC_STH) { + if (!isZeroOffset) { + if (masks[RegClass_GPR] & (1 << array[0]->args[0].data.reg.reg)) + return 0; + + if (usedbetween(array[0], array[1], &array[0]->args[0])) + return 0; + if (usedbetween(instr, array[0], &array[0]->args[0])) + return 0; + } + + defininginstruction[instr->defID] = defininginstruction[array[1]->defID + 1]; + + if (!isZeroOffset) { + newInstr = makepcode(PC_STHBRX, array[1]->args[1].data.reg.reg, 0, instr->args[0].data.reg.reg); + newInstr->alias = instr->alias; + change_opcode(instr, PC_ADDI); + + instr->args[0].data.reg.effect &= ~EffectRead; + instr->args[0].data.reg.effect |= EffectWrite; + defininginstruction[instr->defID] = instr; + + insertpcodeafter(instr, newInstr); + + masks[RegClass_GPR] |= 1 << newInstr->args[0].data.reg.reg; + masks[RegClass_GPR] |= 1 << newInstr->args[2].data.reg.reg; + + deletepcode(array[0]); + deletepcode(array[1]); + } else { + change_opcode(instr, PC_STHBRX); + instr->args[0] = array[0]->args[1]; + instr->args[2] = instr->args[1]; + defininginstruction[instr->defID + 2] = defininginstruction[instr->defID + 1]; + + instr->args[1].kind = PCOp_REGISTER; + instr->args[1].arg = RegClass_GPR; + instr->args[1].data.reg.reg = 0; + instr->args[1].data.reg.effect = 0; + } + + return 1; + } + + return 0; +} + +static void peepholeoptimizeblock(PCodeBlock *block) { + RegClass rclass; + PCode *instr; + PCodeArg *op; + int i; + Pattern *pattern; + UInt32 masks[RegClassMax]; + + for (rclass = 0; rclass < RegClassMax; rclass++) + masks[rclass] = liveregs[rclass][block->blockIndex].xC; + + for (instr = block->lastPCode; instr; instr = instr->prevPCode) { + if (dead(instr, masks)) { + deletepcode(instr); + } else { + pattern = peepholepatterns[instr->op]; + + while (pattern) { + if (pattern->func(instr, masks)) { + if (!instr->block) + break; + pattern = peepholepatterns[instr->op]; + } else { + pattern = pattern->next; + } + } + + if (instr->block) { + for (op = instr->args, i = instr->argCount; i--; op++) { + if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite)) + masks[op->arg] &= ~(1 << op->data.reg.reg); + } + + for (op = instr->args, i = instr->argCount; i--; op++) { + if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectRead)) + masks[op->arg] |= 1 << op->data.reg.reg; + } + } + } + } +} + +static SInt32 computepossiblemask(PCode *instr, short reg) { + SInt32 mask; + SInt32 val; + PCodeArg *op; + int i; + + mask = 0xFFFFFFFF; + while (instr) { + for (op = instr->args, i = instr->argCount; i--; op++) { + if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg)) { + switch (instr->op) { + case PC_LBZ: + case PC_LBZU: + case PC_LBZX: + case PC_LBZUX: + mask = 0xFF; + break; + + case PC_LHZ: + case PC_LHZU: + case PC_LHZX: + case PC_LHZUX: + mask = 0xFFFF; + break; + + case PC_LI: + mask = instr->args[1].data.imm.value; + break; + + case PC_SRAWI: + mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg) >> instr->args[2].data.imm.value; + break; + + case PC_RLWINM: + val = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg); + mask = (val << instr->args[2].data.imm.value) | ((UInt32) val >> (32 - instr->args[2].data.imm.value)); + + if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) + val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + else + val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + + mask &= val; + break; + + case PC_RLWIMI: + val = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg); + mask = (val << instr->args[2].data.imm.value) | ((UInt32) val >> (32 - instr->args[2].data.imm.value)); + + if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) + val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + else + val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + + mask &= val; + mask |= computepossiblemask(instr->prevPCode, instr->args[0].data.reg.reg); + break; + + case PC_OR: + mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg) | + computepossiblemask(instr->prevPCode, instr->args[2].data.reg.reg); + break; + + case PC_ORI: + mask = instr->args[2].data.imm.value | + computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg); + break; + + case PC_AND: + mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg) & + computepossiblemask(instr->prevPCode, instr->args[2].data.reg.reg); + break; + + case PC_ANDI: + mask = instr->args[2].data.imm.value & + computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg); + break; + + case PC_MR: + mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg); + break; + } + + return mask; + } + } + instr = instr->prevPCode; + } + + return mask; +} + +static UInt32 fillmaskholes(UInt32 mask) { + UInt32 oneBit; + UInt32 allBits; + UInt32 result; + + oneBit = 1; + allBits = 0xFFFFFFFF; + result = 0; + + if ((mask & 1) && (mask & 0x80000000)) { + result = 0xFFFFFFFF; + while ((mask & oneBit) == 1) { + oneBit <<= 1; + } + + while ((mask & oneBit) == 0) { + result &= ~oneBit; + oneBit <<= 1; + } + + return result; + } else { + while ((mask & oneBit) == 0 && (mask & allBits) != 0) { + oneBit <<= 1; + allBits <<= 1; + } + while ((mask & allBits) != 0) { + result |= oneBit; + oneBit <<= 1; + allBits <<= 1; + } + return result; + } +} + +static int canuseinsert(PCode *instr1, PCode *instr2, short reg) { + if (computepossiblemask(instr2, reg) & fillmaskholes(computepossiblemask(instr1, instr1->args[0].data.reg.reg))) + return 0; + return 1; +} + +static PCode *find_def_backwords(PCode *instr, short reg) { + int i; + + while (instr) { + for (i = 0; i < instr->argCount; i++) { + if (PC_OP_IS_WRITE_REGISTER(&instr->args[i], RegClass_GPR, reg)) + return instr; + } + instr = instr->prevPCode; + } + + return NULL; +} + +static void adjustforward(PCodeBlock *block) { + PCode *instr; + PCode *scan; + PCode *tmp; + PCodeArg *op; + int i; + short opcode; + short reg0; + short reg1; + SInt32 valA; + SInt32 valB; + + instr = block->firstPCode; + while (instr) { + if (instr->op == PC_RLWINM) { + SInt32 val2; + SInt32 val3; + SInt32 val4; + short start; + short end; + + short flag1 = 0; + short flag2 = 0; + reg0 = instr->args[0].data.reg.reg; + reg1 = instr->args[1].data.reg.reg; + val2 = instr->args[2].data.imm.value; + val3 = instr->args[3].data.imm.value; + val4 = instr->args[4].data.imm.value; + + for (scan = instr->nextPCode; scan; scan = scan->nextPCode) { + opcode = scan->op; + if (opcode == PC_RLWINM && scan->args[1].data.reg.reg == reg0) { + if ( + scan->args[3].data.imm.value == val3 && + scan->args[4].data.imm.value == val4 && + scan->args[2].data.imm.value == 0 + ) + { + if (PCODE_FLAG_SET_F(scan) & fRecordBit) { + if (!flag1) { + pcsetrecordbit(instr); + change_opcode(scan, PC_MR); + scan->flags &= ~fRecordBit; + scan->flags |= fIsMove; + change_num_operands(scan, 2); + } else { + change_opcode(scan, PC_MR); + scan->args[2] = scan->args[5]; + change_num_operands(scan, 3); + } + } else { + change_opcode(scan, PC_MR); + change_num_operands(scan, 2); + } + } + else if ( + reg0 != reg1 && + !flag2 && + canmergemasks( + val3, + val4, + scan->args[2].data.imm.value, + scan->args[3].data.imm.value, + scan->args[4].data.imm.value, + &start, &end) + ) + { + scan->args[1].data.reg.reg = reg1; + scan->args[2].data.imm.value = (scan->args[2].data.imm.value + instr->args[2].data.imm.value) & 31; + scan->args[3].data.imm.value = start; + scan->args[4].data.imm.value = end; + } + } + else if ( + opcode == PC_SRAWI && + scan->args[1].data.reg.reg == reg0 && + reg0 != reg1 && + instr->args[2].data.imm.value == 0 && + !(computepossiblemask(instr, reg0) & 0x80000000) && + !flag2 && + canmergemasks(val3, val4, 32 - scan->args[2].data.imm.value, scan->args[2].data.imm.value, 31, &start, &end) && + !isSPRlive(scan, 0) + ) + { + insertpcodeafter(scan, makepcode( + PC_RLWINM, scan->args[0].data.reg.reg, reg1, + 32 - scan->args[2].data.imm.value, start, end + )); + if (PCODE_FLAG_SET_F(scan) & fRecordBit) + pcsetrecordbit(scan->nextPCode); + deletepcode(scan); + } + else if ( + opcode == PC_OR && + !flag2 && + reg0 != reg1 && + !(PCODE_FLAG_SET_F(scan) & fRecordBit) && + !(PCODE_FLAG_SET_F(instr) & fRecordBit) && + scan->args[0].data.reg.reg != instr->args[1].data.reg.reg + ) + { + if (scan->args[1].data.reg.reg == reg0 && canuseinsert(instr, scan, scan->args[2].data.reg.reg)) { + op = &scan->args[2]; + tmp = find_def_backwords(scan->prevPCode, scan->args[2].data.reg.reg); + if (tmp->op == PC_RLWINM && tmp->args[2].data.imm.value == 0) { + if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) + valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + else + valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + + if (tmp->args[3].data.imm.value <= tmp->args[4].data.imm.value) + valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) & ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1))); + else + valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) | ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1))); + + if (valA == ~valB) + op = &tmp->args[1]; + } + + change_opcode(scan, PC_MR); + scan->args[1] = *op; + change_num_operands(scan, 2); + + tmp = copypcode(instr); + change_opcode(tmp, PC_RLWIMI); + tmp->args[0] = scan->args[0]; + tmp->args[0].data.reg.effect |= EffectRead; + + if (ismaskconstant(fillmaskholes(computepossiblemask(instr, instr->args[0].data.reg.reg)), &start, &end)) { + tmp->args[3].data.imm.value = start; + tmp->args[4].data.imm.value = end; + } + + insertpcodeafter(scan, tmp); + break; + } + + if ( + scan->args[2].data.reg.reg == reg0 && + canuseinsert(instr, scan, scan->args[1].data.reg.reg) + ) + { + op = &scan->args[1]; + tmp = find_def_backwords(scan->prevPCode, scan->args[1].data.reg.reg); + if (tmp->op == PC_RLWINM && tmp->args[2].data.imm.value == 0) { + if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) + valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + else + valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1))); + + if (tmp->args[3].data.imm.value <= tmp->args[4].data.imm.value) + valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) & ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1))); + else + valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) | ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1))); + + if (valA == ~valB) + op = &tmp->args[1]; + } + + change_opcode(scan, PC_MR); + scan->args[1] = *op; + change_num_operands(scan, 2); + + tmp = copypcode(instr); + change_opcode(tmp, PC_RLWIMI); + tmp->args[0] = scan->args[0]; + tmp->args[0].data.reg.effect |= EffectRead; + + if (ismaskconstant(fillmaskholes(computepossiblemask(instr, instr->args[0].data.reg.reg)), &start, &end)) { + tmp->args[3].data.imm.value = start; + tmp->args[4].data.imm.value = end; + } + + insertpcodeafter(scan, tmp); + break; + } + } + else if ( + !flag2 && + reg0 != reg1 && + val4 == 31 && + instr->args[2].data.imm.value == 0 && + ( + ((opcode == PC_STB || opcode == PC_STBX) && val3 <= 24) || + ((opcode == PC_STH || opcode == PC_STHX) && val3 <= 16) + ) && + scan->args[0].data.reg.reg == reg0 + ) + { + scan->args[0].data.reg.reg = reg1; + } + else if ( + opcode == PC_EXTSH && + scan->args[1].data.reg.reg == reg0 && + val2 == 0 && + val3 > 16 && + val3 < val4 + ) + { + change_opcode(scan, PC_MR); + if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag1) { + pcsetrecordbit(instr); + scan->flags &= ~fRecordBit; + scan->flags |= fIsMove; + change_num_operands(scan, 2); + } + } + else if ( + opcode == PC_EXTSB && + scan->args[1].data.reg.reg == reg0 && + val2 == 0 && + val3 > 24 && + val3 < val4 + ) + { + change_opcode(scan, PC_MR); + if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag1) { + pcsetrecordbit(instr); + scan->flags &= ~fRecordBit; + scan->flags |= fIsMove; + change_num_operands(scan, 2); + } + } + + for (op = scan->args, i = scan->argCount; i--; op++) { + if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg0)) { + scan = block->lastPCode; + break; + } + + if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg1)) + flag2 = 1; + + if (PC_OP_IS_REGISTER(op, RegClass_CRFIELD, 0)) + flag1 = 1; + } + } + + } else if ( + instr->op == PC_EXTSB && + (reg0 = instr->args[0].data.reg.reg) != (reg1 = instr->args[1].data.reg.reg) + ) + { + short flag = 0; + for (scan = instr->nextPCode; scan; scan = scan->nextPCode) { + if ( + (scan->op >= PC_STB && scan->op <= PC_STBUX) && + scan->args[0].data.reg.reg == reg0 + ) + { + scan->args[0].data.reg.reg = reg1; + } + else if ( + (scan->op == PC_EXTSH || scan->op == PC_EXTSB) && + scan->args[1].data.reg.reg == reg0 + ) + { + change_opcode(scan, PC_MR); + if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag) { + pcsetrecordbit(instr); + scan->flags &= ~fRecordBit; + scan->flags |= fIsMove; + change_num_operands(scan, 2); + } + } + + for (op = scan->args, i = scan->argCount; i--; op++) { + if ( + PC_OP_IS_WRITE_ANY_REGISTER(op, RegClass_GPR) && + (op->data.reg.reg == reg0 || op->data.reg.reg == reg1) + ) + { + scan = block->lastPCode; + break; + } + + if (PC_OP_IS_REGISTER(op, RegClass_CRFIELD, 0)) + flag = 1; + } + } + } else if ( + instr->op == PC_EXTSH && + (reg0 = instr->args[0].data.reg.reg) != (reg1 = instr->args[1].data.reg.reg) + ) + { + short flag = 0; + for (scan = instr->nextPCode; scan; scan = scan->nextPCode) { + if ( + ((scan->op >= PC_STB && scan->op <= PC_STBUX) || (scan->op >= PC_STH && scan->op <= PC_STHUX)) && + scan->args[0].data.reg.reg == reg0 + ) + { + scan->args[0].data.reg.reg = reg1; + } + else if (scan->op == PC_EXTSH && scan->args[1].data.reg.reg == reg0) + { + change_opcode(scan, PC_MR); + if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag) { + pcsetrecordbit(instr); + scan->flags &= ~fRecordBit; + scan->flags |= fIsMove; + change_num_operands(scan, 2); + } + } + + for (op = scan->args, i = scan->argCount; i--; op++) { + if ( + PC_OP_IS_WRITE_ANY_REGISTER(op, RegClass_GPR) && + (op->data.reg.reg == reg0 || op->data.reg.reg == reg1) + ) + { + scan = block->lastPCode; + break; + } + + if (PC_OP_IS_REGISTER(op, RegClass_CRFIELD, 0)) + flag = 1; + } + } + } else if ( + instr->op == PC_ADDI && + (reg0 = instr->args[0].data.reg.reg) == (reg1 = instr->args[1].data.reg.reg) && + instr->args[2].kind == PCOp_IMMEDIATE + ) + { + Boolean flag1 = 0; + Boolean flag2 = 0; + SInt32 val2 = instr->args[2].data.imm.value; + + for (scan = instr->nextPCode; scan; scan = scan->nextPCode) { + if ((scan->flags & fIsWrite) && scan->args[0].data.reg.reg == reg0) + break; + + if ( + (scan->flags & (fIsRead | fIsWrite)) && + scan->args[1].data.reg.reg == reg0 && + scan->args[2].kind == PCOp_IMMEDIATE && + FITS_IN_SHORT(val2 + scan->args[2].data.imm.value) + ) + { + scan->args[2].data.imm.value += val2; + tmp = instr->prevPCode; + if ( + (scan->flags & fIsRead) && + scan->args[0].data.reg.reg == reg0 && + scan->args[0].kind == PCOp_REGISTER && + scan->args[0].arg == RegClass_GPR + ) + { + deletepcode(instr); + } else { + deletepcode(instr); + insertpcodeafter(scan, instr); + } + instr = tmp; + break; + } + + if ( + scan->op == PC_ADDI && + scan->args[1].data.reg.reg == reg0 && + scan->args[2].kind == PCOp_IMMEDIATE && + FITS_IN_SHORT(val2 + scan->args[2].data.imm.value) + ) + { + scan->args[2].data.imm.value += val2; + tmp = instr->prevPCode; + if (scan->args[0].data.reg.reg == reg0) { + deletepcode(instr); + } else { + deletepcode(instr); + insertpcodeafter(scan, instr); + } + instr = tmp; + break; + } + + if (scan->flags & (fIsBranch | fIsCall)) { + if (flag1 && scan->prevPCode != instr) { + tmp = instr->prevPCode; + deletepcode(instr); + insertpcodebefore(scan, instr); + instr = tmp; + } + break; + } + + for (op = scan->args, i = scan->argCount; i--; op++) { + if (PC_OP_IS_R_OR_W_REGISTER(op, RegClass_GPR, reg0)) { + if (flag1 && scan->prevPCode != instr) { + tmp = instr->prevPCode; + deletepcode(instr); + insertpcodebefore(scan, instr); + instr = tmp; + } + flag2 = 1; + break; + } + } + + if (flag2) + break; + + if (scan->op != PC_ADDI) + flag1 = 1; + + if (flag1 && !scan->nextPCode) { + tmp = instr->prevPCode; + deletepcode(instr); + appendpcode(block, instr); + instr = tmp; + break; + } + } + } + + if (instr) + instr = instr->nextPCode; + else + instr = block->firstPCode; + } +} + +static void installpattern(Opcode opcode, PeepholeFunc func) { + Pattern *pattern = lalloc(sizeof(Pattern)); + pattern->func = func; + pattern->next = peepholepatterns[opcode]; + peepholepatterns[opcode] = pattern; +} + +static void installpeepholepatterns(void) { + int i; + + for (i = 0; i < OPCODE_MAX; i++) + peepholepatterns[i] = NULL; + + installpattern(PC_AND, NOT_AND); + installpattern(PC_MR, LI_MR); + installpattern(PC_MR, L_MR); + installpattern(PC_FMR, L_FMR); + installpattern(PC_MR, MR_MR); + installpattern(PC_MR, MR_Rx_Rx); + installpattern(PC_FMR, FMR_FMR); + installpattern(PC_FMR, FMR_Fx_Fx); + installpattern(PC_VMR, VMR_VMRP); + installpattern(PC_VMR, VMR_VMR); + installpattern(PC_VMR, VMR_Vx_Vx); + installpattern(PC_VMR, VSPLTIS_VMR); + installpattern(PC_CMPI, MR_CMPI); + installpattern(PC_RLWIMI, RLWINM_RLWINM); + installpattern(PC_RLWINM, RLWINM_RLWINM); + installpattern(PC_RLWINM, EXTSB_RLWINM); + installpattern(PC_RLWINM, EXTSH_RLWINM); + installpattern(PC_RLWINM, LBZ_RLWINM); + installpattern(PC_RLWINM, LHZ_RLWINM); + installpattern(PC_EXTSH, LHA_EXTSH); + installpattern(PC_STW, RLWINM_RLWIMI_STW); + installpattern(PC_STWX, RLWINM_RLWIMI_STW); + installpattern(PC_STH, RLWINM_RLWIMI_STH); + installpattern(PC_STHX, RLWINM_RLWIMI_STH); + installpattern(PC_LBZ, ADDI_L_S); + installpattern(PC_LHZ, ADDI_L_S); + installpattern(PC_LHA, ADDI_L_S); + installpattern(PC_LWZ, ADDI_L_S); + installpattern(PC_STB, ADDI_L_S); + installpattern(PC_STH, ADDI_L_S); + installpattern(PC_STW, ADDI_L_S); + installpattern(PC_LFS, ADDI_L_S); + installpattern(PC_LFD, ADDI_L_S); + installpattern(PC_STFS, ADDI_L_S); + installpattern(PC_STFD, ADDI_L_S); + installpattern(PC_LBZU, ADDI_LU_SU); + installpattern(PC_LHZU, ADDI_LU_SU); + installpattern(PC_LHAU, ADDI_LU_SU); + installpattern(PC_LWZU, ADDI_LU_SU); + installpattern(PC_STBU, ADDI_LU_SU); + installpattern(PC_STHU, ADDI_LU_SU); + installpattern(PC_STWU, ADDI_LU_SU); + installpattern(PC_LFSU, ADDI_LU_SU); + installpattern(PC_LFDU, ADDI_LU_SU); + installpattern(PC_STFSU, ADDI_LU_SU); + installpattern(PC_STFDU, ADDI_LU_SU); + installpattern(PC_LBZ, L_S_ADDI); + installpattern(PC_LHZ, L_S_ADDI); + installpattern(PC_LHA, L_S_ADDI); + installpattern(PC_LWZ, L_S_ADDI); + installpattern(PC_STB, L_S_ADDI); + installpattern(PC_STH, L_S_ADDI); + installpattern(PC_STW, L_S_ADDI); + installpattern(PC_LFS, L_S_ADDI); + installpattern(PC_LFD, L_S_ADDI); + installpattern(PC_STFS, L_S_ADDI); + installpattern(PC_STFD, L_S_ADDI); + installpattern(PC_STB, L_S); + installpattern(PC_STH, L_S); + installpattern(PC_STW, L_S); + installpattern(PC_STFS, L_S); + installpattern(PC_STFD, L_S); + installpattern(PC_STBX, L_S); + installpattern(PC_STHX, L_S); + installpattern(PC_STWX, L_S); + installpattern(PC_STFSX, L_S); + installpattern(PC_STFDX, L_S); + installpattern(PC_BT, LBZ_EXTSB_CMPI_BC); + installpattern(PC_BF, LBZ_EXTSB_CMPI_BC); + installpattern(PC_BT, RLWINM_CMPLI_BC); + installpattern(PC_BF, RLWINM_CMPLI_BC); + installpattern(PC_BT, LI_CMP_BC); + installpattern(PC_BF, LI_CMP_BC); + installpattern(PC_RLWINM, RLWINM_RLWINM); + installpattern(PC_MULLI, MULLI_MULLI); + installpattern(PC_ADDI, ADDI_ADDI); + installpattern(PC_SRAWI, SRAWI_SRAWI); + installpattern(PC_MR, MR_ADDI); + installpattern(PC_OR, SRW_SUBFIC_RLW_OR); +} + +void peepholeoptimizeforward(Object *func) { + PCodeBlock *block; + + for (block = pcbasicblocks; block; block = block->nextBlock) { + if (block->pcodeCount >= 2) + adjustforward(block); + } +} + +void peepholemergeblocks(Object *func, Boolean flag) { + PCodeBlock *block; + PCodeBlock *next; + Boolean flag2; + PCode *instr; + PCode *nextinstr; + PCLink *link; + PCLink *link2; + + for (block = pcbasicblocks; block; block = block->nextBlock) { + flag2 = 0; + next = block->nextBlock; + + if (!flag) { + flag2 = next && (next->flags & fIsEpilogue); + if (block->flags & fIsProlog) + continue; + } + + if (block->pcodeCount > 0) { + for (instr = block->firstPCode; instr; instr = instr->nextPCode) { + if (instr->flags & (fIsCall | fSideEffects)) + break; + } + + if (instr) + continue; + + instr = block->lastPCode; + if (instr && instr->op == PC_B) { + if (instr->args[0].kind == PCOp_LABEL && instr->args[0].data.label.label->block == next) + deletepcode(instr); + else + continue; + } + + instr = block->lastPCode; + if (instr && (instr->flags & fIsBranch) && instr->op != PC_B) + continue; + + while ( + block->successors->block == next && + block->successors->nextLink == NULL && + next->predecessors->block == block && + next->predecessors->nextLink == NULL && + !flag2 && + !(next->flags & fPCBlockFlag8000) && + (block->pcodeCount + next->pcodeCount) <= 100 + ) + { + if (next->pcodeCount > 0) { + for (instr = next->firstPCode; instr; instr = nextinstr) { + nextinstr = instr->nextPCode; + if (instr->flags & (fIsCall | fSideEffects)) + break; + + deletepcode(instr); + if (instr->op != PC_B) { + appendpcode(block, instr); + } else if (instr->args[0].kind == PCOp_LABEL) { + if (instr->args[0].data.label.label->block != next->nextBlock) + appendpcode(block, instr); + } else { + appendpcode(block, instr); + } + } + } + + if (next->pcodeCount != 0) + break; + if (next == epilogue) + break; + + block->successors = next->successors; + + for (link = block->successors; link; link = link->nextLink) { + for (link2 = link->block->predecessors; link2; link2 = link2->nextLink) { + if (link2->block == next) { + link2->block = block; + break; + } + } + } + + block->nextBlock = next->nextBlock; + if (block->nextBlock) + block->nextBlock->prevBlock = block; + + next->flags |= fDeleted; + next = block->nextBlock; + + if (!flag) + flag2 = next && (next->flags & fIsEpilogue); + } + } + } +} + +void peepholeoptimizepcode(Object *func) { + PCodeBlock *block; + + installpeepholepatterns(); + computeliveregisters(func); + + for (block = pcbasicblocks; block; block = block->nextBlock) { + if (block->pcodeCount >= 1) { + computeinstructionpredecessors(block); + peepholeoptimizeblock(block); + freeoheap(); + } + } +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c new file mode 100644 index 0000000..6fa4524 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c @@ -0,0 +1,1252 @@ +#include "compiler/StackFrame.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/RegisterInfo.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +#define ALIGN(thing, alignment) ( ~((alignment) - 1) & ((thing) + (alignment) - 1) ) +#define ALIGN_REMAINDER(thing, alignment) ( ALIGN(thing, alignment) - (thing) ) + +Boolean requires_frame; +Boolean makes_call; +Boolean uses_globals; +Boolean dynamic_stack; +Boolean large_stack; +static SInt32 out_param_alignment; +static SInt32 in_parameter_size; +static SInt32 in_param_alignment; +static SInt32 frame_alignment; +static SInt32 alloca_alignment; +static SInt32 linkage_area_size; +static SInt32 parameter_area_size; +static SInt32 parameter_area_size_estimate; +static SInt32 local_data_size; +static SInt32 local_data_limit; +static SInt32 large_data_near_size; +static SInt32 large_data_far_size; +static ObjectList *local_objects[ObjClassMax]; +static ObjectList *local_objects_tail[ObjClassMax]; +static SInt32 non_volatile_save_offset[RegClassMax]; +static SInt32 VRSAVE_save_offset; +static SInt32 LR_save_offset; +static SInt32 nonvolatile_save_size; +static UInt32 vrsave_mask; +static SInt32 frame_size; +static SInt32 frame_size_estimate; +static SInt32 genuine_frame_size; +static Object *dummylocal; +static Boolean dynamic_align_stack; +static Boolean has_varargs; +static Boolean compressing_data_area; +static PCode *setup_caller_sp; +static PCode *align_instr1; +static PCode *align_instr2; +static short vrsave_register; +static PCode *loadvrsave; +static PCode *storevrsave; +Object *dummyvaparam; +void *dummyprofiler; + +// forward declarations +static void insert_local_object(UInt8 oclass, Object *obj); +static void compress_data_area(void); +static UInt32 align_bits(UInt32 value, UInt8 bitcount); +static Boolean use_helper_function(char rclass); +static Boolean need_link_register(void); +static void call_helper_function(char *name, char rclass, short effect); +static void save_nonvolatile_FPRs(int reg, SInt32 offset); +static void save_nonvolatile_VRs(int reg, SInt32 offset); +static void restore_nonvolatile_FPRs(int reg, SInt32 offset); +static void restore_nonvolatile_VRs(int reg, SInt32 offset); +static void save_nonvolatile_GPRs(int reg, SInt32 offset); +static void restore_nonvolatile_GPRs(int reg, SInt32 offset); +static void do_allocate_dynamic_stack_space(Boolean isConstantSize, int reg1, int reg2, SInt32 size); + +void init_stack_globals(Object *funcobj) { + RegClass rclass; + ObjClass oclass; + + requires_frame = 0; + makes_call = 0; + uses_globals = 0; + dynamic_stack = 0; + large_stack = 0; + vrsave_register = -1; + dynamic_align_stack = 0; + compressing_data_area = 0; + align_instr1 = NULL; + align_instr2 = NULL; + setup_caller_sp = NULL; + dummyvaparam = NULL; + loadvrsave = NULL; + storevrsave = NULL; + local_data_size = 0; + local_data_limit = 0x2000; + large_data_near_size = 0; + large_data_far_size = 0; + frame_size_estimate = 0; + in_parameter_size = 0; + parameter_area_size = 0; + parameter_area_size_estimate = 0; + frame_alignment = 8; + out_param_alignment = 8; + in_param_alignment = 8; + alloca_alignment = 0; + has_varargs = 0; + linkage_area_size = 0; + frame_size = 0; + genuine_frame_size = 0; + nonvolatile_save_size = -1; + VRSAVE_save_offset = -1; + LR_save_offset = -1; + + for (rclass = 0; rclass < RegClassMax; rclass++) + non_volatile_save_offset[rclass] = -1; + + dummyprofiler = NULL; + dummyvaparam = NULL; + dummylocal = NULL; + + for (oclass = 0; oclass < ObjClassMax; oclass++) { + local_objects[oclass] = NULL; + local_objects_tail[oclass] = NULL; + } +} + +void init_frame_sizes(Boolean has_varargs) { + ObjectList *scan; + Object *obj; + SInt32 r30; + SInt32 align; + SInt32 mask; + + r30 = in_parameter_size + parameter_area_size_estimate; + frame_size_estimate = r30 + 2484; + for (scan = locals; scan; scan = scan->next) { + obj = scan->object; + { + align = CMach_AllocationAlignment(obj->type, obj->qual) - 1; + mask = ~align; + } + frame_size_estimate = (frame_size_estimate + align) & mask; + frame_size_estimate += obj->type->size; + } + + if (frame_size_estimate > 0x8000) { + dynamic_stack = 1; + large_stack = 1; + requires_frame = 1; + } + + local_data_limit = 0x8000 - (r30 + 2484); + + if (dynamic_stack) { + requires_frame = 1; + dummylocal = galloc(sizeof(Object)); + memclrw(dummylocal, sizeof(Object)); + dummylocal->type = (Type *) &stvoid; + dummylocal->otype = OT_OBJECT; + dummylocal->name = GetHashNameNode("<dummy>"); + dummylocal->datatype = DLOCAL; + dummylocal->u.var.info = CodeGen_GetNewVarInfo(); + dummylocal->u.var.info->flags |= VarInfoFlag80; + dummylocal->u.var.info->noregister = 1; + } + + if (dynamic_stack) { + retain_register(NULL, RegClass_GPR, 31); + _FP_ = 31; + } else { + _FP_ = 1; + } +} + +void assign_local_memory(Object *obj) { + // some misassigned registers x.x + short align; + VarInfo *vi; + + align = CMach_AllocationAlignment(obj->type, obj->qual); + if (!compressing_data_area && (obj->u.var.info->flags & VarInfoFlag80)) + return; + + update_frame_align(align); + if (local_data_size + (ALIGN_REMAINDER(local_data_size, align) + ALIGN(obj->type->size, align)) < local_data_limit) { + local_data_size = ALIGN(local_data_size, align); + vi = Registers_GetVarInfo(obj); + vi->flags &= ~VarInfoFlag2; + vi->flags |= VarInfoFlag80; + obj->u.var.uid = local_data_size; + local_data_size += ALIGN(obj->type->size, align); + insert_local_object(ObjClass0, obj); + return; + } + if (compressing_data_area || obj->type->size <= 32) { + large_data_near_size = ALIGN(large_data_near_size, align); + vi = Registers_GetVarInfo(obj); + vi->flags &= ~VarInfoFlag2; + vi->flags |= VarInfoFlag80; + obj->u.var.uid = 0x8000 + large_data_near_size; + large_data_near_size += ALIGN(obj->type->size, align); + insert_local_object(ObjClass1, obj); + } else { + large_data_far_size = ALIGN(large_data_far_size, align); + vi = Registers_GetVarInfo(obj); + vi->flags &= ~VarInfoFlag2; + vi->flags |= VarInfoFlag80; + obj->u.var.uid = 0x10000 + large_data_far_size; + large_data_far_size += ALIGN(obj->type->size, align); + insert_local_object(ObjClass2, obj); + } +} + +void assign_locals_to_memory(ObjectList *first) { + ObjectList *list; + Object *obj; + SInt32 i; + + for (i = 1; i < 1024; i <<= 1) { + for (list = first; list; list = list->next) { + obj = list->object; + if (Registers_GetVarInfo(obj)->used) { + if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) { + if (obj->type->size <= i) + assign_local_memory(obj); + } + } + } + } + + for (list = first; list; list = list->next) { + obj = list->object; + if (Registers_GetVarInfo(obj)->used) { + if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) { + assign_local_memory(list->object); + } + } + + if (obj->type && IS_TYPE_ARRAY(obj->type) && IS_TYPE_VECTOR(TYPE_POINTER(obj->type)->target)) + has_altivec_arrays = 1; + } +} + +void compute_frame_sizes(void) { + SInt32 altivec_size; + SInt32 altivec_offset; + + CError_ASSERT(897, alloca_alignment == 0 || alloca_alignment == frame_alignment); + + update_asm_nonvolatile_registers(); + LR_save_offset = 8; + non_volatile_save_offset[RegClass_FPR] = -(used_nonvolatile_registers[RegClass_FPR] * 8); + non_volatile_save_offset[RegClass_GPR] = -(((15 - non_volatile_save_offset[RegClass_FPR]) & ~15) + used_nonvolatile_registers[RegClass_GPR] * 4); + nonvolatile_save_size = -non_volatile_save_offset[RegClass_GPR]; + non_volatile_save_offset[RegClass_CRFIELD] = 4; + VRSAVE_save_offset = -1; + non_volatile_save_offset[RegClass_VR] = -1; + + if (copts.altivec_model) { + if (vrsave_mask) { + VRSAVE_save_offset = non_volatile_save_offset[RegClass_GPR] - 4; + nonvolatile_save_size = nonvolatile_save_size + 4; + } + altivec_size = used_nonvolatile_registers[RegClass_VR] * 16; + if (altivec_size > 0) + nonvolatile_save_size = ALIGN(nonvolatile_save_size + altivec_size, frame_alignment); + } + + if (parameter_area_size) + requires_frame = 1; + + compress_data_area(); + local_data_size = ALIGN(local_data_size, frame_alignment); + nonvolatile_save_size = ALIGN(nonvolatile_save_size, frame_alignment); + if (!requires_frame && (local_data_size + nonvolatile_save_size) <= 224) { + CError_ASSERT(1005, !dynamic_align_stack); + linkage_area_size = 0; + frame_size = 0; + genuine_frame_size = local_data_size + nonvolatile_save_size; + } else { + requires_frame = 1; + if (parameter_area_size < 32) + parameter_area_size = 32; + parameter_area_size = ALIGN(parameter_area_size + 24, frame_alignment) - 24; + if (large_stack) { + CError_ASSERT(1019, !large_data_far_size); + large_data_near_size += parameter_area_size; + parameter_area_size = 0; + } + linkage_area_size = 24; + frame_size = nonvolatile_save_size + (altivec_offset = parameter_area_size + 24 + local_data_size); + if (copts.altivec_model && used_nonvolatile_registers[RegClass_VR]) + non_volatile_save_offset[RegClass_VR] = altivec_offset; + frame_size += ALIGN_REMAINDER(frame_size, 16); + frame_size = ALIGN(frame_size, frame_alignment); + genuine_frame_size = frame_size; + } + if (!large_stack && frame_size > 0x7FFF) + CError_ErrorTerm(CErrorStr210); +} + +static void allocate_new_frame(int reg1, int reg2) { + if (dynamic_align_stack) { + CError_ASSERT(1116, reg1 != _CALLER_SP_); + emitpcode(PC_RLWINM, reg1, 1, 0, align_bits(frame_alignment, 1), 31); + if (frame_size > 0x7FFF) { + CError_FATAL(1122); + return; + } + + if (frame_size) + emitpcode(PC_SUBFIC, reg1, reg1, -frame_size); + else + emitpcode(PC_SUBFIC, reg1, reg1, -genuine_frame_size); + + if (reg2) + emitpcode(PC_MR, reg2, 1); + + emitpcode(PC_STWUX, 1, 1, reg1); + } else { + if (frame_size > 0x7FFF) + CError_FATAL(1153); + else + emitpcode(PC_STWU, 1, 1, 0, -frame_size); + + if (reg2) + emitpcode(PC_MR, reg2, 1); + } +} + +void generate_prologue(PCodeBlock *block, Boolean has_varargs) { + PCodeBlock *save_block; + Boolean needs_lr; + Statement *save_statement; + Statement stmt; + UInt32 vrsave_low; + UInt32 vrsave_high; + + save_block = pclastblock; + needs_lr = need_link_register(); + save_statement = current_statement; + stmt.sourceoffset = functionbodyoffset; + current_statement = &stmt; + pclastblock = block; + + if (setup_caller_sp && setup_caller_sp->block) { + if ( + setup_caller_sp->op == PC_MR && + setup_caller_sp->args[1].kind == PCOp_REGISTER && + setup_caller_sp->args[1].arg == RegClass_GPR && + setup_caller_sp->args[1].data.reg.reg == _FP_ + ) + CError_FATAL(1197); + + _CALLER_SP_ = setup_caller_sp->args[0].data.reg.reg; + deletepcode(setup_caller_sp); + setup_caller_sp = NULL; + } else if (_CALLER_SP_ != _FP_) { + _CALLER_SP_ = -1; + } + + if (align_instr1 && align_instr1->block) { + deletepcode(align_instr1); + align_instr1 = NULL; + } + + if (align_instr2 && align_instr2->block) { + deletepcode(align_instr2); + align_instr2 = NULL; + } + + if (loadvrsave && loadvrsave->block) { + deletepcode(loadvrsave); + loadvrsave = NULL; + } + + if (storevrsave && storevrsave->block) { + deletepcode(storevrsave); + storevrsave = NULL; + } + + if (needs_lr) + emitpcode(PC_MFLR, 0); + + if (used_nonvolatile_registers[RegClass_CRFIELD]) { + emitpcode(PC_MFCR, 12); + emitpcode(PC_STW, 12, 1, 0, non_volatile_save_offset[RegClass_CRFIELD]); + } + + if (used_nonvolatile_registers[RegClass_FPR]) + save_nonvolatile_FPRs(1, 0); + if (used_nonvolatile_registers[RegClass_GPR]) + save_nonvolatile_GPRs(1, 0); + if (needs_lr) + emitpcode(PC_STW, 0, 1, 0, 8); + + if (frame_size) { + if (vrsave_mask) { + emitpcode(PC_MFSPR, 0, 256); + emitpcode(PC_STW, 0, 1, 0, VRSAVE_save_offset); + vrsave_register = 0; + } + allocate_new_frame(12, (_CALLER_SP_ > 0 && _CALLER_SP_ != _FP_) ? _CALLER_SP_ : 0); + } else { + CError_ASSERT(1326, !dynamic_align_stack); + if (vrsave_mask) + emitpcode(PC_MFSPR, vrsave_register, 256); + } + + if (vrsave_mask) { + vrsave_high = vrsave_mask >> 16; + vrsave_low = vrsave_mask & 0xFFFF; + if (vrsave_mask == 0xFFFFFFFF) { + emitpcode(PC_LI, 0, -1); + } else { + if (vrsave_high) + emitpcode(PC_ORIS, 0, vrsave_register, vrsave_high); + if (vrsave_low) + emitpcode(PC_ORI, 0, 0, vrsave_low); + } + emitpcode(PC_MTSPR, 256, 0); + } + + if (used_nonvolatile_registers[RegClass_VR]) + save_nonvolatile_VRs(1, 0); + + if (dynamic_stack) + emitpcode(PC_MR, 31, 1); + + if (large_stack) + do_allocate_dynamic_stack_space(1, 11, 0, large_data_near_size); + + block->flags |= fIsProlog; + pclastblock = save_block; + current_statement = save_statement; +} + +void generate_epilogue(PCodeBlock *block, Boolean add_blr) { + PCodeBlock *save_block; + Boolean needs_lr; + Statement *save_statement; + Statement stmt; + + save_block = pclastblock; + needs_lr = need_link_register(); + save_statement = current_statement; + if (!save_statement) { + stmt.sourceoffset = current_linenumber; + current_statement = &stmt; + } + pclastblock = block; + + if (used_nonvolatile_registers[RegClass_VR]) + restore_nonvolatile_VRs(_FP_, 0); + + if (dynamic_align_stack) { + load_store_register(PC_LWZ, 1, 1, NULL, 0); + setpcodeflags(fSideEffects); + if (needs_lr) + load_store_register(PC_LWZ, 0, 1, 0, 8); + } else { + if (needs_lr) + load_store_register(PC_LWZ, 0, _FP_, 0, frame_size + 8); + if (frame_size > 0) { + if (dynamic_stack) { + load_store_register(PC_LWZ, 1, 1, 0, 0); + setpcodeflags(fSideEffects); + } else { + emitpcode(PC_ADDI, 1, 1, 0, frame_size); + setpcodeflags(fSideEffects); + } + } + } + + if (used_nonvolatile_registers[RegClass_CRFIELD]) { + load_store_register(PC_LWZ, 12, 1, NULL, non_volatile_save_offset[RegClass_CRFIELD]); + emitpcode(PC_MTCRF, 255, 12); + } + + if (vrsave_mask) { + if (!requires_frame) { + emitpcode(PC_MTSPR, 256, vrsave_register); + } else { + emitpcode(PC_LWZ, 11, 1, 0, VRSAVE_save_offset); + emitpcode(PC_MTSPR, 256, 11); + } + } + + if (used_nonvolatile_registers[RegClass_FPR]) + restore_nonvolatile_FPRs(1, 0); + if (needs_lr && !use_helper_function(RegClass_GPR)) + emitpcode(PC_MTLR, 0); + + if (used_nonvolatile_registers[RegClass_GPR]) + restore_nonvolatile_GPRs(1, 0); + if (needs_lr && use_helper_function(RegClass_GPR)) + emitpcode(PC_MTLR, 0); + + if (add_blr) { + emitpcode(PC_BLR); + setpcodeflags(fIsVolatile); + } + + block->flags |= fIsEpilogue; + pclastblock = save_block; + current_statement = save_statement; +} + +static void load_base_offset(int dest_reg, int base_reg, SInt32 offset) { + if (offset) + emitpcode(PC_ADDI, dest_reg, base_reg, 0, offset); + else + emitpcode(PC_MR, dest_reg, base_reg); +} + +static void save_nonvolatile_FPRs(int reg, SInt32 offset) { + short i; + SInt32 o; + + o = offset + non_volatile_save_offset[RegClass_FPR]; + + if (!use_helper_function(RegClass_FPR)) { + for (i = 1; i <= used_nonvolatile_registers[RegClass_FPR]; i++) { + emitpcode(PC_STFD, 32 - i, reg, NULL, o + (used_nonvolatile_registers[RegClass_FPR] - i) * 8); + setpcodeflags(fIsVolatile); + } + } else { + load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_FPR] * 8); + call_helper_function("__save_fpr_%d", RegClass_FPR, EffectRead); + } +} + +static void save_nonvolatile_VRs(int reg, SInt32 offset) { + short i; + SInt32 o; + + o = offset + non_volatile_save_offset[RegClass_VR]; + + if (!use_helper_function(RegClass_VR)) { + for (i = 1; i <= used_nonvolatile_registers[RegClass_VR]; i++) { + emitpcode(PC_LI, 0, o + (used_nonvolatile_registers[RegClass_VR] - i) * 16); + emitpcode(PC_STVX, 32 - i, reg, 0); + setpcodeflags(fIsVolatile); + } + } else { + load_base_offset(0, reg, o + used_nonvolatile_registers[RegClass_VR] * 16); + call_helper_function("__savev%d", RegClass_VR, EffectRead); + } +} + +static void restore_nonvolatile_FPRs(int reg, SInt32 offset) { + short i; + SInt32 o; + + o = offset + non_volatile_save_offset[RegClass_FPR]; + + if (!use_helper_function(RegClass_FPR)) { + for (i = 1; i <= used_nonvolatile_registers[RegClass_FPR]; i++) { + load_store_register(PC_LFD, 32 - i, reg, NULL, o + (used_nonvolatile_registers[RegClass_FPR] - i) * 8); + setpcodeflags(fIsVolatile); + } + } else { + load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_FPR] * 8); + call_helper_function("__restore_fpr_%d", RegClass_FPR, EffectWrite); + } +} + +static void restore_nonvolatile_VRs(int reg, SInt32 offset) { + short i; + SInt32 o; + + o = offset + non_volatile_save_offset[RegClass_VR]; + + if (!use_helper_function(RegClass_VR)) { + for (i = 1; i <= used_nonvolatile_registers[RegClass_VR]; i++) { + emitpcode(PC_LI, 0, o + (used_nonvolatile_registers[RegClass_VR] - i) * 16); + setpcodeflags(fIsVolatile); + emitpcode(PC_LVX, 32 - i, reg, 0); + setpcodeflags(fIsVolatile); + } + } else { + load_base_offset(0, reg, o + used_nonvolatile_registers[RegClass_VR] * 16); + call_helper_function("__restv%d", RegClass_VR, EffectWrite); + } +} + +static void save_nonvolatile_GPRs(int reg, SInt32 offset) { + int i; + SInt32 o; + + o = offset + non_volatile_save_offset[RegClass_GPR]; + + if (!use_helper_function(RegClass_GPR)) { + if (copts.use_lmw_stmw && ((used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimizesize && (used_nonvolatile_registers[RegClass_GPR] > 1)))) { + emitpcode(PC_STMW, used_nonvolatile_registers[RegClass_GPR] - 1, 32 - used_nonvolatile_registers[RegClass_GPR], reg, 0, o); + } else { + for (i = 1; i <= used_nonvolatile_registers[RegClass_GPR]; i++) { + emitpcode(PC_STW, 32 - i, reg, 0, o + (used_nonvolatile_registers[RegClass_GPR] - i) * 4); + } + } + } else { + load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_GPR] * 4); + call_helper_function("__savegpr_%d", RegClass_GPR, EffectRead); + } +} + +static void restore_nonvolatile_GPRs(int reg, SInt32 offset) { + int i; + SInt32 o; + + o = offset + non_volatile_save_offset[RegClass_GPR]; + + if (!use_helper_function(RegClass_GPR)) { + if (copts.use_lmw_stmw && ((used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimizesize && (used_nonvolatile_registers[RegClass_GPR] > 1)))) { + emitpcode(PC_LMW, used_nonvolatile_registers[RegClass_GPR] - 1, 32 - used_nonvolatile_registers[RegClass_GPR], reg, 0, o); + setpcodeflags(fIsVolatile); + } else { + for (i = 1; i <= used_nonvolatile_registers[RegClass_GPR]; i++) { + emitpcode(PC_LWZ, 32 - i, reg, 0, o + (used_nonvolatile_registers[RegClass_GPR] - i) * 4); + setpcodeflags(fIsVolatile); + } + } + } else { + load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_GPR] * 4); + call_helper_function("__restgpr_%d", RegClass_GPR, EffectWrite); + } +} + +static void do_allocate_dynamic_stack_space(Boolean isConstantSize, int reg1, int reg2, SInt32 size) { + load_store_register(PC_LWZ, reg2, 1, NULL, 0); + if (isConstantSize) { + size = ALIGN(size, frame_alignment); + if (size < 0x8000) { + emitpcode(PC_STWU, reg2, 1, 0, -size); + } else { + emitpcode(PC_LIS, reg1, 0, (short) HIGH_PART(-size)); + if (-size) + emitpcode(PC_ADDI, reg1, reg1, 0, LOW_PART(-size)); + emitpcode(PC_STWUX, reg2, 1, reg1); + setpcodeflags(fIsVolatile | fSideEffects); + } + } else { + emitpcode(PC_STWUX, reg2, 1, reg1); + setpcodeflags(fIsVolatile | fSideEffects); + } +} + +void allocate_dynamic_stack_space(Boolean isConstantSize, int reg1, int reg2, SInt32 size) { + if (copts.altivec_model) + update_frame_align(16); + do_allocate_dynamic_stack_space(isConstantSize, reg1, reg2, size); + add_immediate(reg1, 1, dummylocal, 0); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct Traceback { + UInt8 x0; + UInt8 x1; + UInt8 x2; + UInt8 x3; + UInt8 x4; + UInt8 x5; + + UInt8 x6_0 : 2; + UInt8 x6_1 : 1; // set to 1 + UInt8 x6_2 : 5; + + UInt8 x7_0 : 1; + UInt8 x7_1 : 1; // set to 1 + UInt8 has_dynamic_stack : 1; // set to 1 if dynamic_stack + UInt8 x7_3 : 3; + UInt8 uses_CRs : 1; // set to 1 if CRs used + UInt8 needs_link_register : 1; // set to 1 if link register used + + UInt8 has_frame_size : 1; // set to 1 if frame_size is nonzero + UInt8 x8_1 : 1; // set to 0 + UInt8 used_FPRs : 6; // stores non-volatile FPRs used + + UInt8 x9_0 : 1; // set to 0 + UInt8 x9_1 : 1; // set to 1 if VRs or vrsave used + UInt8 used_GPRs : 6; // stores non-volatile GPRs used + + UInt8 xA; + UInt8 xB; + + SInt32 funcsize; + SInt16 namelen; + char name[0]; +} Traceback; + +typedef struct TracebackExtra { + UInt8 used_VRs : 6; + UInt8 has_vrsave_mask : 1; + UInt8 is_varargs : 1; + UInt8 vec_arg_count : 7; + UInt8 has_vrsave_mask_or_used_VRs : 1; +} TracebackExtra; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +char *generate_traceback(SInt32 funcsize, char *funcname, SInt32 *tbsize, Object *func) { + char *work; + short namelen; + Traceback *buf; + SInt32 bufsize; + + namelen = strlen(funcname); + bufsize = ALIGN(sizeof(Traceback) + namelen + (dynamic_stack ? 1 : 0) + ((used_nonvolatile_registers[RegClass_VR] || vrsave_mask) ? sizeof(TracebackExtra) : 0), 4); + buf = lalloc(bufsize); + memclrw(buf, bufsize); + + buf->x4 = 0; + buf->x5 = copts.cplusplus ? 9 : 0; + buf->x6_1 = 1; + buf->x7_1 = 1; + if (dynamic_stack) + buf->has_dynamic_stack = 1; + if (used_nonvolatile_registers[RegClass_CRFIELD]) + buf->uses_CRs = 1; + if (need_link_register()) + buf->needs_link_register = 1; + if (frame_size) + buf->has_frame_size = 1; + buf->used_FPRs = used_nonvolatile_registers[RegClass_FPR]; + buf->used_GPRs = used_nonvolatile_registers[RegClass_GPR]; + buf->x8_1 = 0; + buf->x9_0 = 0; + buf->x9_1 = (used_nonvolatile_registers[RegClass_VR] || vrsave_mask) != 0; + buf->funcsize = funcsize; + buf->namelen = namelen; + + work = buf->name; + strcpy(work, funcname); + work += namelen; + if (dynamic_stack) { + *(work++) = 31; + } + + if (vrsave_mask || used_nonvolatile_registers[RegClass_VR]) { + TracebackExtra *extra; + Boolean is_varargs; + int vec_count; + FuncArg *args, *scan; + Type *type; + + extra = (TracebackExtra *) work; + vec_count = 0; + args = TYPE_FUNC(func->type)->args; + scan = args; + while (scan && scan != &elipsis) + scan = scan->next; + is_varargs = scan == &elipsis; + while (args) { + if ((type = args->type) && IS_TYPE_VECTOR(type)) + vec_count++; + args = args->next; + } + extra->used_VRs = used_nonvolatile_registers[RegClass_VR]; + extra->has_vrsave_mask = vrsave_mask != 0; + extra->is_varargs = is_varargs; + extra->vec_arg_count = vec_count; + extra->has_vrsave_mask_or_used_VRs = vrsave_mask || used_nonvolatile_registers[RegClass_VR]; + } + + *tbsize = bufsize; + return (char *) buf; +} + +static SInt32 localsbase(void) { + SInt32 size = parameter_area_size; + if (frame_size || dynamic_align_stack) + size += linkage_area_size; + else + size -= genuine_frame_size; + return size; +} + +static SInt32 parametersbase(int flag) { + if (flag) + return 24; + + return frame_size ? (genuine_frame_size + 24) : 24; +} + +void check_dynamic_aligned_frame(void) { + PCode *pc; + + if (used_nonvolatile_registers[RegClass_VR]) { + update_frame_align(16); + requires_frame = 1; + } + + if (frame_alignment > in_param_alignment) { + dynamic_align_stack = 1; + requires_frame = 1; + CError_ASSERT(2091, !has_varargs || _CALLER_SP_ != -1); + CError_ASSERT(2096, _CALLER_SP_ != _FP_); + if (setup_caller_sp && setup_caller_sp->block) { + align_instr1 = makepcode(PC_RLWINM, 12, 1, 0, 5, 31); + insertpcodebefore(setup_caller_sp, align_instr1); + align_instr2 = makepcode(PC_STWUX, 1, 1, 12); + insertpcodeafter(setup_caller_sp, align_instr2); + } + } else { + dynamic_align_stack = 0; + if (setup_caller_sp && setup_caller_sp->block) { + pc = makepcode(PC_MR, _CALLER_SP_, _FP_); + insertpcodebefore(setup_caller_sp, pc); + deletepcode(setup_caller_sp); + setup_caller_sp = pc; + } + _CALLER_SP_ = _FP_; + } + + vrsave_mask = 0; + if (copts.altivec_model) { + vrsave_mask = colored_vrs_as_vrsave(pcbasicblocks); + if (!requires_frame && vrsave_mask) { + vrsave_register = 11; + loadvrsave = makepcode(PC_LWZ, 11, 1, 0, -4); + appendpcode(prologue, loadvrsave); + storevrsave = makepcode(PC_STW, 11, 1, 0, -4); + appendpcode(epilogue, storevrsave); + } + } +} + +void move_varargs_to_memory(void) { + short reg; + + has_varargs = 1; + dummyvaparam = galloc(sizeof(Object)); + memclrw(dummyvaparam, sizeof(Object)); + + dummyvaparam->type = TYPE(&stvoid); + dummyvaparam->otype = OT_OBJECT; + dummyvaparam->name = GetHashNameNode("<vaparam>"); + dummyvaparam->datatype = DLOCAL; + dummyvaparam->u.var.info = CodeGen_GetNewVarInfo(); + dummyvaparam->u.var.uid = 0; + dummyvaparam->u.var.info->noregister = 1; + Registers_GetVarInfo(dummyvaparam)->flags = (Registers_GetVarInfo(dummyvaparam)->flags & ~VarInfoFlag1) | VarInfoFlag1; + + for (reg = last_argument_register[RegClass_GPR] + 1; (int)reg <= 10; reg++) { + emitpcode(PC_STW, reg, local_base_register(dummyvaparam), dummyvaparam, (reg - 3) * 4); + setpcodeflags(fIsPtrOp | fIsArgInit); + } +} + +void assign_arguments_to_memory(Object *func, UInt8 mysteryFlag, Boolean hasVarargs) { + // almost matches except for the not/andc issue + SInt32 pos; + ObjectList *list; + Object *obj; + Type *type; + short reg; + SInt32 chk; + Boolean flag; + + pos = 0; + reg = 2; + + for (list = arguments; list; list = list->next) { + obj = list->object; + type = obj->type; + if (!IS_TYPE_VECTOR(type)) { + obj->datatype = DLOCAL; + obj->u.var.info = CodeGen_GetNewVarInfo(); + if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) || + IS_TYPE_12BYTES_MEMBERPOINTER(type)) { + chk = CMach_ArgumentAlignment(type); + if (chk > 4) { + pos = ALIGN(pos, chk); + update_in_param_align(chk); + } + } + obj->u.var.uid = pos; + Registers_GetVarInfo(obj)->flags = (Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1) | VarInfoFlag1; + if (!copts.littleendian && (IS_TYPE_INT(obj->type) || IS_TYPE_ENUM(obj->type)) && obj->type->size < 4) + obj->u.var.uid += 4 - obj->type->size; + pos += type->size; + pos = ALIGN(pos, 4); + } else { + obj->u.var.info = CodeGen_GetNewVarInfo(); + obj->u.var.uid = 0; + obj->datatype = DLOCAL; + flag = 1; + if (reg <= 13) + flag = hasVarargs; + if (flag) { + pos = ALIGN(pos + 24, 16) - 24; + obj->u.var.uid = pos; + pos += 16; + update_in_param_align(16); + Registers_GetVarInfo(obj)->flags = (Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1) | VarInfoFlag1; + } else { + assign_local_memory(obj); + Registers_GetVarInfo(obj)->flags = Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1; + } + reg++; + } + } + + in_parameter_size = (in_parameter_size < pos) ? pos : in_parameter_size; + CError_ASSERT(2408, !dummyvaparam); +} + +SInt32 set_out_param_displ(SInt32 a, Type *type, Boolean flag, SInt32 *outvar, SInt32 b) { + // does not match due to errant andc + SInt32 argAlign; + + if (!flag && !b) { + *outvar = 0; + return a; + } + + if (IS_TYPE_VECTOR(type)) { + update_out_param_align(16); + a = ALIGN(a + 16 + 24, 16) - 24; + } else if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) || IS_TYPE_12BYTES_MEMBERPOINTER(type)) { + argAlign = CMach_ArgumentAlignment(type); + if (argAlign > 4) { + a = ALIGN(a + 24, argAlign) - 24; + update_in_param_align(argAlign); + } + } + + *outvar = a; + a = ALIGN(a + b, 4); + return a; +} + +SInt32 out_param_displ_to_offset(SInt32 displ) { + return displ + 24; +} + +Boolean needs_frame(void) { + return (frame_size > 224) || requires_frame; +} + +void update_out_param_size(SInt32 size) { + if (size < 32) + size = 32; + if (parameter_area_size < size) + parameter_area_size = size; +} + +void estimate_out_param_size(SInt32 size) { + if (parameter_area_size_estimate < size) + parameter_area_size_estimate = size; +} + +void update_out_param_align(SInt32 align) { + if (out_param_alignment < align) + out_param_alignment = align; + update_frame_align(align); +} + +void update_in_param_align(SInt32 align) { + if (in_param_alignment < align) + in_param_alignment = align; +} + +void update_frame_align(SInt32 align) { + if (frame_alignment < align) + frame_alignment = align; +} + +SInt32 local_offset_32(Object *obj) { + short align; + SInt32 offset; + + if (obj->u.var.info->flags & VarInfoFlag1) + align = CMach_ArgumentAlignment(obj->type); + else + align = CMach_AllocationAlignment(obj->type, obj->qual); + + offset = obj->u.var.uid; + if (offset > 0x7FFF) + offset = 0x8000 - offset - ALIGN(obj->type->size, align); + + if (obj->u.var.info->flags & VarInfoFlag1) + return offset + parametersbase(local_base_register(obj) != _FP_); + else + return offset + localsbase(); +} + +SInt32 local_offset_lo(Object *obj, SInt32 offset) { + SInt32 combo = offset + local_offset_32(obj); + return LOW_PART(combo); + //return (SInt16) (offset + local_offset_32(obj)); +} + +SInt32 local_offset_ha(Object *obj, SInt32 offset) { + SInt32 combo = offset + local_offset_32(obj); + return HIGH_PART(combo); + //return (SInt16) ((combo >> 16) + ((combo & 0x8000) >> 15)); +} + +SInt32 local_offset_16(Object *obj) { + SInt32 offset32 = local_offset_32(obj); + SInt16 offset16 = (SInt16) offset32; + CError_ASSERT(2662, offset32 == offset16); + return offset16; +} + +Boolean local_is_16bit_offset(Object *obj) { + SInt32 offset32 = local_offset_32(obj); + SInt16 offset16 = (SInt16) offset32; + return offset32 == offset16; +} + +int local_base_register(Object *obj) { + PCode *pc; + + if (obj->u.var.info->flags & VarInfoFlag1) { + if (coloring && _CALLER_SP_ == -1) { + _CALLER_SP_ = used_virtual_registers[RegClass_GPR]++; + pc = makepcode(PC_LWZ, _CALLER_SP_, 1, 0, 0); + setup_caller_sp = pc; + appendpcode(prologue, pc); + } + return _CALLER_SP_; + } else { + return _FP_; + } +} + +static UInt32 align_bits(UInt32 value, UInt8 bitcount) { + UInt32 base = bitcount != 0; + switch (value) { + case 0x0002: return base + 30; + case 0x0004: return base + 29; + case 0x0008: return base + 28; + case 0x0010: return base + 27; + case 0x0020: return base + 26; + case 0x0040: return base + 25; + case 0x0080: return base + 24; + case 0x0100: return base + 23; + case 0x0200: return base + 22; + case 0x0400: return base + 21; + case 0x0800: return base + 20; + case 0x1000: return base + 19; + case 0x2000: return base + 18; + default: + CError_FATAL(2754); + return base + 27; + } +} + +Boolean is_large_frame(void) { + CError_ASSERT(2769, frame_size != -1); + return large_stack; +} + +void no_frame_for_asm(void) { + frame_size = 0; +} + +Boolean can_add_displ_to_local(Object *obj, SInt32 displ) { + if (obj->datatype != DLOCAL) + return 0; + + if (local_offset_32(obj) == (short) local_offset_32(obj)) + if ((displ + local_offset_32(obj)) == (short) (displ + local_offset_32(obj))) + return 1; + + return 0; +} + +SInt32 get_alloca_alignment(void) { + SInt32 align = frame_alignment; + if (copts.altivec_model) + align = ALIGN(align, 16); + + if (!alloca_alignment) + alloca_alignment = align; + else + CError_ASSERT(2825, alloca_alignment == align); + + return align_bits(align, 0); +} + +static Boolean use_helper_function(char rclass) { + if (copts.no_register_save_helpers) + return 0; + + switch (rclass) { + case RegClass_GPR: + if (copts.use_lmw_stmw) + return 0; + return (used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimizesize && used_nonvolatile_registers[RegClass_GPR] > 2); + case RegClass_FPR: + return (used_nonvolatile_registers[RegClass_FPR] > 3) || (copts.optimizesize && used_nonvolatile_registers[RegClass_FPR] > 2); + case RegClass_VR: + return (used_nonvolatile_registers[RegClass_VR] > 3) || (copts.optimizesize && used_nonvolatile_registers[RegClass_VR] > 2); + default: + CError_FATAL(2862); + return 0; + } +} + +static Boolean need_link_register(void) { + if (copts.codegen_pic && uses_globals) + return 1; + + if (makes_call) + return 1; + + return use_helper_function(RegClass_FPR) || use_helper_function(RegClass_GPR) || use_helper_function(RegClass_VR); +} + +static void call_helper_function(char *name, char rclass, short effect) { + char str[32]; + Object *func; + NameSpace *save_scope; + PCode *pc; + int extra_args; + PCodeArg *arg; + short i; + + extra_args = 1; + if (rclass == RegClass_VR) + extra_args = 2; + + sprintf(str, name, 32 - used_nonvolatile_registers[rclass]); + + save_scope = cscope_current; + cscope_current = cscope_root; + func = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + cscope_current = save_scope; + + func->name = GetHashNameNodeExport(str); + + pc = makepcode(PC_BL, extra_args + used_nonvolatile_registers[rclass], func, 0); + for (i = 1, arg = &pc->args[1]; i <= used_nonvolatile_registers[rclass]; i++, arg++) { + arg->kind = PCOp_REGISTER; + arg->arg = rclass; + arg->data.reg.reg = n_real_registers[rclass] - i; + arg->data.reg.effect = effect; + } + + if (rclass == RegClass_VR) { + arg[1].kind = PCOp_REGISTER; + arg[1].arg = RegClass_GPR; + arg[1].data.reg.reg = 12; + arg[1].data.reg.effect = EffectWrite; + arg[2].kind = PCOp_REGISTER; + arg[2].arg = RegClass_GPR; + arg[2].data.reg.reg = 0; + arg[2].data.reg.effect = EffectRead; + } else { + arg[1].kind = PCOp_REGISTER; + arg[1].arg = RegClass_GPR; + arg[1].data.reg.reg = 11; + arg[1].data.reg.effect = EffectRead; + } + + appendpcode(pclastblock, pc); + setpcodeflags(fSideEffects); +} + +static SInt32 nearest_power_of_two(SInt32 n) { + SInt32 power = 1; + do { + power <<= 1; + } while (power && power < n); + + CError_ASSERT(2933, power != 0); + return power; +} + +static void compress_data_area(void) { + // doesn't quite match + SInt32 r0; + SInt32 r7; + ObjectList *list; + Object *obj; + PCodeBlock *block; + PCode *pc; + int i; + + compressing_data_area = 1; + + if (large_stack) { + r0 = 0; + } else { + r0 = parameter_area_size; + if (r0 < 32) + r0 = 32; + } + r7 = ALIGN(r0 + 24, frame_alignment) - 24; + local_data_limit = 0x8000 - ALIGN(24 + in_parameter_size + nonvolatile_save_size + r7, frame_alignment); + + if (local_objects_tail[ObjClass0]) { + if (local_objects[ObjClass1]) { + local_objects_tail[ObjClass0]->next = local_objects[ObjClass1]; + local_objects_tail[ObjClass0] = local_objects_tail[ObjClass1]; + } + if (local_objects[ObjClass2]) { + local_objects_tail[ObjClass0]->next = local_objects[ObjClass2]; + local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2]; + } + } else if (local_objects_tail[ObjClass1]) { + local_objects[ObjClass0] = local_objects[ObjClass1]; + local_objects_tail[ObjClass0] = local_objects_tail[ObjClass1]; + if (local_objects[ObjClass2]) { + local_objects_tail[ObjClass0]->next = local_objects[ObjClass2]; + local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2]; + } + } else { + local_objects[ObjClass0] = local_objects[ObjClass2]; + local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2]; + } + + for (list = local_objects[ObjClass0]; list; list = list->next) + Registers_GetVarInfo(list->object)->used = 0; + + for (block = pcbasicblocks; block; block = block->nextBlock) { + for (pc = block->firstPCode; pc; pc = pc->nextPCode) { + for (i = 0; i < pc->argCount; i++) { + if (pc->args[i].kind == PCOp_MEMORY && pc->args[i].data.mem.obj && pc->args[i].data.mem.obj->datatype == DLOCAL) + Registers_GetVarInfo(pc->args[i].data.mem.obj)->used = 1; + } + } + } + + local_data_size = 0; + large_data_near_size = 0; + large_data_far_size = 0; + + for (list = local_objects[ObjClass0]; list; list = list->next) { + obj = list->object; + if (Registers_GetVarInfo(obj)->used) + assign_local_memory(obj); + } +} + +static void insert_local_object(UInt8 oclass, Object *obj) { + ObjectList *list; + + if (!compressing_data_area) { + list = lalloc(sizeof(ObjectList)); + memclrw(list, sizeof(ObjectList)); + list->object = obj; + if (!local_objects[oclass]) + local_objects[oclass] = list; + if (local_objects_tail[oclass]) + local_objects_tail[oclass]->next = list; + local_objects_tail[oclass] = list; + } +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c new file mode 100644 index 0000000..7c28b88 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c @@ -0,0 +1,792 @@ +#include "compiler/StructMoves.h" +#include "compiler/CError.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/Operands.h" +#include "compiler/PCode.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/Registers.h" + +void make_addressable(Operand *opnd, SInt32 offset, int unusedArg) { + int reg; + + if (opnd->optype == OpndType_IndirectSymbol) + coerce_to_addressable(opnd); + + if (opnd->optype != OpndType_IndirectGPR_ImmOffset || (opnd->immOffset + offset) > 0x7FFF) { + reg = used_virtual_registers[RegClass_GPR]++; + load_address(reg, opnd); + opnd->optype = OpndType_IndirectGPR_ImmOffset; + opnd->reg = reg; + opnd->object = NULL; + opnd->immOffset = 0; + } +} + +static void load_displaced_address(Operand *opnd, SInt32 offset) { + int reg; + + reg = used_virtual_registers[RegClass_GPR]++; + if (opnd->optype == OpndType_IndirectSymbol) + coerce_to_addressable(opnd); + + if (opnd->optype == OpndType_IndirectGPR_ImmOffset) { + offset += opnd->immOffset; + if (!FITS_IN_SHORT(offset)) { + add_immediate(reg, opnd->reg, opnd->object, opnd->immOffset); + emitpcode(PC_ADDI, reg, reg, 0, offset - opnd->immOffset); + } else { + add_immediate(reg, opnd->reg, opnd->object, offset); + } + } else if (opnd->optype == OpndType_IndirectGPR_Indexed) { + emitpcode(PC_ADD, reg, opnd->reg, opnd->regOffset); + emitpcode(PC_ADDI, reg, reg, 0, offset); + } else { + CError_FATAL(80); + } + + opnd->optype = OpndType_IndirectGPR_ImmOffset; + opnd->reg = reg; + opnd->object = NULL; + opnd->immOffset = 0; +} + +static void move_block_via_load_store(Operand *dst, Operand *src, SInt32 len, SInt32 align) { + SInt32 step; + SInt32 pos; + int floatReg; + int reg; + + if (src->optype == OpndType_IndirectSymbol) + coerce_to_addressable(src); + if (dst->optype == OpndType_IndirectSymbol) + coerce_to_addressable(dst); + + if (len == 8) { + floatReg = used_virtual_registers[RegClass_FPR]++; + if (src->optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register(PC_LFD, floatReg, src->reg, src->object, src->immOffset); + setpcodeflags(src->flags); + } else if (src->optype == OpndType_IndirectGPR_Indexed) { + emitpcode(PC_LFDX, floatReg, src->reg, src->regOffset); + setpcodeflags(src->flags); + } else { + CError_FATAL(145); + } + + if (dst->optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register(PC_STFD, floatReg, dst->reg, dst->object, dst->immOffset); + setpcodeflags(dst->flags); + } else if (dst->optype == OpndType_IndirectGPR_Indexed) { + emitpcode(PC_STFDX, floatReg, dst->reg, dst->regOffset); + setpcodeflags(dst->flags); + } else { + CError_FATAL(157); + } + + return; + } + + if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) { + SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align; + step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2; + } else { + step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2; + } + + if (step != len) { + if (dst->optype == OpndType_IndirectGPR_Indexed) + make_addressable(dst, len, 0); + if (src->optype == OpndType_IndirectGPR_Indexed) + make_addressable(src, len, 0); + } + + for (pos = 0; len != 0; len -= step, pos += step) { + reg = used_virtual_registers[RegClass_GPR]++; + if (src->optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register( + (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ, + reg, + src->reg, + src->object, + src->immOffset + pos + ); + setpcodeflags(src->flags); + } else if (src->optype == OpndType_IndirectGPR_Indexed) { + emitpcode( + (step == 1) ? PC_LBZX : (step == 2) ? PC_LHZX : PC_LWZX, + reg, + src->reg, + src->regOffset + ); + setpcodeflags(src->flags); + } else { + CError_FATAL(183); + } + + if (dst->optype == OpndType_IndirectGPR_ImmOffset) { + load_store_register( + (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW, + reg, + dst->reg, + dst->object, + dst->immOffset + pos + ); + setpcodeflags(dst->flags); + } else if (dst->optype == OpndType_IndirectGPR_Indexed) { + emitpcode( + (step == 1) ? PC_STBX : (step == 2) ? PC_STHX : PC_STWX, + reg, + dst->reg, + dst->regOffset + ); + setpcodeflags(dst->flags); + } else { + CError_FATAL(195); + } + } +} + +static void move_block_via_load_store_sequence(Operand *dst, Operand *src, SInt32 len, SInt32 align) { + SInt32 pos; + int i; + SInt32 step; + + pos = 0; + make_addressable(dst, len, 0); + make_addressable(src, len, 0); + + if ((align % 8) == 0) { + while (len >= 16) { + int reg1 = used_virtual_registers[RegClass_FPR]++; + int reg2 = used_virtual_registers[RegClass_FPR]++; + load_store_register(PC_LFD, reg1, src->reg, src->object, src->immOffset + pos); + setpcodeflags(src->flags); + load_store_register(PC_LFD, reg2, src->reg, src->object, src->immOffset + pos + 8); + setpcodeflags(src->flags); + + load_store_register(PC_STFD, reg1, dst->reg, dst->object, dst->immOffset + pos); + setpcodeflags(dst->flags); + load_store_register(PC_STFD, reg2, dst->reg, dst->object, dst->immOffset + pos + 8); + setpcodeflags(dst->flags); + + pos += 16; + len -= 16; + } + } + + while (len >= 8) { + if ((align % 8) == 0) { + int reg = used_virtual_registers[RegClass_FPR]++; + + load_store_register(PC_LFD, reg, src->reg, src->object, src->immOffset + pos); + setpcodeflags(src->flags); + + load_store_register(PC_STFD, reg, dst->reg, dst->object, dst->immOffset + pos); + setpcodeflags(dst->flags); + + pos += 8; + len -= 8; + } else { + if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) { + SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align; + step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp > 2) ? 2 : 1; + } else { + step = 4; + } + + for (i = 0; i < 8; i += (step * 2)) { + int reg1 = used_virtual_registers[RegClass_GPR]++; + int reg2 = used_virtual_registers[RegClass_GPR]++; + + load_store_register( + (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ, + reg1, + src->reg, + src->object, + src->immOffset + pos + ); + setpcodeflags(src->flags); + + load_store_register( + (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ, + reg2, + src->reg, + src->object, + src->immOffset + pos + step + ); + setpcodeflags(src->flags); + + load_store_register( + (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW, + reg1, + dst->reg, + dst->object, + dst->immOffset + pos + ); + setpcodeflags(dst->flags); + + load_store_register( + (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW, + reg2, + dst->reg, + dst->object, + dst->immOffset + pos + step + ); + setpcodeflags(dst->flags); + + pos += (step * 2); + len -= (step * 2); + } + } + } + + while (len) { + int reg; + + if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) { + SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align; + step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2; + } else { + step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2; + } + + reg = used_virtual_registers[RegClass_GPR]++; + + load_store_register( + (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ, + reg, + src->reg, + src->object, + src->immOffset + pos + ); + setpcodeflags(src->flags); + + load_store_register( + (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW, + reg, + dst->reg, + dst->object, + dst->immOffset + pos + ); + setpcodeflags(dst->flags); + + len -= step; + pos += step; + } +} + +static void move_block_via_inline_loop(Operand *dst, Operand *src, SInt32 len, SInt32 align) { + PCodeLabel *label; // r25 + SInt32 pos; // r25 + SInt32 step; // r24 + int reg1; // r22 + int reg2; // r23 + SInt32 remainder; // r23 + + label = makepclabel(); + + if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) { + SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align; + step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2; + } else { + step = 4; + } + + load_displaced_address(dst, -step); + load_displaced_address(src, -step); + + CError_ASSERT(377, (len / step) != 0); + + reg1 = used_virtual_registers[RegClass_GPR]++; + load_immediate(reg1, len / (step * 2)); + emitpcode(PC_MTCTR, reg1); + branch_label(label); + + reg1 = used_virtual_registers[RegClass_GPR]++; + reg2 = used_virtual_registers[RegClass_GPR]++; + + load_store_register( + (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ, + reg1, + src->reg, + NULL, + step + ); + setpcodeflags(src->flags); + + load_store_register( + (step == 1) ? PC_LBZU : (step == 2) ? PC_LHZU : PC_LWZU, + reg2, + src->reg, + NULL, + step * 2 + ); + setpcodeflags(src->flags); + + load_store_register( + (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW, + reg1, + dst->reg, + NULL, + step + ); + setpcodeflags(dst->flags); + + load_store_register( + (step == 1) ? PC_STBU : (step == 2) ? PC_STHU : PC_STWU, + reg2, + dst->reg, + NULL, + step * 2 + ); + setpcodeflags(dst->flags); + + branch_decrement_always(PC_BDNZ, label); + + for (remainder = len & 7, pos = step; remainder != 0; remainder -= step, pos += step) { + int reg; + + if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) { + SInt32 tmp = (align == 0) ? 1 : (align > remainder) ? remainder : align; + step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2; + } else { + step = ((UInt32) remainder > 4) ? 4 : ((UInt32) remainder <= 2) ? remainder : 2; + } + + reg = used_virtual_registers[RegClass_GPR]++; + + load_store_register( + (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ, + reg, + src->reg, + NULL, + pos + ); + setpcodeflags(src->flags); + + load_store_register( + (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW, + reg, + dst->reg, + NULL, + pos + ); + setpcodeflags(dst->flags); + } +} + +void move_block(Operand *dst, Operand *src, SInt32 len, SInt32 align) { + Operand myDst; + + myDst = *dst; + + CError_ASSERT(447, myDst.optype >= OpndType_IndirectGPR_ImmOffset); + CError_ASSERT(449, src->optype >= OpndType_IndirectGPR_ImmOffset); + + if (len == 1 || len == 2 || len == 4) + move_block_via_load_store(&myDst, src, len, align); + else if (len == 8 && align == 8) + move_block_via_load_store(&myDst, src, len, align); + else if (len <= 16 || (copts.optimizesize == 0 && len <= 64)) + move_block_via_load_store_sequence(&myDst, src, len, align); + else + move_block_via_inline_loop(&myDst, src, len, align); +} + +static void load_word_of_small_struct(short dstReg, short srcReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) { + short tmpReg; + short extra = 0; + + switch (len) { + case 1: + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7); + setpcodeflags(opnd->flags); + break; + case 2: + case 3: + if (align > 1) { + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset); + extra += 2; + setpcodeflags(opnd->flags); + emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15); + setpcodeflags(opnd->flags); + } else { + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7); + setpcodeflags(opnd->flags); + + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1); + extra += 2; + setpcodeflags(opnd->flags); + emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15); + setpcodeflags(opnd->flags); + } + if (len == 3) { + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + extra); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23); + setpcodeflags(opnd->flags); + } + break; + case 4: + if (align > 2) { + load_store_register(PC_LWZ, dstReg, srcReg, opnd->object, offset); + setpcodeflags(opnd->flags); + } else if (align > 1) { + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15); + setpcodeflags(opnd->flags); + + load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset + 2); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 16, 31); + setpcodeflags(opnd->flags); + } else { + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7); + setpcodeflags(opnd->flags); + + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15); + setpcodeflags(opnd->flags); + + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 2); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23); + setpcodeflags(opnd->flags); + + load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 3); + setpcodeflags(opnd->flags); + emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 24, 31); + setpcodeflags(opnd->flags); + } + break; + } +} + +void load_small_block_into_reg(short dstReg, Operand *srcOpnd, Type *type, SInt32 align) { + short finalReg; + short tmpReg; + SInt32 absAddress; + + coerce_to_addressable(srcOpnd); + + if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) { + CError_FATAL(557); + + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_address(tmpReg, srcOpnd); + srcOpnd->optype = OpndType_IndirectGPR_ImmOffset; + srcOpnd->reg = tmpReg; + srcOpnd->object = NULL; + srcOpnd->immOffset = 0; + } + + if (copts.misaligned_mem_access) + align = 4; + + switch (srcOpnd->optype) { + case OpndType_GPRPair: + return; + case OpndType_GPR: + return; + case OpndType_GPR_ImmOffset: + finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++; + add_immediate(finalReg, srcOpnd->reg, srcOpnd->object, srcOpnd->immOffset); + break; + case OpndType_GPR_Indexed: + finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_ADD, finalReg, srcOpnd->reg, srcOpnd->regOffset); + break; + case OpndType_Absolute: + finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++; + absAddress = srcOpnd->immediate; + if (FITS_IN_SHORT(absAddress)) { + emitpcode(PC_LI, finalReg, absAddress); + } else { + tmpReg = finalReg; + if (copts.optimizationlevel > 1 && absAddress) + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress)); + if (absAddress) + emitpcode(PC_ADDI, finalReg, tmpReg, 0, LOW_PART(absAddress)); + } + break; + case OpndType_IndirectGPR_ImmOffset: + finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++; + load_word_of_small_struct(finalReg, srcOpnd->reg, srcOpnd, srcOpnd->immOffset, type->size, align); + break; + default: + CError_FATAL(606); + } + + srcOpnd->optype = OpndType_GPR; + srcOpnd->reg = finalReg; +} + +void load_small_block_into_reg_pair(short dstRegLo, short dstRegHi, Operand *srcOpnd, Type *type, SInt32 align) { + short finalRegLo; + short finalRegHi; + short tmpRegLo; + short tmpRegHi; + short tmpReg; + SInt32 absAddress; + + finalRegHi = -1; + coerce_to_addressable(srcOpnd); + + if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) { + CError_FATAL(624); + + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_address(tmpReg, srcOpnd); + srcOpnd->optype = OpndType_IndirectGPR_ImmOffset; + srcOpnd->reg = tmpReg; + srcOpnd->object = NULL; + srcOpnd->immOffset = 0; + } + + if (copts.misaligned_mem_access) + align = 4; + + switch (srcOpnd->optype) { + case OpndType_GPRPair: + if (dstRegLo != 0 && dstRegHi == 0) + dstRegHi = used_virtual_registers[RegClass_GPR]++; + if (dstRegHi != 0 && dstRegLo == 0) + dstRegLo = used_virtual_registers[RegClass_GPR]++; + + if (srcOpnd->reg != dstRegLo || srcOpnd->regHi != dstRegHi) { + tmpRegLo = dstRegLo ? dstRegLo : srcOpnd->reg; + tmpRegHi = dstRegHi ? dstRegHi : srcOpnd->regHi; + + if (tmpRegLo != srcOpnd->reg) { + if (tmpRegLo == srcOpnd->regHi) { + CError_ASSERT(657, tmpRegLo != tmpRegHi); + emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi); + emitpcode(PC_MR, tmpRegLo, srcOpnd->reg); + } else { + emitpcode(PC_MR, tmpRegLo, srcOpnd->reg); + if (srcOpnd->regHi != tmpRegHi) + emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi); + } + } else if (tmpRegHi != srcOpnd->regHi) { + if (tmpRegHi == srcOpnd->reg) { + CError_ASSERT(671, tmpRegLo != tmpRegHi); + emitpcode(PC_MR, tmpRegLo, srcOpnd->reg); + emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi); + } else { + emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi); + if (srcOpnd->reg != tmpRegLo) + emitpcode(PC_MR, tmpRegLo, srcOpnd->reg); + } + } + } + + finalRegLo = srcOpnd->reg; + finalRegHi = srcOpnd->regHi; + break; + case OpndType_GPR: + CError_FATAL(688); + break; + case OpndType_GPR_ImmOffset: + CError_FATAL(691); + break; + case OpndType_GPR_Indexed: + CError_FATAL(694); + break; + case OpndType_Absolute: + finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++; + absAddress = srcOpnd->immediate; + if (FITS_IN_SHORT(absAddress)) { + emitpcode(PC_LI, finalRegLo, absAddress); + } else { + tmpReg = finalRegLo; + if (copts.optimizationlevel > 1 && absAddress) + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress)); + if (absAddress) + emitpcode(PC_ADDI, finalRegLo, tmpReg, 0, LOW_PART(absAddress)); + } + + finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++; + if (is_unsigned(type) || absAddress >= 0) + load_immediate(finalRegHi, 0); + else + load_immediate(finalRegHi, -1); + + break; + case OpndType_IndirectGPR_ImmOffset: + finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++; + finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++; + if (srcOpnd->reg == finalRegHi) { + if (srcOpnd->reg == finalRegLo) { + CError_FATAL(726); + } else { + load_word_of_small_struct( + finalRegLo, srcOpnd->reg, srcOpnd, + srcOpnd->immOffset + low_offset, type->size - 4, align); + load_word_of_small_struct( + finalRegHi, srcOpnd->reg, srcOpnd, + srcOpnd->immOffset + high_offset, 4, align); + } + } else { + load_word_of_small_struct( + finalRegHi, srcOpnd->reg, srcOpnd, + srcOpnd->immOffset + high_offset, 4, align); + load_word_of_small_struct( + finalRegLo, srcOpnd->reg, srcOpnd, + srcOpnd->immOffset + low_offset, type->size - 4, align); + } + break; + default: + CError_FATAL(737); + } + + if (finalRegHi == -1) { + CError_FATAL(741); + } else { + srcOpnd->optype = OpndType_GPRPair; + srcOpnd->reg = finalRegLo; + srcOpnd->regHi = finalRegHi; + } +} + +static void store_word_of_small_struct(short srcReg, short dstReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) { + short tmpReg; + short extra = 0; + + switch (len) { + case 1: + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset); + setpcodeflags(opnd->flags); + break; + case 2: + case 3: + if (align > 1) { + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset); + extra += 2; + setpcodeflags(opnd->flags); + } else { + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset); + setpcodeflags(opnd->flags); + + emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1); + extra += 2; + setpcodeflags(opnd->flags); + } + if (len == 3) { + emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + extra); + setpcodeflags(opnd->flags); + } + break; + case 4: + if (align > 2) { + load_store_register(PC_STW, srcReg, dstReg, opnd->object, offset); + setpcodeflags(opnd->flags); + } else if (align > 1) { + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset); + setpcodeflags(opnd->flags); + + load_store_register(PC_STH, srcReg, dstReg, opnd->object, offset + 2); + setpcodeflags(opnd->flags); + } else { + tmpReg = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset); + setpcodeflags(opnd->flags); + + emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1); + setpcodeflags(opnd->flags); + + emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31); + setpcodeflags(opnd->flags); + load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 2); + setpcodeflags(opnd->flags); + + load_store_register(PC_STB, srcReg, dstReg, opnd->object, offset + 3); + setpcodeflags(opnd->flags); + } + break; + } +} + +void store_small_block_from_reg(short srcReg, Operand *dstOpnd, Type *type, SInt32 align) { + short tmpReg; + + coerce_to_addressable(dstOpnd); + + if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) { + CError_FATAL(839); + + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_address(tmpReg, dstOpnd); + dstOpnd->optype = OpndType_IndirectGPR_ImmOffset; + dstOpnd->reg = tmpReg; + dstOpnd->object = NULL; + dstOpnd->immOffset = 0; + } + + if (copts.misaligned_mem_access) + align = 4; + + store_word_of_small_struct(srcReg, dstOpnd->reg, dstOpnd, dstOpnd->immOffset, type->size, align); +} + +void store_small_block_from_reg_pair(short srcRegLo, short srcRegHi, Operand *dstOpnd, Type *type, SInt32 align) { + short tmpReg; + + coerce_to_addressable(dstOpnd); + + if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) { + CError_FATAL(860); + + tmpReg = used_virtual_registers[RegClass_GPR]++; + load_address(tmpReg, dstOpnd); + dstOpnd->optype = OpndType_IndirectGPR_ImmOffset; + dstOpnd->reg = tmpReg; + dstOpnd->object = NULL; + dstOpnd->immOffset = 0; + } + + if (copts.misaligned_mem_access) + align = 4; + + store_word_of_small_struct( + srcRegLo, dstOpnd->reg, dstOpnd, + dstOpnd->immOffset + low_offset, type->size - 4, align); + store_word_of_small_struct( + srcRegHi, dstOpnd->reg, dstOpnd, + dstOpnd->immOffset + high_offset, 4, align); +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c new file mode 100644 index 0000000..4bbd82e --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c @@ -0,0 +1,518 @@ +#include "compiler/Switch.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/InstrSelection.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/Operands.h" +#include "compiler/PCode.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/RegisterInfo.h" +#include "compiler/TOC.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" + +ObjectList *switchtables; +static SwitchCase **caselabels; +static CaseRange *caseranges; +static SInt32 ncases; +static SInt32 nranges_minus1; +static CInt64 min; +static CInt64 max; +static CInt64 first; +static short selector_gpr; +static short selector_gprHi; +static Type *selector_type; +static PCodeLabel *defaultlabel; +static CInt64 range; + +static int compare_cases(const void *a, const void *b) { + const SwitchCase **casea = (const SwitchCase **) a; + const SwitchCase **caseb = (const SwitchCase **) b; + + if (CInt64_Less((*casea)->min, (*caseb)->min)) + return -1; + if (CInt64_Greater((*casea)->min, (*caseb)->min)) + return 1; + return 0; +} + +static void build_case_ranges(Type *type, SwitchCase *cases, CLabel *label) { + SwitchCase **caseptr; + SInt32 i; + SwitchCase *curcase; + CaseRange *currange; + + if (type->size == 8) { + min.lo = 0; + min.hi = 0x80000000; + max.lo = 0xFFFFFFFF; + max.hi = 0x7FFFFFFF; + } else if (type->size == 4) { + CInt64_SetLong(&min, 0x80000000); + CInt64_SetLong(&max, 0x7FFFFFFF); + } else if (is_unsigned(type)) { + min.hi = 0; + min.lo = 0; + max.hi = 0; + max.lo = 0xFFFF; + } else { + CInt64_SetLong(&min, -0x8000); + CInt64_SetLong(&max, 0x7FFF); + } + + caselabels = lalloc(sizeof(SwitchCase *) * ncases); + caseptr = caselabels; + while (cases) { + *caseptr = cases; + cases = cases->next; + ++caseptr; + } + + caseranges = lalloc(((ncases * 2) + 2) * sizeof(CaseRange)); + if (type->size < 8) { + for (i = 0; i < ncases; i++) + CInt64_SetLong(&caselabels[i]->min, caselabels[i]->min.lo); + } + + qsort(caselabels, ncases, sizeof(SwitchCase *), &compare_cases); + + currange = caseranges; + currange->min = min; + currange->range = CInt64_Sub(max, min); + currange->label = label->pclabel; + + for (i = 0; i < ncases; i++) { + curcase = caselabels[i]; + if (CInt64_GreaterEqual(curcase->min, min) && CInt64_LessEqual(curcase->min, max)) { + if (CInt64_Equal(currange->min, min)) + first = curcase->min; + range = CInt64_Sub(curcase->min, first); + + if (CInt64_Greater(curcase->min, currange->min)) { + currange->range = CInt64_Sub(CInt64_Sub(curcase->min, currange->min), cint64_one); + (++currange)->min = curcase->min; + } else if (CInt64_Greater(currange->min, min) && curcase->label->pclabel == currange[-1].label) { + currange[-1].range = CInt64_Add(currange[-1].range, cint64_one); + if (CInt64_Equal(currange->range, cint64_zero)) { + currange--; + } else { + currange->min = CInt64_Add(currange->min, cint64_one); + currange->range = CInt64_Sub(currange->range, cint64_one); + } + continue; + } + + currange->range = cint64_zero; + currange->label = curcase->label->pclabel; + + if (CInt64_Less(curcase->min, max)) { + currange++; + currange->min = CInt64_Add(curcase->min, cint64_one); + currange->range = CInt64_Sub(max, currange->min); + currange->label = label->pclabel; + } + } + } + + nranges_minus1 = currange - caseranges; +} + +static void treecompare(SInt32 start, SInt32 end) { + SInt32 r30; + SInt32 r29; + CaseRange *currange; + int count; + + count = end - start; + CError_ASSERT(175, selector_type->size <= 4); + + r29 = start + (count >> 1) + 1; + currange = caseranges + r29; + + if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) { + currange--; + r29--; + } + + r30 = r29 - 1; + + if (selector_type->size < 4 && is_unsigned(selector_type)) { + emitpcode(PC_CMPLI, 0, selector_gpr, CInt64_GetULong(&currange->min)); + } else if (FITS_IN_SHORT((SInt32) CInt64_GetULong(&currange->min))) { + emitpcode(PC_CMPI, 0, selector_gpr, CInt64_GetULong(&currange->min)); + } else { + SInt32 value = CInt64_GetULong(&currange->min); + int reg = ALLOC_GPR(); + load_immediate(reg, value); + emitpcode(PC_CMP, 0, selector_gpr, reg); + } + + if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) { + branch_conditional(0, EEQU, 1, currange->label); + r29++; + } + + if (r29 == end) { + if (start == r30) { + if (caseranges[start].label == caseranges[end].label) { + branch_always(caseranges[start].label); + } else { + branch_conditional(0, EGREATEREQU, 1, caseranges[end].label); + branch_always(caseranges[start].label); + } + } else { + branch_conditional(0, EGREATEREQU, 1, caseranges[end].label); + treecompare(start, r30); + } + } else { + if (start == r30) { + branch_conditional(0, ELESS, 1, caseranges[start].label); + treecompare(r29, end); + } else { + PCodeLabel *label = makepclabel(); + branch_conditional(0, EGREATEREQU, 1, label); + treecompare(start, r30); + branch_label(label); + treecompare(r29, end); + } + } +} + +static void I8_treecompare(SInt32 start, SInt32 end) { + SInt32 r30; + SInt32 r29; + CaseRange *currange; + int count; + + count = end - start; + + r29 = start + (count >> 1) + 1; + currange = caseranges + r29; + + if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) { + currange--; + r29--; + } + + r30 = r29 - 1; + + if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) { + short a = ALLOC_GPR(); + short b = ALLOC_GPR(); + load_immediate(a, currange->min.lo); + load_immediate(b, currange->min.hi); + emitpcode(PC_XOR, a, selector_gpr, a); + emitpcode(PC_XOR, b, selector_gprHi, b); + emitpcode(PC_OR, b, a, b); + emitpcode(PC_CMPI, 0, b, 0); + branch_conditional(0, EEQU, 1, currange->label); + r29++; + } + + if (r29 == end) { + if (start == r30) { + if (caseranges[start].label == caseranges[end].label) { + branch_always(caseranges[start].label); + } else { + short a = ALLOC_GPR(); + short b = ALLOC_GPR(); + short c = ALLOC_GPR(); + short d = ALLOC_GPR(); + load_immediate(a, currange->min.lo); + load_immediate(b, currange->min.hi); + if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { + emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); + emitpcode(PC_XORIS, d, b, 0x8000); + } else { + c = selector_gprHi; + d = b; + } + emitpcode(PC_SUBFC, a, a, selector_gpr); + emitpcode(PC_SUBFE, b, d, c); + emitpcode(PC_SUBFE, b, a, a); + emitpcode(PC_NEG, b, b); + emitpcode(PC_CMPI, 0, b, 0); + branch_conditional(0, EEQU, 1, caseranges[end].label); + branch_always(caseranges[start].label); + } + } else { + short a = ALLOC_GPR(); + short b = ALLOC_GPR(); + short c = ALLOC_GPR(); + short d = ALLOC_GPR(); + load_immediate(a, currange->min.lo); + load_immediate(b, currange->min.hi); + if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { + emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); + emitpcode(PC_XORIS, d, b, 0x8000); + } else { + c = selector_gprHi; + d = b; + } + emitpcode(PC_SUBFC, a, a, selector_gpr); + emitpcode(PC_SUBFE, b, d, c); + emitpcode(PC_SUBFE, b, a, a); + emitpcode(PC_NEG, b, b); + emitpcode(PC_CMPI, 0, b, 0); + branch_conditional(0, EEQU, 1, caseranges[end].label); + I8_treecompare(start, r30); + } + } else { + if (start == r30) { + short a = ALLOC_GPR(); + short b = ALLOC_GPR(); + short c = ALLOC_GPR(); + short d = ALLOC_GPR(); + load_immediate(a, currange->min.lo); + load_immediate(b, currange->min.hi); + if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { + emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); + emitpcode(PC_XORIS, d, b, 0x8000); + } else { + c = selector_gprHi; + d = b; + } + emitpcode(PC_SUBFC, a, selector_gpr, a); + emitpcode(PC_SUBFE, b, c, d); + emitpcode(PC_SUBFE, b, a, a); + emitpcode(PC_NEG, b, b); + emitpcode(PC_CMPI, 0, b, 0); + branch_conditional(0, ENOTEQU, 1, caseranges[end].label); + I8_treecompare(r29, end); + } else { + PCodeLabel *label; + short a = ALLOC_GPR(); + short b = ALLOC_GPR(); + short c = ALLOC_GPR(); + short d = ALLOC_GPR(); + load_immediate(a, currange->min.lo); + load_immediate(b, currange->min.hi); + if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) { + emitpcode(PC_XORIS, c, selector_gprHi, 0x8000); + emitpcode(PC_XORIS, d, b, 0x8000); + } else { + c = selector_gprHi; + d = b; + } + emitpcode(PC_SUBFC, a, a, selector_gpr); + emitpcode(PC_SUBFE, b, d, c); + emitpcode(PC_SUBFE, b, a, a); + emitpcode(PC_NEG, b, b); + emitpcode(PC_CMPI, 0, b, 0); + label = makepclabel(); + branch_conditional(0, EEQU, 1, label); + I8_treecompare(start, r30); + branch_label(label); + I8_treecompare(r29, end); + } + } +} + +static void generate_tree(ENode *expr) { + Operand op; + + memclrw(&op, sizeof(Operand)); + if (TYPE_IS_8BYTES(expr->rtype)) { + GEN_NODE(expr, &op); + coerce_to_register_pair(&op, expr->rtype, 0, 0); + selector_type = expr->rtype; + selector_gpr = op.reg; + selector_gprHi = op.regHi; + I8_treecompare(0, nranges_minus1); + } else { + GEN_NODE(expr, &op); + if (expr->rtype->size < 4) + extend32(&op, expr->rtype, 0); + ENSURE_GPR(&op, expr->rtype, 0); + selector_type = expr->rtype; + selector_gpr = op.reg; + treecompare(0, nranges_minus1); + } +} + +static Object *create_switch_table(void) { + Object *obj; + ObjectList *list; + UInt32 *outptr; + CaseRange *currange; + SInt32 size; + CInt64 value; + + obj = galloc(sizeof(Object)); + list = galloc(sizeof(ObjectList)); + memclrw(obj, sizeof(Object)); + memclrw(list, sizeof(ObjectList)); + + obj->otype = OT_OBJECT; + obj->access = ACCESSPUBLIC; + obj->datatype = DDATA; + obj->name = CParser_GetUniqueName(); + obj->toc = NULL; + obj->sclass = TK_STATIC; + obj->qual = Q_CONST; + obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED; + obj->u.data.linkname = obj->name; + obj->type = NULL; + createIndirect(obj, 0, 0); + obj->type = TYPE(&void_ptr); + + size = CInt64_GetULong(&range) + 1; + obj->u.data.u.switchtable.size = size; + obj->u.data.u.switchtable.data = lalloc(4 * size); + + currange = caseranges; + outptr = (UInt32 *) obj->u.data.u.switchtable.data; + value = cint64_zero; + while (CInt64_LessEqual(value, range)) { + while (CInt64_Greater(CInt64_Add(first, value), CInt64_Add(currange->min, currange->range))) + currange++; + *outptr = CTool_CreateIndexFromPointer(currange->label); + value = CInt64_Add(value, cint64_one); + outptr++; + } + + list->object = obj; + list->next = switchtables; + switchtables = list; + return list->object; +} + +static void generate_table(ENode *expr, SwitchInfo *info) { + Object *table; + SwitchCase *curcase; + short reg; + short reg2; + short reg3; + Operand op1; + Operand op2; + + CInt64 val3 = {0, 3}; + memclrw(&op1, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + + if (CInt64_Greater(first, cint64_zero) && CInt64_Less(first, val3)) { + range = CInt64_Add(range, first); + first = cint64_zero; + } + + table = create_switch_table(); + CError_ASSERT(553, !TYPE_IS_8BYTES(expr->rtype)); + + GEN_NODE(expr, &op1); + if (expr->rtype->size < 4) + extend32(&op1, expr->rtype, 0); + ENSURE_GPR(&op1, expr->rtype, 0); + + reg = op1.reg; + if (CInt64_NotEqual(first, cint64_zero)) { + SInt32 value; + reg = ALLOC_GPR(); + value = -CInt64_GetULong(&first); + if (!FITS_IN_SHORT(value)) { + emitpcode(PC_ADDIS, reg, op1.reg, 0, HIGH_PART(value)); + if (value) + emitpcode(PC_ADDI, reg, reg, 0, LOW_PART(value)); + } else { + emitpcode(PC_ADDI, reg, op1.reg, 0, value); + } + } + + if (!FITS_IN_SHORT(CInt64_GetULong(&range))) { + short tmp = ALLOC_GPR(); + load_immediate(tmp, CInt64_GetULong(&range)); + emitpcode(PC_CMPL, 0, reg, tmp); + } else { + emitpcode(PC_CMPLI, 0, reg, CInt64_GetULong(&range)); + } + + branch_conditional(0, EGREATER, 1, defaultlabel); + if (table->toc) { + op2.optype = OpndType_Symbol; + op2.object = table->toc; + indirect(&op2, NULL); + } else { + op2.optype = OpndType_Symbol; + op2.object = table; + } + + if (op2.optype != OpndType_GPR) { + Coerce_to_register(&op2, TYPE(&void_ptr), reg2 = ALLOC_GPR()); + } + + if (op2.optype != OpndType_GPR) { + CError_FATAL(599); + } else { + if (op2.reg != reg2) + emitpcode(PC_MR, reg2, op2.reg); + } + + if (CInt64_Equal(first, cint64_zero)) { + reg = ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, op1.reg, 2, 0, 29); + } else { + emitpcode(PC_RLWINM, reg, reg, 2, 0, 29); + } + + reg3 = reg2; + emitpcode(PC_LWZX, reg3, reg3, reg); + for (curcase = info->cases; curcase; curcase = curcase->next) + pcbranch(pclastblock, curcase->label->pclabel); + pcbranch(pclastblock, info->defaultlabel->pclabel); + emitpcode(PC_MTCTR, reg3); + branch_indirect(table); +} + +void switchstatement(ENode *expr, SwitchInfo *info) { + Boolean use_table; + SwitchCase *swcase; + + use_table = copts.switch_tables; + + ncases = 0; + for (swcase = info->cases; swcase; swcase = swcase->next) { + if (!swcase->label->pclabel) + swcase->label->pclabel = makepclabel(); + ncases++; + } + + CError_ASSERT(656, ncases >= 0 && ncases <= 0x3333332U); + + if (!info->defaultlabel->pclabel) + info->defaultlabel->pclabel = makepclabel(); + defaultlabel = info->defaultlabel->pclabel; + + build_case_ranges(expr->rtype, info->cases, info->defaultlabel); + + if (TYPE_IS_8BYTES(expr->rtype)) { + generate_tree(expr); + return; + } + + if (!use_table || nranges_minus1 < 8 || (nranges_minus1 * 2) < ((range.lo / 2) + 4)) + generate_tree(expr); + else + generate_table(expr, info); +} + +void dumpswitchtables(Object *funcobj) { + Object *table; + ObjectList *list; + SInt32 size; + UInt32 *array; + + for (list = switchtables; list; list = list->next) { + table = list->object; + CError_ASSERT(694, table->otype == OT_OBJECT && table->access == ACCESSPUBLIC && table->datatype == DDATA); + + size = table->u.data.u.switchtable.size; + array = (UInt32 *) table->u.data.u.switchtable.data; + while (size--) { + *array = CTool_EndianConvertWord32(((PCodeLabel *) CTool_ResolveIndexToPointer(*array))->block->codeOffset); + array++; + } + + ObjGen_DeclareSwitchTable(table, funcobj); + } +} diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c new file mode 100644 index 0000000..7af09e3 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c @@ -0,0 +1,2272 @@ +#include "cos.h" +#include "compiler/TOC.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInit.h" +#include "compiler/CInt64.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/InstrSelection.h" +#include "compiler/Intrinsics.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/Operands.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/PPCError.h" +#include "compiler/RegisterInfo.h" +#include "compiler/StackFrame.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +ObjectList *toclist; +ObjectList *exceptionlist; +void *descriptorlist; +PoolEntry *floatconstpool; +PoolEntry *doubleconstpool; +ObjectList *floatconstlist; +PoolEntry *vectorconstpool; +ObjectList *vectorconstlist; +Object toc0; +Boolean no_descriptors; +Object pic_base; +VarInfo pic_base_varinfo; +short pic_base_reg; +CodeLabelList *codelabellist; + +UInt8 lvslBytes[16][16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, + 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E +}; + +UInt8 lvsrBytes[16][16] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, + 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, + 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 +}; + +// forward decls +static void estimate_func_param_size(ENode *node); + +static int disables_optimizer(ENode *node) { + ENode *funcref = node->data.funccall.funcref; + if (ENODE_IS(funcref, EOBJREF)) { + if (!strcmp(CMangler_GetLinkName(funcref->data.objref)->name, "___setjmp")) + return 1; + if (!strcmp(CMangler_GetLinkName(funcref->data.objref)->name, "___vec_setjmp")) + return 1; + } + return 0; +} + +void setupaddressing(void) { + floatconstlist = NULL; + descriptorlist = NULL; + toclist = NULL; + exceptionlist = NULL; + vectorconstlist = NULL; + vectorconstpool = NULL; + floatconstpool = NULL; + doubleconstpool = NULL; + + no_descriptors = 1; + memclrw(&toc0, sizeof(toc0)); + + pic_base_reg = 0; + memclrw(&pic_base, sizeof(pic_base)); + memclrw(&pic_base_varinfo, sizeof(pic_base_varinfo)); + pic_base.otype = OT_OBJECT; + pic_base.type = (Type *) &void_ptr; + pic_base.datatype = DNONLAZYPTR; + pic_base.u.toc.info = &pic_base_varinfo; +} + +void createNonLazyPointer(Object *obj) { + Object *toc; + ObjectList *list; + + toc = galloc(sizeof(Object)); + obj->toc = toc; + memclrw(toc, sizeof(Object)); + + toc->otype = OT_OBJECT; + toc->name = CParser_GetUniqueName(); + toc->toc = NULL; + toc->section = SECT_NONLAZY_PTRS; + toc->u.toc.info = CodeGen_GetNewVarInfo(); + toc->sclass = TK_STATIC; + toc->qual = Q_CONST; + toc->datatype = DNONLAZYPTR; + toc->flags |= OBJECT_FLAGS_2; + toc->type = CDecl_NewPointerType(obj->type); + toc->u.toc.over_load = obj; + toc->u.toc.linkname = CMangler_GetLinkName(obj); + + list = galloc(sizeof(ObjectList)); + memclrw(list, sizeof(ObjectList)); + list->object = toc; + list->next = toclist; + toclist = list; +} + +void referenceIndirectPointer(Object *obj) { + VarInfo *vi = obj->toc->u.toc.info; + vi->used = 1; + vi->usage += copts.optimizesize ? 1 : curstmtvalue; +} + +Object *createIndirect(Object *obj, Boolean flag1, Boolean flag2) { + CError_ASSERT(622, !copts.no_common || (obj->section != SECT_COMMON_VARS) || (obj->qual & Q_20000)); + + if (CParser_HasInternalLinkage(obj)) + return NULL; + if (ObjGen_IsExported(obj)) + return NULL; + + if (!copts.no_common && obj->datatype == DDATA && obj->section == SECT_DEFAULT && (obj->qual & Q_1000000)) + obj->section = SECT_COMMON_VARS; + + if (copts.codegen_dynamic && (!copts.no_common || !(obj->qual & Q_1000000))) { + if (!obj->toc) + createNonLazyPointer(obj); + else if (flag1) + obj->toc->u.toc.info = CodeGen_GetNewVarInfo(); + + if (flag2) + referenceIndirectPointer(obj); + + return obj->toc; + } else { + return NULL; + } +} + +Object *createfloatconstant(Type *type, Float *data) { + ObjectList *list; + Object *obj; + UInt32 *check; + + for (list = floatconstlist; list; list = list->next) { + obj = list->object; + check = (UInt32 *) obj->u.data.u.floatconst; + if (obj->type == type && check[0] == ((UInt32 *) data)[0] && check[1] == ((UInt32 *) data)[1]) + return obj; + } + + obj = galloc(sizeof(Object)); + memclrw(obj, sizeof(Object)); + obj->otype = OT_OBJECT; + obj->type = type; + obj->name = CParser_GetUniqueName(); + obj->toc = NULL; + obj->u.data.info = NULL; + obj->u.data.linkname = obj->name; + obj->sclass = TK_STATIC; + obj->qual = Q_CONST | Q_INLINE_DATA; + obj->datatype = DDATA; + if (type->size == 8) + obj->section = SECT_8BYTE_LITERALS; + else if (type->size == 4) + obj->section = SECT_4BYTE_LITERALS; + else + CError_FATAL(807); + + obj->flags |= OBJECT_FLAGS_2; + + obj->u.data.u.floatconst = galloc(sizeof(Float)); + *obj->u.data.u.floatconst = *data; + + list = galloc(sizeof(ObjectList)); + memclrw(list, sizeof(ObjectList)); + list->object = obj; + list->next = floatconstlist; + floatconstlist = list; + + ObjGen_DeclareFloatConst(obj); + return obj; +} + +Object *createvectorconstant(Type *type, MWVector128 *data) { + ObjectList *list; + Object *obj; + MWVector128 *check; + + for (list = vectorconstlist; list; list = list->next) { + obj = list->object; + check = obj->u.data.u.vector128const; + if (check->ul[0] == data->ul[0] && check->ul[1] == data->ul[1] && check->ul[2] == data->ul[2] && check->ul[3] == data->ul[3]) + return obj; + } + + obj = galloc(sizeof(Object)); + memclrw(obj, sizeof(Object)); + obj->otype = OT_OBJECT; + obj->type = type; + obj->name = CParser_GetUniqueName(); + obj->toc = NULL; + obj->u.data.info = NULL; + obj->u.data.linkname = obj->name; + obj->sclass = TK_STATIC; + obj->qual = Q_CONST | Q_INLINE_DATA; + obj->datatype = DDATA; + if (type->size == 16) + obj->section = SECT_16BYTE_LITERALS; + else + CError_FATAL(900); + + obj->flags |= OBJECT_FLAGS_2; + + obj->u.data.u.vector128const = galloc(sizeof(MWVector128)); + *obj->u.data.u.vector128const = *data; + + list = galloc(sizeof(ObjectList)); + memclrw(list, sizeof(ObjectList)); + list->object = obj; + list->next = vectorconstlist; + vectorconstlist = list; + + ObjGen_DeclareVectorConst(obj); + return obj; +} + +void DeclarePooledConstants(void) { + PoolEntry *entry; + char *buffer; + SInt32 fsize; + SInt32 dsize; + SInt32 vsize; + + fsize = 0; + for (entry = floatconstpool; entry; entry = entry->next) + fsize += 4; + + if (fsize) { + floatconstpool->object->type = CDecl_NewArrayType(TYPE(&stfloat), fsize); + buffer = galloc(fsize); + for (entry = floatconstpool; entry; entry = entry->next) + memcpy(buffer + entry->offset, entry->buffer, 4); + CInit_DeclareReadOnlyData(floatconstpool->object, buffer, NULL, fsize); + } + + dsize = 0; + for (entry = doubleconstpool; entry; entry = entry->next) + dsize += 8; + + if (dsize) { + doubleconstpool->object->type = CDecl_NewArrayType(TYPE(&stdouble), dsize); + buffer = galloc(dsize); + for (entry = doubleconstpool; entry; entry = entry->next) + memcpy(buffer + entry->offset, entry->buffer, 8); + CInit_DeclareReadOnlyData(doubleconstpool->object, buffer, NULL, dsize); + } + + vsize = 0; + for (entry = vectorconstpool; entry; entry = entry->next) + vsize += 16; + + if (vsize) { + vectorconstpool->object->type = CDecl_NewArrayType(TYPE(&stvectorsignedlong), vsize); + buffer = galloc(vsize); + for (entry = vectorconstpool; entry; entry = entry->next) + memcpy(buffer + entry->offset, entry->buffer, 16); + CInit_DeclareReadOnlyData(vectorconstpool->object, buffer, NULL, vsize); + } +} + +static Object *CreatePooledFloatConst(Type *type, Float *data, SInt32 *pOffset) { + if (type->size == 8u) { + PoolEntry *entry; + void *buffer; + Object *object; + SInt32 offset; + + buffer = galloc(8u); + CMach_InitFloatMem(type, *data, buffer); + if (cparamblkptr->precompile == 1) + CError_Error(CErrorStr180); + + for (entry = doubleconstpool; entry; entry = entry->next) { + if (!memcmp(entry->buffer, buffer, 8u)) + break; + } + + if (!entry) { + if (doubleconstpool) { + object = doubleconstpool->object; + offset = doubleconstpool->offset + 8u; + doubleconstpool->object->type->size += 8u; + } else { + DeclInfo di; + memclrw(&di, sizeof(di)); + di.thetype = CDecl_NewArrayType(TYPE(&stdouble), 8u); + di.name = GetHashNameNodeExport("@doubleBase0"); + di.qual = Q_CONST; + di.storageclass = TK_STATIC; + di.is_extern_c = 1; + di.section = SECT_CONST; + object = CParser_NewGlobalDataObject(&di); + object->nspace = cscope_root; + offset = 0; + } + + entry = galloc(sizeof(PoolEntry)); + entry->next = doubleconstpool; + doubleconstpool = entry; + entry->object = object; + entry->offset = offset; + entry->buffer = galloc(8u); + memcpy(entry->buffer, buffer, 8u); + } + + *pOffset = entry->offset; + return entry->object; + } + + if (type->size == 4u) { + PoolEntry *entry; + void *buffer; + Object *object; + SInt32 offset; + + buffer = galloc(4u); + CMach_InitFloatMem(type, *data, buffer); + if (cparamblkptr->precompile == 1) + CError_Error(CErrorStr180); + + for (entry = floatconstpool; entry; entry = entry->next) { + if (!memcmp(entry->buffer, buffer, 4u)) + break; + } + + if (!entry) { + if (floatconstpool) { + object = floatconstpool->object; + offset = floatconstpool->offset + 4u; + object->type->size += 4u; + } else { + DeclInfo di; + memclrw(&di, sizeof(di)); + di.thetype = CDecl_NewArrayType(TYPE(&stfloat), 4u); + di.name = GetHashNameNodeExport("@floatBase0"); + di.qual = Q_CONST; + di.storageclass = TK_STATIC; + di.is_extern_c = 1; + di.section = SECT_CONST; + object = CParser_NewGlobalDataObject(&di); + object->nspace = cscope_root; + offset = 0; + } + + entry = galloc(sizeof(PoolEntry)); + entry->next = floatconstpool; + floatconstpool = entry; + entry->object = object; + entry->offset = offset; + entry->buffer = galloc(4u); + memcpy(entry->buffer, buffer, 4u); + } + + *pOffset = entry->offset; + return entry->object; + } + + CError_FATAL(1183); + return NULL; +} + +Object *CreateFloatConst(Type *type, Float *data, SInt32 *pOffset) { + *pOffset = 0; + return createfloatconstant(type, data); +} + +static void RewriteFloatConst(ENode *expr) { + Object *obj; + SInt32 n; + ENode *subexpr; + + obj = CreateFloatConst(expr->rtype, &expr->data.floatval, &n); + if (n) { + subexpr = makediadicnode(create_objectrefnode(obj), intconstnode(TYPE(&stunsignedlong), n), EADD); + } else { + subexpr = create_objectrefnode(obj); + } + + expr->type = EINDIRECT; + expr->cost = 1; + expr->flags |= Q_CONST; + expr->data.monadic = subexpr; +} + +static void RewriteVectorConst(ENode *expr) { + PoolEntry *entry; + Object *object; + SInt32 offset; + ENode *inner; + UInt8 data[16]; + + CMach_InitVectorMem(expr->rtype, expr->data.vector128val, data, 1); + + if (cparamblkptr->precompile == 1) + CError_Error(CErrorStr180); + + for (entry = vectorconstpool; entry; entry = entry->next) { + if (!memcmp(entry->buffer, data, 16)) + break; + } + + if (!entry) { + if (vectorconstpool) { + object = vectorconstpool->object; + offset = vectorconstpool->offset + 16; + vectorconstpool->object->type->size += 16; + } else { + DeclInfo di; + memclrw(&di, sizeof(di)); + di.thetype = CDecl_NewArrayType(TYPE(&stvectorsignedlong), 16); + di.name = GetHashNameNodeExport("@vectorBase0"); + di.qual = Q_CONST; + di.storageclass = TK_STATIC; + di.is_extern_c = 1; + di.section = SECT_CONST; + object = CParser_NewGlobalDataObject(&di); + object->nspace = cscope_root; + offset = 0; + } + + entry = galloc(sizeof(PoolEntry)); + entry->next = vectorconstpool; + vectorconstpool = entry; + entry->object = object; + entry->offset = offset; + entry->buffer = galloc(16); + memcpy(entry->buffer, data, 16); + } + + if (entry->offset) { + inner = makediadicnode( + create_objectrefnode(entry->object), + intconstnode(TYPE(&stunsignedlong), entry->offset), + EADD); + } else { + inner = create_objectrefnode(entry->object); + } + + expr->type = EINDIRECT; + expr->cost = 1; + expr->flags |= ENODE_FLAG_CONST; + expr->data.monadic = inner; +} + +static Object *createcodelabel(CLabel *label) { + CodeLabelList *list; + Object *obj; + + for (list = codelabellist; list; list = list->next) { + if (list->label == label) + return list->object; + } + + obj = galloc(sizeof(Object)); + memclrw(obj, sizeof(Object)); + obj->otype = OT_OBJECT; + obj->type = (Type *) &void_ptr; + obj->name = label->uniquename; + obj->toc = NULL; + obj->u.data.info = NULL; // not sure if this is the right union! + obj->sclass = TK_STATIC; + obj->qual = Q_CONST; + obj->datatype = DDATA; + obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED; + + list = galloc(sizeof(CodeLabelList)); + memclrw(list, sizeof(CodeLabelList)); + list->object = obj; + list->label = label; + list->next = codelabellist; + codelabellist = list; + + return obj; +} + +void dumpcodelabels(Object *func) { + CodeLabelList *list; + + for (list = codelabellist; list; list = list->next) + ObjGen_DeclareCodeLabel(list->object, list->label->pclabel->block->codeOffset, func); +} + +static void referenceexception(Object *obj) { + ObjectList *list; + + if (obj && obj->otype == OT_OBJECT && obj->datatype == DLOCAL) { + for (list = exceptionlist; list; list = list->next) { + if (list->object == obj) + return; + } + + list = lalloc(sizeof(ObjectList)); + memclrw(list, sizeof(ObjectList)); + list->object = obj; + list->next = exceptionlist; + exceptionlist = list; + } +} + +static ENodeType invert_relop(ENodeType nodetype) { + switch (nodetype) { + 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 nodetype; + } +} + +static ENode *COND_to_COMPARE(ENode *cond, ENode *expr1, ENode *expr2) { + SInt32 val1; + SInt32 val2; + SInt32 condval; + ENodeType invop; + + while (expr1->type == ETYPCON && TYPE_FITS_IN_REGISTER(expr1->rtype)) + expr1 = expr1->data.monadic; + while (expr2->type == ETYPCON && TYPE_FITS_IN_REGISTER(expr2->rtype)) + expr2 = expr2->data.monadic; + + if (expr1->type != EINTCONST || !TYPE_FITS_IN_REGISTER(expr1->rtype) || !CInt64_IsInRange(expr1->data.intval, 4)) + return NULL; + if (expr2->type != EINTCONST || !TYPE_FITS_IN_REGISTER(expr2->rtype) || !CInt64_IsInRange(expr2->data.intval, 4)) + return NULL; + + val1 = expr1->data.intval.lo; + val2 = expr2->data.intval.lo; + condval = 0; + switch (val1) { + case 1: + if (val2 != 0) + return NULL; + break; + case 0: + condval = 1; + if (val2 != 1) + return NULL; + break; + default: + return NULL; + } + + while (cond->type == ELOGNOT) { + condval = (condval + 1) & 1; + cond = cond->data.monadic; + } + + if (condval) { + invop = invert_relop(cond->type); + if (invop == cond->type) + return NULL; + cond->type = invop; + } + + return cond; +} + +static ENode *comparewithzero(ENode *expr) { + ENode *expr1; + ENode *expr2; + ENode *tmp; + + expr1 = lalloc(sizeof(ENode)); + memclrw(expr1, sizeof(ENode)); + expr2 = lalloc(sizeof(ENode)); + memclrw(expr2, sizeof(ENode)); + + while (expr->type == EFORCELOAD || expr->type == ETYPCON || expr->type == ECOMMA) { + if (!TYPE_FITS_IN_REGISTER(expr->rtype)) + break; + if (expr->type == ECOMMA) { + expr->data.diadic.right = comparewithzero(expr->data.diadic.right); + return expr; + } + expr = expr->data.monadic; + } + + if (expr->type == ECOND && TYPE_FITS_IN_REGISTER(expr->rtype)) { + tmp = COND_to_COMPARE(expr->data.cond.cond, expr->data.cond.expr1, expr->data.cond.expr2); + if (tmp) + expr = tmp; + } + + if (expr->type >= ELESS && expr->type <= ENOTEQU) + return expr; + + if (IS_TYPE_FLOAT(expr->rtype)) { + static Float float0 = {0.0}; + + expr2->type = EFLOATCONST; + expr2->cost = 0; + expr2->rtype = (expr->rtype->size == 4) ? (Type *) &stfloat : (Type *) &stdouble; + expr2->data.floatval = float0; + } else { + expr2->type = EINTCONST; + expr2->cost = 0; + if (TYPE_IS_8BYTES(expr->rtype)) + expr2->rtype = (Type *) &stsignedlonglong; + else + expr2->rtype = (Type *) &stsignedint; + expr2->data.intval.lo = 0; + expr2->data.intval.hi = 0; + } + + expr1->type = ENOTEQU; + expr1->cost = expr->cost; + expr1->rtype = (Type *) &stsignedint; + expr1->data.diadic.left = expr; + expr1->data.diadic.right = expr2; + return expr1; +} + +static void rewritefunctioncallreturningstruct(ENode *expr) { + ENode *ret_expr; + ENode *copy; + + ret_expr = expr->data.funccall.args->node; + + copy = lalloc(sizeof(ENode)); + memclrw(copy, sizeof(ENode)); + + *copy = *expr; + expr->type = ECOMMA; + expr->data.diadic.left = copy; + expr->data.diadic.right = ret_expr; +} + +static void rewritestrcpy(ENode *expr) { + ENode *int_expr; + ENodeList *list; + + int_expr = lalloc(sizeof(ENode)); + memclrw(int_expr, sizeof(ENode)); + int_expr->type = EINTCONST; + int_expr->cost = 0; + int_expr->flags = 0; + int_expr->rtype = (Type *) &stunsignedlong; + CInt64_SetLong(&int_expr->data.intval, expr->data.funccall.args->next->node->data.string.size); + + list = lalloc(sizeof(ENodeList)); + memclrw(list, sizeof(ENodeList)); + list->next = NULL; + list->node = int_expr; + expr->data.funccall.args->next->next = list; + expr->data.funccall.funcref->data.objref = __memcpy_object; +} + +static SInt32 magnitude(Type *type) { + if (IS_TYPE_FLOAT(type)) + return type->size * 4; + else if (is_unsigned(type)) + return (type->size * 2) + 1; + else + return type->size * 2; +} + +static Type *promote_type(Type *type) { + if (IS_TYPE_ENUM(type)) + type = TYPE_ENUM(type)->enumtype; + if (TYPE_INTEGRAL(type)->integral > stsignedint.integral) + return type; + else + return (Type *) &stsignedint; +} + +static Type *common_type(Type *type1, Type *type2) { + Type *tmp; + + if (IS_TYPE_FLOAT(type1) || IS_TYPE_FLOAT(type2)) { + if (TYPE_INTEGRAL(type1)->integral > TYPE_INTEGRAL(type2)->integral) + return type1; + else + return type2; + } + + type1 = promote_type(type1); + type2 = promote_type(type2); + if (type1 != type2) { + if (TYPE_INTEGRAL(type1)->integral < TYPE_INTEGRAL(type2)->integral) { + tmp = type1; + type1 = type2; + type2 = tmp; + } + + if (type1->size == type2->size && !is_unsigned(type1) && is_unsigned(type2)) { + if (type1 == (Type *) &stsignedlong) { + type1 = (Type *) &stunsignedlong; + } else { + CError_ASSERT(1789, type1 == (Type *) &stsignedlonglong); + type1 = (Type *) &stunsignedlonglong; + } + } + } + + return type1; +} + +static void rewrite_opassign(ENode *expr, ENodeType exprtype) { + ENode *left_sub; + ENode *right; + Type *left_type; + Type *right_type; + ENode *new_expr; + ENode *tmp; + Type *commontype; + Type *promo_left; + Type *promo_right; + + left_sub = expr->data.diadic.left->data.monadic; + right = expr->data.diadic.right; + left_type = expr->data.diadic.left->rtype; + right_type = expr->data.diadic.right->rtype; + + new_expr = lalloc(sizeof(ENode)); + memclrw(new_expr, sizeof(ENode)); + new_expr->type = exprtype; + new_expr->rtype = left_type; + new_expr->data.diadic.left = expr->data.diadic.left; + new_expr->data.diadic.right = right; + + expr->type = EASS; + expr->data.diadic.left = left_sub; + expr->data.diadic.right = new_expr; + + if (left_sub->type != EOBJREF) { + ENode *define; + ENode *reuse; + + define = lalloc(sizeof(ENode)); + memclrw(define, sizeof(ENode)); + define->type = EDEFINE; + define->rtype = left_type; + + reuse = lalloc(sizeof(ENode)); + memclrw(reuse, sizeof(ENode)); + reuse->type = EREUSE; + reuse->rtype = left_type; + reuse->data.monadic = define; + + if (left_sub->type != EBITFIELD) { + define->data.monadic = expr->data.diadic.left; + expr->data.diadic.left = define; + new_expr->data.diadic.left->data.diadic.left = reuse; + } else { + ENode *copy; + define->data.monadic = left_sub->data.diadic.left; + left_sub->data.diadic.left = define; + + copy = lalloc(sizeof(ENode)); + *copy = *left_sub; + copy->data.diadic.left = reuse; + new_expr->data.diadic.left->data.diadic.left = copy; + } + } + + switch (exprtype) { + case EADD: + case ESUB: + if (IS_TYPE_POINTER(left_type)) + break; + if (right->type == EINTCONST && TYPE_FITS_IN_REGISTER(left_type)) + break; + case EAND: + case EXOR: + case EOR: + if (left_type == right_type) + break; + case EMUL: + case EDIV: + case EMODULO: + commontype = common_type(left_type, right_type); + if (left_type != commontype) { + tmp = lalloc(sizeof(ENode)); + memclrw(tmp, sizeof(ENode)); + tmp->type = ETYPCON; + tmp->rtype = left_type; + tmp->data.monadic = expr->data.diadic.right; + expr->data.diadic.right = tmp; + + tmp = lalloc(sizeof(ENode)); + memclrw(tmp, sizeof(ENode)); + tmp->type = ETYPCON; + tmp->rtype = commontype; + tmp->data.monadic = new_expr->data.diadic.left; + new_expr->data.diadic.left = tmp; + } + if (right_type != commontype) { + tmp = lalloc(sizeof(ENode)); + memclrw(tmp, sizeof(ENode)); + tmp->type = ETYPCON; + tmp->rtype = commontype; + tmp->data.monadic = new_expr->data.diadic.right; + new_expr->data.diadic.right = tmp; + } + new_expr->rtype = commontype; + break; + + case ESHL: + case ESHR: + promo_left = promote_type(left_type); + promo_right = promote_type(right_type); + if (left_type != promo_left) { + tmp = lalloc(sizeof(ENode)); + memclrw(tmp, sizeof(ENode)); + tmp->type = ETYPCON; + tmp->rtype = left_type; + tmp->data.monadic = expr->data.diadic.right; + expr->data.diadic.right = tmp; + + tmp = lalloc(sizeof(ENode)); + memclrw(tmp, sizeof(ENode)); + tmp->type = ETYPCON; + tmp->rtype = promo_left; + tmp->data.monadic = new_expr->data.diadic.left; + new_expr->data.diadic.left = tmp; + } + if (right_type != promo_right) { + if (new_expr->data.diadic.right->type == EINTCONST && promo_right == (Type *) &stsignedint) { + new_expr->data.diadic.right->rtype = (Type *) &stsignedint; + } else { + tmp = lalloc(sizeof(ENode)); + memclrw(tmp, sizeof(ENode)); + tmp->type = ETYPCON; + tmp->rtype = promo_right; + tmp->data.monadic = new_expr->data.diadic.right; + new_expr->data.diadic.right = tmp; + } + } + new_expr->rtype = promo_left; + break; + } +} + +static void rewrite_preincdec(ENode *expr) { + ENode *subexpr; // r31 + Type *type; // r28 + ENode *new_expr; // r29 + + subexpr = expr->data.monadic; + type = expr->rtype; + + new_expr = lalloc(sizeof(ENode)); + memclrw(new_expr, sizeof(ENode)); + + if (IS_TYPE_FLOAT(type)) { + new_expr->type = EFLOATCONST; + new_expr->cost = 0; + new_expr->rtype = type; + new_expr->data.floatval = one_point_zero; + } else if (IS_TYPE_POINTER(type)) { + new_expr->type = EINTCONST; + new_expr->cost = 0; + new_expr->rtype = (Type *) &stunsignedlong; + new_expr->data.intval.hi = 0; + new_expr->data.intval.lo = TYPE_POINTER(type)->target->size; + } else { + new_expr->type = EINTCONST; + new_expr->cost = 0; + new_expr->rtype = type; + new_expr->data.intval.hi = 0; + new_expr->data.intval.lo = 1; + } + + expr->type = (expr->type == EPREDEC) ? ESUBASS : EADDASS; + expr->data.diadic.left = subexpr; + expr->data.diadic.right = new_expr; +} + +// Don't know what this would be called in the original, but weh +typedef union signed_vec { + SInt8 sc[16]; + SInt16 ss[8]; + SInt32 sl[4]; +} signed_vec; + +Boolean canoptimizevectorconst(MWVector128 *vecp, Type *type, COVCResult *result) { + // this function is very broken + signed_vec vec; + union { SInt32 lg; SInt8 ch[4]; } conv32; + union { SInt16 sh; SInt8 ch[2]; } conv16; + char flag; + SInt8 first8; + SInt16 first16; + SInt32 first32; + int i; + char ci; + UInt32 l0, l1, l2, l3; + + if (IS_TYPE_VECTOR(type)) { + vec = *((signed_vec *) vecp); + + first8 = vec.sc[0]; + flag = 1; + i = 1; + while (flag && i < 16) + flag = first8 == vec.sc[i++]; + /*flag = 1; + for (i = 1; flag && i < 16; i++) { + flag = first8 == vec.sc[i]; + }*/ + + if (flag && first8 < 16 && first8 > -17) { + if (result) { + result->op1 = PC_VSPLTISB; + result->op2 = -1; + result->arg = first8; + } + return 1; + } + + first16 = vec.ss[0]; + flag = 1; + for (i = 1; flag && i < 8; i++) { + flag = vec.ss[i] == first16; + } + + conv16.sh = first16; + if (flag && conv16.ch[0] == 0 && conv16.ch[1] < 16 && conv16.ch[1] >= 0) { + if (result) { + result->op1 = PC_VSPLTISH; + result->op2 = -1; + result->arg = conv16.ch[1]; + } + return 1; + } + + if (flag && conv16.ch[0] == -1 && (conv16.ch[1] & 0xF0) == 0xF0) { + if (result) { + result->op1 = PC_VSPLTISH; + result->op2 = -1; + result->arg = conv16.ch[1]; + } + return 1; + } + + first32 = vec.sl[0]; + flag = 1; + for (i = 1; flag && i < 4; i++) { + flag = vec.sl[i] == first32; + } + + conv32.lg = first32; + if (flag && conv32.ch[0] == 0 && conv32.ch[1] == 0 && conv32.ch[2] == 0 && conv32.ch[3] < 16 && conv32.ch[3] >= 0) { + if (result) { + result->op1 = PC_VSPLTISW; + result->op2 = -1; + result->arg = conv32.ch[3]; + } + return 1; + } + + if (flag && conv32.ch[0] == -1 && conv32.ch[1] == -1 && conv32.ch[2] == -1 && (conv32.ch[3] & 0xF0) == 0xF0) { + if (result) { + result->op1 = PC_VSPLTISW; + result->op2 = -1; + result->arg = conv32.ch[3]; + } + return 1; + } + + l0 = vec.sl[0]; + l1 = vec.sl[1]; + l2 = vec.sl[2]; + l3 = vec.sl[3]; + for (ci = 0; ci < 16; ci++) { + UInt32 *l; + UInt32 *r; + + l = (UInt32 *) lvslBytes[(char) ci]; + r = (UInt32 *) lvsrBytes[(char) ci]; + if (l0 == l[0] && l1 == l[1] && l2 == l[2] && l3 == l[3]) { + if (result) { + result->op1 = -1; + result->op2 = PC_LVSL; + result->arg = ci; + } + return 1; + } + if (l0 == r[0] && l1 == r[1] && l2 == r[2] && l3 == r[3]) { + if (result) { + result->op1 = -1; + result->op2 = PC_LVSR; + result->arg = ci; + } + return 1; + } + } + } + + return 0; +} + +static SInt32 countindirects(ENode *expr) { + SInt32 tmp1; + SInt32 tmp2; + + switch (expr->type) { + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EVECTOR128CONST: + return 0; + case ECOND: + if (expr->data.cond.cond->hascall || expr->data.cond.expr1->hascall || expr->data.cond.expr2->hascall) + return 2; + + if ((tmp1 = countindirects(expr->data.cond.cond)) >= 2) + return 2; + if ((tmp2 = countindirects(expr->data.cond.expr1)) >= 2) + return 2; + if (tmp2 > tmp1) + tmp1 = tmp2; + if ((tmp2 = countindirects(expr->data.cond.expr2)) >= 2) + return 2; + if (tmp2 > tmp1) + tmp1 = tmp2; + return tmp1; + case EFUNCCALL: + case EFUNCCALLP: + return 2; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + if ((tmp1 = countindirects(expr->data.diadic.left)) >= 2) + return 2; + if ((tmp2 = countindirects(expr->data.diadic.right)) >= 2) + return 2; + if (tmp2 > tmp1) + tmp1 = tmp2; + return tmp1; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + if (expr->type == EINDIRECT) + return countindirects(expr->data.monadic) + 1; + else + return countindirects(expr->data.monadic); + default: + return 2; + } +} + +static Boolean DetectCondSideAffect(ENode *expr) { + switch (expr->type) { + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case EAND: + case EXOR: + case EOR: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + if (DetectCondSideAffect(expr->data.diadic.left)) + return 1; + return DetectCondSideAffect(expr->data.diadic.right); + case EINDIRECT: + if (expr->data.monadic->type == EINDIRECT) + return 1; + if (expr->data.monadic->type == EOBJREF) { + if (expr->data.monadic->data.objref->datatype != DLOCAL && expr->data.monadic->data.objref->datatype != DDATA) + return 1; + if (IS_TYPE_POINTER(expr->data.monadic->data.objref->type)) + return 1; + return Registers_GetVarInfo(expr->data.monadic->data.objref)->noregister != 0; + } + return 1; + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + return DetectCondSideAffect(expr->data.monadic); + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EVECTOR128CONST: + return 0; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case ELAND: + case ELOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOND: + case EFUNCCALL: + case EFUNCCALLP: + case EMFPOINTER: + case ENULLCHECK: + case EPRECOMP: + case EDEFINE: + case EREUSE: + case EASSBLK: + case ECONDASS: + return 1; + default: + CError_FATAL(2523); + return 1; + } +} + +static UInt8 WeightandSumOps(ENode *expr) { + UInt32 score; + + switch (expr->type) { + case ECOND: + case ECONDASS: + score = WeightandSumOps(expr->data.cond.cond); + score += WeightandSumOps(expr->data.cond.expr1); + score += WeightandSumOps(expr->data.cond.expr2); + break; + case EMUL: + case EMULV: + case EMULASS: + score = WeightandSumOps(expr->data.diadic.left) + 10; + score += WeightandSumOps(expr->data.diadic.right); + break; + case EDIV: + case EMODULO: + case EDIVASS: + case EMODASS: + score = WeightandSumOps(expr->data.diadic.left) + 20; + score += WeightandSumOps(expr->data.diadic.right); + break; + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + score = WeightandSumOps(expr->data.diadic.left) + 1; + score += WeightandSumOps(expr->data.diadic.right); + break; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + score = WeightandSumOps(expr->data.monadic) + 1; + break; + case EINDIRECT: + if (expr->data.monadic->type == EOBJREF && expr->data.monadic->data.objref->datatype == DLOCAL) + if (!Registers_GetVarInfo(expr->data.monadic->data.objref)->noregister) + return 0; + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + score = WeightandSumOps(expr->data.monadic); + break; + case EOBJREF: + score = 0; + break; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EVECTOR128CONST: + score = 0; + break; + case EFUNCCALL: + case EFUNCCALLP: + score = 5; + break; + default: + score = 255; + } + + if (score >= 255) + score = 255; + return (UInt8) score; +} + +Boolean TOC_use_fsel(ENode *expr) { + ENode *left; + ENode *right; + Type *rtype; + int score1; + int score2; + + left = expr->data.cond.expr1; + right = expr->data.cond.expr2; + rtype = expr->rtype; + + if (!copts.peephole) return 0; + if (!copts.gen_fsel) return 0; + if (left->hascall) return 0; + if (right->hascall) return 0; + if (!IS_TYPE_FLOAT(rtype)) return 0; + if (!IS_TYPE_FLOAT(left->rtype)) return 0; + if (!IS_TYPE_FLOAT(right->rtype)) return 0; + + if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU) + return 0; + if (!IS_TYPE_FLOAT(expr->data.cond.cond->data.diadic.right->rtype)) + return 0; + if (expr->data.cond.cond->type == ELOGNOT || expr->data.cond.cond->type == ELAND || expr->data.cond.cond->type == ELOR) + return 0; + + if (expr->type == ECONDASS) { + if (left->type != EINDIRECT) + return 0; + if (left->data.monadic->type != EOBJREF) + return 0; + } + + if (DetectCondSideAffect(left)) + return 0; + if (DetectCondSideAffect(right)) + return 0; + + if (expr->type == ECONDASS) + score1 = 1; + else + score1 = WeightandSumOps(left); + score2 = WeightandSumOps(right); + + if (score1 > copts.gen_fsel) + return 0; + else if (score2 > copts.gen_fsel) + return 0; + else + return 1; +} + +Boolean TOC_use_isel(ENode *expr, Boolean flag) { + int opt; + ENode *left; + ENode *right; + Type *rtype; + Object *obj; + int score1; + int score2; + + left = expr->data.cond.expr1; + right = expr->data.cond.expr2; + rtype = expr->rtype; + if (flag) + opt = 10; + else + opt = copts.gen_isel; + + if (!opt) return 0; + if (!copts.peephole) return 0; + if (left->hascall) return 0; + if (right->hascall) return 0; + if (!TYPE_FITS_IN_REGISTER(rtype)) return 0; + if (!TYPE_FITS_IN_REGISTER(left->rtype)) return 0; + if (!TYPE_FITS_IN_REGISTER(right->rtype)) return 0; + + if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU) + return 0; + if (TYPE_IS_8BYTES(rtype)) + return 0; + + if (flag) { + if (!TYPE_FITS_IN_REGISTER(expr->data.cond.cond->data.diadic.right->rtype)) + return 0; + if (TYPE_IS_8BYTES(expr->data.cond.cond->data.diadic.right->rtype)) + return 0; + } + + if (expr->type == ECONDASS) { + if (left->type != EINDIRECT) + return 0; + if (left->data.monadic->type != EOBJREF) + return 0; + if (flag) { + obj = left->data.monadic->data.objref; + if (obj->datatype != DLOCAL) + return 0; + if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) + return 0; + if (obj->u.var.info->rclass != RegClass_GPR) + return 0; + } + } + + if (DetectCondSideAffect(left)) + return 0; + if (DetectCondSideAffect(right)) + return 0; + + if (expr->type == ECONDASS) + score1 = 1; + else + score1 = WeightandSumOps(left); + score2 = WeightandSumOps(right); + + if (score1 > opt) + return 0; + else if (score2 > opt) + return 0; + else + return 1; +} + +SInt32 GetSizeSkip(ENode *expr) { + if (expr->type == EASS) + expr = expr->data.diadic.right; + if (expr->type == ETYPCON && expr->data.monadic->rtype->size < expr->rtype->size) + return expr->data.monadic->rtype->size; + else + return expr->rtype->size; +} + +void Optimize64bitMath(ENode *expr) { + ENode *left; // r23 + ENode *right; // r28 + SInt32 leftsize; // r24 + SInt32 rightsize; // r25 + SInt32 totalsize; // r22 + int unsignedflag; // r4 + + CError_ASSERT(2886, TYPE_IS_8BYTES(expr->rtype)); + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + leftsize = GetSizeSkip(left); + totalsize = (leftsize + (rightsize = GetSizeSkip(right))); + unsignedflag = is_unsigned(expr->rtype) != 0; + + switch (totalsize) { + case 2: + case 3: + case 4: + if (unsignedflag) { + left->rtype = (Type *) &stunsignedint; + right->rtype = (Type *) &stunsignedint; + } else { + left->rtype = (Type *) &stsignedint; + right->rtype = (Type *) &stsignedint; + } + break; + case 5: + case 6: + case 8: + case 9: + case 10: + case 12: + if (expr->type != ESUB || leftsize >= rightsize) { + if (leftsize < 4) { + if (unsignedflag) + left->rtype = (Type *) &stunsignedint; + else + left->rtype = (Type *) &stsignedint; + } else { + if (left->type == ETYPCON && left->data.monadic->rtype != (Type *) &stfloat) + expr->data.diadic.left = left->data.monadic; + } + if (rightsize < 4) { + if (unsignedflag) + right->rtype = (Type *) &stunsignedint; + else + right->rtype = (Type *) &stsignedint; + } else { + if (right->type == ETYPCON && right->data.monadic->rtype != (Type *) &stfloat) + expr->data.diadic.right = right->data.monadic; + } + } + break; + case 16: + break; + default: + CError_FATAL(2975); + } +} + +static Boolean OptimizeNestedAssginments(ENode **pexpr, Object *check) { + ENode *expr; + Boolean success1; + Boolean success2; + + expr = *pexpr; + switch (expr->type) { + case EOBJREF: + return check != expr->data.objref; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + switch (expr->type) { + case EASS: + if (ENODE_IS(expr->data.diadic.left, EOBJREF) && expr->data.diadic.left->data.objref == check) { + *pexpr = expr->data.diadic.right; + return OptimizeNestedAssginments(pexpr, check); + } + break; + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + CError_FATAL(3033); + return 0; + } + if (OptimizeNestedAssginments(&expr->data.diadic.right, check)) + return OptimizeNestedAssginments(&expr->data.diadic.left, check); + else + return 0; + break; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + return OptimizeNestedAssginments(&expr->data.monadic, check); + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EVECTOR128CONST: + return 1; + case ECOND: + success2 = OptimizeNestedAssginments(&expr->data.cond.expr2, check); + success1 = OptimizeNestedAssginments(&expr->data.cond.expr1, check); + if (!success2 || !success1) + return 0; + return OptimizeNestedAssginments(&expr->data.cond.cond, check) == 0; + case ECONDASS: + if (!OptimizeNestedAssginments(&expr->data.cond.expr2, check)) + return 0; + if (OptimizeNestedAssginments(&expr->data.cond.cond, check)) + return OptimizeNestedAssginments(&expr->data.cond.expr1, check) == 0; + else + return 0; + case EFUNCCALL: + case EFUNCCALLP: + case EMFPOINTER: + case ENULLCHECK: + case EPRECOMP: + case EDEFINE: + case EREUSE: + case EASSBLK: + return 0; + default: + CError_FATAL(3083); + return 0; + } +} + +static void expandTOCexpression(ENode *expr, Type *type, int ignored) { + Object *obj; + Object *tmpobj; + ENode *cond; + ENode *tmpexpr; + ENode *newexpr; + ENodeList *list; + + expr->ignored = ignored; + switch (expr->type) { + case EINTCONST: + expr->hascall = 0; + break; + case EFLOATCONST: + uses_globals = 1; + RewriteFloatConst(expr); + expandTOCexpression(expr, NULL, 0); + break; + case EVECTOR128CONST: + if (!canoptimizevectorconst(&expr->data.vector128val, expr->rtype, NULL)) { + uses_globals = 1; + RewriteVectorConst(expr); + expandTOCexpression(expr, NULL, 0); + } + break; + case ESTRINGCONST: + uses_globals = 1; + CInit_RewriteString(expr, 1); + expandTOCexpression(expr, NULL, 0); + break; + case EOBJREF: + obj = expr->data.objref; + CError_ASSERT(3203, obj->datatype != DALIAS); + if (obj->datatype == DFUNC || obj->datatype == DVFUNC) + uses_globals = 1; + if (obj->datatype == DDATA) { + uses_globals = 1; + if (createIndirect(obj, 0, 1)) { + tmpexpr = lalloc(sizeof(ENode)); + memclrw(tmpexpr, sizeof(ENode)); + tmpexpr->type = EOBJREF; + tmpexpr->cost = 0; + tmpexpr->data.objref = obj->toc; + tmpexpr->rtype = CDecl_NewPointerType(expr->rtype); + + expr->type = EINDIRECT; + expr->cost = 1; + expr->data.monadic = tmpexpr; + } + } + expr->hascall = 0; + break; + case ECONDASS: + expr->ignored = 0; + case ECOND: + if (!ENODE_IS_RANGE(expr->data.cond.cond, ELESS, ENOTEQU)) + expr->data.cond.cond = comparewithzero(expr->data.cond.cond); + expandTOCexpression(expr->data.cond.expr1, NULL, ignored); + expandTOCexpression(expr->data.cond.expr2, NULL, ignored); + if (TOC_use_fsel(expr)) { + cond = expr->data.cond.cond; + if (ENODE_IS(cond->data.diadic.right, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.right->data.floatval)) { + expandTOCexpression(cond->data.diadic.left, NULL, 0); + } else if (ENODE_IS(cond->data.diadic.left, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.left->data.floatval)) { + expandTOCexpression(cond->data.diadic.right, NULL, 0); + } else { + expandTOCexpression(expr->data.cond.cond, NULL, 0); + } + } else { + expandTOCexpression(expr->data.cond.cond, NULL, 0); + } + expr->hascall = expr->data.cond.cond->hascall | expr->data.cond.expr1->hascall | expr->data.cond.expr2->hascall; + break; + case EFUNCCALL: + case EFUNCCALLP: + if (is_intrinsic_function_call(expr)) { + expr->hascall = 0; + if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_008) { + if (copts.altivec_model) + update_frame_align(16); + dynamic_stack = 1; + requires_frame = 1; + } else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_035) { + if (expr->data.funccall.args->next->node->type == ESTRINGCONST) { + rewritestrcpy(expr); + } else { + requires_frame = 1; + makes_call = 1; + expr->hascall = 1; + } + } else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_036) { + if (expr->data.funccall.args->next->next->node->type != EINTCONST) { + requires_frame = 1; + makes_call = 1; + expr->hascall = 1; + } + } + } else { + requires_frame = 1; + makes_call = 1; + expr->hascall = 1; + } + + if (disables_optimizer(expr)) { + disable_optimizer |= 1; + if (copts.disable_registers) + disable_optimizer |= 2; + } + + if (ENODE_IS(expr->data.funccall.funcref, EINDIRECT) && IS_TYPE_FUNC(expr->data.funccall.funcref->rtype)) + *expr->data.funccall.funcref = *expr->data.funccall.funcref->data.monadic; + + if (ENODE_IS(expr->data.funccall.funcref, EOBJREF)) { + expr->data.funccall.funcref->hascall = 0; + if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC && (expr->data.funccall.funcref->flags & ENODE_FLAG_80)) { + tmpobj = galloc(sizeof(Object)); + *tmpobj = *expr->data.funccall.funcref->data.objref; + tmpobj->datatype = DFUNC; + expr->data.funccall.funcref->data.objref = tmpobj; + } + } else { + expandTOCexpression(expr->data.funccall.funcref, NULL, 0); + } + + for (list = expr->data.funccall.args; list; list = list->next) + expandTOCexpression(list->node, NULL, 0); + + if (expr->hascall) + estimate_func_param_size(expr); + + if (is_intrinsic_function_call(expr)) { + for (list = expr->data.funccall.args; list; list = list->next) + expr->hascall |= list->node->hascall; + } + + if (CMach_PassResultInHiddenArg(TYPE_FUNC(expr->data.funccall.functype)->functype)) + rewritefunctioncallreturningstruct(expr); + + break; + case ECOMMA: + expandTOCexpression(expr->data.diadic.left, NULL, 1); + expandTOCexpression(expr->data.diadic.right, NULL, ignored); + expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; + break; + case ELAND: + case ELOR: + if (!ENODE_IS(expr->data.diadic.left, ELOGNOT) && !ENODE_IS2(expr->data.diadic.left, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.left, ELESS, ENOTEQU)) + expr->data.diadic.left = comparewithzero(expr->data.diadic.left); + if (!ENODE_IS(expr->data.diadic.right, ELOGNOT) && !ENODE_IS2(expr->data.diadic.right, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.right, ELESS, ENOTEQU)) + expr->data.diadic.right = comparewithzero(expr->data.diadic.right); + expandTOCexpression(expr->data.diadic.left, NULL, 0); + expandTOCexpression(expr->data.diadic.right, NULL, 0); + expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; + break; + case EDIVASS: + if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) + uses_globals = 1; + rewrite_opassign(expr, EDIV); + goto opassign_common; + case EMULASS: + if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) + uses_globals = 1; + rewrite_opassign(expr, EMUL); + goto opassign_common; + case EADDASS: + if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) + uses_globals = 1; + rewrite_opassign(expr, EADD); + goto opassign_common; + case ESUBASS: + if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) + uses_globals = 1; + rewrite_opassign(expr, ESUB); + goto opassign_common; + case EMODASS: + if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) + uses_globals = 1; + rewrite_opassign(expr, EMODULO); + goto opassign_common; + case ESHLASS: + rewrite_opassign(expr, ESHL); + goto opassign_common; + case ESHRASS: + rewrite_opassign(expr, ESHR); + goto opassign_common; + case EANDASS: + rewrite_opassign(expr, EAND); + goto opassign_common; + case EXORASS: + rewrite_opassign(expr, EXOR); + goto opassign_common; + case EORASS: + rewrite_opassign(expr, EOR); + goto opassign_common; + case EASS: + if (ENODE_IS(expr->data.diadic.left, EINDIRECT)) + expr->data.diadic.left = expr->data.diadic.left->data.monadic; + opassign_common: + expandTOCexpression(expr->data.diadic.left, NULL, 0); + expandTOCexpression(expr->data.diadic.right, NULL, 0); + expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; + break; + case EEQU: + case ENOTEQU: + if (ENODE_IS(expr->data.diadic.right, EINTCONST) && expr->data.diadic.right->data.intval.lo == 0 && expr->data.diadic.right->data.intval.hi == 0) { + for (tmpexpr = expr->data.diadic.left; ENODE_IS2(tmpexpr, EFORCELOAD, ETYPCON); tmpexpr = tmpexpr->data.monadic) { + if (!TYPE_FITS_IN_REGISTER(tmpexpr->rtype)) + break; + } + if (ENODE_IS(tmpexpr, ELOGNOT) && TYPE_FITS_IN_REGISTER(tmpexpr->data.monadic->rtype)) { + if (ENODE_IS(expr, EEQU)) + expr->type = ENOTEQU; + else + expr->type = EEQU; + expr->data.diadic.left = tmpexpr->data.monadic; + expandTOCexpression(expr, NULL, 0); + break; + } + if (ENODE_IS(tmpexpr, EEQU)) { + if (ENODE_IS(expr, EEQU)) + tmpexpr->type = ENOTEQU; + *expr = *tmpexpr; + expandTOCexpression(expr, NULL, 0); + break; + } + if (ENODE_IS(tmpexpr, ENOTEQU)) { + if (ENODE_IS(expr, EEQU)) + tmpexpr->type = EEQU; + *expr = *tmpexpr; + expandTOCexpression(expr, NULL, 0); + break; + } + if (ENODE_IS(tmpexpr, ECOND)) { + newexpr = COND_to_COMPARE(tmpexpr->data.cond.cond, tmpexpr->data.cond.expr1, tmpexpr->data.cond.expr2); + if (newexpr) { + *tmpexpr = *newexpr; + expandTOCexpression(expr, NULL, 0); + break; + } + } + } + case EDIV: + if (ENODE_IS(expr, EDIV) && ENODE_IS(expr->data.diadic.right, EFLOATCONST) && CMach_FloatIsPowerOf2(expr->data.diadic.right->data.floatval)) { + expr->type = EMUL; + expr->data.diadic.right->data.floatval = CMach_FloatReciprocal(expr->data.diadic.right->data.floatval); + } + case EMODULO: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + expandTOCexpression(expr->data.diadic.left, NULL, 0); + expandTOCexpression(expr->data.diadic.right, NULL, 0); + expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; + if (TYPE_IS_8BYTES(expr->rtype)) { + if (ENODE_IS2(expr, ESHL, ESHR) && !ENODE_IS(expr->data.diadic.right, EINTCONST)) { + expr->hascall = 1; + requires_frame = 1; + makes_call = 1; + } + if (ENODE_IS2(expr, EDIV, EMODULO)) { + if (ENODE_IS(expr->data.diadic.right, EINTCONST)) { + if (I8_log2n(((SInt64) expr->data.diadic.right->data.intval.hi << 32) + expr->data.diadic.right->data.intval.lo) <= 0) { + expr->hascall = 1; + requires_frame = 1; + makes_call = 1; + } + } else { + expr->hascall = 1; + requires_frame = 1; + makes_call = 1; + } + } + } + break; + case ESUB: + if (ENODE_IS(expr->data.diadic.right, EINTCONST)) { + expr->type = EADD; + expr->data.diadic.right->data.intval = CInt64_Neg(expr->data.diadic.right->data.intval); + } + case EMUL: + case EADD: + case EAND: + case EXOR: + case EOR: + expandTOCexpression(expr->data.diadic.left, type, 0); + expandTOCexpression(expr->data.diadic.right, type, 0); + expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; + if (ENODE_IS3(expr, EMUL, EADD, ESUB) && TYPE_IS_8BYTES(expr->rtype)) + Optimize64bitMath(expr); + if (type) { + if ( + ENODE_IS(expr->data.diadic.left, ETYPCON) && + IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->rtype) && + IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->data.monadic->rtype) && + expr->data.diadic.left->data.monadic->rtype->size >= type->size && + !TYPE_IS_8BYTES(expr->data.diadic.left->data.monadic->rtype) + ) + expr->data.diadic.left = expr->data.diadic.left->data.monadic; + + if ( + ENODE_IS(expr->data.diadic.right, ETYPCON) && + IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->rtype) && + IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->data.monadic->rtype) && + expr->data.diadic.right->data.monadic->rtype->size >= type->size && + !TYPE_IS_8BYTES(expr->data.diadic.right->data.monadic->rtype) + ) + expr->data.diadic.right = expr->data.diadic.right->data.monadic; + + expr->rtype = type; + } + break; + + case ETYPCON: + tmpexpr = expr->data.monadic; + if ((IS_TYPE_INT_OR_ENUM(expr->rtype) && expr->rtype->size < 4) && IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && !TYPE_IS_8BYTES(tmpexpr->rtype)) { + expandTOCexpression(tmpexpr, expr->rtype, 0); + } else { + expandTOCexpression(tmpexpr, NULL, expr->rtype->type == TYPEVOID); + } + + expr->hascall = tmpexpr->hascall; + if (IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype)) + uses_globals = 1; + + if ((TYPE_IS_8BYTES(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype)) || (TYPE_IS_8BYTES(expr->rtype) && IS_TYPE_FLOAT(tmpexpr->rtype))) { + uses_globals = 1; + expr->hascall = 1; + requires_frame = 1; + makes_call = 1; + } + + if (IS_TYPE_FLOAT(tmpexpr->rtype)) { + if (is_unsigned(expr->rtype) && expr->rtype->size == 4) { + expr->hascall = 1; + requires_frame = 1; + makes_call = 1; + } else { + uses_globals = 1; + } + } + + if (IS_TYPE_VECTOR(expr->rtype) && !IS_TYPE_VECTOR(tmpexpr->rtype)) + PPCError_Error(PPCErrorStr114); + break; + + case EPOSTINC: + if (!expr->ignored) { + if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype)) + uses_globals = 1; + expandTOCexpression(expr->data.monadic, NULL, 0); + expr->hascall = expr->data.monadic->hascall; + break; + } + expr->type = EPREINC; + case EPREINC: + rewrite_preincdec(expr); + rewrite_opassign(expr, EADD); + goto opassign_common; + + case EPOSTDEC: + if (!expr->ignored) { + if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype)) + uses_globals = 1; + expandTOCexpression(expr->data.monadic, NULL, 0); + expr->hascall = expr->data.monadic->hascall; + break; + } + expr->type = EPREDEC; + case EPREDEC: + rewrite_preincdec(expr); + rewrite_opassign(expr, ESUB); + goto opassign_common; + + case ELOGNOT: + if (!ENODE_IS(expr->data.monadic, ELOGNOT) && !ENODE_IS2(expr->data.monadic, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.monadic, ELESS, ENOTEQU)) + expr->data.monadic = comparewithzero(expr->data.monadic); + case EMONMIN: + case EBINNOT: + tmpexpr = expr->data.monadic; + expandTOCexpression(tmpexpr, type, 0); + expr->hascall = tmpexpr->hascall; + if (type && ENODE_IS(expr->data.monadic, ETYPCON)) { + if (IS_TYPE_INT_OR_ENUM(expr->data.monadic->rtype) && IS_TYPE_INT_OR_ENUM(expr->data.monadic->data.monadic->rtype)) { + if (expr->data.monadic->data.monadic->rtype->size >= type->size) { + expr->data.monadic = expr->data.monadic->data.monadic; + expr->rtype = type; + } + } + } + break; + + case EINDIRECT: + case EFORCELOAD: + case EBITFIELD: + tmpexpr = expr->data.monadic; + expandTOCexpression(tmpexpr, NULL, 0); + expr->hascall = tmpexpr->hascall; + break; + + case EDEFINE: + tmpexpr = expr->data.monadic; + expandTOCexpression(tmpexpr, NULL, 0); + expr->hascall = tmpexpr->hascall; + break; + + case EREUSE: + expr->hascall = expr->data.monadic->hascall; + break; + + case ENULLCHECK: + expandTOCexpression(expr->data.diadic.left, NULL, 0); + expandTOCexpression(expr->data.diadic.right, NULL, 0); + expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; + break; + + case EPRECOMP: + expr->hascall = 0; + break; + + case ELABEL: + obj = createcodelabel(expr->data.label); + newexpr = lalloc(sizeof(ENode)); + memclrw(newexpr, sizeof(ENode)); + newexpr->type = EOBJREF; + newexpr->cost = 0; + newexpr->data.objref = obj; + newexpr->rtype = CDecl_NewPointerType(obj->type); + + expr->type = EINDIRECT; + expr->cost = 1; + expr->data.monadic = newexpr; + expr->hascall = 0; + break; + } +} + +static void checkexceptionreferences(ExceptionAction *action) { + for (; action; action = action->prev) { + switch (action->type) { + case EAT_DESTROYLOCAL: + referenceexception(action->data.destroy_local.local); + break; + case EAT_DESTROYLOCALCOND: + referenceexception(action->data.destroy_local_cond.local); + referenceexception(action->data.destroy_local_cond.cond); + break; + case EAT_DESTROYLOCALOFFSET: + referenceexception(action->data.destroy_local_offset.local); + break; + case EAT_DESTROYLOCALPOINTER: + referenceexception(action->data.destroy_local_pointer.pointer); + break; + case EAT_DESTROYLOCALARRAY: + referenceexception(action->data.destroy_local_array.localarray); + break; + case EAT_DESTROYBASE: + referenceexception(action->data.destroy_member.objectptr); // wrong union? + break; + case EAT_DESTROYPARTIALARRAY: + referenceexception(action->data.destroy_partial_array.arraypointer); + referenceexception(action->data.destroy_partial_array.arraycounter); + referenceexception(action->data.destroy_partial_array.element_size); + break; + case EAT_DESTROYMEMBER: + referenceexception(action->data.destroy_member.objectptr); + break; + case EAT_DESTROYMEMBERCOND: + referenceexception(action->data.destroy_member_cond.objectptr); + referenceexception(action->data.destroy_member_cond.cond); + break; + case EAT_DESTROYMEMBERARRAY: + referenceexception(action->data.destroy_member_array.objectptr); + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + referenceexception(action->data.delete_pointer.pointerobject); + break; + case EAT_DELETEPOINTERCOND: + referenceexception(action->data.delete_pointer_cond.pointerobject); + referenceexception(action->data.delete_pointer_cond.cond); + break; + case EAT_CATCHBLOCK: + referenceexception(action->data.catch_block.catch_object); + referenceexception(action->data.catch_block.catch_info_object); + break; + case EAT_ACTIVECATCHBLOCK: + referenceexception(action->data.active_catch_block.catch_info_object); + break; + } + } +} + +void expandTOCreferences(Statement **stmts) { + Statement *stmt; + IAOperand *op; + int i; + InlineAsm *ia; + VarInfo *vi; + + codelabellist = NULL; + exceptionlist = NULL; + + for (stmt = *stmts; stmt; stmt = stmt->next) { + curstmtvalue = stmt->value; + if (stmt->flags & StmtFlag_1) { + has_catch_blocks = 1; + dynamic_stack = 1; + requires_frame = 1; + } + + switch (stmt->type) { + case ST_EXPRESSION: + expandTOCexpression(stmt->expr, NULL, 1); + if (stmt->expr->type == ETYPCON && IS_TYPE_VOID(stmt->expr->rtype)) + stmt->expr = stmt->expr->data.monadic; + break; + case ST_GOTOEXPR: + expandTOCexpression(stmt->expr, NULL, 0); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + if (stmt->expr->type < ELESS || stmt->expr->type > ENOTEQU) + stmt->expr = comparewithzero(stmt->expr); + expandTOCexpression(stmt->expr, NULL, 0); + break; + case ST_RETURN: + if (!stmt->expr) + continue; + expandTOCexpression( + stmt->expr, NULL, + IS_TYPE_ARRAY(stmt->expr->rtype) || IS_TYPE_NONVECTOR_STRUCT(stmt->expr->rtype) || IS_TYPE_CLASS(stmt->expr->rtype) || + IS_TYPE_12BYTES_MEMBERPOINTER(stmt->expr->rtype)); + break; + case ST_SWITCH: + uses_globals = 1; + expandTOCexpression(stmt->expr, NULL, 0); + break; + case ST_ENDCATCHDTOR: + requires_frame = 1; + makes_call = 1; + break; + case ST_ASM: + if ((ia = (InlineAsm *) stmt->expr)) { + if (ia->flags & IAFlag1) { + if (ia->opcode == IADirective_FrFree) + requires_frame = 1; + } else { + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_Reg) { + if (!op->u.reg.object) { + if (op->u.reg.num == INVALID_PIC_REG) + uses_globals = 1; + else if (op->u.reg.effect & EffectWrite) + asm_used_register(op->u.reg.rclass, op->u.reg.num); + } else if ((vi = Registers_GetVarInfo(op->u.reg.object))) { + vi->flags |= VarInfoFlag40; + } + } else if (op->type == IAOpnd_3) { + uses_globals = 1; + } + } + + if (ia->flags & IAFlag2) + makes_call = 1; + } + } + break; + } + + checkexceptionreferences(stmt->dobjstack); + } +} + +void resetTOCvarinfo(void) { + ObjectList *list; + + for (list = toclist; list; list = list->next) + list->object->u.toc.info = CodeGen_GetNewVarInfo(); +} + +Boolean needdescriptor(void) { + // completely unused, dunno what args this might take + return 0; +} + +Object *createstaticinitobject(void) { + char buf[100]; + char *p; + Str255 fname; + TypeFunc *tfunc; + Object *obj; + + COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, fname); + sprintf(buf, "__sinit_%*.*s", -fname[0], fname[0], &fname[1]); + for (p = &buf[1]; *p; p++) { + if (*p == '.') + *p = '_'; + } + + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->functype = &stvoid; + tfunc->args = NULL; + tfunc->flags = FUNC_DEFINED; + + obj = galloc(sizeof(Object)); + memclrw(obj, sizeof(Object)); + obj->otype = OT_OBJECT; + obj->type = (Type *) tfunc; + obj->name = GetHashNameNodeExport(buf); + obj->sclass = TK_STATIC; + obj->datatype = DFUNC; + + return obj; +} + +static void estimate_func_param_size(ENode *node) { + SInt32 work; + ENodeList *list; + SInt32 align; + + work = 0; + for (list = node->data.funccall.args; list; list = list->next) { + align = ~7 & (CMach_ArgumentAlignment(list->node->rtype) + 7); + work += ~(align - 1) & (list->node->rtype->size + align - 1); + } + + estimate_out_param_size(work); +} |