#include "compiler.h" #include "compiler/CError.h" #include "compiler/PCode.h" #include "compiler/PCodeInfo.h" #include "compiler/PCodeUtilities.h" #include "compiler/enode.h" #include "compiler/objects.h" #include "compiler/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; PCodeLabel *returnlabel; PCodeLabel *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 void *saveheaperror; enum { GPRLimit = 10, FPRLimit = 13, VRLimit = 13 }; 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.little_endian) 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; #line 497 CError_ASSERT(pic_base_reg); } else { #line 500 CError_FATAL(); } } 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; #line 605 CError_ASSERT(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); #line 698 CError_ASSERT(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); #line 782 CError_ASSERT(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); #line 846 CError_ASSERT(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; #line 901 CError_ASSERT(obj->datatype == DLOCAL); if (!vi->used) return; if (reg) { if (vi->reg) { if (TYPE_IS_8BYTES(type)) { if (copts.little_endian) { if (vi->reg != reg) emitpcode(PC_MR, vi->reg, reg); if (reg < GPRLimit) { #line 916 CError_FAIL((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) { #line 931 CError_FAIL((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: #line 993 CError_FATAL(); } } 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: #line 1095 CError_FATAL(); } } } else if (!optimizing) { local_base_register(obj); } } } static void load_TOC_pointers(void) { VarInfo *vi; Object *obj; ObjectList *list; PCode *pc; if (uses_globals && pic_base_reg) { pic_base_pcodelabel = makepclabel(); pc = makepcode(PC_BC, 20, 7, 3); pcsetlinkbit(pc); pcsetsideeffects(pc); appendpcode(pclastblock, pc); pcbranch(pclastblock, pic_base_pcodelabel); makepcblock(); pclabel(pclastblock, pic_base_pcodelabel); emitpcode(PC_MFLR, pic_base_reg); } // TODO: depends on Operands for (list = toclist; list; list = list->next) { } } static Boolean 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() { // TODO } 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, UInt16 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) { } static void labelstatement() {} static void gotostatement() {} static void gotoexpression() {} static void conditionalstatement() {} static void returnstatement() {} static void capturestackpointer() {} static void resetstackpointer() {} static void callprofiler() {} static void exitprofiler() {} void CodeGen_Generator() {} void CodeGen_GenVDispatchThunk() {} void CodeGen_SetupRuntimeObjects() {} Boolean CodeGen_ReInitRuntimeObjects(Boolean is_precompiler) {} Boolean CodeGen_IsPublicRuntimeObject(Object *obj) {} void CodeGen_SOMStub() {} void CodeGen_ParseDeclSpec() {} static void CodeGen_EOLCheck() {} static void schedule_for() {} static void pragma_scheduling() {} static void CodeGen_ParseLongIntegerORonORoff() {} void CodeGen_ParsePragma(HashNameNode *name) {} void CodeGen_UpdateObject(Object *object) {} void CodeGen_UpdateBackEndOptions() {} void CodeGen_objc_method_self_offset() {} void CodeGen_objc_method_sel_offset() {} void CodeGen_objc_method_arg_offset() {} void CodeGen_objc_method_args_size() {} void CodeGen_HandleIntrinsicCall() {} void CodeGen_HandleTypeCast() {} void CodeGen_AssignCheck() {} void CodeGen_CollapseVectorExpression() {} void CodeGen_InsertSpecialMacros() {} char *CodeGen_ExpandSpecialMacro(Macro *macro) {} void CodeGen_reportheapinfo() {} static void CodeGen_heaperror() {} void CodeGen_InitialSanityCheck() {}