MWCC/compiler_and_linker/unsorted/TOC.c

2049 lines
67 KiB
C
Raw Normal View History

2022-11-07 03:06:21 +00:00
#include "cos.h"
#include "compiler/TOC.h"
#include "compiler/CDecl.h"
2022-11-07 03:06:21 +00:00
#include "compiler/CError.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/InstrSelection.h"
2022-11-07 03:06:21 +00:00
#include "compiler/Operands.h"
#include "compiler/PCode.h"
#include "compiler/PCodeInfo.h"
#include "compiler/StackFrame.h"
#include "compiler/CompilerTools.h"
2022-11-07 03:06:21 +00:00
#include "compiler/enode.h"
#include "compiler/objects.h"
#include "compiler/types.h"
ObjectList *toclist;
ObjectList *exceptionlist;
void *descriptorlist;
void *floatconstpool;
void *doubleconstpool;
ObjectList *floatconstlist;
void *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 = OBJECT_SCLASS_102;
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) {
#line 622
CError_ASSERT(!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 = OBJECT_SCLASS_102;
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 {
#line 807
CError_FATAL();
}
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 = OBJECT_SCLASS_102;
obj->qual = Q_CONST | Q_10000;
obj->datatype = DDATA;
if (type->size == 16) {
obj->section = SECT_16BYTE_LITERALS;
} else {
#line 900
CError_FATAL();
}
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() {
// TODO CInit
}
static Object *CreatePooledFloatConst(Type *type, Float *data, SInt32 *unkptr) {
// TODO CDecl
}
Object *CreateFloatConst(Type *type, Float *data, SInt32 *unkptr) {
*unkptr = 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(&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) {
UInt8 data[16];
// TODO
}
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 = OBJECT_SCLASS_102;
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 {
#line 1789
CError_ASSERT(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;
for (i = 0; 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:
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 != DDATA && expr->data.monadic->data.objref->datatype != DLOCAL)
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:
#line 2523
CError_FATAL();
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
#line 2886
CError_ASSERT(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:
#line 2975
CError_FATAL();
}
}
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:
#line 3033
CError_FATAL();
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:
#line 3083
CError_FATAL();
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;
#line 3203
CError_ASSERT(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_8) {
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_35) {
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_36) {
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;
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 (stmt->expr) {
// TODO - ASM weirdness here
}
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 = OBJECT_SCLASS_102;
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);
}