mirror of https://git.wuffs.org/MWCC
535 lines
17 KiB
C
535 lines
17 KiB
C
#include "compiler/CIRTransform.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInit.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/types.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/CDecl.h"
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma options align=mac68k
|
|
#endif
|
|
typedef struct CIRTransTemp {
|
|
struct CIRTransTemp *next;
|
|
Object *object;
|
|
Boolean flag;
|
|
} CIRTransTemp;
|
|
|
|
typedef struct MultiAccessOperand {
|
|
Object *object;
|
|
Object *tempobj;
|
|
ENode *ass;
|
|
Type *type;
|
|
Type *bitfieldType;
|
|
} MultiAccessOperand;
|
|
|
|
// no idea what this is for...
|
|
typedef struct StrangeRuntimeFunction {
|
|
Object *object;
|
|
short unk;
|
|
char name[1];
|
|
} StrangeRuntimeFunction;
|
|
#ifdef __MWERKS__
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
static TypeFunc cirtrans_rtfunc8 = {
|
|
TYPEFUNC, 0, NULL, NULL, TYPE(&void_ptr), 0, 0
|
|
};
|
|
static TypeFunc cirtrans_rtfunc4 = {
|
|
TYPEFUNC, 0, NULL, NULL, TYPE(&stunsignedlong), 0, 0
|
|
};
|
|
static TypeFunc cirtrans_rtfunc2 = {
|
|
TYPEFUNC, 0, NULL, NULL, TYPE(&stsignedshort), 0, 0
|
|
};
|
|
|
|
static CIRTransTemp *cirtrans_temps;
|
|
Boolean modulo_generated;
|
|
Boolean bigswitch_generated;
|
|
Boolean alloca_called;
|
|
|
|
// forward decls
|
|
static ENode *CIRTrans_TransExpr(ENode *expr, Boolean flag);
|
|
|
|
void CIRTrans_Setup(void) {
|
|
}
|
|
|
|
void CIRTrans_Cleanup(void) {
|
|
}
|
|
|
|
static Object *CIRTrans_GetRuntimeFunction(StrangeRuntimeFunction *rtfunc, Type *type) {
|
|
Object *object;
|
|
|
|
object = rtfunc->object;
|
|
if (!object) {
|
|
object = CParser_NewFunctionObject(NULL);
|
|
rtfunc->object = object;
|
|
|
|
object->nspace = cscope_root;
|
|
object->name = GetHashNameNodeExport(rtfunc->name);
|
|
object->flags = OBJECT_FLAGS_10;
|
|
|
|
if (type) {
|
|
switch (type->size) {
|
|
case 2:
|
|
object->type = TYPE(&cirtrans_rtfunc2);
|
|
break;
|
|
case 4:
|
|
object->type = TYPE(&cirtrans_rtfunc4);
|
|
break;
|
|
case 8:
|
|
object->type = TYPE(&cirtrans_rtfunc8);
|
|
break;
|
|
default:
|
|
CError_FATAL(427);
|
|
}
|
|
} else {
|
|
object->type = TYPE(&cirtrans_rtfunc8);
|
|
}
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
static Object *CIRTrans_GetTemporary(Type *type) {
|
|
CIRTransTemp *temp;
|
|
|
|
for (temp = cirtrans_temps; temp; temp = temp->next) {
|
|
if (temp->object->type->size == type->size && !temp->flag) {
|
|
temp->flag = 1;
|
|
return temp->object;
|
|
}
|
|
}
|
|
|
|
temp = oalloc(sizeof(CIRTransTemp));
|
|
temp->next = cirtrans_temps;
|
|
cirtrans_temps = temp;
|
|
|
|
temp->object = create_temp_object(type);
|
|
temp->flag = 1;
|
|
return temp->object;
|
|
}
|
|
|
|
static ENode *CIRTrans_CheckRuntimeAssign(ENode *expr) {
|
|
ENode *inner;
|
|
|
|
if (ENODE_IS(expr->data.diadic.right, EINDIRECT)) {
|
|
inner = expr->data.diadic.right->data.monadic;
|
|
if (
|
|
ENODE_IS(inner, EFUNCCALL) &&
|
|
(inner->flags & ENODE_FLAG_80) &&
|
|
inner->data.funccall.args &&
|
|
ENODE_IS(inner->data.funccall.args->node, EOBJREF)
|
|
)
|
|
{
|
|
CError_ASSERT(502, ENODE_IS(expr->data.diadic.left, EINDIRECT));
|
|
inner->data.funccall.args->node = expr->data.diadic.left->data.monadic;
|
|
inner->flags &= ~ENODE_FLAG_80;
|
|
return expr->data.diadic.right;
|
|
}
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
static void CIRTrans_SetupMultiAccessOperand(MultiAccessOperand *mop, ENode *expr) {
|
|
memclrw(mop, sizeof(MultiAccessOperand));
|
|
|
|
mop->type = expr->rtype;
|
|
|
|
CError_ASSERT(522, ENODE_IS(expr, EINDIRECT));
|
|
expr = expr->data.monadic;
|
|
|
|
if (ENODE_IS(expr, EOBJREF)) {
|
|
mop->object = expr->data.objref;
|
|
} else {
|
|
if (ENODE_IS(expr, EBITFIELD)) {
|
|
mop->bitfieldType = expr->rtype;
|
|
expr = expr->data.monadic;
|
|
}
|
|
expr->rtype = CDecl_NewPointerType(mop->type);
|
|
mop->tempobj = create_temp_object(expr->rtype);
|
|
mop->ass = makediadicnode(create_objectnode(mop->tempobj), expr, EASS);
|
|
}
|
|
}
|
|
|
|
static ENode *CIRTrans_GetMultiAccessOperand(MultiAccessOperand *mop) {
|
|
ENode *expr;
|
|
|
|
if (mop->object == NULL) {
|
|
expr = create_objectnode(mop->tempobj);
|
|
if (mop->bitfieldType) {
|
|
expr = makemonadicnode(expr, EBITFIELD);
|
|
expr->rtype = mop->bitfieldType;
|
|
}
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
} else {
|
|
expr = create_objectnode(mop->object);
|
|
}
|
|
|
|
expr->rtype = mop->type;
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CIRTrans_InitMultiAccessExpression(MultiAccessOperand *mop, ENode *expr) {
|
|
if (mop->ass) {
|
|
expr = makediadicnode(mop->ass, expr, ECOMMA);
|
|
expr->rtype = expr->data.diadic.right->rtype;
|
|
}
|
|
return expr;
|
|
}
|
|
|
|
ENode *CIRTrans_TransformOpAss(ENode *expr) {
|
|
ENodeType nt;
|
|
ENode *expr2;
|
|
MultiAccessOperand mop;
|
|
|
|
if (!ENODE_IS(expr->data.diadic.left, EINDIRECT)) {
|
|
CError_Error(CErrorStr142);
|
|
return nullnode();
|
|
}
|
|
|
|
CIRTrans_SetupMultiAccessOperand(&mop, expr->data.diadic.left);
|
|
|
|
switch (expr->type) {
|
|
case EMULASS:
|
|
nt = EMUL;
|
|
break;
|
|
case EDIVASS:
|
|
nt = EDIV;
|
|
break;
|
|
case EMODASS:
|
|
nt = EMODULO;
|
|
break;
|
|
case EADDASS:
|
|
nt = EADD;
|
|
break;
|
|
case ESUBASS:
|
|
nt = ESUB;
|
|
break;
|
|
case ESHLASS:
|
|
nt = ESHL;
|
|
break;
|
|
case ESHRASS:
|
|
nt = ESHR;
|
|
break;
|
|
case EANDASS:
|
|
nt = EAND;
|
|
break;
|
|
case EXORASS:
|
|
nt = EXOR;
|
|
break;
|
|
case EORASS:
|
|
nt = EOR;
|
|
break;
|
|
default:
|
|
CError_FATAL(622);
|
|
}
|
|
|
|
expr2 = CIRTrans_GetMultiAccessOperand(&mop);
|
|
|
|
if (!IS_TYPE_POINTER_ONLY(expr2->rtype)) {
|
|
expr2 = CExpr_NewDyadicNode(expr2, nt, expr->data.diadic.right);
|
|
if (expr2->rtype != expr->data.diadic.left->rtype) {
|
|
expr2 = makemonadicnode(expr2, ETYPCON);
|
|
expr2->rtype = expr->data.diadic.left->rtype;
|
|
}
|
|
} else {
|
|
expr2 = makediadicnode(expr2, expr->data.diadic.right, nt);
|
|
}
|
|
|
|
if (IS_TYPE_FLOAT(expr2->rtype))
|
|
expr2 = CExpr_BinaryFloatExpression(expr2);
|
|
|
|
expr2 = makediadicnode(CIRTrans_GetMultiAccessOperand(&mop), expr2, EASS);
|
|
return CIRTrans_InitMultiAccessExpression(&mop, expr2);
|
|
}
|
|
|
|
static void CIRTrans_TransIncDec() {
|
|
// empty, never called
|
|
}
|
|
|
|
static ENode *CIRTrans_TransIntConst(ENode *expr) {
|
|
Object *obj;
|
|
UInt8 data[16];
|
|
|
|
CMach_InitIntMem(expr->rtype, expr->data.intval, data);
|
|
|
|
obj = CParser_NewGlobalDataObject(NULL);
|
|
obj->name = CParser_GetUniqueName();
|
|
obj->type = expr->rtype;
|
|
obj->sclass = TK_STATIC;
|
|
obj->datatype = DDATA;
|
|
CScope_AddGlobalObject(obj);
|
|
CInit_DeclareData(obj, data, NULL, obj->type->size);
|
|
return create_objectnode(obj);
|
|
}
|
|
|
|
static ENode *CIRTrans_TransFloatConst(ENode *expr) {
|
|
Object *obj;
|
|
UInt8 data[16];
|
|
|
|
CMach_InitFloatMem(expr->rtype, expr->data.floatval, data);
|
|
|
|
obj = CParser_NewGlobalDataObject(NULL);
|
|
obj->name = CParser_GetUniqueName();
|
|
obj->type = expr->rtype;
|
|
obj->sclass = TK_STATIC;
|
|
obj->datatype = DDATA;
|
|
CScope_AddGlobalObject(obj);
|
|
CInit_DeclareData(obj, data, NULL, obj->type->size);
|
|
return create_objectnode(obj);
|
|
}
|
|
|
|
static ENode *CIRTrans_TransUnary(ENode *expr, Type *type, StrangeRuntimeFunction *rtfunc) {
|
|
if (type->size > 4) {
|
|
expr = funccallexpr(
|
|
CIRTrans_GetRuntimeFunction(rtfunc, type),
|
|
create_objectrefnode(CIRTrans_GetTemporary(type)),
|
|
expr,
|
|
NULL,
|
|
NULL);
|
|
expr->flags |= ENODE_FLAG_80;
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->rtype = type;
|
|
return expr;
|
|
} else {
|
|
expr = funccallexpr(
|
|
CIRTrans_GetRuntimeFunction(rtfunc, type),
|
|
expr,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
expr->rtype = type;
|
|
return expr;
|
|
}
|
|
}
|
|
|
|
static ENode *CIRTrans_TransBinary(ENode *expr, StrangeRuntimeFunction *rtfunc) {
|
|
ENode *expr2;
|
|
|
|
if (expr->rtype->size > 4) {
|
|
expr2 = funccallexpr(
|
|
CIRTrans_GetRuntimeFunction(rtfunc, expr->rtype),
|
|
create_objectrefnode(CIRTrans_GetTemporary(expr->rtype)),
|
|
expr->data.diadic.left,
|
|
expr->data.diadic.right,
|
|
NULL);
|
|
expr2->flags |= ENODE_FLAG_80;
|
|
expr2 = makemonadicnode(expr2, EINDIRECT);
|
|
expr2->rtype = expr->rtype;
|
|
return expr2;
|
|
} else {
|
|
expr2 = funccallexpr(
|
|
CIRTrans_GetRuntimeFunction(rtfunc, expr->rtype),
|
|
expr->data.diadic.left,
|
|
expr->data.diadic.right,
|
|
NULL,
|
|
NULL);
|
|
expr2->rtype = expr->rtype;
|
|
return expr2;
|
|
}
|
|
}
|
|
|
|
static ENodeList *CIRTrans_TransExprList(ENodeList *list) {
|
|
ENodeList *scan;
|
|
|
|
for (scan = list; scan; scan = scan->next)
|
|
scan->node = CIRTrans_TransExpr(scan->node, 1);
|
|
|
|
return list;
|
|
}
|
|
|
|
static ENode *CIRTrans_TransExpr(ENode *expr, Boolean flag) {
|
|
switch (expr->type) {
|
|
case EINDIRECT:
|
|
case EFORCELOAD:
|
|
case EBITFIELD:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag);
|
|
break;
|
|
case EPOSTINC:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1);
|
|
break;
|
|
case EPOSTDEC:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1);
|
|
break;
|
|
case EPREINC:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1);
|
|
break;
|
|
case EPREDEC:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, 1);
|
|
break;
|
|
case ETYPCON:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag);
|
|
if (!flag)
|
|
return expr->data.monadic;
|
|
break;
|
|
case EBINNOT:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag);
|
|
break;
|
|
case ELOGNOT:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag);
|
|
break;
|
|
case EMONMIN:
|
|
expr->data.monadic = CIRTrans_TransExpr(expr->data.monadic, flag);
|
|
break;
|
|
case EADD:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case ESUB:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EMUL:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
case EDIV:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EMODULO:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case ESHL:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case ESHR:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EROTL:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EROTR:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EAND:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EXOR:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EOR:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
if (!flag) {
|
|
expr->type = ECOMMA;
|
|
expr->rtype = expr->data.diadic.right->rtype;
|
|
return expr;
|
|
}
|
|
break;
|
|
case ELAND:
|
|
case ELOR:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EMULV:
|
|
case EADDV:
|
|
case ESUBV:
|
|
case EPMODULO:
|
|
case EBCLR:
|
|
case EBTST:
|
|
case EBSET:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, flag);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case EASS:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, 1);
|
|
break;
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, 1);
|
|
break;
|
|
case EMODASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 1);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, 1);
|
|
break;
|
|
case ECOMMA:
|
|
expr->data.diadic.left = CIRTrans_TransExpr(expr->data.diadic.left, 0);
|
|
expr->data.diadic.right = CIRTrans_TransExpr(expr->data.diadic.right, flag);
|
|
break;
|
|
case ECOND:
|
|
expr->data.cond.cond = CIRTrans_TransExpr(expr->data.cond.cond, 1);
|
|
expr->data.cond.expr1 = CIRTrans_TransExpr(expr->data.cond.expr1, 1);
|
|
expr->data.cond.expr2 = CIRTrans_TransExpr(expr->data.cond.expr2, 1);
|
|
break;
|
|
case EMFPOINTER:
|
|
expr->data.mfpointer.accessnode = CIRTrans_TransExpr(expr->data.mfpointer.accessnode, flag);
|
|
expr->data.mfpointer.mfpointer = CIRTrans_TransExpr(expr->data.mfpointer.mfpointer, flag);
|
|
break;
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
if (
|
|
ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
|
|
!strcmp(expr->data.funccall.funcref->data.objref->name->name, "__alloca")
|
|
)
|
|
alloca_called = 1;
|
|
expr->data.funccall.funcref = CIRTrans_TransExpr(expr->data.funccall.funcref, 1);
|
|
expr->data.funccall.args = CIRTrans_TransExprList(expr->data.funccall.args);
|
|
break;
|
|
case ENULLCHECK:
|
|
expr->data.nullcheck.nullcheckexpr = CIRTrans_TransExpr(expr->data.nullcheck.nullcheckexpr, 1);
|
|
expr->data.nullcheck.condexpr = CIRTrans_TransExpr(expr->data.nullcheck.condexpr, 1);
|
|
break;
|
|
case ENEWEXCEPTION:
|
|
case ENEWEXCEPTIONARRAY:
|
|
expr->data.newexception.initexpr = CIRTrans_TransExpr(expr->data.newexception.initexpr, 1);
|
|
expr->data.newexception.tryexpr = CIRTrans_TransExpr(expr->data.newexception.tryexpr, 1);
|
|
break;
|
|
case EINITTRYCATCH:
|
|
expr->data.itc.initexpr = CIRTrans_TransExpr(expr->data.itc.initexpr, 1);
|
|
expr->data.itc.tryexpr = CIRTrans_TransExpr(expr->data.itc.tryexpr, 1);
|
|
expr->data.itc.catchexpr = CIRTrans_TransExpr(expr->data.itc.catchexpr, 1);
|
|
expr->data.itc.result = CIRTrans_TransExpr(expr->data.itc.result, 1);
|
|
break;
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case ESTRINGCONST:
|
|
case EOBJREF:
|
|
case EPRECOMP:
|
|
case ETEMP:
|
|
case ELABEL:
|
|
case EMEMBER:
|
|
case EINSTRUCTION:
|
|
case EVECTOR128CONST:
|
|
break;
|
|
default:
|
|
CError_FATAL(1947);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
void CIRTrans_Transform(void) {
|
|
cirtrans_temps = NULL;
|
|
}
|