#include "cos.h" #include "compiler/TOC.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CExpr.h" #include "compiler/CInit.h" #include "compiler/CInt64.h" #include "compiler/CFunc.h" #include "compiler/CMachine.h" #include "compiler/CMangler.h" #include "compiler/CParser.h" #include "compiler/CodeGen.h" #include "compiler/CompilerTools.h" #include "compiler/Exceptions.h" #include "compiler/InlineAsm.h" #include "compiler/InlineAsmPPC.h" #include "compiler/InstrSelection.h" #include "compiler/Intrinsics.h" #include "compiler/ObjGenMachO.h" #include "compiler/Operands.h" #include "compiler/PCode.h" #include "compiler/PCodeInfo.h" #include "compiler/PPCError.h" #include "compiler/RegisterInfo.h" #include "compiler/StackFrame.h" #include "compiler/enode.h" #include "compiler/objects.h" #include "compiler/types.h" ObjectList *toclist; ObjectList *exceptionlist; void *descriptorlist; PoolEntry *floatconstpool; PoolEntry *doubleconstpool; ObjectList *floatconstlist; PoolEntry *vectorconstpool; ObjectList *vectorconstlist; Object toc0; Boolean no_descriptors; Object pic_base; VarInfo pic_base_varinfo; short pic_base_reg; CodeLabelList *codelabellist; UInt8 lvslBytes[16][16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E }; UInt8 lvsrBytes[16][16] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; // forward decls static void estimate_func_param_size(ENode *node); static int disables_optimizer(ENode *node) { ENode *funcref = node->data.funccall.funcref; if (ENODE_IS(funcref, EOBJREF)) { if (!strcmp(CMangler_GetLinkName(funcref->data.objref)->name, "___setjmp")) return 1; if (!strcmp(CMangler_GetLinkName(funcref->data.objref)->name, "___vec_setjmp")) return 1; } return 0; } void setupaddressing(void) { floatconstlist = NULL; descriptorlist = NULL; toclist = NULL; exceptionlist = NULL; vectorconstlist = NULL; vectorconstpool = NULL; floatconstpool = NULL; doubleconstpool = NULL; no_descriptors = 1; memclrw(&toc0, sizeof(toc0)); pic_base_reg = 0; memclrw(&pic_base, sizeof(pic_base)); memclrw(&pic_base_varinfo, sizeof(pic_base_varinfo)); pic_base.otype = OT_OBJECT; pic_base.type = (Type *) &void_ptr; pic_base.datatype = DNONLAZYPTR; pic_base.u.toc.info = &pic_base_varinfo; } void createNonLazyPointer(Object *obj) { Object *toc; ObjectList *list; toc = galloc(sizeof(Object)); obj->toc = toc; memclrw(toc, sizeof(Object)); toc->otype = OT_OBJECT; toc->name = CParser_GetUniqueName(); toc->toc = NULL; toc->section = SECT_NONLAZY_PTRS; toc->u.toc.info = CodeGen_GetNewVarInfo(); toc->sclass = TK_STATIC; toc->qual = Q_CONST; toc->datatype = DNONLAZYPTR; toc->flags |= OBJECT_FLAGS_2; toc->type = CDecl_NewPointerType(obj->type); toc->u.toc.over_load = obj; toc->u.toc.linkname = CMangler_GetLinkName(obj); list = galloc(sizeof(ObjectList)); memclrw(list, sizeof(ObjectList)); list->object = toc; list->next = toclist; toclist = list; } void referenceIndirectPointer(Object *obj) { VarInfo *vi = obj->toc->u.toc.info; vi->used = 1; vi->usage += copts.optimizesize ? 1 : curstmtvalue; } Object *createIndirect(Object *obj, Boolean flag1, Boolean flag2) { CError_ASSERT(622, !copts.no_common || (obj->section != SECT_COMMON_VARS) || (obj->qual & Q_20000)); if (CParser_HasInternalLinkage(obj)) return NULL; if (ObjGen_IsExported(obj)) return NULL; if (!copts.no_common && obj->datatype == DDATA && obj->section == SECT_DEFAULT && (obj->qual & Q_1000000)) obj->section = SECT_COMMON_VARS; if (copts.codegen_dynamic && (!copts.no_common || !(obj->qual & Q_1000000))) { if (!obj->toc) createNonLazyPointer(obj); else if (flag1) obj->toc->u.toc.info = CodeGen_GetNewVarInfo(); if (flag2) referenceIndirectPointer(obj); return obj->toc; } else { return NULL; } } Object *createfloatconstant(Type *type, Float *data) { ObjectList *list; Object *obj; UInt32 *check; for (list = floatconstlist; list; list = list->next) { obj = list->object; check = (UInt32 *) obj->u.data.u.floatconst; if (obj->type == type && check[0] == ((UInt32 *) data)[0] && check[1] == ((UInt32 *) data)[1]) return obj; } obj = galloc(sizeof(Object)); memclrw(obj, sizeof(Object)); obj->otype = OT_OBJECT; obj->type = type; obj->name = CParser_GetUniqueName(); obj->toc = NULL; obj->u.data.info = NULL; obj->u.data.linkname = obj->name; obj->sclass = TK_STATIC; obj->qual = Q_CONST | Q_INLINE_DATA; obj->datatype = DDATA; if (type->size == 8) obj->section = SECT_8BYTE_LITERALS; else if (type->size == 4) obj->section = SECT_4BYTE_LITERALS; else CError_FATAL(807); obj->flags |= OBJECT_FLAGS_2; obj->u.data.u.floatconst = galloc(sizeof(Float)); *obj->u.data.u.floatconst = *data; list = galloc(sizeof(ObjectList)); memclrw(list, sizeof(ObjectList)); list->object = obj; list->next = floatconstlist; floatconstlist = list; ObjGen_DeclareFloatConst(obj); return obj; } Object *createvectorconstant(Type *type, MWVector128 *data) { ObjectList *list; Object *obj; MWVector128 *check; for (list = vectorconstlist; list; list = list->next) { obj = list->object; check = obj->u.data.u.vector128const; if (check->ul[0] == data->ul[0] && check->ul[1] == data->ul[1] && check->ul[2] == data->ul[2] && check->ul[3] == data->ul[3]) return obj; } obj = galloc(sizeof(Object)); memclrw(obj, sizeof(Object)); obj->otype = OT_OBJECT; obj->type = type; obj->name = CParser_GetUniqueName(); obj->toc = NULL; obj->u.data.info = NULL; obj->u.data.linkname = obj->name; obj->sclass = TK_STATIC; obj->qual = Q_CONST | Q_INLINE_DATA; obj->datatype = DDATA; if (type->size == 16) obj->section = SECT_16BYTE_LITERALS; else CError_FATAL(900); obj->flags |= OBJECT_FLAGS_2; obj->u.data.u.vector128const = galloc(sizeof(MWVector128)); *obj->u.data.u.vector128const = *data; list = galloc(sizeof(ObjectList)); memclrw(list, sizeof(ObjectList)); list->object = obj; list->next = vectorconstlist; vectorconstlist = list; ObjGen_DeclareVectorConst(obj); return obj; } void DeclarePooledConstants(void) { PoolEntry *entry; char *buffer; SInt32 fsize; SInt32 dsize; SInt32 vsize; fsize = 0; for (entry = floatconstpool; entry; entry = entry->next) fsize += 4; if (fsize) { floatconstpool->object->type = CDecl_NewArrayType(TYPE(&stfloat), fsize); buffer = galloc(fsize); for (entry = floatconstpool; entry; entry = entry->next) memcpy(buffer + entry->offset, entry->buffer, 4); CInit_DeclareReadOnlyData(floatconstpool->object, buffer, NULL, fsize); } dsize = 0; for (entry = doubleconstpool; entry; entry = entry->next) dsize += 8; if (dsize) { doubleconstpool->object->type = CDecl_NewArrayType(TYPE(&stdouble), dsize); buffer = galloc(dsize); for (entry = doubleconstpool; entry; entry = entry->next) memcpy(buffer + entry->offset, entry->buffer, 8); CInit_DeclareReadOnlyData(doubleconstpool->object, buffer, NULL, dsize); } vsize = 0; for (entry = vectorconstpool; entry; entry = entry->next) vsize += 16; if (vsize) { vectorconstpool->object->type = CDecl_NewArrayType(TYPE(&stvectorsignedlong), vsize); buffer = galloc(vsize); for (entry = vectorconstpool; entry; entry = entry->next) memcpy(buffer + entry->offset, entry->buffer, 16); CInit_DeclareReadOnlyData(vectorconstpool->object, buffer, NULL, vsize); } } static Object *CreatePooledFloatConst(Type *type, Float *data, SInt32 *pOffset) { if (type->size == 8u) { PoolEntry *entry; void *buffer; Object *object; SInt32 offset; buffer = galloc(8u); CMach_InitFloatMem(type, *data, buffer); if (cparamblkptr->precompile == 1) CError_Error(CErrorStr180); for (entry = doubleconstpool; entry; entry = entry->next) { if (!memcmp(entry->buffer, buffer, 8u)) break; } if (!entry) { if (doubleconstpool) { object = doubleconstpool->object; offset = doubleconstpool->offset + 8u; doubleconstpool->object->type->size += 8u; } else { DeclInfo di; memclrw(&di, sizeof(di)); di.thetype = CDecl_NewArrayType(TYPE(&stdouble), 8u); di.name = GetHashNameNodeExport("@doubleBase0"); di.qual = Q_CONST; di.storageclass = TK_STATIC; di.is_extern_c = 1; di.section = SECT_CONST; object = CParser_NewGlobalDataObject(&di); object->nspace = cscope_root; offset = 0; } entry = galloc(sizeof(PoolEntry)); entry->next = doubleconstpool; doubleconstpool = entry; entry->object = object; entry->offset = offset; entry->buffer = galloc(8u); memcpy(entry->buffer, buffer, 8u); } *pOffset = entry->offset; return entry->object; } if (type->size == 4u) { PoolEntry *entry; void *buffer; Object *object; SInt32 offset; buffer = galloc(4u); CMach_InitFloatMem(type, *data, buffer); if (cparamblkptr->precompile == 1) CError_Error(CErrorStr180); for (entry = floatconstpool; entry; entry = entry->next) { if (!memcmp(entry->buffer, buffer, 4u)) break; } if (!entry) { if (floatconstpool) { object = floatconstpool->object; offset = floatconstpool->offset + 4u; object->type->size += 4u; } else { DeclInfo di; memclrw(&di, sizeof(di)); di.thetype = CDecl_NewArrayType(TYPE(&stfloat), 4u); di.name = GetHashNameNodeExport("@floatBase0"); di.qual = Q_CONST; di.storageclass = TK_STATIC; di.is_extern_c = 1; di.section = SECT_CONST; object = CParser_NewGlobalDataObject(&di); object->nspace = cscope_root; offset = 0; } entry = galloc(sizeof(PoolEntry)); entry->next = floatconstpool; floatconstpool = entry; entry->object = object; entry->offset = offset; entry->buffer = galloc(4u); memcpy(entry->buffer, buffer, 4u); } *pOffset = entry->offset; return entry->object; } CError_FATAL(1183); return NULL; } Object *CreateFloatConst(Type *type, Float *data, SInt32 *pOffset) { *pOffset = 0; return createfloatconstant(type, data); } static void RewriteFloatConst(ENode *expr) { Object *obj; SInt32 n; ENode *subexpr; obj = CreateFloatConst(expr->rtype, &expr->data.floatval, &n); if (n) { subexpr = makediadicnode(create_objectrefnode(obj), intconstnode(TYPE(&stunsignedlong), n), EADD); } else { subexpr = create_objectrefnode(obj); } expr->type = EINDIRECT; expr->cost = 1; expr->flags |= Q_CONST; expr->data.monadic = subexpr; } static void RewriteVectorConst(ENode *expr) { PoolEntry *entry; Object *object; SInt32 offset; ENode *inner; UInt8 data[16]; CMach_InitVectorMem(expr->rtype, expr->data.vector128val, data, 1); if (cparamblkptr->precompile == 1) CError_Error(CErrorStr180); for (entry = vectorconstpool; entry; entry = entry->next) { if (!memcmp(entry->buffer, data, 16)) break; } if (!entry) { if (vectorconstpool) { object = vectorconstpool->object; offset = vectorconstpool->offset + 16; vectorconstpool->object->type->size += 16; } else { DeclInfo di; memclrw(&di, sizeof(di)); di.thetype = CDecl_NewArrayType(TYPE(&stvectorsignedlong), 16); di.name = GetHashNameNodeExport("@vectorBase0"); di.qual = Q_CONST; di.storageclass = TK_STATIC; di.is_extern_c = 1; di.section = SECT_CONST; object = CParser_NewGlobalDataObject(&di); object->nspace = cscope_root; offset = 0; } entry = galloc(sizeof(PoolEntry)); entry->next = vectorconstpool; vectorconstpool = entry; entry->object = object; entry->offset = offset; entry->buffer = galloc(16); memcpy(entry->buffer, data, 16); } if (entry->offset) { inner = makediadicnode( create_objectrefnode(entry->object), intconstnode(TYPE(&stunsignedlong), entry->offset), EADD); } else { inner = create_objectrefnode(entry->object); } expr->type = EINDIRECT; expr->cost = 1; expr->flags |= ENODE_FLAG_CONST; expr->data.monadic = inner; } static Object *createcodelabel(CLabel *label) { CodeLabelList *list; Object *obj; for (list = codelabellist; list; list = list->next) { if (list->label == label) return list->object; } obj = galloc(sizeof(Object)); memclrw(obj, sizeof(Object)); obj->otype = OT_OBJECT; obj->type = (Type *) &void_ptr; obj->name = label->uniquename; obj->toc = NULL; obj->u.data.info = NULL; // not sure if this is the right union! obj->sclass = TK_STATIC; obj->qual = Q_CONST; obj->datatype = DDATA; obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED; list = galloc(sizeof(CodeLabelList)); memclrw(list, sizeof(CodeLabelList)); list->object = obj; list->label = label; list->next = codelabellist; codelabellist = list; return obj; } void dumpcodelabels(Object *func) { CodeLabelList *list; for (list = codelabellist; list; list = list->next) ObjGen_DeclareCodeLabel(list->object, list->label->pclabel->block->codeOffset, func); } static void referenceexception(Object *obj) { ObjectList *list; if (obj && obj->otype == OT_OBJECT && obj->datatype == DLOCAL) { for (list = exceptionlist; list; list = list->next) { if (list->object == obj) return; } list = lalloc(sizeof(ObjectList)); memclrw(list, sizeof(ObjectList)); list->object = obj; list->next = exceptionlist; exceptionlist = list; } } static ENodeType invert_relop(ENodeType nodetype) { switch (nodetype) { case ELESS: return EGREATEREQU; case EGREATER: return ELESSEQU; case ELESSEQU: return EGREATER; case EGREATEREQU: return ELESS; case EEQU: return ENOTEQU; case ENOTEQU: return EEQU; default: return nodetype; } } static ENode *COND_to_COMPARE(ENode *cond, ENode *expr1, ENode *expr2) { SInt32 val1; SInt32 val2; SInt32 condval; ENodeType invop; while (expr1->type == ETYPCON && TYPE_FITS_IN_REGISTER(expr1->rtype)) expr1 = expr1->data.monadic; while (expr2->type == ETYPCON && TYPE_FITS_IN_REGISTER(expr2->rtype)) expr2 = expr2->data.monadic; if (expr1->type != EINTCONST || !TYPE_FITS_IN_REGISTER(expr1->rtype) || !CInt64_IsInRange(expr1->data.intval, 4)) return NULL; if (expr2->type != EINTCONST || !TYPE_FITS_IN_REGISTER(expr2->rtype) || !CInt64_IsInRange(expr2->data.intval, 4)) return NULL; val1 = expr1->data.intval.lo; val2 = expr2->data.intval.lo; condval = 0; switch (val1) { case 1: if (val2 != 0) return NULL; break; case 0: condval = 1; if (val2 != 1) return NULL; break; default: return NULL; } while (cond->type == ELOGNOT) { condval = (condval + 1) & 1; cond = cond->data.monadic; } if (condval) { invop = invert_relop(cond->type); if (invop == cond->type) return NULL; cond->type = invop; } return cond; } static ENode *comparewithzero(ENode *expr) { ENode *expr1; ENode *expr2; ENode *tmp; expr1 = lalloc(sizeof(ENode)); memclrw(expr1, sizeof(ENode)); expr2 = lalloc(sizeof(ENode)); memclrw(expr2, sizeof(ENode)); while (expr->type == EFORCELOAD || expr->type == ETYPCON || expr->type == ECOMMA) { if (!TYPE_FITS_IN_REGISTER(expr->rtype)) break; if (expr->type == ECOMMA) { expr->data.diadic.right = comparewithzero(expr->data.diadic.right); return expr; } expr = expr->data.monadic; } if (expr->type == ECOND && TYPE_FITS_IN_REGISTER(expr->rtype)) { tmp = COND_to_COMPARE(expr->data.cond.cond, expr->data.cond.expr1, expr->data.cond.expr2); if (tmp) expr = tmp; } if (expr->type >= ELESS && expr->type <= ENOTEQU) return expr; if (IS_TYPE_FLOAT(expr->rtype)) { static Float float0 = {0.0}; expr2->type = EFLOATCONST; expr2->cost = 0; expr2->rtype = (expr->rtype->size == 4) ? (Type *) &stfloat : (Type *) &stdouble; expr2->data.floatval = float0; } else { expr2->type = EINTCONST; expr2->cost = 0; if (TYPE_IS_8BYTES(expr->rtype)) expr2->rtype = (Type *) &stsignedlonglong; else expr2->rtype = (Type *) &stsignedint; expr2->data.intval.lo = 0; expr2->data.intval.hi = 0; } expr1->type = ENOTEQU; expr1->cost = expr->cost; expr1->rtype = (Type *) &stsignedint; expr1->data.diadic.left = expr; expr1->data.diadic.right = expr2; return expr1; } static void rewritefunctioncallreturningstruct(ENode *expr) { ENode *ret_expr; ENode *copy; ret_expr = expr->data.funccall.args->node; copy = lalloc(sizeof(ENode)); memclrw(copy, sizeof(ENode)); *copy = *expr; expr->type = ECOMMA; expr->data.diadic.left = copy; expr->data.diadic.right = ret_expr; } static void rewritestrcpy(ENode *expr) { ENode *int_expr; ENodeList *list; int_expr = lalloc(sizeof(ENode)); memclrw(int_expr, sizeof(ENode)); int_expr->type = EINTCONST; int_expr->cost = 0; int_expr->flags = 0; int_expr->rtype = (Type *) &stunsignedlong; CInt64_SetLong(&int_expr->data.intval, expr->data.funccall.args->next->node->data.string.size); list = lalloc(sizeof(ENodeList)); memclrw(list, sizeof(ENodeList)); list->next = NULL; list->node = int_expr; expr->data.funccall.args->next->next = list; expr->data.funccall.funcref->data.objref = __memcpy_object; } static SInt32 magnitude(Type *type) { if (IS_TYPE_FLOAT(type)) return type->size * 4; else if (is_unsigned(type)) return (type->size * 2) + 1; else return type->size * 2; } static Type *promote_type(Type *type) { if (IS_TYPE_ENUM(type)) type = TYPE_ENUM(type)->enumtype; if (TYPE_INTEGRAL(type)->integral > stsignedint.integral) return type; else return (Type *) &stsignedint; } static Type *common_type(Type *type1, Type *type2) { Type *tmp; if (IS_TYPE_FLOAT(type1) || IS_TYPE_FLOAT(type2)) { if (TYPE_INTEGRAL(type1)->integral > TYPE_INTEGRAL(type2)->integral) return type1; else return type2; } type1 = promote_type(type1); type2 = promote_type(type2); if (type1 != type2) { if (TYPE_INTEGRAL(type1)->integral < TYPE_INTEGRAL(type2)->integral) { tmp = type1; type1 = type2; type2 = tmp; } if (type1->size == type2->size && !is_unsigned(type1) && is_unsigned(type2)) { if (type1 == (Type *) &stsignedlong) { type1 = (Type *) &stunsignedlong; } else { CError_ASSERT(1789, type1 == (Type *) &stsignedlonglong); type1 = (Type *) &stunsignedlonglong; } } } return type1; } static void rewrite_opassign(ENode *expr, ENodeType exprtype) { ENode *left_sub; ENode *right; Type *left_type; Type *right_type; ENode *new_expr; ENode *tmp; Type *commontype; Type *promo_left; Type *promo_right; left_sub = expr->data.diadic.left->data.monadic; right = expr->data.diadic.right; left_type = expr->data.diadic.left->rtype; right_type = expr->data.diadic.right->rtype; new_expr = lalloc(sizeof(ENode)); memclrw(new_expr, sizeof(ENode)); new_expr->type = exprtype; new_expr->rtype = left_type; new_expr->data.diadic.left = expr->data.diadic.left; new_expr->data.diadic.right = right; expr->type = EASS; expr->data.diadic.left = left_sub; expr->data.diadic.right = new_expr; if (left_sub->type != EOBJREF) { ENode *define; ENode *reuse; define = lalloc(sizeof(ENode)); memclrw(define, sizeof(ENode)); define->type = EDEFINE; define->rtype = left_type; reuse = lalloc(sizeof(ENode)); memclrw(reuse, sizeof(ENode)); reuse->type = EREUSE; reuse->rtype = left_type; reuse->data.monadic = define; if (left_sub->type != EBITFIELD) { define->data.monadic = expr->data.diadic.left; expr->data.diadic.left = define; new_expr->data.diadic.left->data.diadic.left = reuse; } else { ENode *copy; define->data.monadic = left_sub->data.diadic.left; left_sub->data.diadic.left = define; copy = lalloc(sizeof(ENode)); *copy = *left_sub; copy->data.diadic.left = reuse; new_expr->data.diadic.left->data.diadic.left = copy; } } switch (exprtype) { case EADD: case ESUB: if (IS_TYPE_POINTER(left_type)) break; if (right->type == EINTCONST && TYPE_FITS_IN_REGISTER(left_type)) break; case EAND: case EXOR: case EOR: if (left_type == right_type) break; case EMUL: case EDIV: case EMODULO: commontype = common_type(left_type, right_type); if (left_type != commontype) { tmp = lalloc(sizeof(ENode)); memclrw(tmp, sizeof(ENode)); tmp->type = ETYPCON; tmp->rtype = left_type; tmp->data.monadic = expr->data.diadic.right; expr->data.diadic.right = tmp; tmp = lalloc(sizeof(ENode)); memclrw(tmp, sizeof(ENode)); tmp->type = ETYPCON; tmp->rtype = commontype; tmp->data.monadic = new_expr->data.diadic.left; new_expr->data.diadic.left = tmp; } if (right_type != commontype) { tmp = lalloc(sizeof(ENode)); memclrw(tmp, sizeof(ENode)); tmp->type = ETYPCON; tmp->rtype = commontype; tmp->data.monadic = new_expr->data.diadic.right; new_expr->data.diadic.right = tmp; } new_expr->rtype = commontype; break; case ESHL: case ESHR: promo_left = promote_type(left_type); promo_right = promote_type(right_type); if (left_type != promo_left) { tmp = lalloc(sizeof(ENode)); memclrw(tmp, sizeof(ENode)); tmp->type = ETYPCON; tmp->rtype = left_type; tmp->data.monadic = expr->data.diadic.right; expr->data.diadic.right = tmp; tmp = lalloc(sizeof(ENode)); memclrw(tmp, sizeof(ENode)); tmp->type = ETYPCON; tmp->rtype = promo_left; tmp->data.monadic = new_expr->data.diadic.left; new_expr->data.diadic.left = tmp; } if (right_type != promo_right) { if (new_expr->data.diadic.right->type == EINTCONST && promo_right == (Type *) &stsignedint) { new_expr->data.diadic.right->rtype = (Type *) &stsignedint; } else { tmp = lalloc(sizeof(ENode)); memclrw(tmp, sizeof(ENode)); tmp->type = ETYPCON; tmp->rtype = promo_right; tmp->data.monadic = new_expr->data.diadic.right; new_expr->data.diadic.right = tmp; } } new_expr->rtype = promo_left; break; } } static void rewrite_preincdec(ENode *expr) { ENode *subexpr; // r31 Type *type; // r28 ENode *new_expr; // r29 subexpr = expr->data.monadic; type = expr->rtype; new_expr = lalloc(sizeof(ENode)); memclrw(new_expr, sizeof(ENode)); if (IS_TYPE_FLOAT(type)) { new_expr->type = EFLOATCONST; new_expr->cost = 0; new_expr->rtype = type; new_expr->data.floatval = one_point_zero; } else if (IS_TYPE_POINTER(type)) { new_expr->type = EINTCONST; new_expr->cost = 0; new_expr->rtype = (Type *) &stunsignedlong; new_expr->data.intval.hi = 0; new_expr->data.intval.lo = TYPE_POINTER(type)->target->size; } else { new_expr->type = EINTCONST; new_expr->cost = 0; new_expr->rtype = type; new_expr->data.intval.hi = 0; new_expr->data.intval.lo = 1; } expr->type = (expr->type == EPREDEC) ? ESUBASS : EADDASS; expr->data.diadic.left = subexpr; expr->data.diadic.right = new_expr; } // Don't know what this would be called in the original, but weh typedef union signed_vec { SInt8 sc[16]; SInt16 ss[8]; SInt32 sl[4]; } signed_vec; Boolean canoptimizevectorconst(MWVector128 *vecp, Type *type, COVCResult *result) { // this function is very broken signed_vec vec; union { SInt32 lg; SInt8 ch[4]; } conv32; union { SInt16 sh; SInt8 ch[2]; } conv16; char flag; SInt8 first8; SInt16 first16; SInt32 first32; int i; char ci; UInt32 l0, l1, l2, l3; if (IS_TYPE_VECTOR(type)) { vec = *((signed_vec *) vecp); first8 = vec.sc[0]; flag = 1; i = 1; while (flag && i < 16) flag = first8 == vec.sc[i++]; /*flag = 1; for (i = 1; flag && i < 16; i++) { flag = first8 == vec.sc[i]; }*/ if (flag && first8 < 16 && first8 > -17) { if (result) { result->op1 = PC_VSPLTISB; result->op2 = -1; result->arg = first8; } return 1; } first16 = vec.ss[0]; flag = 1; for (i = 1; flag && i < 8; i++) { flag = vec.ss[i] == first16; } conv16.sh = first16; if (flag && conv16.ch[0] == 0 && conv16.ch[1] < 16 && conv16.ch[1] >= 0) { if (result) { result->op1 = PC_VSPLTISH; result->op2 = -1; result->arg = conv16.ch[1]; } return 1; } if (flag && conv16.ch[0] == -1 && (conv16.ch[1] & 0xF0) == 0xF0) { if (result) { result->op1 = PC_VSPLTISH; result->op2 = -1; result->arg = conv16.ch[1]; } return 1; } first32 = vec.sl[0]; flag = 1; for (i = 1; flag && i < 4; i++) { flag = vec.sl[i] == first32; } conv32.lg = first32; if (flag && conv32.ch[0] == 0 && conv32.ch[1] == 0 && conv32.ch[2] == 0 && conv32.ch[3] < 16 && conv32.ch[3] >= 0) { if (result) { result->op1 = PC_VSPLTISW; result->op2 = -1; result->arg = conv32.ch[3]; } return 1; } if (flag && conv32.ch[0] == -1 && conv32.ch[1] == -1 && conv32.ch[2] == -1 && (conv32.ch[3] & 0xF0) == 0xF0) { if (result) { result->op1 = PC_VSPLTISW; result->op2 = -1; result->arg = conv32.ch[3]; } return 1; } l0 = vec.sl[0]; l1 = vec.sl[1]; l2 = vec.sl[2]; l3 = vec.sl[3]; for (ci = 0; ci < 16; ci++) { UInt32 *l; UInt32 *r; l = (UInt32 *) lvslBytes[(char) ci]; r = (UInt32 *) lvsrBytes[(char) ci]; if (l0 == l[0] && l1 == l[1] && l2 == l[2] && l3 == l[3]) { if (result) { result->op1 = -1; result->op2 = PC_LVSL; result->arg = ci; } return 1; } if (l0 == r[0] && l1 == r[1] && l2 == r[2] && l3 == r[3]) { if (result) { result->op1 = -1; result->op2 = PC_LVSR; result->arg = ci; } return 1; } } } return 0; } static SInt32 countindirects(ENode *expr) { SInt32 tmp1; SInt32 tmp2; switch (expr->type) { case EINTCONST: case EFLOATCONST: case ESTRINGCONST: case EOBJREF: case EVECTOR128CONST: return 0; case ECOND: if (expr->data.cond.cond->hascall || expr->data.cond.expr1->hascall || expr->data.cond.expr2->hascall) return 2; if ((tmp1 = countindirects(expr->data.cond.cond)) >= 2) return 2; if ((tmp2 = countindirects(expr->data.cond.expr1)) >= 2) return 2; if (tmp2 > tmp1) tmp1 = tmp2; if ((tmp2 = countindirects(expr->data.cond.expr2)) >= 2) return 2; if (tmp2 > tmp1) tmp1 = tmp2; return tmp1; case EFUNCCALL: case EFUNCCALLP: return 2; case EMUL: case EMULV: case EDIV: case EMODULO: case EADDV: case ESUBV: case EADD: case ESUB: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case EAND: case EXOR: case EOR: case ELAND: case ELOR: case EASS: case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: case ECOMMA: case EPMODULO: case EROTL: case EROTR: case EBCLR: case EBTST: case EBSET: if ((tmp1 = countindirects(expr->data.diadic.left)) >= 2) return 2; if ((tmp2 = countindirects(expr->data.diadic.right)) >= 2) return 2; if (tmp2 > tmp1) tmp1 = tmp2; return tmp1; case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: case EINDIRECT: case EMONMIN: case EBINNOT: case ELOGNOT: case EFORCELOAD: case ETYPCON: case EBITFIELD: if (expr->type == EINDIRECT) return countindirects(expr->data.monadic) + 1; else return countindirects(expr->data.monadic); default: return 2; } } static Boolean DetectCondSideAffect(ENode *expr) { switch (expr->type) { case EMUL: case EMULV: case EDIV: case EMODULO: case EADDV: case ESUBV: case EADD: case ESUB: case ESHL: case ESHR: case EAND: case EXOR: case EOR: case ECOMMA: case EPMODULO: case EROTL: case EROTR: case EBCLR: case EBTST: case EBSET: if (DetectCondSideAffect(expr->data.diadic.left)) return 1; return DetectCondSideAffect(expr->data.diadic.right); case EINDIRECT: if (expr->data.monadic->type == EINDIRECT) return 1; if (expr->data.monadic->type == EOBJREF) { if (expr->data.monadic->data.objref->datatype != DLOCAL && expr->data.monadic->data.objref->datatype != DDATA) return 1; if (IS_TYPE_POINTER(expr->data.monadic->data.objref->type)) return 1; return Registers_GetVarInfo(expr->data.monadic->data.objref)->noregister != 0; } return 1; case EMONMIN: case EBINNOT: case ELOGNOT: case EFORCELOAD: case ETYPCON: case EBITFIELD: return DetectCondSideAffect(expr->data.monadic); case EINTCONST: case EFLOATCONST: case ESTRINGCONST: case EOBJREF: case EVECTOR128CONST: return 0; case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case ELAND: case ELOR: case EASS: case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: case ECOND: case EFUNCCALL: case EFUNCCALLP: case EMFPOINTER: case ENULLCHECK: case EPRECOMP: case EDEFINE: case EREUSE: case EASSBLK: case ECONDASS: return 1; default: CError_FATAL(2523); return 1; } } static UInt8 WeightandSumOps(ENode *expr) { UInt32 score; switch (expr->type) { case ECOND: case ECONDASS: score = WeightandSumOps(expr->data.cond.cond); score += WeightandSumOps(expr->data.cond.expr1); score += WeightandSumOps(expr->data.cond.expr2); break; case EMUL: case EMULV: case EMULASS: score = WeightandSumOps(expr->data.diadic.left) + 10; score += WeightandSumOps(expr->data.diadic.right); break; case EDIV: case EMODULO: case EDIVASS: case EMODASS: score = WeightandSumOps(expr->data.diadic.left) + 20; score += WeightandSumOps(expr->data.diadic.right); break; case EADDV: case ESUBV: case EADD: case ESUB: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case EAND: case EXOR: case EOR: case ELAND: case ELOR: case EASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: case ECOMMA: case EPMODULO: case EROTL: case EROTR: case EBCLR: case EBTST: case EBSET: score = WeightandSumOps(expr->data.diadic.left) + 1; score += WeightandSumOps(expr->data.diadic.right); break; case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: case EMONMIN: case EBINNOT: case ELOGNOT: score = WeightandSumOps(expr->data.monadic) + 1; break; case EINDIRECT: if (expr->data.monadic->type == EOBJREF && expr->data.monadic->data.objref->datatype == DLOCAL) if (!Registers_GetVarInfo(expr->data.monadic->data.objref)->noregister) return 0; case EFORCELOAD: case ETYPCON: case EBITFIELD: score = WeightandSumOps(expr->data.monadic); break; case EOBJREF: score = 0; break; case EINTCONST: case EFLOATCONST: case ESTRINGCONST: case EVECTOR128CONST: score = 0; break; case EFUNCCALL: case EFUNCCALLP: score = 5; break; default: score = 255; } if (score >= 255) score = 255; return (UInt8) score; } Boolean TOC_use_fsel(ENode *expr) { ENode *left; ENode *right; Type *rtype; int score1; int score2; left = expr->data.cond.expr1; right = expr->data.cond.expr2; rtype = expr->rtype; if (!copts.peephole) return 0; if (!copts.gen_fsel) return 0; if (left->hascall) return 0; if (right->hascall) return 0; if (!IS_TYPE_FLOAT(rtype)) return 0; if (!IS_TYPE_FLOAT(left->rtype)) return 0; if (!IS_TYPE_FLOAT(right->rtype)) return 0; if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU) return 0; if (!IS_TYPE_FLOAT(expr->data.cond.cond->data.diadic.right->rtype)) return 0; if (expr->data.cond.cond->type == ELOGNOT || expr->data.cond.cond->type == ELAND || expr->data.cond.cond->type == ELOR) return 0; if (expr->type == ECONDASS) { if (left->type != EINDIRECT) return 0; if (left->data.monadic->type != EOBJREF) return 0; } if (DetectCondSideAffect(left)) return 0; if (DetectCondSideAffect(right)) return 0; if (expr->type == ECONDASS) score1 = 1; else score1 = WeightandSumOps(left); score2 = WeightandSumOps(right); if (score1 > copts.gen_fsel) return 0; else if (score2 > copts.gen_fsel) return 0; else return 1; } Boolean TOC_use_isel(ENode *expr, Boolean flag) { int opt; ENode *left; ENode *right; Type *rtype; Object *obj; int score1; int score2; left = expr->data.cond.expr1; right = expr->data.cond.expr2; rtype = expr->rtype; if (flag) opt = 10; else opt = copts.gen_isel; if (!opt) return 0; if (!copts.peephole) return 0; if (left->hascall) return 0; if (right->hascall) return 0; if (!TYPE_FITS_IN_REGISTER(rtype)) return 0; if (!TYPE_FITS_IN_REGISTER(left->rtype)) return 0; if (!TYPE_FITS_IN_REGISTER(right->rtype)) return 0; if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU) return 0; if (TYPE_IS_8BYTES(rtype)) return 0; if (flag) { if (!TYPE_FITS_IN_REGISTER(expr->data.cond.cond->data.diadic.right->rtype)) return 0; if (TYPE_IS_8BYTES(expr->data.cond.cond->data.diadic.right->rtype)) return 0; } if (expr->type == ECONDASS) { if (left->type != EINDIRECT) return 0; if (left->data.monadic->type != EOBJREF) return 0; if (flag) { obj = left->data.monadic->data.objref; if (obj->datatype != DLOCAL) return 0; if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) return 0; if (obj->u.var.info->rclass != RegClass_GPR) return 0; } } if (DetectCondSideAffect(left)) return 0; if (DetectCondSideAffect(right)) return 0; if (expr->type == ECONDASS) score1 = 1; else score1 = WeightandSumOps(left); score2 = WeightandSumOps(right); if (score1 > opt) return 0; else if (score2 > opt) return 0; else return 1; } SInt32 GetSizeSkip(ENode *expr) { if (expr->type == EASS) expr = expr->data.diadic.right; if (expr->type == ETYPCON && expr->data.monadic->rtype->size < expr->rtype->size) return expr->data.monadic->rtype->size; else return expr->rtype->size; } void Optimize64bitMath(ENode *expr) { ENode *left; // r23 ENode *right; // r28 SInt32 leftsize; // r24 SInt32 rightsize; // r25 SInt32 totalsize; // r22 int unsignedflag; // r4 CError_ASSERT(2886, TYPE_IS_8BYTES(expr->rtype)); left = expr->data.diadic.left; right = expr->data.diadic.right; leftsize = GetSizeSkip(left); totalsize = (leftsize + (rightsize = GetSizeSkip(right))); unsignedflag = is_unsigned(expr->rtype) != 0; switch (totalsize) { case 2: case 3: case 4: if (unsignedflag) { left->rtype = (Type *) &stunsignedint; right->rtype = (Type *) &stunsignedint; } else { left->rtype = (Type *) &stsignedint; right->rtype = (Type *) &stsignedint; } break; case 5: case 6: case 8: case 9: case 10: case 12: if (expr->type != ESUB || leftsize >= rightsize) { if (leftsize < 4) { if (unsignedflag) left->rtype = (Type *) &stunsignedint; else left->rtype = (Type *) &stsignedint; } else { if (left->type == ETYPCON && left->data.monadic->rtype != (Type *) &stfloat) expr->data.diadic.left = left->data.monadic; } if (rightsize < 4) { if (unsignedflag) right->rtype = (Type *) &stunsignedint; else right->rtype = (Type *) &stsignedint; } else { if (right->type == ETYPCON && right->data.monadic->rtype != (Type *) &stfloat) expr->data.diadic.right = right->data.monadic; } } break; case 16: break; default: CError_FATAL(2975); } } static Boolean OptimizeNestedAssginments(ENode **pexpr, Object *check) { ENode *expr; Boolean success1; Boolean success2; expr = *pexpr; switch (expr->type) { case EOBJREF: return check != expr->data.objref; case EMUL: case EMULV: case EDIV: case EMODULO: case EADDV: case ESUBV: case EADD: case ESUB: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case EAND: case EXOR: case EOR: case ELAND: case ELOR: case EASS: case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: case ECOMMA: case EPMODULO: case EROTL: case EROTR: case EBCLR: case EBTST: case EBSET: switch (expr->type) { case EASS: if (ENODE_IS(expr->data.diadic.left, EOBJREF) && expr->data.diadic.left->data.objref == check) { *pexpr = expr->data.diadic.right; return OptimizeNestedAssginments(pexpr, check); } break; case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: CError_FATAL(3033); return 0; } if (OptimizeNestedAssginments(&expr->data.diadic.right, check)) return OptimizeNestedAssginments(&expr->data.diadic.left, check); else return 0; break; case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: case EINDIRECT: case EMONMIN: case EBINNOT: case ELOGNOT: case EFORCELOAD: case ETYPCON: case EBITFIELD: return OptimizeNestedAssginments(&expr->data.monadic, check); case EINTCONST: case EFLOATCONST: case ESTRINGCONST: case EVECTOR128CONST: return 1; case ECOND: success2 = OptimizeNestedAssginments(&expr->data.cond.expr2, check); success1 = OptimizeNestedAssginments(&expr->data.cond.expr1, check); if (!success2 || !success1) return 0; return OptimizeNestedAssginments(&expr->data.cond.cond, check) == 0; case ECONDASS: if (!OptimizeNestedAssginments(&expr->data.cond.expr2, check)) return 0; if (OptimizeNestedAssginments(&expr->data.cond.cond, check)) return OptimizeNestedAssginments(&expr->data.cond.expr1, check) == 0; else return 0; case EFUNCCALL: case EFUNCCALLP: case EMFPOINTER: case ENULLCHECK: case EPRECOMP: case EDEFINE: case EREUSE: case EASSBLK: return 0; default: CError_FATAL(3083); return 0; } } static void expandTOCexpression(ENode *expr, Type *type, int ignored) { Object *obj; Object *tmpobj; ENode *cond; ENode *tmpexpr; ENode *newexpr; ENodeList *list; expr->ignored = ignored; switch (expr->type) { case EINTCONST: expr->hascall = 0; break; case EFLOATCONST: uses_globals = 1; RewriteFloatConst(expr); expandTOCexpression(expr, NULL, 0); break; case EVECTOR128CONST: if (!canoptimizevectorconst(&expr->data.vector128val, expr->rtype, NULL)) { uses_globals = 1; RewriteVectorConst(expr); expandTOCexpression(expr, NULL, 0); } break; case ESTRINGCONST: uses_globals = 1; CInit_RewriteString(expr, 1); expandTOCexpression(expr, NULL, 0); break; case EOBJREF: obj = expr->data.objref; CError_ASSERT(3203, obj->datatype != DALIAS); if (obj->datatype == DFUNC || obj->datatype == DVFUNC) uses_globals = 1; if (obj->datatype == DDATA) { uses_globals = 1; if (createIndirect(obj, 0, 1)) { tmpexpr = lalloc(sizeof(ENode)); memclrw(tmpexpr, sizeof(ENode)); tmpexpr->type = EOBJREF; tmpexpr->cost = 0; tmpexpr->data.objref = obj->toc; tmpexpr->rtype = CDecl_NewPointerType(expr->rtype); expr->type = EINDIRECT; expr->cost = 1; expr->data.monadic = tmpexpr; } } expr->hascall = 0; break; case ECONDASS: expr->ignored = 0; case ECOND: if (!ENODE_IS_RANGE(expr->data.cond.cond, ELESS, ENOTEQU)) expr->data.cond.cond = comparewithzero(expr->data.cond.cond); expandTOCexpression(expr->data.cond.expr1, NULL, ignored); expandTOCexpression(expr->data.cond.expr2, NULL, ignored); if (TOC_use_fsel(expr)) { cond = expr->data.cond.cond; if (ENODE_IS(cond->data.diadic.right, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.right->data.floatval)) { expandTOCexpression(cond->data.diadic.left, NULL, 0); } else if (ENODE_IS(cond->data.diadic.left, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.left->data.floatval)) { expandTOCexpression(cond->data.diadic.right, NULL, 0); } else { expandTOCexpression(expr->data.cond.cond, NULL, 0); } } else { expandTOCexpression(expr->data.cond.cond, NULL, 0); } expr->hascall = expr->data.cond.cond->hascall | expr->data.cond.expr1->hascall | expr->data.cond.expr2->hascall; break; case EFUNCCALL: case EFUNCCALLP: if (is_intrinsic_function_call(expr)) { expr->hascall = 0; if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_008) { if (copts.altivec_model) update_frame_align(16); dynamic_stack = 1; requires_frame = 1; } else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_035) { if (expr->data.funccall.args->next->node->type == ESTRINGCONST) { rewritestrcpy(expr); } else { requires_frame = 1; makes_call = 1; expr->hascall = 1; } } else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_036) { if (expr->data.funccall.args->next->next->node->type != EINTCONST) { requires_frame = 1; makes_call = 1; expr->hascall = 1; } } } else { requires_frame = 1; makes_call = 1; expr->hascall = 1; } if (disables_optimizer(expr)) { disable_optimizer |= 1; if (copts.disable_registers) disable_optimizer |= 2; } if (ENODE_IS(expr->data.funccall.funcref, EINDIRECT) && IS_TYPE_FUNC(expr->data.funccall.funcref->rtype)) *expr->data.funccall.funcref = *expr->data.funccall.funcref->data.monadic; if (ENODE_IS(expr->data.funccall.funcref, EOBJREF)) { expr->data.funccall.funcref->hascall = 0; if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC && (expr->data.funccall.funcref->flags & ENODE_FLAG_80)) { tmpobj = galloc(sizeof(Object)); *tmpobj = *expr->data.funccall.funcref->data.objref; tmpobj->datatype = DFUNC; expr->data.funccall.funcref->data.objref = tmpobj; } } else { expandTOCexpression(expr->data.funccall.funcref, NULL, 0); } for (list = expr->data.funccall.args; list; list = list->next) expandTOCexpression(list->node, NULL, 0); if (expr->hascall) estimate_func_param_size(expr); if (is_intrinsic_function_call(expr)) { for (list = expr->data.funccall.args; list; list = list->next) expr->hascall |= list->node->hascall; } if (CMach_PassResultInHiddenArg(TYPE_FUNC(expr->data.funccall.functype)->functype)) rewritefunctioncallreturningstruct(expr); break; case ECOMMA: expandTOCexpression(expr->data.diadic.left, NULL, 1); expandTOCexpression(expr->data.diadic.right, NULL, ignored); expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; break; case ELAND: case ELOR: if (!ENODE_IS(expr->data.diadic.left, ELOGNOT) && !ENODE_IS2(expr->data.diadic.left, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.left, ELESS, ENOTEQU)) expr->data.diadic.left = comparewithzero(expr->data.diadic.left); if (!ENODE_IS(expr->data.diadic.right, ELOGNOT) && !ENODE_IS2(expr->data.diadic.right, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.right, ELESS, ENOTEQU)) expr->data.diadic.right = comparewithzero(expr->data.diadic.right); expandTOCexpression(expr->data.diadic.left, NULL, 0); expandTOCexpression(expr->data.diadic.right, NULL, 0); expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; break; case EDIVASS: if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) uses_globals = 1; rewrite_opassign(expr, EDIV); goto opassign_common; case EMULASS: if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) uses_globals = 1; rewrite_opassign(expr, EMUL); goto opassign_common; case EADDASS: if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) uses_globals = 1; rewrite_opassign(expr, EADD); goto opassign_common; case ESUBASS: if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) uses_globals = 1; rewrite_opassign(expr, ESUB); goto opassign_common; case EMODASS: if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype)) uses_globals = 1; rewrite_opassign(expr, EMODULO); goto opassign_common; case ESHLASS: rewrite_opassign(expr, ESHL); goto opassign_common; case ESHRASS: rewrite_opassign(expr, ESHR); goto opassign_common; case EANDASS: rewrite_opassign(expr, EAND); goto opassign_common; case EXORASS: rewrite_opassign(expr, EXOR); goto opassign_common; case EORASS: rewrite_opassign(expr, EOR); goto opassign_common; case EASS: if (ENODE_IS(expr->data.diadic.left, EINDIRECT)) expr->data.diadic.left = expr->data.diadic.left->data.monadic; opassign_common: expandTOCexpression(expr->data.diadic.left, NULL, 0); expandTOCexpression(expr->data.diadic.right, NULL, 0); expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; break; case EEQU: case ENOTEQU: if (ENODE_IS(expr->data.diadic.right, EINTCONST) && expr->data.diadic.right->data.intval.lo == 0 && expr->data.diadic.right->data.intval.hi == 0) { for (tmpexpr = expr->data.diadic.left; ENODE_IS2(tmpexpr, EFORCELOAD, ETYPCON); tmpexpr = tmpexpr->data.monadic) { if (!TYPE_FITS_IN_REGISTER(tmpexpr->rtype)) break; } if (ENODE_IS(tmpexpr, ELOGNOT) && TYPE_FITS_IN_REGISTER(tmpexpr->data.monadic->rtype)) { if (ENODE_IS(expr, EEQU)) expr->type = ENOTEQU; else expr->type = EEQU; expr->data.diadic.left = tmpexpr->data.monadic; expandTOCexpression(expr, NULL, 0); break; } if (ENODE_IS(tmpexpr, EEQU)) { if (ENODE_IS(expr, EEQU)) tmpexpr->type = ENOTEQU; *expr = *tmpexpr; expandTOCexpression(expr, NULL, 0); break; } if (ENODE_IS(tmpexpr, ENOTEQU)) { if (ENODE_IS(expr, EEQU)) tmpexpr->type = EEQU; *expr = *tmpexpr; expandTOCexpression(expr, NULL, 0); break; } if (ENODE_IS(tmpexpr, ECOND)) { newexpr = COND_to_COMPARE(tmpexpr->data.cond.cond, tmpexpr->data.cond.expr1, tmpexpr->data.cond.expr2); if (newexpr) { *tmpexpr = *newexpr; expandTOCexpression(expr, NULL, 0); break; } } } case EDIV: if (ENODE_IS(expr, EDIV) && ENODE_IS(expr->data.diadic.right, EFLOATCONST) && CMach_FloatIsPowerOf2(expr->data.diadic.right->data.floatval)) { expr->type = EMUL; expr->data.diadic.right->data.floatval = CMach_FloatReciprocal(expr->data.diadic.right->data.floatval); } case EMODULO: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: expandTOCexpression(expr->data.diadic.left, NULL, 0); expandTOCexpression(expr->data.diadic.right, NULL, 0); expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; if (TYPE_IS_8BYTES(expr->rtype)) { if (ENODE_IS2(expr, ESHL, ESHR) && !ENODE_IS(expr->data.diadic.right, EINTCONST)) { expr->hascall = 1; requires_frame = 1; makes_call = 1; } if (ENODE_IS2(expr, EDIV, EMODULO)) { if (ENODE_IS(expr->data.diadic.right, EINTCONST)) { if (I8_log2n(((SInt64) expr->data.diadic.right->data.intval.hi << 32) + expr->data.diadic.right->data.intval.lo) <= 0) { expr->hascall = 1; requires_frame = 1; makes_call = 1; } } else { expr->hascall = 1; requires_frame = 1; makes_call = 1; } } } break; case ESUB: if (ENODE_IS(expr->data.diadic.right, EINTCONST)) { expr->type = EADD; expr->data.diadic.right->data.intval = CInt64_Neg(expr->data.diadic.right->data.intval); } case EMUL: case EADD: case EAND: case EXOR: case EOR: expandTOCexpression(expr->data.diadic.left, type, 0); expandTOCexpression(expr->data.diadic.right, type, 0); expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; if (ENODE_IS3(expr, EMUL, EADD, ESUB) && TYPE_IS_8BYTES(expr->rtype)) Optimize64bitMath(expr); if (type) { if ( ENODE_IS(expr->data.diadic.left, ETYPCON) && IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->rtype) && IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->data.monadic->rtype) && expr->data.diadic.left->data.monadic->rtype->size >= type->size && !TYPE_IS_8BYTES(expr->data.diadic.left->data.monadic->rtype) ) expr->data.diadic.left = expr->data.diadic.left->data.monadic; if ( ENODE_IS(expr->data.diadic.right, ETYPCON) && IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->rtype) && IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->data.monadic->rtype) && expr->data.diadic.right->data.monadic->rtype->size >= type->size && !TYPE_IS_8BYTES(expr->data.diadic.right->data.monadic->rtype) ) expr->data.diadic.right = expr->data.diadic.right->data.monadic; expr->rtype = type; } break; case ETYPCON: tmpexpr = expr->data.monadic; if ((IS_TYPE_INT_OR_ENUM(expr->rtype) && expr->rtype->size < 4) && IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && !TYPE_IS_8BYTES(tmpexpr->rtype)) { expandTOCexpression(tmpexpr, expr->rtype, 0); } else { expandTOCexpression(tmpexpr, NULL, expr->rtype->type == TYPEVOID); } expr->hascall = tmpexpr->hascall; if (IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype)) uses_globals = 1; if ((TYPE_IS_8BYTES(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype)) || (TYPE_IS_8BYTES(expr->rtype) && IS_TYPE_FLOAT(tmpexpr->rtype))) { uses_globals = 1; expr->hascall = 1; requires_frame = 1; makes_call = 1; } if (IS_TYPE_FLOAT(tmpexpr->rtype)) { if (is_unsigned(expr->rtype) && expr->rtype->size == 4) { expr->hascall = 1; requires_frame = 1; makes_call = 1; } else { uses_globals = 1; } } if (IS_TYPE_VECTOR(expr->rtype) && !IS_TYPE_VECTOR(tmpexpr->rtype)) PPCError_Error(114); break; case EPOSTINC: if (!expr->ignored) { if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype)) uses_globals = 1; expandTOCexpression(expr->data.monadic, NULL, 0); expr->hascall = expr->data.monadic->hascall; break; } expr->type = EPREINC; case EPREINC: rewrite_preincdec(expr); rewrite_opassign(expr, EADD); goto opassign_common; case EPOSTDEC: if (!expr->ignored) { if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype)) uses_globals = 1; expandTOCexpression(expr->data.monadic, NULL, 0); expr->hascall = expr->data.monadic->hascall; break; } expr->type = EPREDEC; case EPREDEC: rewrite_preincdec(expr); rewrite_opassign(expr, ESUB); goto opassign_common; case ELOGNOT: if (!ENODE_IS(expr->data.monadic, ELOGNOT) && !ENODE_IS2(expr->data.monadic, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.monadic, ELESS, ENOTEQU)) expr->data.monadic = comparewithzero(expr->data.monadic); case EMONMIN: case EBINNOT: tmpexpr = expr->data.monadic; expandTOCexpression(tmpexpr, type, 0); expr->hascall = tmpexpr->hascall; if (type && ENODE_IS(expr->data.monadic, ETYPCON)) { if (IS_TYPE_INT_OR_ENUM(expr->data.monadic->rtype) && IS_TYPE_INT_OR_ENUM(expr->data.monadic->data.monadic->rtype)) { if (expr->data.monadic->data.monadic->rtype->size >= type->size) { expr->data.monadic = expr->data.monadic->data.monadic; expr->rtype = type; } } } break; case EINDIRECT: case EFORCELOAD: case EBITFIELD: tmpexpr = expr->data.monadic; expandTOCexpression(tmpexpr, NULL, 0); expr->hascall = tmpexpr->hascall; break; case EDEFINE: tmpexpr = expr->data.monadic; expandTOCexpression(tmpexpr, NULL, 0); expr->hascall = tmpexpr->hascall; break; case EREUSE: expr->hascall = expr->data.monadic->hascall; break; case ENULLCHECK: expandTOCexpression(expr->data.diadic.left, NULL, 0); expandTOCexpression(expr->data.diadic.right, NULL, 0); expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall; break; case EPRECOMP: expr->hascall = 0; break; case ELABEL: obj = createcodelabel(expr->data.label); newexpr = lalloc(sizeof(ENode)); memclrw(newexpr, sizeof(ENode)); newexpr->type = EOBJREF; newexpr->cost = 0; newexpr->data.objref = obj; newexpr->rtype = CDecl_NewPointerType(obj->type); expr->type = EINDIRECT; expr->cost = 1; expr->data.monadic = newexpr; expr->hascall = 0; break; } } static void checkexceptionreferences(ExceptionAction *action) { for (; action; action = action->prev) { switch (action->type) { case EAT_DESTROYLOCAL: referenceexception(action->data.destroy_local.local); break; case EAT_DESTROYLOCALCOND: referenceexception(action->data.destroy_local_cond.local); referenceexception(action->data.destroy_local_cond.cond); break; case EAT_DESTROYLOCALOFFSET: referenceexception(action->data.destroy_local_offset.local); break; case EAT_DESTROYLOCALPOINTER: referenceexception(action->data.destroy_local_pointer.pointer); break; case EAT_DESTROYLOCALARRAY: referenceexception(action->data.destroy_local_array.localarray); break; case EAT_DESTROYBASE: referenceexception(action->data.destroy_member.objectptr); // wrong union? break; case EAT_DESTROYPARTIALARRAY: referenceexception(action->data.destroy_partial_array.arraypointer); referenceexception(action->data.destroy_partial_array.arraycounter); referenceexception(action->data.destroy_partial_array.element_size); break; case EAT_DESTROYMEMBER: referenceexception(action->data.destroy_member.objectptr); break; case EAT_DESTROYMEMBERCOND: referenceexception(action->data.destroy_member_cond.objectptr); referenceexception(action->data.destroy_member_cond.cond); break; case EAT_DESTROYMEMBERARRAY: referenceexception(action->data.destroy_member_array.objectptr); break; case EAT_DELETEPOINTER: case EAT_DELETELOCALPOINTER: referenceexception(action->data.delete_pointer.pointerobject); break; case EAT_DELETEPOINTERCOND: referenceexception(action->data.delete_pointer_cond.pointerobject); referenceexception(action->data.delete_pointer_cond.cond); break; case EAT_CATCHBLOCK: referenceexception(action->data.catch_block.catch_object); referenceexception(action->data.catch_block.catch_info_object); break; case EAT_ACTIVECATCHBLOCK: referenceexception(action->data.active_catch_block.catch_info_object); break; } } } void expandTOCreferences(Statement **stmts) { Statement *stmt; IAOperand *op; int i; InlineAsm *ia; VarInfo *vi; codelabellist = NULL; exceptionlist = NULL; for (stmt = *stmts; stmt; stmt = stmt->next) { curstmtvalue = stmt->value; if (stmt->flags & StmtFlag_1) { has_catch_blocks = 1; dynamic_stack = 1; requires_frame = 1; } switch (stmt->type) { case ST_EXPRESSION: expandTOCexpression(stmt->expr, NULL, 1); if (stmt->expr->type == ETYPCON && IS_TYPE_VOID(stmt->expr->rtype)) stmt->expr = stmt->expr->data.monadic; break; case ST_GOTOEXPR: expandTOCexpression(stmt->expr, NULL, 0); break; case ST_IFGOTO: case ST_IFNGOTO: if (stmt->expr->type < ELESS || stmt->expr->type > ENOTEQU) stmt->expr = comparewithzero(stmt->expr); expandTOCexpression(stmt->expr, NULL, 0); break; case ST_RETURN: if (!stmt->expr) continue; expandTOCexpression( stmt->expr, NULL, IS_TYPE_ARRAY(stmt->expr->rtype) || IS_TYPE_NONVECTOR_STRUCT(stmt->expr->rtype) || IS_TYPE_CLASS(stmt->expr->rtype) || IS_TYPE_12BYTES_MEMBERPOINTER(stmt->expr->rtype)); break; case ST_SWITCH: uses_globals = 1; expandTOCexpression(stmt->expr, NULL, 0); break; case ST_ENDCATCHDTOR: requires_frame = 1; makes_call = 1; break; case ST_ASM: if ((ia = (InlineAsm *) stmt->expr)) { if (ia->flags & IAFlag1) { if (ia->opcode == IADirective_FrFree) requires_frame = 1; } else { for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { if (op->type == IAOpnd_Reg) { if (!op->u.reg.object) { if (op->u.reg.num == INVALID_PIC_REG) uses_globals = 1; else if (op->u.reg.effect & EffectWrite) asm_used_register(op->u.reg.rclass, op->u.reg.num); } else if ((vi = Registers_GetVarInfo(op->u.reg.object))) { vi->flags |= VarInfoFlag40; } } else if (op->type == IAOpnd_3) { uses_globals = 1; } } if (ia->flags & IAFlag2) makes_call = 1; } } break; } checkexceptionreferences(stmt->dobjstack); } } void resetTOCvarinfo(void) { ObjectList *list; for (list = toclist; list; list = list->next) list->object->u.toc.info = CodeGen_GetNewVarInfo(); } Boolean needdescriptor(void) { // completely unused, dunno what args this might take return 0; } Object *createstaticinitobject(void) { char buf[100]; char *p; Str255 fname; TypeFunc *tfunc; Object *obj; COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, fname); sprintf(buf, "__sinit_%*.*s", -fname[0], fname[0], &fname[1]); for (p = &buf[1]; *p; p++) { if (*p == '.') *p = '_'; } tfunc = galloc(sizeof(TypeFunc)); memclrw(tfunc, sizeof(TypeFunc)); tfunc->type = TYPEFUNC; tfunc->functype = &stvoid; tfunc->args = NULL; tfunc->flags = FUNC_DEFINED; obj = galloc(sizeof(Object)); memclrw(obj, sizeof(Object)); obj->otype = OT_OBJECT; obj->type = (Type *) tfunc; obj->name = GetHashNameNodeExport(buf); obj->sclass = TK_STATIC; obj->datatype = DFUNC; return obj; } static void estimate_func_param_size(ENode *node) { SInt32 work; ENodeList *list; SInt32 align; work = 0; for (list = node->data.funccall.args; list; list = list->next) { align = ~7 & (CMach_ArgumentAlignment(list->node->rtype) + 7); work += ~(align - 1) & (list->node->rtype->size + align - 1); } estimate_out_param_size(work); }