#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/uDump.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) { VarInfo *vi; ObjectList *list; Object *obj; 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; Object *obj; SInt32 size; CodeGen_InitialSanityCheck(); if (!saveheaperror) { saveheaperror = getheaperror(); setheaperror(CodeGen_heaperror); } if (cparamblkptr->precompile == 1) CError_Error(CErrorStr180); if (!func) { func = createstaticinitobject(); } else if (func && func->name) { PrintProgressFunction(func->name->name); } 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); obj = stmt->expr->data.objref; add_immediate(3, local_base_register(obj), obj, 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(115); 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, "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, "unroll_instr_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, "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(161); CodeGen_EOLCheck(); return; } } else if (t == TK_IDENTIFIER && !strcmp(tkidentifier->name, "reset")) { CPrep_PopOption(OPT_OFFSET(function_align)); } else { PPCError_Warning(161); } CodeGen_EOLCheck(); return; } if (!strcmp(name->name, "processor")) { if (cscope_currentfunc) { PPCError_Warning(156, "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(208); 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(208); } else { PPCError_Warning(208); } 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(191); 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(161); } 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(189); 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_TYPE_4: case STRUCT_TYPE_5: case STRUCT_TYPE_6: case STRUCT_TYPE_7: case STRUCT_TYPE_8: case STRUCT_TYPE_9: case STRUCT_TYPE_A: case STRUCT_TYPE_B: case STRUCT_TYPE_C: case STRUCT_TYPE_D: case STRUCT_TYPE_E: 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_TYPE_4: case STRUCT_TYPE_5: case STRUCT_TYPE_6: if (i < 15) { PPCError_Error(110, type, 0); } else if (i > 15) { PPCError_Error(111, 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(112); break; } if (copts.pedantic) { if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_4) { if (!CInt64_IsInURange(v, 1)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 1)) PPCError_Warning(113, 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_TYPE_4) { if (!CInt64_IsInURange(v, 1)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 1)) PPCError_Warning(113, type, 0); } } vec->uc[0] = (UInt8) v.lo; } else { PPCError_Error(112); break; } result = 1; } break; case STRUCT_TYPE_7: case STRUCT_TYPE_8: case STRUCT_TYPE_9: case STRUCT_TYPE_E: if (i < 7) { PPCError_Error(110, type, 0); } else if (i > 7) { PPCError_Error(111, 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(112); break; } if (copts.pedantic) { if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_7 || TYPE_STRUCT(type)->stype == STRUCT_TYPE_E) { if (!CInt64_IsInURange(v, 2)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 2)) PPCError_Warning(113, 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_TYPE_7 || TYPE_STRUCT(type)->stype == STRUCT_TYPE_E) { if (!CInt64_IsInURange(v, 2)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 2)) PPCError_Warning(113, type, 0); } } vec->us[0] = (UInt16) v.lo; } else { PPCError_Error(112); break; } result = 1; } break; case STRUCT_TYPE_A: case STRUCT_TYPE_B: case STRUCT_TYPE_C: if (i < 3) { PPCError_Error(110, type, 0); } else if (i > 3) { PPCError_Error(111, 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(112); break; } if (copts.pedantic) { if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_A) { if (!CInt64_IsInURange(v, 4)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 4)) PPCError_Warning(113, 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_TYPE_A) { if (!CInt64_IsInURange(v, 4)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 4)) PPCError_Warning(113, type, 0); } } vec->ul[0] = v.lo; } else { PPCError_Error(112); break; } result = 1; } break; case STRUCT_TYPE_D: if (i < 3) { PPCError_Error(110, type, 0); } else if (i > 3) { PPCError_Error(111, 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(112); 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(112); 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_TYPE_4: case STRUCT_TYPE_5: case STRUCT_TYPE_6: { CInt64 v = expr->data.intval; if (copts.pedantic) { if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_4) { if (!CInt64_IsInURange(v, 1)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 1)) PPCError_Warning(113, type, 0); } } while (i < 16) vec->uc[i++] = (UInt8) v.lo; result = 1; break; } case STRUCT_TYPE_7: case STRUCT_TYPE_8: case STRUCT_TYPE_9: case STRUCT_TYPE_E: { CInt64 v = expr->data.intval; if (copts.pedantic) { if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_7 || TYPE_STRUCT(type)->stype == STRUCT_TYPE_E) { if (!CInt64_IsInURange(v, 2)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 2)) PPCError_Warning(113, type, 0); } } while (i < 8) vec->us[i++] = (UInt16) v.lo; result = 1; break; } case STRUCT_TYPE_A: case STRUCT_TYPE_B: case STRUCT_TYPE_C: { CInt64 v = expr->data.intval; if (copts.pedantic) { if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_A) { if (!CInt64_IsInURange(v, 4)) PPCError_Warning(113, type, 0); } else { if (!CInt64_IsInRange(v, 4)) PPCError_Warning(113, type, 0); } } while (i < 4) vec->ul[i++] = v.lo; result = 1; break; } case STRUCT_TYPE_D: { Float fv; if (!CInt64_IsInRange(expr->data.intval, 4)) { PPCError_Error(112); 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(112); } } else if (ENODE_IS(expr, EFLOATCONST)) { switch (TYPE_STRUCT(type)->stype) { default: PPCError_Error(112); break; case STRUCT_TYPE_D: { 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(112); } else if (!ENODE_IS(expr, EVECTOR128CONST)) { PPCError_Error(112); } 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) { }