#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_INTERNAL; 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; }