mirror of https://git.wuffs.org/MWCC
2273 lines
74 KiB
C
2273 lines
74 KiB
C
#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.optimize_for_size ? 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_10000;
|
|
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_10000;
|
|
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->isPrecompiling == 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.x4E = 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->isPrecompiling == 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.x4E = 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->isPrecompiling == 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.x4E = 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_FLAGS_4;
|
|
|
|
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.x1E;
|
|
|
|
if (!opt) return 0;
|
|
if (!copts.peephole) return 0;
|
|
if (left->hascall) return 0;
|
|
if (right->hascall) return 0;
|
|
if (!TYPE_FITS_IN_REGISTER(rtype)) return 0;
|
|
if (!TYPE_FITS_IN_REGISTER(left->rtype)) return 0;
|
|
if (!TYPE_FITS_IN_REGISTER(right->rtype)) return 0;
|
|
|
|
if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU)
|
|
return 0;
|
|
if (TYPE_IS_8BYTES(rtype))
|
|
return 0;
|
|
|
|
if (flag) {
|
|
if (!TYPE_FITS_IN_REGISTER(expr->data.cond.cond->data.diadic.right->rtype))
|
|
return 0;
|
|
if (TYPE_IS_8BYTES(expr->data.cond.cond->data.diadic.right->rtype))
|
|
return 0;
|
|
}
|
|
|
|
if (expr->type == ECONDASS) {
|
|
if (left->type != EINDIRECT)
|
|
return 0;
|
|
if (left->data.monadic->type != EOBJREF)
|
|
return 0;
|
|
if (flag) {
|
|
obj = left->data.monadic->data.objref;
|
|
if (obj->datatype != DLOCAL)
|
|
return 0;
|
|
if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0)
|
|
return 0;
|
|
if (obj->u.var.info->rclass != RegClass_GPR)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (DetectCondSideAffect(left))
|
|
return 0;
|
|
if (DetectCondSideAffect(right))
|
|
return 0;
|
|
|
|
if (expr->type == ECONDASS)
|
|
score1 = 1;
|
|
else
|
|
score1 = WeightandSumOps(left);
|
|
score2 = WeightandSumOps(right);
|
|
|
|
if (score1 > opt)
|
|
return 0;
|
|
else if (score2 > opt)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
SInt32 GetSizeSkip(ENode *expr) {
|
|
if (expr->type == EASS)
|
|
expr = expr->data.diadic.right;
|
|
if (expr->type == ETYPCON && expr->data.monadic->rtype->size < expr->rtype->size)
|
|
return expr->data.monadic->rtype->size;
|
|
else
|
|
return expr->rtype->size;
|
|
}
|
|
|
|
void Optimize64bitMath(ENode *expr) {
|
|
ENode *left; // r23
|
|
ENode *right; // r28
|
|
SInt32 leftsize; // r24
|
|
SInt32 rightsize; // r25
|
|
SInt32 totalsize; // r22
|
|
int unsignedflag; // r4
|
|
|
|
CError_ASSERT(2886, TYPE_IS_8BYTES(expr->rtype));
|
|
|
|
left = expr->data.diadic.left;
|
|
right = expr->data.diadic.right;
|
|
leftsize = GetSizeSkip(left);
|
|
totalsize = (leftsize + (rightsize = GetSizeSkip(right)));
|
|
unsignedflag = is_unsigned(expr->rtype) != 0;
|
|
|
|
switch (totalsize) {
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
if (unsignedflag) {
|
|
left->rtype = (Type *) &stunsignedint;
|
|
right->rtype = (Type *) &stunsignedint;
|
|
} else {
|
|
left->rtype = (Type *) &stsignedint;
|
|
right->rtype = (Type *) &stsignedint;
|
|
}
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 12:
|
|
if (expr->type != ESUB || leftsize >= rightsize) {
|
|
if (leftsize < 4) {
|
|
if (unsignedflag)
|
|
left->rtype = (Type *) &stunsignedint;
|
|
else
|
|
left->rtype = (Type *) &stsignedint;
|
|
} else {
|
|
if (left->type == ETYPCON && left->data.monadic->rtype != (Type *) &stfloat)
|
|
expr->data.diadic.left = left->data.monadic;
|
|
}
|
|
if (rightsize < 4) {
|
|
if (unsignedflag)
|
|
right->rtype = (Type *) &stunsignedint;
|
|
else
|
|
right->rtype = (Type *) &stsignedint;
|
|
} else {
|
|
if (right->type == ETYPCON && right->data.monadic->rtype != (Type *) &stfloat)
|
|
expr->data.diadic.right = right->data.monadic;
|
|
}
|
|
}
|
|
break;
|
|
case 16:
|
|
break;
|
|
default:
|
|
CError_FATAL(2975);
|
|
}
|
|
}
|
|
|
|
static Boolean OptimizeNestedAssginments(ENode **pexpr, Object *check) {
|
|
ENode *expr;
|
|
Boolean success1;
|
|
Boolean success2;
|
|
|
|
expr = *pexpr;
|
|
switch (expr->type) {
|
|
case EOBJREF:
|
|
return check != expr->data.objref;
|
|
case EMUL:
|
|
case EMULV:
|
|
case EDIV:
|
|
case EMODULO:
|
|
case EADDV:
|
|
case ESUBV:
|
|
case EADD:
|
|
case ESUB:
|
|
case ESHL:
|
|
case ESHR:
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
case ELAND:
|
|
case ELOR:
|
|
case EASS:
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
case ECOMMA:
|
|
case EPMODULO:
|
|
case EROTL:
|
|
case EROTR:
|
|
case EBCLR:
|
|
case EBTST:
|
|
case EBSET:
|
|
switch (expr->type) {
|
|
case EASS:
|
|
if (ENODE_IS(expr->data.diadic.left, EOBJREF) && expr->data.diadic.left->data.objref == check) {
|
|
*pexpr = expr->data.diadic.right;
|
|
return OptimizeNestedAssginments(pexpr, check);
|
|
}
|
|
break;
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
CError_FATAL(3033);
|
|
return 0;
|
|
}
|
|
if (OptimizeNestedAssginments(&expr->data.diadic.right, check))
|
|
return OptimizeNestedAssginments(&expr->data.diadic.left, check);
|
|
else
|
|
return 0;
|
|
break;
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
case EINDIRECT:
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
case ELOGNOT:
|
|
case EFORCELOAD:
|
|
case ETYPCON:
|
|
case EBITFIELD:
|
|
return OptimizeNestedAssginments(&expr->data.monadic, check);
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case ESTRINGCONST:
|
|
case EVECTOR128CONST:
|
|
return 1;
|
|
case ECOND:
|
|
success2 = OptimizeNestedAssginments(&expr->data.cond.expr2, check);
|
|
success1 = OptimizeNestedAssginments(&expr->data.cond.expr1, check);
|
|
if (!success2 || !success1)
|
|
return 0;
|
|
return OptimizeNestedAssginments(&expr->data.cond.cond, check) == 0;
|
|
case ECONDASS:
|
|
if (!OptimizeNestedAssginments(&expr->data.cond.expr2, check))
|
|
return 0;
|
|
if (OptimizeNestedAssginments(&expr->data.cond.cond, check))
|
|
return OptimizeNestedAssginments(&expr->data.cond.expr1, check) == 0;
|
|
else
|
|
return 0;
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
case EMFPOINTER:
|
|
case ENULLCHECK:
|
|
case EPRECOMP:
|
|
case EDEFINE:
|
|
case EREUSE:
|
|
case EASSBLK:
|
|
return 0;
|
|
default:
|
|
CError_FATAL(3083);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void expandTOCexpression(ENode *expr, Type *type, int ignored) {
|
|
Object *obj;
|
|
Object *tmpobj;
|
|
ENode *cond;
|
|
ENode *tmpexpr;
|
|
ENode *newexpr;
|
|
ENodeList *list;
|
|
|
|
expr->ignored = ignored;
|
|
switch (expr->type) {
|
|
case EINTCONST:
|
|
expr->hascall = 0;
|
|
break;
|
|
case EFLOATCONST:
|
|
uses_globals = 1;
|
|
RewriteFloatConst(expr);
|
|
expandTOCexpression(expr, NULL, 0);
|
|
break;
|
|
case EVECTOR128CONST:
|
|
if (!canoptimizevectorconst(&expr->data.vector128val, expr->rtype, NULL)) {
|
|
uses_globals = 1;
|
|
RewriteVectorConst(expr);
|
|
expandTOCexpression(expr, NULL, 0);
|
|
}
|
|
break;
|
|
case ESTRINGCONST:
|
|
uses_globals = 1;
|
|
CInit_RewriteString(expr, 1);
|
|
expandTOCexpression(expr, NULL, 0);
|
|
break;
|
|
case EOBJREF:
|
|
obj = expr->data.objref;
|
|
CError_ASSERT(3203, obj->datatype != DALIAS);
|
|
if (obj->datatype == DFUNC || obj->datatype == DVFUNC)
|
|
uses_globals = 1;
|
|
if (obj->datatype == DDATA) {
|
|
uses_globals = 1;
|
|
if (createIndirect(obj, 0, 1)) {
|
|
tmpexpr = lalloc(sizeof(ENode));
|
|
memclrw(tmpexpr, sizeof(ENode));
|
|
tmpexpr->type = EOBJREF;
|
|
tmpexpr->cost = 0;
|
|
tmpexpr->data.objref = obj->toc;
|
|
tmpexpr->rtype = CDecl_NewPointerType(expr->rtype);
|
|
|
|
expr->type = EINDIRECT;
|
|
expr->cost = 1;
|
|
expr->data.monadic = tmpexpr;
|
|
}
|
|
}
|
|
expr->hascall = 0;
|
|
break;
|
|
case ECONDASS:
|
|
expr->ignored = 0;
|
|
case ECOND:
|
|
if (!ENODE_IS_RANGE(expr->data.cond.cond, ELESS, ENOTEQU))
|
|
expr->data.cond.cond = comparewithzero(expr->data.cond.cond);
|
|
expandTOCexpression(expr->data.cond.expr1, NULL, ignored);
|
|
expandTOCexpression(expr->data.cond.expr2, NULL, ignored);
|
|
if (TOC_use_fsel(expr)) {
|
|
cond = expr->data.cond.cond;
|
|
if (ENODE_IS(cond->data.diadic.right, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.right->data.floatval)) {
|
|
expandTOCexpression(cond->data.diadic.left, NULL, 0);
|
|
} else if (ENODE_IS(cond->data.diadic.left, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.left->data.floatval)) {
|
|
expandTOCexpression(cond->data.diadic.right, NULL, 0);
|
|
} else {
|
|
expandTOCexpression(expr->data.cond.cond, NULL, 0);
|
|
}
|
|
} else {
|
|
expandTOCexpression(expr->data.cond.cond, NULL, 0);
|
|
}
|
|
expr->hascall = expr->data.cond.cond->hascall | expr->data.cond.expr1->hascall | expr->data.cond.expr2->hascall;
|
|
break;
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
if (is_intrinsic_function_call(expr)) {
|
|
expr->hascall = 0;
|
|
if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_008) {
|
|
if (copts.altivec_model)
|
|
update_frame_align(16);
|
|
dynamic_stack = 1;
|
|
requires_frame = 1;
|
|
} else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_035) {
|
|
if (expr->data.funccall.args->next->node->type == ESTRINGCONST) {
|
|
rewritestrcpy(expr);
|
|
} else {
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
expr->hascall = 1;
|
|
}
|
|
} else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_036) {
|
|
if (expr->data.funccall.args->next->next->node->type != EINTCONST) {
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
expr->hascall = 1;
|
|
}
|
|
}
|
|
} else {
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
expr->hascall = 1;
|
|
}
|
|
|
|
if (disables_optimizer(expr)) {
|
|
disable_optimizer |= 1;
|
|
if (copts.disable_registers)
|
|
disable_optimizer |= 2;
|
|
}
|
|
|
|
if (ENODE_IS(expr->data.funccall.funcref, EINDIRECT) && IS_TYPE_FUNC(expr->data.funccall.funcref->rtype))
|
|
*expr->data.funccall.funcref = *expr->data.funccall.funcref->data.monadic;
|
|
|
|
if (ENODE_IS(expr->data.funccall.funcref, EOBJREF)) {
|
|
expr->data.funccall.funcref->hascall = 0;
|
|
if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC && (expr->data.funccall.funcref->flags & ENODE_FLAG_80)) {
|
|
tmpobj = galloc(sizeof(Object));
|
|
*tmpobj = *expr->data.funccall.funcref->data.objref;
|
|
tmpobj->datatype = DFUNC;
|
|
expr->data.funccall.funcref->data.objref = tmpobj;
|
|
}
|
|
} else {
|
|
expandTOCexpression(expr->data.funccall.funcref, NULL, 0);
|
|
}
|
|
|
|
for (list = expr->data.funccall.args; list; list = list->next)
|
|
expandTOCexpression(list->node, NULL, 0);
|
|
|
|
if (expr->hascall)
|
|
estimate_func_param_size(expr);
|
|
|
|
if (is_intrinsic_function_call(expr)) {
|
|
for (list = expr->data.funccall.args; list; list = list->next)
|
|
expr->hascall |= list->node->hascall;
|
|
}
|
|
|
|
if (CMach_PassResultInHiddenArg(TYPE_FUNC(expr->data.funccall.functype)->functype))
|
|
rewritefunctioncallreturningstruct(expr);
|
|
|
|
break;
|
|
case ECOMMA:
|
|
expandTOCexpression(expr->data.diadic.left, NULL, 1);
|
|
expandTOCexpression(expr->data.diadic.right, NULL, ignored);
|
|
expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
|
|
break;
|
|
case ELAND:
|
|
case ELOR:
|
|
if (!ENODE_IS(expr->data.diadic.left, ELOGNOT) && !ENODE_IS2(expr->data.diadic.left, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.left, ELESS, ENOTEQU))
|
|
expr->data.diadic.left = comparewithzero(expr->data.diadic.left);
|
|
if (!ENODE_IS(expr->data.diadic.right, ELOGNOT) && !ENODE_IS2(expr->data.diadic.right, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.right, ELESS, ENOTEQU))
|
|
expr->data.diadic.right = comparewithzero(expr->data.diadic.right);
|
|
expandTOCexpression(expr->data.diadic.left, NULL, 0);
|
|
expandTOCexpression(expr->data.diadic.right, NULL, 0);
|
|
expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
|
|
break;
|
|
case EDIVASS:
|
|
if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
|
|
uses_globals = 1;
|
|
rewrite_opassign(expr, EDIV);
|
|
goto opassign_common;
|
|
case EMULASS:
|
|
if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
|
|
uses_globals = 1;
|
|
rewrite_opassign(expr, EMUL);
|
|
goto opassign_common;
|
|
case EADDASS:
|
|
if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
|
|
uses_globals = 1;
|
|
rewrite_opassign(expr, EADD);
|
|
goto opassign_common;
|
|
case ESUBASS:
|
|
if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
|
|
uses_globals = 1;
|
|
rewrite_opassign(expr, ESUB);
|
|
goto opassign_common;
|
|
case EMODASS:
|
|
if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
|
|
uses_globals = 1;
|
|
rewrite_opassign(expr, EMODULO);
|
|
goto opassign_common;
|
|
case ESHLASS:
|
|
rewrite_opassign(expr, ESHL);
|
|
goto opassign_common;
|
|
case ESHRASS:
|
|
rewrite_opassign(expr, ESHR);
|
|
goto opassign_common;
|
|
case EANDASS:
|
|
rewrite_opassign(expr, EAND);
|
|
goto opassign_common;
|
|
case EXORASS:
|
|
rewrite_opassign(expr, EXOR);
|
|
goto opassign_common;
|
|
case EORASS:
|
|
rewrite_opassign(expr, EOR);
|
|
goto opassign_common;
|
|
case EASS:
|
|
if (ENODE_IS(expr->data.diadic.left, EINDIRECT))
|
|
expr->data.diadic.left = expr->data.diadic.left->data.monadic;
|
|
opassign_common:
|
|
expandTOCexpression(expr->data.diadic.left, NULL, 0);
|
|
expandTOCexpression(expr->data.diadic.right, NULL, 0);
|
|
expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
|
|
break;
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
if (ENODE_IS(expr->data.diadic.right, EINTCONST) && expr->data.diadic.right->data.intval.lo == 0 && expr->data.diadic.right->data.intval.hi == 0) {
|
|
for (tmpexpr = expr->data.diadic.left; ENODE_IS2(tmpexpr, EFORCELOAD, ETYPCON); tmpexpr = tmpexpr->data.monadic) {
|
|
if (!TYPE_FITS_IN_REGISTER(tmpexpr->rtype))
|
|
break;
|
|
}
|
|
if (ENODE_IS(tmpexpr, ELOGNOT) && TYPE_FITS_IN_REGISTER(tmpexpr->data.monadic->rtype)) {
|
|
if (ENODE_IS(expr, EEQU))
|
|
expr->type = ENOTEQU;
|
|
else
|
|
expr->type = EEQU;
|
|
expr->data.diadic.left = tmpexpr->data.monadic;
|
|
expandTOCexpression(expr, NULL, 0);
|
|
break;
|
|
}
|
|
if (ENODE_IS(tmpexpr, EEQU)) {
|
|
if (ENODE_IS(expr, EEQU))
|
|
tmpexpr->type = ENOTEQU;
|
|
*expr = *tmpexpr;
|
|
expandTOCexpression(expr, NULL, 0);
|
|
break;
|
|
}
|
|
if (ENODE_IS(tmpexpr, ENOTEQU)) {
|
|
if (ENODE_IS(expr, EEQU))
|
|
tmpexpr->type = EEQU;
|
|
*expr = *tmpexpr;
|
|
expandTOCexpression(expr, NULL, 0);
|
|
break;
|
|
}
|
|
if (ENODE_IS(tmpexpr, ECOND)) {
|
|
newexpr = COND_to_COMPARE(tmpexpr->data.cond.cond, tmpexpr->data.cond.expr1, tmpexpr->data.cond.expr2);
|
|
if (newexpr) {
|
|
*tmpexpr = *newexpr;
|
|
expandTOCexpression(expr, NULL, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
case EDIV:
|
|
if (ENODE_IS(expr, EDIV) && ENODE_IS(expr->data.diadic.right, EFLOATCONST) && CMach_FloatIsPowerOf2(expr->data.diadic.right->data.floatval)) {
|
|
expr->type = EMUL;
|
|
expr->data.diadic.right->data.floatval = CMach_FloatReciprocal(expr->data.diadic.right->data.floatval);
|
|
}
|
|
case EMODULO:
|
|
case ESHL:
|
|
case ESHR:
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
expandTOCexpression(expr->data.diadic.left, NULL, 0);
|
|
expandTOCexpression(expr->data.diadic.right, NULL, 0);
|
|
expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
|
|
if (TYPE_IS_8BYTES(expr->rtype)) {
|
|
if (ENODE_IS2(expr, ESHL, ESHR) && !ENODE_IS(expr->data.diadic.right, EINTCONST)) {
|
|
expr->hascall = 1;
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
}
|
|
if (ENODE_IS2(expr, EDIV, EMODULO)) {
|
|
if (ENODE_IS(expr->data.diadic.right, EINTCONST)) {
|
|
if (I8_log2n(((SInt64) expr->data.diadic.right->data.intval.hi << 32) + expr->data.diadic.right->data.intval.lo) <= 0) {
|
|
expr->hascall = 1;
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
}
|
|
} else {
|
|
expr->hascall = 1;
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ESUB:
|
|
if (ENODE_IS(expr->data.diadic.right, EINTCONST)) {
|
|
expr->type = EADD;
|
|
expr->data.diadic.right->data.intval = CInt64_Neg(expr->data.diadic.right->data.intval);
|
|
}
|
|
case EMUL:
|
|
case EADD:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
expandTOCexpression(expr->data.diadic.left, type, 0);
|
|
expandTOCexpression(expr->data.diadic.right, type, 0);
|
|
expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
|
|
if (ENODE_IS3(expr, EMUL, EADD, ESUB) && TYPE_IS_8BYTES(expr->rtype))
|
|
Optimize64bitMath(expr);
|
|
if (type) {
|
|
if (
|
|
ENODE_IS(expr->data.diadic.left, ETYPCON) &&
|
|
IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->rtype) &&
|
|
IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->data.monadic->rtype) &&
|
|
expr->data.diadic.left->data.monadic->rtype->size >= type->size &&
|
|
!TYPE_IS_8BYTES(expr->data.diadic.left->data.monadic->rtype)
|
|
)
|
|
expr->data.diadic.left = expr->data.diadic.left->data.monadic;
|
|
|
|
if (
|
|
ENODE_IS(expr->data.diadic.right, ETYPCON) &&
|
|
IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->rtype) &&
|
|
IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->data.monadic->rtype) &&
|
|
expr->data.diadic.right->data.monadic->rtype->size >= type->size &&
|
|
!TYPE_IS_8BYTES(expr->data.diadic.right->data.monadic->rtype)
|
|
)
|
|
expr->data.diadic.right = expr->data.diadic.right->data.monadic;
|
|
|
|
expr->rtype = type;
|
|
}
|
|
break;
|
|
|
|
case ETYPCON:
|
|
tmpexpr = expr->data.monadic;
|
|
if ((IS_TYPE_INT_OR_ENUM(expr->rtype) && expr->rtype->size < 4) && IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && !TYPE_IS_8BYTES(tmpexpr->rtype)) {
|
|
expandTOCexpression(tmpexpr, expr->rtype, 0);
|
|
} else {
|
|
expandTOCexpression(tmpexpr, NULL, expr->rtype->type == TYPEVOID);
|
|
}
|
|
|
|
expr->hascall = tmpexpr->hascall;
|
|
if (IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype))
|
|
uses_globals = 1;
|
|
|
|
if ((TYPE_IS_8BYTES(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype)) || (TYPE_IS_8BYTES(expr->rtype) && IS_TYPE_FLOAT(tmpexpr->rtype))) {
|
|
uses_globals = 1;
|
|
expr->hascall = 1;
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
}
|
|
|
|
if (IS_TYPE_FLOAT(tmpexpr->rtype)) {
|
|
if (is_unsigned(expr->rtype) && expr->rtype->size == 4) {
|
|
expr->hascall = 1;
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
} else {
|
|
uses_globals = 1;
|
|
}
|
|
}
|
|
|
|
if (IS_TYPE_VECTOR(expr->rtype) && !IS_TYPE_VECTOR(tmpexpr->rtype))
|
|
PPCError_Error(114);
|
|
break;
|
|
|
|
case EPOSTINC:
|
|
if (!expr->ignored) {
|
|
if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype))
|
|
uses_globals = 1;
|
|
expandTOCexpression(expr->data.monadic, NULL, 0);
|
|
expr->hascall = expr->data.monadic->hascall;
|
|
break;
|
|
}
|
|
expr->type = EPREINC;
|
|
case EPREINC:
|
|
rewrite_preincdec(expr);
|
|
rewrite_opassign(expr, EADD);
|
|
goto opassign_common;
|
|
|
|
case EPOSTDEC:
|
|
if (!expr->ignored) {
|
|
if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype))
|
|
uses_globals = 1;
|
|
expandTOCexpression(expr->data.monadic, NULL, 0);
|
|
expr->hascall = expr->data.monadic->hascall;
|
|
break;
|
|
}
|
|
expr->type = EPREDEC;
|
|
case EPREDEC:
|
|
rewrite_preincdec(expr);
|
|
rewrite_opassign(expr, ESUB);
|
|
goto opassign_common;
|
|
|
|
case ELOGNOT:
|
|
if (!ENODE_IS(expr->data.monadic, ELOGNOT) && !ENODE_IS2(expr->data.monadic, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.monadic, ELESS, ENOTEQU))
|
|
expr->data.monadic = comparewithzero(expr->data.monadic);
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
tmpexpr = expr->data.monadic;
|
|
expandTOCexpression(tmpexpr, type, 0);
|
|
expr->hascall = tmpexpr->hascall;
|
|
if (type && ENODE_IS(expr->data.monadic, ETYPCON)) {
|
|
if (IS_TYPE_INT_OR_ENUM(expr->data.monadic->rtype) && IS_TYPE_INT_OR_ENUM(expr->data.monadic->data.monadic->rtype)) {
|
|
if (expr->data.monadic->data.monadic->rtype->size >= type->size) {
|
|
expr->data.monadic = expr->data.monadic->data.monadic;
|
|
expr->rtype = type;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EINDIRECT:
|
|
case EFORCELOAD:
|
|
case EBITFIELD:
|
|
tmpexpr = expr->data.monadic;
|
|
expandTOCexpression(tmpexpr, NULL, 0);
|
|
expr->hascall = tmpexpr->hascall;
|
|
break;
|
|
|
|
case EDEFINE:
|
|
tmpexpr = expr->data.monadic;
|
|
expandTOCexpression(tmpexpr, NULL, 0);
|
|
expr->hascall = tmpexpr->hascall;
|
|
break;
|
|
|
|
case EREUSE:
|
|
expr->hascall = expr->data.monadic->hascall;
|
|
break;
|
|
|
|
case ENULLCHECK:
|
|
expandTOCexpression(expr->data.diadic.left, NULL, 0);
|
|
expandTOCexpression(expr->data.diadic.right, NULL, 0);
|
|
expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
|
|
break;
|
|
|
|
case EPRECOMP:
|
|
expr->hascall = 0;
|
|
break;
|
|
|
|
case ELABEL:
|
|
obj = createcodelabel(expr->data.label);
|
|
newexpr = lalloc(sizeof(ENode));
|
|
memclrw(newexpr, sizeof(ENode));
|
|
newexpr->type = EOBJREF;
|
|
newexpr->cost = 0;
|
|
newexpr->data.objref = obj;
|
|
newexpr->rtype = CDecl_NewPointerType(obj->type);
|
|
|
|
expr->type = EINDIRECT;
|
|
expr->cost = 1;
|
|
expr->data.monadic = newexpr;
|
|
expr->hascall = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void checkexceptionreferences(ExceptionAction *action) {
|
|
for (; action; action = action->prev) {
|
|
switch (action->type) {
|
|
case EAT_DESTROYLOCAL:
|
|
referenceexception(action->data.destroy_local.local);
|
|
break;
|
|
case EAT_DESTROYLOCALCOND:
|
|
referenceexception(action->data.destroy_local_cond.local);
|
|
referenceexception(action->data.destroy_local_cond.cond);
|
|
break;
|
|
case EAT_DESTROYLOCALOFFSET:
|
|
referenceexception(action->data.destroy_local_offset.local);
|
|
break;
|
|
case EAT_DESTROYLOCALPOINTER:
|
|
referenceexception(action->data.destroy_local_pointer.pointer);
|
|
break;
|
|
case EAT_DESTROYLOCALARRAY:
|
|
referenceexception(action->data.destroy_local_array.localarray);
|
|
break;
|
|
case EAT_DESTROYBASE:
|
|
referenceexception(action->data.destroy_member.objectptr); // wrong union?
|
|
break;
|
|
case EAT_DESTROYPARTIALARRAY:
|
|
referenceexception(action->data.destroy_partial_array.arraypointer);
|
|
referenceexception(action->data.destroy_partial_array.arraycounter);
|
|
referenceexception(action->data.destroy_partial_array.element_size);
|
|
break;
|
|
case EAT_DESTROYMEMBER:
|
|
referenceexception(action->data.destroy_member.objectptr);
|
|
break;
|
|
case EAT_DESTROYMEMBERCOND:
|
|
referenceexception(action->data.destroy_member_cond.objectptr);
|
|
referenceexception(action->data.destroy_member_cond.cond);
|
|
break;
|
|
case EAT_DESTROYMEMBERARRAY:
|
|
referenceexception(action->data.destroy_member_array.objectptr);
|
|
break;
|
|
case EAT_DELETEPOINTER:
|
|
case EAT_DELETELOCALPOINTER:
|
|
referenceexception(action->data.delete_pointer.pointerobject);
|
|
break;
|
|
case EAT_DELETEPOINTERCOND:
|
|
referenceexception(action->data.delete_pointer_cond.pointerobject);
|
|
referenceexception(action->data.delete_pointer_cond.cond);
|
|
break;
|
|
case EAT_CATCHBLOCK:
|
|
referenceexception(action->data.catch_block.catch_object);
|
|
referenceexception(action->data.catch_block.catch_info_object);
|
|
break;
|
|
case EAT_ACTIVECATCHBLOCK:
|
|
referenceexception(action->data.active_catch_block.catch_info_object);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void expandTOCreferences(Statement **stmts) {
|
|
Statement *stmt;
|
|
IAOperand *op;
|
|
int i;
|
|
InlineAsm *ia;
|
|
VarInfo *vi;
|
|
|
|
codelabellist = NULL;
|
|
exceptionlist = NULL;
|
|
|
|
for (stmt = *stmts; stmt; stmt = stmt->next) {
|
|
curstmtvalue = stmt->value;
|
|
if (stmt->flags & StmtFlag_1) {
|
|
has_catch_blocks = 1;
|
|
dynamic_stack = 1;
|
|
requires_frame = 1;
|
|
}
|
|
|
|
switch (stmt->type) {
|
|
case ST_EXPRESSION:
|
|
expandTOCexpression(stmt->expr, NULL, 1);
|
|
if (stmt->expr->type == ETYPCON && IS_TYPE_VOID(stmt->expr->rtype))
|
|
stmt->expr = stmt->expr->data.monadic;
|
|
break;
|
|
case ST_GOTOEXPR:
|
|
expandTOCexpression(stmt->expr, NULL, 0);
|
|
break;
|
|
case ST_IFGOTO:
|
|
case ST_IFNGOTO:
|
|
if (stmt->expr->type < ELESS || stmt->expr->type > ENOTEQU)
|
|
stmt->expr = comparewithzero(stmt->expr);
|
|
expandTOCexpression(stmt->expr, NULL, 0);
|
|
break;
|
|
case ST_RETURN:
|
|
if (!stmt->expr)
|
|
continue;
|
|
expandTOCexpression(
|
|
stmt->expr, NULL,
|
|
IS_TYPE_ARRAY(stmt->expr->rtype) || IS_TYPE_NONVECTOR_STRUCT(stmt->expr->rtype) || IS_TYPE_CLASS(stmt->expr->rtype) ||
|
|
IS_TYPE_12BYTES_MEMBERPOINTER(stmt->expr->rtype));
|
|
break;
|
|
case ST_SWITCH:
|
|
uses_globals = 1;
|
|
expandTOCexpression(stmt->expr, NULL, 0);
|
|
break;
|
|
case ST_ENDCATCHDTOR:
|
|
requires_frame = 1;
|
|
makes_call = 1;
|
|
break;
|
|
case ST_ASM:
|
|
if ((ia = (InlineAsm *) stmt->expr)) {
|
|
if (ia->flags & IAFlag1) {
|
|
if (ia->opcode == IADirective_FrFree)
|
|
requires_frame = 1;
|
|
} else {
|
|
for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
|
|
if (op->type == IAOpnd_Reg) {
|
|
if (!op->u.reg.object) {
|
|
if (op->u.reg.num == INVALID_PIC_REG)
|
|
uses_globals = 1;
|
|
else if (op->u.reg.effect & EffectWrite)
|
|
asm_used_register(op->u.reg.rclass, op->u.reg.num);
|
|
} else if ((vi = Registers_GetVarInfo(op->u.reg.object))) {
|
|
vi->flags |= VarInfoFlag40;
|
|
}
|
|
} else if (op->type == IAOpnd_3) {
|
|
uses_globals = 1;
|
|
}
|
|
}
|
|
|
|
if (ia->flags & IAFlag2)
|
|
makes_call = 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
checkexceptionreferences(stmt->dobjstack);
|
|
}
|
|
}
|
|
|
|
void resetTOCvarinfo(void) {
|
|
ObjectList *list;
|
|
|
|
for (list = toclist; list; list = list->next)
|
|
list->object->u.toc.info = CodeGen_GetNewVarInfo();
|
|
}
|
|
|
|
Boolean needdescriptor(void) {
|
|
// completely unused, dunno what args this might take
|
|
return 0;
|
|
}
|
|
|
|
Object *createstaticinitobject(void) {
|
|
char buf[100];
|
|
char *p;
|
|
Str255 fname;
|
|
TypeFunc *tfunc;
|
|
Object *obj;
|
|
|
|
COS_FileGetFSSpecInfo(&cparamblkptr->mainFileSpec, 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_FLAGS_2;
|
|
|
|
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);
|
|
}
|