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