summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
committerAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
commit094b96ca1df4a035b5f93c351f773306c0241f3f (patch)
tree95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-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.c2272
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);
+}