diff options
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c')
-rw-r--r-- | compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c | 2437 |
1 files changed, 2437 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) { +} |